|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "io.h"
7: #include "../port/error.h"
8:
9: #define DPRINT if(0) print
10:
11: #define NOW (MACHP(0)->ticks)
12:
13: typedef struct Dkmsg Dkmsg;
14: typedef struct Line Line;
15: typedef struct Dk Dk;
16:
17: enum {
18: Maxdk = 4,
19: };
20:
21: /*
22: * types of possible dkcalls
23: */
24: enum {
25: Dial,
26: Announce,
27: Redial
28: };
29:
30: /*
31: * format of messages to/from the datakit controller on the common
32: * signalling line
33: */
34: struct Dkmsg {
35: uchar type;
36: uchar srv;
37: uchar param0l;
38: uchar param0h;
39: uchar param1l;
40: uchar param1h;
41: uchar param2l;
42: uchar param2h;
43: uchar param3l;
44: uchar param3h;
45: uchar param4l;
46: uchar param4h;
47: };
48:
49: /*
50: * message codes (T_xxx == dialin.type, D_xxx == dialin.srv)
51: */
52: #define T_SRV 1 /* service request */
53: #define D_SERV 1 /* (host to dkmux) announce a service */
54: #define D_DIAL 2 /* (host to dkmux) connect to a service */
55: #define D_XINIT 7 /* (dkmux to host) line has been spliced */
56: #define T_REPLY 2 /* reply to T_SRV/D_SERV or T_SRV/D_DIAL */
57: #define D_OK 1 /* not used */
58: #define D_OPEN 2 /* (dkmux to host) connection established */
59: #define D_FAIL 3 /* (dkmux to host) connection failed */
60: #define T_CHG 3 /* change the status of a connection */
61: #define D_CLOSE 1 /* close the connection */
62: #define D_ISCLOSED 2 /* (dkmux to host) confirm a close */
63: #define D_CLOSEALL 3 /* (dkmux to host) close all connections */
64: #define D_REDIAL 6 /* (host to dkmux) redial a call */
65: #define T_ALIVE 4 /* (host to dkmux) keep alive message */
66: #define D_CONTINUE 0 /* host has not died since last msg */
67: #define D_RESTART 1 /* host has restarted */
68: #define D_MAXCHAN 2 /* request maximum line number */
69: #define T_RESTART 8 /* (dkmux to host) datakit restarted */
70:
71: /*
72: * macros for cracking/forming the window negotiation parameter
73: */
74: #define MIN(x,y) (x < y ? x : y)
75: #define W_WINDOW(o,d,t) ((o<<8) | (d<<4) | t | 0100000)
76: #define W_VALID(x) ((x) & 0100000)
77: #define W_ORIG(x) (((x)>>8) & 017)
78: #define W_DEST(x) (((x)>>4) & 017)
79: #define W_TRAF(x) ((x) & 017)
80: #define W_DESTMAX(x,y) (W_WINDOW(W_ORIG(x),MIN(W_DEST(x),y),W_TRAF(x)))
81: #define W_LIMIT(x,y) (W_WINDOW(MIN(W_ORIG(x),y),MIN(W_DEST(x),y),W_TRAF(x)))
82: #define W_VALUE(x) (1<<((x)+4))
83:
84: struct Line {
85: QLock;
86: Netprot; /* stat info */
87: int lineno;
88: Rendez r; /* wait here for dial */
89: int state; /* dial state */
90: int err; /* dialing error (if non zero) */
91: int window; /* negotiated window */
92: int timestamp; /* timestamp of last call received on this line */
93: int calltolive; /* multiple of 15 seconds for dialing state to last */
94: Queue *rq;
95: char addr[64];
96: char raddr[64];
97: char ruser[32];
98: Dk *dp; /* interface contianing this line */
99: };
100:
101: /*
102: * a dkmux dk. one exists for every stream that a
103: * dkmux line discipline is pushed onto.
104: */
105: struct Dk
106: {
107: QLock netlock;
108: Network net; /* stat info */
109: Line **linep; /* array of line structures */
110:
111: QLock csclock;
112: Chan *csc;
113:
114: char name[64]; /* dk name */
115: Queue *wq; /* dk output queue */
116: int ncsc; /* csc line number */
117: int lines; /* number of lines */
118: int restart;
119: int urpwindow;
120: Rendez timer;
121: int closeall; /* set when we receive a closeall message */
122: Rendez closeallr; /* wait here for a closeall */
123: };
124: Lock dklock;
125: Dk *dk[Maxdk];
126:
127: /*
128: * conversation states (for Line.state)
129: */
130: typedef enum {
131: Lclosed=0,
132: Lopened, /* opened but no call out */
133: Lconnected, /* opened and a call set up on htis line */
134: Lrclose, /* remote end has closed down */
135: Llclose, /* local end has closed down */
136: Ldialing, /* dialing a new call */
137: Llistening, /* this line listening for calls */
138: Lackwait, /* incoming call waiting for ack/nak */
139: Laccepting, /* waiting for user to accept or reject the call */
140: } Lstate;
141: char *dkstate[] =
142: {
143: [Lclosed] "Closed",
144: [Lopened] "Opened",
145: [Lconnected] "Established",
146: [Lrclose] "Rclose",
147: [Llclose] "Lclose",
148: [Ldialing] "Dialing",
149: [Llistening] "Listen",
150: [Lackwait] "Ackwait",
151: [Laccepting] "Accepting",
152: };
153:
154: /*
155: * map datakit error to errno
156: */
157: enum {
158: DKok,
159: DKbusy,
160: DKnetotl,
161: DKdestotl,
162: DKbadnet,
163: DKnetbusy,
164: DKinuse,
165: DKreject,
166: };
167: char* dkerr[]={
168: [DKok] "",
169: [DKbusy] "devdk: destination busy",
170: [DKnetotl] "devdk: network not answering",
171: [DKdestotl] "devdk: destination not answering",
172: [DKbadnet] "devdk: unknown address",
173: [DKnetbusy] "devdk: network busy",
174: [DKinuse] "devdk: service in use",
175: [DKreject] "devdk: connection refused",
176: };
177: #define DKERRS sizeof(dkerr)/sizeof(char*)
178:
179: /*
180: * imported
181: */
182: extern Qinfo urpinfo;
183:
184: /*
185: * predeclared
186: */
187: Chan* dkattach(char*);
188: static void dkmuxconfig(Queue*, Block*);
189: static Chan* dkopenline(Dk*, int);
190: static Chan* dkopencsc(Dk*);
191: static int dkmesg(Chan*, int, int, int, int);
192: static void dkcsckproc(void*);
193: static void dkanswer(Chan*, int, int);
194: static void dkwindow(Chan*);
195: static void dkcall(int, Chan*, char*, char*, char*);
196: static void dktimer(void*);
197: static void dkchgmesg(Chan*, Dk*, Dkmsg*, int);
198: static void dkreplymesg(Dk*, Dkmsg*, int);
199: Chan* dkopen(Chan*, int);
200: static void dkhangup(Line*);
201:
202: /*
203: * for standard network interface (net.c)
204: */
205: static int dkcloneline(Chan*);
206: static int dklisten(Chan*);
207: static void dkfilladdr(Chan*, char*, int);
208: static void dkfillraddr(Chan*, char*, int);
209: static void dkfillruser(Chan*, char*, int);
210: static void dkfillstatus(Chan*, char*, int);
211:
212: extern Qinfo dkinfo;
213:
214: /*
215: * the datakit multiplexor stream module definition
216: */
217: static Streamopen dkmuxopen;
218: static Streamput dkmuxoput;
219: static Streamput dkmuxiput;
220: Qinfo dkmuxinfo =
221: {
222: dkmuxiput,
223: dkmuxoput,
224: dkmuxopen,
225: 0,
226: "dkmux"
227: };
228:
229: /*
230: * allocate a line if it doesn't exist
231: */
232: static Line*
233: linealloc(Dk *dp, int lineno, int dolock)
234: {
235: Line *lp;
236:
237: if(dolock)
238: qlock(&dp->netlock);
239: if(lineno > dp->lines)
240: panic("linealloc");
241: lp = dp->linep[lineno];
242: if(lp == 0){
243: lp = smalloc(sizeof(Line));
244: lp->lineno = lineno;
245: netadd(&dp->net, lp, lineno);
246: dp->linep[lineno] = lp;
247: }
248: if(dolock)
249: qunlock(&dp->netlock);
250: return lp;
251: }
252:
253: /*
254: * a new dkmux. hold the stream in place so it can never be closed down.
255: */
256: static void
257: dkmuxopen(Queue *q, Stream *s)
258: {
259: RD(q)->ptr = 0;
260: WR(q)->ptr = 0;
261:
262: naildownstream(s);
263: }
264:
265: /*
266: * handle configuration
267: */
268: static void
269: dkmuxoput(Queue *q, Block *bp)
270: {
271: if(bp->type != M_DATA){
272: if(streamparse("config", bp))
273: dkmuxconfig(q, bp);
274: else
275: PUTNEXT(q, bp);
276: return;
277: }
278: PUTNEXT(q, bp);
279: }
280:
281: /*
282: * gather a message and send it up the appropriate stream
283: *
284: * The first two bytes of each message contains the channel
285: * number, low order byte first.
286: *
287: * Simplifying assumption: one put == one message && the channel number
288: * is in the first block. If this isn't true, demultiplexing will not
289: * work.
290: */
291: static void
292: dkmuxiput(Queue *q, Block *bp)
293: {
294: Dk *dp;
295: Line *lp;
296: int line;
297:
298: /*
299: * not configured yet
300: */
301: if(q->other->ptr == 0){
302: freeb(bp);
303: return;
304: }
305:
306: dp = (Dk *)q->ptr;
307: if(bp->type != M_DATA){
308: PUTNEXT(q, bp);
309: return;
310: }
311:
312: line = bp->rptr[0] | (bp->rptr[1]<<8);
313: bp->rptr += 2;
314: if(line<0 || line>=dp->lines){
315: DPRINT("dkmuxiput bad line %d\n", line);
316: freeb(bp);
317: return;
318: }
319:
320: lp = linealloc(dp, line, 1);
321: if(lp && canqlock(lp)){
322: if(lp->rq)
323: PUTNEXT(lp->rq, bp);
324: else{
325: DPRINT("dkmuxiput unopened line %d\n", line);
326: freeb(bp);
327: }
328: qunlock(lp);
329: } else {
330: DPRINT("dkmuxiput unopened line %d\n", line);
331: freeb(bp);
332: }
333: }
334:
335: /*
336: * the datakit line stream module definition
337: */
338: static Streamopen dkstopen;
339: static Streamclose dkstclose;
340: static Streamput dkoput, dkiput;
341: Qinfo dkinfo =
342: {
343: dkiput,
344: dkoput,
345: dkstopen,
346: dkstclose,
347: "dk"
348: };
349:
350: /*
351: * open and save a pointer to the conversation
352: */
353: static void
354: dkstopen(Queue *q, Stream *s)
355: {
356: Dk *dp;
357: Line *lp;
358:
359: dp = dk[s->dev];
360: q->other->ptr = q->ptr = lp = dp->linep[s->id];
361: lp->dp = dp;
362: lp->rq = q;
363: if(lp->state==Lclosed)
364: lp->state = Lopened;
365: }
366:
367: /*
368: * close down a datakit conversation
369: */
370: static void
371: dkstclose(Queue *q)
372: {
373: Dk *dp;
374: Line *lp;
375: Chan *c;
376:
377: lp = (Line *)q->ptr;
378: dp = lp->dp;
379:
380: /*
381: * if we never got going, we're done
382: */
383: if(lp->rq == 0){
384: lp->state = Lclosed;
385: return;
386: }
387:
388: /*
389: * these states don't need the datakit
390: */
391: switch(lp->state){
392: case Lclosed:
393: case Llclose:
394: case Lopened:
395: lp->state = Lclosed;
396: goto out;
397: }
398:
399: c = 0;
400: if(waserror()){
401: lp->state = Lclosed;
402: if(c)
403: close(c);
404: goto out;
405: }
406: c = dkopencsc(dp);
407:
408: /*
409: * shake hands with dk
410: */
411: switch(lp->state){
412: case Lrclose:
413: dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
414: lp->state = Lclosed;
415: break;
416:
417: case Lackwait:
418: dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
419: lp->state = Llclose;
420: break;
421:
422: case Llistening:
423: dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
424: lp->state = Llclose;
425: break;
426:
427: case Lconnected:
428: dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
429: lp->state = Llclose;
430: break;
431: }
432: poperror();
433: close(c);
434:
435: out:
436: qlock(lp);
437: lp->rq = 0;
438: qunlock(lp);
439:
440: netdisown(lp);
441: lp->window = 0;
442: }
443:
444: /*
445: * this is only called by hangup
446: */
447: static void
448: dkiput(Queue *q, Block *bp)
449: {
450: PUTNEXT(q, bp);
451: }
452:
453: /*
454: * we assume that each put is a message.
455: *
456: * add a 2 byte channel number to the start of each message,
457: * low order byte first. Make sure the first block contains
458: * both the 2 channel bytes and the control byte.
459: */
460: static void
461: dkoput(Queue *q, Block *bp)
462: {
463: Line *lp;
464: Dk *dp;
465: int line;
466:
467: if(bp->type != M_DATA){
468: freeb(bp);
469: error(Ebadarg);
470: }
471:
472: lp = (Line *)q->ptr;
473: dp = lp->dp;
474: line = lp->lineno;
475:
476: bp = padb(bp, 2);
477: bp->rptr[0] = line;
478: bp->rptr[1] = line>>8;
479:
480: FLOWCTL(dp->wq, bp);
481: }
482:
483: /*
484: * configure a datakit multiplexor. this takes 5 arguments separated
485: * by spaces:
486: * the line number of the common signalling channel (must be > 0)
487: * the number of lines in the device (optional)
488: * the word `restart' or `norestart' (optional/default==restart)
489: * the name of the dk (default==dk)
490: * the urp window size (default==2048)
491: *
492: * we can configure only once
493: */
494: static int
495: haveca(void *arg)
496: {
497: Dk *dp;
498:
499: dp = arg;
500: return dp->closeall;
501: }
502: static void
503: dkmuxconfig(Queue *q, Block *bp)
504: {
505: Dk *dp;
506: char *fields[5];
507: int n;
508: char buf[64];
509: char name[NAMELEN];
510: int lines;
511: int ncsc;
512: int restart;
513: int window;
514:
515: if(WR(q)->ptr){
516: freeb(bp);
517: error(Egreg);
518: }
519:
520: /*
521: * defaults
522: */
523: ncsc = 1;
524: restart = 1;
525: lines = 16;
526: window = 2048;
527: strcpy(name, "dk");
528:
529: /*
530: * parse
531: */
532: n = getfields((char *)bp->rptr, fields, 5, " ");
533: switch(n){
534: case 5:
535: window = strtoul(fields[4], 0, 0);
536: if(window < 16)
537: window = 1<<(window+4);
538: case 4:
539: strncpy(name, fields[3], sizeof(name));
540: name[sizeof(name)-1] = 0;
541: case 3:
542: if(strcmp(fields[2], "restart")!=0)
543: restart = 0;
544: case 2:
545: lines = strtoul(fields[1], 0, 0);
546: case 1:
547: ncsc = strtoul(fields[0], 0, 0);
548: break;
549: default:
550: freeb(bp);
551: error(Ebadarg);
552: }
553: freeb(bp);
554: if(ncsc <= 0 || lines <= ncsc)
555: error(Ebadarg);
556:
557: /*
558: * find a free dk slot. it name is already configured
559: * or no slots are left, error.
560: */
561: lock(&dklock);
562: if(waserror()){
563: unlock(&dklock);
564: nexterror();
565: }
566: for(n = 0; n < Maxdk; n++){
567: dp = dk[n];
568: if(dp == 0)
569: break;
570: if(strcmp(name, dp->name) == 0)
571: error(Einuse);
572: }
573: if(n == Maxdk)
574: error(Enoifc);
575:
576: /*
577: * allocate both a dk structure and an array of pointers to line
578: * structures
579: */
580: dp = smalloc(sizeof(Dk));
581: dp->ncsc = ncsc;
582: dp->lines = lines;
583: dp->linep = smalloc(sizeof(Line*) * dp->lines);
584: strcpy(dp->name, name);
585: dp->net.name = dp->name;
586: dp->net.nconv = dp->lines;
587: dp->net.devp = &dkinfo;
588: dp->net.protop = &urpinfo;
589: dp->net.listen = dklisten;
590: dp->net.clone = dkcloneline;
591: dp->net.ninfo = 5;
592: dp->net.info[0].name = "local";
593: dp->net.info[0].fill = dkfilladdr;
594: dp->net.info[1].name = "remote";
595: dp->net.info[1].fill = dkfillraddr;
596: dp->net.info[2].name = "ruser";
597: dp->net.info[2].fill = dkfillruser;
598: dp->net.info[3].name = "urpstats";
599: dp->net.info[3].fill = urpfillstats;
600: dp->net.info[4].name = "status";
601: dp->net.info[4].fill = dkfillstatus;
602: dp->restart = restart;
603: dp->urpwindow = window;
604: dp->wq = WR(q);
605: q->ptr = q->other->ptr = dp;
606: dk[n] = dp;
607: unlock(&dklock);
608: poperror();
609:
610: /*
611: * open csc here so that boot, dktimer, and dkcsckproc aren't
612: * all fighting for it at once.
613: */
614: dkopencsc(dp);
615:
616: /*
617: * start a process to listen to csc messages
618: */
619: sprint(buf, "csc.%s.%d", dp->name, dp->ncsc);
620: kproc(buf, dkcsckproc, dp);
621:
622: /*
623: * tell datakit we've rebooted. It should close all channels.
624: * do this here to get it done before trying to open a channel.
625: */
626: if(dp->restart) {
627: DPRINT("dktimer: restart %s\n", dp->name);
628: dp->closeall = 0;
629: dkmesg(dp->csc, T_ALIVE, D_RESTART, 0, 0);
630: }
631: tsleep(&dp->closeallr, haveca, dp, 15000);
632:
633: /*
634: * start a keepalive process
635: */
636: sprint(buf, "timer.%s.%d", dp->name, dp->ncsc);
637: kproc(buf, dktimer, dp);
638: }
639:
640: void
641: dkreset(void)
642: {
643: newqinfo(&dkmuxinfo);
644: }
645:
646: void
647: dkinit(void)
648: {
649: }
650:
651: Chan*
652: dkattach(char *spec)
653: {
654: Chan *c;
655: Dk *dp;
656: int dev;
657:
658: /*
659: * find a multiplexor with the same name (default dk)
660: */
661: if(*spec == 0)
662: spec = "dk";
663: for(dev = 0; dev < Maxdk; dev++){
664: dp = dk[dev];
665: if(dp && strcmp(dp->name, spec) == 0)
666: break;
667: }
668: if(dev == Maxdk)
669: error(Enoifc);
670:
671: /*
672: * return the new channel
673: */
674: c = devattach('k', spec);
675: c->dev = dev;
676: return c;
677: }
678:
679: Chan*
680: dkclone(Chan *c, Chan *nc)
681: {
682: return devclone(c, nc);
683: }
684:
685: int
686: dkwalk(Chan *c, char *name)
687: {
688: return netwalk(c, name, &dk[c->dev]->net);
689: }
690:
691: void
692: dkstat(Chan *c, char *dp)
693: {
694: netstat(c, dp, &dk[c->dev]->net);
695: }
696:
697: Chan*
698: dkopen(Chan *c, int omode)
699: {
700: Dk *dp;
701:
702: dp = dk[c->dev];
703: linealloc(dp, STREAMID(c->qid.path), 1);
704: return netopen(c, omode, &dp->net);
705: }
706:
707: void
708: dkcreate(Chan *c, char *name, int omode, ulong perm)
709: {
710: USED(c);
711: USED(name);
712: USED(omode);
713: USED(perm);
714: error(Eperm);
715: }
716:
717: void
718: dkclose(Chan *c)
719: {
720: if(c->stream)
721: streamclose(c);
722: }
723:
724: long
725: dkread(Chan *c, void *a, long n, ulong offset)
726: {
727: return netread(c, a, n, offset, &dk[c->dev]->net);
728: }
729:
730: long
731: dkwrite(Chan *c, void *a, long n, ulong offset)
732: {
733: int t;
734: char buf[256];
735: char *field[5];
736: int m;
737:
738: USED(offset);
739: t = STREAMTYPE(c->qid.path);
740:
741: /*
742: * get data dispatched as quickly as possible
743: */
744: if(t == Sdataqid)
745: return streamwrite(c, a, n, 0);
746:
747: /*
748: * easier to do here than in dkoput
749: */
750: if(t == Sctlqid){
751: if(n > sizeof buf - 1)
752: n = sizeof buf - 1;
753: strncpy(buf, a, n);
754: buf[n] = '\0';
755: m = getfields(buf, field, 5, " ");
756: if(strncmp(field[0], "connect", 7)==0){
757: if(m < 2)
758: error(Ebadarg);
759: dkcall(Dial, c, field[1], 0, 0);
760: } else if(strncmp(field[0], "announce", 8)==0){
761: if(m < 2)
762: error(Ebadarg);
763: dkcall(Announce, c, field[1], 0, 0);
764: } else if(strncmp(field[0], "redial", 6)==0){
765: if(m < 4)
766: error(Ebadarg);
767: dkcall(Redial, c, field[1], field[2], field[3]);
768: } else if(strncmp(field[0], "accept", 6)==0){
769: if(m < 2)
770: error(Ebadarg);
771: dkanswer(c, strtoul(field[1], 0, 0), 0);
772: } else if(strncmp(field[0], "reject", 6)==0){
773: if(m < 3)
774: error(Ebadarg);
775: for(m = 0; m < DKERRS-1; m++)
776: if(strcmp(field[2], dkerr[m]) == 0)
777: break;
778: dkanswer(c, strtoul(field[1], 0, 0), m);
779: } else
780: return streamwrite(c, a, n, 0);
781: return n;
782: }
783:
784: error(Eperm);
785: return -1; /* never reached */
786: }
787:
788: void
789: dkremove(Chan *c)
790: {
791: USED(c);
792: error(Eperm);
793: }
794:
795: void
796: dkwstat(Chan *c, char *dp)
797: {
798: netwstat(c, dp, &dk[c->dev]->net);
799: }
800:
801: /*
802: * return the number of an unused line (reserve it)
803: */
804: static int
805: dkcloneline(Chan *c)
806: {
807: Line *lp;
808: Dk *dp;
809: int line;
810:
811: dp = dk[c->dev];
812: /*
813: * get an unused device and open its control file
814: */
815: qlock(&dp->netlock);
816: for(line = dp->ncsc+1; line < dp->lines; line++){
817: lp = dp->linep[line];
818: if(lp == 0 || lp->state == Lclosed){
819: lp = linealloc(dp, line, 0);
820: lp->state = Lopened;
821:
822: /* current user becomes owner */
823: netown(lp, u->p->user, 0);
824:
825: qunlock(&dp->netlock);
826: return lp->lineno;
827: }
828: }
829: qunlock(&dp->netlock);
830: error(Enodev);
831: return -1; /* never reached */
832: }
833:
834: static Chan*
835: dkopenline(Dk *dp, int line)
836: {
837: Chan *c;
838:
839: c = 0;
840: if(waserror()){
841: if(c)
842: close(c);
843: nexterror();
844: }
845: c = dkattach(dp->name);
846: c->qid.path = STREAMQID(line, Sdataqid);
847: dkopen(c, ORDWR);
848: poperror();
849:
850: return c;
851: }
852:
853: /*
854: * open the common signalling channel (dp->csc's reference count never goes below 1)
855: */
856: static Chan*
857: dkopencsc(Dk *dp)
858: {
859: qlock(&dp->csclock);
860: if(dp->csc == 0)
861: dp->csc = dkopenline(dp, dp->ncsc);
862: incref(dp->csc);
863: qunlock(&dp->csclock);
864: return dp->csc;
865: }
866:
867: /*
868: * return the contents of the info files
869: */
870: void
871: dkfilladdr(Chan *c, char *buf, int len)
872: {
873: if(len < sizeof(dk[0]->linep[0]->addr)+2)
874: error(Ebadarg);
875: sprint(buf, "%s\n", dk[c->dev]->linep[STREAMID(c->qid.path)]->addr);
876: }
877: void
878: dkfillraddr(Chan *c, char *buf, int len)
879: {
880: if(len < sizeof(dk[0]->linep[0]->raddr)+2)
881: error(Ebadarg);
882: sprint(buf, "%s\n", dk[c->dev]->linep[STREAMID(c->qid.path)]->raddr);
883: }
884: void
885: dkfillruser(Chan *c, char *buf, int len)
886: {
887: if(len < sizeof(dk[0]->linep[0]->ruser)+2)
888: error(Ebadarg);
889: sprint(buf, "%s\n", dk[c->dev]->linep[STREAMID(c->qid.path)]->ruser);
890: }
891: void
892: dkfillstatus(Chan *c, char *buf, int len)
893: {
894: Dk *dp;
895: Line *lp;
896: int line;
897: char lbuf[65];
898:
899: line = STREAMID(c->qid.path);
900: dp = dk[c->dev];
901: lp = linealloc(dp, line, 1);
902: sprint(lbuf, "%s/%d %d %s window %d\n", dp->name, line,
903: lp->state != Lclosed ? 1 : 0, dkstate[lp->state], lp->window);
904: strncpy(buf, lbuf, len);
905: }
906:
907: /*
908: * send a message to the datakit on the common signaling line
909: */
910: static int
911: dkmesg(Chan *c, int type, int srv, int p0, int p1)
912: {
913: Dkmsg d;
914:
915: if(waserror()){
916: print("dkmesg: error\n");
917: return -1;
918: }
919: d.type = type;
920: d.srv = srv;
921: d.param0l = p0;
922: d.param0h = p0>>8;
923: d.param1l = p1;
924: d.param1h = p1>>8;
925: d.param2l = 0;
926: d.param2h = 0;
927: d.param3l = 0;
928: d.param3h = 0;
929: d.param4l = 0;
930: d.param4h = 0;
931: streamwrite(c, (char *)&d, sizeof(Dkmsg), 1);
932: poperror();
933: return 0;
934: }
935:
936: /*
937: * call out on a datakit
938: */
939: static int
940: calldone(void *a)
941: {
942: Line *lp;
943:
944: lp = (Line *)a;
945: return lp->state != Ldialing;
946: }
947: static void
948: dkcall(int type, Chan *c, char *addr, char *nuser, char *machine)
949: {
950: char dialstr[66];
951: int line, win;
952: char dialtone;
953: int t_val, d_val;
954: Dk *dp;
955: Line *lp;
956: Chan *dc;
957: Chan *csc;
958: char *bang, *dot;
959:
960: line = STREAMID(c->qid.path);
961: dp = dk[c->dev];
962: lp = linealloc(dp, line, 1);
963:
964: /*
965: * only dial on virgin lines
966: */
967: if(lp->state != Lopened)
968: error(Ebadarg);
969:
970: DPRINT("dkcall(line=%d, type=%d, dest=%s)\n", line, type, addr);
971:
972: /*
973: * build dial string
974: * - guard against new lines
975: * - change ! into . to delimit service
976: */
977: if(strchr(addr, '\n'))
978: error(Ebadarg);
979: if(strlen(addr)+strlen(u->p->user)+2 >= sizeof(dialstr))
980: error(Ebadarg);
981: strcpy(dialstr, addr);
982: bang = strchr(dialstr, '!');
983: if(bang){
984: dot = strchr(dialstr, '.');
985: if(dot==0 || dot > bang)
986: *bang = '.';
987: }
988: switch(type){
989: case Dial:
990: t_val = T_SRV;
991: d_val = D_DIAL;
992: strcat(dialstr, "\n");
993: strcat(dialstr, u->p->user);
994: strcat(dialstr, "\n");
995: break;
996: case Announce:
997: t_val = T_SRV;
998: d_val = D_SERV;
999: break;
1000: case Redial:
1001: t_val = T_CHG;
1002: d_val = D_REDIAL;
1003: strcat(dialstr, "\n");
1004: strcat(dialstr, nuser);
1005: strcat(dialstr, "\n");
1006: strcat(dialstr, machine);
1007: strcat(dialstr, "\n");
1008: break;
1009: default:
1010: t_val = 0;
1011: d_val = 0;
1012: panic("bad dial type");
1013: }
1014:
1015: /*
1016: * open the data file
1017: */
1018: dc = dkopenline(dp, line);
1019: if(waserror()){
1020: close(dc);
1021: nexterror();
1022: }
1023: lp->calltolive = 4;
1024: lp->state = Ldialing;
1025:
1026: /*
1027: * tell the controller we want to make a call
1028: */
1029: DPRINT("dialout\n");
1030: csc = dkopencsc(dp);
1031: if(waserror()){
1032: close(csc);
1033: nexterror();
1034: }
1035: for(win = 0; ; win++)
1036: if(W_VALUE(win) >= dp->urpwindow || win == 15)
1037: break;
1038: dkmesg(csc, t_val, d_val, line, W_WINDOW(win, win, 2));
1039: poperror();
1040: close(csc);
1041:
1042: /*
1043: * if redial, wait for a dial tone (otherwise we might send
1044: * the dialstr to the previous other end and not the controller)
1045: */
1046: if(type==Redial){
1047: if(streamread(dc, &dialtone, 1L) != 1L){
1048: lp->state = Lconnected;
1049: error(Ebadarg);
1050: }
1051: }
1052:
1053: /*
1054: * make the call
1055: */
1056: DPRINT("dialstr %s\n", dialstr);
1057: streamwrite(dc, dialstr, (long)strlen(dialstr), 1);
1058: close(dc);
1059: poperror();
1060:
1061: /*
1062: * redial's never get a reply, assume it worked
1063: */
1064: if(type == Redial) {
1065: lp->state = Lconnected;
1066: return;
1067: }
1068:
1069: /*
1070: * wait for a reply
1071: */
1072: DPRINT("reply wait\n");
1073: sleep(&lp->r, calldone, lp);
1074:
1075: /*
1076: * if there was an error, translate it to a plan 9
1077: * errno and report it to the user.
1078: */
1079: DPRINT("got reply %d\n", lp->state);
1080: if(lp->state != Lconnected) {
1081: if(lp->err >= DKERRS)
1082: error(dkerr[0]);
1083: else
1084: error(dkerr[lp->err]);
1085: }
1086:
1087: /*
1088: * change state if serving
1089: */
1090: if(type == D_SERV){
1091: lp->state = Llistening;
1092: }
1093: DPRINT("connected!\n");
1094:
1095: /*
1096: * decode the window size
1097: */
1098: if (W_VALID(lp->window)){
1099: /*
1100: * a 1127 window negotiation
1101: */
1102: lp->window = W_VALUE(W_DEST(lp->window));
1103: } else if(lp->window>2 && lp->window<31){
1104: /*
1105: * a generic window negotiation
1106: */
1107: lp->window = 1<<lp->window;
1108: } else
1109: lp->window = 0;
1110:
1111: /*
1112: * tag the connection
1113: */
1114: strncpy(lp->addr, addr, sizeof(lp->addr)-1);
1115: strncpy(lp->raddr, addr, sizeof(lp->raddr)-1);
1116:
1117: /*
1118: * reset the protocol
1119: */
1120: dkwindow(c);
1121: }
1122:
1123: /*
1124: * listen for a call, reflavor the
1125: */
1126: static int
1127: dklisten(Chan *c)
1128: {
1129: char dialstr[512];
1130: char *line[12];
1131: char *field[8];
1132: Line *lp;
1133: Dk *dp;
1134: int n, lineno, ts, window;
1135: int from;
1136: Chan *dc;
1137: static int dts;
1138: char *cp;
1139:
1140: dp = dk[c->dev];
1141: from = STREAMID(c->qid.path);
1142:
1143: /*
1144: * open the data file
1145: */
1146: dc = dkopenline(dp, STREAMID(c->qid.path));
1147: if(waserror()){
1148: close(dc);
1149: nexterror();
1150: }
1151:
1152: /*
1153: * wait for a call in
1154: */
1155: for(;;){
1156: /*
1157: * read the dialstring and null terminate it
1158: */
1159: n = streamread(dc, dialstr, sizeof(dialstr)-1);
1160: DPRINT("returns %d\n", n);
1161: if(n <= 0)
1162: error(Eio);
1163: dialstr[n] = 0;
1164: DPRINT("dialstr = %s\n", dialstr);
1165:
1166: /*
1167: * break the dial string into lines
1168: */
1169: n = getfields(dialstr, line, 12, "\n");
1170: if (n < 2) {
1171: DPRINT("bad dialstr from dk (1 line)\n");
1172: error(Eio);
1173: }
1174:
1175: /*
1176: * line 0 is `line.tstamp.traffic[.urpparms.window]'
1177: */
1178: window = 0;
1179: switch(getfields(line[0], field, 5, ".")){
1180: case 5:
1181: /*
1182: * generic way of passing window
1183: */
1184: window = strtoul(field[4], 0, 0);
1185: if(window > 0 && window <31)
1186: window = 1<<window;
1187: else
1188: window = 0;
1189: /*
1190: * intentional fall through
1191: */
1192: case 3:
1193: /*
1194: * 1127 way of passing window
1195: */
1196: if(window == 0){
1197: window = strtoul(field[2], 0, 0);
1198: if(W_VALID(window))
1199: window = W_VALUE(W_ORIG(window));
1200: else
1201: window = 0;
1202: }
1203: break;
1204: default:
1205: print("bad message from dk(bad first line)\n");
1206: continue;
1207: }
1208: lineno = strtoul(field[0], 0, 0);
1209: if(lineno >= dp->lines){
1210: print("dklisten: illegal line %d\n", lineno);
1211: continue;
1212: }
1213: lp = linealloc(dp, lineno, 1);
1214: ts = strtoul(field[1], 0, 0);
1215:
1216: /*
1217: * this could be a duplicate request
1218: */
1219: if(ts == lp->timestamp){
1220: if((dts++ % 1000) == 0)
1221: print("dklisten: repeat timestamp %d\n", lineno);
1222: if(lp->state != Lconnected)
1223: dkanswer(c, lineno, DKbusy);
1224: continue;
1225: }
1226:
1227: /*
1228: * take care of glare (datakit picked an inuse channel
1229: * for the call to come in on).
1230: */
1231: if(!canqlock(lp)){
1232: DPRINT("DKbusy1\n");
1233: dkanswer(c, lineno, DKbusy);
1234: continue;
1235: } else {
1236: if(lp->state != Lclosed){
1237: qunlock(lp);
1238: DPRINT("DKbusy2 %ux\n", lp->state);
1239: dkanswer(c, lineno, DKbusy);
1240: continue;
1241: }
1242: }
1243: lp->window = window;
1244:
1245: /*
1246: * Line 1 is `my-dk-name.service[.more-things]'.
1247: * Special characters are escaped by '\'s. Convert to
1248: * a plan 9 address, i.e. system!service.
1249: */
1250: strncpy(lp->addr, line[1], sizeof(lp->addr)-1);
1251: if(cp = strchr(lp->addr, '.')){
1252: *cp = '!';
1253: if(cp = strchr(cp, '.'))
1254: *cp = 0;
1255: }
1256:
1257: /*
1258: * the rest is variable length
1259: */
1260: switch(n) {
1261: case 2:
1262: /* no more lines */
1263: lp->ruser[0] = 0;
1264: lp->raddr[0] = 0;
1265: break;
1266: case 3:
1267: /* line 2 is `source.user.param1.param2' */
1268: getfields(line[2], field, 3, ".");
1269: strncpy(lp->raddr, field[0], sizeof(lp->raddr)-1);
1270: strncpy(lp->ruser, field[1], sizeof(lp->ruser)-1);
1271: break;
1272: case 4:
1273: /* line 2 is `user.param1.param2' */
1274: getfields(line[2], field, 2, ".");
1275: strncpy(lp->ruser, field[0], sizeof(lp->ruser)-1);
1276:
1277: /* line 3 is `source.node.mod.line' */
1278: strncpy(lp->raddr, line[3], sizeof(lp->raddr)-1);
1279: break;
1280: default:
1281: print("bad message from dk(>4 line)\n");
1282: qunlock(lp);
1283: error(Ebadarg);
1284: }
1285:
1286: DPRINT("src(%s)user(%s)dest(%s)w(%d)\n", lp->raddr, lp->ruser,
1287: lp->addr, W_TRAF(lp->window));
1288:
1289: lp->timestamp = ts;
1290: lp->state = Lconnected;
1291:
1292: /* listener becomes owner */
1293: netown(lp, dp->linep[from]->owner, 0);
1294:
1295: qunlock(lp);
1296: close(dc);
1297: poperror();
1298: DPRINT("dklisten returns %d\n", lineno);
1299: return lineno;
1300: }
1301: panic("dklisten terminates strangely\n");
1302: return -1; /* never reached */
1303: }
1304:
1305: /*
1306: * answer a call
1307: */
1308: static void
1309: dkanswer(Chan *c, int line, int code)
1310: {
1311: char reply[64];
1312: Chan *dc;
1313: Line *lp;
1314: Dk *dp;
1315:
1316: dp = dk[c->dev];
1317: lp = linealloc(dp, line, 1);
1318:
1319: /*
1320: * open the data file (c is a control file)
1321: */
1322: dc = dkattach(dp->name);
1323: if(waserror()){
1324: close(dc);
1325: nexterror();
1326: }
1327: dc->qid.path = STREAMQID(STREAMID(c->qid.path), Sdataqid);
1328: dkopen(dc, ORDWR);
1329:
1330: /*
1331: * send the reply
1332: */
1333: sprint(reply, "%ud.%ud.%ud", line, lp->timestamp, code);
1334: DPRINT("dkanswer %s\n", reply);
1335: streamwrite(dc, reply, strlen(reply), 1);
1336: close(dc);
1337: poperror();
1338:
1339: /*
1340: * set window size
1341: */
1342: if(code == 0){
1343: if(waserror()){
1344: close(dc);
1345: nexterror();
1346: }
1347: sprint(reply, "init %d %d", lp->window, Streamhi);
1348: dc = dkopenline(dp, line);
1349: dc->qid.path = STREAMQID(line, Sctlqid);
1350: streamwrite(dc, reply, strlen(reply), 1);
1351: close(dc);
1352: poperror();
1353: }
1354: }
1355:
1356: /*
1357: * set the window size and reset the protocol
1358: */
1359: static void
1360: dkwindow(Chan *c)
1361: {
1362: char buf[64];
1363: Line *lp;
1364:
1365: lp = linealloc(dk[c->dev], STREAMID(c->qid.path), 1);
1366: if(lp->window == 0)
1367: lp->window = 64;
1368: sprint(buf, "init %d %d", lp->window, Streamhi);
1369: streamwrite(c, buf, strlen(buf), 1);
1370: }
1371:
1372: /*
1373: * hangup a datakit connection
1374: */
1375: static void
1376: dkhangup(Line *lp)
1377: {
1378: Block *bp;
1379:
1380: qlock(lp);
1381: if(lp->rq){
1382: bp = allocb(0);
1383: bp->type = M_HANGUP;
1384: PUTNEXT(lp->rq, bp);
1385: }
1386: qunlock(lp);
1387: }
1388:
1389: /*
1390: * A process which listens to all input on a csc line
1391: */
1392: static void
1393: dkcsckproc(void *a)
1394: {
1395: long n;
1396: Dk *dp;
1397: Dkmsg d;
1398: int line;
1399:
1400: dp = a;
1401:
1402: if(waserror()){
1403: close(dp->csc);
1404: return;
1405: }
1406: DPRINT("dkcsckproc: %d\n", dp->ncsc);
1407:
1408: /*
1409: * loop forever listening
1410: */
1411: for(;;){
1412: n = streamread(dp->csc, (char *)&d, (long)sizeof(d));
1413: if(n != sizeof(d)){
1414: if(n == 0)
1415: error(Ehungup);
1416: print("strange csc message %d\n", n);
1417: continue;
1418: }
1419: line = (d.param0h<<8) + d.param0l;
1420: DPRINT("t(%d)s(%d)l(%d)\n", d.type, d.srv, line);
1421: switch (d.type) {
1422:
1423: case T_CHG: /* controller wants to close a line */
1424: dkchgmesg(dp->csc, dp, &d, line);
1425: break;
1426:
1427: case T_REPLY: /* reply to a dial request */
1428: dkreplymesg(dp, &d, line);
1429: break;
1430:
1431: case T_SRV: /* ignore it, it's useless */
1432: /* print("dksrvmesg(%d)\n", line); /**/
1433: break;
1434:
1435: case T_RESTART: /* datakit reboot */
1436: if(line >=0 && line<dp->lines)
1437: dp->lines = line+1;
1438: break;
1439:
1440: default:
1441: print("unrecognized csc message %o.%o(%o)\n",
1442: d.type, d.srv, line);
1443: break;
1444: }
1445: }
1446: }
1447:
1448: /*
1449: * datakit requests or confirms closing a line
1450: */
1451: static void
1452: dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line)
1453: {
1454: Line *lp;
1455:
1456: switch (dialp->srv) {
1457:
1458: case D_CLOSE: /* remote shutdown */
1459: if (line <= 0 || line >= dp->lines || (lp = dp->linep[line]) == 0) {
1460: /* tell controller this line is not in use */
1461: dkmesg(c, T_CHG, D_CLOSE, line, 0);
1462: return;
1463: }
1464: switch (lp->state) {
1465:
1466: case Ldialing:
1467: /* simulate a failed connection */
1468: dkreplymesg(dp, (Dkmsg *)0, line);
1469: lp->state = Lrclose;
1470: break;
1471:
1472: case Lrclose:
1473: case Lconnected:
1474: case Llistening:
1475: case Lackwait:
1476: dkhangup(lp);
1477: lp->state = Lrclose;
1478: break;
1479:
1480: case Lopened:
1481: dkmesg(c, T_CHG, D_CLOSE, line, 0);
1482: break;
1483:
1484: case Llclose:
1485: case Lclosed:
1486: dkhangup(lp);
1487: dkmesg(c, T_CHG, D_CLOSE, line, 0);
1488: lp->state = Lclosed;
1489: break;
1490: }
1491: break;
1492:
1493: case D_ISCLOSED: /* acknowledging a local shutdown */
1494: if (line <= 0 || line >= dp->lines || (lp = dp->linep[line]) == 0)
1495: return;
1496: switch (lp->state) {
1497: case Llclose:
1498: case Lclosed:
1499: lp->state = Lclosed;
1500: break;
1501:
1502: case Lrclose:
1503: case Lconnected:
1504: case Llistening:
1505: case Lackwait:
1506: break;
1507: }
1508: break;
1509:
1510: case D_CLOSEALL:
1511: /*
1512: * datakit wants us to close all lines
1513: */
1514: for(line = dp->ncsc+1; line < dp->lines; line++){
1515: lp = dp->linep[line];
1516: if(lp == 0)
1517: continue;
1518: switch (lp->state) {
1519:
1520: case Ldialing:
1521: /* simulate a failed connection */
1522: dkreplymesg(dp, (Dkmsg *)0, line);
1523: lp->state = Lrclose;
1524: break;
1525:
1526: case Lrclose:
1527: case Lconnected:
1528: case Llistening:
1529: case Lackwait:
1530: lp->state = Lrclose;
1531: dkhangup(lp);
1532: break;
1533:
1534: case Lopened:
1535: break;
1536:
1537: case Llclose:
1538: case Lclosed:
1539: lp->state = Lclosed;
1540: break;
1541: }
1542: }
1543: dp->closeall = 1;
1544: wakeup(&dp->closeallr);
1545: break;
1546:
1547: default:
1548: print("unrecognized T_CHG\n");
1549: }
1550: }
1551:
1552: /*
1553: * datakit replies to a dialout. capture reply code and traffic parameters
1554: */
1555: static void
1556: dkreplymesg(Dk *dp, Dkmsg *dialp, int line)
1557: {
1558: Line *lp;
1559:
1560: DPRINT("dkreplymesg(%d)\n", line);
1561:
1562: if(line < 0 || line >= dp->lines || (lp = dp->linep[line]) == 0)
1563: return;
1564:
1565: if(lp->state != Ldialing)
1566: return;
1567:
1568: if(dialp){
1569: /*
1570: * a reply from the dk
1571: */
1572: lp->state = (dialp->srv==D_OPEN) ? Lconnected : Lrclose;
1573: lp->err = (dialp->param1h<<8) + dialp->param1l;
1574: lp->window = lp->err;
1575: DPRINT("dkreplymesg: %d\n", lp->state);
1576: } else {
1577: /*
1578: * a local abort
1579: */
1580: lp->state = Lrclose;
1581: lp->err = 0;
1582: }
1583:
1584: if(lp->state==Lrclose){
1585: dkhangup(lp);
1586: }
1587: wakeup(&lp->r);
1588: }
1589:
1590: /*
1591: * send a I'm alive message every 7.5 seconds and remind the dk of
1592: * any closed channels it hasn't acknowledged.
1593: */
1594: static void
1595: dktimer(void *a)
1596: {
1597: int i;
1598: Dk *dp;
1599: Line *lp;
1600: Chan *c;
1601:
1602: dp = (Dk *)a;
1603: c = dkopencsc(dp);
1604:
1605: while(waserror());
1606:
1607: for(;;){
1608: /*
1609: * send keep alive
1610: */
1611: DPRINT("keep alive\n");
1612: dkmesg(c, T_ALIVE, D_CONTINUE, 0, 0);
1613:
1614: /*
1615: * remind controller of dead lines and
1616: * timeout calls that take to long
1617: */
1618: for (i=dp->ncsc+1; i<dp->lines; i++){
1619: lp = dp->linep[i];
1620: if(lp == 0)
1621: continue;
1622: switch(lp->state){
1623: case Llclose:
1624: dkmesg(c, T_CHG, D_CLOSE, i, 0);
1625: break;
1626:
1627: case Ldialing:
1628: if(lp->calltolive==0 || --lp->calltolive!=0)
1629: break;
1630: dkreplymesg(dp, (Dkmsg *)0, i);
1631: break;
1632: }
1633: }
1634: tsleep(&dp->timer, return0, 0, 7500);
1635: }
1636: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.