r26644: Janitorial: Pass resolve_context explicitly to various SMB functions, should...
[jelmer/samba4-debian.git] / source / libcli / raw / clisocket.c
index 9aea8624d002267c00afcccb3669424343c66089..8beaef3daabdf752f6a78f8e4f66e5026f5c1b10 100644 (file)
@@ -1,12 +1,14 @@
 /* 
    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
    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 "lib/events/events.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/composite/composite.h"
+#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(void)
+
+static void smbcli_sock_connect_recv_conn(struct composite_context *ctx);
+
+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_socket *sock;
+       struct composite_context *result, *ctx;
+       struct sock_connect_state *state;
+       int i;
 
-       sock = talloc_named(NULL, sizeof(*sock), "smbcli_socket");
-       if (!sock) {
-               return NULL;
+       result = talloc_zero(mem_ctx, struct composite_context);
+       if (result == NULL) goto failed;
+       result->state = COMPOSITE_STATE_IN_PROGRESS;
+
+       if (event_ctx != NULL) {
+               result->event_ctx = talloc_reference(result, event_ctx);
+       } else {
+               result->event_ctx = event_context_init(result);
        }
 
-       ZERO_STRUCTP(sock);
-       sock->fd = -1;
-       sock->port = 0;
-       /* 20 second default timeout */
-       sock->timeout = 20000;
+       if (result->event_ctx == NULL) goto failed;
+
+       state = talloc(result, struct sock_connect_state);
+       if (state == NULL) goto failed;
+       state->ctx = result;
+       result->private_data = state;
+
+       state->host_name = talloc_strdup(state, host_name);
+       if (state->host_name == NULL) goto failed;
 
-       sock->hostname = 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]);
+       }
 
-       return 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;
+
+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
-*/
-BOOL smbcli_sock_connect(struct smbcli_socket *sock, struct in_addr *ip, int port)
+static void smbcli_sock_connect_recv_conn(struct composite_context *ctx)
 {
-       if (getenv("LIBSMB_PROG")) {
-               sock->fd = sock_exec(getenv("LIBSMB_PROG"));
-               return sock->fd != -1;
-       }
+       struct sock_connect_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct sock_connect_state);
+       struct socket_context *sock;
+       uint16_t port;
 
-       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;
-                       }
-               }
-               return False;
-       }
+       state->ctx->status = socket_connect_multi_recv(ctx, state, &sock,
+                                                      &port);
+       if (!composite_is_ok(state->ctx)) return;
 
-       sock->dest_ip = *ip;
-       sock->port = port;
-       sock->fd = open_socket_out(SOCK_STREAM,
-                                  &sock->dest_ip,
-                                  sock->port, 
-                                  LONG_CONNECT_TIMEOUT);
-       if (sock->fd == -1) {
-               return False;
-       }
+       state->ctx->status =
+               socket_set_option(sock, lp_socket_options(global_loadparm), NULL);
+       if (!composite_is_ok(state->ctx)) return;
 
-       set_blocking(sock->fd, False);
-       set_socket_options(sock->fd, lp_socket_options());
 
-       return True;
-}
+       state->result = talloc_zero(state, struct smbcli_socket);
+       if (composite_nomem(state->result, state->ctx)) return;
 
+       state->result->sock = talloc_steal(state->result, sock);
+       state->result->port = port;
+       state->result->hostname = talloc_steal(sock, state->host_name);
 
-/****************************************************************************
- mark the socket as dead
-****************************************************************************/
-void smbcli_sock_dead(struct smbcli_socket *sock)
-{
-       if (sock->fd != -1) {
-               close(sock->fd);
-               sock->fd = -1;
-       }
+       state->result->event.ctx =
+               talloc_reference(state->result, state->ctx->event_ctx);
+       if (composite_nomem(state->result->event.ctx, state->ctx)) return;
+
+       composite_done(state->ctx);
 }
 
-/****************************************************************************
- reduce socket reference count - if it becomes zero then close
-****************************************************************************/
-void smbcli_sock_close(struct smbcli_socket *sock)
+/*
+  finish a smbcli_sock_connect_send() operation
+*/
+NTSTATUS smbcli_sock_connect_recv(struct composite_context *c,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct smbcli_socket **result)
 {
-       sock->reference_count--;
-       if (sock->reference_count <= 0) {
-               smbcli_sock_dead(sock);
+       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;
 }
 
-/****************************************************************************
- Set socket options on a open connection.
-****************************************************************************/
-void smbcli_sock_set_options(struct smbcli_socket *sock, const char *options)
+/*
+  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(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)
 {
-       set_socket_options(sock->fd, options);
+       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);
 }
 
+
 /****************************************************************************
- Write to socket. Return amount written.
+ mark the socket as dead
 ****************************************************************************/
-ssize_t smbcli_sock_write(struct smbcli_socket *sock, const char *data, size_t len)
+void smbcli_sock_dead(struct smbcli_socket *sock)
 {
-       if (sock->fd == -1) {
-               errno = EIO;
-               return -1;
-       }
-
-       return write_data(sock->fd, data, len);
+       talloc_free(sock->event.fde);
+       sock->event.fde = NULL;
+       talloc_free(sock->sock);
+       sock->sock = NULL;
 }
 
-
 /****************************************************************************
- Read from socket. return amount read
+ Set socket options on a open connection.
 ****************************************************************************/
-ssize_t smbcli_sock_read(struct smbcli_socket *sock, char *data, size_t len)
+void smbcli_sock_set_options(struct smbcli_socket *sock, const char *options)
 {
-       if (sock->fd == -1) {
-               errno = EIO;
-               return -1;
-       }
-
-       return read_data(sock->fd, data, len);
+       socket_set_option(sock->sock, options, NULL);
 }
 
 /****************************************************************************
 resolve a hostname and connect 
 ****************************************************************************/
-BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, int port)
+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 = 0x20;
-       struct in_addr ip;
+       int name_type = NBT_NAME_SERVER;
+       const char *address;
+       NTSTATUS status;
+       struct nbt_name nbt_name;
        char *name, *p;
-       BOOL ret;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       struct smbcli_socket *result;
+
+       if (tmp_ctx == NULL) {
+               DEBUG(0, ("talloc_new failed\n"));
+               return NULL;
+       }
 
-       if (getenv("LIBSMB_PROG")) {
-               sock->fd = sock_exec(getenv("LIBSMB_PROG"));
-               return sock->fd != -1;
+       name = talloc_strdup(tmp_ctx, host);
+       if (name == NULL) {
+               DEBUG(0, ("talloc_strdup failed\n"));
+               talloc_free(tmp_ctx);
+               return NULL;
        }
 
-       name = talloc_strdup(sock, host);
+       if (event_ctx == NULL) {
+               event_ctx = event_context_init(mem_ctx);
+       }
+
+       if (event_ctx == NULL) {
+               DEBUG(0, ("event_context_init failed\n"));
+               talloc_free(tmp_ctx);
+               return NULL;
+       }
 
        /* allow hostnames of the form NAME#xx and do a netbios lookup */
        if ((p = strchr(name, '#'))) {
@@ -165,18 +228,25 @@ BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, in
                *p = 0;
        }
 
-       if (!resolve_name(name, name, &ip, name_type)) {
-               talloc_free(name);
-               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;
        }
 
-       ret = smbcli_sock_connect(sock, &ip, port);
+       status = smbcli_sock_connect(mem_ctx, address, ports, name, resolve_ctx,
+                                    event_ctx, &result);
 
-       if (ret) {
-               sock->hostname = talloc_steal(sock, name);
-       } else {
-               talloc_free(name);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(9, ("smbcli_sock_connect failed: %s\n",
+                         nt_errstr(status)));
+               talloc_free(tmp_ctx);
+               return NULL;
        }
 
-       return ret;
+       talloc_free(tmp_ctx);
+
+       return result;
 }