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