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"
overall state
*/
struct connect_multi_state {
- const char *server_address;
+ struct socket_address **server_address;
+ unsigned num_address, current_address, current_port;
int num_ports;
uint16_t *ports;
uint16_t result_port;
int num_connects_sent, num_connects_recv;
+
+ struct socket_connect_multi_ex *ex;
};
/*
};
static void continue_resolve_name(struct composite_context *creq);
-static void connect_multi_timer(struct event_context *ev,
- struct timed_event *te,
+static void connect_multi_timer(struct tevent_context *ev,
+ struct tevent_timer *te,
struct timeval tv, void *p);
static void connect_multi_next_socket(struct composite_context *result);
static void continue_one(struct composite_context *creq);
+static void continue_one_ex(struct tevent_req *subreq);
/*
setup an async socket_connect, with multiple ports
*/
-_PUBLIC_ struct composite_context *socket_connect_multi_send(TALLOC_CTX *mem_ctx,
- const char *server_address,
+_PUBLIC_ struct composite_context *socket_connect_multi_ex_send(
+ TALLOC_CTX *mem_ctx,
+ const char *server_name,
int num_server_ports,
uint16_t *server_ports,
- struct event_context *event_ctx)
+ struct resolve_context *resolve_ctx,
+ struct tevent_context *event_ctx,
+ struct socket_connect_multi_ex *ex)
{
struct composite_context *result;
struct connect_multi_state *multi;
int i;
+ struct nbt_name name;
+ struct composite_context *creq;
+
result = talloc_zero(mem_ctx, struct composite_context);
if (result == NULL) return NULL;
result->state = COMPOSITE_STATE_IN_PROGRESS;
if (composite_nomem(multi, result)) goto failed;
result->private_data = multi;
- multi->server_address = talloc_strdup(multi, server_address);
- if (composite_nomem(multi->server_address, result)) goto failed;
-
multi->num_ports = num_server_ports;
multi->ports = talloc_array(multi, uint16_t, multi->num_ports);
if (composite_nomem(multi->ports, result)) goto failed;
multi->ports[i] = server_ports[i];
}
- if (!is_ipaddress(server_address)) {
- /*
- we don't want to do the name resolution separately
+ multi->ex = ex;
+
+ /*
+ we don't want to do the name resolution separately
for each port, so start it now, then only start on
the real sockets once we have an IP
- */
- struct nbt_name name;
- struct composite_context *creq;
- make_nbt_name_client(&name, server_address);
- creq = resolve_name_send(&name, result->event_ctx,
- lp_name_resolve_order());
- if (composite_nomem(creq, result)) goto failed;
- composite_continue(result, creq, continue_resolve_name, result);
- return result;
- }
+ */
+ make_nbt_name_server(&name, server_name);
- /* now we've setup the state we can process the first socket */
- connect_multi_next_socket(result);
+ creq = resolve_name_all_send(resolve_ctx, multi, 0, multi->ports[0], &name, result->event_ctx);
+ if (composite_nomem(creq, result)) goto failed;
- if (!NT_STATUS_IS_OK(result->status)) {
- goto failed;
- }
+ composite_continue(result, creq, continue_resolve_name, result);
return result;
+
failed:
composite_error(result, result->status);
return result;
struct composite_context *creq;
int next = multi->num_connects_sent;
- if (next == multi->num_ports) {
+ if (next == multi->num_address * multi->num_ports) {
/* don't do anything, just wait for the existing ones to finish */
return;
}
+ if (multi->current_address == multi->num_address) {
+ multi->current_address = 0;
+ multi->current_port += 1;
+ }
multi->num_connects_sent += 1;
+ if (multi->server_address == NULL || multi->server_address[multi->current_address] == NULL) {
+ composite_error(result, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ return;
+ }
+
state = talloc(multi, struct connect_one_state);
if (composite_nomem(state, result)) return;
state->result = result;
- result->status = socket_create("ipv4", SOCKET_TYPE_STREAM, &state->sock, 0);
+ result->status = socket_create(
+ state, multi->server_address[multi->current_address]->family,
+ SOCKET_TYPE_STREAM, &state->sock, 0);
if (!composite_is_ok(result)) return;
- /* Form up the particular address we are interested in */
- state->addr = socket_address_from_strings(state, state->sock->backend_name,
- multi->server_address, multi->ports[next]);
+ state->addr = socket_address_copy(state, multi->server_address[multi->current_address]);
if (composite_nomem(state->addr, result)) return;
- talloc_steal(state, state->sock);
+ socket_address_set_port(state->addr, multi->ports[multi->current_port]);
creq = socket_connect_send(state->sock, NULL,
- state->addr, 0, result->event_ctx);
+ state->addr, 0,
+ result->event_ctx);
if (composite_nomem(creq, result)) return;
talloc_steal(state, creq);
+ multi->current_address++;
composite_continue(result, creq, continue_one, state);
- /* if there are more ports to go then setup a timer to fire when we have waited
+ /* if there are more ports / addresses to go then setup a timer to fire when we have waited
for a couple of milli-seconds, when that goes off we try the next port regardless
of whether this port has completed */
- if (multi->num_ports > multi->num_connects_sent) {
+ if (multi->num_ports * multi->num_address > multi->num_connects_sent) {
/* note that this timer is a child of the single
connect attempt state, so it will go away when this
request completes */
- event_add_timed(result->event_ctx, state,
- timeval_current_ofs(0, MULTI_PORT_DELAY),
+ tevent_add_timer(result->event_ctx, state,
+ timeval_current_ofs_usec(MULTI_PORT_DELAY),
connect_multi_timer, result);
}
}
/*
a timer has gone off telling us that we should try the next port
*/
-static void connect_multi_timer(struct event_context *ev,
- struct timed_event *te,
+static void connect_multi_timer(struct tevent_context *ev,
+ struct tevent_timer *te,
struct timeval tv, void *p)
{
struct composite_context *result = talloc_get_type(p, struct composite_context);
struct composite_context);
struct connect_multi_state *multi = talloc_get_type(result->private_data,
struct connect_multi_state);
- const char *addr;
+ struct socket_address **addr;
+ unsigned i;
- result->status = resolve_name_recv(creq, multi, &addr);
+ result->status = resolve_name_all_recv(creq, multi, &addr, NULL);
if (!composite_is_ok(result)) return;
- multi->server_address = addr;
+ for(i=0; addr[i]; i++);
+ multi->num_address = i;
+ multi->server_address = talloc_steal(multi, addr);
connect_multi_next_socket(result);
}
struct connect_multi_state *multi = talloc_get_type(result->private_data,
struct connect_multi_state);
NTSTATUS status;
- multi->num_connects_recv++;
status = socket_connect_recv(creq);
+ if (multi->ex) {
+ struct tevent_req *subreq;
+
+ subreq = multi->ex->establish_send(state,
+ result->event_ctx,
+ state->sock,
+ state->addr,
+ multi->ex->private_data);
+ if (composite_nomem(subreq, result)) return;
+ tevent_req_set_callback(subreq, continue_one_ex, state);
+ return;
+ }
+
+ multi->num_connects_recv++;
+
+ if (NT_STATUS_IS_OK(status)) {
+ multi->sock = talloc_steal(multi, state->sock);
+ multi->result_port = state->addr->port;
+ }
+
+ talloc_free(state);
+
+ if (NT_STATUS_IS_OK(status) ||
+ multi->num_connects_recv == (multi->num_address * multi->num_ports)) {
+ result->status = status;
+ composite_done(result);
+ return;
+ }
+
+ /* try the next port */
+ connect_multi_next_socket(result);
+}
+
+/*
+ one of our multi->ex->establish_send() calls hash finished. If it got a
+ connection or there are none left then we are done
+*/
+static void continue_one_ex(struct tevent_req *subreq)
+{
+ struct connect_one_state *state =
+ tevent_req_callback_data(subreq,
+ struct connect_one_state);
+ struct composite_context *result = state->result;
+ struct connect_multi_state *multi =
+ talloc_get_type_abort(result->private_data,
+ struct connect_multi_state);
+ NTSTATUS status;
+ multi->num_connects_recv++;
+
+ status = multi->ex->establish_recv(subreq);
+ TALLOC_FREE(subreq);
+
if (NT_STATUS_IS_OK(status)) {
multi->sock = talloc_steal(multi, state->sock);
multi->result_port = state->addr->port;
talloc_free(state);
- if (NT_STATUS_IS_OK(status) ||
- multi->num_connects_recv == multi->num_ports) {
+ if (NT_STATUS_IS_OK(status) ||
+ multi->num_connects_recv == (multi->num_address * multi->num_ports)) {
result->status = status;
composite_done(result);
return;
/*
async recv routine for socket_connect_multi()
*/
-_PUBLIC_ NTSTATUS socket_connect_multi_recv(struct composite_context *ctx,
+_PUBLIC_ NTSTATUS socket_connect_multi_ex_recv(struct composite_context *ctx,
TALLOC_CTX *mem_ctx,
struct socket_context **sock,
uint16_t *port)
return status;
}
+NTSTATUS socket_connect_multi_ex(TALLOC_CTX *mem_ctx,
+ const char *server_address,
+ int num_server_ports, uint16_t *server_ports,
+ struct resolve_context *resolve_ctx,
+ struct tevent_context *event_ctx,
+ struct socket_connect_multi_ex *ex,
+ struct socket_context **result,
+ uint16_t *result_port)
+{
+ struct composite_context *ctx =
+ socket_connect_multi_ex_send(mem_ctx, server_address,
+ num_server_ports, server_ports,
+ resolve_ctx,
+ event_ctx,
+ ex);
+ return socket_connect_multi_ex_recv(ctx, mem_ctx, result, result_port);
+}
+
+/*
+ setup an async socket_connect, with multiple ports
+*/
+_PUBLIC_ struct composite_context *socket_connect_multi_send(
+ TALLOC_CTX *mem_ctx,
+ const char *server_name,
+ int num_server_ports,
+ uint16_t *server_ports,
+ struct resolve_context *resolve_ctx,
+ struct tevent_context *event_ctx)
+{
+ return socket_connect_multi_ex_send(mem_ctx,
+ server_name,
+ num_server_ports,
+ server_ports,
+ resolve_ctx,
+ event_ctx,
+ NULL); /* ex */
+}
+
+/*
+ async recv routine for socket_connect_multi()
+ */
+_PUBLIC_ NTSTATUS socket_connect_multi_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ struct socket_context **sock,
+ uint16_t *port)
+{
+ return socket_connect_multi_ex_recv(ctx, mem_ctx, sock, 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 resolve_context *resolve_ctx,
+ struct tevent_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);
+ return socket_connect_multi_ex(mem_ctx,
+ server_address,
+ num_server_ports,
+ server_ports,
+ resolve_ctx,
+ event_ctx,
+ NULL, /* ex */
+ result,
+ result_port);
}