fixed several places that unnecessarily take a reference to the event context
[kai/samba-autobuild/.git] / source4 / libcli / raw / clisocket.c
index 78a096fb8fbec466d03ba61cff08f3e9d558a538..02da4917e31b0836ea4b15c27ef551b2d7ed2134 100644 (file)
@@ -8,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"
+#include "lib/socket/socket.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+#include "libcli/raw/raw_proto.h"
+
+struct sock_connect_state {
+       struct composite_context *ctx;
+       const char *host_name;
+       int num_ports;
+       uint16_t *ports;
+       const char *socket_options;
+       struct smbcli_socket *result;
+};
 
 /*
-  this private structure is used during async connection handling
+  connect a smbcli_socket context to an IP/port pair
+  if port is 0 then choose 445 then 139
 */
-struct clisocket_connect {
-       int port_num;
-       int *iports;
-       struct smbcli_socket *sock;
-       const char *dest_host;
-};
 
+static void smbcli_sock_connect_recv_conn(struct composite_context *ctx);
 
-/*
-  create a smbcli_socket context
-  The event_ctx is optional - if not supplied one will be created
-*/
-struct smbcli_socket *smbcli_sock_init(TALLOC_CTX *mem_ctx, 
-                                      struct event_context *event_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 tevent_context *event_ctx,
+                                                  const char *socket_options)
 {
-       struct smbcli_socket *sock;
+       struct composite_context *result, *ctx;
+       struct sock_connect_state *state;
+       int i;
 
-       sock = talloc_zero(mem_ctx, struct 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) {
-               sock->event.ctx = talloc_reference(sock, event_ctx);
-       } else {
-               sock->event.ctx = event_context_init(sock);
-       }
-       if (sock->event.ctx == NULL) {
-               talloc_free(sock);
-               return NULL;
-       }
+       result->event_ctx = event_ctx;
+       if (result->event_ctx == NULL) goto failed;
 
-       return sock;
-}
+       state = talloc(result, struct sock_connect_state);
+       if (state == NULL) goto failed;
+       state->ctx = result;
+       result->private_data = state;
 
-static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock, 
-                                       const char *hostaddr, int port);
+       state->host_name = talloc_strdup(state, host_name);
+       if (state->host_name == NULL) goto failed;
 
-/*
-  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 *c = talloc_get_type(fde->private, struct composite_context);
-       struct clisocket_connect *conn = talloc_get_type(c->private, struct clisocket_connect);
-       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);
-               conn->sock->hostname = talloc_strdup(conn->sock, conn->dest_host);
-               c->state = SMBCLI_REQUEST_DONE;
-               if (c->async.fn) {
-                       c->async.fn(c);
-               }
-               return;
+       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]);
        }
+       state->socket_options = talloc_reference(state, socket_options);
 
-       /* that port failed - try the next port */
-       for (i=conn->port_num+1;conn->iports[i];i++) {
-               conn->port_num = i;
-               c->status = smbcli_sock_connect_one(conn->sock, 
-                                                   conn->dest_host, 
-                                                   conn->iports[i]);
-               if (NT_STATUS_IS_OK(c->status) ||
-                   NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-                       conn->sock->event.fde->private = c;
-                       return;
-               }
-       }
+       ctx = socket_connect_multi_send(state, host_addr,
+                                       state->num_ports, state->ports,
+                                       resolve_ctx,
+                                       state->ctx->event_ctx);
+       if (ctx == NULL) goto failed;
+       ctx->async.fn = smbcli_sock_connect_recv_conn;
+       ctx->async.private_data = state;
+       return result;
 
-       c->state = SMBCLI_REQUEST_ERROR;
-       if (c->async.fn) {
-               c->async.fn(c);
-       }
+failed:
+       talloc_free(result);
+       return NULL;
 }
 
-
-/*
-  try to connect to the given address/port
-*/
-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)
 {
-       struct fd_event fde;
-       NTSTATUS status;
+       struct sock_connect_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct sock_connect_state);
+       struct socket_context *sock;
+       uint16_t port;
 
-       if (sock->sock) {
-               talloc_free(sock->sock);
-               sock->sock = NULL;
-       }
-       talloc_free(sock->event.fde);
+       state->ctx->status = socket_connect_multi_recv(ctx, state, &sock,
+                                                      &port);
+       if (!composite_is_ok(state->ctx)) return;
 
-       status = socket_create("ip", SOCKET_TYPE_STREAM, &sock->sock, 0);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
+       state->ctx->status =
+               socket_set_option(sock, state->socket_options, NULL);
+       if (!composite_is_ok(state->ctx)) return;
 
-       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;
+       state->result = talloc_zero(state, struct smbcli_socket);
+       if (composite_nomem(state->result, state->ctx)) return;
 
-       sock->event.fde = event_add_fd(sock->event.ctx, &fde, sock);
+       state->result->sock = talloc_steal(state->result, sock);
+       state->result->port = port;
+       state->result->hostname = talloc_steal(sock, state->host_name);
 
-       sock->port = port;
-       set_blocking(fde.fd, False);
+       state->result->event.ctx = state->ctx->event_ctx;
+       if (composite_nomem(state->result->event.ctx, state->ctx)) return;
 
