|
|
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.