xref: /openbsd/regress/usr.bin/nc/util.c (revision 5a9255e7)
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