summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libcli/raw/clisocket.c244
-rw-r--r--source4/libcli/raw/clitransport.c33
-rw-r--r--source4/libcli/raw/libcliraw.h31
-rw-r--r--source4/libcli/raw/rawrequest.c2
-rw-r--r--source4/libcli/util/errormap.c2
-rw-r--r--source4/librpc/rpc/dcerpc_smb.c2
-rw-r--r--source4/ntvfs/cifs/vfs_cifs.c10
-rw-r--r--source4/torture/torture.c3
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;
}