xref: /minix/external/bsd/bind/dist/lib/isccc/ccmsg.c (revision fb9c64b2)
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, &region, 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, &region, 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