1251af36eSbostic /*-
2*36527226Sbostic * Copyright (c) 1985, 1993
3*36527226Sbostic * The Regents of the University of California. All rights reserved.
4b0eb8cefSbostic *
5e1a0b129Sbostic * %sccs.include.redist.c%
67dca7a75Sgusella */
77dca7a75Sgusella
87dca7a75Sgusella #ifndef lint
9*36527226Sbostic static char sccsid[] = "@(#)readmsg.c 8.1 (Berkeley) 06/06/93";
10b0eb8cefSbostic #endif /* not lint */
117dca7a75Sgusella
12251af36eSbostic #ifdef sgi
13251af36eSbostic #ident "$Revision: 1.17 $"
14251af36eSbostic #endif
15251af36eSbostic
167dca7a75Sgusella #include "globals.h"
177dca7a75Sgusella
183d0f82beSbloom extern char *tsptype[];
197dca7a75Sgusella
207dca7a75Sgusella /*
217dca7a75Sgusella * LOOKAT checks if the message is of the requested type and comes from
227dca7a75Sgusella * the right machine, returning 1 in case of affirmative answer
237dca7a75Sgusella */
249a0c20d0Sbloom #define LOOKAT(msg, mtype, mfrom, netp, froms) \
25251af36eSbostic (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) && \
26251af36eSbostic ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) && \
27251af36eSbostic ((netp) == 0 || \
28251af36eSbostic ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr))
297dca7a75Sgusella
307dca7a75Sgusella struct timeval rtime, rwait, rtout;
317dca7a75Sgusella struct tsp msgin;
327dca7a75Sgusella static struct tsplist {
337dca7a75Sgusella struct tsp info;
34251af36eSbostic struct timeval when;
357dca7a75Sgusella struct sockaddr_in addr;
367dca7a75Sgusella struct tsplist *p;
377dca7a75Sgusella } msgslist;
387dca7a75Sgusella struct sockaddr_in from;
3968699400Sbloom struct netinfo *fromnet;
40251af36eSbostic struct timeval from_when;
417dca7a75Sgusella
427dca7a75Sgusella /*
437dca7a75Sgusella * `readmsg' returns message `type' sent by `machfrom' if it finds it
447dca7a75Sgusella * either in the receive queue, or in a linked list of previously received
457dca7a75Sgusella * messages that it maintains.
467dca7a75Sgusella * Otherwise it waits to see if the appropriate message arrives within
477dca7a75Sgusella * `intvl' seconds. If not, it returns NULL.
487dca7a75Sgusella */
497dca7a75Sgusella
509a0c20d0Sbloom struct tsp *
readmsg(type,machfrom,intvl,netfrom)519a0c20d0Sbloom readmsg(type, machfrom, intvl, netfrom)
527dca7a75Sgusella int type;
537dca7a75Sgusella char *machfrom;
547dca7a75Sgusella struct timeval *intvl;
559a0c20d0Sbloom struct netinfo *netfrom;
567dca7a75Sgusella {
577dca7a75Sgusella int length;
58e01940c7Sbloom fd_set ready;
597dca7a75Sgusella static struct tsplist *head = &msgslist;
607dca7a75Sgusella static struct tsplist *tail = &msgslist;
61251af36eSbostic static int msgcnt = 0;
629a0c20d0Sbloom struct tsplist *prev;
639a0c20d0Sbloom register struct netinfo *ntp;
649a0c20d0Sbloom register struct tsplist *ptr;
657dca7a75Sgusella
667dca7a75Sgusella if (trace) {
67251af36eSbostic fprintf(fd, "readmsg: looking for %s from %s, %s\n",
68251af36eSbostic tsptype[type], machfrom == NULL ? "ANY" : machfrom,
69251af36eSbostic netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net));
70251af36eSbostic if (head->p != 0) {
71251af36eSbostic length = 1;
72251af36eSbostic for (ptr = head->p; ptr != 0; ptr = ptr->p) {
73251af36eSbostic /* do not repeat the hundreds of messages */
74251af36eSbostic if (++length > 3) {
75251af36eSbostic if (ptr == tail) {
76251af36eSbostic fprintf(fd,"\t ...%d skipped\n",
77251af36eSbostic length);
78251af36eSbostic } else {
79251af36eSbostic continue;
80251af36eSbostic }
81251af36eSbostic }
82251af36eSbostic fprintf(fd, length > 1 ? "\t" : "queue:\t");
8368699400Sbloom print(&ptr->info, &ptr->addr);
84251af36eSbostic }
857dca7a75Sgusella }
867dca7a75Sgusella }
877dca7a75Sgusella
887dca7a75Sgusella ptr = head->p;
897dca7a75Sgusella prev = head;
907dca7a75Sgusella
917dca7a75Sgusella /*
927dca7a75Sgusella * Look for the requested message scanning through the
937dca7a75Sgusella * linked list. If found, return it and free the space
947dca7a75Sgusella */
957dca7a75Sgusella
967dca7a75Sgusella while (ptr != NULL) {
979a0c20d0Sbloom if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) {
98251af36eSbostic again:
99d3f923b6Sbloom msgin = ptr->info;
1007dca7a75Sgusella from = ptr->addr;
101251af36eSbostic from_when = ptr->when;
1027dca7a75Sgusella prev->p = ptr->p;
1037dca7a75Sgusella if (ptr == tail)
1047dca7a75Sgusella tail = prev;
1057dca7a75Sgusella free((char *)ptr);
106839f8c0bSbloom fromnet = NULL;
107d3f923b6Sbloom if (netfrom == NULL)
108d3f923b6Sbloom for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
109d3f923b6Sbloom if ((ntp->mask & from.sin_addr.s_addr) ==
110251af36eSbostic ntp->net.s_addr) {
111d3f923b6Sbloom fromnet = ntp;
1127dca7a75Sgusella break;
113d3f923b6Sbloom }
114d3f923b6Sbloom }
115d3f923b6Sbloom else
116d3f923b6Sbloom fromnet = netfrom;
117d3f923b6Sbloom if (trace) {
118251af36eSbostic fprintf(fd, "readmsg: found ");
119d3f923b6Sbloom print(&msgin, &from);
120d3f923b6Sbloom }
121251af36eSbostic
122251af36eSbostic /* The protocol can get far behind. When it does, it gets
123251af36eSbostic * hopelessly confused. So delete duplicate messages.
124251af36eSbostic */
125251af36eSbostic for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) {
126251af36eSbostic if (ptr->addr.sin_addr.s_addr
127251af36eSbostic == from.sin_addr.s_addr
128251af36eSbostic && ptr->info.tsp_type == msgin.tsp_type) {
129251af36eSbostic if (trace)
130251af36eSbostic fprintf(fd, "\tdup ");
131251af36eSbostic goto again;
132251af36eSbostic }
133251af36eSbostic }
134251af36eSbostic msgcnt--;
135d3f923b6Sbloom return(&msgin);
1367dca7a75Sgusella } else {
1377dca7a75Sgusella prev = ptr;
1387dca7a75Sgusella ptr = ptr->p;
1397dca7a75Sgusella }
1407dca7a75Sgusella }
1417dca7a75Sgusella
1427dca7a75Sgusella /*
1437dca7a75Sgusella * If the message was not in the linked list, it may still be
1447dca7a75Sgusella * coming from the network. Set the timer and wait
1457dca7a75Sgusella * on a select to read the next incoming message: if it is the
1467dca7a75Sgusella * right one, return it, otherwise insert it in the linked list.
1477dca7a75Sgusella */
1487dca7a75Sgusella
149251af36eSbostic (void)gettimeofday(&rtout, 0);
150251af36eSbostic timevaladd(&rtout, intvl);
1519a0c20d0Sbloom FD_ZERO(&ready);
152251af36eSbostic for (;;) {
153251af36eSbostic (void)gettimeofday(&rtime, 0);
154251af36eSbostic timevalsub(&rwait, &rtout, &rtime);
1557dca7a75Sgusella if (rwait.tv_sec < 0)
1567dca7a75Sgusella rwait.tv_sec = rwait.tv_usec = 0;
157251af36eSbostic else if (rwait.tv_sec == 0
158251af36eSbostic && rwait.tv_usec < 1000000/CLK_TCK)
159251af36eSbostic rwait.tv_usec = 1000000/CLK_TCK;
1607dca7a75Sgusella
1617dca7a75Sgusella if (trace) {
162251af36eSbostic fprintf(fd, "readmsg: wait %ld.%6ld at %s\n",
163251af36eSbostic rwait.tv_sec, rwait.tv_usec, date());
164251af36eSbostic /* Notice a full disk, as we flush trace info.
165251af36eSbostic * It is better to flush periodically than at
166251af36eSbostic * every line because the tracing consists of bursts
167251af36eSbostic * of many lines. Without care, tracing slows
168251af36eSbostic * down the code enough to break the protocol.
169251af36eSbostic */
170251af36eSbostic if (rwait.tv_sec != 0
171251af36eSbostic && EOF == fflush(fd))
172251af36eSbostic traceoff("Tracing ended for cause at %s\n");
1737dca7a75Sgusella }
1747dca7a75Sgusella
175251af36eSbostic FD_SET(sock, &ready);
176251af36eSbostic if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0,
177251af36eSbostic &rwait)) {
178251af36eSbostic if (rwait.tv_sec == 0 && rwait.tv_usec == 0)
179251af36eSbostic return(0);
180251af36eSbostic continue;
181251af36eSbostic }
182251af36eSbostic length = sizeof(from);
183251af36eSbostic if (recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0,
184251af36eSbostic (struct sockaddr*)&from, &length) < 0) {
185251af36eSbostic syslog(LOG_ERR, "recvfrom: %m");
186251af36eSbostic exit(1);
187251af36eSbostic }
188251af36eSbostic (void)gettimeofday(&from_when, (struct timezone *)0);
1897dca7a75Sgusella bytehostorder(&msgin);
1907dca7a75Sgusella
191839f8c0bSbloom if (msgin.tsp_vers > TSPVERSION) {
192839f8c0bSbloom if (trace) {
193839f8c0bSbloom fprintf(fd,"readmsg: version mismatch\n");
194251af36eSbostic /* should do a dump of the packet */
195839f8c0bSbloom }
196839f8c0bSbloom continue;
197839f8c0bSbloom }
198839f8c0bSbloom
199d3f923b6Sbloom fromnet = NULL;
200d3f923b6Sbloom for (ntp = nettab; ntp != NULL; ntp = ntp->next)
201d3f923b6Sbloom if ((ntp->mask & from.sin_addr.s_addr) ==
202251af36eSbostic ntp->net.s_addr) {
203d3f923b6Sbloom fromnet = ntp;
204d3f923b6Sbloom break;
205d3f923b6Sbloom }
206d3f923b6Sbloom
207d3f923b6Sbloom /*
208d3f923b6Sbloom * drop packets from nets we are ignoring permanently
209d3f923b6Sbloom */
210d3f923b6Sbloom if (fromnet == NULL) {
211839f8c0bSbloom /*
212839f8c0bSbloom * The following messages may originate on
213839f8c0bSbloom * this host with an ignored network address
214839f8c0bSbloom */
215839f8c0bSbloom if (msgin.tsp_type != TSP_TRACEON &&
216839f8c0bSbloom msgin.tsp_type != TSP_SETDATE &&
217839f8c0bSbloom msgin.tsp_type != TSP_MSITE &&
218839f8c0bSbloom msgin.tsp_type != TSP_TEST &&
219839f8c0bSbloom msgin.tsp_type != TSP_TRACEOFF) {
220d3f923b6Sbloom if (trace) {
221251af36eSbostic fprintf(fd,"readmsg: discard null net ");
222d3f923b6Sbloom print(&msgin, &from);
223d3f923b6Sbloom }
224d3f923b6Sbloom continue;
225d3f923b6Sbloom }
226839f8c0bSbloom }
227d3f923b6Sbloom
2287dca7a75Sgusella /*
229251af36eSbostic * Throw away messages coming from this machine,
230251af36eSbostic * unless they are of some particular type.
2317dca7a75Sgusella * This gets rid of broadcast messages and reduces
2327dca7a75Sgusella * master processing time.
2337dca7a75Sgusella */
234251af36eSbostic if (!strcmp(msgin.tsp_name, hostname)
235251af36eSbostic && msgin.tsp_type != TSP_SETDATE
236251af36eSbostic && msgin.tsp_type != TSP_TEST
237251af36eSbostic && msgin.tsp_type != TSP_MSITE
238251af36eSbostic && msgin.tsp_type != TSP_TRACEON
239251af36eSbostic && msgin.tsp_type != TSP_TRACEOFF
240251af36eSbostic && msgin.tsp_type != TSP_LOOP) {
2417dca7a75Sgusella if (trace) {
242251af36eSbostic fprintf(fd, "readmsg: discard own ");
24368699400Sbloom print(&msgin, &from);
2447dca7a75Sgusella }
2457dca7a75Sgusella continue;
2467dca7a75Sgusella }
2477dca7a75Sgusella
2487dca7a75Sgusella /*
249251af36eSbostic * Send acknowledgements here; this is faster and
250251af36eSbostic * avoids deadlocks that would occur if acks were
251251af36eSbostic * sent from a higher level routine. Different
252251af36eSbostic * acknowledgements are necessary, depending on
253251af36eSbostic * status.
2547dca7a75Sgusella */
255251af36eSbostic if (fromnet == NULL) /* do not de-reference 0 */
256251af36eSbostic ignoreack();
257251af36eSbostic else if (fromnet->status == MASTER)
2587dca7a75Sgusella masterack();
259d3f923b6Sbloom else if (fromnet->status == SLAVE)
2607dca7a75Sgusella slaveack();
261839f8c0bSbloom else
262839f8c0bSbloom ignoreack();
263839f8c0bSbloom
2649a0c20d0Sbloom if (LOOKAT(msgin, type, machfrom, netfrom, from)) {
265d3f923b6Sbloom if (trace) {
266d3f923b6Sbloom fprintf(fd, "readmsg: ");
267d3f923b6Sbloom print(&msgin, &from);
268d3f923b6Sbloom }
269d3f923b6Sbloom return(&msgin);
270251af36eSbostic } else if (++msgcnt > NHOSTS*3) {
271251af36eSbostic
272251af36eSbostic /* The protocol gets hopelessly confused if it gets too far
273251af36eSbostic * behind. However, it seems able to recover from all cases of lost
274251af36eSbostic * packets. Therefore, if we are swamped, throw everything away.
275251af36eSbostic */
276251af36eSbostic if (trace)
277251af36eSbostic fprintf(fd,
278251af36eSbostic "readmsg: discarding %d msgs\n",
279251af36eSbostic msgcnt);
280251af36eSbostic msgcnt = 0;
281251af36eSbostic while ((ptr=head->p) != NULL) {
282251af36eSbostic head->p = ptr->p;
283251af36eSbostic free((char *)ptr);
284251af36eSbostic }
285251af36eSbostic tail = head;
2867dca7a75Sgusella } else {
2877dca7a75Sgusella tail->p = (struct tsplist *)
2887dca7a75Sgusella malloc(sizeof(struct tsplist));
2897dca7a75Sgusella tail = tail->p;
2907dca7a75Sgusella tail->p = NULL;
2917dca7a75Sgusella tail->info = msgin;
2927dca7a75Sgusella tail->addr = from;
293251af36eSbostic /* timestamp msgs so SETTIMEs are correct */
294251af36eSbostic tail->when = from_when;
2957dca7a75Sgusella }
2967dca7a75Sgusella }
2977dca7a75Sgusella }
2987dca7a75Sgusella
2997dca7a75Sgusella /*
300251af36eSbostic * Send the necessary acknowledgements:
3017dca7a75Sgusella * only the type ACK is to be sent by a slave
3027dca7a75Sgusella */
303251af36eSbostic void
slaveack()3047dca7a75Sgusella slaveack()
3057dca7a75Sgusella {
3067dca7a75Sgusella switch(msgin.tsp_type) {
3077dca7a75Sgusella
3087dca7a75Sgusella case TSP_ADJTIME:
3097dca7a75Sgusella case TSP_SETTIME:
3107dca7a75Sgusella case TSP_ACCEPT:
3117dca7a75Sgusella case TSP_REFUSE:
3127dca7a75Sgusella case TSP_TRACEON:
3137dca7a75Sgusella case TSP_TRACEOFF:
3147d3e17d0Sbloom case TSP_QUIT:
3153d0f82beSbloom if (trace) {
3163d0f82beSbloom fprintf(fd, "Slaveack: ");
317251af36eSbostic print(&msgin, &from);
3183d0f82beSbloom }
319251af36eSbostic xmit(TSP_ACK,msgin.tsp_seq, &from);
3207dca7a75Sgusella break;
321251af36eSbostic
3227dca7a75Sgusella default:
323251af36eSbostic if (trace) {
324251af36eSbostic fprintf(fd, "Slaveack: no ack: ");
325251af36eSbostic print(&msgin, &from);
326251af36eSbostic }
3277dca7a75Sgusella break;
3287dca7a75Sgusella }
3297dca7a75Sgusella }
3307dca7a75Sgusella
3317dca7a75Sgusella /*
332839f8c0bSbloom * Certain packets may arrive from this machine on ignored networks.
333839f8c0bSbloom * These packets should be acknowledged.
334839f8c0bSbloom */
335251af36eSbostic void
ignoreack()336839f8c0bSbloom ignoreack()
337839f8c0bSbloom {
338839f8c0bSbloom switch(msgin.tsp_type) {
339839f8c0bSbloom
340839f8c0bSbloom case TSP_TRACEON:
341839f8c0bSbloom case TSP_TRACEOFF:
342251af36eSbostic case TSP_QUIT:
343839f8c0bSbloom if (trace) {
344839f8c0bSbloom fprintf(fd, "Ignoreack: ");
345251af36eSbostic print(&msgin, &from);
346839f8c0bSbloom }
347251af36eSbostic xmit(TSP_ACK,msgin.tsp_seq, &from);
348839f8c0bSbloom break;
349251af36eSbostic
350839f8c0bSbloom default:
351251af36eSbostic if (trace) {
352251af36eSbostic fprintf(fd, "Ignoreack: no ack: ");
353251af36eSbostic print(&msgin, &from);
354251af36eSbostic }
355839f8c0bSbloom break;
356839f8c0bSbloom }
357839f8c0bSbloom }
358839f8c0bSbloom
359839f8c0bSbloom /*
3607dca7a75Sgusella * `masterack' sends the necessary acknowledgments
3617dca7a75Sgusella * to the messages received by a master
3627dca7a75Sgusella */
363251af36eSbostic void
masterack()3647dca7a75Sgusella masterack()
3657dca7a75Sgusella {
3667dca7a75Sgusella struct tsp resp;
3677dca7a75Sgusella
3687dca7a75Sgusella resp = msgin;
3697dca7a75Sgusella resp.tsp_vers = TSPVERSION;
3707dca7a75Sgusella (void)strcpy(resp.tsp_name, hostname);
3717dca7a75Sgusella
3727dca7a75Sgusella switch(msgin.tsp_type) {
3737dca7a75Sgusella
3747dca7a75Sgusella case TSP_QUIT:
3757dca7a75Sgusella case TSP_TRACEON:
3767dca7a75Sgusella case TSP_TRACEOFF:
3777dca7a75Sgusella case TSP_MSITEREQ:
3783d0f82beSbloom if (trace) {
3793d0f82beSbloom fprintf(fd, "Masterack: ");
380251af36eSbostic print(&msgin, &from);
3813d0f82beSbloom }
382251af36eSbostic xmit(TSP_ACK,msgin.tsp_seq, &from);
3837dca7a75Sgusella break;
384251af36eSbostic
3857dca7a75Sgusella case TSP_RESOLVE:
3867dca7a75Sgusella case TSP_MASTERREQ:
3873d0f82beSbloom if (trace) {
3883d0f82beSbloom fprintf(fd, "Masterack: ");
389251af36eSbostic print(&msgin, &from);
3903d0f82beSbloom }
391251af36eSbostic xmit(TSP_MASTERACK,msgin.tsp_seq, &from);
3927dca7a75Sgusella break;
393251af36eSbostic
3947dca7a75Sgusella default:
395251af36eSbostic if (trace) {
396251af36eSbostic fprintf(fd,"Masterack: no ack: ");
397251af36eSbostic print(&msgin, &from);
398251af36eSbostic }
3997dca7a75Sgusella break;
4007dca7a75Sgusella }
4017dca7a75Sgusella }
4027dca7a75Sgusella
4037dca7a75Sgusella /*
4047dca7a75Sgusella * Print a TSP message
4057dca7a75Sgusella */
406251af36eSbostic void
print(msg,addr)40768699400Sbloom print(msg, addr)
4087dca7a75Sgusella struct tsp *msg;
40968699400Sbloom struct sockaddr_in *addr;
4107dca7a75Sgusella {
411251af36eSbostic char tm[26];
4123b9cae83Sbloom switch (msg->tsp_type) {
4133b9cae83Sbloom
4143b9cae83Sbloom case TSP_LOOP:
415251af36eSbostic fprintf(fd, "%s %d %-6u #%d %-15s %s\n",
41653012953Sbloom tsptype[msg->tsp_type],
41753012953Sbloom msg->tsp_vers,
41853012953Sbloom msg->tsp_seq,
41953012953Sbloom msg->tsp_hopcnt,
420251af36eSbostic inet_ntoa(addr->sin_addr),
421251af36eSbostic msg->tsp_name);
4223b9cae83Sbloom break;
4233b9cae83Sbloom
424e182bc12Skarels case TSP_SETTIME:
4253b9cae83Sbloom case TSP_SETDATE:
4263b9cae83Sbloom case TSP_SETDATEREQ:
427251af36eSbostic #ifdef sgi
428251af36eSbostic (void)cftime(tm, "%D %T", &msg->tsp_time.tv_sec);
429251af36eSbostic #else
430251af36eSbostic strncpy(tm, ctime(&msg->tsp_time.tv_sec)+3+1, sizeof(tm));
431251af36eSbostic tm[15] = '\0'; /* ugh */
432251af36eSbostic #endif /* sgi */
433251af36eSbostic fprintf(fd, "%s %d %-6u %s %-15s %s\n",
434251af36eSbostic tsptype[msg->tsp_type],
435251af36eSbostic msg->tsp_vers,
436251af36eSbostic msg->tsp_seq,
437251af36eSbostic tm,
438251af36eSbostic inet_ntoa(addr->sin_addr),
439251af36eSbostic msg->tsp_name);
440251af36eSbostic break;
441251af36eSbostic
442251af36eSbostic case TSP_ADJTIME:
443251af36eSbostic fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n",
4447dca7a75Sgusella tsptype[msg->tsp_type],
4457dca7a75Sgusella msg->tsp_vers,
4467dca7a75Sgusella msg->tsp_seq,
4477dca7a75Sgusella msg->tsp_time.tv_sec,
4487dca7a75Sgusella msg->tsp_time.tv_usec,
449251af36eSbostic inet_ntoa(addr->sin_addr),
450251af36eSbostic msg->tsp_name);
4513b9cae83Sbloom break;
4523b9cae83Sbloom
4533b9cae83Sbloom default:
454251af36eSbostic fprintf(fd, "%s %d %-6u %-15s %s\n",
4553b9cae83Sbloom tsptype[msg->tsp_type],
4563b9cae83Sbloom msg->tsp_vers,
4573b9cae83Sbloom msg->tsp_seq,
458251af36eSbostic inet_ntoa(addr->sin_addr),
459251af36eSbostic msg->tsp_name);
4603b9cae83Sbloom break;
4617dca7a75Sgusella }
46253012953Sbloom }
463