1 /*-
2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)readmsg.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #ifdef sgi
13 #ident "$Revision: 1.17 $"
14 #endif
15
16 #include "globals.h"
17
18 extern char *tsptype[];
19
20 /*
21 * LOOKAT checks if the message is of the requested type and comes from
22 * the right machine, returning 1 in case of affirmative answer
23 */
24 #define LOOKAT(msg, mtype, mfrom, netp, froms) \
25 (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) && \
26 ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) && \
27 ((netp) == 0 || \
28 ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr))
29
30 struct timeval rtime, rwait, rtout;
31 struct tsp msgin;
32 static struct tsplist {
33 struct tsp info;
34 struct timeval when;
35 struct sockaddr_in addr;
36 struct tsplist *p;
37 } msgslist;
38 struct sockaddr_in from;
39 struct netinfo *fromnet;
40 struct timeval from_when;
41
42 /*
43 * `readmsg' returns message `type' sent by `machfrom' if it finds it
44 * either in the receive queue, or in a linked list of previously received
45 * messages that it maintains.
46 * Otherwise it waits to see if the appropriate message arrives within
47 * `intvl' seconds. If not, it returns NULL.
48 */
49
50 struct tsp *
readmsg(type,machfrom,intvl,netfrom)51 readmsg(type, machfrom, intvl, netfrom)
52 int type;
53 char *machfrom;
54 struct timeval *intvl;
55 struct netinfo *netfrom;
56 {
57 int length;
58 fd_set ready;
59 static struct tsplist *head = &msgslist;
60 static struct tsplist *tail = &msgslist;
61 static int msgcnt = 0;
62 struct tsplist *prev;
63 register struct netinfo *ntp;
64 register struct tsplist *ptr;
65
66 if (trace) {
67 fprintf(fd, "readmsg: looking for %s from %s, %s\n",
68 tsptype[type], machfrom == NULL ? "ANY" : machfrom,
69 netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net));
70 if (head->p != 0) {
71 length = 1;
72 for (ptr = head->p; ptr != 0; ptr = ptr->p) {
73 /* do not repeat the hundreds of messages */
74 if (++length > 3) {
75 if (ptr == tail) {
76 fprintf(fd,"\t ...%d skipped\n",
77 length);
78 } else {
79 continue;
80 }
81 }
82 fprintf(fd, length > 1 ? "\t" : "queue:\t");
83 print(&ptr->info, &ptr->addr);
84 }
85 }
86 }
87
88 ptr = head->p;
89 prev = head;
90
91 /*
92 * Look for the requested message scanning through the
93 * linked list. If found, return it and free the space
94 */
95
96 while (ptr != NULL) {
97 if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) {
98 again:
99 msgin = ptr->info;
100 from = ptr->addr;
101 from_when = ptr->when;
102 prev->p = ptr->p;
103 if (ptr == tail)
104 tail = prev;
105 free((char *)ptr);
106 fromnet = NULL;
107 if (netfrom == NULL)
108 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
109 if ((ntp->mask & from.sin_addr.s_addr) ==
110 ntp->net.s_addr) {
111 fromnet = ntp;
112 break;
113 }
114 }
115 else
116 fromnet = netfrom;
117 if (trace) {
118 fprintf(fd, "readmsg: found ");
119 print(&msgin, &from);
120 }
121
122 /* The protocol can get far behind. When it does, it gets
123 * hopelessly confused. So delete duplicate messages.
124 */
125 for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) {
126 if (ptr->addr.sin_addr.s_addr
127 == from.sin_addr.s_addr
128 && ptr->info.tsp_type == msgin.tsp_type) {
129 if (trace)
130 fprintf(fd, "\tdup ");
131 goto again;
132 }
133 }
134 msgcnt--;
135 return(&msgin);
136 } else {
137 prev = ptr;
138 ptr = ptr->p;
139 }
140 }
141
142 /*
143 * If the message was not in the linked list, it may still be
144 * coming from the network. Set the timer and wait
145 * on a select to read the next incoming message: if it is the
146 * right one, return it, otherwise insert it in the linked list.
147 */
148
149 (void)gettimeofday(&rtout, 0);
150 timevaladd(&rtout, intvl);
151 FD_ZERO(&ready);
152 for (;;) {
153 (void)gettimeofday(&rtime, 0);
154 timevalsub(&rwait, &rtout, &rtime);
155 if (rwait.tv_sec < 0)
156 rwait.tv_sec = rwait.tv_usec = 0;
157 else if (rwait.tv_sec == 0
158 && rwait.tv_usec < 1000000/CLK_TCK)
159 rwait.tv_usec = 1000000/CLK_TCK;
160
161 if (trace) {
162 fprintf(fd, "readmsg: wait %ld.%6ld at %s\n",
163 rwait.tv_sec, rwait.tv_usec, date());
164 /* Notice a full disk, as we flush trace info.
165 * It is better to flush periodically than at
166 * every line because the tracing consists of bursts
167 * of many lines. Without care, tracing slows
168 * down the code enough to break the protocol.
169 */
170 if (rwait.tv_sec != 0
171 && EOF == fflush(fd))
172 traceoff("Tracing ended for cause at %s\n");
173 }
174
175 FD_SET(sock, &ready);
176 if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0,
177 &rwait)) {
178 if (rwait.tv_sec == 0 && rwait.tv_usec == 0)
179 return(0);
180 continue;
181 }
182 length = sizeof(from);
183 if (recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0,
184 (struct sockaddr*)&from, &length) < 0) {
185 syslog(LOG_ERR, "recvfrom: %m");
186 exit(1);
187 }
188 (void)gettimeofday(&from_when, (struct timezone *)0);
189 bytehostorder(&msgin);
190
191 if (msgin.tsp_vers > TSPVERSION) {
192 if (trace) {
193 fprintf(fd,"readmsg: version mismatch\n");
194 /* should do a dump of the packet */
195 }
196 continue;
197 }
198
199 fromnet = NULL;
200 for (ntp = nettab; ntp != NULL; ntp = ntp->next)
201 if ((ntp->mask & from.sin_addr.s_addr) ==
202 ntp->net.s_addr) {
203 fromnet = ntp;
204 break;
205 }
206
207 /*
208 * drop packets from nets we are ignoring permanently
209 */
210 if (fromnet == NULL) {
211 /*
212 * The following messages may originate on
213 * this host with an ignored network address
214 */
215 if (msgin.tsp_type != TSP_TRACEON &&
216 msgin.tsp_type != TSP_SETDATE &&
217 msgin.tsp_type != TSP_MSITE &&
218 msgin.tsp_type != TSP_TEST &&
219 msgin.tsp_type != TSP_TRACEOFF) {
220 if (trace) {
221 fprintf(fd,"readmsg: discard null net ");
222 print(&msgin, &from);
223 }
224 continue;
225 }
226 }
227
228 /*
229 * Throw away messages coming from this machine,
230 * unless they are of some particular type.
231 * This gets rid of broadcast messages and reduces
232 * master processing time.
233 */
234 if (!strcmp(msgin.tsp_name, hostname)
235 && msgin.tsp_type != TSP_SETDATE
236 && msgin.tsp_type != TSP_TEST
237 && msgin.tsp_type != TSP_MSITE
238 && msgin.tsp_type != TSP_TRACEON
239 && msgin.tsp_type != TSP_TRACEOFF
240 && msgin.tsp_type != TSP_LOOP) {
241 if (trace) {
242 fprintf(fd, "readmsg: discard own ");
243 print(&msgin, &from);
244 }
245 continue;
246 }
247
248 /*
249 * Send acknowledgements here; this is faster and
250 * avoids deadlocks that would occur if acks were
251 * sent from a higher level routine. Different
252 * acknowledgements are necessary, depending on
253 * status.
254 */
255 if (fromnet == NULL) /* do not de-reference 0 */
256 ignoreack();
257 else if (fromnet->status == MASTER)
258 masterack();
259 else if (fromnet->status == SLAVE)
260 slaveack();
261 else
262 ignoreack();
263
264 if (LOOKAT(msgin, type, machfrom, netfrom, from)) {
265 if (trace) {
266 fprintf(fd, "readmsg: ");
267 print(&msgin, &from);
268 }
269 return(&msgin);
270 } else if (++msgcnt > NHOSTS*3) {
271
272 /* The protocol gets hopelessly confused if it gets too far
273 * behind. However, it seems able to recover from all cases of lost
274 * packets. Therefore, if we are swamped, throw everything away.
275 */
276 if (trace)
277 fprintf(fd,
278 "readmsg: discarding %d msgs\n",
279 msgcnt);
280 msgcnt = 0;
281 while ((ptr=head->p) != NULL) {
282 head->p = ptr->p;
283 free((char *)ptr);
284 }
285 tail = head;
286 } else {
287 tail->p = (struct tsplist *)
288 malloc(sizeof(struct tsplist));
289 tail = tail->p;
290 tail->p = NULL;
291 tail->info = msgin;
292 tail->addr = from;
293 /* timestamp msgs so SETTIMEs are correct */
294 tail->when = from_when;
295 }
296 }
297 }
298
299 /*
300 * Send the necessary acknowledgements:
301 * only the type ACK is to be sent by a slave
302 */
303 void
slaveack()304 slaveack()
305 {
306 switch(msgin.tsp_type) {
307
308 case TSP_ADJTIME:
309 case TSP_SETTIME:
310 case TSP_ACCEPT:
311 case TSP_REFUSE:
312 case TSP_TRACEON:
313 case TSP_TRACEOFF:
314 case TSP_QUIT:
315 if (trace) {
316 fprintf(fd, "Slaveack: ");
317 print(&msgin, &from);
318 }
319 xmit(TSP_ACK,msgin.tsp_seq, &from);
320 break;
321
322 default:
323 if (trace) {
324 fprintf(fd, "Slaveack: no ack: ");
325 print(&msgin, &from);
326 }
327 break;
328 }
329 }
330
331 /*
332 * Certain packets may arrive from this machine on ignored networks.
333 * These packets should be acknowledged.
334 */
335 void
ignoreack()336 ignoreack()
337 {
338 switch(msgin.tsp_type) {
339
340 case TSP_TRACEON:
341 case TSP_TRACEOFF:
342 case TSP_QUIT:
343 if (trace) {
344 fprintf(fd, "Ignoreack: ");
345 print(&msgin, &from);
346 }
347 xmit(TSP_ACK,msgin.tsp_seq, &from);
348 break;
349
350 default:
351 if (trace) {
352 fprintf(fd, "Ignoreack: no ack: ");
353 print(&msgin, &from);
354 }
355 break;
356 }
357 }
358
359 /*
360 * `masterack' sends the necessary acknowledgments
361 * to the messages received by a master
362 */
363 void
masterack()364 masterack()
365 {
366 struct tsp resp;
367
368 resp = msgin;
369 resp.tsp_vers = TSPVERSION;
370 (void)strcpy(resp.tsp_name, hostname);
371
372 switch(msgin.tsp_type) {
373
374 case TSP_QUIT:
375 case TSP_TRACEON:
376 case TSP_TRACEOFF:
377 case TSP_MSITEREQ:
378 if (trace) {
379 fprintf(fd, "Masterack: ");
380 print(&msgin, &from);
381 }
382 xmit(TSP_ACK,msgin.tsp_seq, &from);
383 break;
384
385 case TSP_RESOLVE:
386 case TSP_MASTERREQ:
387 if (trace) {
388 fprintf(fd, "Masterack: ");
389 print(&msgin, &from);
390 }
391 xmit(TSP_MASTERACK,msgin.tsp_seq, &from);
392 break;
393
394 default:
395 if (trace) {
396 fprintf(fd,"Masterack: no ack: ");
397 print(&msgin, &from);
398 }
399 break;
400 }
401 }
402
403 /*
404 * Print a TSP message
405 */
406 void
print(msg,addr)407 print(msg, addr)
408 struct tsp *msg;
409 struct sockaddr_in *addr;
410 {
411 char tm[26];
412 switch (msg->tsp_type) {
413
414 case TSP_LOOP:
415 fprintf(fd, "%s %d %-6u #%d %-15s %s\n",
416 tsptype[msg->tsp_type],
417 msg->tsp_vers,
418 msg->tsp_seq,
419 msg->tsp_hopcnt,
420 inet_ntoa(addr->sin_addr),
421 msg->tsp_name);
422 break;
423
424 case TSP_SETTIME:
425 case TSP_SETDATE:
426 case TSP_SETDATEREQ:
427 #ifdef sgi
428 (void)cftime(tm, "%D %T", &msg->tsp_time.tv_sec);
429 #else
430 strncpy(tm, ctime(&msg->tsp_time.tv_sec)+3+1, sizeof(tm));
431 tm[15] = '\0'; /* ugh */
432 #endif /* sgi */
433 fprintf(fd, "%s %d %-6u %s %-15s %s\n",
434 tsptype[msg->tsp_type],
435 msg->tsp_vers,
436 msg->tsp_seq,
437 tm,
438 inet_ntoa(addr->sin_addr),
439 msg->tsp_name);
440 break;
441
442 case TSP_ADJTIME:
443 fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n",
444 tsptype[msg->tsp_type],
445 msg->tsp_vers,
446 msg->tsp_seq,
447 msg->tsp_time.tv_sec,
448 msg->tsp_time.tv_usec,
449 inet_ntoa(addr->sin_addr),
450 msg->tsp_name);
451 break;
452
453 default:
454 fprintf(fd, "%s %d %-6u %-15s %s\n",
455 tsptype[msg->tsp_type],
456 msg->tsp_vers,
457 msg->tsp_seq,
458 inet_ntoa(addr->sin_addr),
459 msg->tsp_name);
460 break;
461 }
462 }
463