00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <isc/socket.h>
00025 #include <isc/string.h>
00026 #include <isc/task.h>
00027 #include <isc/util.h>
00028
00029 #include <dns/adb.h>
00030 #include <dns/view.h>
00031 #include <dns/log.h>
00032
00033 #include <named/types.h>
00034 #include <named/log.h>
00035 #include <named/lwresd.h>
00036 #include <named/lwdclient.h>
00037
00038 #define SHUTTINGDOWN(cm) ((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) != 0)
00039
00040 static void
00041 lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev);
00042
00043 void
00044 ns_lwdclient_log(int level, const char *format, ...) {
00045 va_list args;
00046
00047 va_start(args, format);
00048 isc_log_vwrite(dns_lctx,
00049 DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
00050 ISC_LOG_DEBUG(level), format, args);
00051 va_end(args);
00052 }
00053
00054 isc_result_t
00055 ns_lwdclientmgr_create(ns_lwreslistener_t *listener, unsigned int nclients,
00056 isc_taskmgr_t *taskmgr)
00057 {
00058 ns_lwresd_t *lwresd = listener->manager;
00059 ns_lwdclientmgr_t *cm;
00060 ns_lwdclient_t *client;
00061 unsigned int i;
00062 isc_result_t result = ISC_R_FAILURE;
00063
00064 cm = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclientmgr_t));
00065 if (cm == NULL)
00066 return (ISC_R_NOMEMORY);
00067
00068 cm->listener = NULL;
00069 ns_lwreslistener_attach(listener, &cm->listener);
00070 cm->mctx = lwresd->mctx;
00071 cm->sock = NULL;
00072 isc_socket_attach(listener->sock, &cm->sock);
00073 cm->view = lwresd->view;
00074 cm->lwctx = NULL;
00075 cm->task = NULL;
00076 cm->flags = 0;
00077 ISC_LINK_INIT(cm, link);
00078 ISC_LIST_INIT(cm->idle);
00079 ISC_LIST_INIT(cm->running);
00080
00081 if (lwres_context_create(&cm->lwctx, cm->mctx,
00082 ns__lwresd_memalloc, ns__lwresd_memfree,
00083 LWRES_CONTEXT_SERVERMODE)
00084 != ISC_R_SUCCESS)
00085 goto errout;
00086
00087 for (i = 0; i < nclients; i++) {
00088 client = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclient_t));
00089 if (client != NULL) {
00090 ns_lwdclient_log(50, "created client %p, manager %p",
00091 client, cm);
00092 ns_lwdclient_initialize(client, cm);
00093 }
00094 }
00095
00096
00097
00098
00099 if (ISC_LIST_EMPTY(cm->idle))
00100 goto errout;
00101
00102 result = isc_task_create(taskmgr, 0, &cm->task);
00103 if (result != ISC_R_SUCCESS)
00104 goto errout;
00105 isc_task_setname(cm->task, "lwdclient", NULL);
00106
00107
00108
00109
00110 result = isc_task_onshutdown(cm->task, lwdclientmgr_shutdown_callback,
00111 cm);
00112 if (result != ISC_R_SUCCESS)
00113 goto errout;
00114
00115 ns_lwreslistener_linkcm(listener, cm);
00116
00117 return (ISC_R_SUCCESS);
00118
00119 errout:
00120 client = ISC_LIST_HEAD(cm->idle);
00121 while (client != NULL) {
00122 ISC_LIST_UNLINK(cm->idle, client, link);
00123 isc_mem_put(lwresd->mctx, client, sizeof(*client));
00124 client = ISC_LIST_HEAD(cm->idle);
00125 }
00126
00127 if (cm->task != NULL)
00128 isc_task_detach(&cm->task);
00129
00130 if (cm->lwctx != NULL)
00131 lwres_context_destroy(&cm->lwctx);
00132
00133 isc_mem_put(lwresd->mctx, cm, sizeof(*cm));
00134 return (result);
00135 }
00136
00137 static void
00138 lwdclientmgr_destroy(ns_lwdclientmgr_t *cm) {
00139 ns_lwdclient_t *client;
00140 ns_lwreslistener_t *listener;
00141
00142 if (!SHUTTINGDOWN(cm))
00143 return;
00144
00145
00146
00147
00148
00149
00150 client = ISC_LIST_HEAD(cm->idle);
00151 while (client != NULL) {
00152 ns_lwdclient_log(50, "destroying client %p, manager %p",
00153 client, cm);
00154 ISC_LIST_UNLINK(cm->idle, client, link);
00155 isc_mem_put(cm->mctx, client, sizeof(*client));
00156 client = ISC_LIST_HEAD(cm->idle);
00157 }
00158
00159 if (!ISC_LIST_EMPTY(cm->running))
00160 return;
00161
00162 lwres_context_destroy(&cm->lwctx);
00163 cm->view = NULL;
00164 isc_socket_detach(&cm->sock);
00165 isc_task_detach(&cm->task);
00166
00167 listener = cm->listener;
00168 ns_lwreslistener_unlinkcm(listener, cm);
00169 ns_lwdclient_log(50, "destroying manager %p", cm);
00170 isc_mem_put(cm->mctx, cm, sizeof(*cm));
00171 ns_lwreslistener_detach(&listener);
00172 }
00173
00174 static void
00175 process_request(ns_lwdclient_t *client) {
00176 lwres_buffer_t b;
00177 isc_result_t result;
00178
00179 lwres_buffer_init(&b, client->buffer, client->recvlength);
00180 lwres_buffer_add(&b, client->recvlength);
00181
00182 result = lwres_lwpacket_parseheader(&b, &client->pkt);
00183 if (result != ISC_R_SUCCESS) {
00184 ns_lwdclient_log(50, "invalid packet header received");
00185 goto restart;
00186 }
00187
00188 ns_lwdclient_log(50, "opcode %08x", client->pkt.opcode);
00189
00190 switch (client->pkt.opcode) {
00191 case LWRES_OPCODE_GETADDRSBYNAME:
00192 ns_lwdclient_processgabn(client, &b);
00193 return;
00194 case LWRES_OPCODE_GETNAMEBYADDR:
00195 ns_lwdclient_processgnba(client, &b);
00196 return;
00197 case LWRES_OPCODE_GETRDATABYNAME:
00198 ns_lwdclient_processgrbn(client, &b);
00199 return;
00200 case LWRES_OPCODE_NOOP:
00201 ns_lwdclient_processnoop(client, &b);
00202 return;
00203 default:
00204 ns_lwdclient_log(50, "unknown opcode %08x", client->pkt.opcode);
00205 goto restart;
00206 }
00207
00208
00209
00210
00211 restart:
00212 ns_lwdclient_log(50, "restarting client %p...", client);
00213 ns_lwdclient_stateidle(client);
00214 }
00215
00216 void
00217 ns_lwdclient_recv(isc_task_t *task, isc_event_t *ev) {
00218 isc_result_t result;
00219 ns_lwdclient_t *client = ev->ev_arg;
00220 ns_lwdclientmgr_t *cm = client->clientmgr;
00221 isc_socketevent_t *dev = (isc_socketevent_t *)ev;
00222
00223 INSIST(dev->region.base == client->buffer);
00224 INSIST(NS_LWDCLIENT_ISRECV(client));
00225
00226 NS_LWDCLIENT_SETRECVDONE(client);
00227
00228 INSIST((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0);
00229 cm->flags &= ~NS_LWDCLIENTMGR_FLAGRECVPENDING;
00230
00231 ns_lwdclient_log(50,
00232 "event received: task %p, length %u, result %u (%s)",
00233 task, dev->n, dev->result,
00234 isc_result_totext(dev->result));
00235
00236 if (dev->result != ISC_R_SUCCESS) {
00237 isc_event_free(&ev);
00238 dev = NULL;
00239
00240
00241
00242
00243 ns_lwdclient_stateidle(client);
00244
00245 return;
00246 }
00247
00248 client->recvlength = dev->n;
00249 client->address = dev->address;
00250 if ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) {
00251 client->pktinfo = dev->pktinfo;
00252 client->pktinfo_valid = ISC_TRUE;
00253 } else
00254 client->pktinfo_valid = ISC_FALSE;
00255 isc_event_free(&ev);
00256 dev = NULL;
00257
00258 result = ns_lwdclient_startrecv(cm);
00259 if (result != ISC_R_SUCCESS)
00260 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00261 NS_LOGMODULE_LWRESD, ISC_LOG_ERROR,
00262 "could not start lwres "
00263 "client handler: %s",
00264 isc_result_totext(result));
00265
00266 process_request(client);
00267 }
00268
00269
00270
00271
00272 isc_result_t
00273 ns_lwdclient_startrecv(ns_lwdclientmgr_t *cm) {
00274 ns_lwdclient_t *client;
00275 isc_result_t result;
00276 isc_region_t r;
00277
00278 if (SHUTTINGDOWN(cm)) {
00279 lwdclientmgr_destroy(cm);
00280 return (ISC_R_SUCCESS);
00281 }
00282
00283
00284
00285
00286 if ((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0)
00287 return (ISC_R_SUCCESS);
00288
00289
00290
00291
00292 client = ISC_LIST_HEAD(cm->idle);
00293 if (client == NULL)
00294 return (ISC_R_SUCCESS);
00295 INSIST(NS_LWDCLIENT_ISIDLE(client));
00296
00297
00298
00299
00300 r.base = client->buffer;
00301 r.length = LWRES_RECVLENGTH;
00302 result = isc_socket_recv(cm->sock, &r, 0, cm->task, ns_lwdclient_recv,
00303 client);
00304 if (result != ISC_R_SUCCESS)
00305 return (result);
00306
00307
00308
00309
00310 cm->flags |= NS_LWDCLIENTMGR_FLAGRECVPENDING;
00311
00312
00313
00314
00315
00316 NS_LWDCLIENT_SETRECV(client);
00317 ISC_LIST_UNLINK(cm->idle, client, link);
00318 ISC_LIST_APPEND(cm->running, client, link);
00319
00320 return (ISC_R_SUCCESS);
00321 }
00322
00323 static void
00324 lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev) {
00325 ns_lwdclientmgr_t *cm = ev->ev_arg;
00326 ns_lwdclient_t *client;
00327
00328 REQUIRE(!SHUTTINGDOWN(cm));
00329
00330 ns_lwdclient_log(50, "got shutdown event, task %p, lwdclientmgr %p",
00331 task, cm);
00332
00333
00334
00335
00336
00337
00338 client = ISC_LIST_HEAD(cm->idle);
00339 while (client != NULL) {
00340 ns_lwdclient_log(50, "destroying client %p, manager %p",
00341 client, cm);
00342 ISC_LIST_UNLINK(cm->idle, client, link);
00343 isc_mem_put(cm->mctx, client, sizeof(*client));
00344 client = ISC_LIST_HEAD(cm->idle);
00345 }
00346
00347
00348
00349
00350 isc_socket_cancel(cm->sock, task, ISC_SOCKCANCEL_ALL);
00351
00352
00353
00354
00355
00356 client = ISC_LIST_HEAD(cm->running);
00357 while (client != NULL) {
00358 if (client->find != client->v4find
00359 && client->find != client->v6find)
00360 dns_adb_cancelfind(client->find);
00361 if (client->v4find != NULL)
00362 dns_adb_cancelfind(client->v4find);
00363 if (client->v6find != NULL)
00364 dns_adb_cancelfind(client->v6find);
00365 client = ISC_LIST_NEXT(client, link);
00366 }
00367
00368 cm->flags |= NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN;
00369
00370 isc_event_free(&ev);
00371 }
00372
00373
00374
00375
00376
00377 void
00378 ns_lwdclient_stateidle(ns_lwdclient_t *client) {
00379 ns_lwdclientmgr_t *cm;
00380 isc_result_t result;
00381
00382 cm = client->clientmgr;
00383
00384 INSIST(client->sendbuf == NULL);
00385 INSIST(client->sendlength == 0);
00386 INSIST(client->arg == NULL);
00387 INSIST(client->v4find == NULL);
00388 INSIST(client->v6find == NULL);
00389
00390 ISC_LIST_UNLINK(cm->running, client, link);
00391 ISC_LIST_PREPEND(cm->idle, client, link);
00392
00393 NS_LWDCLIENT_SETIDLE(client);
00394
00395 result = ns_lwdclient_startrecv(cm);
00396 if (result != ISC_R_SUCCESS)
00397 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00398 NS_LOGMODULE_LWRESD, ISC_LOG_ERROR,
00399 "could not start lwres "
00400 "client handler: %s",
00401 isc_result_totext(result));
00402 }
00403
00404 void
00405 ns_lwdclient_send(isc_task_t *task, isc_event_t *ev) {
00406 ns_lwdclient_t *client = ev->ev_arg;
00407 ns_lwdclientmgr_t *cm = client->clientmgr;
00408 isc_socketevent_t *dev = (isc_socketevent_t *)ev;
00409
00410 UNUSED(task);
00411 UNUSED(dev);
00412
00413 INSIST(NS_LWDCLIENT_ISSEND(client));
00414 INSIST(client->sendbuf == dev->region.base);
00415
00416 ns_lwdclient_log(50, "task %p for client %p got send-done event",
00417 task, client);
00418
00419 if (client->sendbuf != client->buffer)
00420 lwres_context_freemem(cm->lwctx, client->sendbuf,
00421 client->sendlength);
00422 client->sendbuf = NULL;
00423 client->sendlength = 0;
00424
00425 ns_lwdclient_stateidle(client);
00426
00427 isc_event_free(&ev);
00428 }
00429
00430 isc_result_t
00431 ns_lwdclient_sendreply(ns_lwdclient_t *client, isc_region_t *r) {
00432 struct in6_pktinfo *pktinfo;
00433 ns_lwdclientmgr_t *cm = client->clientmgr;
00434
00435 if (client->pktinfo_valid)
00436 pktinfo = &client->pktinfo;
00437 else
00438 pktinfo = NULL;
00439 return (isc_socket_sendto(cm->sock, r, cm->task, ns_lwdclient_send,
00440 client, &client->address, pktinfo));
00441 }
00442
00443 void
00444 ns_lwdclient_initialize(ns_lwdclient_t *client, ns_lwdclientmgr_t *cmgr) {
00445 client->clientmgr = cmgr;
00446 ISC_LINK_INIT(client, link);
00447 NS_LWDCLIENT_SETIDLE(client);
00448 client->arg = NULL;
00449
00450 client->recvlength = 0;
00451
00452 client->sendbuf = NULL;
00453 client->sendlength = 0;
00454
00455 client->find = NULL;
00456 client->v4find = NULL;
00457 client->v6find = NULL;
00458 client->find_wanted = 0;
00459
00460 client->options = 0;
00461 client->byaddr = NULL;
00462
00463 client->lookup = NULL;
00464
00465 client->pktinfo_valid = ISC_FALSE;
00466
00467 ISC_LIST_APPEND(cmgr->idle, client, link);
00468 }