]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Clients now listen on sockets instead of accepting queries from dispatchers.
authorBrian Wellington <source@isc.org>
Sat, 27 Jan 2001 02:08:07 +0000 (02:08 +0000)
committerBrian Wellington <source@isc.org>
Sat, 27 Jan 2001 02:08:07 +0000 (02:08 +0000)
When a socket is shared by clients and query-source, the client hands off
responses to the dispatcher.

bin/named/client.c
bin/named/include/named/client.h
bin/named/interfacemgr.c
lib/dns/dispatch.c
lib/dns/include/dns/dispatch.h
lib/dns/include/dns/events.h

index 125ef4cabda9e8d39d2061ffa047770ab31cbfdc..0935024f7fbc75c585deaf404ed212c74b291abe 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: client.c,v 1.141 2001/01/23 18:47:33 gson Exp $ */
+/* $Id: client.c,v 1.142 2001/01/27 02:07:59 bwelling Exp $ */
 
 #include <config.h>
 
@@ -134,10 +134,10 @@ struct ns_clientmgr {
  * client manager's list of active clients.
  *
  * If it is a TCP client object, it has a TCP listener socket
- * and an outstading TCP listen request.
+ * and an outstanding TCP listen request.
  *
- * If it is a UDP client object, it is associated with a
- * dispatch and has an outstanding dispatch request.
+ * If it is a UDP client object, it has a UDP listener socket
+ * and an outstanding UDP receive request.
  */
 
 #define NS_CLIENTSTATE_READING  3
@@ -152,8 +152,7 @@ struct ns_clientmgr {
 /*
  * The client object has received a request and is working
  * on it.  It has a view, and it may  have any of a non-reset OPT,
- * recursion quota, and an outstanding write request.  If it
- * is a UDP client object, it has a dispatch event.
+ * recursion quota, and an outstanding write request.
  */
 
 #define NS_CLIENTSTATE_MAX      9
@@ -166,6 +165,7 @@ struct ns_clientmgr {
 
 static void client_read(ns_client_t *client);
 static void client_accept(ns_client_t *client);
+static void client_udprecv(ns_client_t *client);
 static void clientmgr_destroy(ns_clientmgr_t *manager);
 static isc_boolean_t exit_check(ns_client_t *client);
 static void ns_client_endrequest(ns_client_t *client);
@@ -191,14 +191,9 @@ client_deactivate(ns_client_t *client) {
        if (client->tcplistener != NULL)
                isc_socket_detach(&client->tcplistener);
 
-       if (client->dispentry != NULL) {
-               dns_dispatchevent_t **deventp;
-               if (client->dispevent != NULL)
-                       deventp = &client->dispevent;
-               else
-                       deventp = NULL;
-               dns_dispatch_removerequest(&client->dispentry, deventp);
-       }
+       if (client->udpsocket != NULL)
+               isc_socket_detach(&client->udpsocket);
+
        if (client->dispatch != NULL)
                dns_dispatch_detach(&client->dispatch);
 
@@ -237,6 +232,7 @@ client_free(ns_client_t *client) {
 
        ns_query_free(client);
        isc_mem_put(client->mctx, client->sendbuf, SEND_BUFFER_SIZE);
+       isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE);
        isc_timer_detach(&client->timer);
 
        if (client->tcpbuf != NULL)
@@ -338,13 +334,14 @@ exit_check(ns_client_t *client) {
                        if (TCP_CLIENT(client))
                                socket = client->tcpsocket;
                        else
-                               socket =
-                               dns_dispatch_getsocket(client->dispatch);
+                               socket = client->udpsocket;
                        isc_socket_cancel(socket, client->task,
                                          ISC_SOCKCANCEL_SEND);
                }
 
-               if (! (client->nsends == 0 && client->references == 0)) {
+               if (! (client->nsends == 0 && client->nrecvs == 0 &&
+                      client->references == 0))
+               {
                        /*
                         * Still waiting for I/O cancel completion.
                         * or lingering references.
@@ -411,16 +408,8 @@ exit_check(ns_client_t *client) {
                if (NS_CLIENTSTATE_READY == client->newstate) {
                        if (TCP_CLIENT(client)) {
                                client_accept(client);
-                       } else {
-                               /*
-                                * Give the processed dispatch event back to
-                                * the dispatch. This tells the dispatch
-                                * that we are ready to receive the next event.
-                                */
-                               dns_dispatch_freeevent(client->dispatch,
-                                                      client->dispentry,
-                                                      &client->dispevent);
-                       }
+                       } else
+                               client_udprecv(client);
                        client->newstate = NS_CLIENTSTATE_MAX;
                        return (ISC_TRUE);
                }
@@ -440,6 +429,16 @@ exit_check(ns_client_t *client) {
                        return (ISC_TRUE);
                }
                /* Accept cancel is complete. */
+
+               if (client->nrecvs > 0)
+                       isc_socket_cancel(client->udpsocket, client->task,
+                                         ISC_SOCKCANCEL_RECV);
+               if (! (client->nrecvs == 0)) {
+                       /* Still waiting for recv cancel completion. */
+                       return (ISC_TRUE);
+               }
+               /* Recv cancel is complete. */
+
                client_deactivate(client);
                client->state = NS_CLIENTSTATE_INACTIVE;
                INSIST(client->recursionquota == NULL);
@@ -468,7 +467,6 @@ exit_check(ns_client_t *client) {
 static void
 client_start(isc_task_t *task, isc_event_t *event) {
        ns_client_t *client = (ns_client_t *) event->ev_arg;
-       isc_result_t result;
 
        INSIST(task == client->task);
 
@@ -477,25 +475,7 @@ client_start(isc_task_t *task, isc_event_t *event) {
        if (TCP_CLIENT(client)) {
                client_accept(client);
        } else {
-               result = dns_dispatch_addrequest(client->dispatch,
-                                                client->task,
-                                                client_request,
-                                                client,
-                                                &client->dispentry);
-
-               if (result != ISC_R_SUCCESS) {
-                       ns_client_log(client,
-                                     DNS_LOGCATEGORY_SECURITY,
-                                     NS_LOGMODULE_CLIENT,
-                                     ISC_LOG_DEBUG(3),
-                                     "dns_dispatch_addrequest() "
-                                     "failed: %s",
-                                     isc_result_totext(result));
-                       /*
-                        * Not much we can do here but log the failure;
-                        * the client will effectively go idle.
-                        */
-               }
+               client_udprecv(client);
        }
 }
 
@@ -535,6 +515,7 @@ ns_client_endrequest(ns_client_t *client) {
        INSIST(client->naccepts == 0);
        INSIST(client->nreads == 0);
        INSIST(client->nsends == 0);
+       INSIST(client->nrecvs == 0);
        INSIST(client->state == NS_CLIENTSTATE_WORKING);
 
        CTRACE("endrequest");
@@ -731,8 +712,8 @@ client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) {
                socket = client->tcpsocket;
                address = NULL;
        } else {
-               socket = dns_dispatch_getsocket(client->dispatch);
-               address = &client->dispevent->addr;
+               socket = client->udpsocket;
+               address = &client->peeraddr;
 
                isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
                if (ns_g_server->blackholeacl != NULL &&
@@ -1135,16 +1116,17 @@ client_getoptattrs(ns_client_t *client, dns_rdataset_t *opt) {
 
 
 /*
- * Handle an incoming request event from the dispatch (UDP case)
+ * Handle an incoming request event from the socket (UDP case)
  * or tcpmsg (TCP case).
  */
 static void
 client_request(isc_task_t *task, isc_event_t *event) {
        ns_client_t *client;
-       dns_dispatchevent_t *devent;
+       isc_socketevent_t *sevent;
        isc_result_t result;
        isc_result_t sigresult;
        isc_buffer_t *buffer;
+       isc_buffer_t tbuffer;
        dns_view_t *view;
        dns_rdataset_t *opt;
        isc_boolean_t ra;       /* Recursion available. */
@@ -1166,21 +1148,22 @@ client_request(isc_task_t *task, isc_event_t *event) {
        RWLOCK(&ns_g_server->conflock, isc_rwlocktype_read);
        dns_zonemgr_lockconf(ns_g_server->zonemgr, isc_rwlocktype_read);
 
-       if (event->ev_type == DNS_EVENT_DISPATCH) {
+       if (event->ev_type == ISC_SOCKEVENT_RECVDONE) {
                INSIST(!TCP_CLIENT(client));
-               devent = (dns_dispatchevent_t *)event;
-               REQUIRE(client->dispentry != NULL);
-               client->dispevent = devent;
-               buffer = &devent->buffer;
-               result = devent->result;
-               client->peeraddr = devent->addr;
+               sevent = (isc_socketevent_t *)event;
+               isc_buffer_init(&tbuffer, sevent->region.base, sevent->n);
+               isc_buffer_add(&tbuffer, sevent->n);
+               buffer = &tbuffer;
+               result = sevent->result;
+               client->peeraddr = sevent->address;
                client->peeraddr_valid = ISC_TRUE;
-               if ((devent->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) {
+               if ((sevent->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) {
                        client->attributes |= NS_CLIENTATTR_PKTINFO;
-                       client->pktinfo = devent->pktinfo;
+                       client->pktinfo = sevent->pktinfo;
                }
-               if ((devent->attributes & ISC_SOCKEVENTATTR_MULTICAST) != 0)
+               if ((sevent->attributes & ISC_SOCKEVENTATTR_MULTICAST) != 0)
                        client->attributes |= NS_CLIENTATTR_MULTICAST;
+               client->nrecvs--;
        } else {
                INSIST(TCP_CLIENT(client));
                REQUIRE(event->ev_type == DNS_EVENT_TCPMSG);
@@ -1232,14 +1215,20 @@ client_request(isc_task_t *task, isc_event_t *event) {
        }
 
        /*
-        * We expect a query, not a response.  Unexpected UDP responses
-        * are discarded early by the dispatcher, but TCP responses
-        * bypass the dispatcher and must be discarded here.
+        * We expect a query, not a response.  If this is a UDP response,
+        * forward it to the dispatcher.  If it's a TCP response,
+        * discarded it here.
         */
        if ((client->message->flags & DNS_MESSAGEFLAG_QR) != 0) {
-               CTRACE("unexpected response");
-               ns_client_next(client, DNS_R_FORMERR);
-               goto cleanup_serverlock;
+               if (TCP_CLIENT(client)) {
+                       CTRACE("unexpected response");
+                       ns_client_next(client, DNS_R_FORMERR);
+                       goto cleanup_serverlock;
+               } else {
+                       dns_dispatch_importrecv(client->dispatch, &event);
+                       ns_client_next(client, ISC_R_SUCCESS);
+                       goto cleanup_serverlock;
+               }
        }
 
        /*
@@ -1546,6 +1535,10 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp)
        if  (client->sendbuf == NULL)
                goto cleanup_message;
 
+       client->recvbuf = isc_mem_get(manager->mctx, RECV_BUFFER_SIZE);
+       if  (client->recvbuf == NULL)
+               goto cleanup_sendbuf;
+
        client->magic = NS_CLIENT_MAGIC;
        client->mctx = manager->mctx;
        client->manager = NULL;
@@ -1554,13 +1547,13 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp)
        client->naccepts = 0;
        client->nreads = 0;
        client->nsends = 0;
+       client->nrecvs = 0;
        client->references = 0;
        client->attributes = 0;
        client->view = NULL;
        client->lockview = NULL;
        client->dispatch = NULL;
-       client->dispentry = NULL;
-       client->dispevent = NULL;
+       client->udpsocket = NULL;
        client->tcplistener = NULL;
        client->tcpsocket = NULL;
        client->tcpmsg_valid = ISC_FALSE;
@@ -1594,7 +1587,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp)
         */
        result = ns_query_init(client);
        if (result != ISC_R_SUCCESS)
-               goto cleanup_sendbuf;
+               goto cleanup_recvbuf;
 
        CTRACE("create");
 
@@ -1602,6 +1595,9 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp)
 
        return (ISC_R_SUCCESS);
 
+ cleanup_recvbuf:
+       isc_mem_put(manager->mctx, client->recvbuf, RECV_BUFFER_SIZE);
+
  cleanup_sendbuf:
        isc_mem_put(manager->mctx, client->sendbuf, SEND_BUFFER_SIZE);
 
@@ -1782,6 +1778,34 @@ client_accept(ns_client_t *client) {
        UNLOCK(&client->interface->lock);
 }
 
+static void
+client_udprecv(ns_client_t *client) {
+       isc_result_t result;
+       isc_region_t r;
+
+       CTRACE("udprecv");
+
+       r.base = client->recvbuf;
+       r.length = RECV_BUFFER_SIZE;
+       result = isc_socket_recv(client->udpsocket, &r, 1,
+                                client->task, client_request, client);
+       if (result != ISC_R_SUCCESS) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_socket_recv() failed: %s",
+                                isc_result_totext(result));
+               /*
+                * XXXBEW  What should we do?  We're trying to accept but
+                *         it didn't work.  If we just give up, then UDP
+                *         service may eventually stop.
+                *
+                *         For now, we just go idle.
+                */
+               return;
+       }
+       INSIST(client->nrecvs == 0);
+       client->nrecvs++;
+}
+
 void
 ns_client_attach(ns_client_t *source, ns_client_t **targetp) {
        REQUIRE(NS_CLIENT_VALID(source));
@@ -1972,8 +1996,12 @@ ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n,
                        isc_socket_attach(ifp->tcpsocket,
                                          &client->tcplistener);
                } else {
+                       isc_socket_t *sock;
+
                        dns_dispatch_attach(ifp->udpdispatch,
                                            &client->dispatch);
+                       sock = dns_dispatch_getsocket(client->dispatch);
+                       isc_socket_attach(sock, &client->udpsocket);
                }
                client->manager = manager;
                ISC_LIST_APPEND(manager->active, client, link);
index c1ba4c0485ca043da8923e2cb7555c01f4d1725b..62ba9ffbe98692b515f655243d39915925f5a3d3 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: client.h,v 1.49 2001/01/09 21:40:12 bwelling Exp $ */
+/* $Id: client.h,v 1.50 2001/01/27 02:08:03 bwelling Exp $ */
 
 #ifndef NAMED_CLIENT_H
 #define NAMED_CLIENT_H 1
@@ -93,14 +93,14 @@ struct ns_client {
        int                     naccepts;
        int                     nreads;
        int                     nsends;
+       int                     nrecvs;
        int                     references;
        unsigned int            attributes;
        isc_task_t *            task;
        dns_view_t *            view;
        dns_view_t *            lockview;
        dns_dispatch_t *        dispatch;
-       dns_dispentry_t *       dispentry;
-       dns_dispatchevent_t *   dispevent;
+       isc_socket_t *          udpsocket;
        isc_socket_t *          tcplistener;
        isc_socket_t *          tcpsocket;
        unsigned char *         tcpbuf;
@@ -109,6 +109,7 @@ struct ns_client {
        isc_timer_t *           timer;
        dns_message_t *         message;
        unsigned char *         sendbuf;
+       unsigned char *         recvbuf;
        dns_rdataset_t *        opt;
        isc_uint16_t            udpsize;
        isc_uint16_t            extflags;
index 233c47c598f013717f0b84b439ce77de398db245..e6c61680281ec698189172d6a2644abdc4bbde6c 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: interfacemgr.c,v 1.55 2001/01/09 21:39:42 bwelling Exp $ */
+/* $Id: interfacemgr.c,v 1.56 2001/01/27 02:08:01 bwelling Exp $ */
 
 #include <config.h>
 
@@ -244,6 +244,7 @@ ns_interface_listenudp(ns_interface_t *ifp) {
                attrs |= DNS_DISPATCHATTR_IPV4;
        else
                attrs |= DNS_DISPATCHATTR_IPV6;
+       attrs |= DNS_DISPATCHATTR_NOLISTEN;
        attrmask = 0;
        attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
        attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
@@ -269,6 +270,8 @@ ns_interface_listenudp(ns_interface_t *ifp) {
        return (ISC_R_SUCCESS);
 
  addtodispatch_failure:
+       dns_dispatch_changeattributes(ifp->udpdispatch, 0,
+                                     DNS_DISPATCHATTR_NOLISTEN);
        dns_dispatch_detach(&ifp->udpdispatch);
  udp_dispatch_failure:
        return (result);
@@ -373,8 +376,11 @@ ns_interface_destroy(ns_interface_t *ifp) {
 
        ns_interface_shutdown(ifp);
 
-       if (ifp->udpdispatch != NULL)
+       if (ifp->udpdispatch != NULL) {
+               dns_dispatch_changeattributes(ifp->udpdispatch, 0,
+                                             DNS_DISPATCHATTR_NOLISTEN);
                dns_dispatch_detach(&ifp->udpdispatch);
+       }
        if (ifp->tcpsocket != NULL)
                isc_socket_detach(&ifp->tcpsocket);
 
index bc661b8bb20686da5491341666c930d69b4200bd..904501e3df3ff63cff86b5c3f8d47cac21b601a3 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dispatch.c,v 1.85 2001/01/25 13:52:32 gson Exp $ */
+/* $Id: dispatch.c,v 1.86 2001/01/27 02:08:04 bwelling Exp $ */
 
 #include <config.h>
 
@@ -109,6 +109,7 @@ struct dns_dispatch {
        isc_sockaddr_t          local;          /* local address */
        unsigned int            maxrequests;    /* max requests */
        dns_acl_t              *blackhole;
+       isc_event_t            *ctlevent;
 
        /* Locked by mgr->lock. */
        ISC_LINK(dns_dispatch_t) link;
@@ -156,7 +157,7 @@ struct dns_dispatch {
 static dns_dispentry_t *bucket_search(dns_qid_t *, isc_sockaddr_t *,
                                      dns_messageid_t, unsigned int);
 static isc_boolean_t destroy_disp_ok(dns_dispatch_t *);
-static void destroy_disp(dns_dispatch_t **);
+static void destroy_disp(isc_task_t *task, isc_event_t *event);
 static void udp_recv(isc_task_t *, isc_event_t *);
 static void tcp_recv(isc_task_t *, isc_event_t *);
 static inline void startrecv(dns_dispatch_t *);
@@ -376,14 +377,19 @@ destroy_disp_ok(dns_dispatch_t *disp)
  * The manager must be locked.
  */
 static void
-destroy_disp(dns_dispatch_t **dispp) {
-       dns_dispatchmgr_t *mgr;
+destroy_disp(isc_task_t *task, isc_event_t *event) {
        dns_dispatch_t *disp;
+       dns_dispatchmgr_t *mgr;
+       isc_boolean_t killmgr;
 
-       disp = *dispp;
-       *dispp = NULL;
+       INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL);
+
+       UNUSED(task);
+
+       disp = event->ev_arg;
        mgr = disp->mgr;
 
+       LOCK(&mgr->lock);
        ISC_LIST_UNLINK(mgr->list, disp, link);
 
        dispatch_log(disp, LVL(90),
@@ -392,8 +398,14 @@ destroy_disp(dns_dispatch_t **dispp) {
 
        isc_socket_detach(&disp->socket);
        isc_task_detach(&disp->task);
+       isc_event_free(&event);
 
        dispatch_free(&disp);
+
+       killmgr = destroy_mgr_ok(mgr);
+       UNLOCK(&mgr->lock);
+       if (killmgr)
+               destroy_mgr(&mgr);
 }
 
 
@@ -537,8 +549,10 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
                     "got packet: requests %d, buffers %d, recvs %d",
                     disp->requests, disp->mgr->buffers, disp->recv_pending);
 
-       INSIST(disp->recv_pending != 0);
-       disp->recv_pending = 0;
+       if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) {
+               INSIST(disp->recv_pending != 0);
+               disp->recv_pending = 0;
+       }
 
        if (disp->shutting_down) {
                /*
@@ -551,14 +565,8 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
 
                killit = destroy_disp_ok(disp);
                UNLOCK(&disp->lock);
-               if (killit) {
-                       LOCK(&mgr->lock);
-                       destroy_disp(&disp);
-                       killit = destroy_mgr_ok(mgr);
-                       UNLOCK(&mgr->lock);
-                       if (killit)
-                               destroy_mgr(&mgr);
-               }
+               if (killit)
+                       isc_task_send(disp->task, &disp->ctlevent);
 
                return;
        }
@@ -800,14 +808,8 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
                 */
                killit = destroy_disp_ok(disp);
                UNLOCK(&disp->lock);
-               if (killit) {
-                       LOCK(&mgr->lock);
-                       destroy_disp(&disp);
-                       killit = destroy_mgr_ok(mgr);
-                       UNLOCK(&mgr->lock);
-                       if (killit)
-                               destroy_mgr(&mgr);
-               }
+               if (killit)
+                       isc_task_send(disp->task, &disp->ctlevent);
                return;
        }
 
@@ -921,6 +923,9 @@ startrecv(dns_dispatch_t *disp) {
        if (disp->shutting_down == 1)
                return;
 
+       if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
+               return;
+
        if (disp->recv_pending != 0)
                return;
 
@@ -1560,6 +1565,13 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
        if (result != ISC_R_SUCCESS)
                goto kill_socket;
 
+       disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
+                                           DNS_EVENT_DISPATCHCONTROL,
+                                           destroy_disp, disp,
+                                           sizeof(isc_event_t));
+       if (disp->ctlevent == NULL)
+               goto kill_task;
+
        isc_task_setname(disp->task, "tcpdispatch", disp);
 
        dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg);
@@ -1583,6 +1595,8 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
        /*
         * Error returns.
         */
+ kill_task:
+       isc_task_detach(&disp->task);
  kill_socket:
        isc_socket_detach(&disp->socket);
  deallocate_dispatch:
@@ -1634,6 +1648,13 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
                if (disp->maxrequests < maxrequests)
                        disp->maxrequests = maxrequests;
 
+               if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0 &&
+                   (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
+                       disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
+                       if (disp->recv_pending > 0)
+                               isc_socket_cancel(disp->socket, NULL,
+                                                 ISC_SOCKCANCEL_RECV);
+
                UNLOCK(&disp->lock);
                UNLOCK(&mgr->lock);
 
@@ -1693,6 +1714,13 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
        if (result != ISC_R_SUCCESS)
                goto kill_socket;
 
+       disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
+                                           DNS_EVENT_DISPATCHCONTROL,
+                                           destroy_disp, disp,
+                                           sizeof(isc_event_t));
+       if (disp->ctlevent == NULL)
+               goto kill_task;
+
        isc_task_setname(disp->task, "udpdispatch", disp);
 
        attributes &= ~DNS_DISPATCHATTR_TCP;
@@ -1715,6 +1743,8 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
        /*
         * Error returns.
         */
+ kill_task:
+       isc_task_detach(&disp->task);
  kill_socket:
        isc_socket_detach(&disp->socket);
  deallocate_dispatch:
@@ -1771,14 +1801,8 @@ dns_dispatch_detach(dns_dispatch_t **dispp) {
 
        killit = destroy_disp_ok(disp);
        UNLOCK(&disp->lock);
-       if (killit) {
-               LOCK(&mgr->lock);
-               destroy_disp(&disp);
-               killit = destroy_mgr_ok(mgr);
-               UNLOCK(&mgr->lock);
-               if (killit)
-                       destroy_mgr(&mgr);
-       }
+       if (killit)
+               isc_task_send(disp->task, &disp->ctlevent);
 }
 
 isc_result_t
@@ -1988,13 +2012,8 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp,
 
        killit = destroy_disp_ok(disp);
        UNLOCK(&disp->lock);
-       if (killit) {
-               destroy_disp(&disp);
-               killit = destroy_mgr_ok(mgr);
-               UNLOCK(&mgr->lock);
-               if (killit)
-                       destroy_mgr(&mgr);
-       }
+       if (killit)
+               isc_task_send(disp->task, &disp->ctlevent);
 }
 
 isc_result_t
@@ -2138,13 +2157,8 @@ dns_dispatch_removerequest(dns_dispentry_t **resp,
 
        killit = destroy_disp_ok(disp);
        UNLOCK(&disp->lock);
-       if (killit) {
-               destroy_disp(&disp);
-               killit = destroy_mgr_ok(mgr);
-               UNLOCK(&mgr->lock);
-               if (killit)
-                       destroy_mgr(&mgr);
-       }
+       if (killit)
+               isc_task_send(disp->task, &disp->ctlevent);
 }
 
 void
@@ -2344,11 +2358,45 @@ dns_dispatch_changeattributes(dns_dispatch_t *disp,
         */
 
        LOCK(&disp->lock);
+
+       if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 &&
+           (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0)
+       {
+               disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN;
+               startrecv(disp);
+       }
+
        disp->attributes &= ~mask;
        disp->attributes |= (attributes & mask);
        UNLOCK(&disp->lock);
 }
 
+void
+dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t **eventp) {
+       void *buf;
+       isc_socketevent_t *sevent;
+
+       REQUIRE(VALID_DISPATCH(disp));
+       REQUIRE((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0);
+       REQUIRE(eventp != NULL && *eventp != NULL);
+
+       sevent = (isc_socketevent_t *)*eventp;
+
+       INSIST(sevent->n <= disp->mgr->buffersize);
+       buf = allocate_udp_buffer(disp);
+       if (buf == NULL) {
+               isc_event_free(eventp);
+               return;
+       }
+       memcpy(buf, sevent->region.base, sevent->n);
+       sevent->region.base = buf;
+       sevent->region.length = disp->mgr->buffersize;
+       sevent->ev_action = udp_recv;
+       sevent->ev_arg = disp;
+       sevent->ev_sender = NULL;
+       isc_task_send(disp->task, eventp);
+}
+
 #if 0
 void
 dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) {
index 90706b8478630aa94b33a9bef845d11aa23edf5e..1f26167db24a238eb898ba0038b7d287156c8725 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dispatch.h,v 1.38 2001/01/09 21:52:47 bwelling Exp $ */
+/* $Id: dispatch.h,v 1.39 2001/01/27 02:08:06 bwelling Exp $ */
 
 #ifndef DNS_DISPATCH_H
 #define DNS_DISPATCH_H 1
@@ -105,8 +105,8 @@ struct dns_dispatchevent {
  * _IPV4, _IPV6
  *     The dispatcher uses an ipv4 or ipv6 socket.
  *
- * _ACCEPTREQUEST
- *     The dispatcher can be used to accept requests.
+ * _NOLISTEN
+ *     The dispatcher should not listen on the socket.
  *
  * _MAKEQUERY
  *     The dispatcher can be used to issue queries to other servers, and
@@ -117,7 +117,7 @@ struct dns_dispatchevent {
 #define DNS_DISPATCHATTR_UDP           0x00000004U
 #define DNS_DISPATCHATTR_IPV4          0x00000008U
 #define DNS_DISPATCHATTR_IPV6          0x00000010U
-#define DNS_DISPATCHATTR_ACCEPTREQUEST 0x00000020U
+#define DNS_DISPATCHATTR_NOLISTEN      0x00000020U
 #define DNS_DISPATCHATTR_MAKEQUERY     0x00000040U
 #define DNS_DISPATCHATTR_CONNECTED     0x00000080U
 
@@ -462,6 +462,18 @@ dns_dispatch_changeattributes(dns_dispatch_t *disp,
  *     attribute on a TCP socket isn't reasonable.
  */
 
+void
+dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t **eventp);
+/*
+ * Give a socket receive event to the dispatcher.  This is used for sockets
+ * shared between dispatchers and clients.  If the dispatcher fails to send
+ * the event, it frees it.
+ *
+ * Requires:
+ *     disp is valid, and the attribute DNS_DISPATCHATTR_NOLISTEN is set.
+ *     eventp != NULL && *eventp != NULL
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_DISPATCH_H */
index 8747e810d98a3acfc9457d5e062fdfc077a00252..5886de7a266d7f105330e12f90d3ce2a088cd9f5 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: events.h,v 1.35 2001/01/19 22:22:17 bwelling Exp $ */
+/* $Id: events.h,v 1.36 2001/01/27 02:08:07 bwelling Exp $ */
 
 #ifndef DNS_EVENTS_H
 #define DNS_EVENTS_H 1
@@ -58,6 +58,7 @@
 #define DNS_EVENT_IOREADY                      (ISC_EVENTCLASS_DNS + 29)
 #define DNS_EVENT_LOOKUPDONE                   (ISC_EVENTCLASS_DNS + 30)
 #define DNS_EVENT_QUERYABORTED                 (ISC_EVENTCLASS_DNS + 31)
+#define DNS_EVENT_DISPATCHCONTROL              (ISC_EVENTCLASS_DNS + 32)
 
 #define DNS_EVENT_FIRSTEVENT                   (ISC_EVENTCLASS_DNS + 0)
 #define DNS_EVENT_LASTEVENT                    (ISC_EVENTCLASS_DNS + 65535)