xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/dns/tcpmsg.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1*4afad4b7Schristos /*	$NetBSD: tcpmsg.c,v 1.1 2024/02/18 20:57:34 christos Exp $	*/
2*4afad4b7Schristos 
3*4afad4b7Schristos /*
4*4afad4b7Schristos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5*4afad4b7Schristos  *
6*4afad4b7Schristos  * SPDX-License-Identifier: MPL-2.0
7*4afad4b7Schristos  *
8*4afad4b7Schristos  * This Source Code Form is subject to the terms of the Mozilla Public
9*4afad4b7Schristos  * License, v. 2.0.  If a copy of the MPL was not distributed with this
10*4afad4b7Schristos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11*4afad4b7Schristos  *
12*4afad4b7Schristos  * See the COPYRIGHT file distributed with this work for additional
13*4afad4b7Schristos  * information regarding copyright ownership.
14*4afad4b7Schristos  */
15*4afad4b7Schristos 
16*4afad4b7Schristos /*! \file */
17*4afad4b7Schristos 
18*4afad4b7Schristos #include <inttypes.h>
19*4afad4b7Schristos 
20*4afad4b7Schristos #include <isc/mem.h>
21*4afad4b7Schristos #include <isc/print.h>
22*4afad4b7Schristos #include <isc/task.h>
23*4afad4b7Schristos #include <isc/util.h>
24*4afad4b7Schristos 
25*4afad4b7Schristos #include <dns/events.h>
26*4afad4b7Schristos #include <dns/result.h>
27*4afad4b7Schristos #include <dns/tcpmsg.h>
28*4afad4b7Schristos 
29*4afad4b7Schristos #ifdef TCPMSG_DEBUG
30*4afad4b7Schristos #include <stdio.h> /* Required for printf. */
31*4afad4b7Schristos #define XDEBUG(x) printf x
32*4afad4b7Schristos #else /* ifdef TCPMSG_DEBUG */
33*4afad4b7Schristos #define XDEBUG(x)
34*4afad4b7Schristos #endif /* ifdef TCPMSG_DEBUG */
35*4afad4b7Schristos 
36*4afad4b7Schristos #define TCPMSG_MAGIC	  ISC_MAGIC('T', 'C', 'P', 'm')
37*4afad4b7Schristos #define VALID_TCPMSG(foo) ISC_MAGIC_VALID(foo, TCPMSG_MAGIC)
38*4afad4b7Schristos 
39*4afad4b7Schristos static void
40*4afad4b7Schristos recv_length(isc_task_t *, isc_event_t *);
41*4afad4b7Schristos static void
42*4afad4b7Schristos recv_message(isc_task_t *, isc_event_t *);
43*4afad4b7Schristos 
44*4afad4b7Schristos static void
recv_length(isc_task_t * task,isc_event_t * ev_in)45*4afad4b7Schristos recv_length(isc_task_t *task, isc_event_t *ev_in) {
46*4afad4b7Schristos 	isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
47*4afad4b7Schristos 	isc_event_t *dev;
48*4afad4b7Schristos 	dns_tcpmsg_t *tcpmsg = ev_in->ev_arg;
49*4afad4b7Schristos 	isc_region_t region;
50*4afad4b7Schristos 	isc_result_t result;
51*4afad4b7Schristos 
52*4afad4b7Schristos 	INSIST(VALID_TCPMSG(tcpmsg));
53*4afad4b7Schristos 
54*4afad4b7Schristos 	dev = &tcpmsg->event;
55*4afad4b7Schristos 	tcpmsg->address = ev->address;
56*4afad4b7Schristos 
57*4afad4b7Schristos 	if (ev->result != ISC_R_SUCCESS) {
58*4afad4b7Schristos 		tcpmsg->result = ev->result;
59*4afad4b7Schristos 		goto send_and_free;
60*4afad4b7Schristos 	}
61*4afad4b7Schristos 
62*4afad4b7Schristos 	/*
63*4afad4b7Schristos 	 * Success.
64*4afad4b7Schristos 	 */
65*4afad4b7Schristos 	tcpmsg->size = ntohs(tcpmsg->size);
66*4afad4b7Schristos 	if (tcpmsg->size == 0) {
67*4afad4b7Schristos 		tcpmsg->result = ISC_R_UNEXPECTEDEND;
68*4afad4b7Schristos 		goto send_and_free;
69*4afad4b7Schristos 	}
70*4afad4b7Schristos 	if (tcpmsg->size > tcpmsg->maxsize) {
71*4afad4b7Schristos 		tcpmsg->result = ISC_R_RANGE;
72*4afad4b7Schristos 		goto send_and_free;
73*4afad4b7Schristos 	}
74*4afad4b7Schristos 
75*4afad4b7Schristos 	region.base = isc_mem_get(tcpmsg->mctx, tcpmsg->size);
76*4afad4b7Schristos 	region.length = tcpmsg->size;
77*4afad4b7Schristos 	if (region.base == NULL) {
78*4afad4b7Schristos 		tcpmsg->result = ISC_R_NOMEMORY;
79*4afad4b7Schristos 		goto send_and_free;
80*4afad4b7Schristos 	}
81*4afad4b7Schristos 	XDEBUG(("Allocated %d bytes\n", tcpmsg->size));
82*4afad4b7Schristos 
83*4afad4b7Schristos 	isc_buffer_init(&tcpmsg->buffer, region.base, region.length);
84*4afad4b7Schristos 	result = isc_socket_recv(tcpmsg->sock, &region, 0, task, recv_message,
85*4afad4b7Schristos 				 tcpmsg);
86*4afad4b7Schristos 	if (result != ISC_R_SUCCESS) {
87*4afad4b7Schristos 		tcpmsg->result = result;
88*4afad4b7Schristos 		goto send_and_free;
89*4afad4b7Schristos 	}
90*4afad4b7Schristos 
91*4afad4b7Schristos 	isc_event_free(&ev_in);
92*4afad4b7Schristos 	return;
93*4afad4b7Schristos 
94*4afad4b7Schristos send_and_free:
95*4afad4b7Schristos 	isc_task_send(tcpmsg->task, &dev);
96*4afad4b7Schristos 	tcpmsg->task = NULL;
97*4afad4b7Schristos 	isc_event_free(&ev_in);
98*4afad4b7Schristos 	return;
99*4afad4b7Schristos }
100*4afad4b7Schristos 
101*4afad4b7Schristos static void
recv_message(isc_task_t * task,isc_event_t * ev_in)102*4afad4b7Schristos recv_message(isc_task_t *task, isc_event_t *ev_in) {
103*4afad4b7Schristos 	isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
104*4afad4b7Schristos 	isc_event_t *dev;
105*4afad4b7Schristos 	dns_tcpmsg_t *tcpmsg = ev_in->ev_arg;
106*4afad4b7Schristos 
107*4afad4b7Schristos 	(void)task;
108*4afad4b7Schristos 
109*4afad4b7Schristos 	INSIST(VALID_TCPMSG(tcpmsg));
110*4afad4b7Schristos 
111*4afad4b7Schristos 	dev = &tcpmsg->event;
112*4afad4b7Schristos 	tcpmsg->address = ev->address;
113*4afad4b7Schristos 
114*4afad4b7Schristos 	if (ev->result != ISC_R_SUCCESS) {
115*4afad4b7Schristos 		tcpmsg->result = ev->result;
116*4afad4b7Schristos 		goto send_and_free;
117*4afad4b7Schristos 	}
118*4afad4b7Schristos 
119*4afad4b7Schristos 	tcpmsg->result = ISC_R_SUCCESS;
120*4afad4b7Schristos 	isc_buffer_add(&tcpmsg->buffer, ev->n);
121*4afad4b7Schristos 
122*4afad4b7Schristos 	XDEBUG(("Received %u bytes (of %d)\n", ev->n, tcpmsg->size));
123*4afad4b7Schristos 
124*4afad4b7Schristos send_and_free:
125*4afad4b7Schristos 	isc_task_send(tcpmsg->task, &dev);
126*4afad4b7Schristos 	tcpmsg->task = NULL;
127*4afad4b7Schristos 	isc_event_free(&ev_in);
128*4afad4b7Schristos }
129*4afad4b7Schristos 
130*4afad4b7Schristos void
dns_tcpmsg_init(isc_mem_t * mctx,isc_socket_t * sock,dns_tcpmsg_t * tcpmsg)131*4afad4b7Schristos dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg) {
132*4afad4b7Schristos 	REQUIRE(mctx != NULL);
133*4afad4b7Schristos 	REQUIRE(sock != NULL);
134*4afad4b7Schristos 	REQUIRE(tcpmsg != NULL);
135*4afad4b7Schristos 
136*4afad4b7Schristos 	tcpmsg->magic = TCPMSG_MAGIC;
137*4afad4b7Schristos 	tcpmsg->size = 0;
138*4afad4b7Schristos 	tcpmsg->buffer.base = NULL;
139*4afad4b7Schristos 	tcpmsg->buffer.length = 0;
140*4afad4b7Schristos 	tcpmsg->maxsize = 65535; /* Largest message possible. */
141*4afad4b7Schristos 	tcpmsg->mctx = mctx;
142*4afad4b7Schristos 	tcpmsg->sock = sock;
143*4afad4b7Schristos 	tcpmsg->task = NULL;		   /* None yet. */
144*4afad4b7Schristos 	tcpmsg->result = ISC_R_UNEXPECTED; /* None yet. */
145*4afad4b7Schristos 
146*4afad4b7Schristos 	/* Should probably initialize the event here, but it can wait. */
147*4afad4b7Schristos }
148*4afad4b7Schristos 
149*4afad4b7Schristos void
dns_tcpmsg_setmaxsize(dns_tcpmsg_t * tcpmsg,unsigned int maxsize)150*4afad4b7Schristos dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize) {
151*4afad4b7Schristos 	REQUIRE(VALID_TCPMSG(tcpmsg));
152*4afad4b7Schristos 	REQUIRE(maxsize < 65536);
153*4afad4b7Schristos 
154*4afad4b7Schristos 	tcpmsg->maxsize = maxsize;
155*4afad4b7Schristos }
156*4afad4b7Schristos 
157*4afad4b7Schristos isc_result_t
dns_tcpmsg_readmessage(dns_tcpmsg_t * tcpmsg,isc_task_t * task,isc_taskaction_t action,void * arg)158*4afad4b7Schristos dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg, isc_task_t *task,
159*4afad4b7Schristos 		       isc_taskaction_t action, void *arg) {
160*4afad4b7Schristos 	isc_result_t result;
161*4afad4b7Schristos 	isc_region_t region;
162*4afad4b7Schristos 
163*4afad4b7Schristos 	REQUIRE(VALID_TCPMSG(tcpmsg));
164*4afad4b7Schristos 	REQUIRE(task != NULL);
165*4afad4b7Schristos 	REQUIRE(tcpmsg->task == NULL); /* not currently in use */
166*4afad4b7Schristos 
167*4afad4b7Schristos 	if (tcpmsg->buffer.base != NULL) {
168*4afad4b7Schristos 		isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base,
169*4afad4b7Schristos 			    tcpmsg->buffer.length);
170*4afad4b7Schristos 		tcpmsg->buffer.base = NULL;
171*4afad4b7Schristos 		tcpmsg->buffer.length = 0;
172*4afad4b7Schristos 	}
173*4afad4b7Schristos 
174*4afad4b7Schristos 	tcpmsg->task = task;
175*4afad4b7Schristos 	tcpmsg->action = action;
176*4afad4b7Schristos 	tcpmsg->arg = arg;
177*4afad4b7Schristos 	tcpmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
178*4afad4b7Schristos 
179*4afad4b7Schristos 	ISC_EVENT_INIT(&tcpmsg->event, sizeof(isc_event_t), 0, 0,
180*4afad4b7Schristos 		       DNS_EVENT_TCPMSG, action, arg, tcpmsg, NULL, NULL);
181*4afad4b7Schristos 
182*4afad4b7Schristos 	region.base = (unsigned char *)&tcpmsg->size;
183*4afad4b7Schristos 	region.length = 2; /* uint16_t */
184*4afad4b7Schristos 	result = isc_socket_recv(tcpmsg->sock, &region, 0, tcpmsg->task,
185*4afad4b7Schristos 				 recv_length, tcpmsg);
186*4afad4b7Schristos 
187*4afad4b7Schristos 	if (result != ISC_R_SUCCESS) {
188*4afad4b7Schristos 		tcpmsg->task = NULL;
189*4afad4b7Schristos 	}
190*4afad4b7Schristos 
191*4afad4b7Schristos 	return (result);
192*4afad4b7Schristos }
193*4afad4b7Schristos 
194*4afad4b7Schristos void
dns_tcpmsg_cancelread(dns_tcpmsg_t * tcpmsg)195*4afad4b7Schristos dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg) {
196*4afad4b7Schristos 	REQUIRE(VALID_TCPMSG(tcpmsg));
197*4afad4b7Schristos 
198*4afad4b7Schristos 	isc_socket_cancel(tcpmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
199*4afad4b7Schristos }
200*4afad4b7Schristos 
201*4afad4b7Schristos void
dns_tcpmsg_keepbuffer(dns_tcpmsg_t * tcpmsg,isc_buffer_t * buffer)202*4afad4b7Schristos dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer) {
203*4afad4b7Schristos 	REQUIRE(VALID_TCPMSG(tcpmsg));
204*4afad4b7Schristos 	REQUIRE(buffer != NULL);
205*4afad4b7Schristos 
206*4afad4b7Schristos 	*buffer = tcpmsg->buffer;
207*4afad4b7Schristos 	tcpmsg->buffer.base = NULL;
208*4afad4b7Schristos 	tcpmsg->buffer.length = 0;
209*4afad4b7Schristos }
210*4afad4b7Schristos 
211*4afad4b7Schristos #if 0
212*4afad4b7Schristos void
213*4afad4b7Schristos dns_tcpmsg_freebuffer(dns_tcpmsg_t *tcpmsg) {
214*4afad4b7Schristos 	REQUIRE(VALID_TCPMSG(tcpmsg));
215*4afad4b7Schristos 
216*4afad4b7Schristos 	if (tcpmsg->buffer.base == NULL) {
217*4afad4b7Schristos 		return;
218*4afad4b7Schristos 	}
219*4afad4b7Schristos 
220*4afad4b7Schristos 	isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, tcpmsg->buffer.length);
221*4afad4b7Schristos 	tcpmsg->buffer.base = NULL;
222*4afad4b7Schristos 	tcpmsg->buffer.length = 0;
223*4afad4b7Schristos }
224*4afad4b7Schristos #endif /* if 0 */
225*4afad4b7Schristos 
226*4afad4b7Schristos void
dns_tcpmsg_invalidate(dns_tcpmsg_t * tcpmsg)227*4afad4b7Schristos dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg) {
228*4afad4b7Schristos 	REQUIRE(VALID_TCPMSG(tcpmsg));
229*4afad4b7Schristos 
230*4afad4b7Schristos 	tcpmsg->magic = 0;
231*4afad4b7Schristos 
232*4afad4b7Schristos 	if (tcpmsg->buffer.base != NULL) {
233*4afad4b7Schristos 		isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base,
234*4afad4b7Schristos 			    tcpmsg->buffer.length);
235*4afad4b7Schristos 		tcpmsg->buffer.base = NULL;
236*4afad4b7Schristos 		tcpmsg->buffer.length = 0;
237*4afad4b7Schristos 	}
238*4afad4b7Schristos }
239