diff options
Diffstat (limited to 'util/netevent.c')
-rw-r--r-- | util/netevent.c | 610 |
1 files changed, 558 insertions, 52 deletions
diff --git a/util/netevent.c b/util/netevent.c index 3e7a433e50214..545f09742c7c0 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -373,12 +373,7 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet, if(sent == -1) { if(!udp_send_errno_needs_log(addr, addrlen)) return 0; -#ifndef USE_WINSOCK - verbose(VERB_OPS, "sendto failed: %s", strerror(errno)); -#else - verbose(VERB_OPS, "sendto failed: %s", - wsa_strerror(WSAGetLastError())); -#endif + verbose(VERB_OPS, "sendto failed: %s", sock_strerror(errno)); log_addr(VERB_OPS, "remote address is", (struct sockaddr_storage*)addr, addrlen); return 0; @@ -739,7 +734,7 @@ static void setup_tcp_handler(struct comm_point* c, int fd, int cur, int max) { int handler_usage; - log_assert(c->type == comm_tcp); + log_assert(c->type == comm_tcp || c->type == comm_http); log_assert(c->fd == -1); sldns_buffer_clear(c->buffer); #ifdef USE_DNSCRYPT @@ -845,7 +840,6 @@ int comm_point_perform_accept(struct comm_point* c, return -1; } #endif - log_err_addr("accept failed", strerror(errno), addr, *addrlen); #else /* USE_WINSOCK */ if(WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAECONNRESET) @@ -854,9 +848,9 @@ int comm_point_perform_accept(struct comm_point* c, ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ); return -1; } - log_err_addr("accept failed", wsa_strerror(WSAGetLastError()), - addr, *addrlen); #endif + log_err_addr("accept failed", sock_strerror(errno), addr, + *addrlen); return -1; } if(c->tcp_conn_limit && c->type == comm_tcp_accept) { @@ -914,6 +908,42 @@ comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl) } #endif +#ifdef HAVE_NGHTTP2 +/** Create http2 session server. Per connection, after TCP accepted.*/ +static int http2_session_server_create(struct http2_session* h2_session) +{ + log_assert(h2_session->callbacks); + h2_session->is_drop = 0; + if(nghttp2_session_server_new(&h2_session->session, + h2_session->callbacks, + h2_session) == NGHTTP2_ERR_NOMEM) { + log_err("failed to create nghttp2 session server"); + return 0; + } + + return 1; +} + +/** Submit http2 setting to session. Once per session. */ +static int http2_submit_settings(struct http2_session* h2_session) +{ + int ret; + nghttp2_settings_entry settings[1] = { + {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, + h2_session->c->http2_max_streams}}; + + ret = nghttp2_submit_settings(h2_session->session, NGHTTP2_FLAG_NONE, + settings, 1); + if(ret) { + verbose(VERB_QUERY, "http2: submit_settings failed, " + "error: %s", nghttp2_strerror(ret)); + return 0; + } + return 1; +} +#endif /* HAVE_NGHTTP2 */ + + void comm_point_tcp_accept_callback(int fd, short event, void* arg) { @@ -935,7 +965,28 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg) /* clear leftover flags from previous use, and then set the * correct event base for the event structure for libevent */ ub_event_free(c_hdl->ev->ev); - c_hdl->ev->ev = ub_event_new(c_hdl->ev->base->eb->base, -1, UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT, comm_point_tcp_handle_callback, c_hdl); + + if(c_hdl->type == comm_http) { +#ifdef HAVE_NGHTTP2 + if(!c_hdl->h2_session || + !http2_session_server_create(c_hdl->h2_session)) { + log_warn("failed to create nghttp2"); + return; + } + if(!c_hdl->h2_session || + !http2_submit_settings(c_hdl->h2_session)) { + log_warn("failed to submit http2 settings"); + return; + } +#endif + c_hdl->ev->ev = ub_event_new(c_hdl->ev->base->eb->base, -1, + UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT, + comm_point_http_handle_callback, c_hdl); + } else { + c_hdl->ev->ev = ub_event_new(c_hdl->ev->base->eb->base, -1, + UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT, + comm_point_tcp_handle_callback, c_hdl); + } if(!c_hdl->ev->ev) { log_warn("could not ub_event_new, dropped tcp"); return; @@ -1169,6 +1220,18 @@ ssl_handshake(struct comm_point* c) c->repinfo.addrlen); } + /* check if http2 use is negotiated */ + if(c->type == comm_http && c->h2_session) { + const unsigned char *alpn; + unsigned int alpnlen = 0; + SSL_get0_alpn_selected(c->ssl, &alpn, &alpnlen); + if(alpnlen == 2 && memcmp("h2", alpn, 2) == 0) { + /* connection upgraded to HTTP2 */ + c->tcp_do_toggle_rw = 0; + c->use_h2 = 1; + } + } + /* setup listen rw correctly */ if(c->tcp_is_reading) { if(c->ssl_shake_state != comm_ssl_shake_read) @@ -1435,8 +1498,6 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) if(errno == ECONNRESET && verbosity < 2) return 0; /* silence reset by peer */ #endif - log_err_addr("read (in tcp s)", strerror(errno), - &c->repinfo.addr, c->repinfo.addrlen); #else /* USE_WINSOCK */ if(WSAGetLastError() == WSAECONNRESET) return 0; @@ -1447,10 +1508,9 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) UB_EV_READ); return 1; } - log_err_addr("read (in tcp s)", - wsa_strerror(WSAGetLastError()), - &c->repinfo.addr, c->repinfo.addrlen); #endif + log_err_addr("read (in tcp s)", sock_strerror(errno), + &c->repinfo.addr, c->repinfo.addrlen); return 0; } c->tcp_byte_count += r; @@ -1483,8 +1543,6 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) #ifndef USE_WINSOCK if(errno == EINTR || errno == EAGAIN) return 1; - log_err_addr("read (in tcp r)", strerror(errno), - &c->repinfo.addr, c->repinfo.addrlen); #else /* USE_WINSOCK */ if(WSAGetLastError() == WSAECONNRESET) return 0; @@ -1494,10 +1552,9 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ); return 1; } - log_err_addr("read (in tcp r)", - wsa_strerror(WSAGetLastError()), - &c->repinfo.addr, c->repinfo.addrlen); #endif + log_err_addr("read (in tcp r)", sock_strerror(errno), + &c->repinfo.addr, c->repinfo.addrlen); return 0; } sldns_buffer_skip(c->buffer, r); @@ -1716,8 +1773,6 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c) if(errno == ECONNRESET && verbosity < 2) return 0; /* silence reset by peer */ #endif - log_err_addr("tcp send r", strerror(errno), - &c->repinfo.addr, c->repinfo.addrlen); #else if(WSAGetLastError() == WSAEINPROGRESS) return 1; @@ -1727,9 +1782,9 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c) } if(WSAGetLastError() == WSAECONNRESET && verbosity < 2) return 0; /* silence reset by peer */ - log_err_addr("tcp send r", wsa_strerror(WSAGetLastError()), - &c->repinfo.addr, c->repinfo.addrlen); #endif + log_err_addr("tcp send r", sock_strerror(errno), + &c->repinfo.addr, c->repinfo.addrlen); return 0; } sldns_buffer_skip(buffer, r); @@ -1914,8 +1969,6 @@ http_read_more(int fd, struct comm_point* c) #ifndef USE_WINSOCK if(errno == EINTR || errno == EAGAIN) return 1; - log_err_addr("read (in http r)", strerror(errno), - &c->repinfo.addr, c->repinfo.addrlen); #else /* USE_WINSOCK */ if(WSAGetLastError() == WSAECONNRESET) return 0; @@ -1925,10 +1978,9 @@ http_read_more(int fd, struct comm_point* c) ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ); return 1; } - log_err_addr("read (in http r)", - wsa_strerror(WSAGetLastError()), - &c->repinfo.addr, c->repinfo.addrlen); #endif + log_err_addr("read (in http r)", sock_strerror(errno), + &c->repinfo.addr, c->repinfo.addrlen); return 0; } sldns_buffer_skip(c->buffer, r); @@ -2186,11 +2238,209 @@ http_chunked_segment(struct comm_point* c) return 1; } +#ifdef HAVE_NGHTTP2 +/** Create new http2 session. Called when creating handling comm point. */ +struct http2_session* http2_session_create(struct comm_point* c) +{ + struct http2_session* session = calloc(1, sizeof(*session)); + if(!session) { + log_err("malloc failure while creating http2 session"); + return NULL; + } + session->c = c; + + return session; +} +#endif + +/** Delete http2 session. After closing connection or on error */ +void http2_session_delete(struct http2_session* h2_session) +{ +#ifdef HAVE_NGHTTP2 + if(h2_session->callbacks) + nghttp2_session_callbacks_del(h2_session->callbacks); + free(h2_session); +#else + (void)h2_session; +#endif +} + +#ifdef HAVE_NGHTTP2 +struct http2_stream* http2_stream_create(int32_t stream_id) +{ + struct http2_stream* h2_stream = calloc(1, sizeof(*h2_stream)); + if(!h2_stream) { + log_err("malloc failure while creating http2 stream"); + return NULL; + } + h2_stream->stream_id = stream_id; + return h2_stream; +} + +/** Delete http2 stream. After session delete or stream close callback */ +static void http2_stream_delete(struct http2_session* h2_session, + struct http2_stream* h2_stream) +{ + if(h2_stream->mesh_state) { + mesh_state_remove_reply(h2_stream->mesh, h2_stream->mesh_state, + h2_session->c); + h2_stream->mesh_state = NULL; + } + http2_req_stream_clear(h2_stream); + free(h2_stream); +} +#endif + +void http2_stream_add_meshstate(struct http2_stream* h2_stream, + struct mesh_area* mesh, struct mesh_state* m) +{ + h2_stream->mesh = mesh; + h2_stream->mesh_state = m; +} + +/** delete http2 session server. After closing connection. */ +static void http2_session_server_delete(struct http2_session* h2_session) +{ +#ifdef HAVE_NGHTTP2 + struct http2_stream* h2_stream, *next; + nghttp2_session_del(h2_session->session); /* NULL input is fine */ + h2_session->session = NULL; + for(h2_stream = h2_session->first_stream; h2_stream;) { + next = h2_stream->next; + http2_stream_delete(h2_session, h2_stream); + h2_stream = next; + } + h2_session->first_stream = NULL; + h2_session->is_drop = 0; + h2_session->postpone_drop = 0; + h2_session->c->h2_stream = NULL; +#endif + (void)h2_session; +} + +#ifdef HAVE_NGHTTP2 +void http2_session_add_stream(struct http2_session* h2_session, + struct http2_stream* h2_stream) +{ + if(h2_session->first_stream) + h2_session->first_stream->prev = h2_stream; + h2_stream->next = h2_session->first_stream; + h2_session->first_stream = h2_stream; +} + +/** remove stream from session linked list. After stream close callback or + * closing connection */ +void http2_session_remove_stream(struct http2_session* h2_session, + struct http2_stream* h2_stream) +{ + if(h2_stream->prev) + h2_stream->prev->next = h2_stream->next; + else + h2_session->first_stream = h2_stream->next; + if(h2_stream->next) + h2_stream->next->prev = h2_stream->prev; + +} + +int http2_stream_close_cb(nghttp2_session* ATTR_UNUSED(session), + int32_t stream_id, uint32_t ATTR_UNUSED(error_code), void* cb_arg) +{ + struct http2_stream* h2_stream; + struct http2_session* h2_session = (struct http2_session*)cb_arg; + if(!(h2_stream = nghttp2_session_get_stream_user_data( + h2_session->session, stream_id))) { + return 0; + } + http2_session_remove_stream(h2_session, h2_stream); + http2_stream_delete(h2_session, h2_stream); + return 0; +} + +ssize_t http2_recv_cb(nghttp2_session* ATTR_UNUSED(session), uint8_t* buf, + size_t len, int ATTR_UNUSED(flags), void* cb_arg) +{ +#ifdef HAVE_SSL + struct http2_session* h2_session = (struct http2_session*)cb_arg; + int r; + + log_assert(h2_session->c->type == comm_http); + log_assert(h2_session->c->h2_session); + + if(!h2_session->c->ssl) + return 0; + + ERR_clear_error(); + r = SSL_read(h2_session->c->ssl, buf, len); + if(r <= 0) { + int want = SSL_get_error(h2_session->c->ssl, r); + if(want == SSL_ERROR_ZERO_RETURN) { + return NGHTTP2_ERR_EOF; + } else if(want == SSL_ERROR_WANT_READ) { + return NGHTTP2_ERR_WOULDBLOCK; + } else if(want == SSL_ERROR_WANT_WRITE) { + h2_session->c->ssl_shake_state = comm_ssl_shake_hs_write; + comm_point_listen_for_rw(h2_session->c, 0, 1); + return NGHTTP2_ERR_WOULDBLOCK; + } else if(want == SSL_ERROR_SYSCALL) { +#ifdef ECONNRESET + if(errno == ECONNRESET && verbosity < 2) + return NGHTTP2_ERR_CALLBACK_FAILURE; +#endif + if(errno != 0) + log_err("SSL_read syscall: %s", + strerror(errno)); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + log_crypto_err("could not SSL_read"); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + return r; +#else + (void)buf; + (void)len; + (void)cb_arg; + return -1; +#endif +} +#endif /* HAVE_NGHTTP2 */ + +/** Handle http2 read */ +static int +comm_point_http2_handle_read(int ATTR_UNUSED(fd), struct comm_point* c) +{ +#ifdef HAVE_NGHTTP2 + int ret; + log_assert(c->h2_session); + log_assert(c->ssl); + + /* reading until recv cb returns NGHTTP2_ERR_WOULDBLOCK */ + ret = nghttp2_session_recv(c->h2_session->session); + if(ret) { + if(ret != NGHTTP2_ERR_EOF && + ret != NGHTTP2_ERR_CALLBACK_FAILURE) { + verbose(VERB_QUERY, "http2: session_recv failed, " + "error: %s", nghttp2_strerror(ret)); + } + return 0; + } + if(nghttp2_session_want_write(c->h2_session->session)) { + c->tcp_is_reading = 0; + comm_point_stop_listening(c); + comm_point_start_listening(c, -1, c->tcp_timeout_msec); + } else if(!nghttp2_session_want_read(c->h2_session->session)) + return 0; /* connection can be closed */ + return 1; +#else + (void)c; + return 0; +#endif +} + /** - * Handle http reading callback. + * Handle http reading callback. * @param fd: file descriptor of socket. * @param c: comm point to read from into buffer. - * @return: 0 on error + * @return: 0 on error */ static int comm_point_http_handle_read(int fd, struct comm_point* c) @@ -2210,6 +2460,18 @@ comm_point_http_handle_read(int fd, struct comm_point* c) if(!c->tcp_is_reading) return 1; + + if(c->use_h2) { + return comm_point_http2_handle_read(fd, c); + } + + /* http version is <= http/1.1 */ + + if(c->http_min_version >= http_version_2) { + /* HTTP/2 failed, not allowed to use lower version. */ + return 0; + } + /* read more data */ if(c->ssl) { if(!ssl_http_read_more(c)) @@ -2220,7 +2482,9 @@ comm_point_http_handle_read(int fd, struct comm_point* c) } sldns_buffer_flip(c->buffer); + while(sldns_buffer_remaining(c->buffer) > 0) { + /* Handle HTTP/1.x data */ /* if we are reading headers, read more headers */ if(c->http_in_headers || c->http_in_chunk_headers) { /* if header is done, process the header */ @@ -2364,8 +2628,6 @@ http_write_more(int fd, struct comm_point* c) #ifndef USE_WINSOCK if(errno == EINTR || errno == EAGAIN) return 1; - log_err_addr("http send r", strerror(errno), - &c->repinfo.addr, c->repinfo.addrlen); #else if(WSAGetLastError() == WSAEINPROGRESS) return 1; @@ -2373,15 +2635,92 @@ http_write_more(int fd, struct comm_point* c) ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE); return 1; } - log_err_addr("http send r", wsa_strerror(WSAGetLastError()), - &c->repinfo.addr, c->repinfo.addrlen); #endif + log_err_addr("http send r", sock_strerror(errno), + &c->repinfo.addr, c->repinfo.addrlen); return 0; } sldns_buffer_skip(c->buffer, r); return 1; } +#ifdef HAVE_NGHTTP2 +ssize_t http2_send_cb(nghttp2_session* ATTR_UNUSED(session), const uint8_t* buf, + size_t len, int ATTR_UNUSED(flags), void* cb_arg) +{ +#ifdef HAVE_SSL + int r; + struct http2_session* h2_session = (struct http2_session*)cb_arg; + log_assert(h2_session->c->type == comm_http); + log_assert(h2_session->c->h2_session); + + if(!h2_session->c->ssl) + return 0; + + ERR_clear_error(); + r = SSL_write(h2_session->c->ssl, buf, len); + if(r <= 0) { + int want = SSL_get_error(h2_session->c->ssl, r); + if(want == SSL_ERROR_ZERO_RETURN) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } else if(want == SSL_ERROR_WANT_READ) { + h2_session->c->ssl_shake_state = comm_ssl_shake_hs_read; + comm_point_listen_for_rw(h2_session->c, 1, 0); + return NGHTTP2_ERR_WOULDBLOCK; + } else if(want == SSL_ERROR_WANT_WRITE) { + return NGHTTP2_ERR_WOULDBLOCK; + } else if(want == SSL_ERROR_SYSCALL) { +#ifdef EPIPE + if(errno == EPIPE && verbosity < 2) + return NGHTTP2_ERR_CALLBACK_FAILURE; +#endif + if(errno != 0) + log_err("SSL_write syscall: %s", + strerror(errno)); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + log_crypto_err("could not SSL_write"); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + return r; +#else + (void)buf; + (void)len; + (void)cb_arg; + return -1; +#endif +} +#endif /* HAVE_NGHTTP2 */ + +/** Handle http2 writing */ +static int +comm_point_http2_handle_write(int ATTR_UNUSED(fd), struct comm_point* c) +{ +#ifdef HAVE_NGHTTP2 + int ret; + log_assert(c->h2_session); + log_assert(c->ssl); + + ret = nghttp2_session_send(c->h2_session->session); + if(ret) { + verbose(VERB_QUERY, "http2: session_send failed, " + "error: %s", nghttp2_strerror(ret)); + return 0; + } + + if(nghttp2_session_want_read(c->h2_session->session)) { + c->tcp_is_reading = 1; + comm_point_stop_listening(c); + comm_point_start_listening(c, -1, c->tcp_timeout_msec); + } else if(!nghttp2_session_want_write(c->h2_session->session)) + return 0; /* connection can be closed */ + return 1; +#else + (void)c; + return 0; +#endif +} + /** * Handle http writing callback. * @param fd: file descriptor of socket. @@ -2413,6 +2752,18 @@ comm_point_http_handle_write(int fd, struct comm_point* c) #endif /* HAVE_SSL */ if(c->tcp_is_reading) return 1; + + if(c->use_h2) { + return comm_point_http2_handle_write(fd, c); + } + + /* http version is <= http/1.1 */ + + if(c->http_min_version >= http_version_2) { + /* HTTP/2 failed, not allowed to use lower version. */ + return 0; + } + /* if we are writing, write more */ if(c->ssl) { if(!ssl_http_write_more(c)) @@ -2724,11 +3075,129 @@ comm_point_create_tcp_handler(struct comm_base *base, return c; } +static struct comm_point* +comm_point_create_http_handler(struct comm_base *base, + struct comm_point* parent, size_t bufsize, int harden_large_queries, + uint32_t http_max_streams, char* http_endpoint, + comm_point_callback_type* callback, void* callback_arg) +{ + struct comm_point* c = (struct comm_point*)calloc(1, + sizeof(struct comm_point)); + short evbits; + if(!c) + return NULL; + c->ev = (struct internal_event*)calloc(1, + sizeof(struct internal_event)); + if(!c->ev) { + free(c); + return NULL; + } + c->ev->base = base; + c->fd = -1; + c->buffer = sldns_buffer_new(bufsize); + if(!c->buffer) { + free(c->ev); + free(c); + return NULL; + } + c->timeout = (struct timeval*)malloc(sizeof(struct timeval)); + if(!c->timeout) { + sldns_buffer_free(c->buffer); + free(c->ev); + free(c); + return NULL; + } + c->tcp_is_reading = 0; + c->tcp_byte_count = 0; + c->tcp_parent = parent; + c->tcp_timeout_msec = parent->tcp_timeout_msec; + c->tcp_conn_limit = parent->tcp_conn_limit; + c->tcl_addr = NULL; + c->tcp_keepalive = 0; + c->max_tcp_count = 0; + c->cur_tcp_count = 0; + c->tcp_handlers = NULL; + c->tcp_free = NULL; + c->type = comm_http; + c->tcp_do_close = 1; + c->do_not_close = 0; + c->tcp_do_toggle_rw = 1; /* will be set to 0 after http2 upgrade */ + c->tcp_check_nb_connect = 0; +#ifdef USE_MSG_FASTOPEN + c->tcp_do_fastopen = 0; +#endif +#ifdef USE_DNSCRYPT + c->dnscrypt = 0; + c->dnscrypt_buffer = NULL; +#endif + c->repinfo.c = c; + c->callback = callback; + c->cb_arg = callback_arg; + + c->http_min_version = http_version_2; + c->http2_stream_max_qbuffer_size = bufsize; + if(harden_large_queries && bufsize > 512) + c->http2_stream_max_qbuffer_size = 512; + c->http2_max_streams = http_max_streams; + if(!(c->http_endpoint = strdup(http_endpoint))) { + log_err("could not strdup http_endpoint"); + sldns_buffer_free(c->buffer); + free(c->timeout); + free(c->ev); + free(c); + return NULL; + } + c->use_h2 = 0; +#ifdef HAVE_NGHTTP2 + if(!(c->h2_session = http2_session_create(c))) { + log_err("could not create http2 session"); + free(c->http_endpoint); + sldns_buffer_free(c->buffer); + free(c->timeout); + free(c->ev); + free(c); + return NULL; + } + if(!(c->h2_session->callbacks = http2_req_callbacks_create())) { + log_err("could not create http2 callbacks"); + http2_session_delete(c->h2_session); + free(c->http_endpoint); + sldns_buffer_free(c->buffer); + free(c->timeout); + free(c->ev); + free(c); + return NULL; + } +#endif + + /* add to parent free list */ + c->tcp_free = parent->tcp_free; + parent->tcp_free = c; + /* ub_event stuff */ + evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT; + c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, + comm_point_http_handle_callback, c); + if(c->ev->ev == NULL) + { + log_err("could not set http handler event"); + parent->tcp_free = c->tcp_free; + http2_session_delete(c->h2_session); + sldns_buffer_free(c->buffer); + free(c->timeout); + free(c->ev); + free(c); + return NULL; + } + return c; +} + struct comm_point* comm_point_create_tcp(struct comm_base *base, int fd, int num, - int idle_timeout, struct tcl_list* tcp_conn_limit, size_t bufsize, - struct sldns_buffer* spoolbuf, comm_point_callback_type* callback, - void* callback_arg) + int idle_timeout, int harden_large_queries, + uint32_t http_max_streams, char* http_endpoint, + struct tcl_list* tcp_conn_limit, size_t bufsize, + struct sldns_buffer* spoolbuf, enum listen_type port_type, + comm_point_callback_type* callback, void* callback_arg) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -2792,10 +3261,24 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, comm_point_delete(c); return NULL; } - /* now prealloc the tcp handlers */ + /* now prealloc the handlers */ for(i=0; i<num; i++) { - c->tcp_handlers[i] = comm_point_create_tcp_handler(base, - c, bufsize, spoolbuf, callback, callback_arg); + if(port_type == listen_type_tcp || + port_type == listen_type_ssl || + port_type == listen_type_tcp_dnscrypt) { + c->tcp_handlers[i] = comm_point_create_tcp_handler(base, + c, bufsize, spoolbuf, callback, callback_arg); + } else if(port_type == listen_type_http) { + c->tcp_handlers[i] = comm_point_create_http_handler( + base, c, bufsize, harden_large_queries, + http_max_streams, http_endpoint, + callback, callback_arg); + } + else { + log_err("could not create tcp handler, unknown listen " + "type"); + return NULL; + } if(!c->tcp_handlers[i]) { comm_point_delete(c); return NULL; @@ -3079,6 +3562,9 @@ comm_point_close(struct comm_point* c) tcl_close_connection(c->tcl_addr); if(c->tcp_req_info) tcp_req_info_clear(c->tcp_req_info); + if(c->h2_session) + http2_session_server_delete(c->h2_session); + /* close fd after removing from event lists, or epoll.. is messed up */ if(c->fd != -1 && !c->do_not_close) { if(c->type == comm_tcp || c->type == comm_http) { @@ -3087,11 +3573,7 @@ comm_point_close(struct comm_point* c) ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE); } verbose(VERB_ALGO, "close fd %d", c->fd); -#ifndef USE_WINSOCK - close(c->fd); -#else - closesocket(c->fd); -#endif + sock_close(c->fd); } c->fd = -1; } @@ -3107,6 +3589,10 @@ comm_point_delete(struct comm_point* c) SSL_free(c->ssl); #endif } + if(c->type == comm_http && c->http_endpoint) { + free(c->http_endpoint); + c->http_endpoint = NULL; + } comm_point_close(c); if(c->tcp_handlers) { int i; @@ -3125,6 +3611,9 @@ comm_point_delete(struct comm_point* c) if(c->tcp_req_info) { tcp_req_info_delete(c->tcp_req_info); } + if(c->h2_session) { + http2_session_delete(c->h2_session); + } } ub_event_free(c->ev->ev); free(c->ev); @@ -3170,6 +3659,17 @@ comm_point_send_reply(struct comm_reply *repinfo) #endif if(repinfo->c->tcp_req_info) { tcp_req_info_send_reply(repinfo->c->tcp_req_info); + } else if(repinfo->c->use_h2) { + if(!http2_submit_dns_response(repinfo->c->h2_session)) { + comm_point_drop_reply(repinfo); + return; + } + repinfo->c->h2_stream = NULL; + repinfo->c->tcp_is_reading = 0; + comm_point_stop_listening(repinfo->c); + comm_point_start_listening(repinfo->c, -1, + repinfo->c->tcp_timeout_msec); + return; } else { comm_point_start_listening(repinfo->c, -1, repinfo->c->tcp_timeout_msec); @@ -3188,6 +3688,16 @@ comm_point_drop_reply(struct comm_reply* repinfo) return; if(repinfo->c->tcp_req_info) repinfo->c->tcp_req_info->is_drop = 1; + if(repinfo->c->type == comm_http) { + if(repinfo->c->h2_session) { + repinfo->c->h2_session->is_drop = 1; + if(!repinfo->c->h2_session->postpone_drop) + reclaim_http_handler(repinfo->c); + return; + } + reclaim_http_handler(repinfo->c); + return; + } reclaim_tcp_handler(repinfo->c); } @@ -3232,11 +3742,7 @@ comm_point_start_listening(struct comm_point* c, int newfd, int msec) } if(newfd != -1) { if(c->fd != -1) { -#ifndef USE_WINSOCK - close(c->fd); -#else - closesocket(c->fd); -#endif + sock_close(c->fd); } c->fd = newfd; ub_event_set_fd(c->ev->ev, c->fd); |