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