xref: /minix3/external/bsd/bind/dist/lib/dns/tcpmsg.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
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, &region, 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, &region, 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