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