1 /* $NetBSD: tcpmsg.c,v 1.4 2014/12/10 04:37:58 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-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 DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: tcpmsg.c,v 1.31 2007/06/19 23:47:16 tbox Exp */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <isc/mem.h> 27 #include <isc/task.h> 28 #include <isc/util.h> 29 30 #include <dns/events.h> 31 #include <dns/result.h> 32 #include <dns/tcpmsg.h> 33 34 #ifdef TCPMSG_DEBUG 35 #include <stdio.h> /* Required for printf. */ 36 #define XDEBUG(x) printf x 37 #else 38 #define XDEBUG(x) 39 #endif 40 41 #define TCPMSG_MAGIC ISC_MAGIC('T', 'C', 'P', 'm') 42 #define VALID_TCPMSG(foo) ISC_MAGIC_VALID(foo, TCPMSG_MAGIC) 43 44 static void recv_length(isc_task_t *, isc_event_t *); 45 static void recv_message(isc_task_t *, isc_event_t *); 46 47 48 static void recv_length(isc_task_t * task,isc_event_t * ev_in)49 recv_length(isc_task_t *task, isc_event_t *ev_in) { 50 isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; 51 isc_event_t *dev; 52 dns_tcpmsg_t *tcpmsg = ev_in->ev_arg; 53 isc_region_t region; 54 isc_result_t result; 55 56 INSIST(VALID_TCPMSG(tcpmsg)); 57 58 dev = &tcpmsg->event; 59 tcpmsg->address = ev->address; 60 61 if (ev->result != ISC_R_SUCCESS) { 62 tcpmsg->result = ev->result; 63 goto send_and_free; 64 } 65 66 /* 67 * Success. 68 */ 69 tcpmsg->size = ntohs(tcpmsg->size); 70 if (tcpmsg->size == 0) { 71 tcpmsg->result = ISC_R_UNEXPECTEDEND; 72 goto send_and_free; 73 } 74 if (tcpmsg->size > tcpmsg->maxsize) { 75 tcpmsg->result = ISC_R_RANGE; 76 goto send_and_free; 77 } 78 79 region.base = isc_mem_get(tcpmsg->mctx, tcpmsg->size); 80 region.length = tcpmsg->size; 81 if (region.base == NULL) { 82 tcpmsg->result = ISC_R_NOMEMORY; 83 goto send_and_free; 84 } 85 XDEBUG(("Allocated %d bytes\n", tcpmsg->size)); 86 87 isc_buffer_init(&tcpmsg->buffer, region.base, region.length); 88 result = isc_socket_recv(tcpmsg->sock, ®ion, 0, 89 task, recv_message, tcpmsg); 90 if (result != ISC_R_SUCCESS) { 91 tcpmsg->result = result; 92 goto send_and_free; 93 } 94 95 isc_event_free(&ev_in); 96 return; 97 98 send_and_free: 99 isc_task_send(tcpmsg->task, &dev); 100 tcpmsg->task = NULL; 101 isc_event_free(&ev_in); 102 return; 103 } 104 105 static void recv_message(isc_task_t * task,isc_event_t * ev_in)106 recv_message(isc_task_t *task, isc_event_t *ev_in) { 107 isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; 108 isc_event_t *dev; 109 dns_tcpmsg_t *tcpmsg = ev_in->ev_arg; 110 111 (void)task; 112 113 INSIST(VALID_TCPMSG(tcpmsg)); 114 115 dev = &tcpmsg->event; 116 tcpmsg->address = ev->address; 117 118 if (ev->result != ISC_R_SUCCESS) { 119 tcpmsg->result = ev->result; 120 goto send_and_free; 121 } 122 123 tcpmsg->result = ISC_R_SUCCESS; 124 isc_buffer_add(&tcpmsg->buffer, ev->n); 125 126 XDEBUG(("Received %d bytes (of %d)\n", ev->n, tcpmsg->size)); 127 128 send_and_free: 129 isc_task_send(tcpmsg->task, &dev); 130 tcpmsg->task = NULL; 131 isc_event_free(&ev_in); 132 } 133 134 void dns_tcpmsg_init(isc_mem_t * mctx,isc_socket_t * sock,dns_tcpmsg_t * tcpmsg)135 dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg) { 136 REQUIRE(mctx != NULL); 137 REQUIRE(sock != NULL); 138 REQUIRE(tcpmsg != NULL); 139 140 tcpmsg->magic = TCPMSG_MAGIC; 141 tcpmsg->size = 0; 142 tcpmsg->buffer.base = NULL; 143 tcpmsg->buffer.length = 0; 144 tcpmsg->maxsize = 65535; /* Largest message possible. */ 145 tcpmsg->mctx = mctx; 146 tcpmsg->sock = sock; 147 tcpmsg->task = NULL; /* None yet. */ 148 tcpmsg->result = ISC_R_UNEXPECTED; /* None yet. */ 149 /* 150 * Should probably initialize the event here, but it can wait. 151 */ 152 } 153 154 155 void dns_tcpmsg_setmaxsize(dns_tcpmsg_t * tcpmsg,unsigned int maxsize)156 dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize) { 157 REQUIRE(VALID_TCPMSG(tcpmsg)); 158 REQUIRE(maxsize < 65536); 159 160 tcpmsg->maxsize = maxsize; 161 } 162 163 164 isc_result_t dns_tcpmsg_readmessage(dns_tcpmsg_t * tcpmsg,isc_task_t * task,isc_taskaction_t action,void * arg)165 dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg, 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_TCPMSG(tcpmsg)); 172 REQUIRE(task != NULL); 173 REQUIRE(tcpmsg->task == NULL); /* not currently in use */ 174 175 if (tcpmsg->buffer.base != NULL) { 176 isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, 177 tcpmsg->buffer.length); 178 tcpmsg->buffer.base = NULL; 179 tcpmsg->buffer.length = 0; 180 } 181 182 tcpmsg->task = task; 183 tcpmsg->action = action; 184 tcpmsg->arg = arg; 185 tcpmsg->result = ISC_R_UNEXPECTED; /* unknown right now */ 186 187 ISC_EVENT_INIT(&tcpmsg->event, sizeof(isc_event_t), 0, 0, 188 DNS_EVENT_TCPMSG, action, arg, tcpmsg, 189 NULL, NULL); 190 191 region.base = (unsigned char *)&tcpmsg->size; 192 region.length = 2; /* isc_uint16_t */ 193 result = isc_socket_recv(tcpmsg->sock, ®ion, 0, 194 tcpmsg->task, recv_length, tcpmsg); 195 196 if (result != ISC_R_SUCCESS) 197 tcpmsg->task = NULL; 198 199 return (result); 200 } 201 202 void dns_tcpmsg_cancelread(dns_tcpmsg_t * tcpmsg)203 dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg) { 204 REQUIRE(VALID_TCPMSG(tcpmsg)); 205 206 isc_socket_cancel(tcpmsg->sock, NULL, ISC_SOCKCANCEL_RECV); 207 } 208 209 void dns_tcpmsg_keepbuffer(dns_tcpmsg_t * tcpmsg,isc_buffer_t * buffer)210 dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer) { 211 REQUIRE(VALID_TCPMSG(tcpmsg)); 212 REQUIRE(buffer != NULL); 213 214 *buffer = tcpmsg->buffer; 215 tcpmsg->buffer.base = NULL; 216 tcpmsg->buffer.length = 0; 217 } 218 219 #if 0 220 void 221 dns_tcpmsg_freebuffer(dns_tcpmsg_t *tcpmsg) { 222 REQUIRE(VALID_TCPMSG(tcpmsg)); 223 224 if (tcpmsg->buffer.base == NULL) 225 return; 226 227 isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, tcpmsg->buffer.length); 228 tcpmsg->buffer.base = NULL; 229 tcpmsg->buffer.length = 0; 230 } 231 #endif 232 233 void dns_tcpmsg_invalidate(dns_tcpmsg_t * tcpmsg)234 dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg) { 235 REQUIRE(VALID_TCPMSG(tcpmsg)); 236 237 tcpmsg->magic = 0; 238 239 if (tcpmsg->buffer.base != NULL) { 240 isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, 241 tcpmsg->buffer.length); 242 tcpmsg->buffer.base = NULL; 243 tcpmsg->buffer.length = 0; 244 } 245 } 246