X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=networking%2Fnc.c;h=3f4149e14289bfdb866408cf534b09b151f23bcc;hb=59fe8b90890a07c87ec9c2943bae515d5c6d959d;hp=fcacb0c45b45231f634fdc6317475dadf2a6e668;hpb=3570a34de46b1f7dedd16999bb1687e2d6b55d40;p=oweals%2Fbusybox.git diff --git a/networking/nc.c b/networking/nc.c index fcacb0c45..3f4149e14 100644 --- a/networking/nc.c +++ b/networking/nc.c @@ -1,128 +1,172 @@ /* vi: set sw=4 ts=4: */ /* nc: mini-netcat - built from the ground up for LRP - Copyright (C) 1998 Charles P. Wright + * + * Copyright (C) 1998, 1999 Charles P. Wright + * Copyright (C) 1998 Dave Cinege + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ - 0.0.1 6K It works. - 0.0.2 5K Smaller and you can also check the exit condition if you wish. - 0.0.3 Uses select() +#include "busybox.h" - 19980918 Busy Boxed! Dave Cinege - 19990512 Uses Select. Charles P. Wright - 19990513 Fixes stdin stupidity and uses buffers. Charles P. Wright +static void timeout(int signum) +{ + bb_error_msg_and_die("Timed out"); +} - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. +int nc_main(int argc, char **argv) +{ + int do_listen = 0, lport = 0, delay = 0, wsecs = 0, execflag = 0, opt, + sfd = 0, cfd; + struct sockaddr_in address; + struct hostent *hostinfo; + fd_set readfds, testfds; + char *infile = NULL; + + memset(&address, 0, sizeof(address)); + + if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { + while ((opt = getopt(argc, argv, "lp:" USE_NC_EXTRA("i:ew:f:"))) > 0) { + if (ENABLE_NC_SERVER && opt=='l') do_listen++; + else if (ENABLE_NC_SERVER && opt=='p') + lport = bb_lookup_port(optarg, "tcp", 0); + else if (ENABLE_NC_EXTRA && opt=='w') wsecs = atoi(optarg); + else if (ENABLE_NC_EXTRA && opt=='i') delay = atoi(optarg); + else if (ENABLE_NC_EXTRA && opt=='f') infile = optarg; + else if (ENABLE_NC_EXTRA && opt=='e' && optind!=argc) { + execflag++; + break; + } else bb_show_usage(); + } + } - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + + // For listen or file we need zero arguments, dialout is 2. + // For exec we need at least one more argument at the end, more ok - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + opt = (do_listen || infile) ? 0 : 2 + execflag; + if (execflag ? argc-optind < opt : argc-optind!=opt || + (infile && do_listen)) + bb_show_usage(); -*/ -#include "busybox.h" -#include -#include -#include + if (wsecs) { + signal(SIGALRM, timeout); + alarm(wsecs); + } + + if (infile) cfd = xopen(infile, O_RDWR); + else { + opt = 1; + sfd = xsocket(AF_INET, SOCK_STREAM, 0); + fcntl(sfd, F_SETFD, FD_CLOEXEC); + setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); + address.sin_family = AF_INET; -#include -#include -#include -#include -#include -#include -#include + // Set local port. -#define BUFSIZE 100 + if (lport != 0) { + address.sin_port = lport; -int nc_main(int argc, char **argv) -{ - int sfd; - int result; - int len; - char ch[BUFSIZE]; + xbind(sfd, (struct sockaddr *) &address, sizeof(address)); + } - struct sockaddr_in address; - struct hostent *hostinfo; + if (do_listen) { + socklen_t addrlen = sizeof(address); - fd_set readfds, testfds; + xlisten(sfd, do_listen); - argc--; - argv++; - if (argc < 2 || **(argv + 1) == '-') { - usage(nc_usage); - } + // If we didn't specify a port number, query and print it to stderr. + + if (!lport) { + socklen_t len = sizeof(address); + getsockname(sfd, &address, &len); + fdprintf(2, "%d\n", SWAP_BE16(address.sin_port)); + } +repeatyness: + if ((cfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0) + bb_perror_msg_and_die("accept"); + + if (!execflag) close(sfd); + } else { + hostinfo = xgethostbyname(argv[optind]); - sfd = socket(AF_INET, SOCK_STREAM, 0); + address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; + address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0); - hostinfo = (struct hostent *) gethostbyname(*argv); + if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) + bb_perror_msg_and_die("connect"); + cfd = sfd; + } + } - if (!hostinfo) { - fatalError("cannot resolve %s\n", *argv); + if (wsecs) { + alarm(0); + signal(SIGALRM, SIG_DFL); } - address.sin_family = AF_INET; - address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; - address.sin_port = htons(atoi(*(++argv))); + /* -e given? */ + if (execflag) { + if(cfd) { + signal(SIGCHLD, SIG_IGN); + dup2(cfd, 0); + close(cfd); + } + dup2(0, 1); + dup2(0, 2); - len = sizeof(address); + // With more than one -l, repeatedly act as server. - result = connect(sfd, (struct sockaddr *) &address, len); + if (do_listen>1 && vfork()) { + // This is a bit weird as cleanup goes, since we wind up with no + // stdin/stdout/stderr. But it's small and shouldn't hurt anything. + // We check for cfd == 0 above. + close(0); + close(1); + close(2); - if (result < 0) { - perror("nc: connect"); - exit(2); + goto repeatyness; + } + execvp(argv[optind], argv+optind); + /* Don't print stuff or it will go over the wire.... */ + _exit(127); } + // Select loop copying stdin to cfd, and cfd to stdout. + FD_ZERO(&readfds); - FD_SET(sfd, &readfds); - FD_SET(fileno(stdin), &readfds); + FD_SET(cfd, &readfds); + FD_SET(STDIN_FILENO, &readfds); - while (1) { + for (;;) { int fd; int ofd; int nread; testfds = readfds; - result = - select(FD_SETSIZE, &testfds, (fd_set *) NULL, (fd_set *) NULL, - (struct timeval *) 0); - - if (result < 1) { - perror("nc: select"); - exit(3); - } + if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0) + bb_perror_msg_and_die("select"); for (fd = 0; fd < FD_SETSIZE; fd++) { if (FD_ISSET(fd, &testfds)) { - int trn = 0; - int rn; + nread = safe_read(fd, bb_common_bufsiz1, + sizeof(bb_common_bufsiz1)); - ioctl(fd, FIONREAD, &nread); - - if (fd == sfd) { - if (nread == 0) - exit(0); - ofd = fileno(stdout); + if (fd == cfd) { + if (nread<1) exit(0); + ofd = STDOUT_FILENO; } else { - ofd = sfd; + if (nread<1) { + // Close outgoing half-connection so they get EOF, but + // leave incoming alone so we can see response. + shutdown(cfd, 1); + FD_CLR(STDIN_FILENO, &readfds); + } + ofd = cfd; } - - - do { - rn = (BUFSIZE < nread - trn) ? BUFSIZE : nread - trn; - trn += rn; - read(fd, ch, rn); - write(ofd, ch, rn); - } - while (trn < nread); + xwrite(ofd, bb_common_bufsiz1, nread); + if (delay > 0) sleep(delay); } } }