diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 5db2b940b..dc1946d99 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -2167,7 +2167,8 @@ void tcp_req_info_clear(struct tcp_req_info* req) open = req->open_req_list; while(open) { nopen = open->next; - mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp); + mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp, + NULL); free(open); open = nopen; } @@ -3597,15 +3598,29 @@ doq_conn_create(struct comm_point* c, struct doq_pkt_addr* paddr, return conn; } +/** The arguments for doq stream tree del. */ +struct doq_stream_tree_del_args { + /** The doq table. */ + struct doq_table* table; + /** The doq connection for the stream. */ + struct doq_conn* conn; +}; + /** delete stream tree node */ static void stream_tree_del(rbnode_type* node, void* arg) { - struct doq_table* table = (struct doq_table*)arg; + struct doq_stream_tree_del_args* args = (struct doq_stream_tree_del_args*)arg; + struct doq_table* table = args->table; struct doq_stream* stream; if(!node) return; stream = (struct doq_stream*)node; + if(stream->mesh_state) { + mesh_state_remove_reply(stream->mesh, stream->mesh_state, + args->conn->doq_socket->cp, stream); + stream->mesh_state = NULL; + } if(stream->in) doq_table_quic_size_subtract(table, stream->inlen); if(stream->out) @@ -3627,7 +3642,11 @@ doq_conn_delete(struct doq_conn* conn, struct doq_table* table) * because the ngtcp2 conn is deleted. */ SSL_set_app_data(conn->ssl, NULL); if(conn->stream_tree.count != 0) { - traverse_postorder(&conn->stream_tree, stream_tree_del, table); + struct doq_stream_tree_del_args args; + memset(&args, 0, sizeof(args)); + args.table = table; + args.conn = conn; + traverse_postorder(&conn->stream_tree, stream_tree_del, &args); } free(conn->key.dcid); SSL_free(conn->ssl); @@ -3940,6 +3959,11 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream, if(stream->is_closed) return 1; stream->is_closed = 1; + if(stream->mesh_state) { + mesh_state_remove_reply(stream->mesh, stream->mesh_state, + conn->doq_socket->cp, stream); + stream->mesh_state = NULL; + } doq_stream_off_write_list(conn, stream); if(send_shutdown) { verbose(VERB_ALGO, "doq: shutdown stream_id %d with app_error_code %d", @@ -4012,7 +4036,33 @@ doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream, doq_conn_write_enable(conn); return 1; } +#endif /* HAVE_NGTCP2 */ +void +doq_stream_add_meshstate(struct doq_stream* stream, + struct mesh_area* mesh, struct mesh_state* m) +{ +#ifdef HAVE_NGTCP2 + stream->mesh = mesh; + stream->mesh_state = m; +#else + (void)stream; (void)mesh; (void)m; +#endif +} + +void +doq_stream_remove_mesh_state(struct doq_stream* stream) +{ +#ifdef HAVE_NGTCP2 + if(!stream) + return; + stream->mesh_state = NULL; +#else + (void)stream; +#endif +} + +#ifdef HAVE_NGTCP2 /** doq stream data length has completed, allocations can be done. False on * allocation failure. */ static int @@ -4067,6 +4117,7 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream) return 0; } c->repinfo.doq_streamid = stream->stream_id; + c->repinfo.doq_stream = stream; conn->doq_socket->current_conn = conn; fptr_ok(fptr_whitelist_comm_point(c->callback)); if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo)) { diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index 963595a1c..88bbb10de 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -61,6 +61,8 @@ struct config_file; struct addrinfo; struct sldns_buffer; struct tcl_list; +struct mesh_area; +struct mesh_state; /** * Listening for queries structure. @@ -689,6 +691,11 @@ struct doq_stream { uint8_t* out; /** if the stream is on the write list */ uint8_t on_write_list; + /** The mesh area and mesh state, set when this stream's query was + * dispatched into the mesh; used to detach the reply on stream close */ + struct mesh_area* mesh; + /** the mesh state for the query, is nonNULL when there is one. */ + struct mesh_state* mesh_state; /** the prev and next on the write list, if on the list */ struct doq_stream* write_prev, *write_next; }; @@ -791,7 +798,16 @@ int doq_stream_close(struct doq_conn* conn, struct doq_stream* stream, /** send reply for a connection */ int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream, struct sldns_buffer* buf); +#endif /* HAVE_NGTCP2 */ +/** add mesh state to doq stream */ +void doq_stream_add_meshstate(struct doq_stream* stream, + struct mesh_area* mesh, struct mesh_state* m); + +/** remove mesh state from doq stream */ +void doq_stream_remove_mesh_state(struct doq_stream* stream); + +#ifdef HAVE_NGTCP2 /** the connection has write interest, wants to write packets */ void doq_conn_write_enable(struct doq_conn* conn); diff --git a/services/mesh.c b/services/mesh.c index 286901047..f06c1cb9d 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -467,6 +467,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, "incoming query."); if(rep->c->use_h2) http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_drop_reply(rep); mesh->stats_dropped++; return; @@ -480,6 +482,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, "dropping incoming query."); if(rep->c->use_h2) http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_drop_reply(rep); mesh->num_queries_replyaddr_limit++; return; @@ -552,6 +556,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, } if(rep->c->use_h2) { http2_stream_add_meshstate(rep->c->h2_stream, mesh, s); + } else if(rep->c->type == comm_doq && rep->doq_stream) { + doq_stream_add_meshstate(rep->doq_stream, mesh, s); } /* add serve expired timer if required and not already there */ if(timeout && !mesh_serve_expired_init(s, timeout)) { @@ -605,6 +611,8 @@ servfail_mem: qinfo, qid, qflags, edns); if(rep->c->use_h2) http2_stream_remove_mesh_state(rep->c->h2_stream); + else if(rep->c->type == comm_doq && rep->doq_stream) + doq_stream_remove_mesh_state(rep->doq_stream); comm_point_send_reply(rep); if(added) mesh_state_delete(&s->s); @@ -1484,6 +1492,10 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, * for HTTP/2 stream to refer to mesh state, in case * connection gets cleanup before HTTP/2 stream close. */ r->h2_stream->mesh_state = NULL; +#ifdef HAVE_NGTCP2 + } else if(r->query_reply.doq_stream) { + r->query_reply.doq_stream->mesh_state = NULL; +#endif } /* send the reply */ /* We don't reuse the encoded answer if: @@ -1777,6 +1789,8 @@ void mesh_query_done(struct mesh_state* mstate) mstate->reply_list = NULL; if(r->query_reply.c->use_h2) http2_stream_remove_mesh_state(r->h2_stream); + else if(r->query_reply.doq_stream) + doq_stream_remove_mesh_state(r->query_reply.doq_stream); comm_point_drop_reply(&r->query_reply); mstate->reply_list = reply_list; log_assert(mstate->s.env->mesh->num_reply_addrs > 0); @@ -1814,6 +1828,8 @@ void mesh_query_done(struct mesh_state* mstate) mstate->reply_list = NULL; if(r->query_reply.c->use_h2) { http2_stream_remove_mesh_state(r->h2_stream); + } else if(r->query_reply.doq_stream) { + doq_stream_remove_mesh_state(r->query_reply.doq_stream); } comm_point_drop_reply(&r->query_reply); mstate->reply_list = reply_list; @@ -2009,6 +2025,8 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, if(rep->c->use_h2) r->h2_stream = rep->c->h2_stream; else r->h2_stream = NULL; + if(rep->c->type != comm_doq) + r->query_reply.doq_stream = NULL; /* Data related to local alias stored in 'qinfo' (if any) is ephemeral * and can be different for different original queries (even if the @@ -2366,7 +2384,7 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp, } void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, - struct comm_point* cp) + struct comm_point* cp, struct doq_stream* doq_stream) { struct mesh_reply* n, *prev = NULL; n = m->reply_list; @@ -2374,7 +2392,8 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, * there is no accounting twice */ if(!n) return; /* nothing to remove, also no accounting needed */ while(n) { - if(n->query_reply.c == cp) { + if(n->query_reply.c == cp + && (!doq_stream || n->query_reply.doq_stream == doq_stream)) { /* unlink it */ if(prev) prev->next = n->next; else m->reply_list = n->next; @@ -2387,6 +2406,10 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, * share the same comm_point); make sure the streams * don't point back. */ if(n->h2_stream) n->h2_stream->mesh_state = NULL; +#ifdef HAVE_NGTCP2 + if(n->query_reply.doq_stream) + n->query_reply.doq_stream->mesh_state = NULL; +#endif /* prev = prev; */ n = n->next; @@ -2554,6 +2577,8 @@ mesh_serve_expired_callback(void* arg) mstate->reply_list = NULL; if(r->query_reply.c->use_h2) http2_stream_remove_mesh_state(r->h2_stream); + else if(r->query_reply.doq_stream) + doq_stream_remove_mesh_state(r->query_reply.doq_stream); comm_point_drop_reply(&r->query_reply); mstate->reply_list = reply_list; mstate->s.env->mesh->num_queries_discard_timeout++; diff --git a/services/mesh.h b/services/mesh.h index 9ee585156..352260e26 100644 --- a/services/mesh.h +++ b/services/mesh.h @@ -683,9 +683,11 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp, * @param mesh: to update the counters. * @param m: the mesh state. * @param cp: the comm_point to remove from the list. + * @param doq_stream: if not NULL, it specifies the doq_stream to match + * for the delete. */ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, - struct comm_point* cp); + struct comm_point* cp, struct doq_stream* doq_stream); /** Callback for when the serve expired client timer has run out. Tries to * find an expired answer in the cache and reply that to the client. diff --git a/util/netevent.c b/util/netevent.c index a86e22518..12cce1a60 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -3174,7 +3174,7 @@ static void http2_stream_delete(struct http2_session* h2_session, { if(h2_stream->mesh_state) { mesh_state_remove_reply(h2_stream->mesh, h2_stream->mesh_state, - h2_session->c); + h2_session->c, NULL); h2_stream->mesh_state = NULL; } http2_req_stream_clear(h2_stream); diff --git a/util/netevent.h b/util/netevent.h index c5114bbbe..e4bc216aa 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -187,6 +187,8 @@ struct comm_reply { /** port number for doq */ int doq_srcport; #endif /* HAVE_NGTCP2 */ + /** The doq stream to register mesh states to. */ + struct doq_stream* doq_stream; }; /**