1*00b67f09SDavid van Moolenbroek /* $NetBSD: tcpmsg.c,v 1.4 2014/12/10 04:37:58 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 1999-2001 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: tcpmsg.c,v 1.31 2007/06/19 23:47:16 tbox Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek
26*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
27*00b67f09SDavid van Moolenbroek #include <isc/task.h>
28*00b67f09SDavid van Moolenbroek #include <isc/util.h>
29*00b67f09SDavid van Moolenbroek
30*00b67f09SDavid van Moolenbroek #include <dns/events.h>
31*00b67f09SDavid van Moolenbroek #include <dns/result.h>
32*00b67f09SDavid van Moolenbroek #include <dns/tcpmsg.h>
33*00b67f09SDavid van Moolenbroek
34*00b67f09SDavid van Moolenbroek #ifdef TCPMSG_DEBUG
35*00b67f09SDavid van Moolenbroek #include <stdio.h> /* Required for printf. */
36*00b67f09SDavid van Moolenbroek #define XDEBUG(x) printf x
37*00b67f09SDavid van Moolenbroek #else
38*00b67f09SDavid van Moolenbroek #define XDEBUG(x)
39*00b67f09SDavid van Moolenbroek #endif
40*00b67f09SDavid van Moolenbroek
41*00b67f09SDavid van Moolenbroek #define TCPMSG_MAGIC ISC_MAGIC('T', 'C', 'P', 'm')
42*00b67f09SDavid van Moolenbroek #define VALID_TCPMSG(foo) ISC_MAGIC_VALID(foo, TCPMSG_MAGIC)
43*00b67f09SDavid van Moolenbroek
44*00b67f09SDavid van Moolenbroek static void recv_length(isc_task_t *, isc_event_t *);
45*00b67f09SDavid van Moolenbroek static void recv_message(isc_task_t *, isc_event_t *);
46*00b67f09SDavid van Moolenbroek
47*00b67f09SDavid van Moolenbroek
48*00b67f09SDavid van Moolenbroek static void
recv_length(isc_task_t * task,isc_event_t * ev_in)49*00b67f09SDavid van Moolenbroek recv_length(isc_task_t *task, isc_event_t *ev_in) {
50*00b67f09SDavid van Moolenbroek isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
51*00b67f09SDavid van Moolenbroek isc_event_t *dev;
52*00b67f09SDavid van Moolenbroek dns_tcpmsg_t *tcpmsg = ev_in->ev_arg;
53*00b67f09SDavid van Moolenbroek isc_region_t region;
54*00b67f09SDavid van Moolenbroek isc_result_t result;
55*00b67f09SDavid van Moolenbroek
56*00b67f09SDavid van Moolenbroek INSIST(VALID_TCPMSG(tcpmsg));
57*00b67f09SDavid van Moolenbroek
58*00b67f09SDavid van Moolenbroek dev = &tcpmsg->event;
59*00b67f09SDavid van Moolenbroek tcpmsg->address = ev->address;
60*00b67f09SDavid van Moolenbroek
61*00b67f09SDavid van Moolenbroek if (ev->result != ISC_R_SUCCESS) {
62*00b67f09SDavid van Moolenbroek tcpmsg->result = ev->result;
63*00b67f09SDavid van Moolenbroek goto send_and_free;
64*00b67f09SDavid van Moolenbroek }
65*00b67f09SDavid van Moolenbroek
66*00b67f09SDavid van Moolenbroek /*
67*00b67f09SDavid van Moolenbroek * Success.
68*00b67f09SDavid van Moolenbroek */
69*00b67f09SDavid van Moolenbroek tcpmsg->size = ntohs(tcpmsg->size);
70*00b67f09SDavid van Moolenbroek if (tcpmsg->size == 0) {
71*00b67f09SDavid van Moolenbroek tcpmsg->result = ISC_R_UNEXPECTEDEND;
72*00b67f09SDavid van Moolenbroek goto send_and_free;
73*00b67f09SDavid van Moolenbroek }
74*00b67f09SDavid van Moolenbroek if (tcpmsg->size > tcpmsg->maxsize) {
75*00b67f09SDavid van Moolenbroek tcpmsg->result = ISC_R_RANGE;
76*00b67f09SDavid van Moolenbroek goto send_and_free;
77*00b67f09SDavid van Moolenbroek }
78*00b67f09SDavid van Moolenbroek
79*00b67f09SDavid van Moolenbroek region.base = isc_mem_get(tcpmsg->mctx, tcpmsg->size);
80*00b67f09SDavid van Moolenbroek region.length = tcpmsg->size;
81*00b67f09SDavid van Moolenbroek if (region.base == NULL) {
82*00b67f09SDavid van Moolenbroek tcpmsg->result = ISC_R_NOMEMORY;
83*00b67f09SDavid van Moolenbroek goto send_and_free;
84*00b67f09SDavid van Moolenbroek }
85*00b67f09SDavid van Moolenbroek XDEBUG(("Allocated %d bytes\n", tcpmsg->size));
86*00b67f09SDavid van Moolenbroek
87*00b67f09SDavid van Moolenbroek isc_buffer_init(&tcpmsg->buffer, region.base, region.length);
88*00b67f09SDavid van Moolenbroek result = isc_socket_recv(tcpmsg->sock, ®ion, 0,
89*00b67f09SDavid van Moolenbroek task, recv_message, tcpmsg);
90*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
91*00b67f09SDavid van Moolenbroek tcpmsg->result = result;
92*00b67f09SDavid van Moolenbroek goto send_and_free;
93*00b67f09SDavid van Moolenbroek }
94*00b67f09SDavid van Moolenbroek
95*00b67f09SDavid van Moolenbroek isc_event_free(&ev_in);
96*00b67f09SDavid van Moolenbroek return;
97*00b67f09SDavid van Moolenbroek
98*00b67f09SDavid van Moolenbroek send_and_free:
99*00b67f09SDavid van Moolenbroek isc_task_send(tcpmsg->task, &dev);
100*00b67f09SDavid van Moolenbroek tcpmsg->task = NULL;
101*00b67f09SDavid van Moolenbroek isc_event_free(&ev_in);
102*00b67f09SDavid van Moolenbroek return;
103*00b67f09SDavid van Moolenbroek }
104*00b67f09SDavid van Moolenbroek
105*00b67f09SDavid van Moolenbroek static void
recv_message(isc_task_t * task,isc_event_t * ev_in)106*00b67f09SDavid van Moolenbroek recv_message(isc_task_t *task, isc_event_t *ev_in) {
107*00b67f09SDavid van Moolenbroek isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
108*00b67f09SDavid van Moolenbroek isc_event_t *dev;
109*00b67f09SDavid van Moolenbroek dns_tcpmsg_t *tcpmsg = ev_in->ev_arg;
110*00b67f09SDavid van Moolenbroek
111*00b67f09SDavid van Moolenbroek (void)task;
112*00b67f09SDavid van Moolenbroek
113*00b67f09SDavid van Moolenbroek INSIST(VALID_TCPMSG(tcpmsg));
114*00b67f09SDavid van Moolenbroek
115*00b67f09SDavid van Moolenbroek dev = &tcpmsg->event;
116*00b67f09SDavid van Moolenbroek tcpmsg->address = ev->address;
117*00b67f09SDavid van Moolenbroek
118*00b67f09SDavid van Moolenbroek if (ev->result != ISC_R_SUCCESS) {
119*00b67f09SDavid van Moolenbroek tcpmsg->result = ev->result;
120*00b67f09SDavid van Moolenbroek goto send_and_free;
121*00b67f09SDavid van Moolenbroek }
122*00b67f09SDavid van Moolenbroek
123*00b67f09SDavid van Moolenbroek tcpmsg->result = ISC_R_SUCCESS;
124*00b67f09SDavid van Moolenbroek isc_buffer_add(&tcpmsg->buffer, ev->n);
125*00b67f09SDavid van Moolenbroek
126*00b67f09SDavid van Moolenbroek XDEBUG(("Received %d bytes (of %d)\n", ev->n, tcpmsg->size));
127*00b67f09SDavid van Moolenbroek
128*00b67f09SDavid van Moolenbroek send_and_free:
129*00b67f09SDavid van Moolenbroek isc_task_send(tcpmsg->task, &dev);
130*00b67f09SDavid van Moolenbroek tcpmsg->task = NULL;
131*00b67f09SDavid van Moolenbroek isc_event_free(&ev_in);
132*00b67f09SDavid van Moolenbroek }
133*00b67f09SDavid van Moolenbroek
134*00b67f09SDavid van Moolenbroek void
dns_tcpmsg_init(isc_mem_t * mctx,isc_socket_t * sock,dns_tcpmsg_t * tcpmsg)135*00b67f09SDavid van Moolenbroek dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg) {
136*00b67f09SDavid van Moolenbroek REQUIRE(mctx != NULL);
137*00b67f09SDavid van Moolenbroek REQUIRE(sock != NULL);
138*00b67f09SDavid van Moolenbroek REQUIRE(tcpmsg != NULL);
139*00b67f09SDavid van Moolenbroek
140*00b67f09SDavid van Moolenbroek tcpmsg->magic = TCPMSG_MAGIC;
141*00b67f09SDavid van Moolenbroek tcpmsg->size = 0;
142*00b67f09SDavid van Moolenbroek tcpmsg->buffer.base = NULL;
143*00b67f09SDavid van Moolenbroek tcpmsg->buffer.length = 0;
144*00b67f09SDavid van Moolenbroek tcpmsg->maxsize = 65535; /* Largest message possible. */
145*00b67f09SDavid van Moolenbroek tcpmsg->mctx = mctx;
146*00b67f09SDavid van Moolenbroek tcpmsg->sock = sock;
147*00b67f09SDavid van Moolenbroek tcpmsg->task = NULL; /* None yet. */
148*00b67f09SDavid van Moolenbroek tcpmsg->result = ISC_R_UNEXPECTED; /* None yet. */
149*00b67f09SDavid van Moolenbroek /*
150*00b67f09SDavid van Moolenbroek * Should probably initialize the event here, but it can wait.
151*00b67f09SDavid van Moolenbroek */
152*00b67f09SDavid van Moolenbroek }
153*00b67f09SDavid van Moolenbroek
154*00b67f09SDavid van Moolenbroek
155*00b67f09SDavid van Moolenbroek void
dns_tcpmsg_setmaxsize(dns_tcpmsg_t * tcpmsg,unsigned int maxsize)156*00b67f09SDavid van Moolenbroek dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize) {
157*00b67f09SDavid van Moolenbroek REQUIRE(VALID_TCPMSG(tcpmsg));
158*00b67f09SDavid van Moolenbroek REQUIRE(maxsize < 65536);
159*00b67f09SDavid van Moolenbroek
160*00b67f09SDavid van Moolenbroek tcpmsg->maxsize = maxsize;
161*00b67f09SDavid van Moolenbroek }
162*00b67f09SDavid van Moolenbroek
163*00b67f09SDavid van Moolenbroek
164*00b67f09SDavid van Moolenbroek isc_result_t
dns_tcpmsg_readmessage(dns_tcpmsg_t * tcpmsg,isc_task_t * task,isc_taskaction_t action,void * arg)165*00b67f09SDavid van Moolenbroek dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg,
166*00b67f09SDavid van Moolenbroek isc_task_t *task, isc_taskaction_t action, void *arg)
167*00b67f09SDavid van Moolenbroek {
168*00b67f09SDavid van Moolenbroek isc_result_t result;
169*00b67f09SDavid van Moolenbroek isc_region_t region;
170*00b67f09SDavid van Moolenbroek
171*00b67f09SDavid van Moolenbroek REQUIRE(VALID_TCPMSG(tcpmsg));
172*00b67f09SDavid van Moolenbroek REQUIRE(task != NULL);
173*00b67f09SDavid van Moolenbroek REQUIRE(tcpmsg->task == NULL); /* not currently in use */
174*00b67f09SDavid van Moolenbroek
175*00b67f09SDavid van Moolenbroek if (tcpmsg->buffer.base != NULL) {
176*00b67f09SDavid van Moolenbroek isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base,
177*00b67f09SDavid van Moolenbroek tcpmsg->buffer.length);
178*00b67f09SDavid van Moolenbroek tcpmsg->buffer.base = NULL;
179*00b67f09SDavid van Moolenbroek tcpmsg->buffer.length = 0;
180*00b67f09SDavid van Moolenbroek }
181*00b67f09SDavid van Moolenbroek
182*00b67f09SDavid van Moolenbroek tcpmsg->task = task;
183*00b67f09SDavid van Moolenbroek tcpmsg->action = action;
184*00b67f09SDavid van Moolenbroek tcpmsg->arg = arg;
185*00b67f09SDavid van Moolenbroek tcpmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
186*00b67f09SDavid van Moolenbroek
187*00b67f09SDavid van Moolenbroek ISC_EVENT_INIT(&tcpmsg->event, sizeof(isc_event_t), 0, 0,
188*00b67f09SDavid van Moolenbroek DNS_EVENT_TCPMSG, action, arg, tcpmsg,
189*00b67f09SDavid van Moolenbroek NULL, NULL);
190*00b67f09SDavid van Moolenbroek
191*00b67f09SDavid van Moolenbroek region.base = (unsigned char *)&tcpmsg->size;
192*00b67f09SDavid van Moolenbroek region.length = 2; /* isc_uint16_t */
193*00b67f09SDavid van Moolenbroek result = isc_socket_recv(tcpmsg->sock, ®ion, 0,
194*00b67f09SDavid van Moolenbroek tcpmsg->task, recv_length, tcpmsg);
195*00b67f09SDavid van Moolenbroek
196*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
197*00b67f09SDavid van Moolenbroek tcpmsg->task = NULL;
198*00b67f09SDavid van Moolenbroek
199*00b67f09SDavid van Moolenbroek return (result);
200*00b67f09SDavid van Moolenbroek }
201*00b67f09SDavid van Moolenbroek
202*00b67f09SDavid van Moolenbroek void
dns_tcpmsg_cancelread(dns_tcpmsg_t * tcpmsg)203*00b67f09SDavid van Moolenbroek dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg) {
204*00b67f09SDavid van Moolenbroek REQUIRE(VALID_TCPMSG(tcpmsg));
205*00b67f09SDavid van Moolenbroek
206*00b67f09SDavid van Moolenbroek isc_socket_cancel(tcpmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
207*00b67f09SDavid van Moolenbroek }
208*00b67f09SDavid van Moolenbroek
209*00b67f09SDavid van Moolenbroek void
dns_tcpmsg_keepbuffer(dns_tcpmsg_t * tcpmsg,isc_buffer_t * buffer)210*00b67f09SDavid van Moolenbroek dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer) {
211*00b67f09SDavid van Moolenbroek REQUIRE(VALID_TCPMSG(tcpmsg));
212*00b67f09SDavid van Moolenbroek REQUIRE(buffer != NULL);
213*00b67f09SDavid van Moolenbroek
214*00b67f09SDavid van Moolenbroek *buffer = tcpmsg->buffer;
215*00b67f09SDavid van Moolenbroek tcpmsg->buffer.base = NULL;
216*00b67f09SDavid van Moolenbroek tcpmsg->buffer.length = 0;
217*00b67f09SDavid van Moolenbroek }
218*00b67f09SDavid van Moolenbroek
219*00b67f09SDavid van Moolenbroek #if 0
220*00b67f09SDavid van Moolenbroek void
221*00b67f09SDavid van Moolenbroek dns_tcpmsg_freebuffer(dns_tcpmsg_t *tcpmsg) {
222*00b67f09SDavid van Moolenbroek REQUIRE(VALID_TCPMSG(tcpmsg));
223*00b67f09SDavid van Moolenbroek
224*00b67f09SDavid van Moolenbroek if (tcpmsg->buffer.base == NULL)
225*00b67f09SDavid van Moolenbroek return;
226*00b67f09SDavid van Moolenbroek
227*00b67f09SDavid van Moolenbroek isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, tcpmsg->buffer.length);
228*00b67f09SDavid van Moolenbroek tcpmsg->buffer.base = NULL;
229*00b67f09SDavid van Moolenbroek tcpmsg->buffer.length = 0;
230*00b67f09SDavid van Moolenbroek }
231*00b67f09SDavid van Moolenbroek #endif
232*00b67f09SDavid van Moolenbroek
233*00b67f09SDavid van Moolenbroek void
dns_tcpmsg_invalidate(dns_tcpmsg_t * tcpmsg)234*00b67f09SDavid van Moolenbroek dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg) {
235*00b67f09SDavid van Moolenbroek REQUIRE(VALID_TCPMSG(tcpmsg));
236*00b67f09SDavid van Moolenbroek
237*00b67f09SDavid van Moolenbroek tcpmsg->magic = 0;
238*00b67f09SDavid van Moolenbroek
239*00b67f09SDavid van Moolenbroek if (tcpmsg->buffer.base != NULL) {
240*00b67f09SDavid van Moolenbroek isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base,
241*00b67f09SDavid van Moolenbroek tcpmsg->buffer.length);
242*00b67f09SDavid van Moolenbroek tcpmsg->buffer.base = NULL;
243*00b67f09SDavid van Moolenbroek tcpmsg->buffer.length = 0;
244*00b67f09SDavid van Moolenbroek }
245*00b67f09SDavid van Moolenbroek }
246