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