r26644: Janitorial: Pass resolve_context explicitly to various SMB functions, should...
[jelmer/samba4-debian.git] / source / libcli / raw / clisocket.c
index d20dc4bf256037f660ce211a1a0f4c1389df8e80..8beaef3daabdf752f6a78f8e4f66e5026f5c1b10 100644 (file)
@@ -1,5 +1,6 @@
 /* 
    Unix SMB/CIFS implementation.
+
    SMB client socket context management functions
 
    Copyright (C) Andrew Tridgell 1994-2005
@@ -7,7 +8,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "events.h"
+#include "lib/events/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;
+#include "lib/socket/socket.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+
+struct sock_connect_state {
+       struct composite_context *ctx;
+       const char *host_name;
+       int num_ports;
+       uint16_t *ports;
+       struct smbcli_socket *result;
 };
 
 /*
-  create a smbcli_socket context
+  connect a smbcli_socket context to an IP/port pair
+  if port is 0 then choose 445 then 139
 */
-struct smbcli_socket *smbcli_sock_init(TALLOC_CTX *mem_ctx)
-{
-       struct smbcli_socket *sock;
-
-       sock = talloc_zero(mem_ctx, struct smbcli_socket);
-       if (!sock) {
-               return 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);
+static void smbcli_sock_connect_recv_conn(struct composite_context *ctx);
 
-/*
-  handle socket write events during an async connect. These happen when the OS
-  has either completed the connect() or has returned an error
-*/
-static void smbcli_sock_connect_handler(struct event_context *ev, struct fd_event *fde, 
-                                       struct timeval t, uint16_t flags)
+struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx,
+                                                  const char *host_addr,
+                                                  const char **ports,
+                                                  const char *host_name,
+                                                  struct resolve_context *resolve_ctx,
+                                                  struct event_context *event_ctx)
 {
-       struct smbcli_composite *c = fde->private;
-       struct clisocket_connect *conn = c->private;
+       struct composite_context *result, *ctx;
+       struct sock_connect_state *state;
        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;
-       }
 
-       /* 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;
-               }
-       }
+       result = talloc_zero(mem_ctx, struct composite_context);
+       if (result == NULL) goto failed;
+       result->state = COMPOSITE_STATE_IN_PROGRESS;
 
-       c->state = SMBCLI_REQUEST_ERROR;
-       if (c->async.fn) {
-               c->async.fn(c);
+       if (event_ctx != NULL) {
+               result->event_ctx = talloc_reference(result, event_ctx);
+       } else {
+               result->event_ctx = event_context_init(result);
        }
-}
 
+       if (result->event_ctx == NULL) goto failed;
 
-/*
-  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;
+       state = talloc(result, struct sock_connect_state);
+       if (state == NULL) goto failed;
+       state->ctx = result;
+       result->private_data = state;
 
-       if (sock->sock) {
-               talloc_free(sock->sock);
-               sock->sock = NULL;
-       }
+       state->host_name = talloc_strdup(state, host_name);
+       if (state->host_name == NULL) goto failed;
 
-       if (sock->event.fde) {
-               event_remove_fd(sock->event.ctx, sock->event.fde);
-               sock->event.fde = NULL;
+       state->num_ports = str_list_length(ports);
+       state->ports = talloc_array(state, uint16_t, state->num_ports);
+       if (state->ports == NULL) goto failed;
+       for (i=0;ports[i];i++) {
+               state->ports[i] = atoi(ports[i]);
        }
 
-       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;
+       ctx = socket_connect_multi_send(state, host_addr,
+                                       state->num_ports, state->ports,
+                                       lp_resolve_context(global_loadparm),
+                                       state->ctx->event_ctx);
+       if (ctx == NULL) goto failed;
+       ctx->async.fn = smbcli_sock_connect_recv_conn;
+       ctx->async.private_data = state;
+       return result;
 
-       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);
+failed:
+       talloc_free(result);
+       return 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)
+static void smbcli_sock_connect_recv_conn(struct composite_context *ctx)
 {
-       struct smbcli_composite *c;
-       struct clisocket_connect *conn;
-       int i;
+       struct sock_connect_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct sock_connect_state);
+       struct socket_context *sock;
+       uint16_t port;
 
-       c = talloc_zero(sock, struct smbcli_composite);
-       if (c == NULL) return NULL;
+       state->ctx->status = socket_connect_multi_recv(ctx, state, &sock,
+                                                      &port);
+       if (!composite_is_ok(state->ctx)) return;
 
-       c->event_ctx = sock->event.ctx;
+       state->ctx->status =
+               socket_set_option(sock, lp_socket_options(global_loadparm), NULL);
+       if (!composite_is_ok(state->ctx)) return;
 
-       conn = talloc(c, struct clisocket_connect);
-       if (conn == NULL) goto failed;
 
-       conn->sock = sock;
+       state->result = talloc_zero(state, struct smbcli_socket);
+       if (composite_nomem(state->result, state->ctx)) return;
 
-       /* 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;
-       }
+       state->result->sock = talloc_steal(state->result, sock);
+       state->result->port = port;
+       state->result->hostname = talloc_steal(sock, state->host_name);
 
-       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;
-               }
-       }
+       state->result->event.ctx =
+               talloc_reference(state->result, state->ctx->event_ctx);
+       if (composite_nomem(state->result->event.ctx, state->ctx)) return;
 
-       c->state = SMBCLI_REQUEST_ERROR;
-       return c;
-       
-failed:
-       talloc_free(c);
-       return NULL;
+       composite_done(state->ctx);
 }
 
 /*
   finish a smbcli_sock_connect_send() operation
 */
