xref: /openbsd/regress/usr.bin/nc/util.c (revision 905646f0)
1 /*	$OpenBSD: util.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
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
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
79 alarm_timeout(void)
80 {
81 	/* just abort after 10 seconds */
82 	if ((int)alarm(10) == -1)
83 		err(1, "alarm");
84 }
85 
86 void
87 print_sockname(int s)
88 {
89 	struct sockaddr_storage ss;
90 	socklen_t slen;
91 	char host[NI_MAXHOST], port[NI_MAXSERV];
92 
93 	slen = sizeof(ss);
94 	if (getsockname(s, (struct sockaddr *)&ss, &slen) == -1)
95 		err(1, "getsockname");
96 	if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host),
97 	    port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV))
98 		errx(1, "getnameinfo");
99 	printf("%s\n", port);
100 	if (fflush(stdout) != 0)
101 		err(1, "fflush stdout");
102 	fprintf(stderr, "sock: %s %s\n", host, port);
103 }
104 
105 void
106 print_peername(int s)
107 {
108 	struct sockaddr_storage ss;
109 	socklen_t slen;
110 	char host[NI_MAXHOST], port[NI_MAXSERV];
111 
112 	slen = sizeof(ss);
113 	if (getpeername(s, (struct sockaddr *)&ss, &slen) == -1)
114 		err(1, "getpeername");
115 	if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host),
116 	    port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV))
117 		errx(1, "getnameinfo");
118 	fprintf(stderr, "peer: %s %s\n", host, port);
119 }
120 
121 void
122 receive_eof(int s)
123 {
124 	char buf[100];
125 	size_t len;
126 	ssize_t n;
127 
128 	n = recv(s, buf, sizeof(buf) - 1, 0);
129 	if (n == -1)
130 		err(1, "recv");
131 	if (n == 0) {
132 		fprintf(stderr, "<<< EOF\n");
133 		return;
134 	}
135 	len = n;
136 	buf[len] = '\0';
137 	if (buf[len - 1] == '\n')
138 		buf[--len] = '\0';
139 	fprintf(stderr, "<<< %s\n", buf);
140 	errx(1, "expected receive EOF, got '%s'", buf);
141 }
142 
143 void
144 send_shutdown(int s)
145 {
146 	if (shutdown(s, SHUT_WR) == -1)
147 		err(1, "shutdown");
148 }
149 
150 void
151 receive_line(int s, const char *msg)
152 {
153 	char buf[100];
154 	size_t off, len;
155 	ssize_t n;
156 
157 	len = 0;
158 	while (len < sizeof(buf) - 1) {
159 		off = len;
160 		n = recv(s, buf + off, sizeof(buf) - 1 - off, 0);
161 		if (n == -1)
162 			err(1, "recv");
163 		if (n == 0) {
164 			fprintf(stderr, "<<< EOF\n");
165 			break;
166 		}
167 		len += n;
168 		buf[len] = '\0';
169 		if (buf[len - 1] == '\n')
170 			fprintf(stderr, "<<< %s", buf + off);
171 		else
172 			fprintf(stderr, "<<< %s\n", buf + off);
173 		if (strchr(buf + off, '\n') != NULL)
174 			break;
175 	}
176 	if (len == 0)
177 		errx(1, "empty receive buffer");
178 	if (buf[len - 1] != '\n')
179 		errx(1, "new line missing in receive buffer");
180 	buf[--len] = '\0';
181 	if (strcmp(msg, buf) != 0)
182 		errx(1, "expected receive '%s', got '%s'", msg, buf);
183 }
184 
185 void
186 send_line(int s, const char *msg)
187 {
188 	char buf[100];
189 	size_t off, len;
190 	ssize_t n;
191 
192 	len = strlcpy(buf, msg, sizeof(buf));
193 	if (len >= sizeof(buf))
194 		errx(1, "message too long for send buffer");
195 	if (buf[len] != '\n') {
196 		buf[len++] = '\n';
197 		if (len >= sizeof(buf))
198 			errx(1, "new line too long for send buffer");
199 		buf[len] = 0;
200 	}
201 
202 	off = 0;
203 	while (off < len) {
204 		fprintf(stderr, ">>> %s", buf + off);
205 		n = send(s, buf + off, len - off, 0);
206 		if (n == -1)
207 			err(1, "send");
208 		off += n;
209 	}
210 }
211