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, ®ion, 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, ®ion, 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