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