1 /* vi: set sw=4 ts=4: */
2 /* nc: mini-netcat - built from the ground up for LRP
4 * Copyright (C) 1998, 1999 Charles P. Wright
5 * Copyright (C) 1998 Dave Cinege
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
13 #include "nc_bloaty.c"
16 /* Lots of small differences in features
17 * when compared to "standard" nc
20 static void timeout(int signum UNUSED_PARAM
)
22 bb_error_msg_and_die("timed out");
25 int nc_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
26 int nc_main(int argc
, char **argv
)
28 /* sfd sits _here_ only because of "repeat" option (-l -l). */
29 int sfd
= sfd
; /* for gcc */
32 SKIP_NC_SERVER(const) unsigned do_listen
= 0;
33 SKIP_NC_EXTRA (const) unsigned wsecs
= 0;
34 SKIP_NC_EXTRA (const) unsigned delay
= 0;
35 SKIP_NC_EXTRA (const int execparam
= 0;)
36 USE_NC_EXTRA (char **execparam
= NULL
;)
37 len_and_sockaddr
*lsa
;
38 fd_set readfds
, testfds
;
39 int opt
; /* must be signed (getopt returns -1) */
41 if (ENABLE_NC_SERVER
|| ENABLE_NC_EXTRA
) {
42 /* getopt32 is _almost_ usable:
43 ** it cannot handle "... -e prog -prog-opt" */
44 while ((opt
= getopt(argc
, argv
,
45 "" USE_NC_SERVER("lp:") USE_NC_EXTRA("w:i:f:e:") )) > 0
47 if (ENABLE_NC_SERVER
&& opt
=='l')
48 USE_NC_SERVER(do_listen
++);
49 else if (ENABLE_NC_SERVER
&& opt
=='p')
50 USE_NC_SERVER(lport
= bb_lookup_port(optarg
, "tcp", 0));
51 else if (ENABLE_NC_EXTRA
&& opt
=='w')
52 USE_NC_EXTRA( wsecs
= xatou(optarg
));
53 else if (ENABLE_NC_EXTRA
&& opt
=='i')
54 USE_NC_EXTRA( delay
= xatou(optarg
));
55 else if (ENABLE_NC_EXTRA
&& opt
=='f')
56 USE_NC_EXTRA( cfd
= xopen(optarg
, O_RDWR
));
57 else if (ENABLE_NC_EXTRA
&& opt
=='e' && optind
<= argc
) {
58 /* We cannot just 'break'. We should let getopt finish.
59 ** Or else we won't be able to find where
60 ** 'host' and 'port' params are
61 ** (think "nc -w 60 host port -e prog"). */
64 // +2: one for progname (optarg) and one for NULL
65 execparam
= xzalloc(sizeof(char*) * (argc
- optind
+ 2));
68 while (optind
< argc
) {
69 *p
++ = argv
[optind
++];
72 /* optind points to argv[arvc] (NULL) now.
73 ** FIXME: we assume that getopt will not count options
74 ** possibly present on "-e prog args" and will not
75 ** include them into final value of optind
76 ** which is to be used ... */
77 } else bb_show_usage();
79 argv
+= optind
; /* ... here! */
81 // -l and -f don't mix
82 if (do_listen
&& cfd
) bb_show_usage();
83 // Listen or file modes need zero arguments, client mode needs 2
84 if (do_listen
|| cfd
) {
85 if (argc
) bb_show_usage();
87 if (!argc
|| argc
> 2) bb_show_usage();
90 if (argc
!= 3) bb_show_usage();
96 signal(SIGALRM
, timeout
);
102 /* create_and_bind_stream_or_die(NULL, lport)
103 * would've work wonderfully, but we need
105 sfd
= xsocket_stream(&lsa
);
107 set_nport(lsa
, htons(lport
));
108 setsockopt_reuseaddr(sfd
);
109 xbind(sfd
, &lsa
->u
.sa
, lsa
->len
);
110 xlisten(sfd
, do_listen
); /* can be > 1 */
111 /* If we didn't specify a port number,
112 * query and print it after listen() */
114 socklen_t addrlen
= lsa
->len
;
115 getsockname(sfd
, &lsa
->u
.sa
, &addrlen
);
116 lport
= get_nport(&lsa
->u
.sa
);
117 fdprintf(2, "%d\n", ntohs(lport
));
119 close_on_exec_on(sfd
);
121 cfd
= accept(sfd
, NULL
, 0);
123 bb_perror_msg_and_die("accept");
127 cfd
= create_and_connect_stream_or_die(argv
[0],
128 argv
[1] ? bb_lookup_port(argv
[1], "tcp", 0) : 0);
134 /* Non-ignored siganls revert to SIG_DFL on exec anyway */
135 /*signal(SIGALRM, SIG_DFL);*/
140 signal(SIGCHLD
, SIG_IGN
);
141 // With more than one -l, repeatedly act as server.
142 if (do_listen
> 1 && vfork()) {
144 // This is a bit weird as cleanup goes, since we wind up with no
145 // stdin/stdout/stderr. But it's small and shouldn't hurt anything.
146 // We check for cfd == 0 above.
147 logmode
= LOGMODE_NONE
;
153 /* child (or main thread if no multiple -l) */
157 USE_NC_EXTRA(BB_EXECVP(execparam
[0], execparam
);)
158 /* Don't print stuff or it will go over the wire.... */
162 // Select loop copying stdin to cfd, and cfd to stdout.
165 FD_SET(cfd
, &readfds
);
166 FD_SET(STDIN_FILENO
, &readfds
);
175 if (select(FD_SETSIZE
, &testfds
, NULL
, NULL
, NULL
) < 0)
176 bb_perror_msg_and_die("select");
178 #define iobuf bb_common_bufsiz1
179 for (fd
= 0; fd
< FD_SETSIZE
; fd
++) {
180 if (FD_ISSET(fd
, &testfds
)) {
181 nread
= safe_read(fd
, iobuf
, sizeof(iobuf
));
188 // Close outgoing half-connection so they get EOF, but
189 // leave incoming alone so we can see response.
191 FD_CLR(STDIN_FILENO
, &readfds
);
195 xwrite(ofd
, iobuf
, nread
);
196 if (delay
> 0) sleep(delay
);