1
0
mirror of https://github.com/samba-team/samba.git synced 2025-11-06 08:23:50 +03:00

r11369: Implement socket_connect_multi: Connect to multiple ipv4 tcp ports in

sequence, with a 2-millisecond timeout between firing the syn packets. Build
smbcli_sock_connect_send upon that.

Volker
This commit is contained in:
Volker Lendecke
2005-10-28 11:02:42 +00:00
committed by Gerald (Jerry) Carter
parent abff53b633
commit 5718df44d9
10 changed files with 442 additions and 431 deletions

View File

@@ -330,5 +330,6 @@ struct param_section;
struct param; struct param;
struct socket_context; struct socket_context;
struct smbcli_socket;
struct _krb5_krb_auth_data; struct _krb5_krb_auth_data;

View File

@@ -36,6 +36,7 @@ INIT_OBJ_FILES = \
socket.o socket.o
ADD_OBJ_FILES = \ ADD_OBJ_FILES = \
access.o \ access.o \
connect_multi.o \
connect.o connect.o
NOPROTO=YES NOPROTO=YES
# End SUBSYSTEM SOCKET # End SUBSYSTEM SOCKET

View File

@@ -0,0 +1,266 @@
/*
Unix SMB/CIFS implementation.
Fire connect requests to a host and a number of ports, with a timeout
between the connect request. Return if the first connect comes back
successfully or return the last error.
Copyright (C) Volker Lendecke 2005
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
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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.
*/
#include "includes.h"
#include "lib/socket/socket.h"
#include "lib/events/events.h"
#include "libcli/composite/composite.h"
struct connect_multi_state {
struct composite_context *ctx;
const char *server_address;
int num_ports;
uint16_t *ports;
struct socket_context *result;
uint16_t result_port;
int num_connects_sent, num_connects_in_fly;
struct fd_event **write_events;
struct socket_context **sockets;
struct timed_event *next_timeout;
};
static void connect_multi_connect_handler(struct event_context *ev,
struct fd_event *fde,
uint16_t flags, void *p);
static NTSTATUS connect_multi_next_socket(struct connect_multi_state *state);
static void connect_multi_fire_next(struct event_context *ev,
struct timed_event *te,
struct timeval tv, void *p);
struct composite_context *socket_connect_multi_send(TALLOC_CTX *mem_ctx,
const char *server_address,
int num_server_ports,
uint16_t *server_ports,
struct event_context *event_ctx)
{
struct composite_context *result;
struct connect_multi_state *state;
int i;
result = talloc_zero(mem_ctx, struct composite_context);
if (result == NULL) goto failed;
result->state = COMPOSITE_STATE_IN_PROGRESS;
result->event_ctx = event_ctx;
state = talloc(result, struct connect_multi_state);
if (state == NULL) goto failed;
state->ctx = result;
result->private_data = state;
state->server_address = talloc_strdup(state, server_address);
if (state->server_address == NULL) goto failed;
state->num_ports = num_server_ports;
state->ports = talloc_array(state, uint16_t, state->num_ports);
if (state->ports == NULL) goto failed;
for (i=0; i<state->num_ports; i++) {
state->ports[i] = server_ports[i];
}
state->sockets =
talloc_array(state, struct socket_context *, state->num_ports);
if (state->sockets == NULL) goto failed;
state->write_events =
talloc_array(state, struct fd_event *, state->num_ports);
if (state->write_events == NULL) goto failed;
state->num_connects_sent = 0;
state->num_connects_in_fly = 0;
result->status = connect_multi_next_socket(state);
if (!NT_STATUS_IS_OK(result->status)) {
composite_trigger_error(result);
return result;
}
return result;
failed:
talloc_free(result);
return NULL;
}
static NTSTATUS connect_multi_next_socket(struct connect_multi_state *state)
{
NTSTATUS status;
int res, next = state->num_connects_sent;
status = socket_create("ipv4", SOCKET_TYPE_STREAM,
&state->sockets[next], 0);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
res = set_blocking(socket_get_fd(state->sockets[next]), False);
if (res != 0) {
return map_nt_error_from_unix(errno);
}
talloc_steal(state->sockets, state->sockets[next]);
status = socket_connect(state->sockets[next], NULL, 0,
state->server_address, state->ports[next], 0);
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
return status;
}
state->write_events[next] =
event_add_fd(state->ctx->event_ctx, state->write_events,
socket_get_fd(state->sockets[next]),
EVENT_FD_WRITE,
connect_multi_connect_handler, state);
if (state->write_events[next] == NULL) {
return NT_STATUS_NO_MEMORY;
}
state->num_connects_sent += 1;
state->num_connects_in_fly += 1;
if (state->num_ports > state->num_connects_sent) {
state->next_timeout =
event_add_timed(state->ctx->event_ctx, state,
timeval_current_ofs(0, 2000),
connect_multi_fire_next, state);
if (state->next_timeout == NULL) {
talloc_free(state->sockets[next]);
state->sockets[next] = NULL;
talloc_free(state->write_events[next]);
state->write_events[next] = NULL;
return NT_STATUS_NO_MEMORY;
}
}
return NT_STATUS_OK;
}
static void connect_multi_fire_next(struct event_context *ev,
struct timed_event *te,
struct timeval tv, void *p)
{
struct connect_multi_state *state =
talloc_get_type(p, struct connect_multi_state);
state->ctx->status = connect_multi_next_socket(state);
if (!composite_is_ok(state->ctx)) return;
}
static void connect_multi_connect_handler(struct event_context *ev,
struct fd_event *fde,
uint16_t flags, void *p)
{
struct connect_multi_state *state =
talloc_get_type(p, struct connect_multi_state);
int i;
for (i=0; i<state->num_connects_sent; i++) {
if (fde == state->write_events[i]) {
break;
}
}
if (i == state->num_connects_sent) {
composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
return;
}
state->num_connects_in_fly -= 1;
state->ctx->status = socket_connect_complete(state->sockets[i], 0);
if (NT_STATUS_IS_OK(state->ctx->status)) {
state->result = talloc_steal(state, state->sockets[i]);
state->result_port = state->ports[i];
talloc_free(state->sockets);
state->sockets = NULL;
talloc_free(state->write_events);
state->write_events = NULL;
composite_done(state->ctx);
return;
}
talloc_free(state->sockets[i]);
state->sockets[i] = NULL;
if ((state->num_connects_in_fly == 0) &&
(state->num_connects_sent == state->num_ports)) {
composite_error(state->ctx, state->ctx->status);
return;
}
if (state->num_connects_in_fly != 0) {
/* Waiting for something to happen on the net or the next
* timeout to trigger */
return;
}
SMB_ASSERT(state->num_connects_sent < state->num_ports);
SMB_ASSERT(state->next_timeout != NULL);
/* There are ports left but nothing on the net, so trigger the next
* one immediately. */
talloc_free(state->next_timeout);
state->next_timeout =
event_add_timed(state->ctx->event_ctx, state, timeval_zero(),
connect_multi_fire_next, state);
if (composite_nomem(state->next_timeout, state->ctx)) return;
}
NTSTATUS socket_connect_multi_recv(struct composite_context *ctx,
TALLOC_CTX *mem_ctx,
struct socket_context **result,
uint16_t *port)
{
NTSTATUS status = composite_wait(ctx);
if (NT_STATUS_IS_OK(status)) {
struct connect_multi_state *state =
talloc_get_type(ctx->private_data,
struct connect_multi_state);
*result = talloc_steal(mem_ctx, state->result);
*port = state->result_port;
}
talloc_free(ctx);
return status;
}
NTSTATUS socket_connect_multi(TALLOC_CTX *mem_ctx,
const char *server_address,
int num_server_ports, uint16_t *server_ports,
struct event_context *event_ctx,
struct socket_context **result,
uint16_t *result_port)
{
struct composite_context *ctx =
socket_connect_multi_send(mem_ctx, server_address,
num_server_ports, server_ports,
event_ctx);
return socket_connect_multi_recv(ctx, mem_ctx, result, result_port);
}

