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