request.c revision 78da321b437bbb690ef570ccf17dcc8583a5a4a0
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * Copyright (C) 2000 Internet Software Consortium.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * Permission to use, copy, modify, and distribute this software for any
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * purpose with or without fee is hereby granted, provided that the above
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * copyright notice and this permission notice appear in all copies.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews#define VALID_REQUESTMGR(mgr) ((mgr) != NULL && \
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews#define VALID_REQUEST(request) ((request) != NULL && \
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewstypedef ISC_LIST(dns_request_t) dns_requestlist_t;
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews /* locked */
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsstatic void mgr_destroy(dns_requestmgr_t *requestmgr);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsstatic void mgr_shutdown(dns_requestmgr_t *requestmgr);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsstatic void send_shutdown_events(dns_requestmgr_t *requestmgr);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrewsstatic isc_result_t render(dns_message_t *message, isc_buffer_t **buffer,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsstatic void req_senddone(isc_task_t *task, isc_event_t *event);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsstatic void req_response(isc_task_t *task, isc_event_t *event);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsstatic void req_timeout(isc_task_t *task, isc_event_t *event);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsstatic void req_connected(isc_task_t *task, isc_event_t *event);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsstatic void req_sendevent(dns_request_t *request, isc_result_t result);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsstatic void req_destroy(dns_request_t *request);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(isc_socket_gettype(socket) == isc_sockettype_udp);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(isc_socket_gettype(socket) == isc_sockettype_udp);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews requestmgr->references = 1; /* implict attach */
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsdns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * We're already shutdown. Send the event.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews ISC_LIST_APPEND(requestmgr->whenshutdown, event, link);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsdns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Caller holds lock.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews for (request = ISC_LIST_HEAD(requestmgr->requests);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsdns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsdns_requestmgr_detach(dns_requestmgr_t **requestmgrp) {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewssend_shutdown_events(dns_requestmgr_t *requestmgr) {
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews * Caller must be holding the manager lock.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews for (event = ISC_LIST_HEAD(requestmgr->whenshutdown);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews ISC_LIST_UNLINK(requestmgr->whenshutdown, event, link);
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews isc_mem_put(requestmgr->mctx, requestmgr, sizeof *requestmgr);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsreq_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews socket = dns_dispatch_getsocket(request->dispatch);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews return (isc_socket_sendto(socket, &r, task, req_senddone,
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsdns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrews REQUIRE(requestp != NULL && *requestp == NULL);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Zero structure.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews dns_requestmgr_attach(requestmgr, &request->requestmgr);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Create timer now. We will set it below once.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews result = isc_socket_create(requestmgr->socketmgr,
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = dns_dispatch_create(mctx, socket, task,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews socket = dns_dispatch_getsocket(request->dispatch);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews result = dns_dispatch_addresponse(request->dispatch, address, task,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews result = render(message, &request->query, mctx);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Try again using TCP.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews if (result != ISC_R_SUCCESS && result != DNS_R_USETCP)
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews ISC_LIST_APPEND(requestmgr->requests, request, link);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews result = isc_time_nowplusinterval(&expires, &interval);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews result = isc_timer_reset(request->timer, isc_timertype_once,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews result = isc_socket_connect(socket, address, task,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_event_free((isc_event_t **)&request->event);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrewsrender(dns_message_t *message, isc_buffer_t **bufferp, isc_mem_t *mctx) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * Create buffer able to hold largest possible message.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = isc_buffer_allocate(mctx, &buf1, 65535,
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * Render message.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = dns_message_renderbegin(message, buf1);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * Copy rendered message to exact sized buffer.
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews result = isc_buffer_allocate(mctx, &buf2, r.length +
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_buffer_putuint16(buf2, (isc_uint16_t)r.length);
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews * Cleanup and return.
b54630c4518a1a173fee3478f4bf51dff450b6dcMark Andrewsdns_request_getresponse(dns_request_t *request, dns_message_t *message) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews return (dns_message_parse(message, request->answer, ISC_TRUE));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews *** Private: request.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsreq_connected(isc_task_t *task, isc_event_t *event) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews isc_socketevent_t *sevent = (isc_socketevent_t *)event;
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews REQUIRE(event->type == ISC_SOCKEVENT_SENDDONE);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsreq_senddone(isc_task_t *task, isc_event_t *event) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_socketevent_t *sevent = (isc_socketevent_t *)event;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews REQUIRE(event->type == ISC_SOCKEVENT_SENDDONE);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsreq_response(isc_task_t *task, isc_event_t *event) {
34ee961fa2f0f5f2ee3cff40fdb4d7d7b48b7728Mark Andrews dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Copy buffer to request.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews result = isc_buffer_allocate(request->mctx, &request->answer, r.length,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews result = isc_buffer_copyregion(request->answer, &r);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews dns_dispatch_removeresponse(request->dispatch, &request->dispentry,
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews * Send completion event.
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsreq_timeout(isc_task_t *task, isc_event_t *event) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrewsreq_sendevent(dns_request_t *request, isc_result_t result) {
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_task_sendanddetach(&task, (isc_event_t **)&request->event);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_event_free((isc_event_t **)&request->event);
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews isc_mem_put(request->mctx, request, sizeof(*request));
78da321b437bbb690ef570ccf17dcc8583a5a4a0Mark Andrews socket = dns_dispatch_getsocket(request->dispatch);