-       return socket_connect(sock->sock, NULL, 0, hostaddr, port, 0);
-}
-                                       
-
-/*
-  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 composite_context *smbcli_sock_connect_send(struct smbcli_socket *sock, 
-                                                 const char *host_addr, int port)
-{
-       struct composite_context *c;
-       struct clisocket_connect *conn;
-       int i;
-
-       c = talloc_zero(sock, struct composite_context);
-       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;
-       }
-
-       conn->dest_host = talloc_strdup(c, host_addr);
-       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++) {
-               conn->port_num = i;
-               conn->sock->port = conn->iports[i];
-               c->status = smbcli_sock_connect_one(sock, 
-                                                   conn->dest_host, 
-                                                   conn->iports[i]);
-               if (NT_STATUS_IS_OK(c->status) ||
-                   NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-                       sock->event.fde->private = c;
-                       return c;
-               }
-       }
-
-       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 composite_context *c)
+NTSTATUS smbcli_sock_connect_recv(struct composite_context *c,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct smbcli_socket **result)
 {
-       NTSTATUS status;
-       status = 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;
 }
@@ -233,28 +148,31 @@ NTSTATUS smbcli_sock_connect_recv(struct composite_context *c)
 
   sync version of the function
 */
-NTSTATUS smbcli_sock_connect(struct smbcli_socket *sock, const char *host_addr, 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 tevent_context *event_ctx,
+                                const char *socket_options,
+                            struct smbcli_socket **result)
 {
-       struct composite_context *c;
-
-       c = smbcli_sock_connect_send(sock, host_addr, 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, socket_options);
+       return smbcli_sock_connect_recv(c, mem_ctx, result);
 }
 
 
 /****************************************************************************
  mark the socket as dead
 ****************************************************************************/
-void smbcli_sock_dead(struct smbcli_socket *sock)
+_PUBLIC_ 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;
 }
 
 /****************************************************************************
@@ -265,66 +183,39 @@ void smbcli_sock_set_options(struct smbcli_socket *sock, const char *options)
        socket_set_option(sock->sock, options, NULL);
 }
 
-/****************************************************************************
- Write to socket. Return amount written.
-****************************************************************************/
-ssize_t smbcli_sock_write(struct smbcli_socket *sock, const uint8_t *data, size_t len)
-{
-       NTSTATUS status;
-       DATA_BLOB blob;
-       size_t nsent;
-
-       if (sock->sock == NULL) {
-               errno = EIO;
-               return -1;
-       }
-
-       blob.data = discard_const(data);
-       blob.length = len;
-
-       status = socket_send(sock->sock, &blob, &nsent, 0);
-       if (NT_STATUS_IS_ERR(status)) {
-               return -1;
-       }
-
-       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;
-       }
-
-       status = socket_recv(sock->sock, data, len, &nread, 0);
-       if (NT_STATUS_IS_ERR(status)) {
-               return -1;
-       }
-
-       return nread;
-}
-
-
 /****************************************************************************
 resolve a hostname and connect 
 ****************************************************************************/
-BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, int port)
+_PUBLIC_ struct smbcli_socket *smbcli_sock_connect_byname(const char *host, const char **ports,
+                                                TALLOC_CTX *mem_ctx,
+                                                struct resolve_context *resolve_ctx,
+                                                struct tevent_context *event_ctx,
+                                                const char *socket_options)
 {
        int name_type = NBT_NAME_SERVER;
        const char *address;
        NTSTATUS status;
        struct nbt_name nbt_name;
        char *name, *p;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       struct smbcli_socket *result;
 
-       name = talloc_strdup(sock, host);
+       if (event_ctx == NULL) {
+               DEBUG(0, ("Invalid NULL event context passed in as parameter\n"));
+               return NULL;
+       }
+
+       if (tmp_ctx == NULL) {
+               DEBUG(0, ("talloc_new failed\n"));
+               return NULL;
+       }
+
+       name = talloc_strdup(tmp_ctx, host);
+       if (name == NULL) {
+               DEBUG(0, ("talloc_strdup failed\n"));
+               talloc_free(tmp_ctx);
+               return NULL;
+       }
 
        /* allow hostnames of the form NAME#xx and do a netbios lookup */
        if ((p = strchr(name, '#'))) {
@@ -332,18 +223,26 @@ BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, in
                *p = 0;
        }
 
-       nbt_name.name = name;
-       nbt_name.type = name_type;
-       nbt_name.scope = NULL;
+       make_nbt_name(&nbt_name, host, name_type);
        
-       status = resolve_name(&nbt_name, sock, &address);
+       status = resolve_name(resolve_ctx, &nbt_name, tmp_ctx, &address, event_ctx);
        if (!NT_STATUS_IS_OK(status)) {
-               return False;
+               talloc_free(tmp_ctx);
+               return NULL;
        }
 
-       sock->hostname = name;
+       status = smbcli_sock_connect(mem_ctx, address, ports, name, resolve_ctx,
+                                    event_ctx, 
+                                        socket_options, &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, address, port);
+       talloc_free(tmp_ctx);
 
-       return NT_STATUS_IS_OK(status);
+       return result;
 }