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