client.c revision cc1b6f86f2e0bff7e903a4e7d2cd10e6a59b8b9c
ca41b452ede6feaa9d8739ec3cae19389a7b0d03Bob Halley * Copyright (C) 1999 Internet Software Consortium.
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * Permission to use, copy, modify, and distribute this software for any
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * purpose with or without fee is hereby granted, provided that the above
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * copyright notice and this permission notice appear in all copies.
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff#define TCP_CLIENT(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0)
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff /* Unlocked. */
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff unsigned int magic;
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff /* Locked by lock. */
910df98b0efcbe8380b952887f4071051cc39a25Michael Graffstatic void clientmgr_destroy(ns_clientmgr_t *manager);
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * Important note!
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * All client state changes, other than that from idle to listening, occur
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * as a result of events. This guarantees serialization and avoids the
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff * need for locking.
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * If a routine is ever created that allows someone other than the client's
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * task to change the client, then the client will have to be locked.
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * Free a client immediately if possible, otherwise start
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * shutting it down and postpone freeing to later.
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff isc_boolean_t need_clientmgr_destroy = ISC_FALSE;
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff isc_socket_cancel(client->tcplistener, client->task,
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff isc_socket_cancel(client->tcpsocket, client->task,
c803787146cadcb2d7e10cbf4491f3be513dfa1aMichael Graff if (!(client->nreads == 0 && client->naccepts == 0 &&
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff client->nsends == 0 && client->nwaiting == 0)) {
2bcb48cfcae36398454c98e40c563e2cde748e07Michael Graff /* Still waiting for events. */
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff /* We have received our last event. */
86944a4c8002e80ae9b6eb5a5e29b797879be45fMichael Graff INSIST(dns_rdataset_isassociated(client->opt));
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff dns_message_puttemprdataset(client->message, &client->opt);
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff if (manager->nclients == 0 && manager->exiting)
3ac63b472022ff92691d1fe69ac715a729671965Michael Graff ISC_LIST_UNLINK(manager->clients, client, link);
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff isc_mem_put(client->mctx, client, sizeof *client);
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * The client's task has received a shutdown event.
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graffclient_shutdown(isc_task_t *task, isc_event_t *event) {
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff REQUIRE(event->type == ISC_TASKEVENT_SHUTDOWN);
fd15c8e32ed0c1cfd3ed737858a81966e7fbaeacAndreas Gustafssonstatic void client_read(ns_client_t *client);
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graffstatic void client_accept(ns_client_t *client);
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graffns_client_next(ns_client_t *client, isc_result_t result) {
36ca83769dbba29a3d8670eef9acd95c7a71a7f6Michael Graff * XXXRTH If result != ISC_R_SUCCESS:
efc8a09e19dfcfafa92fd2ad113073a4f5295e9bMichael Graff * Log result if there is interest in doing so.
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff INSIST(dns_rdataset_isassociated(client->opt));
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff dns_message_puttemprdataset(client->message, &client->opt);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff dns_dispatch_freeevent(client->dispatch, client->dispentry,
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * XXXAG Destroying the tcpmsg here
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff * looks bogus - it may still get events.
528829aa8ad69238e674cd81078bc14d4199691bMichael Graffclient_senddone(isc_task_t *task, isc_event_t *event) {
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff isc_socketevent_t *sevent = (isc_socketevent_t *)event;
c803787146cadcb2d7e10cbf4491f3be513dfa1aMichael Graff REQUIRE(sevent->type == ISC_SOCKEVENT_SENDDONE);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff isc_mempool_put(client->sendbufs, sevent->region.base);
da547174e2b7beb6d6119d58197ad0bc85b91179Michael Graff * If all of its sendbufs buffers were busy, the client might be
da547174e2b7beb6d6119d58197ad0bc85b91179Michael Graff * waiting for one to become available.
f00d96a15cdd11e764437f9359e67328631caaeaMichael Graff /* XXXRTH need to add exit draining mode. */
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff unsigned char *data;
e198cb953c1a5bc189ae21dc3f8d622f5a08bc34Bob Halley if ((client->attributes & NS_CLIENTATTR_RA) != 0)
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff * We couldn't get memory, but there is at least one
e198cb953c1a5bc189ae21dc3f8d622f5a08bc34Bob Halley * send outstanding. We arrange to be restarted when a
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff * send completes.
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff * XXXRTH The following doesn't deal with TSIGs, TCP buffer resizing,
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff * or ENDS1 more data packets.
738b9aa3ded1ef724922d6695cb04ec2e721bdd1Bob Halley * XXXRTH "tcpbuffer" is a hack to get things working.
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff isc_buffer_init(&tcpbuffer, data, SEND_BUFFER_SIZE,
910df98b0efcbe8380b952887f4071051cc39a25Michael Graff isc_buffer_init(&buffer, data + 2, SEND_BUFFER_SIZE - 2,
ff9bb3fc5453bbf310b67c560fbf04a5c0fb60daMichael Graff isc_buffer_init(&buffer, data, bufsize, ISC_BUFFERTYPE_BINARY);
970cccf46e0f949a1a9edbcd8302dd2a112b43c2Michael Graff result = dns_message_renderbegin(client->message, &buffer);
cebd4498636d3d480f6f2a7aa2eb72bd2ed64010Michael Graff result = dns_message_setopt(client->message, client->opt);
1c3bc66ada38236cc81c41b7174a9f0a872c9ab6Michael Graff * XXXRTH dns_message_setopt() should probably do this...
f942258b6380ba1f2c2f057a79ffc37bc3436488Michael Graff result = dns_message_rendersection(client->message,
f942258b6380ba1f2c2f057a79ffc37bc3436488Michael Graff result = dns_message_rendersection(client->message,
f942258b6380ba1f2c2f057a79ffc37bc3436488Michael Graff result = dns_message_rendersection(client->message,
f942258b6380ba1f2c2f057a79ffc37bc3436488Michael Graff result = dns_message_rendersection(client->message,
78854e02c127f31ab90f56da0531542004b45377Michael Graff if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
29f28fe573d4b3b318b3b026d567c1eb86738015Michael Graff result = dns_message_renderend(client->message);
30251e07d1705d1a85b0e1d5a969496e1aed612eMichael Graff isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t)r.length);
d4d2a13916a114879763562db6a19b70b1444ec1Michael Graff socket = dns_dispatch_getsocket(client->dispatch);
a9ece9973c35d4d780338e89e288fb6a59575324Michael Graff result = isc_socket_sendto(socket, &r, client->task, client_senddone,
910df98b0efcbe8380b952887f4071051cc39a25Michael Graffns_client_error(ns_client_t *client, isc_result_t result) {
static inline isc_result_t
return (result);
return (result);
return (result);
return (ISC_R_SUCCESS);
unsigned int version;
if (version != 0) {
case dns_opcode_query:
case dns_opcode_update:
case dns_opcode_notify:
case dns_opcode_iquery:
static isc_result_t
return (ISC_R_NOMEMORY);
goto cleanup_client;
goto cleanup_task;
goto cleanup_task;
goto cleanup_timer;
goto cleanup_message;
goto cleanup_sendbufs;
return (ISC_R_SUCCESS);
return (result);
return (ISC_R_NOMEMORY);
goto cleanup_manager;
return (ISC_R_SUCCESS);
return (result);
if (need_destroy)
REQUIRE(n > 0);
&client);
return (result);
REQUIRE(n > 0);
return (result);