diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-01-12 20:59:31 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-01-12 20:59:31 +0000 |
commit | 5d68724d5b89fbf2856fdfbf36b85ac36a8f4464 (patch) | |
tree | 755b7393aab965f03de260a833f77cc4d51e6187 /networking/nc.c | |
parent | 2c91652bbcc82c794c26230806058b04f1711033 (diff) | |
download | busybox-w32-5d68724d5b89fbf2856fdfbf36b85ac36a8f4464.tar.gz busybox-w32-5d68724d5b89fbf2856fdfbf36b85ac36a8f4464.tar.bz2 busybox-w32-5d68724d5b89fbf2856fdfbf36b85ac36a8f4464.zip |
next part of ipv6-ization. mostly netcat.
Diffstat (limited to 'networking/nc.c')
-rw-r--r-- | networking/nc.c | 103 |
1 files changed, 49 insertions, 54 deletions
diff --git a/networking/nc.c b/networking/nc.c index e1c22839c..37e658d4b 100644 --- a/networking/nc.c +++ b/networking/nc.c | |||
@@ -9,6 +9,10 @@ | |||
9 | 9 | ||
10 | #include "busybox.h" | 10 | #include "busybox.h" |
11 | 11 | ||
12 | /* Lots of small differences in features | ||
13 | * when compared to "standard" nc | ||
14 | */ | ||
15 | |||
12 | static void timeout(int signum) | 16 | static void timeout(int signum) |
13 | { | 17 | { |
14 | bb_error_msg_and_die("timed out"); | 18 | bb_error_msg_and_die("timed out"); |
@@ -16,7 +20,8 @@ static void timeout(int signum) | |||
16 | 20 | ||
17 | int nc_main(int argc, char **argv) | 21 | int nc_main(int argc, char **argv) |
18 | { | 22 | { |
19 | int sfd = 0; | 23 | /* sfd sits _here_ only because of "repeat" option (-l -l). */ |
24 | int sfd = sfd; /* for gcc */ | ||
20 | int cfd = 0; | 25 | int cfd = 0; |
21 | SKIP_NC_SERVER(const) unsigned do_listen = 0; | 26 | SKIP_NC_SERVER(const) unsigned do_listen = 0; |
22 | SKIP_NC_SERVER(const) unsigned lport = 0; | 27 | SKIP_NC_SERVER(const) unsigned lport = 0; |
@@ -24,12 +29,10 @@ int nc_main(int argc, char **argv) | |||
24 | SKIP_NC_EXTRA (const) unsigned delay = 0; | 29 | SKIP_NC_EXTRA (const) unsigned delay = 0; |
25 | SKIP_NC_EXTRA (const int execparam = 0;) | 30 | SKIP_NC_EXTRA (const int execparam = 0;) |
26 | USE_NC_EXTRA (char **execparam = NULL;) | 31 | USE_NC_EXTRA (char **execparam = NULL;) |
27 | struct sockaddr_in address; | 32 | len_and_sockaddr *lsa; |
28 | fd_set readfds, testfds; | 33 | fd_set readfds, testfds; |
29 | int opt; /* must be signed (getopt returns -1) */ | 34 | int opt; /* must be signed (getopt returns -1) */ |
30 | 35 | ||
31 | memset(&address, 0, sizeof(address)); | ||
32 | |||
33 | if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { | 36 | if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { |
34 | /* getopt32 is _almost_ usable: | 37 | /* getopt32 is _almost_ usable: |
35 | ** it cannot handle "... -e prog -prog-opt" */ | 38 | ** it cannot handle "... -e prog -prog-opt" */ |
@@ -39,7 +42,6 @@ int nc_main(int argc, char **argv) | |||
39 | if (ENABLE_NC_SERVER && opt=='l') USE_NC_SERVER(do_listen++); | 42 | if (ENABLE_NC_SERVER && opt=='l') USE_NC_SERVER(do_listen++); |
40 | else if (ENABLE_NC_SERVER && opt=='p') { | 43 | else if (ENABLE_NC_SERVER && opt=='p') { |
41 | USE_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0)); | 44 | USE_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0)); |
42 | USE_NC_SERVER(lport = htons(lport)); | ||
43 | } | 45 | } |
44 | else if (ENABLE_NC_EXTRA && opt=='w') USE_NC_EXTRA( wsecs = xatou(optarg)); | 46 | else if (ENABLE_NC_EXTRA && opt=='w') USE_NC_EXTRA( wsecs = xatou(optarg)); |
45 | else if (ENABLE_NC_EXTRA && opt=='i') USE_NC_EXTRA( delay = xatou(optarg)); | 47 | else if (ENABLE_NC_EXTRA && opt=='i') USE_NC_EXTRA( delay = xatou(optarg)); |
@@ -71,9 +73,11 @@ int nc_main(int argc, char **argv) | |||
71 | // -l and -f don't mix | 73 | // -l and -f don't mix |
72 | if (do_listen && cfd) bb_show_usage(); | 74 | if (do_listen && cfd) bb_show_usage(); |
73 | // Listen or file modes need zero arguments, client mode needs 2 | 75 | // Listen or file modes need zero arguments, client mode needs 2 |
74 | opt = ((do_listen || cfd) ? 0 : 2); | 76 | if (do_listen || cfd) { |
75 | if (argc != opt) | 77 | if (argc) bb_show_usage(); |
76 | bb_show_usage(); | 78 | } else { |
79 | if (!argc || argc > 2) bb_show_usage(); | ||
80 | } | ||
77 | } else { | 81 | } else { |
78 | if (argc != 3) bb_show_usage(); | 82 | if (argc != 3) bb_show_usage(); |
79 | argc--; | 83 | argc--; |
@@ -86,46 +90,37 @@ int nc_main(int argc, char **argv) | |||
86 | } | 90 | } |
87 | 91 | ||
88 | if (!cfd) { | 92 | if (!cfd) { |
89 | sfd = xsocket(AF_INET, SOCK_STREAM, 0); | ||
90 | fcntl(sfd, F_SETFD, FD_CLOEXEC); | ||
91 | setsockopt_reuseaddr(sfd); | ||
92 | address.sin_family = AF_INET; | ||
93 | |||
94 | // Set local port. | ||
95 | |||
96 | if (lport != 0) { | ||
97 | address.sin_port = lport; | ||
98 | xbind(sfd, (struct sockaddr *) &address, sizeof(address)); | ||
99 | } | ||
100 | |||
101 | if (do_listen) { | 93 | if (do_listen) { |
102 | socklen_t addrlen = sizeof(address); | 94 | socklen_t addrlen; |
103 | 95 | ||
104 | xlisten(sfd, do_listen); | 96 | /* create_and_bind_stream_or_die(NULL, lport) |
105 | 97 | * would've work wonderfully, but we need | |
106 | // If we didn't specify a port number, query and print it to stderr. | 98 | * to know lsa */ |
107 | 99 | sfd = xsocket_stream(&lsa); | |
100 | if (lport) | ||
101 | set_nport(lsa, htons(lport)); | ||
102 | setsockopt_reuseaddr(sfd); | ||
103 | xbind(sfd, &lsa->sa, lsa->len); | ||
104 | xlisten(sfd, do_listen); /* can be > 1 */ | ||
105 | /* If we didn't specify a port number, | ||
106 | * query and print it after listen() */ | ||
108 | if (!lport) { | 107 | if (!lport) { |
109 | socklen_t len = sizeof(address); | 108 | addrlen = lsa->len; |
110 | getsockname(sfd, (struct sockaddr *) &address, &len); | 109 | getsockname(sfd, &lsa->sa, &addrlen); |
111 | fdprintf(2, "%d\n", SWAP_BE16(address.sin_port)); | 110 | lport = get_nport(lsa); |
111 | fdprintf(2, "%d\n", ntohs(lport)); | ||
112 | } | 112 | } |
113 | repeatyness: | 113 | fcntl(sfd, F_SETFD, FD_CLOEXEC); |
114 | cfd = accept(sfd, (struct sockaddr *) &address, &addrlen); | 114 | accept_again: |
115 | addrlen = lsa->len; | ||
116 | cfd = accept(sfd, NULL, 0); /* &lsa->sa, &addrlen); */ | ||
115 | if (cfd < 0) | 117 | if (cfd < 0) |
116 | bb_perror_msg_and_die("accept"); | 118 | bb_perror_msg_and_die("accept"); |
117 | 119 | if (!execparam) | |
118 | if (!execparam) close(sfd); | 120 | close(sfd); |
119 | } else { | 121 | } else { |
120 | struct hostent *hostinfo; | 122 | cfd = create_and_connect_stream_or_die(argv[0], |
121 | hostinfo = xgethostbyname(argv[0]); | 123 | argv[1] ? bb_lookup_port(argv[1], "tcp", 0) : 0); |
122 | |||
123 | address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; | ||
124 | address.sin_port = bb_lookup_port(argv[1], "tcp", 0); | ||
125 | address.sin_port = htons(address.sin_port); | ||
126 | |||
127 | xconnect(sfd, (struct sockaddr *) &address, sizeof(address)); | ||
128 | cfd = sfd; | ||
129 | } | 124 | } |
130 | } | 125 | } |
131 | 126 | ||
@@ -136,17 +131,10 @@ int nc_main(int argc, char **argv) | |||
136 | 131 | ||
137 | /* -e given? */ | 132 | /* -e given? */ |
138 | if (execparam) { | 133 | if (execparam) { |
139 | if (cfd) { | 134 | signal(SIGCHLD, SIG_IGN); |
140 | signal(SIGCHLD, SIG_IGN); | ||
141 | dup2(cfd, 0); | ||
142 | close(cfd); | ||
143 | } | ||
144 | dup2(0, 1); | ||
145 | dup2(0, 2); | ||
146 | |||
147 | // With more than one -l, repeatedly act as server. | 135 | // With more than one -l, repeatedly act as server. |
148 | |||
149 | if (do_listen > 1 && vfork()) { | 136 | if (do_listen > 1 && vfork()) { |
137 | /* parent */ | ||
150 | // This is a bit weird as cleanup goes, since we wind up with no | 138 | // This is a bit weird as cleanup goes, since we wind up with no |
151 | // stdin/stdout/stderr. But it's small and shouldn't hurt anything. | 139 | // stdin/stdout/stderr. But it's small and shouldn't hurt anything. |
152 | // We check for cfd == 0 above. | 140 | // We check for cfd == 0 above. |
@@ -154,9 +142,15 @@ int nc_main(int argc, char **argv) | |||
154 | close(0); | 142 | close(0); |
155 | close(1); | 143 | close(1); |
156 | close(2); | 144 | close(2); |
157 | 145 | goto accept_again; | |
158 | goto repeatyness; | ||
159 | } | 146 | } |
147 | /* child (or main thread if no multiple -l) */ | ||
148 | if (cfd) { | ||
149 | dup2(cfd, 0); | ||
150 | close(cfd); | ||
151 | } | ||
152 | dup2(0, 1); | ||
153 | dup2(0, 2); | ||
160 | USE_NC_EXTRA(execvp(execparam[0], execparam);) | 154 | USE_NC_EXTRA(execvp(execparam[0], execparam);) |
161 | /* Don't print stuff or it will go over the wire.... */ | 155 | /* Don't print stuff or it will go over the wire.... */ |
162 | _exit(127); | 156 | _exit(127); |
@@ -184,7 +178,8 @@ int nc_main(int argc, char **argv) | |||
184 | sizeof(bb_common_bufsiz1)); | 178 | sizeof(bb_common_bufsiz1)); |
185 | 179 | ||
186 | if (fd == cfd) { | 180 | if (fd == cfd) { |
187 | if (nread<1) exit(0); | 181 | if (nread < 1) |
182 | exit(0); | ||
188 | ofd = STDOUT_FILENO; | 183 | ofd = STDOUT_FILENO; |
189 | } else { | 184 | } else { |
190 | if (nread<1) { | 185 | if (nread<1) { |