29 |
int sfd = sfd; /* for gcc */ |
int sfd = sfd; /* for gcc */ |
30 |
int cfd = 0; |
int cfd = 0; |
31 |
unsigned lport = 0; |
unsigned lport = 0; |
32 |
SKIP_NC_SERVER(const) unsigned do_listen = 0; |
IF_NOT_NC_SERVER(const) unsigned do_listen = 0; |
33 |
SKIP_NC_EXTRA (const) unsigned wsecs = 0; |
IF_NOT_NC_EXTRA (const) unsigned wsecs = 0; |
34 |
SKIP_NC_EXTRA (const) unsigned delay = 0; |
IF_NOT_NC_EXTRA (const) unsigned delay = 0; |
35 |
SKIP_NC_EXTRA (const int execparam = 0;) |
IF_NOT_NC_EXTRA (const int execparam = 0;) |
36 |
USE_NC_EXTRA (char **execparam = NULL;) |
IF_NC_EXTRA (char **execparam = NULL;) |
|
len_and_sockaddr *lsa; |
|
37 |
fd_set readfds, testfds; |
fd_set readfds, testfds; |
38 |
int opt; /* must be signed (getopt returns -1) */ |
int opt; /* must be signed (getopt returns -1) */ |
39 |
|
|
41 |
/* getopt32 is _almost_ usable: |
/* getopt32 is _almost_ usable: |
42 |
** it cannot handle "... -e prog -prog-opt" */ |
** it cannot handle "... -e prog -prog-opt" */ |
43 |
while ((opt = getopt(argc, argv, |
while ((opt = getopt(argc, argv, |
44 |
"" USE_NC_SERVER("lp:") USE_NC_EXTRA("w:i:f:e:") )) > 0 |
"" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0 |
45 |
) { |
) { |
46 |
if (ENABLE_NC_SERVER && opt=='l') |
if (ENABLE_NC_SERVER && opt == 'l') |
47 |
USE_NC_SERVER(do_listen++); |
IF_NC_SERVER(do_listen++); |
48 |
else if (ENABLE_NC_SERVER && opt=='p') |
else if (ENABLE_NC_SERVER && opt == 'p') |
49 |
USE_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0)); |
IF_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0)); |
50 |
else if (ENABLE_NC_EXTRA && opt=='w') |
else if (ENABLE_NC_EXTRA && opt == 'w') |
51 |
USE_NC_EXTRA( wsecs = xatou(optarg)); |
IF_NC_EXTRA( wsecs = xatou(optarg)); |
52 |
else if (ENABLE_NC_EXTRA && opt=='i') |
else if (ENABLE_NC_EXTRA && opt == 'i') |
53 |
USE_NC_EXTRA( delay = xatou(optarg)); |
IF_NC_EXTRA( delay = xatou(optarg)); |
54 |
else if (ENABLE_NC_EXTRA && opt=='f') |
else if (ENABLE_NC_EXTRA && opt == 'f') |
55 |
USE_NC_EXTRA( cfd = xopen(optarg, O_RDWR)); |
IF_NC_EXTRA( cfd = xopen(optarg, O_RDWR)); |
56 |
else if (ENABLE_NC_EXTRA && opt=='e' && optind <= argc) { |
else if (ENABLE_NC_EXTRA && opt == 'e' && optind <= argc) { |
57 |
/* We cannot just 'break'. We should let getopt finish. |
/* We cannot just 'break'. We should let getopt finish. |
58 |
** Or else we won't be able to find where |
** Or else we won't be able to find where |
59 |
** 'host' and 'port' params are |
** 'host' and 'port' params are |
60 |
** (think "nc -w 60 host port -e prog"). */ |
** (think "nc -w 60 host port -e prog"). */ |
61 |
USE_NC_EXTRA( |
IF_NC_EXTRA( |
62 |
char **p; |
char **p; |
63 |
// +2: one for progname (optarg) and one for NULL |
// +2: one for progname (optarg) and one for NULL |
64 |
execparam = xzalloc(sizeof(char*) * (argc - optind + 2)); |
execparam = xzalloc(sizeof(char*) * (argc - optind + 2)); |
79 |
argc -= optind; |
argc -= optind; |
80 |
// -l and -f don't mix |
// -l and -f don't mix |
81 |
if (do_listen && cfd) bb_show_usage(); |
if (do_listen && cfd) bb_show_usage(); |
82 |
// Listen or file modes need zero arguments, client mode needs 2 |
// File mode needs need zero arguments, listen mode needs zero or one, |
83 |
if (do_listen || cfd) { |
// client mode needs one or two |
84 |
|
if (cfd) { |
85 |
if (argc) bb_show_usage(); |
if (argc) bb_show_usage(); |
86 |
|
} else if (do_listen) { |
87 |
|
if (argc > 1) bb_show_usage(); |
88 |
} else { |
} else { |
89 |
if (!argc || argc > 2) bb_show_usage(); |
if (!argc || argc > 2) bb_show_usage(); |
90 |
} |
} |
101 |
|
|
102 |
if (!cfd) { |
if (!cfd) { |
103 |
if (do_listen) { |
if (do_listen) { |
104 |
/* create_and_bind_stream_or_die(NULL, lport) |
sfd = create_and_bind_stream_or_die(argv[0], lport); |
|
* would've work wonderfully, but we need |
|
|
* to know lsa */ |
|
|
sfd = xsocket_stream(&lsa); |
|
|
if (lport) |
|
|
set_nport(lsa, htons(lport)); |
|
|
setsockopt_reuseaddr(sfd); |
|
|
xbind(sfd, &lsa->u.sa, lsa->len); |
|
105 |
xlisten(sfd, do_listen); /* can be > 1 */ |
xlisten(sfd, do_listen); /* can be > 1 */ |
106 |
|
#if 0 /* nc-1.10 does not do this (without -v) */ |
107 |
/* If we didn't specify a port number, |
/* If we didn't specify a port number, |
108 |
* query and print it after listen() */ |
* query and print it after listen() */ |
109 |
if (!lport) { |
if (!lport) { |
110 |
socklen_t addrlen = lsa->len; |
len_and_sockaddr lsa; |
111 |
getsockname(sfd, &lsa->u.sa, &addrlen); |
lsa.len = LSA_SIZEOF_SA; |
112 |
lport = get_nport(&lsa->u.sa); |
getsockname(sfd, &lsa.u.sa, &lsa.len); |
113 |
|
lport = get_nport(&lsa.u.sa); |
114 |
fdprintf(2, "%d\n", ntohs(lport)); |
fdprintf(2, "%d\n", ntohs(lport)); |
115 |
} |
} |
116 |
|
#endif |
117 |
close_on_exec_on(sfd); |
close_on_exec_on(sfd); |
118 |
accept_again: |
accept_again: |
119 |
cfd = accept(sfd, NULL, 0); |
cfd = accept(sfd, NULL, 0); |
129 |
|
|
130 |
if (wsecs) { |
if (wsecs) { |
131 |
alarm(0); |
alarm(0); |
132 |
/* Non-ignored siganls revert to SIG_DFL on exec anyway */ |
/* Non-ignored signals revert to SIG_DFL on exec anyway */ |
133 |
/*signal(SIGALRM, SIG_DFL);*/ |
/*signal(SIGALRM, SIG_DFL);*/ |
134 |
} |
} |
135 |
|
|
136 |
/* -e given? */ |
/* -e given? */ |
137 |
if (execparam) { |
if (execparam) { |
138 |
signal(SIGCHLD, SIG_IGN); |
pid_t pid; |
139 |
// With more than one -l, repeatedly act as server. |
/* With more than one -l, repeatedly act as server */ |
140 |
if (do_listen > 1 && vfork()) { |
if (do_listen > 1 && (pid = vfork()) != 0) { |
141 |
/* parent */ |
/* parent or error */ |
142 |
// This is a bit weird as cleanup goes, since we wind up with no |
if (pid < 0) |
143 |
// stdin/stdout/stderr. But it's small and shouldn't hurt anything. |
bb_perror_msg_and_die("vfork"); |
144 |
// We check for cfd == 0 above. |
/* prevent zombies */ |
145 |
logmode = LOGMODE_NONE; |
signal(SIGCHLD, SIG_IGN); |
146 |
close(0); |
close(cfd); |
|
close(1); |
|
|
close(2); |
|
147 |
goto accept_again; |
goto accept_again; |
148 |
} |
} |
149 |
/* child (or main thread if no multiple -l) */ |
/* child, or main thread if only one -l */ |
150 |
xmove_fd(cfd, 0); |
xmove_fd(cfd, 0); |
151 |
xdup2(0, 1); |
xdup2(0, 1); |
152 |
xdup2(0, 2); |
xdup2(0, 2); |
153 |
USE_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) |
IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) |
154 |
/* Don't print stuff or it will go over the wire.... */ |
/* Don't print stuff or it will go over the wire... */ |
155 |
_exit(127); |
_exit(127); |
156 |
} |
} |
157 |
|
|
158 |
// Select loop copying stdin to cfd, and cfd to stdout. |
/* Select loop copying stdin to cfd, and cfd to stdout */ |
159 |
|
|
160 |
FD_ZERO(&readfds); |
FD_ZERO(&readfds); |
161 |
FD_SET(cfd, &readfds); |
FD_SET(cfd, &readfds); |
168 |
|
|
169 |
testfds = readfds; |
testfds = readfds; |
170 |
|
|
171 |
if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0) |
if (select(cfd + 1, &testfds, NULL, NULL, NULL) < 0) |
172 |
bb_perror_msg_and_die("select"); |
bb_perror_msg_and_die("select"); |
173 |
|
|
174 |
#define iobuf bb_common_bufsiz1 |
#define iobuf bb_common_bufsiz1 |
175 |
for (fd = 0; fd < FD_SETSIZE; fd++) { |
fd = STDIN_FILENO; |
176 |
|
while (1) { |
177 |
if (FD_ISSET(fd, &testfds)) { |
if (FD_ISSET(fd, &testfds)) { |
178 |
nread = safe_read(fd, iobuf, sizeof(iobuf)); |
nread = safe_read(fd, iobuf, sizeof(iobuf)); |
179 |
if (fd == cfd) { |
if (fd == cfd) { |
181 |
exit(EXIT_SUCCESS); |
exit(EXIT_SUCCESS); |
182 |
ofd = STDOUT_FILENO; |
ofd = STDOUT_FILENO; |
183 |
} else { |
} else { |
184 |
if (nread<1) { |
if (nread < 1) { |
185 |
// Close outgoing half-connection so they get EOF, but |
/* Close outgoing half-connection so they get EOF, |
186 |
// leave incoming alone so we can see response. |
* but leave incoming alone so we can see response */ |
187 |
shutdown(cfd, 1); |
shutdown(cfd, 1); |
188 |
FD_CLR(STDIN_FILENO, &readfds); |
FD_CLR(STDIN_FILENO, &readfds); |
189 |
} |
} |
190 |
ofd = cfd; |
ofd = cfd; |
191 |
} |
} |
192 |
xwrite(ofd, iobuf, nread); |
xwrite(ofd, iobuf, nread); |
193 |
if (delay > 0) sleep(delay); |
if (delay > 0) |
194 |
|
sleep(delay); |
195 |
} |
} |
196 |
|
if (fd == cfd) |
197 |
|
break; |
198 |
|
fd = cfd; |
199 |
} |
} |
200 |
} |
} |
201 |
} |
} |