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