summaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-04-06 10:41:05 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-04-06 10:41:05 +0000
commit19507f0869571f29cfd0a4aed3d7c07db038b129 (patch)
tree55db16b423e06c9e2753c47e4a1af0d56dd14ca4 /networking
parent5a30d59c3d24c04fb93b8bdfb95f94b124203aa1 (diff)
downloadbusybox-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.c248
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 */ 53enum {
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
49struct globals { 61struct 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! */
199Debug(("findline returning %d", x)) 209Debug("findline returning %d", x);
200 return x; 210 return x;
201 } 211 }
202 p++; 212 p++;
203 } /* for */ 213 } /* for */
204Debug(("findline returning whole thing: %d", siz)) 214Debug("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)
252static void dolisten(void) 262static 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
326our socket on it, so that our outbound packets will have correct local IP.
327Unfortunately, bind() on already bound socket will fail now (EINVAL):
328 xbind(netfd, &ouraddr->sa, ouraddr->len);
329Need to read the packet, save data, close this socket and
330create 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
395static int udptest(void) 422static 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
451int 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... */
434static void oprint(int which, char *buf, int n) 464#if ENABLE_NC_EXTRA
465static 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
526void 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 }
573Debug(("got %d from the net, errno %d", rr, errno)) 605Debug("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 }
618Debug(("wrote %d to stdout, errno %d", rr, errno)) 650Debug("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 }
633Debug(("wrote %d to net, errno %d", rr, errno)) 665Debug("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);
657int nc_main(int argc, char **argv) 689int 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 */