View File

@@ -153,4 +153,19 @@ NTSTATUS socket_connect_ev(struct socket_context *sock,
const char *server_address, int server_port, const char *server_address, int server_port,
uint32_t flags, struct event_context *ev); uint32_t flags, struct event_context *ev);
struct composite_context *socket_connect_multi_send(TALLOC_CTX *mem_ctx,
const char *server_address,
int num_server_ports,
uint16_t *server_ports,
struct event_context *event_ctx);
NTSTATUS socket_connect_multi_recv(struct composite_context *ctx,
TALLOC_CTX *mem_ctx,
struct socket_context **result,
uint16_t *port);
NTSTATUS socket_connect_multi(TALLOC_CTX *mem_ctx, const char *server_address,
int num_server_ports, uint16_t *server_ports,
struct event_context *event_ctx,
struct socket_context **result,
uint16_t *port);
#endif /* _SAMBA_SOCKET_H */ #endif /* _SAMBA_SOCKET_H */

View File

@@ -32,13 +32,9 @@ BOOL smbcli_socket_connect(struct smbcli_state *cli, const char *server)
{ {
struct smbcli_socket *sock; struct smbcli_socket *sock;
sock = smbcli_sock_init(cli, NULL); sock = smbcli_sock_connect_byname(server, 0, NULL, NULL);
if (!sock) return False;
if (!smbcli_sock_connect_byname(sock, server, 0)) { if (sock == NULL) return False;
talloc_free(sock);
return False;
}
cli->transport = smbcli_transport_init(sock, cli, True); cli->transport = smbcli_transport_init(sock, cli, True);
if (!cli->transport) { if (!cli->transport) {

View File

@@ -24,7 +24,6 @@ ADD_OBJ_FILES = \
smb_composite/loadfile.o \ smb_composite/loadfile.o \
smb_composite/savefile.o \ smb_composite/savefile.o \
smb_composite/connect.o \ smb_composite/connect.o \
smb_composite/connect_multi.o \
smb_composite/sesssetup.o \ smb_composite/sesssetup.o \
smb_composite/fetchfile.o \ smb_composite/fetchfile.o \
smb_composite/appendacl.o \ smb_composite/appendacl.o \

View File

@@ -428,17 +428,8 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
return result; return result;
} }
state->ctx->status = socket_create("ipv4", SOCKET_TYPE_STREAM, ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port,
&conn->sock, 0); conn->event.event_ctx);
if (!NT_STATUS_IS_OK(state->ctx->status)) {
composite_trigger_error(state->ctx);
return result;
}
talloc_steal(conn, conn->sock);
ctx = socket_connect_send(conn->sock, NULL, 0, conn->host,
conn->port, 0, conn->event.event_ctx);
if (ctx == NULL) goto failed; if (ctx == NULL) goto failed;
ctx->async.fn = ldap_connect_recv_conn; ctx->async.fn = ldap_connect_recv_conn;
@@ -456,8 +447,10 @@ static void ldap_connect_recv_conn(struct composite_context *ctx)
talloc_get_type(ctx->async.private_data, talloc_get_type(ctx->async.private_data,
struct ldap_connect_state); struct ldap_connect_state);
struct ldap_connection *conn = state->conn; struct ldap_connection *conn = state->conn;
uint16_t port;
state->ctx->status = socket_connect_recv(ctx); state->ctx->status = socket_connect_multi_recv(ctx, state, &conn->sock,
&port);
if (!composite_is_ok(state->ctx)) return; if (!composite_is_ok(state->ctx)) return;
/* setup a handler for events on this socket */ /* setup a handler for events on this socket */

View File

@@ -27,206 +27,130 @@
#include "libcli/composite/composite.h" #include "libcli/composite/composite.h"
#include "lib/socket/socket.h" #include "lib/socket/socket.h"
/* struct sock_connect_state {
this private structure is used during async connection handling struct composite_context *ctx;
*/ const char *host_name;
struct clisocket_connect { int num_ports;
int port_num; uint16_t *ports;
int *iports; struct smbcli_socket *result;
struct smbcli_socket *sock;
const char *dest_host_addr;
const char *dest_hostname;
}; };
/*
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 smbcli_socket *sock;
sock = talloc_zero(mem_ctx, struct smbcli_socket);
if (!sock) {
return NULL;
}
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;
}
/* ensure we don't get SIGPIPE */
BlockSignals(True,SIGPIPE);
return sock;
}
static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock,
const char *hostaddr, int port,
struct composite_context *c);
/*
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,
uint16_t flags, void *private_data)
{
struct composite_context *c = talloc_get_type(private_data, struct composite_context);
struct clisocket_connect *conn = talloc_get_type(c->private_data, 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_hostname);
c->state = COMPOSITE_STATE_DONE;
if (c->async.fn) {
c->async.fn(c);
}
return;
}
/* 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_addr,
conn->iports[i], c);
if (NT_STATUS_IS_OK(c->status) ||
NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
return;
}
}
c->state = COMPOSITE_STATE_ERROR;
if (c->async.fn) {
c->async.fn(c);
}
}
/*
try to connect to the given address/port
*/
static NTSTATUS smbcli_sock_connect_one(struct smbcli_socket *sock,
const char *hostaddr, int port,
struct composite_context *c)
{
NTSTATUS status;
if (sock->sock) {
talloc_free(sock->sock);
sock->sock = NULL;
}
talloc_free(sock->event.fde);
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 */
sock->event.fde = event_add_fd(sock->event.ctx, sock, socket_get_fd(sock->sock),
EVENT_FD_WRITE, smbcli_sock_connect_handler, c);
sock->port = port;
set_blocking(socket_get_fd(sock->sock), False);
return socket_connect(sock->sock, NULL, 0, hostaddr, port, 0);
}
/* /*
connect a smbcli_socket context to an IP/port pair connect a smbcli_socket context to an IP/port pair
if port is 0 then choose 445 then 139 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, static void smbcli_sock_connect_recv_conn(struct composite_context *ctx);
const char *host_name)
struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx,
const char *host_addr,
int port,
const char *host_name,
struct event_context *event_ctx)
{ {
struct composite_context *c; struct composite_context *result, *ctx;
struct clisocket_connect *conn; struct sock_connect_state *state;
int i;
c = talloc_zero(sock, struct composite_context); result = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL; if (result == NULL) goto failed;
result->state = COMPOSITE_STATE_IN_PROGRESS;
c->event_ctx = sock->event.ctx; if (event_ctx != NULL) {
result->event_ctx = talloc_reference(result, event_ctx);
} else {
result->event_ctx = event_context_init(result);
}
conn = talloc(c, struct clisocket_connect); if (result->event_ctx == NULL) goto failed;
if (conn == NULL) goto failed;
conn->sock = sock; 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;
/* work out what ports we will try */
if (port == 0) { if (port == 0) {
const char **ports = lp_smb_ports(); const char **ports = lp_smb_ports();
int i;
for (i=0;ports[i];i++) /* noop */ ; for (i=0;ports[i];i++) /* noop */ ;
conn->iports = talloc_array(c, int, i+1); if (i == 0) {
if (conn->iports == NULL) goto failed; DEBUG(3, ("no smb ports defined\n"));
goto failed;
}
state->num_ports = i;
state->ports = talloc_array(state, uint16_t, i);
if (state->ports == NULL) goto failed;
for (i=0;ports[i];i++) { for (i=0;ports[i];i++) {
conn->iports[i] = atoi(ports[i]); state->ports[i] = atoi(ports[i]);
} }
conn->iports[i] = 0;
} else { } else {
conn->iports = talloc_array(c, int, 2); state->ports = talloc_array(state, uint16_t, 1);
if (conn->iports == NULL) goto failed; if (state->ports == NULL) goto failed;
conn->iports[0] = port; state->num_ports = 1;
conn->iports[1] = 0; state->ports[0] = port;
} }
conn->dest_host_addr = talloc_strdup(c, host_addr); ctx = socket_connect_multi_send(state, host_addr,
if (conn->dest_host_addr == NULL) goto failed; state->num_ports, state->ports,
state->ctx->event_ctx);
if (ctx == NULL) goto failed;
ctx->async.fn = smbcli_sock_connect_recv_conn;
ctx->async.private_data = state;
return result;
conn->dest_hostname = talloc_strdup(c, host_name);
if (conn->dest_hostname == NULL) goto failed;
c->private_data = conn;
c->state = COMPOSITE_STATE_IN_PROGRESS;
/* 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_addr,
conn->iports[i], c);
if (NT_STATUS_IS_OK(c->status) ||
NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
return c;
}
}
c->state = COMPOSITE_STATE_ERROR;
return c;
failed: failed:
talloc_free(c); talloc_free(result);
return NULL; return NULL;
} }
static void smbcli_sock_connect_recv_conn(struct composite_context *ctx)
{
struct sock_connect_state *state =
talloc_get_type(ctx->async.private_data,
struct sock_connect_state);
struct socket_context *sock;
uint16_t port;
state->ctx->status = socket_connect_multi_recv(ctx, state, &sock,
&port);
if (!composite_is_ok(state->ctx)) return;
state->ctx->status =
socket_set_option(sock, lp_socket_options(), NULL);
if (!composite_is_ok(state->ctx)) return;
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);
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);
}
/* /*
finish a smbcli_sock_connect_send() operation 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; NTSTATUS status = composite_wait(c);
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); talloc_free(c);
return status; return status;
} }
@@ -237,17 +161,16 @@ NTSTATUS smbcli_sock_connect_recv(struct composite_context *c)
sync version of the function 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_name) const char *host_addr, int port,
const char *host_name,
struct event_context *event_ctx,
struct smbcli_socket **result)
{ {
struct composite_context *c; struct composite_context *c =
smbcli_sock_connect_send(mem_ctx, host_addr, port, host_name,
c = smbcli_sock_connect_send(sock, host_addr, port, host_name); event_ctx);
if (c == NULL) { return smbcli_sock_connect_recv(c, mem_ctx, result);
return NT_STATUS_NO_MEMORY;
}
return smbcli_sock_connect_recv(c);
} }
@@ -306,15 +229,39 @@ NTSTATUS smbcli_sock_read(struct smbcli_socket *sock, uint8_t *data,
/**************************************************************************** /****************************************************************************
resolve a hostname and connect 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, int port,
TALLOC_CTX *mem_ctx,
struct event_context *event_ctx)
{ {
int name_type = NBT_NAME_SERVER; int name_type = NBT_NAME_SERVER;
const char *address; const char *address;
NTSTATUS status; NTSTATUS status;
struct nbt_name nbt_name; struct nbt_name nbt_name;
char *name, *p; char *name, *p;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
struct smbcli_socket *result;
name = talloc_strdup(sock, host); 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;
}
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 */ /* allow hostnames of the form NAME#xx and do a netbios lookup */
if ((p = strchr(name, '#'))) { if ((p = strchr(name, '#'))) {
@@ -322,16 +269,25 @@ BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, in
*p = 0; *p = 0;
} }
nbt_name.name = name; make_nbt_name(&nbt_name, host, name_type);
nbt_name.type = name_type;
nbt_name.scope = NULL;
status = resolve_name(&nbt_name, sock, &address, sock->event.ctx); status = resolve_name(&nbt_name, tmp_ctx, &address, event_ctx);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
talloc_free(tmp_ctx);
return False; return False;
} }
status = smbcli_sock_connect(sock, address, port, name); status = smbcli_sock_connect(mem_ctx, address, port, name, event_ctx,
&result);
return NT_STATUS_IS_OK(status); if (!NT_STATUS_IS_OK(status)) {
DEBUG(9, ("smbcli_sock_connect failed: %s\n",
nt_errstr(status)));
talloc_free(tmp_ctx);
return NULL;
}
talloc_free(tmp_ctx);
return result;
} }

