1135446Strhodes/*
2193149Sdougb * Portions Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Portions Copyright (C) 2001  Internet Software Consortium.
4193149Sdougb *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6193149Sdougb * purpose with or without fee is hereby granted, provided that the above
7193149Sdougb * copyright notice and this permission notice appear in all copies.
8193149Sdougb *
9193149Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
10193149Sdougb * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
11193149Sdougb * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
12193149Sdougb * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13193149Sdougb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14193149Sdougb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15193149Sdougb * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16193149Sdougb *
17135446Strhodes * Portions Copyright (C) 2001  Nominum, Inc.
18135446Strhodes *
19193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
20135446Strhodes * purpose with or without fee is hereby granted, provided that the above
21135446Strhodes * copyright notice and this permission notice appear in all copies.
22135446Strhodes *
23135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
24135446Strhodes * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
25135446Strhodes * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
26135446Strhodes * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27135446Strhodes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28135446Strhodes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29135446Strhodes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30135446Strhodes */
31135446Strhodes
32234010Sdougb/* $Id: ccmsg.c,v 1.10 2007/08/28 07:20:43 tbox Exp $ */
33135446Strhodes
34170222Sdougb/*! \file */
35170222Sdougb
36135446Strhodes#include <config.h>
37135446Strhodes
38135446Strhodes#include <isc/mem.h>
39135446Strhodes#include <isc/result.h>
40135446Strhodes#include <isc/task.h>
41135446Strhodes#include <isc/util.h>
42135446Strhodes
43135446Strhodes#include <isccc/events.h>
44135446Strhodes#include <isccc/ccmsg.h>
45135446Strhodes
46135446Strhodes#define CCMSG_MAGIC		ISC_MAGIC('C', 'C', 'm', 's')
47135446Strhodes#define VALID_CCMSG(foo)	ISC_MAGIC_VALID(foo, CCMSG_MAGIC)
48135446Strhodes
49135446Strhodesstatic void recv_length(isc_task_t *, isc_event_t *);
50135446Strhodesstatic void recv_message(isc_task_t *, isc_event_t *);
51135446Strhodes
52135446Strhodes
53135446Strhodesstatic void
54135446Strhodesrecv_length(isc_task_t *task, isc_event_t *ev_in) {
55135446Strhodes	isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
56135446Strhodes	isc_event_t *dev;
57135446Strhodes	isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
58135446Strhodes	isc_region_t region;
59135446Strhodes	isc_result_t result;
60135446Strhodes
61135446Strhodes	INSIST(VALID_CCMSG(ccmsg));
62135446Strhodes
63135446Strhodes	dev = &ccmsg->event;
64135446Strhodes
65135446Strhodes	if (ev->result != ISC_R_SUCCESS) {
66135446Strhodes		ccmsg->result = ev->result;
67135446Strhodes		goto send_and_free;
68135446Strhodes	}
69135446Strhodes
70135446Strhodes	/*
71135446Strhodes	 * Success.
72135446Strhodes	 */
73135446Strhodes	ccmsg->size = ntohl(ccmsg->size);
74135446Strhodes	if (ccmsg->size == 0) {
75135446Strhodes		ccmsg->result = ISC_R_UNEXPECTEDEND;
76135446Strhodes		goto send_and_free;
77135446Strhodes	}
78135446Strhodes	if (ccmsg->size > ccmsg->maxsize) {
79135446Strhodes		ccmsg->result = ISC_R_RANGE;
80135446Strhodes		goto send_and_free;
81135446Strhodes	}
82135446Strhodes
83135446Strhodes	region.base = isc_mem_get(ccmsg->mctx, ccmsg->size);
84135446Strhodes	region.length = ccmsg->size;
85135446Strhodes	if (region.base == NULL) {
86135446Strhodes		ccmsg->result = ISC_R_NOMEMORY;
87135446Strhodes		goto send_and_free;
88135446Strhodes	}
89135446Strhodes
90135446Strhodes	isc_buffer_init(&ccmsg->buffer, region.base, region.length);
91135446Strhodes	result = isc_socket_recv(ccmsg->sock, &region, 0,
92135446Strhodes				 task, recv_message, ccmsg);
93135446Strhodes	if (result != ISC_R_SUCCESS) {
94135446Strhodes		ccmsg->result = result;
95135446Strhodes		goto send_and_free;
96135446Strhodes	}
97135446Strhodes
98135446Strhodes	isc_event_free(&ev_in);
99135446Strhodes	return;
100135446Strhodes
101135446Strhodes send_and_free:
102135446Strhodes	isc_task_send(ccmsg->task, &dev);
103135446Strhodes	ccmsg->task = NULL;
104135446Strhodes	isc_event_free(&ev_in);
105135446Strhodes	return;
106135446Strhodes}
107135446Strhodes
108135446Strhodesstatic void
109135446Strhodesrecv_message(isc_task_t *task, isc_event_t *ev_in) {
110135446Strhodes	isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
111135446Strhodes	isc_event_t *dev;
112135446Strhodes	isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
113135446Strhodes
114135446Strhodes	(void)task;
115135446Strhodes
116135446Strhodes	INSIST(VALID_CCMSG(ccmsg));
117135446Strhodes
118135446Strhodes	dev = &ccmsg->event;
119135446Strhodes
120135446Strhodes	if (ev->result != ISC_R_SUCCESS) {
121135446Strhodes		ccmsg->result = ev->result;
122135446Strhodes		goto send_and_free;
123135446Strhodes	}
124135446Strhodes
125135446Strhodes	ccmsg->result = ISC_R_SUCCESS;
126135446Strhodes	isc_buffer_add(&ccmsg->buffer, ev->n);
127135446Strhodes	ccmsg->address = ev->address;
128135446Strhodes
129135446Strhodes send_and_free:
130135446Strhodes	isc_task_send(ccmsg->task, &dev);
131135446Strhodes	ccmsg->task = NULL;
132135446Strhodes	isc_event_free(&ev_in);
133135446Strhodes}
134135446Strhodes
135135446Strhodesvoid
136135446Strhodesisccc_ccmsg_init(isc_mem_t *mctx, isc_socket_t *sock, isccc_ccmsg_t *ccmsg) {
137135446Strhodes	REQUIRE(mctx != NULL);
138135446Strhodes	REQUIRE(sock != NULL);
139135446Strhodes	REQUIRE(ccmsg != NULL);
140135446Strhodes
141135446Strhodes	ccmsg->magic = CCMSG_MAGIC;
142135446Strhodes	ccmsg->size = 0;
143135446Strhodes	ccmsg->buffer.base = NULL;
144135446Strhodes	ccmsg->buffer.length = 0;
145135446Strhodes	ccmsg->maxsize = 4294967295U;	/* Largest message possible. */
146135446Strhodes	ccmsg->mctx = mctx;
147135446Strhodes	ccmsg->sock = sock;
148135446Strhodes	ccmsg->task = NULL;			/* None yet. */
149135446Strhodes	ccmsg->result = ISC_R_UNEXPECTED;	/* None yet. */
150135446Strhodes	/*
151135446Strhodes	 * Should probably initialize the event here, but it can wait.
152135446Strhodes	 */
153135446Strhodes}
154135446Strhodes
155135446Strhodes
156135446Strhodesvoid
157135446Strhodesisccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize) {
158135446Strhodes	REQUIRE(VALID_CCMSG(ccmsg));
159135446Strhodes
160135446Strhodes	ccmsg->maxsize = maxsize;
161135446Strhodes}
162135446Strhodes
163135446Strhodes
164135446Strhodesisc_result_t
165135446Strhodesisccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg,
166135446Strhodes		       isc_task_t *task, isc_taskaction_t action, void *arg)
167135446Strhodes{
168135446Strhodes	isc_result_t result;
169135446Strhodes	isc_region_t region;
170135446Strhodes
171135446Strhodes	REQUIRE(VALID_CCMSG(ccmsg));
172135446Strhodes	REQUIRE(task != NULL);
173135446Strhodes	REQUIRE(ccmsg->task == NULL);  /* not currently in use */
174135446Strhodes
175135446Strhodes	if (ccmsg->buffer.base != NULL) {
176135446Strhodes		isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
177135446Strhodes			    ccmsg->buffer.length);
178135446Strhodes		ccmsg->buffer.base = NULL;
179135446Strhodes		ccmsg->buffer.length = 0;
180135446Strhodes	}
181135446Strhodes
182135446Strhodes	ccmsg->task = task;
183135446Strhodes	ccmsg->action = action;
184135446Strhodes	ccmsg->arg = arg;
185135446Strhodes	ccmsg->result = ISC_R_UNEXPECTED;  /* unknown right now */
186135446Strhodes
187135446Strhodes	ISC_EVENT_INIT(&ccmsg->event, sizeof(isc_event_t), 0, 0,
188135446Strhodes		       ISCCC_EVENT_CCMSG, action, arg, ccmsg,
189135446Strhodes		       NULL, NULL);
190135446Strhodes
191135446Strhodes	region.base = (unsigned char *)&ccmsg->size;
192135446Strhodes	region.length = 4;  /* isc_uint32_t */
193135446Strhodes	result = isc_socket_recv(ccmsg->sock, &region, 0,
194135446Strhodes				 ccmsg->task, recv_length, ccmsg);
195135446Strhodes
196135446Strhodes	if (result != ISC_R_SUCCESS)
197135446Strhodes		ccmsg->task = NULL;
198135446Strhodes
199135446Strhodes	return (result);
200135446Strhodes}
201135446Strhodes
202135446Strhodesvoid
203135446Strhodesisccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg) {
204135446Strhodes	REQUIRE(VALID_CCMSG(ccmsg));
205135446Strhodes
206135446Strhodes	isc_socket_cancel(ccmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
207135446Strhodes}
208135446Strhodes
209135446Strhodes#if 0
210135446Strhodesvoid
211135446Strhodesisccc_ccmsg_freebuffer(isccc_ccmsg_t *ccmsg) {
212135446Strhodes	REQUIRE(VALID_CCMSG(ccmsg));
213135446Strhodes
214135446Strhodes	if (ccmsg->buffer.base == NULL)
215135446Strhodes		return;
216135446Strhodes
217135446Strhodes	isc_mem_put(ccmsg->mctx, ccmsg->buffer.base, ccmsg->buffer.length);
218135446Strhodes	ccmsg->buffer.base = NULL;
219135446Strhodes	ccmsg->buffer.length = 0;
220135446Strhodes}
221135446Strhodes#endif
222135446Strhodes
223135446Strhodesvoid
224135446Strhodesisccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg) {
225135446Strhodes	REQUIRE(VALID_CCMSG(ccmsg));
226135446Strhodes
227135446Strhodes	ccmsg->magic = 0;
228135446Strhodes
229135446Strhodes	if (ccmsg->buffer.base != NULL) {
230135446Strhodes		isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
231135446Strhodes			    ccmsg->buffer.length);
232135446Strhodes		ccmsg->buffer.base = NULL;
233135446Strhodes		ccmsg->buffer.length = 0;
234135446Strhodes	}
235135446Strhodes}
236