/*--------------------------------------------------------------------*/ /* Flow control ("f") protocol. */ /* */ /* This protocol relies on flow control of the data stream. It */ /* is meant for working over links that can (almost) be */ /* guaranteed to be errorfree, specifically X.25/PAD links. A */ /* sumcheck is carried out over a whole file only. If a */ /* transport fails the receiver can request retransmission(s). */ /* This protocol uses a 7-bit datapath only, so it can be used */ /* on links that are not 8-bit transparent. */ /* */ /* When using this protocol with an X.25 PAD: Although this */ /* protocol uses no control chars except CR, control chars NULL */ /* and ^P are used before this protocol is started; since ^P is */ /* the default char for accessing PAD X.28 command mode, be */ /* sure to disable that access (PAD par 1). Also make sure */ /* both flow control pars (5 and 12) are set. The CR used in */ /* this proto is meant to trigger packet transmission, hence */ /* par 3 should be set to 2; a good value for the Idle Timer */ /* (par 4) is 10. All other pars should be set to 0. */ /* */ /* Normally a calling site will take care of setting the local */ /* PAD pars via an X.28 command and those of the remote PAD via */ /* an X.29 command, unless the remote site has a special */ /* channel assigned for this protocol with the proper par */ /* settings. */ /* */ /* Author: Piet Beertema, CWI, Amsterdam, Sep 1984 */ /* */ /* Adapted to uupc 3.0 and THINK C 4.0 by Dave Platt, Jul 1991 */ /*--------------------------------------------------------------------*/ /* * $Id: DCPFPKT.C 1.7 1993/04/05 12:26:01 ahd Exp $ * * $Log: DCPFPKT.C $ * Revision 1.7 1993/04/05 12:26:01 ahd * Correct prototypes to match gpkt * * Revision 1.6 1993/04/05 04:35:40 ahd * Allow unique send/receive packet sizes * * Revision 1.5 1992/11/20 12:38:26 ahd * Drop rcsid * * Revision 1.4 1992/11/19 03:01:13 ahd * drop rcsid * * Revision 1.3 1992/11/19 02:36:29 ahd * Revision 1.2 1992/11/15 20:10:47 ahd * Clean up modem file support for different protocols * */ /*--------------------------------------------------------------------*/ /* System include files */ /*--------------------------------------------------------------------*/ #include #include #include /*--------------------------------------------------------------------*/ /* UUPC/extended include files */ /*--------------------------------------------------------------------*/ #include "lib.h" #include "dcp.h" #include "dcpfpkt.h" #include "dcpsys.h" #include "hostable.h" #include "security.h" #include "ssleep.h" #include "modem.h" #include "ulib.h" /*--------------------------------------------------------------------*/ /* Defines */ /*--------------------------------------------------------------------*/ #ifndef MAXMSGLEN #define MAXMSGLEN BUFSIZ #endif MAXMSGLEN currentfile(); /*--------------------------------------------------------------------*/ /* Internal function prototypes */ /*--------------------------------------------------------------------*/ static short fsendresp(short state); /*--------------------------------------------------------------------*/ /* Global variables */ /*--------------------------------------------------------------------*/ static short chksum; /*--------------------------------------------------------------------*/ /* f o p e n p k */ /* */ /* Open "f" protocol to other system */ /*--------------------------------------------------------------------*/ short fopenpk(const boolean master) { flowcontrol(TRUE); if ( M_fPacketSize > MAXPACK) M_fPacketSize = MAXPACK; r_pktsize = s_pktsize = M_fPacketSize; ssleep(2); /* Give peer time to perform corresponding port setup */ return OK; } /* fopenpk */ /*--------------------------------------------------------------------*/ /* f c l o s e p k */ /* */ /* Shutdown "f" procotol with other system */ /*--------------------------------------------------------------------*/ short fclosepk() { flowcontrol(FALSE); return OK; } /* fclosepk */ /*--------------------------------------------------------------------*/ /* f w r m s g */ /* */ /* Send a control message to remote system with "f" procotol */ /*--------------------------------------------------------------------*/ short fwrmsg(char *str) { char bufr[MAXMSGLEN]; char *s = bufr; while (*str) *s++ = *str++; if (*(s-1) == '\n') s--; *s++ = '\r'; if (swrite(bufr, s - bufr) == (s - bufr)) return OK; else return FAILED; } /* fwrmsg */ /*--------------------------------------------------------------------*/ /* f r d m s g */ /* */ /* Read a control message from remote host with "f" protocol */ /*--------------------------------------------------------------------*/ short frdmsg(char *str) { char *smax; char *s = str; smax = s + MAXPACK - 1; for (;;) { if (sread(s, 1, M_fPacketTimeout) <= 0) { printmsg(0,"frdmsg: timeout reading message"); *s++ = '\0'; goto msgerr; } if (*s == '\r') break; if (*s < ' ') continue; if (s++ >= smax) { printmsg(0,"frdmsg: buffer overflow"); *--s = '\0'; goto msgerr; } /* if (s++ >= smax) */ } *s = '\0'; return OK; msgerr: printmsg(0,"frdmsg: Message received \"%s\"", str); return FAILED; } /* frdmsg */ /*--------------------------------------------------------------------*/ /* f g e t p k t */ /* */ /* Receive an "f" protocol packet of data from the other system */ /*--------------------------------------------------------------------*/ short fgetpkt(char *packet, short *bytes) { char *op, c, *ip; short sum, len, left; char buf[5], tbuf[1]; short i; static char special = 0; static boolean eof = FALSE; /*--------------------------------------------------------------------*/ /* Handle EOF on previous call */ /*--------------------------------------------------------------------*/ if ( eof ) { eof = FALSE; printmsg(0,"fgetpkt: EOF from other host"); *bytes = 0; if (fsendresp(OK) == OK) return OK; else return FAILED; } /* if ( eof ) */ left = s_pktsize; op = packet; sum = chksum; /*--------------------------------------------------------------------*/ /* Loop to fill up one packet */ /*--------------------------------------------------------------------*/ do { ip = tbuf; len = sread(ip, 1, M_fPacketTimeout); /* single-byte reads for now */ if (len == 0) { printmsg(0,"fgetpkt: Timeout after %d seconds", M_fPacketTimeout); return FAILED; /* Fail if timed out */ } if ((*ip &= 0177) >= '\172') { if (special) { special = 0; if (*ip++ != '\176') { printmsg(0,"fgetpkt: Did not expect character ^%c (x%02x)", (char) (*(ip-1) + 'A') , (short) *(ip-1)); goto dcorr; } len = 0; while (len < 5) { i = sread(&buf[len], 5 - len, M_fPacketTimeout); if (i == 0) { printmsg(0, "fgetpkt: Timeout reading %d chars after %d seconds", 5 - len, M_fPacketTimeout); goto dcorr; } len += i; } printmsg(6, "fgetpkt: buf=|%.*s|", len , packet); if (buf[4] != '\r') { printmsg(0, "fgetpkt: error: Expected carriage return, " "not %s%c (x%02x)", (buf[4] < ' ') ? "^" : "" , (char) (buf[4] + ((buf[4] < ' ') ? 'A' : 0)), (short) buf[4]); goto dcorr; } sscanf(buf, "%4x", &chksum); *bytes = op - packet; if (chksum == sum) { eof = TRUE; printmsg(6, "fgetpkt: data=|%.*s|", *bytes , packet); return OK; } else { printmsg(0, "fgetpkt: Checksum mismatch, told %04x, calc %04x", chksum, sum); fsendresp(RETRY); return RETRY; } } special = *ip++; } else { if (*ip < '\040') { printmsg(0,"fgetpkt: error: got control character ^%c (%x)", (char) (*ip + 'A') , (short) *ip); goto dcorr; } switch (special) { case 0: c = (char) (*ip++); break; case '\172': c = (char) (*ip++ - 0100); break; case '\173': c = (char) (*ip++ + 0100); break; case '\174': c = (char) (*ip++ + 0100); break; case '\175': c = (char) (*ip++ + 0200); break; case '\176': c = (char) (*ip++ + 0300); break; default: printmsg(0,"fgetpkt: Invalid special chracter 0x%2x", (short) special ); panic(); c = '\0'; } *op++ = c; left --; if (sum & 0x8000) { sum <<= 1; sum++; } else sum <<= 1; sum += c & 0377; sum &= 0xffff; special = 0; } } while (left > 0); /*--------------------------------------------------------------------*/ /* The packet is full of data, return to caller */ /*--------------------------------------------------------------------*/ *bytes = s_pktsize; printmsg(6, "fgetpkt: data=|%.*s|", *bytes , packet); chksum = sum; return OK; /*--------------------------------------------------------------------*/ /* The data is corrupt; flush the incoming file */ /*--------------------------------------------------------------------*/ dcorr: printmsg (0, "Data corrupted, skipping to EOF"); len = 1; while (len) len = sread(packet, 1, M_fPacketTimeout); fsendresp(RETRY); return RETRY; } /* fgetpkt */ /*--------------------------------------------------------------------*/ /* f s e n d p k t */ /* */ /* Send an "f" protocol packet to the other system */ /*--------------------------------------------------------------------*/ short fsendpkt(char *ip, short len) { char *op; short sum, nl; short ret; char obuf[MAXPACK * 2]; op = obuf; nl = 0; sum = chksum; if (len == 0) { printmsg(0,"fsendpkt: Internal error: zero length for packet"); return FAILED; } do { if (sum & 0x8000) { sum <<= 1; sum++; } else sum <<= 1; sum += *ip & 0377; sum &= 0xffff; if (*ip & 0200) { *ip &= 0177; if (*ip < 040) { *op++ = '\174'; *op++ = (char) (*ip++ + 0100); } else if (*ip <= 0171) { *op++ = '\175'; *op++ = *ip++; } else { *op++ = '\176'; *op++ = (char) (*ip++ - 0100); } nl += 2; } else { if (*ip < 040) { *op++ = '\172'; *op++ = (char) (*ip++ + 0100); nl += 2; } else if (*ip <= 0171) { *op++ = *ip++; nl++; } else { *op++ = '\173'; *op++ = (char) (*ip++ - 0100); nl += 2; } } } while (--len > 0); chksum = sum; ret = swrite(obuf, nl); if ( ret == nl ) return OK; else return FAILED; } /* fsendpkt */ /*--------------------------------------------------------------------*/ /* f f i l e p k t */ /* */ /* Prepare for processing an "f" procotol file transfer */ /*--------------------------------------------------------------------*/ short ffilepkt( void) { chksum = 0xffff; printmsg(3,"ffilepkt: Checksum reset"); return OK; } /* ffilepkt */ /*--------------------------------------------------------------------*/ /* f e o f */ /* */ /* Transmit "f" protocol end of file to the other system */ /*--------------------------------------------------------------------*/ short feofpkt( void ) { char ibuf[MAXMSGLEN]; /*--------------------------------------------------------------------*/ /* Transmit EOF with an attached checksum */ /*--------------------------------------------------------------------*/ printmsg(0,"feofpkt: sending EOF"); sprintf(ibuf, "\176\176%04x", chksum); printmsg(2,"--> %s", ibuf); fwrmsg(ibuf); /*--------------------------------------------------------------------*/ /* Now get the response and report it */ /*--------------------------------------------------------------------*/ if (frdmsg(ibuf) == FAILED) return FAILED; printmsg(2,"<-- %s",ibuf); /*--------------------------------------------------------------------*/ /* Determine our next step from the result */ /*--------------------------------------------------------------------*/ switch(*ibuf) { case 'R': return RETRY; case 'G': return OK; default: return FAILED; } /* switch */ } /* feofpkt */ /*--------------------------------------------------------------------*/ /* f s e n d r e s p */ /* */ /* Send result to a file transfer to other host */ /*--------------------------------------------------------------------*/ static short fsendresp(short state) { char *s; switch (state) { case OK: s = "G"; break; case RETRY: s = "R"; break; default: s = "Q"; break; } printmsg(2,"--> %s", s); return fwrmsg(s); } /* fsendresp */