vfs: check userland buffers before reading them.
[haiku.git] / src / tests / kits / net / sock / main.c
blob73a441457776ea9b27094f8ce3ccbc9c4d9a51e4
1 /* -*- c-basic-offset: 8; -*-
3 * Copyright (c) 1993 W. Richard Stevens. All rights reserved.
4 * Permission to use or modify this software and its documentation only for
5 * educational purposes and without fee is hereby granted, provided that
6 * the above copyright notice appear in all copies. The author makes no
7 * representations about the suitability of this software for any purpose.
8 * It is provided "as is" without express or implied warranty.
9 */
11 #include <stdio.h>
12 #include <netdb.h>
13 #include <sys/types.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
16 #include <unistd.h>
17 #ifdef HAVE_GETOPT_H
18 #include <getopt.h>
19 #endif
20 #include <string.h>
21 #include "sock.h"
23 char *host; /* hostname or dotted-decimal string */
24 char *port;
26 /* DefinE global variables */
27 int bindport; /* 0 or TCP or UDP port number to bind */
28 /* set by -b or -l options */
29 int broadcast; /* SO_BROADCAST */
30 int cbreak; /* set terminal to cbreak mode */
31 int chunkwrite; /* write in small chunks; not all-at-once */
32 int client = 1; /* acting as client is the default */
33 int connectudp = 1; /* connect UDP client */
34 int crlf; /* convert newline to CR/LF & vice versa */
35 int debug; /* SO_DEBUG */
36 int dofork; /* concurrent server, do a fork() */
37 int dontroute; /* SO_DONTROUTE */
38 char foreignip[32]; /* foreign IP address, dotted-decimal string */
39 int foreignport; /* foreign port number */
40 int halfclose; /* TCP half close option */
41 int ignorewerr; /* true if write() errors should be ignored */
42 int iptos = -1; /* IP_TOS opton */
43 int ipttl = -1; /* IP_TTL opton */
44 char joinip[32]; /* multicast IP address, dotted-decimal string */
45 int keepalive; /* SO_KEEPALIVE */
46 long linger = -1; /* 0 or positive turns on option */
47 int listenq = 5; /* listen queue for TCP Server */
48 char localip[32]; /* local IP address, dotted-decimal string */
49 int maxseg; /* TCP_MAXSEG */
50 int mcastttl; /* multicast TTL */
51 int msgpeek; /* MSG_PEEK */
52 int nodelay; /* TCP_NODELAY (Nagle algorithm) */
53 int nbuf = 1024; /* number of buffers to write (sink mode) */
54 int onesbcast; /* set IP_ONESBCAST for 255.255.255.255 bcasts */
55 int pauseclose; /* #ms to sleep after recv FIN, before close */
56 int pauseinit; /* #ms to sleep before first read */
57 int pauselisten; /* #ms to sleep after listen() */
58 int pauserw; /* #ms to sleep before each read or write */
59 int reuseaddr; /* SO_REUSEADDR */
60 int reuseport; /* SO_REUSEPORT */
61 int readlen = 1024; /* default read length for socket */
62 int writelen = 1024; /* default write length for socket */
63 int recvdstaddr; /* IP_RECVDSTADDR option */
64 int rcvbuflen; /* size for SO_RCVBUF */
65 int sndbuflen; /* size for SO_SNDBUF */
66 long rcvtimeo; /* SO_RCVTIMEO */
67 long sndtimeo; /* SO_SNDTIMEO */
68 int sroute_cnt; /* count of #IP addresses in route */
69 char *rbuf; /* pointer that is malloc'ed */
70 char *wbuf; /* pointer that is malloc'ed */
71 int server; /* to act as server requires -s option */
72 int sigio; /* send SIGIO */
73 int sourcesink; /* source/sink mode */
74 int udp; /* use UDP instead of TCP */
75 int urgwrite; /* write urgent byte after this write */
76 int verbose; /* each -v increments this by 1 */
77 int usewritev; /* use writev() instead of write() */
79 struct sockaddr_in cliaddr, servaddr;
81 static void usage(const char *);
83 int
84 main(int argc, char *argv[])
86 int c, fd;
87 char *ptr;
89 if (argc < 2)
90 usage("");
92 opterr = 0; /* don't want getopt() writing to stderr */
93 while ( (c = getopt(argc, argv, "2b:cf:g:hij:kl:n:op:q:r:st:uvw:x:y:ABCDEFG:H:IJ:KL:NO:P:Q:R:S:TU:VWX:YZ")) != -1) {
94 switch (c) {
95 #ifdef IP_ONESBCAST
96 case '2': /* use 255.255.255.255 as broadcast address */
97 onesbcast = 1;
98 break;
99 #endif
101 case 'b':
102 bindport = atoi(optarg);
103 break;
105 case 'c': /* convert newline to CR/LF & vice versa */
106 crlf = 1;
107 break;
109 case 'f': /* foreign IP address and port#: a.b.c.d.p */
110 if ( (ptr = strrchr(optarg, '.')) == NULL)
111 usage("invalid -f option");
113 *ptr++ = 0; /* null replaces final period */
114 foreignport = atoi(ptr); /* port number */
115 strcpy(foreignip, optarg); /* save dotted-decimal IP */
116 break;
118 case 'g': /* loose source route */
119 sroute_doopt(0, optarg);
120 break;
122 case 'h': /* TCP half-close option */
123 halfclose = 1;
124 break;
126 case 'i': /* source/sink option */
127 sourcesink = 1;
128 break;
130 #ifdef IP_ADD_MEMBERSHIP
131 case 'j': /* join multicast group a.b.c.d */
132 strcpy(joinip, optarg); /* save dotted-decimal IP */
133 break;
134 #endif
136 case 'k': /* chunk-write option */
137 chunkwrite = 1;
138 break;
140 case 'l': /* local IP address and port#: a.b.c.d.p */
141 if ( (ptr = strrchr(optarg, '.')) == NULL)
142 usage("invalid -l option");
144 *ptr++ = 0; /* null replaces final period */
145 bindport = atoi(ptr); /* port number */
146 strcpy(localip, optarg); /* save dotted-decimal IP */
147 break;
149 case 'n': /* number of buffers to write */
150 nbuf = atol(optarg);
151 break;
153 case 'o': /* do not connect UDP client */
154 connectudp = 0;
155 break;
157 case 'p': /* pause before each read or write */
158 pauserw = atoi(optarg);
159 break;
161 case 'q': /* listen queue for TCP server */
162 listenq = atoi(optarg);
163 break;
165 case 'r': /* read() length */
166 readlen = atoi(optarg);
167 break;
169 case 's': /* server */
170 server = 1;
171 client = 0;
172 break;
174 #ifdef IP_MULTICAST_TTL
175 case 't': /* IP_MULTICAST_TTL */
176 mcastttl = atoi(optarg);
177 break;
178 #endif
180 case 'u': /* use UDP instead of TCP */
181 udp = 1;
182 break;
184 case 'v': /* output what's going on */
185 verbose++;
186 break;
188 case 'w': /* write() length */
189 writelen = atoi(optarg);
190 break;
192 case 'x': /* SO_RCVTIMEO socket option */
193 rcvtimeo = atol(optarg);
194 break;
196 case 'y': /* SO_SNDTIMEO socket option */
197 sndtimeo = atol(optarg);
198 break;
200 case 'A': /* SO_REUSEADDR socket option */
201 reuseaddr = 1;
202 break;
204 case 'B': /* SO_BROADCAST socket option */
205 broadcast = 1;
206 break;
208 case 'C': /* set standard input to cbreak mode */
209 cbreak = 1;
210 break;
212 case 'D': /* SO_DEBUG socket option */
213 debug = 1;
214 break;
216 case 'E': /* IP_RECVDSTADDR socket option */
217 recvdstaddr = 1;
218 break;
220 case 'F': /* concurrent server, do a fork() */
221 dofork = 1;
222 break;
224 case 'G': /* strict source route */
225 sroute_doopt(1, optarg);
226 break;
228 #ifdef IP_TOS
229 case 'H': /* IP_TOS socket option */
230 iptos = atoi(optarg);
231 break;
232 #endif
234 case 'I': /* SIGIO signal */
235 sigio = 1;
236 break;
238 #ifdef IP_TTL
239 case 'J': /* IP_TTL socket option */
240 ipttl = atoi(optarg);
241 break;
242 #endif
244 case 'K': /* SO_KEEPALIVE socket option */
245 keepalive = 1;
246 break;
248 case 'L': /* SO_LINGER socket option */
249 linger = atol(optarg);
250 break;
252 case 'N': /* SO_NODELAY socket option */
253 nodelay = 1;
254 break;
256 case 'O': /* pause before listen(), before first accept() */
257 pauselisten = atoi(optarg);
258 break;
260 case 'P': /* pause before first read() */
261 pauseinit = atoi(optarg);
262 break;
264 case 'Q': /* pause after receiving FIN, but before close() */
265 pauseclose = atoi(optarg);
266 break;
268 case 'R': /* SO_RCVBUF socket option */
269 rcvbuflen = atoi(optarg);
270 break;
272 case 'S': /* SO_SNDBUF socket option */
273 sndbuflen = atoi(optarg);
274 break;
276 #ifdef SO_REUSEPORT
277 case 'T': /* SO_REUSEPORT socket option */
278 reuseport = 1;
279 break;
280 #endif
282 case 'U': /* when to write urgent byte */
283 urgwrite = atoi(optarg);
284 break;
286 case 'V': /* use writev() instead of write() */
287 usewritev = 1;
288 chunkwrite = 1; /* implies this option too */
289 break;
291 case 'W': /* ignore write errors */
292 ignorewerr = 1;
293 break;
295 case 'X': /* TCP maximum segment size option */
296 maxseg = atoi(optarg);
297 break;
299 case 'Y': /* SO_DONTROUTE socket option */
300 dontroute = 1;
301 break;
303 case 'Z': /* MSG_PEEK option */
304 msgpeek = MSG_PEEK;
305 break;
307 case '?':
308 usage("unrecognized option");
312 /* check for options that don't make sense */
313 if (udp && halfclose)
314 usage("can't specify -h and -u");
315 if (udp && debug)
316 usage("can't specify -D and -u");
317 if (udp && linger >= 0)
318 usage("can't specify -L and -u");
319 if (udp && nodelay)
320 usage("can't specify -N and -u");
321 #ifdef notdef
322 if (udp == 0 && broadcast)
323 usage("can't specify -B with TCP");
324 #endif
325 if (udp == 0 && foreignip[0] != 0)
326 usage("can't specify -f with TCP");
328 if (client) {
329 if (optind != argc-2)
330 usage("missing <hostname> and/or <port>");
331 host = argv[optind];
332 port = argv[optind+1];
334 } else {
335 /* If server specifies host and port, then local address is
336 bound to the "host" argument, instead of being wildcarded. */
337 if (optind == argc-2) {
338 host = argv[optind];
339 port = argv[optind+1];
340 } else if (optind == argc-1) {
341 host = NULL;
342 port = argv[optind];
343 } else
344 usage("missing <port>");
347 if (client)
348 fd = cliopen(host, port);
349 else
350 fd = servopen(host, port);
352 if (sourcesink) { /* ignore stdin/stdout */
353 if (client) {
354 if (udp)
355 source_udp(fd);
356 else
357 source_tcp(fd);
358 } else {
359 if (udp)
360 sink_udp(fd);
361 else
362 sink_tcp(fd);
365 } else { /* copy stdin/stdout to/from socket */
366 if (udp)
367 loop_udp(fd);
368 else
369 loop_tcp(fd);
372 exit(0);
375 static void
376 usage(const char *msg)
378 err_msg(
379 "usage: sock [ options ] <host> <port> (for client; default)\n"
380 " sock [ options ] -s [ <IPaddr> ] <port> (for server)\n"
381 " sock [ options ] -i <host> <port> (for \"source\" client)\n"
382 " sock [ options ] -i -s [ <IPaddr> ] <port> (for \"sink\" server)\n"
383 "options: -b n bind n as client's local port number\n"
384 " -c convert newline to CR/LF & vice versa\n"
385 " -f a.b.c.d.p foreign IP address = a.b.c.d, foreign port# = p\n"
386 " -g a.b.c.d loose source route\n"
387 " -h issue TCP half close on standard input EOF\n"
388 " -i \"source\" data to socket, \"sink\" data from socket (w/-s)\n"
389 #ifdef IP_ADD_MEMBERSHIP
390 " -j a.b.c.d join multicast group\n"
391 #endif
392 " -k write or writev in chunks\n"
393 " -l a.b.c.d.p client's local IP address = a.b.c.d, local port# = p\n"
394 " -n n #buffers to write for \"source\" client (default 1024)\n"
395 " -o do NOT connect UDP client\n"
396 " -p n #ms to pause before each read or write (source/sink)\n"
397 " -q n size of listen queue for TCP server (default 5)\n"
398 " -r n #bytes per read() for \"sink\" server (default 1024)\n"
399 " -s operate as server instead of client\n"
400 #ifdef IP_MULTICAST_TTL
401 " -t n set multicast ttl\n"
402 #endif
403 " -u use UDP instead of TCP\n"
404 " -v verbose\n"
405 " -w n #bytes per write() for \"source\" client (default 1024)\n"
406 " -x n #ms for SO_RCVTIMEO (receive timeout)\n"
407 " -y n #ms for SO_SNDTIMEO (send timeout)\n"
408 " -A SO_REUSEADDR option\n"
409 " -B SO_BROADCAST option\n"
410 " -C set terminal to cbreak mode\n"
411 " -D SO_DEBUG option\n"
412 " -E IP_RECVDSTADDR option\n"
413 " -F fork after connection accepted (TCP concurrent server)\n"
414 " -G a.b.c.d strict source route\n"
415 #ifdef IP_TOS
416 " -H n IP_TOS option (16=min del, 8=max thru, 4=max rel, 2=min$)\n"
417 #endif
418 " -I SIGIO signal\n"
419 #ifdef IP_TTL
420 " -J n IP_TTL option\n"
421 #endif
422 " -K SO_KEEPALIVE option\n"
423 " -L n SO_LINGER option, n = linger time\n"
424 " -N TCP_NODELAY option\n"
425 " -O n #ms to pause after listen, but before first accept\n"
426 " -P n #ms to pause before first read or write (source/sink)\n"
427 " -Q n #ms to pause after receiving FIN, but before close\n"
428 " -R n SO_RCVBUF option\n"
429 " -S n SO_SNDBUF option\n"
430 #ifdef SO_REUSEPORT
431 " -T SO_REUSEPORT option\n"
432 #endif
433 " -U n enter urgent mode before write number n (source only)\n"
434 " -V use writev() instead of write(); enables -k too\n"
435 " -W ignore write errors for sink client\n"
436 " -X n TCP_MAXSEG option (set MSS)\n"
437 " -Y SO_DONTROUTE option\n"
438 " -Z MSG_PEEK\n"
439 #ifdef IP_ONESBCAST
440 " -2 IP_ONESBCAST option (255.255.255.255 for broadcast\n"
441 #endif
444 if (msg[0] != 0)
445 err_quit("%s", msg);
446 exit(1);