"Fossies" - the Fresh Open Source Software Archive 
Member "Pound-3.0.2/src/http.c" (28 Nov 2021, 24926 Bytes) of package /linux/www/Pound-3.0.2.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "http.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
3.0d_vs_3.0e.
1 /*
2 * Pound - the reverse-proxy load-balancer
3 * Copyright (C) 2002-2020 Apsis GmbH
4 *
5 * This file is part of Pound.
6 *
7 * Pound is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Pound is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/> .
19 *
20 * Contact information:
21 * Apsis GmbH
22 * P.O.Box
23 * 8707 Uetikon am See
24 * Switzerland
25 * EMail: roseg@apsis.ch
26 */
27
28 #include "pound.h"
29
30 void *
31 thr_service(void *arg)
32 {
33 SERVICE *svc;
34 struct SESSION {
35 char *addr;
36 BACKEND *be;
37 time_t last_access;
38 UT_hash_handle hh;
39 } *sessions, *cur, *tmp;
40 time_t lastscan, now;
41 struct nn_pollfd s_poll;
42 char *msg, addr[NI_MAXHOST];
43 int n, i;
44
45 logmsg(1, "%lX start service %s:%d", pthread_self(), __FILE__, __LINE__);
46 svc = (SERVICE *)arg;
47 sessions = NULL;
48 lastscan = time(NULL);
49 sem_post(&sem_start);
50 for(;;) {
51 if(svc->session == 0) {
52 logmsg(4, "%lX Null session: %s:%d", pthread_self(), __FILE__, __LINE__);
53 /* accept a listener request, return an appropriate backend */
54 if(nn_recv(svc->sock, &msg, NN_MSG, 0) <= 0) {
55 logmsg(0, "Session: bad receive %s", nn_strerror(nn_errno()));
56 continue;
57 }
58 nn_freemsg(msg);
59 if(svc->backends_len > 1) {
60 n = random();
61 for(i = 0; i < svc->backends_len; i++) {
62 n = (n + i) % svc->backends_len;
63 if(!svc->backends[n]->is_dead)
64 break;
65 }
66 } else
67 n = 0;
68 if(!svc->backends[n]->is_dead) {
69 nn_send(svc->sock, &svc->backends[n], sizeof(svc->backends[n]), 0);
70 logmsg(4, "%lX Null session returns %d %s:%d", pthread_self(), n, __FILE__, __LINE__);
71 } else {
72 nn_send(svc->sock, "", 0, 0);
73 logmsg(4, "%lX Null session no backend %s:%d", pthread_self(), __FILE__, __LINE__);
74 }
75 }
76 now = time(NULL);
77 if(now >= (lastscan + svc->session)) {
78 /* prune expired sessions */
79 HASH_ITER(hh, sessions, cur, tmp)
80 if((cur->last_access + svc->session) < now) {
81 logmsg(4, "%lX prune %s %s:%d", pthread_self(), cur->addr, __FILE__, __LINE__);
82 HASH_DEL(sessions, cur);
83 free(cur->addr);
84 free(cur);
85 }
86 lastscan = time(NULL);
87 }
88 s_poll.fd = svc->sock;
89 s_poll.events = NN_POLLIN;
90 if(nn_poll(&s_poll, 1, (svc->session - (now - lastscan)) * 1000) != 1)
91 continue;
92 /* accept a listener request, return an appropriate backend */
93 if(nn_recv(svc->sock, &msg, NN_MSG, 0) <= 0) {
94 logmsg(0, "Session: bad receive %s", nn_strerror(nn_errno()));
95 continue;
96 }
97 strcpy(addr, msg);
98 nn_freemsg(msg);
99 logmsg(4, "%lX find %s %s:%d", pthread_self(), addr, __FILE__, __LINE__);
100 HASH_FIND_STR(sessions, msg, cur);
101 if(cur && !cur->be->is_dead) {
102 logmsg(4, "%lX found %s session %s:%d", pthread_self(), addr, __FILE__, __LINE__);
103 nn_send(svc->sock, &cur->be, sizeof(cur->be), 0);
104 cur->last_access = time(NULL);
105 continue;
106 }
107 if(svc->backends_len > 1) {
108 n = random();
109 for(i = 0; i < svc->backends_len; i++) {
110 n = (n + i) % svc->backends_len;
111 if(!svc->backends[n]->is_dead)
112 break;
113 }
114 } else
115 n = 0;
116 if(!svc->backends[n]->is_dead) {
117 if((cur = (struct SESSION *)malloc(sizeof(struct SESSION))) == NULL)
118 logmsg(0, "Session: out of memory");
119 else {
120 cur->addr = strdup(addr);
121 cur->be = svc->backends[i];
122 cur->last_access = time(NULL);
123 HASH_ADD_KEYPTR(hh, sessions, cur->addr, strlen(cur->addr), cur);
124 logmsg(4, "%lX added %s %s:%d", pthread_self(), addr, __FILE__, __LINE__);
125 }
126 nn_send(svc->sock, &svc->backends[n], sizeof(svc->backends[n]), 0);
127 } else {
128 nn_send(svc->sock, "", 0, 0);
129 logmsg(4, "%lX no backend %s:%d", pthread_self(), __FILE__, __LINE__);
130 }
131 }
132 }
133
134 int
135 get_be(HTTP_LISTENER *http, char *peer_name, char *request, char *headers[], struct hpack_headerblock *h2)
136 {
137 int i, j, found, s_private;
138 char *msg, private_name[NI_MAXHOST], buf[MAXBUF], *method, *path;
139 BACKEND *be;
140 struct nn_pollfd private_poll;
141 struct hpack_header *header;
142
143 logmsg(1, "%lX start get_be %s:%d", pthread_self(), __FILE__, __LINE__);
144 if(request != NULL) {
145 logmsg(2, "%lX get_be HTTP/1.1 %s:%d", pthread_self(), __FILE__, __LINE__);
146 for(i = 0; i < http->services_len; i++) {
147 if(http->services[i]->url != NULL && regexec(http->services[i]->url, request, 0, NULL, REG_ICASE))
148 continue;
149 found = (http->services[i]->head_require == NULL);
150 for(j = 0; j < MAXHEADERS; j++) {
151 if(headers[j] == NULL)
152 continue;
153 if(http->services[i]->head_deny != NULL && !regexec(http->services[i]->head_deny, headers[j], 0, NULL, REG_ICASE)) {
154 found = 0;
155 break;
156 }
157 if(http->services[i]->head_require != NULL && !regexec(http->services[i]->head_require, headers[j], 0, NULL, REG_ICASE))
158 found = 1;
159 }
160 if(found)
161 break;
162 }
163 } else {
164 logmsg(2, "%lX get_be HTTP/2 %s:%d", pthread_self(), __FILE__, __LINE__);
165 for(i = 0; i < http->services_len; i++) {
166 found = (http->services[i]->head_require == NULL);
167 method = path = NULL;
168 TAILQ_FOREACH(header, h2, hdr_entry) {
169 if(!strcasecmp(header->hdr_name, ":method"))
170 method = header->hdr_value;
171 else if(!strcasecmp(header->hdr_name, ":path"))
172 path = header->hdr_value;
173 else if(strcasecmp(header->hdr_name, ":scheme")) {
174 /* we don't care about :scheme */
175 if(!strcasecmp(header->hdr_name, ":authority"))
176 snprintf(buf, MAXBUF, "Host: %s\r\n", header->hdr_value);
177 else
178 snprintf(buf, MAXBUF, "%s: %s\r\n", header->hdr_name, header->hdr_value);
179 logmsg(4, "%lX check %d header %s %s:%d", pthread_self(), i, buf, __FILE__, __LINE__);
180 if(http->services[i]->head_require != NULL && !regexec(http->services[i]->head_require, buf, 0, NULL, REG_ICASE))
181 found = 1;
182 if(http->services[i]->head_deny != NULL && !regexec(http->services[i]->head_deny, buf, 0, NULL, REG_ICASE)) {
183 found = 0;
184 break;
185 }
186 }
187 }
188 if(!found)
189 continue;
190 if(http->services[i]->url == NULL)
191 break;
192 snprintf(buf, MAXBUF, "%s %s HTTP/1.1\r\n", method, path);
193 logmsg(4, "%lX check %d request %s %s:%d", pthread_self(), i, buf, __FILE__, __LINE__);
194 if(!regexec(http->services[i]->url, buf, 0, NULL, REG_ICASE))
195 break;
196 }
197 }
198
199 logmsg(2, "%lX %sfound %d %s:%d", pthread_self(), i >= http->services_len? "not ": "", i, __FILE__, __LINE__);
200 if(i >= http->services_len)
201 return -1;
202 nn_send(http->services[i]->sock_in, peer_name, strlen(peer_name) + 1, 0);
203 if(nn_recv(http->services[i]->sock_in, &msg, NN_MSG, 0) == sizeof(be))
204 memcpy(&be, msg, sizeof(be));
205 else
206 be = NULL;
207 nn_freemsg(msg);
208
209 if(be == NULL || (s_private = nn_socket(AF_SP, NN_PAIR)) < 0)
210 return -1;
211
212 do {
213 snprintf(private_name, NI_MAXHOST, "inproc://HTTP_%ld", random() % 10000);
214 } while(nn_bind(s_private, private_name) < 0);
215
216 if(nn_send(be->sock_in, private_name, strlen(private_name) + 1, 0) < 0) {
217 nn_close(s_private);
218 return -1;
219 }
220
221 private_poll.fd = s_private;
222 private_poll.events = NN_POLLOUT;
223 if(nn_poll(&private_poll, 1, http->client * 1000) != 1) {
224 nn_close(s_private);
225 return -1;
226 }
227
228 logmsg(2, "%lX done get_be %s:%d", pthread_self(), __FILE__, __LINE__);
229 return s_private;
230 }
231
232 static int
233 put_err(FILE *f_client, int code, char *reason, char *body)
234 {
235 static char *fmt_body = "HTTP/1.1 %d %s\r\nContent-length: %d\r\n\r\n";
236 static char *fmt_empty = "HTTP/1.1 %d %s\r\r\n";
237
238 if(body != NULL) {
239 fprintf(f_client, fmt_body, code, reason, body);
240 return strlen(fmt_body) + 1 + strlen(reason) + strlen(body);
241 } else {
242 fprintf(f_client, fmt_empty, code, reason);
243 return strlen(fmt_empty) + 1 + strlen(reason);
244 }
245 }
246
247 static void
248 do_request(HTTP_LISTENER *http, FILE *f_client, char *peer_name, char *crt_buf)
249 {
250 BACKEND *be;
251 char *msg, *headers[MAXHEADERS], private_name[NI_MAXHOST], request[MAXBUF], buf[MAXBUF];
252 int i, is_closed, close_at_end, upgrade_h2, is_chunked, is_expect, s_private, header_found;
253 long content_length;
254 struct timespec t_wait;
255 regmatch_t match[2];
256
257 logmsg(1, "%lX start do_request %s:%d", pthread_self(), __FILE__, __LINE__);
258 for(;;) {
259 logmsg(2, "%lX start loop %s:%d", pthread_self(), __FILE__, __LINE__);
260 is_closed = 0;
261 close_at_end = 0;
262 content_length = 0L;
263 is_chunked = 0;
264 is_expect = 0;
265 upgrade_h2 = 0;
266 for(i = 0; i < MAXHEADERS; i++)
267 headers[i] = NULL;
268 while(!(is_closed = (fgets(buf, MAXBUF - 1, f_client) == NULL))) {
269 if(buf[0] != '\r' && buf[0] != '\n')
270 break;
271 }
272 if(is_closed) {
273 logmsg(2, "%lX client closed %s:%d", pthread_self(), __FILE__, __LINE__);
274 return;
275 }
276 strcpy(request, buf);
277 if(!strncasecmp(request, "CONNECT", strlen("CONNECT"))) {
278 /* CONNECT is the only refused HTTP request type */
279 time_stamp(buf);
280 logmsg(0, "%s - - [%s] \"%s\" 405 %d CONNECT not allowed", peer_name, buf, request, put_err(f_client, 405, "CONNECT not allowed", global.err405));
281 return;
282 }
283 logmsg(4, "%lX request %s %s:%d", pthread_self(), request, __FILE__, __LINE__);
284 if(!strcasecmp(request, global.http2_preamble[0])) {
285 /* if the request looks like
286 PRI * HTTP/2.0\r\n
287 followed by
288 \r\n
289 SM\r\n
290 \r\n
291 then this is a direct HTTP/2 connection or a HTTP/2 over TLS connection
292
293 so call do_http2() and return
294 */
295 for(i = 1; global.http2_preamble[i]; i++) {
296 if(fgets(buf, MAXBUF - 1, f_client) == NULL) {
297 time_stamp(buf);
298 logmsg(0, "%s - - [%s] \"%s\" 405 %d HTTP/2 preamble premature EOF", peer_name, buf, request, put_err(f_client, 405, "HTTP/2 preamble premature EOF", global.err405));
299 return;
300 }
301 logmsg(4, "%lX preamble %d -> %s %s:%d", pthread_self(), i, buf, __FILE__, __LINE__);
302 if(strcasecmp(buf, global.http2_preamble[i])) {
303 fwrite(global.err405, 1, strlen(global.err405), f_client);
304 time_stamp(buf);
305 logmsg(0, "%s - - [%s] \"%s\" 405 %d HTTP/2 partial preamble", peer_name, buf, request, put_err(f_client, 405, "HTTP/2 partial preamble", global.err405));
306 return;
307 }
308 }
309 do_http2(http, f_client, peer_name, crt_buf, upgrade_h2);
310 return;
311 }
312 for(i = 0; i < MAXHEADERS && !(is_closed = ((fgets(buf, MAXBUF - 1, f_client) == NULL))); ) {
313 logmsg(4, "%lX header %s %s:%d", pthread_self(), buf, __FILE__, __LINE__);
314 if(buf[0] == '\r' || buf[0] == '\n')
315 break;
316 if(!strncasecmp(buf, "Upgrade:", strlen("Upgrade:"))) {
317 /* Upgrade: h2c ==> next request will be HTTP2 */
318 upgrade_h2 = upgrade_h2 || !regexec(&rex_Upgrade_HTTP2, buf, 0, NULL, 0);
319 continue;
320 } else if(!strncasecmp(buf, "Connection:", strlen("Connection:"))) {
321 /* Connection: Upgrade in conjunction with Upgrade: h2c ==> next request will be HTTP2
322 Response will be:
323 Connection: Upgrade
324 Upgrade: h2c
325 so call do_http2() on receipt of the preamble
326 do_http2() will issue a RST_STREAM/REFUSED_STREAM on stream 1 so the client will re-issue the request in HTTP/2
327 */
328 upgrade_h2 = upgrade_h2 || !regexec(&rex_Connection_HTTP2, buf, 0, NULL, 0);
329 close_at_end = !regexec(&rex_Connection_Closed, buf, 0, NULL, 0);
330 logmsg(3, "%lX upgrade_h2 %d close_at_end %d %s:%d", pthread_self(), upgrade_h2, close_at_end, __FILE__, __LINE__);
331 continue;
332 } else if(!regexec(&rex_ContentLength, buf, 2, match, REG_ICASE))
333 sscanf(buf + match[1].rm_so, "%ld", &content_length);
334 else if(!regexec(&rex_Chunked, buf, 0, NULL, REG_ICASE))
335 is_chunked = 1;
336 else
337 is_expect = !regexec(&rex_Expect, buf, 0, NULL, REG_ICASE);
338 if((headers[i++] = strdup(buf)) == NULL) {
339 logmsg(0, "Out of memory");
340 time_stamp(buf);
341 logmsg(0, "%s - - [%s] \"%s\" 500 %d Out of memory", peer_name, buf, request, put_err(f_client, 500, "Out of memory", global.err500));
342 is_closed = 1;
343 break;
344 }
345 }
346 logmsg(3, "%lX content_length %d is_chunked %d is_expect %d %s:%d", pthread_self(), content_length, is_chunked, is_expect, __FILE__, __LINE__);
347 if(is_closed) {
348 for(i = 0; i < MAXHEADERS; i++)
349 if(headers[i])
350 free(headers[i]);
351 return;
352 }
353 if(content_length > 0L && is_chunked) {
354 time_stamp(buf);
355 logmsg(0, "%s - - [%s] \"%s\" 405 %d Chunked and Content-length", peer_name, buf, request, put_err(f_client, 405, "Chunked and Content-length", global.err405));
356 for(i = 0; i < MAXHEADERS; i++)
357 if(headers[i])
358 free(headers[i]);
359 return;
360 }
361 if(is_expect)
362 put_err(f_client, 100, "Continue", NULL);
363
364 if(upgrade_h2) {
365 logmsg(2, "%lX upgrade HTTP/2 consume request %s:%d", pthread_self(), __FILE__, __LINE__);
366 if(content_length > 0L)
367 while(content_length > 0L) {
368 i = fread(buf, sizeof(char), content_length >= MAXBUF? MAXBUF - 1: content_length, f_client);
369 if(i <= 0)
370 content_length = -1L;
371 }
372 else if(is_chunked)
373 while(fgets(buf, MAXBUF - 1, f_client) != NULL) {
374 sscanf(buf, "%ld", &content_length);
375 if(content_length > 0L) {
376 while(content_length > 0L) {
377 i = fread(buf, sizeof(char), content_length >= MAXBUF? MAXBUF - 1: content_length, f_client);
378 if(i <= 0)
379 content_length = -1L;
380 }
381 fgets(buf, MAXBUF, f_client);
382 } else {
383 while(fgets(buf, MAXBUF, f_client) != NULL) {
384 if(buf[0] == '\r' || buf[0] == '\n')
385 break;
386 }
387 }
388 }
389 put_err(f_client, 101, "Switching protocols\r\nConnection: Upgrade\r\nUpgrade: h2c", NULL);
390 continue;
391 }
392
393 if((s_private = get_be(http, peer_name, request, headers, NULL)) < 0) {
394 time_stamp(buf);
395 logmsg(0, "%s - - [%s] \"%s\" 500 %d No backend", peer_name, buf, request, put_err(f_client, 500, "No backend", global.err500));
396 return;
397 }
398
399 logmsg(2, "%lX got backend %s:%d", pthread_self(), __FILE__, __LINE__);
400 i = 1;
401 nn_send(s_private, &i, sizeof(int), 0);
402 nn_send(s_private, peer_name, strlen(peer_name) + 1, 0);
403 nn_send(s_private, request, strlen(request) + 1, 0);
404 if(crt_buf[0]) {
405 logmsg(3, "%lX send cert %s:%d", pthread_self(), __FILE__, __LINE__);
406 nn_send(s_private, "X-Pound-Cert: ", 15, 0);
407 nn_send(s_private, crt_buf, strlen(crt_buf) + 1, 0);
408 nn_send(s_private, "\r\n", 3, 0);
409 }
410 logmsg(3, "%lX send headers %s:%d", pthread_self(), __FILE__, __LINE__);
411 for(i = 0; i < MAXHEADERS; i++)
412 if(headers[i]) {
413 nn_send(s_private, headers[i], strlen(headers[i]) + 1, 0);
414 free(headers[i]);
415 }
416 nn_send(s_private, "\r\n", 3, 0);
417
418 if(content_length > 0L) {
419 logmsg(3, "%lX send content_length %s:%d", pthread_self(), __FILE__, __LINE__);
420 while(content_length > 0L) {
421 memset(buf, '\0', MAXBUF);
422 i = fread(buf, sizeof(char), content_length >= MAXBUF? MAXBUF - 1: content_length, f_client);
423 if(i > 0) {
424 nn_send(s_private, buf, i, 0);
425 content_length -= i;
426 } else
427 content_length = -1L;
428 }
429 } else if(is_chunked) {
430 logmsg(3, "%lX send is_chunked %s:%d", pthread_self(), __FILE__, __LINE__);
431 while(fgets(buf, MAXBUF - 1, f_client) != NULL) {
432 sscanf(buf, "%ld", &content_length);
433 if(content_length > 0L) {
434 while(content_length > 0L) {
435 memset(buf, '\0', MAXBUF);
436 i = fread(buf, sizeof(char), content_length >= MAXBUF? MAXBUF - 1: content_length, f_client);
437 if(i > 0) {
438 nn_send(s_private, buf, i, 0);
439 content_length -= i;
440 } else
441 content_length = -1L;
442 }
443 if(fgets(buf, MAXBUF, f_client) != NULL)
444 nn_send(s_private, buf, strlen(buf) + 1, 0);
445 } else {
446 while(fgets(buf, MAXBUF, f_client) != NULL) {
447 if(regexec(&rex_ContentLength, buf, 2, match, REG_ICASE))
448 nn_send(s_private, buf, strlen(buf) + 1, 0);
449 if(buf[0] == '\r' || buf[0] == '\n')
450 break;
451 }
452 }
453 }
454 }
455 nn_send(s_private, "", 0, 0);
456
457 logmsg(2, "%lX pass response %s:%d", pthread_self(), __FILE__, __LINE__);
458 while((i = nn_recv(s_private, &msg, NN_MSG, 0)) > 0) {
459 fwrite(msg, i, 1, f_client);
460 nn_freemsg(msg);
461 }
462
463 /* end of comms; has to be done from this side, as no LINGER available */
464 nn_send(s_private, "", 0, 0);
465 /* sleep to make sure all messages are through before closing the channel */
466 t_wait.tv_sec = 0;
467 t_wait.tv_nsec = 1000000;
468 nanosleep(&t_wait, NULL);
469
470 nn_close(s_private);
471 logmsg(2, "%lX loop done %s:%d", pthread_self(), __FILE__, __LINE__);
472 if(close_at_end)
473 return ;
474 }
475 }
476
477 typedef struct cookie {
478 mbedtls_ssl_context *fd;
479 } COOKIE;
480
481 static size_t
482 c_read(void *cv, char *buf, size_t size)
483 {
484 COOKIE *c;
485 int n;
486 size_t n_read;
487
488 c = (COOKIE *)cv;
489 n_read = 0;
490 while(n_read < size && (n = mbedtls_ssl_read(c->fd, buf + n_read, size - n_read)) > 0)
491 n_read += n;
492 return n_read;
493 }
494
495 static size_t
496 c_write(void *cv, char *buf, size_t size)
497 {
498 COOKIE *c;
499
500 c = (COOKIE *)cv;
501 return mbedtls_ssl_write(c->fd, buf, size);
502 }
503
504 static int
505 c_close(void *cv)
506 {
507 COOKIE *c;
508 int res;
509 mbedtls_net_context *ssl_fd;
510
511 c = (COOKIE *)cv;
512 res = mbedtls_ssl_close_notify(c->fd);
513 ssl_fd = c->fd->p_bio;
514 mbedtls_ssl_free(c->fd);
515 mbedtls_net_free(ssl_fd);
516 return res;
517 }
518
519 void *
520 thr_http(void *arg)
521 {
522 HTTP_LISTENER *http;
523 BACKEND *be;
524 char *msg, peer_name[NI_MAXHOST], crt_buf[MAXBUF];
525 struct sockaddr peer_addr;
526 int sock_client, n;
527 FILE *f_client;
528 struct linger s_linger;
529 struct timeval s_time;
530 mbedtls_ssl_context ssl;
531 mbedtls_net_context ssl_client;
532 COOKIE c;
533 cookie_io_functions_t cio;
534
535 logmsg(1, "%lX thr_http start %s:%d", pthread_self(), __FILE__, __LINE__);
536 http = (HTTP_LISTENER *)arg;
537 sem_post(&sem_start);
538 for(;;) {
539 logmsg(2, "%lX start loop %s:%d", pthread_self(), __FILE__, __LINE__);
540 if(nn_recv(http->sock_fan, &msg, NN_MSG, 0) <= 0) {
541 logmsg(0, "HTTP: bad receive %s", nn_strerror(nn_errno()));
542 continue;
543 }
544 memcpy(&sock_client, msg, sizeof(sock_client));
545 nn_freemsg(msg);
546 n = sizeof(peer_addr);
547 getpeername(sock_client, &peer_addr, &n);
548 getnameinfo(&peer_addr, sizeof(peer_addr), peer_name, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
549 logmsg(4, "%lX peer address %s %s:%d", pthread_self(), peer_name, __FILE__, __LINE__);
550 if(http->conf == NULL) {
551 s_linger.l_onoff = 1;
552 s_linger.l_linger = 0;
553 setsockopt(sock_client, SOL_SOCKET, SO_LINGER, &s_linger, sizeof(s_linger));
554 s_time.tv_sec = http->client;
555 s_time.tv_usec = 0;
556 setsockopt(sock_client, SOL_SOCKET, SO_RCVTIMEO, &s_time, sizeof(s_time));
557 setsockopt(sock_client, SOL_SOCKET, SO_SNDTIMEO, &s_time, sizeof(s_time));
558 f_client = fdopen(sock_client, "r+");
559 } else {
560 mbedtls_net_init(&ssl_client);
561 ssl_client.fd = sock_client;
562 mbedtls_ssl_init(&ssl);
563 mbedtls_ssl_setup(&ssl, http->conf);
564 mbedtls_ssl_set_bio(&ssl, &sock_client, mbedtls_net_send, NULL, mbedtls_net_recv_timeout);
565 if(n = mbedtls_ssl_handshake(&ssl)) {
566 mbedtls_strerror(n, crt_buf, MAXBUF);
567 logmsg(0, "Failed handshake from %s: %d - %s", peer_name, n, crt_buf);
568 mbedtls_ssl_free(&ssl);
569 close(sock_client);
570 continue;
571 }
572 logmsg(2, "%lX handshake OK %s:%d", pthread_self(), __FILE__, __LINE__);
573 if(mbedtls_ssl_get_peer_cert(&ssl) != NULL) {
574 mbedtls_x509_crt_info(crt_buf, MAXBUF, "\t", mbedtls_ssl_get_peer_cert(&ssl));
575 logmsg(4, "%lX peer certificate %s %s:%d", pthread_self(), crt_buf, __FILE__, __LINE__);
576 for(n = 0; n < MAXBUF && crt_buf[n]; n++)
577 ;
578 crt_buf[--n] = '\0';
579 } else
580 crt_buf[0] = '\0';
581 /* for HTTP2: !strcmp(mbedtls_ssl_get_alpn_protocol(&ssl), "h2"), but we don't really need it */
582 c.fd = &ssl;
583 cio.read = (cookie_read_function_t *)c_read;
584 cio.write = (cookie_write_function_t *)c_write;
585 cio.seek = NULL;
586 cio.close = (cookie_close_function_t *)c_close;
587
588 if((f_client = fopencookie(&c, "w+", cio)) == NULL) {
589 logmsg(0, "fopencookie failed");
590 mbedtls_ssl_free(&ssl);
591 mbedtls_net_free(&ssl_client);
592 close(sock_client);
593 continue;
594 }
595 setvbuf(f_client, NULL, _IONBF, 0);
596 }
597 do_request(http, f_client, peer_name, crt_buf);
598 fclose(f_client);
599 logmsg(2, "%lX done loop %s:%d", pthread_self(), __FILE__, __LINE__);
600 }
601 }