Merge from vendor branch BSDTAR:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / isccc / ccmsg.c
1 /*
2  * Portions Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 2001  Internet Software Consortium.
4  * Portions Copyright (C) 2001  Nominum, Inc.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
12  * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
13  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 /* $Id: ccmsg.c,v 1.4.2.1 2004/03/09 06:12:25 marka Exp $ */
20
21 #include <config.h>
22
23 #include <isc/mem.h>
24 #include <isc/result.h>
25 #include <isc/task.h>
26 #include <isc/util.h>
27
28 #include <isccc/events.h>
29 #include <isccc/ccmsg.h>
30
31 #define CCMSG_MAGIC             ISC_MAGIC('C', 'C', 'm', 's')
32 #define VALID_CCMSG(foo)        ISC_MAGIC_VALID(foo, CCMSG_MAGIC)
33
34 static void recv_length(isc_task_t *, isc_event_t *);
35 static void recv_message(isc_task_t *, isc_event_t *);
36
37
38 static void
39 recv_length(isc_task_t *task, isc_event_t *ev_in) {
40         isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
41         isc_event_t *dev;
42         isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
43         isc_region_t region;
44         isc_result_t result;
45
46         INSIST(VALID_CCMSG(ccmsg));
47
48         dev = &ccmsg->event;
49
50         if (ev->result != ISC_R_SUCCESS) {
51                 ccmsg->result = ev->result;
52                 goto send_and_free;
53         }
54
55         /*
56          * Success.
57          */
58         ccmsg->size = ntohl(ccmsg->size);
59         if (ccmsg->size == 0) {
60                 ccmsg->result = ISC_R_UNEXPECTEDEND;
61                 goto send_and_free;
62         }
63         if (ccmsg->size > ccmsg->maxsize) {
64                 ccmsg->result = ISC_R_RANGE;
65                 goto send_and_free;
66         }
67
68         region.base = isc_mem_get(ccmsg->mctx, ccmsg->size);
69         region.length = ccmsg->size;
70         if (region.base == NULL) {
71                 ccmsg->result = ISC_R_NOMEMORY;
72                 goto send_and_free;
73         }
74
75         isc_buffer_init(&ccmsg->buffer, region.base, region.length);
76         result = isc_socket_recv(ccmsg->sock, &region, 0,
77                                  task, recv_message, ccmsg);
78         if (result != ISC_R_SUCCESS) {
79                 ccmsg->result = result;
80                 goto send_and_free;
81         }
82
83         isc_event_free(&ev_in);
84         return;
85
86  send_and_free:
87         isc_task_send(ccmsg->task, &dev);
88         ccmsg->task = NULL;
89         isc_event_free(&ev_in);
90         return;
91 }
92
93 static void
94 recv_message(isc_task_t *task, isc_event_t *ev_in) {
95         isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
96         isc_event_t *dev;
97         isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
98
99         (void)task;
100
101         INSIST(VALID_CCMSG(ccmsg));
102
103         dev = &ccmsg->event;
104
105         if (ev->result != ISC_R_SUCCESS) {
106                 ccmsg->result = ev->result;
107                 goto send_and_free;
108         }
109
110         ccmsg->result = ISC_R_SUCCESS;
111         isc_buffer_add(&ccmsg->buffer, ev->n);
112         ccmsg->address = ev->address;
113
114  send_and_free:
115         isc_task_send(ccmsg->task, &dev);
116         ccmsg->task = NULL;
117         isc_event_free(&ev_in);
118 }
119
120 void
121 isccc_ccmsg_init(isc_mem_t *mctx, isc_socket_t *sock, isccc_ccmsg_t *ccmsg) {
122         REQUIRE(mctx != NULL);
123         REQUIRE(sock != NULL);
124         REQUIRE(ccmsg != NULL);
125
126         ccmsg->magic = CCMSG_MAGIC;
127         ccmsg->size = 0;
128         ccmsg->buffer.base = NULL;
129         ccmsg->buffer.length = 0;
130         ccmsg->maxsize = 4294967295U;   /* Largest message possible. */
131         ccmsg->mctx = mctx;
132         ccmsg->sock = sock;
133         ccmsg->task = NULL;                     /* None yet. */
134         ccmsg->result = ISC_R_UNEXPECTED;       /* None yet. */
135         /*
136          * Should probably initialize the event here, but it can wait.
137          */
138 }
139
140
141 void
142 isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize) {
143         REQUIRE(VALID_CCMSG(ccmsg));
144
145         ccmsg->maxsize = maxsize;
146 }
147
148
149 isc_result_t
150 isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg,
151                        isc_task_t *task, isc_taskaction_t action, void *arg)
152 {
153         isc_result_t result;
154         isc_region_t region;
155
156         REQUIRE(VALID_CCMSG(ccmsg));
157         REQUIRE(task != NULL);
158         REQUIRE(ccmsg->task == NULL);  /* not currently in use */
159
160         if (ccmsg->buffer.base != NULL) {
161                 isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
162                             ccmsg->buffer.length);
163                 ccmsg->buffer.base = NULL;
164                 ccmsg->buffer.length = 0;
165         }
166
167         ccmsg->task = task;
168         ccmsg->action = action;
169         ccmsg->arg = arg;
170         ccmsg->result = ISC_R_UNEXPECTED;  /* unknown right now */
171
172         ISC_EVENT_INIT(&ccmsg->event, sizeof(isc_event_t), 0, 0,
173                        ISCCC_EVENT_CCMSG, action, arg, ccmsg,
174                        NULL, NULL);
175
176         region.base = (unsigned char *)&ccmsg->size;
177         region.length = 4;  /* isc_uint32_t */
178         result = isc_socket_recv(ccmsg->sock, &region, 0,
179                                  ccmsg->task, recv_length, ccmsg);
180
181         if (result != ISC_R_SUCCESS)
182                 ccmsg->task = NULL;
183
184         return (result);
185 }
186
187 void
188 isccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg) {
189         REQUIRE(VALID_CCMSG(ccmsg));
190
191         isc_socket_cancel(ccmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
192 }
193
194 #if 0
195 void
196 isccc_ccmsg_freebuffer(isccc_ccmsg_t *ccmsg) {
197         REQUIRE(VALID_CCMSG(ccmsg));
198
199         if (ccmsg->buffer.base == NULL)
200                 return;
201
202         isc_mem_put(ccmsg->mctx, ccmsg->buffer.base, ccmsg->buffer.length);
203         ccmsg->buffer.base = NULL;
204         ccmsg->buffer.length = 0;
205 }
206 #endif
207
208 void
209 isccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg) {
210         REQUIRE(VALID_CCMSG(ccmsg));
211
212         ccmsg->magic = 0;
213
214         if (ccmsg->buffer.base != NULL) {
215                 isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
216                             ccmsg->buffer.length);
217                 ccmsg->buffer.base = NULL;
218                 ccmsg->buffer.length = 0;
219         }
220 }