|
|
1.1 root 1: /* protj.c
2: The 'j' protocol.
3:
4: Copyright (C) 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 [email protected] 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 protj_rcsid[] = "$Id: protj.c,v 1.1 93/07/30 07:53:35 bin Exp Locker: bin $";
30: #endif
31:
32: #include <ctype.h>
33: #include <errno.h>
34:
35: #include "uudefs.h"
36: #include "conn.h"
37: #include "trans.h"
38: #include "system.h"
39: #include "prot.h"
40:
41: /* The 'j' protocol.
42:
43: The 'j' protocol is a wrapper around the 'i' protocol, which avoids
44: the use of certain characters, such as XON and XOFF.
45:
46: Each 'j' protocol packet begins with a '^' character, followed by a
47: two byte encoded size giving the total number of bytes in the
48: packet. The first byte is HIGH, the second byte is LOW, and the
49: number of bytes is (HIGH - 32) * 64 + (LOW - 32), where 32 <= HIGH
50: < 127 and 32 <= LOW < 96 (i.e., HIGH and LOW are printable ASCII
51: characters). This is followed by a '=' character. The next two
52: bytes are the number of data bytes in the packet, using the same
53: encoding. This is followed by a '@' character, and then that
54: number of data bytes. The remaining bytes in the packet are
55: indices of bytes which must be transformed, followed by a trailing
56: '~' character. The indices are encoded in the following overly
57: complex format.
58:
59: Each byte index is two bytes long. The first byte in the index is
60: INDEX-HIGH and the second is INDEX-LOW. If 32 <= INDEX-HIGH < 126,
61: the byte index refers to the byte at position (INDEX-HIGH - 32) *
62: 32 + INDEX-LOW % 32 in the actual data, where 32 <= INDEX-LOW <
63: 127. If 32 <= INDEX-LOW < 64, then 128 must be added to the
64: indexed byte. If 64 <= INDEX-LOW < 96, then the indexed byte must
65: be exclusive or'red with 32. If 96 <= INDEX-LOW < 127, both
66: operations must be performed. If INDEX-HIGH == 126, then the byte
67: index refers to the byte at position (INDEX-LOW - 32) * 32 + 31,
68: where 32 <= INDEX-LOW < 126. 128 must be added to the byte, and it
69: must be exclusive or'red with 32. This unfortunately requires a
70: special test (when encoding INDEX-LOW must be checked for 127; when
71: decoding INDEX-HIGH must be checked for 126). It does, however,
72: permit the byte indices field to consist exclusively of printable
73: ASCII characters.
74:
75: The maximum value for a byte index is (125 - 32) * 32 + 31 == 3007,
76: so the is the maximum number of data bytes permitted. Since it is
77: convenient to have each 'j' protocol packet correspond to each 'i'
78: protocol packet, we restrict the 'i' protocol accordingly.
79:
80: Note that this encoding method assumes that we can send all
81: printable ASCII characters. */
82:
83: /* The first byte of each packet. I just picked these values
84: randomly, trying to get characters that were perhaps slightly less
85: likely to appear in normal text. */
86: #define FIRST '\136'
87:
88: /* The fourth byte of each packet. */
89: #define FOURTH '\075'
90:
91: /* The seventh byte of each packet. */
92: #define SEVENTH '\100'
93:
94: /* The trailing byte of each packet. */
95: #define TRAILER '\176'
96:
97: /* The length of the header. */
98: #define CHDRLEN (7)
99:
100: /* Get a number of bytes encoded in a two byte length at the start of
101: a packet. */
102: #define CGETLENGTH(b1, b2) (((b1) - 32) * 64 + ((b2) - 32))
103:
104: /* Set the high and low bytes of a two byte length at the start of a
105: packet. */
106: #define ISETLENGTH_FIRST(i) ((i) / 64 + 32)
107: #define ISETLENGTH_SECOND(i) ((i) % 64 + 32)
108:
109: /* The maximum packet size we support, as determined by the byte
110: indices. */
111: #define IMAXPACKSIZE ((125 - 32) * 32 + 31)
112:
113: /* Amount to offset the bytes in the byte index by. */
114: #define INDEX_OFFSET (32)
115:
116: /* Maximum value of INDEX-LOW, before offsetting. */
117: #define INDEX_MAX_LOW (32)
118:
119: /* Maximum value of INDEX-HIGH, before offsetting. */
120: #define INDEX_MAX_HIGH (94)
121:
122: /* The set of characters to avoid. */
123: static char *zJavoid;
124:
125: /* The number of characters to avoid. */
126: static size_t cJavoid;
127:
128: /* A buffer used when sending data. */
129: static char *zJbuf;
130:
131: /* The end of the undecoded data in abPrecbuf. */
132: static int iJrecend;
133:
134: /* Local functions. */
135: static boolean fjsend_data P((struct sconnection *qconn, const char *zsend,
136: size_t csend, boolean fdoread));
137: static boolean fjreceive_data P((struct sconnection *qconn, size_t cneed,
138: size_t *pcrec, int ctimeout,
139: boolean freport));
140: static boolean fjprocess_data P((size_t *pcneed));
141:
142: /* Start the protocol. We first send over the list of characters to
143: avoid as an escape sequence, starting with FIRST and ending with
144: TRAILER. There is no error checking done on this string. */
145:
146: boolean
147: fjstart (qdaemon, pzlog)
148: struct sdaemon *qdaemon;
149: char **pzlog;
150: {
151: size_t clen;
152: char *zsend;
153: int b;
154: size_t cbuf, cgot;
155: char *zbuf;
156: int i;
157:
158: /* Send the characters we want to avoid to the other side. */
159: clen = strlen (zJavoid_parameter);
160: zsend = zbufalc (clen + 3);
161: zsend[0] = FIRST;
162: memcpy (zsend + 1, zJavoid_parameter, clen);
163: zsend[clen + 1] = TRAILER;
164: zsend[clen + 2] = '\0';
165: if (! fsend_data (qdaemon->qconn, zsend, clen + 2, TRUE))
166: {
167: ubuffree (zsend);
168: return FALSE;
169: }
170: ubuffree (zsend);
171:
172: /* Read the characters the other side wants to avoid. */
173: while ((b = breceive_char (qdaemon->qconn, cIsync_timeout, TRUE))
174: != FIRST)
175: {
176: if (b < 0)
177: {
178: if (b == -1)
179: ulog (LOG_ERROR, "Timed out in 'j' protocol startup");
180: return FALSE;
181: }
182: }
183:
184: cbuf = 20;
185: zbuf = zbufalc (cbuf);
186: cgot = 0;
187: while ((b = breceive_char (qdaemon->qconn, cIsync_timeout, TRUE))
188: != TRAILER)
189: {
190: if (b < 0)
191: {
192: ubuffree (zbuf);
193: if (b == -1)
194: ulog (LOG_ERROR, "Timed out in 'j' protocol startup");
195: return FALSE;
196: }
197: if (cgot + 1 >= cbuf)
198: {
199: char *znew;
200:
201: cbuf += 20;
202: znew = zbufalc (cbuf);
203: memcpy (znew, zbuf, cgot);
204: ubuffree (zbuf);
205: zbuf = znew;
206: }
207: zbuf[cgot] = b;
208: ++cgot;
209: }
210: zbuf[cgot] = '\0';
211:
212: /* Merge the local and remote avoid bytes into one list, translated
213: into bytes. */
214: cgot = cescape (zbuf);
215:
216: clen = strlen (zJavoid_parameter);
217: zJavoid = zbufalc (clen + cgot + 1);
218: memcpy (zJavoid, zJavoid_parameter, clen + 1);
219: cJavoid = cescape (zJavoid);
220:
221: for (i = 0; i < cgot; i++)
222: {
223: if (memchr (zJavoid, zbuf[i], cJavoid) == NULL)
224: {
225: zJavoid[cJavoid] = zbuf[i];
226: ++cJavoid;
227: }
228: }
229:
230: ubuffree (zbuf);
231:
232: /* We can't avoid ASCII printable characters, since the encoding
233: method assumes that they can always be sent. If it ever turns
234: out to be important, a different encoding method could be used,
235: perhaps keyed by a different FIRST character. */
236: if (cJavoid == 0)
237: {
238: ulog (LOG_ERROR, "No characters to avoid in 'j' protocol");
239: return FALSE;
240: }
241: for (i = 0; i < cJavoid; i++)
242: {
243: if (zJavoid[i] >= 32 && zJavoid[i] <= 126)
244: {
245: ulog (LOG_ERROR, "'j' protocol can't avoid character '\\%03o'",
246: zJavoid[i]);
247: return FALSE;
248: }
249: }
250:
251: /* If we are avoiding XON and XOFF, use XON/XOFF handshaking. */
252: if (memchr (zJavoid, '\021', cJavoid) != NULL
253: && memchr (zJavoid, '\023', cJavoid) != NULL)
254: {
255: if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE,
256: STRIPSETTING_EIGHTBITS, XONXOFF_ON))
257: return FALSE;
258: }
259:
260: /* Let the port settle. */
261: usysdep_sleep (2);
262:
263: /* Allocate a buffer we use when sending data. We will probably
264: never actually need one this big; if this code is ported to a
265: computer with small amounts of memory, this should be changed to
266: increase the buffer size as needed. */
267: zJbuf = zbufalc (CHDRLEN + IMAXPACKSIZE * 3 + 1);
268: zJbuf[0] = FIRST;
269: zJbuf[3] = FOURTH;
270: zJbuf[6] = SEVENTH;
271:
272: /* iJrecend is the end of the undecoded data, and iPrecend is the
273: end of the decoded data. At this point there is no decoded data,
274: and we must initialize the variables accordingly. */
275: iJrecend = iPrecend;
276: iPrecend = iPrecstart;
277:
278: /* Now do the 'i' protocol startup. */
279: return fijstart (qdaemon, pzlog, IMAXPACKSIZE, fjsend_data,
280: fjreceive_data);
281: }
282:
283: /* Shut down the protocol. */
284:
285: boolean
286: fjshutdown (qdaemon)
287: struct sdaemon *qdaemon;
288: {
289: boolean fret;
290:
291: fret = fishutdown (qdaemon);
292: ubuffree (zJavoid);
293: ubuffree (zJbuf);
294: return fret;
295: }
296:
297: /* Encode a packet of data and send it. This copies the data, which
298: is a waste of time, but calling fsend_data three times (for the
299: header, the body, and the trailer) would waste even more time. */
300:
301: static boolean
302: fjsend_data (qconn, zsend, csend, fdoread)
303: struct sconnection *qconn;
304: const char *zsend;
305: size_t csend;
306: boolean fdoread;
307: {
308: char *zput, *zindex;
309: const char *zfrom, *zend;
310: char bfirst, bsecond;
311: int iprecendhold;
312: boolean fret;
313:
314: zput = zJbuf + CHDRLEN;
315: zindex = zput + csend;
316: zfrom = zsend;
317: zend = zsend + csend;
318:
319: /* Optimize for the common case of avoiding two characters. */
320: bfirst = zJavoid[0];
321: if (cJavoid <= 1)
322: bsecond = bfirst;
323: else
324: bsecond = zJavoid[1];
325: while (zfrom < zend)
326: {
327: char b;
328: boolean f128, f32;
329: int i, ihigh, ilow;
330:
331: b = *zfrom++;
332: if (b != bfirst && b != bsecond)
333: {
334: int ca;
335: char *za;
336:
337: if (cJavoid <= 2)
338: {
339: *zput++ = b;
340: continue;
341: }
342:
343: ca = cJavoid - 2;
344: za = zJavoid + 2;
345: while (ca-- != 0)
346: if (*za++ == b)
347: break;
348:
349: if (ca < 0)
350: {
351: *zput++ = b;
352: continue;
353: }
354: }
355:
356: if ((b & 0x80) == 0)
357: f128 = FALSE;
358: else
359: {
360: b &=~ 0x80;
361: f128 = TRUE;
362: }
363: if (b >= 32 && b != 127)
364: f32 = FALSE;
365: else
366: {
367: b ^= 0x20;
368: f32 = TRUE;
369: }
370:
371: /* We must now put the byte index into the buffer. The byte
372: index is encoded similarly to the length of the actual data,
373: but the byte index also encodes the operations that must be
374: performed on the byte. The first byte in the index is the
375: most significant bits. If we only had to subtract 128 from
376: the byte, we use the second byte directly. If we had to xor
377: the byte with 32, we add 32 to the second byte index. If we
378: had to perform both operations, we add 64 to the second byte
379: index. However, if we had to perform both operations, and
380: the second byte index was 31, then after adding 64 and
381: offsetting by 32 we would come up with 127, which we are not
382: permitted to use. Therefore, in this special case we set the
383: first byte of the index to 126 and put the original first
384: byte into the second byte position instead. This is why we
385: could not permit the high byte of the length of the actual
386: data to be 126. We can get away with the switch because both
387: the value of the second byte index (31) and the operations to
388: perform (both) are known. */
389: i = zput - (zJbuf + CHDRLEN);
390: ihigh = i / INDEX_MAX_LOW;
391: ilow = i % INDEX_MAX_LOW;
392:
393: if (f128 && ! f32)
394: ;
395: else if (f32 && ! f128)
396: ilow += INDEX_MAX_LOW;
397: else
398: {
399: /* Both operations had to be performed. */
400: if (ilow != INDEX_MAX_LOW - 1)
401: ilow += 2 * INDEX_MAX_LOW;
402: else
403: {
404: ilow = ihigh;
405: ihigh = INDEX_MAX_HIGH;
406: }
407: }
408:
409: *zindex++ = ihigh + INDEX_OFFSET;
410: *zindex++ = ilow + INDEX_OFFSET;
411: *zput++ = b;
412: }
413:
414: *zindex++ = TRAILER;
415:
416: /* Set the lengths into the buffer. zJbuf[0,3,6] were set when
417: zJbuf was allocated, and are never changed thereafter. */
418: zJbuf[1] = ISETLENGTH_FIRST (zindex - zJbuf);
419: zJbuf[2] = ISETLENGTH_SECOND (zindex - zJbuf);
420: zJbuf[4] = ISETLENGTH_FIRST (csend);
421: zJbuf[5] = ISETLENGTH_SECOND (csend);
422:
423: /* Send the data over the line. We must preserve iPrecend as
424: discussed in fjreceive_data. */
425: iprecendhold = iPrecend;
426: iPrecend = iJrecend;
427: fret = fsend_data (qconn, zJbuf, (size_t) (zindex - zJbuf), fdoread);
428: iJrecend = iPrecend;
429: iPrecend = iprecendhold;
430:
431: /* Process any bytes that may have been placed in abPrecbuf. */
432: if (fret && iPrecend != iJrecend)
433: {
434: if (! fjprocess_data ((size_t *) NULL))
435: return FALSE;
436: }
437:
438: return fret;
439: }
440:
441: /* Receive and decode data. This is called by fiwait_for_packet. We
442: need to be able to return decoded data between iPrecstart and
443: iPrecend, while not losing any undecoded partial packets we may
444: have read. We use iJrecend as a pointer to the end of the
445: undecoded data, and set iPrecend for the decoded data. iPrecend
446: points to the start of the undecoded data. */
447:
448: static boolean
449: fjreceive_data (qconn, cineed, pcrec, ctimeout, freport)
450: struct sconnection *qconn;
451: size_t cineed;
452: size_t *pcrec;
453: int ctimeout;
454: boolean freport;
455: {
456: int iprecendstart;
457: size_t cjneed;
458: size_t crec;
459: int cnew;
460:
461: iprecendstart = iPrecend;
462:
463: /* Figure out how many bytes we need to decode the next packet. */
464: if (! fjprocess_data (&cjneed))
465: return FALSE;
466:
467: /* As we long as we read some data but don't have enough to decode a
468: packet, we try to read some more. We decrease the timeout each
469: time so that we will not wait forever if the connection starts
470: dribbling data. */
471: do
472: {
473: int iprecendhold;
474: size_t cneed;
475:
476: if (cjneed > cineed)
477: cneed = cjneed;
478: else
479: cneed = cineed;
480:
481: /* We are setting iPrecend to the end of the decoded data for
482: the 'i' protocol. When we do the actual read, we have to set
483: it to the end of the undecoded data so that any undecoded
484: data we have received is not overwritten. */
485: iprecendhold = iPrecend;
486: iPrecend = iJrecend;
487: if (! freceive_data (qconn, cneed, &crec, ctimeout, freport))
488: return FALSE;
489: iJrecend = iPrecend;
490: iPrecend = iprecendhold;
491:
492: /* Process any data we have received. This will set iPrecend to
493: the end of the new decoded data. */
494: if (! fjprocess_data (&cjneed))
495: return FALSE;
496:
497: cnew = iPrecend - iprecendstart;
498: if (cnew < 0)
499: cnew += CRECBUFLEN;
500:
501: if (cnew > cineed)
502: cineed = 0;
503: else
504: cineed -= cnew;
505:
506: --ctimeout;
507: }
508: while (cnew == 0 && crec > 0 && ctimeout > 0);
509:
510: DEBUG_MESSAGE1 (DEBUG_PROTO, "fjreceive_data: Got %d decoded bytes",
511: cnew);
512:
513: *pcrec = cnew;
514: return TRUE;
515: }
516:
517: /* Decode the data in the buffer, optionally returning the number of
518: bytes needed to complete the next packet. */
519:
520: static boolean
521: fjprocess_data (pcneed)
522: size_t *pcneed;
523: {
524: int istart;
525:
526: istart = iPrecend;
527: while (istart != iJrecend)
528: {
529: int i, iget;
530: char ab[CHDRLEN];
531: int cpacket, cdata, chave;
532: int iindex, iendindex;
533:
534: /* Find the next occurrence of FIRST. If we have to skip some
535: garbage bytes to get to it, zero them out (so they don't
536: confuse the 'i' protocol) and advance iPrecend. This will
537: save us from looking at them again. */
538: if (abPrecbuf[istart] != FIRST)
539: {
540: int cintro;
541: char *zintro;
542: size_t cskipped;
543:
544: cintro = iJrecend - istart;
545: if (cintro < 0)
546: cintro = CRECBUFLEN - istart;
547:
548: zintro = memchr (abPrecbuf + istart, FIRST, (size_t) cintro);
549: if (zintro == NULL)
550: {
551: bzero (abPrecbuf + istart, (size_t) cintro);
552: istart = (istart + cintro) % CRECBUFLEN;
553: iPrecend = istart;
554: continue;
555: }
556:
557: cskipped = zintro - (abPrecbuf + istart);
558: bzero (abPrecbuf + istart, cskipped);
559: istart += cskipped;
560: iPrecend = istart;
561: }
562:
563: for (i = 0, iget = istart;
564: i < CHDRLEN && iget != iJrecend;
565: ++i, iget = (iget + 1) % CRECBUFLEN)
566: ab[i] = abPrecbuf[iget];
567:
568: if (i < CHDRLEN)
569: {
570: if (pcneed != NULL)
571: *pcneed = CHDRLEN - i;
572: return TRUE;
573: }
574:
575: cpacket = CGETLENGTH (ab[1], ab[2]);
576: cdata = CGETLENGTH (ab[4], ab[5]);
577:
578: /* Make sure the header has the right magic characters, that the
579: data is not larger than the packet, and that we have an even
580: number of byte index characters. */
581: if (ab[3] != FOURTH
582: || ab[6] != SEVENTH
583: || cdata > cpacket - CHDRLEN - 1
584: || (cpacket - cdata - CHDRLEN - 1) % 2 == 1)
585: {
586: istart = (istart + 1) % CRECBUFLEN;
587: continue;
588: }
589:
590: chave = iJrecend - istart;
591: if (chave < 0)
592: chave += CRECBUFLEN;
593:
594: if (chave < cpacket)
595: {
596: if (pcneed != NULL)
597: *pcneed = cpacket - chave;
598: return TRUE;
599: }
600:
601: /* Figure out where the byte indices start and end. */
602: iindex = (istart + CHDRLEN + cdata) % CRECBUFLEN;
603: iendindex = (istart + cpacket - 1) % CRECBUFLEN;
604:
605: /* Make sure the magic trailer character is there. */
606: if (abPrecbuf[iendindex] != TRAILER)
607: {
608: istart = (istart + 1) % CRECBUFLEN;
609: continue;
610: }
611:
612: /* We have a packet to decode. The decoding process is simpler
613: than the encoding process, since all we have to do is examine
614: the byte indices. We zero out the byte indices as we go, so
615: that they will not confuse the 'i' protocol. */
616: while (iindex != iendindex)
617: {
618: int ihigh, ilow;
619: boolean f32, f128;
620: int iset;
621:
622: ihigh = abPrecbuf[iindex] - INDEX_OFFSET;
623: abPrecbuf[iindex] = 0;
624: iindex = (iindex + 1) % CRECBUFLEN;
625: ilow = abPrecbuf[iindex] - INDEX_OFFSET;
626: abPrecbuf[iindex] = 0;
627: iindex = (iindex + 1) % CRECBUFLEN;
628:
629: /* Now we must undo the encoding, by adding 128 and xoring
630: with 32 as appropriate. Which to do is encoded in the
631: low byte, except that if the high byte is the special
632: value 126, then the low byte is actually the high byte
633: and both operations are performed. */
634: f128 = TRUE;
635: f32 = TRUE;
636: if (ihigh == INDEX_MAX_HIGH)
637: iset = ilow * INDEX_MAX_LOW + INDEX_MAX_LOW - 1;
638: else
639: {
640: iset = ihigh * INDEX_MAX_LOW + ilow % INDEX_MAX_LOW;
641: if (ilow < INDEX_MAX_LOW)
642: f32 = FALSE;
643: else if (ilow < 2 * INDEX_MAX_LOW)
644: f128 = FALSE;
645: }
646:
647: /* Now iset is the index from the start of the data to the
648: byte to modify; adjust it to an index in abPrecbuf. */
649: iset = (istart + CHDRLEN + iset) % CRECBUFLEN;
650:
651: if (f128)
652: abPrecbuf[iset] |= 0x80;
653: if (f32)
654: abPrecbuf[iset] ^= 0x20;
655: }
656:
657: /* Zero out the header and trailer to avoid confusing the 'i'
658: protocol, and update iPrecend to the end of decoded data. */
659: for (i = 0, iget = istart;
660: i < CHDRLEN && iget != iJrecend;
661: ++i, iget = (iget + 1) % CRECBUFLEN)
662: abPrecbuf[iget] = 0;
663: abPrecbuf[iendindex] = 0;
664: iPrecend = (iendindex + 1) % CRECBUFLEN;
665: istart = iPrecend;
666: }
667:
668: if (pcneed != NULL)
669: *pcneed = CHDRLEN + 1;
670: return TRUE;
671: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.