dnscrypto-proxy: Update to release 1.3.0
[tomato.git] / release / src / router / dnscrypt / src / proxy / tcp_request.c
blob5c95e7b8959bf12191e4ed268351713476eaa697
2 #include <config.h>
3 #include <sys/types.h>
4 #ifdef _WIN32
5 # include <winsock2.h>
6 #else
7 # include <sys/socket.h>
8 # include <netinet/in.h>
9 # include <netinet/tcp.h>
10 #endif
12 #include <assert.h>
13 #include <limits.h>
14 #include <signal.h>
15 #include <stdint.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
20 #include <event2/buffer.h>
21 #include <event2/bufferevent.h>
22 #include <event2/event.h>
23 #include <event2/listener.h>
24 #include <event2/util.h>
26 #include "dnscrypt_client.h"
27 #include "dnscrypt_proxy.h"
28 #include "logger.h"
29 #include "probes.h"
30 #include "tcp_request.h"
31 #include "tcp_request_p.h"
32 #include "udp_request.h"
33 #ifdef PLUGINS
34 # include "plugin_support.h"
35 #endif
37 static void
38 tcp_request_free(TCPRequest * const tcp_request)
40 ProxyContext *proxy_context;
42 if (tcp_request->timeout_timer != NULL) {
43 event_free(tcp_request->timeout_timer);
44 tcp_request->timeout_timer = NULL;
46 if (tcp_request->client_proxy_bev != NULL) {
47 DNSCRYPT_PROXY_REQUEST_TCP_DONE(tcp_request);
48 bufferevent_free(tcp_request->client_proxy_bev);
49 tcp_request->client_proxy_bev = NULL;
51 if (tcp_request->proxy_resolver_bev != NULL) {
52 DNSCRYPT_PROXY_REQUEST_TCP_PROXY_RESOLVER_DONE(tcp_request);
53 bufferevent_free(tcp_request->proxy_resolver_bev);
54 tcp_request->proxy_resolver_bev = NULL;
56 if (tcp_request->proxy_resolver_query_evbuf != NULL) {
57 evbuffer_free(tcp_request->proxy_resolver_query_evbuf);
58 tcp_request->proxy_resolver_query_evbuf = NULL;
60 proxy_context = tcp_request->proxy_context;
61 if (tcp_request->status.is_in_queue != 0) {
62 assert(! TAILQ_EMPTY(&proxy_context->tcp_request_queue));
63 TAILQ_REMOVE(&proxy_context->tcp_request_queue, tcp_request, queue);
64 assert(proxy_context->connections_count > 0U);
65 proxy_context->connections_count--;
66 DNSCRYPT_PROXY_STATUS_REQUESTS_ACTIVE(proxy_context->connections_count,
67 proxy_context->connections_count_max);
69 tcp_request->proxy_context = NULL;
70 free(tcp_request);
73 static void
74 tcp_request_kill(TCPRequest * const tcp_request)
76 if (tcp_request == NULL || tcp_request->status.is_dying) {
77 return;
79 tcp_request->status.is_dying = 1;
80 tcp_request_free(tcp_request);
83 static void
84 tcp_tune(evutil_socket_t handle)
86 if (handle == -1) {
87 return;
89 setsockopt(handle, IPPROTO_TCP, TCP_NODELAY,
90 (void *) (int []) { 1 }, sizeof (int));
93 static void
94 timeout_timer_cb(evutil_socket_t timeout_timer_handle, short ev_flags,
95 void * const tcp_request_)
97 TCPRequest * const tcp_request = tcp_request_;
99 (void) ev_flags;
100 (void) timeout_timer_handle;
101 DNSCRYPT_PROXY_REQUEST_TCP_TIMEOUT(tcp_request);
102 logger_noformat(tcp_request->proxy_context, LOG_DEBUG,
103 "resolver timeout (TCP)");
104 tcp_request_kill(tcp_request);
107 static void
108 proxy_resolver_event_cb(struct bufferevent * const proxy_resolver_bev,
109 const short events, void * const tcp_request_)
111 TCPRequest * const tcp_request = tcp_request_;
113 (void) proxy_resolver_bev;
114 if ((events & BEV_EVENT_ERROR) != 0) {
115 DNSCRYPT_PROXY_REQUEST_TCP_PROXY_RESOLVER_NETWORK_ERROR(tcp_request);
116 tcp_request_kill(tcp_request);
117 return;
119 if ((events & BEV_EVENT_CONNECTED) == 0) {
120 DNSCRYPT_PROXY_REQUEST_TCP_PROXY_RESOLVER_CONNECTED(tcp_request);
121 tcp_tune(bufferevent_getfd(proxy_resolver_bev));
122 return;
126 static void
127 resolver_proxy_read_cb(struct bufferevent * const proxy_resolver_bev,
128 void * const tcp_request_)
130 uint8_t dns_reply_len_buf[2];
131 uint8_t dns_uncurved_reply_len_buf[2];
132 uint8_t *dns_reply;
133 TCPRequest *tcp_request = tcp_request_;
134 ProxyContext *proxy_context = tcp_request->proxy_context;
135 struct evbuffer *input = bufferevent_get_input(proxy_resolver_bev);
136 size_t available_size;
137 size_t dns_reply_len;
138 size_t uncurved_len;
140 if (tcp_request->status.has_dns_reply_len == 0) {
141 assert(evbuffer_get_length(input) >= (size_t) 2U);
142 evbuffer_remove(input, dns_reply_len_buf, sizeof dns_reply_len_buf);
143 tcp_request->dns_reply_len = (size_t)
144 ((dns_reply_len_buf[0] << 8) | dns_reply_len_buf[1]);
145 tcp_request->status.has_dns_reply_len = 1;
147 assert(tcp_request->status.has_dns_reply_len != 0);
148 dns_reply_len = tcp_request->dns_reply_len;
149 if (dns_reply_len <
150 (size_t) DNS_HEADER_SIZE + dnscrypt_response_header_size()) {
151 logger_noformat(proxy_context, LOG_WARNING, "Short reply received");
152 DNSCRYPT_PROXY_REQUEST_TCP_PROXY_RESOLVER_GOT_INVALID_REPLY(tcp_request);
153 tcp_request_kill(tcp_request);
154 return;
156 available_size = evbuffer_get_length(input);
157 if (available_size < dns_reply_len) {
158 bufferevent_setwatermark(tcp_request->proxy_resolver_bev,
159 EV_READ, dns_reply_len, dns_reply_len);
160 return;
162 DNSCRYPT_PROXY_REQUEST_TCP_PROXY_RESOLVER_REPLIED(tcp_request);
163 assert(available_size >= dns_reply_len);
164 dns_reply = evbuffer_pullup(input, (ssize_t) dns_reply_len);
165 if (dns_reply == NULL) {
166 tcp_request_kill(tcp_request);
167 return;
169 uncurved_len = dns_reply_len;
170 DNSCRYPT_PROXY_REQUEST_UNCURVE_START(tcp_request, uncurved_len);
171 if (dnscrypt_client_uncurve(&proxy_context->dnscrypt_client,
172 tcp_request->client_nonce,
173 dns_reply, &uncurved_len) != 0) {
174 DNSCRYPT_PROXY_REQUEST_UNCURVE_ERROR(tcp_request);
175 DNSCRYPT_PROXY_REQUEST_TCP_PROXY_RESOLVER_GOT_INVALID_REPLY(tcp_request);
176 logger_noformat(tcp_request->proxy_context, LOG_WARNING,
177 "Received a suspicious reply from the resolver");
178 tcp_request_kill(tcp_request);
179 return;
181 DNSCRYPT_PROXY_REQUEST_UNCURVE_DONE(tcp_request, uncurved_len);
182 memset(tcp_request->client_nonce, 0, sizeof tcp_request->client_nonce);
183 assert(uncurved_len <= dns_reply_len);
184 dns_reply_len = uncurved_len;
185 #ifdef PLUGINS
186 const size_t max_reply_size_for_filter = tcp_request->dns_reply_len;
187 DCPluginDNSPacket dcp_packet = {
188 .client_sockaddr = &tcp_request->client_sockaddr,
189 .dns_packet = dns_reply,
190 .dns_packet_len_p = &dns_reply_len,
191 .client_sockaddr_len_s = (size_t) tcp_request->client_sockaddr_len,
192 .dns_packet_max_len = max_reply_size_for_filter
194 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_START(tcp_request, dns_reply_len,
195 max_reply_size_for_filter);
196 assert(proxy_context->app_context->dcps_context != NULL);
197 const DCPluginSyncFilterResult res =
198 plugin_support_context_apply_sync_post_filters
199 (proxy_context->app_context->dcps_context, &dcp_packet);
200 assert(dns_reply_len > (size_t) 0U &&
201 dns_reply_len <= tcp_request->dns_reply_len &&
202 dns_reply_len <= max_reply_size_for_filter);
203 if (res != DCP_SYNC_FILTER_RESULT_OK) {
204 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_ERROR(tcp_request, res);
205 tcp_request_kill(tcp_request);
206 return;
208 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_DONE(tcp_request, dns_reply_len,
209 max_reply_size_for_filter);
210 #endif
211 dns_uncurved_reply_len_buf[0] = (dns_reply_len >> 8) & 0xff;
212 dns_uncurved_reply_len_buf[1] = dns_reply_len & 0xff;
213 if (bufferevent_write(tcp_request->client_proxy_bev,
214 dns_uncurved_reply_len_buf, (size_t) 2U) != 0 ||
215 bufferevent_write(tcp_request->client_proxy_bev, dns_reply,
216 dns_reply_len) != 0) {
217 tcp_request_kill(tcp_request);
218 return;
220 bufferevent_enable(tcp_request->client_proxy_bev, EV_WRITE);
221 DNSCRYPT_PROXY_REQUEST_TCP_PROXY_RESOLVER_DONE(tcp_request);
222 bufferevent_free(tcp_request->proxy_resolver_bev);
223 tcp_request->proxy_resolver_bev = NULL;
226 static void
227 client_proxy_event_cb(struct bufferevent * const client_proxy_bev,
228 const short events, void * const tcp_request_)
230 TCPRequest * const tcp_request = tcp_request_;
232 (void) client_proxy_bev;
233 (void) events;
234 tcp_request_kill(tcp_request);
237 static void
238 client_proxy_write_cb(struct bufferevent * const client_proxy_bev,
239 void * const tcp_request_)
241 TCPRequest * const tcp_request = tcp_request_;
243 (void) client_proxy_bev;
244 DNSCRYPT_PROXY_REQUEST_TCP_REPLIED(tcp_request);
245 tcp_request_kill(tcp_request);
248 #ifdef PLUGINS
249 static void
250 proxy_to_client_direct(TCPRequest * const tcp_request,
251 const uint8_t * const dns_reply,
252 const size_t dns_reply_len)
254 uint8_t dns_reply_len_buf[2];
256 DNSCRYPT_PROXY_REQUEST_TCP_PROXY_RESOLVER_DONE(tcp_request);
257 bufferevent_free(tcp_request->proxy_resolver_bev);
258 tcp_request->proxy_resolver_bev = NULL;
260 dns_reply_len_buf[0] = (dns_reply_len >> 8) & 0xff;
261 dns_reply_len_buf[1] = dns_reply_len & 0xff;
262 if (bufferevent_write(tcp_request->client_proxy_bev,
263 dns_reply_len_buf, (size_t) 2U) != 0 ||
264 bufferevent_write(tcp_request->client_proxy_bev, dns_reply,
265 dns_reply_len) != 0) {
266 tcp_request_kill(tcp_request);
267 return;
269 bufferevent_enable(tcp_request->client_proxy_bev, EV_WRITE);
270 assert(tcp_request->proxy_resolver_bev == NULL);
272 #endif
274 static void
275 client_proxy_read_cb(struct bufferevent * const client_proxy_bev,
276 void * const tcp_request_)
278 uint8_t dns_query[DNS_MAX_PACKET_SIZE_TCP - 2U];
279 uint8_t dns_query_len_buf[2];
280 uint8_t dns_curved_query_len_buf[2];
281 TCPRequest *tcp_request = tcp_request_;
282 ProxyContext *proxy_context = tcp_request->proxy_context;
283 struct evbuffer *input = bufferevent_get_input(client_proxy_bev);
284 ssize_t curve_ret;
285 size_t available_size;
286 size_t dns_query_len;
287 size_t max_query_size;
289 if (tcp_request->status.has_dns_query_len == 0) {
290 assert(evbuffer_get_length(input) >= (size_t) 2U);
291 evbuffer_remove(input, dns_query_len_buf, sizeof dns_query_len_buf);
292 tcp_request->dns_query_len = (size_t)
293 ((dns_query_len_buf[0] << 8) | dns_query_len_buf[1]);
294 tcp_request->status.has_dns_query_len = 1;
296 assert(tcp_request->status.has_dns_query_len != 0);
297 dns_query_len = tcp_request->dns_query_len;
298 if (dns_query_len < (size_t) DNS_HEADER_SIZE) {
299 logger_noformat(proxy_context, LOG_WARNING, "Short query received");
300 tcp_request_kill(tcp_request);
301 return;
303 available_size = evbuffer_get_length(input);
304 if (available_size < dns_query_len) {
305 bufferevent_setwatermark(tcp_request->client_proxy_bev,
306 EV_READ, dns_query_len, dns_query_len);
307 return;
309 assert(available_size >= dns_query_len);
310 bufferevent_disable(tcp_request->client_proxy_bev, EV_READ);
311 assert(tcp_request->proxy_resolver_query_evbuf == NULL);
312 if ((tcp_request->proxy_resolver_query_evbuf = evbuffer_new()) == NULL) {
313 tcp_request_kill(tcp_request);
314 return;
316 if ((ssize_t)
317 evbuffer_remove_buffer(input, tcp_request->proxy_resolver_query_evbuf,
318 dns_query_len) != (ssize_t) dns_query_len) {
319 tcp_request_kill(tcp_request);
320 return;
322 assert(dns_query_len <= sizeof dns_query);
323 if ((ssize_t) evbuffer_remove(tcp_request->proxy_resolver_query_evbuf,
324 dns_query, dns_query_len)
325 != (ssize_t) dns_query_len) {
326 tcp_request_kill(tcp_request);
327 return;
329 max_query_size = sizeof dns_query;
330 assert(max_query_size < DNS_MAX_PACKET_SIZE_TCP);
331 #ifdef PLUGINS
332 size_t max_query_size_for_filter = dns_query_len;
333 if (max_query_size > DNSCRYPT_MAX_PADDING + dnscrypt_query_header_size()) {
334 max_query_size_for_filter = max_query_size -
335 (DNSCRYPT_MAX_PADDING + dnscrypt_query_header_size());
337 DCPluginDNSPacket dcp_packet = {
338 .client_sockaddr = &tcp_request->client_sockaddr,
339 .dns_packet = dns_query,
340 .dns_packet_len_p = &dns_query_len,
341 .client_sockaddr_len_s = (size_t) tcp_request->client_sockaddr_len,
342 .dns_packet_max_len = max_query_size_for_filter
344 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_START(tcp_request, dns_query_len,
345 max_query_size_for_filter);
346 assert(proxy_context->app_context->dcps_context != NULL);
347 const DCPluginSyncFilterResult res =
348 plugin_support_context_apply_sync_pre_filters
349 (proxy_context->app_context->dcps_context, &dcp_packet);
350 assert(dns_query_len > (size_t) 0U && dns_query_len <= max_query_size &&
351 dns_query_len <= max_query_size_for_filter);
352 switch (res) {
353 case DCP_SYNC_FILTER_RESULT_OK:
354 break;
355 case DCP_SYNC_FILTER_RESULT_DIRECT:
356 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_DONE(tcp_request, dns_query_len,
357 max_query_size_for_filter);
358 proxy_to_client_direct(tcp_request, dns_query, dns_query_len);
359 return;
360 default:
361 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_ERROR(tcp_request, res);
362 tcp_request_kill(tcp_request);
363 return;
365 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_DONE(tcp_request, dns_query_len,
366 max_query_size_for_filter);
367 #endif
368 assert(SIZE_MAX - DNSCRYPT_MAX_PADDING - dnscrypt_query_header_size()
369 > dns_query_len);
370 size_t max_len = dns_query_len + DNSCRYPT_MAX_PADDING +
371 dnscrypt_query_header_size();
372 if (max_len > max_query_size) {
373 max_len = max_query_size;
375 if (dns_query_len + dnscrypt_query_header_size() > max_len) {
376 tcp_request_kill(tcp_request);
377 return;
379 assert(max_len <= DNS_MAX_PACKET_SIZE_TCP - 2U);
380 assert(max_len <= sizeof dns_query);
381 assert(dns_query_len <= max_len);
382 DNSCRYPT_PROXY_REQUEST_CURVE_START(tcp_request, dns_query_len);
383 curve_ret =
384 dnscrypt_client_curve(&proxy_context->dnscrypt_client,
385 tcp_request->client_nonce,
386 dns_query, dns_query_len, max_len);
387 if (curve_ret <= (ssize_t) 0) {
388 DNSCRYPT_PROXY_REQUEST_CURVE_ERROR(tcp_request);
389 tcp_request_kill(tcp_request);
390 return;
392 DNSCRYPT_PROXY_REQUEST_CURVE_DONE(tcp_request, (size_t) curve_ret);
393 dns_curved_query_len_buf[0] = (curve_ret >> 8) & 0xff;
394 dns_curved_query_len_buf[1] = curve_ret & 0xff;
395 if (bufferevent_write(tcp_request->proxy_resolver_bev,
396 dns_curved_query_len_buf, (size_t) 2U) != 0 ||
397 bufferevent_write(tcp_request->proxy_resolver_bev, dns_query,
398 (size_t) curve_ret) != 0) {
399 tcp_request_kill(tcp_request);
400 return;
402 bufferevent_enable(tcp_request->proxy_resolver_bev, EV_READ);
405 static void
406 tcp_connection_cb(struct evconnlistener * const tcp_conn_listener,
407 evutil_socket_t handle,
408 struct sockaddr * const client_sockaddr,
409 const int client_sockaddr_len_int,
410 void * const proxy_context_)
412 ProxyContext *proxy_context = proxy_context_;
413 TCPRequest *tcp_request;
415 (void) tcp_conn_listener;
416 (void) client_sockaddr;
417 (void) client_sockaddr_len_int;
418 if ((tcp_request = calloc((size_t) 1U, sizeof *tcp_request)) == NULL) {
419 return;
421 tcp_request->proxy_context = proxy_context;
422 tcp_request->timeout_timer = NULL;
423 tcp_request->proxy_resolver_query_evbuf = NULL;
424 #ifdef PLUGINS
425 assert(client_sockaddr_len_int >= 0 &&
426 sizeof tcp_request->client_sockaddr >=
427 (size_t) client_sockaddr_len_int);
428 memcpy(&tcp_request->client_sockaddr, client_sockaddr,
429 (size_t) client_sockaddr_len_int);
430 tcp_request->client_sockaddr_len = (ev_socklen_t) client_sockaddr_len_int;
431 #endif
432 tcp_request->client_proxy_bev =
433 bufferevent_socket_new(proxy_context->event_loop, handle,
434 BEV_OPT_CLOSE_ON_FREE);
435 if (tcp_request->client_proxy_bev == NULL) {
436 evutil_closesocket(handle);
437 free(tcp_request);
438 return;
440 tcp_request->proxy_resolver_bev = bufferevent_socket_new
441 (proxy_context->event_loop, -1, BEV_OPT_CLOSE_ON_FREE);
442 if (tcp_request->proxy_resolver_bev == NULL) {
443 bufferevent_free(tcp_request->client_proxy_bev);
444 tcp_request->client_proxy_bev = NULL;
445 free(tcp_request);
446 return;
448 if (proxy_context->connections_count >=
449 proxy_context->connections_count_max) {
450 DNSCRYPT_PROXY_REQUEST_TCP_OVERLOADED();
451 if (tcp_listener_kill_oldest_request(proxy_context) != 0) {
452 udp_listener_kill_oldest_request(proxy_context);
455 proxy_context->connections_count++;
456 assert(proxy_context->connections_count
457 <= proxy_context->connections_count_max);
458 DNSCRYPT_PROXY_STATUS_REQUESTS_ACTIVE(proxy_context->connections_count,
459 proxy_context->connections_count_max);
460 DNSCRYPT_PROXY_REQUEST_TCP_START(tcp_request);
461 TAILQ_INSERT_TAIL(&proxy_context->tcp_request_queue,
462 tcp_request, queue);
463 memset(&tcp_request->status, 0, sizeof tcp_request->status);
464 tcp_request->status.is_in_queue = 1;
465 if ((tcp_request->timeout_timer =
466 evtimer_new(tcp_request->proxy_context->event_loop,
467 timeout_timer_cb, tcp_request)) == NULL) {
468 tcp_request_kill(tcp_request);
469 return;
471 const struct timeval tv = {
472 .tv_sec = (time_t) DNS_QUERY_TIMEOUT, .tv_usec = 0
474 evtimer_add(tcp_request->timeout_timer, &tv);
475 bufferevent_setwatermark(tcp_request->client_proxy_bev,
476 EV_READ, (size_t) 2U,
477 (size_t) DNS_MAX_PACKET_SIZE_TCP);
478 bufferevent_setcb(tcp_request->client_proxy_bev,
479 client_proxy_read_cb, client_proxy_write_cb,
480 client_proxy_event_cb, tcp_request);
481 if (bufferevent_socket_connect
482 (tcp_request->proxy_resolver_bev,
483 (struct sockaddr *) &proxy_context->resolver_sockaddr,
484 (int) proxy_context->resolver_sockaddr_len) != 0) {
485 tcp_request_kill(tcp_request);
486 return;
488 bufferevent_setwatermark(tcp_request->proxy_resolver_bev,
489 EV_READ, (size_t) 2U,
490 (size_t) DNS_MAX_PACKET_SIZE_TCP);
491 bufferevent_setcb(tcp_request->proxy_resolver_bev,
492 resolver_proxy_read_cb, NULL, proxy_resolver_event_cb,
493 tcp_request);
494 DNSCRYPT_PROXY_REQUEST_TCP_PROXY_RESOLVER_START(tcp_request);
495 bufferevent_enable(tcp_request->client_proxy_bev, EV_READ);
498 static void
499 tcp_accept_timer_cb(evutil_socket_t handle, const short event,
500 void * const proxy_context_)
502 ProxyContext *proxy_context = proxy_context_;
504 (void) handle;
505 (void) event;
506 event_free(proxy_context->tcp_accept_timer);
507 proxy_context->tcp_accept_timer = NULL;
508 evconnlistener_enable(proxy_context->tcp_conn_listener);
511 static void
512 tcp_accept_error_cb(struct evconnlistener * const tcp_conn_listener,
513 void * const proxy_context_)
515 ProxyContext *proxy_context = proxy_context_;
517 (void) tcp_conn_listener;
518 DNSCRYPT_PROXY_REQUEST_TCP_NETWORK_ERROR(NULL);
519 if (proxy_context->tcp_accept_timer == NULL) {
520 proxy_context->tcp_accept_timer = evtimer_new
521 (proxy_context->event_loop, tcp_accept_timer_cb, proxy_context);
522 if (proxy_context->tcp_accept_timer == NULL) {
523 return;
526 if (evtimer_pending(proxy_context->tcp_accept_timer, NULL)) {
527 return;
529 evconnlistener_disable(proxy_context->tcp_conn_listener);
531 const struct timeval tv = { .tv_sec = (time_t) 1, .tv_usec = 0 };
532 evtimer_add(proxy_context->tcp_accept_timer, &tv);
536 tcp_listener_kill_oldest_request(ProxyContext * const proxy_context)
538 if (TAILQ_EMPTY(&proxy_context->tcp_request_queue)) {
539 return -1;
541 tcp_request_kill(TAILQ_FIRST(&proxy_context->tcp_request_queue));
543 return 0;
547 tcp_listener_bind(ProxyContext * const proxy_context)
549 assert(proxy_context->tcp_conn_listener == NULL);
550 #ifndef LEV_OPT_DEFERRED_ACCEPT
551 # define LEV_OPT_DEFERRED_ACCEPT 0
552 #endif
553 proxy_context->tcp_conn_listener =
554 evconnlistener_new_bind(proxy_context->event_loop,
555 tcp_connection_cb, proxy_context,
556 LEV_OPT_CLOSE_ON_FREE |
557 LEV_OPT_CLOSE_ON_EXEC |
558 LEV_OPT_REUSEABLE |
559 LEV_OPT_DEFERRED_ACCEPT,
560 TCP_REQUEST_BACKLOG,
561 (struct sockaddr *)
562 &proxy_context->local_sockaddr,
563 (int) proxy_context->local_sockaddr_len);
564 if (proxy_context->tcp_conn_listener == NULL) {
565 logger(NULL, LOG_ERR, "Unable to bind (TCP)");
566 return -1;
568 if (evconnlistener_disable(proxy_context->tcp_conn_listener) != 0) {
569 evconnlistener_free(proxy_context->tcp_conn_listener);
570 proxy_context->tcp_conn_listener = NULL;
571 return -1;
573 evconnlistener_set_error_cb(proxy_context->tcp_conn_listener,
574 tcp_accept_error_cb);
575 TAILQ_INIT(&proxy_context->tcp_request_queue);
577 return 0;
581 tcp_listener_start(ProxyContext * const proxy_context)
583 assert(proxy_context->tcp_conn_listener != NULL);
584 if (evconnlistener_enable(proxy_context->tcp_conn_listener) != 0) {
585 return -1;
587 return 0;
590 void
591 tcp_listener_stop(ProxyContext * const proxy_context)
593 evconnlistener_free(proxy_context->tcp_conn_listener);
594 proxy_context->tcp_conn_listener = NULL;
595 while (tcp_listener_kill_oldest_request(proxy_context) != 0) { }
596 logger_noformat(proxy_context, LOG_INFO, "TCP listener shut down");