/contrib/bind9/lib/dns/tcpmsg.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 243 lines · 169 code · 50 blank · 24 comment · 25 complexity · 0878bc8d30f112f65c24b5de8e926942 MD5 · raw file

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