3 Subroutines that support the generic listener object. */
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.
23 * Redwood City, CA 94063
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>
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
*,
42 static void trace_listener_accept_stop (trace_type_t
*);
43 trace_type_t
*trace_listener_accept
;
46 OMAPI_OBJECT_ALLOC (omapi_listener
,
47 omapi_listener_object_t
, omapi_type_listener
)
49 isc_result_t
omapi_listen (omapi_object_t
*h
,
56 log_debug ("omapi_listen(port=%d, max=%d)", port
, max
);
59 addr
.addrtype
= AF_INET
;
60 addr
.addrlen
= sizeof (struct in_addr
);
61 memset (addr
.address
, 0, sizeof addr
.address
); /* INADDR_ANY */
64 return omapi_listen_addr (h
, &addr
, max
);
67 isc_result_t
omapi_listen_addr (omapi_object_t
*h
,
72 omapi_listener_object_t
*obj
;
76 obj
= (omapi_listener_object_t
*)0;
77 status
= omapi_listener_allocate (&obj
, MDL
);
78 if (status
!= ISC_R_SUCCESS
)
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
);
88 status
= omapi_object_reference (&obj
-> inner
, h
, MDL
);
89 if (status
!= ISC_R_SUCCESS
) {
90 omapi_listener_dereference (&obj
, MDL
);
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
);
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
);
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
);
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
;
134 /* Set the REUSEADDR option so that we don't fail to start if
135 we're being restarted. */
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
146 i
= bind (obj
-> socket
,
147 (struct sockaddr
*)&obj
-> address
,
148 sizeof obj
-> address
);
150 omapi_listener_dereference (&obj
, MDL
);
151 if (errno
== EADDRINUSE
)
152 return ISC_R_ADDRNOTAVAIL
;
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,
172 #if defined (TRACING)
175 omapi_listener_dereference (&obj
, MDL
);
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
)
187 l
= (omapi_listener_object_t
*)h
;
192 /* Reader callback for a listener object. Accept an incoming connection. */
193 isc_result_t
omapi_accept (omapi_object_t
*h
)
197 omapi_connection_object_t
*obj
;
198 omapi_listener_object_t
*listener
;
199 struct sockaddr_in addr
;
202 if (h
-> type
!= omapi_type_listener
)
203 return ISC_R_INVALIDARG
;
204 listener
= (omapi_listener_object_t
*)h
;
206 /* Accept the connection. */
208 socket
= accept (listener
-> socket
,
209 ((struct sockaddr
*)&(addr
)), &len
);
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 ()) {
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
,
231 obj
= (omapi_connection_object_t
*)0;
232 status
= omapi_listener_connect (&obj
, listener
, socket
, &addr
);
233 if (status
!= ISC_R_SUCCESS
) {
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
247 omapi_connection_dereference (&obj
, MDL
);
248 if (status
!= ISC_R_SUCCESS
)
249 omapi_disconnect ((omapi_object_t
*)(obj
), 1);
253 isc_result_t
omapi_listener_connect (omapi_connection_object_t
**obj
,
254 omapi_listener_object_t
*listener
,
256 struct sockaddr_in
*remote_addr
)
259 omapi_object_t
*h
= (omapi_object_t
*)listener
;
262 #ifdef DEBUG_PROTOCOL
263 log_debug ("omapi_accept()");
266 /* Get the handle. */
267 status
= omapi_connection_allocate (obj
, MDL
);
268 if (status
!= ISC_R_SUCCESS
)
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
);
291 omapi_listener_reference (&(*obj
) -> listener
, listener
, MDL
);
292 #if defined (TRACING)
293 omapi_connection_register (*obj
, MDL
);
295 status
= omapi_signal (h
, "connect", (*obj
));
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
)
313 if (!trace_listeners
) {
314 status
= omapi_listener_array_allocate (&trace_listeners
,
316 if (status
!= ISC_R_SUCCESS
) {
318 log_error ("trace_listener_remember: %s",
319 isc_result_totext (status
));
323 status
= omapi_listener_array_extend (trace_listeners
, obj
,
325 if (status
!= ISC_R_SUCCESS
)
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
;
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
);
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
) { }
368 isc_result_t
omapi_listener_configure_security (omapi_object_t
*h
,
369 isc_result_t (*verify_addr
)
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
,
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
,
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()");
425 if (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
,
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
,
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
,
458 return ISC_R_SUCCESS
;