xref: /netbsd/external/mpl/bind/dist/lib/isccc/ccmsg.c (revision c0b5d9fb)
1 /*	$NetBSD: ccmsg.c,v 1.6 2022/09/23 12:15:35 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0 AND ISC
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*
17  * Copyright (C) 2001 Nominum, Inc.
18  *
19  * Permission to use, copy, modify, and/or distribute this software for any
20  * purpose with or without fee is hereby granted, provided that the above
21  * copyright notice and this permission notice appear in all copies.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
24  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
26  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30  */
31 
32 /*! \file */
33 
34 #include <inttypes.h>
35 
36 #include <isc/mem.h>
37 #include <isc/result.h>
38 #include <isc/task.h>
39 #include <isc/util.h>
40 
41 #include <isccc/ccmsg.h>
42 #include <isccc/events.h>
43 
44 #define CCMSG_MAGIC	 ISC_MAGIC('C', 'C', 'm', 's')
45 #define VALID_CCMSG(foo) ISC_MAGIC_VALID(foo, CCMSG_MAGIC)
46 
47 static void
48 recv_length(isc_task_t *, isc_event_t *);
49 static void
50 recv_message(isc_task_t *, isc_event_t *);
51 
52 static void
recv_length(isc_task_t * task,isc_event_t * ev_in)53 recv_length(isc_task_t *task, isc_event_t *ev_in) {
54 	isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
55 	isc_event_t *dev;
56 	isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
57 	isc_region_t region;
58 	isc_result_t result;
59 
60 	INSIST(VALID_CCMSG(ccmsg));
61 
62 	dev = &ccmsg->event;
63 
64 	if (ev->result != ISC_R_SUCCESS) {
65 		ccmsg->result = ev->result;
66 		goto send_and_free;
67 	}
68 
69 	/*
70 	 * Success.
71 	 */
72 	ccmsg->size = ntohl(ccmsg->size);
73 	if (ccmsg->size == 0) {
74 		ccmsg->result = ISC_R_UNEXPECTEDEND;
75 		goto send_and_free;
76 	}
77 	if (ccmsg->size > ccmsg->maxsize) {
78 		ccmsg->result = ISC_R_RANGE;
79 		goto send_and_free;
80 	}
81 
82 	region.base = isc_mem_get(ccmsg->mctx, ccmsg->size);
83 	region.length = ccmsg->size;
84 	if (region.base == NULL) {
85 		ccmsg->result = ISC_R_NOMEMORY;
86 		goto send_and_free;
87 	}
88 
89 	isc_buffer_init(&ccmsg->buffer, region.base, region.length);
90 	result = isc_socket_recv(ccmsg->sock, &region, 0, task, recv_message,
91 				 ccmsg);
92 	if (result != ISC_R_SUCCESS) {
93 		ccmsg->result = result;
94 		goto send_and_free;
95 	}
96 
97 	isc_event_free(&ev_in);
98 	return;
99 
100 send_and_free:
101 	isc_task_send(ccmsg->task, &dev);
102 	ccmsg->task = NULL;
103 	isc_event_free(&ev_in);
104 	return;
105 }
106 
107 static void
recv_message(isc_task_t * task,isc_event_t * ev_in)108 recv_message(isc_task_t *task, isc_event_t *ev_in) {
109 	isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
110 	isc_event_t *dev;
111 	isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
112 
113 	(void)task;
114 
115 	INSIST(VALID_CCMSG(ccmsg));
116 
117 	dev = &ccmsg->event;
118 
119 	if (ev->result != ISC_R_SUCCESS) {
120 		ccmsg->result = ev->result;
121 		goto send_and_free;
122 	}
123 
124 	ccmsg->result = ISC_R_SUCCESS;
125 	isc_buffer_add(&ccmsg->buffer, ev->n);
126 	ccmsg->address = ev->address;
127 
128 send_and_free:
129 	isc_task_send(ccmsg->task, &dev);
130 	ccmsg->task = NULL;
131 	isc_event_free(&ev_in);
132 }
133 
134 void
isccc_ccmsg_init(isc_mem_t * mctx,isc_socket_t * sock,isccc_ccmsg_t * ccmsg)135 isccc_ccmsg_init(isc_mem_t *mctx, isc_socket_t *sock, isccc_ccmsg_t *ccmsg) {
136 	REQUIRE(mctx != NULL);
137 	REQUIRE(sock != NULL);
138 	REQUIRE(ccmsg != NULL);
139 
140 	ccmsg->magic = CCMSG_MAGIC;
141 	ccmsg->size = 0;
142 	ccmsg->buffer.base = NULL;
143 	ccmsg->buffer.length = 0;
144 	ccmsg->maxsize = 4294967295U; /* Largest message possible. */
145 	ccmsg->mctx = mctx;
146 	ccmsg->sock = sock;
147 	ccmsg->task = NULL;		  /* None yet. */
148 	ccmsg->result = ISC_R_UNEXPECTED; /* None yet. */
149 					  /*
150 					   * Should probably initialize the
151 					   *event here, but it can wait.
152 					   */
153 }
154 
155 void
isccc_ccmsg_setmaxsize(isccc_ccmsg_t * ccmsg,unsigned int maxsize)156 isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize) {
157 	REQUIRE(VALID_CCMSG(ccmsg));
158 
159 	ccmsg->maxsize = maxsize;
160 }
161 
162 isc_result_t
isccc_ccmsg_readmessage(isccc_ccmsg_t * ccmsg,isc_task_t * task,isc_taskaction_t action,void * arg)163 isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg, isc_task_t *task,
164 			isc_taskaction_t action, void *arg) {
165 	isc_result_t result;
166 	isc_region_t region;
167 
168 	REQUIRE(VALID_CCMSG(ccmsg));
169 	REQUIRE(task != NULL);
170 	REQUIRE(ccmsg->task == NULL); /* not currently in use */
171 
172 	if (ccmsg->buffer.base != NULL) {
173 		isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
174 			    ccmsg->buffer.length);
175 		ccmsg->buffer.base = NULL;
176 		ccmsg->buffer.length = 0;
177 	}
178 
179 	ccmsg->task = task;
180 	ccmsg->action = action;
181 	ccmsg->arg = arg;
182 	ccmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
183 
184 	ISC_EVENT_INIT(&ccmsg->event, sizeof(isc_event_t), 0, 0,
185 		       ISCCC_EVENT_CCMSG, action, arg, ccmsg, NULL, NULL);
186 
187 	region.base = (unsigned char *)&ccmsg->size;
188 	region.length = 4; /* uint32_t */
189 	result = isc_socket_recv(ccmsg->sock, &region, 0, ccmsg->task,
190 				 recv_length, ccmsg);
191 
192 	if (result != ISC_R_SUCCESS) {
193 		ccmsg->task = NULL;
194 	}
195 
196 	return (result);
197 }
198 
199 void
isccc_ccmsg_cancelread(isccc_ccmsg_t * ccmsg)200 isccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg) {
201 	REQUIRE(VALID_CCMSG(ccmsg));
202 
203 	isc_socket_cancel(ccmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
204 }
205 
206 #if 0
207 void
208 isccc_ccmsg_freebuffer(isccc_ccmsg_t*ccmsg) {
209 	REQUIRE(VALID_CCMSG(ccmsg));
210 
211 	if (ccmsg->buffer.base == NULL) {
212 		return;
213 	}
214 
215 	isc_mem_put(ccmsg->mctx,ccmsg->buffer.base,ccmsg->buffer.length);
216 	ccmsg->buffer.base = NULL;
217 	ccmsg->buffer.length = 0;
218 }
219 #endif /* if 0 */
220 
221 void
isccc_ccmsg_invalidate(isccc_ccmsg_t * ccmsg)222 isccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg) {
223 	REQUIRE(VALID_CCMSG(ccmsg));
224 
225 	ccmsg->magic = 0;
226 
227 	if (ccmsg->buffer.base != NULL) {
228 		isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
229 			    ccmsg->buffer.length);
230 		ccmsg->buffer.base = NULL;
231 		ccmsg->buffer.length = 0;
232 	}
233 }
234