1119418Sobrien/* $NetBSD: readmsg.c,v 1.23 2017/08/11 16:47:42 ginsbach Exp $ */ 251694Sroger 351694Sroger/*- 451694Sroger * Copyright (c) 1985, 1993 The Regents of the University of California. 551694Sroger * All rights reserved. 651694Sroger * 751694Sroger * Redistribution and use in source and binary forms, with or without 851694Sroger * modification, are permitted provided that the following conditions 951694Sroger * are met: 1051694Sroger * 1. Redistributions of source code must retain the above copyright 1151694Sroger * notice, this list of conditions and the following disclaimer. 1251694Sroger * 2. Redistributions in binary form must reproduce the above copyright 1351694Sroger * notice, this list of conditions and the following disclaimer in the 1451694Sroger * documentation and/or other materials provided with the distribution. 1551694Sroger * 3. Neither the name of the University nor the names of its contributors 1651694Sroger * may be used to endorse or promote products derived from this software 1751694Sroger * without specific prior written permission. 1851694Sroger * 1951694Sroger * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2051694Sroger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2151694Sroger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2251694Sroger * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2351694Sroger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2451694Sroger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2551694Sroger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2651694Sroger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2751694Sroger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2851694Sroger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2951694Sroger * SUCH DAMAGE. 3051694Sroger */ 3151694Sroger 3251694Sroger#include <sys/cdefs.h> 3351694Sroger#ifndef lint 34119418Sobrien#if 0 35119418Sobrienstatic char sccsid[] = "@(#)readmsg.c 8.1 (Berkeley) 6/6/93"; 3651694Sroger#else 37119418Sobrien__RCSID("$NetBSD: readmsg.c,v 1.23 2017/08/11 16:47:42 ginsbach Exp $"); 38119418Sobrien#endif 39119418Sobrien#endif /* not lint */ 40119418Sobrien 41119418Sobrien#include "globals.h" 42119418Sobrien 43119418Sobrienextern const char * const tsptype[]; 44119418Sobrien 45119418Sobrien/* 46119418Sobrien * LOOKAT checks if the message is of the requested type and comes from 47119418Sobrien * the right machine, returning 1 in case of affirmative answer 48119418Sobrien */ 4959014Sroger#define LOOKAT(msg, mtype, mfrom, netp, froms) \ 5051694Sroger (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) && \ 5151694Sroger ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) && \ 5251694Sroger ((netp) == 0 || \ 5351694Sroger ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr)) 5462214Sroger 5562214Srogerstruct timeval rtime, rwait, rtout; 5662214Srogerstruct tsp msgin; 5762214Srogerstatic struct tsplist { 5862214Sroger struct tsp info; 5962214Sroger struct timeval when; 6051694Sroger struct sockaddr_in addr; 6151694Sroger struct tsplist *p; 6251694Sroger} msgslist; 6351694Srogerstruct sockaddr_in from; 6451694Srogerstruct netinfo *fromnet; 6551694Srogerstruct timeval from_when; 6651694Sroger 6751694Sroger/* 6870834Swollman * `readmsg' returns message `type' sent by `machfrom' if it finds it 6970834Swollman * either in the receive queue, or in a linked list of previously received 7070834Swollman * messages that it maintains. 7151694Sroger * Otherwise it waits to see if the appropriate message arrives within 7270834Swollman * `intvl' seconds. If not, it returns NULL. 7351694Sroger */ 7451694Sroger 7551694Srogerstruct tsp * 7651694Srogerreadmsg(int type, char *machfrom, struct timeval *intvl, 7751694Sroger struct netinfo *netfrom) 7851694Sroger{ 7951694Sroger socklen_t length; 8093023Snsouch struct pollfd set[1]; 8151694Sroger static struct tsplist *head = &msgslist; 8251694Sroger static struct tsplist *tail = &msgslist; 8351694Sroger static int msgcnt = 0; 8459014Sroger struct tsplist *prev; 8559014Sroger struct netinfo *ntp; 8659014Sroger struct tsplist *ptr; 8759014Sroger ssize_t n; 8859014Sroger 8959014Sroger if (trace) { 9051694Sroger fprintf(fd, "readmsg: looking for %s from %s, %s\n", 9151694Sroger tsptype[type], machfrom == NULL ? "ANY" : machfrom, 9251694Sroger netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net)); 9351694Sroger if (head->p != 0) { 9451694Sroger length = 1; 9567306Sroger for (ptr = head->p; ptr != 0; ptr = ptr->p) { 9667306Sroger /* do not repeat the hundreds of messages */ 9751694Sroger if (++length > 3) { 9851694Sroger if (ptr == tail) { 99119277Simp fprintf(fd,"\t ...%d skipped\n", 100119277Simp length); 101119277Simp } else { 102119277Simp continue; 10351694Sroger } 10451694Sroger } 10551694Sroger fprintf(fd, length > 1 ? "\t" : "queue:\t"); 10651694Sroger print(&ptr->info, &ptr->addr); 10751694Sroger } 10851694Sroger } 10959014Sroger } 110118819Salex 111118819Salex ptr = head->p; 112118819Salex prev = head; 113118819Salex 114118819Salex /* 115118819Salex * Look for the requested message scanning through the 11651694Sroger * linked list. If found, return it and free the space 11751694Sroger */ 11851694Sroger 11951694Sroger while (ptr != NULL) { 12051694Sroger if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) { 12151694Srogeragain: 12259014Sroger msgin = ptr->info; 123118819Salex from = ptr->addr; 124118819Salex from_when = ptr->when; 125118819Salex prev->p = ptr->p; 126118819Salex if (ptr == tail) 127118819Salex tail = prev; 12851694Sroger free(ptr); 12962214Sroger fromnet = NULL; 13051694Sroger if (netfrom == NULL) 13162214Sroger for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 13262214Sroger if ((ntp->mask & from.sin_addr.s_addr) == 13351694Sroger ntp->net.s_addr) { 13451694Sroger fromnet = ntp; 13551694Sroger break; 13651694Sroger } 13751694Sroger } 13851694Sroger else 13951694Sroger fromnet = netfrom; 14051694Sroger if (trace) { 14151694Sroger fprintf(fd, "readmsg: found "); 14251694Sroger print(&msgin, &from); 14351694Sroger } 14462214Sroger 14562214Sroger/* The protocol can get far behind. When it does, it gets 14662214Sroger * hopelessly confused. So delete duplicate messages. 14762214Sroger */ 14862214Sroger for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) { 14962214Sroger if (ptr->addr.sin_addr.s_addr 15062214Sroger == from.sin_addr.s_addr 15162214Sroger && ptr->info.tsp_type == msgin.tsp_type) { 15262214Sroger if (trace) 15362214Sroger fprintf(fd, "\tdup "); 15462214Sroger goto again; 15562214Sroger } 15662214Sroger } 15762214Sroger msgcnt--; 15862214Sroger return(&msgin); 15962214Sroger } else { 16062214Sroger prev = ptr; 16162214Sroger ptr = ptr->p; 16262214Sroger } 16362214Sroger } 16459014Sroger 16559014Sroger /* 16659014Sroger * If the message was not in the linked list, it may still be 16759014Sroger * coming from the network. Set the timer and wait 16859014Sroger * on a select to read the next incoming message: if it is the 16959014Sroger * right one, return it, otherwise insert it in the linked list. 17059014Sroger */ 17159014Sroger 17259014Sroger (void)gettimeofday(&rtout, 0); 17359014Sroger timeradd(&rtout, intvl, &rtout); 17459014Sroger set[0].fd = sock; 17559014Sroger set[0].events = POLLIN; 17651694Sroger for (;;) { 17751694Sroger (void)gettimeofday(&rtime, 0); 17851694Sroger timersub(&rtout, &rtime, &rwait); 17962214Sroger if (rwait.tv_sec < 0) 18062214Sroger rwait.tv_sec = rwait.tv_usec = 0; 18162214Sroger else if (rwait.tv_sec == 0 18262214Sroger && rwait.tv_usec < 1000000/CLK_TCK) 18362214Sroger rwait.tv_usec = 1000000/CLK_TCK; 18462214Sroger 18562214Sroger if (trace) { 18662214Sroger fprintf(fd, "readmsg: wait %ld.%6ld at %s\n", 18762214Sroger (long int)rwait.tv_sec, (long int)rwait.tv_usec, 188123291Sobrien date()); 189123291Sobrien /* Notice a full disk, as we flush trace info. 19062214Sroger * It is better to flush periodically than at 19162214Sroger * every line because the tracing consists of bursts 19262214Sroger * of many lines. Without care, tracing slows 19362214Sroger * down the code enough to break the protocol. 19462214Sroger */ 19562214Sroger if (rwait.tv_sec != 0 19693023Snsouch && EOF == fflush(fd)) 19765692Sroger traceoff("Tracing ended for cause"); 19865392Speter } 19993023Snsouch 20093023Snsouch if (!poll(set, 1, (int)(rwait.tv_sec * 1000 + rwait.tv_usec / 1000))) { 20193023Snsouch if (rwait.tv_sec == 0 && rwait.tv_usec == 0) 20262214Sroger return(0); 20365392Speter continue; 20451694Sroger } 20562214Sroger length = sizeof(from); 20651694Sroger memset(&msgin, 0, sizeof(msgin)); 20751694Sroger if ((n = recvfrom(sock, &msgin, sizeof(struct tsp), 0, 20851694Sroger (struct sockaddr*)(void *)&from, &length)) < 0) { 20951694Sroger syslog(LOG_ERR, "recvfrom: %m"); 21051694Sroger exit(EXIT_FAILURE); 21151694Sroger } 21251694Sroger /* 21351694Sroger * The 4.3BSD protocol spec had a 32-byte tsp_name field, and 21451694Sroger * this is still OS-dependent. Demand that the packet is at 21551694Sroger * least long enough to hold a 4.3BSD packet. 21651694Sroger */ 21751694Sroger if (n < (ssize_t)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) { 21851694Sroger syslog(LOG_NOTICE, 21951694Sroger "short packet (%lu/%lu bytes) from %s", 22051694Sroger (u_long)n, 22151694Sroger (u_long)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32), 22251694Sroger inet_ntoa(from.sin_addr)); 22351694Sroger continue; 22493023Snsouch } 22593023Snsouch (void)gettimeofday(&from_when, (struct timezone *)0); 22693023Snsouch bytehostorder(&msgin); 22793023Snsouch 22893023Snsouch if (msgin.tsp_vers > TSPVERSION) { 22993023Snsouch if (trace) { 23093023Snsouch fprintf(fd,"readmsg: version mismatch\n"); 23193023Snsouch /* should do a dump of the packet */ 23293023Snsouch } 23393023Snsouch continue; 23493023Snsouch } 23593023Snsouch 23693023Snsouch if (memchr(msgin.tsp_name, 23793023Snsouch '\0', sizeof msgin.tsp_name) == NULL) { 23893023Snsouch syslog(LOG_NOTICE, "hostname field not NUL terminated " 23993023Snsouch "in packet from %s", inet_ntoa(from.sin_addr)); 24051694Sroger continue; 24151694Sroger } 24251694Sroger 24351694Sroger fromnet = NULL; 24451694Sroger for (ntp = nettab; ntp != NULL; ntp = ntp->next) 24551694Sroger if ((ntp->mask & from.sin_addr.s_addr) == 24651694Sroger ntp->net.s_addr) { 24751694Sroger fromnet = ntp; 24851694Sroger break; 24951694Sroger } 25051694Sroger 25151694Sroger /* 25251694Sroger * drop packets from nets we are ignoring permanently 25351694Sroger */ 25451694Sroger if (fromnet == NULL) { 25551694Sroger /* 25651694Sroger * The following messages may originate on 25751694Sroger * this host with an ignored network address 25851694Sroger */ 25951694Sroger if (msgin.tsp_type != TSP_TRACEON && 26051694Sroger msgin.tsp_type != TSP_SETDATE && 261111815Sphk msgin.tsp_type != TSP_MSITE && 262111815Sphk msgin.tsp_type != TSP_TEST && 263111815Sphk msgin.tsp_type != TSP_TRACEOFF) { 264111815Sphk if (trace) { 265111815Sphk fprintf(fd,"readmsg: discard null net "); 266111815Sphk print(&msgin, &from); 267111815Sphk } 268111815Sphk continue; 269111815Sphk } 27051694Sroger } 27151694Sroger 27252995Speter /* 27367306Sroger * Throw away messages coming from this machine, 27465728Sroger * unless they are of some particular type. 27565728Sroger * This gets rid of broadcast messages and reduces 27667306Sroger * master processing time. 27751694Sroger */ 27851694Sroger if (!strcmp(msgin.tsp_name, hostname) 27951694Sroger && msgin.tsp_type != TSP_SETDATE 28051694Sroger && msgin.tsp_type != TSP_TEST 28151694Sroger && msgin.tsp_type != TSP_MSITE 28251694Sroger && msgin.tsp_type != TSP_TRACEON 28351694Sroger && msgin.tsp_type != TSP_TRACEOFF 28451694Sroger && msgin.tsp_type != TSP_LOOP) { 28551694Sroger if (trace) { 28651694Sroger fprintf(fd, "readmsg: discard own "); 28751694Sroger print(&msgin, &from); 28867306Sroger } 28967306Sroger continue; 29067306Sroger } 29167306Sroger 29267306Sroger /* 29367306Sroger * Send acknowledgements here; this is faster and 29467306Sroger * avoids deadlocks that would occur if acks were 29567306Sroger * sent from a higher level routine. Different 29667306Sroger * acknowledgements are necessary, depending on 29767306Sroger * status. 29867306Sroger */ 29967306Sroger if (fromnet == NULL) /* do not de-reference 0 */ 30067306Sroger ignoreack(); 30167306Sroger else if (fromnet->status == MASTER) 30267306Sroger masterack(); 30367306Sroger else if (fromnet->status == SLAVE) 30467306Sroger slaveack(); 30567306Sroger else 30667306Sroger ignoreack(); 30751694Sroger 30851694Sroger if (LOOKAT(msgin, type, machfrom, netfrom, from)) { 30951694Sroger if (trace) { 31051694Sroger fprintf(fd, "readmsg: "); 31151694Sroger print(&msgin, &from); 31251694Sroger } 31351694Sroger return(&msgin); 31451694Sroger } else if (++msgcnt > NHOSTS*3) { 31551694Sroger 31651694Sroger/* The protocol gets hopelessly confused if it gets too far 31751694Sroger* behind. However, it seems able to recover from all cases of lost 31851694Sroger* packets. Therefore, if we are swamped, throw everything away. 31951694Sroger*/ 32051694Sroger if (trace) 32151694Sroger fprintf(fd, 32251694Sroger "readmsg: discarding %d msgs\n", 32351694Sroger msgcnt); 32451694Sroger msgcnt = 0; 32551694Sroger while ((ptr = head->p) != NULL) { 32651694Sroger head->p = ptr->p; 32751694Sroger free(ptr); 32851694Sroger } 32951694Sroger tail = head; 33051694Sroger } else { 33151694Sroger tail->p = malloc(sizeof(struct tsplist)); 33251694Sroger tail = tail->p; 33362112Sroger tail->p = NULL; 33462112Sroger tail->info = msgin; 33562112Sroger tail->addr = from; 33651694Sroger /* timestamp msgs so SETTIMEs are correct */ 33751694Sroger tail->when = from_when; 33851694Sroger } 33951694Sroger } 34051694Sroger} 34151694Sroger 34251694Sroger/* 34351694Sroger * Send the necessary acknowledgements: 34451694Sroger * only the type ACK is to be sent by a slave 34551694Sroger */ 346119690Sjhbvoid 34765049Srogerslaveack(void) 34865049Sroger{ 34951694Sroger switch(msgin.tsp_type) { 35065049Sroger 35151694Sroger case TSP_ADJTIME: 35251694Sroger case TSP_SETTIME: 35351694Sroger case TSP_ACCEPT: 35451694Sroger case TSP_REFUSE: 35551694Sroger case TSP_TRACEON: 35659014Sroger case TSP_TRACEOFF: 35759014Sroger case TSP_QUIT: 35851694Sroger if (trace) { 35959014Sroger fprintf(fd, "Slaveack: "); 36051694Sroger print(&msgin, &from); 36151694Sroger } 36251694Sroger xmit(TSP_ACK,msgin.tsp_seq, &from); 36359014Sroger break; 36459014Sroger 36551694Sroger default: 36651694Sroger if (trace) { 36751694Sroger fprintf(fd, "Slaveack: no ack: "); 36851694Sroger print(&msgin, &from); 36951694Sroger } 37051694Sroger break; 37151694Sroger } 37251694Sroger} 37351694Sroger 37451694Sroger/* 37551694Sroger * Certain packets may arrive from this machine on ignored networks. 37651694Sroger * These packets should be acknowledged. 37751694Sroger */ 37865049Srogervoid 37965049Srogerignoreack(void) 38065049Sroger{ 38151694Sroger switch(msgin.tsp_type) { 38251694Sroger 38351694Sroger case TSP_TRACEON: 38451694Sroger case TSP_TRACEOFF: 38551694Sroger case TSP_QUIT: 38651694Sroger if (trace) { 38759250Sroger fprintf(fd, "Ignoreack: "); 38851694Sroger print(&msgin, &from); 38951694Sroger } 39051694Sroger xmit(TSP_ACK,msgin.tsp_seq, &from); 39151694Sroger break; 39251694Sroger 39351694Sroger default: 39451694Sroger if (trace) { 39551694Sroger fprintf(fd, "Ignoreack: no ack: "); 39651694Sroger print(&msgin, &from); 39751694Sroger } 39851694Sroger break; 39951694Sroger } 40051694Sroger} 40151694Sroger 40251694Sroger/* 40351694Sroger * `masterack' sends the necessary acknowledgements 40451694Sroger * to the messages received by a master 40551694Sroger */ 40651694Srogervoid 40751694Srogermasterack(void) 40851694Sroger{ 40951694Sroger struct tsp resp; 41051694Sroger 41151694Sroger resp = msgin; 41251694Sroger resp.tsp_vers = TSPVERSION; 41365692Sroger set_tsp_name(&resp, hostname); 41493023Snsouch 41551694Sroger switch(msgin.tsp_type) { 41651694Sroger 41751694Sroger case TSP_QUIT: 41851694Sroger case TSP_TRACEON: 41951694Sroger case TSP_TRACEOFF: 42051694Sroger case TSP_MSITEREQ: 42151694Sroger if (trace) { 42251694Sroger fprintf(fd, "Masterack: "); 42351694Sroger print(&msgin, &from); 42451694Sroger } 42551694Sroger xmit(TSP_ACK,msgin.tsp_seq, &from); 42651694Sroger break; 42751694Sroger 42851694Sroger case TSP_RESOLVE: 42951694Sroger case TSP_MASTERREQ: 43051694Sroger if (trace) { 43151694Sroger fprintf(fd, "Masterack: "); 43251694Sroger print(&msgin, &from); 43351694Sroger } 43451694Sroger xmit(TSP_MASTERACK,msgin.tsp_seq, &from); 43551694Sroger break; 43651694Sroger 43751694Sroger default: 43851694Sroger if (trace) { 43951694Sroger fprintf(fd,"Masterack: no ack: "); 44051694Sroger print(&msgin, &from); 44151694Sroger } 44251694Sroger break; 44351694Sroger } 44451694Sroger} 44551694Sroger 44651694Sroger/* 44751694Sroger * Print a TSP message 44851694Sroger */ 44967306Srogervoid 45067306Srogerprint(struct tsp *msg, struct sockaddr_in *addr) 45167306Sroger{ 45267306Sroger char tm[26]; 45367306Sroger time_t msgtime; 45467306Sroger 45567306Sroger if (msg->tsp_type >= TSPTYPENUMBER) { 45651694Sroger fprintf(fd, "bad type (%u) on packet from %s\n", 45767306Sroger msg->tsp_type, inet_ntoa(addr->sin_addr)); 45867306Sroger return; 45967306Sroger } 46067306Sroger 46167306Sroger switch (msg->tsp_type) { 46267306Sroger 46367306Sroger case TSP_LOOP: 46467306Sroger fprintf(fd, "%s %d %-6u #%d %-15s %s\n", 46567306Sroger tsptype[msg->tsp_type], 46667306Sroger msg->tsp_vers, 46767306Sroger msg->tsp_seq, 46851694Sroger msg->tsp_hopcnt, 46951694Sroger inet_ntoa(addr->sin_addr), 47051694Sroger msg->tsp_name); 47165049Sroger break; 47265049Sroger 47365049Sroger case TSP_SETTIME: 47465049Sroger case TSP_SETDATE: 47551694Sroger case TSP_SETDATEREQ: 47651694Sroger msgtime = msg->tsp_time.tv_sec; 47751694Sroger strlcpy(tm, ctime(&msgtime)+3+1, sizeof(tm)); 47851694Sroger tm[15] = '\0'; /* ugh */ 47951694Sroger fprintf(fd, "%s %d %-6u %s %-15s %s\n", 48051694Sroger tsptype[msg->tsp_type], 48151694Sroger msg->tsp_vers, 48251694Sroger msg->tsp_seq, 48351694Sroger tm, 48451694Sroger inet_ntoa(addr->sin_addr), 48551694Sroger msg->tsp_name); 48651694Sroger break; 487118819Salex 488118819Salex case TSP_ADJTIME: 489118819Salex fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n", 490118819Salex tsptype[msg->tsp_type], 491118819Salex msg->tsp_vers, 492118819Salex msg->tsp_seq, 49351694Sroger (long)msg->tsp_time.tv_sec, 49459014Sroger (long)msg->tsp_time.tv_usec, 49559014Sroger inet_ntoa(addr->sin_addr), 49651694Sroger msg->tsp_name); 49793023Snsouch break; 49893023Snsouch 499115556Sphk default: 500115556Sphk fprintf(fd, "%s %d %-6u %-15s %s\n", 50193023Snsouch tsptype[msg->tsp_type], 502123088Struckman msg->tsp_vers, 503123088Struckman msg->tsp_seq, 504123088Struckman inet_ntoa(addr->sin_addr), 50593023Snsouch msg->tsp_name); 50667306Sroger break; 50767306Sroger } 50867306Sroger} 50951694Sroger