7 #define NS(x) ((vlong)x)
8 #define US(x) (NS(x) * 1000LL)
9 #define MS(x) (US(x) * 1000LL)
10 #define S(x) (MS(x) * 1000LL)
20 Timer = 0, // Alt channels.
22 Maxto = 24 * 3600, // A full day to reconnect.
25 typedef struct Endpoints Endpoints;
34 ulong nb; // Number of data bytes in this message
35 ulong msg; // Message number
36 ulong acked; // Number of messages acked
39 typedef struct t_Buf {
44 static char *progname;
45 static Channel *unsent;
46 static Channel *unacked;
47 static Channel *empty;
53 static char *dialstring;
54 static int maxto = Maxto;
55 static char *Logname = LOGNAME;
60 { nil, nil, CHANRCV }, // timer
61 { nil, nil, CHANRCV }, // unsent
62 { nil, nil, CHANEND },
65 static void fromnet(void*);
66 static void fromclient(void*);
67 static void reconnect(void);
68 static void synchronize(void);
69 static int sendcommand(ulong, ulong);
70 static void showmsg(int, char *, Buf *);
71 static int writen(int, uchar *, int);
72 static int getport(char *);
73 static void dmessage(int, char *, ...);
74 static void timerproc(void *);
75 static Endpoints *getendpoints(char *);
76 static void freeendpoints(Endpoints *);
81 fprint(2, "Usage: %s [-cd] [-m maxto] dialstring|netdir\n", progname);
86 catch(void *, char *s)
88 if (!strcmp(s, "alarm")) {
89 syslog(0, Logname, "Timed out while waiting for client on %s, exiting...",
97 threadmain(int argc, char **argv)
113 maxto = (int)strtol(EARGF(usage()), (char **)nil, 0);
126 if ((p = strstr(devdir, "/local")) != nil)
130 dialstring = argv[0];
133 int fd = open("#c/cons", OWRITE|OCEXEC);
137 fmtinstall('F', fcallfmt);
141 unsent = chancreate(sizeof(Buf *), Nbuf);
142 unacked = chancreate(sizeof(Buf *), Nbuf);
143 empty = chancreate(sizeof(Buf *), Nbuf);
144 timer = chancreate(sizeof(uchar *), 1);
146 for (i = 0; i != Nbuf; i++) {
147 Buf *b = malloc(sizeof(Buf));
153 if (proccreate(fromnet, nil, Stacksize) < 0)
154 sysfatal("%s; Cannot start fromnet; %r", progname);
156 reconnect(); // Set up the initial connection.
159 if (proccreate(fromclient, nil, Stacksize) < 0)
160 sysfatal("%s; Cannot start fromclient; %r", progname);
162 if (proccreate(timerproc, timer, Stacksize) < 0)
163 sysfatal("%s; Cannot start timerproc; %r", progname);
166 a[Unsent].c = unsent;
169 synctime = nsec() + Synctime;
176 // Wait for the netreader to die.
178 dmessage(1, "main; waiting for netreader to die\n");
182 // the reader died; reestablish the world.
189 delta = (synctime - nsec()) / MS(1);
198 if (writen(netfd, (uchar *)&hdr, sizeof(Hdr)) < 0) {
199 dmessage(2, "main; writen failed; %r\n");
203 synctime = nsec() + Synctime;
204 assert(synctime > now);
214 b->hdr.acked = inmsg;
216 if (writen(netfd, (uchar *)&b->hdr, sizeof(Hdr)) < 0) {
217 dmessage(2, "main; writen failed; %r\n");
221 if (writen(netfd, b->buf, b->hdr.nb) < 0) {
222 dmessage(2, "main; writen failed; %r\n");
231 syslog(0, Logname, "exiting...");
245 if ((int)(b->hdr.nb = read(0, b->buf, Bufsize)) <= 0) {
246 if ((int)b->hdr.nb < 0)
247 dmessage(2, "fromclient; Cannot read 9P message; %r\n");
249 dmessage(2, "fromclient; Client terminated\n");
252 b->hdr.msg = outmsg++;
254 showmsg(1, "fromclient", b);
265 static int lastacked;
268 b = (Buf *)malloc(sizeof(Buf));
275 dmessage(1, "fromnet; waiting for connection... (inmsg %d)\n",
281 if ((len = readn(netfd, &b->hdr, sizeof(Hdr))) <= 0) {
283 dmessage(1, "fromnet; (hdr) network failure; %r\n");
285 dmessage(1, "fromnet; (hdr) network closed\n");
290 dmessage(2, "fromnet: Got message, size %d, nb %d, msg %d\n", len,
291 b->hdr.nb, b->hdr.msg);
293 if (b->hdr.nb == 0) {
294 if ((long)b->hdr.msg >= 0) {
295 dmessage(1, "fromnet; network closed\n");
301 if ((len = readn(netfd, b->buf, b->hdr.nb)) <= 0 || len != b->hdr.nb) {
303 dmessage(1, "fromnet; network closed\n");
305 dmessage(1, "fromnet; network failure; %r\n");
311 if (b->hdr.msg < inmsg) {
312 dmessage(1, "fromnet; skipping message %d, currently at %d\n",
317 // Process the acked list.
318 acked = b->hdr.acked - lastacked;
319 for (i = 0; i != acked; i++) {
323 if (rb->hdr.msg != lastacked + i) {
324 dmessage(1, "rb %p, msg %d, lastacked %d, i %d\n",
325 rb, rb? rb->hdr.msg: -2, lastacked, i);
331 lastacked = b->hdr.acked;
335 showmsg(1, "fromnet", b);
337 if (writen(1, b->buf, len) < 0)
338 sysfatal("fromnet; cannot write to client; %r");
350 syslog(0, Logname, "dialing %s", dialstring);
351 while ((fd = dial(dialstring, nil, nil, nil)) < 0) {
355 errstr(err, sizeof err);
356 if (strstr(err, "connection refused")) {
357 dmessage(1, "reconnect; server died...\n");
358 threadexitsall("server died...");
360 dmessage(1, "reconnect: dialed %s; %s\n", dialstring, err);
363 syslog(0, Logname, "reconnected to %s", dialstring);
368 syslog(0, Logname, "waiting for connection on %s", devdir);
370 if ((lcfd = listen(devdir, ldir)) < 0)
371 sysfatal("reconnect; cannot listen; %r");
373 if ((fd = accept(lcfd, ldir)) < 0)
374 sysfatal("reconnect; cannot accept; %r");
378 ep = getendpoints(ldir);
379 dmessage(1, "rsys '%s'\n", ep->rsys);
380 syslog(0, Logname, "connected from %s", ep->rsys);
384 netfd = fd; // Wakes up the netreader.
393 // Ignore network errors here. If we fail during
394 // synchronization, the next alarm will pick up
397 tmp = chancreate(sizeof(Buf *), Nbuf);
398 while ((b = nbrecvp(unacked)) != nil) {
399 writen(netfd, (uchar *)b, sizeof(Hdr) + b->hdr.nb);
407 showmsg(int level, char *s, Buf *b)
410 dmessage(level, "%s; b == nil\n", s);
415 "%s; (len %d) %X %X %X %X %X %X %X %X %X (%p)\n", s,
417 b->buf[0], b->buf[1], b->buf[2],
418 b->buf[3], b->buf[4], b->buf[5],
419 b->buf[6], b->buf[7], b->buf[8], b);
423 writen(int fd, uchar *buf, int nb)
433 if ((n = write(fd, buf, nb)) < 0) {
434 dmessage(1, "writen; Write failed; %r\n");
437 dmessage(2, "writen: wrote %d bytes\n", n);
450 sleep((Synctime / MS(1)) >> 1);
451 sendp(timer, "timer");
456 dmessage(int level, char *fmt, ...)
464 vfprint(2, fmt, arg);
469 getendpoint(char *dir, char *file, char **sysp, char **servp)
477 snprint(buf, sizeof buf, "%s/%s", dir, file);
478 fd = open(buf, OREAD);
480 n = read(fd, buf, sizeof(buf)-1);
483 serv = strchr(buf, '!');
493 serv = strdup("unknown");
495 sys = strdup("unknown");
501 getendpoints(char *dir)
505 ep = malloc(sizeof(*ep));
506 getendpoint(dir, "local", &ep->lsys, &ep->lserv);
507 getendpoint(dir, "remote", &ep->rsys, &ep->rserv);
512 freeendpoints(Endpoints *ep)