Exemple #1
0
/* 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;
}
Exemple #2
0
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);
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}