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