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