home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff294.lzh / DNet / unix / dnet / control.c < prev    next >
C/C++ Source or Header  |  1989-12-11  |  13KB  |  576 lines

  1.  
  2. /*
  3.  *  CONTROL.C
  4.  *
  5.  *    DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
  6.  *
  7.  *  -handle various actions:
  8.  *    RTO    - read timeout
  9.  *    WTO    - write timeout (a packet not acked)
  10.  *    RNET    - state machine for raw receive packet
  11.  *    WNET    - starts timeout sequence if Write occured
  12.  *    WUPDATE - update write windows, send packets
  13.  *    RUPDATE - execute received packets in correct sequence
  14.  *    RECCMD    - execute decoded SCMD commands obtained from received
  15.  *            packets.
  16.  */
  17.  
  18. #include "dnet.h"
  19. #include <stdio.h>
  20.  
  21. extern void do_cmd();
  22.  
  23. ubyte TmpBuf[MAXPACKET];
  24.  
  25. /*
  26.  *  RTO:    read timeout.   Timeout occured while waiting for the rest of
  27.  *        a packet.  Reset state and restart read.
  28.  */
  29.  
  30. do_rto()
  31. {
  32.     RState = 0;
  33.     RcvData = 0;
  34.     if (DDebug)
  35.     fprintf(stderr, "RTO\n");
  36. }
  37.  
  38. /*
  39.  *  WTO:    Write timeout (unresolved output windows exist).  Resend a CHECK
  40.  *        command for all unresolved (READY) output windows
  41.  */
  42.  
  43. void
  44. do_wto()
  45. {
  46.     register short i;
  47.     register PKT *pkt;
  48.     short to = 0;
  49.  
  50.     if (DDebug)
  51.     fprintf(stderr, "WTO\n");
  52.     if (Restart) {
  53.     WriteRestart();
  54.     return;
  55.     }
  56.     for (i = 0; i < WPUsed; ++i) {
  57.     pkt = WPak[i];
  58.     if (pkt->state == READY) {  /*  send check  */
  59.         WriteChk((WPStart + i) & 7);
  60.         ++to;
  61.     }
  62.     }
  63.     if (to)
  64.     WTimeout(WTIME);
  65. }
  66.  
  67. /*
  68.  *  RNET:   Receved data ready from network.  The RNet request will
  69.  *        automagically be reissued on return.
  70.  */
  71.  
  72. do_rnet()
  73. {
  74.     ubyte *ptr = RcvBuf;
  75.     long len = RcvData;
  76.  
  77.     RcvData = 0;
  78.  
  79.     RExpect = RecvPacket(ptr, len);
  80. }
  81.  
  82.  
  83. /*
  84.  *  DO_WUPDATE()
  85.  *
  86.  *  (1) Remove EMPTY windows at head of transmit queue.
  87.  *  (2) Fill up transmit queue with pending requests, if any.
  88.  *
  89.  *  First two bits determine CMD as follows:
  90.  *        0bbbbbbb+0x20    DATA        0-95 bytes of DATA
  91.  *        10bbbccc        DATA        0-7 bytes of DATA, ccc=channel
  92.  *                                  command.
  93.  *        11bbbbbb bbbbbbbb    DATA        0-1023 bytes of DATA
  94.  *
  95.  *  Note!  By encoding the quick-data packet with the length + 0x20, you
  96.  *  don't take the 6 bit encoding hit when sending small amounts of ascii
  97.  *  data such as keystrokes.
  98.  */
  99.  
  100. do_wupdate()
  101. {
  102.     static short XPri;
  103.     int maxpktsize;
  104.     register XIOR *ior;
  105.     register PKT *pkt;
  106.     register long len;
  107.     short loop = 0;
  108.  
  109.     WReady = 0;
  110.     while (WPUsed && WPak[0]->state == EMPTY) {
  111.     pkt = WPak[0];
  112.     WPak[0] = WPak[1];
  113.     WPak[1] = WPak[2];
  114.     WPak[2] = WPak[3];
  115.     WPak[3] = pkt;
  116.     --WPUsed;
  117.     ++WPStart;
  118.     }
  119.     if (Restart)
  120.     return(0);
  121.  
  122.     while (WPUsed != 4 && (ior = (XIOR *)RemHead(&TxList))) {
  123.     register long offset = 0;
  124.  
  125.     if (++loop == 2) {
  126.         WReady = 1;
  127.         AddHead(&TxList, ior);
  128.         return(0);
  129.     }
  130.  
  131.     {
  132.         short npri;
  133.  
  134.         if (ior->io_Command == SCMD_DATA)
  135.         npri = ior->io_Pri << 2;
  136.         else
  137.         npri = XPri;
  138.         if (npri >= XPri)  {
  139.         XPri = npri;
  140.         } else {
  141.         if (XPri - npri > 100)
  142.             XPri -= 10;
  143.         else if (XPri - npri > 50)
  144.             XPri -= 5;
  145.         else
  146.             --XPri;
  147.         }
  148.         maxpktsize = MAXPKT - (XPri - npri);
  149.         if (DDebug)
  150.         fprintf(stderr, "**MAXPKTSIZE = %ld  XPri %ld npri %ld\n",
  151.             maxpktsize, XPri, npri
  152.         );
  153.         if (maxpktsize < MINPKT)
  154.         maxpktsize = MINPKT;
  155.     }
  156.  
  157.     pkt = WPak[WPUsed];
  158.  
  159.     for (;;) {
  160.         if (offset > (maxpktsize-8))            /*  not enough room */
  161.         break;
  162.         if (ior->io_Command == SCMD_DATA && ior->io_Channel != WChan) {
  163.         /*  CSWITCH */
  164.         WChan = ior->io_Channel;
  165.         TmpBuf[offset+0] = 0x80|SCMD_SWITCH|(2<<3);
  166.         TmpBuf[offset+1] = WChan >> 8;
  167.         TmpBuf[offset+2] = WChan;
  168.         offset += 3;
  169.         if (DDebug)
  170.             fprintf(stderr, "SEND SWITCH %ld\n", WChan);
  171.         }
  172.         len = ior->io_Length - ior->io_Actual;
  173.         if (ior->io_Command == SCMD_DATA) {     /*  DATA    */
  174.         if (DDebug)
  175.             fprintf(stderr, "SEND DATA %ld bytes\n", len);
  176.         if (offset + len > (maxpktsize-4))
  177.             len = (maxpktsize-4) - offset;
  178.         if (len < 0x20) {
  179.             TmpBuf[offset] = len + 0x20;
  180.             ++offset;
  181.         } else {
  182.             TmpBuf[offset+0] = 0x40 + len / 96;
  183.             TmpBuf[offset+1] = 0x20 + len % 96;
  184.             offset += 2;
  185.         }
  186.         } else {                    /*    COMMAND */
  187.         TmpBuf[offset] = 0x80|ior->io_Command|(len<<3);
  188.         ++offset;
  189.         if (DDebug)
  190.             printf("constr sdcmd %02x len %d\n", TmpBuf[0], len);
  191.         }
  192.         bcopy((char *)ior->io_Data+ior->io_Actual,TmpBuf+offset,len);
  193.         offset += len;
  194.         ior->io_Actual += len;
  195.         if (ior->io_Actual == ior->io_Length) {
  196.         free(ior->io_Data);
  197.         free(ior);
  198.         ior = (XIOR *)RemHead(&TxList);          /* Next packet      */
  199.         if (ior == NULL)
  200.             break;
  201.         }
  202.     }
  203.     pkt->state = READY;
  204.     BuildDataPacket(pkt, (WPStart + WPUsed) & 7, TmpBuf, offset);
  205.     WritePacket(pkt);
  206.  
  207.     if (ior) {
  208.         ++ior->io_Pri;
  209.         Enqueue(&TxList, ior);
  210.         --ior->io_Pri;
  211.     }
  212.     ++WPUsed;
  213.     }
  214. }
  215.  
  216. void
  217. dumpcheck(ptr)
  218. register ubyte *ptr;
  219. {
  220.     register short i;
  221.     for (i = 0;i < 8; ++i) {
  222.     if (ptr[i])
  223.         replywindow(i);
  224.     ptr[i] = 0;
  225.     }
  226. }
  227.  
  228. void
  229. do_cmd(ctl, buf, bytes)
  230. short ctl;    /* actually a ubyte */
  231. ubyte *buf;
  232. {
  233.     ubyte window = ctl & 7;
  234.     ubyte rwindow;
  235.     static ubyte Chk, Chkwin[8];    /* remember window checks */
  236.  
  237.     if (ctl == -1)  {                           /* end of sequence */
  238.     dumpcheck(Chkwin);
  239.     Chk = 0;
  240.     return;
  241.     }
  242.     if ((ctl & PKF_MASK) == PKCMD_CHECK) {      /* CHECK packet    */
  243.     Chkwin[window] = 1;
  244.     Chk = 1;
  245.     return;
  246.     }
  247.     if (Chk) {                                  /* NON-CHECK packet*/
  248.     dumpcheck(Chkwin);
  249.     Chk = 0;
  250.     }
  251.     switch(ctl & PKF_MASK) {
  252.     case PKCMD_WRITE:
  253.     case PKCMD_WRITE6:
  254.     case PKCMD_WRITE7:
  255.     rwindow = (window - RPStart) & 7;
  256.     if (rwindow < 4) {
  257.         bcopy(buf, RPak[rwindow]->data, bytes);
  258.         RPak[rwindow]->buflen = bytes;
  259.         RPak[rwindow]->state = READY;
  260.         if (rwindow == 0)
  261.         do_rupdate();
  262.     }
  263.     replywindow(window);
  264.     break;
  265.     case PKCMD_ACK:
  266.     rwindow = (window - WPStart) & 7;
  267.     if (rwindow < WPUsed)       /*  mark as sent    */
  268.         WPak[rwindow]->state = EMPTY;
  269.     break;
  270.     case PKCMD_NAK:            /*    resend        */
  271.     rwindow = (window - WPStart) & 7;
  272.     if (rwindow < WPUsed) {     /*  resend          */
  273.         WritePacket(WPak[rwindow]);
  274.     } else {
  275.         fprintf(stderr, "Soft Error: Illegal NAK\n");
  276.     }
  277.     break;
  278.     case PKCMD_ACKRSTART:
  279.     case PKCMD_RESTART:
  280.     {
  281.         uword chan;
  282.         uword chksum;
  283.         int len;
  284.         int fd;
  285.  
  286.         if ((ctl & PKF_MASK) == PKCMD_ACKRSTART)
  287.         Restart = 0;
  288.         do_netreset();
  289.         if ((ctl & PKF_MASK) == PKCMD_RESTART) {
  290.         WritePacket(BuildRestartAckPacket("3", 1));
  291.         }
  292.         if (bytes)
  293.         setlistenport(buf);
  294.         else
  295.         setlistenport("3");
  296.         do_wupdate();
  297.     }
  298.     break;
  299.     default:
  300.     if (DDebug)
  301.         printf("do_cmd: bad packet ctl %02x\n", ctl);
  302.     break;
  303.     }
  304.     do_rupdate();
  305. }
  306.  
  307. do_rupdate()
  308. {
  309.     while (RPak[0]->state == READY) {
  310.     register PKT *pkt = RPak[0];
  311.     register ubyte *ptr = pkt->data;
  312.     register uword len;
  313.     uword iolen = pkt->buflen;
  314.     ubyte cmd;
  315.  
  316.     while (iolen) {
  317.         if (DDebug)
  318.             printf("rupdate %02x\n", ptr[0]);
  319.         cmd = SCMD_DATA;
  320.         len = ptr[0];
  321.         ++ptr;
  322.         --iolen;
  323.         if (len >= 128) {
  324.         cmd = len & 7;
  325.         len = (len >> 3) & 7;
  326.         } else {
  327.         if (len < 0x40) {
  328.             len -= 0x20;
  329.         } else {
  330.             len = (len - 0x40) * 96 + (*ptr - 0x20);
  331.             ++ptr;
  332.             --iolen;
  333.         }
  334.         } 
  335.         iolen -= len;
  336.         if (DDebug)
  337.         fprintf(stderr, " MPXCMD %ld (%ld bytes)\n", cmd, len);
  338.         do_reccmd(cmd, ptr, len);
  339.         ptr += len;
  340.     }
  341.     RPak[0] = RPak[1];
  342.     RPak[1] = RPak[2];
  343.     RPak[2] = RPak[3];
  344.     RPak[3] = pkt;
  345.     pkt->state = EMPTY;
  346.     ++RPStart;
  347.     }
  348. }
  349.  
  350. do_reccmd(cmd, ptr, len)
  351. ubyte *ptr;
  352. {
  353.     if (DDebug)
  354.     printf("-reccmd %02x (%ld bytes)\n", cmd, len);
  355.     switch(cmd) {
  356.     case SCMD_DATA:
  357.     if (RChan < MAXCHAN && (Chan[RChan].flags & CHANF_ROK))
  358.         gwrite(Chan[RChan].fd, ptr, len);
  359.     break;
  360.     case SCMD_SWITCH:
  361.     RChan = (ptr[0]<<8)|ptr[1];
  362.     break;
  363.     case SCMD_OPEN:
  364.     {
  365.         register COPEN *cop = (COPEN *)ptr;
  366.         CACKCMD ack;
  367.         uword chan = (cop->chanh << 8) | cop->chanl;
  368.  
  369.         ack.chanh = cop->chanh;
  370.         ack.chanl = cop->chanl;
  371.         ack.error = 0;
  372.  
  373.         if (chan >= MAXCHAN || Chan[chan].state) {
  374.         ack.error = 33;     /* magic */
  375.         WriteStream(SCMD_ACKCMD, &ack, sizeof(CACKCMD), chan);
  376.         break;
  377.         }
  378.         {
  379.         int error;
  380.         int s;
  381.         uword port = (cop->porth<<8)|cop->portl;
  382.  
  383.         if (isinternalport(port)) {
  384.             error = iconnect(&s, port);
  385.         } else {
  386.             struct sockaddr sa;
  387.             s = socket(PF_UNIX, SOCK_STREAM, 0);
  388.             if (DDebug)
  389.             fprintf(stderr, " REC OPEN, CONNECTING ch%d po%d\n",
  390.                 chan, port
  391.             );
  392.             sa.sa_family = AF_INET;
  393.             sprintf(sa.sa_data,".PORT.%ld", port);
  394.             error = connect(s, &sa, sizeof(sa));
  395.             if (error < 0) {
  396.             startserver(port);
  397.             error = connect(s, &sa, sizeof(sa));
  398.             }
  399.             if (DDebug)
  400.             fprintf(stderr, " CONNECTED err=%ld\n", error);
  401.         }
  402.         if (error < 0) {
  403.             ack.error = 2;
  404.         } else {
  405.             extern void do_open();
  406.             fcntl(s, F_SETFL, FNDELAY);
  407.             Chan[chan].state = CHAN_OPEN;
  408.             Chan[chan].flags = CHANF_ROK|CHANF_WOK;
  409.             Chan[chan].fd = s;
  410.             Chan[chan].pri= cop->pri;
  411.             FD_SET(s, &Fdread);
  412.             FD_SET(s, &Fdexcept);
  413.             FdChan[s] = chan;
  414.             Fdstate[s] = do_open;
  415.         }
  416.         WriteStream(SCMD_ACKCMD, &ack, sizeof(CACKCMD), -1);
  417.         }
  418.     }
  419.     break;
  420.     case SCMD_CLOSE:    /*  receive close   */
  421.     {
  422.         extern void nop();
  423.         register CCLOSE *clo = (CCLOSE *)ptr;
  424.         uword chan = (clo->chanh<<8)|clo->chanl;
  425.         int fd = Chan[chan].fd;
  426.  
  427.         if (DDebug)
  428.         fprintf(stderr, " SCMD_CLOSE\n");
  429.         if (chan >= MAXCHAN || Chan[chan].state == CHAN_FREE)
  430.         break;
  431.         /*
  432.         Chan[chan].state = CHAN_CLOSE;
  433.         Chan[chan].flags |= CHANF_RCLOSE;
  434.         */
  435.         Chan[chan].flags &= ~(CHANF_ROK|CHANF_WOK);
  436.         FD_CLR(fd, &Fdread);
  437.         FD_CLR(fd, &Fdexcept);
  438.         Chan[chan].state = CHAN_FREE;
  439.         Chan[chan].fd = -1;
  440.         Fdstate[fd] = nop;
  441.         close(fd);
  442.         ClearChan(&TxList, chan, 0);
  443.  
  444.         if (Chan[chan].flags & CHANF_LCLOSE) {
  445.         if (DDebug)
  446.             fprintf(stderr," REMOTE CLOSE %ld, LOCAL ALREADY CLOSED\n",
  447.             fd
  448.             );
  449.         } else {
  450.         CCLOSE cc;
  451.         char dummy;
  452.         cc.chanh = chan >> 8;
  453.         cc.chanl = chan;
  454.         WriteStream(SCMD_CLOSE, &cc, sizeof(CCLOSE), chan);
  455.         /*
  456.         shutdown(Chan[chan].fd, 2);
  457.         write(Chan[chan].fd, &dummy, 0);
  458.         */
  459.         if (DDebug)
  460.             fprintf(stderr," REMOTE CLOSE %ld, LOCAL NOT YET CLOSED\n",
  461.             fd
  462.             );
  463.         }
  464.     }
  465.     break;
  466.     case SCMD_ACKCMD:    /*  acknowledge of my open    */
  467.     {
  468.         register CACKCMD *cack = (CACKCMD *)ptr;
  469.         uword chan = (cack->chanh<<8)|cack->chanl;
  470.         if (chan >= MAXCHAN || Chan[chan].state != CHAN_LOPEN)
  471.         break;
  472.         if (DDebug)
  473.         fprintf(stderr, "ackerr = %ld\n", cack->error);
  474.         if (cack->error == 33) {
  475.         uword newchan = alloc_channel();
  476.         COPEN co;
  477.         if (newchan < MAXCHAN) {
  478.             Chan[newchan] = Chan[chan];
  479.             Chan[chan].state = CHAN_FREE;
  480.             Chan[chan].fd = -1;
  481.             co.chanh = newchan >> 8;
  482.             co.chanl = newchan;
  483.             co.porth = Chan[chan].port >> 8;
  484.             co.portl = Chan[chan].port;
  485.             co.error = 0;
  486.             co.pri   = Chan[chan].pri;
  487.             WriteStream(SCMD_OPEN, &co, sizeof(COPEN), newchan);
  488.             break;
  489.         }
  490.         }
  491.         if (cack->error) {
  492.         extern void nop();
  493.         ubyte error = cack->error;
  494.         int fd = Chan[chan].fd;
  495.  
  496.         gwrite(fd, &error, 1);
  497.         Fdstate[fd] = nop;
  498.         Chan[chan].fd = -1;
  499.         Chan[chan].state = CHAN_FREE;
  500.         FD_CLR(fd, &Fdread);
  501.         FD_CLR(fd, &Fdexcept);
  502.         close(fd);
  503.         } else {
  504.         ubyte error = 0;
  505.         extern void do_open();
  506.         gwrite(Chan[chan].fd, &error, 1);
  507.         Chan[chan].state = CHAN_OPEN;
  508.         Chan[chan].flags = CHANF_ROK|CHANF_WOK;
  509.         Fdstate[Chan[chan].fd] = do_open;
  510.         }
  511.     }
  512.     break;
  513.     case SCMD_EOFCMD:    /*  EOF on channel        */
  514.     {
  515.         register CEOFCMD *eof = (CEOFCMD *)ptr;
  516.         uword chan = (eof->chanh<<8)|eof->chanl;
  517.  
  518.         if (chan < MAXCHAN && Chan[chan].state == CHAN_OPEN) {
  519.         Chan[chan].flags &= ~eof->flags;
  520.         if (eof->flags & CHANF_ROK) {
  521.             char dummy;
  522.             shutdown(Chan[chan].fd, 1);
  523.             write(Chan[chan].fd, &dummy, 0);
  524.         }
  525.         }
  526.     }
  527.     break;
  528.     case SCMD_QUIT:
  529.     dneterror("QUIT");
  530.     break;
  531.     case SCMD_IOCTL:
  532.     {
  533.         register CIOCTL *cio = (CIOCTL *)ptr;
  534.         uword chan = (cio->chanh<<8)|cio->chanl;
  535.  
  536.         if (chan < MAXCHAN && Chan[chan].state == CHAN_OPEN) {
  537.         switch(cio->cmd) {
  538.         case CIO_SETROWS:
  539.             isetrows(Chan[chan].fd, (cio->valh<<8)|cio->vall);
  540.             break;
  541.         case CIO_SETCOLS:
  542.             isetcols(Chan[chan].fd, (cio->valh<<8)|cio->vall);
  543.             break;
  544.         case CIO_STOP:
  545.             break;
  546.         case CIO_START:
  547.             break;
  548.         case CIO_FLUSH:
  549.             ClearChan(&TxList, chan, 0);
  550.             break;
  551.         }
  552.         }
  553.     }
  554.     break;
  555.     default:
  556.     break;
  557.     }
  558. }
  559.  
  560. replywindow(window)
  561. {
  562.     ubyte rwindow = (window - RPStart) & 7;
  563.  
  564.     if (DDebug) {
  565.     if (rwindow >= 4 || RPak[rwindow]->state == READY)
  566.         fprintf(stderr, " ACK WINDOW %ld\n", window);
  567.     else
  568.         fprintf(stderr, " NAK WINDOW %ld\n", window);
  569.     }
  570.     if (rwindow >= 4 || RPak[rwindow]->state == READY)  /* data ready */
  571.     WriteAck(window);
  572.     else
  573.     WriteNak(window);
  574. }
  575.  
  576.