2 * Copyright (C) 2004, 2006 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.206.3 2006/08/10 23:59:28 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
));
55 tcpmsg
->address
= ev
->address
;
57 if (ev
->result
!= ISC_R_SUCCESS
) {
58 tcpmsg
->result
= ev
->result
;
65 tcpmsg
->size
= ntohs(tcpmsg
->size
);
66 if (tcpmsg
->size
== 0) {
67 tcpmsg
->result
= ISC_R_UNEXPECTEDEND
;
70 if (tcpmsg
->size
> tcpmsg
->maxsize
) {
71 tcpmsg
->result
= ISC_R_RANGE
;
75 region
.base
= isc_mem_get(tcpmsg
->mctx
, tcpmsg
->size
);
76 region
.length
= tcpmsg
->size
;
77 if (region
.base
== NULL
) {
78 tcpmsg
->result
= ISC_R_NOMEMORY
;
81 XDEBUG(("Allocated %d bytes\n", tcpmsg
->size
));
83 isc_buffer_init(&tcpmsg
->buffer
, region
.base
, region
.length
);
84 result
= isc_socket_recv(tcpmsg
->sock
, ®ion
, 0,
85 task
, recv_message
, tcpmsg
);
86 if (result
!= ISC_R_SUCCESS
) {
87 tcpmsg
->result
= result
;
91 isc_event_free(&ev_in
);
95 isc_task_send(tcpmsg
->task
, &dev
);
97 isc_event_free(&ev_in
);
102 recv_message(isc_task_t
*task
, isc_event_t
*ev_in
) {
103 isc_socketevent_t
*ev
= (isc_socketevent_t
*)ev_in
;
105 dns_tcpmsg_t
*tcpmsg
= ev_in
->ev_arg
;
109 INSIST(VALID_TCPMSG(tcpmsg
));
111 dev
= &tcpmsg
->event
;
112 tcpmsg
->address
= ev
->address
;
114 if (ev
->result
!= ISC_R_SUCCESS
) {
115 tcpmsg
->result
= ev
->result
;
119 tcpmsg
->result
= ISC_R_SUCCESS
;
120 isc_buffer_add(&tcpmsg
->buffer
, ev
->n
);
122 XDEBUG(("Received %d bytes (of %d)\n", ev
->n
, tcpmsg
->size
));
125 isc_task_send(tcpmsg
->task
, &dev
);
127 isc_event_free(&ev_in
);
131 dns_tcpmsg_init(isc_mem_t
*mctx
, isc_socket_t
*sock
, dns_tcpmsg_t
*tcpmsg
) {
132 REQUIRE(mctx
!= NULL
);
133 REQUIRE(sock
!= NULL
);
134 REQUIRE(tcpmsg
!= NULL
);
136 tcpmsg
->magic
= TCPMSG_MAGIC
;
138 tcpmsg
->buffer
.base
= NULL
;
139 tcpmsg
->buffer
.length
= 0;
140 tcpmsg
->maxsize
= 65535; /* Largest message possible. */
143 tcpmsg
->task
= NULL
; /* None yet. */
144 tcpmsg
->result
= ISC_R_UNEXPECTED
; /* None yet. */
146 * Should probably initialize the event here, but it can wait.
152 dns_tcpmsg_setmaxsize(dns_tcpmsg_t
*tcpmsg
, unsigned int maxsize
) {
153 REQUIRE(VALID_TCPMSG(tcpmsg
));
154 REQUIRE(maxsize
< 65536);
156 tcpmsg
->maxsize
= maxsize
;
161 dns_tcpmsg_readmessage(dns_tcpmsg_t
*tcpmsg
,
162 isc_task_t
*task
, isc_taskaction_t action
, void *arg
)
167 REQUIRE(VALID_TCPMSG(tcpmsg
));
168 REQUIRE(task
!= NULL
);
169 REQUIRE(tcpmsg
->task
== NULL
); /* not currently in use */
171 if (tcpmsg
->buffer
.base
!= NULL
) {
172 isc_mem_put(tcpmsg
->mctx
, tcpmsg
->buffer
.base
,
173 tcpmsg
->buffer
.length
);
174 tcpmsg
->buffer
.base
= NULL
;
175 tcpmsg
->buffer
.length
= 0;
179 tcpmsg
->action
= action
;
181 tcpmsg
->result
= ISC_R_UNEXPECTED
; /* unknown right now */
183 ISC_EVENT_INIT(&tcpmsg
->event
, sizeof(isc_event_t
), 0, 0,
184 DNS_EVENT_TCPMSG
, action
, arg
, tcpmsg
,
187 region
.base
= (unsigned char *)&tcpmsg
->size
;
188 region
.length
= 2; /* isc_uint16_t */
189 result
= isc_socket_recv(tcpmsg
->sock
, ®ion
, 0,
190 tcpmsg
->task
, recv_length
, tcpmsg
);
192 if (result
!= ISC_R_SUCCESS
)
199 dns_tcpmsg_cancelread(dns_tcpmsg_t
*tcpmsg
) {
200 REQUIRE(VALID_TCPMSG(tcpmsg
));
202 isc_socket_cancel(tcpmsg
->sock
, NULL
, ISC_SOCKCANCEL_RECV
);
206 dns_tcpmsg_keepbuffer(dns_tcpmsg_t
*tcpmsg
, isc_buffer_t
*buffer
) {
207 REQUIRE(VALID_TCPMSG(tcpmsg
));
208 REQUIRE(buffer
!= NULL
);
210 *buffer
= tcpmsg
->buffer
;
211 tcpmsg
->buffer
.base
= NULL
;
212 tcpmsg
->buffer
.length
= 0;
217 dns_tcpmsg_freebuffer(dns_tcpmsg_t
*tcpmsg
) {
218 REQUIRE(VALID_TCPMSG(tcpmsg
));
220 if (tcpmsg
->buffer
.base
== NULL
)
223 isc_mem_put(tcpmsg
->mctx
, tcpmsg
->buffer
.base
, tcpmsg
->buffer
.length
);
224 tcpmsg
->buffer
.base
= NULL
;
225 tcpmsg
->buffer
.length
= 0;
230 dns_tcpmsg_invalidate(dns_tcpmsg_t
*tcpmsg
) {
231 REQUIRE(VALID_TCPMSG(tcpmsg
));
235 if (tcpmsg
->buffer
.base
!= NULL
) {
236 isc_mem_put(tcpmsg
->mctx
, tcpmsg
->buffer
.base
,
237 tcpmsg
->buffer
.length
);
238 tcpmsg
->buffer
.base
= NULL
;
239 tcpmsg
->buffer
.length
= 0;