aboutsummaryrefslogtreecommitdiff
path: root/networking/nc_bloaty.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2013-07-28 22:23:12 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2013-07-28 22:23:12 +0200
commitffeeb7a96c74f1f001495c2311526681e2271a77 (patch)
tree72ebc9e50c877f83069fea5cc12633a860dc9c3b /networking/nc_bloaty.c
parentca54b662e7a058a1f687da2eac6752590a9ed2ee (diff)
downloadbusybox-w32-ffeeb7a96c74f1f001495c2311526681e2271a77.tar.gz
busybox-w32-ffeeb7a96c74f1f001495c2311526681e2271a77.tar.bz2
busybox-w32-ffeeb7a96c74f1f001495c2311526681e2271a77.zip
nc: exit when both stdin and network are closed.
function old new delta nc_main 1051 1042 -9 readwrite 943 887 -56 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/nc_bloaty.c')
-rw-r--r--networking/nc_bloaty.c50
1 files changed, 31 insertions, 19 deletions
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 00ba6f114..f01e862ae 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -48,6 +48,12 @@
48 * - TCP connects from wrong ip/ports (if peer ip:port is specified 48 * - TCP connects from wrong ip/ports (if peer ip:port is specified
49 * on the command line, but accept() says that it came from different addr) 49 * on the command line, but accept() says that it came from different addr)
50 * are closed, but we don't exit - we continue to listen/accept. 50 * are closed, but we don't exit - we continue to listen/accept.
51 * Since bbox 1.22:
52 * - nc exits when _both_ stdin and network are closed.
53 * This makes these two commands:
54 * echo "Yes" | nc 127.0.0.1 1234
55 * echo "no" | nc -lp 1234
56 * exchange their data _and exit_ instead of being stuck.
51 */ 57 */
52 58
53/* done in nc.c: #include "libbb.h" */ 59/* done in nc.c: #include "libbb.h" */
@@ -134,8 +140,6 @@ struct globals {
134 140
135 jmp_buf jbuf; /* timer crud */ 141 jmp_buf jbuf; /* timer crud */
136 142
137 fd_set ding1; /* for select loop */
138 fd_set ding2;
139 char bigbuf_in[BIGSIZ]; /* data buffers */ 143 char bigbuf_in[BIGSIZ]; /* data buffers */
140 char bigbuf_net[BIGSIZ]; 144 char bigbuf_net[BIGSIZ];
141}; 145};
@@ -147,8 +151,6 @@ struct globals {
147#define themaddr (G.themaddr ) 151#define themaddr (G.themaddr )
148#define remend (G.remend ) 152#define remend (G.remend )
149#define jbuf (G.jbuf ) 153#define jbuf (G.jbuf )
150#define ding1 (G.ding1 )
151#define ding2 (G.ding2 )
152#define bigbuf_in (G.bigbuf_in ) 154#define bigbuf_in (G.bigbuf_in )
153#define bigbuf_net (G.bigbuf_net) 155#define bigbuf_net (G.bigbuf_net)
154#define o_verbose (G.o_verbose ) 156#define o_verbose (G.o_verbose )
@@ -592,10 +594,17 @@ static int readwrite(void)
592 unsigned netretry; /* net-read retry counter */ 594 unsigned netretry; /* net-read retry counter */
593 unsigned wretry; /* net-write sanity counter */ 595 unsigned wretry; /* net-write sanity counter */
594 unsigned wfirst; /* one-shot flag to skip first net read */ 596 unsigned wfirst; /* one-shot flag to skip first net read */
597 unsigned fds_open;
595 598
596 /* if you don't have all this FD_* macro hair in sys/types.h, you'll have to 599 /* if you don't have all this FD_* macro hair in sys/types.h, you'll have to
597 either find it or do your own bit-bashing: *ding1 |= (1 << fd), etc... */ 600 either find it or do your own bit-bashing: *ding1 |= (1 << fd), etc... */
598 FD_SET(netfd, &ding1); /* global: the net is open */ 601 fd_set ding1; /* for select loop */
602 fd_set ding2;
603 FD_ZERO(&ding1);
604 FD_SET(netfd, &ding1);
605 FD_SET(STDIN_FILENO, &ding1);
606 fds_open = 2;
607
599 netretry = 2; 608 netretry = 2;
600 wfirst = 0; 609 wfirst = 0;
601 rzleft = rnleft = 0; 610 rzleft = rnleft = 0;
@@ -604,7 +613,8 @@ static int readwrite(void)
604 613
605 errno = 0; /* clear from sleep, close, whatever */ 614 errno = 0; /* clear from sleep, close, whatever */
606 /* and now the big ol' select shoveling loop ... */ 615 /* and now the big ol' select shoveling loop ... */
607 while (FD_ISSET(netfd, &ding1)) { /* i.e. till the *net* closes! */ 616 /* nc 1.10 has "while (FD_ISSET(netfd)" here */
617 while (fds_open) {
608 wretry = 8200; /* more than we'll ever hafta write */ 618 wretry = 8200; /* more than we'll ever hafta write */
609 if (wfirst) { /* any saved stdin buffer? */ 619 if (wfirst) { /* any saved stdin buffer? */
610 wfirst = 0; /* clear flag for the duration */ 620 wfirst = 0; /* clear flag for the duration */
@@ -629,13 +639,14 @@ static int readwrite(void)
629 /* if we have a timeout AND stdin is closed AND we haven't heard anything 639 /* if we have a timeout AND stdin is closed AND we haven't heard anything
630 from the net during that time, assume it's dead and close it too. */ 640 from the net during that time, assume it's dead and close it too. */
631 if (rr == 0) { 641 if (rr == 0) {
632 if (!FD_ISSET(STDIN_FILENO, &ding1)) 642 if (!FD_ISSET(STDIN_FILENO, &ding1)) {
633 netretry--; /* we actually try a coupla times. */ 643 netretry--; /* we actually try a coupla times. */
634 if (!netretry) { 644 if (!netretry) {
635 if (o_verbose > 1) /* normally we don't care */ 645 if (o_verbose > 1) /* normally we don't care */
636 fprintf(stderr, "net timeout\n"); 646 fprintf(stderr, "net timeout\n");
637 close(netfd); 647 close(netfd);
638 return 0; /* not an error! */ 648 return 0; /* not an error! */
649 }
639 } 650 }
640 } /* select timeout */ 651 } /* select timeout */
641 /* xxx: should we check the exception fds too? The read fds seem to give 652 /* xxx: should we check the exception fds too? The read fds seem to give
@@ -649,7 +660,8 @@ static int readwrite(void)
649 /* nc 1.10 doesn't do this */ 660 /* nc 1.10 doesn't do this */
650 bb_perror_msg("net read"); 661 bb_perror_msg("net read");
651 } 662 }
652 FD_CLR(netfd, &ding1); /* net closed, we'll finish up... */ 663 FD_CLR(netfd, &ding1); /* net closed */
664 fds_open--;
653 rzleft = 0; /* can't write anymore: broken pipe */ 665 rzleft = 0; /* can't write anymore: broken pipe */
654 } else { 666 } else {
655 rnleft = rr; 667 rnleft = rr;
@@ -671,9 +683,10 @@ Debug("got %d from the net, errno %d", rr, errno);
671 if (rr <= 0) { /* at end, or fukt, or ... */ 683 if (rr <= 0) { /* at end, or fukt, or ... */
672 FD_CLR(STDIN_FILENO, &ding1); /* disable and close stdin */ 684 FD_CLR(STDIN_FILENO, &ding1); /* disable and close stdin */
673 close(STDIN_FILENO); 685 close(STDIN_FILENO);
674// Does it make sense to shutdown(net_fd, SHUT_WR) 686 /* Let peer know we have no more data */
675// to let other side know that we won't write anything anymore? 687 /* nc 1.10 doesn't do this: */
676// (and what about keeping compat if we do that?) 688 shutdown(netfd, SHUT_WR);
689 fds_open--;
677 } else { 690 } else {
678 rzleft = rr; 691 rzleft = rr;
679 zp = bigbuf_in; 692 zp = bigbuf_in;
@@ -725,7 +738,7 @@ Debug("wrote %d to net, errno %d", rr, errno);
725 errno = 0; /* clear from sleep */ 738 errno = 0; /* clear from sleep */
726 continue; /* ...with hairy select loop... */ 739 continue; /* ...with hairy select loop... */
727 } 740 }
728 if ((rzleft) || (rnleft)) { /* shovel that shit till they ain't */ 741 if (rzleft || rnleft) { /* shovel that shit till they ain't */
729 wretry--; /* none left, and get another load */ 742 wretry--; /* none left, and get another load */
730 goto shovel; 743 goto shovel;
731 } 744 }
@@ -876,9 +889,8 @@ int nc_main(int argc UNUSED_PARAM, char **argv)
876 } 889 }
877#endif 890#endif
878 891
879 FD_SET(STDIN_FILENO, &ding1); /* stdin *is* initially open */
880 if (proggie) { 892 if (proggie) {
881 close(0); /* won't need stdin */ 893 close(STDIN_FILENO); /* won't need stdin */
882 option_mask32 &= ~OPT_o; /* -o with -e is meaningless! */ 894 option_mask32 &= ~OPT_o; /* -o with -e is meaningless! */
883 } 895 }
884#if ENABLE_NC_EXTRA 896#if ENABLE_NC_EXTRA