home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d145 / dnet.lha / Dnet / amiga / dnet / control.c < prev    next >
C/C++ Source or Header  |  1988-05-26  |  14KB  |  603 lines

  1.  
  2. /*
  3.  *  CONTROL.C
  4.  *
  5.  *  DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
  6.  *
  7.  */
  8.  
  9. #include "dnet.h"
  10. #include <stdio.h>
  11.  
  12. static ubyte Dctl;
  13.  
  14. /*
  15.  *  RTO:    read timeout.   Timeout occured while waiting for the rest of
  16.  *        a packet.  Reset state and restart read.
  17.  *
  18.  *  called from iosink loop, ok if signal mask cleared
  19.  */
  20.  
  21. do_rto(ior)
  22. IOT *ior;
  23. {
  24.     AbortIO(RNet);
  25.     WaitIO(RNet);
  26.  
  27.     RNet->io_Data = (APTR)&Raux->sync;
  28.     RNet->io_Length = 3;
  29.     SendIO(RNet);
  30.     if (RState == RS_DATA && (Dctl & PKF_MASK) == PKCMD_WRITE)
  31.     replywindow(Dctl >> 5);     /* NAK the packet */
  32.     RState = 0;
  33. }
  34.  
  35. /*
  36.  *  WTO:    Write timeout (unresolved output windows exist).  Resend a CHECK
  37.  *        command for all unresolved (READY) output windows
  38.  */
  39.  
  40. void
  41. do_wto(ior)
  42. {
  43.     register short i;
  44.     register PKT *pkt;
  45.  
  46.     if (Restart) {
  47.     NetWrite(RestartPkt, 3, 1);
  48.     return;
  49.     }
  50.     for (i = 0; i < WPUsed; ++i) {
  51.     pkt = WPak[i];
  52.     if (pkt->state == READY)    /*  send check  */
  53.         NetWrite(CheckPkt[(WPStart+i)&7], 3, 1);
  54.     }
  55. }
  56.  
  57. /*
  58.  *  RNET:   Receved data ready from network.  The RNet request will
  59.  *        automagically be reissued on return.
  60.  *
  61.  *  NOTE:   The buffer the data is contained in can be anything, and
  62.  *        is not restricted to the Auxillary request this routine uses.
  63.  *
  64.  *        called from iosink loop, signal mask can be cleared.
  65.  */
  66.  
  67. do_rnet(ior)
  68. IOR *ior;
  69. {
  70.     register ubyte *ptr = (ubyte *)ior->io_Data;
  71.     register long len  = ior->io_Actual;
  72.     long n;
  73.     ubyte cd;
  74.     static uword dlen;
  75.     static uword dblen;
  76.  
  77.     if (len <= 0) {
  78.     len = 0;
  79.     RState = RS_SYNC;
  80.     }
  81.     while (len) {
  82.     switch(RState) {
  83.     case RS_SYNC:
  84.         --len;
  85.         if (*ptr++ == SYNC)
  86.         RState = RS_CTL;
  87.         break;
  88.     case RS_CTL:
  89.         --len;
  90.         Dctl = *ptr++;
  91.         RState = RS_CCHK;
  92.         break;
  93.     case RS_CCHK:
  94.         if ((ubyte)(((SYNC<<1)^Dctl)) == *ptr) {
  95.         ++ptr;
  96.         --len;
  97.         if (Dctl & PKF_DATA) {
  98.             RState = RS_LEN1;
  99.             break;
  100.         }
  101.         RState = RS_SYNC;
  102.         do_cmd(Dctl, NULL, 0);
  103.         } else {
  104.         if (len) {      /*  Resync at earliest point    */
  105.             ++len;
  106.             --ptr;
  107.         }
  108.         }
  109.         RState = RS_SYNC;
  110.         break;
  111.     case RS_LEN1:
  112.         dlen = *ptr;
  113.         ++ptr;
  114.         --len;
  115.         RState = RS_LEN2;
  116.         break;
  117.     case RS_LEN2:
  118.         dlen = (dlen << 8) + *ptr + 2;
  119.         if (dlen < 2)
  120.         fprintf(stderr, "WARNING, DATALEN <2: %02lx %ld\n", Dctl, dlen);
  121.         if (dlen > MAXPKT+2) {
  122.         fprintf(stderr, "DATALEN FAILURE: %02lx %ld\n", Dctl, dlen);
  123.         RState = RS_SYNC;
  124.         break;
  125.         }
  126.         ++ptr;
  127.         --len;
  128.         dblen = 0;
  129.         RState = RS_DATA;
  130.         break;
  131.     case RS_DATA:
  132.         len += dblen;    /*  move to beginning of data buffer    */
  133.         ptr -= dblen;
  134.         if (dlen <= len) {
  135.         register uword chk = chkbuf(ptr, dlen - 2);
  136.         if ((chk >> 8) == ptr[dlen-2] && (ubyte)chk == ptr[dlen-1]) {
  137.             do_cmd(Dctl, ptr, dlen-2);
  138.             len -= dlen;
  139.             ptr += dlen;
  140.         } else {
  141.             if ((Dctl & PKF_MASK) == PKCMD_WRITE)
  142.             replywindow(Dctl >> 5); /*  NAK the packet */
  143.         }
  144.         RState = RS_SYNC;
  145.         } else {
  146.         goto break2;    /*  incomplete read  */
  147.         }
  148.         break;
  149.     }
  150.     }
  151. break2:
  152.     if (Rto_act) {
  153.     AbortIO(&Rto);
  154.     WaitIO(&Rto);
  155.     Rto_act = 0;
  156.     }
  157.     n = NetReady(ior, &cd);
  158.     if (n > MAXPKT)
  159.     n = MAXPKT;
  160.     switch(RState) {
  161.     default:
  162.     printf("SoftError: Illegal state %ld\n", RState);
  163.     RState = RS_SYNC;
  164.     /* fall through */
  165.     case RS_SYNC:    /*  Wait for sync & cmd.  No timeout needed    */
  166.     RNet->io_Data = (APTR)&Raux->sync;
  167.     RNet->io_Length = MAX(3, n);
  168.     break;
  169.     case RS_CTL:    /*  Have sync, need CTL and CCHK.        */
  170.     RNet->io_Data = (APTR)&Raux->ctl;
  171.     RNet->io_Length = MAX(2, n);
  172.     break;
  173.     case RS_CCHK:
  174.     RNet->io_Data = (APTR)&Raux->cchk;
  175.     RNet->io_Length = MAX(1, n);
  176.     break;
  177.     case RS_LEN1:
  178.     RNet->io_Data = (APTR)&Raux->lenh;
  179.     RNet->io_Length = MAX(2, n);
  180.     break;
  181.     case RS_LEN2:
  182.     RNet->io_Data = (APTR)&Raux->lenl;
  183.     RNet->io_Length = MAX(1, n);
  184.     break;
  185.     case RS_DATA:    /*  need dlen, have len.  Start read request and TO   */
  186.     if (ptr != Raux->data && len)
  187.         CopyMem(ptr, Raux->data, len);
  188.     dblen = len;
  189.     RNet->io_Data = (APTR)((char *)Raux->data + dblen);
  190.     RNet->io_Length = dlen - len;
  191.     Rto.tr_time.tv_secs = RTimeoutVal / 1000000;    /*  packet to  */
  192.     Rto.tr_time.tv_micro= RTimeoutVal % 1000000;
  193.     SendIO(&Rto);
  194.     Rto_act = 1;
  195.     break;
  196.     }
  197.     do_wupdate();
  198.     return ((cd) ? 1 : -1);
  199. }
  200.  
  201. /*
  202.  *  WNET:   The last data packet has been sent to the network...  Start a
  203.  *        timeout sequence (1 second).  If this times out we will send
  204.  *        a CHECK packet for all unresolved transmission windows.
  205.  */
  206.  
  207. do_wnet()
  208. {
  209.     if (Wto_act) {
  210.     AbortIO(&Wto);
  211.     WaitIO(&Wto);
  212.     }
  213.     Wto.tr_time.tv_secs = WTimeoutVal / 1000000;
  214.     Wto.tr_time.tv_micro= WTimeoutVal % 1000000;
  215.     SendIO(&Wto);
  216.     Wto_act = 1;
  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 IOR *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.     while (WPUsed != 4 && (ior = (IOR *)RemHead(&TxList))) {
  252.     register long offset = 0;
  253.     if (DDebug)
  254.         printf("Extract Request: %08lx %ld bytes\n", ior, ior->io_Length);
  255.     {
  256.         short npri;
  257.  
  258.         if (ior->io_Command == SCMD_DATA) {
  259.         ubyte chan = (ulong)ior->io_Unit;
  260.         if (Chan[chan].state == CHAN_CLOSE) {   /* channel closed */
  261.             ior->io_Error = 1;
  262.             ReplyMsg(ior);
  263.             continue;
  264.         }
  265.         npri = ior->io_Message.mn_Node.ln_Pri << 2;
  266.         } else {
  267.         npri = XPri;
  268.         }
  269.         if (npri >= XPri)
  270.         XPri = npri;
  271.         else {
  272.         if (XPri - npri > 100)
  273.             XPri -= 10;
  274.         else if (XPri - npri > 50)
  275.             XPri -= 5;
  276.         else
  277.             --XPri;
  278.         }
  279.         maxpktsize = MAXPKT - (XPri - npri);
  280.         if (maxpktsize < MINPKT)
  281.         maxpktsize = MINPKT;
  282.     }
  283.     pkt = WPak[WPUsed];
  284.     pkt->state = READY;
  285.     pkt->sync  = SYNC;
  286.     pkt->ctl   = PKCMD_WRITE | PKF_DATA | ((WPStart + WPUsed)<<5);
  287.     pkt->cchk = (pkt->sync << 1) ^ pkt->ctl;
  288.     for (;;) {
  289.         if (offset > (maxpktsize-8))        /*  not enough room */
  290.         break;
  291.         if (ior->io_Command == SCMD_DATA && (ulong)ior->io_Unit   != WChan) {
  292.         /*  CSWITCH */
  293.         WChan = (ulong)ior->io_Unit;
  294.         pkt->data[offset+0] = 0x80|SCMD_SWITCH|(2<<3);
  295.         pkt->data[offset+1] = WChan >> 8;
  296.         pkt->data[offset+2] = WChan;
  297.         offset += 3;
  298.         }
  299.         len = ior->io_Length - ior->io_Actual;
  300.         if (ior->io_Command == SCMD_DATA) {     /*  DATA    */
  301.         if (offset + len > (maxpktsize-4))
  302.             len = (maxpktsize-4) - offset;
  303.         if (len < 128) {
  304.             pkt->data[offset] = len;
  305.             ++offset;
  306.         } else {
  307.             pkt->data[offset+0] = (len>>8)|0xC0;
  308.             pkt->data[offset+1] = len;
  309.             offset += 2;
  310.         }
  311.         } else {                    /*    COMMAND */
  312.         pkt->data[offset] = 0x80|ior->io_Command|(len<<3);
  313.         ++offset;
  314.         }
  315.         CopyMem((char *)ior->io_Data + ior->io_Actual, pkt->data + offset, len);
  316.         offset += len;
  317.         ior->io_Actual += len;
  318.         if (ior->io_Actual == ior->io_Length) {
  319.         ReplyMsg(ior);
  320.         ior = (IOR *)RemHead(&TxList);        /*  Next packet     */
  321.         if (ior == NULL)
  322.             break;
  323.         }
  324.     }
  325.     pkt->iolength = offset + OVERHEAD;
  326.     pkt->lenh = offset >> 8;
  327.     pkt->lenl = offset;
  328.     {
  329.         register uword chksum = chkbuf(pkt->data, offset);
  330.         pkt->data[offset+0] = chksum >> 8;
  331.         pkt->data[offset+1] = chksum;
  332.     }
  333.     NetWrite(&pkt->sync, pkt->iolength, 1);
  334.     if (ior) {
  335.         ++ior->io_Message.mn_Node.ln_Pri;
  336.         Enqueue(&TxList, ior);
  337.         --ior->io_Message.mn_Node.ln_Pri;
  338.     }
  339.     ++WPUsed;
  340.     }
  341. }
  342.  
  343. do_cmd(ctl, buf, bytes)
  344. ubyte ctl;
  345. ubyte *buf;
  346. {
  347.     ubyte window = ctl >> 5;
  348.     ubyte rwindow;
  349.  
  350.     switch(ctl & PKF_MASK) {
  351.     case PKCMD_WRITE:
  352.     rwindow = (window - RPStart) & 7;
  353.     if (rwindow < 4) {
  354.         CopyMem(buf, RPak[rwindow]->data, bytes);
  355.         RPak[rwindow]->iolength = bytes;
  356.         RPak[rwindow]->state = READY;
  357.         do_rupdate();
  358.     }
  359.     replywindow(window);
  360.     break;
  361.     case PKCMD_CHECK:
  362.     replywindow(window);
  363.     break;
  364.     case PKCMD_ACK:
  365.     rwindow = (window - WPStart) & 7;
  366.     if (rwindow < WPUsed)       /*  mark as sent    */
  367.         WPak[rwindow]->state = EMPTY;
  368.     break;
  369.     case PKCMD_NAK:            /*    resend        */
  370.     rwindow = (window - WPStart) & 7;
  371.     if (rwindow < WPUsed) {     /*  resend          */
  372.         NetWrite(&WPak[rwindow]->sync, WPak[rwindow]->iolength, 0);
  373.     } else {
  374.         puts("Soft Error: Illegal NAK");
  375.     }
  376.     break;
  377.     case PKCMD_RESTART:
  378.     case PKCMD_ACKRSTART:
  379.     if ((ctl & PKF_MASK) == PKCMD_ACKRSTART)
  380.         Restart = 0;
  381.     do_netreset();
  382.     /* RxPtr? */
  383.  
  384.     if ((ctl & PKF_MASK) == PKCMD_RESTART) {
  385.         short len;
  386.         uword chksum;
  387.         static ubyte buf[32];
  388.  
  389.         NetWrite(NULL, 0, 0);
  390.         strcpy(buf+5, HostName);
  391.         len = strlen(buf+5)+1;
  392.         buf[0] = SYNC;
  393.         buf[1] = PKCMD_ACKRSTART | PKF_DATA;
  394.         buf[2] = (SYNC << 1) ^ buf[1];
  395.         buf[3] = 0;
  396.         buf[4] = len;
  397.         chksum = chkbuf(buf+5, len);
  398.         buf[5+len] = chksum >> 8;
  399.         buf[6+len] = chksum;
  400.         NetWrite(buf, 7+len, 1);
  401.     }
  402.     /*
  403.     if (bytes)
  404.         setlistenport(buf);
  405.     else
  406.         setlistenport("");
  407.     */
  408.     break;
  409.     }
  410.     do_rupdate();
  411. }
  412.  
  413. do_rupdate()
  414. {
  415.     while (RPak[0]->state == READY) {
  416.     register PKT *pkt = RPak[0];
  417.     register ubyte *ptr = pkt->data;
  418.     register uword len;
  419.     uword iolen = pkt->iolength;
  420.     ubyte cmd;
  421.  
  422.     while (iolen) {
  423.         cmd = SCMD_DATA;
  424.         len = ptr[0];
  425.         ++ptr;
  426.         --iolen;
  427.         if (len >= 128) {
  428.         if (len < 0xC0) {
  429.             cmd = len & 7;
  430.             len = (len >> 3) & 7;
  431.         } else {
  432.             len = ((len << 8) | *ptr) & 0x3FFF;
  433.             ++ptr;
  434.             --iolen;
  435.         }
  436.         }
  437.         iolen -= len;
  438.         if (DDebug)
  439.         printf("RECEIVE CMD %2ld ", cmd);
  440.         do_reccmd(cmd, ptr, len);
  441.         ptr += len;
  442.     }
  443.     RPak[0] = RPak[1];
  444.     RPak[1] = RPak[2];
  445.     RPak[2] = RPak[3];
  446.     RPak[3] = pkt;
  447.     pkt->state = EMPTY;
  448.     ++RPStart;
  449.     }
  450. }
  451.  
  452. do_reccmd(cmd, ptr, len)
  453. ubyte *ptr;
  454. {
  455.     switch(cmd) {
  456.     case SCMD_DATA:    /*  data for channel    */
  457.     if (RChan < MAXCHAN && (Chan[RChan].flags & CHANF_ROK)) {
  458.         register IOR *ior = (IOR *)AllocMem(sizeof(IOR), MEMF_PUBLIC);
  459.         ior->io_Unit = (struct Unit *)RChan;
  460.         ior->io_Data = (APTR)AllocMem(len, MEMF_PUBLIC);
  461.         ior->io_Length = len;
  462.         ior->io_Actual = 0;
  463.         CopyMem(ptr, ior->io_Data, len);
  464.         ior->io_Message.mn_Node.ln_Name = (char *)PKT_REQ;
  465.         ior->io_Command = DNCMD_WRITE;
  466.         ior->io_Message.mn_ReplyPort = IOSink;
  467.         PutMsg(Chan[RChan].port, ior);
  468.     }
  469.     break;
  470.     case SCMD_SWITCH:
  471.     RChan = (ptr[0]<<8)|ptr[1];
  472.     break;
  473.     case SCMD_OPEN:
  474.     {
  475.         register COPEN *cop = (COPEN *)ptr;
  476.         PORT *port;
  477.         CACKCMD ack;
  478.         char buf[32];
  479.         uword chan = (cop->chanh << 8) | cop->chanl;
  480.         uword portnum = (cop->porth << 8) | cop->portl;
  481.  
  482.         ack.chanh = cop->chanh;
  483.         ack.chanl = cop->chanl;
  484.         ack.error = 0;
  485.  
  486.         if (chan >= MAXCHAN || Chan[chan].state) {
  487.         ack.error = 33;     /* magic */
  488.         WriteStream(SCMD_ACKCMD, &ack, sizeof(CACKCMD), -1);
  489.         break;
  490.         }
  491.         sprintf(buf, "DNET.PORT.%ld", portnum);
  492.         if ((port = (PORT *)FindPort(buf)) == NULL) {
  493.         RunServer(portnum);
  494.         if ((port = (PORT *)FindPort(buf)) == NULL) {
  495.             ack.error = 2;
  496.             WriteStream(SCMD_ACKCMD, &ack, sizeof(CACKCMD), -1);
  497.             break;
  498.         }
  499.         }
  500.         /*    ln_Name type of 0 causes reply to go to DNetPort    */
  501.         WritePort(port, DNCMD_SOPEN, NULL, 0, 0, chan);
  502.         Chan[chan].state = CHAN_ROPEN;
  503.         Chan[chan].pri = cop->pri;
  504.     }
  505.     break;
  506.     case SCMD_CLOSE:    /*  receive close   */
  507.     {
  508.         register CCLOSE *clo = (CCLOSE *)ptr;
  509.         uword chan = (clo->chanh<<8)|clo->chanl;
  510.  
  511.         if (chan >= MAXCHAN || Chan[chan].state == CHAN_FREE) {
  512.         break;
  513.         }
  514.         Chan[chan].state = CHAN_CLOSE;
  515.         Chan[chan].flags |= CHANF_RCLOSE;
  516.         Chan[chan].flags &= ~(CHANF_ROK|CHANF_WOK);
  517.         if (Chan[chan].flags & CHANF_LCLOSE) {
  518.         Chan[chan].state = CHAN_FREE;
  519.         ReplyMsg(Chan[chan].ior);
  520.         Chan[chan].ior = NULL;
  521.         } else {    /*  send EOF  */
  522.         WritePort(Chan[chan].port, DNCMD_CLOSE, NULL, 0, PKT_REQ, chan);
  523.         }
  524.     }
  525.     break;
  526.     case SCMD_ACKCMD:    /*  acknowledge of my open    */
  527.     {
  528.         register CACKCMD *cack = (CACKCMD *)ptr;
  529.         uword chan = (cack->chanh<<8)|cack->chanl;
  530.         if (chan >= MAXCHAN || Chan[chan].state != CHAN_LOPEN) {
  531.         break;
  532.         }
  533.         /*
  534.          *    Channel in use (collision), try again
  535.          */
  536.         if (cack->error == 33) {
  537.         uword newchan = alloc_channel();
  538.         COPEN co;
  539.         if (newchan < MAXCHAN) {
  540.             Chan[newchan] = Chan[chan];
  541.             Chan[chan].state = CHAN_FREE;
  542.             Chan[chan].ior = NULL;
  543.             co.chanh = newchan >> 8;
  544.             co.chanl = newchan;
  545.             co.porth = (ulong)Chan[newchan].ior->io_Unit >> 8;
  546.             co.portl = (ulong)Chan[newchan].ior->io_Unit;
  547.             co.error = 0;
  548.             co.pri = Chan[chan].pri;
  549.             WriteStream(SCMD_OPEN, &co, sizeof(COPEN), chan);
  550.             break;
  551.         }
  552.         }
  553.         if (cack->error) {
  554.         Chan[chan].state = CHAN_FREE;
  555.         Chan[chan].ior->io_Error = cack->error;
  556.         ReplyMsg(Chan[chan].ior);
  557.         Chan[chan].ior = NULL;
  558.         } else {
  559.         Chan[chan].state = CHAN_OPEN;
  560.         Chan[chan].ior->io_Error = 0;
  561.         Chan[chan].ior->io_Unit = (struct Unit *)chan;
  562.         Chan[chan].flags = CHANF_ROK|CHANF_WOK;
  563.         ReplyMsg(Chan[chan].ior);
  564.         Chan[chan].ior = NULL;
  565.         }
  566.     }
  567.     break;
  568.     case SCMD_EOFCMD:    /*  EOF on channel        */
  569.     {
  570.         register CEOFCMD *eof = (CEOFCMD *)ptr;
  571.         uword chan = (eof->chanh<<8)|eof->chanl;
  572.  
  573.         if (chan < MAXCHAN && Chan[chan].state == CHAN_OPEN) {
  574.         Chan[chan].flags &= ~eof->flags;
  575.         if (eof->flags & CHANF_ROK)
  576.             WritePort(Chan[chan].port, DNCMD_EOF, NULL, 0, PKT_REQ, chan);
  577.         } else {
  578.         printf("SCMD_EOFCMD: Error chan %ld  state %ld\n",
  579.             chan, Chan[chan].state
  580.         );
  581.         }
  582.     }
  583.     break;
  584.     default:
  585.     /*
  586.      * actually just unsupported... IOCTL maybe
  587.     printf("BAD SCMD, %ld\n", cmd);
  588.     */
  589.     break;
  590.     }
  591. }
  592.  
  593. replywindow(window)
  594. {
  595.     ubyte rwindow = (window - RPStart) & 7;
  596.  
  597.     if (rwindow >= 4 || RPak[rwindow]->state == READY)  /* data ready */
  598.     NetWrite(AckPkt[window], 3, 0);
  599.     else
  600.     NetWrite(NakPkt[window], 3, 0);
  601. }
  602.  
  603.