3 Subroutines that support the generic listener object. */
6 * Copyright (c) 1999-2001 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
44 #include <omapip/omapip_p.h>
47 omapi_array_t *trace_listeners;
48 static void trace_listener_accept_input (trace_type_t *, unsigned, char *);
49 static void trace_listener_remember (omapi_listener_object_t *,
51 static void trace_listener_accept_stop (trace_type_t *);
52 trace_type_t *trace_listener_accept;
55 OMAPI_OBJECT_ALLOC (omapi_listener,
56 omapi_listener_object_t, omapi_type_listener)
58 isc_result_t omapi_listen (omapi_object_t *h,
65 log_debug ("omapi_listen(port=%d, max=%d)", port, max);
68 addr.addrtype = AF_INET;
69 addr.addrlen = sizeof (struct in_addr);
70 memset (addr.address, 0, sizeof addr.address); /* INADDR_ANY */
73 return omapi_listen_addr (h, &addr, max);
76 isc_result_t omapi_listen_addr (omapi_object_t *h,
83 omapi_listener_object_t *obj;
88 obj = (omapi_listener_object_t *)0;
89 status = omapi_listener_allocate (&obj, MDL);
90 if (status != ISC_R_SUCCESS)
93 /* Connect this object to the inner object. */
94 status = omapi_object_reference (&h -> outer,
95 (omapi_object_t *)obj, MDL);
96 if (status != ISC_R_SUCCESS) {
97 omapi_listener_dereference (&obj, MDL);
100 status = omapi_object_reference (&obj -> inner, h, MDL);
101 if (status != ISC_R_SUCCESS) {
102 omapi_listener_dereference (&obj, MDL);
106 /* Currently only support TCPv4 addresses. */
107 if (addr -> addrtype != AF_INET)
108 return ISC_R_INVALIDARG;
110 /* Set up the address on which we will listen... */
111 obj -> address.sin_port = htons (addr -> port);
112 memcpy (&obj -> address.sin_addr,
113 addr -> address, sizeof obj -> address.sin_addr);
114 #if defined (HAVE_SA_LEN)
115 obj -> address.sin_len =
116 sizeof (struct sockaddr_in);
118 obj -> address.sin_family = AF_INET;
119 memset (&(obj -> address.sin_zero), 0,
120 sizeof obj -> address.sin_zero);
122 #if defined (TRACING)
123 /* If we're playing back a trace file, we remember the object
124 on the trace listener queue. */
125 if (trace_playback ()) {
126 trace_listener_remember (obj, MDL);
129 /* Create a socket on which to listen. */
130 obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
131 if (!obj -> socket) {
132 omapi_listener_dereference (&obj, MDL);
134 || errno == ENFILE || errno == ENOBUFS)
135 return ISC_R_NORESOURCES;
136 return ISC_R_UNEXPECTED;
139 #if defined (HAVE_SETFD)
140 if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
141 close (obj -> socket);
142 omapi_listener_dereference (&obj, MDL);
143 return ISC_R_UNEXPECTED;
147 /* Set the REUSEADDR option so that we don't fail to start if
148 we're being restarted. */
150 if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
151 (char *)&i, sizeof i) < 0) {
152 close (obj -> socket);
153 omapi_listener_dereference (&obj, MDL);
154 return ISC_R_UNEXPECTED;
157 /* Try to bind to the wildcard address using the port number
159 i = bind (obj -> socket,
160 (struct sockaddr *)&obj -> address,
161 sizeof obj -> address);
163 omapi_listener_dereference (&obj, MDL);
164 if (errno == EADDRINUSE)
165 return ISC_R_ADDRNOTAVAIL;
168 return ISC_R_UNEXPECTED;
171 /* Now tell the kernel to listen for connections. */
172 if (listen (obj -> socket, max)) {
173 omapi_listener_dereference (&obj, MDL);
174 return ISC_R_UNEXPECTED;
177 if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
178 omapi_listener_dereference (&obj, MDL);
179 return ISC_R_UNEXPECTED;
182 status = omapi_register_io_object ((omapi_object_t *)obj,
183 omapi_listener_readfd, 0,
185 #if defined (TRACING)
188 omapi_listener_dereference (&obj, MDL);
192 /* Return the socket on which the dispatcher should wait for readiness
193 to read, for a listener object. */
194 int omapi_listener_readfd (omapi_object_t *h)
196 omapi_listener_object_t *l;
198 if (h -> type != omapi_type_listener)
200 l = (omapi_listener_object_t *)h;
205 /* Reader callback for a listener object. Accept an incoming connection. */
206 isc_result_t omapi_accept (omapi_object_t *h)
210 omapi_connection_object_t *obj;
211 omapi_listener_object_t *listener;
212 omapi_addr_t remote_addr;
214 struct sockaddr_in addr;
217 if (h -> type != omapi_type_listener)
218 return ISC_R_INVALIDARG;
219 listener = (omapi_listener_object_t *)h;
221 /* Accept the connection. */
223 socket = accept (listener -> socket,
224 ((struct sockaddr *)&(addr)), &len);
226 if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
227 return ISC_R_NORESOURCES;
228 return ISC_R_UNEXPECTED;
231 #if defined (TRACING)
232 /* If we're recording a trace, remember the connection. */
233 if (trace_record ()) {
236 iov [0].buf = (char *)&addr.sin_port;
237 iov [0].len = sizeof addr.sin_port;
238 iov [1].buf = (char *)&addr.sin_addr;
239 iov [1].len = sizeof addr.sin_addr;
240 iov [2].buf = (char *)&listener -> address.sin_port;
241 iov [2].len = sizeof listener -> address.sin_port;
242 trace_write_packet_iov (trace_listener_accept,
247 obj = (omapi_connection_object_t *)0;
248 status = omapi_listener_connect (&obj, listener, socket, &addr);
249 if (status != ISC_R_SUCCESS) {
254 status = omapi_register_io_object ((omapi_object_t *)obj,
255 omapi_connection_readfd,
256 omapi_connection_writefd,
257 omapi_connection_reader,
258 omapi_connection_writer,
259 omapi_connection_reaper);
261 /* Lose our reference to the connection, so it'll be gc'd when it's
263 omapi_connection_dereference (&obj, MDL);
264 if (status != ISC_R_SUCCESS)
265 omapi_disconnect ((omapi_object_t *)(obj), 1);
269 isc_result_t omapi_listener_connect (omapi_connection_object_t **obj,
270 omapi_listener_object_t *listener,
272 struct sockaddr_in *remote_addr)
275 omapi_object_t *h = (omapi_object_t *)listener;
278 #ifdef DEBUG_PROTOCOL
279 log_debug ("omapi_accept()");
282 /* Get the handle. */
283 status = omapi_connection_allocate (obj, MDL);
284 if (status != ISC_R_SUCCESS)
287 (*obj) -> state = omapi_connection_connected;
288 (*obj) -> remote_addr = *remote_addr;
289 (*obj) -> socket = socket;
291 /* Verify that this host is allowed to connect. */
292 if (listener -> verify_addr) {
293 addr.addrtype = AF_INET;
294 addr.addrlen = sizeof (remote_addr -> sin_addr);
295 memcpy (addr.address, &remote_addr -> sin_addr,
296 sizeof (remote_addr -> sin_addr));
297 addr.port = ntohs(remote_addr -> sin_port);
299 status = (listener -> verify_addr) (h, &addr);
300 if (status != ISC_R_SUCCESS) {
301 omapi_disconnect ((omapi_object_t *)(*obj), 1);
302 omapi_connection_dereference (obj, MDL);
307 omapi_listener_reference (&(*obj) -> listener, listener, MDL);
308 #if defined (TRACING)
309 omapi_connection_register (*obj, MDL);
311 status = omapi_signal (h, "connect", (*obj));
315 #if defined (TRACING)
316 OMAPI_ARRAY_TYPE(omapi_listener, omapi_listener_object_t)
318 void omapi_listener_trace_setup (void) {
319 trace_listener_accept =
320 trace_type_register ("listener-accept", (void *)0,
321 trace_listener_accept_input,
322 trace_listener_accept_stop, MDL);
325 static void trace_listener_remember (omapi_listener_object_t *obj,
326 const char *file, int line)
329 if (!trace_listeners) {
330 status = omapi_listener_array_allocate (&trace_listeners,
332 if (status != ISC_R_SUCCESS) {
334 log_error ("trace_listener_remember: %s",
335 isc_result_totext (status));
339 status = omapi_listener_array_extend (trace_listeners, obj,
341 if (status != ISC_R_SUCCESS)
345 static void trace_listener_accept_input (trace_type_t *ttype,
346 unsigned length, char *buf)
348 struct in_addr *addr;
349 u_int16_t *remote_port;
350 u_int16_t *local_port;
351 omapi_connection_object_t *obj;
353 struct sockaddr_in remote_addr;
355 addr = (struct in_addr *)buf;
356 remote_port = (u_int16_t *)(addr + 1);
357 local_port = remote_port + 1;
359 memset (&remote_addr, 0, sizeof remote_addr);
360 remote_addr.sin_addr = *addr;
361 remote_addr.sin_port = *remote_port;
363 omapi_array_foreach_begin (trace_listeners,
364 omapi_listener_object_t, lp) {
365 if (lp -> address.sin_port == *local_port) {
366 obj = (omapi_connection_object_t *)0;
367 status = omapi_listener_connect (&obj,
368 lp, 0, &remote_addr);
369 omapi_listener_dereference (&lp, MDL);
372 } omapi_array_foreach_end (trace_listeners,
373 omapi_listener_object_t, lp);
374 log_error ("trace_listener_accept: %s from %s/%d to port %d",
375 "unexpected connect",
376 inet_ntoa (*addr), *remote_port, *local_port);
379 static void trace_listener_accept_stop (trace_type_t *ttype) { }
384 isc_result_t omapi_listener_configure_security (omapi_object_t *h,
385 isc_result_t (*verify_addr)
389 omapi_listener_object_t *l;
391 if (h -> type != omapi_type_listener)
392 return ISC_R_INVALIDARG;
393 l = (omapi_listener_object_t *)h;
395 l -> verify_addr = verify_addr;
397 return ISC_R_SUCCESS;
400 isc_result_t omapi_listener_set_value (omapi_object_t *h,
402 omapi_data_string_t *name,
403 omapi_typed_data_t *value)
405 if (h -> type != omapi_type_listener)
406 return ISC_R_INVALIDARG;
408 if (h -> inner && h -> inner -> type -> set_value)
409 return (*(h -> inner -> type -> set_value))
410 (h -> inner, id, name, value);
411 return ISC_R_NOTFOUND;
414 isc_result_t omapi_listener_get_value (omapi_object_t *h,
416 omapi_data_string_t *name,
417 omapi_value_t **value)
419 if (h -> type != omapi_type_listener)
420 return ISC_R_INVALIDARG;
422 if (h -> inner && h -> inner -> type -> get_value)
423 return (*(h -> inner -> type -> get_value))
424 (h -> inner, id, name, value);
425 return ISC_R_NOTFOUND;
428 isc_result_t omapi_listener_destroy (omapi_object_t *h,
429 const char *file, int line)
431 omapi_listener_object_t *l;
433 if (h -> type != omapi_type_listener)
434 return ISC_R_INVALIDARG;
435 l = (omapi_listener_object_t *)h;
437 #ifdef DEBUG_PROTOCOL
438 log_debug ("omapi_listener_destroy()");
441 if (l -> socket != -1) {
445 return ISC_R_SUCCESS;
448 isc_result_t omapi_listener_signal_handler (omapi_object_t *h,
449 const char *name, va_list ap)
451 if (h -> type != omapi_type_listener)
452 return ISC_R_INVALIDARG;
454 if (h -> inner && h -> inner -> type -> signal_handler)
455 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
457 return ISC_R_NOTFOUND;
460 /* Write all the published values associated with the object through the
461 specified connection. */
463 isc_result_t omapi_listener_stuff_values (omapi_object_t *c,
469 if (l -> type != omapi_type_listener)
470 return ISC_R_INVALIDARG;
472 if (l -> inner && l -> inner -> type -> stuff_values)
473 return (*(l -> inner -> type -> stuff_values)) (c, id,
475 return ISC_R_SUCCESS;