xref: /minix3/external/bsd/bind/dist/lib/dns/tcpmsg.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
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, &region, 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, &region, 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