|
|
1.1 root 1: /* trans.c
2: Routines to handle file transfers.
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 trans_rcsid[] = "$Id: trans.c,v 1.1 93/07/30 07:54:20 bin Exp Locker: bin $";
30: #endif
31:
32: #include <errno.h>
33:
34: #include "uudefs.h"
35: #include "uuconf.h"
36: #include "prot.h"
37: #include "system.h"
38: #include "trans.h"
39:
40: /* Local functions. */
41:
42: static void utqueue P((struct stransfer **, struct stransfer *,
43: boolean fhead));
44: static void utdequeue P((struct stransfer *));
45: static void utchanalc P((struct sdaemon *qdaemon, struct stransfer *qtrans));
46: __inline__ static struct stransfer *qtchan P((int ichan));
47: __inline__ static void utchanfree P((struct stransfer *qtrans));
48: static boolean ftcharge P((struct sdaemon *qdaemon,
49: struct stransfer *qtrans,
50: boolean fsend, boolean fforce));
51: static boolean fcheck_queue P((struct sdaemon *qdaemon));
52: static boolean ftadd_cmd P((struct sdaemon *qdaemon, const char *z,
53: size_t cdata, int iremote, boolean flast));
54: static boolean fremote_hangup_reply P((struct stransfer *qtrans,
55: struct sdaemon *qdaemon));
56: static boolean flocal_poll_file P((struct stransfer *qtrans,
57: struct sdaemon *qdaemon));
58:
59: /* Queue of transfer structures that are ready to start which have
60: been requested by the local system. These are only permitted to
61: start when the local system is the master. */
62: static struct stransfer *qTlocal;
63:
64: /* Queue of transfer structures that are ready to start which have
65: been requested by the remote system. These are responses to
66: commands received from the remote system, and should be started as
67: soon as possible. */
68: static struct stransfer *qTremote;
69:
70: /* Queue of transfer structures that have been started and want to
71: send information. This should be static, but the 'a' protocol
72: looks at it, at least for now. */
73: struct stransfer *qTsend;
74:
75: /* Queue of transfer structures that have been started and are waiting
76: to receive information. */
77: static struct stransfer *qTreceive;
78:
79: /* Queue of free transfer structures. */
80: static struct stransfer *qTavail;
81:
82: /* Array of transfer structures indexed by local channel number. This
83: is maintained for local jobs. */
84: static struct stransfer *aqTchan[IMAX_CHAN + 1];
85:
86: /* Number of local channel numbers currently allocated. */
87: static int cTchans;
88:
89: /* Next channel number to allocate. */
90: static int iTchan;
91:
92: /* Array of transfer structures indexed by remote channel number.
93: This is maintained for remote jobs. */
94: static struct stransfer *aqTremote[IMAX_CHAN + 1];
95:
96: /* A structure used to charge time to file transfers. */
97: struct scharge
98: {
99: /* The transfer we are currently charging. */
100: struct stransfer *qtrans;
101: /* The time at the last update. */
102: long isecs;
103: long imicros;
104: };
105:
106: /* We are always charging one send and one receive. */
107: static struct scharge sTsend;
108: static struct scharge sTreceive;
109:
110: /* The minimum amount of time, in seconds, to wait between times we
111: check the spool directory, if we are busy transferring data. If we
112: have nothing to do, we will check the spool directory regardless of
113: how long ago the last check was. This should probably be
114: configurable. */
115: #define CCHECKWAIT (600)
116:
117: /* The time we last checked the spool directory for work. This is set
118: from the return value of ixsysdep_process_time, not ixsysdep_time,
119: for convenience in the routines which use it. */
120: static long iTchecktime;
121:
122: /* The size of the command we have read so far in ftadd_cmd. */
123: static size_t cTcmdlen;
124:
125: /* The structure we use when waiting for an acknowledgement of a
126: confirmed received file in fsent_receive_ack, and a list of those
127: structures. */
128:
129: struct sreceive_ack
130: {
131: struct sreceive_ack *qnext;
132: char *zto;
133: char *ztemp;
134: boolean fmarked;
135: };
136:
137: static struct sreceive_ack *qTreceive_ack;
138:
139: /* Queue up a transfer structure before *pq. This puts it at the head
140: or the tail of the list headed by *pq. */
141:
142: static void
143: utqueue (pq, q, fhead)
144: struct stransfer **pq;
145: struct stransfer *q;
146: boolean fhead;
147: {
148: if (*pq == NULL)
149: {
150: *pq = q;
151: q->qprev = q->qnext = q;
152: }
153: else
154: {
155: q->qnext = *pq;
156: q->qprev = (*pq)->qprev;
157: q->qprev->qnext = q;
158: q->qnext->qprev = q;
159: if (fhead)
160: *pq = q;
161: }
162: q->pqqueue = pq;
163: }
164:
165: /* Dequeue a transfer structure. */
166:
167: static void
168: utdequeue (q)
169: struct stransfer *q;
170: {
171: if (q->pqqueue != NULL)
172: {
173: if (*(q->pqqueue) == q)
174: {
175: if (q->qnext == q)
176: *(q->pqqueue) = NULL;
177: else
178: *(q->pqqueue) = q->qnext;
179: }
180: q->pqqueue = NULL;
181: }
182: if (q->qprev != NULL)
183: q->qprev->qnext = q->qnext;
184: if (q->qnext != NULL)
185: q->qnext->qprev = q->qprev;
186: q->qprev = NULL;
187: q->qnext = NULL;
188: }
189:
190: /* Queue up a transfer structure requested by the local system. */
191:
192: /*ARGSIGNORED*/
193: boolean
194: fqueue_local (qdaemon, qtrans)
195: struct sdaemon *qdaemon;
196: struct stransfer *qtrans;
197: {
198: utdequeue (qtrans);
199: utqueue (&qTlocal, qtrans, FALSE);
200: return TRUE;
201: }
202:
203: /* Queue up a transfer structure requested by the remote system. The
204: stransfer structure should have the iremote field set. We need to
205: record it, so that any subsequent data associated with this
206: channel can be routed to the right place. */
207:
208: boolean
209: fqueue_remote (qdaemon, qtrans)
210: struct sdaemon *qdaemon;
211: struct stransfer *qtrans;
212: {
213: DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fqueue_remote: Channel %d",
214: qtrans->iremote);
215: if (qtrans->iremote > 0)
216: aqTremote[qtrans->iremote] = qtrans;
217: utdequeue (qtrans);
218: utqueue (&qTremote, qtrans, FALSE);
219:
220: /* We just received data for this transfer, so start charging. */
221: return ftcharge (qdaemon, qtrans, FALSE, FALSE);
222: }
223:
224: /* Queue up a transfer with something to send. */
225:
226: boolean
227: fqueue_send (qdaemon, qtrans)
228: struct sdaemon *qdaemon;
229: struct stransfer *qtrans;
230: {
231: #if DEBUG > 0
232: if (qtrans->psendfn == NULL)
233: ulog (LOG_FATAL, "fqueue_send: Bad call");
234: #endif
235: utdequeue (qtrans);
236: utqueue (&qTsend, qtrans, FALSE);
237:
238: /* Since we're now going to wait to send data, don't charge this
239: transfer for receive time. */
240: if (qtrans == sTreceive.qtrans)
241: return ftcharge (qdaemon, (struct stransfer *) NULL, FALSE, FALSE);
242: return TRUE;
243: }
244:
245: /* Queue up a transfer with something to receive. */
246:
247: boolean
248: fqueue_receive (qdaemon, qtrans)
249: struct sdaemon *qdaemon;
250: struct stransfer *qtrans;
251: {
252: #if DEBUG > 0
253: if (qtrans->precfn == NULL)
254: ulog (LOG_FATAL, "fqueue_receive: Bad call");
255: #endif
256: utdequeue (qtrans);
257: utqueue (&qTreceive, qtrans, FALSE);
258:
259: /* Since we are now going to wait to receive data, don't charge this
260: transfer for send time. */
261: if (qtrans == sTsend.qtrans)
262: return ftcharge (qdaemon, (struct stransfer *) NULL, TRUE, FALSE);
263: return TRUE;
264: }
265:
266: /* Get a new local channel number. */
267:
268: static void
269: utchanalc (qdaemon, qtrans)
270: struct sdaemon *qdaemon;
271: struct stransfer *qtrans;
272: {
273: do
274: {
275: ++iTchan;
276: if (iTchan > qdaemon->qproto->cchans)
277: iTchan = 1;
278: }
279: while (aqTchan[iTchan] != NULL);
280:
281: qtrans->ilocal = iTchan;
282: aqTchan[iTchan] = qtrans;
283: ++cTchans;
284: }
285:
286: /* Return the transfer for a channel number. */
287:
288: __inline__
289: static struct stransfer *
290: qtchan (ic)
291: int ic;
292: {
293: return aqTchan[ic];
294: }
295:
296: /* Clear the channel number for a transfer. */
297:
298: __inline__
299: static void
300: utchanfree (qt)
301: struct stransfer *qt;
302: {
303: if (qt->ilocal != 0)
304: {
305: aqTchan[qt->ilocal] = NULL;
306: qt->ilocal = 0;
307: --cTchans;
308: }
309: }
310:
311: /* Allocate a new transfer structure. */
312:
313: struct stransfer *
314: qtransalc (qcmd)
315: struct scmd *qcmd;
316: {
317: register struct stransfer *q;
318:
319: q = qTavail;
320: if (q != NULL)
321: utdequeue (q);
322: else
323: q = (struct stransfer *) xmalloc (sizeof (struct stransfer));
324: q->qnext = NULL;
325: q->qprev = NULL;
326: q->pqqueue = NULL;
327: q->psendfn = NULL;
328: q->precfn = NULL;
329: q->pinfo = NULL;
330: q->fsendfile = FALSE;
331: q->frecfile = FALSE;
332: q->e = EFILECLOSED;
333: q->ipos = 0;
334: q->fcmd = FALSE;
335: q->zcmd = NULL;
336: q->ccmd = 0;
337: q->ilocal = 0;
338: q->iremote = 0;
339: if (qcmd != NULL)
340: {
341: q->s = *qcmd;
342: q->s.zfrom = zbufcpy (qcmd->zfrom);
343: q->s.zto = zbufcpy (qcmd->zto);
344: q->s.zuser = zbufcpy (qcmd->zuser);
345: q->s.zoptions = zbufcpy (qcmd->zoptions);
346: q->s.ztemp = zbufcpy (qcmd->ztemp);
347: q->s.znotify = zbufcpy (qcmd->znotify);
348: q->s.zcmd = zbufcpy (qcmd->zcmd);
349: }
350: else
351: {
352: q->s.zfrom = NULL;
353: q->s.zto = NULL;
354: q->s.zuser = NULL;
355: q->s.zoptions = NULL;
356: q->s.ztemp = NULL;
357: q->s.znotify = NULL;
358: q->s.zcmd = NULL;
359: }
360: q->isecs = 0;
361: q->imicros = 0;
362: q->cbytes = 0;
363:
364: return q;
365: }
366:
367: /* Free a transfer structure. This does not free any pinfo
368: information that may have been allocated. */
369:
370: void
371: utransfree (q)
372: struct stransfer *q;
373: {
374: ubuffree (q->zcmd);
375: ubuffree ((char *) q->s.zfrom);
376: ubuffree ((char *) q->s.zto);
377: ubuffree ((char *) q->s.zuser);
378: ubuffree ((char *) q->s.zoptions);
379: ubuffree ((char *) q->s.ztemp);
380: ubuffree ((char *) q->s.znotify);
381: ubuffree ((char *) q->s.zcmd);
382:
383: utchanfree (q);
384: if (q->iremote > 0)
385: {
386: aqTremote[q->iremote] = NULL;
387: q->iremote = 0;
388: }
389:
390: #if DEBUG > 0
391: q->zcmd = NULL;
392: q->s.zfrom = NULL;
393: q->s.zto = NULL;
394: q->s.zuser = NULL;
395: q->s.zoptions = NULL;
396: q->s.ztemp = NULL;
397: q->s.znotify = NULL;
398: q->s.zcmd = NULL;
399: q->psendfn = NULL;
400: q->precfn = NULL;
401: #endif
402:
403: /* Don't try to charge time to this structure any longer. */
404: if (sTsend.qtrans == q)
405: sTsend.qtrans = NULL;
406: if (sTreceive.qtrans == q)
407: sTreceive.qtrans = NULL;
408:
409: utdequeue (q);
410: utqueue (&qTavail, q, FALSE);
411: }
412:
413: /* Handle timing of file tranfers. This is called when processing
414: starts for a transfer structure. All time up to the next call to
415: this function is charged to that transfer structure. Sending time
416: and receiving time are charged separately. Normally if we are
417: about to start charging the same structure we are already charging,
418: we do nothing; but if the fforce argument is TRUE, we charge the
419: time anyhow. */
420:
421: static boolean
422: ftcharge (qdaemon, qtrans, fsend, fforce)
423: struct sdaemon *qdaemon;
424: struct stransfer *qtrans;
425: boolean fsend;
426: boolean fforce;
427: {
428: struct scharge *qcharge, *qother;
429: long inextsecs, inextmicros;
430:
431: if (fsend)
432: {
433: qcharge = &sTsend;
434: qother = &sTreceive;
435: }
436: else
437: {
438: qcharge = &sTreceive;
439: qother = &sTsend;
440: }
441:
442: if (! fforce && qtrans == qcharge->qtrans)
443: return TRUE;
444:
445: inextsecs = ixsysdep_process_time (&inextmicros);
446: if (qcharge->qtrans != NULL)
447: {
448: qcharge->qtrans->isecs += inextsecs - qcharge->isecs;
449: qcharge->qtrans->imicros += inextmicros - qcharge->imicros;
450:
451: /* If we are charging the same structure for both send and
452: receive, update the time we are not currently charging so
453: that we don't charge twice for the same time. */
454: if (qcharge->qtrans == qother->qtrans)
455: {
456: qother->isecs = inextsecs;
457: qother->imicros = inextmicros;
458: }
459: }
460:
461: qcharge->qtrans = qtrans;
462: qcharge->isecs = inextsecs;
463: qcharge->imicros = inextmicros;
464:
465: /* If enough time has elapsed since the last time we checked the
466: queue, check it again. We do this here because we have already
467: gone to the trouble of getting the time. */
468: if (inextsecs - iTchecktime >= CCHECKWAIT)
469: {
470: if (! fcheck_queue (qdaemon))
471: return FALSE;
472: }
473:
474: return TRUE;
475: }
476:
477:
478: /* Gather local commands and queue them up for later processing. Also
479: recompute time based control values. */
480:
481: boolean
482: fqueue (qdaemon, pfany)
483: struct sdaemon *qdaemon;
484: boolean *pfany;
485: {
486: const struct uuconf_system *qsys;
487: int bgrade;
488: struct uuconf_timespan *qlocal_size, *qremote_size;
489:
490: if (pfany != NULL)
491: *pfany = FALSE;
492:
493: qsys = qdaemon->qsys;
494:
495: /* If we are not the caller, the grade will be set during the
496: initial handshake. */
497: if (! qdaemon->fcaller)
498: bgrade = qdaemon->bgrade;
499: else
500: {
501: long ival;
502:
503: if (! ftimespan_match (qsys->uuconf_qtimegrade, &ival,
504: (int *) NULL))
505: bgrade = '\0';
506: else
507: bgrade = (char) ival;
508: }
509:
510: /* Determine the maximum sizes we can send and receive. */
511: if (qdaemon->fcaller)
512: {
513: qlocal_size = qsys->uuconf_qcall_local_size;
514: qremote_size = qsys->uuconf_qcall_remote_size;
515: }
516: else
517: {
518: qlocal_size = qsys->uuconf_qcalled_local_size;
519: qremote_size = qsys->uuconf_qcalled_remote_size;
520: }
521:
522: if (! ftimespan_match (qlocal_size, &qdaemon->clocal_size, (int *) NULL))
523: qdaemon->clocal_size = (long) -1;
524: if (! ftimespan_match (qremote_size, &qdaemon->cremote_size, (int *) NULL))
525: qdaemon->cremote_size = (long) -1;
526:
527: if (bgrade == '\0')
528: return TRUE;
529:
530: if (! fsysdep_get_work_init (qsys, bgrade))
531: return FALSE;
532:
533: while (TRUE)
534: {
535: struct scmd s;
536:
537: if (! fsysdep_get_work (qsys, bgrade, &s))
538: return FALSE;
539:
540: if (s.bcmd == 'H')
541: {
542: ulog_user ((const char *) NULL);
543: break;
544: }
545:
546: if (s.bcmd == 'P')
547: {
548: struct stransfer *qtrans;
549:
550: /* A poll file. */
551: ulog_user ((const char *) NULL);
552: qtrans = qtransalc (&s);
553: qtrans->psendfn = flocal_poll_file;
554: if (! fqueue_local (qdaemon, qtrans))
555: return FALSE;
556: continue;
557: }
558:
559: ulog_user (s.zuser);
560:
561: switch (s.bcmd)
562: {
563: case 'S':
564: case 'E':
565: if (! flocal_send_file_init (qdaemon, &s))
566: return FALSE;
567: break;
568: case 'R':
569: if (! flocal_rec_file_init (qdaemon, &s))
570: return FALSE;
571: break;
572: case 'X':
573: if (! flocal_xcmd_init (qdaemon, &s))
574: return FALSE;
575: break;
576: #if DEBUG > 0
577: default:
578: ulog (LOG_FATAL, "fqueue: Can't happen");
579: break;
580: #endif
581: }
582: }
583:
584: if (pfany != NULL)
585: *pfany = qTlocal != NULL;
586:
587: iTchecktime = ixsysdep_process_time ((long *) NULL);
588:
589: return TRUE;
590: }
591:
592: /* Clear everything off the work queue. This is used when the call is
593: complete, or if the call is never made. */
594:
595: void
596: uclear_queue (qdaemon)
597: struct sdaemon *qdaemon;
598: {
599: int i;
600:
601: usysdep_get_work_free (qdaemon->qsys);
602:
603: qTlocal = NULL;
604: qTremote = NULL;
605: qTsend = NULL;
606: qTreceive = NULL;
607: cTchans = 0;
608: iTchan = 0;
609: sTsend.qtrans = NULL;
610: sTreceive.qtrans = NULL;
611: cTcmdlen = 0;
612: qTreceive_ack = NULL;
613: for (i = 0; i < IMAX_CHAN + 1; i++)
614: {
615: aqTchan[i] = NULL;
616: aqTremote[i] = NULL;
617: }
618: }
619:
620: /* Recheck the work queue during a conversation. This is only called
621: if it's been more than CCHECKWAIT seconds since the last time the
622: queue was checked. */
623:
624: static boolean
625: fcheck_queue (qdaemon)
626: struct sdaemon *qdaemon;
627: {
628: int cchans;
629:
630: /* Only check if we are the master, or if there are multiple
631: channels, or if we aren't already trying to get the other side to
632: hang up. Otherwise, there's nothing we can do with any new jobs
633: we might find. */
634: if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0)
635: cchans = 1;
636: else
637: cchans = qdaemon->qproto->cchans;
638: if (qdaemon->fmaster
639: || cchans > 1
640: || ! qdaemon->frequest_hangup)
641: {
642: boolean fany;
643:
644: DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
645: "fcheck_queue: Rechecking work queue");
646: if (! fqueue (qdaemon, &fany))
647: return FALSE;
648:
649: /* If we found something to do, and we're not the master, and we
650: don't have multiple channels to send new jobs over, try to
651: get the other side to hang up. */
652: if (fany && ! qdaemon->fmaster && cchans <= 1)
653: qdaemon->frequest_hangup = TRUE;
654: }
655:
656: return TRUE;
657: }
658:
659: /* The main transfer loop. The uucico daemon spends essentially all
660: its time in this function. */
661:
662: boolean
663: floop (qdaemon)
664: struct sdaemon *qdaemon;
665: {
666: int cchans;
667: boolean fret;
668:
669: /* If we are using a half-duplex line, act as though we have only a
670: single channel; otherwise we might start a send and a receive at
671: the same time. */
672: if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0)
673: cchans = 1;
674: else
675: cchans = qdaemon->qproto->cchans;
676:
677: fret = TRUE;
678:
679: while (! qdaemon->fhangup)
680: {
681: register struct stransfer *q;
682:
683: #if DEBUG > 1
684: /* If we're doing any debugging, close the log and debugging
685: files regularly. This will let people copy them off and
686: remove them while the conversation is in progresss. */
687: if (iDebug != 0)
688: {
689: ulog_close ();
690: ustats_close ();
691: }
692: #endif
693:
694: if (qdaemon->fmaster)
695: {
696: boolean fhangup;
697:
698: /* We've managed to become the master, so we no longer want
699: to request a hangup. */
700: qdaemon->frequest_hangup = FALSE;
701:
702: fhangup = FALSE;
703:
704: if (qdaemon->fhangup_requested
705: && qTsend == NULL)
706: {
707: /* The remote system has requested that we transfer
708: control by sending CYM after receiving a file. */
709: DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
710: "floop: Transferring control at remote request");
711: fhangup = TRUE;
712: }
713: else if (qTremote == NULL
714: && qTlocal == NULL
715: && qTsend == NULL
716: && qTreceive == NULL)
717: {
718: /* We don't have anything to do. Try to find some new
719: jobs. If we can't, transfer control. */
720: if (! fqueue (qdaemon, (boolean *) NULL))
721: {
722: fret = FALSE;
723: break;
724: }
725: if (qTlocal == NULL)
726: {
727: DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO,
728: "floop: No work for master");
729: fhangup = TRUE;
730: }
731: }
732:
733: if (fhangup)
734: {
735: if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, "H", 0, 0))
736: {
737: fret = FALSE;
738: break;
739: }
740: qdaemon->fmaster = FALSE;
741: }
742: }
743:
744: /* If we are no long the master, clear any requested hangup. We
745: may have already hung up before checking this variable in the
746: block above. */
747: if (! qdaemon->fmaster)
748: qdaemon->fhangup_requested = FALSE;
749:
750: /* Immediately queue up any remote jobs. We don't need local
751: channel numbers for them, since we can disambiguate based on
752: the remote channel number. */
753: while (qTremote != NULL)
754: {
755: q = qTremote;
756: utdequeue (q);
757: utqueue (&qTsend, q, TRUE);
758: }
759:
760: /* If we are the master, or if we have multiple channels, try to
761: queue up additional local jobs. */
762: if (qdaemon->fmaster || cchans > 1)
763: {
764: while (qTlocal != NULL && cTchans < cchans)
765: {
766: /* We have room for an additional channel. */
767: q = qTlocal;
768: if (! fqueue_send (qdaemon, q))
769: {
770: fret = FALSE;
771: break;
772: }
773: utchanalc (qdaemon, q);
774: }
775: if (! fret)
776: break;
777: }
778:
779: q = qTsend;
780:
781: if (q == NULL)
782: {
783: ulog_user ((const char *) NULL);
784: DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "floop: Waiting for data");
785: if (! (*qdaemon->qproto->pfwait) (qdaemon))
786: {
787: fret = FALSE;
788: break;
789: }
790: }
791: else
792: {
793: ulog_user (q->s.zuser);
794:
795: if (! q->fsendfile)
796: {
797: if (! ftcharge (qdaemon, q, TRUE, TRUE))
798: {
799: fret = FALSE;
800: break;
801: }
802:
803: if (! (*q->psendfn) (q, qdaemon))
804: {
805: fret = FALSE;
806: break;
807: }
808: }
809: else
810: {
811: if (! ftcharge (qdaemon, q, TRUE, FALSE))
812: {
813: fret = FALSE;
814: break;
815: }
816:
817: if (q->zlog != NULL)
818: {
819: ulog (LOG_NORMAL, "%s", q->zlog);
820: ubuffree (q->zlog);
821: q->zlog = NULL;
822: }
823:
824: /* We can read the file in a tight loop until qTremote
825: changes or until we have transferred the entire file.
826: We can disregard any changes to qTlocal since we
827: already have something to send anyhow. */
828: while (qTremote == NULL)
829: {
830: char *zdata;
831: size_t cdata;
832: long ipos;
833:
834: zdata = (*qdaemon->qproto->pzgetspace) (qdaemon, &cdata);
835: if (zdata == NULL)
836: {
837: fret = FALSE;
838: break;
839: }
840:
841: if (ffileeof (q->e))
842: cdata = 0;
843: else
844: {
845: cdata = cfileread (q->e, zdata, cdata);
846: if (ffilereaderror (q->e, cdata))
847: {
848: /* There is no way to report a file reading
849: error, so we just drop the connection. */
850: ulog (LOG_ERROR, "read: %s", strerror (errno));
851: fret = FALSE;
852: break;
853: }
854: }
855:
856: ipos = q->ipos;
857: q->ipos += cdata;
858: q->cbytes += cdata;
859:
860: if (! (*qdaemon->qproto->pfsenddata) (qdaemon, zdata,
861: cdata, q->ilocal,
862: q->iremote, ipos))
863: {
864: fret = FALSE;
865: break;
866: }
867:
868: /* It is possible that this transfer has just been
869: cancelled. */
870: if (q != qTsend || ! q->fsendfile)
871: break;
872:
873: if (cdata == 0)
874: {
875: /* We must update the time now, because this
876: call may make an entry in the statistics
877: file. */
878: if (! ftcharge (qdaemon, q, TRUE, TRUE))
879: fret = FALSE;
880: q->fsendfile = FALSE;
881: if (! (*q->psendfn) (q, qdaemon))
882: fret = FALSE;
883: break;
884: }
885: }
886:
887: if (! fret)
888: break;
889: }
890: }
891: }
892:
893: ulog_user ((const char *) NULL);
894:
895: (void) (*qdaemon->qproto->pfshutdown) (qdaemon);
896:
897: if (fret)
898: uwindow_acked (qdaemon, TRUE);
899: else
900: ufailed (qdaemon);
901:
902: return fret;
903: }
904:
905: /* This is called by the protocol routines when they have received
906: some data. If pfexit is not NULL, *pfexit should be set to TRUE if
907: the protocol receive loop should exit back to the main floop
908: routine, above. It is only important to set *pfexit to TRUE if the
909: main loop called the pfwait entry point, so we need never set it to
910: TRUE if we just receive data for a file. This routine never sets
911: *pfexit to FALSE. */
912:
913: boolean
914: fgot_data (qdaemon, zfirst, cfirst, zsecond, csecond, ilocal, iremote, ipos,
915: fallacked, pfexit)
916: struct sdaemon *qdaemon;
917: const char *zfirst;
918: size_t cfirst;
919: const char *zsecond;
920: size_t csecond;
921: int ilocal;
922: int iremote;
923: long ipos;
924: boolean fallacked;
925: boolean *pfexit;
926: {
927: struct stransfer *q;
928: int cwrote;
929: boolean fret;
930:
931: if (fallacked && qTreceive_ack != NULL)
932: uwindow_acked (qdaemon, TRUE);
933:
934: /* Now we have to decide which transfer structure gets the data. If
935: ilocal is -1, it means that the protocol does not know where to
936: route the data. In that case we route it to the first transfer
937: that is waiting for data, or, if none, as a new command. If
938: ilocal is 0, we either select based on the remote channel number
939: or we have a new command. */
940: if (ilocal == -1 && qTreceive != NULL)
941: q = qTreceive;
942: else if (ilocal == 0 && iremote > 0 && aqTremote[iremote] != NULL)
943: q = aqTremote[iremote];
944: else if (ilocal <= 0)
945: {
946: const char *znull;
947:
948: ulog_user ((const char *) NULL);
949:
950: /* This data is part of a command. If there is no null
951: character in the data, this string will be continued by the
952: next packet. Otherwise this must be the last string in the
953: command, and we don't care about what comes after the null
954: byte. */
955: znull = (const char *) memchr (zfirst, '\0', cfirst);
956: if (znull != NULL)
957: fret = ftadd_cmd (qdaemon, zfirst, (size_t) (znull - zfirst),
958: iremote, TRUE);
959: else
960: {
961: fret = ftadd_cmd (qdaemon, zfirst, cfirst, iremote, FALSE);
962: if (fret && csecond > 0)
963: {
964: znull = (const char *) memchr (zsecond, '\0', csecond);
965: if (znull != NULL)
966: fret = ftadd_cmd (qdaemon, zsecond,
967: (size_t) (znull - zsecond), iremote, TRUE);
968: else
969: fret = ftadd_cmd (qdaemon, zsecond, csecond, iremote, FALSE);
970: }
971: }
972:
973: if (pfexit != NULL && (qdaemon->fhangup || qTremote != NULL))
974: *pfexit = TRUE;
975:
976: return fret;
977: }
978: else
979: {
980: /* Get the transfer structure this data is intended for. */
981:
982: q = qtchan (ilocal);
983: }
984:
985: #if DEBUG > 0
986: if (q == NULL || q->precfn == NULL)
987: {
988: ulog (LOG_ERROR, "Protocol error: %lu bytes remote %d local %d",
989: (unsigned long) (cfirst + csecond),
990: iremote, ilocal);
991: return FALSE;
992: }
993: #endif
994:
995: ulog_user (q->s.zuser);
996:
997: fret = TRUE;
998:
999: /* If we're receiving a command, then accumulate it up to the null
1000: byte. */
1001: if (q->fcmd)
1002: {
1003: const char *znull;
1004:
1005: znull = NULL;
1006: while (cfirst > 0)
1007: {
1008: size_t cnew;
1009: char *znew;
1010:
1011: znull = (const char *) memchr (zfirst, '\0', cfirst);
1012: if (znull != NULL)
1013: cnew = znull - zfirst;
1014: else
1015: cnew = cfirst;
1016: znew = zbufalc (q->ccmd + cnew + 1);
1017: memcpy (znew, q->zcmd, q->ccmd);
1018: memcpy (znew + q->ccmd, zfirst, cnew);
1019: znew[q->ccmd + cnew] = '\0';
1020: ubuffree (q->zcmd);
1021: q->zcmd = znew;
1022: q->ccmd += cnew;
1023:
1024: if (znull != NULL)
1025: break;
1026:
1027: zfirst = zsecond;
1028: cfirst = csecond;
1029: csecond = 0;
1030: }
1031:
1032: if (znull != NULL)
1033: {
1034: char *zcmd;
1035: size_t ccmd;
1036:
1037: if (! ftcharge (qdaemon, q, FALSE, TRUE))
1038: fret = FALSE;
1039: zcmd = q->zcmd;
1040: ccmd = q->ccmd;
1041: q->fcmd = FALSE;
1042: q->zcmd = NULL;
1043: q->ccmd = 0;
1044: if (! (*q->precfn) (q, qdaemon, zcmd, ccmd + 1))
1045: fret = FALSE;
1046: ubuffree (zcmd);
1047: }
1048: else
1049: {
1050: if (! ftcharge (qdaemon, q, FALSE, FALSE))
1051: fret = FALSE;
1052: }
1053:
1054: if (pfexit != NULL
1055: && (qdaemon->fhangup
1056: || qdaemon->fmaster
1057: || qTsend != NULL))
1058: *pfexit = TRUE;
1059: }
1060: else if (! q->frecfile || cfirst == 0)
1061: {
1062: /* We're either not receiving a file or the file transfer is
1063: complete. */
1064: if (! ftcharge (qdaemon, q, FALSE, TRUE))
1065: fret = FALSE;
1066: q->frecfile = FALSE;
1067: if (! (*q->precfn) (q, qdaemon, zfirst, cfirst))
1068: fret = FALSE;
1069: if (fret && csecond > 0)
1070: return fgot_data (qdaemon, zsecond, csecond,
1071: (const char *) NULL, (size_t) 0,
1072: ilocal, iremote, ipos + (long) cfirst,
1073: FALSE, pfexit);
1074: if (pfexit != NULL
1075: && (qdaemon->fhangup
1076: || qdaemon->fmaster
1077: || qTsend != NULL))
1078: *pfexit = TRUE;
1079: }
1080: else
1081: {
1082: if (! ftcharge (qdaemon, q, FALSE, FALSE))
1083: fret = FALSE;
1084:
1085: if (q->zlog != NULL)
1086: {
1087: ulog (LOG_NORMAL, "%s", q->zlog);
1088: ubuffree (q->zlog);
1089: q->zlog = NULL;
1090: }
1091:
1092: if (ipos != -1 && ipos != q->ipos)
1093: {
1094: DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO,
1095: "fgot_data: Seeking to %ld", ipos);
1096: if (! ffileseek (q->e, ipos))
1097: {
1098: ulog (LOG_ERROR, "seek: %s", strerror (errno));
1099: fret = FALSE;
1100: }
1101: q->ipos = ipos;
1102: }
1103:
1104: if (fret)
1105: {
1106: while (cfirst > 0)
1107: {
1108: cwrote = cfilewrite (q->e, (char *) zfirst, cfirst);
1109: if (cwrote == cfirst)
1110: {
1111: #if FREE_SPACE_DELTA > 0
1112: long cfree_space;
1113:
1114: /* Check that there is still enough space on the
1115: disk. If there isn't, we drop the connection,
1116: because we have no way to abort a file transfer
1117: in progress. */
1118: cfree_space = qdaemon->qsys->uuconf_cfree_space;
1119: if (cfree_space > 0
1120: && ((q->cbytes / FREE_SPACE_DELTA)
1121: != (q->cbytes + cfirst) / FREE_SPACE_DELTA)
1122: && ! frec_check_free (q, cfree_space))
1123: {
1124: fret = FALSE;
1125: break;
1126: }
1127: #endif
1128: q->cbytes += cfirst;
1129: q->ipos += cfirst;
1130: }
1131: else
1132: {
1133: if (cwrote < 0)
1134: ulog (LOG_ERROR, "write: %s", strerror (errno));
1135: else
1136: ulog (LOG_ERROR,
1137: "Wrote %d to file when trying to write %lu",
1138: cwrote, (unsigned long) cfirst);
1139:
1140: /* Any write error is almost certainly a temporary
1141: condition, or else UUCP would not be functioning
1142: at all. If we continue to accept the file, we
1143: will wind up rejecting it at the end (what else
1144: could we do?) and the remote system will throw
1145: away the request. We're better off just dropping
1146: the connection, which is what happens when we
1147: return FALSE, and trying again later. */
1148: fret = FALSE;
1149: break;
1150: }
1151:
1152: zfirst = zsecond;
1153: cfirst = csecond;
1154: csecond = 0;
1155: }
1156: }
1157:
1158: if (pfexit != NULL && qdaemon->fhangup)
1159: *pfexit = TRUE;
1160: }
1161:
1162: return fret;
1163: }
1164:
1165: /* Accumulate a string into a command. If the command is complete,
1166: start up a new transfer. */
1167:
1168: static boolean
1169: ftadd_cmd (qdaemon, z, clen, iremote, flast)
1170: struct sdaemon *qdaemon;
1171: const char *z;
1172: size_t clen;
1173: int iremote;
1174: boolean flast;
1175: {
1176: static char *zbuf;
1177: static size_t cbuf;
1178: size_t cneed;
1179: struct scmd s;
1180:
1181: cneed = cTcmdlen + clen + 1;
1182: if (cneed > cbuf)
1183: {
1184: zbuf = (char *) xrealloc ((pointer) zbuf, cneed);
1185: cbuf = cneed;
1186: }
1187:
1188: memcpy (zbuf + cTcmdlen, z, clen);
1189: zbuf[cTcmdlen + clen] = '\0';
1190:
1191: if (! flast)
1192: {
1193: cTcmdlen += clen;
1194: return TRUE;
1195: }
1196:
1197: /* Don't save this string for next time. */
1198: cTcmdlen = 0;
1199:
1200: DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO,
1201: "ftadd_cmd: Got command \"%s\"", zbuf);
1202:
1203: if (! fparse_cmd (zbuf, &s))
1204: {
1205: ulog (LOG_ERROR, "Received garbled command \"%s\"", zbuf);
1206: return TRUE;
1207: }
1208:
1209: if (s.bcmd != 'H' && s.bcmd != 'Y' && s.bcmd != 'N')
1210: ulog_user (s.zuser);
1211: else
1212: ulog_user ((const char *) NULL);
1213:
1214: switch (s.bcmd)
1215: {
1216: case 'S':
1217: case 'E':
1218: return fremote_send_file_init (qdaemon, &s, iremote);
1219: case 'R':
1220: return fremote_rec_file_init (qdaemon, &s, iremote);
1221: case 'X':
1222: return fremote_xcmd_init (qdaemon, &s, iremote);
1223: case 'H':
1224: /* This is a remote request for a hangup. We close the log
1225: files so that they may be moved at this point. */
1226: ulog_close ();
1227: ustats_close ();
1228: {
1229: struct stransfer *q;
1230:
1231: q = qtransalc ((struct scmd *) NULL);
1232: q->psendfn = fremote_hangup_reply;
1233: q->iremote = iremote;
1234: return fqueue_remote (qdaemon, q);
1235: }
1236: case 'N':
1237: /* This means a hangup request is being denied; we just ignore
1238: this and wait for further commands. */
1239: return TRUE;
1240: case 'Y':
1241: /* This is a remote confirmation of a hangup. We reconfirm. */
1242: if (qdaemon->fhangup)
1243: return TRUE;
1244: #if DEBUG > 0
1245: if (qdaemon->fmaster)
1246: ulog (LOG_ERROR, "Got hangup reply as master");
1247: #endif
1248: /* Don't check errors rigorously here, since the other side
1249: might jump the gun and hang up. The fLog_sighup variable
1250: will get set TRUE again when the port is closed. */
1251: fLog_sighup = FALSE;
1252: (void) (*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, iremote);
1253: qdaemon->fhangup = TRUE;
1254: return TRUE;
1255: #if DEBUG > 0
1256: default:
1257: ulog (LOG_FATAL, "ftadd_cmd: Can't happen");
1258: return FALSE;
1259: #endif
1260: }
1261: }
1262:
1263: /* The remote system is requesting a hang up. If we have something to
1264: do, send an HN. Otherwise send two HY commands (the other side is
1265: presumed to send an HY command between the first and second, but we
1266: don't bother to wait for it) and hang up. */
1267:
1268: static boolean
1269: fremote_hangup_reply (qtrans, qdaemon)
1270: struct stransfer *qtrans;
1271: struct sdaemon *qdaemon;
1272: {
1273: boolean fret;
1274:
1275: utransfree (qtrans);
1276:
1277: if (qTremote == NULL
1278: && qTlocal == NULL
1279: && qTsend == NULL
1280: && qTreceive == NULL)
1281: {
1282: if (! fqueue (qdaemon, (boolean *) NULL))
1283: return FALSE;
1284:
1285: if (qTlocal == NULL)
1286: {
1287: DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fremote_hangup_reply: No work");
1288: fret = ((*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, 0)
1289: && (*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, 0));
1290: qdaemon->fhangup = TRUE;
1291: return fret;
1292: }
1293: }
1294:
1295: DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fremote_hangup_reply: Found work");
1296: fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, "HN", 0, 0);
1297: qdaemon->fmaster = TRUE;
1298: return fret;
1299: }
1300:
1301: /* As described in system.h, we need to keep track of which files have
1302: been successfully received for which we do not know that the other
1303: system has received our acknowledgement. This routine is called to
1304: keep a list of such files. */
1305:
1306: static struct sreceive_ack *qTfree_receive_ack;
1307:
1308: void
1309: usent_receive_ack (qdaemon, qtrans)
1310: struct sdaemon *qdaemon;
1311: struct stransfer *qtrans;
1312: {
1313: struct sreceive_ack *q;
1314:
1315: if (qTfree_receive_ack == NULL)
1316: q = (struct sreceive_ack *) xmalloc (sizeof (struct sreceive_ack));
1317: else
1318: {
1319: q = qTfree_receive_ack;
1320: qTfree_receive_ack = q->qnext;
1321: }
1322:
1323: q->qnext = qTreceive_ack;
1324: q->zto = zbufcpy (qtrans->s.zto);
1325: q->ztemp = zbufcpy (qtrans->s.ztemp);
1326: q->fmarked = FALSE;
1327:
1328: qTreceive_ack = q;
1329: }
1330:
1331: /* This routine is called by the protocol code when either all
1332: outstanding data has been acknowledged or one complete window has
1333: passed. It may be called directly by the protocol, or it may be
1334: called via fgot_data. If one complete window has passed, then all
1335: unmarked receives are marked, and we know that all marked ones have
1336: been acked. */
1337:
1338: void
1339: uwindow_acked (qdaemon, fallacked)
1340: struct sdaemon *qdaemon;
1341: boolean fallacked;
1342: {
1343: register struct sreceive_ack **pq;
1344:
1345: pq = &qTreceive_ack;
1346: while (*pq != NULL)
1347: {
1348: if (fallacked || (*pq)->fmarked)
1349: {
1350: struct sreceive_ack *q;
1351:
1352: q = *pq;
1353: (void) fsysdep_forget_reception (qdaemon->qsys, q->zto,
1354: q->ztemp);
1355: ubuffree (q->zto);
1356: ubuffree (q->ztemp);
1357: *pq = q->qnext;
1358: q->qnext = qTfree_receive_ack;
1359: qTfree_receive_ack = q;
1360: }
1361: else
1362: {
1363: (*pq)->fmarked = TRUE;
1364: pq = &(*pq)->qnext;
1365: }
1366: }
1367: }
1368:
1369: /* This routine is called when an error occurred and we are crashing
1370: out of the connection. It is used to report statistics on failed
1371: transfers to the statistics file, and it also discards useless
1372: temporary files for file receptions. Note that the number of bytes
1373: we report as having been sent has little or nothing to do with the
1374: number of bytes the remote site actually received. */
1375:
1376: void
1377: ufailed (qdaemon)
1378: struct sdaemon *qdaemon;
1379: {
1380: register struct stransfer *q;
1381:
1382: /* Update the transfer times, but avoid looking in the queue. */
1383: iTchecktime = ixsysdep_process_time ((long *) NULL);
1384: (void) ftcharge (qdaemon, (struct stransfer *) NULL, TRUE, TRUE);
1385: (void) ftcharge (qdaemon, (struct stransfer *) NULL, FALSE, TRUE);
1386:
1387: if (qTsend != NULL)
1388: {
1389: q = qTsend;
1390: do
1391: {
1392: if ((q->fsendfile || q->frecfile)
1393: && q->cbytes > 0)
1394: ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname,
1395: q->fsendfile, q->cbytes, q->isecs, q->imicros,
1396: FALSE);
1397: if (q->frecfile)
1398: (void) frec_discard_temp (qdaemon, q);
1399: q = q->qnext;
1400: }
1401: while (q != qTsend);
1402: }
1403:
1404: if (qTreceive != NULL)
1405: {
1406: q = qTreceive;
1407: do
1408: {
1409: if ((q->fsendfile || q->frecfile)
1410: && q->cbytes > 0)
1411: ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname,
1412: q->fsendfile, q->cbytes, q->isecs, q->imicros,
1413: FALSE);
1414: if (q->frecfile)
1415: (void) frec_discard_temp (qdaemon, q);
1416: q = q->qnext;
1417: }
1418: while (q != qTreceive);
1419: }
1420: }
1421:
1422: /* When a local poll file is found, it is entered on the queue like
1423: any other job. When it is pulled off the queue, this function is
1424: called. It just calls fsysdep_did_work, which will remove the poll
1425: file. This ensures that poll files are only removed if the system
1426: is actually called. */
1427:
1428: /*ARGSUSED*/
1429: static boolean
1430: flocal_poll_file (qtrans, qdaemon)
1431: struct stransfer *qtrans;
1432: struct sdaemon *qdaemon;
1433: {
1434: boolean fret;
1435:
1436: fret = fsysdep_did_work (qtrans->s.pseq);
1437: utransfree (qtrans);
1438: return fret;
1439: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.