Commit | Line | Data |
---|---|---|
ad4b9c34 RG |
1 | /* |
2 | * Copyright (c) 1983 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
7 | #ifndef lint | |
95f51977 | 8 | static char sccsid[] = "@(#)cmds.c 2.2 (Berkeley) 4/21/86"; |
ad4b9c34 RG |
9 | #endif not lint |
10 | ||
11 | #include "timedc.h" | |
12 | #include <netinet/in_systm.h> | |
13 | #include <netinet/ip.h> | |
14 | #include <netinet/ip_icmp.h> | |
15 | #define TSPTYPES | |
16 | #include <protocols/timed.h> | |
17 | #include <sys/file.h> | |
18 | ||
ad4b9c34 RG |
19 | int id; |
20 | int sock; | |
21 | int sock_raw; | |
86fe47ef | 22 | char hostname[MAXHOSTNAMELEN]; |
ad4b9c34 RG |
23 | struct hostent *hp, *gethostbyname(); |
24 | struct sockaddr_in server; | |
25 | extern int measure_delta; | |
26 | int bytenetorder(), bytehostorder(); | |
27 | char *strcpy(); | |
28 | ||
29 | /* | |
30 | * Clockdiff computes the difference between the time of the machine on | |
31 | * which it is called and the time of the machines given as argument. | |
32 | * The time differences measured by clockdiff are obtained using a sequence | |
33 | * of ICMP TSTAMP messages which are returned to the sender by the IP module | |
34 | * in the remote machine. | |
35 | * In order to compare clocks of machines in different time zones, the time | |
36 | * is transmitted (as a 32-bit value) in milliseconds since midnight UT. | |
37 | * If a hosts uses a different time format, it should set the high order | |
38 | * bit of the 32-bit quantity it transmits. | |
39 | * However, VMS apparently transmits the time in milliseconds since midnight | |
40 | * local time (rather than GMT) without setting the high order bit. | |
41 | * Furthermore, it does not understand daylight-saving time. This makes | |
42 | * clockdiff behaving inconsistently with hosts running VMS. | |
43 | * | |
44 | * In order to reduce the sensitivity to the variance of message transmission | |
45 | * time, clockdiff sends a sequence of messages. Yet, measures between | |
46 | * two `distant' hosts can be affected by a small error. The error can, however, | |
47 | * be reduced by increasing the number of messages sent in each measurement. | |
48 | */ | |
49 | ||
50 | clockdiff(argc, argv) | |
51 | int argc; | |
52 | char *argv[]; | |
53 | { | |
54 | int measure_status; | |
55 | struct timeval ack; | |
56 | int measure(); | |
57 | ||
58 | if(argc < 2) { | |
59 | printf("Usage: clockdiff host ... \n"); | |
60 | return; | |
61 | } | |
62 | ||
63 | id = getpid(); | |
64 | (void)gethostname(hostname,sizeof(hostname)); | |
65 | ||
66 | while (argc > 1) { | |
67 | argc--; argv++; | |
68 | hp = gethostbyname(*argv); | |
69 | if (hp == NULL) { | |
70 | printf("%s: unknown host\n", *argv); | |
71 | continue; | |
72 | } | |
73 | server.sin_family = hp->h_addrtype; | |
74 | bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length); | |
38d4e510 JB |
75 | ack.tv_sec = 10; |
76 | ack.tv_usec = 0; | |
77 | if ((measure_status = measure(&ack, &server)) < 0) { | |
ad4b9c34 RG |
78 | perror("measure"); |
79 | return; | |
80 | } | |
81 | switch (measure_status) { | |
82 | ||
83 | case HOSTDOWN: | |
84 | printf("%s is down\n", hp->h_name); | |
85 | continue; | |
86 | break; | |
87 | case NONSTDTIME: | |
88 | printf("%s time transmitted in a non-standard format\n", hp->h_name); | |
89 | continue; | |
90 | break; | |
91 | case UNREACHABLE: | |
92 | printf("%s is unreachable\n", hp->h_name); | |
93 | continue; | |
94 | break; | |
95 | default: | |
96 | break; | |
97 | } | |
98 | ||
99 | if (measure_delta > 0) | |
100 | printf("time on %s is %d ms. ahead of time on %s\n", | |
101 | hp->h_name, measure_delta, | |
102 | hostname); | |
103 | else | |
104 | if (measure_delta == 0) | |
105 | printf("%s and %s have the same time\n", | |
106 | hp->h_name, hostname); | |
107 | else | |
108 | printf("time on %s is %d ms. behind time on %s\n", | |
109 | hp->h_name, -measure_delta, hostname); | |
110 | } | |
111 | return; | |
112 | } | |
113 | /* | |
114 | * finds location of master timedaemon | |
115 | */ | |
116 | ||
117 | msite(argc) | |
118 | int argc; | |
119 | { | |
120 | int length; | |
75d5ce8a JB |
121 | int cc; |
122 | fd_set ready; | |
ad4b9c34 RG |
123 | struct sockaddr_in dest; |
124 | struct timeval tout; | |
125 | struct sockaddr_in from; | |
126 | struct tsp msg; | |
127 | struct servent *srvp; | |
128 | ||
129 | if (argc != 1) { | |
130 | printf("Usage: msite\n"); | |
131 | return; | |
132 | } | |
133 | ||
ad4b9c34 RG |
134 | srvp = getservbyname("timed", "udp"); |
135 | if (srvp == 0) { | |
136 | fprintf(stderr, "udp/timed: unknown service\n"); | |
137 | return; | |
138 | } | |
139 | dest.sin_port = srvp->s_port; | |
140 | dest.sin_family = AF_INET; | |
141 | ||
142 | (void)gethostname(hostname,sizeof(hostname)); | |
143 | hp = gethostbyname(hostname); | |
144 | if (hp == NULL) { | |
145 | perror("gethostbyname"); | |
146 | return; | |
147 | } | |
148 | bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); | |
149 | ||
150 | (void)strcpy(msg.tsp_name, hostname); | |
151 | msg.tsp_type = TSP_MSITE; | |
152 | msg.tsp_vers = TSPVERSION; | |
153 | bytenetorder(&msg); | |
154 | length = sizeof(struct sockaddr_in); | |
155 | if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, | |
156 | &dest, length) < 0) { | |
157 | perror("sendto"); | |
158 | return; | |
159 | } | |
160 | ||
161 | tout.tv_sec = 15; | |
162 | tout.tv_usec = 0; | |
75d5ce8a JB |
163 | FD_ZERO(&ready); |
164 | FD_SET(sock, &ready); | |
165 | if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { | |
ad4b9c34 RG |
166 | length = sizeof(struct sockaddr_in); |
167 | cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, | |
168 | &from, &length); | |
169 | if (cc < 0) { | |
170 | perror("recvfrom"); | |
171 | return; | |
172 | } | |
173 | bytehostorder(&msg); | |
174 | if (msg.tsp_type == TSP_ACK) | |
175 | printf("master timedaemon runs on %s\n", msg.tsp_name); | |
176 | else | |
177 | printf("received wrong ack: %s\n", | |
178 | tsptype[msg.tsp_type]); | |
179 | } else | |
180 | printf("communication error\n"); | |
181 | } | |
182 | ||
183 | /* | |
184 | * quits timedc | |
185 | */ | |
186 | ||
187 | quit() | |
188 | { | |
189 | exit(0); | |
190 | } | |
191 | ||
192 | #define MAXH 4 /* max no. of hosts where election can occur */ | |
193 | ||
194 | /* | |
195 | * Causes the election timer to expire on the selected hosts | |
196 | * It sends just one udp message per machine, relying on | |
197 | * reliability of communication channel. | |
198 | */ | |
199 | ||
200 | testing(argc, argv) | |
201 | int argc; | |
202 | char *argv[]; | |
203 | { | |
204 | int length; | |
205 | int nhosts; | |
206 | struct servent *srvp; | |
207 | struct sockaddr_in sin[MAXH]; | |
208 | struct tsp msg; | |
209 | ||
210 | if(argc < 2) { | |
211 | printf("Usage: testing host ...\n"); | |
212 | return; | |
213 | } | |
214 | ||
ad4b9c34 RG |
215 | srvp = getservbyname("timed", "udp"); |
216 | if (srvp == 0) { | |
217 | fprintf(stderr, "udp/timed: unknown service\n"); | |
218 | return; | |
219 | } | |
220 | ||
221 | nhosts = 0; | |
222 | while (argc > 1) { | |
223 | argc--; argv++; | |
224 | hp = gethostbyname(*argv); | |
225 | if (hp == NULL) { | |
95f51977 | 226 | printf("%s: unknown host %s\n", *argv); |
ad4b9c34 RG |
227 | argc--; argv++; |
228 | continue; | |
229 | } | |
230 | sin[nhosts].sin_port = srvp->s_port; | |
231 | sin[nhosts].sin_family = hp->h_addrtype; | |
232 | bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length); | |
233 | if (++nhosts == MAXH) | |
234 | break; | |
235 | } | |
236 | ||
237 | msg.tsp_type = TSP_TEST; | |
238 | msg.tsp_vers = TSPVERSION; | |
239 | (void)gethostname(hostname, sizeof(hostname)); | |
240 | (void)strcpy(msg.tsp_name, hostname); | |
241 | bytenetorder(&msg); /* it is not really necessary here */ | |
242 | while (nhosts-- > 0) { | |
243 | length = sizeof(struct sockaddr_in); | |
244 | if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, | |
245 | &sin[nhosts], length) < 0) { | |
246 | perror("sendto"); | |
247 | return; | |
248 | } | |
249 | } | |
250 | } | |
251 | ||
252 | /* | |
253 | * Enables or disables tracing on local timedaemon | |
254 | */ | |
255 | ||
256 | tracing(argc, argv) | |
257 | int argc; | |
258 | char *argv[]; | |
259 | { | |
260 | int onflag; | |
261 | int length; | |
75d5ce8a JB |
262 | int cc; |
263 | fd_set ready; | |
ad4b9c34 RG |
264 | struct sockaddr_in dest; |
265 | struct timeval tout; | |
266 | struct sockaddr_in from; | |
267 | struct tsp msg; | |
268 | struct servent *srvp; | |
269 | ||
270 | if (argc != 2) { | |
271 | printf("Usage: tracing { on | off }\n"); | |
272 | return; | |
273 | } | |
274 | ||
ad4b9c34 RG |
275 | srvp = getservbyname("timed", "udp"); |
276 | if (srvp == 0) { | |
277 | fprintf(stderr, "udp/timed: unknown service\n"); | |
278 | return; | |
279 | } | |
280 | dest.sin_port = srvp->s_port; | |
281 | dest.sin_family = AF_INET; | |
282 | ||
283 | (void)gethostname(hostname,sizeof(hostname)); | |
284 | hp = gethostbyname(hostname); | |
285 | bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); | |
286 | ||
287 | if (strcmp(argv[1], "on") == 0) { | |
288 | msg.tsp_type = TSP_TRACEON; | |
289 | onflag = ON; | |
290 | } else { | |
291 | msg.tsp_type = TSP_TRACEOFF; | |
292 | onflag = OFF; | |
293 | } | |
294 | ||
295 | (void)strcpy(msg.tsp_name, hostname); | |
296 | msg.tsp_vers = TSPVERSION; | |
297 | bytenetorder(&msg); | |
298 | length = sizeof(struct sockaddr_in); | |
299 | if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, | |
300 | &dest, length) < 0) { | |
301 | perror("sendto"); | |
302 | return; | |
303 | } | |
304 | ||
305 | tout.tv_sec = 5; | |
306 | tout.tv_usec = 0; | |
75d5ce8a JB |
307 | FD_ZERO(&ready); |
308 | FD_SET(sock, &ready); | |
309 | if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { | |
ad4b9c34 RG |
310 | length = sizeof(struct sockaddr_in); |
311 | cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0, | |
312 | &from, &length); | |
313 | if (cc < 0) { | |
314 | perror("recvfrom"); | |
315 | return; | |
316 | } | |
317 | bytehostorder(&msg); | |
318 | if (msg.tsp_type == TSP_ACK) | |
319 | if (onflag) | |
320 | printf("timed tracing enabled\n"); | |
321 | else | |
322 | printf("timed tracing disabled\n"); | |
323 | else | |
324 | printf("wrong ack received: %s\n", | |
325 | tsptype[msg.tsp_type]); | |
326 | } else | |
327 | printf("communication error\n"); | |
328 | } | |
329 | ||
330 | priv_resources() | |
331 | { | |
332 | int port; | |
333 | struct sockaddr_in sin; | |
334 | ||
335 | sock = socket(AF_INET, SOCK_DGRAM, 0); | |
336 | if (sock < 0) { | |
337 | perror("opening socket"); | |
338 | return(-1); | |
339 | } | |
340 | ||
341 | sin.sin_family = AF_INET; | |
342 | sin.sin_addr.s_addr = 0; | |
343 | for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { | |
344 | sin.sin_port = htons((u_short)port); | |
345 | if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0) | |
346 | break; | |
347 | if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { | |
348 | perror("bind"); | |
349 | (void) close(sock); | |
350 | return(-1); | |
351 | } | |
352 | } | |
353 | if (port == IPPORT_RESERVED / 2) { | |
354 | fprintf(stderr, "all reserved ports in use\n"); | |
355 | (void) close(sock); | |
356 | return(-1); | |
357 | } | |
358 | ||
359 | sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); | |
360 | if (sock_raw < 0) { | |
361 | perror("opening raw socket"); | |
362 | (void) close(sock_raw); | |
363 | return(-1); | |
364 | } | |
365 | return(1); | |
366 | } |