connection.c revision 1.2.2.2 1 1.2.2.2 pgoyette /* $NetBSD: connection.c,v 1.2.2.2 2018/04/16 01:59:48 pgoyette Exp $ */
2 1.2.2.2 pgoyette
3 1.2.2.2 pgoyette /* connection.c
4 1.2.2.2 pgoyette
5 1.2.2.2 pgoyette Subroutines for dealing with connections. */
6 1.2.2.2 pgoyette
7 1.2.2.2 pgoyette /*
8 1.2.2.2 pgoyette * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
9 1.2.2.2 pgoyette * Copyright (c) 1999-2003 by Internet Software Consortium
10 1.2.2.2 pgoyette *
11 1.2.2.2 pgoyette * This Source Code Form is subject to the terms of the Mozilla Public
12 1.2.2.2 pgoyette * License, v. 2.0. If a copy of the MPL was not distributed with this
13 1.2.2.2 pgoyette * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 1.2.2.2 pgoyette *
15 1.2.2.2 pgoyette * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 1.2.2.2 pgoyette * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 1.2.2.2 pgoyette * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 1.2.2.2 pgoyette * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 1.2.2.2 pgoyette * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 1.2.2.2 pgoyette * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 1.2.2.2 pgoyette * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 1.2.2.2 pgoyette *
23 1.2.2.2 pgoyette * Internet Systems Consortium, Inc.
24 1.2.2.2 pgoyette * 950 Charter Street
25 1.2.2.2 pgoyette * Redwood City, CA 94063
26 1.2.2.2 pgoyette * <info (at) isc.org>
27 1.2.2.2 pgoyette * https://www.isc.org/
28 1.2.2.2 pgoyette *
29 1.2.2.2 pgoyette */
30 1.2.2.2 pgoyette
31 1.2.2.2 pgoyette #include <sys/cdefs.h>
32 1.2.2.2 pgoyette __RCSID("$NetBSD: connection.c,v 1.2.2.2 2018/04/16 01:59:48 pgoyette Exp $");
33 1.2.2.2 pgoyette
34 1.2.2.2 pgoyette #include "dhcpd.h"
35 1.2.2.2 pgoyette #include <isc/util.h>
36 1.2.2.2 pgoyette #include <omapip/omapip_p.h>
37 1.2.2.2 pgoyette #include <arpa/inet.h>
38 1.2.2.2 pgoyette #include <arpa/nameser.h>
39 1.2.2.2 pgoyette #include <errno.h>
40 1.2.2.2 pgoyette
41 1.2.2.2 pgoyette #if defined (TRACING)
42 1.2.2.2 pgoyette static void trace_connect_input (trace_type_t *, unsigned, char *);
43 1.2.2.2 pgoyette static void trace_connect_stop (trace_type_t *);
44 1.2.2.2 pgoyette static void trace_disconnect_input (trace_type_t *, unsigned, char *);
45 1.2.2.2 pgoyette static void trace_disconnect_stop (trace_type_t *);
46 1.2.2.2 pgoyette trace_type_t *trace_connect;
47 1.2.2.2 pgoyette trace_type_t *trace_disconnect;
48 1.2.2.2 pgoyette extern omapi_array_t *trace_listeners;
49 1.2.2.2 pgoyette #endif
50 1.2.2.2 pgoyette static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
51 1.2.2.2 pgoyette
52 1.2.2.2 pgoyette OMAPI_OBJECT_ALLOC (omapi_connection,
53 1.2.2.2 pgoyette omapi_connection_object_t, omapi_type_connection)
54 1.2.2.2 pgoyette
55 1.2.2.2 pgoyette isc_result_t omapi_connect (omapi_object_t *c,
56 1.2.2.2 pgoyette const char *server_name,
57 1.2.2.2 pgoyette unsigned port)
58 1.2.2.2 pgoyette {
59 1.2.2.2 pgoyette struct hostent *he;
60 1.2.2.2 pgoyette unsigned i, hix;
61 1.2.2.2 pgoyette omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
62 1.2.2.2 pgoyette struct in_addr foo;
63 1.2.2.2 pgoyette isc_result_t status;
64 1.2.2.2 pgoyette
65 1.2.2.2 pgoyette #ifdef DEBUG_PROTOCOL
66 1.2.2.2 pgoyette log_debug ("omapi_connect(%s, port=%d)", server_name, port);
67 1.2.2.2 pgoyette #endif
68 1.2.2.2 pgoyette
69 1.2.2.2 pgoyette if (!inet_aton (server_name, &foo)) {
70 1.2.2.2 pgoyette /* If we didn't get a numeric address, try for a domain
71 1.2.2.2 pgoyette name. It's okay for this call to block. */
72 1.2.2.2 pgoyette he = gethostbyname (server_name);
73 1.2.2.2 pgoyette if (!he)
74 1.2.2.2 pgoyette return DHCP_R_HOSTUNKNOWN;
75 1.2.2.2 pgoyette for (i = 0; he -> h_addr_list [i]; i++)
76 1.2.2.2 pgoyette ;
77 1.2.2.2 pgoyette if (i == 0)
78 1.2.2.2 pgoyette return DHCP_R_HOSTUNKNOWN;
79 1.2.2.2 pgoyette hix = i;
80 1.2.2.2 pgoyette
81 1.2.2.2 pgoyette status = omapi_addr_list_new (&addrs, hix, MDL);
82 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS)
83 1.2.2.2 pgoyette return status;
84 1.2.2.2 pgoyette for (i = 0; i < hix; i++) {
85 1.2.2.2 pgoyette addrs -> addresses [i].addrtype = he -> h_addrtype;
86 1.2.2.2 pgoyette addrs -> addresses [i].addrlen = he -> h_length;
87 1.2.2.2 pgoyette memcpy (addrs -> addresses [i].address,
88 1.2.2.2 pgoyette he -> h_addr_list [i],
89 1.2.2.2 pgoyette (unsigned)he -> h_length);
90 1.2.2.2 pgoyette addrs -> addresses [i].port = port;
91 1.2.2.2 pgoyette }
92 1.2.2.2 pgoyette } else {
93 1.2.2.2 pgoyette status = omapi_addr_list_new (&addrs, 1, MDL);
94 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS)
95 1.2.2.2 pgoyette return status;
96 1.2.2.2 pgoyette addrs -> addresses [0].addrtype = AF_INET;
97 1.2.2.2 pgoyette addrs -> addresses [0].addrlen = sizeof foo;
98 1.2.2.2 pgoyette memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
99 1.2.2.2 pgoyette addrs -> addresses [0].port = port;
100 1.2.2.2 pgoyette }
101 1.2.2.2 pgoyette status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
102 1.2.2.2 pgoyette omapi_addr_list_dereference (&addrs, MDL);
103 1.2.2.2 pgoyette return status;
104 1.2.2.2 pgoyette }
105 1.2.2.2 pgoyette
106 1.2.2.2 pgoyette isc_result_t omapi_connect_list (omapi_object_t *c,
107 1.2.2.2 pgoyette omapi_addr_list_t *remote_addrs,
108 1.2.2.2 pgoyette omapi_addr_t *local_addr)
109 1.2.2.2 pgoyette {
110 1.2.2.2 pgoyette isc_result_t status;
111 1.2.2.2 pgoyette omapi_connection_object_t *obj;
112 1.2.2.2 pgoyette int flag;
113 1.2.2.2 pgoyette struct sockaddr_in local_sin;
114 1.2.2.2 pgoyette
115 1.2.2.2 pgoyette obj = (omapi_connection_object_t *)0;
116 1.2.2.2 pgoyette status = omapi_connection_allocate (&obj, MDL);
117 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS)
118 1.2.2.2 pgoyette return status;
119 1.2.2.2 pgoyette
120 1.2.2.2 pgoyette status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
121 1.2.2.2 pgoyette MDL);
122 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
123 1.2.2.2 pgoyette omapi_connection_dereference (&obj, MDL);
124 1.2.2.2 pgoyette return status;
125 1.2.2.2 pgoyette }
126 1.2.2.2 pgoyette status = omapi_object_reference (&obj -> inner, c, MDL);
127 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
128 1.2.2.2 pgoyette omapi_connection_dereference (&obj, MDL);
129 1.2.2.2 pgoyette return status;
130 1.2.2.2 pgoyette }
131 1.2.2.2 pgoyette
132 1.2.2.2 pgoyette /* Store the address list on the object. */
133 1.2.2.2 pgoyette omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
134 1.2.2.2 pgoyette obj -> cptr = 0;
135 1.2.2.2 pgoyette obj -> state = omapi_connection_unconnected;
136 1.2.2.2 pgoyette
137 1.2.2.2 pgoyette #if defined (TRACING)
138 1.2.2.2 pgoyette /* If we're playing back, don't actually try to connect - just leave
139 1.2.2.2 pgoyette the object available for a subsequent connect or disconnect. */
140 1.2.2.2 pgoyette if (!trace_playback ()) {
141 1.2.2.2 pgoyette #endif
142 1.2.2.2 pgoyette /* Create a socket on which to communicate. */
143 1.2.2.2 pgoyette obj -> socket =
144 1.2.2.2 pgoyette socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
145 1.2.2.2 pgoyette if (obj -> socket < 0) {
146 1.2.2.2 pgoyette omapi_connection_dereference (&obj, MDL);
147 1.2.2.2 pgoyette if (errno == EMFILE || errno == ENFILE
148 1.2.2.2 pgoyette || errno == ENOBUFS)
149 1.2.2.2 pgoyette return ISC_R_NORESOURCES;
150 1.2.2.2 pgoyette return ISC_R_UNEXPECTED;
151 1.2.2.2 pgoyette }
152 1.2.2.2 pgoyette
153 1.2.2.2 pgoyette /* Set up the local address, if any. */
154 1.2.2.2 pgoyette if (local_addr) {
155 1.2.2.2 pgoyette /* Only do TCPv4 so far. */
156 1.2.2.2 pgoyette if (local_addr -> addrtype != AF_INET) {
157 1.2.2.2 pgoyette close(obj->socket);
158 1.2.2.2 pgoyette omapi_connection_dereference (&obj, MDL);
159 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
160 1.2.2.2 pgoyette }
161 1.2.2.2 pgoyette local_sin.sin_port = htons (local_addr -> port);
162 1.2.2.2 pgoyette memcpy (&local_sin.sin_addr,
163 1.2.2.2 pgoyette local_addr -> address,
164 1.2.2.2 pgoyette local_addr -> addrlen);
165 1.2.2.2 pgoyette #if defined (HAVE_SA_LEN)
166 1.2.2.2 pgoyette local_sin.sin_len = sizeof local_addr;
167 1.2.2.2 pgoyette #endif
168 1.2.2.2 pgoyette local_sin.sin_family = AF_INET;
169 1.2.2.2 pgoyette memset (&local_sin.sin_zero, 0,
170 1.2.2.2 pgoyette sizeof local_sin.sin_zero);
171 1.2.2.2 pgoyette
172 1.2.2.2 pgoyette if (bind (obj -> socket, (struct sockaddr *)&local_sin,
173 1.2.2.2 pgoyette sizeof local_sin) < 0) {
174 1.2.2.2 pgoyette omapi_connection_object_t **objp = &obj;
175 1.2.2.2 pgoyette omapi_object_t **o = (omapi_object_t **)objp;
176 1.2.2.2 pgoyette close(obj->socket);
177 1.2.2.2 pgoyette omapi_object_dereference(o, MDL);
178 1.2.2.2 pgoyette if (errno == EADDRINUSE)
179 1.2.2.2 pgoyette return ISC_R_ADDRINUSE;
180 1.2.2.2 pgoyette if (errno == EADDRNOTAVAIL)
181 1.2.2.2 pgoyette return ISC_R_ADDRNOTAVAIL;
182 1.2.2.2 pgoyette if (errno == EACCES)
183 1.2.2.2 pgoyette return ISC_R_NOPERM;
184 1.2.2.2 pgoyette return ISC_R_UNEXPECTED;
185 1.2.2.2 pgoyette }
186 1.2.2.2 pgoyette obj -> local_addr = local_sin;
187 1.2.2.2 pgoyette }
188 1.2.2.2 pgoyette
189 1.2.2.2 pgoyette #if defined(F_SETFD)
190 1.2.2.2 pgoyette if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
191 1.2.2.2 pgoyette close (obj -> socket);
192 1.2.2.2 pgoyette omapi_connection_dereference (&obj, MDL);
193 1.2.2.2 pgoyette return ISC_R_UNEXPECTED;
194 1.2.2.2 pgoyette }
195 1.2.2.2 pgoyette #endif
196 1.2.2.2 pgoyette
197 1.2.2.2 pgoyette /* Set the SO_REUSEADDR flag (this should not fail). */
198 1.2.2.2 pgoyette flag = 1;
199 1.2.2.2 pgoyette if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
200 1.2.2.2 pgoyette (char *)&flag, sizeof flag) < 0) {
201 1.2.2.2 pgoyette omapi_connection_dereference (&obj, MDL);
202 1.2.2.2 pgoyette return ISC_R_UNEXPECTED;
203 1.2.2.2 pgoyette }
204 1.2.2.2 pgoyette
205 1.2.2.2 pgoyette /* Set the file to nonblocking mode. */
206 1.2.2.2 pgoyette if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
207 1.2.2.2 pgoyette omapi_connection_dereference (&obj, MDL);
208 1.2.2.2 pgoyette return ISC_R_UNEXPECTED;
209 1.2.2.2 pgoyette }
210 1.2.2.2 pgoyette
211 1.2.2.2 pgoyette #ifdef SO_NOSIGPIPE
212 1.2.2.2 pgoyette /*
213 1.2.2.2 pgoyette * If available stop the OS from killing our
214 1.2.2.2 pgoyette * program on a SIGPIPE failure
215 1.2.2.2 pgoyette */
216 1.2.2.2 pgoyette flag = 1;
217 1.2.2.2 pgoyette if (setsockopt(obj->socket, SOL_SOCKET, SO_NOSIGPIPE,
218 1.2.2.2 pgoyette (char *)&flag, sizeof(flag)) < 0) {
219 1.2.2.2 pgoyette omapi_connection_dereference (&obj, MDL);
220 1.2.2.2 pgoyette return ISC_R_UNEXPECTED;
221 1.2.2.2 pgoyette }
222 1.2.2.2 pgoyette #endif
223 1.2.2.2 pgoyette
224 1.2.2.2 pgoyette status = (omapi_register_io_object
225 1.2.2.2 pgoyette ((omapi_object_t *)obj,
226 1.2.2.2 pgoyette 0, omapi_connection_writefd,
227 1.2.2.2 pgoyette 0, omapi_connection_connect,
228 1.2.2.2 pgoyette omapi_connection_reaper));
229 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS)
230 1.2.2.2 pgoyette goto out;
231 1.2.2.2 pgoyette status = omapi_connection_connect_internal ((omapi_object_t *)
232 1.2.2.2 pgoyette obj);
233 1.2.2.2 pgoyette /*
234 1.2.2.2 pgoyette * inprogress is the same as success but used
235 1.2.2.2 pgoyette * to indicate to the dispatch code that we should
236 1.2.2.2 pgoyette * mark the socket as requiring more attention.
237 1.2.2.2 pgoyette * Routines calling this function should handle
238 1.2.2.2 pgoyette * success properly.
239 1.2.2.2 pgoyette */
240 1.2.2.2 pgoyette if (status == ISC_R_INPROGRESS) {
241 1.2.2.2 pgoyette status = ISC_R_SUCCESS;
242 1.2.2.2 pgoyette }
243 1.2.2.2 pgoyette #if defined (TRACING)
244 1.2.2.2 pgoyette }
245 1.2.2.2 pgoyette omapi_connection_register (obj, MDL);
246 1.2.2.2 pgoyette #endif
247 1.2.2.2 pgoyette
248 1.2.2.2 pgoyette out:
249 1.2.2.2 pgoyette omapi_connection_dereference (&obj, MDL);
250 1.2.2.2 pgoyette return status;
251 1.2.2.2 pgoyette }
252 1.2.2.2 pgoyette
253 1.2.2.2 pgoyette #if defined (TRACING)
254 1.2.2.2 pgoyette omapi_array_t *omapi_connections;
255 1.2.2.2 pgoyette
256 1.2.2.2 pgoyette OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t)
257 1.2.2.2 pgoyette
258 1.2.2.2 pgoyette void omapi_connection_trace_setup (void) {
259 1.2.2.2 pgoyette trace_connect = trace_type_register ("connect", (void *)0,
260 1.2.2.2 pgoyette trace_connect_input,
261 1.2.2.2 pgoyette trace_connect_stop, MDL);
262 1.2.2.2 pgoyette trace_disconnect = trace_type_register ("disconnect", (void *)0,
263 1.2.2.2 pgoyette trace_disconnect_input,
264 1.2.2.2 pgoyette trace_disconnect_stop, MDL);
265 1.2.2.2 pgoyette }
266 1.2.2.2 pgoyette
267 1.2.2.2 pgoyette void omapi_connection_register (omapi_connection_object_t *obj,
268 1.2.2.2 pgoyette const char *file, int line)
269 1.2.2.2 pgoyette {
270 1.2.2.2 pgoyette isc_result_t status;
271 1.2.2.2 pgoyette trace_iov_t iov [6];
272 1.2.2.2 pgoyette int iov_count = 0;
273 1.2.2.2 pgoyette int32_t connect_index, listener_index;
274 1.2.2.2 pgoyette static int32_t index;
275 1.2.2.2 pgoyette
276 1.2.2.2 pgoyette if (!omapi_connections) {
277 1.2.2.2 pgoyette status = omapi_connection_array_allocate (&omapi_connections,
278 1.2.2.2 pgoyette file, line);
279 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS)
280 1.2.2.2 pgoyette return;
281 1.2.2.2 pgoyette }
282 1.2.2.2 pgoyette
283 1.2.2.2 pgoyette status = omapi_connection_array_extend (omapi_connections, obj,
284 1.2.2.2 pgoyette (int *)0, file, line);
285 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
286 1.2.2.2 pgoyette obj -> index = -1;
287 1.2.2.2 pgoyette return;
288 1.2.2.2 pgoyette }
289 1.2.2.2 pgoyette
290 1.2.2.2 pgoyette #if defined (TRACING)
291 1.2.2.2 pgoyette if (trace_record ()) {
292 1.2.2.2 pgoyette /* Connection registration packet:
293 1.2.2.2 pgoyette
294 1.2.2.2 pgoyette int32_t index
295 1.2.2.2 pgoyette int32_t listener_index [-1 means no listener]
296 1.2.2.2 pgoyette u_int16_t remote_port
297 1.2.2.2 pgoyette u_int16_t local_port
298 1.2.2.2 pgoyette u_int32_t remote_addr
299 1.2.2.2 pgoyette u_int32_t local_addr */
300 1.2.2.2 pgoyette
301 1.2.2.2 pgoyette connect_index = htonl (index);
302 1.2.2.2 pgoyette index++;
303 1.2.2.2 pgoyette if (obj -> listener)
304 1.2.2.2 pgoyette listener_index = htonl (obj -> listener -> index);
305 1.2.2.2 pgoyette else
306 1.2.2.2 pgoyette listener_index = htonl (-1);
307 1.2.2.2 pgoyette iov [iov_count].buf = (char *)&connect_index;
308 1.2.2.2 pgoyette iov [iov_count++].len = sizeof connect_index;
309 1.2.2.2 pgoyette iov [iov_count].buf = (char *)&listener_index;
310 1.2.2.2 pgoyette iov [iov_count++].len = sizeof listener_index;
311 1.2.2.2 pgoyette iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
312 1.2.2.2 pgoyette iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
313 1.2.2.2 pgoyette iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
314 1.2.2.2 pgoyette iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
315 1.2.2.2 pgoyette iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
316 1.2.2.2 pgoyette iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
317 1.2.2.2 pgoyette iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
318 1.2.2.2 pgoyette iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
319 1.2.2.2 pgoyette
320 1.2.2.2 pgoyette status = trace_write_packet_iov (trace_connect,
321 1.2.2.2 pgoyette iov_count, iov, file, line);
322 1.2.2.2 pgoyette }
323 1.2.2.2 pgoyette #endif
324 1.2.2.2 pgoyette }
325 1.2.2.2 pgoyette
326 1.2.2.2 pgoyette static void trace_connect_input (trace_type_t *ttype,
327 1.2.2.2 pgoyette unsigned length, char *buf)
328 1.2.2.2 pgoyette {
329 1.2.2.2 pgoyette struct sockaddr_in remote, local;
330 1.2.2.2 pgoyette int32_t connect_index, listener_index;
331 1.2.2.2 pgoyette char *s = buf;
332 1.2.2.2 pgoyette omapi_connection_object_t *obj;
333 1.2.2.2 pgoyette isc_result_t status;
334 1.2.2.2 pgoyette int i;
335 1.2.2.2 pgoyette
336 1.2.2.2 pgoyette if (length != ((sizeof connect_index) +
337 1.2.2.2 pgoyette (sizeof remote.sin_port) +
338 1.2.2.2 pgoyette (sizeof remote.sin_addr)) * 2) {
339 1.2.2.2 pgoyette log_error ("Trace connect: invalid length %d", length);
340 1.2.2.2 pgoyette return;
341 1.2.2.2 pgoyette }
342 1.2.2.2 pgoyette
343 1.2.2.2 pgoyette memset (&remote, 0, sizeof remote);
344 1.2.2.2 pgoyette memset (&local, 0, sizeof local);
345 1.2.2.2 pgoyette memcpy (&connect_index, s, sizeof connect_index);
346 1.2.2.2 pgoyette s += sizeof connect_index;
347 1.2.2.2 pgoyette memcpy (&listener_index, s, sizeof listener_index);
348 1.2.2.2 pgoyette s += sizeof listener_index;
349 1.2.2.2 pgoyette memcpy (&remote.sin_port, s, sizeof remote.sin_port);
350 1.2.2.2 pgoyette s += sizeof remote.sin_port;
351 1.2.2.2 pgoyette memcpy (&local.sin_port, s, sizeof local.sin_port);
352 1.2.2.2 pgoyette s += sizeof local.sin_port;
353 1.2.2.2 pgoyette memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
354 1.2.2.2 pgoyette s += sizeof remote.sin_addr;
355 1.2.2.2 pgoyette memcpy (&local.sin_addr, s, sizeof local.sin_addr);
356 1.2.2.2 pgoyette s += sizeof local.sin_addr;
357 1.2.2.2 pgoyette POST(s);
358 1.2.2.2 pgoyette
359 1.2.2.2 pgoyette connect_index = ntohl (connect_index);
360 1.2.2.2 pgoyette listener_index = ntohl (listener_index);
361 1.2.2.2 pgoyette
362 1.2.2.2 pgoyette /* If this was a connect to a listener, then we just slap together
363 1.2.2.2 pgoyette a new connection. */
364 1.2.2.2 pgoyette if (listener_index != -1) {
365 1.2.2.2 pgoyette omapi_listener_object_t *listener;
366 1.2.2.2 pgoyette listener = (omapi_listener_object_t *)0;
367 1.2.2.2 pgoyette omapi_array_foreach_begin (trace_listeners,
368 1.2.2.2 pgoyette omapi_listener_object_t, lp) {
369 1.2.2.2 pgoyette if (lp -> address.sin_port == local.sin_port) {
370 1.2.2.2 pgoyette omapi_listener_reference (&listener, lp, MDL);
371 1.2.2.2 pgoyette omapi_listener_dereference (&lp, MDL);
372 1.2.2.2 pgoyette break;
373 1.2.2.2 pgoyette }
374 1.2.2.2 pgoyette } omapi_array_foreach_end (trace_listeners,
375 1.2.2.2 pgoyette omapi_listener_object_t, lp);
376 1.2.2.2 pgoyette if (!listener) {
377 1.2.2.2 pgoyette log_error ("%s%ld, addr %s, port %d",
378 1.2.2.2 pgoyette "Spurious traced listener connect - index ",
379 1.2.2.2 pgoyette (long int)listener_index,
380 1.2.2.2 pgoyette inet_ntoa (local.sin_addr),
381 1.2.2.2 pgoyette ntohs (local.sin_port));
382 1.2.2.2 pgoyette return;
383 1.2.2.2 pgoyette }
384 1.2.2.2 pgoyette obj = (omapi_connection_object_t *)0;
385 1.2.2.2 pgoyette status = omapi_listener_connect (&obj, listener, -1, &remote);
386 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
387 1.2.2.2 pgoyette log_error ("traced listener connect: %s",
388 1.2.2.2 pgoyette isc_result_totext (status));
389 1.2.2.2 pgoyette }
390 1.2.2.2 pgoyette if (obj)
391 1.2.2.2 pgoyette omapi_connection_dereference (&obj, MDL);
392 1.2.2.2 pgoyette omapi_listener_dereference (&listener, MDL);
393 1.2.2.2 pgoyette return;
394 1.2.2.2 pgoyette }
395 1.2.2.2 pgoyette
396 1.2.2.2 pgoyette /* Find the matching connect object, if there is one. */
397 1.2.2.2 pgoyette omapi_array_foreach_begin (omapi_connections,
398 1.2.2.2 pgoyette omapi_connection_object_t, lp) {
399 1.2.2.2 pgoyette for (i = 0; (lp->connect_list &&
400 1.2.2.2 pgoyette i < lp->connect_list->count); i++) {
401 1.2.2.2 pgoyette if (!memcmp (&remote.sin_addr,
402 1.2.2.2 pgoyette &lp->connect_list->addresses[i].address,
403 1.2.2.2 pgoyette sizeof remote.sin_addr) &&
404 1.2.2.2 pgoyette (ntohs (remote.sin_port) ==
405 1.2.2.2 pgoyette lp->connect_list->addresses[i].port)) {
406 1.2.2.2 pgoyette lp->state = omapi_connection_connected;
407 1.2.2.2 pgoyette lp->remote_addr = remote;
408 1.2.2.2 pgoyette lp->remote_addr.sin_family = AF_INET;
409 1.2.2.2 pgoyette omapi_addr_list_dereference(&lp->connect_list, MDL);
410 1.2.2.2 pgoyette lp->index = connect_index;
411 1.2.2.2 pgoyette status = omapi_signal_in((omapi_object_t *)lp,
412 1.2.2.2 pgoyette "connect");
413 1.2.2.2 pgoyette omapi_connection_dereference (&lp, MDL);
414 1.2.2.2 pgoyette return;
415 1.2.2.2 pgoyette }
416 1.2.2.2 pgoyette }
417 1.2.2.2 pgoyette } omapi_array_foreach_end (omapi_connections,
418 1.2.2.2 pgoyette omapi_connection_object_t, lp);
419 1.2.2.2 pgoyette
420 1.2.2.2 pgoyette log_error ("Spurious traced connect - index %ld, addr %s, port %d",
421 1.2.2.2 pgoyette (long int)connect_index, inet_ntoa (remote.sin_addr),
422 1.2.2.2 pgoyette ntohs (remote.sin_port));
423 1.2.2.2 pgoyette return;
424 1.2.2.2 pgoyette }
425 1.2.2.2 pgoyette
426 1.2.2.2 pgoyette static void trace_connect_stop (trace_type_t *ttype) { }
427 1.2.2.2 pgoyette
428 1.2.2.2 pgoyette static void trace_disconnect_input (trace_type_t *ttype,
429 1.2.2.2 pgoyette unsigned length, char *buf)
430 1.2.2.2 pgoyette {
431 1.2.2.2 pgoyette int32_t *index;
432 1.2.2.2 pgoyette if (length != sizeof *index) {
433 1.2.2.2 pgoyette log_error ("trace disconnect: wrong length %d", length);
434 1.2.2.2 pgoyette return;
435 1.2.2.2 pgoyette }
436 1.2.2.2 pgoyette
437 1.2.2.2 pgoyette index = (int32_t *)buf;
438 1.2.2.2 pgoyette
439 1.2.2.2 pgoyette omapi_array_foreach_begin (omapi_connections,
440 1.2.2.2 pgoyette omapi_connection_object_t, lp) {
441 1.2.2.2 pgoyette if (lp -> index == ntohl (*index)) {
442 1.2.2.2 pgoyette omapi_disconnect ((omapi_object_t *)lp, 1);
443 1.2.2.2 pgoyette omapi_connection_dereference (&lp, MDL);
444 1.2.2.2 pgoyette return;
445 1.2.2.2 pgoyette }
446 1.2.2.2 pgoyette } omapi_array_foreach_end (omapi_connections,
447 1.2.2.2 pgoyette omapi_connection_object_t, lp);
448 1.2.2.2 pgoyette
449 1.2.2.2 pgoyette log_error ("trace disconnect: no connection matching index %ld",
450 1.2.2.2 pgoyette (long int)ntohl (*index));
451 1.2.2.2 pgoyette }
452 1.2.2.2 pgoyette
453 1.2.2.2 pgoyette static void trace_disconnect_stop (trace_type_t *ttype) { }
454 1.2.2.2 pgoyette #endif
455 1.2.2.2 pgoyette
456 1.2.2.2 pgoyette /* Disconnect a connection object from the remote end. If force is nonzero,
457 1.2.2.2 pgoyette close the connection immediately. Otherwise, shut down the receiving end
458 1.2.2.2 pgoyette but allow any unsent data to be sent before actually closing the socket. */
459 1.2.2.2 pgoyette
460 1.2.2.2 pgoyette isc_result_t omapi_disconnect (omapi_object_t *h,
461 1.2.2.2 pgoyette int force)
462 1.2.2.2 pgoyette {
463 1.2.2.2 pgoyette omapi_connection_object_t *c;
464 1.2.2.2 pgoyette
465 1.2.2.2 pgoyette #ifdef DEBUG_PROTOCOL
466 1.2.2.2 pgoyette log_debug ("omapi_disconnect(%s)", force ? "force" : "");
467 1.2.2.2 pgoyette #endif
468 1.2.2.2 pgoyette
469 1.2.2.2 pgoyette c = (omapi_connection_object_t *)h;
470 1.2.2.2 pgoyette if (c -> type != omapi_type_connection)
471 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
472 1.2.2.2 pgoyette
473 1.2.2.2 pgoyette #if defined (TRACING)
474 1.2.2.2 pgoyette if (trace_record ()) {
475 1.2.2.2 pgoyette isc_result_t status;
476 1.2.2.2 pgoyette int32_t index;
477 1.2.2.2 pgoyette
478 1.2.2.2 pgoyette index = htonl (c -> index);
479 1.2.2.2 pgoyette status = trace_write_packet (trace_disconnect,
480 1.2.2.2 pgoyette sizeof index, (char *)&index,
481 1.2.2.2 pgoyette MDL);
482 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
483 1.2.2.2 pgoyette trace_stop ();
484 1.2.2.2 pgoyette log_error ("trace_write_packet: %s",
485 1.2.2.2 pgoyette isc_result_totext (status));
486 1.2.2.2 pgoyette }
487 1.2.2.2 pgoyette }
488 1.2.2.2 pgoyette if (!trace_playback ()) {
489 1.2.2.2 pgoyette #endif
490 1.2.2.2 pgoyette if (!force) {
491 1.2.2.2 pgoyette /* If we're already disconnecting, we don't have to do
492 1.2.2.2 pgoyette anything. */
493 1.2.2.2 pgoyette if (c -> state == omapi_connection_disconnecting)
494 1.2.2.2 pgoyette return ISC_R_SUCCESS;
495 1.2.2.2 pgoyette
496 1.2.2.2 pgoyette /* Try to shut down the socket - this sends a FIN to
497 1.2.2.2 pgoyette the remote end, so that it won't send us any more
498 1.2.2.2 pgoyette data. If the shutdown succeeds, and we still
499 1.2.2.2 pgoyette have bytes left to write, defer closing the socket
500 1.2.2.2 pgoyette until that's done. */
501 1.2.2.2 pgoyette if (!shutdown (c -> socket, SHUT_RD)) {
502 1.2.2.2 pgoyette if (c -> out_bytes > 0) {
503 1.2.2.2 pgoyette c -> state =
504 1.2.2.2 pgoyette omapi_connection_disconnecting;
505 1.2.2.2 pgoyette return ISC_R_SUCCESS;
506 1.2.2.2 pgoyette }
507 1.2.2.2 pgoyette }
508 1.2.2.2 pgoyette }
509 1.2.2.2 pgoyette close (c -> socket);
510 1.2.2.2 pgoyette #if defined (TRACING)
511 1.2.2.2 pgoyette }
512 1.2.2.2 pgoyette #endif
513 1.2.2.2 pgoyette c -> state = omapi_connection_closed;
514 1.2.2.2 pgoyette
515 1.2.2.2 pgoyette #if 0
516 1.2.2.2 pgoyette /*
517 1.2.2.2 pgoyette * Disconnecting from the I/O object seems incorrect as it doesn't
518 1.2.2.2 pgoyette * cause the I/O object to be cleaned and released. Previous to
519 1.2.2.2 pgoyette * using the isc socket library this wouldn't have caused a problem
520 1.2.2.2 pgoyette * with the socket library we would have a reference to a closed
521 1.2.2.2 pgoyette * socket. Instead we now do an unregister to properly free the
522 1.2.2.2 pgoyette * I/O object.
523 1.2.2.2 pgoyette */
524 1.2.2.2 pgoyette
525 1.2.2.2 pgoyette /* Disconnect from I/O object, if any. */
526 1.2.2.2 pgoyette if (h -> outer) {
527 1.2.2.2 pgoyette if (h -> outer -> inner)
528 1.2.2.2 pgoyette omapi_object_dereference (&h -> outer -> inner, MDL);
529 1.2.2.2 pgoyette omapi_object_dereference (&h -> outer, MDL);
530 1.2.2.2 pgoyette }
531 1.2.2.2 pgoyette #else
532 1.2.2.2 pgoyette if (h->outer) {
533 1.2.2.2 pgoyette omapi_unregister_io_object(h);
534 1.2.2.2 pgoyette }
535 1.2.2.2 pgoyette #endif
536 1.2.2.2 pgoyette
537 1.2.2.2 pgoyette /* If whatever created us registered a signal handler, send it
538 1.2.2.2 pgoyette a disconnect signal. */
539 1.2.2.2 pgoyette omapi_signal (h, "disconnect", h);
540 1.2.2.2 pgoyette
541 1.2.2.2 pgoyette /* Disconnect from protocol object, if any. */
542 1.2.2.2 pgoyette if (h->inner != NULL) {
543 1.2.2.2 pgoyette if (h->inner->outer != NULL) {
544 1.2.2.2 pgoyette omapi_object_dereference(&h->inner->outer, MDL);
545 1.2.2.2 pgoyette }
546 1.2.2.2 pgoyette omapi_object_dereference(&h->inner, MDL);
547 1.2.2.2 pgoyette }
548 1.2.2.2 pgoyette
549 1.2.2.2 pgoyette /* XXX: the code to free buffers should be in the dereference
550 1.2.2.2 pgoyette function, but there is no special-purpose function to
551 1.2.2.2 pgoyette dereference connections, so these just get leaked */
552 1.2.2.2 pgoyette /* Free any buffers */
553 1.2.2.2 pgoyette if (c->inbufs != NULL) {
554 1.2.2.2 pgoyette omapi_buffer_dereference(&c->inbufs, MDL);
555 1.2.2.2 pgoyette }
556 1.2.2.2 pgoyette c->in_bytes = 0;
557 1.2.2.2 pgoyette if (c->outbufs != NULL) {
558 1.2.2.2 pgoyette omapi_buffer_dereference(&c->outbufs, MDL);
559 1.2.2.2 pgoyette }
560 1.2.2.2 pgoyette c->out_bytes = 0;
561 1.2.2.2 pgoyette
562 1.2.2.2 pgoyette return ISC_R_SUCCESS;
563 1.2.2.2 pgoyette }
564 1.2.2.2 pgoyette
565 1.2.2.2 pgoyette isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
566 1.2.2.2 pgoyette {
567 1.2.2.2 pgoyette omapi_connection_object_t *c;
568 1.2.2.2 pgoyette
569 1.2.2.2 pgoyette if (h -> type != omapi_type_connection)
570 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
571 1.2.2.2 pgoyette c = (omapi_connection_object_t *)h;
572 1.2.2.2 pgoyette
573 1.2.2.2 pgoyette c -> bytes_needed = bytes;
574 1.2.2.2 pgoyette if (c -> bytes_needed <= c -> in_bytes) {
575 1.2.2.2 pgoyette return ISC_R_SUCCESS;
576 1.2.2.2 pgoyette }
577 1.2.2.2 pgoyette return DHCP_R_NOTYET;
578 1.2.2.2 pgoyette }
579 1.2.2.2 pgoyette
580 1.2.2.2 pgoyette /* Return the socket on which the dispatcher should wait for readiness
581 1.2.2.2 pgoyette to read, for a connection object. */
582 1.2.2.2 pgoyette int omapi_connection_readfd (omapi_object_t *h)
583 1.2.2.2 pgoyette {
584 1.2.2.2 pgoyette omapi_connection_object_t *c;
585 1.2.2.2 pgoyette if (h -> type != omapi_type_connection)
586 1.2.2.2 pgoyette return -1;
587 1.2.2.2 pgoyette c = (omapi_connection_object_t *)h;
588 1.2.2.2 pgoyette if (c -> state != omapi_connection_connected)
589 1.2.2.2 pgoyette return -1;
590 1.2.2.2 pgoyette return c -> socket;
591 1.2.2.2 pgoyette }
592 1.2.2.2 pgoyette
593 1.2.2.2 pgoyette /*
594 1.2.2.2 pgoyette * Return the socket on which the dispatcher should wait for readiness
595 1.2.2.2 pgoyette * to write, for a connection object. When bytes are buffered we should
596 1.2.2.2 pgoyette * also poke the dispatcher to tell it to start or re-start watching the
597 1.2.2.2 pgoyette * socket.
598 1.2.2.2 pgoyette */
599 1.2.2.2 pgoyette int omapi_connection_writefd (omapi_object_t *h)
600 1.2.2.2 pgoyette {
601 1.2.2.2 pgoyette omapi_connection_object_t *c;
602 1.2.2.2 pgoyette if (h -> type != omapi_type_connection)
603 1.2.2.2 pgoyette return -1;
604 1.2.2.2 pgoyette c = (omapi_connection_object_t *)h;
605 1.2.2.2 pgoyette return c->socket;
606 1.2.2.2 pgoyette }
607 1.2.2.2 pgoyette
608 1.2.2.2 pgoyette isc_result_t omapi_connection_connect (omapi_object_t *h)
609 1.2.2.2 pgoyette {
610 1.2.2.2 pgoyette isc_result_t status;
611 1.2.2.2 pgoyette
612 1.2.2.2 pgoyette /*
613 1.2.2.2 pgoyette * We use the INPROGRESS status to indicate that
614 1.2.2.2 pgoyette * we want more from the socket. In this case we
615 1.2.2.2 pgoyette * have now connected and are trying to write to
616 1.2.2.2 pgoyette * the socket for the first time. For the signaling
617 1.2.2.2 pgoyette * code this is the same as a SUCCESS so we don't
618 1.2.2.2 pgoyette * pass it on as a signal.
619 1.2.2.2 pgoyette */
620 1.2.2.2 pgoyette status = omapi_connection_connect_internal (h);
621 1.2.2.2 pgoyette if (status == ISC_R_INPROGRESS)
622 1.2.2.2 pgoyette return ISC_R_INPROGRESS;
623 1.2.2.2 pgoyette
624 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS)
625 1.2.2.2 pgoyette omapi_signal (h, "status", status);
626 1.2.2.2 pgoyette
627 1.2.2.2 pgoyette return ISC_R_SUCCESS;
628 1.2.2.2 pgoyette }
629 1.2.2.2 pgoyette
630 1.2.2.2 pgoyette static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
631 1.2.2.2 pgoyette {
632 1.2.2.2 pgoyette int error = 0;
633 1.2.2.2 pgoyette omapi_connection_object_t *c;
634 1.2.2.2 pgoyette socklen_t sl;
635 1.2.2.2 pgoyette isc_result_t status;
636 1.2.2.2 pgoyette
637 1.2.2.2 pgoyette if (h -> type != omapi_type_connection)
638 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
639 1.2.2.2 pgoyette c = (omapi_connection_object_t *)h;
640 1.2.2.2 pgoyette
641 1.2.2.2 pgoyette if (c -> state == omapi_connection_connecting) {
642 1.2.2.2 pgoyette sl = sizeof error;
643 1.2.2.2 pgoyette if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
644 1.2.2.2 pgoyette (char *)&error, &sl) < 0) {
645 1.2.2.2 pgoyette omapi_disconnect (h, 1);
646 1.2.2.2 pgoyette return ISC_R_SUCCESS;
647 1.2.2.2 pgoyette }
648 1.2.2.2 pgoyette if (!error)
649 1.2.2.2 pgoyette c -> state = omapi_connection_connected;
650 1.2.2.2 pgoyette }
651 1.2.2.2 pgoyette if (c -> state == omapi_connection_connecting ||
652 1.2.2.2 pgoyette c -> state == omapi_connection_unconnected) {
653 1.2.2.2 pgoyette if (c -> cptr >= c -> connect_list -> count) {
654 1.2.2.2 pgoyette switch (error) {
655 1.2.2.2 pgoyette case ECONNREFUSED:
656 1.2.2.2 pgoyette status = ISC_R_CONNREFUSED;
657 1.2.2.2 pgoyette break;
658 1.2.2.2 pgoyette case ENETUNREACH:
659 1.2.2.2 pgoyette status = ISC_R_NETUNREACH;
660 1.2.2.2 pgoyette break;
661 1.2.2.2 pgoyette default:
662 1.2.2.2 pgoyette status = uerr2isc (error);
663 1.2.2.2 pgoyette break;
664 1.2.2.2 pgoyette }
665 1.2.2.2 pgoyette omapi_disconnect (h, 1);
666 1.2.2.2 pgoyette return status;
667 1.2.2.2 pgoyette }
668 1.2.2.2 pgoyette
669 1.2.2.2 pgoyette if (c -> connect_list -> addresses [c -> cptr].addrtype !=
670 1.2.2.2 pgoyette AF_INET) {
671 1.2.2.2 pgoyette omapi_disconnect (h, 1);
672 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
673 1.2.2.2 pgoyette }
674 1.2.2.2 pgoyette
675 1.2.2.2 pgoyette memcpy (&c -> remote_addr.sin_addr,
676 1.2.2.2 pgoyette &c -> connect_list -> addresses [c -> cptr].address,
677 1.2.2.2 pgoyette sizeof c -> remote_addr.sin_addr);
678 1.2.2.2 pgoyette c -> remote_addr.sin_family = AF_INET;
679 1.2.2.2 pgoyette c -> remote_addr.sin_port =
680 1.2.2.2 pgoyette htons (c -> connect_list -> addresses [c -> cptr].port);
681 1.2.2.2 pgoyette #if defined (HAVE_SA_LEN)
682 1.2.2.2 pgoyette c -> remote_addr.sin_len = sizeof c -> remote_addr;
683 1.2.2.2 pgoyette #endif
684 1.2.2.2 pgoyette memset (&c -> remote_addr.sin_zero, 0,
685 1.2.2.2 pgoyette sizeof c -> remote_addr.sin_zero);
686 1.2.2.2 pgoyette ++c -> cptr;
687 1.2.2.2 pgoyette
688 1.2.2.2 pgoyette error = connect (c -> socket,
689 1.2.2.2 pgoyette (struct sockaddr *)&c -> remote_addr,
690 1.2.2.2 pgoyette sizeof c -> remote_addr);
691 1.2.2.2 pgoyette if (error < 0) {
692 1.2.2.2 pgoyette error = errno;
693 1.2.2.2 pgoyette if (error != EINPROGRESS) {
694 1.2.2.2 pgoyette omapi_disconnect (h, 1);
695 1.2.2.2 pgoyette switch (error) {
696 1.2.2.2 pgoyette case ECONNREFUSED:
697 1.2.2.2 pgoyette status = ISC_R_CONNREFUSED;
698 1.2.2.2 pgoyette break;
699 1.2.2.2 pgoyette case ENETUNREACH:
700 1.2.2.2 pgoyette status = ISC_R_NETUNREACH;
701 1.2.2.2 pgoyette break;
702 1.2.2.2 pgoyette default:
703 1.2.2.2 pgoyette status = uerr2isc (error);
704 1.2.2.2 pgoyette break;
705 1.2.2.2 pgoyette }
706 1.2.2.2 pgoyette return status;
707 1.2.2.2 pgoyette }
708 1.2.2.2 pgoyette c -> state = omapi_connection_connecting;
709 1.2.2.2 pgoyette return DHCP_R_INCOMPLETE;
710 1.2.2.2 pgoyette }
711 1.2.2.2 pgoyette c -> state = omapi_connection_connected;
712 1.2.2.2 pgoyette }
713 1.2.2.2 pgoyette
714 1.2.2.2 pgoyette /* I don't know why this would fail, so I'm tempted not to test
715 1.2.2.2 pgoyette the return value. */
716 1.2.2.2 pgoyette sl = sizeof (c -> local_addr);
717 1.2.2.2 pgoyette if (getsockname (c -> socket,
718 1.2.2.2 pgoyette (struct sockaddr *)&c -> local_addr, &sl) < 0) {
719 1.2.2.2 pgoyette }
720 1.2.2.2 pgoyette
721 1.2.2.2 pgoyette /* Reregister with the I/O object. If we don't already have an
722 1.2.2.2 pgoyette I/O object this turns into a register call, otherwise we simply
723 1.2.2.2 pgoyette modify the pointers in the I/O object. */
724 1.2.2.2 pgoyette
725 1.2.2.2 pgoyette status = omapi_reregister_io_object (h,
726 1.2.2.2 pgoyette omapi_connection_readfd,
727 1.2.2.2 pgoyette omapi_connection_writefd,
728 1.2.2.2 pgoyette omapi_connection_reader,
729 1.2.2.2 pgoyette omapi_connection_writer,
730 1.2.2.2 pgoyette omapi_connection_reaper);
731 1.2.2.2 pgoyette
732 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
733 1.2.2.2 pgoyette omapi_disconnect (h, 1);
734 1.2.2.2 pgoyette return status;
735 1.2.2.2 pgoyette }
736 1.2.2.2 pgoyette
737 1.2.2.2 pgoyette omapi_signal_in (h, "connect");
738 1.2.2.2 pgoyette omapi_addr_list_dereference (&c -> connect_list, MDL);
739 1.2.2.2 pgoyette return ISC_R_INPROGRESS;
740 1.2.2.2 pgoyette }
741 1.2.2.2 pgoyette
742 1.2.2.2 pgoyette /* Reaper function for connection - if the connection is completely closed,
743 1.2.2.2 pgoyette reap it. If it's in the disconnecting state, there were bytes left
744 1.2.2.2 pgoyette to write when the user closed it, so if there are now no bytes left to
745 1.2.2.2 pgoyette write, we can close it. */
746 1.2.2.2 pgoyette isc_result_t omapi_connection_reaper (omapi_object_t *h)
747 1.2.2.2 pgoyette {
748 1.2.2.2 pgoyette omapi_connection_object_t *c;
749 1.2.2.2 pgoyette
750 1.2.2.2 pgoyette if (h -> type != omapi_type_connection)
751 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
752 1.2.2.2 pgoyette
753 1.2.2.2 pgoyette c = (omapi_connection_object_t *)h;
754 1.2.2.2 pgoyette if (c -> state == omapi_connection_disconnecting &&
755 1.2.2.2 pgoyette c -> out_bytes == 0) {
756 1.2.2.2 pgoyette #ifdef DEBUG_PROTOCOL
757 1.2.2.2 pgoyette log_debug ("omapi_connection_reaper(): disconnect");
758 1.2.2.2 pgoyette #endif
759 1.2.2.2 pgoyette omapi_disconnect (h, 1);
760 1.2.2.2 pgoyette }
761 1.2.2.2 pgoyette if (c -> state == omapi_connection_closed) {
762 1.2.2.2 pgoyette #ifdef DEBUG_PROTOCOL
763 1.2.2.2 pgoyette log_debug ("omapi_connection_reaper(): closed");
764 1.2.2.2 pgoyette #endif
765 1.2.2.2 pgoyette return ISC_R_NOTCONNECTED;
766 1.2.2.2 pgoyette }
767 1.2.2.2 pgoyette return ISC_R_SUCCESS;
768 1.2.2.2 pgoyette }
769 1.2.2.2 pgoyette
770 1.2.2.2 pgoyette static isc_result_t make_dst_key (dst_key_t **dst_key, omapi_object_t *a) {
771 1.2.2.2 pgoyette omapi_value_t *name = (omapi_value_t *)0;
772 1.2.2.2 pgoyette omapi_value_t *algorithm = (omapi_value_t *)0;
773 1.2.2.2 pgoyette omapi_value_t *key = (omapi_value_t *)0;
774 1.2.2.2 pgoyette char *name_str = NULL;
775 1.2.2.2 pgoyette isc_result_t status = ISC_R_SUCCESS;
776 1.2.2.2 pgoyette
777 1.2.2.2 pgoyette if (status == ISC_R_SUCCESS)
778 1.2.2.2 pgoyette status = omapi_get_value_str
779 1.2.2.2 pgoyette (a, (omapi_object_t *)0, "name", &name);
780 1.2.2.2 pgoyette
781 1.2.2.2 pgoyette if (status == ISC_R_SUCCESS)
782 1.2.2.2 pgoyette status = omapi_get_value_str
783 1.2.2.2 pgoyette (a, (omapi_object_t *)0, "algorithm", &algorithm);
784 1.2.2.2 pgoyette
785 1.2.2.2 pgoyette if (status == ISC_R_SUCCESS)
786 1.2.2.2 pgoyette status = omapi_get_value_str
787 1.2.2.2 pgoyette (a, (omapi_object_t *)0, "key", &key);
788 1.2.2.2 pgoyette
789 1.2.2.2 pgoyette if (status == ISC_R_SUCCESS) {
790 1.2.2.2 pgoyette if ((algorithm->value->type != omapi_datatype_data &&
791 1.2.2.2 pgoyette algorithm->value->type != omapi_datatype_string) ||
792 1.2.2.2 pgoyette strncasecmp((char *)algorithm->value->u.buffer.value,
793 1.2.2.2 pgoyette NS_TSIG_ALG_HMAC_MD5 ".",
794 1.2.2.2 pgoyette algorithm->value->u.buffer.len) != 0) {
795 1.2.2.2 pgoyette status = DHCP_R_INVALIDARG;
796 1.2.2.2 pgoyette }
797 1.2.2.2 pgoyette }
798 1.2.2.2 pgoyette
799 1.2.2.2 pgoyette if (status == ISC_R_SUCCESS) {
800 1.2.2.2 pgoyette name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL);
801 1.2.2.2 pgoyette if (!name_str)
802 1.2.2.2 pgoyette status = ISC_R_NOMEMORY;
803 1.2.2.2 pgoyette }
804 1.2.2.2 pgoyette
805 1.2.2.2 pgoyette if (status == ISC_R_SUCCESS) {
806 1.2.2.2 pgoyette memcpy (name_str,
807 1.2.2.2 pgoyette name -> value -> u.buffer.value,
808 1.2.2.2 pgoyette name -> value -> u.buffer.len);
809 1.2.2.2 pgoyette name_str [name -> value -> u.buffer.len] = 0;
810 1.2.2.2 pgoyette
811 1.2.2.2 pgoyette status = isclib_make_dst_key(name_str,
812 1.2.2.2 pgoyette DHCP_HMAC_MD5_NAME,
813 1.2.2.2 pgoyette key->value->u.buffer.value,
814 1.2.2.2 pgoyette key->value->u.buffer.len,
815 1.2.2.2 pgoyette dst_key);
816 1.2.2.2 pgoyette
817 1.2.2.2 pgoyette if (*dst_key == NULL)
818 1.2.2.2 pgoyette status = ISC_R_NOMEMORY;
819 1.2.2.2 pgoyette }
820 1.2.2.2 pgoyette
821 1.2.2.2 pgoyette if (name_str)
822 1.2.2.2 pgoyette dfree (name_str, MDL);
823 1.2.2.2 pgoyette if (key)
824 1.2.2.2 pgoyette omapi_value_dereference (&key, MDL);
825 1.2.2.2 pgoyette if (algorithm)
826 1.2.2.2 pgoyette omapi_value_dereference (&algorithm, MDL);
827 1.2.2.2 pgoyette if (name)
828 1.2.2.2 pgoyette omapi_value_dereference (&name, MDL);
829 1.2.2.2 pgoyette
830 1.2.2.2 pgoyette return status;
831 1.2.2.2 pgoyette }
832 1.2.2.2 pgoyette
833 1.2.2.2 pgoyette isc_result_t omapi_connection_sign_data (int mode,
834 1.2.2.2 pgoyette dst_key_t *key,
835 1.2.2.2 pgoyette void **context,
836 1.2.2.2 pgoyette const unsigned char *data,
837 1.2.2.2 pgoyette const unsigned len,
838 1.2.2.2 pgoyette omapi_typed_data_t **result)
839 1.2.2.2 pgoyette {
840 1.2.2.2 pgoyette omapi_typed_data_t *td = (omapi_typed_data_t *)0;
841 1.2.2.2 pgoyette isc_result_t status;
842 1.2.2.2 pgoyette dst_context_t **dctx = (dst_context_t **)context;
843 1.2.2.2 pgoyette
844 1.2.2.2 pgoyette /* Create the context for the dst module */
845 1.2.2.2 pgoyette if (mode & SIG_MODE_INIT) {
846 1.2.2.2 pgoyette status = dst_context_create(key, dhcp_gbl_ctx.mctx, dctx);
847 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
848 1.2.2.2 pgoyette return status;
849 1.2.2.2 pgoyette }
850 1.2.2.2 pgoyette }
851 1.2.2.2 pgoyette
852 1.2.2.2 pgoyette /* If we have any data add it to the context */
853 1.2.2.2 pgoyette if (len != 0) {
854 1.2.2.2 pgoyette isc_region_t region;
855 1.2.2.2 pgoyette region.base = (unsigned char *)data;
856 1.2.2.2 pgoyette region.length = len;
857 1.2.2.2 pgoyette dst_context_adddata(*dctx, ®ion);
858 1.2.2.2 pgoyette }
859 1.2.2.2 pgoyette
860 1.2.2.2 pgoyette /* Finish the signature and clean up the context */
861 1.2.2.2 pgoyette if (mode & SIG_MODE_FINAL) {
862 1.2.2.2 pgoyette unsigned int sigsize;
863 1.2.2.2 pgoyette isc_buffer_t sigbuf;
864 1.2.2.2 pgoyette
865 1.2.2.2 pgoyette status = dst_key_sigsize(key, &sigsize);
866 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
867 1.2.2.2 pgoyette goto cleanup;
868 1.2.2.2 pgoyette }
869 1.2.2.2 pgoyette
870 1.2.2.2 pgoyette status = omapi_typed_data_new (MDL, &td,
871 1.2.2.2 pgoyette omapi_datatype_data,
872 1.2.2.2 pgoyette sigsize);
873 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
874 1.2.2.2 pgoyette goto cleanup;
875 1.2.2.2 pgoyette }
876 1.2.2.2 pgoyette
877 1.2.2.2 pgoyette isc_buffer_init(&sigbuf, td->u.buffer.value, td->u.buffer.len);
878 1.2.2.2 pgoyette status = dst_context_sign(*dctx, &sigbuf);
879 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
880 1.2.2.2 pgoyette goto cleanup;
881 1.2.2.2 pgoyette }
882 1.2.2.2 pgoyette
883 1.2.2.2 pgoyette if (result) {
884 1.2.2.2 pgoyette omapi_typed_data_reference (result, td, MDL);
885 1.2.2.2 pgoyette }
886 1.2.2.2 pgoyette
887 1.2.2.2 pgoyette cleanup:
888 1.2.2.2 pgoyette /* We are done with the context and the td. On success
889 1.2.2.2 pgoyette * the td is now referenced from result, on failure we
890 1.2.2.2 pgoyette * don't need it any more */
891 1.2.2.2 pgoyette if (td) {
892 1.2.2.2 pgoyette omapi_typed_data_dereference (&td, MDL);
893 1.2.2.2 pgoyette }
894 1.2.2.2 pgoyette dst_context_destroy(dctx);
895 1.2.2.2 pgoyette return status;
896 1.2.2.2 pgoyette }
897 1.2.2.2 pgoyette
898 1.2.2.2 pgoyette return ISC_R_SUCCESS;
899 1.2.2.2 pgoyette }
900 1.2.2.2 pgoyette
901 1.2.2.2 pgoyette isc_result_t omapi_connection_output_auth_length (omapi_object_t *h,
902 1.2.2.2 pgoyette unsigned *l)
903 1.2.2.2 pgoyette {
904 1.2.2.2 pgoyette omapi_connection_object_t *c;
905 1.2.2.2 pgoyette
906 1.2.2.2 pgoyette if (h->type != omapi_type_connection)
907 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
908 1.2.2.2 pgoyette c = (omapi_connection_object_t *)h;
909 1.2.2.2 pgoyette
910 1.2.2.2 pgoyette if (c->out_key == NULL)
911 1.2.2.2 pgoyette return ISC_R_NOTFOUND;
912 1.2.2.2 pgoyette
913 1.2.2.2 pgoyette return(dst_key_sigsize(c->out_key, l));
914 1.2.2.2 pgoyette }
915 1.2.2.2 pgoyette
916 1.2.2.2 pgoyette isc_result_t omapi_connection_set_value (omapi_object_t *h,
917 1.2.2.2 pgoyette omapi_object_t *id,
918 1.2.2.2 pgoyette omapi_data_string_t *name,
919 1.2.2.2 pgoyette omapi_typed_data_t *value)
920 1.2.2.2 pgoyette {
921 1.2.2.2 pgoyette omapi_connection_object_t *c;
922 1.2.2.2 pgoyette isc_result_t status;
923 1.2.2.2 pgoyette
924 1.2.2.2 pgoyette if (h -> type != omapi_type_connection)
925 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
926 1.2.2.2 pgoyette c = (omapi_connection_object_t *)h;
927 1.2.2.2 pgoyette
928 1.2.2.2 pgoyette if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
929 1.2.2.2 pgoyette if (value && value -> type != omapi_datatype_object)
930 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
931 1.2.2.2 pgoyette
932 1.2.2.2 pgoyette if (c -> in_context) {
933 1.2.2.2 pgoyette omapi_connection_sign_data (SIG_MODE_FINAL,
934 1.2.2.2 pgoyette c -> in_key,
935 1.2.2.2 pgoyette &c -> in_context,
936 1.2.2.2 pgoyette 0, 0,
937 1.2.2.2 pgoyette (omapi_typed_data_t **) 0);
938 1.2.2.2 pgoyette }
939 1.2.2.2 pgoyette
940 1.2.2.2 pgoyette if (c->in_key != NULL) {
941 1.2.2.2 pgoyette dst_key_free(&c->in_key);
942 1.2.2.2 pgoyette }
943 1.2.2.2 pgoyette
944 1.2.2.2 pgoyette if (value) {
945 1.2.2.2 pgoyette status = make_dst_key (&c -> in_key,
946 1.2.2.2 pgoyette value -> u.object);
947 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS)
948 1.2.2.2 pgoyette return status;
949 1.2.2.2 pgoyette }
950 1.2.2.2 pgoyette
951 1.2.2.2 pgoyette return ISC_R_SUCCESS;
952 1.2.2.2 pgoyette }
953 1.2.2.2 pgoyette else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
954 1.2.2.2 pgoyette if (value && value -> type != omapi_datatype_object)
955 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
956 1.2.2.2 pgoyette
957 1.2.2.2 pgoyette if (c -> out_context) {
958 1.2.2.2 pgoyette omapi_connection_sign_data (SIG_MODE_FINAL,
959 1.2.2.2 pgoyette c -> out_key,
960 1.2.2.2 pgoyette &c -> out_context,
961 1.2.2.2 pgoyette 0, 0,
962 1.2.2.2 pgoyette (omapi_typed_data_t **) 0);
963 1.2.2.2 pgoyette }
964 1.2.2.2 pgoyette
965 1.2.2.2 pgoyette if (c->out_key != NULL) {
966 1.2.2.2 pgoyette dst_key_free(&c->out_key);
967 1.2.2.2 pgoyette }
968 1.2.2.2 pgoyette
969 1.2.2.2 pgoyette if (value) {
970 1.2.2.2 pgoyette status = make_dst_key (&c -> out_key,
971 1.2.2.2 pgoyette value -> u.object);
972 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS)
973 1.2.2.2 pgoyette return status;
974 1.2.2.2 pgoyette }
975 1.2.2.2 pgoyette
976 1.2.2.2 pgoyette return ISC_R_SUCCESS;
977 1.2.2.2 pgoyette }
978 1.2.2.2 pgoyette
979 1.2.2.2 pgoyette if (h -> inner && h -> inner -> type -> set_value)
980 1.2.2.2 pgoyette return (*(h -> inner -> type -> set_value))
981 1.2.2.2 pgoyette (h -> inner, id, name, value);
982 1.2.2.2 pgoyette return ISC_R_NOTFOUND;
983 1.2.2.2 pgoyette }
984 1.2.2.2 pgoyette
985 1.2.2.2 pgoyette isc_result_t omapi_connection_get_value (omapi_object_t *h,
986 1.2.2.2 pgoyette omapi_object_t *id,
987 1.2.2.2 pgoyette omapi_data_string_t *name,
988 1.2.2.2 pgoyette omapi_value_t **value)
989 1.2.2.2 pgoyette {
990 1.2.2.2 pgoyette omapi_connection_object_t *c;
991 1.2.2.2 pgoyette omapi_typed_data_t *td = (omapi_typed_data_t *)0;
992 1.2.2.2 pgoyette isc_result_t status;
993 1.2.2.2 pgoyette unsigned int sigsize;
994 1.2.2.2 pgoyette
995 1.2.2.2 pgoyette if (h -> type != omapi_type_connection)
996 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
997 1.2.2.2 pgoyette c = (omapi_connection_object_t *)h;
998 1.2.2.2 pgoyette
999 1.2.2.2 pgoyette if (omapi_ds_strcmp (name, "input-signature") == 0) {
1000 1.2.2.2 pgoyette if (!c -> in_key || !c -> in_context)
1001 1.2.2.2 pgoyette return ISC_R_NOTFOUND;
1002 1.2.2.2 pgoyette
1003 1.2.2.2 pgoyette status = omapi_connection_sign_data (SIG_MODE_FINAL,
1004 1.2.2.2 pgoyette c -> in_key,
1005 1.2.2.2 pgoyette &c -> in_context,
1006 1.2.2.2 pgoyette 0, 0, &td);
1007 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS)
1008 1.2.2.2 pgoyette return status;
1009 1.2.2.2 pgoyette
1010 1.2.2.2 pgoyette status = omapi_make_value (value, name, td, MDL);
1011 1.2.2.2 pgoyette omapi_typed_data_dereference (&td, MDL);
1012 1.2.2.2 pgoyette return status;
1013 1.2.2.2 pgoyette
1014 1.2.2.2 pgoyette } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
1015 1.2.2.2 pgoyette if (c->in_key == NULL)
1016 1.2.2.2 pgoyette return ISC_R_NOTFOUND;
1017 1.2.2.2 pgoyette
1018 1.2.2.2 pgoyette status = dst_key_sigsize(c->in_key, &sigsize);
1019 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
1020 1.2.2.2 pgoyette return(status);
1021 1.2.2.2 pgoyette }
1022 1.2.2.2 pgoyette
1023 1.2.2.2 pgoyette return omapi_make_int_value(value, name, sigsize, MDL);
1024 1.2.2.2 pgoyette
1025 1.2.2.2 pgoyette } else if (omapi_ds_strcmp (name, "output-signature") == 0) {
1026 1.2.2.2 pgoyette if (!c -> out_key || !c -> out_context)
1027 1.2.2.2 pgoyette return ISC_R_NOTFOUND;
1028 1.2.2.2 pgoyette
1029 1.2.2.2 pgoyette status = omapi_connection_sign_data (SIG_MODE_FINAL,
1030 1.2.2.2 pgoyette c -> out_key,
1031 1.2.2.2 pgoyette &c -> out_context,
1032 1.2.2.2 pgoyette 0, 0, &td);
1033 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS)
1034 1.2.2.2 pgoyette return status;
1035 1.2.2.2 pgoyette
1036 1.2.2.2 pgoyette status = omapi_make_value (value, name, td, MDL);
1037 1.2.2.2 pgoyette omapi_typed_data_dereference (&td, MDL);
1038 1.2.2.2 pgoyette return status;
1039 1.2.2.2 pgoyette
1040 1.2.2.2 pgoyette } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
1041 1.2.2.2 pgoyette if (c->out_key == NULL)
1042 1.2.2.2 pgoyette return ISC_R_NOTFOUND;
1043 1.2.2.2 pgoyette
1044 1.2.2.2 pgoyette
1045 1.2.2.2 pgoyette status = dst_key_sigsize(c->out_key, &sigsize);
1046 1.2.2.2 pgoyette if (status != ISC_R_SUCCESS) {
1047 1.2.2.2 pgoyette return(status);
1048 1.2.2.2 pgoyette }
1049 1.2.2.2 pgoyette
1050 1.2.2.2 pgoyette return omapi_make_int_value(value, name, sigsize, MDL);
1051 1.2.2.2 pgoyette }
1052 1.2.2.2 pgoyette
1053 1.2.2.2 pgoyette if (h -> inner && h -> inner -> type -> get_value)
1054 1.2.2.2 pgoyette return (*(h -> inner -> type -> get_value))
1055 1.2.2.2 pgoyette (h -> inner, id, name, value);
1056 1.2.2.2 pgoyette return ISC_R_NOTFOUND;
1057 1.2.2.2 pgoyette }
1058 1.2.2.2 pgoyette
1059 1.2.2.2 pgoyette isc_result_t omapi_connection_destroy (omapi_object_t *h,
1060 1.2.2.2 pgoyette const char *file, int line)
1061 1.2.2.2 pgoyette {
1062 1.2.2.2 pgoyette omapi_connection_object_t *c;
1063 1.2.2.2 pgoyette
1064 1.2.2.2 pgoyette #ifdef DEBUG_PROTOCOL
1065 1.2.2.2 pgoyette log_debug ("omapi_connection_destroy()");
1066 1.2.2.2 pgoyette #endif
1067 1.2.2.2 pgoyette
1068 1.2.2.2 pgoyette if (h -> type != omapi_type_connection)
1069 1.2.2.2 pgoyette return ISC_R_UNEXPECTED;
1070 1.2.2.2 pgoyette c = (omapi_connection_object_t *)(h);
1071 1.2.2.2 pgoyette if (c -> state == omapi_connection_connected)
1072 1.2.2.2 pgoyette omapi_disconnect (h, 1);
1073 1.2.2.2 pgoyette if (c -> listener)
1074 1.2.2.2 pgoyette omapi_listener_dereference (&c -> listener, file, line);
1075 1.2.2.2 pgoyette if (c -> connect_list)
1076 1.2.2.2 pgoyette omapi_addr_list_dereference (&c -> connect_list, file, line);
1077 1.2.2.2 pgoyette return ISC_R_SUCCESS;
1078 1.2.2.2 pgoyette }
1079 1.2.2.2 pgoyette
1080 1.2.2.2 pgoyette isc_result_t omapi_connection_signal_handler (omapi_object_t *h,
1081 1.2.2.2 pgoyette const char *name, va_list ap)
1082 1.2.2.2 pgoyette {
1083 1.2.2.2 pgoyette if (h -> type != omapi_type_connection)
1084 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
1085 1.2.2.2 pgoyette
1086 1.2.2.2 pgoyette #ifdef DEBUG_PROTOCOL
1087 1.2.2.2 pgoyette log_debug ("omapi_connection_signal_handler(%s)", name);
1088 1.2.2.2 pgoyette #endif
1089 1.2.2.2 pgoyette
1090 1.2.2.2 pgoyette if (h -> inner && h -> inner -> type -> signal_handler)
1091 1.2.2.2 pgoyette return (*(h -> inner -> type -> signal_handler)) (h -> inner,
1092 1.2.2.2 pgoyette name, ap);
1093 1.2.2.2 pgoyette return ISC_R_NOTFOUND;
1094 1.2.2.2 pgoyette }
1095 1.2.2.2 pgoyette
1096 1.2.2.2 pgoyette /* Write all the published values associated with the object through the
1097 1.2.2.2 pgoyette specified connection. */
1098 1.2.2.2 pgoyette
1099 1.2.2.2 pgoyette isc_result_t omapi_connection_stuff_values (omapi_object_t *c,
1100 1.2.2.2 pgoyette omapi_object_t *id,
1101 1.2.2.2 pgoyette omapi_object_t *m)
1102 1.2.2.2 pgoyette {
1103 1.2.2.2 pgoyette if (m -> type != omapi_type_connection)
1104 1.2.2.2 pgoyette return DHCP_R_INVALIDARG;
1105 1.2.2.2 pgoyette
1106 1.2.2.2 pgoyette if (m -> inner && m -> inner -> type -> stuff_values)
1107 1.2.2.2 pgoyette return (*(m -> inner -> type -> stuff_values)) (c, id,
1108 1.2.2.2 pgoyette m -> inner);
1109 1.2.2.2 pgoyette return ISC_R_SUCCESS;
1110 1.2.2.2 pgoyette }
1111