Non-blocking connect()

Stefan (metze) Metzmacher metze at samba.org
Mon Jan 10 07:31:28 GMT 2005


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Volker Lendecke schrieb:
| Hi!
|
| During some tests with the non-blocking stuff in samba4 I found that there's no
| non-blocking connect(). Attached find a patch that attempts to do it. I'm not
| sure whether this matches samba4-style, thus I did not commit it right away.
|
| Comments?
|
| Volker

Hi Volker,

hmm, I think it should be somehow be possible for the caller to specify an event context and
callback for an async connect.

maybe with a socket_connect_ex() but I'm  not sure about details...

about coding details:

I think it would be better to add a fn_get_option() backend function and not use getsockopt()
in the main code.

and use a private struct in sock->private_data to store int error

| ------------------------------------------------------------------------
|
| Index: lib/socket/socket.c
| ===================================================================
| --- lib/socket/socket.c	(revision 4617)
| +++ lib/socket/socket.c	(working copy)
| @@ -19,6 +19,7 @@
|  */
|
|  #include "includes.h"
| +#include "events.h"
|
|  /*
|    auto-close sockets on free
| @@ -68,6 +69,9 @@
|  		(*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
|  	}
|
| +	if (!(flags & SOCKET_FLAG_BLOCK))
| +		set_blocking((*new_sock)->fd, False);
| +
|  	talloc_set_destructor(*new_sock, socket_destructor);
|
|  	return NT_STATUS_OK;
| @@ -79,11 +83,48 @@
|  	talloc_free(sock);
|  }
|
| -NTSTATUS socket_connect(struct socket_context *sock,
| -			const char *my_address, int my_port,
| -			const char *server_address, int server_port,
| -			uint32_t flags)
| +static void socket_connect_handler(struct event_context *ev,
| +				   struct fd_event *fde,
| +				   struct timeval t,
| +				   uint16_t flags)
|  {
| +	struct socket_context *sock;
| +	socklen_t optlen;
| +
| +	sock = fde->private;
| +
| +	if (((flags & EVENT_FD_READ) == 0) &&
| +	    ((flags & EVENT_FD_WRITE) != 0)) {
| +		/* Only writable, success! */
| +		sock->state = SOCKET_STATE_CLIENT_CONNECTED;
| +		return;
| +	}
| +
| +	/* We might have an error here */
| +	sock->state = SOCKET_STATE_CLIENT_ERROR;
| +	optlen = sizeof(sock->error);
| +
| +	if (getsockopt(socket_get_fd(sock), SOL_SOCKET, SO_ERROR,
| +		       &sock->error, &optlen) != 0) {
| +		sock->error = errno;
| +		return;
| +	}
| +
| +	if (sock->error == 0)
| +		sock->state = SOCKET_STATE_CLIENT_CONNECTED;
| +
| +	return;
| +}
| +
| +NTSTATUS socket_connect_send(struct socket_context *sock,
| +			     const char *my_address, int my_port,
| +			     const char *server_address, int server_port,
| +			     uint32_t flags,
| +			     struct event_context *ev)
| +{
| +	NTSTATUS status;
| +	struct fd_event fde;
| +
|  	if (sock->type != SOCKET_TYPE_STREAM) {
|  		return NT_STATUS_INVALID_PARAMETER;
|  	}
| @@ -96,9 +137,61 @@
|  		return NT_STATUS_NOT_IMPLEMENTED;
|  	}
|
| -	return sock->ops->fn_connect(sock, my_address, my_port, server_address, server_port, flags);
| +	status = sock->ops->fn_connect(sock, my_address, my_port,
| +				       server_address, server_port, flags);
| +
| +	if (sock->state == SOCKET_STATE_CLIENT_CONNECTED) {
| +		/* Happens with a blocking socket */
| +		return NT_STATUS_OK;
| +	}
| +
| +	if (!NT_STATUS_IS_OK(status))
| +		return status;
| +
| +	fde.fd = socket_get_fd(sock);
| +	fde.flags = EVENT_FD_READ | EVENT_FD_WRITE;
| +	fde.handler = socket_connect_handler;
| +	fde.private = sock;
| +	fde.ref_count = 1;
| +
| +	event_add_fd(ev, &fde);
| +
| +	return NT_STATUS_OK;
|  }
|
| +NTSTATUS socket_connect(struct socket_context *sock,
| +			const char *my_address, int my_port,
| +			const char *server_address, int server_port,
| +			uint32_t flags)
| +{
| +	struct event_context *ev = event_context_init(NULL);
| +	NTSTATUS result;
| +
| +	NT_STATUS_HAVE_NO_MEMORY(ev);
| +
| +	result = socket_connect_send(sock, my_address, my_port, server_address,
| +				     server_port, flags, ev);
| +
| +	if (!NT_STATUS_IS_OK(result))
| +		goto done;
| +
| +	if (sock->state != SOCKET_STATE_CLIENT_CONNECTED) {
| +		if (event_loop_once(ev) != 0) {
| +			result = NT_STATUS_UNSUCCESSFUL;
| +			goto done;
| +		}
| +
| +		if (sock->state != SOCKET_STATE_CLIENT_CONNECTED) {
| +			result = map_nt_error_from_unix(sock->error);
| +			goto done;
| +		}
| +	}
| +
| + done:
| +	event_context_destroy(ev);
| +	return result;
| +}
| +
|  NTSTATUS socket_listen(struct socket_context *sock, const char *my_address, int port, int
queue_size, uint32_t flags)
|  {
|  	if (sock->type != SOCKET_TYPE_STREAM) {
| Index: lib/socket/socket_ipv4.c
| ===================================================================
| --- lib/socket/socket_ipv4.c	(revision 4617)
| +++ lib/socket/socket_ipv4.c	(working copy)
| @@ -75,20 +75,20 @@
|  	srv_addr.sin_family	= PF_INET;
|
|  	ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
| -	if (ret == -1) {
| -		return map_nt_error_from_unix(errno);
| +
| +	if (ret == 0) {
| +		sock->state = SOCKET_STATE_CLIENT_CONNECTED;
| +		return NT_STATUS_OK;
|  	}
|
| -	if (!(flags & SOCKET_FLAG_BLOCK)) {
| -		ret = set_blocking(sock->fd, False);
| -		if (ret == -1) {
| -			return map_nt_error_from_unix(errno);
| -		}
| +	if (!(sock->flags & SOCKET_FLAG_BLOCK) &&
| +	    (errno == EINPROGRESS || errno == EALREADY || errno == EAGAIN)) {
| +		/* Something is going on */
| +		sock->state = SOCKET_STATE_CLIENT_START;
| +		return NT_STATUS_OK;
|  	}
|
| -	sock->state = SOCKET_STATE_CLIENT_CONNECTED;
| -
| -	return NT_STATUS_OK;
| +	return map_nt_error_from_unix(errno);
|  }
|
|  static NTSTATUS ipv4_tcp_listen(struct socket_context *sock,
| Index: lib/socket/socket.h
| ===================================================================
| --- lib/socket/socket.h	(revision 4617)
| +++ lib/socket/socket.h	(working copy)
| @@ -84,6 +84,7 @@
|  struct socket_context {
|  	enum socket_type type;
|  	enum socket_state state;
| +	int error;
|  	uint32_t flags;
|
|  	int fd;


- --
metze

Stefan Metzmacher <metze at samba.org> www.samba.org
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3-nr1 (Windows XP)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFB4i9Qm70gjA5TCD8RApeZAJ9+1x1w/RLsGJukskHhB6reipdDEQCfbZjL
PUqgwRuF3lQ11iqTb7zLuiU=
=lhT2
-----END PGP SIGNATURE-----


More information about the samba-technical mailing list