1 /* vi: set sw=4 ts=4: */
2 /* nc: mini-netcat - built from the ground up for LRP
4 * Copyright (C) 1998, 1999 Charles P. Wright
5 * Copyright (C) 1998 Dave Cinege
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
12 #define xread bb_xread
14 static void timeout(int signum)
16 bb_error_msg_and_die("Timed out");
19 int nc_main(int argc, char **argv)
21 int do_listen = 0, lport = 0, delay = 0, wsecs = 0, execflag = 0, opt,
23 struct sockaddr_in address;
24 struct hostent *hostinfo;
25 fd_set readfds, testfds;
28 memset(&address, 0, sizeof(address));
30 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
31 while ((opt = getopt(argc, argv, "lp:" USE_NC_EXTRA("i:ew:f:"))) > 0) {
32 if (ENABLE_NC_SERVER && opt=='l') do_listen++;
33 else if (ENABLE_NC_SERVER && opt=='p')
34 lport = bb_lookup_port(optarg, "tcp", 0);
35 else if (ENABLE_NC_EXTRA && opt=='w') wsecs = atoi(optarg);
36 else if (ENABLE_NC_EXTRA && opt=='i') delay = atoi(optarg);
37 else if (ENABLE_NC_EXTRA && opt=='f') infile = optarg;
38 else if (ENABLE_NC_EXTRA && opt=='e' && optind!=argc) {
41 } else bb_show_usage();
46 // For listen or file we need zero arguments, dialout is 2.
47 // For exec we need at least one more argument at the end, more ok
49 opt = (do_listen || infile) ? 0 : 2 + execflag;
50 if (execflag ? argc-optind < opt : argc-optind!=opt ||
51 (infile && do_listen))
55 signal(SIGALRM, timeout);
59 if (infile) cfd = bb_xopen(infile, O_RDWR);
62 sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0);
63 fcntl(sfd, F_SETFD, FD_CLOEXEC);
64 setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));
65 address.sin_family = AF_INET;
70 address.sin_port = lport;
72 bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address));
76 socklen_t addrlen = sizeof(address);
78 bb_xlisten(sfd, do_listen);
80 // If we didn't specify a port number, query and print it to stderr.
83 socklen_t len = sizeof(address);
84 getsockname(sfd, &address, &len);
85 fdprintf(2, "%d\n", SWAP_BE16(address.sin_port));
88 if ((cfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
89 bb_perror_msg_and_die("accept");
91 if (!execflag) close(sfd);
93 hostinfo = xgethostbyname(argv[optind]);
95 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
96 address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0);
98 if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
99 bb_perror_msg_and_die("connect");
106 signal(SIGALRM, SIG_DFL);
112 signal(SIGCHLD, SIG_IGN);
119 // With more than one -l, repeatedly act as server.
121 if (do_listen>1 && vfork()) {
122 // This is a bit weird as cleanup goes, since we wind up with no
123 // stdin/stdout/stderr. But it's small and shouldn't hurt anything.
124 // We check for cfd == 0 above.
131 execvp(argv[optind], argv+optind);
132 /* Don't print stuff or it will go over the wire.... */
136 // Select loop copying stdin to cfd, and cfd to stdout.
139 FD_SET(cfd, &readfds);
140 FD_SET(STDIN_FILENO, &readfds);
149 if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
150 bb_perror_msg_and_die("select");
152 for (fd = 0; fd < FD_SETSIZE; fd++) {
153 if (FD_ISSET(fd, &testfds)) {
154 nread = xread(fd, bb_common_bufsiz1, sizeof(bb_common_bufsiz1));
161 // Close outgoing half-connection so they get EOF, but
162 // leave incoming alone so we can see response.
164 FD_CLR(STDIN_FILENO, &readfds);
169 if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0)
170 bb_perror_msg_and_die(bb_msg_write_error);
171 if (delay > 0) sleep(delay);