xref: /minix3/minix/commands/swifi/tests/socket.c (revision 875abb872412bde4d3ba5da66423f55431e19dcf)
1*875abb87SDavid van Moolenbroek /*
2*875abb87SDavid van Moolenbroek socket.c
3*875abb87SDavid van Moolenbroek 
4*875abb87SDavid van Moolenbroek Created:	Feb 2001 by Philip Homburg <philip@f-mnx.phicoh.com>
5*875abb87SDavid van Moolenbroek 
6*875abb87SDavid van Moolenbroek Open a TCP connection
7*875abb87SDavid van Moolenbroek */
8*875abb87SDavid van Moolenbroek 
9*875abb87SDavid van Moolenbroek #include <errno.h>
10*875abb87SDavid van Moolenbroek #include <fcntl.h>
11*875abb87SDavid van Moolenbroek #include <stdarg.h>
12*875abb87SDavid van Moolenbroek #include <stdio.h>
13*875abb87SDavid van Moolenbroek #include <stdlib.h>
14*875abb87SDavid van Moolenbroek #include <signal.h>
15*875abb87SDavid van Moolenbroek #include <string.h>
16*875abb87SDavid van Moolenbroek #include <unistd.h>
17*875abb87SDavid van Moolenbroek 
18*875abb87SDavid van Moolenbroek #include <sys/ioctl.h>
19*875abb87SDavid van Moolenbroek #include <sys/wait.h>
20*875abb87SDavid van Moolenbroek 
21*875abb87SDavid van Moolenbroek #include <net/hton.h>
22*875abb87SDavid van Moolenbroek #include <net/netlib.h>
23*875abb87SDavid van Moolenbroek #include <net/gen/in.h>
24*875abb87SDavid van Moolenbroek #include <net/gen/inet.h>
25*875abb87SDavid van Moolenbroek #include <netdb.h>
26*875abb87SDavid van Moolenbroek #include <net/gen/socket.h>
27*875abb87SDavid van Moolenbroek #include <net/gen/tcp.h>
28*875abb87SDavid van Moolenbroek #include <net/gen/tcp_io.h>
29*875abb87SDavid van Moolenbroek #include <arpa/inet.h>
30*875abb87SDavid van Moolenbroek 
31*875abb87SDavid van Moolenbroek #define BUF_SIZE	10240
32*875abb87SDavid van Moolenbroek 
33*875abb87SDavid van Moolenbroek char *progname;
34*875abb87SDavid van Moolenbroek int tcpfd= -1;
35*875abb87SDavid van Moolenbroek char buf[BUF_SIZE];
36*875abb87SDavid van Moolenbroek static int bulk= 0;
37*875abb87SDavid van Moolenbroek static int push= 0;
38*875abb87SDavid van Moolenbroek static int stdout_issocket= 0;
39*875abb87SDavid van Moolenbroek static int timeout;
40*875abb87SDavid van Moolenbroek 
41*875abb87SDavid van Moolenbroek static void do_conn(char *hostname, char *portname);
42*875abb87SDavid van Moolenbroek static void alrm_conn(int sig);
43*875abb87SDavid van Moolenbroek static void alrm_io(int sig);
44*875abb87SDavid van Moolenbroek static void fullduplex(void);
45*875abb87SDavid van Moolenbroek static void fatal(char *msg, ...);
46*875abb87SDavid van Moolenbroek static void usage(void);
47*875abb87SDavid van Moolenbroek 
main(int argc,char * argv[])48*875abb87SDavid van Moolenbroek int main(int argc, char *argv[])
49*875abb87SDavid van Moolenbroek {
50*875abb87SDavid van Moolenbroek 	int c;
51*875abb87SDavid van Moolenbroek 	char *hostname;
52*875abb87SDavid van Moolenbroek 	char *portname;
53*875abb87SDavid van Moolenbroek 	char *check;
54*875abb87SDavid van Moolenbroek 	int B_flag, P_flag, s_flag;
55*875abb87SDavid van Moolenbroek 	char *t_arg;
56*875abb87SDavid van Moolenbroek 
57*875abb87SDavid van Moolenbroek 	(progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
58*875abb87SDavid van Moolenbroek 
59*875abb87SDavid van Moolenbroek 	B_flag= 0;
60*875abb87SDavid van Moolenbroek 	P_flag= 0;
61*875abb87SDavid van Moolenbroek 	s_flag= 0;
62*875abb87SDavid van Moolenbroek 	t_arg= NULL;
63*875abb87SDavid van Moolenbroek 	while (c= getopt(argc, argv, "BPst:?"), c != -1)
64*875abb87SDavid van Moolenbroek 	{
65*875abb87SDavid van Moolenbroek 		switch(c)
66*875abb87SDavid van Moolenbroek 		{
67*875abb87SDavid van Moolenbroek 		case 'B':	B_flag= 1; break;
68*875abb87SDavid van Moolenbroek 		case 'P':	P_flag= 1; break;
69*875abb87SDavid van Moolenbroek 		case 's':	s_flag= 1; break;
70*875abb87SDavid van Moolenbroek 		case 't':	t_arg= optarg; break;
71*875abb87SDavid van Moolenbroek 		case '?':	usage();
72*875abb87SDavid van Moolenbroek 		default:
73*875abb87SDavid van Moolenbroek 			fatal("getopt failed: '%c'", c);
74*875abb87SDavid van Moolenbroek 		}
75*875abb87SDavid van Moolenbroek 	}
76*875abb87SDavid van Moolenbroek 	if (t_arg)
77*875abb87SDavid van Moolenbroek 	{
78*875abb87SDavid van Moolenbroek 		timeout= strtol(t_arg, &check, 0);
79*875abb87SDavid van Moolenbroek 		if (check[0] != '\0')
80*875abb87SDavid van Moolenbroek 			fatal("unable to parse timeout '%s'\n", t_arg);
81*875abb87SDavid van Moolenbroek 		if (timeout <= 0)
82*875abb87SDavid van Moolenbroek 			fatal("bad timeout '%d'\n", timeout);
83*875abb87SDavid van Moolenbroek 	}
84*875abb87SDavid van Moolenbroek 	else
85*875abb87SDavid van Moolenbroek 		timeout= 0;
86*875abb87SDavid van Moolenbroek 
87*875abb87SDavid van Moolenbroek 	if (optind+2 != argc)
88*875abb87SDavid van Moolenbroek 		usage();
89*875abb87SDavid van Moolenbroek 	hostname= argv[optind++];
90*875abb87SDavid van Moolenbroek 	portname= argv[optind++];
91*875abb87SDavid van Moolenbroek 
92*875abb87SDavid van Moolenbroek 	bulk= B_flag;
93*875abb87SDavid van Moolenbroek 	push= P_flag;
94*875abb87SDavid van Moolenbroek 	stdout_issocket= s_flag;
95*875abb87SDavid van Moolenbroek 
96*875abb87SDavid van Moolenbroek 	do_conn(hostname, portname);
97*875abb87SDavid van Moolenbroek 
98*875abb87SDavid van Moolenbroek 	/* XXX */
99*875abb87SDavid van Moolenbroek 	if (timeout)
100*875abb87SDavid van Moolenbroek 	{
101*875abb87SDavid van Moolenbroek 		signal(SIGALRM, alrm_io);
102*875abb87SDavid van Moolenbroek 		alarm(timeout);
103*875abb87SDavid van Moolenbroek 	}
104*875abb87SDavid van Moolenbroek 
105*875abb87SDavid van Moolenbroek 	fullduplex();
106*875abb87SDavid van Moolenbroek 	exit(0);
107*875abb87SDavid van Moolenbroek }
108*875abb87SDavid van Moolenbroek 
do_conn(char * hostname,char * portname)109*875abb87SDavid van Moolenbroek static void do_conn(char *hostname, char *portname)
110*875abb87SDavid van Moolenbroek {
111*875abb87SDavid van Moolenbroek 	ipaddr_t addr;
112*875abb87SDavid van Moolenbroek 	tcpport_t port;
113*875abb87SDavid van Moolenbroek 	struct hostent *he;
114*875abb87SDavid van Moolenbroek 	struct servent *se;
115*875abb87SDavid van Moolenbroek 	char *tcp_device, *check;
116*875abb87SDavid van Moolenbroek 	nwio_tcpconf_t tcpconf;
117*875abb87SDavid van Moolenbroek 	nwio_tcpcl_t tcpcl;
118*875abb87SDavid van Moolenbroek 	nwio_tcpopt_t tcpopt;
119*875abb87SDavid van Moolenbroek 
120*875abb87SDavid van Moolenbroek 	if (!inet_aton(hostname, (struct in_addr *)&addr))
121*875abb87SDavid van Moolenbroek 	{
122*875abb87SDavid van Moolenbroek 		he= gethostbyname(hostname);
123*875abb87SDavid van Moolenbroek 		if (he == NULL)
124*875abb87SDavid van Moolenbroek 			fatal("unknown hostname '%s'", hostname);
125*875abb87SDavid van Moolenbroek 		if (he->h_addrtype != AF_INET || he->h_length != sizeof(addr))
126*875abb87SDavid van Moolenbroek 			fatal("bad address for '%s'", hostname);
127*875abb87SDavid van Moolenbroek 		memcpy(&addr, he->h_addr, sizeof(addr));
128*875abb87SDavid van Moolenbroek 	}
129*875abb87SDavid van Moolenbroek 
130*875abb87SDavid van Moolenbroek 	port= strtol(portname, &check, 0);
131*875abb87SDavid van Moolenbroek 	if (check[0] != 0)
132*875abb87SDavid van Moolenbroek 	{
133*875abb87SDavid van Moolenbroek 		se= getservbyname(portname, "tcp");
134*875abb87SDavid van Moolenbroek 		if (se == NULL)
135*875abb87SDavid van Moolenbroek 			fatal("unkown port '%s'", portname);
136*875abb87SDavid van Moolenbroek 		port= ntohs(se->s_port);
137*875abb87SDavid van Moolenbroek 	}
138*875abb87SDavid van Moolenbroek 
139*875abb87SDavid van Moolenbroek 	tcp_device= getenv("TCP_DEVICE");
140*875abb87SDavid van Moolenbroek 	if (tcp_device == NULL) tcp_device= TCP_DEVICE;
141*875abb87SDavid van Moolenbroek 
142*875abb87SDavid van Moolenbroek 	tcpfd= open(tcp_device, O_RDWR);
143*875abb87SDavid van Moolenbroek 	if (tcpfd == -1)
144*875abb87SDavid van Moolenbroek 		fatal("unable to open '%s': %s", tcp_device, strerror(errno));
145*875abb87SDavid van Moolenbroek 	tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA |
146*875abb87SDavid van Moolenbroek 		NWTC_SET_RP;
147*875abb87SDavid van Moolenbroek 	tcpconf.nwtc_remaddr= addr;
148*875abb87SDavid van Moolenbroek 	tcpconf.nwtc_remport= htons(port);;
149*875abb87SDavid van Moolenbroek 	if (ioctl(tcpfd, NWIOSTCPCONF, &tcpconf) == -1)
150*875abb87SDavid van Moolenbroek 		fatal("NWIOSTCPCONF failed: %s", strerror(errno));
151*875abb87SDavid van Moolenbroek 
152*875abb87SDavid van Moolenbroek 	if (timeout)
153*875abb87SDavid van Moolenbroek 	{
154*875abb87SDavid van Moolenbroek 		signal(SIGALRM, alrm_conn);
155*875abb87SDavid van Moolenbroek 		alarm(timeout);
156*875abb87SDavid van Moolenbroek 	}
157*875abb87SDavid van Moolenbroek 
158*875abb87SDavid van Moolenbroek 	tcpcl.nwtcl_flags= 0;
159*875abb87SDavid van Moolenbroek 	if (ioctl(tcpfd, NWIOTCPCONN, &tcpcl) == -1)
160*875abb87SDavid van Moolenbroek 	{
161*875abb87SDavid van Moolenbroek 		fatal("unable to connect to %s:%u: %s",
162*875abb87SDavid van Moolenbroek 			inet_ntoa(*(struct in_addr *)&addr),
163*875abb87SDavid van Moolenbroek 			ntohs(tcpconf.nwtc_remport), strerror(errno));
164*875abb87SDavid van Moolenbroek 	}
165*875abb87SDavid van Moolenbroek 
166*875abb87SDavid van Moolenbroek 	alarm(0);
167*875abb87SDavid van Moolenbroek 
168*875abb87SDavid van Moolenbroek 	if (bulk)
169*875abb87SDavid van Moolenbroek 	{
170*875abb87SDavid van Moolenbroek 		tcpopt.nwto_flags= NWTO_BULK;
171*875abb87SDavid van Moolenbroek 		if (ioctl(tcpfd, NWIOSTCPOPT, &tcpopt) == -1)
172*875abb87SDavid van Moolenbroek 			fatal("NWIOSTCPOPT failed: %s", strerror(errno));
173*875abb87SDavid van Moolenbroek 	}
174*875abb87SDavid van Moolenbroek }
175*875abb87SDavid van Moolenbroek 
alrm_conn(int sig)176*875abb87SDavid van Moolenbroek static void alrm_conn(int sig)
177*875abb87SDavid van Moolenbroek {
178*875abb87SDavid van Moolenbroek 	fatal("timeout during connect");
179*875abb87SDavid van Moolenbroek }
180*875abb87SDavid van Moolenbroek 
alrm_io(int sig)181*875abb87SDavid van Moolenbroek static void alrm_io(int sig)
182*875abb87SDavid van Moolenbroek {
183*875abb87SDavid van Moolenbroek 	fatal("timeout during io");
184*875abb87SDavid van Moolenbroek }
185*875abb87SDavid van Moolenbroek 
fullduplex(void)186*875abb87SDavid van Moolenbroek static void fullduplex(void)
187*875abb87SDavid van Moolenbroek {
188*875abb87SDavid van Moolenbroek 	pid_t cpid;
189*875abb87SDavid van Moolenbroek 	int o, r, s, s_errno, loc;
190*875abb87SDavid van Moolenbroek 
191*875abb87SDavid van Moolenbroek 	cpid= fork();
192*875abb87SDavid van Moolenbroek 	switch(cpid)
193*875abb87SDavid van Moolenbroek 	{
194*875abb87SDavid van Moolenbroek 	case -1:	fatal("fork failed: %s", strerror(errno));
195*875abb87SDavid van Moolenbroek 	case 0:
196*875abb87SDavid van Moolenbroek 		/* Read from TCP, write to stdout. */
197*875abb87SDavid van Moolenbroek 		for (;;)
198*875abb87SDavid van Moolenbroek 		{
199*875abb87SDavid van Moolenbroek 			r= read(tcpfd, buf, BUF_SIZE);
200*875abb87SDavid van Moolenbroek 			if (r == 0)
201*875abb87SDavid van Moolenbroek 				break;
202*875abb87SDavid van Moolenbroek 			if (r == -1)
203*875abb87SDavid van Moolenbroek 			{
204*875abb87SDavid van Moolenbroek 				r= errno;
205*875abb87SDavid van Moolenbroek 				if (stdout_issocket)
206*875abb87SDavid van Moolenbroek 					ioctl(1, NWIOTCPSHUTDOWN, NULL);
207*875abb87SDavid van Moolenbroek 				fatal("error reading from TCP conn.: %s",
208*875abb87SDavid van Moolenbroek 					strerror(errno));
209*875abb87SDavid van Moolenbroek 			}
210*875abb87SDavid van Moolenbroek 			s= r;
211*875abb87SDavid van Moolenbroek 			for (o= 0; o<s; o += r)
212*875abb87SDavid van Moolenbroek 			{
213*875abb87SDavid van Moolenbroek 				r= write(1, buf+o, s-o);
214*875abb87SDavid van Moolenbroek 				if (r <= 0)
215*875abb87SDavid van Moolenbroek 				{
216*875abb87SDavid van Moolenbroek 					fatal("error writing to stdout: %s",
217*875abb87SDavid van Moolenbroek 						r == 0 ? "EOF" :
218*875abb87SDavid van Moolenbroek 						strerror(errno));
219*875abb87SDavid van Moolenbroek 				}
220*875abb87SDavid van Moolenbroek 			}
221*875abb87SDavid van Moolenbroek 		}
222*875abb87SDavid van Moolenbroek 		if (stdout_issocket)
223*875abb87SDavid van Moolenbroek 		{
224*875abb87SDavid van Moolenbroek 			r= ioctl(1, NWIOTCPSHUTDOWN, NULL);
225*875abb87SDavid van Moolenbroek 			if (r == -1)
226*875abb87SDavid van Moolenbroek 			{
227*875abb87SDavid van Moolenbroek 				fatal("NWIOTCPSHUTDOWN failed on stdout: %s",
228*875abb87SDavid van Moolenbroek 					strerror(errno));
229*875abb87SDavid van Moolenbroek 			}
230*875abb87SDavid van Moolenbroek 		}
231*875abb87SDavid van Moolenbroek 		exit(0);
232*875abb87SDavid van Moolenbroek 	default:
233*875abb87SDavid van Moolenbroek 		break;
234*875abb87SDavid van Moolenbroek 	}
235*875abb87SDavid van Moolenbroek 
236*875abb87SDavid van Moolenbroek 	/* Read from stdin, write to TCP. */
237*875abb87SDavid van Moolenbroek 	for (;;)
238*875abb87SDavid van Moolenbroek 	{
239*875abb87SDavid van Moolenbroek 		r= read(0, buf, BUF_SIZE);
240*875abb87SDavid van Moolenbroek 		if (r == 0)
241*875abb87SDavid van Moolenbroek 			break;
242*875abb87SDavid van Moolenbroek 		if (r == -1)
243*875abb87SDavid van Moolenbroek 		{
244*875abb87SDavid van Moolenbroek 			s_errno= errno;
245*875abb87SDavid van Moolenbroek 			kill(cpid, SIGTERM);
246*875abb87SDavid van Moolenbroek 			fatal("error reading from stdin: %s",
247*875abb87SDavid van Moolenbroek 				strerror(s_errno));
248*875abb87SDavid van Moolenbroek 		}
249*875abb87SDavid van Moolenbroek 		s= r;
250*875abb87SDavid van Moolenbroek 		for (o= 0; o<s; o += r)
251*875abb87SDavid van Moolenbroek 		{
252*875abb87SDavid van Moolenbroek 			r= write(tcpfd, buf+o, s-o);
253*875abb87SDavid van Moolenbroek 			if (r <= 0)
254*875abb87SDavid van Moolenbroek 			{
255*875abb87SDavid van Moolenbroek 				s_errno= errno;
256*875abb87SDavid van Moolenbroek 				kill(cpid, SIGTERM);
257*875abb87SDavid van Moolenbroek 				fatal("error writing to TCP conn.: %s",
258*875abb87SDavid van Moolenbroek 					r == 0 ? "EOF" :
259*875abb87SDavid van Moolenbroek 					strerror(s_errno));
260*875abb87SDavid van Moolenbroek 			}
261*875abb87SDavid van Moolenbroek 		}
262*875abb87SDavid van Moolenbroek 		if (push)
263*875abb87SDavid van Moolenbroek 			ioctl(tcpfd, NWIOTCPPUSH, NULL);
264*875abb87SDavid van Moolenbroek 	}
265*875abb87SDavid van Moolenbroek 	if (ioctl(tcpfd, NWIOTCPSHUTDOWN, NULL) == -1)
266*875abb87SDavid van Moolenbroek 	{
267*875abb87SDavid van Moolenbroek 		s_errno= errno;
268*875abb87SDavid van Moolenbroek 		kill(cpid, SIGTERM);
269*875abb87SDavid van Moolenbroek 		fatal("unable to shut down TCP conn.: %s", strerror(s_errno));
270*875abb87SDavid van Moolenbroek 	}
271*875abb87SDavid van Moolenbroek 
272*875abb87SDavid van Moolenbroek 	r= waitpid(cpid, &loc, 0);
273*875abb87SDavid van Moolenbroek 	if (r == -1)
274*875abb87SDavid van Moolenbroek 	{
275*875abb87SDavid van Moolenbroek 		s_errno= errno;
276*875abb87SDavid van Moolenbroek 		kill(cpid, SIGTERM);
277*875abb87SDavid van Moolenbroek 		fatal("waitpid failed: %s", strerror(s_errno));
278*875abb87SDavid van Moolenbroek 	}
279*875abb87SDavid van Moolenbroek 	if (WIFEXITED(loc))
280*875abb87SDavid van Moolenbroek 		exit(WEXITSTATUS(loc));
281*875abb87SDavid van Moolenbroek 	kill(getpid(), WTERMSIG(loc));
282*875abb87SDavid van Moolenbroek 	exit(1);
283*875abb87SDavid van Moolenbroek }
284*875abb87SDavid van Moolenbroek 
fatal(char * fmt,...)285*875abb87SDavid van Moolenbroek static void fatal(char *fmt, ...)
286*875abb87SDavid van Moolenbroek {
287*875abb87SDavid van Moolenbroek 	va_list ap;
288*875abb87SDavid van Moolenbroek 
289*875abb87SDavid van Moolenbroek 	va_start(ap, fmt);
290*875abb87SDavid van Moolenbroek 	fprintf(stderr, "%s: ", progname);
291*875abb87SDavid van Moolenbroek 	vfprintf(stderr, fmt, ap);
292*875abb87SDavid van Moolenbroek 	fprintf(stderr, "\n");
293*875abb87SDavid van Moolenbroek 	va_end(ap);
294*875abb87SDavid van Moolenbroek 	exit(1);
295*875abb87SDavid van Moolenbroek }
296*875abb87SDavid van Moolenbroek 
usage(void)297*875abb87SDavid van Moolenbroek static void usage(void)
298*875abb87SDavid van Moolenbroek {
299*875abb87SDavid van Moolenbroek 	fprintf(stderr, "Usage: %s [-BPs] [-t timeout] hostname portname\n",
300*875abb87SDavid van Moolenbroek 		progname);
301*875abb87SDavid van Moolenbroek 	exit(1);
302*875abb87SDavid van Moolenbroek }
303*875abb87SDavid van Moolenbroek 
304*875abb87SDavid van Moolenbroek /*
305*875abb87SDavid van Moolenbroek  * $PchId: socket.c,v 1.3 2005/01/31 22:33:20 philip Exp $
306*875abb87SDavid van Moolenbroek  */
307