Blame


1 2ff1e2a9 2023-07-22 op /*
2 2ff1e2a9 2023-07-22 op * Copyright (c) 2023 Omar Polo <op@omarpolo.com>
3 2ff1e2a9 2023-07-22 op *
4 2ff1e2a9 2023-07-22 op * Permission to use, copy, modify, and distribute this software for any
5 2ff1e2a9 2023-07-22 op * purpose with or without fee is hereby granted, provided that the above
6 2ff1e2a9 2023-07-22 op * copyright notice and this permission notice appear in all copies.
7 2ff1e2a9 2023-07-22 op *
8 2ff1e2a9 2023-07-22 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 2ff1e2a9 2023-07-22 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 2ff1e2a9 2023-07-22 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 2ff1e2a9 2023-07-22 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 2ff1e2a9 2023-07-22 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 2ff1e2a9 2023-07-22 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 2ff1e2a9 2023-07-22 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 2ff1e2a9 2023-07-22 op */
16 2ff1e2a9 2023-07-22 op
17 2ff1e2a9 2023-07-22 op #include "config.h"
18 2ff1e2a9 2023-07-22 op
19 2ff1e2a9 2023-07-22 op #include <sys/stat.h>
20 2ff1e2a9 2023-07-22 op #include <sys/socket.h>
21 2ff1e2a9 2023-07-22 op
22 2ff1e2a9 2023-07-22 op #include <errno.h>
23 2ff1e2a9 2023-07-22 op #include <fcntl.h>
24 2ff1e2a9 2023-07-22 op #include <netdb.h>
25 2ff1e2a9 2023-07-22 op #include <poll.h>
26 2ff1e2a9 2023-07-22 op #include <stdio.h>
27 2ff1e2a9 2023-07-22 op #include <stdlib.h>
28 2ff1e2a9 2023-07-22 op #include <string.h>
29 2ff1e2a9 2023-07-22 op #include <tls.h>
30 2ff1e2a9 2023-07-22 op #include <unistd.h>
31 2ff1e2a9 2023-07-22 op
32 2ff1e2a9 2023-07-22 op #include "iri.h"
33 da3fc66e 2023-07-22 op
34 da3fc66e 2023-07-22 op #ifndef INFTIM
35 da3fc66e 2023-07-22 op #define INFTIM -1
36 da3fc66e 2023-07-22 op #endif
37 da3fc66e 2023-07-22 op
38 da3fc66e 2023-07-22 op #ifndef __OpenBSD__
39 da3fc66e 2023-07-22 op #define pledge(a, b) (0)
40 da3fc66e 2023-07-22 op #endif
41 2ff1e2a9 2023-07-22 op
42 2ff1e2a9 2023-07-22 op static int
43 2ff1e2a9 2023-07-22 op dial(const char *hostname, const char *port)
44 2ff1e2a9 2023-07-22 op {
45 2ff1e2a9 2023-07-22 op struct addrinfo hints, *res, *res0;
46 2ff1e2a9 2023-07-22 op int error, save_errno, s;
47 2ff1e2a9 2023-07-22 op const char *cause = NULL;
48 2ff1e2a9 2023-07-22 op
49 2ff1e2a9 2023-07-22 op if (port == NULL || *port == '\0')
50 2ff1e2a9 2023-07-22 op port = "1965";
51 2ff1e2a9 2023-07-22 op
52 2ff1e2a9 2023-07-22 op memset(&hints, 0, sizeof(hints));
53 2ff1e2a9 2023-07-22 op hints.ai_family = AF_UNSPEC;
54 2ff1e2a9 2023-07-22 op hints.ai_socktype = SOCK_STREAM;
55 2ff1e2a9 2023-07-22 op error = getaddrinfo(hostname, port, &hints, &res0);
56 2ff1e2a9 2023-07-22 op if (error)
57 2ff1e2a9 2023-07-22 op errx(1, "can't resolve %s: %s", hostname, gai_strerror(error));
58 2ff1e2a9 2023-07-22 op
59 2ff1e2a9 2023-07-22 op s = -1;
60 2ff1e2a9 2023-07-22 op for (res = res0; res; res = res->ai_next) {
61 2ff1e2a9 2023-07-22 op s = socket(res->ai_family, res->ai_socktype,
62 2ff1e2a9 2023-07-22 op res->ai_protocol);
63 2ff1e2a9 2023-07-22 op if (s == -1) {
64 2ff1e2a9 2023-07-22 op cause = "socket";
65 2ff1e2a9 2023-07-22 op continue;
66 2ff1e2a9 2023-07-22 op }
67 2ff1e2a9 2023-07-22 op
68 2ff1e2a9 2023-07-22 op if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
69 2ff1e2a9 2023-07-22 op cause = "connect";
70 2ff1e2a9 2023-07-22 op save_errno = errno;
71 2ff1e2a9 2023-07-22 op close(s);
72 2ff1e2a9 2023-07-22 op errno = save_errno;
73 2ff1e2a9 2023-07-22 op s = -1;
74 2ff1e2a9 2023-07-22 op continue;
75 2ff1e2a9 2023-07-22 op }
76 2ff1e2a9 2023-07-22 op
77 2ff1e2a9 2023-07-22 op if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
78 2ff1e2a9 2023-07-22 op err(1, "fcntl");
79 2ff1e2a9 2023-07-22 op break; /* got one */
80 2ff1e2a9 2023-07-22 op }
81 2ff1e2a9 2023-07-22 op if (s == -1)
82 2ff1e2a9 2023-07-22 op err(1, "%s", cause);
83 2ff1e2a9 2023-07-22 op freeaddrinfo(res0);
84 2ff1e2a9 2023-07-22 op return (s);
85 2ff1e2a9 2023-07-22 op }
86 2ff1e2a9 2023-07-22 op
87 2ff1e2a9 2023-07-22 op /* returns read bytes, or -1 on error */
88 2ff1e2a9 2023-07-22 op static ssize_t
89 2ff1e2a9 2023-07-22 op iomux(struct tls *ctx, int fd, const char *in, size_t inlen, char *out,
90 2ff1e2a9 2023-07-22 op size_t outlen)
91 2ff1e2a9 2023-07-22 op {
92 2ff1e2a9 2023-07-22 op struct pollfd pfd;
93 2ff1e2a9 2023-07-22 op size_t outwrote = 0;
94 2ff1e2a9 2023-07-22 op ssize_t ret;
95 2ff1e2a9 2023-07-22 op
96 2ff1e2a9 2023-07-22 op memset(&pfd, 0, sizeof(pfd));
97 2ff1e2a9 2023-07-22 op pfd.fd = fd;
98 2ff1e2a9 2023-07-22 op pfd.events = POLLIN|POLLOUT;
99 2ff1e2a9 2023-07-22 op
100 2ff1e2a9 2023-07-22 op for (;;) {
101 2ff1e2a9 2023-07-22 op if (poll(&pfd, 1, INFTIM) == -1)
102 2ff1e2a9 2023-07-22 op err(1, "poll");
103 2ff1e2a9 2023-07-22 op if (pfd.revents & (POLLERR|POLLNVAL))
104 2ff1e2a9 2023-07-22 op errx(1, "bad fd %d", pfd.fd);
105 2ff1e2a9 2023-07-22 op
106 2ff1e2a9 2023-07-22 op /* attempt to read */
107 2ff1e2a9 2023-07-22 op if (out != NULL) {
108 2ff1e2a9 2023-07-22 op switch (ret = tls_read(ctx, out, outlen)) {
109 2ff1e2a9 2023-07-22 op case TLS_WANT_POLLIN:
110 2ff1e2a9 2023-07-22 op case TLS_WANT_POLLOUT:
111 2ff1e2a9 2023-07-22 op break;
112 2ff1e2a9 2023-07-22 op case -1:
113 2ff1e2a9 2023-07-22 op return -1;
114 2ff1e2a9 2023-07-22 op case 0:
115 1b1a6fb7 2023-08-04 op if (outwrote == 0)
116 1b1a6fb7 2023-08-04 op return -1;
117 2ff1e2a9 2023-07-22 op return outwrote;
118 2ff1e2a9 2023-07-22 op default:
119 2ff1e2a9 2023-07-22 op outwrote += ret;
120 2ff1e2a9 2023-07-22 op out += ret;
121 2ff1e2a9 2023-07-22 op outlen -= ret;
122 2ff1e2a9 2023-07-22 op }
123 2ff1e2a9 2023-07-22 op
124 2ff1e2a9 2023-07-22 op /*
125 2ff1e2a9 2023-07-22 op * don't write if we're reading; titan works
126 2ff1e2a9 2023-07-22 op * like this.
127 2ff1e2a9 2023-07-22 op */
128 2ff1e2a9 2023-07-22 op if (outwrote != 0)
129 2ff1e2a9 2023-07-22 op continue;
130 2ff1e2a9 2023-07-22 op }
131 2ff1e2a9 2023-07-22 op
132 2ff1e2a9 2023-07-22 op if (inlen == 0 && out == NULL)
133 2ff1e2a9 2023-07-22 op break;
134 2ff1e2a9 2023-07-22 op if (inlen == 0)
135 2ff1e2a9 2023-07-22 op continue;
136 2ff1e2a9 2023-07-22 op
137 2ff1e2a9 2023-07-22 op switch (ret = tls_write(ctx, in, inlen)) {
138 2ff1e2a9 2023-07-22 op case TLS_WANT_POLLIN:
139 2ff1e2a9 2023-07-22 op case TLS_WANT_POLLOUT:
140 2ff1e2a9 2023-07-22 op continue;
141 2ff1e2a9 2023-07-22 op case 0:
142 2ff1e2a9 2023-07-22 op case -1:
143 2ff1e2a9 2023-07-22 op return -1;
144 2ff1e2a9 2023-07-22 op default:
145 2ff1e2a9 2023-07-22 op in += ret;
146 2ff1e2a9 2023-07-22 op inlen -= ret;
147 2ff1e2a9 2023-07-22 op }
148 2ff1e2a9 2023-07-22 op }
149 2ff1e2a9 2023-07-22 op
150 2ff1e2a9 2023-07-22 op return 0;
151 2ff1e2a9 2023-07-22 op }
152 2ff1e2a9 2023-07-22 op
153 9888507c 2023-07-24 op static FILE *
154 9888507c 2023-07-24 op open_input_file(int argc, char **argv)
155 9888507c 2023-07-24 op {
156 9888507c 2023-07-24 op FILE *fp;
157 9888507c 2023-07-24 op char buf[BUFSIZ];
158 9888507c 2023-07-24 op char sfn[22];
159 9888507c 2023-07-24 op size_t r;
160 9888507c 2023-07-24 op int fd;
161 9888507c 2023-07-24 op
162 9888507c 2023-07-24 op if (argc > 1) {
163 9888507c 2023-07-24 op if ((fp = fopen(argv[1], "r")) == NULL)
164 9888507c 2023-07-24 op err(1, "can't open %s", argv[1]);
165 9888507c 2023-07-24 op return fp;
166 9888507c 2023-07-24 op }
167 9888507c 2023-07-24 op
168 9888507c 2023-07-24 op strlcpy(sfn, "/tmp/titan.XXXXXXXXXX", sizeof(sfn));
169 9888507c 2023-07-24 op if ((fd = mkstemp(sfn)) == -1 ||
170 9888507c 2023-07-24 op (fp = fdopen(fd, "w+")) == NULL) {
171 9888507c 2023-07-24 op warn("%s", sfn);
172 9888507c 2023-07-24 op if (fd != -1) {
173 9888507c 2023-07-24 op unlink(sfn);
174 9888507c 2023-07-24 op close(fd);
175 9888507c 2023-07-24 op }
176 9888507c 2023-07-24 op errx(1, "can't create temp file");
177 9888507c 2023-07-24 op }
178 9888507c 2023-07-24 op unlink(sfn);
179 9888507c 2023-07-24 op
180 9888507c 2023-07-24 op for (;;) {
181 9888507c 2023-07-24 op r = fread(buf, 1, sizeof(buf), stdin);
182 9888507c 2023-07-24 op if (r == 0)
183 9888507c 2023-07-24 op break;
184 9888507c 2023-07-24 op fwrite(buf, 1, r, fp);
185 9888507c 2023-07-24 op }
186 9888507c 2023-07-24 op if (ferror(fp))
187 9888507c 2023-07-24 op err(1, "I/O error");
188 9888507c 2023-07-24 op
189 9888507c 2023-07-24 op if (fseeko(fp, 0, SEEK_SET) == -1)
190 9888507c 2023-07-24 op err(1, "fseeko");
191 9888507c 2023-07-24 op
192 9888507c 2023-07-24 op return fp;
193 39273368 2023-07-24 op }
194 39273368 2023-07-24 op
195 39273368 2023-07-24 op static int
196 39273368 2023-07-24 op parse_response(char *r)
197 39273368 2023-07-24 op {
198 39273368 2023-07-24 op int code;
199 39273368 2023-07-24 op
200 39273368 2023-07-24 op if (r[0] < '0' || r[0] > '9' ||
201 39273368 2023-07-24 op r[1] < '0' || r[1] > '9' ||
202 39273368 2023-07-24 op r[2] != ' ')
203 39273368 2023-07-24 op errx(1, "illegal response");
204 39273368 2023-07-24 op
205 39273368 2023-07-24 op code = (r[0] - '0') * 10 + (r[1] - '0');
206 39273368 2023-07-24 op if (code < 10 || code >= 70)
207 39273368 2023-07-24 op errx(1, "invalid response code: %d", code);
208 39273368 2023-07-24 op if (code >= 20 && code < 30)
209 39273368 2023-07-24 op return 0;
210 39273368 2023-07-24 op if (code >= 30 && code < 40) {
211 39273368 2023-07-24 op puts(r + 3);
212 39273368 2023-07-24 op return 0;
213 39273368 2023-07-24 op }
214 39273368 2023-07-24 op warnx("server error: %s", r + 3);
215 39273368 2023-07-24 op return 2;
216 9888507c 2023-07-24 op }
217 9888507c 2023-07-24 op
218 2ff1e2a9 2023-07-22 op static void __dead
219 2ff1e2a9 2023-07-22 op usage(void)
220 2ff1e2a9 2023-07-22 op {
221 2ff1e2a9 2023-07-22 op fprintf(stderr,
222 9888507c 2023-07-24 op "usage: %s [-C cert] [-K key] [-m mime] [-t token] url [file]\n",
223 2ff1e2a9 2023-07-22 op getprogname());
224 2ff1e2a9 2023-07-22 op exit(1);
225 2ff1e2a9 2023-07-22 op }
226 2ff1e2a9 2023-07-22 op
227 2ff1e2a9 2023-07-22 op int
228 2ff1e2a9 2023-07-22 op main(int argc, char **argv)
229 2ff1e2a9 2023-07-22 op {
230 2ff1e2a9 2023-07-22 op struct tls_config *config;
231 2ff1e2a9 2023-07-22 op struct tls *ctx;
232 2ff1e2a9 2023-07-22 op struct stat sb;
233 2ff1e2a9 2023-07-22 op struct iri iri;
234 2ff1e2a9 2023-07-22 op FILE *in;
235 2ff1e2a9 2023-07-22 op const char *cert = NULL, *key = NULL, *mime = NULL, *token = NULL;
236 59051566 2023-08-04 op const char *errstr;
237 2ff1e2a9 2023-07-22 op char iribuf[1025];
238 fcc5a371 2023-08-04 op char reqbuf[1025];
239 2ff1e2a9 2023-07-22 op char resbuf[1025];
240 fcc5a371 2023-08-04 op char *path;
241 39273368 2023-07-24 op int sock, ch, ret = 0;
242 2ff1e2a9 2023-07-22 op
243 9888507c 2023-07-24 op if (pledge("stdio rpath tmppath inet dns", NULL) == -1)
244 2ff1e2a9 2023-07-22 op err(1, "pledge");
245 2ff1e2a9 2023-07-22 op
246 2ff1e2a9 2023-07-22 op while ((ch = getopt(argc, argv, "C:K:m:t:")) != -1) {
247 2ff1e2a9 2023-07-22 op switch (ch) {
248 2ff1e2a9 2023-07-22 op case 'C':
249 2ff1e2a9 2023-07-22 op cert = optarg;
250 2ff1e2a9 2023-07-22 op break;
251 2ff1e2a9 2023-07-22 op case 'K':
252 2ff1e2a9 2023-07-22 op key = optarg;
253 2ff1e2a9 2023-07-22 op break;
254 2ff1e2a9 2023-07-22 op case 'm':
255 2ff1e2a9 2023-07-22 op mime = optarg;
256 2ff1e2a9 2023-07-22 op break;
257 2ff1e2a9 2023-07-22 op case 't':
258 2ff1e2a9 2023-07-22 op token = optarg;
259 2ff1e2a9 2023-07-22 op break;
260 fd48b7c0 2024-01-08 op default:
261 fd48b7c0 2024-01-08 op usage();
262 2ff1e2a9 2023-07-22 op }
263 2ff1e2a9 2023-07-22 op }
264 2ff1e2a9 2023-07-22 op argc -= optind;
265 2ff1e2a9 2023-07-22 op argv += optind;
266 2ff1e2a9 2023-07-22 op
267 2ff1e2a9 2023-07-22 op if (cert == NULL && key != NULL)
268 2ff1e2a9 2023-07-22 op usage();
269 2ff1e2a9 2023-07-22 op if (cert != NULL && key == NULL)
270 2ff1e2a9 2023-07-22 op key = cert;
271 2ff1e2a9 2023-07-22 op
272 dd3f04b2 2024-01-08 op if (argc != 1 && argc != 2)
273 2ff1e2a9 2023-07-22 op usage();
274 2ff1e2a9 2023-07-22 op
275 9888507c 2023-07-24 op in = open_input_file(argc, argv);
276 2ff1e2a9 2023-07-22 op
277 9888507c 2023-07-24 op /* drop rpath tmppath */
278 2ff1e2a9 2023-07-22 op if (pledge("stdio inet dns", NULL) == -1)
279 2ff1e2a9 2023-07-22 op err(1, "pledge");
280 2ff1e2a9 2023-07-22 op
281 2ff1e2a9 2023-07-22 op if (fstat(fileno(in), &sb) == -1)
282 2ff1e2a9 2023-07-22 op err(1, "fstat");
283 2ff1e2a9 2023-07-22 op
284 5d38e5d8 2023-08-04 op /* prepare the IRI */
285 fcc5a371 2023-08-04 op if (strlcpy(iribuf, argv[0], sizeof(iribuf)) >= sizeof(iribuf))
286 5d38e5d8 2023-08-04 op errx(1, "IRI too long");
287 fcc5a371 2023-08-04 op
288 59051566 2023-08-04 op if (!parse_iri(iribuf, &iri, &errstr))
289 59051566 2023-08-04 op errx(1, "invalid IRI: %s", errstr);
290 fcc5a371 2023-08-04 op
291 11ff7f93 2023-08-04 op if (strcmp(iri.schema, "titan") != 0)
292 5d38e5d8 2023-08-04 op errx(1, "not a titan:// IRI");
293 11ff7f93 2023-08-04 op
294 2ff1e2a9 2023-07-22 op if (token && mime) {
295 fcc5a371 2023-08-04 op if (asprintf(&path, "%s;size=%lld;token=%s;mime=%s", iri.path,
296 2ff1e2a9 2023-07-22 op (long long)sb.st_size, token, mime) == -1)
297 2ff1e2a9 2023-07-22 op err(1, "asprintf");
298 2ff1e2a9 2023-07-22 op } else if (token) {
299 fcc5a371 2023-08-04 op if (asprintf(&path, "%s;size=%lld;token=%s", iri.path,
300 2ff1e2a9 2023-07-22 op (long long)sb.st_size, token) == -1)
301 2ff1e2a9 2023-07-22 op err(1, "asprintf");
302 2ff1e2a9 2023-07-22 op } else if (mime) {
303 fcc5a371 2023-08-04 op if (asprintf(&path, "%s;size=%lld;mime=%s", iri.path,
304 2ff1e2a9 2023-07-22 op (long long)sb.st_size, mime) == -1)
305 2ff1e2a9 2023-07-22 op err(1, "asprintf");
306 2ff1e2a9 2023-07-22 op } else {
307 fcc5a371 2023-08-04 op if (asprintf(&path, "%s;size=%lld", iri.path,
308 2ff1e2a9 2023-07-22 op (long long)sb.st_size) == -1)
309 2ff1e2a9 2023-07-22 op err(1, "asprintf");
310 2ff1e2a9 2023-07-22 op }
311 2ff1e2a9 2023-07-22 op
312 fcc5a371 2023-08-04 op iri.path = path;
313 fcc5a371 2023-08-04 op if (!serialize_iri(&iri, reqbuf, sizeof(reqbuf)) ||
314 fcc5a371 2023-08-04 op strlcat(reqbuf, "\r\n", sizeof(reqbuf)) >= sizeof(reqbuf))
315 5d38e5d8 2023-08-04 op errx(1, "IRI too long");
316 2ff1e2a9 2023-07-22 op
317 2ff1e2a9 2023-07-22 op if ((config = tls_config_new()) == NULL)
318 2ff1e2a9 2023-07-22 op err(1, "tls_config_new");
319 2ff1e2a9 2023-07-22 op tls_config_insecure_noverifycert(config);
320 2ff1e2a9 2023-07-22 op tls_config_insecure_noverifyname(config);
321 2ff1e2a9 2023-07-22 op
322 2ff1e2a9 2023-07-22 op if (cert && tls_config_set_keypair_file(config, cert, key) == -1)
323 2ff1e2a9 2023-07-22 op errx(1, "cant load certificate client %s", cert);
324 2ff1e2a9 2023-07-22 op
325 2ff1e2a9 2023-07-22 op if ((ctx = tls_client()) == NULL)
326 2ff1e2a9 2023-07-22 op errx(1, "can't create tls context");
327 2ff1e2a9 2023-07-22 op
328 2ff1e2a9 2023-07-22 op if (tls_configure(ctx, config) == -1)
329 2ff1e2a9 2023-07-22 op errx(1, "tls_configure: %s", tls_error(ctx));
330 2ff1e2a9 2023-07-22 op
331 2ff1e2a9 2023-07-22 op sock = dial(iri.host, iri.port);
332 2ff1e2a9 2023-07-22 op
333 2ff1e2a9 2023-07-22 op /* drop inet tls */
334 2ff1e2a9 2023-07-22 op if (pledge("stdio", NULL) == -1)
335 2ff1e2a9 2023-07-22 op err(1, "pledge");
336 2ff1e2a9 2023-07-22 op
337 32b1638e 2023-07-24 op if (tls_connect_socket(ctx, sock, iri.host) == -1)
338 32b1638e 2023-07-24 op errx(1, "failed to connect to %s:%s: %s", iri.host,
339 32b1638e 2023-07-24 op *iri.port == '\0' ? "1965" : iri.port, tls_error(ctx));
340 32b1638e 2023-07-24 op
341 2ff1e2a9 2023-07-22 op /* send request */
342 fcc5a371 2023-08-04 op if (iomux(ctx, sock, reqbuf, strlen(reqbuf), NULL, 0) == -1)
343 2ff1e2a9 2023-07-22 op errx(1, "I/O error: %s", tls_error(ctx));
344 2ff1e2a9 2023-07-22 op
345 2ff1e2a9 2023-07-22 op for (;;) {
346 2ff1e2a9 2023-07-22 op static char buf[BUFSIZ];
347 2ff1e2a9 2023-07-22 op size_t buflen;
348 2ff1e2a9 2023-07-22 op ssize_t w;
349 2ff1e2a9 2023-07-22 op char *m;
350 2ff1e2a9 2023-07-22 op
351 2ff1e2a9 2023-07-22 op /* will be zero on EOF */
352 2ff1e2a9 2023-07-22 op buflen = fread(buf, 1, sizeof(buf), in);
353 2ff1e2a9 2023-07-22 op
354 2ff1e2a9 2023-07-22 op w = iomux(ctx, sock, buf, buflen, resbuf, sizeof(resbuf));
355 d671434b 2023-08-04 op if (w == -1) {
356 d671434b 2023-08-04 op errstr = tls_error(ctx);
357 d671434b 2023-08-04 op if (errstr == NULL)
358 d671434b 2023-08-04 op errstr = "unexpected EOF";
359 d671434b 2023-08-04 op errx(1, "I/O error: %s", errstr);
360 d671434b 2023-08-04 op }
361 2ff1e2a9 2023-07-22 op if (w != 0) {
362 2ff1e2a9 2023-07-22 op if ((m = memmem(resbuf, w, "\r\n", 2)) == NULL)
363 2ff1e2a9 2023-07-22 op errx(1, "invalid reply");
364 2ff1e2a9 2023-07-22 op *m = '\0';
365 39273368 2023-07-24 op ret = parse_response(resbuf);
366 2ff1e2a9 2023-07-22 op break;
367 2ff1e2a9 2023-07-22 op }
368 2ff1e2a9 2023-07-22 op }
369 2ff1e2a9 2023-07-22 op
370 2ff1e2a9 2023-07-22 op /* close connection */
371 2ff1e2a9 2023-07-22 op for (;;) {
372 2ff1e2a9 2023-07-22 op struct pollfd pfd;
373 2ff1e2a9 2023-07-22 op
374 2ff1e2a9 2023-07-22 op memset(&pfd, 0, sizeof(pfd));
375 2ff1e2a9 2023-07-22 op pfd.fd = sock;
376 2ff1e2a9 2023-07-22 op pfd.events = POLLIN|POLLOUT;
377 2ff1e2a9 2023-07-22 op
378 2ff1e2a9 2023-07-22 op switch (tls_close(ctx)) {
379 2ff1e2a9 2023-07-22 op case TLS_WANT_POLLIN:
380 2ff1e2a9 2023-07-22 op case TLS_WANT_POLLOUT:
381 2ff1e2a9 2023-07-22 op if (poll(&pfd, 1, INFTIM) == -1)
382 2ff1e2a9 2023-07-22 op err(1, "poll");
383 2ff1e2a9 2023-07-22 op break;
384 2ff1e2a9 2023-07-22 op case -1:
385 2ff1e2a9 2023-07-22 op warnx("tls_close: %s", tls_error(ctx));
386 2ff1e2a9 2023-07-22 op /* fallthrough */
387 2ff1e2a9 2023-07-22 op default:
388 2ff1e2a9 2023-07-22 op tls_free(ctx);
389 39273368 2023-07-24 op return (ret);
390 2ff1e2a9 2023-07-22 op }
391 2ff1e2a9 2023-07-22 op }
392 2ff1e2a9 2023-07-22 op }