home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / net / prot.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  9KB  |  381 lines

  1. /* Copyright (c) 1979 Regents of the University of California */
  2. # include "defs.h"
  3. static struct packet *xptr, *gptr;
  4. # define PACKETLENGTH (datasize + sizeof *xptr - 1)
  5. # define ACKLENGTH (sizeof *xptr - 1)
  6. static int bufleft;
  7. int atime = ATIME;
  8. int maxbread = MAXBREAD;
  9. static char savebuf[BFS*2], retransmit;
  10. static jmp_buf env;
  11.  
  12. /*
  13.    one problem has been character loss on
  14.    overloaded systems due to the daemon
  15.    taking too long to swap in
  16.    and losing characters.
  17.    A high priority process of small size
  18.    with a pipe would do the job.
  19. */
  20. alarmint(){
  21.     errno = 100;
  22.     signal(SIGCLK,SIG_IGN);        /* alarm off */
  23.     longjmp(env,0);            /* ugh */
  24.     }
  25. /* returns number of bytes written, error returns WRITEFAIL (-3) */
  26. xwrite(inbuf,size,amt)
  27.   char *inbuf;
  28. {
  29.     struct packet *rpp;
  30.     int cnt, num, savetime;
  31.     register char *p, *b;
  32.     register int i;
  33.     if(xptr == NULL)xptr = (struct packet *)calloc((PACKETLENGTH+20)/4,4);
  34.     if(xptr == NULL){error("xptr NULL"); return(WRITEFAIL); }
  35.     amt = amt * size;
  36.     cnt = 0;
  37.     retransmit = 0;
  38.     savetime = atime;
  39.     while(amt > 0){
  40.         if(retransmit > maxbread){
  41.             debug("xwrite fail");
  42.             return(WRITEFAIL);
  43.             }
  44.         b = inbuf+cnt;
  45.         num = min(datasize,amt);
  46.         xptr->pcode = REQUEST;
  47.         xptr->seqno = masterseqno;
  48.         xptr->len = num;
  49.         p = xptr->data;
  50.         i = num;
  51.         while(i--)*p++ = *b++;
  52.         sendpacket(xptr);
  53.         rpp = getpacket();
  54.         if(rpp == NULL){
  55.             atime += 3;        /* wait three more secs */
  56.             retransmit++;
  57.             dump.nretrans++;
  58.             continue;
  59.             }
  60.         if(rpp->chksum != 0 || rpp->pcode != ACK
  61.             || rpp->seqno != xptr->seqno ){
  62.             if(rpp->pcode == RESET){
  63.                 error("reset");
  64.                 return(WRITEFAIL);
  65.                 }
  66.             if(rpp->seqno == 1 && rpp->pcode == REQUEST){
  67.                 error("collision");
  68.                 return(WRITEFAIL);
  69.                 }
  70.             if(rpp->chksum != 0)
  71.                 error("chksum %d",rpp->seqno);
  72.             else if(rpp->pcode != ACK)
  73.                 error("not ack %d %d",rpp->pcode,rpp->seqno);
  74.             else if(rpp->seqno != xptr ->seqno)
  75.                 error("WRSQNO got %d request %d",rpp->seqno,
  76.                     xptr->seqno);
  77.             atime += 3;
  78.             retransmit++;
  79.             dump.nretrans++;
  80.             continue;
  81.             }
  82.         masterseqno++;
  83.         amt -= num;
  84.         retransmit = 0;
  85.         cnt += num;
  86.         }
  87.     atime = savetime;
  88.     return(cnt/size);
  89.     }
  90. /* return the number of bytes read, or error = BROKENREAD (-2) */
  91. nread(b,size,num)
  92.   register char *b;
  93. {
  94.     register char *p;
  95.     int bcnt = 0;
  96.         char *q;
  97.     register struct packet *pp;
  98.     int n,j,cnt;
  99.     num = num * size;
  100.     cnt = 0;
  101.     if(bufleft > 0){
  102.         p = savebuf;
  103.         cnt = n = min(bufleft,num);
  104.         while(n--)*b++ = *p++;
  105.         num -= cnt;
  106.         bufleft -= cnt;
  107.         if(bufleft > 0){
  108.             q = savebuf;
  109.             n = bufleft;
  110.             while(n--)*q++ = *p++;
  111.             }
  112.         }
  113.     if(num <= 0)
  114.         return(cnt/size);
  115.     retransmit = 0;
  116.     for(;;){
  117.         pp = getpacket();
  118.         if(pp == NULL){
  119.             if(++bcnt >= maxbread){
  120.                 debug("read timeout");
  121.                 return(BROKENREAD);
  122.                 }
  123.             continue;
  124.             }
  125.         if(pp->chksum != 0){
  126.             error("chksum %d",pp->seqno);
  127.             retransmit++;
  128.             continue;
  129.             }
  130.         if(pp->pcode & ~(REQUEST|RESET)){
  131.             error("pcode %d %d",pp->pcode,pp->seqno);
  132.             retransmit++;
  133.             continue;
  134.             }
  135.         else if(pp->pcode == RESET)break;
  136.         else {        /* else was a REQUEST packet, no chksum errs */
  137.             pp->pcode = ACK;
  138.             n = pp->len;
  139.             pp->len = 0;
  140.             sendpacket(pp);        /* send ACK */
  141.             pp->len = n;
  142.             break;
  143.             }
  144.         }
  145.     retransmit = 0;
  146.     j = n = min(num,pp->len);
  147.     cnt += j;
  148.     p = pp->data;
  149.     while(n--)*b++ = *p++;
  150.     if(pp->len > num){
  151.         n = bufleft = pp->len - num;
  152.         q = savebuf;
  153.         while(n--)*q++ = *p++;
  154.         }
  155.     return(cnt/size);
  156.     }
  157. printpacket(pp,dest)
  158.   char *dest;
  159.   struct packet *pp; {
  160.     char *s;
  161.     int i;
  162.     char c;
  163.     dest[0] = 0;
  164.     if(pp == NULL)return;
  165.     if(pp->pcode == REQUEST)c='r';
  166.     else if(pp->pcode == ACK)c = 'a';
  167.     else if(pp->pcode == RESET)c = 'x';
  168.     else if(pp->pcode == PURGE)c = 'p';
  169.     else c = 'u';
  170.     sprintf(dest,"p:%d len:%d c:%c d:", pp->seqno, pp->len, c);
  171.     s = dest + strlen(dest);
  172.     for(i=0; i<pp->len && pp->data[i]; i++)*s++ = pp->data[i];
  173.     *s = 0;
  174.     }
  175. /*
  176.  * A purge can always be sent -
  177.  * the receiver totally ignores it.
  178.  * It is used to push the packet terminator
  179.  * down the wire in case of a crash
  180.  * leaving the receiver half reading.
  181.  */
  182. sendpurge()
  183.   {
  184.     if(xptr == NULL)xptr = (struct packet *)calloc((PACKETLENGTH+20)/4,4);
  185.     if(xptr == NULL){
  186.         error("bad xptr");
  187.         return;
  188.         }
  189.     xptr->pcode = PURGE;
  190.     xptr->seqno = 0;
  191.     xptr->len = 0;
  192.     debug("send purge");
  193.     sendpacket(xptr);
  194.     }
  195. /*
  196.  * A reset is sent by the sender whenever he begins to send.
  197.  * It is not acknowledged.
  198.  * The receiver must be prepared, when he receives a reset,
  199.  * to receive a new transmission.
  200.  */
  201. sendreset()
  202.   {
  203.     if(xptr == NULL)xptr = (struct packet *)calloc((PACKETLENGTH+20)/4,4);
  204.     if(xptr == NULL){
  205.         error("bad xptr");
  206.         return;
  207.         }
  208.     xptr->pcode = RESET;
  209.     xptr->seqno = 0;
  210.     xptr->len = 0;
  211.     debug("send reset");
  212.     sendpacket(xptr);
  213.     }
  214. /*
  215.  * Getreset returns in either of two cases:
  216.  * 1) the read times out (return BROKENREAD)
  217.  * 2) a reset packet is received (return 0)
  218.  * all other packets received are ignored.
  219.  */
  220. getreset() {
  221.     register struct packet *pp;
  222.     register int bcnt = 0;
  223.     bufleft = 0;        /* if any chars are left in buffer, flush them*/
  224.     atime = ATIME + ((rand()>>8)%15);
  225.     lastseqno = -1;        /* forces non-RESET pks to not be ACK-ed */
  226.     for(;;){
  227.         pp = getpacket();
  228.         if(pp == NULL){
  229.             if(++bcnt >= maxbread){
  230.                 debug("reset timeout");
  231.                 return(BROKENREAD);
  232.                 }
  233.             continue;
  234.             }
  235.         if(pp->pcode == RESET){
  236.             debug("got reset");
  237.             addtolog(remote,"^R%c ",remote);
  238.             lastseqno = 0;
  239.             return(0);
  240.             }
  241.         }
  242.     }
  243. /*
  244.  *    Just sends packet pp
  245.  *    Calculates the chksum
  246.  */
  247. sendpacket(pp)
  248.   struct packet *pp; {
  249.     char buf[BFS*2];
  250.     int len, n, i;
  251.     long nt,ot;
  252.     register char *q, *p;
  253.     register int j;
  254.     dump.nbytesent += pp->len;
  255.     dump.npacksent++;
  256.     pp->chksum = 0;
  257.     n = 0;
  258.     p = (char *)pp;
  259.     len = ACKLENGTH + pp->len;
  260.     for(j = 0; j < len; j++)n ^= *p++;
  261.     pp->chksum = n;
  262.     p = buf;
  263.     q = (char *)pp;
  264.     len = n = (len+2)/3;
  265.     while(n--){
  266.         *p++ = (*q & 077) + INCR;
  267.         j =    (*q++ >> 6) &03;
  268.         *p++ = (((*q << 2) | j) & 077) + INCR;
  269.         j =    (*q++ >> 4) & 017;
  270.         *p++ = (((*q << 4) | j) & 077) + INCR;
  271.         *p++ = ((*q++ >> 2) & 077) + INCR;
  272.         }
  273.     *p++ = '\n';
  274.     *p = 0;
  275. /*    because of bugs in processing around erase and kill in v6 */
  276.     for(p=buf; *p; p++)
  277.         if(*p == '\\')*p = '}';
  278.     /*
  279.     debug("send %d %s",len*4+1,buf);
  280.     */
  281.     ot = gettime();
  282.     i = fwrite(buf,1,len*4+1, writetty);
  283.     nt = gettime();
  284.     dump.waittime += (nt - ot);            /* add time writing */
  285.     /*
  286.     debug("count %d",i);
  287.     */
  288.     fflush(writetty);
  289.     }
  290. /*
  291.  *    returns NULL if couldn't get a packet with correct seqno
  292.  *    chksum not checked here
  293.  *     because other programs may want to interrogate checksum
  294.  */
  295. struct packet *getpacket() {
  296.     char buf[BFS*2];
  297.     int i,n,j, len, plen;
  298.     int bcnt;
  299.     register char *q, *p;
  300.     long ot, nt;
  301.     if(gptr == NULL)gptr = (struct packet *)calloc((PACKETLENGTH+20)/4,4);
  302.     if(gptr == NULL){error("gptr NULL"); return(NULL); }
  303.     bcnt = 0;
  304.     errno = 0;
  305.     setjmp(env);
  306.     alarm(0);
  307.     signal(SIGCLK,alarmint);
  308.     for(;;){
  309.         if(bcnt++ > maxbread)errno = 100;    /* give up */
  310.         if(errno == 100){
  311.             if(debugflg)putchar('^');
  312.             return(NULL);
  313.             }
  314.         alarm(atime);
  315.         ot = gettime();
  316.         p = fgets(buf,BFS*2,readtty);
  317.         alarm(0);
  318.         nt = gettime();
  319.         dump.waittime += (nt - ot);
  320.         if(p == NULL){error("getpacket fails"); return(NULL); }
  321.         plen = strlen(buf);
  322.         /*
  323.         debug("receive %d %s",plen,buf);
  324.         */
  325.         /* remove this loop later */
  326.         for(p=buf; *p; p++)
  327.             if(*p == '}')*p = '\\';
  328.         p = buf;
  329.         q = (char *)gptr;
  330.         n = (strlen(buf)+3) /4;
  331.         while(n--){
  332.             if(*p == '\n')break;
  333.             if(*p < INCR || *p & 0200)error("bad char %o\n",*p);
  334.             i =  *p++ - INCR;
  335.             j =  *p++ - INCR;
  336.             *q++ = ((j & 03) << 6) | (i & 077);
  337.             i =  *p++ -INCR;
  338.             *q++ = ((i & 017) << 4) | ((j >> 2) & 017);
  339.             j =  *p++ - INCR;
  340.             *q++ = ((j & 077) << 2) | ((i >> 4) & 03);
  341.             }
  342.         *q = 0;
  343.         if(plen != ((ACKLENGTH + gptr->len + 2)/3)*4 + 1){
  344.             error("too short %d",gptr->seqno);
  345.             continue;
  346.             }
  347.         if(gptr->pcode == PURGE){
  348.             debug("got purge");
  349.             continue;        /* never seen */
  350.             }
  351.         if(gptr->pcode == RESET)
  352.             break;
  353.         if(gptr->seqno == lastseqno){
  354.             if(retransmit)break;
  355.             /* send ACK - it was lost first time thru */
  356.             len = gptr->len;
  357.             n = gptr->pcode;
  358.             gptr->len = 0;
  359.             gptr->pcode = ACK;
  360.             sendpacket(gptr);
  361.             gptr->len = len;
  362.             gptr->pcode = n;
  363.             error("sendlostack %d",lastseqno);
  364.             break;
  365.             }
  366.         if(gptr->seqno == lastseqno + 1)break;
  367.         error("Wrong seq no g: %d last: %d",gptr->seqno,
  368.             lastseqno);
  369.         }
  370.     lastseqno = gptr->seqno;
  371.     n = 0;
  372.     len = gptr->len + ACKLENGTH;
  373.     p = (char *)gptr;
  374.     for(i=0; i < len; i++)n ^= *p++;
  375.     gptr->chksum = n;
  376.     if(n != 0)dump.ncksum++;
  377.     dump.nbytercv += gptr->len;
  378.     dump.npackrcv++;
  379.     return(gptr);
  380. }
  381.