turns printfs back on
[freebsd-src/fkvm-freebsd.git] / contrib / bind9 / bin / named / lwdclient.c
blob68069ed2cef47be271d1cfe2df942d1db4b536d5
1 /*
2 * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: lwdclient.c,v 1.17.18.2 2005/04/29 00:15:23 marka Exp $ */
20 /*! \file */
22 #include <config.h>
24 #include <isc/socket.h>
25 #include <isc/string.h>
26 #include <isc/task.h>
27 #include <isc/util.h>
29 #include <dns/adb.h>
30 #include <dns/view.h>
31 #include <dns/log.h>
33 #include <named/types.h>
34 #include <named/log.h>
35 #include <named/lwresd.h>
36 #include <named/lwdclient.h>
38 #define SHUTTINGDOWN(cm) ((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) != 0)
40 static void
41 lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev);
43 void
44 ns_lwdclient_log(int level, const char *format, ...) {
45 va_list args;
47 va_start(args, format);
48 isc_log_vwrite(dns_lctx,
49 DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
50 ISC_LOG_DEBUG(level), format, args);
51 va_end(args);
54 isc_result_t
55 ns_lwdclientmgr_create(ns_lwreslistener_t *listener, unsigned int nclients,
56 isc_taskmgr_t *taskmgr)
58 ns_lwresd_t *lwresd = listener->manager;
59 ns_lwdclientmgr_t *cm;
60 ns_lwdclient_t *client;
61 unsigned int i;
62 isc_result_t result = ISC_R_FAILURE;
64 cm = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclientmgr_t));
65 if (cm == NULL)
66 return (ISC_R_NOMEMORY);
68 cm->listener = NULL;
69 ns_lwreslistener_attach(listener, &cm->listener);
70 cm->mctx = lwresd->mctx;
71 cm->sock = NULL;
72 isc_socket_attach(listener->sock, &cm->sock);
73 cm->view = lwresd->view;
74 cm->lwctx = NULL;
75 cm->task = NULL;
76 cm->flags = 0;
77 ISC_LINK_INIT(cm, link);
78 ISC_LIST_INIT(cm->idle);
79 ISC_LIST_INIT(cm->running);
81 if (lwres_context_create(&cm->lwctx, cm->mctx,
82 ns__lwresd_memalloc, ns__lwresd_memfree,
83 LWRES_CONTEXT_SERVERMODE)
84 != ISC_R_SUCCESS)
85 goto errout;
87 for (i = 0; i < nclients; i++) {
88 client = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclient_t));
89 if (client != NULL) {
90 ns_lwdclient_log(50, "created client %p, manager %p",
91 client, cm);
92 ns_lwdclient_initialize(client, cm);
97 * If we could create no clients, clean up and return.
99 if (ISC_LIST_EMPTY(cm->idle))
100 goto errout;
102 result = isc_task_create(taskmgr, 0, &cm->task);
103 if (result != ISC_R_SUCCESS)
104 goto errout;
107 * This MUST be last, since there is no way to cancel an onshutdown...
109 result = isc_task_onshutdown(cm->task, lwdclientmgr_shutdown_callback,
110 cm);
111 if (result != ISC_R_SUCCESS)
112 goto errout;
114 ns_lwreslistener_linkcm(listener, cm);
116 return (ISC_R_SUCCESS);
118 errout:
119 client = ISC_LIST_HEAD(cm->idle);
120 while (client != NULL) {
121 ISC_LIST_UNLINK(cm->idle, client, link);
122 isc_mem_put(lwresd->mctx, client, sizeof(*client));
123 client = ISC_LIST_HEAD(cm->idle);
126 if (cm->task != NULL)
127 isc_task_detach(&cm->task);
129 if (cm->lwctx != NULL)
130 lwres_context_destroy(&cm->lwctx);
132 isc_mem_put(lwresd->mctx, cm, sizeof(*cm));
133 return (result);
136 static void
137 lwdclientmgr_destroy(ns_lwdclientmgr_t *cm) {
138 ns_lwdclient_t *client;
139 ns_lwreslistener_t *listener;
141 if (!SHUTTINGDOWN(cm))
142 return;
145 * run through the idle list and free the clients there. Idle
146 * clients do not have a recv running nor do they have any finds
147 * or similar running.
149 client = ISC_LIST_HEAD(cm->idle);
150 while (client != NULL) {
151 ns_lwdclient_log(50, "destroying client %p, manager %p",
152 client, cm);
153 ISC_LIST_UNLINK(cm->idle, client, link);
154 isc_mem_put(cm->mctx, client, sizeof(*client));
155 client = ISC_LIST_HEAD(cm->idle);
158 if (!ISC_LIST_EMPTY(cm->running))
159 return;
161 lwres_context_destroy(&cm->lwctx);
162 cm->view = NULL;
163 isc_socket_detach(&cm->sock);
164 isc_task_detach(&cm->task);
166 listener = cm->listener;
167 ns_lwreslistener_unlinkcm(listener, cm);
168 ns_lwdclient_log(50, "destroying manager %p", cm);
169 isc_mem_put(cm->mctx, cm, sizeof(*cm));
170 ns_lwreslistener_detach(&listener);
173 static void
174 process_request(ns_lwdclient_t *client) {
175 lwres_buffer_t b;
176 isc_result_t result;
178 lwres_buffer_init(&b, client->buffer, client->recvlength);
179 lwres_buffer_add(&b, client->recvlength);
181 result = lwres_lwpacket_parseheader(&b, &client->pkt);
182 if (result != ISC_R_SUCCESS) {
183 ns_lwdclient_log(50, "invalid packet header received");
184 goto restart;
187 ns_lwdclient_log(50, "opcode %08x", client->pkt.opcode);
189 switch (client->pkt.opcode) {
190 case LWRES_OPCODE_GETADDRSBYNAME:
191 ns_lwdclient_processgabn(client, &b);
192 return;
193 case LWRES_OPCODE_GETNAMEBYADDR:
194 ns_lwdclient_processgnba(client, &b);
195 return;
196 case LWRES_OPCODE_GETRDATABYNAME:
197 ns_lwdclient_processgrbn(client, &b);
198 return;
199 case LWRES_OPCODE_NOOP:
200 ns_lwdclient_processnoop(client, &b);
201 return;
202 default:
203 ns_lwdclient_log(50, "unknown opcode %08x", client->pkt.opcode);
204 goto restart;
208 * Drop the packet.
210 restart:
211 ns_lwdclient_log(50, "restarting client %p...", client);
212 ns_lwdclient_stateidle(client);
215 void
216 ns_lwdclient_recv(isc_task_t *task, isc_event_t *ev) {
217 isc_result_t result;
218 ns_lwdclient_t *client = ev->ev_arg;
219 ns_lwdclientmgr_t *cm = client->clientmgr;
220 isc_socketevent_t *dev = (isc_socketevent_t *)ev;
222 INSIST(dev->region.base == client->buffer);
223 INSIST(NS_LWDCLIENT_ISRECV(client));
225 NS_LWDCLIENT_SETRECVDONE(client);
227 INSIST((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0);
228 cm->flags &= ~NS_LWDCLIENTMGR_FLAGRECVPENDING;
230 ns_lwdclient_log(50,
231 "event received: task %p, length %u, result %u (%s)",
232 task, dev->n, dev->result,
233 isc_result_totext(dev->result));
235 if (dev->result != ISC_R_SUCCESS) {
236 isc_event_free(&ev);
237 dev = NULL;
240 * Go idle.
242 ns_lwdclient_stateidle(client);
244 return;
247 client->recvlength = dev->n;
248 client->address = dev->address;
249 if ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) {
250 client->pktinfo = dev->pktinfo;
251 client->pktinfo_valid = ISC_TRUE;
252 } else
253 client->pktinfo_valid = ISC_FALSE;
254 isc_event_free(&ev);
255 dev = NULL;
257 result = ns_lwdclient_startrecv(cm);
258 if (result != ISC_R_SUCCESS)
259 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
260 NS_LOGMODULE_LWRESD, ISC_LOG_ERROR,
261 "could not start lwres "
262 "client handler: %s",
263 isc_result_totext(result));
265 process_request(client);
269 * This function will start a new recv() on a socket for this client manager.
271 isc_result_t
272 ns_lwdclient_startrecv(ns_lwdclientmgr_t *cm) {
273 ns_lwdclient_t *client;
274 isc_result_t result;
275 isc_region_t r;
277 if (SHUTTINGDOWN(cm)) {
278 lwdclientmgr_destroy(cm);
279 return (ISC_R_SUCCESS);
283 * If a recv is already running, don't bother.
285 if ((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0)
286 return (ISC_R_SUCCESS);
289 * If we have no idle slots, just return success.
291 client = ISC_LIST_HEAD(cm->idle);
292 if (client == NULL)
293 return (ISC_R_SUCCESS);
294 INSIST(NS_LWDCLIENT_ISIDLE(client));
297 * Issue the recv. If it fails, return that it did.
299 r.base = client->buffer;
300 r.length = LWRES_RECVLENGTH;
301 result = isc_socket_recv(cm->sock, &r, 0, cm->task, ns_lwdclient_recv,
302 client);
303 if (result != ISC_R_SUCCESS)
304 return (result);
307 * Set the flag to say we've issued a recv() call.
309 cm->flags |= NS_LWDCLIENTMGR_FLAGRECVPENDING;
312 * Remove the client from the idle list, and put it on the running
313 * list.
315 NS_LWDCLIENT_SETRECV(client);
316 ISC_LIST_UNLINK(cm->idle, client, link);
317 ISC_LIST_APPEND(cm->running, client, link);
319 return (ISC_R_SUCCESS);
322 static void
323 lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev) {
324 ns_lwdclientmgr_t *cm = ev->ev_arg;
325 ns_lwdclient_t *client;
327 REQUIRE(!SHUTTINGDOWN(cm));
329 ns_lwdclient_log(50, "got shutdown event, task %p, lwdclientmgr %p",
330 task, cm);
333 * run through the idle list and free the clients there. Idle
334 * clients do not have a recv running nor do they have any finds
335 * or similar running.
337 client = ISC_LIST_HEAD(cm->idle);
338 while (client != NULL) {
339 ns_lwdclient_log(50, "destroying client %p, manager %p",
340 client, cm);
341 ISC_LIST_UNLINK(cm->idle, client, link);
342 isc_mem_put(cm->mctx, client, sizeof(*client));
343 client = ISC_LIST_HEAD(cm->idle);
347 * Cancel any pending I/O.
349 isc_socket_cancel(cm->sock, task, ISC_SOCKCANCEL_ALL);
352 * Run through the running client list and kill off any finds
353 * in progress.
355 client = ISC_LIST_HEAD(cm->running);
356 while (client != NULL) {
357 if (client->find != client->v4find
358 && client->find != client->v6find)
359 dns_adb_cancelfind(client->find);
360 if (client->v4find != NULL)
361 dns_adb_cancelfind(client->v4find);
362 if (client->v6find != NULL)
363 dns_adb_cancelfind(client->v6find);
364 client = ISC_LIST_NEXT(client, link);
367 cm->flags |= NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN;
369 isc_event_free(&ev);
373 * Do all the crap needed to move a client from the run queue to the idle
374 * queue.
376 void
377 ns_lwdclient_stateidle(ns_lwdclient_t *client) {
378 ns_lwdclientmgr_t *cm;
379 isc_result_t result;
381 cm = client->clientmgr;
383 INSIST(client->sendbuf == NULL);
384 INSIST(client->sendlength == 0);
385 INSIST(client->arg == NULL);
386 INSIST(client->v4find == NULL);
387 INSIST(client->v6find == NULL);
389 ISC_LIST_UNLINK(cm->running, client, link);
390 ISC_LIST_PREPEND(cm->idle, client, link);
392 NS_LWDCLIENT_SETIDLE(client);
394 result = ns_lwdclient_startrecv(cm);
395 if (result != ISC_R_SUCCESS)
396 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
397 NS_LOGMODULE_LWRESD, ISC_LOG_ERROR,
398 "could not start lwres "
399 "client handler: %s",
400 isc_result_totext(result));
403 void
404 ns_lwdclient_send(isc_task_t *task, isc_event_t *ev) {
405 ns_lwdclient_t *client = ev->ev_arg;
406 ns_lwdclientmgr_t *cm = client->clientmgr;
407 isc_socketevent_t *dev = (isc_socketevent_t *)ev;
409 UNUSED(task);
410 UNUSED(dev);
412 INSIST(NS_LWDCLIENT_ISSEND(client));
413 INSIST(client->sendbuf == dev->region.base);
415 ns_lwdclient_log(50, "task %p for client %p got send-done event",
416 task, client);
418 if (client->sendbuf != client->buffer)
419 lwres_context_freemem(cm->lwctx, client->sendbuf,
420 client->sendlength);
421 client->sendbuf = NULL;
422 client->sendlength = 0;
424 ns_lwdclient_stateidle(client);
426 isc_event_free(&ev);
429 isc_result_t
430 ns_lwdclient_sendreply(ns_lwdclient_t *client, isc_region_t *r) {
431 struct in6_pktinfo *pktinfo;
432 ns_lwdclientmgr_t *cm = client->clientmgr;
434 if (client->pktinfo_valid)
435 pktinfo = &client->pktinfo;
436 else
437 pktinfo = NULL;
438 return (isc_socket_sendto(cm->sock, r, cm->task, ns_lwdclient_send,
439 client, &client->address, pktinfo));
442 void
443 ns_lwdclient_initialize(ns_lwdclient_t *client, ns_lwdclientmgr_t *cmgr) {
444 client->clientmgr = cmgr;
445 ISC_LINK_INIT(client, link);
446 NS_LWDCLIENT_SETIDLE(client);
447 client->arg = NULL;
449 client->recvlength = 0;
451 client->sendbuf = NULL;
452 client->sendlength = 0;
454 client->find = NULL;
455 client->v4find = NULL;
456 client->v6find = NULL;
457 client->find_wanted = 0;
459 client->options = 0;
460 client->byaddr = NULL;
462 client->lookup = NULL;
464 client->pktinfo_valid = ISC_FALSE;
466 ISC_LIST_APPEND(cmgr->idle, client, link);