docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source4 / lib / socket / connect_multi.c
index 4ce5115e97dca1df5d0c2bc4635e8cc908529e65..b29fffb33b4009a05898b17417d1856d46cb5af4 100644 (file)
@@ -33,7 +33,8 @@
   overall state
 */
 struct connect_multi_state {
-       struct socket_address *server_address;
+       struct socket_address **server_address;
+       unsigned num_address, current_address, current_port;
        int num_ports;
        uint16_t *ports;
 
@@ -41,6 +42,8 @@ struct connect_multi_state {
        uint16_t result_port;
 
        int num_connects_sent, num_connects_recv;
+
+       struct socket_connect_multi_ex *ex;
 };
 
 /*
@@ -58,17 +61,19 @@ static void connect_multi_timer(struct tevent_context *ev,
                                    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_name,
                                                    int num_server_ports,
                                                    uint16_t *server_ports,
                                                    struct resolve_context *resolve_ctx,
-                                                   struct tevent_context *event_ctx)
+                                                   struct tevent_context *event_ctx,
+                                                   struct socket_connect_multi_ex *ex)
 {
        struct composite_context *result;
        struct connect_multi_state *multi;
@@ -94,6 +99,8 @@ _PUBLIC_ struct composite_context *socket_connect_multi_send(
                multi->ports[i] = server_ports[i];
        }
 
+       multi->ex = ex;
+
        /*  
            we don't want to do the name resolution separately
                    for each port, so start it now, then only start on
@@ -125,26 +132,35 @@ 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(multi->server_address->family, 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;
 
-       state->addr = socket_address_copy(state, multi->server_address);
+       state->addr = socket_address_copy(state, multi->server_address[multi->current_address]);
        if (composite_nomem(state->addr, result)) return;
 
-       socket_address_set_port(state->addr, multi->ports[next]);
-
-       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,
@@ -152,16 +168,17 @@ static void connect_multi_next_socket(struct composite_context *result)
        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,
+               tevent_add_timer(result->event_ctx, state,
                                timeval_current_ofs_usec(MULTI_PORT_DELAY),
                                connect_multi_timer, result);
        }
@@ -189,12 +206,14 @@ static void continue_resolve_name(struct composite_context *creq)
        struct connect_multi_state *multi = talloc_get_type(result->private_data, 
                                                            struct connect_multi_state);
        struct socket_address **addr;
+       unsigned i;
 
        result->status = resolve_name_all_recv(creq, multi, &addr, NULL);
        if (!composite_is_ok(result)) return;
 
-       /* Let's just go for the first for now */
-       multi->server_address = addr[0];
+       for(i=0; addr[i]; i++);
+       multi->num_address = i;
+       multi->server_address = talloc_steal(multi, addr);
 
        connect_multi_next_socket(result);
 }
@@ -211,10 +230,61 @@ 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;
+       }
+
+       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;
@@ -222,8 +292,8 @@ 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;
@@ -236,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)
@@ -253,6 +323,55 @@ _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,
@@ -261,10 +380,13 @@ NTSTATUS socket_connect_multi(TALLOC_CTX *mem_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);
 }