ccmsg.c revision 1.3.4.1 1 /* $NetBSD: ccmsg.c,v 1.3.4.1 2024/02/29 12:35:23 martin 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/netmgr.h>
38 #include <isc/result.h>
39 #include <isc/string.h>
40 #include <isc/util.h>
41
42 #include <isccc/ccmsg.h>
43 #include <isccc/events.h>
44
45 #define CCMSG_MAGIC ISC_MAGIC('C', 'C', 'm', 's')
46 #define VALID_CCMSG(foo) ISC_MAGIC_VALID(foo, CCMSG_MAGIC)
47
48 static void
49 recv_data(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
50 void *arg) {
51 isccc_ccmsg_t *ccmsg = arg;
52 size_t size;
53
54 INSIST(VALID_CCMSG(ccmsg));
55
56 switch (eresult) {
57 case ISC_R_SHUTTINGDOWN:
58 case ISC_R_CANCELED:
59 case ISC_R_EOF:
60 ccmsg->result = eresult;
61 goto done;
62 case ISC_R_SUCCESS:
63 if (region == NULL) {
64 ccmsg->result = ISC_R_EOF;
65 goto done;
66 }
67 ccmsg->result = ISC_R_SUCCESS;
68 break;
69 default:
70 ccmsg->result = eresult;
71 goto done;
72 }
73
74 if (!ccmsg->length_received) {
75 if (region->length < sizeof(uint32_t)) {
76 ccmsg->result = ISC_R_UNEXPECTEDEND;
77 goto done;
78 }
79
80 ccmsg->size = ntohl(*(uint32_t *)region->base);
81
82 if (ccmsg->size == 0) {
83 ccmsg->result = ISC_R_UNEXPECTEDEND;
84 goto done;
85 }
86 if (ccmsg->size > ccmsg->maxsize) {
87 ccmsg->result = ISC_R_RANGE;
88 goto done;
89 }
90
91 isc_region_consume(region, sizeof(uint32_t));
92 isc_buffer_allocate(ccmsg->mctx, &ccmsg->buffer, ccmsg->size);
93
94 ccmsg->length_received = true;
95 }
96
97 /*
98 * If there's no more data, wait for more
99 */
100 if (region->length == 0) {
101 return;
102 }
103
104 /* We have some data in the buffer, read it */
105
106 size = ISC_MIN(isc_buffer_availablelength(ccmsg->buffer),
107 region->length);
108 isc_buffer_putmem(ccmsg->buffer, region->base, size);
109 isc_region_consume(region, size);
110
111 if (isc_buffer_usedlength(ccmsg->buffer) == ccmsg->size) {
112 ccmsg->result = ISC_R_SUCCESS;
113 goto done;
114 }
115
116 /* Wait for more data to come */
117 return;
118
119 done:
120 isc_nm_pauseread(handle);
121 ccmsg->cb(handle, ccmsg->result, ccmsg->cbarg);
122 }
123
124 void
125 isccc_ccmsg_init(isc_mem_t *mctx, isc_nmhandle_t *handle,
126 isccc_ccmsg_t *ccmsg) {
127 REQUIRE(mctx != NULL);
128 REQUIRE(handle != NULL);
129 REQUIRE(ccmsg != NULL);
130
131 *ccmsg = (isccc_ccmsg_t){
132 .magic = CCMSG_MAGIC,
133 .maxsize = 0xffffffffU, /* Largest message possible. */
134 .mctx = mctx,
135 .handle = handle,
136 .result = ISC_R_UNEXPECTED /* None yet. */
137 };
138 }
139
140 void
141 isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize) {
142 REQUIRE(VALID_CCMSG(ccmsg));
143
144 ccmsg->maxsize = maxsize;
145 }
146
147 void
148 isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg, isc_nm_cb_t cb, void *cbarg) {
149 REQUIRE(VALID_CCMSG(ccmsg));
150
151 if (ccmsg->buffer != NULL) {
152 isc_buffer_free(&ccmsg->buffer);
153 }
154
155 ccmsg->cb = cb;
156 ccmsg->cbarg = cbarg;
157 ccmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
158 ccmsg->length_received = false;
159
160 if (ccmsg->reading) {
161 isc_nm_resumeread(ccmsg->handle);
162 } else {
163 isc_nm_read(ccmsg->handle, recv_data, ccmsg);
164 ccmsg->reading = true;
165 }
166 }
167
168 void
169 isccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg) {
170 REQUIRE(VALID_CCMSG(ccmsg));
171
172 if (ccmsg->reading) {
173 isc_nm_cancelread(ccmsg->handle);
174 ccmsg->reading = false;
175 }
176 }
177
178 void
179 isccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg) {
180 REQUIRE(VALID_CCMSG(ccmsg));
181
182 ccmsg->magic = 0;
183
184 if (ccmsg->buffer != NULL) {
185 isc_buffer_free(&ccmsg->buffer);
186 }
187 }
188