Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / tcpmsg.c
blob4d456bea7ef77fe94ec7e69f81929f49c67ac491
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-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: tcpmsg.c,v 1.24.2.1 2004/03/09 06:11:08 marka Exp $ */
20 #include <config.h>
22 #include <isc/mem.h>
23 #include <isc/task.h>
24 #include <isc/util.h>
26 #include <dns/events.h>
27 #include <dns/result.h>
28 #include <dns/tcpmsg.h>
30 #ifdef TCPMSG_DEBUG
31 #include <stdio.h> /* Required for printf. */
32 #define XDEBUG(x) printf x
33 #else
34 #define XDEBUG(x)
35 #endif
37 #define TCPMSG_MAGIC ISC_MAGIC('T', 'C', 'P', 'm')
38 #define VALID_TCPMSG(foo) ISC_MAGIC_VALID(foo, TCPMSG_MAGIC)
40 static void recv_length(isc_task_t *, isc_event_t *);
41 static void recv_message(isc_task_t *, isc_event_t *);
44 static void
45 recv_length(isc_task_t *task, isc_event_t *ev_in) {
46 isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
47 isc_event_t *dev;
48 dns_tcpmsg_t *tcpmsg = ev_in->ev_arg;
49 isc_region_t region;
50 isc_result_t result;
52 INSIST(VALID_TCPMSG(tcpmsg));
54 dev = &tcpmsg->event;
56 if (ev->result != ISC_R_SUCCESS) {
57 tcpmsg->result = ev->result;
58 goto send_and_free;
62 * Success.
64 tcpmsg->size = ntohs(tcpmsg->size);
65 if (tcpmsg->size == 0) {
66 tcpmsg->result = ISC_R_UNEXPECTEDEND;
67 goto send_and_free;
69 if (tcpmsg->size > tcpmsg->maxsize) {
70 tcpmsg->result = ISC_R_RANGE;
71 goto send_and_free;
74 region.base = isc_mem_get(tcpmsg->mctx, tcpmsg->size);
75 region.length = tcpmsg->size;
76 if (region.base == NULL) {
77 tcpmsg->result = ISC_R_NOMEMORY;
78 goto send_and_free;
80 XDEBUG(("Allocated %d bytes\n", tcpmsg->size));
82 isc_buffer_init(&tcpmsg->buffer, region.base, region.length);
83 result = isc_socket_recv(tcpmsg->sock, &region, 0,
84 task, recv_message, tcpmsg);
85 if (result != ISC_R_SUCCESS) {
86 tcpmsg->result = result;
87 goto send_and_free;
90 isc_event_free(&ev_in);
91 return;
93 send_and_free:
94 isc_task_send(tcpmsg->task, &dev);
95 tcpmsg->task = NULL;
96 isc_event_free(&ev_in);
97 return;
100 static void
101 recv_message(isc_task_t *task, isc_event_t *ev_in) {
102 isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
103 isc_event_t *dev;
104 dns_tcpmsg_t *tcpmsg = ev_in->ev_arg;
106 (void)task;
108 INSIST(VALID_TCPMSG(tcpmsg));
110 dev = &tcpmsg->event;
112 if (ev->result != ISC_R_SUCCESS) {
113 tcpmsg->result = ev->result;
114 goto send_and_free;
117 tcpmsg->result = ISC_R_SUCCESS;
118 isc_buffer_add(&tcpmsg->buffer, ev->n);
119 tcpmsg->address = ev->address;
121 XDEBUG(("Received %d bytes (of %d)\n", ev->n, tcpmsg->size));
123 send_and_free:
124 isc_task_send(tcpmsg->task, &dev);
125 tcpmsg->task = NULL;
126 isc_event_free(&ev_in);
129 void
130 dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg) {
131 REQUIRE(mctx != NULL);
132 REQUIRE(sock != NULL);
133 REQUIRE(tcpmsg != NULL);
135 tcpmsg->magic = TCPMSG_MAGIC;
136 tcpmsg->size = 0;
137 tcpmsg->buffer.base = NULL;
138 tcpmsg->buffer.length = 0;
139 tcpmsg->maxsize = 65535; /* Largest message possible. */
140 tcpmsg->mctx = mctx;
141 tcpmsg->sock = sock;
142 tcpmsg->task = NULL; /* None yet. */
143 tcpmsg->result = ISC_R_UNEXPECTED; /* None yet. */
145 * Should probably initialize the event here, but it can wait.
150 void
151 dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize) {
152 REQUIRE(VALID_TCPMSG(tcpmsg));
153 REQUIRE(maxsize < 65536);
155 tcpmsg->maxsize = maxsize;
159 isc_result_t
160 dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg,
161 isc_task_t *task, isc_taskaction_t action, void *arg)
163 isc_result_t result;
164 isc_region_t region;
166 REQUIRE(VALID_TCPMSG(tcpmsg));
167 REQUIRE(task != NULL);
168 REQUIRE(tcpmsg->task == NULL); /* not currently in use */
170 if (tcpmsg->buffer.base != NULL) {
171 isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base,
172 tcpmsg->buffer.length);
173 tcpmsg->buffer.base = NULL;
174 tcpmsg->buffer.length = 0;
177 tcpmsg->task = task;
178 tcpmsg->action = action;
179 tcpmsg->arg = arg;
180 tcpmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
182 ISC_EVENT_INIT(&tcpmsg->event, sizeof(isc_event_t), 0, 0,
183 DNS_EVENT_TCPMSG, action, arg, tcpmsg,
184 NULL, NULL);
186 region.base = (unsigned char *)&tcpmsg->size;
187 region.length = 2; /* isc_uint16_t */
188 result = isc_socket_recv(tcpmsg->sock, &region, 0,
189 tcpmsg->task, recv_length, tcpmsg);
191 if (result != ISC_R_SUCCESS)
192 tcpmsg->task = NULL;
194 return (result);
197 void
198 dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg) {
199 REQUIRE(VALID_TCPMSG(tcpmsg));
201 isc_socket_cancel(tcpmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
204 void
205 dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer) {
206 REQUIRE(VALID_TCPMSG(tcpmsg));
207 REQUIRE(buffer != NULL);
209 *buffer = tcpmsg->buffer;
210 tcpmsg->buffer.base = NULL;
211 tcpmsg->buffer.length = 0;
214 #if 0
215 void
216 dns_tcpmsg_freebuffer(dns_tcpmsg_t *tcpmsg) {
217 REQUIRE(VALID_TCPMSG(tcpmsg));
219 if (tcpmsg->buffer.base == NULL)
220 return;
222 isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, tcpmsg->buffer.length);
223 tcpmsg->buffer.base = NULL;
224 tcpmsg->buffer.length = 0;
226 #endif
228 void
229 dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg) {
230 REQUIRE(VALID_TCPMSG(tcpmsg));
232 tcpmsg->magic = 0;
234 if (tcpmsg->buffer.base != NULL) {
235 isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base,
236 tcpmsg->buffer.length);
237 tcpmsg->buffer.base = NULL;
238 tcpmsg->buffer.length = 0;