Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / dhcp / omapip / listener.c
blob055400755cc1de24b5a195c130aaf83f5c396ee0
1 /* listener.c
3 Subroutines that support the generic listener object. */
5 /*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1999-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
35 #include <omapip/omapip_p.h>
37 #if defined (TRACING)
38 omapi_array_t *trace_listeners;
39 static void trace_listener_accept_input (trace_type_t *, unsigned, char *);
40 static void trace_listener_remember (omapi_listener_object_t *,
41 const char *, int);
42 static void trace_listener_accept_stop (trace_type_t *);
43 trace_type_t *trace_listener_accept;
44 #endif
46 OMAPI_OBJECT_ALLOC (omapi_listener,
47 omapi_listener_object_t, omapi_type_listener)
49 isc_result_t omapi_listen (omapi_object_t *h,
50 unsigned port,
51 int max)
53 omapi_addr_t addr;
55 #ifdef DEBUG_PROTOCOL
56 log_debug ("omapi_listen(port=%d, max=%d)", port, max);
57 #endif
59 addr.addrtype = AF_INET;
60 addr.addrlen = sizeof (struct in_addr);
61 memset (addr.address, 0, sizeof addr.address); /* INADDR_ANY */
62 addr.port = port;
64 return omapi_listen_addr (h, &addr, max);
67 isc_result_t omapi_listen_addr (omapi_object_t *h,
68 omapi_addr_t *addr,
69 int max)
71 isc_result_t status;
72 omapi_listener_object_t *obj;
73 int i;
75 /* Get the handle. */
76 obj = (omapi_listener_object_t *)0;
77 status = omapi_listener_allocate (&obj, MDL);
78 if (status != ISC_R_SUCCESS)
79 return status;
81 /* Connect this object to the inner object. */
82 status = omapi_object_reference (&h -> outer,
83 (omapi_object_t *)obj, MDL);
84 if (status != ISC_R_SUCCESS) {
85 omapi_listener_dereference (&obj, MDL);
86 return status;
88 status = omapi_object_reference (&obj -> inner, h, MDL);
89 if (status != ISC_R_SUCCESS) {
90 omapi_listener_dereference (&obj, MDL);
91 return status;
94 /* Currently only support TCPv4 addresses. */
95 if (addr -> addrtype != AF_INET)
96 return ISC_R_INVALIDARG;
98 /* Set up the address on which we will listen... */
99 memset (&obj -> address, 0, sizeof obj -> address);
100 obj -> address.sin_port = htons (addr -> port);
101 memcpy (&obj -> address.sin_addr,
102 addr -> address, sizeof obj -> address.sin_addr);
103 #if defined (HAVE_SA_LEN)
104 obj -> address.sin_len =
105 sizeof (struct sockaddr_in);
106 #endif
107 obj -> address.sin_family = AF_INET;
109 #if defined (TRACING)
110 /* If we're playing back a trace file, we remember the object
111 on the trace listener queue. */
112 if (trace_playback ()) {
113 trace_listener_remember (obj, MDL);
114 } else {
115 #endif
116 /* Create a socket on which to listen. */
117 obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
118 if (!obj -> socket) {
119 omapi_listener_dereference (&obj, MDL);
120 if (errno == EMFILE
121 || errno == ENFILE || errno == ENOBUFS)
122 return ISC_R_NORESOURCES;
123 return ISC_R_UNEXPECTED;
126 #if defined (HAVE_SETFD)
127 if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
128 close (obj -> socket);
129 omapi_listener_dereference (&obj, MDL);
130 return ISC_R_UNEXPECTED;
132 #endif
134 /* Set the REUSEADDR option so that we don't fail to start if
135 we're being restarted. */
136 i = 1;
137 if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
138 (char *)&i, sizeof i) < 0) {
139 close (obj -> socket);
140 omapi_listener_dereference (&obj, MDL);
141 return ISC_R_UNEXPECTED;
144 /* Try to bind to the wildcard address using the port number
145 we were given. */
146 i = bind (obj -> socket,
147 (struct sockaddr *)&obj -> address,
148 sizeof obj -> address);
149 if (i < 0) {
150 omapi_listener_dereference (&obj, MDL);
151 if (errno == EADDRINUSE)
152 return ISC_R_ADDRNOTAVAIL;
153 if (errno == EPERM)
154 return ISC_R_NOPERM;
155 return ISC_R_UNEXPECTED;
158 /* Now tell the kernel to listen for connections. */
159 if (listen (obj -> socket, max)) {
160 omapi_listener_dereference (&obj, MDL);
161 return ISC_R_UNEXPECTED;
164 if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
165 omapi_listener_dereference (&obj, MDL);
166 return ISC_R_UNEXPECTED;
169 status = omapi_register_io_object ((omapi_object_t *)obj,
170 omapi_listener_readfd, 0,
171 omapi_accept, 0, 0);
172 #if defined (TRACING)
174 #endif
175 omapi_listener_dereference (&obj, MDL);
176 return status;
179 /* Return the socket on which the dispatcher should wait for readiness
180 to read, for a listener object. */
181 int omapi_listener_readfd (omapi_object_t *h)
183 omapi_listener_object_t *l;
185 if (h -> type != omapi_type_listener)
186 return -1;
187 l = (omapi_listener_object_t *)h;
189 return l -> socket;
192 /* Reader callback for a listener object. Accept an incoming connection. */
193 isc_result_t omapi_accept (omapi_object_t *h)
195 isc_result_t status;
196 SOCKLEN_T len;
197 omapi_connection_object_t *obj;
198 omapi_listener_object_t *listener;
199 struct sockaddr_in addr;
200 int socket;
202 if (h -> type != omapi_type_listener)
203 return ISC_R_INVALIDARG;
204 listener = (omapi_listener_object_t *)h;
206 /* Accept the connection. */
207 len = sizeof addr;
208 socket = accept (listener -> socket,
209 ((struct sockaddr *)&(addr)), &len);
210 if (socket < 0) {
211 if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
212 return ISC_R_NORESOURCES;
213 return ISC_R_UNEXPECTED;
216 #if defined (TRACING)
217 /* If we're recording a trace, remember the connection. */
218 if (trace_record ()) {
219 trace_iov_t iov [3];
220 iov [0].buf = (char *)&addr.sin_port;
221 iov [0].len = sizeof addr.sin_port;
222 iov [1].buf = (char *)&addr.sin_addr;
223 iov [1].len = sizeof addr.sin_addr;
224 iov [2].buf = (char *)&listener -> address.sin_port;
225 iov [2].len = sizeof listener -> address.sin_port;
226 trace_write_packet_iov (trace_listener_accept,
227 3, iov, MDL);
229 #endif
231 obj = (omapi_connection_object_t *)0;
232 status = omapi_listener_connect (&obj, listener, socket, &addr);
233 if (status != ISC_R_SUCCESS) {
234 close (socket);
235 return status;
238 status = omapi_register_io_object ((omapi_object_t *)obj,
239 omapi_connection_readfd,
240 omapi_connection_writefd,
241 omapi_connection_reader,
242 omapi_connection_writer,
243 omapi_connection_reaper);
245 /* Lose our reference to the connection, so it'll be gc'd when it's
246 reaped. */
247 omapi_connection_dereference (&obj, MDL);
248 if (status != ISC_R_SUCCESS)
249 omapi_disconnect ((omapi_object_t *)(obj), 1);
250 return status;
253 isc_result_t omapi_listener_connect (omapi_connection_object_t **obj,
254 omapi_listener_object_t *listener,
255 int socket,
256 struct sockaddr_in *remote_addr)
258 isc_result_t status;
259 omapi_object_t *h = (omapi_object_t *)listener;
260 omapi_addr_t addr;
262 #ifdef DEBUG_PROTOCOL
263 log_debug ("omapi_accept()");
264 #endif
266 /* Get the handle. */
267 status = omapi_connection_allocate (obj, MDL);
268 if (status != ISC_R_SUCCESS)
269 return status;
271 (*obj) -> state = omapi_connection_connected;
272 (*obj) -> remote_addr = *remote_addr;
273 (*obj) -> socket = socket;
275 /* Verify that this host is allowed to connect. */
276 if (listener -> verify_addr) {
277 addr.addrtype = AF_INET;
278 addr.addrlen = sizeof (remote_addr -> sin_addr);
279 memcpy (addr.address, &remote_addr -> sin_addr,
280 sizeof (remote_addr -> sin_addr));
281 addr.port = ntohs(remote_addr -> sin_port);
283 status = (listener -> verify_addr) (h, &addr);
284 if (status != ISC_R_SUCCESS) {
285 omapi_disconnect ((omapi_object_t *)(*obj), 1);
286 omapi_connection_dereference (obj, MDL);
287 return status;
291 omapi_listener_reference (&(*obj) -> listener, listener, MDL);
292 #if defined (TRACING)
293 omapi_connection_register (*obj, MDL);
294 #endif
295 status = omapi_signal (h, "connect", (*obj));
296 return status;
299 #if defined (TRACING)
300 OMAPI_ARRAY_TYPE(omapi_listener, omapi_listener_object_t)
302 void omapi_listener_trace_setup (void) {
303 trace_listener_accept =
304 trace_type_register ("listener-accept", (void *)0,
305 trace_listener_accept_input,
306 trace_listener_accept_stop, MDL);
309 static void trace_listener_remember (omapi_listener_object_t *obj,
310 const char *file, int line)
312 isc_result_t status;
313 if (!trace_listeners) {
314 status = omapi_listener_array_allocate (&trace_listeners,
315 file, line);
316 if (status != ISC_R_SUCCESS) {
317 foo:
318 log_error ("trace_listener_remember: %s",
319 isc_result_totext (status));
320 return;
323 status = omapi_listener_array_extend (trace_listeners, obj,
324 &obj -> index, MDL);
325 if (status != ISC_R_SUCCESS)
326 goto foo;
329 static void trace_listener_accept_input (trace_type_t *ttype,
330 unsigned length, char *buf)
332 struct in_addr *addr;
333 u_int16_t *remote_port;
334 u_int16_t *local_port;
335 omapi_connection_object_t *obj;
336 isc_result_t status;
337 struct sockaddr_in remote_addr;
339 addr = (struct in_addr *)buf;
340 remote_port = (u_int16_t *)(addr + 1);
341 local_port = remote_port + 1;
343 memset (&remote_addr, 0, sizeof remote_addr);
344 remote_addr.sin_addr = *addr;
345 remote_addr.sin_port = *remote_port;
347 omapi_array_foreach_begin (trace_listeners,
348 omapi_listener_object_t, lp) {
349 if (lp -> address.sin_port == *local_port) {
350 obj = (omapi_connection_object_t *)0;
351 status = omapi_listener_connect (&obj,
352 lp, 0, &remote_addr);
353 omapi_listener_dereference (&lp, MDL);
354 return;
356 } omapi_array_foreach_end (trace_listeners,
357 omapi_listener_object_t, lp);
358 log_error ("trace_listener_accept: %s from %s/%d to port %d",
359 "unexpected connect",
360 inet_ntoa (*addr), *remote_port, *local_port);
363 static void trace_listener_accept_stop (trace_type_t *ttype) { }
366 #endif
368 isc_result_t omapi_listener_configure_security (omapi_object_t *h,
369 isc_result_t (*verify_addr)
370 (omapi_object_t *,
371 omapi_addr_t *))
373 omapi_listener_object_t *l;
375 if (h -> type != omapi_type_listener)
376 return ISC_R_INVALIDARG;
377 l = (omapi_listener_object_t *)h;
379 l -> verify_addr = verify_addr;
381 return ISC_R_SUCCESS;
384 isc_result_t omapi_listener_set_value (omapi_object_t *h,
385 omapi_object_t *id,
386 omapi_data_string_t *name,
387 omapi_typed_data_t *value)
389 if (h -> type != omapi_type_listener)
390 return ISC_R_INVALIDARG;
392 if (h -> inner && h -> inner -> type -> set_value)
393 return (*(h -> inner -> type -> set_value))
394 (h -> inner, id, name, value);
395 return ISC_R_NOTFOUND;
398 isc_result_t omapi_listener_get_value (omapi_object_t *h,
399 omapi_object_t *id,
400 omapi_data_string_t *name,
401 omapi_value_t **value)
403 if (h -> type != omapi_type_listener)
404 return ISC_R_INVALIDARG;
406 if (h -> inner && h -> inner -> type -> get_value)
407 return (*(h -> inner -> type -> get_value))
408 (h -> inner, id, name, value);
409 return ISC_R_NOTFOUND;
412 isc_result_t omapi_listener_destroy (omapi_object_t *h,
413 const char *file, int line)
415 omapi_listener_object_t *l;
417 if (h -> type != omapi_type_listener)
418 return ISC_R_INVALIDARG;
419 l = (omapi_listener_object_t *)h;
421 #ifdef DEBUG_PROTOCOL
422 log_debug ("omapi_listener_destroy()");
423 #endif
425 if (l -> socket != -1) {
426 close (l -> socket);
427 l -> socket = -1;
429 return ISC_R_SUCCESS;
432 isc_result_t omapi_listener_signal_handler (omapi_object_t *h,
433 const char *name, va_list ap)
435 if (h -> type != omapi_type_listener)
436 return ISC_R_INVALIDARG;
438 if (h -> inner && h -> inner -> type -> signal_handler)
439 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
440 name, ap);
441 return ISC_R_NOTFOUND;
444 /* Write all the published values associated with the object through the
445 specified connection. */
447 isc_result_t omapi_listener_stuff_values (omapi_object_t *c,
448 omapi_object_t *id,
449 omapi_object_t *l)
452 if (l -> type != omapi_type_listener)
453 return ISC_R_INVALIDARG;
455 if (l -> inner && l -> inner -> type -> stuff_values)
456 return (*(l -> inner -> type -> stuff_values)) (c, id,
457 l -> inner);
458 return ISC_R_SUCCESS;