ccmsg.c revision 1.3 1 1.2 christos /* $NetBSD: ccmsg.c,v 1.3 2019/01/09 16:55:18 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.1 christos * file, You can obtain one at http://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
29 1.1 christos /*! \file */
30 1.1 christos
31 1.1 christos #include <config.h>
32 1.1 christos
33 1.3 christos #include <inttypes.h>
34 1.3 christos
35 1.1 christos #include <isc/mem.h>
36 1.1 christos #include <isc/result.h>
37 1.1 christos #include <isc/task.h>
38 1.1 christos #include <isc/util.h>
39 1.1 christos
40 1.1 christos #include <isccc/events.h>
41 1.1 christos #include <isccc/ccmsg.h>
42 1.1 christos
43 1.1 christos #define CCMSG_MAGIC ISC_MAGIC('C', 'C', 'm', 's')
44 1.1 christos #define VALID_CCMSG(foo) ISC_MAGIC_VALID(foo, CCMSG_MAGIC)
45 1.1 christos
46 1.1 christos static void recv_length(isc_task_t *, isc_event_t *);
47 1.1 christos static void recv_message(isc_task_t *, isc_event_t *);
48 1.1 christos
49 1.1 christos
50 1.1 christos static void
51 1.1 christos recv_length(isc_task_t *task, isc_event_t *ev_in) {
52 1.1 christos isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
53 1.1 christos isc_event_t *dev;
54 1.1 christos isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
55 1.1 christos isc_region_t region;
56 1.1 christos isc_result_t result;
57 1.1 christos
58 1.1 christos INSIST(VALID_CCMSG(ccmsg));
59 1.1 christos
60 1.1 christos dev = &ccmsg->event;
61 1.1 christos
62 1.1 christos if (ev->result != ISC_R_SUCCESS) {
63 1.1 christos ccmsg->result = ev->result;
64 1.1 christos goto send_and_free;
65 1.1 christos }
66 1.1 christos
67 1.1 christos /*
68 1.1 christos * Success.
69 1.1 christos */
70 1.1 christos ccmsg->size = ntohl(ccmsg->size);
71 1.1 christos if (ccmsg->size == 0) {
72 1.1 christos ccmsg->result = ISC_R_UNEXPECTEDEND;
73 1.1 christos goto send_and_free;
74 1.1 christos }
75 1.1 christos if (ccmsg->size > ccmsg->maxsize) {
76 1.1 christos ccmsg->result = ISC_R_RANGE;
77 1.1 christos goto send_and_free;
78 1.1 christos }
79 1.1 christos
80 1.1 christos region.base = isc_mem_get(ccmsg->mctx, ccmsg->size);
81 1.1 christos region.length = ccmsg->size;
82 1.1 christos if (region.base == NULL) {
83 1.1 christos ccmsg->result = ISC_R_NOMEMORY;
84 1.1 christos goto send_and_free;
85 1.1 christos }
86 1.1 christos
87 1.1 christos isc_buffer_init(&ccmsg->buffer, region.base, region.length);
88 1.1 christos result = isc_socket_recv(ccmsg->sock, ®ion, 0,
89 1.1 christos task, recv_message, ccmsg);
90 1.1 christos if (result != ISC_R_SUCCESS) {
91 1.1 christos ccmsg->result = result;
92 1.1 christos goto send_and_free;
93 1.1 christos }
94 1.1 christos
95 1.1 christos isc_event_free(&ev_in);
96 1.1 christos return;
97 1.1 christos
98 1.1 christos send_and_free:
99 1.1 christos isc_task_send(ccmsg->task, &dev);
100 1.1 christos ccmsg->task = NULL;
101 1.1 christos isc_event_free(&ev_in);
102 1.1 christos return;
103 1.1 christos }
104 1.1 christos
105 1.1 christos static void
106 1.1 christos recv_message(isc_task_t *task, isc_event_t *ev_in) {
107 1.1 christos isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
108 1.1 christos isc_event_t *dev;
109 1.1 christos isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
110 1.1 christos
111 1.1 christos (void)task;
112 1.1 christos
113 1.1 christos INSIST(VALID_CCMSG(ccmsg));
114 1.1 christos
115 1.1 christos dev = &ccmsg->event;
116 1.1 christos
117 1.1 christos if (ev->result != ISC_R_SUCCESS) {
118 1.1 christos ccmsg->result = ev->result;
119 1.1 christos goto send_and_free;
120 1.1 christos }
121 1.1 christos
122 1.1 christos ccmsg->result = ISC_R_SUCCESS;
123 1.1 christos isc_buffer_add(&ccmsg->buffer, ev->n);
124 1.1 christos ccmsg->address = ev->address;
125 1.1 christos
126 1.1 christos send_and_free:
127 1.1 christos isc_task_send(ccmsg->task, &dev);
128 1.1 christos ccmsg->task = NULL;
129 1.1 christos isc_event_free(&ev_in);
130 1.1 christos }
131 1.1 christos
132 1.1 christos void
133 1.1 christos isccc_ccmsg_init(isc_mem_t *mctx, isc_socket_t *sock, isccc_ccmsg_t *ccmsg) {
134 1.1 christos REQUIRE(mctx != NULL);
135 1.1 christos REQUIRE(sock != NULL);
136 1.1 christos REQUIRE(ccmsg != NULL);
137 1.1 christos
138 1.1 christos ccmsg->magic = CCMSG_MAGIC;
139 1.1 christos ccmsg->size = 0;
140 1.1 christos ccmsg->buffer.base = NULL;
141 1.1 christos ccmsg->buffer.length = 0;
142 1.1 christos ccmsg->maxsize = 4294967295U; /* Largest message possible. */
143 1.1 christos ccmsg->mctx = mctx;
144 1.1 christos ccmsg->sock = sock;
145 1.1 christos ccmsg->task = NULL; /* None yet. */
146 1.1 christos ccmsg->result = ISC_R_UNEXPECTED; /* None yet. */
147 1.1 christos /*
148 1.1 christos * Should probably initialize the event here, but it can wait.
149 1.1 christos */
150 1.1 christos }
151 1.1 christos
152 1.1 christos
153 1.1 christos void
154 1.1 christos isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize) {
155 1.1 christos REQUIRE(VALID_CCMSG(ccmsg));
156 1.1 christos
157 1.1 christos ccmsg->maxsize = maxsize;
158 1.1 christos }
159 1.1 christos
160 1.1 christos
161 1.1 christos isc_result_t
162 1.1 christos isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg,
163 1.1 christos isc_task_t *task, isc_taskaction_t action, void *arg)
164 1.1 christos {
165 1.1 christos isc_result_t result;
166 1.1 christos isc_region_t region;
167 1.1 christos
168 1.1 christos REQUIRE(VALID_CCMSG(ccmsg));
169 1.1 christos REQUIRE(task != NULL);
170 1.1 christos REQUIRE(ccmsg->task == NULL); /* not currently in use */
171 1.1 christos
172 1.1 christos if (ccmsg->buffer.base != NULL) {
173 1.1 christos isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
174 1.1 christos ccmsg->buffer.length);
175 1.1 christos ccmsg->buffer.base = NULL;
176 1.1 christos ccmsg->buffer.length = 0;
177 1.1 christos }
178 1.1 christos
179 1.1 christos ccmsg->task = task;
180 1.1 christos ccmsg->action = action;
181 1.1 christos ccmsg->arg = arg;
182 1.1 christos ccmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
183 1.1 christos
184 1.1 christos ISC_EVENT_INIT(&ccmsg->event, sizeof(isc_event_t), 0, 0,
185 1.1 christos ISCCC_EVENT_CCMSG, action, arg, ccmsg,
186 1.1 christos NULL, NULL);
187 1.1 christos
188 1.1 christos region.base = (unsigned char *)&ccmsg->size;
189 1.3 christos region.length = 4; /* uint32_t */
190 1.1 christos result = isc_socket_recv(ccmsg->sock, ®ion, 0,
191 1.1 christos ccmsg->task, recv_length, ccmsg);
192 1.1 christos
193 1.1 christos if (result != ISC_R_SUCCESS)
194 1.1 christos ccmsg->task = NULL;
195 1.1 christos
196 1.1 christos return (result);
197 1.1 christos }
198 1.1 christos
199 1.1 christos void
200 1.1 christos isccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg) {
201 1.1 christos REQUIRE(VALID_CCMSG(ccmsg));
202 1.1 christos
203 1.1 christos isc_socket_cancel(ccmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
204 1.1 christos }
205 1.1 christos
206 1.1 christos #if 0
207 1.1 christos void
208 1.1 christos isccc_ccmsg_freebuffer(isccc_ccmsg_t *ccmsg) {
209 1.1 christos REQUIRE(VALID_CCMSG(ccmsg));
210 1.1 christos
211 1.1 christos if (ccmsg->buffer.base == NULL)
212 1.1 christos return;
213 1.1 christos
214 1.1 christos isc_mem_put(ccmsg->mctx, ccmsg->buffer.base, ccmsg->buffer.length);
215 1.1 christos ccmsg->buffer.base = NULL;
216 1.1 christos ccmsg->buffer.length = 0;
217 1.1 christos }
218 1.1 christos #endif
219 1.1 christos
220 1.1 christos void
221 1.1 christos isccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg) {
222 1.1 christos REQUIRE(VALID_CCMSG(ccmsg));
223 1.1 christos
224 1.1 christos ccmsg->magic = 0;
225 1.1 christos
226 1.1 christos if (ccmsg->buffer.base != NULL) {
227 1.1 christos isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
228 1.1 christos ccmsg->buffer.length);
229 1.1 christos ccmsg->buffer.base = NULL;
230 1.1 christos ccmsg->buffer.length = 0;
231 1.1 christos }
232 1.1 christos }
233