1 /*
2
3 encapsulate.c, part of
4 netpipes: network pipe utilities
5 Copyright (C) 1996 Robert Forsman
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 */
22
23 static char info[] = "encapsulate: a utility for sockets\nWritten 1996 by Robert Forsman <thoth@purplefrog.com>\n";
24
25 /*
26 Encapsulate
27
28 encapsulate is designed to be used in a script spawned as the child
29 of a faucet or hose.
30
31 ============================================================
32
33 NEW version of encapsulate now. It uses the Session Control
34 Protocol described in http://sunsite.unc.edu/ses/scp.html .
35
36 ARGS:
37
38 If they don't specify --client or --server, compare your socket ID
39 (IP first, then port if IPs match) to the other end. The
40 numerically lower one is the server. The MSB is the first octet of
41 the IP. If they're identical, you have bigger problems >:)
42
43 For each --outfd on the subprocess, send a SYN packet with a new
44 session ID. For each --infd on the subprocess, set aside a
45 structure to wait for a SYN packet from the other end. Each SYN
46 packet will be associated with a file descriptor in the order they
47 were specified on the command line.
48
49 The --duplex descriptors are trickier. They need one session ID,
50 but who gets to allocate it? With --Duplex the "client" (which
51 could be local or remote) allocates the session ID and sends the SYN
52 packet. The "server" then sends a SYN packet for the same session
53 ID causing the connection to become two-way.
54
55 With --duplex, the local program waits for a SYN from the other side
56 and responds with a SYN of its own to duplex the session. With
57 --DUPLEX the local program sends the SYN packet and the remote side
58 is expected to duplex the session. The short flags correspond to
59 the long like so:
60
61 --Duplex n -dn
62 --duplex n -ion
63 --DUPLEX n -oin
64
65 Notice how the order of the i and o correspond to the order in which
66 the SYN packets are sent.
67
68 INTEROPERABILITY
69
70 This program is immensely complicated by the fact that I want it to
71 interoperate with a server that could also be speaking SCP (with
72 some theoretical restrictions to prevent the following problems).
73
74 1) SYN packets to associate with input descriptors could come
75 arbitrarily late in the conversaion.
76
77 2) The remote program might not be obeying our rules for the
78 --Duplex family of directives (this particular problem, and others,
79 could also be caused by command line mismatches on either side of
80 the link).
81
82 3) In my reading I haven't found any restrictions on bouncing the
83 connection between RO, RW and WO, which would wreak havoc on the
84 file-descriptor model `encapsulate' is based on.
85
86 For #1, I plan to just cope. As long as the SYNs eventually arrive,
87 things should work. #2 is stickier, and I want to figure out an
88 appropriate way to give a warning that a deadlock might be
89 occurring. #3 I will handle by ruthless application of RESET
90 packets and messages to stderr.
91
92
93 INCOMING BUFFER: store data from socket before it is sent to the
94 subprocess.
95
96 HEADER BUFFER: store headers from new SCP packets.
97
98 OUTGOING BUFFER 1: store data from subprocess before it is
99 encapsulated in an SCP packet. NOTE: once data from a subprocess
100 descriptor is stored in here, no other outgoing (subprocess-
101 writeable) descriptors should be polled. There is only one of these
102 buffers. This might result in a kind of starvation, so consider
103 doing a round-robin thing with the outgoing subprocess descriptors
104 that have data available.
105
106 OUTGOING BUFFER 2: store the SCP packet while it's being written to
107 the socket. While this buffer is in use, no packets can be
108 encapsulated, so data can accumulate in outgoing buffer 1. This is
109 good because then we have a bigger packet for next time.
110
111 Note: we'll be able to read arbitrarily-sized SCP packets due to the
112 design of the state machine. We'll be limited in the size of
113 packets we send by the size of outgoing buffer 1. I can hear you
114 saying "so what".
115
116 */
117
118 #include <stdio.h>
119 #include <errno.h>
120 extern int errno; /* I hate the errno header file */
121 #include <stdlib.h>
122 #include <unistd.h>
123 #include <signal.h>
124 #include <sys/socket.h>
125 #include <netinet/in.h>
126 #include <sys/time.h>
127 #include <sys/types.h>
128 #include <sys/wait.h>
129 #include <sys/un.h>
130
131 #include "common.h"
132 #include "memmove.h"
133
134 #define EXITCODE_ARGS 127
135 #define EXITCODE_SYSCALLFAILED 126
136 #define EXITCODE_EXECFAILED 125
137 #define EXITCODE_SIGNAL 124
138 #define EXITCODE_PROTOCOL 123
139 #define EXITCODE_GOT_RESET 122
140
141 #define PACKETCODE_EOF 0
142 #define PACKETCODE_EOF_WAITING 1
143 #define PACKETCODE_EXITSTATUS 2
144
145 /*typedef short Nshort;*/
146
147 #define SCP_SYN 0x80
148 #define SCP_FIN 0x40
149 #define SCP_PUSH 0x20
150 #define SCP_RESET 0x10
151
152 #define SESSION_ENCAP 70
153
154 /* encapsulate Control Protocol */
155 #define ECP_EOF 0
156 #define ECP_EXITCODE 1
157
158 /********************************************************************/
159
160 static int subproc=0;
161 static int verbose=0;
162
163 /********************************************************************/
164
usage()165 static void usage()
166 {
167 fprintf(stderr,"Usage : %s --fd n [ --verbose ] [ --subproc [ --infd n ] [ --outfd n ] [ --Duplex n ] [ --duplex n ] [ --DUPLEX n ] [ --prefer-local ] [ --prefer-remote ] [ --local-only ] [ --remote-only ] [ --client ] [ --server ] -[#n][v][s[in][on][dn][ion][oin][l][r][L][R]] <command> <args> ]\n",
168 progname);
169 }
170
171 /********************************************************************/
172
173 static int remote_return_code = 0;
174 static int local_return_code = 0;
175 static int exitcode_warnings = 0;
176
177 static int child_unreaped = 0;
178 static int child_running = 0;
179 static void probe_child();
180
Im_server_p(sock_fd)181 static int Im_server_p(sock_fd)
182 int sock_fd;
183 {
184 struct sockaddr_in me, him;
185 int len, i;
186
187 len = sizeof(me);
188 getsockname(sock_fd, (struct sockaddr*)&me, &len);
189
190 len = sizeof(him);
191 getpeername(sock_fd, (struct sockaddr*)&him, &len);
192
193 i = memcmp(&me.sin_addr, &him.sin_addr, 4);
194 if (i<0)
195 return 1;
196 else if (i>0)
197 return 0;
198
199 if (me.sin_port<him.sin_port)
200 return 1;
201 else
202 return 0;
203 }
204
205 struct pipeline {
206 int child_fd;
207 int pipe[2]; /* [0] is for the parent. [1] is for the child */
208 /* this is different from the pipe system call */
209 enum pipe_polarity {
210 READABLE,
211 DUPLEX/*conditional initiate*/,
212 DUPLEX_IO/*they initiate*/,
213 DUPLEX_OI/*we initiate*/,
214 WRITEABLE
215 } code;
216
217 /* once the connections are live we need extra info */
218 int session_id; /* odd for servers, even for clients */
219 int syn_received;
220
221 int bytes_left; /* in the packet we've partially read */
222
223 struct pipeline *next; /* linked list */
224 enum special_action {
225 NOTHING,
226 CLOSE_TO_READ, /* we got a FIN for this session_id */
227 CLOSE_TO_RW, /* we got a RESET for this session_id */
228 CLOSE_TO_WRITE, /* the child closed the descriptor */
229 } specact;
230 };
231
232 struct pipeline pl_bit_bucket;
233 struct pipeline *pl_encapsulate_control;
234 struct pipeline *pipe_head=0;
235
236 int session_id_;
237
238 /******************/
239
add_subproc_fd(fd,code,sid)240 void add_subproc_fd(fd, code, sid)
241 int fd;
242 enum pipe_polarity code;
243 int sid;
244 {
245 struct pipeline *temp;
246 temp = malloc(sizeof(*temp));
247 temp->child_fd = fd;
248 temp->code = code;
249 temp->session_id = sid;
250 temp->syn_received = 0;
251 temp->bytes_left = 0;
252 temp->specact = NOTHING;
253 temp->next = 0;
254 /* add to tail */
255 {
256 struct pipeline **curr;
257 for (curr = &pipe_head; *curr; curr = &( (*curr)->next ) )
258 ;
259 *curr = temp;
260 }
261 }
262
add_control_channel()263 void add_control_channel()
264 {
265 struct pipeline *temp;
266 temp = malloc(sizeof(*temp));
267 temp->child_fd = -1;
268 temp->pipe[0] = -10;
269 temp->code = DUPLEX_OI;
270 temp->session_id = SESSION_ENCAP;
271 temp->syn_received = 0;
272 temp->bytes_left = 0;
273 temp->specact = NOTHING;
274 temp->next = 0;
275 /* add to tail */
276 {
277 struct pipeline **curr;
278 for (curr = &pipe_head; *curr; curr = &( (*curr)->next ) )
279 ;
280 *curr = temp;
281 }
282
283 pl_encapsulate_control = temp;
284 }
285
remove_pipeline_(pl)286 void remove_pipeline_(pl)
287 struct pipeline ** pl;
288 {
289 struct pipeline *tmp;
290 tmp = *pl;
291 *pl = tmp->next;
292 free(tmp);
293 }
294
remove_pipeline(pl)295 void remove_pipeline(pl)
296 struct pipeline * pl;
297 {
298 struct pipeline **curr;
299 for (curr = &pipe_head;
300 *curr && *curr != pl;
301 curr = &( (*curr)->next ) )
302 ;
303 if (0==*curr) {
304 fprintf(stderr, "%s: greivous internal error. attempt to delete unlisted pipeline from queue\n", progname);
305 exit(1);
306 }
307 remove_pipeline_(curr);
308 }
309
310 /* build a buffer full of SYN packets. The beginning of the buffer is
311 the return value, and the length is stored into len_ret. */
prepare_SYNs(len_ret)312 static char * prepare_SYNs(len_ret)
313 int *len_ret;
314 {
315 struct pipeline *curr;
316 int size = 64;
317 char *rval = (char*)malloc(size);
318 *len_ret = 0;
319
320 for (curr = pipe_head; curr; curr = curr->next) {
321 switch (curr->code) {
322 case WRITEABLE:
323 case DUPLEX_IO:
324 /* we need to wait for the other side to send a SYN for
325 these two */
326 /* curr->session_id = -1; it's already -1 */
327 break;
328 case READABLE:
329 case DUPLEX_OI:
330 if (*len_ret + 8 > size) {
331 rval = (char*)realloc(rval, size *=2);
332 }
333 {
334 char *p = rval + *len_ret;
335 if (curr->session_id<0) {
336 curr->session_id = session_id_;
337 /* XXX - gotta prevent stompage in later rev */
338 session_id_ += 2; /* odd for servers, even for clients */
339 }
340 p[0] = SCP_SYN;
341 p[1] = (curr->session_id >>16 ) &0xff;
342 p[2] = (curr->session_id >> 8 ) &0xff;
343 p[3] = (curr->session_id >> 0 ) &0xff;
344 p[4] = p[5] = p[6] = p[7] = 0;
345 *len_ret += 8;
346 #ifdef DEBUG
347 fprintf(stderr, "%s: prepared SYN for session 0x%06x\n",
348 progname, curr->session_id);
349 #endif
350 }
351 break;
352 case DUPLEX: /* can't happen */
353 abort();
354 exit(1);
355 }
356 }
357
358 return rval;
359 }
360
361 struct special_packet {
362 char *buf;
363 int len;
364
365 struct special_packet *next;
366 };
367
368 struct special_packet *special_packet_queue = 0;
369
370
371 /* stuffs a special packet into the special-packet-queue for sending
372 at the next possible moment. sp and sp->buf must be heap-allocated. */
prime_packet_queue_(sp)373 void prime_packet_queue_(sp)
374 struct special_packet *sp;
375 {
376 struct special_packet **curr;
377
378 /* add to tail */
379 for (curr = &special_packet_queue; *curr; curr = &(*curr)->next)
380 ;
381
382 *curr = sp;
383 sp->next = 0;
384 }
385
prime_packet_queue(buf,len)386 void prime_packet_queue(buf, len)
387 char *buf;
388 int len;
389 {
390 struct special_packet *tmp;
391 tmp = malloc(sizeof(*tmp));
392 tmp->buf = buf;
393 tmp->len = len;
394 prime_packet_queue_(tmp);
395 }
396
397 /********************************************************************/
398
maybe_inject_special_packets(buf,len,size)399 void maybe_inject_special_packets(buf, len, size)
400 char *buf;
401 int *len;
402 int size;
403 {
404 struct special_packet *sp;
405 if (*len>0)
406 return; /* can't fit one in */
407
408 sp = special_packet_queue;
409
410 if (sp ==0)
411 return; /* no special packets */
412
413 if (sp->len > size) {
414 memcpy(buf, sp->buf, size);
415 memmove(sp->buf, sp->buf + size, sp->len -size);
416 sp->len -= size;
417 *len = size;
418 } else {
419 memcpy(buf, sp->buf, sp->len);
420 *len = sp->len;
421
422 special_packet_queue = sp->next;
423
424 free(sp->buf);
425 free(sp);
426 }
427 }
428
build_fd_lists(readfds,writefds,curr_readable,curr_writeable,sock_fd,maxfd,ibuf_len,ibuf_size,obuf_len,obuf_size,obuf2_len,obuf2_off)429 void build_fd_lists(readfds, writefds,
430 curr_readable, curr_writeable,
431 sock_fd, maxfd,
432 ibuf_len, ibuf_size,
433 obuf_len, obuf_size,
434 obuf2_len, obuf2_off)
435 fd_set *readfds, *writefds;
436 struct pipeline *curr_readable, *curr_writeable;
437 int sock_fd, *maxfd;
438 int ibuf_len, ibuf_size;
439 int obuf_len, obuf_size;
440 int obuf2_len, obuf2_off;
441 {
442 FD_ZERO(readfds);
443 FD_ZERO(writefds);
444 *maxfd = -1;
445 #define MAX_FD(i) if (*maxfd < (i)) *maxfd = (i)
446
447 /* when can we write to a child? */
448 if (ibuf_len>0 &&
449 curr_writeable->pipe[0]>=0 ) {
450 /* curr_writeable != 0 */
451 FD_SET(curr_writeable->pipe[0], writefds);
452 MAX_FD( curr_writeable->pipe[0] );
453 }
454
455 /* when can we read from the socket? */
456 if ( curr_writeable == 0
457 ||
458 (ibuf_len<ibuf_size &&
459 curr_writeable &&
460 curr_writeable->bytes_left > 0 )
461 ) {
462 #if 1
463 FD_SET(sock_fd, readfds);
464 MAX_FD(sock_fd);
465 #else
466 struct pipeline *curr;
467 for (curr = pipe_head; curr; curr = curr ? curr->next : 0) {
468 switch(curr->code) {
469 case DUPLEX_IO:
470 case DUPLEX_OI:
471 case DUPLEX: /* DUPLEX is not really possible */
472 case WRITEABLE:
473 FD_SET(sock_fd, readfds);
474 MAX_FD(sock_fd);
475 curr = 0; /* bail from for loop */
476 break;
477 case READABLE:
478 /* we don't write to this one */
479 break;
480 }
481 }
482 #endif
483 }
484
485 /* when can we read from a child? */
486 if ( curr_readable == 0 ) {
487 /* select from ANY incoming child descriptor */
488 struct pipeline *curr;
489 for (curr = pipe_head; curr; curr = curr->next) {
490 if (curr->pipe[0]<0) continue;
491 if ( curr->code == DUPLEX_IO &&
492 ! curr->syn_received)
493 continue;
494 if ( curr->specact == CLOSE_TO_WRITE ) continue;
495 switch(curr->code) {
496 case READABLE:
497 case DUPLEX_IO:
498 case DUPLEX_OI:
499 case DUPLEX: /* DUPLEX is not really possible */
500 FD_SET(curr->pipe[0], readfds);
501 MAX_FD(curr->pipe[0]);
502 break;
503 case WRITEABLE:
504 /* we don't read from this one */
505 break;
506 }
507 }
508 } else if (obuf_len < obuf_size &&
509 /* yes, the curr_readable could be WRITEABLE-only
510 when the child closes its descriptor, but we
511 haven't copied the bytes into the outgoing
512 socket buffer. In that case we don't want to
513 read from the descriptor. curr_readable will be
514 zeroed when the bytes get copied into the
515 outgoing socket buffer */
516 curr_readable->code != WRITEABLE &&
517 !( curr_readable->specact == CLOSE_TO_WRITE
518 || curr_readable->specact == CLOSE_TO_RW)
519 ) {
520 FD_SET(curr_readable->pipe[0], readfds);
521 MAX_FD(curr_readable->pipe[0]);
522 }
523
524 /* when can we write to the socket? */
525 if (obuf2_len>obuf2_off) {
526 FD_SET(sock_fd, writefds);
527 MAX_FD(sock_fd);
528 }
529 }
530
build_packet_header(buf,flags,session,length)531 void build_packet_header (buf, flags, session, length)
532 char *buf; /* length 8 */
533 int flags, session;
534 unsigned length;
535 {
536 buf[0] = flags;
537 buf[1] = session>>16;
538 buf[2] = session>>8;
539 buf[3] = session;
540 buf[4] = length>>24;
541 buf[5] = length>>16;
542 buf[6] = length>>8;
543 buf[7] = length;
544 }
545
send_reset(struct pipeline * pl)546 void send_reset(struct pipeline *pl)
547 {
548 char *buf = malloc(8);
549 build_packet_header(buf, SCP_RESET, pl->session_id, 0);
550 prime_packet_queue(buf, 8);
551 }
552
553 /* returns number of bytes read into buf at offset *buf_len, limited by
554 buf_size. An uncrecoverable error aborts the program */
read_from_child(pl,buf,buf_len,buf_size)555 int read_from_child(pl, buf, buf_len, buf_size)
556 struct pipeline *pl;
557 char *buf;
558 int *buf_len;
559 int buf_size;
560 {
561 int rval;
562
563 #if DEBUG>1
564 fprintf(stderr, "%s: read(in[c%d], buf+%d, %d-%d)",
565 progname, pl->child_fd, *buf_len, buf_size, *buf_len);
566 #endif
567 rval = read(pl->pipe[0], buf+*buf_len, buf_size - *buf_len);
568 #if DEBUG>1
569 fprintf(stderr, "=%d;\n", rval);
570 #endif
571 if (rval == 0) {
572 #ifdef DEBUG
573 fprintf(stderr, "%s: closing in[%d=c%d]\n", progname, pl->pipe[0], pl->child_fd);
574 #endif
575 pl->specact = CLOSE_TO_WRITE;
576 } else if (rval<0) {
577 if (errno == EINTR) {
578 return 0; /* no biggie, retry later */
579 } else {
580 fprintf(stderr, "%s: error during read(in[%d],,). Aborting. ",
581 progname, pl->pipe[0]);
582 perror("");
583 exit(EXITCODE_SYSCALLFAILED);
584 }
585 } else {
586 *buf_len += rval;
587 }
588 return rval;
589 }
590
591 /* returns number of bytes written from buf, limited by (*buf_len).
592 It takes care of moving the bytes in the buffer for the case of an
593 incomplete write. An uncrecoverable error aborts the program */
write_to_child(pl,buf,buf_len)594 int write_to_child(pl, buf, buf_len)
595 struct pipeline *pl;
596 char *buf;
597 int *buf_len;
598 {
599 int rval;
600
601 #if DEBUG>1
602 fprintf(stderr, "%s: write(out[%d/c%d], buf, %d)",
603 progname, pl->pipe[0], pl->child_fd, *buf_len);
604 #endif
605 rval = write(pl->pipe[0], buf, *buf_len);
606 #if DEBUG>1
607 fprintf(stderr, "=%d;\n", rval);
608 #endif
609 if (rval == 0) {
610 #ifdef DEBUG
611 fprintf(stderr, "%s: Inexplicable! write(out[%d],,%d) returns 0", progname, pl->pipe[0], *buf_len);
612 #endif
613 } else if (rval<0) {
614 if (errno == EINTR) {
615 return 0; /* no biggie, retry later */
616 } else if (errno == EPIPE) {
617 /* DOH! fake it */
618 fprintf(stderr, "%s: EPIPE while writing to child fd %d\n", progname, pl->child_fd);
619 exitcode_warnings = EXITCODE_GOT_RESET;
620 pl->specact = CLOSE_TO_READ;
621 *buf_len = 0;
622 send_reset(pl);
623 return 0; /* this is NOT a normal thing */
624 } else {
625 fprintf(stderr, "%s: error during write(out[%d],,). Aborting. ",
626 progname, pl->pipe[0]);
627 perror("");
628 exit(EXITCODE_SYSCALLFAILED);
629 }
630 } else {
631 memmove(buf, buf+rval, *buf_len - rval);
632 *buf_len -= rval;
633 }
634 return rval;
635 }
636
637 /* updates obuf_off to reflect how many bytes it copied from obuf to fd */
write_to_socket(fd,obuf,obuf_off,obuf_len)638 void write_to_socket(fd, obuf, obuf_off, obuf_len)
639 int fd;
640 char *obuf;
641 int *obuf_off;
642 int obuf_len;
643 {
644 int rval;
645
646 #if DEBUG>1
647 fprintf(stderr, "%s: write(sock_fd, buf+%d, %d-%d)",
648 progname, *obuf_off, obuf_len, *obuf_off);
649 #endif
650 rval = write(fd, obuf+ *obuf_off, obuf_len-*obuf_off);
651 #if DEBUG>1
652 fprintf(stderr, "=%d;\n", rval);
653 #endif
654 if (rval==0) {
655 fprintf(stderr, "%s: Inexplicable! write(sock_fd,,%d) returns 0\n",
656 progname, obuf_len-*obuf_off);
657 exit(EXITCODE_SYSCALLFAILED);
658 } else if (rval<0) {
659 if (errno!=EINTR) {
660 fprintf(stderr, "%s: error during write(sock_fd,,%d). Aborting. ",
661 progname, obuf_len-*obuf_off);
662 perror("");
663 exit(EXITCODE_SYSCALLFAILED);
664 }
665 /* never mind. try again later */
666 } else {
667 *obuf_off += rval;
668 }
669 }
670
671 /* read bytes from the socket */
672
read_from_socket(fd,pl,buf,buf_len,buf_size)673 void read_from_socket(fd, pl, buf, buf_len, buf_size)
674 int fd;
675 struct pipeline *pl;
676 char *buf;
677 int *buf_len, buf_size;
678 {
679 int desired_read = buf_size - *buf_len;
680 int rval;
681
682 if (pl && desired_read > pl->bytes_left) {
683 desired_read = pl->bytes_left;
684 }
685 #if DEBUG>1
686 fprintf(stderr, "%s: read(sock_fd, buf+%d, %d)",
687 progname, *buf_len, desired_read);
688 #endif
689 rval = read(fd, buf+*buf_len, desired_read);
690 #if DEBUG>1
691 fprintf(stderr, "=%d;\n", rval);
692 #endif
693 if (rval==0) {
694 fprintf(stderr, "%s: encapsulation protocol error reading socket. Socket closed prematurely by remote end.\n", progname);
695 /*sock_closed = 1;*/
696 exit(EXITCODE_PROTOCOL);
697 } else if (rval<0) {
698 if (errno!=EINTR) {
699 fprintf(stderr, "%s: error during read(sock_fd,,%d). Aborting. ",
700 progname, desired_read);
701 perror("");
702 exit(EXITCODE_SYSCALLFAILED);
703 }
704 /* never mind. try again later */
705 } else {
706 *buf_len += rval;
707
708 if (pl) pl->bytes_left -= rval;
709 }
710
711 if (pl == &pl_bit_bucket) {
712 /* throw away the bytes */
713 #ifdef DEBUG
714 fprintf(stderr, "%s: %d bytes into the bit bucket\n", progname, *buf_len);
715 #endif
716 *buf_len = 0;
717 }
718 }
719
interpret_scp_header(header,pl)720 void interpret_scp_header(header, pl)
721 unsigned char *header; /* size 8 */
722 struct pipeline **pl;
723 {
724 int flags, session_id;
725 unsigned int length;
726 struct pipeline *found = 0;
727
728 flags = header[0];
729 session_id = ( header[1] << 16 ) | ( header[2] << 8 ) | header[3];
730 length = ( header[4] << 24 ) | ( header[5] << 16 ) | ( header[6] << 8 ) | header[7];
731
732 #ifdef DEBUG
733 fprintf(stderr, "%s: packet. flags=0x%02x, session=0x%06x, length=%d\n",
734 progname, flags, session_id, length);
735 #endif
736
737 if ( (flags & (SCP_SYN|0xf)) == SCP_SYN) {
738 struct pipeline *curr;
739 found = 0;
740 /* see if there's one descriptor that's waiting for this
741 particular session_id */
742 for (curr = pipe_head; curr && !found; curr = curr->next ) {
743 if (curr->syn_received)
744 continue;
745 switch(curr->code) {
746 case WRITEABLE: case DUPLEX_IO: case DUPLEX_OI: case DUPLEX:
747 /* DUPLEX not actually possible */
748 if (curr->session_id == session_id) {
749 found = curr;
750 found->syn_received = 1;
751 }
752 break;
753 case READABLE:
754 break; /* like, whatever */
755 }
756 }
757 if (!found) for (curr = pipe_head; curr && !found; curr = curr->next ) {
758 if (curr->syn_received)
759 continue;
760 switch(curr->code) {
761 case WRITEABLE: case DUPLEX_IO: case DUPLEX_OI:
762 case DUPLEX: /* DUPLEX not actually possible */
763 if (curr->session_id<0) {
764 found = curr;
765 found->session_id = session_id;
766 found->syn_received = 1;
767 }
768 break;
769 case READABLE:
770 break; /* like, whatever */
771 }
772 }
773 if (!found) {
774 fprintf(stderr, "%s: Warning! discarding SYN for session_id=0x%06x, to the bit bucket!\n", progname, session_id);
775 found = &pl_bit_bucket;
776 } else {
777 #ifdef DEBUG
778 fprintf(stderr, "%s: received SYN for session 0x%06x", progname, session_id);
779 #endif
780 if (found->code == DUPLEX_IO) {
781 char *buf = malloc(8);
782 build_packet_header(buf, SCP_SYN, session_id, 0);
783 prime_packet_queue(buf, 8);
784 #ifdef DEBUG
785 fprintf(stderr, "; sending one back");
786 #endif
787 }
788 #ifdef DEBUG
789 putc('\n', stderr);
790 #endif
791 }
792 /* fall through and accept any data that might be in the packet */
793 } else if ( (flags & (SCP_FIN|0xf)) == SCP_FIN) {
794 struct pipeline *curr;
795 for (curr = pipe_head; curr && !found; curr = curr->next ) {
796 if (! curr->syn_received)
797 continue;
798 if (curr->session_id != session_id)
799 continue;
800
801 switch(curr->code) {
802 case WRITEABLE: case DUPLEX_IO: case DUPLEX_OI:
803 case DUPLEX: /* DUPLEX not actually possible */
804 found = curr;
805 found->specact = CLOSE_TO_READ;
806 break;
807 case READABLE:
808 break; /* like, whatever */
809 }
810 }
811 if (!found) {
812 fprintf(stderr, "%s: Warning! discarding FIN for session_id=0x%06x, to the bit bucket!\n", progname, session_id);
813 found = &pl_bit_bucket;
814 } else {
815 #ifdef DEBUG
816 fprintf(stderr, "%s: received FIN for session 0x%06x\n", progname, session_id);
817 #endif
818 }
819 } else if ( (flags & (SCP_PUSH|0xf)) == SCP_PUSH) {
820 /* like, whatever */
821 } else if ( (flags & (SCP_RESET|0xf)) == SCP_RESET) {
822 struct pipeline *curr;
823 /* why are they doing this to me? */
824 fprintf(stderr, "%s: RESET received for session_id=%d. closing descriptor bidirectionally\n", progname, session_id);
825 for (curr = pipe_head; curr && !found; curr = curr->next ) {
826 if (! curr->syn_received)
827 continue;
828 if (curr->session_id != session_id)
829 continue;
830
831 switch(curr->code) {
832 case READABLE: case DUPLEX_IO: case DUPLEX_OI:
833 case DUPLEX: /* DUPLEX not actually possible */
834 case WRITEABLE:
835 found = curr;
836 found->specact = CLOSE_TO_RW;
837 exitcode_warnings = EXITCODE_GOT_RESET;
838 break;
839 }
840 }
841 if (!found) {
842 fprintf(stderr, "%s: Warning! discarding RESET for session_id=0x%06x, to the bit bucket!\n", progname, session_id);
843 found = &pl_bit_bucket;
844 }
845 } else if (flags != 0) {
846 fprintf(stderr, "%s: Warning! funky flags 0x%02x on packet, to the bit bucket!\n", progname, flags);
847 found = &pl_bit_bucket;
848 } else {
849 struct pipeline *curr;
850 for (curr = pipe_head; curr && !found; curr = curr->next ) {
851 if (curr->session_id == session_id) {
852 found = curr;
853 break;
854 }
855 }
856 if (!found) {
857 fprintf(stderr, "%s: Warning! discarding data packet for session_id=0x%06x, to the bit bucket!\n", progname, session_id);
858 found = &pl_bit_bucket;
859 }
860 }
861
862 if (length) {
863
864 if (found->code == READABLE) {
865 fprintf(stderr, "%s: Got data for session 0x%06x I can't write to. RESETting\n", progname, session_id);
866 send_reset(found);
867 found = &pl_bit_bucket;
868 }
869
870 *pl = found;
871 (*pl)->bytes_left = length;
872 }
873 }
874
handle_control_message(buf,len)875 void handle_control_message(buf, len)
876 char *buf;
877 int len;
878 {
879 if (len<1) {
880 fprintf(stderr, "%s: Internal Error: control message length <1. \n", progname);
881 exit(1);
882 }
883
884 switch(buf[0]) {
885 case ECP_EOF:
886 if (len!=1) {
887 fprintf(stderr, "%s: Protocol Error: control message[0] length(%d) !=1. \n", progname, len);
888 exit(EXITCODE_PROTOCOL);
889 }
890 #ifdef DEBUG
891 fprintf(stderr, "%s: Got EOF from remote.\n", progname);
892 #endif
893
894 if (pl_encapsulate_control->code == WRITEABLE) {
895 remove_pipeline(pl_encapsulate_control);
896 pl_encapsulate_control = 0;
897 } else {
898 pl_encapsulate_control->code = READABLE;
899 }
900
901 break;
902
903 case ECP_EXITCODE:
904 if (len!=2) {
905 fprintf(stderr, "%s: Protocol Error: control message[1] length(%d) !=2. \n", progname, len);
906 exit(EXITCODE_PROTOCOL);
907 }
908 remote_return_code = (unsigned char )buf[1];
909 #ifdef DEBUG
910 fprintf(stderr, "%s: remote exit status: %d\n",
911 progname, remote_return_code);
912 #endif
913
914 if (pl_encapsulate_control->code == WRITEABLE) {
915 remove_pipeline(pl_encapsulate_control);
916 pl_encapsulate_control = 0;
917 } else {
918 pl_encapsulate_control->code = READABLE;
919 }
920
921 break;
922
923 default:
924 fprintf(stderr, "%s: Protocol Error: unknown control message [%d]. \n", progname, (unsigned char)buf[0]);
925 exit(EXITCODE_PROTOCOL);
926 break;
927 }
928 }
929
perform_special_actions(ibuf_len,obuf_len,curr_readable,curr_writeable)930 void perform_special_actions(ibuf_len, obuf_len, curr_readable, curr_writeable)
931 int *ibuf_len;
932 int *obuf_len;
933 struct pipeline **curr_readable, **curr_writeable;
934 {
935 struct pipeline **curr;
936 for (curr = &pipe_head;
937 *curr;
938 curr = curr ? (&(*curr)->next) : &pipe_head ) {
939 switch ((*curr)->specact) {
940 case NOTHING:
941 break;
942 case CLOSE_TO_READ:
943 /* got a FIN packet */
944 if (*ibuf_len>0)
945 break; /* can't drop it yet */
946 if (*curr_writeable == *curr
947 || *curr_readable == *curr) {
948 /* fprintf(stderr, "%s: weird, special action CLOSE_TO_READ applied to a curr_ pipeline %lx\n", progname, (long)*curr); */
949 break;
950 }
951 switch((*curr)->code) {
952 case WRITEABLE:
953 #ifdef DEBUG
954 fprintf(stderr, "%s: closing W child fd %d\n", progname, (*curr)->child_fd);
955 #endif
956 close((*curr)->pipe[0]);
957 remove_pipeline_(curr);
958 curr = 0; /* start scanning from the beginning */
959 break;
960 case DUPLEX: /* DUPLEX not actually possible */
961 case DUPLEX_IO:
962 case DUPLEX_OI:
963 #ifdef DEBUG
964 fprintf(stderr, "%s: converting child fd %d to child-write-only\n", progname, (*curr)->child_fd);
965 #endif
966 (*curr)->specact = NOTHING;
967 (*curr)->code = READABLE;
968 shutdown((*curr)->pipe[0], 1);
969
970 break;
971 case READABLE:
972 fprintf(stderr, "%s: internal error, attempt to CLOSE_TO_READ on a READABLE descriptor\n", progname);
973 exit(1);
974 }
975 break;
976 case CLOSE_TO_RW:
977 /* got a RESET packet. get drastic */
978 if ( (*curr)->bytes_left >0) {
979 fprintf(stderr, "%s: Freaky, %d bytes_left in CLOSE_TO_RW channel\n", progname, (*curr)->bytes_left);
980 break; /* can't dump it without corrupting the stream */
981 }
982 if (*curr_readable == *curr) {
983 *obuf_len = 0;
984 *curr_readable = 0;
985 }
986 if (*curr_writeable == *curr) {
987 *ibuf_len = 0;
988 *curr_writeable = 0;
989 }
990 #ifdef DEBUG
991 fprintf(stderr, "%s: RESETting child fd %d\n", progname, (*curr)->child_fd);
992 #endif
993 {
994 struct pipeline *temp = *curr;
995 close(temp->pipe[0]);
996 *curr = temp->next;
997 free(temp);
998 }
999 curr = 0; /* start scanning from the beginning */
1000 break;
1001 case CLOSE_TO_WRITE:
1002 /* child closed the descriptor */
1003 if (*curr_writeable == *curr
1004 || *curr_readable == *curr) {
1005 /*fprintf(stderr, "%s: weird, special action CLOSE_TO_WRITE applied to a curr_ pipeline %lx\n", progname, (long)*curr);*/
1006 break;
1007 }
1008
1009 {
1010 char *buf;
1011 int len;
1012 len = 8;
1013 buf = malloc(len);
1014 build_packet_header(buf, SCP_FIN, (*curr)->session_id, 0);
1015 prime_packet_queue(buf, len);
1016 #ifdef DEBUG
1017 fprintf(stderr, "%s: sending FIN for session 0x%06x\n", progname, (*curr)->session_id);
1018 #endif
1019 }
1020
1021 switch((*curr)->code) {
1022 case READABLE:
1023 #ifdef DEBUG
1024 fprintf(stderr, "%s: closing R child fd %d\n", progname, (*curr)->child_fd);
1025 #endif
1026 {
1027 struct pipeline *temp = *curr;
1028 temp = *curr;
1029 close(temp->pipe[0]);
1030 *curr = temp->next;
1031 free(temp);
1032 }
1033 curr = 0; /* start scanning from the beginning */
1034 break;
1035 case DUPLEX: /* DUPLEX not actually possible */
1036 case DUPLEX_IO:
1037 case DUPLEX_OI:
1038 #ifdef DEBUG
1039 fprintf(stderr, "%s: converting child fd %d to child-read-only\n", progname, (*curr)->child_fd);
1040 #endif
1041 (*curr)->specact = NOTHING;
1042 (*curr)->code = WRITEABLE;
1043 shutdown((*curr)->pipe[0], 0);
1044
1045 break;
1046 case WRITEABLE:
1047 fprintf(stderr, "%s: internal error, attempt to CLOSE_TO_WRITE on a WRITEABLE descriptor\n", progname);
1048 exit(1);
1049 }
1050
1051 break;
1052 }
1053 }
1054 }
1055
1056 #define BUF_SIZE 4096
1057
main_io_loop(sock_fd)1058 static void main_io_loop(sock_fd)
1059 int sock_fd;
1060 {
1061 char incoming_buf[BUF_SIZE]; /* read from socket, will write to child */
1062 char outgoing_buf[BUF_SIZE]; /* read from child, will packetize into : */
1063 char outgoing2_buf[BUF_SIZE+8]; /* packet buf, will write to socket */
1064
1065 /* bytes in the buffer to child */
1066 /* this is nonzero only if curr_writeable is nonNULL */
1067 int incoming_len=0;
1068
1069 /* this is nonzero only if curr_readable is nonNULL */
1070 /* bytes in the buffer from child */
1071 int outgoing_len=0;
1072
1073 /* bytes in the buffer to socket */
1074 /* this is independent of the curr_ variables */
1075 int outgoing2_len=0;
1076 int outgoing2_off=0;
1077
1078 /* for reading SCP headers */
1079 char header_buf[8];
1080 int header_len;
1081
1082 fd_set readfds, writefds;
1083 int maxfd;
1084
1085 struct pipeline *curr_readable=0; /* child descriptor we're reading */
1086 struct pipeline *curr_writeable=0; /* child descriptor we're writing */
1087
1088 while (1) {
1089 int rval;
1090
1091 build_fd_lists (
1092 &readfds, &writefds,
1093 curr_readable, curr_writeable,
1094 sock_fd, &maxfd,
1095 incoming_len, sizeof(incoming_len),
1096 outgoing_len, sizeof(outgoing_buf),
1097 outgoing2_len, outgoing2_off);
1098
1099 if (
1100 #if 0
1101 maxfd<0
1102 ||
1103 #else
1104 (!subproc || !child_unreaped)
1105 &&
1106 #endif
1107 (0==pipe_head && 0 == outgoing2_len
1108 && special_packet_queue == 0)
1109 ) {
1110 if (incoming_len != 0 ||
1111 outgoing_len != 0 ||
1112 outgoing2_len != 0) {
1113 fprintf(stderr, "%s: leftover bytes in buffers at end of encapsulation. That is bad because it means Bob made a logic error in his code.\n", progname);
1114 }
1115 break; /* run out of things to do */
1116 }
1117
1118 if (maxfd>0) {
1119 struct timeval tv;
1120 tv.tv_sec = 0;
1121 tv.tv_usec = 500000;
1122 rval = select(maxfd+1, &readfds, &writefds, (fd_set*)0, &tv);
1123
1124 if (rval<0) {
1125 if (errno == EINTR) {
1126 continue;
1127 } else {
1128 fprintf(stderr, "%s: error during select: ", progname);
1129 perror("");
1130 exit(EXITCODE_SYSCALLFAILED);
1131 }
1132 /* NOTREACHED */
1133 } else if (rval==0) {
1134 /* got a timeout */
1135
1136 }
1137
1138 /* read bytes from the child */
1139 {
1140 struct pipeline *curr;
1141 for (curr = pipe_head; curr; curr = curr->next) {
1142 switch (curr->code) {
1143 case READABLE:
1144 case DUPLEX_IO:
1145 case DUPLEX_OI:
1146 case DUPLEX:
1147 if (curr->pipe[0]>=0 &&
1148 FD_ISSET(curr->pipe[0], &readfds) &&
1149 (curr==curr_readable || 0==curr_readable)) {
1150 if (read_from_child(curr, outgoing_buf, &outgoing_len,
1151 sizeof(outgoing_buf)) )
1152 curr_readable = curr;
1153 }
1154 break;
1155 case WRITEABLE:
1156 break;
1157 }
1158 }
1159 }
1160
1161 /* write bytes to the child */
1162 if (curr_writeable && incoming_len>0 &&
1163 curr_writeable->pipe[0] >=0 &&
1164 FD_ISSET(curr_writeable->pipe[0], &writefds) ) {
1165 write_to_child(curr_writeable, incoming_buf, &incoming_len);
1166 if (incoming_len<1 && curr_writeable->bytes_left <1) {
1167 curr_writeable = 0;
1168 }
1169 }
1170
1171
1172 /* write bytes to the socket */
1173 if (FD_ISSET(sock_fd, &writefds)) {
1174 write_to_socket(sock_fd, outgoing2_buf,
1175 &outgoing2_off, outgoing2_len);
1176 if (outgoing2_off >= outgoing2_len) {
1177 outgoing2_len = 0;
1178 outgoing2_off = 0;
1179 }
1180 }
1181
1182 /* read bytes from the socket */
1183 if (FD_ISSET(sock_fd, &readfds)) {
1184
1185 if (curr_writeable) {
1186 read_from_socket(sock_fd, curr_writeable,
1187 incoming_buf, &incoming_len,
1188 sizeof(incoming_buf) );
1189 } else {
1190 read_from_socket(sock_fd, (struct pipeline *)0,
1191 header_buf, &header_len,
1192 sizeof(header_buf));
1193
1194 if (header_len==sizeof(header_buf)) {
1195 interpret_scp_header(header_buf, &curr_writeable);
1196 header_len = 0;
1197 }
1198 }
1199 }
1200 }
1201
1202 maybe_inject_special_packets(outgoing2_buf, &outgoing2_len,
1203 sizeof(outgoing2_buf));
1204
1205 if (outgoing2_len==0 && outgoing_len>0) {
1206 build_packet_header(outgoing2_buf, 0, curr_readable->session_id,
1207 outgoing_len);
1208 memcpy(outgoing2_buf + 8, outgoing_buf, outgoing_len);
1209 outgoing2_len = outgoing_len + 8;
1210 outgoing_len = 0;
1211 }
1212
1213 if (curr_readable && outgoing_len==0) {
1214 curr_readable = 0;
1215 }
1216
1217 if (curr_writeable
1218 && curr_writeable->bytes_left == 0
1219 && curr_writeable == pl_encapsulate_control
1220 && incoming_len>0) {
1221 handle_control_message(incoming_buf, incoming_len);
1222 incoming_len = 0;
1223 curr_writeable = 0;
1224 }
1225
1226 if (subproc) {
1227 if (!child_running && child_unreaped) {
1228 probe_child();
1229 }
1230 } else {
1231 if (pipe_head != 0 &&
1232 pipe_head == pl_encapsulate_control &&
1233 pipe_head->next == 0 &&
1234 pipe_head->code != WRITEABLE) {
1235 /* all channels are closed */
1236 char *buf;
1237 int len = 1;
1238 #ifdef DEBUG
1239 fprintf(stderr, "%s: sending EOF\n",
1240 progname);
1241 #endif
1242 buf = malloc(8+len);
1243 build_packet_header(buf, 0, SESSION_ENCAP, len);
1244 buf[8] = ECP_EOF;
1245 prime_packet_queue(buf, 8+len);
1246
1247 if (pl_encapsulate_control->code == READABLE) {
1248 remove_pipeline(pl_encapsulate_control);
1249 pl_encapsulate_control = 0;
1250 } else {
1251 pl_encapsulate_control->code = WRITEABLE;
1252 }
1253 }
1254 }
1255
1256 perform_special_actions(&incoming_len, &outgoing_len,
1257 &curr_readable, &curr_writeable);
1258 }
1259 }
1260
1261 /********************************************************************/
1262
1263 static int childpid = -1;
1264
waitonchild()1265 static void waitonchild()
1266 {
1267 /* got a SIGCHILD.
1268 It must be that: */
1269 child_running = 0;
1270 }
1271
probe_child()1272 static void probe_child()
1273 {
1274 if (child_running || !child_unreaped)
1275 return;
1276
1277 if ( 0>=wait(&local_return_code)) {
1278 fprintf(stderr, "%s: wait returned error or zero: ", progname);
1279 perror("");
1280 exit(EXITCODE_SYSCALLFAILED);
1281 }
1282 if (!WIFEXITED(local_return_code))
1283 local_return_code = EXITCODE_SIGNAL;
1284 else
1285 local_return_code = WEXITSTATUS(local_return_code);
1286
1287 {
1288 char *buf;
1289 int len = 2;
1290 #ifdef DEBUG
1291 fprintf(stderr, "%s: sending exit status %d\n",
1292 progname, local_return_code);
1293 #endif
1294 buf = malloc(8+len);
1295 build_packet_header(buf, 0, SESSION_ENCAP, len);
1296 buf[8] = ECP_EXITCODE;
1297 buf[8+1] = local_return_code;
1298 prime_packet_queue(buf, len+8);
1299
1300 if (pl_encapsulate_control->code == READABLE) {
1301 remove_pipeline(pl_encapsulate_control);
1302 pl_encapsulate_control = 0;
1303 } else {
1304 pl_encapsulate_control->code = WRITEABLE;
1305 }
1306 }
1307
1308 child_unreaped = 0;
1309 }
1310
spawn_child(cmd,sockfd)1311 static void spawn_child(cmd, sockfd)
1312 char **cmd;
1313 int sockfd;
1314 {
1315 struct pipeline *curr;
1316
1317 signal(SIGCHLD,waitonchild);
1318 child_running = 1; /* well, not yet. */
1319 child_unreaped = 1;
1320
1321 /* We're about to allocate a big stack of descriptors. Let's make
1322 sure we don't step on on our own toes. Dup descriptor 0 onto
1323 each of the descriptors so that our allocations won't get one
1324 of them. If you don't have a descriptor 0, then you're a FREAK! */
1325 /* Uhoh. Some of them may already be connected to the parent.
1326 Bob attaches some funky things in funky places. */
1327 /* The way I tell if a descriptor has been allocated or not is I
1328 select() on it. If I get EBADF, the descriptor has not been
1329 allocated and I can stomp on it before the fork. If I don't,
1330 then I won't stomp on it till after the fork. */
1331 {
1332 for (curr = pipe_head; curr; curr = curr->next) {
1333 if (curr->child_fd<0)
1334 continue;
1335 if (!valid_descriptor(curr->child_fd))
1336 dup2(0, curr->child_fd); /* "reserve" it */
1337 }
1338 }
1339
1340 for (curr = pipe_head; curr; curr = curr->next) {
1341 if (curr->child_fd<0)
1342 continue; /* skip this special channel */
1343 switch (curr->code) {
1344 case READABLE:
1345 case WRITEABLE:
1346 if (pipe(curr->pipe) !=0) {
1347 fprintf(stderr, "%s: totally failed to pipe(2): ", progname);
1348 perror("");
1349 exit (EXITCODE_SYSCALLFAILED);
1350 }
1351 break;
1352 case DUPLEX:
1353 case DUPLEX_IO:
1354 case DUPLEX_OI:
1355 if (0!=socketpair(AF_UNIX, SOCK_STREAM, 0/*let it choose*/,
1356 curr->pipe)) {
1357 fprintf(stderr, "%s: totally failed to socketpair(2): ",
1358 progname);
1359 perror("");
1360 exit (EXITCODE_SYSCALLFAILED);
1361 }
1362 }
1363 if (curr->code == WRITEABLE) {
1364 /* we need to invert the polarity for this case, eh, Geordi? */
1365 int t;
1366 t = curr->pipe[0];
1367 curr->pipe[0] = curr->pipe[1];
1368 curr->pipe[1] = t;
1369 }
1370 }
1371
1372 childpid = fork();
1373 if (childpid<0) {
1374 fprintf(stderr, "%s: unable to fork: ", progname);
1375 perror("");
1376 /* I would clear child_running, but, look at the next line */
1377 exit(EXITCODE_SYSCALLFAILED);
1378 }
1379
1380 /* now there's a child running (assuming no race conditions, which
1381 is why I set it up above and not here. I'm stupid, but
1382 paranoid). */
1383
1384 if (childpid==0) {
1385 /* child */
1386 close(sockfd); /* can't have the child accidentally
1387 stomping on our conversation. */
1388 for (curr = pipe_head; curr; curr = curr->next) {
1389 if (curr->child_fd<0)
1390 continue; /* skip this special channel */
1391 close(curr->pipe[0]);
1392 dup2(curr->pipe[1], curr->child_fd);
1393 close(curr->pipe[1]);
1394 }
1395
1396 execvp(*cmd, cmd);
1397 fprintf(stderr, "%s: Unable to exec %s: ", progname, *cmd);
1398 perror("");
1399
1400 exit(EXITCODE_EXECFAILED);
1401
1402 } else {
1403 /* parent */
1404 for (curr = pipe_head; curr; curr = curr->next) {
1405 if (curr->child_fd<0)
1406 continue; /* skip this special channel */
1407 close(curr->pipe[1]);
1408 }
1409 }
1410 }
1411
rig_single()1412 static void rig_single()
1413 {
1414 struct pipeline *curr;
1415 /* Dear mother of god. I have to invert the polarity of all the
1416 pipes. How the hell am I going to explain this in the manual
1417 page? */
1418
1419 for (curr = pipe_head; curr; curr = curr->next) {
1420 switch (curr->code) {
1421 case READABLE:
1422 curr->code = WRITEABLE;
1423 break;
1424 case WRITEABLE:
1425 curr->code = READABLE;
1426 break;
1427 default:
1428 /* I don't need to diddle the duplex cases really */
1429 break;
1430 }
1431
1432 /* so that select and I/O will work */
1433 curr->pipe[0] = curr->child_fd;
1434 curr->pipe[1] = -1;
1435 }
1436
1437 }
1438
1439 /********************************************************************/
1440
scan_flag_numeric_fd(s,fdp)1441 static int scan_flag_numeric_fd(s, fdp)
1442 char *s;
1443 int *fdp;
1444 {
1445 int n;
1446 if (1 != sscanf(s, "%i%n", fdp, &n)) {
1447 fprintf(stderr, "%s: parse error in file descriptor list at '%s'\n", progname, s);
1448 exit(EXITCODE_ARGS);
1449 }
1450 return n;
1451 }
1452
1453 /********************************************************************/
1454
1455 enum mergereturns_ {
1456 UNINITIALIZED,
1457 PREFER_LOCAL, /* if both local and remote processes
1458 error, return the local code */
1459 PREFER_REMOTE, /* if both local and remote processes
1460 error, return the remote code. */
1461 LOCAL_ONLY, /* return the exit code of the local
1462 process, ignoring the return code
1463 of the remote process. */
1464 REMOTE_ONLY, /* return the exit code of the remote
1465 process, ignoring the return code
1466 of the local process. */
1467 } merge_returns = UNINITIALIZED;
1468
1469 static int sockfd = -1;
1470 static int im_server = -1;
1471
main(argc,argv)1472 int main (argc,argv)
1473 int argc;
1474 char ** argv;
1475
1476 {
1477 set_progname(argv[0]);
1478
1479 #if 0
1480 if (sizeof(Nshort) != 2) {
1481 fprintf(stderr, "%s: greivous porting error. sizeof(Nshort) == %d, not 2.\n",
1482 progname, sizeof(Nshort));
1483 exit(EXITCODE_ARGS);
1484 }
1485 #endif
1486
1487 while (argc>1) {
1488 char *arg = argv[1];
1489 if (arg[0] != '-') {
1490 break;
1491 }
1492 arg++;
1493 if (arg[0] == '-') {
1494 arg++;
1495 if (0==strcmp(arg, "verbose")) {
1496 verbose = 1;
1497 argv++; argc--;
1498 } else if (0==strcmp(arg, "fd")) {
1499 argv++; argc--;
1500 if (argc<2) {
1501 fprintf(stderr, "%s: --fd requires file number for socket.\n",
1502 progname);
1503 usage();
1504 exit(EXITCODE_ARGS);
1505 } else if (sockfd>=0) {
1506 fprintf(stderr, "%s: --fd can only be specified once\n",
1507 progname);
1508 usage();
1509 exit(EXITCODE_ARGS);
1510 } else {
1511 sockfd = atoi(argv[1]);
1512 argv++; argc--;
1513 }
1514 } else if (0==strcmp(arg, "subproc")) {
1515 subproc = 1;
1516 argv++; argc--;
1517 } else if (0==strcmp(arg, "infd") ||
1518 0==strcmp(arg, "outfd") ||
1519 0==strcmp(arg, "duplex") ||
1520 0==strcmp(arg, "Duplex") ||
1521 0==strcmp(arg, "DUPLEX")) {
1522 long fd, sid;
1523 char *p;
1524 int err = 0;
1525 enum pipe_polarity pol = -1;
1526 argv++; argc--;
1527 if (argc<2 || argv[1][0] == 0) {
1528 err = 1;
1529 } else {
1530 fd = strtol(argv[1], &p, 0);
1531 if (*p==0) {
1532 sid = -1;
1533 } else if (p[0] == '=' && p[1] != 0) {
1534 sid = strtol(p+1, &p, 0);
1535 if (*p != 0) {
1536 err = 1;
1537 }
1538 } else {
1539 err = 1;
1540 }
1541 }
1542 if (err) {
1543 fprintf(stderr, "%s: %s requires descriptor number as argument\n", progname, arg-2);
1544 usage();
1545 exit(EXITCODE_ARGS);
1546 }
1547
1548 {
1549 if (0==strcmp(arg, "infd")) pol = WRITEABLE;
1550 else if (0==strcmp(arg, "outfd")) pol = READABLE;
1551 else if (0==strcmp(arg, "duplex")) pol = DUPLEX_IO;
1552 else if (0==strcmp(arg, "Duplex")) pol = DUPLEX;
1553 else if (0==strcmp(arg, "DUPLEX")) pol = DUPLEX_OI;
1554 }
1555 if (pol == -1) {
1556 fprintf(stderr, "%s: code error, polarity uninitialized %s:%d\n", progname, __FILE__, __LINE__);
1557 abort();
1558 }
1559 add_subproc_fd(fd, pol, -1);
1560 argv++; argc--;
1561 } else if (0==strcmp(arg, "prefer-local")||
1562 0==strcmp(arg, "preferlocal")) {
1563 merge_returns = PREFER_LOCAL;
1564 argv++; argc--;
1565 } else if (0==strcmp(arg, "prefer-remote")||
1566 0==strcmp(arg, "preferremote")) {
1567 merge_returns = PREFER_REMOTE;
1568 argv++; argc--;
1569 } else if (0==strcmp(arg, "local-only")||
1570 0==strcmp(arg, "localonly")) {
1571 merge_returns = LOCAL_ONLY;
1572 argv++; argc--;
1573 } else if (0==strcmp(arg, "remote-only")||
1574 0==strcmp(arg, "remoteonly")) {
1575 merge_returns = REMOTE_ONLY;
1576 argv++; argc--;
1577 } else if (0==strcmp(arg, "client")) {
1578 im_server = 0;
1579 argv++; argc--;
1580 } else if (0==strcmp(arg, "server")) {
1581 im_server = 1;
1582 argv++; argc--;
1583 } else {
1584 /* unknown -- flag. Assume it's a command :) */
1585 break;
1586 }
1587 } else {
1588 /* it's a set of single dash flags. */
1589 do { switch (arg[0]) {
1590 case '#':
1591 arg += scan_flag_numeric_fd(arg+1, &sockfd);
1592 break;
1593 case 'v':
1594 verbose = 1;
1595 break;
1596 case 's':
1597 subproc=1;
1598 break;
1599 case 'i':
1600 if (arg[1] == 'o') {
1601 int fd;
1602 arg += scan_flag_numeric_fd(arg+2, &fd);
1603 add_subproc_fd(fd, DUPLEX_IO, -1);
1604 } else {
1605 int fd;
1606 arg += scan_flag_numeric_fd(arg+1, &fd);
1607 add_subproc_fd(fd, WRITEABLE, -1);
1608 }
1609 break;
1610 case 'o':
1611 if (arg[1] == 'i') {
1612 int fd;
1613 arg += scan_flag_numeric_fd(arg+2, &fd);
1614 add_subproc_fd(fd, DUPLEX_OI, -1);
1615 } else {
1616 int fd;
1617 arg += scan_flag_numeric_fd(arg+1, &fd);
1618 add_subproc_fd(fd, READABLE, -1);
1619 }
1620 break;
1621 case 'd':
1622 {
1623 int fd;
1624 arg += scan_flag_numeric_fd(arg+1, &fd);
1625 add_subproc_fd(fd, DUPLEX, -1);
1626 }
1627 break;
1628 case 'l':
1629 merge_returns = PREFER_LOCAL;
1630 break;
1631 case 'r':
1632 merge_returns = PREFER_REMOTE;
1633 break;
1634 case 'L':
1635 merge_returns = LOCAL_ONLY;
1636 break;
1637 case 'R':
1638 merge_returns = REMOTE_ONLY;
1639 break;
1640 case 0:
1641 fprintf(stderr, "%s: blank compact flag.\n", progname);
1642 /* fall through */
1643 default:
1644 fprintf(stderr, "%s: Unknown compact flag beginning %s\n", progname, arg);
1645 usage();
1646 exit (EXITCODE_ARGS);
1647 } arg++;
1648 } while (arg[0]);
1649
1650 argv++;
1651 argc--;
1652 }
1653 }
1654
1655 /* argv+1 points to an unrecognized flag that must be the
1656 subprocess cmd and arguments. */
1657
1658 if (argc>1 && !subproc) {
1659 fprintf(stderr, "%s: Unknown flag %s\n", progname, argv[1]);
1660 usage();
1661 exit (EXITCODE_ARGS);
1662 }
1663
1664 if (sockfd<0) {
1665 fprintf(stderr, "%s: I must know the file number for the socket.\n",
1666 progname);
1667 usage();
1668 exit(EXITCODE_ARGS);
1669 }
1670
1671 if (subproc) {
1672 if (merge_returns == UNINITIALIZED)
1673 merge_returns = PREFER_LOCAL;
1674 /* check to make sure at least one descriptor is rerouted */
1675 if (pipe_head == 0) {
1676 fprintf(stderr, "%s: must redirect at least one descriptor of subprocess.\n", progname);
1677 usage();
1678 exit(EXITCODE_ARGS);
1679 }
1680 } else {
1681 if (pipe_head == 0) {
1682 /* rig the degenerate case */
1683 add_subproc_fd(0, WRITEABLE, -1);
1684 add_subproc_fd(1, READABLE, -1);
1685 }
1686 if (merge_returns == PREFER_LOCAL ||
1687 merge_returns == PREFER_REMOTE ||
1688 merge_returns == LOCAL_ONLY ||
1689 merge_returns == REMOTE_ONLY) {
1690 fprintf(stderr, "%s: no local process to get a return code from\n", progname);
1691 usage();
1692 exit (EXITCODE_ARGS);
1693 }
1694
1695 merge_returns = LOCAL_ONLY;
1696 }
1697
1698 add_control_channel(); /* for passing exit status. Is DUPLEX_OI. */
1699
1700 if (verbose)
1701 emit_version("encapsulate", 1996);
1702
1703 if (im_server<0) {
1704 im_server = Im_server_p(sockfd);
1705 }
1706
1707 {
1708 struct pipeline *curr;
1709 for (curr = pipe_head; curr; curr = curr->next) {
1710 if (curr->code == DUPLEX)
1711 curr->code = im_server ? DUPLEX_IO : DUPLEX_OI;
1712 }
1713
1714 /* might as well initialize our session_id counter */
1715 session_id_ = im_server ? 1025 : 1024;
1716 /* below 1024 is reserved */
1717 }
1718
1719
1720 if (subproc)
1721 spawn_child(argv+1, sockfd);
1722 else {
1723 /* I have to invert the polarity of writable and readable
1724 channels, but not duplex. Also have to copy the child_fd
1725 to pipe[0]. What a hellish mess. */
1726 rig_single(); }
1727
1728 signal(SIGPIPE, SIG_IGN); /* handle the error returns */
1729
1730 {
1731 char *buf;
1732 int len;
1733 buf = prepare_SYNs( &len);
1734 prime_packet_queue(buf, len);
1735 }
1736
1737 main_io_loop(sockfd);
1738
1739 #ifdef DEBUG
1740 fprintf(stderr, "%s: end of IO loop\n", progname);
1741 #endif
1742
1743 #if 0
1744 while (child_running) {
1745 pause();
1746 }
1747 probe_child();
1748 #endif
1749
1750 if (local_return_code ==0)
1751 local_return_code = exitcode_warnings;
1752
1753 switch (merge_returns) {
1754 case PREFER_LOCAL:
1755 if (local_return_code!=0)
1756 exit (local_return_code);
1757 else
1758 exit (remote_return_code);
1759 /* NOTREACHED */
1760 case PREFER_REMOTE:
1761 if (remote_return_code!=0)
1762 exit (remote_return_code);
1763 else
1764 exit (local_return_code);
1765 /* NOTREACHED */
1766 case LOCAL_ONLY:
1767 exit(local_return_code);
1768 case REMOTE_ONLY:
1769 exit(remote_return_code);
1770 default:
1771 fprintf(stderr, "%s: logic error. merge_returns has bogus value.\n",
1772 progname);
1773 exit(EXITCODE_ARGS);
1774 }
1775 }
1776