View File

@@ -41,7 +41,6 @@ struct connect_state {
struct smbcli_socket *sock; struct smbcli_socket *sock;
struct smbcli_transport *transport; struct smbcli_transport *transport;
struct smbcli_session *session; struct smbcli_session *session;
struct smb_composite_connectmulti *conn;
struct smb_composite_connect *io; struct smb_composite_connect *io;
union smb_tcon *io_tcon; union smb_tcon *io_tcon;
struct smb_composite_sesssetup *io_setup; struct smb_composite_sesssetup *io_setup;
@@ -73,7 +72,7 @@ static NTSTATUS connect_send_negprot(struct composite_context *c,
/* /*
a tree connect request has competed a tree connect request has completed
*/ */
static NTSTATUS connect_tcon(struct composite_context *c, static NTSTATUS connect_tcon(struct composite_context *c,
struct smb_composite_connect *io) struct smb_composite_connect *io)
@@ -232,7 +231,7 @@ static NTSTATUS connect_session_setup(struct composite_context *c,
} }
/* /*
a negprot request has competed a negprot request has completed
*/ */
static NTSTATUS connect_negprot(struct composite_context *c, static NTSTATUS connect_negprot(struct composite_context *c,
struct smb_composite_connect *io) struct smb_composite_connect *io)
@@ -271,7 +270,7 @@ static NTSTATUS connect_negprot(struct composite_context *c,
/* /*
a session request operation has competed a session request operation has completed
*/ */
static NTSTATUS connect_session_request(struct composite_context *c, static NTSTATUS connect_session_request(struct composite_context *c,
struct smb_composite_connect *io) struct smb_composite_connect *io)
@@ -287,7 +286,7 @@ static NTSTATUS connect_session_request(struct composite_context *c,
} }
/* /*
a socket connection operation has competed a socket connection operation has completed
*/ */
static NTSTATUS connect_socket(struct composite_context *c, static NTSTATUS connect_socket(struct composite_context *c,
struct smb_composite_connect *io) struct smb_composite_connect *io)
@@ -296,11 +295,9 @@ static NTSTATUS connect_socket(struct composite_context *c,
NTSTATUS status; NTSTATUS status;
struct nbt_name calling, called; struct nbt_name calling, called;
status = smb_composite_connectmulti_recv(state->creq, state); status = smbcli_sock_connect_recv(state->creq, state, &state->sock);
NT_STATUS_NOT_OK_RETURN(status); NT_STATUS_NOT_OK_RETURN(status);
state->sock = state->conn->out.socket;
/* the socket is up - we can initialise the smbcli transport layer */ /* the socket is up - we can initialise the smbcli transport layer */
state->transport = smbcli_transport_init(state->sock, state, True); state->transport = smbcli_transport_init(state->sock, state, True);
NT_STATUS_HAVE_NO_MEMORY(state->transport); NT_STATUS_HAVE_NO_MEMORY(state->transport);
@@ -339,37 +336,12 @@ static NTSTATUS connect_resolve(struct composite_context *c,
struct connect_state *state = talloc_get_type(c->private_data, struct connect_state); struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
NTSTATUS status; NTSTATUS status;
const char *address; const char *address;
struct smb_composite_connectmulti *conn;
status = resolve_name_recv(state->creq, state, &address); status = resolve_name_recv(state->creq, state, &address);
NT_STATUS_NOT_OK_RETURN(status); NT_STATUS_NOT_OK_RETURN(status);
conn = talloc(state, struct smb_composite_connectmulti); state->creq = smbcli_sock_connect_send(state, address, io->in.port,
NT_STATUS_HAVE_NO_MEMORY(conn); io->in.dest_host, c->event_ctx);
state->conn = conn;
conn->in.num_dests = 1;
conn->in.addresses = talloc_array(state->conn, const char *, 1);
NT_STATUS_HAVE_NO_MEMORY(conn->in.addresses);
conn->in.addresses[0] = address;
conn->in.hostnames = talloc_array(state->conn, const char *, 1);
NT_STATUS_HAVE_NO_MEMORY(conn->in.hostnames);
if (state->io->in.called_name != NULL) {
conn->in.hostnames[0] = state->io->in.called_name;
} else {
conn->in.hostnames[0] = state->io->in.dest_host;
}
conn->in.ports = NULL;
if (state->io->in.port != 0) {
conn->in.ports = talloc_array(state->conn, int, 1);
NT_STATUS_HAVE_NO_MEMORY(conn->in.ports);
conn->in.ports[0] = state->io->in.port;
}
state->creq = smb_composite_connectmulti_send(conn, state,
c->event_ctx);
NT_STATUS_HAVE_NO_MEMORY(state->creq); NT_STATUS_HAVE_NO_MEMORY(state->creq);
state->stage = CONNECT_SOCKET; state->stage = CONNECT_SOCKET;

View File

@@ -1,188 +0,0 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Volker Lendecke
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
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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.
*/
/*
a composite API to fire connect calls to multiple targets, picking the first
one.
*/
#include "includes.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/composite/composite.h"
#include "libcli/smb_composite/smb_composite.h"
struct connectmulti_state {
struct smb_composite_connectmulti *io;
struct composite_context *creq;
struct smbcli_socket *result;
int num_socks, socks_left;
struct smbcli_socket **socks;
struct composite_context **creqs;
};
static void connect_receive(struct composite_context *c)
{
struct connectmulti_state *state =
talloc_get_type(c->async.private_data,
struct connectmulti_state);
int i;
for (i=0; i<state->num_socks; i++) {
if (state->creqs[i] == c) {
break;
}
}
if (i == state->num_socks) {
c->status = NT_STATUS_INTERNAL_ERROR;
c->state = COMPOSITE_STATE_ERROR;
if (state->creq->async.fn != NULL) {
state->creq->async.fn(state->creq);
}
return;
}
state->creq->status = smbcli_sock_connect_recv(c);
if (!NT_STATUS_IS_OK(state->creq->status)) {
talloc_free(state->socks[i]);
state->socks[i] = NULL;
state->creqs[i] = NULL;
state->socks_left -= 1;
if (state->socks_left == 0) {
state->creq->state = COMPOSITE_STATE_ERROR;
if (state->creq->async.fn != NULL) {
state->creq->async.fn(state->creq);
}
}
return;
}
state->result = talloc_steal(state, state->socks[i]);
talloc_free(state->socks);
state->creq->state = COMPOSITE_STATE_DONE;
if (state->creq->async.fn != NULL) {
state->creq->async.fn(state->creq);
}
}
struct composite_context *smb_composite_connectmulti_send(struct smb_composite_connectmulti *io,
TALLOC_CTX *mem_ctx,
struct event_context *event_ctx)
{
struct composite_context *c;
struct connectmulti_state *state;
int num_socks = io->in.num_dests;
const char **hostnames = io->in.hostnames;
const char **addresses = io->in.addresses;
int *ports = io->in.ports;
int i;
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) goto failed;
state = talloc(c, struct connectmulti_state);
if (state == NULL) goto failed;
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->event_ctx = talloc_reference(c, event_ctx);
c->private_data = state;
if (ports == NULL) {
int j, nports;
const char **smb_ports = lp_smb_ports();
for (nports=0; smb_ports[nports]; nports++) /* noop */;
num_socks *= nports;
hostnames = talloc_array(state, const char *, num_socks);
if (hostnames == NULL) goto failed;
addresses = talloc_array(state, const char *, num_socks);
if (addresses == NULL) goto failed;
ports = talloc_array(state, int, num_socks);
if (ports == NULL) goto failed;
for (i=0; i<io->in.num_dests; i++) {
for (j=0; j<nports; j++) {
hostnames[i*nports+j] = io->in.hostnames[i];
addresses[i*nports+j] = io->in.addresses[i];
ports[i*nports+j] = atoi(smb_ports[j]);
}
}
}
state->io = io;
state->creq = c;
state->num_socks = num_socks;
state->socks_left = num_socks;
state->socks = talloc_array(state, struct smbcli_socket *, num_socks);
state->creqs = talloc_array(state, struct composite_context *,
num_socks);
if ((state->socks == NULL) || (state->creqs == NULL)) goto failed;
for (i=0; i<num_socks; i++) {
state->socks[i] = smbcli_sock_init(state->socks, event_ctx);
if (state->socks[i] == NULL) goto failed;
/* If the event_ctx we got given is NULL, the first socket
* creates one and all others need to refer to it. */
event_ctx = state->socks[i]->event.ctx;
state->creqs[i] = smbcli_sock_connect_send(state->socks[i],
addresses[i],
ports[i],
hostnames[i]);
if (state->creqs[i] == NULL) goto failed;
state->creqs[i]->async.fn = connect_receive;
state->creqs[i]->async.private_data = state;
}
return c;
failed:
talloc_free(c);
return NULL;
}
NTSTATUS smb_composite_connectmulti_recv(struct composite_context *c,
TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
status = composite_wait(c);
if (NT_STATUS_IS_OK(status)) {
struct connectmulti_state *state =
talloc_get_type(c->private_data,
struct connectmulti_state);
state->io->out.socket = talloc_steal(mem_ctx, state->result);
}
talloc_free(c);
return status;
}
NTSTATUS smb_composite_connectmulti(struct smb_composite_connectmulti *io,
TALLOC_CTX *mem_ctx,
struct event_context *ev)
{
struct composite_context *c =
smb_composite_connectmulti_send(io, mem_ctx, ev);
return smb_composite_connectmulti_recv(c, mem_ctx);
}