Since rangecoder is just a bunch of C functions, move it into the one user
[oweals/busybox.git] / networking / nc.c
1 /* vi: set sw=4 ts=4: */
2 /*  nc: mini-netcat - built from the ground up for LRP
3     Copyright (C) 1998  Charles P. Wright
4
5     0.0.1   6K      It works.
6     0.0.2   5K      Smaller and you can also check the exit condition if you wish.
7     0.0.3           Uses select()
8
9     19980918 Busy Boxed! Dave Cinege
10     19990512 Uses Select. Charles P. Wright
11     19990513 Fixes stdin stupidity and uses buffers.  Charles P. Wright
12
13     Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <signal.h>
21
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <netdb.h>
27 #include <sys/ioctl.h>
28 #include "busybox.h"
29
30 static void timeout(int signum)
31 {
32         bb_error_msg_and_die("Timed out");
33 }
34
35 int nc_main(int argc, char **argv)
36 {
37         int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x;
38
39 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE
40         char *pr00gie = NULL;
41 #endif
42
43         struct sockaddr_in address;
44         struct hostent *hostinfo;
45
46         fd_set readfds, testfds;
47
48         while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) {
49                 switch (opt) {
50                         case 'l':
51                                 do_listen++;
52                                 break;
53                         case 'p':
54                                 lport = bb_lookup_port(optarg, "tcp", 0);
55                                 break;
56                         case 'i':
57                                 delay = atoi(optarg);
58                                 break;
59 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE
60                         case 'e':
61                                 pr00gie = optarg;
62                                 break;
63 #endif
64                         case 'w':
65                                 wsecs = atoi(optarg);
66                                 break;
67                         default:
68                                 bb_show_usage();
69                 }
70         }
71
72         if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
73                 bb_show_usage();
74
75         sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0);
76         x = 1;
77         if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1)
78                 bb_perror_msg_and_die("reuseaddr");
79         address.sin_family = AF_INET;
80
81         if (wsecs) {
82                 signal(SIGALRM, timeout);
83                 alarm(wsecs);
84         }
85
86         if (lport != 0) {
87                 memset(&address.sin_addr, 0, sizeof(address.sin_addr));
88                 address.sin_port = lport;
89
90                 bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address));
91         }
92
93         if (do_listen) {
94                 socklen_t addrlen = sizeof(address);
95
96                 bb_xlisten(sfd, 1);
97                 if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
98                         bb_perror_msg_and_die("accept");
99
100                 close(sfd);
101                 sfd = tmpfd;
102         } else {
103                 hostinfo = xgethostbyname(argv[optind]);
104
105                 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
106                 address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0);
107
108                 if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
109                         bb_perror_msg_and_die("connect");
110         }
111
112         if (wsecs) {
113                 alarm(0);
114                 signal(SIGALRM, SIG_DFL);
115         }
116
117 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE
118         /* -e given? */
119         if (pr00gie) {
120                 dup2(sfd, 0);
121                 close(sfd);
122                 dup2(0, 1);
123                 dup2(0, 2);
124                 execl(pr00gie, pr00gie, NULL);
125                 /* Don't print stuff or it will go over the wire.... */
126                 _exit(-1);
127         }
128 #endif /* CONFIG_NC_GAPING_SECURITY_HOLE */
129
130         FD_ZERO(&readfds);
131         FD_SET(sfd, &readfds);
132         FD_SET(STDIN_FILENO, &readfds);
133
134         while (1) {
135                 int fd;
136                 int ofd;
137                 int nread;
138
139                 testfds = readfds;
140
141                 if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
142                         bb_perror_msg_and_die("select");
143
144                 for (fd = 0; fd < FD_SETSIZE; fd++) {
145                         if (FD_ISSET(fd, &testfds)) {
146                                 if ((nread = safe_read(fd, bb_common_bufsiz1,
147                                         sizeof(bb_common_bufsiz1))) < 0)
148                                 {
149                                         bb_perror_msg_and_die(bb_msg_read_error);
150                                 }
151
152                                 if (fd == sfd) {
153                                         if (nread == 0)
154                                                 exit(0);
155                                         ofd = STDOUT_FILENO;
156                                 } else {
157                                         if (nread <= 0) {
158                                                 shutdown(sfd, 1 /* send */ );
159                                                 close(STDIN_FILENO);
160                                                 FD_CLR(STDIN_FILENO, &readfds);
161                                         }
162                                         ofd = sfd;
163                                 }
164
165                                 if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0)
166                                         bb_perror_msg_and_die(bb_msg_write_error);
167                                 if (delay > 0) {
168                                         sleep(delay);
169                                 }
170                         }
171                 }
172         }
173 }