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