"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/bin/named/lwdclient.c" (7 Sep 2020, 12023 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "lwdclient.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /* $Id: lwdclient.c,v 1.22 2007/06/18 23:47:18 tbox Exp $ */
   13 
   14 /*! \file */
   15 
   16 #include <config.h>
   17 
   18 #include <isc/socket.h>
   19 #include <isc/string.h>
   20 #include <isc/task.h>
   21 #include <isc/util.h>
   22 
   23 #include <dns/adb.h>
   24 #include <dns/view.h>
   25 #include <dns/log.h>
   26 
   27 #include <named/types.h>
   28 #include <named/log.h>
   29 #include <named/lwresd.h>
   30 #include <named/lwdclient.h>
   31 
   32 #define SHUTTINGDOWN(cm) ((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) != 0)
   33 
   34 static void
   35 lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev);
   36 
   37 void
   38 ns_lwdclient_log(int level, const char *format, ...) {
   39     va_list args;
   40 
   41     va_start(args, format);
   42     isc_log_vwrite(dns_lctx,
   43                DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
   44                ISC_LOG_DEBUG(level), format, args);
   45     va_end(args);
   46 }
   47 
   48 isc_result_t
   49 ns_lwdclientmgr_create(ns_lwreslistener_t *listener, unsigned int nclients,
   50             isc_taskmgr_t *taskmgr)
   51 {
   52     ns_lwresd_t *lwresd = listener->manager;
   53     ns_lwdclientmgr_t *cm;
   54     ns_lwdclient_t *client;
   55     unsigned int i;
   56     isc_result_t result;
   57 
   58     cm = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclientmgr_t));
   59     if (cm == NULL)
   60         return (ISC_R_NOMEMORY);
   61 
   62     result = isc_mutex_init(&cm->lock);
   63     if (result != ISC_R_SUCCESS)
   64         goto freecm;
   65 
   66     cm->listener = NULL;
   67     ns_lwreslistener_attach(listener, &cm->listener);
   68     cm->mctx = lwresd->mctx;
   69     cm->sock = NULL;
   70     isc_socket_attach(listener->sock, &cm->sock);
   71     cm->view = lwresd->view;
   72     cm->lwctx = NULL;
   73     cm->task = NULL;
   74     cm->flags = 0;
   75     ISC_LINK_INIT(cm, link);
   76     ISC_LIST_INIT(cm->idle);
   77     ISC_LIST_INIT(cm->running);
   78 
   79     result = lwres_context_create(&cm->lwctx, cm->mctx,
   80                       ns__lwresd_memalloc, ns__lwresd_memfree,
   81                       LWRES_CONTEXT_SERVERMODE);
   82      if (result != ISC_R_SUCCESS)
   83         goto errout;
   84 
   85     for (i = 0; i < nclients; i++) {
   86         client = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclient_t));
   87         if (client != NULL) {
   88             ns_lwdclient_log(50, "created client %p, manager %p",
   89                      client, cm);
   90             ns_lwdclient_initialize(client, cm);
   91         }
   92     }
   93 
   94     /*
   95      * If we could create no clients, clean up and return.
   96      */
   97     if (ISC_LIST_EMPTY(cm->idle)) {
   98         result = ISC_R_NOMEMORY;
   99         goto errout;
  100     }
  101 
  102     result = isc_task_create(taskmgr, 0, &cm->task);
  103     if (result != ISC_R_SUCCESS)
  104         goto errout;
  105     isc_task_setname(cm->task, "lwdclient", NULL);
  106 
  107     /*
  108      * This MUST be last, since there is no way to cancel an onshutdown...
  109      */
  110     result = isc_task_onshutdown(cm->task, lwdclientmgr_shutdown_callback,
  111                      cm);
  112     if (result != ISC_R_SUCCESS)
  113         goto errout;
  114 
  115     ns_lwreslistener_linkcm(listener, cm);
  116 
  117     return (ISC_R_SUCCESS);
  118 
  119  errout:
  120     client = ISC_LIST_HEAD(cm->idle);
  121     while (client != NULL) {
  122         ISC_LIST_UNLINK(cm->idle, client, link);
  123         isc_mem_put(lwresd->mctx, client, sizeof(*client));
  124         client = ISC_LIST_HEAD(cm->idle);
  125     }
  126 
  127     if (cm->task != NULL)
  128         isc_task_detach(&cm->task);
  129 
  130     if (cm->lwctx != NULL)
  131         lwres_context_destroy(&cm->lwctx);
  132 
  133     DESTROYLOCK(&cm->lock);
  134 
  135  freecm:
  136     isc_mem_put(lwresd->mctx, cm, sizeof(*cm));
  137     return (result);
  138 }
  139 
  140 static void
  141 lwdclientmgr_destroy(ns_lwdclientmgr_t *cm) {
  142     ns_lwdclient_t *client;
  143     ns_lwreslistener_t *listener;
  144 
  145     LOCK(&cm->lock);
  146     if (!SHUTTINGDOWN(cm)) {
  147         UNLOCK(&cm->lock);
  148         return;
  149     }
  150 
  151     /*
  152      * Run through the idle list and free the clients there.  Idle
  153      * clients do not have a recv running nor do they have any finds
  154      * or similar running.
  155      */
  156     client = ISC_LIST_HEAD(cm->idle);
  157     while (client != NULL) {
  158         ns_lwdclient_log(50, "destroying client %p, manager %p",
  159                  client, cm);
  160         ISC_LIST_UNLINK(cm->idle, client, link);
  161         isc_mem_put(cm->mctx, client, sizeof(*client));
  162         client = ISC_LIST_HEAD(cm->idle);
  163     }
  164 
  165     if (!ISC_LIST_EMPTY(cm->running)) {
  166         UNLOCK(&cm->lock);
  167         return;
  168     }
  169 
  170     UNLOCK(&cm->lock);
  171 
  172     lwres_context_destroy(&cm->lwctx);
  173     cm->view = NULL;
  174     isc_socket_detach(&cm->sock);
  175     isc_task_detach(&cm->task);
  176 
  177     DESTROYLOCK(&cm->lock);
  178 
  179     listener = cm->listener;
  180     ns_lwreslistener_unlinkcm(listener, cm);
  181     ns_lwdclient_log(50, "destroying manager %p", cm);
  182     isc_mem_put(cm->mctx, cm, sizeof(*cm));
  183     ns_lwreslistener_detach(&listener);
  184 }
  185 
  186 static void
  187 process_request(ns_lwdclient_t *client) {
  188     lwres_buffer_t b;
  189     isc_result_t result;
  190 
  191     lwres_buffer_init(&b, client->buffer, client->recvlength);
  192     lwres_buffer_add(&b, client->recvlength);
  193 
  194     result = lwres_lwpacket_parseheader(&b, &client->pkt);
  195     if (result != ISC_R_SUCCESS) {
  196         ns_lwdclient_log(50, "invalid packet header received");
  197         goto restart;
  198     }
  199 
  200     ns_lwdclient_log(50, "opcode %08x", client->pkt.opcode);
  201 
  202     switch (client->pkt.opcode) {
  203     case LWRES_OPCODE_GETADDRSBYNAME:
  204         ns_lwdclient_processgabn(client, &b);
  205         return;
  206     case LWRES_OPCODE_GETNAMEBYADDR:
  207         ns_lwdclient_processgnba(client, &b);
  208         return;
  209     case LWRES_OPCODE_GETRDATABYNAME:
  210         ns_lwdclient_processgrbn(client, &b);
  211         return;
  212     case LWRES_OPCODE_NOOP:
  213         ns_lwdclient_processnoop(client, &b);
  214         return;
  215     default:
  216         ns_lwdclient_log(50, "unknown opcode %08x", client->pkt.opcode);
  217         goto restart;
  218     }
  219 
  220     /*
  221      * Drop the packet.
  222      */
  223  restart:
  224     ns_lwdclient_log(50, "restarting client %p...", client);
  225     ns_lwdclient_stateidle(client);
  226 }
  227 
  228 void
  229 ns_lwdclient_recv(isc_task_t *task, isc_event_t *ev) {
  230     isc_result_t result;
  231     ns_lwdclient_t *client = ev->ev_arg;
  232     ns_lwdclientmgr_t *cm = client->clientmgr;
  233     isc_socketevent_t *dev = (isc_socketevent_t *)ev;
  234 
  235     INSIST(dev->region.base == client->buffer);
  236     INSIST(NS_LWDCLIENT_ISRECV(client));
  237 
  238     NS_LWDCLIENT_SETRECVDONE(client);
  239 
  240     LOCK(&cm->lock);
  241     INSIST((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0);
  242     cm->flags &= ~NS_LWDCLIENTMGR_FLAGRECVPENDING;
  243     UNLOCK(&cm->lock);
  244 
  245     ns_lwdclient_log(50,
  246              "event received: task %p, length %u, result %u (%s)",
  247              task, dev->n, dev->result,
  248              isc_result_totext(dev->result));
  249 
  250     if (dev->result != ISC_R_SUCCESS) {
  251         isc_event_free(&ev);
  252         dev = NULL;
  253 
  254         /*
  255          * Go idle.
  256          */
  257         ns_lwdclient_stateidle(client);
  258 
  259         return;
  260     }
  261 
  262     client->recvlength = dev->n;
  263     client->address = dev->address;
  264     if ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) {
  265         client->pktinfo = dev->pktinfo;
  266         client->pktinfo_valid = true;
  267     } else
  268         client->pktinfo_valid = false;
  269     isc_event_free(&ev);
  270     dev = NULL;
  271 
  272     result = ns_lwdclient_startrecv(cm);
  273     if (result != ISC_R_SUCCESS)
  274         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
  275                   NS_LOGMODULE_LWRESD, ISC_LOG_ERROR,
  276                   "could not start lwres "
  277                   "client handler: %s",
  278                   isc_result_totext(result));
  279 
  280     process_request(client);
  281 }
  282 
  283 /*
  284  * This function will start a new recv() on a socket for this client manager.
  285  */
  286 isc_result_t
  287 ns_lwdclient_startrecv(ns_lwdclientmgr_t *cm) {
  288     ns_lwdclient_t *client;
  289     isc_result_t result;
  290     isc_region_t r;
  291     bool destroy = false;
  292 
  293 
  294     LOCK(&cm->lock);
  295     if (SHUTTINGDOWN(cm)) {
  296         destroy = true;
  297         result = ISC_R_SUCCESS;
  298         goto unlock;
  299     }
  300 
  301     /*
  302      * If a recv is already running, don't bother.
  303      */
  304     if ((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0) {
  305         result = ISC_R_SUCCESS;
  306         goto unlock;
  307     }
  308 
  309     /*
  310      * If we have no idle slots, just return success.
  311      */
  312     client = ISC_LIST_HEAD(cm->idle);
  313     if (client == NULL) {
  314         result = ISC_R_SUCCESS;
  315         goto unlock;
  316     }
  317 
  318     INSIST(NS_LWDCLIENT_ISIDLE(client));
  319 
  320     /*
  321      * Set the flag to say there is a recv pending.  If isc_socket_recv
  322      * fails we will clear the flag otherwise it will be cleared by
  323      * ns_lwdclient_recv.
  324      */
  325     cm->flags |= NS_LWDCLIENTMGR_FLAGRECVPENDING;
  326 
  327     /*
  328      * Issue the recv.  If it fails, return that it did.
  329      */
  330     r.base = client->buffer;
  331     r.length = LWRES_RECVLENGTH;
  332     result = isc_socket_recv(cm->sock, &r, 0, cm->task, ns_lwdclient_recv,
  333                  client);
  334     if (result != ISC_R_SUCCESS) {
  335         cm->flags &= ~NS_LWDCLIENTMGR_FLAGRECVPENDING;
  336         goto unlock;
  337     }
  338 
  339     /*
  340      * Remove the client from the idle list, and put it on the running
  341      * list.
  342      */
  343     NS_LWDCLIENT_SETRECV(client);
  344     ISC_LIST_UNLINK(cm->idle, client, link);
  345     ISC_LIST_APPEND(cm->running, client, link);
  346 
  347  unlock:
  348     UNLOCK(&cm->lock);
  349 
  350     if (destroy)
  351         lwdclientmgr_destroy(cm);
  352 
  353     return (result);
  354 }
  355 
  356 static void
  357 lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev) {
  358     ns_lwdclientmgr_t *cm = ev->ev_arg;
  359     ns_lwdclient_t *client;
  360 
  361     REQUIRE(!SHUTTINGDOWN(cm));
  362 
  363     ns_lwdclient_log(50, "got shutdown event, task %p, lwdclientmgr %p",
  364              task, cm);
  365 
  366     /*
  367      * run through the idle list and free the clients there.  Idle
  368      * clients do not have a recv running nor do they have any finds
  369      * or similar running.
  370      */
  371     LOCK(&cm->lock);
  372     client = ISC_LIST_HEAD(cm->idle);
  373     while (client != NULL) {
  374         ns_lwdclient_log(50, "destroying client %p, manager %p",
  375                  client, cm);
  376         ISC_LIST_UNLINK(cm->idle, client, link);
  377         isc_mem_put(cm->mctx, client, sizeof(*client));
  378         client = ISC_LIST_HEAD(cm->idle);
  379     }
  380     UNLOCK(&cm->lock);
  381 
  382     /*
  383      * Cancel any pending I/O.
  384      */
  385     isc_socket_cancel(cm->sock, task, ISC_SOCKCANCEL_ALL);
  386 
  387     /*
  388      * Run through the running client list and kill off any finds
  389      * in progress.
  390      */
  391     LOCK(&cm->lock);
  392     client = ISC_LIST_HEAD(cm->running);
  393     while (client != NULL) {
  394         if (client->find != client->v4find
  395             && client->find != client->v6find)
  396             dns_adb_cancelfind(client->find);
  397         if (client->v4find != NULL)
  398             dns_adb_cancelfind(client->v4find);
  399         if (client->v6find != NULL)
  400             dns_adb_cancelfind(client->v6find);
  401         client = ISC_LIST_NEXT(client, link);
  402     }
  403 
  404     cm->flags |= NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN;
  405 
  406     UNLOCK(&cm->lock);
  407 
  408     isc_event_free(&ev);
  409 }
  410 
  411 /*
  412  * Do all the crap needed to move a client from the run queue to the idle
  413  * queue.
  414  */
  415 void
  416 ns_lwdclient_stateidle(ns_lwdclient_t *client) {
  417     ns_lwdclientmgr_t *cm;
  418     isc_result_t result;
  419 
  420     cm = client->clientmgr;
  421 
  422     INSIST(client->sendbuf == NULL);
  423     INSIST(client->sendlength == 0);
  424     INSIST(client->arg == NULL);
  425     INSIST(client->v4find == NULL);
  426     INSIST(client->v6find == NULL);
  427 
  428     LOCK(&cm->lock);
  429     ISC_LIST_UNLINK(cm->running, client, link);
  430     ISC_LIST_PREPEND(cm->idle, client, link);
  431     UNLOCK(&cm->lock);
  432 
  433     NS_LWDCLIENT_SETIDLE(client);
  434 
  435     result = ns_lwdclient_startrecv(cm);
  436     if (result != ISC_R_SUCCESS)
  437         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
  438                   NS_LOGMODULE_LWRESD, ISC_LOG_ERROR,
  439                   "could not start lwres "
  440                   "client handler: %s",
  441                   isc_result_totext(result));
  442 }
  443 
  444 void
  445 ns_lwdclient_send(isc_task_t *task, isc_event_t *ev) {
  446     ns_lwdclient_t *client = ev->ev_arg;
  447     ns_lwdclientmgr_t *cm = client->clientmgr;
  448     isc_socketevent_t *dev = (isc_socketevent_t *)ev;
  449 
  450     UNUSED(task);
  451     UNUSED(dev);
  452 
  453     INSIST(NS_LWDCLIENT_ISSEND(client));
  454     INSIST(client->sendbuf == dev->region.base);
  455 
  456     ns_lwdclient_log(50, "task %p for client %p got send-done event",
  457              task, client);
  458 
  459     if (client->sendbuf != client->buffer)
  460         lwres_context_freemem(cm->lwctx, client->sendbuf,
  461                       client->sendlength);
  462     client->sendbuf = NULL;
  463     client->sendlength = 0;
  464 
  465     ns_lwdclient_stateidle(client);
  466 
  467     isc_event_free(&ev);
  468 }
  469 
  470 isc_result_t
  471 ns_lwdclient_sendreply(ns_lwdclient_t *client, isc_region_t *r) {
  472     struct in6_pktinfo *pktinfo;
  473     ns_lwdclientmgr_t *cm = client->clientmgr;
  474 
  475     if (client->pktinfo_valid)
  476         pktinfo = &client->pktinfo;
  477     else
  478         pktinfo = NULL;
  479     return (isc_socket_sendto(cm->sock, r, cm->task, ns_lwdclient_send,
  480                   client, &client->address, pktinfo));
  481 }
  482 
  483 void
  484 ns_lwdclient_initialize(ns_lwdclient_t *client, ns_lwdclientmgr_t *cmgr) {
  485     client->clientmgr = cmgr;
  486     ISC_LINK_INIT(client, link);
  487     NS_LWDCLIENT_SETIDLE(client);
  488     client->arg = NULL;
  489 
  490     client->recvlength = 0;
  491 
  492     client->sendbuf = NULL;
  493     client->sendlength = 0;
  494 
  495     client->find = NULL;
  496     client->v4find = NULL;
  497     client->v6find = NULL;
  498     client->find_wanted = 0;
  499 
  500     client->options = 0;
  501     client->byaddr = NULL;
  502 
  503     client->lookup = NULL;
  504 
  505     client->pktinfo_valid = false;
  506 
  507     LOCK(&cmgr->lock);
  508     ISC_LIST_APPEND(cmgr->idle, client, link);
  509     UNLOCK(&cmgr->lock);
  510 }