tcpmsg.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2001  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: tcpmsg.c,v 1.31 2007/06/19 23:47:16 tbox Exp $ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <isc/mem.h>
00025 #include <isc/task.h>
00026 #include <isc/util.h>
00027 
00028 #include <dns/events.h>
00029 #include <dns/result.h>
00030 #include <dns/tcpmsg.h>
00031 
00032 #ifdef TCPMSG_DEBUG
00033 #include <stdio.h>              /* Required for printf. */
00034 #define XDEBUG(x) printf x
00035 #else
00036 #define XDEBUG(x)
00037 #endif
00038 
00039 #define TCPMSG_MAGIC            ISC_MAGIC('T', 'C', 'P', 'm')
00040 #define VALID_TCPMSG(foo)       ISC_MAGIC_VALID(foo, TCPMSG_MAGIC)
00041 
00042 static void recv_length(isc_task_t *, isc_event_t *);
00043 static void recv_message(isc_task_t *, isc_event_t *);
00044 
00045 
00046 static void
00047 recv_length(isc_task_t *task, isc_event_t *ev_in) {
00048         isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
00049         isc_event_t *dev;
00050         dns_tcpmsg_t *tcpmsg = ev_in->ev_arg;
00051         isc_region_t region;
00052         isc_result_t result;
00053 
00054         INSIST(VALID_TCPMSG(tcpmsg));
00055 
00056         dev = &tcpmsg->event;
00057         tcpmsg->address = ev->address;
00058 
00059         if (ev->result != ISC_R_SUCCESS) {
00060                 tcpmsg->result = ev->result;
00061                 goto send_and_free;
00062         }
00063 
00064         /*
00065          * Success.
00066          */
00067         tcpmsg->size = ntohs(tcpmsg->size);
00068         if (tcpmsg->size == 0) {
00069                 tcpmsg->result = ISC_R_UNEXPECTEDEND;
00070                 goto send_and_free;
00071         }
00072         if (tcpmsg->size > tcpmsg->maxsize) {
00073                 tcpmsg->result = ISC_R_RANGE;
00074                 goto send_and_free;
00075         }
00076 
00077         region.base = isc_mem_get(tcpmsg->mctx, tcpmsg->size);
00078         region.length = tcpmsg->size;
00079         if (region.base == NULL) {
00080                 tcpmsg->result = ISC_R_NOMEMORY;
00081                 goto send_and_free;
00082         }
00083         XDEBUG(("Allocated %d bytes\n", tcpmsg->size));
00084 
00085         isc_buffer_init(&tcpmsg->buffer, region.base, region.length);
00086         result = isc_socket_recv(tcpmsg->sock, &region, 0,
00087                                  task, recv_message, tcpmsg);
00088         if (result != ISC_R_SUCCESS) {
00089                 tcpmsg->result = result;
00090                 goto send_and_free;
00091         }
00092 
00093         isc_event_free(&ev_in);
00094         return;
00095 
00096  send_and_free:
00097         isc_task_send(tcpmsg->task, &dev);
00098         tcpmsg->task = NULL;
00099         isc_event_free(&ev_in);
00100         return;
00101 }
00102 
00103 static void
00104 recv_message(isc_task_t *task, isc_event_t *ev_in) {
00105         isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
00106         isc_event_t *dev;
00107         dns_tcpmsg_t *tcpmsg = ev_in->ev_arg;
00108 
00109         (void)task;
00110 
00111         INSIST(VALID_TCPMSG(tcpmsg));
00112 
00113         dev = &tcpmsg->event;
00114         tcpmsg->address = ev->address;
00115 
00116         if (ev->result != ISC_R_SUCCESS) {
00117                 tcpmsg->result = ev->result;
00118                 goto send_and_free;
00119         }
00120 
00121         tcpmsg->result = ISC_R_SUCCESS;
00122         isc_buffer_add(&tcpmsg->buffer, ev->n);
00123 
00124         XDEBUG(("Received %d bytes (of %d)\n", ev->n, tcpmsg->size));
00125 
00126  send_and_free:
00127         isc_task_send(tcpmsg->task, &dev);
00128         tcpmsg->task = NULL;
00129         isc_event_free(&ev_in);
00130 }
00131 
00132 void
00133 dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg) {
00134         REQUIRE(mctx != NULL);
00135         REQUIRE(sock != NULL);
00136         REQUIRE(tcpmsg != NULL);
00137 
00138         tcpmsg->magic = TCPMSG_MAGIC;
00139         tcpmsg->size = 0;
00140         tcpmsg->buffer.base = NULL;
00141         tcpmsg->buffer.length = 0;
00142         tcpmsg->maxsize = 65535;                /* Largest message possible. */
00143         tcpmsg->mctx = mctx;
00144         tcpmsg->sock = sock;
00145         tcpmsg->task = NULL;                    /* None yet. */
00146         tcpmsg->result = ISC_R_UNEXPECTED;      /* None yet. */
00147         /*
00148          * Should probably initialize the event here, but it can wait.
00149          */
00150 }
00151 
00152 
00153 void
00154 dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize) {
00155         REQUIRE(VALID_TCPMSG(tcpmsg));
00156         REQUIRE(maxsize < 65536);
00157 
00158         tcpmsg->maxsize = maxsize;
00159 }
00160 
00161 
00162 isc_result_t
00163 dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg,
00164                        isc_task_t *task, isc_taskaction_t action, void *arg)
00165 {
00166         isc_result_t result;
00167         isc_region_t region;
00168 
00169         REQUIRE(VALID_TCPMSG(tcpmsg));
00170         REQUIRE(task != NULL);
00171         REQUIRE(tcpmsg->task == NULL);  /* not currently in use */
00172 
00173         if (tcpmsg->buffer.base != NULL) {
00174                 isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base,
00175                             tcpmsg->buffer.length);
00176                 tcpmsg->buffer.base = NULL;
00177                 tcpmsg->buffer.length = 0;
00178         }
00179 
00180         tcpmsg->task = task;
00181         tcpmsg->action = action;
00182         tcpmsg->arg = arg;
00183         tcpmsg->result = ISC_R_UNEXPECTED;  /* unknown right now */
00184 
00185         ISC_EVENT_INIT(&tcpmsg->event, sizeof(isc_event_t), 0, 0,
00186                        DNS_EVENT_TCPMSG, action, arg, tcpmsg,
00187                        NULL, NULL);
00188 
00189         region.base = (unsigned char *)&tcpmsg->size;
00190         region.length = 2;  /* isc_uint16_t */
00191         result = isc_socket_recv(tcpmsg->sock, &region, 0,
00192                                  tcpmsg->task, recv_length, tcpmsg);
00193 
00194         if (result != ISC_R_SUCCESS)
00195                 tcpmsg->task = NULL;
00196 
00197         return (result);
00198 }
00199 
00200 void
00201 dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg) {
00202         REQUIRE(VALID_TCPMSG(tcpmsg));
00203 
00204         isc_socket_cancel(tcpmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
00205 }
00206 
00207 void
00208 dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer) {
00209         REQUIRE(VALID_TCPMSG(tcpmsg));
00210         REQUIRE(buffer != NULL);
00211 
00212         *buffer = tcpmsg->buffer;
00213         tcpmsg->buffer.base = NULL;
00214         tcpmsg->buffer.length = 0;
00215 }
00216 
00217 #if 0
00218 void
00219 dns_tcpmsg_freebuffer(dns_tcpmsg_t *tcpmsg) {
00220         REQUIRE(VALID_TCPMSG(tcpmsg));
00221 
00222         if (tcpmsg->buffer.base == NULL)
00223                 return;
00224 
00225         isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, tcpmsg->buffer.length);
00226         tcpmsg->buffer.base = NULL;
00227         tcpmsg->buffer.length = 0;
00228 }
00229 #endif
00230 
00231 void
00232 dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg) {
00233         REQUIRE(VALID_TCPMSG(tcpmsg));
00234 
00235         tcpmsg->magic = 0;
00236 
00237         if (tcpmsg->buffer.base != NULL) {
00238                 isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base,
00239                             tcpmsg->buffer.length);
00240                 tcpmsg->buffer.base = NULL;
00241                 tcpmsg->buffer.length = 0;
00242         }
00243 }

Generated on Tue Apr 28 17:41:01 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha