.... source3/lib/util_sock.c async_connect without retry
[metze/samba/wip.git] / source3 / lib / util_sock.c
index c4de85dd130beb94c04d9642d79f8b74f6cfdd75..349975a4660183a6eafff621413f52ecfd304ab3 100644 (file)
@@ -28,8 +28,8 @@
 #include "../lib/util/tevent_unix.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "../lib/tsocket/tsocket.h"
-#include "lib/sys_rw.h"
-#include "lib/sys_rw_data.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/sys_rw_data.h"
 
 const char *client_addr(int fd, char *addr, size_t addrlen)
 {
@@ -418,16 +418,34 @@ struct open_socket_out_state {
        socklen_t salen;
        uint16_t port;
        int wait_usec;
+       struct tevent_req *connect_subreq;
 };
 
 static void open_socket_out_connected(struct tevent_req *subreq);
 
-static int open_socket_out_state_destructor(struct open_socket_out_state *s)
+static void open_socket_out_cleanup(struct tevent_req *req,
+                                   enum tevent_req_state req_state)
 {
-       if (s->fd != -1) {
-               close(s->fd);
+       struct open_socket_out_state *state =
+               tevent_req_data(req, struct open_socket_out_state);
+
+       /*
+        * Make sure that the async_connect_send subreq has a chance to reset
+        * fcntl before the socket goes away.
+        */
+       TALLOC_FREE(state->connect_subreq);
+
+       if (req_state == TEVENT_REQ_DONE) {
+               /*
+                * we keep the socket open for the caller to use
+                */
+               return;
+       }
+
+       if (state->fd != -1) {
+               close(state->fd);
+               state->fd = -1;
        }
-       return 0;
 }
 
 /****************************************************************************
@@ -441,7 +459,7 @@ struct tevent_req *open_socket_out_send(TALLOC_CTX *mem_ctx,
                                        int timeout)
 {
        char addr[INET6_ADDRSTRLEN];
-       struct tevent_req *result, *subreq;
+       struct tevent_req *result;
        struct open_socket_out_state *state;
        NTSTATUS status;
 
@@ -453,15 +471,17 @@ struct tevent_req *open_socket_out_send(TALLOC_CTX *mem_ctx,
        state->ev = ev;
        state->ss = *pss;
        state->port = port;
-       state->wait_usec = 10000;
+       state->wait_usec = 10000000;
        state->salen = -1;
+       timeout *=100;
 
        state->fd = socket(state->ss.ss_family, SOCK_STREAM, 0);
        if (state->fd == -1) {
                status = map_nt_error_from_unix(errno);
                goto post_status;
        }
-       talloc_set_destructor(state, open_socket_out_state_destructor);
+
+       tevent_req_set_cleanup_fn(result, open_socket_out_cleanup);
 
        if (!tevent_req_set_endtime(
                    result, ev, timeval_current_ofs_msec(timeout))) {
@@ -495,16 +515,17 @@ struct tevent_req *open_socket_out_send(TALLOC_CTX *mem_ctx,
        print_sockaddr(addr, sizeof(addr), &state->ss);
        DEBUG(3,("Connecting to %s at port %u\n", addr, (unsigned int)port));
 
-       subreq = async_connect_send(state, state->ev, state->fd,
-                                   (struct sockaddr *)&state->ss,
-                                   state->salen, NULL, NULL, NULL);
-       if ((subreq == NULL)
+       state->connect_subreq = async_connect_send(
+               state, state->ev, state->fd, (struct sockaddr *)&state->ss,
+               state->salen, NULL, NULL, NULL);
+       if ((state->connect_subreq == NULL)
            || !tevent_req_set_endtime(
-                   subreq, state->ev,
+                   state->connect_subreq, state->ev,
                    timeval_current_ofs(0, state->wait_usec))) {
                goto fail;
        }
-       tevent_req_set_callback(subreq, open_socket_out_connected, result);
+       tevent_req_set_callback(state->connect_subreq,
+                               open_socket_out_connected, result);
        return result;
 
  post_status:
@@ -526,6 +547,7 @@ static void open_socket_out_connected(struct tevent_req *subreq)
 
        ret = async_connect_recv(subreq, &sys_errno);
        TALLOC_FREE(subreq);
+       state->connect_subreq = NULL;
        if (ret == 0) {
                tevent_req_done(req);
                return;
@@ -556,9 +578,9 @@ static void open_socket_out_connected(struct tevent_req *subreq)
                if (!tevent_req_set_endtime(
                            subreq, state->ev,
                            timeval_current_ofs_usec(state->wait_usec))) {
-                       tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
                        return;
                }
+               state->connect_subreq = subreq;
                tevent_req_set_callback(subreq, open_socket_out_connected, req);
                return;
        }
@@ -581,10 +603,12 @@ NTSTATUS open_socket_out_recv(struct tevent_req *req, int *pfd)
        NTSTATUS status;
 
        if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
                return status;
        }
        *pfd = state->fd;
        state->fd = -1;
+       tevent_req_received(req);
        return NT_STATUS_OK;
 }
 
@@ -1046,7 +1070,7 @@ int get_remote_hostname(const struct tsocket_address *remote_address,
        lookup_nc(&nc);
 
        if (nc.name == NULL) {
-               *name = talloc_strdup(mem_ctx, "UNKOWN");
+               *name = talloc_strdup(mem_ctx, "UNKNOWN");
        } else {
                *name = talloc_strdup(mem_ctx, nc.name);
        }
@@ -1072,6 +1096,7 @@ int create_pipe_sock(const char *socket_dir,
        int sock = -1;
        mode_t old_umask;
        char *path = NULL;
+       size_t path_len;
 
        old_umask = umask(0);
 
@@ -1098,7 +1123,17 @@ int create_pipe_sock(const char *socket_dir,
        unlink(path);
        memset(&sunaddr, 0, sizeof(sunaddr));
        sunaddr.sun_family = AF_UNIX;
-       strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
+
+       path_len = strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
+       if (path_len > sizeof(sunaddr.sun_path)) {
+               DBG_ERR("Refusing to attempt to create pipe socket "
+                       "%s.  Path is longer than permitted for a "
+                       "unix domain socket.  It would truncate to "
+                       "%s\n",
+                       path,
+                       sunaddr.sun_path);
+               goto out_close;
+       }
 
        if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
                DEBUG(0, ("bind failed on pipe socket %s: %s\n", path,
@@ -1322,88 +1357,6 @@ bool is_myname_or_ipaddr(const char *s)
        return false;
 }
 
-struct getaddrinfo_state {
-       const char *node;
-       const char *service;
-       const struct addrinfo *hints;
-       struct addrinfo *res;
-       int ret;
-};
-
-static void getaddrinfo_do(void *private_data);
-static void getaddrinfo_done(struct tevent_req *subreq);
-
-struct tevent_req *getaddrinfo_send(TALLOC_CTX *mem_ctx,
-                                   struct tevent_context *ev,
-                                   struct fncall_context *ctx,
-                                   const char *node,
-                                   const char *service,
-                                   const struct addrinfo *hints)
-{
-       struct tevent_req *req, *subreq;
-       struct getaddrinfo_state *state;
-
-       req = tevent_req_create(mem_ctx, &state, struct getaddrinfo_state);
-       if (req == NULL) {
-               return NULL;
-       }
-
-       state->node = node;
-       state->service = service;
-       state->hints = hints;
-
-       subreq = fncall_send(state, ev, ctx, getaddrinfo_do, state);
-       if (tevent_req_nomem(subreq, req)) {
-               return tevent_req_post(req, ev);
-       }
-       tevent_req_set_callback(subreq, getaddrinfo_done, req);
-       return req;
-}
-
-static void getaddrinfo_do(void *private_data)
-{
-       struct getaddrinfo_state *state =
-               talloc_get_type_abort(private_data, struct getaddrinfo_state);
-
-       state->ret = getaddrinfo(state->node, state->service, state->hints,
-                                &state->res);
-}
-
-static void getaddrinfo_done(struct tevent_req *subreq)
-{
-       struct tevent_req *req = tevent_req_callback_data(
-               subreq, struct tevent_req);
-       int ret, err;
-
-       ret = fncall_recv(subreq, &err);
-       TALLOC_FREE(subreq);
-       if (ret == -1) {
-               tevent_req_error(req, err);
-               return;
-       }
-       tevent_req_done(req);
-}
-
-int getaddrinfo_recv(struct tevent_req *req, struct addrinfo **res)
-{
-       struct getaddrinfo_state *state = tevent_req_data(
-               req, struct getaddrinfo_state);
-       int err;
-
-       if (tevent_req_is_unix_error(req, &err)) {
-               switch(err) {
-               case ENOMEM:
-                       return EAI_MEMORY;
-               default:
-                       return EAI_FAIL;
-               }
-       }
-       if (state->ret == 0) {
-               *res = state->res;
-       }
-       return state->ret;
-}
-
 int poll_one_fd(int fd, int events, int timeout, int *revents)
 {
        struct pollfd pfd;