request.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2000-2002  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <isc/magic.h>
00025 #include <isc/mem.h>
00026 #include <isc/task.h>
00027 #include <isc/timer.h>
00028 #include <isc/util.h>
00029 
00030 #include <dns/acl.h>
00031 #include <dns/compress.h>
00032 #include <dns/dispatch.h>
00033 #include <dns/events.h>
00034 #include <dns/log.h>
00035 #include <dns/message.h>
00036 #include <dns/rdata.h>
00037 #include <dns/rdatastruct.h>
00038 #include <dns/request.h>
00039 #include <dns/result.h>
00040 #include <dns/tsig.h>
00041 
00042 #define REQUESTMGR_MAGIC        ISC_MAGIC('R', 'q', 'u', 'M')
00043 #define VALID_REQUESTMGR(mgr)   ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC)
00044 
00045 #define REQUEST_MAGIC           ISC_MAGIC('R', 'q', 'u', '!')
00046 #define VALID_REQUEST(request)  ISC_MAGIC_VALID(request, REQUEST_MAGIC)
00047 
00048 typedef ISC_LIST(dns_request_t) dns_requestlist_t;
00049 
00050 #define DNS_REQUEST_NLOCKS 7
00051 
00052 struct dns_requestmgr {
00053         unsigned int                    magic;
00054         isc_mutex_t                     lock;
00055         isc_mem_t                      *mctx;
00056 
00057         /* locked */
00058         isc_int32_t                     eref;
00059         isc_int32_t                     iref;
00060         isc_timermgr_t                 *timermgr;
00061         isc_socketmgr_t                *socketmgr;
00062         isc_taskmgr_t                  *taskmgr;
00063         dns_dispatchmgr_t              *dispatchmgr;
00064         dns_dispatch_t                 *dispatchv4;
00065         dns_dispatch_t                 *dispatchv6;
00066         isc_boolean_t                   exiting;
00067         isc_eventlist_t                 whenshutdown;
00068         unsigned int                    hash;
00069         isc_mutex_t                     locks[DNS_REQUEST_NLOCKS];
00070         dns_requestlist_t               requests;
00071 };
00072 
00073 struct dns_request {
00074         unsigned int                    magic;
00075         unsigned int                    hash;
00076         isc_mem_t                      *mctx;
00077         isc_int32_t                     flags;
00078         ISC_LINK(dns_request_t)         link;
00079         isc_buffer_t                   *query;
00080         isc_buffer_t                   *answer;
00081         dns_requestevent_t             *event;
00082         dns_dispatch_t                 *dispatch;
00083         dns_dispentry_t                *dispentry;
00084         isc_timer_t                    *timer;
00085         dns_requestmgr_t               *requestmgr;
00086         isc_buffer_t                   *tsig;
00087         dns_tsigkey_t                  *tsigkey;
00088         isc_event_t                     ctlevent;
00089         isc_boolean_t                   canceling; /* ctlevent outstanding */
00090         isc_sockaddr_t                  destaddr;
00091         unsigned int                    udpcount;
00092         isc_dscp_t                      dscp;
00093 };
00094 
00095 #define DNS_REQUEST_F_CONNECTING 0x0001
00096 #define DNS_REQUEST_F_SENDING 0x0002
00097 #define DNS_REQUEST_F_CANCELED 0x0004   /*%< ctlevent received, or otherwise
00098                                            synchronously canceled */
00099 #define DNS_REQUEST_F_TIMEDOUT 0x0008   /*%< canceled due to a timeout */
00100 #define DNS_REQUEST_F_TCP 0x0010        /*%< This request used TCP */
00101 #define DNS_REQUEST_CANCELED(r) \
00102         (((r)->flags & DNS_REQUEST_F_CANCELED) != 0)
00103 #define DNS_REQUEST_CONNECTING(r) \
00104         (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
00105 #define DNS_REQUEST_SENDING(r) \
00106         (((r)->flags & DNS_REQUEST_F_SENDING) != 0)
00107 #define DNS_REQUEST_TIMEDOUT(r) \
00108         (((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0)
00109 
00110 
00111 /***
00112  *** Forward
00113  ***/
00114 
00115 static void mgr_destroy(dns_requestmgr_t *requestmgr);
00116 static void mgr_shutdown(dns_requestmgr_t *requestmgr);
00117 static unsigned int mgr_gethash(dns_requestmgr_t *requestmgr);
00118 static void send_shutdown_events(dns_requestmgr_t *requestmgr);
00119 
00120 static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer,
00121                                unsigned int options, isc_mem_t *mctx);
00122 static void req_senddone(isc_task_t *task, isc_event_t *event);
00123 static void req_response(isc_task_t *task, isc_event_t *event);
00124 static void req_timeout(isc_task_t *task, isc_event_t *event);
00125 static isc_socket_t * req_getsocket(dns_request_t *request);
00126 static void req_connected(isc_task_t *task, isc_event_t *event);
00127 static void req_sendevent(dns_request_t *request, isc_result_t result);
00128 static void req_cancel(dns_request_t *request);
00129 static void req_destroy(dns_request_t *request);
00130 static void req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
00131 static void do_cancel(isc_task_t *task, isc_event_t *event);
00132 
00133 /***
00134  *** Public
00135  ***/
00136 
00137 isc_result_t
00138 dns_requestmgr_create(isc_mem_t *mctx,
00139                       isc_timermgr_t *timermgr,
00140                       isc_socketmgr_t *socketmgr,
00141                       isc_taskmgr_t *taskmgr,
00142                       dns_dispatchmgr_t *dispatchmgr,
00143                       dns_dispatch_t *dispatchv4,
00144                       dns_dispatch_t *dispatchv6,
00145                       dns_requestmgr_t **requestmgrp)
00146 {
00147         dns_requestmgr_t *requestmgr;
00148         isc_socket_t *sock;
00149         isc_result_t result;
00150         int i;
00151         unsigned int dispattr;
00152 
00153         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
00154 
00155         REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
00156         REQUIRE(timermgr != NULL);
00157         REQUIRE(socketmgr != NULL);
00158         REQUIRE(taskmgr != NULL);
00159         REQUIRE(dispatchmgr != NULL);
00160         UNUSED(sock);
00161         if (dispatchv4 != NULL) {
00162                 dispattr = dns_dispatch_getattributes(dispatchv4);
00163                 REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
00164         }
00165         if (dispatchv6 != NULL) {
00166                 dispattr = dns_dispatch_getattributes(dispatchv6);
00167                 REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
00168         }
00169 
00170         requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
00171         if (requestmgr == NULL)
00172                 return (ISC_R_NOMEMORY);
00173 
00174         result = isc_mutex_init(&requestmgr->lock);
00175         if (result != ISC_R_SUCCESS) {
00176                 isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
00177                 return (result);
00178         }
00179         for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
00180                 result = isc_mutex_init(&requestmgr->locks[i]);
00181                 if (result != ISC_R_SUCCESS) {
00182                         while (--i >= 0)
00183                                 DESTROYLOCK(&requestmgr->locks[i]);
00184                         DESTROYLOCK(&requestmgr->lock);
00185                         isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
00186                         return (result);
00187                 }
00188         }
00189         requestmgr->timermgr = timermgr;
00190         requestmgr->socketmgr = socketmgr;
00191         requestmgr->taskmgr = taskmgr;
00192         requestmgr->dispatchmgr = dispatchmgr;
00193         requestmgr->dispatchv4 = NULL;
00194         if (dispatchv4 != NULL)
00195                 dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
00196         requestmgr->dispatchv6 = NULL;
00197         if (dispatchv6 != NULL)
00198                 dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
00199         requestmgr->mctx = NULL;
00200         isc_mem_attach(mctx, &requestmgr->mctx);
00201         requestmgr->eref = 1;   /* implicit attach */
00202         requestmgr->iref = 0;
00203         ISC_LIST_INIT(requestmgr->whenshutdown);
00204         ISC_LIST_INIT(requestmgr->requests);
00205         requestmgr->exiting = ISC_FALSE;
00206         requestmgr->hash = 0;
00207         requestmgr->magic = REQUESTMGR_MAGIC;
00208 
00209         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
00210 
00211         *requestmgrp = requestmgr;
00212         return (ISC_R_SUCCESS);
00213 }
00214 
00215 void
00216 dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
00217                             isc_event_t **eventp)
00218 {
00219         isc_task_t *clone;
00220         isc_event_t *event;
00221 
00222         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_whenshutdown");
00223 
00224         REQUIRE(VALID_REQUESTMGR(requestmgr));
00225         REQUIRE(eventp != NULL);
00226 
00227         event = *eventp;
00228         *eventp = NULL;
00229 
00230         LOCK(&requestmgr->lock);
00231 
00232         if (requestmgr->exiting) {
00233                 /*
00234                  * We're already shutdown.  Send the event.
00235                  */
00236                 event->ev_sender = requestmgr;
00237                 isc_task_send(task, &event);
00238         } else {
00239                 clone = NULL;
00240                 isc_task_attach(task, &clone);
00241                 event->ev_sender = clone;
00242                 ISC_LIST_APPEND(requestmgr->whenshutdown, event, ev_link);
00243         }
00244         UNLOCK(&requestmgr->lock);
00245 }
00246 
00247 void
00248 dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
00249 
00250         REQUIRE(VALID_REQUESTMGR(requestmgr));
00251 
00252         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr);
00253 
00254         LOCK(&requestmgr->lock);
00255         mgr_shutdown(requestmgr);
00256         UNLOCK(&requestmgr->lock);
00257 }
00258 
00259 static void
00260 mgr_shutdown(dns_requestmgr_t *requestmgr) {
00261         dns_request_t *request;
00262 
00263         /*
00264          * Caller holds lock.
00265          */
00266         if (!requestmgr->exiting) {
00267                 requestmgr->exiting = ISC_TRUE;
00268                 for (request = ISC_LIST_HEAD(requestmgr->requests);
00269                      request != NULL;
00270                      request = ISC_LIST_NEXT(request, link)) {
00271                         dns_request_cancel(request);
00272                 }
00273                 if (requestmgr->iref == 0) {
00274                         INSIST(ISC_LIST_EMPTY(requestmgr->requests));
00275                         send_shutdown_events(requestmgr);
00276                 }
00277         }
00278 }
00279 
00280 static void
00281 requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
00282 
00283         /*
00284          * Locked by caller.
00285          */
00286 
00287         REQUIRE(VALID_REQUESTMGR(source));
00288         REQUIRE(targetp != NULL && *targetp == NULL);
00289 
00290         REQUIRE(!source->exiting);
00291 
00292         source->iref++;
00293         *targetp = source;
00294 
00295         req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d",
00296                 source, source->eref, source->iref);
00297 }
00298 
00299 static void
00300 requestmgr_detach(dns_requestmgr_t **requestmgrp) {
00301         dns_requestmgr_t *requestmgr;
00302         isc_boolean_t need_destroy = ISC_FALSE;
00303 
00304         REQUIRE(requestmgrp != NULL);
00305         requestmgr = *requestmgrp;
00306         REQUIRE(VALID_REQUESTMGR(requestmgr));
00307 
00308         *requestmgrp = NULL;
00309         LOCK(&requestmgr->lock);
00310         INSIST(requestmgr->iref > 0);
00311         requestmgr->iref--;
00312 
00313         req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d",
00314                 requestmgr, requestmgr->eref, requestmgr->iref);
00315 
00316         if (requestmgr->iref == 0 && requestmgr->exiting) {
00317                 INSIST(ISC_LIST_HEAD(requestmgr->requests) == NULL);
00318                 send_shutdown_events(requestmgr);
00319                 if (requestmgr->eref == 0)
00320                         need_destroy = ISC_TRUE;
00321         }
00322         UNLOCK(&requestmgr->lock);
00323 
00324         if (need_destroy)
00325                 mgr_destroy(requestmgr);
00326 }
00327 
00328 void
00329 dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
00330 
00331         REQUIRE(VALID_REQUESTMGR(source));
00332         REQUIRE(targetp != NULL && *targetp == NULL);
00333         REQUIRE(!source->exiting);
00334 
00335         LOCK(&source->lock);
00336         source->eref++;
00337         *targetp = source;
00338         UNLOCK(&source->lock);
00339 
00340         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d",
00341                 source, source->eref, source->iref);
00342 }
00343 
00344 void
00345 dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) {
00346         dns_requestmgr_t *requestmgr;
00347         isc_boolean_t need_destroy = ISC_FALSE;
00348 
00349         REQUIRE(requestmgrp != NULL);
00350         requestmgr = *requestmgrp;
00351         REQUIRE(VALID_REQUESTMGR(requestmgr));
00352 
00353         LOCK(&requestmgr->lock);
00354         INSIST(requestmgr->eref > 0);
00355         requestmgr->eref--;
00356 
00357         req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d",
00358                 requestmgr, requestmgr->eref, requestmgr->iref);
00359 
00360         if (requestmgr->eref == 0 && requestmgr->iref == 0) {
00361                 INSIST(requestmgr->exiting &&
00362                        ISC_LIST_HEAD(requestmgr->requests) == NULL);
00363                 need_destroy = ISC_TRUE;
00364         }
00365         UNLOCK(&requestmgr->lock);
00366 
00367         if (need_destroy)
00368                 mgr_destroy(requestmgr);
00369 
00370         *requestmgrp = NULL;
00371 }
00372 
00373 static void
00374 send_shutdown_events(dns_requestmgr_t *requestmgr) {
00375         isc_event_t *event, *next_event;
00376         isc_task_t *etask;
00377 
00378         req_log(ISC_LOG_DEBUG(3), "send_shutdown_events: %p", requestmgr);
00379 
00380         /*
00381          * Caller must be holding the manager lock.
00382          */
00383         for (event = ISC_LIST_HEAD(requestmgr->whenshutdown);
00384              event != NULL;
00385              event = next_event) {
00386                 next_event = ISC_LIST_NEXT(event, ev_link);
00387                 ISC_LIST_UNLINK(requestmgr->whenshutdown, event, ev_link);
00388                 etask = event->ev_sender;
00389                 event->ev_sender = requestmgr;
00390                 isc_task_sendanddetach(&etask, &event);
00391         }
00392 }
00393 
00394 static void
00395 mgr_destroy(dns_requestmgr_t *requestmgr) {
00396         int i;
00397         isc_mem_t *mctx;
00398 
00399         req_log(ISC_LOG_DEBUG(3), "mgr_destroy");
00400 
00401         REQUIRE(requestmgr->eref == 0);
00402         REQUIRE(requestmgr->iref == 0);
00403 
00404         DESTROYLOCK(&requestmgr->lock);
00405         for (i = 0; i < DNS_REQUEST_NLOCKS; i++)
00406                 DESTROYLOCK(&requestmgr->locks[i]);
00407         if (requestmgr->dispatchv4 != NULL)
00408                 dns_dispatch_detach(&requestmgr->dispatchv4);
00409         if (requestmgr->dispatchv6 != NULL)
00410                 dns_dispatch_detach(&requestmgr->dispatchv6);
00411         requestmgr->magic = 0;
00412         mctx = requestmgr->mctx;
00413         isc_mem_put(mctx, requestmgr, sizeof(*requestmgr));
00414         isc_mem_detach(&mctx);
00415 }
00416 
00417 static unsigned int
00418 mgr_gethash(dns_requestmgr_t *requestmgr) {
00419         req_log(ISC_LOG_DEBUG(3), "mgr_gethash");
00420         /*
00421          * Locked by caller.
00422          */
00423         requestmgr->hash++;
00424         return (requestmgr->hash % DNS_REQUEST_NLOCKS);
00425 }
00426 
00427 static inline isc_result_t
00428 req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) {
00429         isc_region_t r;
00430         isc_socket_t *sock;
00431         isc_socketevent_t *sendevent;
00432         isc_result_t result;
00433 
00434         req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
00435 
00436         REQUIRE(VALID_REQUEST(request));
00437         sock = req_getsocket(request);
00438         isc_buffer_usedregion(request->query, &r);
00439         /*
00440          * We could connect the socket when we are using an exclusive dispatch
00441          * as we do in resolver.c, but we prefer implementation simplicity
00442          * at this moment.
00443          */
00444         sendevent = isc_socket_socketevent(request->mctx, sock,
00445                                            ISC_SOCKEVENT_SENDDONE,
00446                                            req_senddone, request);
00447         if (sendevent == NULL)
00448                 return (ISC_R_NOMEMORY);
00449         if (request->dscp == -1) {
00450                 sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP;
00451                 sendevent->dscp = 0;
00452         } else {
00453                 sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP;
00454                 sendevent->dscp = request->dscp;
00455         }
00456 
00457         result = isc_socket_sendto2(sock, &r, task, address, NULL,
00458                                     sendevent, 0);
00459         if (result == ISC_R_SUCCESS)
00460                 request->flags |= DNS_REQUEST_F_SENDING;
00461         return (result);
00462 }
00463 
00464 static isc_result_t
00465 new_request(isc_mem_t *mctx, dns_request_t **requestp)
00466 {
00467         dns_request_t *request;
00468 
00469         request = isc_mem_get(mctx, sizeof(*request));
00470         if (request == NULL)
00471                 return (ISC_R_NOMEMORY);
00472 
00473         /*
00474          * Zero structure.
00475          */
00476         request->magic = 0;
00477         request->mctx = NULL;
00478         request->flags = 0;
00479         ISC_LINK_INIT(request, link);
00480         request->query = NULL;
00481         request->answer = NULL;
00482         request->event = NULL;
00483         request->dispatch = NULL;
00484         request->dispentry = NULL;
00485         request->timer = NULL;
00486         request->requestmgr = NULL;
00487         request->tsig = NULL;
00488         request->tsigkey = NULL;
00489         request->dscp = -1;
00490         ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL,
00491                        DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL,
00492                        NULL, NULL);
00493         request->canceling = ISC_FALSE;
00494         request->udpcount = 0;
00495 
00496         isc_mem_attach(mctx, &request->mctx);
00497 
00498         request->magic = REQUEST_MAGIC;
00499         *requestp = request;
00500         return (ISC_R_SUCCESS);
00501 }
00502 
00503 
00504 static isc_boolean_t
00505 isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) {
00506         dns_acl_t *blackhole;
00507         isc_netaddr_t netaddr;
00508         int match;
00509         isc_boolean_t drop = ISC_FALSE;
00510         char netaddrstr[ISC_NETADDR_FORMATSIZE];
00511 
00512         blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
00513         if (blackhole != NULL) {
00514                 isc_netaddr_fromsockaddr(&netaddr, destaddr);
00515                 if (dns_acl_match(&netaddr, NULL, blackhole,
00516                                   NULL, &match, NULL) == ISC_R_SUCCESS &&
00517                     match > 0)
00518                         drop = ISC_TRUE;
00519         }
00520         if (drop) {
00521                 isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
00522                 req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
00523         }
00524         return (drop);
00525 }
00526 
00527 static isc_result_t
00528 create_tcp_dispatch(isc_boolean_t newtcp, isc_boolean_t share,
00529                     dns_requestmgr_t *requestmgr,
00530                     isc_sockaddr_t *srcaddr,
00531                     isc_sockaddr_t *destaddr, isc_dscp_t dscp,
00532                     isc_boolean_t *connected, dns_dispatch_t **dispatchp)
00533 {
00534         isc_result_t result;
00535         isc_socket_t *sock = NULL;
00536         isc_sockaddr_t src;
00537         unsigned int attrs;
00538         isc_sockaddr_t bind_any;
00539 
00540         if (!newtcp && share) {
00541                 result = dns_dispatch_gettcp2(requestmgr->dispatchmgr,
00542                                               destaddr, srcaddr,
00543                                               connected, dispatchp);
00544                 if (result == ISC_R_SUCCESS) {
00545                         char peer[ISC_SOCKADDR_FORMATSIZE];
00546 
00547                         isc_sockaddr_format(destaddr, peer, sizeof(peer));
00548                         req_log(ISC_LOG_DEBUG(1), "attached to %s TCP "
00549                                 "connection to %s",
00550                                 *connected ? "existing" : "pending", peer);
00551                         return (result);
00552                 }
00553         } else if (!newtcp) {
00554                 result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr,
00555                                              srcaddr, dispatchp);
00556                 if (result == ISC_R_SUCCESS) {
00557                         char peer[ISC_SOCKADDR_FORMATSIZE];
00558 
00559                         *connected = ISC_TRUE;
00560                         isc_sockaddr_format(destaddr, peer, sizeof(peer));
00561                         req_log(ISC_LOG_DEBUG(1), "attached to existing TCP "
00562                                 "connection to %s", peer);
00563                         return (result);
00564                 }
00565         }
00566 
00567         result = isc_socket_create(requestmgr->socketmgr,
00568                                    isc_sockaddr_pf(destaddr),
00569                                    isc_sockettype_tcp, &sock);
00570         if (result != ISC_R_SUCCESS)
00571                 return (result);
00572 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
00573         if (srcaddr == NULL) {
00574                 isc_sockaddr_anyofpf(&bind_any,
00575                                      isc_sockaddr_pf(destaddr));
00576                 result = isc_socket_bind(sock, &bind_any, 0);
00577         } else {
00578                 src = *srcaddr;
00579                 isc_sockaddr_setport(&src, 0);
00580                 result = isc_socket_bind(sock, &src, 0);
00581         }
00582         if (result != ISC_R_SUCCESS)
00583                 goto cleanup;
00584 #endif
00585 
00586         attrs = 0;
00587         attrs |= DNS_DISPATCHATTR_TCP;
00588         if (isc_sockaddr_pf(destaddr) == AF_INET)
00589                 attrs |= DNS_DISPATCHATTR_IPV4;
00590         else
00591                 attrs |= DNS_DISPATCHATTR_IPV6;
00592         attrs |= DNS_DISPATCHATTR_MAKEQUERY;
00593 
00594         isc_socket_dscp(sock, dscp);
00595         result = dns_dispatch_createtcp2(requestmgr->dispatchmgr,
00596                                          sock, requestmgr->taskmgr,
00597                                          srcaddr, destaddr,
00598                                          4096, 32768, 32768, 16411, 16433,
00599                                          attrs, dispatchp);
00600 cleanup:
00601         isc_socket_detach(&sock);
00602         return (result);
00603 }
00604 
00605 static isc_result_t
00606 find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr,
00607                   isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp)
00608 {
00609         dns_dispatch_t *disp = NULL;
00610         unsigned int attrs, attrmask;
00611 
00612         if (srcaddr == NULL) {
00613                 switch (isc_sockaddr_pf(destaddr)) {
00614                 case PF_INET:
00615                         disp = requestmgr->dispatchv4;
00616                         break;
00617 
00618                 case PF_INET6:
00619                         disp = requestmgr->dispatchv6;
00620                         break;
00621 
00622                 default:
00623                         return (ISC_R_NOTIMPLEMENTED);
00624                 }
00625                 if (disp == NULL)
00626                         return (ISC_R_FAMILYNOSUPPORT);
00627                 dns_dispatch_attach(disp, dispatchp);
00628                 return (ISC_R_SUCCESS);
00629         }
00630         attrs = 0;
00631         attrs |= DNS_DISPATCHATTR_UDP;
00632         switch (isc_sockaddr_pf(srcaddr)) {
00633         case PF_INET:
00634                 attrs |= DNS_DISPATCHATTR_IPV4;
00635                 break;
00636 
00637         case PF_INET6:
00638                 attrs |= DNS_DISPATCHATTR_IPV6;
00639                 break;
00640 
00641         default:
00642                 return (ISC_R_NOTIMPLEMENTED);
00643         }
00644         attrmask = 0;
00645         attrmask |= DNS_DISPATCHATTR_UDP;
00646         attrmask |= DNS_DISPATCHATTR_TCP;
00647         attrmask |= DNS_DISPATCHATTR_IPV4;
00648         attrmask |= DNS_DISPATCHATTR_IPV6;
00649         return (dns_dispatch_getudp(requestmgr->dispatchmgr,
00650                                     requestmgr->socketmgr,
00651                                     requestmgr->taskmgr,
00652                                     srcaddr, 4096,
00653                                     32768, 32768, 16411, 16433,
00654                                     attrs, attrmask,
00655                                     dispatchp));
00656 }
00657 
00658 static isc_result_t
00659 get_dispatch(isc_boolean_t tcp, isc_boolean_t newtcp, isc_boolean_t share,
00660              dns_requestmgr_t *requestmgr,
00661              isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
00662              isc_dscp_t dscp, isc_boolean_t *connected,
00663              dns_dispatch_t **dispatchp)
00664 {
00665         isc_result_t result;
00666 
00667         if (tcp)
00668                 result = create_tcp_dispatch(newtcp, share, requestmgr,
00669                                              srcaddr, destaddr, dscp,
00670                                              connected, dispatchp);
00671         else
00672                 result = find_udp_dispatch(requestmgr, srcaddr,
00673                                            destaddr, dispatchp);
00674         return (result);
00675 }
00676 
00677 static isc_result_t
00678 set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) {
00679         isc_time_t expires;
00680         isc_interval_t interval;
00681         isc_result_t result;
00682         isc_timertype_t timertype;
00683 
00684         isc_interval_set(&interval, timeout, 0);
00685         result = isc_time_nowplusinterval(&expires, &interval);
00686         isc_interval_set(&interval, udpresend, 0);
00687 
00688         timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once;
00689         if (result == ISC_R_SUCCESS)
00690                 result = isc_timer_reset(timer, timertype, &expires,
00691                                          &interval, ISC_FALSE);
00692         return (result);
00693 }
00694 
00695 isc_result_t
00696 dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
00697                       isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
00698                       unsigned int options, unsigned int timeout,
00699                       isc_task_t *task, isc_taskaction_t action, void *arg,
00700                       dns_request_t **requestp)
00701 {
00702         return(dns_request_createraw4(requestmgr, msgbuf, srcaddr, destaddr,
00703                                       -1, options, timeout, 0, 0, task, action,
00704                                       arg, requestp));
00705 }
00706 
00707 isc_result_t
00708 dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
00709                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
00710                        unsigned int options, unsigned int timeout,
00711                        unsigned int udptimeout, isc_task_t *task,
00712                        isc_taskaction_t action, void *arg,
00713                        dns_request_t **requestp)
00714 {
00715         unsigned int udpretries = 0;
00716 
00717         if (udptimeout != 0)
00718                 udpretries = timeout / udptimeout;
00719 
00720         return (dns_request_createraw4(requestmgr, msgbuf, srcaddr, destaddr,
00721                                        -1, options, timeout, udptimeout,
00722                                        udpretries, task, action, arg,
00723                                        requestp));
00724 }
00725 
00726 isc_result_t
00727 dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
00728                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
00729                        unsigned int options, unsigned int timeout,
00730                        unsigned int udptimeout, unsigned int udpretries,
00731                        isc_task_t *task, isc_taskaction_t action, void *arg,
00732                        dns_request_t **requestp)
00733 {
00734         return (dns_request_createraw4(requestmgr, msgbuf, srcaddr, destaddr,
00735                                        -1, options, timeout, udptimeout,
00736                                        udpretries, task, action, arg,
00737                                        requestp));
00738 }
00739 
00740 isc_result_t
00741 dns_request_createraw4(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
00742                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
00743                        isc_dscp_t dscp, unsigned int options,
00744                        unsigned int timeout, unsigned int udptimeout,
00745                        unsigned int udpretries, isc_task_t *task,
00746                        isc_taskaction_t action, void *arg,
00747                        dns_request_t **requestp)
00748 {
00749         dns_request_t *request = NULL;
00750         isc_task_t *tclone = NULL;
00751         isc_socket_t *sock = NULL;
00752         isc_result_t result;
00753         isc_mem_t *mctx;
00754         dns_messageid_t id;
00755         isc_boolean_t tcp = ISC_FALSE;
00756         isc_boolean_t newtcp = ISC_FALSE;
00757         isc_boolean_t share = ISC_FALSE;
00758         isc_region_t r;
00759         isc_boolean_t connected = ISC_FALSE;
00760         unsigned int dispopt = 0;
00761 
00762         REQUIRE(VALID_REQUESTMGR(requestmgr));
00763         REQUIRE(msgbuf != NULL);
00764         REQUIRE(destaddr != NULL);
00765         REQUIRE(task != NULL);
00766         REQUIRE(action != NULL);
00767         REQUIRE(requestp != NULL && *requestp == NULL);
00768         REQUIRE(timeout > 0);
00769         if (srcaddr != NULL)
00770                 REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
00771 
00772         mctx = requestmgr->mctx;
00773 
00774         req_log(ISC_LOG_DEBUG(3), "dns_request_createraw");
00775 
00776         if (isblackholed(requestmgr->dispatchmgr, destaddr))
00777                 return (DNS_R_BLACKHOLED);
00778 
00779         request = NULL;
00780         result = new_request(mctx, &request);
00781         if (result != ISC_R_SUCCESS)
00782                 return (result);
00783 
00784         if (udptimeout == 0 && udpretries != 0) {
00785                 udptimeout = timeout / (udpretries + 1);
00786                 if (udptimeout == 0)
00787                         udptimeout = 1;
00788         }
00789         request->udpcount = udpretries;
00790         request->dscp = dscp;
00791 
00792         /*
00793          * Create timer now.  We will set it below once.
00794          */
00795         result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
00796                                   NULL, NULL, task, req_timeout, request,
00797                                   &request->timer);
00798         if (result != ISC_R_SUCCESS)
00799                 goto cleanup;
00800 
00801         request->event = (dns_requestevent_t *)
00802                 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
00803                                    action, arg, sizeof(dns_requestevent_t));
00804         if (request->event == NULL) {
00805                 result = ISC_R_NOMEMORY;
00806                 goto cleanup;
00807         }
00808         isc_task_attach(task, &tclone);
00809         request->event->ev_sender = task;
00810         request->event->request = request;
00811         request->event->result = ISC_R_FAILURE;
00812 
00813         isc_buffer_usedregion(msgbuf, &r);
00814         if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
00815                 result = DNS_R_FORMERR;
00816                 goto cleanup;
00817         }
00818 
00819         if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512)
00820                 tcp = ISC_TRUE;
00821         share = ISC_TF((options & DNS_REQUESTOPT_SHARE) != 0);
00822 
00823  again:
00824         result = get_dispatch(tcp, newtcp, share, requestmgr,
00825                               srcaddr, destaddr, dscp,
00826                               &connected, &request->dispatch);
00827         if (result != ISC_R_SUCCESS)
00828                 goto cleanup;
00829 
00830         if ((options & DNS_REQUESTOPT_FIXEDID) != 0) {
00831                 id = (r.base[0] << 8) | r.base[1];
00832                 dispopt |= DNS_DISPATCHOPT_FIXEDID;
00833         }
00834 
00835         result = dns_dispatch_addresponse3(request->dispatch, dispopt,
00836                                            destaddr, task, req_response,
00837                                            request, &id, &request->dispentry,
00838                                            requestmgr->socketmgr);
00839         if (result != ISC_R_SUCCESS) {
00840                 if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) {
00841                         newtcp = ISC_TRUE;
00842                         connected = ISC_FALSE;
00843                         dns_dispatch_detach(&request->dispatch);
00844                         goto again;
00845                 }
00846                 goto cleanup;
00847         }
00848 
00849         sock = req_getsocket(request);
00850         INSIST(sock != NULL);
00851 
00852         result = isc_buffer_allocate(mctx, &request->query,
00853                                      r.length + (tcp ? 2 : 0));
00854         if (result != ISC_R_SUCCESS)
00855                 goto cleanup;
00856         if (tcp)
00857                 isc_buffer_putuint16(request->query, (isc_uint16_t)r.length);
00858         result = isc_buffer_copyregion(request->query, &r);
00859         if (result != ISC_R_SUCCESS)
00860                 goto cleanup;
00861 
00862         /* Add message ID. */
00863         isc_buffer_usedregion(request->query, &r);
00864         if (tcp)
00865                 isc_region_consume(&r, 2);
00866         r.base[0] = (id>>8) & 0xff;
00867         r.base[1] = id & 0xff;
00868 
00869         LOCK(&requestmgr->lock);
00870         if (requestmgr->exiting) {
00871                 UNLOCK(&requestmgr->lock);
00872                 result = ISC_R_SHUTTINGDOWN;
00873                 goto cleanup;
00874         }
00875         requestmgr_attach(requestmgr, &request->requestmgr);
00876         request->hash = mgr_gethash(requestmgr);
00877         ISC_LIST_APPEND(requestmgr->requests, request, link);
00878         UNLOCK(&requestmgr->lock);
00879 
00880         result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
00881         if (result != ISC_R_SUCCESS)
00882                 goto unlink;
00883 
00884         request->destaddr = *destaddr;
00885         if (tcp && !connected) {
00886                 result = isc_socket_connect(sock, destaddr, task,
00887                                             req_connected, request);
00888                 if (result != ISC_R_SUCCESS)
00889                         goto unlink;
00890                 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
00891         } else {
00892                 result = req_send(request, task, connected ? NULL : destaddr);
00893                 if (result != ISC_R_SUCCESS)
00894                         goto unlink;
00895         }
00896 
00897         req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p",
00898                 request);
00899         *requestp = request;
00900         return (ISC_R_SUCCESS);
00901 
00902  unlink:
00903         LOCK(&requestmgr->lock);
00904         ISC_LIST_UNLINK(requestmgr->requests, request, link);
00905         UNLOCK(&requestmgr->lock);
00906 
00907  cleanup:
00908         if (tclone != NULL)
00909                 isc_task_detach(&tclone);
00910         req_destroy(request);
00911         req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
00912                 dns_result_totext(result));
00913         return (result);
00914 }
00915 
00916 isc_result_t
00917 dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
00918                    isc_sockaddr_t *address, unsigned int options,
00919                    dns_tsigkey_t *key,
00920                    unsigned int timeout, isc_task_t *task,
00921                    isc_taskaction_t action, void *arg,
00922                    dns_request_t **requestp)
00923 {
00924         return (dns_request_createvia4(requestmgr, message, NULL, address,
00925                                        -1, options, key, timeout, 0, 0, task,
00926                                        action, arg, requestp));
00927 }
00928 
00929 isc_result_t
00930 dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message,
00931                       isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
00932                       unsigned int options, dns_tsigkey_t *key,
00933                       unsigned int timeout, isc_task_t *task,
00934                       isc_taskaction_t action, void *arg,
00935                       dns_request_t **requestp)
00936 {
00937         return(dns_request_createvia4(requestmgr, message, srcaddr, destaddr,
00938                                       -1, options, key, timeout, 0, 0, task,
00939                                       action, arg, requestp));
00940 }
00941 
00942 isc_result_t
00943 dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message,
00944                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
00945                        unsigned int options, dns_tsigkey_t *key,
00946                        unsigned int timeout, unsigned int udptimeout,
00947                        isc_task_t *task, isc_taskaction_t action, void *arg,
00948                        dns_request_t **requestp)
00949 {
00950         unsigned int udpretries = 0;
00951 
00952         if (udptimeout != 0)
00953                 udpretries = timeout / udptimeout;
00954         return (dns_request_createvia4(requestmgr, message, srcaddr, destaddr,
00955                                        -1, options, key, timeout, udptimeout,
00956                                        udpretries, task, action, arg,
00957                                        requestp));
00958 }
00959 
00960 isc_result_t
00961 dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
00962                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
00963                        unsigned int options, dns_tsigkey_t *key,
00964                        unsigned int timeout, unsigned int udptimeout,
00965                        unsigned int udpretries, isc_task_t *task,
00966                        isc_taskaction_t action, void *arg,
00967                        dns_request_t **requestp)
00968 {
00969         return (dns_request_createvia4(requestmgr, message, srcaddr, destaddr,
00970                                        -1, options, key, timeout, udptimeout,
00971                                        udpretries, task, action, arg,
00972                                        requestp));
00973 }
00974 
00975 isc_result_t
00976 dns_request_createvia4(dns_requestmgr_t *requestmgr, dns_message_t *message,
00977                        isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
00978                        isc_dscp_t dscp, unsigned int options,
00979                        dns_tsigkey_t *key, unsigned int timeout,
00980                        unsigned int udptimeout, unsigned int udpretries,
00981                        isc_task_t *task, isc_taskaction_t action, void *arg,
00982                        dns_request_t **requestp)
00983 {
00984         dns_request_t *request = NULL;
00985         isc_task_t *tclone = NULL;
00986         isc_socket_t *sock = NULL;
00987         isc_result_t result;
00988         isc_mem_t *mctx;
00989         dns_messageid_t id;
00990         isc_boolean_t tcp;
00991         isc_boolean_t share;
00992         isc_boolean_t settsigkey = ISC_TRUE;
00993         isc_boolean_t connected = ISC_FALSE;
00994 
00995         REQUIRE(VALID_REQUESTMGR(requestmgr));
00996         REQUIRE(message != NULL);
00997         REQUIRE(destaddr != NULL);
00998         REQUIRE(task != NULL);
00999         REQUIRE(action != NULL);
01000         REQUIRE(requestp != NULL && *requestp == NULL);
01001         REQUIRE(timeout > 0);
01002 
01003         mctx = requestmgr->mctx;
01004 
01005         req_log(ISC_LOG_DEBUG(3), "dns_request_createvia");
01006 
01007         if (srcaddr != NULL &&
01008             isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr))
01009                 return (ISC_R_FAMILYMISMATCH);
01010 
01011         if (isblackholed(requestmgr->dispatchmgr, destaddr))
01012                 return (DNS_R_BLACKHOLED);
01013 
01014         request = NULL;
01015         result = new_request(mctx, &request);
01016         if (result != ISC_R_SUCCESS)
01017                 return (result);
01018 
01019         if (udptimeout == 0 && udpretries != 0) {
01020                 udptimeout = timeout / (udpretries + 1);
01021                 if (udptimeout == 0)
01022                         udptimeout = 1;
01023         }
01024         request->udpcount = udpretries;
01025         request->dscp = dscp;
01026 
01027         /*
01028          * Create timer now.  We will set it below once.
01029          */
01030         result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
01031                                   NULL, NULL, task, req_timeout, request,
01032                                   &request->timer);
01033         if (result != ISC_R_SUCCESS)
01034                 goto cleanup;
01035 
01036         request->event = (dns_requestevent_t *)
01037                 isc_event_allocate(mctx, task, DNS_EVENT_REQUESTDONE,
01038                                    action, arg, sizeof(dns_requestevent_t));
01039         if (request->event == NULL) {
01040                 result = ISC_R_NOMEMORY;
01041                 goto cleanup;
01042         }
01043         isc_task_attach(task, &tclone);
01044         request->event->ev_sender = task;
01045         request->event->request = request;
01046         request->event->result = ISC_R_FAILURE;
01047         if (key != NULL)
01048                 dns_tsigkey_attach(key, &request->tsigkey);
01049 
01050  use_tcp:
01051         tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0);
01052         share = ISC_TF((options & DNS_REQUESTOPT_SHARE) != 0);
01053         result = get_dispatch(tcp, ISC_FALSE, share,
01054                               requestmgr, srcaddr, destaddr,
01055                               dscp, &connected, &request->dispatch);
01056         if (result != ISC_R_SUCCESS)
01057                 goto cleanup;
01058 
01059         result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
01060                                            req_response, request, &id,
01061                                            &request->dispentry,
01062                                            requestmgr->socketmgr);
01063         if (result != ISC_R_SUCCESS)
01064                 goto cleanup;
01065         sock = req_getsocket(request);
01066         INSIST(sock != NULL);
01067 
01068         message->id = id;
01069         if (settsigkey) {
01070                 result = dns_message_settsigkey(message, request->tsigkey);
01071                 if (result != ISC_R_SUCCESS)
01072                         goto cleanup;
01073         }
01074         result = req_render(message, &request->query, options, mctx);
01075         if (result == DNS_R_USETCP &&
01076             (options & DNS_REQUESTOPT_TCP) == 0) {
01077                 /*
01078                  * Try again using TCP.
01079                  */
01080                 dns_message_renderreset(message);
01081                 dns_dispatch_removeresponse(&request->dispentry, NULL);
01082                 dns_dispatch_detach(&request->dispatch);
01083                 sock = NULL;
01084                 options |= DNS_REQUESTOPT_TCP;
01085                 settsigkey = ISC_FALSE;
01086                 goto use_tcp;
01087         }
01088         if (result != ISC_R_SUCCESS)
01089                 goto cleanup;
01090 
01091         result = dns_message_getquerytsig(message, mctx, &request->tsig);
01092         if (result != ISC_R_SUCCESS)
01093                 goto cleanup;
01094 
01095         LOCK(&requestmgr->lock);
01096         if (requestmgr->exiting) {
01097                 UNLOCK(&requestmgr->lock);
01098                 result = ISC_R_SHUTTINGDOWN;
01099                 goto cleanup;
01100         }
01101         requestmgr_attach(requestmgr, &request->requestmgr);
01102         request->hash = mgr_gethash(requestmgr);
01103         ISC_LIST_APPEND(requestmgr->requests, request, link);
01104         UNLOCK(&requestmgr->lock);
01105 
01106         result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
01107         if (result != ISC_R_SUCCESS)
01108                 goto unlink;
01109 
01110         request->destaddr = *destaddr;
01111         if (tcp && !connected) {
01112                 result = isc_socket_connect(sock, destaddr, task,
01113                                             req_connected, request);
01114                 if (result != ISC_R_SUCCESS)
01115                         goto unlink;
01116                 request->flags |= DNS_REQUEST_F_CONNECTING|DNS_REQUEST_F_TCP;
01117         } else {
01118                 result = req_send(request, task, connected ? NULL : destaddr);
01119                 if (result != ISC_R_SUCCESS)
01120                         goto unlink;
01121         }
01122 
01123         req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p",
01124                 request);
01125         *requestp = request;
01126         return (ISC_R_SUCCESS);
01127 
01128  unlink:
01129         LOCK(&requestmgr->lock);
01130         ISC_LIST_UNLINK(requestmgr->requests, request, link);
01131         UNLOCK(&requestmgr->lock);
01132 
01133  cleanup:
01134         if (tclone != NULL)
01135                 isc_task_detach(&tclone);
01136         req_destroy(request);
01137         req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s",
01138                 dns_result_totext(result));
01139         return (result);
01140 }
01141 
01142 static isc_result_t
01143 req_render(dns_message_t *message, isc_buffer_t **bufferp,
01144            unsigned int options, isc_mem_t *mctx)
01145 {
01146         isc_buffer_t *buf1 = NULL;
01147         isc_buffer_t *buf2 = NULL;
01148         isc_result_t result;
01149         isc_region_t r;
01150         isc_boolean_t tcp = ISC_FALSE;
01151         dns_compress_t cctx;
01152         isc_boolean_t cleanup_cctx = ISC_FALSE;
01153 
01154         REQUIRE(bufferp != NULL && *bufferp == NULL);
01155 
01156         req_log(ISC_LOG_DEBUG(3), "request_render");
01157 
01158         /*
01159          * Create buffer able to hold largest possible message.
01160          */
01161         result = isc_buffer_allocate(mctx, &buf1, 65535);
01162         if (result != ISC_R_SUCCESS)
01163                 return (result);
01164 
01165         result = dns_compress_init(&cctx, -1, mctx);
01166         if (result != ISC_R_SUCCESS)
01167                 return (result);
01168         cleanup_cctx = ISC_TRUE;
01169 
01170         if ((options & DNS_REQUESTOPT_CASE) != 0)
01171                 dns_compress_setsensitive(&cctx, ISC_TRUE);
01172 
01173         /*
01174          * Render message.
01175          */
01176         result = dns_message_renderbegin(message, &cctx, buf1);
01177         if (result != ISC_R_SUCCESS)
01178                 goto cleanup;
01179         result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
01180         if (result != ISC_R_SUCCESS)
01181                 goto cleanup;
01182         result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
01183         if (result != ISC_R_SUCCESS)
01184                 goto cleanup;
01185         result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
01186         if (result != ISC_R_SUCCESS)
01187                 goto cleanup;
01188         result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
01189         if (result != ISC_R_SUCCESS)
01190                 goto cleanup;
01191         result = dns_message_renderend(message);
01192         if (result != ISC_R_SUCCESS)
01193                 goto cleanup;
01194 
01195         dns_compress_invalidate(&cctx);
01196         cleanup_cctx = ISC_FALSE;
01197 
01198         /*
01199          * Copy rendered message to exact sized buffer.
01200          */
01201         isc_buffer_usedregion(buf1, &r);
01202         if ((options & DNS_REQUESTOPT_TCP) != 0) {
01203                 tcp = ISC_TRUE;
01204         } else if (r.length > 512) {
01205                 result = DNS_R_USETCP;
01206                 goto cleanup;
01207         }
01208         result = isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0));
01209         if (result != ISC_R_SUCCESS)
01210                 goto cleanup;
01211         if (tcp)
01212                 isc_buffer_putuint16(buf2, (isc_uint16_t)r.length);
01213         result = isc_buffer_copyregion(buf2, &r);
01214         if (result != ISC_R_SUCCESS)
01215                 goto cleanup;
01216 
01217         /*
01218          * Cleanup and return.
01219          */
01220         isc_buffer_free(&buf1);
01221         *bufferp = buf2;
01222         return (ISC_R_SUCCESS);
01223 
01224  cleanup:
01225         dns_message_renderreset(message);
01226         if (buf1 != NULL)
01227                 isc_buffer_free(&buf1);
01228         if (buf2 != NULL)
01229                 isc_buffer_free(&buf2);
01230         if (cleanup_cctx)
01231                 dns_compress_invalidate(&cctx);
01232         return (result);
01233 }
01234 
01235 
01236 /*
01237  * If this request is no longer waiting for events,
01238  * send the completion event.  This will ultimately
01239  * cause the request to be destroyed.
01240  *
01241  * Requires:
01242  *      'request' is locked by the caller.
01243  */
01244 static void
01245 send_if_done(dns_request_t *request, isc_result_t result) {
01246         if (request->event != NULL && !request->canceling)
01247                 req_sendevent(request, result);
01248 }
01249 
01250 /*
01251  * Handle the control event.
01252  */
01253 static void
01254 do_cancel(isc_task_t *task, isc_event_t *event) {
01255         dns_request_t *request = event->ev_arg;
01256         UNUSED(task);
01257         INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL);
01258         LOCK(&request->requestmgr->locks[request->hash]);
01259         request->canceling = ISC_FALSE;
01260         if (!DNS_REQUEST_CANCELED(request))
01261                 req_cancel(request);
01262         send_if_done(request, ISC_R_CANCELED);
01263         UNLOCK(&request->requestmgr->locks[request->hash]);
01264 }
01265 
01266 void
01267 dns_request_cancel(dns_request_t *request) {
01268         REQUIRE(VALID_REQUEST(request));
01269 
01270         req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request);
01271 
01272         REQUIRE(VALID_REQUEST(request));
01273 
01274         LOCK(&request->requestmgr->locks[request->hash]);
01275         if (!request->canceling && !DNS_REQUEST_CANCELED(request)) {
01276                 isc_event_t *ev =  &request->ctlevent;
01277                 isc_task_send(request->event->ev_sender, &ev);
01278                 request->canceling = ISC_TRUE;
01279         }
01280         UNLOCK(&request->requestmgr->locks[request->hash]);
01281 }
01282 
01283 isc_result_t
01284 dns_request_getresponse(dns_request_t *request, dns_message_t *message,
01285                         unsigned int options)
01286 {
01287         isc_result_t result;
01288 
01289         REQUIRE(VALID_REQUEST(request));
01290         REQUIRE(request->answer != NULL);
01291 
01292         req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p",
01293                 request);
01294 
01295         result = dns_message_setquerytsig(message, request->tsig);
01296         if (result != ISC_R_SUCCESS)
01297                 return (result);
01298         result = dns_message_settsigkey(message, request->tsigkey);
01299         if (result != ISC_R_SUCCESS)
01300                 return (result);
01301         result = dns_message_parse(message, request->answer, options);
01302         if (result != ISC_R_SUCCESS)
01303                 return (result);
01304         if (request->tsigkey != NULL)
01305                 result = dns_tsig_verify(request->answer, message, NULL, NULL);
01306         return (result);
01307 }
01308 
01309 isc_boolean_t
01310 dns_request_usedtcp(dns_request_t *request) {
01311         REQUIRE(VALID_REQUEST(request));
01312 
01313         return (ISC_TF((request->flags & DNS_REQUEST_F_TCP) != 0));
01314 }
01315 
01316 void
01317 dns_request_destroy(dns_request_t **requestp) {
01318         dns_request_t *request;
01319 
01320         REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
01321 
01322         request = *requestp;
01323 
01324         req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request);
01325 
01326         LOCK(&request->requestmgr->lock);
01327         LOCK(&request->requestmgr->locks[request->hash]);
01328         ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
01329         INSIST(!DNS_REQUEST_CONNECTING(request));
01330         INSIST(!DNS_REQUEST_SENDING(request));
01331         UNLOCK(&request->requestmgr->locks[request->hash]);
01332         UNLOCK(&request->requestmgr->lock);
01333 
01334         /*
01335          * These should have been cleaned up by req_cancel() before
01336          * the completion event was sent.
01337          */
01338         INSIST(!ISC_LINK_LINKED(request, link));
01339         INSIST(request->dispentry == NULL);
01340         INSIST(request->dispatch == NULL);
01341         INSIST(request->timer == NULL);
01342 
01343         req_destroy(request);
01344 
01345         *requestp = NULL;
01346 }
01347 
01348 /***
01349  *** Private: request.
01350  ***/
01351 
01352 static isc_socket_t *
01353 req_getsocket(dns_request_t *request) {
01354         unsigned int dispattr;
01355         isc_socket_t *sock;
01356 
01357         dispattr = dns_dispatch_getattributes(request->dispatch);
01358         if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
01359                 INSIST(request->dispentry != NULL);
01360                 sock = dns_dispatch_getentrysocket(request->dispentry);
01361         } else
01362                 sock = dns_dispatch_getsocket(request->dispatch);
01363 
01364         return (sock);
01365 }
01366 
01367 static void
01368 req_connected(isc_task_t *task, isc_event_t *event) {
01369         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
01370         isc_result_t result;
01371         dns_request_t *request = event->ev_arg;
01372 
01373         REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
01374         REQUIRE(VALID_REQUEST(request));
01375         REQUIRE(DNS_REQUEST_CONNECTING(request));
01376 
01377         req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request);
01378 
01379         LOCK(&request->requestmgr->locks[request->hash]);
01380         request->flags &= ~DNS_REQUEST_F_CONNECTING;
01381 
01382         if (DNS_REQUEST_CANCELED(request)) {
01383                 /*
01384                  * Send delayed event.
01385                  */
01386                 if (DNS_REQUEST_TIMEDOUT(request))
01387                         send_if_done(request, ISC_R_TIMEDOUT);
01388                 else
01389                         send_if_done(request, ISC_R_CANCELED);
01390         } else {
01391                 dns_dispatch_starttcp(request->dispatch);
01392                 result = sevent->result;
01393                 if (result == ISC_R_SUCCESS)
01394                         result = req_send(request, task, NULL);
01395 
01396                 if (result != ISC_R_SUCCESS) {
01397                         req_cancel(request);
01398                         send_if_done(request, ISC_R_CANCELED);
01399                 }
01400         }
01401         UNLOCK(&request->requestmgr->locks[request->hash]);
01402         isc_event_free(&event);
01403 }
01404 
01405 static void
01406 req_senddone(isc_task_t *task, isc_event_t *event) {
01407         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
01408         dns_request_t *request = event->ev_arg;
01409 
01410         REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
01411         REQUIRE(VALID_REQUEST(request));
01412         REQUIRE(DNS_REQUEST_SENDING(request));
01413 
01414         req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
01415 
01416         UNUSED(task);
01417 
01418         LOCK(&request->requestmgr->locks[request->hash]);
01419         request->flags &= ~DNS_REQUEST_F_SENDING;
01420 
01421         if (DNS_REQUEST_CANCELED(request)) {
01422                 /*
01423                  * Send delayed event.
01424                  */
01425                 if (DNS_REQUEST_TIMEDOUT(request))
01426                         send_if_done(request, ISC_R_TIMEDOUT);
01427                 else
01428                         send_if_done(request, ISC_R_CANCELED);
01429         } else if (sevent->result != ISC_R_SUCCESS) {
01430                 req_cancel(request);
01431                 send_if_done(request, ISC_R_CANCELED);
01432         }
01433         UNLOCK(&request->requestmgr->locks[request->hash]);
01434 
01435         isc_event_free(&event);
01436 }
01437 
01438 static void
01439 req_response(isc_task_t *task, isc_event_t *event) {
01440         isc_result_t result;
01441         dns_request_t *request = event->ev_arg;
01442         dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
01443         isc_region_t r;
01444 
01445         REQUIRE(VALID_REQUEST(request));
01446         REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
01447 
01448         UNUSED(task);
01449 
01450         req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
01451                 dns_result_totext(devent->result));
01452 
01453         LOCK(&request->requestmgr->locks[request->hash]);
01454         result = devent->result;
01455         if (result != ISC_R_SUCCESS)
01456                 goto done;
01457 
01458         /*
01459          * Copy buffer to request.
01460          */
01461         isc_buffer_usedregion(&devent->buffer, &r);
01462         result = isc_buffer_allocate(request->mctx, &request->answer,
01463                                      r.length);
01464         if (result != ISC_R_SUCCESS)
01465                 goto done;
01466         result = isc_buffer_copyregion(request->answer, &r);
01467         if (result != ISC_R_SUCCESS)
01468                 isc_buffer_free(&request->answer);
01469  done:
01470         /*
01471          * Cleanup.
01472          */
01473         dns_dispatch_removeresponse(&request->dispentry, &devent);
01474         req_cancel(request);
01475         /*
01476          * Send completion event.
01477          */
01478         send_if_done(request, result);
01479         UNLOCK(&request->requestmgr->locks[request->hash]);
01480 }
01481 
01482 static void
01483 req_timeout(isc_task_t *task, isc_event_t *event) {
01484         dns_request_t *request = event->ev_arg;
01485         isc_result_t result;
01486 
01487         REQUIRE(VALID_REQUEST(request));
01488 
01489         req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
01490 
01491         UNUSED(task);
01492         LOCK(&request->requestmgr->locks[request->hash]);
01493         if (event->ev_type == ISC_TIMEREVENT_TICK &&
01494             request->udpcount-- != 0) {
01495                 if (! DNS_REQUEST_SENDING(request)) {
01496                         result = req_send(request, task, &request->destaddr);
01497                         if (result != ISC_R_SUCCESS) {
01498                                 req_cancel(request);
01499                                 send_if_done(request, result);
01500                         }
01501                 }
01502         } else {
01503                 request->flags |= DNS_REQUEST_F_TIMEDOUT;
01504                 req_cancel(request);
01505                 send_if_done(request, ISC_R_TIMEDOUT);
01506         }
01507         UNLOCK(&request->requestmgr->locks[request->hash]);
01508         isc_event_free(&event);
01509 }
01510 
01511 static void
01512 req_sendevent(dns_request_t *request, isc_result_t result) {
01513         isc_task_t *task;
01514 
01515         REQUIRE(VALID_REQUEST(request));
01516 
01517         req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request);
01518 
01519         /*
01520          * Lock held by caller.
01521          */
01522         task = request->event->ev_sender;
01523         request->event->ev_sender = request;
01524         request->event->result = result;
01525         isc_task_sendanddetach(&task, (isc_event_t **)&request->event);
01526 }
01527 
01528 static void
01529 req_destroy(dns_request_t *request) {
01530         isc_mem_t *mctx;
01531 
01532         REQUIRE(VALID_REQUEST(request));
01533 
01534         req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request);
01535 
01536         request->magic = 0;
01537         if (request->query != NULL)
01538                 isc_buffer_free(&request->query);
01539         if (request->answer != NULL)
01540                 isc_buffer_free(&request->answer);
01541         if (request->event != NULL)
01542                 isc_event_free((isc_event_t **)&request->event);
01543         if (request->dispentry != NULL)
01544                 dns_dispatch_removeresponse(&request->dispentry, NULL);
01545         if (request->dispatch != NULL)
01546                 dns_dispatch_detach(&request->dispatch);
01547         if (request->timer != NULL)
01548                 isc_timer_detach(&request->timer);
01549         if (request->tsig != NULL)
01550                 isc_buffer_free(&request->tsig);
01551         if (request->tsigkey != NULL)
01552                 dns_tsigkey_detach(&request->tsigkey);
01553         if (request->requestmgr != NULL)
01554                 requestmgr_detach(&request->requestmgr);
01555         mctx = request->mctx;
01556         isc_mem_put(mctx, request, sizeof(*request));
01557         isc_mem_detach(&mctx);
01558 }
01559 
01560 /*
01561  * Stop the current request.  Must be called from the request's task.
01562  */
01563 static void
01564 req_cancel(dns_request_t *request) {
01565         isc_socket_t *sock;
01566         unsigned int dispattr;
01567 
01568         REQUIRE(VALID_REQUEST(request));
01569 
01570         req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request);
01571 
01572         /*
01573          * Lock held by caller.
01574          */
01575         request->flags |= DNS_REQUEST_F_CANCELED;
01576 
01577         if (request->timer != NULL)
01578                 isc_timer_detach(&request->timer);
01579         dispattr = dns_dispatch_getattributes(request->dispatch);
01580         sock = NULL;
01581         if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) {
01582                 if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
01583                         if (request->dispentry != NULL) {
01584                                 sock = dns_dispatch_getentrysocket(
01585                                         request->dispentry);
01586                         }
01587                 } else
01588                         sock = dns_dispatch_getsocket(request->dispatch);
01589                 if (DNS_REQUEST_CONNECTING(request) && sock != NULL)
01590                         isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT);
01591                 if (DNS_REQUEST_SENDING(request) && sock != NULL)
01592                         isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND);
01593         }
01594         if (request->dispentry != NULL)
01595                 dns_dispatch_removeresponse(&request->dispentry, NULL);
01596         dns_dispatch_detach(&request->dispatch);
01597 }
01598 
01599 static void
01600 req_log(int level, const char *fmt, ...) {
01601         va_list ap;
01602 
01603         va_start(ap, fmt);
01604         isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
01605                        DNS_LOGMODULE_REQUEST, level, fmt, ap);
01606         va_end(ap);
01607 }

Generated on Tue Apr 28 17:41:00 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha