xref: /plan9/sys/src/cmd/aan.c (revision 58da3067adcdccaaa043d0bfde28ba83b7ced07d)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <auth.h>
49a747e4fSDavid du Colombier #include <fcall.h>
59a747e4fSDavid du Colombier #include <thread.h>
69a747e4fSDavid du Colombier 
79a747e4fSDavid du Colombier #define NS(x)		((vlong)x)
89a747e4fSDavid du Colombier #define US(x)		(NS(x) * 1000LL)
99a747e4fSDavid du Colombier #define MS(x)		(US(x) * 1000LL)
109a747e4fSDavid du Colombier #define S(x)		(MS(x) * 1000LL)
119a747e4fSDavid du Colombier 
129a747e4fSDavid du Colombier #define LOGNAME	"aan"
139a747e4fSDavid du Colombier 
149a747e4fSDavid du Colombier enum {
159a747e4fSDavid du Colombier 	Synctime = S(8),
169a747e4fSDavid du Colombier 	Nbuf = 10,
179a747e4fSDavid du Colombier 	K = 1024,
189a747e4fSDavid du Colombier 	Bufsize = 8 * K,
199a747e4fSDavid du Colombier 	Stacksize = 8 * K,
20*30ce352cSDavid du Colombier 	Timer = 0,		/* Alt channels. */
219a747e4fSDavid du Colombier 	Unsent = 1,
22*30ce352cSDavid du Colombier 	Maxto = 24 * 3600,	/* A full day to reconnect. */
23*30ce352cSDavid du Colombier 	Hdrsz = 12,
249a747e4fSDavid du Colombier };
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier typedef struct Endpoints Endpoints;
279a747e4fSDavid du Colombier struct Endpoints {
289a747e4fSDavid du Colombier 	char	*lsys;
299a747e4fSDavid du Colombier 	char	*lserv;
309a747e4fSDavid du Colombier 	char	*rsys;
319a747e4fSDavid du Colombier 	char	*rserv;
329a747e4fSDavid du Colombier };
339a747e4fSDavid du Colombier 
349a747e4fSDavid du Colombier typedef struct {
35*30ce352cSDavid du Colombier 	ulong	nb;		/* Number of data bytes in this message */
36*30ce352cSDavid du Colombier 	ulong	msg;		/* Message number */
37*30ce352cSDavid du Colombier 	ulong	acked;		/* Number of messages acked */
389a747e4fSDavid du Colombier } Hdr;
399a747e4fSDavid du Colombier 
40*30ce352cSDavid du Colombier typedef struct {
419a747e4fSDavid du Colombier 	Hdr	hdr;
429a747e4fSDavid du Colombier 	uchar	buf[Bufsize];
439a747e4fSDavid du Colombier } Buf;
449a747e4fSDavid du Colombier 
459a747e4fSDavid du Colombier static char	*Logname = LOGNAME;
469a747e4fSDavid du Colombier static int	client;
47*30ce352cSDavid du Colombier static int	debug;
48*30ce352cSDavid du Colombier static char	*devdir;
49*30ce352cSDavid du Colombier static char	*dialstring;
50*30ce352cSDavid du Colombier static int	done;
51*30ce352cSDavid du Colombier static int	inmsg;
52*30ce352cSDavid du Colombier static int	maxto = Maxto;
53*30ce352cSDavid du Colombier static int	netfd;
54*30ce352cSDavid du Colombier 
55*30ce352cSDavid du Colombier static Channel	*empty;
56*30ce352cSDavid du Colombier static Channel	*unacked;
57*30ce352cSDavid du Colombier static Channel	*unsent;
589a747e4fSDavid du Colombier 
599a747e4fSDavid du Colombier static Alt a[] = {
609a747e4fSDavid du Colombier 	/*	c	v	 op   */
61*30ce352cSDavid du Colombier 	{ 	nil,	nil,	CHANRCV	},	/* timer */
62*30ce352cSDavid du Colombier 	{	nil,	nil,	CHANRCV	},	/* unsent */
639a747e4fSDavid du Colombier 	{ 	nil,	nil,	CHANEND	},
649a747e4fSDavid du Colombier };
659a747e4fSDavid du Colombier 
66*30ce352cSDavid du Colombier static void	dmessage(int, char *, ...);
67*30ce352cSDavid du Colombier static void	freeendpoints(Endpoints *);
689a747e4fSDavid du Colombier static void	fromclient(void*);
69*30ce352cSDavid du Colombier static void	fromnet(void*);
70*30ce352cSDavid du Colombier static Endpoints *getendpoints(char *);
71*30ce352cSDavid du Colombier static void	packhdr(Hdr *, uchar *);
729a747e4fSDavid du Colombier static void	reconnect(void);
739a747e4fSDavid du Colombier static void	showmsg(int, char *, Buf *);
74*30ce352cSDavid du Colombier static void	synchronize(void);
759a747e4fSDavid du Colombier static void	timerproc(void *);
76*30ce352cSDavid du Colombier static void	unpackhdr(Hdr *, uchar *);
77*30ce352cSDavid du Colombier static int	writen(int, uchar *, int);
789a747e4fSDavid du Colombier 
799a747e4fSDavid du Colombier static void
usage(void)809a747e4fSDavid du Colombier usage(void)
819a747e4fSDavid du Colombier {
82*30ce352cSDavid du Colombier 	fprint(2, "Usage: %s [-cd] [-m maxto] dialstring|netdir\n", argv0);
8391e577b2SDavid du Colombier 	threadexitsall("usage");
849a747e4fSDavid du Colombier }
859a747e4fSDavid du Colombier 
869a747e4fSDavid du Colombier static int
catch(void *,char * s)879a747e4fSDavid du Colombier catch(void *, char *s)
889a747e4fSDavid du Colombier {
89*30ce352cSDavid du Colombier 	if (strstr(s, "alarm") != nil) {
90*30ce352cSDavid du Colombier 		syslog(0, Logname, "Timed out waiting for client on %s, exiting...",
919a747e4fSDavid du Colombier 			   devdir);
929a747e4fSDavid du Colombier 		threadexitsall(nil);
939a747e4fSDavid du Colombier 	}
949a747e4fSDavid du Colombier 	return 0;
959a747e4fSDavid du Colombier }
969a747e4fSDavid du Colombier 
979a747e4fSDavid du Colombier void
threadmain(int argc,char ** argv)989a747e4fSDavid du Colombier threadmain(int argc, char **argv)
999a747e4fSDavid du Colombier {
100*30ce352cSDavid du Colombier 	int i, fd, failed, delta;
101*30ce352cSDavid du Colombier 	vlong synctime, now;
102*30ce352cSDavid du Colombier 	char *p;
103*30ce352cSDavid du Colombier 	uchar buf[Hdrsz];
104*30ce352cSDavid du Colombier 	Buf *b, *eb;
1059a747e4fSDavid du Colombier 	Channel *timer;
106*30ce352cSDavid du Colombier 	Hdr hdr;
1079a747e4fSDavid du Colombier 
1089a747e4fSDavid du Colombier 	ARGBEGIN {
1099a747e4fSDavid du Colombier 	case 'c':
1109a747e4fSDavid du Colombier 		client++;
1119a747e4fSDavid du Colombier 		break;
1129a747e4fSDavid du Colombier 	case 'd':
1139a747e4fSDavid du Colombier 		debug++;
1149a747e4fSDavid du Colombier 		break;
1159a747e4fSDavid du Colombier 	case 'm':
116*30ce352cSDavid du Colombier 		maxto = strtol(EARGF(usage()), (char **)nil, 0);
1179a747e4fSDavid du Colombier 		break;
1189a747e4fSDavid du Colombier 	default:
1199a747e4fSDavid du Colombier 		usage();
1204e17d7c8SDavid du Colombier 	} ARGEND;
1219a747e4fSDavid du Colombier 
1229a747e4fSDavid du Colombier 	if (argc != 1)
1239a747e4fSDavid du Colombier 		usage();
1249a747e4fSDavid du Colombier 
1259a747e4fSDavid du Colombier 	if (!client) {
1269a747e4fSDavid du Colombier 		devdir = argv[0];
1279a747e4fSDavid du Colombier 		if ((p = strstr(devdir, "/local")) != nil)
1289a747e4fSDavid du Colombier 			*p = '\0';
129*30ce352cSDavid du Colombier 	}else
1309a747e4fSDavid du Colombier 		dialstring = argv[0];
1319a747e4fSDavid du Colombier 
1329a747e4fSDavid du Colombier 	if (debug > 0) {
133*30ce352cSDavid du Colombier 		fd = open("#c/cons", OWRITE|OCEXEC);
1349a747e4fSDavid du Colombier 		dup(fd, 2);
1359a747e4fSDavid du Colombier 	}
1369a747e4fSDavid du Colombier 
1379a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
1389a747e4fSDavid du Colombier 
1399a747e4fSDavid du Colombier 	atnotify(catch, 1);
1409a747e4fSDavid du Colombier 
1419a747e4fSDavid du Colombier 	unsent = chancreate(sizeof(Buf *), Nbuf);
1429a747e4fSDavid du Colombier 	unacked= chancreate(sizeof(Buf *), Nbuf);
1439a747e4fSDavid du Colombier 	empty  = chancreate(sizeof(Buf *), Nbuf);
1449a747e4fSDavid du Colombier 	timer  = chancreate(sizeof(uchar *), 1);
1459a747e4fSDavid du Colombier 
1469a747e4fSDavid du Colombier 	for (i = 0; i != Nbuf; i++) {
147*30ce352cSDavid du Colombier 		eb = malloc(sizeof(Buf));
148*30ce352cSDavid du Colombier 		sendp(empty, eb);
1499a747e4fSDavid du Colombier 	}
1509a747e4fSDavid du Colombier 
1519a747e4fSDavid du Colombier 	netfd = -1;
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier 	if (proccreate(fromnet, nil, Stacksize) < 0)
154*30ce352cSDavid du Colombier 		sysfatal("Cannot start fromnet; %r");
1559a747e4fSDavid du Colombier 
156*30ce352cSDavid du Colombier 	reconnect();		/* Set up the initial connection. */
1579a747e4fSDavid du Colombier 	synchronize();
1589a747e4fSDavid du Colombier 
1599a747e4fSDavid du Colombier 	if (proccreate(fromclient, nil, Stacksize) < 0)
160*30ce352cSDavid du Colombier 		sysfatal("cannot start fromclient; %r");
1619a747e4fSDavid du Colombier 
1629a747e4fSDavid du Colombier 	if (proccreate(timerproc, timer, Stacksize) < 0)
163*30ce352cSDavid du Colombier 		sysfatal("Cannot start timerproc; %r");
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier 	a[Timer].c = timer;
1669a747e4fSDavid du Colombier 	a[Unsent].c = unsent;
1679a747e4fSDavid du Colombier 	a[Unsent].v = &b;
1689a747e4fSDavid du Colombier 
1699a747e4fSDavid du Colombier 	synctime = nsec() + Synctime;
1709a747e4fSDavid du Colombier 	failed = 0;
1719a747e4fSDavid du Colombier 	while (!done) {
1729a747e4fSDavid du Colombier 		if (failed) {
173*30ce352cSDavid du Colombier 			/* Wait for the netreader to die. */
1749a747e4fSDavid du Colombier 			while (netfd >= 0) {
1759a747e4fSDavid du Colombier 				dmessage(1, "main; waiting for netreader to die\n");
1769a747e4fSDavid du Colombier 				sleep(1000);
1779a747e4fSDavid du Colombier 			}
1789a747e4fSDavid du Colombier 
179*30ce352cSDavid du Colombier 			/* the reader died; reestablish the world. */
1809a747e4fSDavid du Colombier 			reconnect();
1819a747e4fSDavid du Colombier 			synchronize();
1829a747e4fSDavid du Colombier 			failed = 0;
1839a747e4fSDavid du Colombier 		}
1849a747e4fSDavid du Colombier 
1859a747e4fSDavid du Colombier 		now = nsec();
1869a747e4fSDavid du Colombier 		delta = (synctime - nsec()) / MS(1);
1879a747e4fSDavid du Colombier 
1889a747e4fSDavid du Colombier 		if (delta <= 0) {
1899a747e4fSDavid du Colombier 			hdr.nb = 0;
1909a747e4fSDavid du Colombier 			hdr.acked = inmsg;
1919a747e4fSDavid du Colombier 			hdr.msg = -1;
192*30ce352cSDavid du Colombier 			packhdr(&hdr, buf);
193*30ce352cSDavid du Colombier 			if (writen(netfd, buf, sizeof(buf)) < 0) {
1949a747e4fSDavid du Colombier 				dmessage(2, "main; writen failed; %r\n");
1959a747e4fSDavid du Colombier 				failed = 1;
1969a747e4fSDavid du Colombier 				continue;
1979a747e4fSDavid du Colombier 			}
1989a747e4fSDavid du Colombier 			synctime = nsec() + Synctime;
1999a747e4fSDavid du Colombier 			assert(synctime > now);
2009a747e4fSDavid du Colombier 		}
2019a747e4fSDavid du Colombier 
2029a747e4fSDavid du Colombier 		switch (alt(a)) {
2039a747e4fSDavid du Colombier 		case Timer:
2049a747e4fSDavid du Colombier 			break;
2059a747e4fSDavid du Colombier 		case Unsent:
2069a747e4fSDavid du Colombier 			sendp(unacked, b);
2079a747e4fSDavid du Colombier 
2089a747e4fSDavid du Colombier 			b->hdr.acked = inmsg;
209*30ce352cSDavid du Colombier 			packhdr(&b->hdr, buf);
210*30ce352cSDavid du Colombier 			if (writen(netfd, buf, sizeof(buf)) < 0 ||
211*30ce352cSDavid du Colombier 			    writen(netfd, b->buf, b->hdr.nb) < 0) {
2129a747e4fSDavid du Colombier 				dmessage(2, "main; writen failed; %r\n");
2139a747e4fSDavid du Colombier 				failed = 1;
2149a747e4fSDavid du Colombier 			}
2159a747e4fSDavid du Colombier 
2169a747e4fSDavid du Colombier 			if (b->hdr.nb == 0)
2179a747e4fSDavid du Colombier 				done = 1;
2189a747e4fSDavid du Colombier 			break;
2199a747e4fSDavid du Colombier 		}
2209a747e4fSDavid du Colombier 	}
2219a747e4fSDavid du Colombier 	syslog(0, Logname, "exiting...");
2229a747e4fSDavid du Colombier 	threadexitsall(nil);
2239a747e4fSDavid du Colombier }
2249a747e4fSDavid du Colombier 
2259a747e4fSDavid du Colombier static void
fromclient(void *)2269a747e4fSDavid du Colombier fromclient(void*)
2279a747e4fSDavid du Colombier {
228*30ce352cSDavid du Colombier 	Buf *b;
2299a747e4fSDavid du Colombier 	static int outmsg;
2309a747e4fSDavid du Colombier 
231*30ce352cSDavid du Colombier 	do {
2329a747e4fSDavid du Colombier 		b = recvp(empty);
2339a747e4fSDavid du Colombier 		if ((int)(b->hdr.nb = read(0, b->buf, Bufsize)) <= 0) {
2349a747e4fSDavid du Colombier 			if ((int)b->hdr.nb < 0)
2359a747e4fSDavid du Colombier 				dmessage(2, "fromclient; Cannot read 9P message; %r\n");
2369a747e4fSDavid du Colombier 			else
2379a747e4fSDavid du Colombier 				dmessage(2, "fromclient; Client terminated\n");
2389a747e4fSDavid du Colombier 			b->hdr.nb = 0;
2399a747e4fSDavid du Colombier 		}
2409a747e4fSDavid du Colombier 		b->hdr.msg = outmsg++;
2419a747e4fSDavid du Colombier 
2429a747e4fSDavid du Colombier 		showmsg(1, "fromclient", b);
2439a747e4fSDavid du Colombier 		sendp(unsent, b);
244*30ce352cSDavid du Colombier 	} while (b->hdr.nb != 0);
2459a747e4fSDavid du Colombier }
2469a747e4fSDavid du Colombier 
2479a747e4fSDavid du Colombier static void
fromnet(void *)2489a747e4fSDavid du Colombier fromnet(void*)
2499a747e4fSDavid du Colombier {
250*30ce352cSDavid du Colombier 	int len, acked, i;
251*30ce352cSDavid du Colombier 	uchar buf[Hdrsz];
252*30ce352cSDavid du Colombier 	Buf *b, *rb;
2539a747e4fSDavid du Colombier 	static int lastacked;
2549a747e4fSDavid du Colombier 
2559a747e4fSDavid du Colombier 	b = (Buf *)malloc(sizeof(Buf));
2569a747e4fSDavid du Colombier 	assert(b);
2579a747e4fSDavid du Colombier 
2589a747e4fSDavid du Colombier 	while (!done) {
2599a747e4fSDavid du Colombier 		while (netfd < 0) {
2609a747e4fSDavid du Colombier 			dmessage(1, "fromnet; waiting for connection... (inmsg %d)\n",
2619a747e4fSDavid du Colombier 					  inmsg);
2629a747e4fSDavid du Colombier 			sleep(1000);
2639a747e4fSDavid du Colombier 		}
2649a747e4fSDavid du Colombier 
265*30ce352cSDavid du Colombier 		/* Read the header. */
266*30ce352cSDavid du Colombier 		if ((len = readn(netfd, buf, sizeof(buf))) <= 0) {
2679a747e4fSDavid du Colombier 			if (len < 0)
2689a747e4fSDavid du Colombier 				dmessage(1, "fromnet; (hdr) network failure; %r\n");
2699a747e4fSDavid du Colombier 			else
2709a747e4fSDavid du Colombier 				dmessage(1, "fromnet; (hdr) network closed\n");
2719a747e4fSDavid du Colombier 			close(netfd);
2729a747e4fSDavid du Colombier 			netfd = -1;
2739a747e4fSDavid du Colombier 			continue;
2749a747e4fSDavid du Colombier 		}
275*30ce352cSDavid du Colombier 		unpackhdr(&b->hdr, buf);
276*30ce352cSDavid du Colombier 		dmessage(2, "fromnet: Got message, size %d, nb %d, msg %d\n",
277*30ce352cSDavid du Colombier 			len, b->hdr.nb, b->hdr.msg);
2789a747e4fSDavid du Colombier 
2799a747e4fSDavid du Colombier 		if (b->hdr.nb == 0) {
2809a747e4fSDavid du Colombier 			if  ((long)b->hdr.msg >= 0) {
2819a747e4fSDavid du Colombier 				dmessage(1, "fromnet; network closed\n");
2829a747e4fSDavid du Colombier 				break;
2839a747e4fSDavid du Colombier 			}
2849a747e4fSDavid du Colombier 			continue;
2859a747e4fSDavid du Colombier 		}
2869a747e4fSDavid du Colombier 
287*30ce352cSDavid du Colombier 		if ((len = readn(netfd, b->buf, b->hdr.nb)) <= 0 ||
288*30ce352cSDavid du Colombier 		    len != b->hdr.nb) {
2899a747e4fSDavid du Colombier 			if (len == 0)
2909a747e4fSDavid du Colombier 				dmessage(1, "fromnet; network closed\n");
2919a747e4fSDavid du Colombier 			else
2929a747e4fSDavid du Colombier 				dmessage(1, "fromnet; network failure; %r\n");
2939a747e4fSDavid du Colombier 			close(netfd);
2949a747e4fSDavid du Colombier 			netfd = -1;
2959a747e4fSDavid du Colombier 			continue;
2969a747e4fSDavid du Colombier 		}
2979a747e4fSDavid du Colombier 
2989a747e4fSDavid du Colombier 		if (b->hdr.msg < inmsg) {
2999a747e4fSDavid du Colombier 			dmessage(1, "fromnet; skipping message %d, currently at %d\n",
3009a747e4fSDavid du Colombier 				b->hdr.msg, inmsg);
3019a747e4fSDavid du Colombier 			continue;
3029a747e4fSDavid du Colombier 		}
3039a747e4fSDavid du Colombier 
304*30ce352cSDavid du Colombier 		/* Process the acked list. */
3059a747e4fSDavid du Colombier 		acked = b->hdr.acked - lastacked;
3069a747e4fSDavid du Colombier 		for (i = 0; i != acked; i++) {
3079a747e4fSDavid du Colombier 			rb = recvp(unacked);
3089a747e4fSDavid du Colombier 			if (rb->hdr.msg != lastacked + i) {
3099a747e4fSDavid du Colombier 				dmessage(1, "rb %p, msg %d, lastacked %d, i %d\n",
3109a747e4fSDavid du Colombier 					rb, rb? rb->hdr.msg: -2, lastacked, i);
3119a747e4fSDavid du Colombier 				assert(0);
3129a747e4fSDavid du Colombier 			}
3139a747e4fSDavid du Colombier 			rb->hdr.msg = -1;
3149a747e4fSDavid du Colombier 			sendp(empty, rb);
3159a747e4fSDavid du Colombier 		}
3169a747e4fSDavid du Colombier 		lastacked = b->hdr.acked;
3179a747e4fSDavid du Colombier 		inmsg++;
3189a747e4fSDavid du Colombier 		showmsg(1, "fromnet", b);
3199a747e4fSDavid du Colombier 		if (writen(1, b->buf, len) < 0)
32014cc0f53SDavid du Colombier 			sysfatal("fromnet; cannot write to client; %r");
3219a747e4fSDavid du Colombier 	}
3229a747e4fSDavid du Colombier 	done = 1;
3239a747e4fSDavid du Colombier }
3249a747e4fSDavid du Colombier 
3259a747e4fSDavid du Colombier static void
reconnect(void)3269a747e4fSDavid du Colombier reconnect(void)
3279a747e4fSDavid du Colombier {
328*30ce352cSDavid du Colombier 	char err[32], ldir[40];
3299a747e4fSDavid du Colombier 	int lcfd, fd;
330*30ce352cSDavid du Colombier 	Endpoints *ep;
3319a747e4fSDavid du Colombier 
3329a747e4fSDavid du Colombier 	if (dialstring) {
3339a747e4fSDavid du Colombier 		syslog(0, Logname, "dialing %s", dialstring);
3349a747e4fSDavid du Colombier   		while ((fd = dial(dialstring, nil, nil, nil)) < 0) {
3359a747e4fSDavid du Colombier 			err[0] = '\0';
3369a747e4fSDavid du Colombier 			errstr(err, sizeof err);
3379a747e4fSDavid du Colombier 			if (strstr(err, "connection refused")) {
3389a747e4fSDavid du Colombier 				dmessage(1, "reconnect; server died...\n");
3399a747e4fSDavid du Colombier 				threadexitsall("server died...");
3409a747e4fSDavid du Colombier 			}
3419a747e4fSDavid du Colombier 			dmessage(1, "reconnect: dialed %s; %s\n", dialstring, err);
3429a747e4fSDavid du Colombier 			sleep(1000);
3439a747e4fSDavid du Colombier 		}
3449a747e4fSDavid du Colombier 		syslog(0, Logname, "reconnected to %s", dialstring);
345*30ce352cSDavid du Colombier 	} else {
3469a747e4fSDavid du Colombier 		syslog(0, Logname, "waiting for connection on %s", devdir);
3479a747e4fSDavid du Colombier 		alarm(maxto * 1000);
3489a747e4fSDavid du Colombier  		if ((lcfd = listen(devdir, ldir)) < 0)
3499a747e4fSDavid du Colombier 			sysfatal("reconnect; cannot listen; %r");
3509a747e4fSDavid du Colombier 
3519a747e4fSDavid du Colombier 		if ((fd = accept(lcfd, ldir)) < 0)
3529a747e4fSDavid du Colombier 			sysfatal("reconnect; cannot accept; %r");
3539a747e4fSDavid du Colombier 		alarm(0);
3549a747e4fSDavid du Colombier 		close(lcfd);
3559a747e4fSDavid du Colombier 
3569a747e4fSDavid du Colombier 		ep = getendpoints(ldir);
3579a747e4fSDavid du Colombier 		dmessage(1, "rsys '%s'\n", ep->rsys);
3589a747e4fSDavid du Colombier 		syslog(0, Logname, "connected from %s", ep->rsys);
3599a747e4fSDavid du Colombier 		freeendpoints(ep);
3609a747e4fSDavid du Colombier 	}
361*30ce352cSDavid du Colombier 	netfd = fd;			/* Wakes up the netreader. */
3629a747e4fSDavid du Colombier }
3639a747e4fSDavid du Colombier 
3649a747e4fSDavid du Colombier static void
synchronize(void)3659a747e4fSDavid du Colombier synchronize(void)
3669a747e4fSDavid du Colombier {
3679a747e4fSDavid du Colombier 	Channel *tmp;
3689a747e4fSDavid du Colombier 	Buf *b;
369*30ce352cSDavid du Colombier 	uchar buf[Hdrsz];
3709a747e4fSDavid du Colombier 
371*30ce352cSDavid du Colombier 	/*
372*30ce352cSDavid du Colombier 	 * Ignore network errors here.  If we fail during
373*30ce352cSDavid du Colombier 	 * synchronization, the next alarm will pick up
374*30ce352cSDavid du Colombier 	 * the error.
375*30ce352cSDavid du Colombier 	 */
3769a747e4fSDavid du Colombier 	tmp = chancreate(sizeof(Buf *), Nbuf);
3779a747e4fSDavid du Colombier 	while ((b = nbrecvp(unacked)) != nil) {
378*30ce352cSDavid du Colombier 		packhdr(&b->hdr, buf);
379*30ce352cSDavid du Colombier 		writen(netfd, buf, sizeof(buf));
380*30ce352cSDavid du Colombier 		writen(netfd, b->buf, b->hdr.nb);
3819a747e4fSDavid du Colombier 		sendp(tmp, b);
3829a747e4fSDavid du Colombier 	}
3839a747e4fSDavid du Colombier 	chanfree(unacked);
3849a747e4fSDavid du Colombier 	unacked = tmp;
3859a747e4fSDavid du Colombier }
3869a747e4fSDavid du Colombier 
3879a747e4fSDavid du Colombier static void
showmsg(int level,char * s,Buf * b)3889a747e4fSDavid du Colombier showmsg(int level, char *s, Buf *b)
3899a747e4fSDavid du Colombier {
3909a747e4fSDavid du Colombier 	if (b == nil) {
3919a747e4fSDavid du Colombier 		dmessage(level, "%s; b == nil\n", s);
3929a747e4fSDavid du Colombier 		return;
3939a747e4fSDavid du Colombier 	}
394*30ce352cSDavid du Colombier 	dmessage(level, "%s;  (len %d) %X %X %X %X %X %X %X %X %X (%p)\n", s,
3959a747e4fSDavid du Colombier 		b->hdr.nb,
3969a747e4fSDavid du Colombier 		b->buf[0], b->buf[1], b->buf[2],
3979a747e4fSDavid du Colombier 		b->buf[3], b->buf[4], b->buf[5],
3989a747e4fSDavid du Colombier 		b->buf[6], b->buf[7], b->buf[8], b);
3999a747e4fSDavid du Colombier }
4009a747e4fSDavid du Colombier 
4019a747e4fSDavid du Colombier static int
writen(int fd,uchar * buf,int nb)4029a747e4fSDavid du Colombier writen(int fd, uchar *buf, int nb)
4039a747e4fSDavid du Colombier {
404*30ce352cSDavid du Colombier 	int n, len = nb;
4059a747e4fSDavid du Colombier 
4069a747e4fSDavid du Colombier 	while (nb > 0) {
4079a747e4fSDavid du Colombier 		if (fd < 0)
4089a747e4fSDavid du Colombier 			return -1;
4099a747e4fSDavid du Colombier 		if ((n = write(fd, buf, nb)) < 0) {
4109a747e4fSDavid du Colombier 			dmessage(1, "writen; Write failed; %r\n");
4119a747e4fSDavid du Colombier 			return -1;
4129a747e4fSDavid du Colombier 		}
4139a747e4fSDavid du Colombier 		dmessage(2, "writen: wrote %d bytes\n", n);
4149a747e4fSDavid du Colombier 		buf += n;
4159a747e4fSDavid du Colombier 		nb -= n;
4169a747e4fSDavid du Colombier 	}
4179a747e4fSDavid du Colombier 	return len;
4189a747e4fSDavid du Colombier }
4199a747e4fSDavid du Colombier 
4209a747e4fSDavid du Colombier static void
timerproc(void * x)4219a747e4fSDavid du Colombier timerproc(void *x)
4229a747e4fSDavid du Colombier {
4239a747e4fSDavid du Colombier 	Channel *timer = x;
424*30ce352cSDavid du Colombier 
4259a747e4fSDavid du Colombier 	while (!done) {
4269a747e4fSDavid du Colombier 		sleep((Synctime / MS(1)) >> 1);
4279a747e4fSDavid du Colombier 		sendp(timer, "timer");
4289a747e4fSDavid du Colombier 	}
4299a747e4fSDavid du Colombier }
4309a747e4fSDavid du Colombier 
4319a747e4fSDavid du Colombier static void
dmessage(int level,char * fmt,...)4329a747e4fSDavid du Colombier dmessage(int level, char *fmt, ...)
4339a747e4fSDavid du Colombier {
4349a747e4fSDavid du Colombier 	va_list arg;
4359a747e4fSDavid du Colombier 
4369a747e4fSDavid du Colombier 	if (level > debug)
4379a747e4fSDavid du Colombier 		return;
4389a747e4fSDavid du Colombier 	va_start(arg, fmt);
4399a747e4fSDavid du Colombier 	vfprint(2, fmt, arg);
4409a747e4fSDavid du Colombier 	va_end(arg);
4419a747e4fSDavid du Colombier }
4429a747e4fSDavid du Colombier 
4439a747e4fSDavid du Colombier static void
getendpoint(char * dir,char * file,char ** sysp,char ** servp)4449a747e4fSDavid du Colombier getendpoint(char *dir, char *file, char **sysp, char **servp)
4459a747e4fSDavid du Colombier {
4469a747e4fSDavid du Colombier 	int fd, n;
4479a747e4fSDavid du Colombier 	char buf[128];
4489a747e4fSDavid du Colombier 	char *sys, *serv;
4499a747e4fSDavid du Colombier 
4509a747e4fSDavid du Colombier 	sys = serv = 0;
4519a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "%s/%s", dir, file);
4529a747e4fSDavid du Colombier 	fd = open(buf, OREAD);
4539a747e4fSDavid du Colombier 	if(fd >= 0){
4549a747e4fSDavid du Colombier 		n = read(fd, buf, sizeof(buf)-1);
4559a747e4fSDavid du Colombier 		if(n>0){
4569a747e4fSDavid du Colombier 			buf[n-1] = 0;
4579a747e4fSDavid du Colombier 			serv = strchr(buf, '!');
4589a747e4fSDavid du Colombier 			if(serv){
4599a747e4fSDavid du Colombier 				*serv++ = 0;
4609a747e4fSDavid du Colombier 				serv = strdup(serv);
4619a747e4fSDavid du Colombier 			}
4629a747e4fSDavid du Colombier 			sys = strdup(buf);
4639a747e4fSDavid du Colombier 		}
4649a747e4fSDavid du Colombier 		close(fd);
4659a747e4fSDavid du Colombier 	}
4669a747e4fSDavid du Colombier 	if(serv == 0)
4679a747e4fSDavid du Colombier 		serv = strdup("unknown");
4689a747e4fSDavid du Colombier 	if(sys == 0)
4699a747e4fSDavid du Colombier 		sys = strdup("unknown");
4709a747e4fSDavid du Colombier 	*servp = serv;
4719a747e4fSDavid du Colombier 	*sysp = sys;
4729a747e4fSDavid du Colombier }
4739a747e4fSDavid du Colombier 
4749a747e4fSDavid du Colombier static Endpoints *
getendpoints(char * dir)4759a747e4fSDavid du Colombier getendpoints(char *dir)
4769a747e4fSDavid du Colombier {
4779a747e4fSDavid du Colombier 	Endpoints *ep;
4789a747e4fSDavid du Colombier 
4799a747e4fSDavid du Colombier 	ep = malloc(sizeof(*ep));
4809a747e4fSDavid du Colombier 	getendpoint(dir, "local", &ep->lsys, &ep->lserv);
4819a747e4fSDavid du Colombier 	getendpoint(dir, "remote", &ep->rsys, &ep->rserv);
4829a747e4fSDavid du Colombier 	return ep;
4839a747e4fSDavid du Colombier }
4849a747e4fSDavid du Colombier 
4859a747e4fSDavid du Colombier static void
freeendpoints(Endpoints * ep)4869a747e4fSDavid du Colombier freeendpoints(Endpoints *ep)
4879a747e4fSDavid du Colombier {
4889a747e4fSDavid du Colombier 	free(ep->lsys);
4899a747e4fSDavid du Colombier 	free(ep->rsys);
4909a747e4fSDavid du Colombier 	free(ep->lserv);
4919a747e4fSDavid du Colombier 	free(ep->rserv);
4929a747e4fSDavid du Colombier 	free(ep);
4939a747e4fSDavid du Colombier }
4949a747e4fSDavid du Colombier 
495*30ce352cSDavid du Colombier /* p must be a uchar* */
496*30ce352cSDavid du Colombier #define	U32GET(p)	(p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24)
497*30ce352cSDavid du Colombier #define	U32PUT(p,v)	(p)[0] = (v); (p)[1] = (v)>>8; \
498*30ce352cSDavid du Colombier 			(p)[2] = (v)>>16; (p)[3] = (v)>>24
499*30ce352cSDavid du Colombier 
500*30ce352cSDavid du Colombier static void
packhdr(Hdr * hdr,uchar * buf)501*30ce352cSDavid du Colombier packhdr(Hdr *hdr, uchar *buf)
502*30ce352cSDavid du Colombier {
503*30ce352cSDavid du Colombier 	uchar *p;
504*30ce352cSDavid du Colombier 
505*30ce352cSDavid du Colombier 	p = buf;
506*30ce352cSDavid du Colombier 	U32PUT(p, hdr->nb);
507*30ce352cSDavid du Colombier 	p += 4;
508*30ce352cSDavid du Colombier 	U32PUT(p, hdr->msg);
509*30ce352cSDavid du Colombier 	p += 4;
510*30ce352cSDavid du Colombier 	U32PUT(p, hdr->acked);
511*30ce352cSDavid du Colombier }
512*30ce352cSDavid du Colombier 
513*30ce352cSDavid du Colombier static void
unpackhdr(Hdr * hdr,uchar * buf)514*30ce352cSDavid du Colombier unpackhdr(Hdr *hdr, uchar *buf)
515*30ce352cSDavid du Colombier {
516*30ce352cSDavid du Colombier 	uchar *p;
517*30ce352cSDavid du Colombier 
518*30ce352cSDavid du Colombier 	p = buf;
519*30ce352cSDavid du Colombier 	hdr->nb = U32GET(p);
520*30ce352cSDavid du Colombier 	p += 4;
521*30ce352cSDavid du Colombier 	hdr->msg = U32GET(p);
522*30ce352cSDavid du Colombier 	p += 4;
523*30ce352cSDavid du Colombier 	hdr->acked = U32GET(p);
524*30ce352cSDavid du Colombier }
525