xref: /openbsd/regress/usr.bin/nc/server-tcp.c (revision 5a9255e7)
1*5a9255e7Sbluhm /*	$OpenBSD: server-tcp.c,v 1.4 2021/07/06 11:50:34 bluhm Exp $	*/
2d80889b6Sbluhm 
3d80889b6Sbluhm /*
4d80889b6Sbluhm  * Copyright (c) 2020 Alexander Bluhm <bluhm@openbsd.org>
5d80889b6Sbluhm  *
6d80889b6Sbluhm  * Permission to use, copy, modify, and distribute this software for any
7d80889b6Sbluhm  * purpose with or without fee is hereby granted, provided that the above
8d80889b6Sbluhm  * copyright notice and this permission notice appear in all copies.
9d80889b6Sbluhm  *
10d80889b6Sbluhm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11d80889b6Sbluhm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12d80889b6Sbluhm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13d80889b6Sbluhm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14d80889b6Sbluhm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15d80889b6Sbluhm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16d80889b6Sbluhm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17d80889b6Sbluhm  */
18d80889b6Sbluhm 
19d80889b6Sbluhm #include <sys/types.h>
20d80889b6Sbluhm #include <sys/socket.h>
21d80889b6Sbluhm 
22d80889b6Sbluhm #include <err.h>
23d80889b6Sbluhm #include <errno.h>
24d80889b6Sbluhm #include <netdb.h>
25d80889b6Sbluhm #include <stdio.h>
26d80889b6Sbluhm #include <stdlib.h>
27d80889b6Sbluhm #include <string.h>
28d80889b6Sbluhm #include <unistd.h>
29d80889b6Sbluhm 
30d80889b6Sbluhm #include "util.h"
31d80889b6Sbluhm 
32d80889b6Sbluhm void __dead usage(void);
33d80889b6Sbluhm int listen_socket(const char *, const char *);
34d80889b6Sbluhm int accept_socket(int);
35d80889b6Sbluhm 
36d80889b6Sbluhm void __dead
usage(void)37d80889b6Sbluhm usage(void)
38d80889b6Sbluhm {
39d80889b6Sbluhm 	fprintf(stderr, "server-tcp [-r rcvmsg] [-s sndmsg] host port\n"
40f214d6d2Sbluhm 	"    -E         wait for EOF\n"
41f214d6d2Sbluhm 	"    -N         shutdown write\n"
42d80889b6Sbluhm 	"    -r rcvmsg  receive from client and check message\n"
43d80889b6Sbluhm 	"    -s sndmsg  send message to client\n");
44d80889b6Sbluhm 	exit(2);
45d80889b6Sbluhm }
46d80889b6Sbluhm 
47d80889b6Sbluhm int
main(int argc,char * argv[])48d80889b6Sbluhm main(int argc, char *argv[])
49d80889b6Sbluhm {
50d80889b6Sbluhm 	const char *host, *port;
51f214d6d2Sbluhm 	struct task todo[100];
52f214d6d2Sbluhm 	size_t tlen = 0;
53d80889b6Sbluhm 	int ch, s;
54d80889b6Sbluhm 
55f214d6d2Sbluhm 	while ((ch = getopt(argc, argv, "ENr:s:")) != -1) {
56d80889b6Sbluhm 		switch (ch) {
57f214d6d2Sbluhm 		case 'E':
58f214d6d2Sbluhm 		case 'N':
59d80889b6Sbluhm 		case 'r':
60d80889b6Sbluhm 		case 's':
61f214d6d2Sbluhm 			if (tlen >= sizeof(todo) / sizeof(todo[0]))
62f214d6d2Sbluhm 				errx(1, "too many tasks");
63f214d6d2Sbluhm 			task_enqueue(&todo[tlen], ch, optarg);
64f214d6d2Sbluhm 			tlen++;
65d80889b6Sbluhm 			break;
66d80889b6Sbluhm 		default:
67d80889b6Sbluhm 			usage();
68d80889b6Sbluhm 		}
69d80889b6Sbluhm 	}
70d80889b6Sbluhm 	argc -= optind;
71d80889b6Sbluhm 	argv += optind;
72d80889b6Sbluhm 
73d80889b6Sbluhm 	if (argc == 2) {
74d80889b6Sbluhm 		host = argv[0];
75d80889b6Sbluhm 		port = argv[1];
76d80889b6Sbluhm 	} else {
77d80889b6Sbluhm 		usage();
78d80889b6Sbluhm 	}
79d80889b6Sbluhm 
80*5a9255e7Sbluhm 	alarm(10);
81d80889b6Sbluhm 	s = listen_socket(host, port);
82d80889b6Sbluhm 	print_sockname(s);
83d80889b6Sbluhm 
84d80889b6Sbluhm 	switch (fork()) {
85d80889b6Sbluhm 	case -1:
86d80889b6Sbluhm 		err(1, "fork");
87d80889b6Sbluhm 	case 0:
88f214d6d2Sbluhm 		/* child continues, set timer for new process */
89*5a9255e7Sbluhm 		alarm(10);
90d80889b6Sbluhm 		break;
91d80889b6Sbluhm 	default:
92d80889b6Sbluhm 		/* parent exits and test runs in parallel */
93d80889b6Sbluhm 		_exit(0);
94d80889b6Sbluhm 	}
95d80889b6Sbluhm 
96d80889b6Sbluhm 	s = accept_socket(s);
97f214d6d2Sbluhm 	task_run(s, todo, tlen);
98d80889b6Sbluhm 	if (close(s) == -1)
99d80889b6Sbluhm 		err(1, "close");
100d80889b6Sbluhm 
101d80889b6Sbluhm 	return 0;
102d80889b6Sbluhm }
103d80889b6Sbluhm 
104d80889b6Sbluhm int
listen_socket(const char * host,const char * port)105d80889b6Sbluhm listen_socket(const char *host, const char *port)
106d80889b6Sbluhm {
107d80889b6Sbluhm 	struct addrinfo hints, *res, *res0;
108d80889b6Sbluhm 	int error;
109d80889b6Sbluhm 	int save_errno;
110d80889b6Sbluhm 	int s;
111d80889b6Sbluhm 	const char *cause = NULL;
112d80889b6Sbluhm 
113d80889b6Sbluhm 	memset(&hints, 0, sizeof(hints));
114d80889b6Sbluhm 	hints.ai_family = AF_UNSPEC;
115d80889b6Sbluhm 	hints.ai_socktype = SOCK_STREAM;
116d80889b6Sbluhm 	hints.ai_flags = AI_PASSIVE;
117d80889b6Sbluhm 	error = getaddrinfo(host, port, &hints, &res0);
118d80889b6Sbluhm 	if (error)
119d80889b6Sbluhm 		errx(1, "%s", gai_strerror(error));
120d80889b6Sbluhm 	for (res = res0; res; res = res->ai_next) {
121d80889b6Sbluhm 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
122d80889b6Sbluhm 		if (s == -1) {
123d80889b6Sbluhm 			cause = "socket";
124d80889b6Sbluhm 			continue;
125d80889b6Sbluhm 		}
126d80889b6Sbluhm 		if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
127d80889b6Sbluhm 			cause = "bind";
128d80889b6Sbluhm 			save_errno = errno;
129d80889b6Sbluhm 			close(s);
1305163d52cSbluhm 			s = -1;
131d80889b6Sbluhm 			errno = save_errno;
132d80889b6Sbluhm 			continue;
133d80889b6Sbluhm 		}
134d80889b6Sbluhm 		break;  /* okay we got one */
135d80889b6Sbluhm 	}
136d80889b6Sbluhm 	if (s == -1)
137d80889b6Sbluhm 		err(1, "%s", cause);
138d80889b6Sbluhm 	freeaddrinfo(res0);
139d80889b6Sbluhm 
140d80889b6Sbluhm 	if (listen(s, 5) == -1)
141d80889b6Sbluhm 		err(1, "listen");
142d80889b6Sbluhm 	return s;
143d80889b6Sbluhm }
144d80889b6Sbluhm 
145d80889b6Sbluhm int
accept_socket(int s)146d80889b6Sbluhm accept_socket(int s)
147d80889b6Sbluhm {
148d80889b6Sbluhm 	struct sockaddr_storage ss;
149d80889b6Sbluhm 	socklen_t slen;
150d80889b6Sbluhm 	char host[NI_MAXHOST], port[NI_MAXSERV];
151d80889b6Sbluhm 
152d80889b6Sbluhm 	slen = sizeof(ss);
153d80889b6Sbluhm 	s = accept(s, (struct sockaddr *)&ss, &slen);
154d80889b6Sbluhm 	if (s == -1)
155d80889b6Sbluhm 		err(1, "accept");
156d80889b6Sbluhm 	if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host),
157d80889b6Sbluhm 	    port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV))
158d80889b6Sbluhm 		errx(1, "getnameinfo");
159d80889b6Sbluhm 	fprintf(stderr, "peer: %s %s\n", host, port);
160d80889b6Sbluhm 
161d80889b6Sbluhm 	return s;
162d80889b6Sbluhm }
163