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