home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-02-29 | 24.2 KB | 923 lines | [TEXT/R*ch] |
- /*
- * @(#)gio.c 1.8 87/09/29 Copyright 1987 Free Software Foundation, Inc.
- *
- * Copying and use of this program are controlled by the terms of the
- * GNU Emacs General Public License.
- *
- * Derived from:
- * i[$]uuslave.c 1.7 08/12/85 14:04:20
- * which came from the ACGNJ BBS system at +1 201 753 9758. Original
- * author unknown.
- */
-
- #ifndef lint
- char gio_version[] = "@(#)gio.c Fort Pond Research-5.1 7/15/90";
- #endif
-
- #include "includes.h" /* All the system header files */
- #include "uucp.h"
-
- extern int errno;
-
- /*
-
- This program implements the uucp (Unix-to-Unix CoPy) protocol as a
- slave (the recipient of a phone call from another Unix system) or, now,
- a master (the originator of a phone call). This
- protocol is used to transfer mail, files, and Usenet news from Unix
- machine to Unix machine. UUCP comes with Unix (unless you get a
- sleazeoid version like Xenix, where they charge you extra for it). You
- can buy a commercial program for MSDOS, called UULINK, which also
- implements this protocol. UULINK costs $300 and you don't get sources,
- though.
-
- The protocol requires a full 8-bit data path with no characters inserted
- or deleted (e.g. ^S and ^Q are used as DATA characters). Simple serial
- ports and modems do this; most complicated networks do not, at least without
- setting up odd modes and such. Telenet's PC Pursuit works fine though.
-
- The basic flow of the protocol is that the calling machine will send down
- a line of text saying what it wants to do (send a file, receive a file,
- or hang up). (The lines of text are encapsulated into packets; see below.)
- The called machine responds with a "yes" or "no" answer, and if the answer
- was yes, it sends or receives the file. Files are terminated with a
- packet containing 0 bytes of data. Then the system that received the file
- sends a "copy succeeded" or "copy failed" line to the other end, and
- they go back to "what do we do now". A request to hang up should be
- answered "no" if the called machine has some mail or files it wants to
- send to the calling machine; the two machines reverse roles and the calling
- machine goes into "what do we do now". If a hangup request is answered "yes",
- the call is terminated.
-
- The data flow described above is actually sent in packets containing
- checksums and acknowledgements. Each packet can either hold a short
- control message, e.g. an ack, or a data block. The data blocks are
- numbered with a 3-bit counter, and sent with a checksum. If the sender
- has not received an acknowledgement for a data block within a certain
- time, it retransmits the block. The size of a data block is negotiated
- at the start of a call. To send a block with fewer bytes, a "short
- data" block is sent, which is just as big as a "long data" block, but
- contains a 1- or 2-byte count of "how many bytes in this block are just
- padding". This is a cute trick since it always works (e.g. if you want
- to send 1023 out of 1024 bytes, you only need one byte for the count;
- while if you want to send 1 byte out of 1024 then you have enough space
- for the count to be 2 bytes).
-
- The short control messages are used to start the call and negotiate the
- packet size and the "window size", to acknowledge or reject packets,
- and to terminate the packet protocol at the end of a call. The window
- size is how many packets one side can send before it will stop and wait
- for an acknowledgement from the other side. A window size of 1 makes
- for a half-duplex protocol (which is what uuslave currently
- implements), but also makes it easy to implement on micros that don't
- handle serial lines with interrupts. In window 1, you just keep
- sending the same packet until the other side acknowledges it. Unix
- always uses a window size of 3, which is the max that can be dealt with
- given the 3-bit packet numbers (for reasons that would take more space
- than I want to spend here). This gives much better throughput, but
- requires full duplex serial port handling and more complicated
- acknowledgement strategies.
-
- At the low level, full 8-bit bytes are sent out and received on an async serial
- port. The received data is scanned for a DLE (hex 10) which indicates the
- start of a packet, and the next 5 bytes are read and checked. If they
- pass, this is a good packet and it is acted upon. (If it's a data
- packet, we have to read in and check the data part too.) If the checks
- fail, all the bytes read so far should be scanned for another DLE.
- */
-
- /*
- * UUCP "g" procotol definitions
- */
- #define MAGIC 0125252 /* checksum is subtracted from this */
-
- /*
- * What is sent from one machine to the other is a control byte and
- * sometimes a data block following.
- * A packet is a just this, with a frame around the control byte and the
- * data, if any, after the frame. The frame is 6 bytes long, and looks like:
- * DLE K C0 C1 C X
- * where:
- * DLE is a literal ASCII DLE (Data Link Escape) character
- * K is binary, 9 for a control packet, or the packet size log 2, minus 4
- * e.g. K = 2 means 64 byte packet since (K+4) is 6 or 64.
- * 2 2
- * C0 and C1 are low, high order checksums for the entire data section, or
- * are low, high order of (MAGIC minus the control byte).
- * C is the control byte for the message.
- * X is the xor of K, C0, C1, and C.
- * If a packet does not satisfy all of the above checks, it is invalid.
- */
- #define DLE 0x10 /* Start of packet indicator */
-
- #define LENBYTE 1 /* Byte offset from DLE to length */
- #define CBYTE 4 /* Byte offset from DLE to control */
- #define FRAMEBYTE 5 /* Byte offset from DLE to end of frame */
-
- #define KCONTROL 9 /* K value for control packets */
-
- /*
- * A control byte is split into three bit fields: type, x, and y.
- * TT XXX YYY
- * Here are the types:
- */
- #define CONTROL 0 /* Control message */
- #define ALTCHN 1 /* Alternate channel message, unused in UUCP */
- #define LONGDATA 2 /* Long data block -- full size spec'd by K */
- #define SHORTDATA 3 /* Short data block -- first byte or two is
- count. Full K-size packet is sent, even
- though the useful data is shorter. */
-
- char *tt_pr[] = {"CONTROL", "ALTCHN", "LONGDATA", "SHORTDATA"};
-
- /* If TT == CONTROL (also K will == KCONTROL) then
- the x field is: and the Y field means: */
- #define CLOSE 1 /* End of communication */
- #define RJ 2 /* Reject packet last good packet # seen */
- #define SRJ 3 /* Selective reject seq # of bad packet, resend
- SRJ is not used by UUCP. */
- #define RR 4 /* Receiver Ready last good packet # seen */
- #define INITC 5 /* Init phase C window size to hand sender */
- #define INITB 6 /* Init phase B max data segment size (K val)
- to hand sender */
- #define INITA 7 /* Init phase A window size to hand sender */
-
- char *ctrl_pr[] = {"*ZERO*",
- "CLOSE", "RJ", "SRJ", "RR", "INITC", "INITB", "INITA"};
-
- /*
- * If TT == LONGDATA or SHORTDATA then x field is the sequence # of this packet
- * and y field is the last good packet # seen.
- *
- * In both data and RJ/RR packets, the "last good packet # seen" starts off
- * as zero.
- */
-
-
- #define MAX_PACKET 4096
-
- unsigned char msgi[MAX_PACKET+SLOP], /* Incoming packet */
- msgo[MAX_PACKET+SLOP]; /* Outgoing packet */
-
- int firstslave, /* First packet of slave's session */
- msgsize, /* Size of data part of msg */
- tt, xxx, yyy, /* Fields from control byte */
- rseq, /* Last good packet # we received */
- his_rseq, /* Last good packet # HE received */
- wseq; /* Next packet # we will send */
-
- int last_op; /* Last data op: OP_READ or OP_WRITE */
- #define OP_READ 0
- #define OP_WRITE 1
-
- int reject; /* Packet # to reject or NOREJECT */
- #define NOREJECT -1
-
- /* Segments are encoded as (log2 length) - 3, except in INITB packet */
- #ifdef BUFFEREDIO
- int wndsiz = 7; /* Ask them to send up to 7 packets */
- #else
- int wndsiz = 1; /* Ask for window of 1 messages flying */
- #endif
- int segsiz = 2; /* Ask for 64 byte messages */
- int sendseg = 2; /* Size segments other guy wants to see */
- int sendwin = 1; /* Size window other guy wants to see */
-
- int sendbytes = 128; /* sendseg, in bytes */
-
- int segbytes[10] = { /* K value (encoded segment size) */
- -1, /* 0 */
- 32, /* 1 */
- 64, /* 2 */
- 128, /* 3 */
- 256, /* 4 */
- 512, /* 5 */
- 1024, /* 6 */
- 2048, /* 7 */
- 4096, /* 8 */
- 0, /* 9 = KCONTROL */
- };
-
- /*
- * Low level output routines. These send packets without checking
- * whether they got properly received.
- *
- * writeframe():
- *
- * Finish off an outgoing frame in msgo and queue it up to be written
- * to the serial port.
- *
- * This routine is called to send each and every packet.
- */
- int
- writeframe(cksm)
- int cksm;
- {
-
- msgo[0] = DLE;
- msgo[2] = cksm;
- msgo[3] = cksm >> 8;
- msgo[5] = msgo[1] ^ msgo[2] ^ msgo[3] ^ msgo[4];
-
- if (DEBUG_LEVEL(9)) {
- int i, maxlen;
-
- printf("T ");
- maxlen = segbytes[msgo[LENBYTE]] + 6;
- for (i = 0; i < maxlen; i++)
- printf("%02x ",msgo[i] & 0xFF);
- putchar('\n');
- }
- if (DEBUG_LEVEL(6)) {
- int t, x, y;
-
- t = msgo[CBYTE] >> 6;
- x = (msgo[CBYTE] >> 3) & 7;
- y = msgo[CBYTE] & 7;
- if ((long)t == (long)CONTROL)
- printf("Sent: CONTROL %s %d\n",
- ctrl_pr[x], y);
- else
- printf("Sent: %s %d %d\n",
- tt_pr[t], x, y);
- }
-
- /*
- * In our window=1 implementation, we just queue the packet
- * up for transmission here (by leaving it in msgo[]). It
- * will be written next time we go through inpkt().
- */
- last_op = OP_WRITE; /* Remember to avoid overwriting the packet */
- return 0; /* Never aborts */
- }
-
- /* Send an ack */
- int
- ackmsg()
- {
-
- msgo[1] = KCONTROL;
- if ((long)reject != (long)NOREJECT)
- msgo[4] = (CONTROL << 6) | (RJ << 3) | reject;
- else
- msgo[4] = (CONTROL << 6) | (RR << 3) | rseq;
- reject = NOREJECT;
- return writeframe((int)(MAGIC - msgo[4]));
- }
-
-
- /* Send a control message other than an ack */
- int
- ctlmsg(byte)
- char byte;
- {
-
- msgo[1] = KCONTROL;
- msgo[4] = (CONTROL << 6) | byte;
- return writeframe((int)(MAGIC - msgo[4]));
- }
-
- /*
- * Medium level output routine. This sends a short or long data packet
- * and figures out when to retransmit and/or insert acknowledgements as
- * needed.
- */
- sendpacket(s, n, sorl)
- char *s;
- int n;
- int sorl; /* SHORTDATA or LONGDATA */
- {
- int cksm, offset, difflen;
-
- if ((long)last_op == (long)OP_WRITE) {
- /* Better get the first one sent and ack'd first */
- /* FIXME, this will change for window > 1 */
- if (inpkt()) return 1;
- }
-
- bzero((char *)(msgo+6), sendbytes);
- msgo[1] = sendseg;
- msgo[4] = (sorl << 6) + (wseq << 3) + rseq;
-
- switch(sorl) {
- case LONGDATA:
- if (n > sendbytes)
- {
- logit("PROTOCOL VIOLATION IN SENDPACKET", "n > sendbytes");
- exit(1);
- }
- offset = 6;
- break;
-
- case SHORTDATA:
- difflen = sendbytes - n;
- if (difflen < 1)
- {
- logit("PROTOCOL VIOLATION IN SENDPACKET", "difflen < 1");
- exit(1);
- }
- offset = 7;
- if (difflen <= 127) {
- msgo[6] = difflen; /* One byte count */
- } else {
- msgo[6] = 128 | difflen; /* low byte, with 0x80 on */
- msgo[7] = difflen >> 7; /* High byte */
- offset = 8;
- }
- }
-
- bcopy(s, (char *)msgo+offset, n); /* Move the data */
-
- cksm = MAGIC - (chksum(&msgo[6], sendbytes) ^ (0377 & msgo[4]));
- wseq = (wseq + 1) & 7; /* Bump sent pkt sequence # */
- return writeframe(cksm);
- }
-
- /*
- * Medium level input routine.
- *
- * Write a packet to the serial port, then read a packet from the serial port.
- * Return 1 if other side went away, 0 if good packet received.
- *
- * With window size of 1, we send a packet and then receive one.
- * FIXME, when we implement a larger window size, this routine will become
- * more complicated and callers will not be able to depend on msgo[]
- * being sent and acknowledged when it returns.
- */
- int
- inpkt()
- {
- int data,count,need;
- register int i;
- unsigned short pktsum, oursum;
- int status;
- /*
- * Next vars are for re-queueing received chars to rescan them
- * for a valid packet after an error.
- */
- int queued = -1; /* <0: off, 0: just finished, >0: # chars pending */
- unsigned char *qp;
- unsigned char qbuf[sizeof msgi]; /* This can be static if 4K
- on the stack is too much */
- # define bad(str) {if (DEBUG_LEVEL(5)) printf str; goto oops; }
-
- if (firstslave) {
- firstslave = 0;
- goto again;
- }
-
- xmit:
- i = segbytes[msgo[LENBYTE]] + 6;
- status = xwrite(0, (char *)msgo,i);
- if ((long)status != (long)i) {
- if (DEBUG_LEVEL(0)) {
- printf("xmit %d bytes failed, status %d, errno %d",
- i, status, errno);
- }
- return 1; /* Write failed */
- }
-
- again:
- count = 0;
-
- DEBUG(9, "R ", 0);
-
- while (1) {
- if (queued >= 0) {
- /*
- * Process some stuff from a string.
- * If we just finished the last char queued, and
- * we are still scanning for a DLE, re-xmit our
- * last packet before we continue reading.
- * On the other hand, if we have a valid packet
- * header accumulating, just keep reading the serial
- * port.
- */
- if (--queued < 0) {
- if (count == 0) {
- DEBUG(6, "End queue. Re-xmit.\n", 0);
- goto xmit; /* No packet comin' in */
- } else {
- DEBUG(6,"End queue. Keep reading\n",0);
- goto readser; /* Seems to be sumpin' */
- }
- }
- data = *qp++; /* Just grab from queue */
- } else {
- readser:
- data = xgetc();
- if (data == EOF) break;
- }
-
- if (DEBUG_LEVEL(9))
- printf("%02x%c ",data & 0xFF, isprint(data)? data: ' ');
-
- switch (count)
- {
- case 0:
- /* Look for DLE */
- if (data == DLE)
- msgi[count++] = DLE;
- break;
-
- case LENBYTE:
- /* Check length byte */
- if (data > KCONTROL || data == 0)
- bad(("packet size"));
- if (segbytes[data] > MAX_PACKET) {
- bad(("packet too long for buffer"));
- oops:
- if (DEBUG_LEVEL(5))
- printf(" bad in above packet\n");
-
- /* FIXME, decode packet header here,
- if enough of it has come in. */
-
- /* See if any DLEs in the bad packet */
- /* Skip 0, we know that's a DLE */
- for (i = 1; i < count; i++) {
- if (msgi[i] == DLE) {
- /* Reprocess from the DLE.
- * if queued, back up the q.
- * if not, make one.
- */
- if (queued >= 0) {
- queued += count - i;
- qp -= count - i;
- DEBUG(6,"Backup and rescan queue\n", 0);
- } else {
- bcopy((char *)msgi+i, (char *)qbuf,
- count - i);
- qp = qbuf;
- queued = count - i;
- DEBUG(6,"Queue and rescan input\n", 0);
- }
- goto again;
- }
- }
-
- if (queued >= 0) {
- DEBUG(6, "Continue scan\n", 0);
- goto again;
- } else {
- DEBUG(6, "Re-xmit previous packet\n",0);
- goto xmit; /* Xmit then rcv */
- }
- }
- msgi[count++] = (unsigned char)data; /* Save it */
- msgsize = segbytes[data]; /* Save Packet size */
- need = 6 + msgsize;
- break;
-
- case CBYTE:
- /* Break up control byte as well as storing it */
- msgi[count++] = (unsigned char)data; /* Save it */
- tt = (data >> 6) & 3;
- xxx = (data >> 3) & 7;
- yyy = data & 7;
-
- /* Now check it a bit */
- switch (tt) { /* Switch on msg type */
- case CONTROL:
- /* Control msg must have KCONTROL size */
- if ((long)msgsize != (long)0) bad(("K versus Control"));
- /* We don't implement SRJ, nor does Unix */
- switch (xxx) {
- case SRJ:
- bad(("SRJ received"));
- case RJ:
- case RR:
- if ((long)yyy != (long)(7 & (wseq - 1)))
- bad(("didn't ack our pkt"));
- }
- break;
-
- case ALTCHN:
- bad(("ALTCHN received")); /* Unsupported */
-
- case SHORTDATA:
- case LONGDATA:
- if (msgsize == 0) bad (("KCONTROL with data"));
- if (((xxx - rseq) & 7) > wndsiz) {
- /* Atari ST cpp has problems with
- * macro args broken across lines?
- * That's why funny indent here
- */
- bad (("data out of window, xxx=%d rseq=%d", xxx, rseq));
- }
- /* FIXME, below enforces window size == 1 */
- /* Note that this is also how we guarantee
- that msgo has been received OK by the time
- we exit inpkt() too. Don't change it unless
- you know what you are doing. */
- if ((long)yyy != (long)(7 & (wseq - 1)))
- bad(("didn't ack our pkt"));
- break;
- }
- break;
-
- case FRAMEBYTE:
- /* See whole frame, check it a bit. */
- msgi[count++] = (unsigned char)data;
- if ((long)data != (long)(msgi[1] ^ msgi[2] ^ msgi[3] ^ msgi[4]))
- bad(("frame checksum"));
- pktsum = msgi[2] + (msgi[3] << 8);
-
- if (tt == CONTROL) {
- /* Check checksums for control packets */
- oursum = MAGIC - msgi[4];
- if ((long)pktsum != (long)oursum)
- bad(("control checksum"));
- /*
- * We have a full control packet.
- * Update received seq number for the ones
- * that carry one.
- */
- switch (xxx) {
- case RJ: case RR:
- if (((wseq - yyy) & 7) > sendwin) {
- bad (("RJ/RR out of window, yyy=%d wseq=%d", yyy, wseq));
- }
- his_rseq = yyy;
- }
- goto done;
- } else {
- /*
- * Received frame of data packet.
- *
- * Now that the checksum has been verified,
- * we can believe the acknowledgement (if
- * any) in it.
- */
- if (((wseq - yyy) & 7) > sendwin) {
- bad (("data ack out of window, yyy=%d wseq=%d", yyy, wseq));
- }
- his_rseq = yyy;
- }
- break;
-
- default:
- msgi[count++] = (unsigned char)data;
- if (count >= need) {
- /* We have received a full data packet */
- oursum = MAGIC - (chksum(&msgi[6], sendbytes)
- ^ (0377 & msgi[4]));
- if ((long)pktsum != (long)oursum) {
- /* Send a reject on this pkt */
- reject = xxx - 1;
- bad(("\ndata checksum in packet %x, ours=%x", pktsum, oursum));
- }
- /* FIXME, this may change for window>1 */
- if ((long)xxx != (long)(rseq+1)%8 ) {
- bad(("Not next packet xxx=%d rseq=%d", xxx, rseq));
- }
- rseq = xxx; /* We saw this pkt OK */
- done:
- if (DEBUG_LEVEL(9))
- putchar('\n');
- if (DEBUG_LEVEL(6)) {
- if (tt == CONTROL)
- printf("Rcvd: CONTROL %s %d\n",
- ctrl_pr[xxx], yyy);
- else
- printf("Rcvd: %s %d %d\n",
- tt_pr[tt], xxx, yyy);
- }
- last_op = OP_READ;
- return(0);
- }
- break;
- }
- }
- DEBUG(6, " EOF\n", 0);
- return(1);
- }
-
- int
- chksum(s,n)
- register unsigned char *s;
- register n;
- {
- register short sum;
- register unsigned short t;
- register short x;
-
- sum = -1;
- x = 0;
- do {
- if (sum < 0)
- {
- sum <<= 1;
- sum++;
- }
- else
- sum <<= 1;
- t = sum;
- sum += *s++ & 0377;
- x += sum ^ n;
- if ((unsigned short)sum <= t)
- sum ^= x;
- } while (--n > 0);
-
- return(sum);
- }
-
- /*
- * Medium level packet driver input routine.
- *
- * Read a data packet from the other side. If called twice in succession,
- * we send an ack of the previous packet. Otherwise we tend to piggyback
- * the acks on data packets.
- *
- * Result is 0 if we got a data packet, 1 if we got some other kind, or
- * a hangup timeout.
- */
- int
- indata()
- {
-
- while (1) {
- if (last_op == OP_READ) {
- ackmsg(); /* Send an ack */
- }
- if (inpkt()) return 1;
-
- switch (tt) {
- case ALTCHN:
- return 1; /* Unsupported - yet */
-
- case LONGDATA:
- case SHORTDATA:
- /*
- * We got a data packet. That's what we want,
- * so return.
- */
- return 0; /* We are done. */
-
- case CONTROL:
- switch (xxx) {
- default:
- return 1; /* Bad packet type */
-
- case RJ: /* Reject prev pkt */
- case RR: /* OK but no data */
- break; /* Ack and try again */
- }
- }
- }
- }
-
- /*
- * Open a conversation in the g protocol. Medium level routine.
- *
- * We need to both send and receive each packet type in turn.
- * If this sequence falters, we start over at INITA, trying a few more times.
- *
- * Returns 0 for success, 1 for failure.
- */
- int
- gturnon(mastermode)
- int mastermode;
- {
- int tries = 0;
- int step = 0;
- static int which[] = {INITA, INITA, INITB, INITB, INITC, INITC};
-
- /* initialize protocol globals, e.g. packet sequence numbers */
-
- rseq = 0; /* Last good packet # we have seen from him */
- wseq = 1; /* Next packet # we will send */
- his_rseq = 0; /* Last good Packet # he has seen from us */
- reject = NOREJECT; /* Don't reject first packet */
- firstslave = mastermode? 0: 1; /* About to do first slave packet? */
-
- if (mastermode) goto master_start;
-
- while (++tries <= 8) {
- /* Receive an initialization packet and handle it */
- if (inpkt() == 0 && tt == CONTROL && xxx == which[step]) {
- switch (xxx) {
- /* Remember we've seen it, grab value */
- case INITA:
- do_inita:
- sendwin = yyy;
- break;
- case INITB:
- /*
- * Get preferred packet size for other guy,
- * but don't overrun our buffer space.
- * The encoded segment size is off-by-1 from
- * the one used in the K field in each packet.
- */
- do {
- sendseg = yyy+1;
- sendbytes = segbytes[sendseg];
- } while (sendbytes > MAX_PACKET && --yyy);
- break;
- case INITC:
- sendwin = yyy;
- break;
- }
- if (++step >= 6) /* Move forward */
- return 0; /* We are done */
- } else {
- /* Start over, sigh */
- step = 0;
- if (xxx == INITA) /* Start with his inita */
- goto do_inita;
- }
-
- master_start:
- /*
- * Transmit an initialization packet.
- */
- switch (which[step]) {
- case INITA:
- ctlmsg((INITA << 3) | wndsiz);
- break;
- case INITB:
- ctlmsg((INITB << 3) | (segsiz - 1));
- break;
- case INITC:
- ctlmsg((INITC << 3) | wndsiz);
- break;
- }
- if (++step >= 6)
- return 0; /* We are done */
- }
- return 1; /* Failure */
- }
-
- /*
- * Turn off conversation in the G protocol. Medium level routine.
- */
- int
- gturnoff()
- {
-
- /* In windowed protocol, we have to check if prev one's been ack'd */
- int i;
- if (last_op == OP_WRITE) {
- if (inpkt()) return 1;
- }
- /* do */
- {
- ctlmsg(CLOSE << 3);
- i = segbytes[msgo[LENBYTE]] + 6;
- xwrite(0, (char *)msgo,i);
- }
- /* while ((tt != CONTROL) && (xxx != CLOSE)); */
- return 0;
- }
-
- /*
- * Read a message from the other side.
- *
- * Messages are always contained in LONGDATA packets. If a message is
- * longer than a single packet, only the last packet will contain a null
- * character. Keep catenating them until you see the null.
- *
- * Return SUCCESS or FAIL. If the received message is longer than our
- * buffer, we eat the whole message, but return FAIL once it ends.
- */
- int
- grdmsg(str, fn)
- char *str; /* Buffer to put it in, sized MAXMSGLEN */
- int fn; /* File descriptor to read it from */
- {
- unsigned msglen;
- unsigned totlen = 0;
- unsigned oldlen;
-
- str[0] = '\0'; /* No command yet */
- do {
- if ((long)(indata()) || (long)tt != (long)LONGDATA)
- return FAIL;
- msgi[6+msgsize] = '\0'; /* Null terminate packet */
- msglen = strlen((char *)msgi+6);
- oldlen = totlen;
- totlen += msglen;
- if (totlen < MAXMSGLEN) {
- strcat(str+oldlen,(char *)&msgi[6]); /* Tack on to command */
- }
- } while (msglen == msgsize); /* Loop if no null in pkt */
-
- return (totlen < MAXMSGLEN)? SUCCESS: FAIL;
- }
-
-
- /*
- * Write a message to the other side.
- *
- * We write the first (or only) packet from our local bufr[], the
- * rest comes straight out of the caller's string.
- */
- int
- gwrmsg(type, str, fn)
- char type;
- char *str;
- int fn;
- {
- char bufr[MAX_PACKET];
- char *ptr;
- int thislen, totlen;
-
- bufr[0] = type;
- totlen = strlen(str) + 1;
- if (totlen > MAXMSGLEN)
- {
- logit("PROTOCOL VIOLATION IN GWRMSG", "totlen > MAXMSGLEN");
- exit(1);
- }
- if (totlen < sendbytes-1)
- thislen = totlen;
- else
- thislen = sendbytes-1;
- strncpy(&bufr[1], str, thislen);
-
- /* strncpy(&bufr[1], str, sendbytes-1); */
- ptr = bufr;
-
- for (;;) {
- thislen = totlen;
- if (thislen > sendbytes) thislen = sendbytes;
- if (sendpacket(ptr, thislen, LONGDATA))
- return FAIL;
- totlen -= sendbytes;
- if (totlen < 0) break;
- if (ptr == bufr) ptr = str + (sendbytes - 1);
- else ptr += sendbytes;
- }
-
- return SUCCESS;
- }
-
- /*
- * Write a file to the other side.
- */
- int
- gwrdata(file, fn)
- FILE *file; /* File to be sent */
- int fn; /* fd of serial line */
- {
- char dskbuf[MAX_PACKET]; /* Disk I/O buffer */
- int count;
-
- do {
- count = fread(dskbuf, sizeof (char), sendbytes, file);
- if (count < 0) return FAIL; /* FIXME, should send EOF */
- if (sendpacket(dskbuf, count,
- (count == sendbytes)? LONGDATA: SHORTDATA))
- return FAIL;
- } while (count);
-
- return SUCCESS;
- }
-
- /*
- * Read a file from the other side.
- */
- int
- grddata(fn, file)
- int fn; /* File desc of serial line */
- FILE *file; /* stdio file ptr of file to read into */
- {
- int offset;
- int status;
- int error = 0;
-
- do {
- /* Read a packet, handle the data in it */
- if (indata())
- return FAIL;
-
- switch (tt) {
- case LONGDATA:
- /* FIXME, check this write */
- offset = 6;
- goto writeit;
- case SHORTDATA:
- if (msgi[6] & 0x80) {
- msgsize -=
- (msgi[7] << 7) | (127&msgi[6]);
- offset = 8;
- } else {
- msgsize -= msgi[6];
- offset = 7;
- }
-
- writeit:
- /* FIXME:
- * Consider skipping further writing if error != 0 */
- if ((long)msgsize != (long)0) {
- status = fwrite((char *)&msgi[offset], sizeof (char),
- msgsize, file);
- if ((long)status != (long)msgsize) error++;
- }
- break;
- }
- } while ((long)msgsize != (long)0);
-
- return error? FAIL: SUCCESS;
- }
-