/* Reader callback for a listener object. Accept an incoming connection. */ isc_result_t omapi_accept (omapi_object_t *h) { isc_result_t status; socklen_t len; omapi_connection_object_t *obj; omapi_listener_object_t *listener; struct sockaddr_in addr; int socket; if (h -> type != omapi_type_listener) return ISC_R_INVALIDARG; listener = (omapi_listener_object_t *)h; /* Accept the connection. */ len = sizeof addr; socket = accept (listener -> socket, ((struct sockaddr *)&(addr)), &len); if (socket < 0) { if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS) return ISC_R_NORESOURCES; return ISC_R_UNEXPECTED; } #if defined (TRACING) /* If we're recording a trace, remember the connection. */ if (trace_record ()) { trace_iov_t iov [3]; iov [0].buf = (char *)&addr.sin_port; iov [0].len = sizeof addr.sin_port; iov [1].buf = (char *)&addr.sin_addr; iov [1].len = sizeof addr.sin_addr; iov [2].buf = (char *)&listener -> address.sin_port; iov [2].len = sizeof listener -> address.sin_port; trace_write_packet_iov (trace_listener_accept, 3, iov, MDL); } #endif obj = (omapi_connection_object_t *)0; status = omapi_listener_connect (&obj, listener, socket, &addr); if (status != ISC_R_SUCCESS) { close (socket); return status; } status = omapi_register_io_object ((omapi_object_t *)obj, omapi_connection_readfd, omapi_connection_writefd, omapi_connection_reader, omapi_connection_writer, omapi_connection_reaper); /* Lose our reference to the connection, so it'll be gc'd when it's reaped. */ omapi_connection_dereference (&obj, MDL); if (status != ISC_R_SUCCESS) omapi_disconnect ((omapi_object_t *)(obj), 1); return status; }
isc_result_t omapi_reregister_io_object (omapi_object_t *h, int (*readfd) (omapi_object_t *), int (*writefd) (omapi_object_t *), isc_result_t (*reader) (omapi_object_t *), isc_result_t (*writer) (omapi_object_t *), isc_result_t (*reaper) (omapi_object_t *)) { omapi_io_object_t *obj; if ((!h -> outer) || (h -> outer -> type != omapi_type_io_object)) { /* If we don't have an object or if the type isn't what * we expect do the normal registration (which will overwrite * an incorrect type, that's what we did historically, may * want to change that) */ return (omapi_register_io_object (h, readfd, writefd, reader, writer, reaper)); } /* We have an io object of the correct type, try to update it */ /*sar*/ /* Should we validate that the fd matches the previous one? * It's suppossed to, that's a requirement, don't bother yet */ obj = (omapi_io_object_t *)h->outer; obj -> readfd = readfd; obj -> writefd = writefd; obj -> reader = reader; obj -> writer = writer; obj -> reaper = reaper; return (ISC_R_SUCCESS); }
isc_result_t omapi_connect_list (omapi_object_t *c, omapi_addr_list_t *remote_addrs, omapi_addr_t *local_addr) { isc_result_t status; omapi_connection_object_t *obj; int flag; struct sockaddr_in local_sin; obj = (omapi_connection_object_t *)0; status = omapi_connection_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) { omapi_connection_dereference (&obj, MDL); return status; } status = omapi_object_reference (&obj -> inner, c, MDL); if (status != ISC_R_SUCCESS) { omapi_connection_dereference (&obj, MDL); return status; } /* Store the address list on the object. */ omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL); obj -> cptr = 0; obj -> state = omapi_connection_unconnected; #if defined (TRACING) /* If we're playing back, don't actually try to connect - just leave the object available for a subsequent connect or disconnect. */ if (!trace_playback ()) { #endif /* Create a socket on which to communicate. */ obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (obj -> socket < 0) { omapi_connection_dereference (&obj, MDL); if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS) return ISC_R_NORESOURCES; return ISC_R_UNEXPECTED; } /* Set up the local address, if any. */ if (local_addr) { /* Only do TCPv4 so far. */ if (local_addr -> addrtype != AF_INET) { omapi_connection_dereference (&obj, MDL); return DHCP_R_INVALIDARG; } local_sin.sin_port = htons (local_addr -> port); memcpy (&local_sin.sin_addr, local_addr -> address, local_addr -> addrlen); #if defined (HAVE_SA_LEN) local_sin.sin_len = sizeof local_addr; #endif local_sin.sin_family = AF_INET; memset (&local_sin.sin_zero, 0, sizeof local_sin.sin_zero); if (bind (obj -> socket, (struct sockaddr *)&local_sin, sizeof local_sin) < 0) { omapi_connection_object_t **objp = &obj; omapi_object_t **o = (omapi_object_t **)objp; omapi_object_dereference(o, MDL); if (errno == EADDRINUSE) return ISC_R_ADDRINUSE; if (errno == EADDRNOTAVAIL) return ISC_R_ADDRNOTAVAIL; if (errno == EACCES) return ISC_R_NOPERM; return ISC_R_UNEXPECTED; } obj -> local_addr = local_sin; } #if defined(F_SETFD) if (fcntl (obj -> socket, F_SETFD, 1) < 0) { close (obj -> socket); omapi_connection_dereference (&obj, MDL); return ISC_R_UNEXPECTED; } #endif /* Set the SO_REUSEADDR flag (this should not fail). */ flag = 1; if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof flag) < 0) { omapi_connection_dereference (&obj, MDL); return ISC_R_UNEXPECTED; } /* Set the file to nonblocking mode. */ if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) { omapi_connection_dereference (&obj, MDL); return ISC_R_UNEXPECTED; } status = (omapi_register_io_object ((omapi_object_t *)obj, 0, omapi_connection_writefd, 0, omapi_connection_connect, omapi_connection_reaper)); if (status != ISC_R_SUCCESS) goto out; status = omapi_connection_connect_internal ((omapi_object_t *) obj); #if defined (TRACING) } omapi_connection_register (obj, MDL); #endif out: omapi_connection_dereference (&obj, MDL); return status; }
isc_result_t omapi_listen_addr (omapi_object_t *h, omapi_addr_t *addr, int max) { isc_result_t status; omapi_listener_object_t *obj; int i; /* Currently only support IPv4 addresses. */ if (addr->addrtype != AF_INET) return ISC_R_INVALIDARG; /* Get the handle. */ obj = (omapi_listener_object_t *)0; status = omapi_listener_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; obj->socket = -1; /* Connect this object to the inner object. */ status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) goto error_exit; status = omapi_object_reference (&obj -> inner, h, MDL); if (status != ISC_R_SUCCESS) goto error_exit; /* Set up the address on which we will listen... */ obj -> address.sin_port = htons (addr -> port); memcpy (&obj -> address.sin_addr, addr -> address, sizeof obj -> address.sin_addr); #if defined (HAVE_SA_LEN) obj -> address.sin_len = sizeof (struct sockaddr_in); #endif obj -> address.sin_family = AF_INET; memset (&(obj -> address.sin_zero), 0, sizeof obj -> address.sin_zero); #if defined (TRACING) /* If we're playing back a trace file, we remember the object on the trace listener queue. */ if (trace_playback ()) { trace_listener_remember (obj, MDL); } else { #endif /* Create a socket on which to listen. */ obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (obj->socket == -1) { if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS) status = ISC_R_NORESOURCES; else status = ISC_R_UNEXPECTED; goto error_exit; } #if defined (HAVE_SETFD) if (fcntl (obj -> socket, F_SETFD, 1) < 0) { status = ISC_R_UNEXPECTED; goto error_exit; } #endif /* Set the REUSEADDR option so that we don't fail to start if we're being restarted. */ i = 1; if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof i) < 0) { status = ISC_R_UNEXPECTED; goto error_exit; } /* Try to bind to the wildcard address using the port number we were given. */ i = bind (obj -> socket, (struct sockaddr *)&obj -> address, sizeof obj -> address); if (i < 0) { if (errno == EADDRINUSE) status = ISC_R_ADDRNOTAVAIL; else if (errno == EPERM) status = ISC_R_NOPERM; else status = ISC_R_UNEXPECTED; goto error_exit; } /* Now tell the kernel to listen for connections. */ if (listen (obj -> socket, max)) { status = ISC_R_UNEXPECTED; goto error_exit; } if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) { status = ISC_R_UNEXPECTED; goto error_exit; } status = omapi_register_io_object ((omapi_object_t *)obj, omapi_listener_readfd, 0, omapi_accept, 0, 0); #if defined (TRACING) } #endif omapi_listener_dereference (&obj, MDL); return status; error_exit: if (obj != NULL) { if (h->outer == (omapi_object_t *)obj) { omapi_object_dereference((omapi_object_t **)&h->outer, MDL); } if (obj->inner == h) { omapi_object_dereference((omapi_object_t **)&obj->inner, MDL); } if (obj->socket != -1) { close(obj->socket); } omapi_listener_dereference(&obj, MDL); } return status; }