docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source4 / lib / socket / connect_multi.c
index 98b4d405b321a18d89bad974473dc5db671e1e60..b29fffb33b4009a05898b17417d1856d46cb5af4 100644 (file)
   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;
 
-       struct resolve_context *resolve_ctx;
-
        struct socket_context *sock;
        uint16_t result_port;
 
        int num_connects_sent, num_connects_recv;
+
+       struct socket_connect_multi_ex *ex;
 };
 
 /*
@@ -55,27 +56,32 @@ struct connect_one_state {
 };
 
 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(
+_PUBLIC_ struct composite_context *socket_connect_multi_ex_send(
                                                    TALLOC_CTX *mem_ctx,
-                                                   const char *server_address,
+                                                   const char *server_name,
                                                    int num_server_ports,
                                                    uint16_t *server_ports,
                                                    struct resolve_context *resolve_ctx,
-                                                   struct event_context *event_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;
@@ -85,11 +91,7 @@ _PUBLIC_ struct composite_context *socket_connect_multi_send(
        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->resolve_ctx = talloc_reference(multi, resolve_ctx);
        multi->ports = talloc_array(multi, uint16_t, multi->num_ports);
        if (composite_nomem(multi->ports, result)) goto failed;
 
@@ -97,30 +99,23 @@ _PUBLIC_ struct composite_context *socket_connect_multi_send(
                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(resolve_ctx, &name, result->event_ctx);
-               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;
@@ -137,44 +132,54 @@ static void connect_multi_next_socket(struct composite_context *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, multi->resolve_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);
        }
 }
@@ -182,8 +187,8 @@ static void connect_multi_next_socket(struct composite_context *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);
@@ -200,12 +205,15 @@ static void continue_resolve_name(struct composite_context *creq)
                                                           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);
 }
@@ -222,10 +230,24 @@ static void continue_one(struct composite_context *creq)
        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;
@@ -233,8 +255,45 @@ static void continue_one(struct composite_context *creq)
 
        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;
+       }
+
+       /* 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_address * multi->num_ports)) {
                result->status = status;
                composite_done(result);
                return;
@@ -247,7 +306,7 @@ static void continue_one(struct composite_context *creq)
 /*
   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)
@@ -264,18 +323,70 @@ _PUBLIC_ NTSTATUS socket_connect_multi_recv(struct composite_context *ctx,
        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 resolve_context *resolve_ctx,
-                             struct event_context *event_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,
-                                         resolve_ctx,
-                                         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);
 }