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    This program is free software; you can redistribute it and/or modify
14    it under the terms of the GNU General Public License as published by
15    the Free Software Foundation; either version 2 of the License, or
16    (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21    GNU General Public License for more details.
22
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27*/
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38#include <netdb.h>
39#include <sys/time.h>
40#include <sys/ioctl.h>
41#include "busybox.h"
42
43int nc_main(int argc, char **argv)
44{
45	int do_listen = 0, lport = 0, tmpfd, opt, sfd;
46	char buf[BUFSIZ];
47
48	struct sockaddr_in address;
49	struct hostent *hostinfo;
50
51	fd_set readfds, testfds;
52
53	while ((opt = getopt(argc, argv, "lp:")) > 0) {
54		switch (opt) {
55			case 'l':
56				do_listen++;
57				break;
58			case 'p':
59				lport = atoi(optarg);
60				break;
61			default:
62				show_usage();
63		}
64	}
65
66	if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
67		show_usage();
68
69	if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
70		perror_msg_and_die("socket");
71
72	address.sin_family = AF_INET;
73
74	if (lport != 0) {
75		memset(&address.sin_addr, 0, sizeof(address.sin_addr));
76		address.sin_port = htons(lport);
77
78		if (bind(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
79			perror_msg_and_die("bind");
80	}
81
82	if (do_listen) {
83		socklen_t addrlen = sizeof(address);
84
85		if (listen(sfd, 1) < 0)
86			perror_msg_and_die("listen");
87
88		if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
89			perror_msg_and_die("accept");
90
91		close(sfd);
92		sfd = tmpfd;
93	} else {
94		hostinfo = xgethostbyname(argv[optind]);
95
96		address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
97		address.sin_port = htons(atoi(argv[optind+1]));
98
99		if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
100			perror_msg_and_die("connect");
101	}
102
103	FD_ZERO(&readfds);
104	FD_SET(sfd, &readfds);
105	FD_SET(STDIN_FILENO, &readfds);
106
107	while (1) {
108		int fd;
109		int ofd;
110		int nread;
111
112		testfds = readfds;
113
114		if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
115			perror_msg_and_die("select");
116
117		for (fd = 0; fd < FD_SETSIZE; fd++) {
118			if (FD_ISSET(fd, &testfds)) {
119				if ((nread = safe_read(fd, buf, sizeof(buf))) < 0)
120					perror_msg_and_die("read");
121
122				if (fd == sfd) {
123					if (nread == 0)
124						exit(0);
125					ofd = STDOUT_FILENO;
126				} else {
127					if (nread == 0)
128						shutdown(sfd, 1);
129					ofd = sfd;
130				}
131
132				if (full_write(ofd, buf, nread) < 0)
133					perror_msg_and_die("write");
134			}
135		}
136	}
137}
138