|
|
1.1 root 1: /* Protocol driver, user level, Berkeley network */
2: /*
3: This code is a little complicated because of a number of different
4: protocols used. Here is an explanation:
5:
6: Level Description
7:
8: 0 Normal Case (6 bit with no kernel driver support)
9:
10: 1 Line Discipline -- uses NETLDISP in sgtty.h and ioctl to set the
11: line discipline. At Berkeley this means avoiding interrupting on
12: every character by using a Silo on a DH or DZ board, and (optionally)
13: bypassing the canonicalization in the tty code by putting the charactars
14: directly in a buffer.
15: condition (netd.dp_bnetldis != 0)
16:
17: 2 8-bit TTY protocol -- implies Level 1 and inserts record separators(012)
18: and escapes other occurrences of 012. Since the driver on the other
19: end must interpolate the escapes, this is an asymmetric protocol where
20: the sender puts in the escapes but the receiver at the user level knows
21: they have already been removed.
22: condition (netd.dp_bnetldis != 0 && netd.dp_use8bit != 0)
23:
24: 3 8-bit Block Device protocol -- this is for a DMC-11, it writes fixed
25: length blocks in both directions with no quoting.
26: condition (netd.dp_bnetldis != 0 && netd.dp_usehighspeed != 0)
27:
28: 4 RAND 8-bit protocol -- included for completeness, is not
29: correctly specified here.
30: Specified by an IFDEF.
31:
32: If the daemons are being simulated by pipes, then netd.dp_pipesim != 0
33: and each of the 4 levels (except RAND) are simulated.
34: In this case at level 2 (use8bit) on the receiver end it does the quoting.
35:
36: */
37: # include "defs.h"
38:
39: /* global */
40: struct dumpstruc dump;
41: struct daemonparms netd;
42:
43: /* local */
44: static int bufleft;
45: static char retransmit;
46: static jmp_buf env;
47: static short masterseqno, lastseqno;
48: /* writing packet */
49: static char wpack[MAXNBUF];
50:
51: /*
52: one problem has been character loss on
53: overloaded systems due to the daemon
54: taking too long to swap in
55: and losing characters.
56: A high priority process of small size
57: with a pipe would do the job.
58: */
59: alarmint(){
60: errno = 100;
61: signal(SIGALRM,SIG_IGN); /* alarm off */
62: longjmp(env,0); /* ugh */
63: }
64: /* returns number of bytes written, error returns WRITEFAIL (-3) */
65: /* inbuf is buffer of amt chars to be written */
66: xwrite(inbuf,amt)
67: char *inbuf;
68: {
69: register char *p, *b;
70: register int i;
71: int cnt, num, savetime;
72: struct packet *rpp, *xptr;
73:
74: xptr = (struct packet *)wpack;
75: cnt = 0;
76: retransmit = 0;
77: savetime = netd.dp_atime;
78: while(amt > 0){
79: if(retransmit > netd.dp_maxbread){
80: debug("xwrite fail");
81: return(WRITEFAIL);
82: }
83: /* format the packet to send */
84: num = min(netd.dp_datasize,amt);
85: /* set the length down if escapes are being used */
86: if(netd.dp_use8bit)num = min(num,MAXNBUF/2);
87: xptr->pcode = REQUEST;
88: xptr->seqno = masterseqno;
89: xptr->len = num;
90: p = xptr->data;
91: i = num;
92: b = inbuf+cnt;
93: while(i--)*p++ = *b++;
94: /* send it */
95: sendpacket(xptr);
96: rpp = getpacket();
97: if(rpp == NULL){
98: netd.dp_atime += 3; /* wait three more secs */
99: retransmit++;
100: dump.nretrans++;
101: continue;
102: }
103: /* various errors */
104: if(rpp->chksum != 0 || rpp->pcode != ACK
105: || rpp->seqno != xptr->seqno ){
106: if(rpp->seqno == 1 && rpp->pcode == REQUEST){
107: error("collision");
108: return(WRITEFAIL);
109: }
110: if(rpp->chksum != 0)
111: error("chksum %d",rpp->seqno);
112: else if(rpp->pcode != ACK)
113: error("not ack %d %d",rpp->pcode,rpp->seqno);
114: else if(rpp->seqno != xptr ->seqno)
115: error("WRSQNO got %d request %d",rpp->seqno,
116: xptr->seqno);
117: netd.dp_atime += 3;
118: retransmit++;
119: dump.nretrans++;
120: continue;
121: }
122: masterseqno++;
123: retransmit = 0;
124: amt -= num;
125: cnt += num;
126: }
127: netd.dp_atime = savetime;
128: return(cnt);
129: }
130: /* return the number of bytes read, or error = BROKENREAD (-2) */
131: nread(bptr,num)
132: register char *bptr;
133: {
134: register char *p;
135: register struct packet *pp;
136: register char *q;
137: int bcnt = 0;
138: int n,j,cnt;
139: static char savebuf[MAXNBUF];
140:
141: /* first see if theres any left from the last packet */
142: cnt = 0;
143: if(bufleft > 0){
144: p = savebuf;
145: cnt = n = min(bufleft,num);
146: while(n--)*bptr++ = *p++;
147: num -= cnt;
148: bufleft -= cnt;
149: if(bufleft > 0){
150: q = savebuf;
151: n = bufleft;
152: while(n--)*q++ = *p++;
153: }
154: }
155: if(num <= 0)
156: return(cnt);
157: /* now read a packet */
158: retransmit = 0;
159: for(;;){
160: pp = getpacket();
161: if(pp == NULL){
162: if(++bcnt >= netd.dp_maxbread){
163: debug("read timeout");
164: return(BROKENREAD);
165: }
166: continue;
167: }
168: /* various errors */
169: if(pp->chksum != 0){
170: error("chksum %d",pp->seqno);
171: retransmit++;
172: continue;
173: }
174: if(pp->pcode & ~REQUEST){
175: error("pcode %d %d",pp->pcode,pp->seqno);
176: retransmit++;
177: continue;
178: }
179: /* this is the normal case, so we ack it */
180: else { /* else was a REQUEST packet, no chksum errs */
181: /*
182: if(pp->seqno == 1)debug("^R ");
183: */
184: pp->pcode = ACK;
185: n = pp->len;
186: pp->len = 0;
187: sendpacket(pp); /* send ACK */
188: pp->len = n;
189: break;
190: }
191: }
192: /* now process this packet, bptr points to where we left off */
193: retransmit = 0;
194: j = n = min(num,pp->len);
195: cnt += j;
196: p = pp->data;
197: while(n--)*bptr++ = *p++;
198: if(pp->len > num){
199: n = bufleft = pp->len - num;
200: bptr = savebuf;
201: while(n--)*bptr++ = *p++;
202: }
203: return(cnt);
204: }
205: printpacket(pp,dest)
206: char *dest;
207: struct packet *pp; {
208: char *s;
209: int i;
210: char c;
211: dest[0] = 0;
212: if(pp == NULL)return;
213: if(pp->pcode == REQUEST)c='r';
214: else if(pp->pcode == ACK)c = 'a';
215: else if(pp->pcode == PURGE)c = 'p';
216: else c = 'u';
217: sprintf(dest,"p:%d len:%d c:%c d:", pp->seqno, pp->len, c);
218: s = dest + strlen(dest);
219: for(i=0; i<pp->len && pp->data[i]; i++)*s++ = pp->data[i];
220: *s = 0;
221: }
222: /*
223: * A purge can always be sent -
224: * the receiver totally ignores it.
225: * It is used to push the packet terminator
226: * down the wire in case of a crash
227: * leaving the receiver half reading.
228: */
229: sendpurge()
230: {
231: struct packet *xptr;
232: xptr = (struct packet *)wpack;
233: xptr->pcode = PURGE;
234: xptr->seqno = 0;
235: xptr->len = 0;
236: debug("send purge");
237: sendpacket(xptr);
238: }
239: /* init sequence numbers */
240: initseqno(){
241: masterseqno = 1;
242: lastseqno = 0;
243: bufleft = 0; /* if any chars are left in buffer, flush them*/
244: netd.dp_atime = netd.dp_oatime + ((rand()>>8)%15);
245: }
246: /*
247: * Just sends packet pp
248: * Calculates the chksum
249: */
250: sendpacket(pp)
251: struct packet *pp; {
252: register char *q, *p;
253: register int j;
254: char *finalp;
255: static char raw[MAXNBUF];
256: int len, n, i;
257:
258: /* writes the data to be sent in array raw */
259: /* finalp will point to either pp or raw */
260: dump.nbytesent += pp->len;
261: dump.npacksent++;
262: pp->chksum = 0;
263: n = 0;
264: p = (char *)pp;
265: len = ACKLENGTH + pp->len;
266: for(j = 0; j < len; j++)n ^= *p++;
267: pp->chksum = n;
268: # ifndef RAND
269: if(netd.dp_usehispeed)finalp = (char *)pp;
270: else if(netd.dp_use8bit){
271: if(len >= MAXNBUF){
272: fprintf(stderr,"Packet size too big- error\n");
273: exit(1);
274: }
275: /* add escapes */
276: p = (char *)pp;
277: q = raw;
278: i = len;
279: len = 0;
280: for(j = 0; j < i; j++){
281: if(*p == '\n' || *p == '\\'){
282: *q++ = '\\';
283: *q++ = *p++;
284: len++;
285: len++;
286: }
287: else {
288: *q++ = *p++;
289: len++;
290: }
291: }
292: *q = '\n';
293: len++;
294: finalp = raw;
295: }
296: else {
297: /* now change 8-bit data to 6-bit data */
298: if(((len+2)*4)/3 >= MAXNBUF){
299: fprintf(stderr,"Packet size too big- error\n");
300: exit(1);
301: }
302: p = raw;
303: q = (char *)pp;
304: len = n = (len+2)/3;
305: while(n--){
306: *p++ = (*q & 077) + INCR;
307: j = (*q++ >> 6) &03;
308: *p++ = (((*q << 2) | j) & 077) + INCR;
309: j = (*q++ >> 4) & 017;
310: *p++ = (((*q << 4) | j) & 077) + INCR;
311: *p++ = ((*q++ >> 2) & 077) + INCR;
312: }
313: *p++ = '\n';
314: *p = 0;
315: /* because of bugs in processing around erase and kill in v6 */
316: for(p=raw; *p; p++)
317: if(*p == '\\')*p = '}';
318: len = len * 4 + 1;
319: finalp = raw;
320: }
321: /*
322: debug("send %d %s",len,raw);
323: */
324: if(netd.dp_usehispeed){
325: if(len > SENDLEN)error("send length too long");
326: len = SENDLEN;
327: }
328: if(netd.dp_pipesim) i = write(netd.dp_pwritefd,finalp,len);
329: else i = write(netd.dp_linefd,finalp,len);
330: dump.braw += i;
331: dump.brawtot += i;
332: # else
333: /* for RAND */
334: i = write(netd.dp_linefd, (char *)pp,len);
335: # endif
336: /*
337: debug("count %d",i);
338: */
339: }
340:
341: static int tooshort;
342: /*
343: * returns NULL if couldn't get a packet with correct seqno
344: * chksum not checked here
345: * because other programs may want to interrogate checksum
346: */
347: struct packet *getpacket() {
348: register struct packet *gptr;
349: register char *p;
350: register int i;
351: int n, bcnt, len;
352: struct packet *decpacket();
353:
354: bcnt = 0;
355: errno = 0;
356: setjmp(env);
357: alarm(0);
358: signal(SIGALRM,alarmint);
359: for(;;){
360: if(bcnt++ > netd.dp_maxbread)errno = 100; /* give up */
361: if(errno == 100){
362: if(debugflg)putchar('^');
363: return(NULL);
364: }
365: /* decode the buffer, including 6-8 bit conv, etc. */
366: gptr = decpacket();
367: if(gptr == NULL){
368: error("getpacket fails");
369: return(NULL);
370: }
371: if(tooshort || gptr->len < 0 || gptr->len > MAXNBUF){
372: error("too short p:%d l:%d",gptr->seqno,gptr->len);
373: continue;
374: }
375: if(gptr->seqno == 1 && gptr->pcode != ACK){
376: debug("got reset");
377: addtolog(remote,"^R ");
378: }
379: if(gptr->pcode == PURGE){
380: debug("got purge");
381: continue; /* never seen */
382: }
383: if(gptr->seqno == lastseqno){
384: if(retransmit)break;
385: /* send ACK - it was lost first time thru */
386: len = gptr->len;
387: n = gptr->pcode;
388: gptr->len = 0;
389: gptr->pcode = ACK;
390: sendpacket(gptr);
391: gptr->len = len;
392: gptr->pcode = n;
393: error("sendlostack %d",lastseqno);
394: break;
395: }
396: /* this is the correct case */
397: if(gptr->seqno == lastseqno + 1)break;
398: error("Wrong seq no g: %d last: %d",gptr->seqno,
399: lastseqno);
400: }
401: lastseqno = gptr->seqno;
402: n = 0;
403: len = gptr->len + ACKLENGTH;
404: p = (char *)gptr;
405: for(i=0; i < len; i++)n ^= *p++;
406: gptr->chksum = n;
407: if(n != 0)dump.ncksum++;
408: dump.nbytercv += gptr->len;
409: dump.npackrcv++;
410: return(gptr);
411: }
412: /* read in and decode packet */
413: /* as a side effect sets "tooshort" */
414: static struct packet *decpacket()
415: {
416: # ifndef RAND
417: register char *p, *q;
418: register int i,j;
419: int n, len, ch;
420: struct packet *pp;
421: static char cooked[MAXNBUF], raw[MAXNBUF];
422:
423: /* read in chars to raw, if processed then return in cooked, otherwise
424: return in raw */
425: alarm(netd.dp_atime);
426: tooshort = 0;
427: if(netd.dp_pipesim){
428: if(netd.dp_usehispeed)
429: len = read(fileno(netd.dp_rdfile),raw,SENDLEN);
430: else {
431: q = raw;
432: len = 0;
433: for(;;){
434: ch = getc(netd.dp_rdfile);
435: len++;
436: if(ch == '\n'){
437: *q++ = '\n';
438: break;
439: }
440: /* eat up the backslashes */
441: if(ch == '\\' && netd.dp_use8bit)
442: ch = getc(netd.dp_rdfile);
443: *q++ = ch;
444: }
445: if(netd.dp_use8bit)len--;
446: }
447: }
448: else if(netd.dp_usehispeed)
449: len = read(fileno(netd.dp_rdfile),raw,SENDLEN);
450: else len = read(netd.dp_linefd,raw,MAXNBUF);
451: alarm(0);
452: if(len == 0)fprintf(stderr,"eof pip %d\n",fileno(netd.dp_rdfile));
453: if(len <= 0)return(NULL);
454: raw[len] = 0;
455: dump.braw += len;
456: dump.brawtot += len;
457: /*
458: debug("receive %d %s",len,raw);
459: */
460: /* if 8 bit the all we need to do is return */
461: if(netd.dp_usehispeed)return((struct packet *)raw);
462: if(netd.dp_use8bit){
463: pp = (struct packet *)raw;
464: if(len != ACKLENGTH + pp->len)tooshort = 1;
465: return(pp);
466: }
467: /* remove this loop later */
468: for(p=raw; *p; p++)
469: if(*p == '}')*p = '\\';
470: p = raw;
471: q = cooked;
472: n = (len+3) /4;
473: while(n--){
474: if(*p == '\n')break;
475: if(*p < INCR || *p & 0200)error("bad char %o\n",*p);
476: i = *p++ - INCR;
477: j = *p++ - INCR;
478: *q++ = ((j & 03) << 6) | (i & 077);
479: i = *p++ -INCR;
480: *q++ = ((i & 017) << 4) | ((j >> 2) & 017);
481: j = *p++ - INCR;
482: *q++ = ((j & 077) << 2) | ((i >> 4) & 03);
483: }
484: *q = 0;
485: pp = (struct packet *)cooked;
486: if(len != ((ACKLENGTH + pp->len + 2)/3)*4 + 1) tooshort = 1;
487: # else
488: /* for RAND */
489: /* not sure of the length computation */
490: if(len != ACKLENGTH + gptr->len) tooshort = 1;
491: # endif
492: return((struct packet *)cooked);
493: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.