1 /* $OpenBSD: client-tcp.c,v 1.3 2021/07/06 11:50:34 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
usage(void)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
main(int argc,char * argv[])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(10);
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
connect_socket(const char * host,const char * port)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