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