3 Subroutines that support the generic listener object. */
6 * Copyright (c) 2004,2007,2009 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.
23 * Redwood City, CA 94063
25 * https://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 * ``https://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''.
37 #include <omapip/omapip_p.h>
41 omapi_array_t *trace_listeners;
42 static void trace_listener_accept_input (trace_type_t *, unsigned, char *);
43 static void trace_listener_remember (omapi_listener_object_t *,
45 static void trace_listener_accept_stop (trace_type_t *);
46 trace_type_t *trace_listener_accept;
49 OMAPI_OBJECT_ALLOC (omapi_listener,
50 omapi_listener_object_t, omapi_type_listener)
52 isc_result_t omapi_listen (omapi_object_t *h,
59 log_debug ("omapi_listen(port=%d, max=%d)", port, max);
62 addr.addrtype = AF_INET;
63 addr.addrlen = sizeof (struct in_addr);
64 memset (addr.address, 0, sizeof addr.address); /* INADDR_ANY */
67 return omapi_listen_addr (h, &addr, max);
70 isc_result_t omapi_listen_addr (omapi_object_t *h,
75 omapi_listener_object_t *obj;
78 /* Currently only support IPv4 addresses. */
79 if (addr->addrtype != AF_INET)
80 return DHCP_R_INVALIDARG;
83 obj = (omapi_listener_object_t *)0;
84 status = omapi_listener_allocate (&obj, MDL);
85 if (status != ISC_R_SUCCESS)
89 /* Connect this object to the inner object. */
90 status = omapi_object_reference (&h -> outer,
91 (omapi_object_t *)obj, MDL);
92 if (status != ISC_R_SUCCESS)
94 status = omapi_object_reference (&obj -> inner, h, MDL);
95 if (status != ISC_R_SUCCESS)
98 /* Set up the address on which we will listen... */
99 obj -> address.sin_port = htons (addr -> port);
100 memcpy (&obj -> address.sin_addr,
101 addr -> address, sizeof obj -> address.sin_addr);
102 #if defined (HAVE_SA_LEN)
103 obj -> address.sin_len =
104 sizeof (struct sockaddr_in);
106 obj -> address.sin_family = AF_INET;
107 memset (&(obj -> address.sin_zero), 0,
108 sizeof obj -> address.sin_zero);
110 #if defined (TRACING)
111 /* If we're playing back a trace file, we remember the object
112 on the trace listener queue. */
113 if (trace_playback ()) {
114 trace_listener_remember (obj, MDL);
117 /* Create a socket on which to listen. */
118 obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
119 if (obj->socket == -1) {
121 || errno == ENFILE || errno == ENOBUFS)
122 status = ISC_R_NORESOURCES;
124 status = ISC_R_UNEXPECTED;
128 #if defined (HAVE_SETFD)
129 if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
130 status = ISC_R_UNEXPECTED;
135 /* Set the REUSEADDR option so that we don't fail to start if
136 we're being restarted. */
138 if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
139 (char *)&i, sizeof i) < 0) {
140 status = ISC_R_UNEXPECTED;
144 /* Try to bind to the wildcard address using the port number
146 i = bind (obj -> socket,
147 (struct sockaddr *)&obj -> address,
148 sizeof obj -> address);
150 if (errno == EADDRINUSE)
151 status = ISC_R_ADDRNOTAVAIL;
152 else if (errno == EPERM)
153 status = ISC_R_NOPERM;
155 status = ISC_R_UNEXPECTED;
159 /* Now tell the kernel to listen for connections. */
160 if (listen (obj -> socket, max)) {
161 status = ISC_R_UNEXPECTED;
165 if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
166 status = ISC_R_UNEXPECTED;
170 status = omapi_register_io_object ((omapi_object_t *)obj,
171 omapi_listener_readfd, 0,
173 #if defined (TRACING)
177 omapi_listener_dereference (&obj, MDL);
182 if (h->outer == (omapi_object_t *)obj) {
183 omapi_object_dereference((omapi_object_t **)&h->outer,
186 if (obj->inner == h) {
187 omapi_object_dereference((omapi_object_t **)&obj->inner,
190 if (obj->socket != -1) {
193 omapi_listener_dereference(&obj, MDL);
198 /* Return the socket on which the dispatcher should wait for readiness
199 to read, for a listener object. */
200 int omapi_listener_readfd (omapi_object_t *h)
202 omapi_listener_object_t *l;
204 if (h -> type != omapi_type_listener)
206 l = (omapi_listener_object_t *)h;
211 /* Reader callback for a listener object. Accept an incoming connection. */
212 isc_result_t omapi_accept (omapi_object_t *h)
216 omapi_connection_object_t *obj;
217 omapi_listener_object_t *listener;
218 struct sockaddr_in addr;
221 if (h -> type != omapi_type_listener)
222 return DHCP_R_INVALIDARG;
223 listener = (omapi_listener_object_t *)h;
225 /* Accept the connection. */
227 socket = accept (listener -> socket,
228 ((struct sockaddr *)&(addr)), &len);
230 if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
231 return ISC_R_NORESOURCES;
232 return ISC_R_UNEXPECTED;
235 #if defined (TRACING)
236 /* If we're recording a trace, remember the connection. */
237 if (trace_record ()) {
239 iov [0].buf = (char *)&addr.sin_port;
240 iov [0].len = sizeof addr.sin_port;
241 iov [1].buf = (char *)&addr.sin_addr;
242 iov [1].len = sizeof addr.sin_addr;
243 iov [2].buf = (char *)&listener -> address.sin_port;
244 iov [2].len = sizeof listener -> address.sin_port;
245 trace_write_packet_iov (trace_listener_accept,
250 obj = (omapi_connection_object_t *)0;
251 status = omapi_listener_connect (&obj, listener, socket, &addr);
252 if (status != ISC_R_SUCCESS) {
257 status = omapi_register_io_object ((omapi_object_t *)obj,
258 omapi_connection_readfd,
259 omapi_connection_writefd,
260 omapi_connection_reader,
261 omapi_connection_writer,
262 omapi_connection_reaper);
264 /* Lose our reference to the connection, so it'll be gc'd when it's
266 omapi_connection_dereference (&obj, MDL);
267 if (status != ISC_R_SUCCESS)
268 omapi_disconnect ((omapi_object_t *)(obj), 1);
272 isc_result_t omapi_listener_connect (omapi_connection_object_t **obj,
273 omapi_listener_object_t *listener,
275 struct sockaddr_in *remote_addr)
278 omapi_object_t *h = (omapi_object_t *)listener;
281 #ifdef DEBUG_PROTOCOL
282 log_debug ("omapi_accept()");
285 /* Get the handle. */
286 status = omapi_connection_allocate (obj, MDL);
287 if (status != ISC_R_SUCCESS)
290 (*obj) -> state = omapi_connection_connected;
291 (*obj) -> remote_addr = *remote_addr;
292 (*obj) -> socket = socket;
294 /* Verify that this host is allowed to connect. */
295 if (listener -> verify_addr) {
296 addr.addrtype = AF_INET;
297 addr.addrlen = sizeof (remote_addr -> sin_addr);
298 memcpy (addr.address, &remote_addr -> sin_addr,
299 sizeof (remote_addr -> sin_addr));
300 addr.port = ntohs(remote_addr -> sin_port);
302 status = (listener -> verify_addr) (h, &addr);
303 if (status != ISC_R_SUCCESS) {
304 omapi_disconnect ((omapi_object_t *)(*obj), 1);
305 omapi_connection_dereference (obj, MDL);
310 omapi_listener_reference (&(*obj) -> listener, listener, MDL);
311 #if defined (TRACING)
312 omapi_connection_register (*obj, MDL);
314 status = omapi_signal (h, "connect", (*obj));
318 #if defined (TRACING)
319 OMAPI_ARRAY_TYPE(omapi_listener, omapi_listener_object_t)
321 void omapi_listener_trace_setup (void) {
322 trace_listener_accept =
323 trace_type_register ("listener-accept", (void *)0,
324 trace_listener_accept_input,
325 trace_listener_accept_stop, MDL);
328 static void trace_listener_remember (omapi_listener_object_t *obj,
329 const char *file, int line)
332 if (!trace_listeners) {
333 status = omapi_listener_array_allocate (&trace_listeners,
335 if (status != ISC_R_SUCCESS) {
337 log_error ("trace_listener_remember: %s",
338 isc_result_totext (status));
342 status = omapi_listener_array_extend (trace_listeners, obj,
344 if (status != ISC_R_SUCCESS)
348 static void trace_listener_accept_input (trace_type_t *ttype,
349 unsigned length, char *buf)
351 struct in_addr *addr;
352 u_int16_t *remote_port;
353 u_int16_t *local_port;
354 omapi_connection_object_t *obj;
356 struct sockaddr_in remote_addr;
358 addr = (struct in_addr *)buf;
359 remote_port = (u_int16_t *)(addr + 1);
360 local_port = remote_port + 1;
362 memset (&remote_addr, 0, sizeof remote_addr);
363 remote_addr.sin_addr = *addr;
364 remote_addr.sin_port = *remote_port;
366 omapi_array_foreach_begin (trace_listeners,
367 omapi_listener_object_t, lp) {
368 if (lp -> address.sin_port == *local_port) {
369 obj = (omapi_connection_object_t *)0;
370 status = omapi_listener_connect (&obj,
371 lp, 0, &remote_addr);
372 omapi_listener_dereference (&lp, MDL);
375 } omapi_array_foreach_end (trace_listeners,
376 omapi_listener_object_t, lp);
377 log_error ("trace_listener_accept: %s from %s/%d to port %d",
378 "unexpected connect",
379 inet_ntoa (*addr), *remote_port, *local_port);
382 static void trace_listener_accept_stop (trace_type_t *ttype) { }
387 isc_result_t omapi_listener_configure_security (omapi_object_t *h,
388 isc_result_t (*verify_addr)
392 omapi_listener_object_t *l;
394 if (h -> type != omapi_type_listener)
395 return DHCP_R_INVALIDARG;
396 l = (omapi_listener_object_t *)h;
398 l -> verify_addr = verify_addr;
400 return ISC_R_SUCCESS;
403 isc_result_t omapi_listener_set_value (omapi_object_t *h,
405 omapi_data_string_t *name,
406 omapi_typed_data_t *value)
408 if (h -> type != omapi_type_listener)
409 return DHCP_R_INVALIDARG;
411 if (h -> inner && h -> inner -> type -> set_value)
412 return (*(h -> inner -> type -> set_value))
413 (h -> inner, id, name, value);
414 return ISC_R_NOTFOUND;
417 isc_result_t omapi_listener_get_value (omapi_object_t *h,
419 omapi_data_string_t *name,
420 omapi_value_t **value)
422 if (h -> type != omapi_type_listener)
423 return DHCP_R_INVALIDARG;
425 if (h -> inner && h -> inner -> type -> get_value)
426 return (*(h -> inner -> type -> get_value))
427 (h -> inner, id, name, value);
428 return ISC_R_NOTFOUND;
431 isc_result_t omapi_listener_destroy (omapi_object_t *h,
432 const char *file, int line)
434 omapi_listener_object_t *l;
436 if (h -> type != omapi_type_listener)
437 return DHCP_R_INVALIDARG;
438 l = (omapi_listener_object_t *)h;
440 #ifdef DEBUG_PROTOCOL
441 log_debug ("omapi_listener_destroy()");
444 if (l -> socket != -1) {
448 return ISC_R_SUCCESS;
451 isc_result_t omapi_listener_signal_handler (omapi_object_t *h,
452 const char *name, va_list ap)
454 if (h -> type != omapi_type_listener)
455 return DHCP_R_INVALIDARG;
457 if (h -> inner && h -> inner -> type -> signal_handler)
458 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
460 return ISC_R_NOTFOUND;
463 /* Write all the published values associated with the object through the
464 specified connection. */
466 isc_result_t omapi_listener_stuff_values (omapi_object_t *c,
470 if (l -> type != omapi_type_listener)
471 return DHCP_R_INVALIDARG;
473 if (l -> inner && l -> inner -> type -> stuff_values)
474 return (*(l -> inner -> type -> stuff_values)) (c, id,
476 return ISC_R_SUCCESS;