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