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 / amiga / dnet / control.c < prev    next >
C/C++ Source or Header  |  1989-12-11  |  13KB  |  574 lines

  1.  
  2. /*
  3.  *  CONTROL.C
  4.  *
  5.  *  DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
  6.  *
  7.  *  Main packet control.  Medium level.  Interprets formatted received
  8.  *  packets and sends formatted tx packets.  Uses low level packet
  9.  *  construction and reception routines in PACKET.C
  10.  */
  11.  
  12. #include "dnet.h"
  13. #include <stdio.h>
  14.  
  15. void do_rupdate();
  16. void do_reccmd();
  17. void replywindow();
  18. void StartWriteTimeout();
  19.  
  20. /*
  21.  *  RTO:    read timeout.   Timeout occured while waiting for the rest of
  22.  *        a packet.  Reset state and restart read.
  23.  *
  24.  *  called from iosink loop, ok if signal mask cleared
  25.  */
  26.  
  27. void
  28. do_rto(ior)
  29. IOT *ior;
  30. {
  31.     NetStartRead(RecvPacket(NULL, 0));
  32. }
  33.  
  34. /*
  35.  *  WTO:    Write timeout (unresolved output windows exist).  Resend a CHECK
  36.  *        command for all unresolved (READY) output windows
  37.  */
  38.  
  39. void
  40. do_wto(ior)
  41. IOT *ior;
  42. {
  43.     short i;
  44.     PKT *pkt;
  45.     short to = 0;
  46.  
  47.     if (Restart) {
  48.     WriteRestart();
  49.     return;
  50.     }
  51.     for (i = 0; i < WPUsed; ++i) {
  52.     pkt = WPak[i];
  53.     if (pkt->state == READY) {
  54.         WriteChk((WPStart + i) & 7);
  55.         ++to;
  56.     }
  57.     }
  58.     if (to)
  59.     StartWriteTimeout(8);
  60. }
  61.  
  62. void
  63. do_rnet(ptr, len)
  64. ubyte *ptr;
  65. long len;
  66. {
  67.     long expect;
  68.     long n;
  69.  
  70.     if (len < 0)
  71.     ptr = NULL;
  72.     expect = RecvPacket(ptr, len);
  73.     n = NetReady();
  74.     if (n > expect)
  75.     expect = n;
  76.     NetStartRead(expect);
  77. }
  78.  
  79. /*
  80.  *  StartWriteTimeout()
  81.  *
  82.  *  Begins a timeout for written packets.  This timeout normally never
  83.  *  occurs even with data errors (the receiver detects missing windows
  84.  *  and sends the appropriate NAK).
  85.  */
  86.  
  87. void
  88. StartWriteTimeout(secs)
  89. {
  90.     if (Wto_act) {
  91.     AbortIO((IOR *)&Wto);
  92.     WaitIO((IOR *)&Wto);
  93.     Wto_act = 0;
  94.     }
  95.     if (secs) {
  96.     Wto.tr_time.tv_secs = secs;
  97.     Wto.tr_time.tv_micro= 0;
  98.     SendIO((IOR *)&Wto);
  99.     Wto_act = 1;
  100.     }
  101. }
  102.  
  103. /*
  104.  *  DO_WUPDATE()
  105.  *
  106.  *  (1) Remove EMPTY windows at head of transmit queue.
  107.  *  (2) Fill up transmit queue with pending requests, if any.
  108.  *  (3) Start timeout for write if did send packet.
  109.  *
  110.  *  CMD 0x20-0x3F   0-31 bytes data
  111.  *    0x40-0x7F   0-N  bytes data (w/ extend byte 0x20-0x7F)
  112.  *    0x80-0xFF   Command.
  113.  *
  114.  *  Note that normal data encoding overhead uses 0x20-0x7F,
  115.  *  thereby allowing 7 bit data to be transmitted with normal
  116.  *  packets instead of expanded (8->6 bits) packets.
  117.  */
  118.  
  119. void
  120. do_wupdate()
  121. {
  122.     static short XPri;
  123.     static ubyte DBuf[MAXPACKET];
  124.     int maxpktsize;
  125.     IOSTD *ior;
  126.     PKT *pkt;
  127.     long len;
  128.     char wrotePkt = 0;
  129.  
  130.     while (WPUsed && WPak[0]->state == EMPTY) {
  131.     pkt = WPak[0];
  132.     WPak[0] = WPak[1];
  133.     WPak[1] = WPak[2];
  134.     WPak[2] = WPak[3];
  135.     WPak[3] = pkt;
  136.     --WPUsed;
  137.     ++WPStart;
  138.     }
  139.     if (Restart)
  140.     return;
  141.  
  142.     /*
  143.      *    Fill new packets and send.
  144.      */
  145.  
  146.     while (WPUsed != 4 && (ior = (IOSTD *)RemHead(&TxList))) {
  147.     long offset = 0;
  148.     if (DDebug)
  149.         printf("Extract Request: %08lx %ld bytes\n", ior, ior->io_Length);
  150.     {
  151.         short npri;
  152.  
  153.         if (ior->io_Command == SCMD_DATA) {
  154.         ubyte chan = (ulong)ior->io_Unit;
  155.         if (Chan[chan].state == CHAN_CLOSE) {   /* channel closed */
  156.             ior->io_Error = 1;
  157.             ReplyMsg((MSG *)ior);
  158.             continue;
  159.         }
  160.         npri = ior->io_Message.mn_Node.ln_Pri << 2;
  161.         } else {
  162.         npri = XPri;
  163.         }
  164.         if (npri >= XPri)
  165.         XPri = npri;
  166.         else {
  167.         if (XPri - npri > 100)
  168.             XPri -= 10;
  169.         else if (XPri - npri > 50)
  170.             XPri -= 5;
  171.         else
  172.             --XPri;
  173.         }
  174.         maxpktsize = MAXPKT - (XPri - npri);
  175.         if (maxpktsize < MINPKT)
  176.         maxpktsize = MINPKT;
  177.     }
  178.     pkt = WPak[WPUsed];
  179.     pkt->state = READY;
  180.  
  181.     for (;;) {
  182.         if (offset > (maxpktsize-8))        /*  not enough room */
  183.         break;
  184.         if (ior->io_Command == SCMD_DATA && (ulong)ior->io_Unit != WChan) {
  185.         /*  CSWITCH */
  186.         WChan = (ulong)ior->io_Unit;
  187.         DBuf[offset+0] = 0x80|SCMD_SWITCH|(2<<3);
  188.         DBuf[offset+1] = WChan >> 8;
  189.         DBuf[offset+2] = WChan;
  190.         offset += 3;
  191.         }
  192.         len = ior->io_Length - ior->io_Actual;
  193.         if (ior->io_Command == SCMD_DATA) {     /*  DATA OUT   */
  194.         if (offset + len > (maxpktsize-4))
  195.             len = (maxpktsize-4) - offset;
  196.         if (len < 0x20) {
  197.             DBuf[offset] = len + 0x20;
  198.             ++offset;
  199.         } else {
  200.             DBuf[offset+0] = 0x40 + len / 96;
  201.             DBuf[offset+1] = 0x20 + len % 96;
  202.             offset += 2;
  203.         }
  204.         BytesOut += len;
  205.         } else {                    /*    COMMAND OUT */
  206.         DBuf[offset] = 0x80|ior->io_Command|(len<<3);
  207.         ++offset;
  208.         }
  209.         BMov((char *)ior->io_Data + ior->io_Actual, DBuf + offset, len);
  210.         offset += len;
  211.         ior->io_Actual += len;
  212.         if (ior->io_Actual == ior->io_Length) {
  213.         ReplyMsg((MSG *)ior);
  214.         ior = (IOSTD *)RemHead(&TxList);        /*  Next packet     */
  215.         if (ior == NULL)
  216.             break;
  217.         }
  218.     }
  219.  
  220.     BuildDataPacket(pkt, (WPStart + WPUsed) & 7, DBuf, offset);
  221.     WritePacket(pkt);
  222.     wrotePkt = 1;
  223.  
  224.     if (ior) {
  225.         ++ior->io_Message.mn_Node.ln_Pri;
  226.         Enqueue(&TxList, (NODE *)ior);
  227.         --ior->io_Message.mn_Node.ln_Pri;
  228.     }
  229.     ++WPUsed;
  230.     ++PacketsOut;
  231.     ResetIdle();
  232.     break;        /*    One at a time, else would take too long */
  233.     }
  234.     if (wrotePkt)
  235.     StartWriteTimeout(8);
  236. }
  237.  
  238.  
  239. void
  240. dumpcheck(ptr)
  241. ubyte *ptr;
  242. {
  243.     short i;
  244.     for (i = 0; i < 8; ++i) {
  245.     if (ptr[i])
  246.         replywindow(i);
  247.     ptr[i] = 0;
  248.     }
  249. }
  250.  
  251. void
  252. do_cmd(ctl, buf, bytes)
  253. uword ctl;    /*  usually just 8 bits though    */
  254. ubyte *buf;
  255. {
  256.     ubyte window = ctl & PKF_SEQUENCE;
  257.     ubyte rwindow;
  258.     static ubyte Chk, Chkwin[8];
  259.  
  260.     if (ctl == 0xFFFF) {
  261.     if (Chk) {
  262.         dumpcheck(Chkwin);
  263.         Chk = 0;
  264.     }
  265.     return;
  266.     }
  267.  
  268.     if (DDebug)
  269.     printf("RECV-PACKET %02x %4ld bytes\n", ctl, bytes);
  270.  
  271.     if ((ctl & PKF_MASK) == PKCMD_CHECK) {
  272.     Chkwin[window] = 1;
  273.     Chk = 1;
  274.     return;
  275.     }
  276.     if (Chk) {
  277.     dumpcheck(Chkwin);
  278.     Chk = 0;
  279.     }
  280.     switch(ctl & PKF_MASK) {
  281.     case PKCMD_WRITE:
  282.     case PKCMD_WRITE6:
  283.     case PKCMD_WRITE7:
  284.     rwindow = (window - RPStart) & 7;
  285.     if (rwindow < 4) {
  286.         BMov(buf, RPak[rwindow]->data, bytes);
  287.         RPak[rwindow]->buflen = bytes;  /*    dummy    */
  288.         RPak[rwindow]->state = READY;
  289.         do_rupdate();
  290.  
  291.         /*
  292.          *    Check for missing receive packet.  rwindow 1..3 and
  293.          *    (rwindow - 1) != READY
  294.          */
  295.  
  296.         if (rwindow && RPak[rwindow-1]->state != READY)
  297.         WriteNak((window - 1) & 7);
  298.     }
  299.     replywindow(window);
  300.     break;
  301.     case PKCMD_ACK:
  302.     rwindow = (window - WPStart) & 7;
  303.     if (rwindow < WPUsed)       /*  mark as sent    */
  304.         WPak[rwindow]->state = EMPTY;
  305.     break;
  306.     case PKCMD_NAK:            /*    resend        */
  307.     rwindow = (window - WPStart) & 7;
  308.     if (rwindow < WPUsed) {     /*  resend          */
  309.         ++PacketsResent;
  310.         WritePacket(WPak[rwindow]);
  311.         StartWriteTimeout(8);
  312.     } else {
  313.         printf("Soft Error: Illegal NAK: %ld %ld %ld %ld\n",
  314.         window, WPStart, rwindow, WPUsed
  315.         );
  316.     }
  317.     break;
  318.     case PKCMD_RESTART:
  319.     case PKCMD_ACKRSTART:
  320.     if ((ctl & PKF_MASK) == PKCMD_ACKRSTART)
  321.         Restart = 0;
  322.     do_netreset();
  323.     /* RxPtr? */
  324.  
  325.     if ((ctl & PKF_MASK) == PKCMD_RESTART) {
  326.         static ubyte buf[32];
  327.  
  328.         strcpy(buf, " ");
  329.  
  330.         /*
  331.          *    note, restart packet may contain only ascii 0x20-0x7F
  332.          *    00 is definitely out.
  333.          */
  334.  
  335.         WritePacket(BuildRestartAckPacket(buf, strlen(buf)));
  336.         StartWriteTimeout(5);
  337.     }
  338.     break;
  339.     }
  340.     do_rupdate();
  341. }
  342.  
  343. /*
  344.  *  Multiplex data onto the low level stream
  345.  *
  346.  *  0x20-0x3F    0-31 bytes of data for current channel
  347.  *  0x80-0xBF    control-command w/0-7 bytes of data
  348.  *  0x40-0x7F    this + extend byte (0x20-0x7F) for long data pkts
  349.  */
  350.  
  351. void
  352. do_rupdate()
  353. {
  354.     while (RPak[0]->state == READY) {
  355.     PKT *pkt = RPak[0];
  356.     ubyte *ptr = pkt->data;
  357.     uword len;
  358.     uword iolen = pkt->buflen;
  359.     ubyte cmd;
  360.  
  361.     while (iolen) {
  362.         cmd = SCMD_DATA;
  363.         len = ptr[0];
  364.         ++ptr;
  365.         --iolen;
  366.         if (len >= 128) {
  367.         cmd = len & 7;
  368.         len = (len >> 3) & 7;
  369.         } else {
  370.         if (len < 0x40) {
  371.             len -= 0x20;
  372.             if (len < 0) {
  373.             printf("HLP len error1 %d\n", len);
  374.             len = 0;
  375.             }
  376.         } else {
  377.             if (*ptr < 0x20)
  378.             printf("HLP len error2 %02x %02x\n", len, *ptr);
  379.             len = (len - 0x40) * 96 + (*ptr - 0x20);
  380.             ++ptr;
  381.             --iolen;
  382.         }
  383.         }
  384.         iolen -= len;
  385.         if (DDebug)
  386.         printf("RECEIVE CMD %2ld ", cmd);
  387.         do_reccmd(cmd, ptr, len);
  388.         ptr += len;
  389.     }
  390.     RPak[0] = RPak[1];
  391.     RPak[1] = RPak[2];
  392.     RPak[2] = RPak[3];
  393.     RPak[3] = pkt;
  394.     pkt->state = EMPTY;
  395.     ++RPStart;
  396.     }
  397. }
  398.  
  399. void
  400. do_reccmd(cmd, ptr, len)
  401. int cmd;
  402. ubyte *ptr;
  403. int len;
  404. {
  405.     switch(cmd) {
  406.     case SCMD_DATA:    /*  data for channel    */
  407.     if (RChan < MAXCHAN && (Chan[RChan].flags & CHANF_ROK)) {
  408.         IOSTD *ior = AllocMem(sizeof(IOSTD), MEMF_PUBLIC);
  409.         ior->io_Unit = (struct Unit *)RChan;
  410.         ior->io_Data = AllocMem(len, MEMF_PUBLIC);
  411.         ior->io_Length = len;
  412.         ior->io_Actual = 0;
  413.         BMov(ptr, ior->io_Data, len);
  414.         ior->io_Message.mn_Node.ln_Name = (char *)PKT_REQ;
  415.         ior->io_Command = DNCMD_WRITE;
  416.         ior->io_Message.mn_ReplyPort = IOSink;
  417.         PutMsg(Chan[RChan].port, (MSG *)ior);
  418.         BytesIn += len;
  419.         ResetIdle();    /*  not idle, have received data    */
  420.     }
  421.     break;
  422.     case SCMD_SWITCH:
  423.     RChan = (ptr[0]<<8)|ptr[1];
  424.     break;
  425.     case SCMD_OPEN:
  426.     {
  427.         COPEN *cop = (COPEN *)ptr;
  428.         PORT *port;
  429.         CACKCMD ack;
  430.         char buf[32];
  431.         uword chan = (cop->chanh << 8) | cop->chanl;
  432.         uword portnum = (cop->porth << 8) | cop->portl;
  433.  
  434.         ack.chanh = cop->chanh;
  435.         ack.chanl = cop->chanl;
  436.         ack.error = 0;
  437.  
  438.         if (chan >= MAXCHAN || Chan[chan].state) {
  439.         ack.error = 33;     /* magic */
  440.         WriteStream(SCMD_ACKCMD, &ack, sizeof(CACKCMD), (uword)-1);
  441.         break;
  442.         }
  443.         sprintf(buf, "DNET.PORT.%ld", portnum);
  444.         if ((port = (PORT *)FindPort(buf)) == NULL) {
  445.         RunServer(portnum);
  446.         if ((port = (PORT *)FindPort(buf)) == NULL) {
  447.             ack.error = 2;
  448.             WriteStream(SCMD_ACKCMD, &ack, sizeof(CACKCMD), (uword)-1);
  449.             break;
  450.         }
  451.         }
  452.         /*    ln_Name type of 0 causes reply to go to DNetPort    */
  453.         WritePort(port, DNCMD_SOPEN, NULL, 0, 0, chan);
  454.         Chan[chan].state = CHAN_ROPEN;
  455.         Chan[chan].pri = cop->pri;
  456.     }
  457.     break;
  458.     case SCMD_CLOSE:    /*  receive close   */
  459.     {
  460.         CCLOSE *clo = (CCLOSE *)ptr;
  461.         uword chan = (clo->chanh<<8)|clo->chanl;
  462.  
  463.         if (DDebug)
  464.         printf("Remote close, chan %d state %d\n", chan, Chan[chan].state);
  465.  
  466.         if (chan >= MAXCHAN || Chan[chan].state == CHAN_FREE) {
  467.         break;
  468.         }
  469.         Chan[chan].state = CHAN_CLOSE;
  470.         Chan[chan].flags |= CHANF_RCLOSE;
  471.         Chan[chan].flags &= ~(CHANF_ROK|CHANF_WOK);
  472.         if (Chan[chan].flags & CHANF_LCLOSE) {
  473.         if (DDebug)
  474.             printf("Local already closed, reply %08lx\n", Chan[chan].ior);
  475.         Chan[chan].state = CHAN_FREE;
  476.         ReplyMsg((MSG *)Chan[chan].ior);
  477.         Chan[chan].ior = NULL;
  478.         } else {    /*  send EOF  */
  479.         if (DDebug)
  480.             printf("Local not already closed\n");
  481.         WritePort(Chan[chan].port, DNCMD_CLOSE, NULL, 0, PKT_REQ, chan);
  482.         }
  483.     }
  484.     break;
  485.     case SCMD_ACKCMD:    /*  acknowledge of my open    */
  486.     {
  487.         CACKCMD *cack = (CACKCMD *)ptr;
  488.         uword chan = (cack->chanh<<8)|cack->chanl;
  489.         if (chan >= MAXCHAN || Chan[chan].state != CHAN_LOPEN) {
  490.         break;
  491.         }
  492.         /*
  493.          *    Channel in use (collision), try again
  494.          */
  495.         if (cack->error == 33) {
  496.         uword newchan = alloc_channel();
  497.         COPEN co;
  498.         if (newchan < MAXCHAN) {
  499.             Chan[newchan] = Chan[chan];
  500.             Chan[chan].state = CHAN_FREE;
  501.             Chan[chan].ior = NULL;
  502.             co.chanh = newchan >> 8;
  503.             co.chanl = newchan;
  504.             co.porth = (ulong)Chan[newchan].ior->io_Unit >> 8;
  505.             co.portl = (ulong)Chan[newchan].ior->io_Unit;
  506.             co.error = 0;
  507.             co.pri = Chan[chan].pri;
  508.             WriteStream(SCMD_OPEN, &co, sizeof(COPEN), chan);
  509.             break;
  510.         }
  511.         }
  512.         if (cack->error) {
  513.         Chan[chan].state = CHAN_FREE;
  514.         Chan[chan].ior->io_Error = cack->error;
  515.         ReplyMsg((MSG *)Chan[chan].ior);
  516.         Chan[chan].ior = NULL;
  517.         } else {
  518.         Chan[chan].state = CHAN_OPEN;
  519.         Chan[chan].ior->io_Error = 0;
  520.         Chan[chan].ior->io_Unit = (struct Unit *)chan;
  521.         Chan[chan].flags = CHANF_ROK|CHANF_WOK;
  522.         ReplyMsg((MSG *)Chan[chan].ior);
  523.         Chan[chan].ior = NULL;
  524.         }
  525.     }
  526.     break;
  527.     case SCMD_EOFCMD:    /*  EOF on channel        */
  528.     {
  529.         CEOFCMD *eof = (CEOFCMD *)ptr;
  530.         uword chan = (eof->chanh<<8)|eof->chanl;
  531.  
  532.         if (chan < MAXCHAN && Chan[chan].state == CHAN_OPEN) {
  533.         Chan[chan].flags &= ~eof->flags;
  534.         if (eof->flags & CHANF_ROK)
  535.             WritePort(Chan[chan].port, DNCMD_EOF, NULL, 0, PKT_REQ, chan);
  536.         } else {
  537.         printf("SCMD_EOFCMD: Error chan %ld  state %ld\n",
  538.             chan, Chan[chan].state
  539.         );
  540.         }
  541.     }
  542.     break;
  543.     case SCMD_IOCTL:
  544.     {
  545.         CIOCTL *cio = (CIOCTL *)ptr;
  546.         uword chan = (cio->chanh<<8)|cio->chanl;
  547.  
  548.         if (Chan[chan].state == CHAN_OPEN)
  549.         WritePort(Chan[chan].port, DNCMD_IOCTL, cio, sizeof(*cio), PKT_REQ, chan);
  550.     }
  551.     break;
  552.     default:
  553.     if (DDebug)
  554.         printf("BAD SCMD, %ld\n", cmd);
  555.     break;
  556.     }
  557. }
  558.  
  559. void
  560. replywindow(window)
  561. int window;
  562. {
  563.     ubyte rwindow = (window - RPStart) & 7;
  564.  
  565.     if (rwindow >= 4 || RPak[rwindow]->state == READY) {  /* data ready */
  566.     WriteAck(window);
  567.     ++PacketsIn;
  568.     } else {
  569.     WriteNak(window);
  570.     ++PacketsNakd;
  571.     }
  572. }
  573.  
  574.