1*5a9255e7Sbluhm /* $OpenBSD: util.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
task_enqueue(struct task * todo,int ch,const char * msg)33f214d6d2Sbluhm task_enqueue(struct task *todo, int ch, const char *msg)
34f214d6d2Sbluhm {
35f214d6d2Sbluhm switch (ch) {
36f214d6d2Sbluhm case 'E':
37f214d6d2Sbluhm todo->t_type = TEOF;
38f214d6d2Sbluhm todo->t_msg = NULL;
39f214d6d2Sbluhm break;
40f214d6d2Sbluhm case 'N':
41f214d6d2Sbluhm todo->t_type = TDWN;
42f214d6d2Sbluhm todo->t_msg = NULL;
43f214d6d2Sbluhm break;
44f214d6d2Sbluhm case 'r':
45f214d6d2Sbluhm todo->t_type = TRCV;
46f214d6d2Sbluhm todo->t_msg = msg;
47f214d6d2Sbluhm break;
48f214d6d2Sbluhm case 's':
49f214d6d2Sbluhm todo->t_type = TSND;
50f214d6d2Sbluhm todo->t_msg = msg;
51f214d6d2Sbluhm break;
52f214d6d2Sbluhm }
53f214d6d2Sbluhm }
54f214d6d2Sbluhm
55f214d6d2Sbluhm void
task_run(int s,struct task * todolist,size_t tlen)56f214d6d2Sbluhm task_run(int s, struct task *todolist, size_t tlen)
57f214d6d2Sbluhm {
58f214d6d2Sbluhm size_t t;
59f214d6d2Sbluhm
60f214d6d2Sbluhm for (t = 0; t < tlen; t++) {
61f214d6d2Sbluhm switch(todolist[t].t_type) {
62f214d6d2Sbluhm case TEOF:
63f214d6d2Sbluhm receive_eof(s);
64f214d6d2Sbluhm break;
65f214d6d2Sbluhm case TDWN:
66f214d6d2Sbluhm send_shutdown(s);
67f214d6d2Sbluhm break;
68f214d6d2Sbluhm case TRCV:
69f214d6d2Sbluhm receive_line(s, todolist[t].t_msg);
70f214d6d2Sbluhm break;
71f214d6d2Sbluhm case TSND:
72f214d6d2Sbluhm send_line(s, todolist[t].t_msg);
73f214d6d2Sbluhm break;
74f214d6d2Sbluhm }
75f214d6d2Sbluhm }
76f214d6d2Sbluhm }
77f214d6d2Sbluhm
78f214d6d2Sbluhm void
print_sockname(int s)79d80889b6Sbluhm print_sockname(int s)
80d80889b6Sbluhm {
81d80889b6Sbluhm struct sockaddr_storage ss;
82d80889b6Sbluhm socklen_t slen;
83d80889b6Sbluhm char host[NI_MAXHOST], port[NI_MAXSERV];
84d80889b6Sbluhm
85d80889b6Sbluhm slen = sizeof(ss);
86d80889b6Sbluhm if (getsockname(s, (struct sockaddr *)&ss, &slen) == -1)
87d80889b6Sbluhm err(1, "getsockname");
88d80889b6Sbluhm if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host),
89d80889b6Sbluhm port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV))
90d80889b6Sbluhm errx(1, "getnameinfo");
91d80889b6Sbluhm printf("%s\n", port);
92d80889b6Sbluhm if (fflush(stdout) != 0)
93d80889b6Sbluhm err(1, "fflush stdout");
94d80889b6Sbluhm fprintf(stderr, "sock: %s %s\n", host, port);
95d80889b6Sbluhm }
96d80889b6Sbluhm
97d80889b6Sbluhm void
print_peername(int s)98d80889b6Sbluhm print_peername(int s)
99d80889b6Sbluhm {
100d80889b6Sbluhm struct sockaddr_storage ss;
101d80889b6Sbluhm socklen_t slen;
102d80889b6Sbluhm char host[NI_MAXHOST], port[NI_MAXSERV];
103d80889b6Sbluhm
104d80889b6Sbluhm slen = sizeof(ss);
105d80889b6Sbluhm if (getpeername(s, (struct sockaddr *)&ss, &slen) == -1)
106d80889b6Sbluhm err(1, "getpeername");
107d80889b6Sbluhm if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host),
108d80889b6Sbluhm port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV))
109d80889b6Sbluhm errx(1, "getnameinfo");
110d80889b6Sbluhm fprintf(stderr, "peer: %s %s\n", host, port);
111d80889b6Sbluhm }
112d80889b6Sbluhm
113d80889b6Sbluhm void
receive_eof(int s)114f214d6d2Sbluhm receive_eof(int s)
115f214d6d2Sbluhm {
116f214d6d2Sbluhm char buf[100];
117f214d6d2Sbluhm size_t len;
118f214d6d2Sbluhm ssize_t n;
119f214d6d2Sbluhm
120f214d6d2Sbluhm n = recv(s, buf, sizeof(buf) - 1, 0);
121f214d6d2Sbluhm if (n == -1)
122f214d6d2Sbluhm err(1, "recv");
123f214d6d2Sbluhm if (n == 0) {
124f214d6d2Sbluhm fprintf(stderr, "<<< EOF\n");
125f214d6d2Sbluhm return;
126f214d6d2Sbluhm }
127f214d6d2Sbluhm len = n;
128f214d6d2Sbluhm buf[len] = '\0';
129f214d6d2Sbluhm if (buf[len - 1] == '\n')
130f214d6d2Sbluhm buf[--len] = '\0';
131f214d6d2Sbluhm fprintf(stderr, "<<< %s\n", buf);
132f214d6d2Sbluhm errx(1, "expected receive EOF, got '%s'", buf);
133f214d6d2Sbluhm }
134f214d6d2Sbluhm
135f214d6d2Sbluhm void
send_shutdown(int s)136f214d6d2Sbluhm send_shutdown(int s)
137f214d6d2Sbluhm {
138f214d6d2Sbluhm if (shutdown(s, SHUT_WR) == -1)
139f214d6d2Sbluhm err(1, "shutdown");
140f214d6d2Sbluhm }
141f214d6d2Sbluhm
142f214d6d2Sbluhm void
receive_line(int s,const char * msg)143d80889b6Sbluhm receive_line(int s, const char *msg)
144d80889b6Sbluhm {
145d80889b6Sbluhm char buf[100];
146d80889b6Sbluhm size_t off, len;
147d80889b6Sbluhm ssize_t n;
148d80889b6Sbluhm
149d80889b6Sbluhm len = 0;
150f214d6d2Sbluhm while (len < sizeof(buf) - 1) {
151d80889b6Sbluhm off = len;
152f214d6d2Sbluhm n = recv(s, buf + off, sizeof(buf) - 1 - off, 0);
153d80889b6Sbluhm if (n == -1)
154d80889b6Sbluhm err(1, "recv");
155d80889b6Sbluhm if (n == 0) {
156d80889b6Sbluhm fprintf(stderr, "<<< EOF\n");
157d80889b6Sbluhm break;
158d80889b6Sbluhm }
159d80889b6Sbluhm len += n;
160d80889b6Sbluhm buf[len] = '\0';
161d80889b6Sbluhm if (buf[len - 1] == '\n')
162d80889b6Sbluhm fprintf(stderr, "<<< %s", buf + off);
163d80889b6Sbluhm else
164d80889b6Sbluhm fprintf(stderr, "<<< %s\n", buf + off);
165d80889b6Sbluhm if (strchr(buf + off, '\n') != NULL)
166d80889b6Sbluhm break;
167d80889b6Sbluhm }
168d80889b6Sbluhm if (len == 0)
169d80889b6Sbluhm errx(1, "empty receive buffer");
170d80889b6Sbluhm if (buf[len - 1] != '\n')
171d80889b6Sbluhm errx(1, "new line missing in receive buffer");
172d80889b6Sbluhm buf[--len] = '\0';
173d80889b6Sbluhm if (strcmp(msg, buf) != 0)
174d80889b6Sbluhm errx(1, "expected receive '%s', got '%s'", msg, buf);
175d80889b6Sbluhm }
176d80889b6Sbluhm
177d80889b6Sbluhm void
send_line(int s,const char * msg)178d80889b6Sbluhm send_line(int s, const char *msg)
179d80889b6Sbluhm {
180d80889b6Sbluhm char buf[100];
181d80889b6Sbluhm size_t off, len;
182d80889b6Sbluhm ssize_t n;
183d80889b6Sbluhm
184d80889b6Sbluhm len = strlcpy(buf, msg, sizeof(buf));
185d80889b6Sbluhm if (len >= sizeof(buf))
186d80889b6Sbluhm errx(1, "message too long for send buffer");
187d80889b6Sbluhm if (buf[len] != '\n') {
188d80889b6Sbluhm buf[len++] = '\n';
189d80889b6Sbluhm if (len >= sizeof(buf))
190d80889b6Sbluhm errx(1, "new line too long for send buffer");
191d80889b6Sbluhm buf[len] = 0;
192d80889b6Sbluhm }
193d80889b6Sbluhm
194d80889b6Sbluhm off = 0;
195d80889b6Sbluhm while (off < len) {
196d80889b6Sbluhm fprintf(stderr, ">>> %s", buf + off);
197d80889b6Sbluhm n = send(s, buf + off, len - off, 0);
198d80889b6Sbluhm if (n == -1)
199d80889b6Sbluhm err(1, "send");
200d80889b6Sbluhm off += n;
201d80889b6Sbluhm }
202d80889b6Sbluhm }
203