/*
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_p(NULL, 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 != 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);
- talloc_free(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(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(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, '#'))) {
*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;
}