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 static void timeout(int signum)
14 bb_error_msg_and_die("Timed out");
17 int nc_main(int argc, char **argv)
19 int do_listen = 0, lport = 0, delay = 0, wsecs = 0, execflag = 0, opt,
21 struct sockaddr_in address;
22 struct hostent *hostinfo;
23 fd_set readfds, testfds;
26 memset(&address, 0, sizeof(address));
28 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
29 while ((opt = getopt(argc, argv, "lp:" USE_NC_EXTRA("i:ew:f:"))) > 0) {
30 if (ENABLE_NC_SERVER && opt=='l') do_listen++;
31 else if (ENABLE_NC_SERVER && opt=='p')
32 lport = bb_lookup_port(optarg, "tcp", 0);
33 else if (ENABLE_NC_EXTRA && opt=='w') wsecs = atoi(optarg);
34 else if (ENABLE_NC_EXTRA && opt=='i') delay = atoi(optarg);
35 else if (ENABLE_NC_EXTRA && opt=='f') infile = optarg;
36 else if (ENABLE_NC_EXTRA && opt=='e' && optind!=argc) {
39 } else bb_show_usage();
44 // For listen or file we need zero arguments, dialout is 2.
45 // For exec we need at least one more argument at the end, more ok
47 opt = (do_listen || infile) ? 0 : 2 + execflag;
48 if (execflag ? argc-optind < opt : argc-optind!=opt ||
49 (infile && do_listen))
53 signal(SIGALRM, timeout);
57 if (infile) cfd = xopen(infile, O_RDWR);
60 sfd = xsocket(AF_INET, SOCK_STREAM, 0);
61 fcntl(sfd, F_SETFD, FD_CLOEXEC);
62 setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));
63 address.sin_family = AF_INET;
68 address.sin_port = lport;
70 xbind(sfd, (struct sockaddr *) &address, sizeof(address));
74 socklen_t addrlen = sizeof(address);
76 xlisten(sfd, do_listen);
78 // If we didn't specify a port number, query and print it to stderr.
81 socklen_t len = sizeof(address);
82 getsockname(sfd, &address, &len);
83 fdprintf(2, "%d\n", SWAP_BE16(address.sin_port));
86 if ((cfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
87 bb_perror_msg_and_die("accept");
89 if (!execflag) close(sfd);
91 hostinfo = xgethostbyname(argv[optind]);
93 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
94 address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0);
96 if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
97 bb_perror_msg_and_die("connect");
104 signal(SIGALRM, SIG_DFL);
110 signal(SIGCHLD, SIG_IGN);
117 // With more than one -l, repeatedly act as server.
119 if (do_listen>1 && vfork()) {
120 // This is a bit weird as cleanup goes, since we wind up with no
121 // stdin/stdout/stderr. But it's small and shouldn't hurt anything.
122 // We check for cfd == 0 above.
129 execvp(argv[optind], argv+optind);
130 /* Don't print stuff or it will go over the wire.... */
134 // Select loop copying stdin to cfd, and cfd to stdout.
137 FD_SET(cfd, &readfds);
138 FD_SET(STDIN_FILENO, &readfds);
147 if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
148 bb_perror_msg_and_die("select");
150 for (fd = 0; fd < FD_SETSIZE; fd++) {
151 if (FD_ISSET(fd, &testfds)) {
152 nread = safe_read(fd, bb_common_bufsiz1,
153 sizeof(bb_common_bufsiz1));
156 if (nread<1) exit(0);
160 // Close outgoing half-connection so they get EOF, but
161 // leave incoming alone so we can see response.
163 FD_CLR(STDIN_FILENO, &readfds);
168 xwrite(ofd, bb_common_bufsiz1, nread);
169 if (delay > 0) sleep(delay);