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 $ */
26 #include <dns/events.h>
27 #include <dns/result.h>
28 #include <dns/tcpmsg.h>
31 #include <stdio.h> /* Required for printf. */
32 #define XDEBUG(x) printf x
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
*);
45 recv_length(isc_task_t
*task
, isc_event_t
*ev_in
) {
46 isc_socketevent_t
*ev
= (isc_socketevent_t
*)ev_in
;
48 dns_tcpmsg_t
*tcpmsg
= ev_in
->ev_arg
;
52 INSIST(VALID_TCPMSG(tcpmsg
));
56 if (ev
->result
!= ISC_R_SUCCESS
) {
57 tcpmsg
->result
= ev
->result
;
64 tcpmsg
->size
= ntohs(tcpmsg
->size
);
65 if (tcpmsg
->size
== 0) {
66 tcpmsg
->result
= ISC_R_UNEXPECTEDEND
;
69 if (tcpmsg
->size
> tcpmsg
->maxsize
) {
70 tcpmsg
->result
= ISC_R_RANGE
;
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
;
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
, ®ion
, 0,
84 task
, recv_message
, tcpmsg
);
85 if (result
!= ISC_R_SUCCESS
) {
86 tcpmsg
->result
= result
;
90 isc_event_free(&ev_in
);
94 isc_task_send(tcpmsg
->task
, &dev
);
96 isc_event_free(&ev_in
);
101 recv_message(isc_task_t
*task
, isc_event_t
*ev_in
) {
102 isc_socketevent_t
*ev
= (isc_socketevent_t
*)ev_in
;
104 dns_tcpmsg_t
*tcpmsg
= ev_in
->ev_arg
;
108 INSIST(VALID_TCPMSG(tcpmsg
));
110 dev
= &tcpmsg
->event
;
112 if (ev
->result
!= ISC_R_SUCCESS
) {
113 tcpmsg
->result
= ev
->result
;
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
));
124 isc_task_send(tcpmsg
->task
, &dev
);
126 isc_event_free(&ev_in
);
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
;
137 tcpmsg
->buffer
.base
= NULL
;
138 tcpmsg
->buffer
.length
= 0;
139 tcpmsg
->maxsize
= 65535; /* Largest message possible. */
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.
151 dns_tcpmsg_setmaxsize(dns_tcpmsg_t
*tcpmsg
, unsigned int maxsize
) {
152 REQUIRE(VALID_TCPMSG(tcpmsg
));
153 REQUIRE(maxsize
< 65536);
155 tcpmsg
->maxsize
= maxsize
;
160 dns_tcpmsg_readmessage(dns_tcpmsg_t
*tcpmsg
,
161 isc_task_t
*task
, isc_taskaction_t action
, void *arg
)
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;
178 tcpmsg
->action
= action
;
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
,
186 region
.base
= (unsigned char *)&tcpmsg
->size
;
187 region
.length
= 2; /* isc_uint16_t */
188 result
= isc_socket_recv(tcpmsg
->sock
, ®ion
, 0,
189 tcpmsg
->task
, recv_length
, tcpmsg
);
191 if (result
!= ISC_R_SUCCESS
)
198 dns_tcpmsg_cancelread(dns_tcpmsg_t
*tcpmsg
) {
199 REQUIRE(VALID_TCPMSG(tcpmsg
));
201 isc_socket_cancel(tcpmsg
->sock
, NULL
, ISC_SOCKCANCEL_RECV
);
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;
216 dns_tcpmsg_freebuffer(dns_tcpmsg_t
*tcpmsg
) {
217 REQUIRE(VALID_TCPMSG(tcpmsg
));
219 if (tcpmsg
->buffer
.base
== NULL
)
222 isc_mem_put(tcpmsg
->mctx
, tcpmsg
->buffer
.base
, tcpmsg
->buffer
.length
);
223 tcpmsg
->buffer
.base
= NULL
;
224 tcpmsg
->buffer
.length
= 0;
229 dns_tcpmsg_invalidate(dns_tcpmsg_t
*tcpmsg
) {
230 REQUIRE(VALID_TCPMSG(tcpmsg
));
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;