diff options
-rw-r--r-- | source4/libcli/raw/clisocket.c | 244 | ||||
-rw-r--r-- | source4/libcli/raw/clitransport.c | 33 | ||||
-rw-r--r-- | source4/libcli/raw/libcliraw.h | 31 | ||||
-rw-r--r-- | source4/libcli/raw/rawrequest.c | 2 | ||||
-rw-r--r-- | source4/libcli/util/errormap.c | 2 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_smb.c | 2 | ||||
-rw-r--r-- | source4/ntvfs/cifs/vfs_cifs.c | 10 | ||||
-rw-r--r-- | source4/torture/torture.c | 3 |
8 files changed, 227 insertions, 100 deletions
diff --git a/source4/libcli/raw/clisocket.c b/source4/libcli/raw/clisocket.c index fb9afeab81..d20dc4bf25 100644 --- a/source4/libcli/raw/clisocket.c +++ b/source4/libcli/raw/clisocket.c @@ -1,7 +1,8 @@ /* Unix SMB/CIFS implementation. SMB client socket context management functions - Copyright (C) Andrew Tridgell 1994-2003 + + Copyright (C) Andrew Tridgell 1994-2005 Copyright (C) James Myers 2003 <myersjj@samba.org> This program is free software; you can redistribute it and/or modify @@ -20,7 +21,18 @@ */ #include "includes.h" +#include "events.h" #include "libcli/raw/libcliraw.h" +#include "libcli/composite/composite.h" + +/* + this private structure is used during async connection handling +*/ +struct clisocket_connect { + int *iports; + struct smbcli_socket *sock; + const char *dest_host; +}; /* create a smbcli_socket context @@ -29,61 +41,210 @@ struct smbcli_socket *smbcli_sock_init(TALLOC_CTX *mem_ctx) { struct smbcli_socket *sock; - sock = talloc_p(mem_ctx, struct smbcli_socket); + sock = talloc_zero(mem_ctx, struct smbcli_socket); if (!sock) { return NULL; } - ZERO_STRUCTP(sock); - sock->sock = NULL; - sock->port = 0; - - /* 20 second default timeout */ - sock->timeout = 20000; - sock->hostname = NULL; + sock->event.ctx = event_context_init(sock); + if (sock->event.ctx == NULL) { + talloc_free(sock); + return NULL; + } return sock; } +static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock, + const char *hostaddr, int port); + /* - connect a smbcli_socket context to an IP/port pair - if port is 0 then choose 445 then 139 + handle socket write events during an async connect. These happen when the OS + has either completed the connect() or has returned an error */ -BOOL smbcli_sock_connect(struct smbcli_socket *sock, struct ipv4_addr *ip, int port) +static void smbcli_sock_connect_handler(struct event_context *ev, struct fd_event *fde, + struct timeval t, uint16_t flags) { - NTSTATUS status; + struct smbcli_composite *c = fde->private; + struct clisocket_connect *conn = c->private; + int i; + + c->status = socket_connect_complete(conn->sock->sock, 0); + if (NT_STATUS_IS_OK(c->status)) { + socket_set_option(conn->sock->sock, lp_socket_options(), NULL); + c->state = SMBCLI_REQUEST_DONE; + if (c->async.fn) { + c->async.fn(c); + } + return; + } - if (port == 0) { - int i; - const char **ports = lp_smb_ports(); - for (i=0;ports[i];i++) { - port = atoi(ports[i]); - if (port != 0 && smbcli_sock_connect(sock, ip, port)) { - return True; + /* that port failed - try the next port */ + for (i=c->stage+1;conn->iports[i];i++) { + c->stage = i; + c->status = smbcli_sock_connect_one(conn->sock, + conn->dest_host, + conn->iports[i]); + if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + conn->sock->event.fde->private = c; + return; + } + if (NT_STATUS_IS_OK(c->status)) { + c->state = SMBCLI_REQUEST_DONE; + if (c->async.fn) { + c->async.fn(c); } + return; } - return False; } - status = socket_create("ip", SOCKET_TYPE_STREAM, &sock->sock, 0); - if (!NT_STATUS_IS_OK(status)) { - return False; + c->state = SMBCLI_REQUEST_ERROR; + if (c->async.fn) { + c->async.fn(c); } - talloc_steal(sock, sock->sock); +} - status = socket_connect(sock->sock, NULL, 0, sys_inet_ntoa(*ip), port, 0); - if (!NT_STATUS_IS_OK(status)) { + +/* + try to connect to the given address/port +*/ +static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock, + const char *hostaddr, int port) +{ + struct fd_event fde; + NTSTATUS status; + + if (sock->sock) { talloc_free(sock->sock); sock->sock = NULL; - return False; } - sock->dest_ip = *ip; + if (sock->event.fde) { + event_remove_fd(sock->event.ctx, sock->event.fde); + sock->event.fde = NULL; + } + + status = socket_create("ip", SOCKET_TYPE_STREAM, &sock->sock, 0); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + talloc_steal(sock, sock->sock); + + /* we initially look for write - see the man page on + non-blocking connect */ + fde.fd = socket_get_fd(sock->sock); + fde.flags = EVENT_FD_WRITE; + fde.handler = smbcli_sock_connect_handler; + fde.private = sock; + + sock->event.fde = event_add_fd(sock->event.ctx, &fde); sock->port = port; + set_blocking(fde.fd, False); + + return socket_connect(sock->sock, NULL, 0, hostaddr, port, 0); +} + - socket_set_option(sock->sock, lp_socket_options(), NULL); +/* + connect a smbcli_socket context to an IP/port pair + if port is 0 then choose 445 then 139 + + this is the async send side of the interface +*/ +struct smbcli_composite *smbcli_sock_connect_send(struct smbcli_socket *sock, + struct ipv4_addr *ip, int port) +{ + struct smbcli_composite *c; + struct clisocket_connect *conn; + int i; + + c = talloc_zero(sock, struct smbcli_composite); + if (c == NULL) return NULL; + + c->event_ctx = sock->event.ctx; + + conn = talloc(c, struct clisocket_connect); + if (conn == NULL) goto failed; + + conn->sock = sock; + + /* work out what ports we will try */ + if (port == 0) { + const char **ports = lp_smb_ports(); + for (i=0;ports[i];i++) /* noop */ ; + conn->iports = talloc_array(c, int, i+1); + if (conn->iports == NULL) goto failed; + for (i=0;ports[i];i++) { + conn->iports[i] = atoi(ports[i]); + } + conn->iports[i] = 0; + } else { + conn->iports = talloc_array(c, int, 2); + if (conn->iports == NULL) goto failed; + conn->iports[0] = port; + conn->iports[1] = 0; + } - return True; + conn->dest_host = talloc_strdup(c, sys_inet_ntoa(*ip)); + if (conn->dest_host == NULL) goto failed; + + c->private = conn; + c->state = SMBCLI_REQUEST_SEND; + + /* startup the connect process for each port in turn until one + succeeds or tells us that it is pending */ + for (i=0;conn->iports[i];i++) { + c->stage = i; + conn->sock->port = conn->iports[i]; + c->status = smbcli_sock_connect_one(sock, + conn->dest_host, + conn->iports[i]); + if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + sock->event.fde->private = c; + return c; + } + if (NT_STATUS_IS_OK(c->status)) { + c->state = SMBCLI_REQUEST_DONE; + return c; + } + } + + c->state = SMBCLI_REQUEST_ERROR; + return c; + +failed: + talloc_free(c); + return NULL; +} + +/* + finish a smbcli_sock_connect_send() operation +*/ +NTSTATUS smbcli_sock_connect_recv(struct smbcli_composite *c) +{ + NTSTATUS status; + status = smb_composite_wait(c); + talloc_free(c); + return status; +} + +/* + connect a smbcli_socket context to an IP/port pair + if port is 0 then choose the ports listed in smb.conf (normally 445 then 139) + + sync version of the function +*/ +NTSTATUS smbcli_sock_connect(struct smbcli_socket *sock, struct ipv4_addr *ip, int port) +{ + struct smbcli_composite *c; + + c = smbcli_sock_connect_send(sock, ip, port); + if (c == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return smbcli_sock_connect_recv(c); } @@ -153,6 +314,7 @@ ssize_t smbcli_sock_read(struct smbcli_socket *sock, uint8_t *data, size_t len) return nread; } + /**************************************************************************** resolve a hostname and connect ****************************************************************************/ @@ -161,14 +323,7 @@ BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, in int name_type = 0x20; struct ipv4_addr ip; char *name, *p; - BOOL ret; - -#if 0 - if (getenv("LIBSMB_PROG")) { - sock->fd = sock_exec(getenv("LIBSMB_PROG")); - return sock->fd != -1; - } -#endif + NTSTATUS status; name = talloc_strdup(sock, host); @@ -179,17 +334,12 @@ BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, in } if (!resolve_name(name, name, &ip, name_type)) { - talloc_free(name); return False; } - ret = smbcli_sock_connect(sock, &ip, port); + sock->hostname = name; - if (ret) { - sock->hostname = talloc_steal(sock, name); - } else { - talloc_free(name); - } + status = smbcli_sock_connect(sock, &ip, port); - return ret; + return NT_STATUS_IS_OK(status); } diff --git a/source4/libcli/raw/clitransport.c b/source4/libcli/raw/clitransport.c index 63ff1e4409..855543d670 100644 --- a/source4/libcli/raw/clitransport.c +++ b/source4/libcli/raw/clitransport.c @@ -53,8 +53,8 @@ static int transport_destructor(void *ptr) struct smbcli_transport *transport = ptr; smbcli_transport_dead(transport); - event_remove_fd(transport->event.ctx, transport->event.fde); - event_remove_timed(transport->event.ctx, transport->event.te); + event_remove_fd(transport->socket->event.ctx, transport->socket->event.fde); + event_remove_timed(transport->socket->event.ctx, transport->socket->event.te); return 0; } @@ -64,19 +64,12 @@ static int transport_destructor(void *ptr) struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock) { struct smbcli_transport *transport; - struct fd_event fde; transport = talloc_p(sock, struct smbcli_transport); if (!transport) return NULL; ZERO_STRUCTP(transport); - transport->event.ctx = event_context_init(transport); - if (transport->event.ctx == NULL) { - talloc_free(transport); - return NULL; - } - transport->socket = talloc_reference(transport, sock); transport->negotiate.protocol = PROTOCOL_NT1; transport->options.use_spnego = lp_use_spnego(); @@ -89,13 +82,11 @@ struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock) ZERO_STRUCT(transport->called); - fde.fd = socket_get_fd(sock->sock); - fde.flags = EVENT_FD_READ; - fde.handler = smbcli_transport_event_handler; - fde.private = transport; - fde.ref_count = 1; - - transport->event.fde = event_add_fd(transport->event.ctx, &fde); + /* take over event handling from the socket layer - it only + handles events up until we are connected */ + transport->socket->event.fde->handler = smbcli_transport_event_handler; + transport->socket->event.fde->private = transport; + transport->socket->event.fde->flags = EVENT_FD_READ; talloc_set_destructor(transport, transport_destructor); @@ -138,7 +129,7 @@ void smbcli_transport_dead(struct smbcli_transport *transport) */ static void smbcli_transport_write_enable(struct smbcli_transport *transport) { - transport->event.fde->flags |= EVENT_FD_WRITE; + transport->socket->event.fde->flags |= EVENT_FD_WRITE; } /* @@ -146,7 +137,7 @@ static void smbcli_transport_write_enable(struct smbcli_transport *transport) */ static void smbcli_transport_write_disable(struct smbcli_transport *transport) { - transport->event.fde->flags &= ~EVENT_FD_WRITE; + transport->socket->event.fde->flags &= ~EVENT_FD_WRITE; } /**************************************************************************** @@ -254,14 +245,14 @@ void smbcli_transport_idle_handler(struct smbcli_transport *transport, transport->idle.private = private; transport->idle.period = period; - if (transport->event.te != NULL) { - event_remove_timed(transport->event.ctx, transport->event.te); + if (transport->socket->event.te != NULL) { + event_remove_timed(transport->socket->event.ctx, transport->socket->event.te); } te.next_event = timeval_current_ofs(0, period); te.handler = idle_handler; te.private = transport; - transport->event.te = event_add_timed(transport->event.ctx, &te); + transport->socket->event.te = event_add_timed(transport->socket->event.ctx, &te); } /* diff --git a/source4/libcli/raw/libcliraw.h b/source4/libcli/raw/libcliraw.h index 51b50fdcb9..4047a5d369 100644 --- a/source4/libcli/raw/libcliraw.h +++ b/source4/libcli/raw/libcliraw.h @@ -61,24 +61,20 @@ struct smbcli_negotiate { /* this is the context for a SMB socket associated with the socket itself */ struct smbcli_socket { - struct ipv4_addr dest_ip; - /* dest hostname (which may or may not be a DNS name) */ - char *hostname; + struct socket_context *sock; - /* the port used */ + /* what port we ended up connected to */ int port; - - struct socket_context *sock; - /* a count of the number of packets we have received. We - * actually only care about zero/non-zero at this stage */ - uint_t pkt_count; + /* the hostname we connected to */ + const char *hostname; - /* the network address of the client */ - char *client_addr; - - /* timeout for socket operations in milliseconds. */ - int timeout; + /* the event handle for waiting for socket IO */ + struct { + struct event_context *ctx; + struct fd_event *fde; + struct timed_event *te; + } event; }; /* @@ -164,13 +160,6 @@ struct smbcli_transport { size_t received; uint8_t *buffer; } recv_buffer; - - /* the event handle for waiting for socket IO */ - struct { - struct event_context *ctx; - struct fd_event *fde; - struct timed_event *te; - } event; }; /* this is the context for the user */ diff --git a/source4/libcli/raw/rawrequest.c b/source4/libcli/raw/rawrequest.c index 8093b298bb..7fb12dcf80 100644 --- a/source4/libcli/raw/rawrequest.c +++ b/source4/libcli/raw/rawrequest.c @@ -333,7 +333,7 @@ BOOL smbcli_request_receive(struct smbcli_request *req) /* keep receiving packets until this one is replied to */ while (req->state <= SMBCLI_REQUEST_RECV) { - if (event_loop_once(req->transport->event.ctx) != 0) { + if (event_loop_once(req->transport->socket->event.ctx) != 0) { return False; } } diff --git a/source4/libcli/util/errormap.c b/source4/libcli/util/errormap.c index 4a57e436c7..b99ab3d2fe 100644 --- a/source4/libcli/util/errormap.c +++ b/source4/libcli/util/errormap.c @@ -1497,7 +1497,7 @@ struct unix_error_map { const struct unix_error_map unix_nt_errmap[] = { { EAGAIN, STATUS_MORE_ENTRIES }, { EINTR, STATUS_MORE_ENTRIES }, - { EINPROGRESS, STATUS_MORE_ENTRIES }, + { EINPROGRESS, NT_STATUS_MORE_PROCESSING_REQUIRED }, { EPERM, NT_STATUS_ACCESS_DENIED }, { EACCES, NT_STATUS_ACCESS_DENIED }, { ENOENT, NT_STATUS_OBJECT_NAME_NOT_FOUND }, diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c index 837561981f..14e9fe3a9c 100644 --- a/source4/librpc/rpc/dcerpc_smb.c +++ b/source4/librpc/rpc/dcerpc_smb.c @@ -317,7 +317,7 @@ static struct event_context *smb_event_context(struct dcerpc_connection *c) { struct smb_private *smb = c->transport.private; - return smb->tree->session->transport->event.ctx; + return smb->tree->session->transport->socket->event.ctx; } diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c index 2a76d245ac..1a5a5ac042 100644 --- a/source4/ntvfs/cifs/vfs_cifs.c +++ b/source4/ntvfs/cifs/vfs_cifs.c @@ -152,12 +152,12 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, smbcli_oplock_handler(private->transport, oplock_handler, private); smbcli_transport_idle_handler(private->transport, idle_func, 50000, private); - private->transport->event.fde->handler = cifs_socket_handler; - private->transport->event.fde->private = private; + private->transport->socket->event.fde->handler = cifs_socket_handler; + private->transport->socket->event.fde->private = private; - private->transport->event.ctx = event_context_merge(tcon->smb_conn->connection->event.ctx, - private->transport->event.ctx); - talloc_reference(private, private->transport->event.ctx); + private->transport->socket->event.ctx = event_context_merge(tcon->smb_conn->connection->event.ctx, + private->transport->socket->event.ctx); + talloc_reference(private, private->transport->socket->event.ctx); private->map_generic = lp_parm_bool(req->tcon->service, "cifs", "mapgeneric", False); diff --git a/source4/torture/torture.c b/source4/torture/torture.c index cc960b6ec7..d50bb9366a 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -62,8 +62,6 @@ static struct smbcli_state *open_nbt_connection(void) return cli; } - cli->transport->socket->timeout = 120000; /* set a really long timeout (2 minutes) */ - if (!smbcli_transport_establish(cli, &calling, &called)) { /* * Well, that failed, try *SMBSERVER ... @@ -111,7 +109,6 @@ BOOL torture_open_connection_share(struct smbcli_state **c, (*c)->transport->options.use_oplocks = use_oplocks; (*c)->transport->options.use_level2_oplocks = use_level_II_oplocks; - (*c)->transport->socket->timeout = 120000; return True; } |