diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-06 10:41:05 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-06 10:41:05 +0000 |
commit | 19507f0869571f29cfd0a4aed3d7c07db038b129 (patch) | |
tree | 55db16b423e06c9e2753c47e4a1af0d56dd14ca4 /networking | |
parent | 5a30d59c3d24c04fb93b8bdfb95f94b124203aa1 (diff) | |
download | busybox-w32-19507f0869571f29cfd0a4aed3d7c07db038b129.tar.gz busybox-w32-19507f0869571f29cfd0a4aed3d7c07db038b129.tar.bz2 busybox-w32-19507f0869571f29cfd0a4aed3d7c07db038b129.zip |
nc: code shrinkage, bugfixes. -50 bytes code size
Diffstat (limited to 'networking')
-rw-r--r-- | networking/nc_bloaty.c | 248 |
1 files changed, 142 insertions, 106 deletions
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index ca5dd1bf7..173f5a867 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c | |||
@@ -39,22 +39,41 @@ | |||
39 | * - Prog in '-e prog' can have prog's parameters and options. | 39 | * - Prog in '-e prog' can have prog's parameters and options. |
40 | * Because of this -e option must be last. | 40 | * Because of this -e option must be last. |
41 | * - nc doesn't redirect stderr to the network socket for the -e prog. | 41 | * - nc doesn't redirect stderr to the network socket for the -e prog. |
42 | * - numeric addresses are printed in (), not [] (IPv6 looks better), | ||
43 | * port numbers are inside (): (1.2.3.4:5678) | ||
44 | * - network read errors are reported on verbose levels > 1 | ||
45 | * (nc 1.10 treats them as EOF) | ||
46 | * - TCP connects from wrong ip/ports (if peer ip:port is specified | ||
47 | * on the command line, but accept() says that it came from different addr) | ||
48 | * are closed, but nc doesn't exit - continues to listen/accept. | ||
42 | */ | 49 | */ |
43 | 50 | ||
44 | /* done in nc.c: #include "busybox.h" */ | 51 | /* done in nc.c: #include "busybox.h" */ |
45 | 52 | ||
46 | #define SLEAZE_PORT 31337 /* for UDP-scan RTT trick, change if ya want */ | 53 | enum { |
47 | #define BIGSIZ 8192 /* big buffers */ | 54 | SLEAZE_PORT = 31337, /* for UDP-scan RTT trick, change if ya want */ |
55 | BIGSIZ = 8192, /* big buffers */ | ||
56 | |||
57 | netfd = 3, | ||
58 | ofd = 4, | ||
59 | }; | ||
48 | 60 | ||
49 | struct globals { | 61 | struct globals { |
50 | int netfd; | 62 | /* global cmd flags: */ |
51 | int ofd; /* hexdump output fd */ | 63 | unsigned o_verbose; |
64 | unsigned o_wait; | ||
65 | #if ENABLE_NC_EXTRA | ||
66 | unsigned o_interval; | ||
67 | #endif | ||
68 | |||
69 | /*int netfd;*/ | ||
70 | /*int ofd;*/ /* hexdump output fd */ | ||
52 | #if ENABLE_LFS | 71 | #if ENABLE_LFS |
53 | #define SENT_N_RECV_M "sent %llu, rcvd %llu\n" | 72 | #define SENT_N_RECV_M "sent %llu, rcvd %llu\n" |
54 | unsigned long long wrote_out; /* total stdout bytes */ | 73 | unsigned long long wrote_out; /* total stdout bytes */ |
55 | unsigned long long wrote_net; /* total net bytes */ | 74 | unsigned long long wrote_net; /* total net bytes */ |
56 | #else | 75 | #else |
57 | #define SENT_N_RECV_M "sent %u, rcvd %u" | 76 | #define SENT_N_RECV_M "sent %u, rcvd %u\n" |
58 | unsigned wrote_out; /* total stdout bytes */ | 77 | unsigned wrote_out; /* total stdout bytes */ |
59 | unsigned wrote_net; /* total net bytes */ | 78 | unsigned wrote_net; /* total net bytes */ |
60 | #endif | 79 | #endif |
@@ -68,15 +87,7 @@ struct globals { | |||
68 | /* remend is set after connect/recv/accept to the actual ip:port of peer */ | 87 | /* remend is set after connect/recv/accept to the actual ip:port of peer */ |
69 | struct len_and_sockaddr remend; | 88 | struct len_and_sockaddr remend; |
70 | 89 | ||
71 | /* global cmd flags: */ | ||
72 | unsigned o_verbose; | ||
73 | unsigned o_wait; | ||
74 | #if ENABLE_NC_EXTRA | ||
75 | unsigned o_interval; | ||
76 | #endif | ||
77 | |||
78 | jmp_buf jbuf; /* timer crud */ | 90 | jmp_buf jbuf; /* timer crud */ |
79 | unsigned char *stage; /* hexdump line buffer */ | ||
80 | 91 | ||
81 | /* will malloc up the following globals: */ | 92 | /* will malloc up the following globals: */ |
82 | fd_set ding1; /* for select loop */ | 93 | fd_set ding1; /* for select loop */ |
@@ -87,15 +98,12 @@ struct globals { | |||
87 | 98 | ||
88 | #define G (*ptr_to_globals) | 99 | #define G (*ptr_to_globals) |
89 | 100 | ||
90 | #define netfd (G.netfd ) | ||
91 | #define ofd (G.ofd ) | ||
92 | #define wrote_out (G.wrote_out ) | 101 | #define wrote_out (G.wrote_out ) |
93 | #define wrote_net (G.wrote_net ) | 102 | #define wrote_net (G.wrote_net ) |
94 | #define ouraddr (G.ouraddr ) | 103 | #define ouraddr (G.ouraddr ) |
95 | #define themaddr (G.themaddr ) | 104 | #define themaddr (G.themaddr ) |
96 | #define remend (G.remend ) | 105 | #define remend (G.remend ) |
97 | #define jbuf (G.jbuf ) | 106 | #define jbuf (G.jbuf ) |
98 | #define stage (G.stage ) | ||
99 | #define ding1 (G.ding1 ) | 107 | #define ding1 (G.ding1 ) |
100 | #define ding2 (G.ding2 ) | 108 | #define ding2 (G.ding2 ) |
101 | #define bigbuf_in (G.bigbuf_in ) | 109 | #define bigbuf_in (G.bigbuf_in ) |
@@ -125,23 +133,25 @@ enum { | |||
125 | 133 | ||
126 | #define o_nflag (option_mask32 & OPT_n) | 134 | #define o_nflag (option_mask32 & OPT_n) |
127 | #define o_udpmode (option_mask32 & OPT_u) | 135 | #define o_udpmode (option_mask32 & OPT_u) |
128 | #if ENABLE_NC_EXTRA | 136 | #if ENABLE_NC_SERVER |
129 | #define o_wfile (option_mask32 & OPT_o) | ||
130 | #define o_listen (option_mask32 & OPT_l) | 137 | #define o_listen (option_mask32 & OPT_l) |
131 | #define o_zero (option_mask32 & OPT_z) | ||
132 | #else | 138 | #else |
133 | #define o_wfile 0 | ||
134 | #define o_listen 0 | 139 | #define o_listen 0 |
140 | #endif | ||
141 | #if ENABLE_NC_EXTRA | ||
142 | #define o_ofile (option_mask32 & OPT_o) | ||
143 | #define o_zero (option_mask32 & OPT_z) | ||
144 | #else | ||
145 | #define o_ofile 0 | ||
135 | #define o_zero 0 | 146 | #define o_zero 0 |
136 | #endif | 147 | #endif |
137 | 148 | ||
138 | /* Debug macro: squirt whatever message and sleep a bit so we can see it go | 149 | /* Debug: squirt whatever message and sleep a bit so we can see it go by. */ |
139 | by. need to call like Debug((stuff)) [with no ; ] so macro args match! | 150 | /* Beware: writes to stdOUT... */ |
140 | Beware: writes to stdOUT... */ | ||
141 | #if 0 | 151 | #if 0 |
142 | #define Debug(x) printf x; printf("\n"); fflush(stdout); sleep(1); | 152 | #define Debug(...) do { printf(__VA_ARGS__); printf("\n"); fflush(stdout); sleep(1); } while(0) |
143 | #else | 153 | #else |
144 | #define Debug(x) /* nil... */ | 154 | #define Debug(...) do { } while(0) |
145 | #endif | 155 | #endif |
146 | 156 | ||
147 | #define holler_error(...) do { if (o_verbose) bb_error_msg(__VA_ARGS__); } while(0) | 157 | #define holler_error(...) do { if (o_verbose) bb_error_msg(__VA_ARGS__); } while(0) |
@@ -196,12 +206,12 @@ static unsigned findline(char *buf, unsigned siz) | |||
196 | if (*p == '\n') { | 206 | if (*p == '\n') { |
197 | x = (int) (p - buf); | 207 | x = (int) (p - buf); |
198 | x++; /* 'sokay if it points just past the end! */ | 208 | x++; /* 'sokay if it points just past the end! */ |
199 | Debug(("findline returning %d", x)) | 209 | Debug("findline returning %d", x); |
200 | return x; | 210 | return x; |
201 | } | 211 | } |
202 | p++; | 212 | p++; |
203 | } /* for */ | 213 | } /* for */ |
204 | Debug(("findline returning whole thing: %d", siz)) | 214 | Debug("findline returning whole thing: %d", siz); |
205 | return siz; | 215 | return siz; |
206 | } /* findline */ | 216 | } /* findline */ |
207 | 217 | ||
@@ -252,7 +262,6 @@ static int connect_w_timeout(int fd) | |||
252 | static void dolisten(void) | 262 | static void dolisten(void) |
253 | { | 263 | { |
254 | int rr; | 264 | int rr; |
255 | const char *errmsg = errmsg; /* gcc */ | ||
256 | 265 | ||
257 | if (!o_udpmode) | 266 | if (!o_udpmode) |
258 | xlisten(netfd, 1); /* TCP: gotta listen() before we can get */ | 267 | xlisten(netfd, 1); /* TCP: gotta listen() before we can get */ |
@@ -272,7 +281,7 @@ static void dolisten(void) | |||
272 | if (rr < 0) | 281 | if (rr < 0) |
273 | bb_perror_msg_and_die("getsockname after bind"); | 282 | bb_perror_msg_and_die("getsockname after bind"); |
274 | addr = xmalloc_sockaddr2dotted(&ouraddr->sa, ouraddr->len); | 283 | addr = xmalloc_sockaddr2dotted(&ouraddr->sa, ouraddr->len); |
275 | fprintf(stderr, "listening on [%s] ...\n", addr); | 284 | fprintf(stderr, "listening on %s ...\n", addr); |
276 | free(addr); | 285 | free(addr); |
277 | } | 286 | } |
278 | 287 | ||
@@ -296,48 +305,67 @@ static void dolisten(void) | |||
296 | Let's try to remember what the "U" is *really* for, eh? */ | 305 | Let's try to remember what the "U" is *really* for, eh? */ |
297 | 306 | ||
298 | /* If peer address is specified, connect to it */ | 307 | /* If peer address is specified, connect to it */ |
308 | remend.len = LSA_SIZEOF_SA; | ||
299 | if (themaddr) { | 309 | if (themaddr) { |
300 | remend = *themaddr; | 310 | remend = *themaddr; |
301 | xconnect(netfd, &themaddr->sa, themaddr->len); | 311 | xconnect(netfd, &themaddr->sa, themaddr->len); |
302 | rr = 0; | ||
303 | } else { /* peek first packet and remember peer addr */ | ||
304 | arm(o_wait); /* might as well timeout this, too */ | ||
305 | if (setjmp(jbuf) == 0) { /* do timeout for initial connect */ | ||
306 | /* (*ouraddr) is prefilled with "default" address */ | ||
307 | /* and here we block... */ | ||
308 | rr = recv_from_to(netfd, NULL, 0, MSG_PEEK, /*was bigbuf_net, BIGSIZ*/ | ||
309 | &remend.sa, &ouraddr->sa, ouraddr->len); | ||
310 | if (rr < 0) | ||
311 | bb_perror_msg_and_die("recvfrom"); | ||
312 | } else | ||
313 | bb_error_msg_and_die("timeout"); | ||
314 | unarm(); | ||
315 | rr = connect(netfd, &remend.sa, ouraddr->len); | ||
316 | errmsg = "connect"; | ||
317 | } | 312 | } |
313 | /* peek first packet and remember peer addr */ | ||
314 | arm(o_wait); /* might as well timeout this, too */ | ||
315 | if (setjmp(jbuf) == 0) { /* do timeout for initial connect */ | ||
316 | /* (*ouraddr) is prefilled with "default" address */ | ||
317 | /* and here we block... */ | ||
318 | rr = recv_from_to(netfd, NULL, 0, MSG_PEEK, /*was bigbuf_net, BIGSIZ*/ | ||
319 | &remend.sa, &ouraddr->sa, ouraddr->len); | ||
320 | if (rr < 0) | ||
321 | bb_perror_msg_and_die("recvfrom"); | ||
322 | } else | ||
323 | bb_error_msg_and_die("timeout"); | ||
324 | unarm(); | ||
325 | /* Now we learned *to which IP* peer has connected, and we want to anchor | ||
326 | our socket on it, so that our outbound packets will have correct local IP. | ||
327 | Unfortunately, bind() on already bound socket will fail now (EINVAL): | ||
328 | xbind(netfd, &ouraddr->sa, ouraddr->len); | ||
329 | Need to read the packet, save data, close this socket and | ||
330 | create new one, and bind() it. TODO */ | ||
331 | if (!themaddr) | ||
332 | xconnect(netfd, &remend.sa, ouraddr->len); | ||
318 | } else { | 333 | } else { |
319 | /* TCP */ | 334 | /* TCP */ |
320 | arm(o_wait); /* wrap this in a timer, too; 0 = forever */ | 335 | arm(o_wait); /* wrap this in a timer, too; 0 = forever */ |
321 | if (setjmp(jbuf) == 0) { | 336 | if (setjmp(jbuf) == 0) { |
337 | again: | ||
322 | remend.len = LSA_SIZEOF_SA; | 338 | remend.len = LSA_SIZEOF_SA; |
323 | rr = accept(netfd, &remend.sa, &remend.len); | 339 | rr = accept(netfd, &remend.sa, &remend.len); |
340 | if (rr < 0) | ||
341 | bb_perror_msg_and_die("accept"); | ||
342 | if (themaddr && memcmp(&remend.sa, &themaddr->sa, remend.len) != 0) { | ||
343 | /* nc 1.10 bails out instead, and its error message | ||
344 | * is not suppressed by o_verbose */ | ||
345 | if (o_verbose) { | ||
346 | char *remaddr = xmalloc_sockaddr2dotted(&remend.sa, remend.len); | ||
347 | bb_error_msg("connect from wrong ip/port %s ignored", remaddr); | ||
348 | free(remaddr); | ||
349 | } | ||
350 | close(rr); | ||
351 | goto again; | ||
352 | } | ||
353 | |||
324 | } else | 354 | } else |
325 | bb_error_msg_and_die("timeout"); | 355 | bb_error_msg_and_die("timeout"); |
326 | unarm(); | 356 | unarm(); |
327 | errmsg = "accept"; | 357 | xmove_fd(rr, netfd); /* dump the old socket, here's our new one */ |
328 | if (rr >= 0) { | 358 | /* find out what address the connection was *to* on our end, in case we're |
329 | close(netfd); /* dump the old socket */ | 359 | doing a listen-on-any on a multihomed machine. This allows one to |
330 | netfd = rr; /* here's our new one */ | 360 | offer different services via different alias addresses, such as the |
331 | /* find out what address the connection was *to* on our end, in case we're | 361 | "virtual web site" hack. */ |
332 | doing a listen-on-any on a multihomed machine. This allows one to | 362 | rr = getsockname(netfd, &ouraddr->sa, &ouraddr->len); |
333 | offer different services via different alias addresses, such as the | 363 | if (rr < 0) |
334 | "virtual web site" hack. */ | 364 | bb_perror_msg_and_die("getsockname after accept"); |
335 | rr = getsockname(netfd, &ouraddr->sa, &ouraddr->len); | ||
336 | errmsg = "getsockname after accept"; | ||
337 | } | ||
338 | } | 365 | } |
339 | if (rr < 0) | 366 | |
340 | bb_perror_msg_and_die(errmsg); | 367 | if (o_verbose) { |
368 | char *lcladdr, *remaddr, *remhostname; | ||
341 | 369 | ||
342 | #if ENABLE_NC_EXTRA && defined(IP_OPTIONS) | 370 | #if ENABLE_NC_EXTRA && defined(IP_OPTIONS) |
343 | /* If we can, look for any IP options. Useful for testing the receiving end of | 371 | /* If we can, look for any IP options. Useful for testing the receiving end of |
@@ -345,9 +373,9 @@ static void dolisten(void) | |||
345 | the connect message, to ensure that the connect msg is uniformly the LAST | 373 | the connect message, to ensure that the connect msg is uniformly the LAST |
346 | thing to emerge after all the intervening crud. Doesn't work for UDP on | 374 | thing to emerge after all the intervening crud. Doesn't work for UDP on |
347 | any machines I've tested, but feel free to surprise me. */ | 375 | any machines I've tested, but feel free to surprise me. */ |
348 | if (o_verbose) { | ||
349 | char optbuf[40]; | 376 | char optbuf[40]; |
350 | int x = sizeof(optbuf); | 377 | int x = sizeof(optbuf); |
378 | |||
351 | rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x); | 379 | rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x); |
352 | if (rr < 0) | 380 | if (rr < 0) |
353 | bb_perror_msg("getsockopt failed"); | 381 | bb_perror_msg("getsockopt failed"); |
@@ -356,7 +384,6 @@ static void dolisten(void) | |||
356 | bigbuf_net[2*x] = '\0'; | 384 | bigbuf_net[2*x] = '\0'; |
357 | fprintf(stderr, "IP options: %s\n", bigbuf_net); | 385 | fprintf(stderr, "IP options: %s\n", bigbuf_net); |
358 | } | 386 | } |
359 | } | ||
360 | #endif | 387 | #endif |
361 | 388 | ||
362 | /* now check out who it is. We don't care about mismatched DNS names here, | 389 | /* now check out who it is. We don't care about mismatched DNS names here, |
@@ -369,11 +396,10 @@ static void dolisten(void) | |||
369 | accept the connection and then reject undesireable ones by closing. | 396 | accept the connection and then reject undesireable ones by closing. |
370 | In other words, we need a TCP MSG_PEEK. */ | 397 | In other words, we need a TCP MSG_PEEK. */ |
371 | /* bbox: removed most of it */ | 398 | /* bbox: removed most of it */ |
372 | if (o_verbose) { | 399 | lcladdr = xmalloc_sockaddr2dotted(&ouraddr->sa, ouraddr->len); |
373 | char *lcladdr = xmalloc_sockaddr2dotted(&ouraddr->sa, ouraddr->len); | 400 | remaddr = xmalloc_sockaddr2dotted(&remend.sa, remend.len); |
374 | char *remaddr = xmalloc_sockaddr2dotted(&remend.sa, remend.len); | 401 | remhostname = o_nflag ? remaddr : xmalloc_sockaddr2host(&remend.sa, remend.len); |
375 | char *remhostname = o_nflag ? remaddr : xmalloc_sockaddr2host(&remend.sa, remend.len); | 402 | fprintf(stderr, "connect to %s from %s (%s)\n", |
376 | fprintf(stderr, "connect to [%s] from %s [%s]\n", | ||
377 | lcladdr, remhostname, remaddr); | 403 | lcladdr, remhostname, remaddr); |
378 | free(lcladdr); | 404 | free(lcladdr); |
379 | free(remaddr); | 405 | free(remaddr); |
@@ -392,6 +418,7 @@ static void dolisten(void) | |||
392 | Use the time delay between writes if given, otherwise use the "tcp ping" | 418 | Use the time delay between writes if given, otherwise use the "tcp ping" |
393 | trick for getting the RTT. [I got that idea from pluvius, and warped it.] | 419 | trick for getting the RTT. [I got that idea from pluvius, and warped it.] |
394 | Return either the original fd, or clean up and return -1. */ | 420 | Return either the original fd, or clean up and return -1. */ |
421 | #if ENABLE_NC_EXTRA | ||
395 | static int udptest(void) | 422 | static int udptest(void) |
396 | { | 423 | { |
397 | int rr; | 424 | int rr; |
@@ -401,7 +428,7 @@ static int udptest(void) | |||
401 | bb_perror_msg("udptest first write"); | 428 | bb_perror_msg("udptest first write"); |
402 | 429 | ||
403 | if (o_wait) | 430 | if (o_wait) |
404 | sleep(o_wait); | 431 | sleep(o_wait); // can be interrupted! while (t) nanosleep(&t)? |
405 | else { | 432 | else { |
406 | /* use the tcp-ping trick: try connecting to a normally refused port, which | 433 | /* use the tcp-ping trick: try connecting to a normally refused port, which |
407 | causes us to block for the time that SYN gets there and RST gets back. | 434 | causes us to block for the time that SYN gets there and RST gets back. |
@@ -412,14 +439,17 @@ static int udptest(void) | |||
412 | rr = xsocket(ouraddr->sa.sa_family, SOCK_STREAM, 0); | 439 | rr = xsocket(ouraddr->sa.sa_family, SOCK_STREAM, 0); |
413 | set_nport(themaddr, htons(SLEAZE_PORT)); | 440 | set_nport(themaddr, htons(SLEAZE_PORT)); |
414 | connect_w_timeout(rr); | 441 | connect_w_timeout(rr); |
415 | //need to restore port? | 442 | /* don't need to restore themaddr's port, it's not used anymore */ |
416 | close(rr); | 443 | close(rr); |
417 | o_wait = 0; /* reset it */ | 444 | o_wait = 0; /* restore */ |
418 | } | 445 | } |
419 | 446 | ||
420 | rr = write(netfd, bigbuf_in, 1); | 447 | rr = write(netfd, bigbuf_in, 1); |
421 | return (rr != 1); /* if rr == 1, return 0 (success) */ | 448 | return (rr != 1); /* if rr == 1, return 0 (success) */ |
422 | } | 449 | } |
450 | #else | ||
451 | int udptest(void); | ||
452 | #endif | ||
423 | 453 | ||
424 | /* oprint: | 454 | /* oprint: |
425 | Hexdump bytes shoveled either way to a running logfile, in the format: | 455 | Hexdump bytes shoveled either way to a running logfile, in the format: |
@@ -431,31 +461,25 @@ static int udptest(void) | |||
431 | a partial line, so be it; we *want* that lockstep indication of who sent | 461 | a partial line, so be it; we *want* that lockstep indication of who sent |
432 | what when. Adapted from dgaudet's original example -- but must be ripping | 462 | what when. Adapted from dgaudet's original example -- but must be ripping |
433 | *fast*, since we don't want to be too disk-bound... */ | 463 | *fast*, since we don't want to be too disk-bound... */ |
434 | static void oprint(int which, char *buf, int n) | 464 | #if ENABLE_NC_EXTRA |
465 | static void oprint(int direction, unsigned char *p, int bc) | ||
435 | { | 466 | { |
436 | int bc; /* in buffer count */ | ||
437 | int obc; /* current "global" offset */ | 467 | int obc; /* current "global" offset */ |
438 | int soc; /* stage write count */ | 468 | int soc; /* stage write count */ |
439 | unsigned char *p; /* main buf ptr; m.b. unsigned here */ | ||
440 | unsigned char *op; /* out hexdump ptr */ | 469 | unsigned char *op; /* out hexdump ptr */ |
441 | unsigned char *a; /* out asc-dump ptr */ | 470 | unsigned char *a; /* out asc-dump ptr */ |
442 | int x; | 471 | int x; |
472 | unsigned char stage[100]; | ||
443 | 473 | ||
444 | if (n == 0) | 474 | if (bc == 0) |
445 | return; | 475 | return; |
446 | 476 | ||
447 | op = stage; | 477 | op = stage; |
448 | if (which) { | 478 | obc = wrote_net; /* use the globals! */ |
449 | *op = '<'; | 479 | if (direction == '<') |
450 | obc = wrote_out; /* use the globals! */ | 480 | obc = wrote_out; |
451 | } else { | 481 | *op++ = direction; |
452 | *op = '>'; | ||
453 | obc = wrote_net; | ||
454 | } | ||
455 | op++; /* preload "direction" */ | ||
456 | *op = ' '; | 482 | *op = ' '; |
457 | p = (unsigned char *) buf; | ||
458 | bc = n; | ||
459 | stage[59] = '#'; /* preload separator */ | 483 | stage[59] = '#'; /* preload separator */ |
460 | stage[60] = ' '; | 484 | stage[60] = ' '; |
461 | 485 | ||
@@ -498,6 +522,9 @@ static void oprint(int which, char *buf, int n) | |||
498 | xwrite(ofd, stage, soc); | 522 | xwrite(ofd, stage, soc); |
499 | } /* while bc */ | 523 | } /* while bc */ |
500 | } | 524 | } |
525 | #else | ||
526 | void oprint(int direction, unsigned char *p, int bc); | ||
527 | #endif | ||
501 | 528 | ||
502 | /* readwrite: | 529 | /* readwrite: |
503 | handle stdin/stdout/network I/O. Bwahaha!! -- the select loop from hell. | 530 | handle stdin/stdout/network I/O. Bwahaha!! -- the select loop from hell. |
@@ -537,9 +564,10 @@ static int readwrite(void) | |||
537 | struct timeval tmp_timer; | 564 | struct timeval tmp_timer; |
538 | tmp_timer.tv_sec = o_wait; | 565 | tmp_timer.tv_sec = o_wait; |
539 | tmp_timer.tv_usec = 0; | 566 | tmp_timer.tv_usec = 0; |
540 | rr = select(16, &ding2, NULL, NULL, &tmp_timer); | 567 | /* highest possible fd is netfd (3) */ |
568 | rr = select(netfd+1, &ding2, NULL, NULL, &tmp_timer); | ||
541 | } else | 569 | } else |
542 | rr = select(16, &ding2, NULL, NULL, NULL); | 570 | rr = select(netfd+1, &ding2, NULL, NULL, NULL); |
543 | if (rr < 0 && errno != EINTR) { /* might have gotten ^Zed, etc */ | 571 | if (rr < 0 && errno != EINTR) { /* might have gotten ^Zed, etc */ |
544 | holler_perror("select"); | 572 | holler_perror("select"); |
545 | close(netfd); | 573 | close(netfd); |
@@ -564,13 +592,17 @@ static int readwrite(void) | |||
564 | if (FD_ISSET(netfd, &ding2)) { /* net: ding! */ | 592 | if (FD_ISSET(netfd, &ding2)) { /* net: ding! */ |
565 | rr = read(netfd, bigbuf_net, BIGSIZ); | 593 | rr = read(netfd, bigbuf_net, BIGSIZ); |
566 | if (rr <= 0) { | 594 | if (rr <= 0) { |
595 | if (rr < 0 && o_verbose > 1) { | ||
596 | /* nc 1.10 doesn't do this */ | ||
597 | bb_perror_msg("net read"); | ||
598 | } | ||
567 | FD_CLR(netfd, &ding1); /* net closed, we'll finish up... */ | 599 | FD_CLR(netfd, &ding1); /* net closed, we'll finish up... */ |
568 | rzleft = 0; /* can't write anymore: broken pipe */ | 600 | rzleft = 0; /* can't write anymore: broken pipe */ |
569 | } else { | 601 | } else { |
570 | rnleft = rr; | 602 | rnleft = rr; |
571 | np = bigbuf_net; | 603 | np = bigbuf_net; |
572 | } | 604 | } |
573 | Debug(("got %d from the net, errno %d", rr, errno)) | 605 | Debug("got %d from the net, errno %d", rr, errno); |
574 | } /* net:ding */ | 606 | } /* net:ding */ |
575 | 607 | ||
576 | /* if we're in "slowly" mode there's probably still stuff in the stdin | 608 | /* if we're in "slowly" mode there's probably still stuff in the stdin |
@@ -609,13 +641,13 @@ Debug(("got %d from the net, errno %d", rr, errno)) | |||
609 | if (rnleft) { | 641 | if (rnleft) { |
610 | rr = write(1, np, rnleft); | 642 | rr = write(1, np, rnleft); |
611 | if (rr > 0) { | 643 | if (rr > 0) { |
612 | if (o_wfile) | 644 | if (o_ofile) |
613 | oprint(1, np, rr); /* log the stdout */ | 645 | oprint('<', np, rr); /* log the stdout */ |
614 | np += rr; /* fix up ptrs and whatnot */ | 646 | np += rr; /* fix up ptrs and whatnot */ |
615 | rnleft -= rr; /* will get sanity-checked above */ | 647 | rnleft -= rr; /* will get sanity-checked above */ |
616 | wrote_out += rr; /* global count */ | 648 | wrote_out += rr; /* global count */ |
617 | } | 649 | } |
618 | Debug(("wrote %d to stdout, errno %d", rr, errno)) | 650 | Debug("wrote %d to stdout, errno %d", rr, errno); |
619 | } /* rnleft */ | 651 | } /* rnleft */ |
620 | if (rzleft) { | 652 | if (rzleft) { |
621 | if (o_interval) /* in "slowly" mode ?? */ | 653 | if (o_interval) /* in "slowly" mode ?? */ |
@@ -624,13 +656,13 @@ Debug(("wrote %d to stdout, errno %d", rr, errno)) | |||
624 | rr = rzleft; | 656 | rr = rzleft; |
625 | rr = write(netfd, zp, rr); /* one line, or the whole buffer */ | 657 | rr = write(netfd, zp, rr); /* one line, or the whole buffer */ |
626 | if (rr > 0) { | 658 | if (rr > 0) { |
627 | if (o_wfile) | 659 | if (o_ofile) |
628 | oprint(0, zp, rr); /* log what got sent */ | 660 | oprint('>', zp, rr); /* log what got sent */ |
629 | zp += rr; | 661 | zp += rr; |
630 | rzleft -= rr; | 662 | rzleft -= rr; |
631 | wrote_net += rr; /* global count */ | 663 | wrote_net += rr; /* global count */ |
632 | } | 664 | } |
633 | Debug(("wrote %d to net, errno %d", rr, errno)) | 665 | Debug("wrote %d to net, errno %d", rr, errno); |
634 | } /* rzleft */ | 666 | } /* rzleft */ |
635 | if (o_interval) { /* cycle between slow lines, or ... */ | 667 | if (o_interval) { /* cycle between slow lines, or ... */ |
636 | sleep(o_interval); | 668 | sleep(o_interval); |
@@ -657,7 +689,7 @@ int nc_main(int argc, char **argv); | |||
657 | int nc_main(int argc, char **argv) | 689 | int nc_main(int argc, char **argv) |
658 | { | 690 | { |
659 | char *str_p, *str_s, *str_w; | 691 | char *str_p, *str_s, *str_w; |
660 | USE_NC_EXTRA(char *str_i;) | 692 | USE_NC_EXTRA(char *str_i, *str_o;) |
661 | char *themdotted = themdotted; /* gcc */ | 693 | char *themdotted = themdotted; /* gcc */ |
662 | char **proggie; | 694 | char **proggie; |
663 | int x; | 695 | int x; |
@@ -694,7 +726,7 @@ int nc_main(int argc, char **argv) | |||
694 | getopt32(argc, argv, "hnp:s:uvw:" USE_NC_SERVER("l") | 726 | getopt32(argc, argv, "hnp:s:uvw:" USE_NC_SERVER("l") |
695 | USE_NC_EXTRA("i:o:z"), | 727 | USE_NC_EXTRA("i:o:z"), |
696 | &str_p, &str_s, &str_w | 728 | &str_p, &str_s, &str_w |
697 | USE_NC_EXTRA(, &str_i, &stage, &o_verbose)); | 729 | USE_NC_EXTRA(, &str_i, &str_o, &o_verbose)); |
698 | argv += optind; | 730 | argv += optind; |
699 | #if ENABLE_NC_EXTRA | 731 | #if ENABLE_NC_EXTRA |
700 | if (option_mask32 & OPT_i) /* line-interval time */ | 732 | if (option_mask32 & OPT_i) /* line-interval time */ |
@@ -716,18 +748,21 @@ int nc_main(int argc, char **argv) | |||
716 | } | 748 | } |
717 | //if (option_mask32 & OPT_z) /* little or no data xfer */ | 749 | //if (option_mask32 & OPT_z) /* little or no data xfer */ |
718 | 750 | ||
719 | bb_sanitize_stdio(); | 751 | /* We manage our fd's so that they are never 0,1,2 */ |
752 | /*bb_sanitize_stdio(); - not needed */ | ||
720 | 753 | ||
721 | /* create & bind network socket */ | 754 | /* create & bind network socket */ |
755 | x = (o_udpmode ? SOCK_DGRAM : SOCK_STREAM); | ||
722 | if (option_mask32 & OPT_s) { /* local address */ | 756 | if (option_mask32 & OPT_s) { /* local address */ |
723 | /* if o_port is still 0, then we will use random port */ | 757 | /* if o_lport is still 0, then we will use random port */ |
724 | ouraddr = xhost2sockaddr(str_s, o_lport); | 758 | ouraddr = xhost2sockaddr(str_s, o_lport); |
725 | netfd = xsocket(ouraddr->sa.sa_family, o_udpmode ? SOCK_DGRAM : SOCK_STREAM, 0); //// 0? | 759 | x = xsocket(ouraddr->sa.sa_family, x, 0); |
726 | } else { | 760 | } else { |
727 | netfd = xsocket_type(&ouraddr, o_udpmode ? SOCK_DGRAM : SOCK_STREAM); | 761 | x = xsocket_type(&ouraddr, x); |
728 | if (o_lport) | 762 | if (o_lport) |
729 | set_nport(ouraddr, htons(o_lport)); | 763 | set_nport(ouraddr, htons(o_lport)); |
730 | } | 764 | } |
765 | xmove_fd(x, netfd); | ||
731 | setsockopt_reuseaddr(netfd); | 766 | setsockopt_reuseaddr(netfd); |
732 | if (o_udpmode) | 767 | if (o_udpmode) |
733 | socket_want_pktinfo(netfd); | 768 | socket_want_pktinfo(netfd); |
@@ -737,21 +772,22 @@ int nc_main(int argc, char **argv) | |||
737 | setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf); | 772 | setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf); |
738 | #endif | 773 | #endif |
739 | 774 | ||
740 | if (o_udpmode) { /* apparently UDP can listen ON */ | 775 | if (OPT_l && (option_mask32 & (OPT_u|OPT_l)) == (OPT_u|OPT_l)) { |
741 | if (!o_lport) /* "port 0", but that's not useful */ | 776 | /* apparently UDP can listen ON "port 0", |
742 | bb_error_msg_and_die("UDP listen needs -p arg"); | 777 | but that's not useful */ |
778 | if (!o_lport) | ||
779 | bb_error_msg_and_die("UDP listen needs nonzero -p port"); | ||
743 | } | 780 | } |
744 | 781 | ||
745 | FD_SET(0, &ding1); /* stdin *is* initially open */ | 782 | FD_SET(0, &ding1); /* stdin *is* initially open */ |
746 | if (proggie) { | 783 | if (proggie) { |
747 | close(0); /* won't need stdin */ | 784 | close(0); /* won't need stdin */ |
748 | option_mask32 &= ~OPT_o; /* -o with -e is meaningless! */ | 785 | option_mask32 &= ~OPT_o; /* -o with -e is meaningless! */ |
749 | ofd = 0; | ||
750 | } | ||
751 | if (o_wfile) { | ||
752 | ofd = xopen(stage, O_WRONLY|O_CREAT|O_TRUNC); | ||
753 | stage = xzalloc(100); | ||
754 | } | 786 | } |
787 | #if ENABLE_NC_EXTRA | ||
788 | if (o_ofile) | ||
789 | xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), ofd); | ||
790 | #endif | ||
755 | 791 | ||
756 | if (argv[0]) { | 792 | if (argv[0]) { |
757 | themaddr = xhost2sockaddr(argv[0], | 793 | themaddr = xhost2sockaddr(argv[0], |
@@ -781,7 +817,7 @@ int nc_main(int argc, char **argv) | |||
781 | x = udptest(); | 817 | x = udptest(); |
782 | if (x == 0) { /* Yow, are we OPEN YET?! */ | 818 | if (x == 0) { /* Yow, are we OPEN YET?! */ |
783 | if (o_verbose) | 819 | if (o_verbose) |
784 | fprintf(stderr, "%s [%s] open\n", argv[0], themdotted); | 820 | fprintf(stderr, "%s (%s) open\n", argv[0], themdotted); |
785 | if (proggie) /* exec is valid for outbound, too */ | 821 | if (proggie) /* exec is valid for outbound, too */ |
786 | doexec(proggie); | 822 | doexec(proggie); |
787 | if (!o_zero) | 823 | if (!o_zero) |
@@ -791,7 +827,7 @@ int nc_main(int argc, char **argv) | |||
791 | /* if we're scanning at a "one -v" verbosity level, don't print refusals. | 827 | /* if we're scanning at a "one -v" verbosity level, don't print refusals. |
792 | Give it another -v if you want to see everything. */ | 828 | Give it another -v if you want to see everything. */ |
793 | if (o_verbose > 1 || (o_verbose && errno != ECONNREFUSED)) | 829 | if (o_verbose > 1 || (o_verbose && errno != ECONNREFUSED)) |
794 | bb_perror_msg("%s [%s]", argv[0], themdotted); | 830 | bb_perror_msg("%s (%s)", argv[0], themdotted); |
795 | } | 831 | } |
796 | } | 832 | } |
797 | if (o_verbose > 1) /* normally we don't care */ | 833 | if (o_verbose > 1) /* normally we don't care */ |