xref: /openbsd-src/regress/usr.bin/nc/client-tcp.c (revision 5a9255e7fde1eff660134511e5a28e2366fbe25a)
1*5a9255e7Sbluhm /*	$OpenBSD: client-tcp.c,v 1.3 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 connect_socket(const char *, const char *);
34d80889b6Sbluhm 
35d80889b6Sbluhm void __dead
usage(void)36d80889b6Sbluhm usage(void)
37d80889b6Sbluhm {
38d80889b6Sbluhm 	fprintf(stderr, "client [-r rcvmsg] [-s sndmsg] host port\n"
39f214d6d2Sbluhm 	"    -E         wait for EOF\n"
40f214d6d2Sbluhm 	"    -N         shutdown write\n"
41d80889b6Sbluhm 	"    -r rcvmsg  receive from server and check message\n"
42d80889b6Sbluhm 	"    -s sndmsg  send message to server\n");
43d80889b6Sbluhm 	exit(2);
44d80889b6Sbluhm }
45d80889b6Sbluhm 
46d80889b6Sbluhm int
main(int argc,char * argv[])47d80889b6Sbluhm main(int argc, char *argv[])
48d80889b6Sbluhm {
49d80889b6Sbluhm 	const char *host, *port;
50f214d6d2Sbluhm 	struct task todo[100];
51f214d6d2Sbluhm 	size_t tlen = 0;
52d80889b6Sbluhm 	int ch, s;
53d80889b6Sbluhm 
54f214d6d2Sbluhm 	while ((ch = getopt(argc, argv, "ENr:s:")) != -1) {
55d80889b6Sbluhm 		switch (ch) {
56f214d6d2Sbluhm 		case 'E':
57f214d6d2Sbluhm 		case 'N':
58d80889b6Sbluhm 		case 'r':
59d80889b6Sbluhm 		case 's':
60f214d6d2Sbluhm 			if (tlen >= sizeof(todo) / sizeof(todo[0]))
61f214d6d2Sbluhm 				errx(1, "too many tasks");
62f214d6d2Sbluhm 			task_enqueue(&todo[tlen], ch, optarg);
63f214d6d2Sbluhm 			tlen++;
64d80889b6Sbluhm 			break;
65d80889b6Sbluhm 		default:
66d80889b6Sbluhm 			usage();
67d80889b6Sbluhm 		}
68d80889b6Sbluhm 	}
69d80889b6Sbluhm 	argc -= optind;
70d80889b6Sbluhm 	argv += optind;
71d80889b6Sbluhm 
72d80889b6Sbluhm 	if (argc == 2) {
73d80889b6Sbluhm 		host = argv[0];
74d80889b6Sbluhm 		port = argv[1];
75d80889b6Sbluhm 	} else {
76d80889b6Sbluhm 		usage();
77d80889b6Sbluhm 	}
78d80889b6Sbluhm 
79*5a9255e7Sbluhm 	alarm(10);
80d80889b6Sbluhm 	s = connect_socket(host, port);
81d80889b6Sbluhm 	print_sockname(s);
82d80889b6Sbluhm 	print_peername(s);
83f214d6d2Sbluhm 	task_run(s, todo, tlen);
84d80889b6Sbluhm 	if (close(s) == -1)
85d80889b6Sbluhm 		err(1, "close");
86d80889b6Sbluhm 
87d80889b6Sbluhm 	return 0;
88d80889b6Sbluhm }
89d80889b6Sbluhm 
90d80889b6Sbluhm int
connect_socket(const char * host,const char * port)91d80889b6Sbluhm connect_socket(const char *host, const char *port)
92d80889b6Sbluhm {
93d80889b6Sbluhm 	struct addrinfo hints, *res, *res0;
94d80889b6Sbluhm 	int error;
95d80889b6Sbluhm 	int save_errno;
96d80889b6Sbluhm 	int s;
97d80889b6Sbluhm 	const char *cause = NULL;
98d80889b6Sbluhm 
99d80889b6Sbluhm 	memset(&hints, 0, sizeof(hints));
100d80889b6Sbluhm 	hints.ai_family = AF_UNSPEC;
101d80889b6Sbluhm 	hints.ai_socktype = SOCK_STREAM;
102d80889b6Sbluhm 	error = getaddrinfo(host, port, &hints, &res0);
103d80889b6Sbluhm 	if (error)
104d80889b6Sbluhm 		errx(1, "%s", gai_strerror(error));
105d80889b6Sbluhm 	s = -1;
106d80889b6Sbluhm 	for (res = res0; res; res = res->ai_next) {
107d80889b6Sbluhm 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
108d80889b6Sbluhm 		if (s == -1) {
109d80889b6Sbluhm 			cause = "socket";
110d80889b6Sbluhm 			continue;
111d80889b6Sbluhm 		}
112d80889b6Sbluhm 		if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
113d80889b6Sbluhm 			cause = "connect";
114d80889b6Sbluhm 			save_errno = errno;
115d80889b6Sbluhm 			close(s);
116d80889b6Sbluhm 			errno = save_errno;
117d80889b6Sbluhm 			s = -1;
118d80889b6Sbluhm 			continue;
119d80889b6Sbluhm 		}
120d80889b6Sbluhm 		break;  /* okay we got one */
121d80889b6Sbluhm 	}
122d80889b6Sbluhm 	if (s == -1)
123d80889b6Sbluhm 		err(1, "%s", cause);
124d80889b6Sbluhm 	freeaddrinfo(res0);
125d80889b6Sbluhm 
126d80889b6Sbluhm 	return s;
127d80889b6Sbluhm }
128