1*bcda20f6Schristos /* $NetBSD: ccmsg.c,v 1.8 2025/01/26 16:25:44 christos Exp $ */ 2d68c78b8Schristos 3d68c78b8Schristos /* 48596601aSchristos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 58596601aSchristos * 68596601aSchristos * SPDX-License-Identifier: MPL-2.0 AND ISC 7d68c78b8Schristos * 8d68c78b8Schristos * This Source Code Form is subject to the terms of the Mozilla Public 9d68c78b8Schristos * License, v. 2.0. If a copy of the MPL was not distributed with this 10fce770bdSchristos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11d68c78b8Schristos * 12d68c78b8Schristos * See the COPYRIGHT file distributed with this work for additional 13d68c78b8Schristos * information regarding copyright ownership. 148596601aSchristos */ 158596601aSchristos 168596601aSchristos /* 178596601aSchristos * Copyright (C) 2001 Nominum, Inc. 18d68c78b8Schristos * 19d68c78b8Schristos * Permission to use, copy, modify, and/or distribute this software for any 20d68c78b8Schristos * purpose with or without fee is hereby granted, provided that the above 21d68c78b8Schristos * copyright notice and this permission notice appear in all copies. 22d68c78b8Schristos * 23d68c78b8Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL 24d68c78b8Schristos * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 25d68c78b8Schristos * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY 26d68c78b8Schristos * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 27d68c78b8Schristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 28d68c78b8Schristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 29d68c78b8Schristos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 30d68c78b8Schristos */ 31d68c78b8Schristos 32d68c78b8Schristos /*! \file */ 33d68c78b8Schristos 34d4a20c3eSchristos #include <inttypes.h> 35d4a20c3eSchristos 36d68c78b8Schristos #include <isc/mem.h> 37bb5aa156Schristos #include <isc/netmgr.h> 38d68c78b8Schristos #include <isc/result.h> 39bb5aa156Schristos #include <isc/string.h> 40d68c78b8Schristos #include <isc/util.h> 41d68c78b8Schristos 42d68c78b8Schristos #include <isccc/ccmsg.h> 43d68c78b8Schristos 44d68c78b8Schristos #define CCMSG_MAGIC ISC_MAGIC('C', 'C', 'm', 's') 45d68c78b8Schristos #define VALID_CCMSG(foo) ISC_MAGIC_VALID(foo, CCMSG_MAGIC) 46d68c78b8Schristos 47*bcda20f6Schristos /* 48*bcda20f6Schristos * Try parsing a message from the internal read_buffer and set state 49*bcda20f6Schristos * accordingly. Returns true if a message was successfully parsed, false if not. 50*bcda20f6Schristos * If no message could be parsed the ccmsg struct remains untouched. 51*bcda20f6Schristos */ 52*bcda20f6Schristos static isc_result_t 53*bcda20f6Schristos try_parse_message(isccc_ccmsg_t *ccmsg) { 54*bcda20f6Schristos REQUIRE(ccmsg != NULL); 55*bcda20f6Schristos 56*bcda20f6Schristos uint32_t len = 0; 57*bcda20f6Schristos if (isc_buffer_peekuint32(ccmsg->buffer, &len) != ISC_R_SUCCESS) { 58*bcda20f6Schristos return ISC_R_NOMORE; 59*bcda20f6Schristos } 60*bcda20f6Schristos if (len == 0) { 61*bcda20f6Schristos return ISC_R_UNEXPECTEDEND; 62*bcda20f6Schristos } 63*bcda20f6Schristos if (len > ccmsg->maxsize) { 64*bcda20f6Schristos return ISC_R_RANGE; 65*bcda20f6Schristos } 66*bcda20f6Schristos if (isc_buffer_remaininglength(ccmsg->buffer) < sizeof(uint32_t) + len) 67*bcda20f6Schristos { 68*bcda20f6Schristos return ISC_R_NOMORE; 69*bcda20f6Schristos } 70*bcda20f6Schristos /* Skip the size we just peeked */ 71*bcda20f6Schristos isc_buffer_forward(ccmsg->buffer, sizeof(uint32_t)); 72*bcda20f6Schristos ccmsg->size = len; 73*bcda20f6Schristos return ISC_R_SUCCESS; 74*bcda20f6Schristos } 75*bcda20f6Schristos 765606745fSchristos static void 77bb5aa156Schristos recv_data(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, 78bb5aa156Schristos void *arg) { 79bb5aa156Schristos isccc_ccmsg_t *ccmsg = arg; 80d68c78b8Schristos 81*bcda20f6Schristos REQUIRE(VALID_CCMSG(ccmsg)); 82d68c78b8Schristos 83*bcda20f6Schristos REQUIRE(handle == ccmsg->handle); 84*bcda20f6Schristos if (eresult != ISC_R_SUCCESS) { 85bb5aa156Schristos goto done; 86d68c78b8Schristos } 87d68c78b8Schristos 88*bcda20f6Schristos REQUIRE(region != NULL); 89*bcda20f6Schristos 90*bcda20f6Schristos /* Copy the received data to our reassembly buffer */ 91*bcda20f6Schristos eresult = isc_buffer_copyregion(ccmsg->buffer, region); 92*bcda20f6Schristos if (eresult != ISC_R_SUCCESS) { 93bb5aa156Schristos goto done; 94bb5aa156Schristos } 95*bcda20f6Schristos isc_region_consume(region, region->length); 96bb5aa156Schristos 97*bcda20f6Schristos /* Try to parse a single message of the buffer */ 98*bcda20f6Schristos eresult = try_parse_message(ccmsg); 99*bcda20f6Schristos /* No results from parsing, we need more data */ 100*bcda20f6Schristos if (eresult == ISC_R_NOMORE) { 101d68c78b8Schristos return; 102d68c78b8Schristos } 103d68c78b8Schristos 104bb5aa156Schristos done: 105*bcda20f6Schristos isc_nm_read_stop(handle); 106*bcda20f6Schristos ccmsg->recv_cb(handle, eresult, ccmsg->recv_cbarg); 107*bcda20f6Schristos 108*bcda20f6Schristos return; 109d68c78b8Schristos } 110d68c78b8Schristos 111d68c78b8Schristos void 112bb5aa156Schristos isccc_ccmsg_init(isc_mem_t *mctx, isc_nmhandle_t *handle, 113bb5aa156Schristos isccc_ccmsg_t *ccmsg) { 114d68c78b8Schristos REQUIRE(mctx != NULL); 115bb5aa156Schristos REQUIRE(handle != NULL); 116d68c78b8Schristos REQUIRE(ccmsg != NULL); 117d68c78b8Schristos 118bb5aa156Schristos *ccmsg = (isccc_ccmsg_t){ 119bb5aa156Schristos .magic = CCMSG_MAGIC, 120bb5aa156Schristos .maxsize = 0xffffffffU, /* Largest message possible. */ 121bb5aa156Schristos .mctx = mctx, 122bb5aa156Schristos }; 123*bcda20f6Schristos 124*bcda20f6Schristos /* Preallocate the buffer to maximum single TCP read */ 125*bcda20f6Schristos isc_buffer_allocate(ccmsg->mctx, &ccmsg->buffer, 126*bcda20f6Schristos UINT16_MAX + sizeof(uint16_t)); 127*bcda20f6Schristos 128*bcda20f6Schristos isc_nmhandle_attach(handle, &ccmsg->handle); 129d68c78b8Schristos } 130d68c78b8Schristos 131d68c78b8Schristos void 132d68c78b8Schristos isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize) { 133d68c78b8Schristos REQUIRE(VALID_CCMSG(ccmsg)); 134d68c78b8Schristos 135d68c78b8Schristos ccmsg->maxsize = maxsize; 136d68c78b8Schristos } 137d68c78b8Schristos 138bb5aa156Schristos void 139bb5aa156Schristos isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg, isc_nm_cb_t cb, void *cbarg) { 140d68c78b8Schristos REQUIRE(VALID_CCMSG(ccmsg)); 141d68c78b8Schristos 142*bcda20f6Schristos if (ccmsg->size != 0) { 143*bcda20f6Schristos /* Remove the previously read message from the buffer */ 144*bcda20f6Schristos isc_buffer_forward(ccmsg->buffer, ccmsg->size); 145*bcda20f6Schristos ccmsg->size = 0; 146*bcda20f6Schristos isc_buffer_trycompact(ccmsg->buffer); 147d68c78b8Schristos } 148d68c78b8Schristos 149*bcda20f6Schristos ccmsg->recv_cb = cb; 150*bcda20f6Schristos ccmsg->recv_cbarg = cbarg; 151d68c78b8Schristos 152*bcda20f6Schristos /* If we have previous data still in the buffer, try to parse it */ 153*bcda20f6Schristos isc_result_t result = try_parse_message(ccmsg); 154*bcda20f6Schristos if (result == ISC_R_NOMORE) { 155*bcda20f6Schristos /* We need to read more data */ 156bb5aa156Schristos isc_nm_read(ccmsg->handle, recv_data, ccmsg); 157*bcda20f6Schristos return; 1585606745fSchristos } 159*bcda20f6Schristos 160*bcda20f6Schristos ccmsg->recv_cb(ccmsg->handle, result, ccmsg->recv_cbarg); 161*bcda20f6Schristos } 162*bcda20f6Schristos 163*bcda20f6Schristos static void 164*bcda20f6Schristos ccmsg_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { 165*bcda20f6Schristos isccc_ccmsg_t *ccmsg = arg; 166*bcda20f6Schristos 167*bcda20f6Schristos REQUIRE(VALID_CCMSG(ccmsg)); 168*bcda20f6Schristos REQUIRE(ccmsg->send_cb != NULL); 169*bcda20f6Schristos 170*bcda20f6Schristos isc_nm_cb_t send_cb = ccmsg->send_cb; 171*bcda20f6Schristos ccmsg->send_cb = NULL; 172*bcda20f6Schristos 173*bcda20f6Schristos send_cb(handle, eresult, ccmsg->send_cbarg); 174*bcda20f6Schristos 175*bcda20f6Schristos isc_nmhandle_detach(&handle); 176d68c78b8Schristos } 177d68c78b8Schristos 178d68c78b8Schristos void 179*bcda20f6Schristos isccc_ccmsg_sendmessage(isccc_ccmsg_t *ccmsg, isc_region_t *region, 180*bcda20f6Schristos isc_nm_cb_t cb, void *cbarg) { 181*bcda20f6Schristos REQUIRE(VALID_CCMSG(ccmsg)); 182*bcda20f6Schristos REQUIRE(ccmsg->send_cb == NULL); 183*bcda20f6Schristos 184*bcda20f6Schristos ccmsg->send_cb = cb; 185*bcda20f6Schristos ccmsg->send_cbarg = cbarg; 186*bcda20f6Schristos 187*bcda20f6Schristos isc_nmhandle_ref(ccmsg->handle); 188*bcda20f6Schristos isc_nm_send(ccmsg->handle, region, ccmsg_senddone, ccmsg); 189*bcda20f6Schristos } 190*bcda20f6Schristos 191*bcda20f6Schristos void 192*bcda20f6Schristos isccc_ccmsg_disconnect(isccc_ccmsg_t *ccmsg) { 193d68c78b8Schristos REQUIRE(VALID_CCMSG(ccmsg)); 194d68c78b8Schristos 195*bcda20f6Schristos if (ccmsg->handle != NULL) { 196*bcda20f6Schristos isc_nm_read_stop(ccmsg->handle); 197*bcda20f6Schristos isc_nmhandle_close(ccmsg->handle); 198*bcda20f6Schristos isc_nmhandle_detach(&ccmsg->handle); 199d68c78b8Schristos } 2005606745fSchristos } 201d68c78b8Schristos 202d68c78b8Schristos void 203d68c78b8Schristos isccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg) { 204d68c78b8Schristos REQUIRE(VALID_CCMSG(ccmsg)); 205*bcda20f6Schristos REQUIRE(ccmsg->handle == NULL); 206d68c78b8Schristos 207d68c78b8Schristos ccmsg->magic = 0; 208d68c78b8Schristos 209bb5aa156Schristos isc_buffer_free(&ccmsg->buffer); 210d68c78b8Schristos } 211*bcda20f6Schristos 212*bcda20f6Schristos void 213*bcda20f6Schristos isccc_ccmsg_toregion(isccc_ccmsg_t *ccmsg, isccc_region_t *ccregion) { 214*bcda20f6Schristos REQUIRE(VALID_CCMSG(ccmsg)); 215*bcda20f6Schristos REQUIRE(ccmsg->buffer); 216*bcda20f6Schristos REQUIRE(isc_buffer_remaininglength(ccmsg->buffer) >= ccmsg->size); 217*bcda20f6Schristos 218*bcda20f6Schristos ccregion->rstart = isc_buffer_current(ccmsg->buffer); 219*bcda20f6Schristos ccregion->rend = ccregion->rstart + ccmsg->size; 220d68c78b8Schristos } 221