1 /* ============================================================================
2  * Copyright (C) 1998 Angus Mackay. All rights reserved;
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
10  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
11  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
13  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
14  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
15  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
16  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
17  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
18  * POSSIBILITY OF SUCH DAMAGE.
19  * ============================================================================
20  */
21 
22 /*
23  * $Id: tcpcat.c,v 1.24 2000/01/23 01:19:22 amackay Exp $
24  *
25  * tcpcat is a simple program that is like `cat' but it works over tcp streams
26  * to allow you to cat from one host to another.
27  *
28  * the host common way to use this program whould be something like this:
29  * on host a: $ tcpcat -l 63255 | gzip -dc | tar xvf -
30  * on host b: $ tcpcat -h hosta:63255  tcpcat-X.X.X.tar.gz
31  *
32  * this program has been tested under Linux 2.0 and Solaris 2.6.
33  *
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #  include <config.h>
38 #endif
39 
40 #define HAVE_TERMIOS_H 1
41 #define HAVE_TCGETATTR 1
42 #define HAVE_TCSETATTR 1
43 #define HAVE_ON_EXIT 1
44 
45 #ifdef HAVE_GETOPT_H
46 #  include <getopt.h>
47 #endif
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 #if HAVE_FCNTL_H
53 #  include <fcntl.h>
54 #endif
55 #include <netinet/in.h>
56 #if HAVE_ARPA_INET_H
57 #  include <arpa/inet.h>
58 #endif
59 #include <netdb.h>
60 #include <sys/socket.h>
61 #if HAVE_SYS_UN_H
62 #  include <sys/un.h>
63 #endif
64 #if HAVE_SYS_TYPES_H
65 #  include <sys/types.h>
66 #endif
67 #if HAVE_SIGNAL_H
68 #  include <signal.h>
69 #endif
70 
71 #if HAVE_SYS_TIME_H
72 #  include <sys/time.h>
73 #endif
74 
75 #ifdef HAVE_TERMIOS_H
76 #  if !defined(HAVE_TCGETATTR) && !defined(HAVE_TCSETATTR)
77 #    undef HAVE_TERMIOS_H
78 #  endif
79 #endif
80 
81 #ifdef HAVE_TERMIOS_H
82 #  include <termios.h>
83 #else
84 #  ifdef HAVE_TERMIO_H
85 #  include <termio.h>
86 #  else
87 #  endif
88 #endif
89 
90 #include "zlib.h"
91 
92 #ifndef HAVE_HERROR
93 #  define herror(x) fprintf(stderr, "%s: error\n", x)
94 #endif
95 
96 #ifdef DEBUG
97 #define dprintf(x) if( options & OPT_DEBUG ) \
98 { \
99   fprintf(stderr, "%s,%d: ", __FILE__, __LINE__); \
100     fprintf x; \
101 }
102 #else
103 #  define dprintf(x)
104 #endif
105 
106 #define EXIT_NO_HOST 2
107 
108 #define MIN_BUFFER_SIZE 1
109 
110 /**************************************************/
111 
112 static char *program_name;
113 static char *host = NULL;
114 static char *listen_port = NULL;
115 static char *connect_port = NULL;
116 static char *connect_bind_port = NULL;
117 static struct timeval *timeout = NULL;
118 static char *echo_file = NULL;
119 
120 static volatile int server_sockfd;
121 static volatile int client_sockfd;
122 static volatile int client_sockfd2;
123 static volatile int echo_fd;
124 static FILE *echo_fp;
125 
126 static int buffersize = 64*1024;
127 static int socketbuffersize = 0;
128 
129 static uLong g_cksum = 0;
130 
131 static int (*do_connect)(volatile int *sock, char *host, char *port);
132 static int (*do_listen)(volatile int *serv_sock, char *host, char *port);
133 static int (*do_accept)(volatile int *sock, volatile int serv_sock);
134 
135 static int options;
136 static long bytes_copied;
137 
138 #define OPT_DEBUG       0x0001
139 #define OPT_LISTEN      0x0002
140 #define OPT_QUIET       0x0004
141 #define OPT_INPUT       0x0008
142 #define OPT_OUTPUT      0x0010
143 #define OPT_VERBOSE     0x0020
144 #define OPT_CONNECT     0x0040
145 #define OPT_AF_UNIX     0x0080
146 #define OPT_CONTINUOUS  0x0100
147 #define OPT_NOBUF       0x0200
148 #define OPT_CKSUM       0x0400
149 #define OPT_ECHO        0x80000000     /* use sign bit for faster checking */
150 
151 #define COPY_IN_OUT_QUIET 0
152 #define COPY_IN_OUT_VERB 1
153 
154 /**************************************************/
155 
156 void print_useage( void );
157 void print_version( void );
158 void parse_args( int argc, char **argv );
159 int do_connect_inet(volatile int *sock, char *host, char *port);
160 int do_connect_unix(volatile int *sock, char *host, char *port);
161 int do_listen_inet(volatile int *serv_sock, char *host, char *port);
162 int do_listen_unix(volatile int *serv_sock, char *host, char *port);
163 int do_accept_inet(volatile int *sock, volatile int serv_sock);
164 int do_accept_unix(volatile int *sock, volatile int serv_sock);
165 void copy_in_out_verb(int input_fd, int output_fd);
166 void copy_in_out_quiet(int input_fd, int output_fd);
167 void copy_in_out4_quiet(int input1_fd, int input2_fd, int output1_fd, int output2_fd);
168 #if defined(__BEOS__)
169 void copy_sin_fout_quiet(int input_fd, int output_fd);
170 void copy_sin_fout_verb(int input_fd, int output_fd);
171 void copy_fin_sout_quiet(int input_fd, int output_fd);
172 void copy_fin_sout_verb(int input_fd, int output_fd);
173 void copy_in_out4_not_available(int a, int b, int c, int d);
174 #endif
175 void set_input_buffer(int fd, int restore);
176 int main( int argc, char **argv );
177 
178 /**************************************************/
179 
xmalloc(size_t size)180 void *xmalloc(size_t size)
181 {
182    void *p;
183 
184    p = malloc(size);
185    if(p == NULL)
186    {
187       fprintf(stderr, "out of memory\n");
188       exit(1);
189    }
190    return p;
191 }
192 
print_useage(void)193 void print_useage( void )
194 {
195   fprintf(stdout, "useage: ");
196   fprintf(stdout, "%s [options] [file]...\n\n", program_name);
197   fprintf(stdout, " Options are:\n");
198   fprintf(stdout, "  -B, --socket-buffer <n[kKmM]>\tuse n byte socket buffer\n");
199   fprintf(stdout, "  -b, --buffer-size <n[kKmM]>\tuse n byte buffer\n");
200   fprintf(stdout, "  -c, --continue\t\tcontinue to accept connections\n");
201 #ifdef DEBUG
202   fprintf(stdout, "  -D, --debug\t\t\tturn on debuggin\n");
203 #endif
204   fprintf(stdout, "  -e, --echo <file>\t\techo data to file\n");
205   fprintf(stdout, "  -h, --host <host>[:<port>]\thost to connect to\n");
206   fprintf(stdout, "  -i, --input\t\t\twhen listening input from stdin\n");
207   fprintf(stdout, "  -l, --listen <port>\t\tlisten for connections on port\n");
208   fprintf(stdout, "  -n, --nobuf\t\t\tif stdin is a terminal do not use line \n\t\t\t\t"
209       "buffering. generate a SIGQUIT (CTRL-\\) to stop \n\t\t\t\t"
210       "or use a timeout\n");
211   fprintf(stdout, "  -o, --output\t\t\twhen connecting output to stdout\n");
212   fprintf(stdout, "  -p, --port <port>\t\tuse port for connect or listen\n");
213   fprintf(stdout, "  -P, --bind-port <port>\tuse port for binded connects (ipaddr:port works)\n");
214   fprintf(stdout, "  -s, --sum\t\t\tprint Adler32 checksum\n");
215   fprintf(stdout, "  -q, --quiet\t\t\tdon't print extra info\n");
216   fprintf(stdout, "  -t, --timeout <period>\tused only when both -i and -o are specified\n");
217   fprintf(stdout, "  -u, --unix-host <file>\taf_unix file to connect to\n");
218   fprintf(stdout, "  -U, --unix-listen <file>\tlisten for connections on af_unix file\n");
219   fprintf(stdout, "  -v, --verbose\t\t\tprint progress dots for stdin/out, "
220       "usually dots \n\t\t\t\tare only printed for sending files\n");
221   fprintf(stdout, "      --help\t\t\tdisplay this help and exit\n");
222   fprintf(stdout, "      --version\t\t\toutput version information and exit\n");
223   fprintf(stdout, "      --credits\t\t\tprint the credits and exit\n");
224   fprintf(stdout, "\n");
225   fprintf(stdout, "using --input and --output basicly swap the roles of the\n");
226   fprintf(stdout, "client/server version of %s.\n", program_name);
227   fprintf(stdout, "\n");
228 }
229 
print_version(void)230 void print_version( void )
231 {
232   fprintf(stdout, "%s: - %s - $Id: tcpcat.c,v 1.24 2000/01/23 01:19:22 amackay Exp $\n", program_name, VERSION);
233 }
234 
print_credits(void)235 void print_credits( void )
236 {
237   fprintf( stdout, "AUTHORS / CONTRIBUTORS\n"
238       "  Angus Mackay <amackay@gusnet.cx>\n"
239       "\n" );
240 }
241 
242 #if HAVE_SIGNAL_H
sig_handler(int sig)243 RETSIGTYPE sig_handler(int sig)
244 {
245   char message[] = "interupted.\n";
246 
247   write(2, message, sizeof(message)-1);
248 
249   // clean up the terminal
250   if(options & OPT_NOBUF)
251   {
252     set_input_buffer(fileno(stdin), 1);
253   }
254 
255   close(client_sockfd);
256   close(server_sockfd);
257   close(echo_fd);
258 
259   // clean up the socket file
260   if( (options & OPT_AF_UNIX) && (options & OPT_LISTEN) && listen_port )
261   {
262     unlink(listen_port);
263   }
264 }
265 #endif
266 
267 /*
268  * longfromstr
269  *
270  * a super atoi that takes things like
271  * 64k == 65536
272  * 0x10M == 16777216
273  * 013 == 11
274  * 43 == 43
275  *
276  */
longfromstr(char * str)277 long longfromstr(char *str)
278 {
279   int mult;
280   int lastchar;
281   long val;
282 
283   lastchar = strlen(str);
284   lastchar = lastchar == 0 ? 0 : lastchar - 1;
285   switch(str[lastchar])
286   {
287     case 'k':
288     case 'K':
289       mult = 1024;
290       break;
291     case 'm':
292     case 'M':
293       mult = 1024*1024;
294       break;
295     case 'g':
296     case 'G':
297       mult = 1024*1024*1024;
298       break;
299     default:
300       mult = 1;
301       break;
302   }
303 
304   val = strtol(str, NULL, 0) * mult;
305 
306   return(val);
307 }
308 
309 #ifdef HAVE_GETOPT_LONG
310 #  define xgetopt( x1, x2, x3, x4, x5 ) getopt_long( x1, x2, x3, x4, x5 )
311 #else
312 #  define xgetopt( x1, x2, x3, x4, x5 ) getopt( x1, x2, x3 )
313 #endif
314 
parse_args(int argc,char ** argv)315 void parse_args( int argc, char **argv )
316 {
317 #ifdef HAVE_GETOPT_LONG
318   struct option long_options[] = {
319       {"socket-buffer", required_argument,      0, 'B'},
320       {"buffer-size",   required_argument,      0, 'b'},
321       {"continue",      no_argument,            0, 'c'},
322       {"debug",         no_argument,            0, 'D'},
323       {"echo",          required_argument,      0, 'e'},
324       {"host",          required_argument,      0, 'h'},
325       {"input",         no_argument,            0, 'i'},
326       {"listen",        required_argument,      0, 'l'},
327       {"nobuf",         no_argument,            0, 'n'},
328       {"output",        no_argument,            0, 'o'},
329       {"port",          required_argument,      0, 'p'},
330       {"bind-port",     required_argument,      0, 'P'},
331       {"quiet",         no_argument,            0, 'q'},
332       {"sum",           no_argument,            0, 's'},
333       {"timeout",       required_argument,      0, 't'},
334       {"unix-listen",   required_argument,      0, 'U'},
335       {"unix-host",     required_argument,      0, 'u'},
336       {"verbose",       no_argument,            0, 'v'},
337       {"help",          no_argument,            0, 'H'},
338       {"version",       no_argument,            0, 'V'},
339       {"credits",       no_argument,            0, 'C'},
340       {0,0,0,0}
341   };
342 #else
343 #  define long_options NULL
344 #endif
345   int opt;
346   char *tmp;
347 
348   while((opt = xgetopt(argc, argv, "B:b:cDe:h:il:noP:p:qst:U:u:vHVC", long_options,
349                        NULL)) != -1)
350   {
351     switch (opt)
352     {
353       case 'B':
354         socketbuffersize = longfromstr(optarg);
355         if(socketbuffersize < MIN_BUFFER_SIZE)
356         {
357            fprintf(stderr, "invalid buffer size of %d, must be larger than %d byte%s\n",
358                    socketbuffersize, MIN_BUFFER_SIZE, MIN_BUFFER_SIZE == 1 ? "" : "s");
359            exit(1);
360         }
361         dprintf((stderr, "socketbuffersize %d\n", socketbuffersize));
362         break;
363 
364       case 'b':
365         buffersize = longfromstr(optarg);
366         if(buffersize < MIN_BUFFER_SIZE)
367         {
368            fprintf(stderr, "invalid buffer size of %d, must be larger than %d byte%s\n",
369                    buffersize, MIN_BUFFER_SIZE, MIN_BUFFER_SIZE == 1 ? "" : "s");
370            exit(1);
371         }
372         dprintf((stderr, "buffersize %d\n", buffersize));
373         break;
374 
375       case 'c':
376         options |= OPT_CONTINUOUS;
377         dprintf((stderr, "continuous enabled\n"));
378         break;
379 
380       case 'D':
381         options |= OPT_DEBUG;
382         dprintf((stderr, "debugging on\n"));
383         break;
384 
385       case 'e':
386         options |= OPT_ECHO;
387         options |= OPT_INPUT;
388         options |= OPT_OUTPUT;
389         if(echo_file)
390         {
391           free(echo_file);
392         }
393         echo_file = strdup(optarg);
394         dprintf((stderr, "echo_file: %s\n", echo_file));
395         break;
396 
397       case 'h':
398         options |= OPT_CONNECT;
399         // look for the port and cut it off if found
400         tmp = strchr(optarg, ':');
401         if (tmp) {
402           *tmp++ = '\0';
403           if(connect_port)
404           {
405             free(connect_port);
406           }
407           connect_port = strdup(tmp);
408         }
409         if(host)
410         {
411           free(host);
412         }
413         host = strdup(optarg);
414         dprintf((stderr, "host: %s\n", host));
415         dprintf((stderr, "connect_port: %s\n", connect_port));
416         break;
417 
418       case 'u':
419         options |= OPT_CONNECT;
420         options |= OPT_AF_UNIX;
421         if(connect_port)
422         {
423           free(connect_port);
424         }
425         connect_port = strdup(optarg);
426         dprintf((stderr, "connect_port: %s\n", connect_port));
427         break;
428 
429       case 'H':
430         print_useage();
431         exit(0);
432         break;
433 
434       case 'i':
435         options |= OPT_INPUT;
436         break;
437 
438       case 'l':
439         options |= OPT_LISTEN;
440         if(listen_port)
441         {
442           free(listen_port);
443         }
444         listen_port = strdup(optarg);
445         dprintf((stderr, "listen_port: %s\n", listen_port));
446         break;
447 
448       case 'n':
449         options |= OPT_NOBUF;
450         break;
451 
452       case 'U':
453         options |= OPT_LISTEN;
454         options |= OPT_AF_UNIX;
455         if(listen_port)
456         {
457           free(listen_port);
458         }
459         listen_port = strdup(optarg);
460         dprintf((stderr, "listen_port: %s\n", listen_port));
461         break;
462 
463       case 'o':
464         options |= OPT_OUTPUT;
465         break;
466 
467         // only use the -p port if we don't already have ports
468       case 'p':
469         if(connect_port == NULL)
470         {
471           connect_port = strdup(optarg);
472           dprintf((stderr, "connect_port: %s\n", connect_port));
473         }
474         if(listen_port == NULL)
475         {
476           listen_port = strdup(optarg);
477           dprintf((stderr, "listen_port: %s\n", listen_port));
478         }
479         break;
480 
481       case 'P':
482         if(connect_bind_port == NULL)
483         {
484           connect_bind_port = strdup(optarg);
485           dprintf((stderr, "connect_bind_port: %s\n", connect_bind_port));
486         }
487         break;
488 
489       case 'q':
490         options |= OPT_QUIET;
491         dprintf((stderr, "options |= OPT_QUIET\n"));
492         break;
493 
494       case 's':
495         options |= OPT_CKSUM;
496         dprintf((stderr, "options |= OPT_CKSUM\n"));
497         break;
498 
499       case 't':
500         if(timeout)
501         {
502           free(timeout);
503         }
504         timeout = (struct timeval*)malloc((int)sizeof(struct timeval));
505         timeout->tv_sec = strtol(optarg, NULL, 10);
506         timeout->tv_usec = (atof(optarg) - timeout->tv_sec) * 1000000L;
507         dprintf((stderr, "timeout: %ld.%06ld\n", timeout->tv_sec, timeout->tv_usec));
508         break;
509 
510       case 'v':
511         options |= OPT_VERBOSE;
512         break;
513 
514       case 'V':
515         print_version();
516         exit(0);
517         break;
518 
519       case 'C':
520         print_credits();
521         exit(0);
522         break;
523 
524       default:
525 #ifdef HAVE_GETOPT_LONG
526         fprintf(stderr, "Try `%s --help' for more information\n", argv[0]);
527 #else
528         fprintf(stderr, "Try `%s -H' for more information\n", argv[0]);
529         fprintf(stderr, "warning: this program was compilied without getopt_long\n");
530         fprintf(stderr, "         as such all long options will not work!\n");
531 #endif
532         exit(1);
533         break;
534     }
535   }
536 
537   // we need a port
538   if( connect_port == NULL && listen_port == NULL )
539   {
540 #ifdef HAVE_GETOPT_LONG
541     fprintf(stderr, "Try `%s --help' for more information\n", argv[0]);
542 #else
543     fprintf(stderr, "Try `%s -H' for more information\n", argv[0]);
544     fprintf(stderr, "warning: this program was compilied without getopt_long\n");
545     fprintf(stderr, "         as such all long options will not work!\n");
546 #endif
547     exit(1);
548   }
549 }
550 
551 /*
552  * do_connect
553  *
554  * connect a socket and return the file descriptor
555  *
556  */
do_connect_common(volatile int * sock,char * host,char * port)557 int do_connect_common(volatile int *sock, char *host, char *port)
558 {
559   int oplen;
560   int sendsize;
561   int recvsize;
562 
563 #if HAVE_SETSOCKOPT && defined(SO_SNDBUF) && defined(SO_RCVBUF)
564   if(socketbuffersize != 0)
565   {
566     sendsize = socketbuffersize;
567     oplen = sizeof(sendsize);
568     if(setsockopt(*sock, SOL_SOCKET, SO_SNDBUF,
569           (void *)&sendsize, oplen) == -1)
570     {
571       perror("setsockopt:SO_SNDBUF");
572     }
573     recvsize = socketbuffersize;
574     oplen = sizeof(recvsize);
575     if(setsockopt(*sock, SOL_SOCKET, SO_RCVBUF,
576           (void *)&recvsize, oplen) == -1)
577     {
578       perror("setsockopt:SO_RCVBUF");
579     }
580   }
581 
582   if( options & OPT_VERBOSE )
583   {
584     oplen = sizeof(sendsize);
585     if(getsockopt(*sock, SOL_SOCKET, SO_SNDBUF,
586           (void *)&sendsize, &oplen) == -1)
587     {
588       perror("setsockopt:SO_SNDBUF");
589     }
590     oplen = sizeof(recvsize);
591     if(getsockopt(*sock, SOL_SOCKET, SO_RCVBUF,
592           (void *)&recvsize, &oplen) == -1)
593     {
594       perror("setsockopt:SO_RCVBUF");
595     }
596 
597     fprintf(stderr, "using %d byte socket send buffer\n", sendsize);
598     fprintf(stderr, "using %d byte socket recv buffer\n", recvsize);
599   }
600 #endif
601 
602   return 0;
603 }
604 
605 /*
606  * do_connect
607  *
608  * connect a socket and return the file descriptor
609  *
610  */
do_connect_inet(volatile int * sock,char * host,char * port)611 int do_connect_inet(volatile int *sock, char *host, char *port)
612 {
613   struct sockaddr_in address;
614   struct hostent *hostinfo;
615   struct servent *servinfo;
616 
617   // set up the socket
618   *sock = socket(AF_INET, SOCK_STREAM, 0);
619   address.sin_family = AF_INET;
620 
621   // get the host address
622   hostinfo = gethostbyname(host);
623   if(!hostinfo)
624   {
625     herror("gethostbyname");
626     exit(EXIT_NO_HOST);
627   }
628   address.sin_addr = *(struct in_addr *)*hostinfo->h_addr_list;
629 
630   // get the host port
631   servinfo = getservbyname(port, "tcp");
632   if(servinfo)
633   {
634     address.sin_port = servinfo->s_port;
635   }
636   else
637   {
638     address.sin_port = htons(atoi(port));
639   }
640 
641   // bind the socket
642   if(connect_bind_port != NULL)
643   {
644     struct sockaddr_in bind_address;
645     struct servent *servinfo;
646     int len;
647     char* host;
648     char* port;
649     char* tmp;
650 
651     bind_address.sin_family = AF_INET;
652 
653     tmp = strchr(connect_bind_port, ':');
654     if(tmp)
655     {
656       *tmp++ = '\0';
657       port = tmp;
658       host = connect_bind_port;
659     }
660     else
661     {
662       host = NULL;
663       port = connect_bind_port;
664     }
665 
666     if(host == NULL)
667     {
668       bind_address.sin_addr.s_addr = htonl(INADDR_ANY);
669     }
670     else
671     {
672       if(inet_aton(host, &(bind_address.sin_addr)) == 0)
673       {
674         fprintf(stderr, "can't decipher ipaddr: %s\n", host);
675         return(-1);
676       }
677     }
678 
679     servinfo = getservbyname(port, "tcp");
680     if(servinfo)
681     {
682       bind_address.sin_port = servinfo->s_port;
683     }
684     else
685     {
686       bind_address.sin_port = htons(atoi(port));
687     }
688 
689     len = sizeof(bind_address);
690     if( bind(*sock, (struct sockaddr *)&bind_address, len) != 0 )
691     {
692       perror("bind");
693       return(-1);
694     }
695   }
696 
697   // connect the socket
698   if(connect(*sock, (struct sockaddr *)&address, sizeof(address)) != 0)
699   {
700     perror("connect");
701     return(-1);
702   }
703 
704   // print out some info
705   if( !(options & OPT_QUIET) )
706   {
707     fprintf(stderr,
708         "connected to %s (%s) on port %d.\n",
709         host,
710         inet_ntoa(address.sin_addr),
711         ntohs(address.sin_port));
712   }
713   if( (options & OPT_ECHO) && echo_file != NULL )
714   {
715     fprintf(echo_fp,
716         "connected to %s (%s) on port %d.\n",
717         host,
718         inet_ntoa(address.sin_addr),
719         ntohs(address.sin_port));
720   }
721 
722   return(do_connect_common(sock, host, port));
723 }
724 
do_connect_unix(volatile int * sock,char * host,char * port)725 int do_connect_unix(volatile int *sock, char *host, char *port)
726 {
727 #if HAVE_SYS_UN_H
728   struct sockaddr_un address;
729 
730   // set up the socket
731   *sock = socket(AF_UNIX, SOCK_STREAM, 0);
732   address.sun_family = AF_UNIX;
733   strcpy(address.sun_path, port);
734 
735   // bind the socket
736   if(connect_bind_port != NULL)
737   {
738     struct sockaddr_un bind_address;
739     int len;
740 
741     bind_address.sun_family = AF_UNIX;
742     strcpy(bind_address.sun_path, connect_bind_port);
743 
744     // warning: you have to delete this socket file now
745     len = sizeof(bind_address);
746     if( bind(*sock, (struct sockaddr *)&bind_address, len) != 0 )
747     {
748       perror("bind");
749       return(-1);
750     }
751   }
752 
753   // connect the socket
754   if(connect(*sock, (struct sockaddr *)&address, sizeof(address)) != 0)
755   {
756     perror("connect");
757     return(-1);
758   }
759 
760   // print out some info
761   if( !(options & OPT_QUIET) )
762   {
763     fprintf(stderr, "connected to unix:%s.\n", port);
764   }
765   if( (options & OPT_ECHO) && echo_file != NULL )
766   {
767     fprintf(echo_fp, "connected to unix:%s.\n", port);
768   }
769 
770 
771   return(do_connect_common(sock, host, port));
772 #else
773   fprintf(stderr, "AF_UNIX support not enabled at compile time\n");
774   return(-1);
775 #endif
776 }
777 
778 /*
779  * do_accept
780  *
781  * do_accept is a one shot deal so it simply sets up a server
782  * socket, accepts a single connection on that socket, copies
783  * all of the input data to stdout, then shuts down the server
784  * socket and the connected socket.
785  *
786  */
do_accept_common(volatile int * sock,volatile int serv_sock)787 int do_accept_common(volatile int *sock, volatile int serv_sock)
788 {
789   int oplen;
790   int sendsize;
791   int recvsize;
792 
793 #if HAVE_SETSOCKOPT && defined(SO_SNDBUF) && defined(SO_RCVBUF)
794   if(socketbuffersize != 0)
795   {
796     sendsize = socketbuffersize;
797     oplen = sizeof(sendsize);
798     if(setsockopt(*sock, SOL_SOCKET, SO_SNDBUF,
799           (void *)&sendsize, oplen) == -1)
800     {
801       perror("setsockopt:SO_SNDBUF");
802     }
803     recvsize = socketbuffersize;
804     oplen = sizeof(recvsize);
805     if(setsockopt(*sock, SOL_SOCKET, SO_RCVBUF,
806           (void *)&recvsize, oplen) == -1)
807     {
808       perror("setsockopt:SO_RCVBUF");
809     }
810   }
811 
812   if( options & OPT_VERBOSE )
813   {
814     oplen = sizeof(sendsize);
815     if(getsockopt(*sock, SOL_SOCKET, SO_SNDBUF,
816           (void *)&sendsize, &oplen) == -1)
817     {
818       perror("getsockopt:SO_SNDBUF");
819     }
820     oplen = sizeof(recvsize);
821     if(getsockopt(*sock, SOL_SOCKET, SO_RCVBUF,
822           (void *)&recvsize, &oplen) == -1)
823     {
824       perror("getsockopt:SO_RCVBUF");
825     }
826 
827     fprintf(stderr, "using %d byte socket send buffer\n", sendsize);
828     fprintf(stderr, "using %d byte socket recv buffer\n", recvsize);
829   }
830 #endif
831 
832   return 0;
833 }
834 
do_listen_common(volatile int * serv_sock,char * host,char * port)835 int do_listen_common(volatile int *serv_sock, char *host, char *port)
836 {
837   return 0;
838 }
839 
do_listen_unix(volatile int * serv_sock,char * host,char * port)840 int do_listen_unix(volatile int *serv_sock, char *host, char *port)
841 {
842 #ifdef HAVE_SYS_UN_H
843   int server_len;
844   int client_len;
845   struct sockaddr_un server_address;
846   struct sockaddr_un client_address;
847 
848   // set up the server socket
849   if( (*serv_sock=socket(AF_UNIX, SOCK_STREAM, 0)) == -1 )
850   {
851     perror("socket");
852     return(-1);
853   }
854   server_address.sun_family = AF_UNIX;
855   strcpy(server_address.sun_path, port);
856 
857   // bind it to a port
858   server_len = sizeof(server_address);
859   if( bind(*serv_sock, (struct sockaddr *)&server_address, server_len) != 0 )
860   {
861     perror("bind");
862     return(-1);
863   }
864 
865   // listen with a backlog of one, this should be zero but the BeOS
866   // doesn't interpret 0 correctly and most OSes don't enforce a backlog
867   // of 0 anyway
868   if( listen(*serv_sock, 1) != 0 )
869   {
870     perror("listen");
871     return(-1);
872   }
873 
874   // print out some info
875   if( !(options & OPT_QUIET) )
876   {
877     fprintf(stderr, "listening on unix:%s.\n", port);
878   }
879   if( (options & OPT_ECHO) && echo_file != NULL )
880   {
881     fprintf(echo_fp, "listening on unix:%s.\n", port);
882   }
883 
884   return(do_listen_common(serv_sock, host, port));
885 #else
886   fprintf(stderr, "AF_UNIX support not enabled at compile time\n");
887   return(-1);
888 #endif
889 }
890 
891 /*
892  * do_accept
893  *
894  * do_accept is a one shot deal so it simply sets up a server
895  * socket, accepts a single connection on that socket, copies
896  * all of the input data to stdout, then shuts down the server
897  * socket and the connected socket.
898  *
899  */
do_accept_unix(volatile int * sock,volatile int serv_sock)900 int do_accept_unix(volatile int *sock, volatile int serv_sock)
901 {
902   int server_len;
903   int client_len;
904   struct sockaddr_un server_address;
905   struct sockaddr_un client_address;
906 
907   // accept a connection on the server socket
908   client_len = sizeof(client_address);
909   *sock = accept( serv_sock,
910       (struct sockaddr *)&client_address,
911       &client_len );
912 
913   // check the socket
914   if( *sock == -1 )
915   {
916     perror("accept");
917     return(-1);
918   }
919 
920   // print out some info
921   if( !(options & OPT_QUIET) )
922   {
923     fprintf(stderr, "connection from unix:%s.\n", client_address.sun_path);
924   }
925   if( (options & OPT_ECHO) && echo_file != NULL )
926   {
927     fprintf(echo_fp, "connection from unix:%s.\n", client_address.sun_path);
928   }
929 
930   return(do_accept_common(sock, serv_sock));
931 }
932 
do_listen_inet(volatile int * serv_sock,char * host,char * port)933 int do_listen_inet(volatile int *serv_sock, char *host, char *port)
934 {
935   int server_len;
936   int client_len;
937   struct sockaddr_in server_address;
938   struct sockaddr_in client_address;
939   int res;
940   int x;
941 #if HAVE_SETSOCKOPT
942 #  ifdef SO_LINGER
943   struct linger ling;
944 #  endif
945 #endif
946 
947   // set up the server socket
948   if( (*serv_sock=socket(AF_INET, SOCK_STREAM, 0)) == -1 )
949   {
950     perror("socket");
951     return(-1);
952   }
953 
954 
955 #if HAVE_SETSOCKOPT
956 #  ifdef SO_REUSEADDR
957   x = 1;
958   res = setsockopt(*serv_sock, SOL_SOCKET, SO_REUSEADDR, (void *)&x, sizeof(x));
959   if(res == -1)
960   {
961     perror("setsockopt:SO_REUSEADDR");
962   }
963 #  endif
964 #  ifdef SO_LINGER
965   ling.l_onoff = 1;
966   ling.l_linger = 10000;
967   res = setsockopt(*serv_sock, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
968   if(res == -1)
969   {
970     perror("setsockopt:SO_LINGER");
971   }
972 #  endif
973 #endif
974 
975 
976   server_address.sin_family = AF_INET;
977   server_address.sin_addr.s_addr = htonl(INADDR_ANY);
978   server_address.sin_port = htons(atoi(port));
979 
980   // bind it to a port
981   server_len = sizeof(server_address);
982   if( bind(*serv_sock, (struct sockaddr *)&server_address, server_len) != 0 )
983   {
984     perror("bind");
985     return(-1);
986   }
987 
988   // listen with a backlog of one, this should be zero but the BeOS
989   // doesn't interpret 0 correctly and most OSes don't enforce a backlog
990   // of 0 anyway
991   if( listen(*serv_sock, 1) != 0 )
992   {
993     perror("listen");
994     return(-1);
995   }
996 
997   // print out some info
998   if( !(options & OPT_QUIET) )
999   {
1000     fprintf(stderr,
1001         "listening on %s port %d.\n",
1002         inet_ntoa(server_address.sin_addr),
1003         ntohs(server_address.sin_port) );
1004   }
1005 
1006   return(do_listen_common(serv_sock, host, port));
1007 }
1008 
do_accept_inet(volatile int * sock,volatile int serv_sock)1009 int do_accept_inet(volatile int *sock, volatile int serv_sock)
1010 {
1011   int server_len;
1012   int client_len;
1013   struct sockaddr_in server_address;
1014   struct sockaddr_in client_address;
1015   int res;
1016   int x;
1017   struct linger ling;
1018 
1019   // accept a connection on the server socket
1020   client_len = sizeof(client_address);
1021   *sock = accept( serv_sock,
1022       (struct sockaddr *)&client_address,
1023       &client_len );
1024 
1025   // check the socket
1026   if( *sock == -1 )
1027   {
1028     perror("accept");
1029     return(-1);
1030   }
1031 
1032   // stop listening after we have 1 connection
1033   //close(serv_sock);
1034 
1035   // print out some info
1036   if( !(options & OPT_QUIET) )
1037   {
1038     fprintf(stderr,
1039         "connection from %s on port %d.\n",
1040         inet_ntoa(client_address.sin_addr),
1041         ntohs(client_address.sin_port));
1042   }
1043   if( (options & OPT_ECHO) && echo_file != NULL )
1044   {
1045     fprintf(echo_fp,
1046         "connection from %s on port %d.\n",
1047         inet_ntoa(client_address.sin_addr),
1048         ntohs(client_address.sin_port));
1049   }
1050 
1051   return(do_accept_common(sock, serv_sock));
1052 }
1053 
read_data(int fd,void * buf,int bufsize)1054 int read_data(int fd, void* buf, int bufsize)
1055 {
1056   int bread = read(fd, buf, buffersize);
1057   if(options & OPT_CKSUM)
1058   {
1059     g_cksum = adler32(g_cksum, buf, bread);
1060   }
1061   return(bread);
1062 }
1063 
revc_data(int fd,void * buf,int bufsize)1064 int revc_data(int fd, void* buf, int bufsize)
1065 {
1066   int bread = recv(fd, buf, buffersize, 0);
1067   if(options & OPT_CKSUM)
1068   {
1069     g_cksum = adler32(g_cksum, buf, bread);
1070   }
1071   return(bread);
1072 }
1073 
1074 /*
1075  * copy_in_out_verb
1076  *
1077  * simply read the input file descriptor and write the
1078  * data to the output file descriptor.
1079  *
1080  * also ouput a progressmeter.
1081  *
1082  */
copy_in_out_verb(int input_fd,int output_fd)1083 void copy_in_out_verb(int input_fd, int output_fd)
1084 {
1085   char *buf;
1086   int bytes_read;
1087 
1088   buf = xmalloc(buffersize);
1089 
1090   while( (bytes_read=read_data(input_fd, buf, buffersize)) > 0 )
1091   {
1092     write(output_fd, buf, bytes_read);
1093     bytes_copied += bytes_read;
1094     fputc('.', stderr);
1095   }
1096 
1097   free(buf);
1098 }
1099 
1100 /*
1101  * copy_in_out_quiet
1102  *
1103  * simply read the input file descriptor and write the
1104  * data to the output file descriptor.
1105  *
1106  */
copy_in_out_quiet(int input_fd,int output_fd)1107 void copy_in_out_quiet(int input_fd, int output_fd)
1108 {
1109   char *buf;
1110   int bytes_read;
1111 
1112   buf = xmalloc(buffersize);
1113 
1114   while( (bytes_read=read_data(input_fd, buf, buffersize)) > 0 )
1115   {
1116     write(output_fd, buf, bytes_read);
1117     bytes_copied += bytes_read;
1118   }
1119 
1120   free(buf);
1121 }
1122 
1123 /*
1124  * copy_in_out4_quiet
1125  *
1126  * read input1_fd => write input2_fd
1127  * read input2_fd => write output_fd
1128  *
1129  * basicly just like telnet.
1130  *
1131  */
copy_in_out4_quiet(int input1_fd,int input2_fd,int output1_fd,int output2_fd)1132 void copy_in_out4_quiet(int input1_fd, int input2_fd, int output1_fd, int output2_fd)
1133 {
1134   char *buf;
1135   int bytes_read = 0;
1136   int max_fd;
1137   fd_set readfds;
1138   fd_set select_readfds;
1139   struct timeval *tv = NULL;
1140   int ret;
1141 
1142   buf = xmalloc(buffersize);
1143 
1144   FD_ZERO(&readfds);
1145   FD_SET(input1_fd, &readfds);
1146   FD_SET(input2_fd, &readfds);
1147 
1148   max_fd = (input1_fd > input2_fd ? input1_fd : input2_fd);
1149   if(timeout != NULL)
1150   {
1151     tv = (struct timeval*)malloc(sizeof(struct timeval));
1152     if(tv == NULL)
1153     {
1154       fprintf(stderr, "internal error, timeout will be ignored\n");
1155       timeout = NULL;
1156     }
1157   }
1158 
1159   for(;;)
1160   {
1161     // refresh our fd set and timeout
1162     memcpy(&select_readfds, &readfds, sizeof(readfds));
1163     if(timeout)
1164     {
1165       memcpy(tv, timeout, sizeof(struct timeval));
1166     }
1167 
1168     // select on the readfds
1169     ret = select(max_fd + 1, &select_readfds, NULL, NULL, tv );
1170     dprintf((stderr, "select: %d\n", ret));
1171 
1172     if ( ret == -1)
1173     {
1174       perror("select");
1175       break;
1176     }
1177     if( ret == 0 )
1178     {
1179       fprintf(stderr, "timeout\n");
1180       break;
1181     }
1182 
1183     /* if we woke up on input1_fd do the data passing */
1184     if(FD_ISSET(input1_fd, &select_readfds))
1185     {
1186       if( (bytes_read=read_data(input1_fd, buf, buffersize) ) <= 0)
1187         break;
1188       if(write(output2_fd, buf, bytes_read) != bytes_read)
1189         break;
1190       if( options & OPT_ECHO )
1191       {
1192         write(echo_fd, "L: ", 3);
1193         write(echo_fd, buf, bytes_read);
1194       }
1195       dprintf((stderr, "transfered %d bytes (%d -> %d)\n", bytes_read,
1196             input1_fd, output2_fd));
1197     }
1198     else if(FD_ISSET(input2_fd, &select_readfds))
1199     {
1200       if( (bytes_read=read_data(input2_fd, buf, buffersize) ) <= 0)
1201         break;
1202       if(write(output1_fd, buf, bytes_read) != bytes_read)
1203         break;
1204       if( options & OPT_ECHO )
1205       {
1206         write(echo_fd, "H: ", 3);
1207         write(echo_fd, buf, bytes_read);
1208       }
1209       dprintf((stderr, "transfered %d bytes (%d -> %d)\n", bytes_read,
1210             input2_fd, output1_fd));
1211     }
1212     else
1213     {
1214       dprintf((stderr, "error: case not handled."));
1215     }
1216     bytes_copied += bytes_read;
1217   }
1218 
1219   if(tv)
1220   {
1221     free(tv);
1222   }
1223 
1224   free(buf);
1225 }
1226 
1227 #if defined(__BEOS__)
1228 /*
1229  * needed for silly OSes
1230  */
copy_sin_fout_quiet(int input_fd,int output_fd)1231 void copy_sin_fout_quiet(int input_fd, int output_fd)
1232 {
1233   char *buf;
1234   int bytes_read;
1235 
1236   buf = xmalloc(buffersize);
1237 
1238   while( (bytes_read=recv_data(input_fd, buf, buffersize, 0)) > 0 )
1239   {
1240     write(output_fd, buf, bytes_read);
1241     bytes_copied += bytes_read;
1242   }
1243 
1244   free(buf);
1245 }
copy_sin_fout_verb(int input_fd,int output_fd)1246 void copy_sin_fout_verb(int input_fd, int output_fd)
1247 {
1248   char *buf;
1249   int bytes_read;
1250 
1251   buf = xmalloc(buffersize);
1252 
1253   while( (bytes_read=recv_data(input_fd, buf, buffersize, 0)) > 0 )
1254   {
1255     write(output_fd, buf, bytes_read);
1256     bytes_copied += bytes_read;
1257     fputc('.', stderr);
1258   }
1259 
1260   free(buf);
1261 }
copy_fin_sout_quiet(int input_fd,int output_fd)1262 void copy_fin_sout_quiet(int input_fd, int output_fd)
1263 {
1264   int bytes_read;
1265   char *buf;
1266 
1267   buf = xmalloc(buffersize);
1268 
1269   while( (bytes_read=read_data(input_fd, buf, buffersize)) > 0 )
1270   {
1271     send(output_fd, buf, bytes_read, 0);
1272     bytes_copied += bytes_read;
1273   }
1274 
1275   free(buf);
1276 }
copy_fin_sout_verb(int input_fd,int output_fd)1277 void copy_fin_sout_verb(int input_fd, int output_fd)
1278 {
1279   char *buf;
1280   int bytes_read;
1281 
1282   buf = xmalloc(buffersize);
1283 
1284   while( (bytes_read=read_data(input_fd, buf, buffersize)) > 0 )
1285   {
1286     send(output_fd, buf, bytes_read, 0);
1287     bytes_copied += bytes_read;
1288     fputc('.', stderr);
1289   }
1290 
1291   free(buf);
1292 }
copy_in_out4_not_available(int a,int b,int c,int d)1293 void copy_in_out4_not_available(int a, int b, int c, int d)
1294 {
1295   fprintf( stderr,
1296   "this functionality is not abailable due to the fact that the OS\n"
1297   "that you are using spererates socket descriptors from file descriptorss.\n"
1298   "the feature could be implemented by using two threads but that isn't very\n"
1299   "pretty.\n" );
1300 }
1301 #endif
1302 
1303 /*
1304  * enable or restore terminal line buffering state
1305  */
set_input_buffer(int fd,int restore)1306 void set_input_buffer(int fd, int restore)
1307 {
1308 #ifdef HAVE_TERMIOS_H
1309   static struct termios orig;
1310   struct termios new;
1311 #else
1312 #  ifdef HAVE_TERMIO_H
1313   static struct termio orig;
1314   struct termio new;
1315 #  endif
1316 #endif
1317   static int need_restore = 0;
1318 
1319 
1320   if(!isatty(fd))
1321   {
1322     return;
1323   }
1324 
1325   dprintf((stderr, "restore: %d\n", restore));
1326   if(!restore)
1327   {
1328 #ifdef HAVE_TERMIOS_H
1329     if(!need_restore)
1330     {
1331       if(tcgetattr(fd, &orig) != 0)
1332       {
1333         perror("tcgetattr");
1334       }
1335     }
1336     new = orig;
1337 
1338     dprintf((stderr, "iflag: 0x%08x oflag: 0x%08x cflag: 0x%08x lflag: 0x%08x\n",
1339         new.c_iflag, new.c_oflag, new.c_cflag, new.c_lflag));
1340 
1341     new.c_lflag &= ~ICANON;
1342 
1343     dprintf((stderr, "iflag: 0x%08x oflag: 0x%08x cflag: 0x%08x lflag: 0x%08x\n",
1344         new.c_iflag, new.c_oflag, new.c_cflag, new.c_lflag));
1345 
1346     if(tcsetattr(fd, TCSANOW, &new) != 0)
1347     {
1348       perror("tcsetattr");
1349     }
1350     else
1351     {
1352       need_restore = 1;
1353     }
1354 #else
1355 #  ifdef HAVE_TERMIO_H
1356     if(!need_restore)
1357     {
1358       if(ioctl(fd, TCGETA, &orig) != 0)
1359       {
1360         perror("ioctl");
1361       }
1362     }
1363     new = orig;
1364 
1365     dprintf((stderr, "iflag: 0x%08x oflag: 0x%08x cflag: 0x%08x lflag: 0x%08x\n",
1366         new.c_iflag, new.c_oflag, new.c_cflag, new.c_lflag));
1367 
1368     new.c_lflag &= ~ICANON;
1369 
1370     dprintf((stderr, "iflag: 0x%08x oflag: 0x%08x cflag: 0x%08x lflag: 0x%08x\n",
1371         new.c_iflag, new.c_oflag, new.c_cflag, new.c_lflag));
1372 
1373     if(ioctl(fd, TCSETA, &new) != 0)
1374     {
1375       perror("ioctl");
1376     }
1377     else
1378     {
1379       need_restore = 1;
1380     }
1381 #  else
1382 #  endif
1383 #endif
1384   }
1385   else
1386   {
1387     if(!need_restore)
1388     {
1389       return;
1390     }
1391 #ifdef HAVE_TERMIOS_H
1392     if(tcsetattr(fd, TCSANOW, &orig) != 0)
1393     {
1394       perror("tcgetattr");
1395     }
1396     else
1397     {
1398       need_restore = 0;
1399     }
1400 #else
1401 #  ifdef HAVE_TERMIO_H
1402     if(ioctl(fd, TCSETA, &orig) != 0)
1403     {
1404       perror("ioctl");
1405     }
1406     else
1407     {
1408       need_restore = 0;
1409     }
1410 #  else
1411 #  endif
1412 #endif
1413   }
1414 
1415 }
1416 
print_sum(void)1417 void print_sum(void)
1418 {
1419   fprintf(stderr, "checksum: %u\n", g_cksum);
1420 }
1421 
main(int argc,char ** argv)1422 int main( int argc, char **argv )
1423 {
1424   int i;
1425   int input_fd;
1426   struct timeval time1;
1427   struct timeval time2;
1428   int first_arg;
1429   void (*copy_in_out4_fp)(int, int, int, int);
1430   void (*copy_sin_fout_fp)(int, int);
1431   void (*copy_fin_sout_fp)(int, int);
1432   void (*send_file_fp)(int, int);
1433 
1434   dprintf((stderr, "staring...\n"));
1435 
1436   program_name = argv[0];
1437   options = 0;
1438   bytes_copied = 0;
1439   timeout = NULL;
1440 
1441 #if HAVE_SIGNAL_H
1442   // catch user interupts
1443   signal(SIGINT, sig_handler);
1444   signal(SIGQUIT, sig_handler);
1445 #endif
1446 
1447   parse_args(argc, argv);
1448   first_arg = optind;
1449 
1450   // set defaults
1451   if( !host )
1452   {
1453     host = strdup("localhost");
1454   }
1455 
1456   // set socket domain
1457   if((options & OPT_AF_UNIX))
1458   {
1459     do_connect = do_connect_unix;
1460     do_listen = do_listen_unix;
1461     do_accept = do_accept_unix;
1462   }
1463   else
1464   {
1465     do_connect = do_connect_inet;
1466     do_listen = do_listen_inet;
1467     do_accept = do_accept_inet;
1468   }
1469 
1470   // corelate options
1471   if( (options & OPT_CONNECT) && (options & OPT_LISTEN) )
1472   {
1473     options |= OPT_INPUT;
1474     options |= OPT_OUTPUT;
1475   }
1476 
1477   // more error checking
1478   if( !(options & OPT_CONNECT) && connect_bind_port != NULL)
1479   {
1480     fprintf(stderr, "you can not use --bind-port if you are not connecting, \njust use --port instead\n");
1481     exit(1);
1482   }
1483 
1484   // if we are listening and not doing input we do output by default
1485   if( (options & OPT_LISTEN) && !(options & OPT_INPUT) )
1486   {
1487     options |= OPT_OUTPUT;
1488   }
1489   // if we are connecting and not doing output we do input by default
1490   if( !(options & OPT_LISTEN) && !(options & OPT_OUTPUT) )
1491   {
1492     options |= OPT_INPUT;
1493   }
1494 
1495   dprintf((stderr, "options: 0x%04X\n", options));
1496   dprintf((stderr, "host: %s\n", host ? host : "(null)"));
1497   dprintf((stderr, "connect_port: %s\n", connect_port ? connect_port : "(null)"));
1498   dprintf((stderr, "listen_port: %s\n", listen_port ? listen_port : "(null)"));
1499 
1500   // check for conflicting options
1501   if( (first_arg != argc) && (options & OPT_OUTPUT) )
1502   {
1503     fprintf(stderr, "Error: when using the output (`-o') option files can");
1504     fprintf(stderr, " not be supplied\n");
1505     exit(1);
1506   }
1507 
1508   /*
1509    * set up the function pointers to handle for silly OSes and
1510    * the options
1511    */
1512   if( (options & OPT_VERBOSE) && !(options & OPT_QUIET) )
1513   {
1514 #if __BEOS__
1515     copy_in_out4_fp = copy_in_out4_not_available;
1516     copy_fin_sout_fp = copy_fin_sout_verb;
1517     copy_sin_fout_fp = copy_sin_fout_verb;
1518     send_file_fp = copy_fin_sout_verb;
1519 #else
1520     copy_in_out4_fp = copy_in_out4_quiet;
1521     copy_fin_sout_fp = copy_in_out_verb;
1522     copy_sin_fout_fp = copy_in_out_verb;
1523     send_file_fp = copy_in_out_verb;
1524 #endif
1525   }
1526   else
1527   {
1528 #if __BEOS__
1529     copy_in_out4_fp = copy_in_out4_not_available;
1530     copy_fin_sout_fp = copy_fin_sout_quiet;
1531     copy_sin_fout_fp = copy_sin_fout_quiet;
1532     if( options & OPT_QUIET)
1533     {
1534       send_file_fp = copy_fin_sout_quiet;
1535     }
1536     else
1537     {
1538       send_file_fp = copy_fin_sout_verb;
1539     }
1540 #else
1541     copy_in_out4_fp = copy_in_out4_quiet;
1542     copy_fin_sout_fp = copy_in_out_quiet;
1543     copy_sin_fout_fp = copy_in_out_quiet;
1544     if( options & OPT_QUIET)
1545     {
1546       send_file_fp = copy_in_out_quiet;
1547     }
1548     else
1549     {
1550       send_file_fp = copy_in_out_verb;
1551     }
1552 #endif
1553   }
1554 
1555   if( options & OPT_VERBOSE )
1556   {
1557     fprintf(stderr, "using %d byte buffer\n", buffersize);
1558   }
1559 
1560   // open our echo file
1561   if( (options & OPT_ECHO) && echo_file != NULL )
1562   {
1563     if( (echo_fd=open(echo_file, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1 )
1564     {
1565       perror(echo_file);
1566       exit(1);
1567     }
1568     if( (echo_fp=fdopen(echo_fd, "w")) == NULL)
1569     {
1570       perror(echo_file);
1571       exit(1);
1572     }
1573     // no buffering on the echo file so we can mix calls to write
1574     // and fprintf
1575     setvbuf(echo_fp, NULL, _IONBF, 0);
1576   }
1577 
1578   if(options & OPT_NOBUF)
1579   {
1580     set_input_buffer(fileno(stdin), 0);
1581   }
1582 
1583   server_sockfd = -1;
1584   do
1585   {
1586     if( (options & OPT_ECHO) && echo_file != NULL )
1587     {
1588       fprintf(echo_fp, "=============\n");
1589     }
1590 
1591     // open up our sockets
1592     if( (options & OPT_LISTEN) && (options & OPT_CONNECT) )
1593     {
1594       if( server_sockfd == -1 )
1595       {
1596         if( do_listen(&server_sockfd, NULL, listen_port) != 0 )
1597         {
1598           fprintf(stderr, "error creating server socket\n");
1599           exit(1);
1600         }
1601       }
1602       if( do_accept(&client_sockfd, server_sockfd) != 0 )
1603       {
1604         fprintf(stderr, "error accepting connections\n");
1605         exit(1);
1606       }
1607       if(!(options & OPT_CONTINUOUS))
1608       {
1609         // stop listening after we have 1 connection
1610         close(server_sockfd);
1611       }
1612       if( do_connect(&client_sockfd2, host, connect_port) != 0 )
1613       {
1614         fprintf(stderr, "error connecting socket\n");
1615         exit(1);
1616       }
1617     }
1618     else if( options & OPT_LISTEN )
1619     {
1620       if( server_sockfd == -1 )
1621       {
1622         if( do_listen(&server_sockfd, NULL, listen_port) != 0 )
1623         {
1624           fprintf(stderr, "error creating server socket\n");
1625           exit(1);
1626         }
1627       }
1628       if( do_accept(&client_sockfd, server_sockfd) != 0 )
1629       {
1630         fprintf(stderr, "error accepting connections\n");
1631         exit(1);
1632       }
1633       if(!(options & OPT_CONTINUOUS))
1634       {
1635         // stop listening after we have 1 connection
1636         close(server_sockfd);
1637       }
1638     }
1639     else if( options & OPT_CONNECT )
1640     {
1641       if( do_connect(&client_sockfd, host, connect_port) != 0 )
1642       {
1643         fprintf(stderr, "error connecting socket\n");
1644         exit(1);
1645       }
1646     }
1647 
1648     gettimeofday(&time1, NULL);
1649 
1650     // if we don't have files supplied on the command line
1651     if( first_arg == argc )
1652     {
1653       /*
1654       * figure out what to do,
1655       * if we have -i and -o then act like
1656       * telnet, otherwise check for -o or -l if not found default
1657       * to read in, write out.
1658       */
1659       if( (options & OPT_OUTPUT) && (options & OPT_INPUT) )
1660       {
1661         if( (options & OPT_CONNECT) && (options & OPT_LISTEN) )
1662         {
1663           copy_in_out4_fp(client_sockfd, client_sockfd2, client_sockfd, client_sockfd2);
1664         }
1665         else
1666         {
1667           // read socket, stdin, write stdout
1668           copy_in_out4_fp(STDIN_FILENO, client_sockfd, STDOUT_FILENO, client_sockfd);
1669         }
1670       }
1671       else if( (options & OPT_OUTPUT) )
1672       {
1673         if(options & OPT_VERBOSE)
1674         {
1675           fprintf(stderr, "receiving ");
1676         }
1677         // read socket, write stdout
1678         copy_sin_fout_fp(client_sockfd, STDOUT_FILENO);;
1679         if(options & OPT_VERBOSE)
1680         {
1681           fprintf(stderr, " done.\n");
1682         }
1683       }
1684       else if( (options & OPT_INPUT) )
1685       {
1686         if(options & OPT_VERBOSE)
1687         {
1688           fprintf(stderr, "sending ");
1689         }
1690         // read stdin, write socket
1691         copy_fin_sout_fp(STDIN_FILENO, client_sockfd);
1692         if(options & OPT_VERBOSE)
1693         {
1694           fprintf(stderr, " done.\n");
1695         }
1696       }
1697       else
1698       {
1699         dprintf((stderr, "case not handeled\n"));
1700       }
1701     }
1702     else
1703     {
1704       // proccess the files
1705       for(i=first_arg; i<argc; i++)
1706       {
1707         dprintf((stderr, "processing file %s...\n", argv[i]));
1708         if( (input_fd=open(argv[i], O_RDONLY)) == -1 )
1709         {
1710           perror(argv[i]);
1711           continue;
1712         }
1713         if( !(options & OPT_QUIET) )
1714         {
1715           fprintf(stderr, "sending file %s ", argv[i]);
1716         }
1717 
1718         // read file, write socket
1719         send_file_fp(input_fd, client_sockfd);
1720 
1721         if( !(options & OPT_QUIET) )
1722         {
1723           fprintf(stderr, " done.\n");
1724         }
1725 
1726         if(close(input_fd) != 0)
1727         {
1728           perror(argv[i]);
1729         }
1730       }
1731     }
1732 
1733     gettimeofday(&time2, NULL);
1734 
1735     close(client_sockfd);
1736     if( (options & OPT_LISTEN) && (options & OPT_CONNECT) )
1737     {
1738       close(client_sockfd2);
1739     }
1740 
1741     if( !(options & OPT_QUIET) )
1742     {
1743       double took;
1744 
1745       took = ((double)time2.tv_sec - (double)time1.tv_sec +
1746           (double)time2.tv_usec/1000000L -
1747           (double)time1.tv_usec/1000000L);
1748 
1749       if( (options & OPT_OUTPUT) && (options & OPT_INPUT) )
1750       {
1751         fprintf( stderr,
1752             "%li bytes transfered in %.2f seconds (%.2f K/s)\n",
1753             bytes_copied,
1754             took,
1755             bytes_copied/took/1024 );
1756       }
1757       else if( (options & OPT_OUTPUT) )
1758       {
1759         fprintf( stderr,
1760             "%li bytes written to stdout in %.2f seconds (%.2f K/s)\n",
1761             bytes_copied,
1762             took,
1763             bytes_copied/took/1024 );
1764       }
1765       else if( (options & OPT_INPUT) )
1766       {
1767         fprintf( stderr,
1768             "%li bytes written to %s:%s in %.2f seconds (%.2f K/s)\n",
1769             bytes_copied,
1770             host,
1771             connect_port,
1772             took,
1773             bytes_copied/took/1024 );
1774       }
1775     }
1776   }
1777   while(options & OPT_CONTINUOUS);
1778 
1779   if( (options & OPT_ECHO) && echo_file != NULL )
1780   {
1781     fclose(echo_fp);
1782     close(echo_fd);
1783   }
1784 
1785   if(options & OPT_NOBUF)
1786   {
1787     set_input_buffer(fileno(stdin), 1);
1788   }
1789 
1790   // clean up the socket file
1791   if( (options & OPT_AF_UNIX) && (options & OPT_LISTEN) && listen_port )
1792   {
1793     unlink(listen_port);
1794   }
1795 
1796   if(options & OPT_CKSUM)
1797   {
1798     print_sum();
1799   }
1800 
1801   dprintf((stderr, "done\n"));
1802   return 0;
1803 }
1804 
1805