78ed81a3 |
1 | /* prott.c |
2 | The 't' protocol. |
3 | |
4 | Copyright (C) 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 | |
22 | The author of the program may be contacted at ian@airs.com or |
23 | c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. |
24 | */ |
25 | |
26 | #include "uucp.h" |
27 | |
28 | #if USE_RCS_ID |
29 | const char prott_rcsid[] = "$Id: prott.c,v 1.1 1993/08/04 19:36:24 jtc Exp $"; |
30 | #endif |
31 | |
32 | #include "uudefs.h" |
33 | #include "uuconf.h" |
34 | #include "conn.h" |
35 | #include "trans.h" |
36 | #include "system.h" |
37 | #include "prot.h" |
38 | \f |
39 | /* This implementation is based on code written by Rick Adams. |
40 | |
41 | This code implements the 't' protocol, which does no error checking |
42 | whatsoever and thus requires an end-to-end verified eight bit |
43 | communication line, such as is provided by TCP. Using it with a |
44 | modem is unadvisable, since errors can occur between the modem and |
45 | the computer. */ |
46 | \f |
47 | /* The buffer size we use. */ |
48 | #define CTBUFSIZE (1024) |
49 | |
50 | /* The offset in the buffer to the data. */ |
51 | #define CTFRAMELEN (4) |
52 | |
53 | /* Commands are sent in multiples of this size. */ |
54 | #define CTPACKSIZE (512) |
55 | |
56 | /* A pointer to the buffer we will use. */ |
57 | static char *zTbuf; |
58 | |
59 | /* True if we are receiving a file. */ |
60 | static boolean fTfile; |
61 | |
62 | /* The timeout we use. */ |
63 | static int cTtimeout = 120; |
64 | |
65 | struct uuconf_cmdtab asTproto_params[] = |
66 | { |
67 | { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cTtimeout, NULL }, |
68 | { NULL, 0, NULL, NULL } |
69 | }; |
70 | |
71 | /* Local function. */ |
72 | |
73 | static boolean ftprocess_data P((struct sdaemon *qdaemon, boolean *pfexit, |
74 | size_t *pcneed)); |
75 | \f |
76 | /* Start the protocol. */ |
77 | |
78 | boolean |
79 | ftstart (qdaemon, pzlog) |
80 | struct sdaemon *qdaemon; |
81 | char **pzlog; |
82 | { |
83 | *pzlog = NULL; |
84 | if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, |
85 | STRIPSETTING_EIGHTBITS, XONXOFF_OFF)) |
86 | return FALSE; |
87 | zTbuf = (char *) xmalloc (CTBUFSIZE + CTFRAMELEN); |
88 | /* The first two bytes of the buffer are always zero. */ |
89 | zTbuf[0] = 0; |
90 | zTbuf[1] = 0; |
91 | fTfile = FALSE; |
92 | usysdep_sleep (2); |
93 | return TRUE; |
94 | } |
95 | \f |
96 | /* Stop the protocol. */ |
97 | |
98 | /*ARGSUSED*/ |
99 | boolean |
100 | ftshutdown (qdaemon) |
101 | struct sdaemon *qdaemon; |
102 | { |
103 | xfree ((pointer) zTbuf); |
104 | zTbuf = NULL; |
105 | cTtimeout = 120; |
106 | return TRUE; |
107 | } |
108 | \f |
109 | /* Send a command string. We send everything up to and including the |
110 | null byte. The number of bytes we send must be a multiple of |
111 | TPACKSIZE. */ |
112 | |
113 | /*ARGSUSED*/ |
114 | boolean |
115 | ftsendcmd (qdaemon, z, ilocal, iremote) |
116 | struct sdaemon *qdaemon; |
117 | const char *z; |
118 | int ilocal; |
119 | int iremote; |
120 | { |
121 | size_t clen, csend; |
122 | char *zalc; |
123 | boolean fret; |
124 | |
125 | DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "ftsendcmd: Sending command \"%s\"", z); |
126 | |
127 | clen = strlen (z); |
128 | |
129 | /* We need to send the smallest multiple of CTPACKSIZE which is |
130 | greater than clen (not equal to clen, since we need room for the |
131 | null byte). */ |
132 | csend = ((clen / CTPACKSIZE) + 1) * CTPACKSIZE; |
133 | |
134 | zalc = zbufalc (csend); |
135 | memcpy (zalc, z, 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 | \f |
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*/ |
147 | char * |
148 | ztgetspace (qdaemon, pclen) |
149 | struct sdaemon *qdaemon; |
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*/ |
161 | boolean |
162 | ftsenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) |
163 | struct sdaemon *qdaemon; |
164 | char *zdata; |
165 | size_t cdata; |
166 | int ilocal; |
167 | int iremote; |
168 | long ipos; |
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 | \f |
185 | /* Process data and return the amount we need in *pfneed. */ |
186 | |
187 | static boolean |
188 | ftprocess_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 | \f |
284 | /* Wait for data to come in and process it until we've reached the end |
285 | of a command or a file. */ |
286 | |
287 | boolean |
288 | ftwait (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 | \f |
312 | /* File level routine, to set fTfile correctly. */ |
313 | |
314 | /*ARGSUSED*/ |
315 | boolean |
316 | ftfile (qdaemon, qtrans, fstart, fsend, cbytes, pfhandled) |
317 | struct sdaemon *qdaemon; |
318 | struct stransfer *qtrans; |
319 | boolean fstart; |
320 | boolean fsend; |
321 | long cbytes; |
322 | boolean *pfhandled; |
323 | { |
324 | *pfhandled = FALSE; |
325 | |
326 | if (! fsend) |
327 | fTfile = fstart; |
328 | |
329 | return TRUE; |
330 | } |