home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d109 / uupc.lha / UUpc / Source / dcpgpkt.c < prev    next >
C/C++ Source or Header  |  1987-10-28  |  15KB  |  619 lines

  1. /*            dcpgpkt.c
  2.  
  3.             Revised edition of dcp
  4.  
  5.             Stuart Lynne May/87
  6.  
  7.             Copyright (c) Richard H. Lamb 1985, 1986, 1987
  8.             Changes Copyright (c) Stuart Lynne 1987
  9.  
  10. */
  11. /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
  12. /* 3-window "g" ptotocol */
  13. /* Thanks got to John Gilmore for sending me a copy of Greg Chesson's 
  14. UUCP protocol description-- Obviously invaluable
  15. Thanks also go to Andrew Tannenbaum for the section on Siding window
  16. protocols with a program example in his "Computer Networks" book 
  17.  
  18. MAINTENANCE NOTES:
  19.   25Aug87 - Allow for up to 7 windows - Jal
  20.  
  21. */
  22.  
  23. #include "dcp.h"
  24. #define PKTSIZE         64
  25. #define PKTSIZ2         2
  26. #define HDRSIZE         6
  27. #define MAXTRY          4
  28.  
  29. #define MAXERR  200        /* Dont want to quit in a middle of a long file*/
  30. #define TIMEOUT 4        /* could be longer */
  31. #define KPKT    1024/PKTSIZE
  32. #define POK      -1
  33.  
  34. #define MAXWINDOW 7
  35. #define NBUF    8   /* always SAME as MAXSEQ ? */
  36. #define MAXSEQ  8
  37.  
  38. #define between(a,b,c) ((a<=b && b<c) || (c<a && a<=b) || (b<c && c<a))
  39.  
  40. /* packet defin */
  41. static int    rwl, swl, swu, rwu, nerr, nbuffers, npkt, irec, timeout, GOT_SYNC, GOT_HDR;
  42. static int    fseq[NBUF], outlen[NBUF], inlen[NBUF], arr[NBUF];
  43. static int    nwindows;
  44. static char    outbuf[NBUF][PKTSIZE+1], inbuf[NBUF][PKTSIZE+1];
  45. static unsigned char    grpkt[HDRSIZE+1];
  46. static long    ftimer[NBUF], acktmr, naktmr;
  47. /* */
  48. /******************SUB SUB SUB PACKET HANDLER************/
  49. gopenpk()
  50. {
  51.     int    i, j, n1, n2, len;
  52.     char    tmp[PKTSIZE+1];
  53.     pktsize = PKTSIZE; /* change it later after the init */
  54.     msgtime = MSGTIME; /* not sure I need this for "g" proto */
  55.     /* initialize proto parameters */
  56.     swl = nerr = nbuffers = npkt = 0;
  57.     swl = swu = 1;
  58.     rwl = 0;
  59.     rwu = MAXWINDOW - 1;
  60.     nwindows = MAXWINDOW;
  61.     for (i = 0; i < NBUF; i++) {
  62.         ftimer[i] = 0; 
  63.         arr[i] = FALSE; 
  64.     }
  65.     GOT_SYNC = GOT_HDR = FALSE;
  66.     /* 3-way handshake */
  67.     timeout = 2; /* want some timeout capability here */
  68.     gspack(7, 0, 0, 0, tmp);
  69. rsrt:
  70.     if (nerr >= MAXERR) 
  71.         return(-1);
  72.     /* INIT sequence. Easy fix for variable pktsize and windows. */
  73.     /* I didnt since all the machines I talk to use W=3 PKTSZ=64 */
  74.     /* If you do this make sure to reflect the changes in "grpack" */
  75.     /* and "gspack" */
  76.     switch (grpack(&n1, &n2, &len, tmp)) {
  77.     case 7:    
  78.         gspack(6, 0, 0, 0, tmp);
  79.         nwindows = n1;
  80.         if ( nwindows > MAXWINDOW )
  81.            nwindows = MAXWINDOW;
  82.         rwu = nwindows - 1;
  83.         goto rsrt;
  84.     case 6: 
  85.         gspack(5, 0, 0, 0, tmp);
  86.         goto rsrt;
  87.     case 5: 
  88.         break;
  89.     default: 
  90.         nerr++; 
  91.         gspack(7, 0, 0, 0, tmp);
  92.         goto rsrt;
  93.     }
  94.     nerr = 0;
  95.     return(0);      /* channel open */
  96. }
  97.  
  98.  
  99. gclosepk()
  100. {
  101.     int    i;
  102.     char    tmp[PKTSIZE+1];
  103.     timeout = 1;
  104.     for (i = 0; i < MAXTRY; i++) {
  105.         gspack(CLOSE, 0, 0, 0, tmp);
  106.         if (gmachine() == CLOSE) 
  107.             break;
  108.     }
  109.     printmsg( 0, "number of errors %d and pkts xfered %d", nerr, npkt );
  110.     return(0);
  111. }
  112.  
  113.  
  114. /*
  115.  *
  116.  * ggetpkt
  117.  ***** description: Gets no more than a packet's worth of data from
  118. ****               the "packet i/o state machine". May have to
  119. ****               periodically run the pkt machine to get some
  120. ****               packets.
  121. * on input: dont care   getpkt(data,&len)  char *data int len
  122. * on return: data+\0 and length in len. ret(0) if alls well
  123. * ret(-1) if problems.(fail)
  124.  */
  125. ggetpkt(cdata, len)
  126. int    *len;
  127. char    cdata[];
  128. {
  129.     int    i2;
  130.     irec = 1;
  131.     timeout = 0;
  132.     /* WAIT FOR THE DESIRED PACKET */
  133.     while ((arr[rwl]) == FALSE) 
  134.         if (gmachine() != POK) 
  135.             return(-1);
  136.     /* GOT A PKT ! */
  137.     i2 = rwl; /*<-- mod(,rwindow) for larger than 8 seq no.s */
  138.     *len = inlen[i2];
  139.     strncpy(cdata, inbuf[i2], *len);
  140.     arr[i2] = FALSE;
  141.     rwu = (1 + rwu) % MAXSEQ; /* bump rec window */
  142.     npkt++;
  143.     return(0);
  144. }
  145.  
  146.  
  147. /*
  148.  *
  149.  *  sendpkt
  150.  *
  151. *****   description:    Put at most a packet's worth of data  in the pkt state
  152.  ****                   machine for xmission.
  153. *****                   May have to run the pkt machine a few times to get
  154. *****                   an available output slot.
  155.  *
  156.  * on input: char *data int len,flg; len=length of data in data.
  157.  *           flg=2 just send the packet with no wait for ack.
  158.  *           flg>0 zero out the unused part of the buffer. (for UUCP "msg"
  159.  *                                                                   pkts)
  160.  *           flg=0 normal data
  161.  * return:   ret(0) if alls well ret(-1) if problems (fail)
  162.  *
  163. */
  164. gsendpkt(cdata, len, flg)
  165. int    len, flg;
  166. char    *cdata;
  167. {
  168.     int    i, i1;
  169.     long    ttmp;
  170.     irec = 0;
  171.     timeout = 0; /* non-blocking reads */
  172.     /* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been */
  173.     /* acked, wait for acks */
  174.     while (nbuffers >= nwindows) 
  175.         if (gmachine() != POK) 
  176.             return(-1);
  177.     i1 = swu;  /* <--If we ever have more than 8 seq no.s, must mod() here*/
  178.     /* PLACE PACKET IN TABLE AND MARK UNACKED */
  179.     /* fill with zeros or not */
  180.     if (flg) {
  181.         strcpy(outbuf[i1], cdata);
  182.         len = PKTSIZE;
  183.         for (i = strlen(cdata); i < len; i++) 
  184.             outbuf[i1][i] = '\0';
  185.     } else {
  186.         strncpy(outbuf[i1], cdata, len);
  187.         outbuf[i1][len] = '\0';
  188.     }
  189.     /* mark packet  */
  190.     outlen[i1] = len;
  191.     ftimer[i1] = time(&ttmp);
  192.     fseq[i1] = swu;
  193.     swu = (1 + swu) % MAXSEQ;    /* bump send window */
  194.     nbuffers++;
  195.     npkt++;
  196.     /* send it */
  197.     gspack(DATA, rwl, fseq[i1], outlen[i1], outbuf[i1]);
  198.     /* send it once then let the pkt machine take it. wouldnt need this for */
  199.     /* mtasking systems */
  200.     /* sl gmachine(); */
  201.     return(0);
  202. }
  203.  
  204.  
  205. /************     packet machine   ****** RH Lamb 3/87 */
  206. /* Idealy we would like to fork this process off in an infinite loop */
  207. /* and send and rec pkts thru "inbuf" and "outbuf". Cant do this in MS-DOS*/
  208. /* so we setup "getpkt" and "sendpkt" to call this routine often and return */
  209. /* only when the input buffer is empty thus "blocking" the pkt-machine task. */
  210. gmachine()
  211. {
  212.     int    rack, rseq, rlen, i1, i2, dflg;
  213.     char    rdata[PKTSIZE+1];
  214.     long    ttmp, itmp;
  215. reply:
  216.     printmsg( 6, "*send %d<W<%d, rec %d<W<%d, err %d", swl, swu, rwl, rwu, nerr );
  217.     /* waiting for ACKs for swl to swu-1. Next pkt to send=swu */
  218.     /* rwl=expected pkt */
  219.     printmsg( 7, "Kbytes transfered %d errors %d\r", npkt / KPKT, nerr );
  220.     if (nerr >= MAXERR) 
  221.         goto close;
  222.     dflg = 0;
  223.     switch (grpack(&rack, &rseq, &rlen, rdata)) {
  224.     case CLOSE:     
  225.         printmsg( 5, "**got CLOSE");
  226.         goto close;
  227.     case NAK:       
  228.         nerr++;
  229.         acktmr = naktmr = 0; /* stop ack/nak timer */
  230.         printmsg( 5, "**got NAK %d", rack );
  231. nloop:          
  232.         if (between(swl, rack, swu)) { /* resend rack->(swu-1) */
  233.             i1 = rack;
  234.             gspack(DATA, rwl, rack, outlen[i1], outbuf[i1]);
  235.             printmsg( 5, "***resent %d", rack );
  236.             ftimer[i1] = time(&ttmp);
  237.             rack = (1 + rack) % MAXSEQ;
  238.             goto nloop;
  239.         }
  240.         if (dflg) 
  241.             return(POK);
  242.         goto reply; /* any other stuff ? */
  243.         
  244.     case EMPTY:     
  245.         printmsg( 5, "**got EMPTY" );
  246.         itmp = time(&ttmp);
  247.         if (acktmr) 
  248.             if ((itmp - acktmr) >= TIMEOUT) { /* ack timed out*/
  249.                 gspack(ACK, rwl, 0, 0, rdata);
  250.                 acktmr = itmp;
  251.             }
  252.         if (naktmr) 
  253.             if ((itmp - naktmr) >= TIMEOUT) { /*nak timed out*/
  254.                 gspack(NAK, rwl, 0, 0, rdata);
  255.                 naktmr = itmp;
  256.             }
  257.         /* resend any timed out un-acked pkts */
  258.         for (i2 = swl; between(swl, i2, swu); i2 = (1 + i2) % MAXSEQ)  {
  259.             acktmr = naktmr = 0; /* reset ack/nak */
  260.             i1 = i2;
  261.             printmsg( 5, "--->seq,elapst %d %ld", i2, (itmp - ftimer[i1]) );
  262.             if ((itmp - ftimer[i1]) >= TIMEOUT) {
  263.                 printmsg( 5, "***timeout %d", i2 );
  264.                 /* since "g" is "go-back-N", when we time out we */
  265.                 /* must send the last N pkts in order. The generalized*/
  266.                 /* sliding window scheme relaxes this reqirment */
  267.                 nerr++;
  268.                 dflg = 1;  /* same hack */
  269.                 rack = i2;
  270.                 goto nloop;
  271.             }
  272.         }
  273.         return(POK);
  274.     case ACK:       
  275.         printmsg( 5, "**got ACK %d", rack );
  276.         acktmr = naktmr = 0; /* disable ack/nak's */
  277. aloop:          
  278.         if (between(swl, rack, swu)) {   /* S<-- -->(S+W-1)%8 */
  279.             printmsg( 5, "***ACK %d", swl );
  280.             ftimer[swl] = 0;
  281.             nbuffers--;
  282.             swl = (1 + swl) % MAXSEQ;
  283.             dflg = 1;  /* same hack */            /* sl */
  284.             goto aloop;
  285.         }
  286.         if (dflg) 
  287.             return(POK); /* hack for non-mtask sys's */
  288.         /* to empty "inbuf[]" */
  289.         goto reply;
  290.     case DATA:      
  291.         printmsg( 5, "**got DATA %d %d", rack, rseq );
  292.         i1 = (1 + rwl) % MAXSEQ; /* (R+1)%8 <-- -->(R+W)%8 */
  293.         i2 = (1 + rwu) % MAXSEQ;
  294.         if (between(i1, rseq, i2)) {
  295.             if (i1 == rseq) {
  296.                 i1 = rseq;
  297.                 arr[i1] = TRUE;
  298.                 inlen[i1] = rlen;
  299.                 strncpy(inbuf[i1], rdata, rlen);
  300.                 rwl = (rwl + 1) % MAXSEQ;
  301.                 printmsg( 5, "***ACK d %d", rwl );
  302.                 gspack(ACK, rwl, 0, 0, rdata);
  303.                 acktmr = time(&ttmp); /* enable ack/nak tmout*/
  304.                 dflg = 1; /*return to call when finished*/
  305.                 /* in a mtask system, unneccesary */
  306.             } else {
  307.                 nerr++; 
  308.                 printmsg( 5, "***unexpect %d ne %d", rseq, rwl );
  309.             }
  310.         } else {
  311.             nerr++; 
  312.             printmsg( 5, "***wrong seq %d", rseq );
  313.         }
  314.         goto aloop;
  315.     case ERROR:     
  316.         nerr++;
  317.         printmsg( 5, "**got BAD CHK" );
  318.         gspack(NAK, rwl, 0, 0, rdata);
  319.         naktmr = time(&ttmp); /* set nak timer */
  320.         printmsg( 5, "***NAK d %d", rwl );
  321.         goto reply;
  322.     default:        
  323.         printmsg( 5, "**got SCREW UP" );
  324.         goto reply; /* ignore it */
  325.     }
  326. close:          
  327.     gspack(CLOSE, 0, 0, 0, rdata);
  328.     return(CLOSE);
  329. }
  330.  
  331.  
  332. /* */
  333. /*************** FRAMMING *****************************/
  334. /*
  335.  *
  336.  *
  337.  *      send a packet
  338.  * nt2=type nt3=pkrec nt4=pksent len=length<=PKTSIZE cnt1= data * ret(0) always
  339.  */
  340. gspack(nt2, nt3, nt4, len, cnt1)
  341. int    nt2, nt3, nt4, len;
  342. char    cnt1[];
  343. {
  344.     unsigned int    check, i;
  345.     unsigned char    c2, pkt[HDRSIZE+1], dpkerr[10];
  346.     if (len > 64) 
  347.         len = 64;
  348.     if (len == 0) 
  349.         cnt1[0] = '\0';
  350. /**Link testing mods- create artificial errors ***/ /*
  351. printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
  352. gets(dpkerr); 
  353.     if(dpkerr[0] == 's') { sscanf(&dpkerr[1],"%d",&nt4); } /**/
  354.     /** End Link testing mods ***/
  355.     printmsg( 5, "send packet type %d, num=%d, n=%d, len=%d", nt2, nt3, nt4, len );
  356.     printmsg( 5, "data =\n|%s|", cnt1 );
  357.     c2 = '\0';
  358.     pkt[0] = '\020';
  359.     pkt[4] = nt2 << 3;
  360.     nt2 &= 7;
  361.     switch (nt2) {
  362.     case 1:      
  363.         break;                  /* stop protocol */
  364.     case 2:      
  365.         pkt[4] += nt3; 
  366.         break;   /* reject        */
  367.     case 3:      
  368.         break;
  369.     case 4:      
  370.         pkt[4] += nt3; 
  371.         break;   /* ack          */
  372.     case 5:      
  373.         pkt[4] += nwindows;   
  374.         break;
  375.     case 6:      
  376.         pkt[4] += 1;   
  377.         break;   /* pktsiz = 64 (1) */
  378.     case 7:      
  379.         pkt[4] += MAXWINDOW;   
  380.         break;
  381.     case 0:      
  382.         pkt[4] += 0x80 + nt3 + (nt4 << 3);
  383.         c2 = (PKTSIZE - len) & 0xff;
  384.         /* havnt set it up for VERY LONG pkts with a few */
  385.         /* bytes yet (-128) */
  386.         if (c2) { /* short packet handling */
  387.             pkt[4] += 0x40;   /* if len < PKTSIZE */
  388.             for (i = PKTSIZE - 1; i > 0; i--) 
  389.                 cnt1[i] = cnt1[i-1];
  390.             cnt1[0] = c2;
  391.         }
  392.         break;
  393.     }
  394.     pkt[4] &= 0xff;
  395.     if (nt2) {
  396.         pkt[1] = 9;             /* control packet size = 0 (9) */
  397.         check = (0xaaaa - pkt[4]) & 0xffff;
  398.     } else {
  399.         pkt[1] = PKTSIZ2;             /* data packet size = 64 (2) */
  400.         check = checksum(cnt1, PKTSIZE);
  401.         i = pkt[4];/* got to do this on PC for ex-or high bits */
  402.         i &= 0xff;
  403.         check = (check ^ i) & 0xffff;
  404.         check = (0xaaaa - check) & 0xffff;
  405.     }
  406.     pkt[2] = check & 0xff;
  407.     pkt[3] = (check >> 8) & 0xff;
  408.     pkt[5] = (pkt[1] ^ pkt[2] ^ pkt[3] ^ pkt[4]) & 0xff;
  409. /***More Link testing MODS ******/ /*
  410. switch(dpkerr[0]) {
  411. case 'e':   cnt1[10] = -cnt1[10];
  412.             break;
  413. case 'h':    pkt[5] = -pkt[5];
  414.             break;
  415. case 'l':    return;
  416. case 'p':    swrite(pkt,HDRSIZE); 
  417.             if(pkt[1] != 9) swrite(cnt1,PKTSIZE-3);
  418.             return;
  419. default:    break;
  420.     }  /**/
  421.     /******End Link Testing Mods **********/
  422.     swrite(pkt, HDRSIZE);       /* header is 6-bytes long */
  423.     /*      write(flog,pkt,HDRSIZE);   */
  424.     if (pkt[1] != 9) { 
  425.         swrite(cnt1, PKTSIZE);     /* data is always 64
  426.         bytes long */
  427.         /*    write(flog,cnt1,PKTSIZE);   */
  428.     }
  429. }
  430.  
  431.  
  432. /* */
  433. /*
  434.  *
  435.  *      read packet
  436.  * on return: nt3=pkrec nt4=pksent len=length <=PKTSIZE  cnt1=data *
  437.  * ret(type) ok; ret(EMPTY) input buf empty; ret(ERROR) bad header;
  438.  *          ret(EMPTY) lost pkt timeout; ret(ERROR) checksum error;ret(-5) ?
  439. ****NOTE :
  440. ***sread(buf,n,timeout)
  441.     while(TRUE) {
  442.         if(# of chars available >= n) (without dec internal counter)
  443.             read n chars into buf (decrenent internal char counter)
  444.             break
  445.         else
  446.             if(time>timeout) break
  447.     }
  448.     return(# of chars available)
  449. ****END NOTE
  450.  */
  451. grpack(nt3, nt4, len, cnt1)
  452. int    *nt3, *nt4, *len;
  453. char    cnt1[];
  454. {
  455.     unsigned int    nt1, check, checkchk, i;
  456.     unsigned char    c, c2;
  457.     int    ii;
  458.     if (GOT_SYNC) 
  459.         goto get_hdr;
  460.     if (GOT_HDR) 
  461.         goto get_data;
  462.     c = '\0';
  463.     while ((c & 0x7f) != '\020')
  464.         if (sread(&c, 1, timeout) == 0)
  465.             return(EMPTY);
  466.     GOT_SYNC = TRUE;
  467. get_hdr:
  468.     if (sread(&grpkt[1], HDRSIZE - 1, timeout) < (HDRSIZE - 1)) 
  469.         return(EMPTY);
  470.     GOT_SYNC = FALSE;
  471.     /*i = grpkt[1] ^ grpkt[2] ^ grpkt[3] ^ grpkt[4] ^ grpkt[5];*/
  472.      i = (unsigned)grpkt[1] ^ (unsigned)grpkt[2] ^
  473.          (unsigned)grpkt[3] ^ (unsigned)grpkt[4] ^
  474.          (unsigned)grpkt[5];
  475.          
  476.     i &= 0xff;
  477.     printmsg( 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
  478.                 grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5],
  479.                 i
  480.             );
  481.             
  482.     if (i) {               /*  bad header */
  483.         printmsg( 0, "****bad header****" );
  484.         return(ERROR); /* Im not sure whether "g" considers it an empty or error */
  485.     }
  486.     GOT_HDR = TRUE;
  487.     if ((grpkt[1] &= 0x7f) == 9) {       /* control packet */
  488.         *len = 0;
  489.         c = grpkt[4] & 0xff;
  490.         nt1  = c >> 3;
  491.         *nt3 = c & 7;
  492.         *nt4 = 0;
  493.         check = 0;
  494.         checkchk = 0;
  495.         cnt1[*len] = '\0';
  496.         GOT_HDR = FALSE;
  497.     } else {       /* data packet */
  498.         if (grpkt[1] != PKTSIZ2) 
  499.             return(-5);   /* cant handle other than 64*/
  500. get_data:
  501.         if (sread(cnt1, PKTSIZE, timeout) < PKTSIZE) 
  502.             return(EMPTY);
  503.         GOT_HDR = FALSE;
  504.         nt1  = 0;
  505.         c2 = grpkt[4] & 0xff;
  506.         c = c2 & 0x3f;
  507.         *nt4 = c >> 3;
  508.         *nt3 = c & 7;
  509.         i = grpkt[3];
  510.         i = (i << 8) & 0xff00;
  511.         check = grpkt[2];
  512.         check = i | (check & 0xff);
  513.         checkchk = checksum(cnt1, PKTSIZE);
  514.         i = grpkt[4] | 0x80;
  515.         i &= 0xff;
  516.         checkchk = 0xaaaa - (checkchk ^ i);
  517.         checkchk &= 0xffff;
  518.         if (checkchk != check) {
  519.             printmsg( 4, "***checksum error***" );
  520.             return(ERROR);
  521.         }
  522.         *len = PKTSIZE;
  523.         /* havnt set it up for very long pkts yet (>128) RH Lamb */
  524.         if (c2 & 0x40) {
  525.             ii = (cnt1[0] & 0xff);
  526.             *len = (*len - ii) & 0xff;
  527.             for (ii = 0; ii < *len; ii++) 
  528.                 cnt1[ii] = cnt1[ii+1];
  529.         }
  530.         cnt1[*len] = '\0';
  531.     }
  532.     printmsg( 5, "rec  packet type %d, num=%d, n=%d, len=%d", nt1, *nt3, *nt4, *len );
  533.     printmsg( 6, "  checksum rec = %x comp = %x, data=\n|%s|", check, checkchk, cnt1 );
  534.     ii = nt1;
  535.     return(ii);
  536. }
  537.  
  538.  
  539. unsigned    checksum(data, len)
  540. int    len;
  541. char    data[];
  542. {
  543.     unsigned int    i, j, tmp, chk1, chk2;
  544.     chk1 = 0xffff;
  545.     chk2 = 0;
  546.     j = len;
  547.     for (i = 0; i < len; i++) {
  548.         if (chk1 & 0x8000) { 
  549.             chk1 <<= 1; 
  550.             chk1++; 
  551.         } else { 
  552.             chk1 <<= 1; 
  553.         }
  554.         tmp = chk1;
  555.         chk1 += (data[i] & 0xff);
  556.         chk2 += chk1 ^ j;
  557.         if ((chk1 & 0xffff) <= (tmp & 0xffff)) 
  558.             chk1 ^= chk2;
  559.         j--;
  560.     }
  561.     return(chk1 & 0xffff);
  562. }
  563.  
  564.  
  565. /* */
  566. /* 
  567. gwrmsg 
  568.     send a null terminated string out
  569. */
  570. gwrmsg( typ, buf )
  571. char typ;
  572. char *buf; /* null terminated */
  573. {
  574. }
  575.  
  576. /*
  577. grdmsg
  578.     read a null terminated string
  579. */
  580. grdmsg( buf )
  581. char * buf;
  582. {
  583.  
  584. }
  585.  
  586. /*
  587. gwrdata
  588.     read a file and send it out
  589. */
  590. gwrdata( f )
  591. {
  592. }
  593.  
  594. /*
  595. grrdata
  596.     read in data and send to file 
  597. */
  598. grrdata( f )
  599. {
  600. }
  601.  
  602.  
  603. /*
  604. grdblk
  605.     read a block of data in
  606. */
  607. grdblk( blk, len )
  608. {
  609. }
  610.  
  611. /*
  612. gwrblk
  613.     write out a block of data
  614. */
  615. gwrblk( blk, len )
  616. {
  617. }
  618.  
  619.