1/* prott.c 2 The 't' protocol. 3 4 Copyright (C) 1991, 1992, 2002 Ian Lance Taylor 5 6 This file is part of the Taylor UUCP package. 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 2 of the 11 License, or (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 21 22 The author of the program may be contacted at ian@airs.com. 23 */ 24 25#include "uucp.h" 26 27#if USE_RCS_ID 28const char prott_rcsid[] = "$Id: prott.c,v 1.32 2002/03/05 19:10:41 ian Rel $"; 29#endif 30 31#include "uudefs.h" 32#include "uuconf.h" 33#include "conn.h" 34#include "trans.h" 35#include "system.h" 36#include "prot.h" 37 38/* This implementation is based on code written by Rick Adams. 39 40 This code implements the 't' protocol, which does no error checking 41 whatsoever and thus requires an end-to-end verified eight bit 42 communication line, such as is provided by TCP. Using it with a 43 modem is unadvisable, since errors can occur between the modem and 44 the computer. */ 45 46/* The buffer size we use. */ 47#define CTBUFSIZE (1024) 48 49/* The offset in the buffer to the data. */ 50#define CTFRAMELEN (4) 51 52/* Commands are sent in multiples of this size. */ 53#define CTPACKSIZE (512) 54 55/* A pointer to the buffer we will use. */ 56static char *zTbuf; 57 58/* True if we are receiving a file. */ 59static boolean fTfile; 60 61/* The timeout we use. */ 62static int cTtimeout = 120; 63 64struct uuconf_cmdtab asTproto_params[] = 65{ 66 { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cTtimeout, NULL }, 67 { NULL, 0, NULL, NULL } 68}; 69 70/* Local function. */ 71 72static boolean ftprocess_data P((struct sdaemon *qdaemon, boolean *pfexit, 73 size_t *pcneed)); 74 75/* Start the protocol. */ 76 77boolean 78ftstart (qdaemon, pzlog) 79 struct sdaemon *qdaemon; 80 char **pzlog; 81{ 82 *pzlog = NULL; 83 if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, 84 STRIPSETTING_EIGHTBITS, XONXOFF_OFF)) 85 return FALSE; 86 zTbuf = (char *) xmalloc (CTBUFSIZE + CTFRAMELEN); 87 /* The first two bytes of the buffer are always zero. */ 88 zTbuf[0] = 0; 89 zTbuf[1] = 0; 90 fTfile = FALSE; 91 usysdep_sleep (2); 92 return TRUE; 93} 94 95/* Stop the protocol. */ 96 97/*ARGSUSED*/ 98boolean 99ftshutdown (qdaemon) 100 struct sdaemon *qdaemon ATTRIBUTE_UNUSED; 101{ 102 xfree ((pointer) zTbuf); 103 zTbuf = NULL; 104 cTtimeout = 120; 105 return TRUE; 106} 107 108/* Send a command string. We send everything up to and including the 109 null byte. The number of bytes we send must be a multiple of 110 TPACKSIZE. */ 111 112/*ARGSUSED*/ 113boolean 114ftsendcmd (qdaemon, z, ilocal, iremote) 115 struct sdaemon *qdaemon; 116 const char *z; 117 int ilocal ATTRIBUTE_UNUSED; 118 int iremote ATTRIBUTE_UNUSED; 119{ 120 size_t clen, csend; 121 char *zalc; 122 boolean fret; 123 124 DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "ftsendcmd: Sending command \"%s\"", z); 125 126 clen = strlen (z); 127 128 /* We need to send the smallest multiple of CTPACKSIZE which is 129 greater than clen (not equal to clen, since we need room for the 130 null byte). */ 131 csend = ((clen / CTPACKSIZE) + 1) * CTPACKSIZE; 132 133 zalc = zbufalc (csend); 134 memcpy (zalc, z, clen); 135 if (csend > clen) 136 bzero (zalc + clen, csend - clen); 137 138 fret = fsend_data (qdaemon->qconn, zalc, csend, TRUE); 139 ubuffree (zalc); 140 return fret; 141} 142 143/* Get space to be filled with data. We provide a buffer which has 144 four bytes at the start available to hold the length. */ 145 146/*ARGSIGNORED*/ 147char * 148ztgetspace (qdaemon, pclen) 149 struct sdaemon *qdaemon ATTRIBUTE_UNUSED; 150 size_t *pclen; 151{ 152 *pclen = CTBUFSIZE; 153 return zTbuf + CTFRAMELEN; 154} 155 156/* Send out some data. We are allowed to modify the four bytes 157 preceding the buffer. This allows us to send the entire block with 158 header bytes in a single call. */ 159 160/*ARGSIGNORED*/ 161boolean 162ftsenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) 163 struct sdaemon *qdaemon; 164 char *zdata; 165 size_t cdata; 166 int ilocal ATTRIBUTE_UNUSED; 167 int iremote ATTRIBUTE_UNUSED; 168 long ipos ATTRIBUTE_UNUSED; 169{ 170 /* Here we do htonl by hand, since it doesn't exist everywhere. We 171 know that the amount of data cannot be greater than CTBUFSIZE, so 172 the first two bytes of this value will always be 0. They were 173 set to 0 in ftstart so we don't touch them here. This is useful 174 because we cannot portably right shift by 24 or 16, since we 175 might be dealing with sixteen bit integers. */ 176 zdata[-2] = (char) ((cdata >> 8) & 0xff); 177 zdata[-1] = (char) (cdata & 0xff); 178 179 /* We pass FALSE to fsend_data since we don't expect the other side 180 to be sending us anything just now. */ 181 return fsend_data (qdaemon->qconn, zdata - CTFRAMELEN, cdata + CTFRAMELEN, 182 FALSE); 183} 184 185/* Process data and return the amount we need in *pfneed. */ 186 187static boolean 188ftprocess_data (qdaemon, pfexit, pcneed) 189 struct sdaemon *qdaemon; 190 boolean *pfexit; 191 size_t *pcneed; 192{ 193 int cinbuf, cfirst, clen; 194 195 *pfexit = FALSE; 196 197 cinbuf = iPrecend - iPrecstart; 198 if (cinbuf < 0) 199 cinbuf += CRECBUFLEN; 200 201 if (! fTfile) 202 { 203 /* We are not receiving a file. Commands are read in chunks of 204 CTPACKSIZE. */ 205 while (cinbuf >= CTPACKSIZE) 206 { 207 cfirst = CRECBUFLEN - iPrecstart; 208 if (cfirst > CTPACKSIZE) 209 cfirst = CTPACKSIZE; 210 211 DEBUG_MESSAGE1 (DEBUG_PROTO, 212 "ftprocess_data: Got %d command bytes", 213 cfirst); 214 215 if (! fgot_data (qdaemon, abPrecbuf + iPrecstart, 216 (size_t) cfirst, abPrecbuf, 217 (size_t) CTPACKSIZE - cfirst, 218 -1, -1, (long) -1, TRUE, pfexit)) 219 return FALSE; 220 221 iPrecstart = (iPrecstart + CTPACKSIZE) % CRECBUFLEN; 222 223 if (*pfexit) 224 return TRUE; 225 226 cinbuf -= CTPACKSIZE; 227 } 228 229 if (pcneed != NULL) 230 *pcneed = CTPACKSIZE - cinbuf; 231 232 return TRUE; 233 } 234 235 /* Here we are receiving a file. The data comes in blocks. The 236 first four bytes contain the length, followed by that amount of 237 data. */ 238 239 while (cinbuf >= CTFRAMELEN) 240 { 241 /* The length is stored in network byte order, MSB first. */ 242 243 clen = (((((((abPrecbuf[iPrecstart] & 0xff) << 8) 244 + (abPrecbuf[(iPrecstart + 1) % CRECBUFLEN] & 0xff)) << 8) 245 + (abPrecbuf[(iPrecstart + 2) % CRECBUFLEN] & 0xff)) << 8) 246 + (abPrecbuf[(iPrecstart + 3) % CRECBUFLEN] & 0xff)); 247 248 if (cinbuf < clen + CTFRAMELEN) 249 { 250 if (pcneed != NULL) 251 *pcneed = clen + CTFRAMELEN - cinbuf; 252 return TRUE; 253 } 254 255 iPrecstart = (iPrecstart + CTFRAMELEN) % CRECBUFLEN; 256 257 cfirst = CRECBUFLEN - iPrecstart; 258 if (cfirst > clen) 259 cfirst = clen; 260 261 DEBUG_MESSAGE1 (DEBUG_PROTO, 262 "ftprocess_data: Got %d data bytes", 263 clen); 264 265 if (! fgot_data (qdaemon, abPrecbuf + iPrecstart, 266 (size_t) cfirst, abPrecbuf, (size_t) (clen - cfirst), 267 -1, -1, (long) -1, TRUE, pfexit)) 268 return FALSE; 269 270 iPrecstart = (iPrecstart + clen) % CRECBUFLEN; 271 272 if (*pfexit) 273 return TRUE; 274 275 cinbuf -= clen + CTFRAMELEN; 276 } 277 278 if (pcneed != NULL) 279 *pcneed = CTFRAMELEN - cinbuf; 280 281 return TRUE; 282} 283 284/* Wait for data to come in and process it until we've reached the end 285 of a command or a file. */ 286 287boolean 288ftwait (qdaemon) 289 struct sdaemon *qdaemon; 290{ 291 while (TRUE) 292 { 293 boolean fexit; 294 size_t cneed, crec; 295 296 if (! ftprocess_data (qdaemon, &fexit, &cneed)) 297 return FALSE; 298 if (fexit) 299 return TRUE; 300 301 if (! freceive_data (qdaemon->qconn, cneed, &crec, cTtimeout, TRUE)) 302 return FALSE; 303 304 if (crec == 0) 305 { 306 ulog (LOG_ERROR, "Timed out waiting for data"); 307 return FALSE; 308 } 309 } 310} 311 312/* File level routine, to set fTfile correctly. */ 313 314/*ARGSUSED*/ 315boolean 316ftfile (qdaemon, qtrans, fstart, fsend, cbytes, pfhandled) 317 struct sdaemon *qdaemon ATTRIBUTE_UNUSED; 318 struct stransfer *qtrans ATTRIBUTE_UNUSED; 319 boolean fstart; 320 boolean fsend; 321 long cbytes ATTRIBUTE_UNUSED; 322 boolean *pfhandled; 323{ 324 *pfhandled = FALSE; 325 326 if (! fsend) 327 fTfile = fstart; 328 329 return TRUE; 330} 331