home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d145 / dnet.lha / Dnet / unix / dnet / control.c < prev    next >
C/C++ Source or Header  |  1988-05-26  |  16KB  |  708 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. /*
  24.  *  RTO:    read timeout.   Timeout occured while waiting for the rest of
  25.  *        a packet.  Reset state and restart read.
  26.  */
  27.  
  28. do_rto()
  29. {
  30.     RState = 0;
  31.     RcvData = 0;
  32.     if (DDebug)
  33.     fprintf(stderr, "RTO\n");
  34. }
  35.  
  36. /*
  37.  *  WTO:    Write timeout (unresolved output windows exist).  Resend a CHECK
  38.  *        command for all unresolved (READY) output windows
  39.  */
  40.  
  41. void
  42. do_wto()
  43. {
  44.     register short i;
  45.     register PKT *pkt;
  46.     register uword len = 0;
  47.  
  48.     if (DDebug)
  49.     fprintf(stderr, "WTO\n");
  50.     if (Restart) {
  51.     WCBuf[0] = SYNC;
  52.     WCBuf[1] = PKCMD_RESTART;
  53.     WCBuf[2] = (WCBuf[0]<<1)^WCBuf[1];
  54.     NetWrite(WCBuf, 3);
  55.     WTimeout(WTIME);
  56.     return;
  57.     }
  58.     for (i = 0; i < WPUsed; ++i) {
  59.     pkt = WPak[i];
  60.     if (pkt->state == READY) {  /*  send check  */
  61.         WCBuf[len+0] = SYNC;
  62.         WCBuf[len+1] = PKCMD_CHECK | ((WPStart + i) << 5);
  63.         WCBuf[len+2] = (WCBuf[len+0] << 1) ^ WCBuf[len+1];
  64.         len += 3;
  65.     }
  66.     }
  67.     if (len) {
  68.     NetWrite(WCBuf, len);
  69.         WTimeout(WTIME);
  70.     }
  71. }
  72.  
  73. /*
  74.  *  RNET:   Receved data ready from network.  The RNet request will
  75.  *        automagically be reissued on return.
  76.  */
  77.  
  78. do_rnet()
  79. {
  80.     register ubyte *ptr = RcvBuf;
  81.     register long len  = RcvData;
  82.     long lrd = len;
  83.     long mark;
  84.     static uword dlen;
  85.     static uword dblen;
  86.     static ubyte dctl;
  87.  
  88.     if (DDebug)
  89.     fprintf(stderr, "NETREAD %08lx %ld\n", RcvBuf, RcvData);
  90.     while (len) {
  91.     switch(RState) {
  92.     case RS_SYNC:
  93.         --len;
  94.         if (*ptr++ == SYNC)
  95.         RState = RS_CTL;
  96.         break;
  97.     case RS_CTL:
  98.         --len;
  99.         dctl = *ptr++;
  100.         RState = RS_CCHK;
  101.         break;
  102.     case RS_CCHK:
  103.         if ((ubyte)(((SYNC<<1)^dctl)) == *ptr) {
  104.         ++ptr;
  105.         --len;
  106.         if (dctl & PKF_DATA) {
  107.             RState = RS_LEN1;
  108.             break;
  109.         }
  110.         RState = RS_SYNC;
  111.         if (DDebug)
  112.             fprintf(stderr, "DO COMMAND (0DATA) 0x%02lx\n", dctl);
  113.         do_cmd(dctl, NULL, 0);
  114.         } else {
  115.         if (DDebug)
  116.             fprintf(stderr, "RS_CCHK FAILED\n");
  117.             if (len) {      /*  Resync at earliest point    */
  118.             ++len;
  119.             --ptr;
  120.             }
  121.         }
  122.         RState = RS_SYNC;
  123.         break;
  124.     case RS_LEN1:
  125.         dlen = *ptr;
  126.         ++ptr;
  127.         --len;
  128.         RState = RS_LEN2;
  129.         break;
  130.     case RS_LEN2:
  131.         dlen = (dlen << 8) + *ptr + 2;
  132.         ++ptr;
  133.         --len;
  134.         if (dlen > MAXPKT+2) {
  135.         if (DDebug)
  136.             fprintf(stderr,"RAW DATA: LENGTH FAILURE (cmd %02x) %ld\n",
  137.             dctl, dlen
  138.             );
  139.         RState = RS_SYNC;
  140.         break;
  141.         }
  142.         RState = RS_DATA;
  143.         break;
  144.     case RS_DATA:
  145.         if (DDebug)
  146.         fprintf(stderr, "RS_DATA->");
  147.         if (dlen <= len) {
  148.         register uword chk = chkbuf(ptr, dlen - 2);
  149.         if ((chk >> 8) == ptr[dlen-2] && (ubyte)chk == ptr[dlen-1]) {
  150.             if (DDebug)
  151.             fprintf(stderr, "DO MPX (%ld DATA) 0x%02lx\n", 
  152.                 dlen-2, dctl
  153.             );
  154.             do_cmd(dctl, ptr, dlen-2);
  155.             len -= dlen;
  156.             ptr += dlen;
  157.         } else {
  158.             if (DDebug)
  159.             fprintf(stderr, "RS_DATA: FAILED\n");
  160.         }
  161.         RState = RS_SYNC;
  162.         } else {
  163.         if (DDebug)
  164.             fprintf(stderr, "RS_DATA: INCOMPLETE READ\n");
  165.         goto break2;    /*  incomplete read  */
  166.         }
  167.         break;
  168.     }
  169.     }
  170. break2:
  171.     switch(RState) {
  172.     case RS_DATA:
  173.     RExpect = dlen - len;
  174.     if (RExpect < 0) {
  175.         fprintf(stderr, "panic, RExpect = %ld\n", RExpect);
  176.         exit(1);
  177.     }
  178.     break;
  179.     default:
  180.     RExpect = 0;
  181.     break;
  182.     }
  183.     do_cmd(-1, NULL, 0);
  184.     mark = len;
  185.     {
  186.     if (len && ptr != RcvBuf)
  187.         bcopy(ptr, RcvBuf, len);
  188.     RcvData = len;
  189.     }
  190.     if (RState == RS_DATA) {
  191.     /*
  192.         RDisable();
  193.         RTimeout(RTIME/1000);
  194.     */
  195.     }
  196.     do_wupdate();
  197.     return(mark);
  198. }
  199.  
  200. /*
  201.  *  WNET:   The last data packet has been sent to the network...  Start a
  202.  *        timeout sequence (1 second).  If this times out we will send
  203.  *        a CHECK packet for all unresolved transmission windows.
  204.  */
  205.  
  206. do_wnet()
  207. {
  208.     if (DidWrite) {
  209.     DidWrite = 0;
  210.         if (DDebug)
  211.         fprintf(stderr, "WNET-STARTTO\n");
  212.         WTimeout(WTIME);
  213.     } else {
  214.     if (DDebug)
  215.         fprintf(stderr, "WNET-NOP\n");
  216.     }
  217. }
  218.  
  219. /*
  220.  *  DO_WUPDATE()
  221.  *
  222.  *  (1) Remove EMPTY windows at head of transmit queue.
  223.  *  (2) Fill up transmit queue with pending requests, if any.
  224.  *
  225.  *  First two bits determine CMD as follows:
  226.  *        0bbbbbbb        DATA        0-127 bytes of DATA
  227.  *        10bbbccc        DATA        0-7 bytes of DATA, ccc=channel
  228.  *                                  command.
  229.  *        11bbbbbb bbbbbbbb    DATA        0-1023 bytes of DATA
  230.  */
  231.  
  232. do_wupdate()
  233. {
  234.     static short XPri;
  235.     int maxpktsize;
  236.     register XIOR *ior;
  237.     register PKT *pkt;
  238.     register long len;
  239.  
  240.     while (WPUsed && WPak[0]->state == EMPTY) {
  241.     pkt = WPak[0];
  242.     WPak[0] = WPak[1];
  243.     WPak[1] = WPak[2];
  244.     WPak[2] = WPak[3];
  245.     WPak[3] = pkt;
  246.     --WPUsed;
  247.     ++WPStart;
  248.     }
  249.     if (Restart)
  250.     return(0);
  251.  
  252.     while (WPUsed != 4 && (ior = (XIOR *)RemHead(&TxList))) {
  253.     register long offset = 0;
  254.  
  255.     {
  256.         short npri;
  257.  
  258.         if (ior->io_Command == SCMD_DATA) 
  259.         npri = ior->io_Pri << 2;
  260.         else
  261.         npri = XPri;
  262.         if (npri >= XPri)  {
  263.         XPri = npri;
  264.         } else {
  265.         if (XPri - npri > 100)
  266.             XPri -= 10;
  267.         else if (XPri - npri > 50)
  268.             XPri -= 5;
  269.         else
  270.             --XPri;
  271.         }
  272.         maxpktsize = MAXPKT - (XPri - npri);
  273.         if (DDebug)
  274.         fprintf(stderr, "**MAXPKTSIZE = %ld  XPri %ld npri %ld\n", 
  275.             maxpktsize, XPri, npri
  276.         );
  277.         if (maxpktsize < MINPKT)
  278.         maxpktsize = MINPKT;
  279.     }
  280.  
  281.     pkt = WPak[WPUsed];
  282.     pkt->state = READY;
  283.     pkt->sync  = SYNC;
  284.     pkt->ctl   = PKCMD_WRITE | PKF_DATA | ((WPStart + WPUsed)<<5);
  285.     pkt->cchk = (pkt->sync << 1) ^ pkt->ctl;
  286.     for (;;) {
  287.         if (offset > (maxpktsize-8))                /*  not enough room */
  288.         break;
  289.         if (ior->io_Command == SCMD_DATA && ior->io_Channel != WChan) {
  290.         /*  CSWITCH */
  291.         WChan = ior->io_Channel;
  292.         pkt->data[offset+0] = 0x80|SCMD_SWITCH|(2<<3);
  293.         pkt->data[offset+1] = WChan >> 8;
  294.         pkt->data[offset+2] = WChan;
  295.         offset += 3;
  296.         if (DDebug)
  297.             fprintf(stderr, "SEND SWITCH %ld\n", WChan);
  298.         }
  299.         len = ior->io_Length - ior->io_Actual;
  300.         if (ior->io_Command == SCMD_DATA) {     /*  DATA    */
  301.         if (DDebug)
  302.             fprintf(stderr, "SEND DATA %ld bytes\n", len);
  303.         if (offset + len > (maxpktsize-4))
  304.             len = (maxpktsize-4) - offset;
  305.         if (len < 128) {
  306.             pkt->data[offset] = len;
  307.             ++offset;
  308.         } else {
  309.             pkt->data[offset+0] = (len>>8)|0xC0;
  310.             pkt->data[offset+1] = len;
  311.             offset += 2;
  312.         }
  313.         } else {                    /*    COMMAND */
  314.         pkt->data[offset] = 0x80|ior->io_Command|(len<<3);
  315.         ++offset;
  316.         }
  317.         bcopy((char *)ior->io_Data+ior->io_Actual,pkt->data+offset,len);
  318.         offset += len;
  319.         ior->io_Actual += len;
  320.         if (ior->io_Actual == ior->io_Length) {
  321.         free(ior->io_Data);
  322.         free(ior);
  323.         ior = (XIOR *)RemHead(&TxList);          /* Next packet      */
  324.         if (ior == NULL)
  325.             break;
  326.         }
  327.     }
  328.     pkt->iolength = offset + OVERHEAD;
  329.     pkt->lenh = offset >> 8;
  330.     pkt->lenl = offset;
  331.     {
  332.         register uword chksum = chkbuf(pkt->data, offset);
  333.         pkt->data[offset+0] = chksum >> 8;
  334.         pkt->data[offset+1] = chksum;
  335.     }
  336.     NetWrite(&pkt->sync, pkt->iolength);
  337.     if (ior) {
  338.         ++ior->io_Pri;
  339.         Enqueue(&TxList, ior);
  340.         --ior->io_Pri;
  341.     }
  342.     ++WPUsed;
  343.     }
  344. }
  345.  
  346. void
  347. dumpcheck(ptr)
  348. register ubyte *ptr;
  349. {
  350.     register short i;
  351.     for (i = 0;i < 8; ++i) {
  352.     if (ptr[i])
  353.         replywindow(i);
  354.     ptr[i] = 0;
  355.     }
  356. }
  357.  
  358. void
  359. do_cmd(ctl, buf, bytes)
  360. short ctl;    /* actually a ubyte */
  361. ubyte *buf;
  362. {
  363.     ubyte window = ctl >> 5;
  364.     ubyte rwindow;
  365.     static ubyte Chk, Chkwin[8];    /* remember window checks */
  366.  
  367.     if (ctl == -1)  {                /* end of sequence */
  368.     dumpcheck(Chkwin);
  369.     Chk = 0;
  370.     return;
  371.     }
  372.     if ((ctl & PKF_MASK) == PKCMD_CHECK) {    /* CHECK packet       */
  373.     Chkwin[window] = 1;
  374.     Chk = 1;
  375.     return;
  376.     }
  377.     if (Chk) {                    /* NON-CHECK packet*/
  378.     dumpcheck(Chkwin);
  379.     Chk = 0;
  380.     }
  381.     switch(ctl & PKF_MASK) {
  382.     case PKCMD_WRITE:
  383.     rwindow = (window - RPStart) & 7;
  384.     if (rwindow < 4) {
  385.         bcopy(buf, RPak[rwindow]->data, bytes);
  386.         RPak[rwindow]->iolength = bytes;
  387.         RPak[rwindow]->state = READY;
  388.         if (rwindow == 0)
  389.         do_rupdate();
  390.     }
  391.     replywindow(window);
  392.     break;
  393.     case PKCMD_ACK:
  394.     rwindow = (window - WPStart) & 7;
  395.     if (rwindow < WPUsed)       /*  mark as sent    */
  396.         WPak[rwindow]->state = EMPTY;
  397.     break;
  398.     case PKCMD_NAK:            /*    resend        */
  399.     rwindow = (window - WPStart) & 7;
  400.     if (rwindow < WPUsed) {     /*  resend          */
  401.         NetWrite(&WPak[rwindow]->sync, WPak[rwindow]->iolength);
  402.     } else {
  403.         fprintf(stderr, "Soft Error: Illegal NAK\n");
  404.     }
  405.     break;
  406.     case PKCMD_ACKRSTART:
  407.     case PKCMD_RESTART:
  408.     {
  409.         uword chan;
  410.         uword chksum;
  411.         int len;
  412.         int fd;
  413.  
  414.         if ((ctl & PKF_MASK) == PKCMD_ACKRSTART)
  415.             Restart = 0;
  416.         do_netreset();
  417.         if ((ctl & PKF_MASK) == PKCMD_RESTART) {
  418.             gethostname(WCBuf+5, sizeof(WCBuf)-5-3);
  419.             len = strlen(WCBuf+5)+1;
  420.             WCBuf[0] = SYNC;
  421.             WCBuf[1] = PKCMD_ACKRSTART | PKF_DATA;
  422.             WCBuf[2] = (SYNC << 1) ^ WCBuf[1];
  423.             WCBuf[3] = 0;
  424.             WCBuf[4] = len;
  425.             chksum = chkbuf(WCBuf+5, len);
  426.             WCBuf[5+len] = chksum >> 8;
  427.             WCBuf[6+len] = chksum;
  428.             NetWrite(WCBuf, 7+len);
  429.         }
  430.         if (bytes)
  431.             setlistenport(buf);
  432.         else
  433.         setlistenport("");
  434.         do_wupdate();
  435.          WTimeout(WTIME);
  436.     }
  437.     break;
  438.     }
  439.     do_rupdate();
  440. }
  441.  
  442. do_rupdate()
  443. {
  444.     while (RPak[0]->state == READY) {
  445.     register PKT *pkt = RPak[0];
  446.     register ubyte *ptr = pkt->data;
  447.     register uword len;
  448.     uword iolen = pkt->iolength;
  449.     ubyte cmd;
  450.  
  451.     if (DDebug)
  452.         fprintf(stderr, "Interpret Received Commands\n");
  453.     while (iolen) {
  454.         cmd = SCMD_DATA;
  455.         len = ptr[0];
  456.         ++ptr;
  457.         --iolen;
  458.         if (len >= 128) {
  459.         if (len < 0xC0) {
  460.             cmd = len & 7;
  461.             len = (len >> 3) & 7;
  462.         } else {
  463.             len = ((len << 8) | *ptr) & 0x3FFF;
  464.             ++ptr;
  465.             --iolen;
  466.         }
  467.         }
  468.         iolen -= len;
  469.         if (DDebug)
  470.         fprintf(stderr, " MPXCMD %ld (%ld bytes)\n", cmd, len);
  471.         do_reccmd(cmd, ptr, len);
  472.         ptr += len;
  473.     }
  474.     RPak[0] = RPak[1];
  475.     RPak[1] = RPak[2];
  476.     RPak[2] = RPak[3];
  477.     RPak[3] = pkt;
  478.     pkt->state = EMPTY;
  479.     ++RPStart;
  480.     }
  481. }
  482.  
  483. do_reccmd(cmd, ptr, len)
  484. ubyte *ptr;
  485. {
  486.     switch(cmd) {
  487.     case SCMD_DATA:
  488.     if (RChan < MAXCHAN && (Chan[RChan].flags & CHANF_ROK))
  489.         gwrite(Chan[RChan].fd, ptr, len);
  490.     break;
  491.     case SCMD_SWITCH:
  492.     RChan = (ptr[0]<<8)|ptr[1];
  493.     break;
  494.     case SCMD_OPEN:
  495.     {
  496.         register COPEN *cop = (COPEN *)ptr;
  497.         CACKCMD ack;
  498.         uword chan = (cop->chanh << 8) | cop->chanl;
  499.  
  500.         ack.chanh = cop->chanh;
  501.         ack.chanl = cop->chanl;
  502.         ack.error = 0;
  503.  
  504.         if (chan >= MAXCHAN || Chan[chan].state) {
  505.         ack.error = 33;     /* magic */
  506.         WriteStream(SCMD_ACKCMD, &ack, sizeof(CACKCMD), chan);
  507.         break;
  508.         }
  509.         {
  510.         int error;
  511.         int s;
  512.         uword port = (cop->porth<<8)|cop->portl;
  513.  
  514.         if (isinternalport(port)) {
  515.             error = iconnect(&s, port);
  516.         } else {
  517.             struct sockaddr sa;
  518.             s = socket(PF_UNIX, SOCK_STREAM, 0);
  519.             if (DDebug)
  520.                 fprintf(stderr, " REC OPEN, CONNECTING\n");
  521.             sa.sa_family = AF_INET;
  522.             sprintf(sa.sa_data,".PORT.%ld", port);
  523.             error = connect(s, &sa, sizeof(sa));
  524.             if (error < 0) {
  525.             startserver(port);
  526.                 error = connect(s, &sa, sizeof(sa));
  527.             }
  528.             if (DDebug)
  529.                 fprintf(stderr, " CONNECTED err=%ld\n", error);
  530.         }
  531.         if (error < 0) {
  532.             ack.error = 2;
  533.         } else {
  534.             extern void do_open();
  535.             fcntl(s, F_SETFL, FNDELAY);
  536.             Chan[chan].state = CHAN_OPEN;
  537.             Chan[chan].flags = CHANF_ROK|CHANF_WOK;
  538.             Chan[chan].fd = s;
  539.             Chan[chan].pri= cop->pri;
  540.             FD_SET(s, &Fdread);
  541.             FD_SET(s, &Fdexcept);
  542.             FdChan[s] = chan;
  543.             Fdstate[s] = do_open;
  544.         }
  545.          WriteStream(SCMD_ACKCMD, &ack, sizeof(CACKCMD), -1);
  546.         }
  547.     }
  548.     break;
  549.     case SCMD_CLOSE:    /*  receive close   */
  550.     {
  551.         extern void nop();
  552.         register CCLOSE *clo = (CCLOSE *)ptr;
  553.         uword chan = (clo->chanh<<8)|clo->chanl;
  554.         int fd = Chan[chan].fd;
  555.  
  556.         if (DDebug)
  557.         fprintf(stderr, " SCMD_CLOSE\n");
  558.         if (chan >= MAXCHAN || Chan[chan].state == CHAN_FREE) 
  559.         break;
  560.         /*
  561.         Chan[chan].state = CHAN_CLOSE;
  562.         Chan[chan].flags |= CHANF_RCLOSE;
  563.         */
  564.         Chan[chan].flags &= ~(CHANF_ROK|CHANF_WOK);
  565.         FD_CLR(fd, &Fdread);
  566.         FD_CLR(fd, &Fdexcept);
  567.         Chan[chan].state = CHAN_FREE;
  568.         Chan[chan].fd = -1;
  569.         Fdstate[fd] = nop;
  570.         close(fd);
  571.         ClearChan(&TxList, chan, 1);
  572.  
  573.         if (Chan[chan].flags & CHANF_LCLOSE) {
  574.         if (DDebug)
  575.             fprintf(stderr," REMOTE CLOSE %ld, LOCAL ALREADY CLOSED\n",
  576.             fd
  577.             );
  578.         } else {
  579.         CCLOSE cc;
  580.         char dummy;
  581.         cc.chanh = chan >> 8;
  582.         cc.chanl = chan;
  583.         WriteStream(SCMD_CLOSE, &cc, sizeof(CCLOSE), chan);
  584.         /*
  585.         shutdown(Chan[chan].fd, 2);
  586.         write(Chan[chan].fd, &dummy, 0);
  587.         */
  588.         if (DDebug)
  589.             fprintf(stderr," REMOTE CLOSE %ld, LOCAL NOT YET CLOSED\n",
  590.             fd
  591.             );
  592.         }
  593.     }
  594.     break;
  595.     case SCMD_ACKCMD:    /*  acknowledge of my open    */
  596.     {
  597.             register CACKCMD *cack = (CACKCMD *)ptr;
  598.         uword chan = (cack->chanh<<8)|cack->chanl;
  599.         if (chan >= MAXCHAN || Chan[chan].state != CHAN_LOPEN) 
  600.         break;
  601.         if (DDebug)
  602.             fprintf(stderr, "ackerr = %ld\n", cack->error);
  603.         if (cack->error == 33) {
  604.         uword newchan = alloc_channel();
  605.         COPEN co;
  606.         if (newchan < MAXCHAN) {
  607.             Chan[newchan] = Chan[chan];
  608.             Chan[chan].state = CHAN_FREE;
  609.             Chan[chan].fd = -1;
  610.             co.chanh = newchan >> 8;
  611.             co.chanl = newchan;
  612.             co.porth = Chan[chan].port >> 8;
  613.             co.portl = Chan[chan].port;
  614.             co.error = 0;
  615.             co.pri   = Chan[chan].pri;
  616.             WriteStream(SCMD_OPEN, &co, sizeof(COPEN), newchan);
  617.             break;
  618.         }
  619.         }
  620.         if (cack->error) {
  621.         extern void nop();
  622.         ubyte error = cack->error;
  623.         int fd = Chan[chan].fd;
  624.  
  625.         gwrite(fd, &error, 1);
  626.             Fdstate[fd] = nop;
  627.         Chan[chan].fd = -1;
  628.         Chan[chan].state = CHAN_FREE;
  629.             FD_CLR(fd, &Fdread);
  630.             FD_CLR(fd, &Fdexcept);
  631.         close(fd);
  632.         } else {
  633.         ubyte error = 0;
  634.         extern void do_open();
  635.         gwrite(Chan[chan].fd, &error, 1);
  636.         Chan[chan].state = CHAN_OPEN;
  637.         Chan[chan].flags = CHANF_ROK|CHANF_WOK;
  638.         Fdstate[Chan[chan].fd] = do_open;
  639.         }
  640.     }
  641.     break;
  642.     case SCMD_EOFCMD:    /*  EOF on channel        */
  643.     {
  644.         register CEOFCMD *eof = (CEOFCMD *)ptr;
  645.         uword chan = (eof->chanh<<8)|eof->chanl;
  646.  
  647.         if (chan < MAXCHAN && Chan[chan].state == CHAN_OPEN) {
  648.         Chan[chan].flags &= ~eof->flags;
  649.         if (eof->flags & CHANF_ROK) {
  650.             char dummy;
  651.             shutdown(Chan[chan].fd, 1);
  652.             write(Chan[chan].fd, &dummy, 0);
  653.         }
  654.         }
  655.     }
  656.     break;
  657.     case SCMD_QUIT:
  658.     dneterror("QUIT");
  659.     break;
  660.     case SCMD_IOCTL:
  661.     {
  662.         register CIOCTL *cio = (CIOCTL *)ptr;
  663.         uword chan = (cio->chanh<<8)|cio->chanl;
  664.  
  665.         if (chan < MAXCHAN && Chan[chan].state == CHAN_OPEN) {
  666.         switch(cio->cmd) {
  667.         case CIO_SETROWS:
  668.             isetrows(Chan[chan].fd, (cio->valh<<8)|cio->vall);
  669.             break;
  670.         case CIO_SETCOLS:
  671.             isetcols(Chan[chan].fd, (cio->valh<<8)|cio->vall);
  672.             break;
  673.         case CIO_STOP:
  674.             break;
  675.         case CIO_START:
  676.             break;
  677.         case CIO_FLUSH:
  678.             ClearChan(&TxList, chan, 0);
  679.             break;
  680.         }
  681.         }
  682.     }
  683.     break;
  684.     default:
  685.     break;
  686.     }
  687. }
  688.  
  689. replywindow(window)
  690. {
  691.     ubyte rwindow = (window - RPStart) & 7;
  692.     WCBuf[0] = SYNC;
  693.  
  694.     if (DDebug) {
  695.     if (rwindow >= 4 || RPak[rwindow]->state == READY)
  696.         fprintf(stderr, " ACK WINDOW %ld\n", window);
  697.     else
  698.         fprintf(stderr, " NAK WINDOW %ld\n", window);
  699.     }
  700.     if (rwindow >= 4 || RPak[rwindow]->state == READY)  /* data ready */
  701.     WCBuf[1] = PKCMD_ACK | (window << 5);           /* ack it     */
  702.     else
  703.     WCBuf[1] = PKCMD_NAK | (window << 5);           /* nack it    */
  704.     WCBuf[2] = (SYNC << 1) ^ WCBuf[1];
  705.     NetWrite(WCBuf, 3);
  706. }
  707.  
  708.