-NTSTATUS smbcli_sock_connect_recv(struct smbcli_composite *c)
+NTSTATUS smbcli_sock_connect_recv(struct composite_context *c,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct smbcli_socket **result)
 {
-       NTSTATUS status;
-       status = smb_composite_wait(c);
+       NTSTATUS status = composite_wait(c);
+       if (NT_STATUS_IS_OK(status)) {
+               struct sock_connect_state *state =
+                       talloc_get_type(c->private_data,
+                                       struct sock_connect_state);
+               *result = talloc_steal(mem_ctx, state->result);
+       }
        talloc_free(c);
        return status;
 }
@@ -235,16 +150,18 @@ NTSTATUS smbcli_sock_connect_recv(struct smbcli_composite *c)
 
   sync version of the function
 */
-NTSTATUS smbcli_sock_connect(struct smbcli_socket *sock, struct ipv4_addr *ip, int port)
+NTSTATUS smbcli_sock_connect(TALLOC_CTX *mem_ctx,
+                            const char *host_addr, const char **ports,
+                            const char *host_name,
+                            struct resolve_context *resolve_ctx,
+                            struct event_context *event_ctx,
+                            struct smbcli_socket **result)
 {
-       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);
+       struct composite_context *c =
+               smbcli_sock_connect_send(mem_ctx, host_addr, ports, host_name,
+                                        resolve_ctx,
+                                        event_ctx);
+       return smbcli_sock_connect_recv(c, mem_ctx, result);
 }
 
 
@@ -253,10 +170,10 @@ NTSTATUS smbcli_sock_connect(struct smbcli_socket *sock, struct ipv4_addr *ip, i
 ****************************************************************************/
 void smbcli_sock_dead(struct smbcli_socket *sock)
 {
-       if (sock->sock != NULL) {
-               talloc_free(sock->sock);
-               sock->sock = NULL;
-       }
+       talloc_free(sock->event.fde);
+       sock->event.fde = NULL;
+       talloc_free(sock->sock);
+       sock->sock = NULL;
 }
 
 /****************************************************************************
@@ -268,78 +185,68 @@ void smbcli_sock_set_options(struct smbcli_socket *sock, const char *options)
 }
 
 /****************************************************************************
- Write to socket. Return amount written.
+resolve a hostname and connect 
 ****************************************************************************/
-ssize_t smbcli_sock_write(struct smbcli_socket *sock, const uint8_t *data, size_t len)
+struct smbcli_socket *smbcli_sock_connect_byname(const char *host, const char **ports,
+                                                TALLOC_CTX *mem_ctx,
+                                                struct resolve_context *resolve_ctx,
+                                                struct event_context *event_ctx)
 {
+       int name_type = NBT_NAME_SERVER;
+       const char *address;
        NTSTATUS status;
-       DATA_BLOB blob;
-       size_t nsent;
+       struct nbt_name nbt_name;
+       char *name, *p;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       struct smbcli_socket *result;
 
-       if (sock->sock == NULL) {
-               errno = EIO;
-               return -1;
+       if (tmp_ctx == NULL) {
+               DEBUG(0, ("talloc_new failed\n"));
+               return NULL;
        }
 
-       blob.data = discard_const(data);
-       blob.length = len;
-
-       status = socket_send(sock->sock, &blob, &nsent, 0);
-       if (NT_STATUS_IS_ERR(status)) {
-               return -1;
+       name = talloc_strdup(tmp_ctx, host);
+       if (name == NULL) {
+               DEBUG(0, ("talloc_strdup failed\n"));
+               talloc_free(tmp_ctx);
+               return NULL;
        }
 
-       return nsent;
-}
-
-
-/****************************************************************************
- Read from socket. return amount read
-****************************************************************************/
-ssize_t smbcli_sock_read(struct smbcli_socket *sock, uint8_t *data, size_t len)
-{
-       NTSTATUS status;
-       size_t nread;
-
-       if (sock->sock == NULL) {
-               errno = EIO;
-               return -1;
+       if (event_ctx == NULL) {
+               event_ctx = event_context_init(mem_ctx);
        }
 
-       status = socket_recv(sock->sock, data, len, &nread, 0);
-       if (NT_STATUS_IS_ERR(status)) {
-               return -1;
+       if (event_ctx == NULL) {
+               DEBUG(0, ("event_context_init failed\n"));
+               talloc_free(tmp_ctx);
+               return NULL;
        }
 
-       return nread;
-}
-
-
-/****************************************************************************
-resolve a hostname and connect 
-****************************************************************************/
-BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, int port)
-{
-       int name_type = 0x20;
-       struct ipv4_addr ip;
-       char *name, *p;
-       NTSTATUS status;
-
-       name = talloc_strdup(sock, host);
-
        /* allow hostnames of the form NAME#xx and do a netbios lookup */
        if ((p = strchr(name, '#'))) {
                name_type = strtol(p+1, NULL, 16);
                *p = 0;
        }
 
-       if (!resolve_name(name, name, &ip, name_type)) {
-               return False;
+       make_nbt_name(&nbt_name, host, name_type);
+       
+       status = resolve_name(resolve_ctx, &nbt_name, tmp_ctx, &address, event_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return NULL;
        }
 
-       sock->hostname = name;
+       status = smbcli_sock_connect(mem_ctx, address, ports, name, resolve_ctx,
+                                    event_ctx, &result);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(9, ("smbcli_sock_connect failed: %s\n",
+                         nt_errstr(status)));
+               talloc_free(tmp_ctx);
+               return NULL;
+       }
 
-       status = smbcli_sock_connect(sock, &ip, port);
+       talloc_free(tmp_ctx);
 
-       return NT_STATUS_IS_OK(status);
+       return result;
 }