See ticket #2968.

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York
From dcaae5431617312b69d175274c8b29c430ec6b04 Mon Sep 17 00:00:00 2001
From: Simo Sorce <s...@redhat.com>
Date: Wed, 2 Mar 2016 14:33:38 -0500
Subject: [PATCH 1/3] Util: Move socket setup in a common utility file

Other components may need to connect sockets, the code here is generic enough
that with minimal modifications can be used for non-ldap connections too.

So create a sss_sockets.c/h utility file with all the non-ldap specific socket
setup functions and make them available for other uses.

Resolves:
https://fedorahosted.org/sssd/ticket/2968
---
 Makefile.am            |   4 +
 src/util/sss_ldap.c    | 258 ++---------------------------------
 src/util/sss_sockets.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/sss_sockets.h |  39 ++++++
 4 files changed, 412 insertions(+), 245 deletions(-)
 create mode 100644 src/util/sss_sockets.c
 create mode 100644 src/util/sss_sockets.h

diff --git a/Makefile.am b/Makefile.am
index 4e4f38a5eaf5bfa2cfafa88b9b32848e6c27131b..587595f1ba341403e6a1699fe314d036bd49e234 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1663,6 +1663,7 @@ ipa_ldap_opt_tests_SOURCES = \
     src/providers/ad/ad_opts.c \
     src/providers/ipa/ipa_opts.c \
     src/providers/krb5/krb5_opts.c \
+    src/util/sss_sockets.c \
     src/util/sss_ldap.c \
     src/tests/ipa_ldap_opt-tests.c
 ipa_ldap_opt_tests_CFLAGS = \
@@ -1877,6 +1878,7 @@ TEST_MOCK_RESP_OBJ = \
      src/responder/common/responder_cache_req.c
 
 TEST_MOCK_PROVIDER_OBJ = \
+     src/util/sss_sockets.c \
      src/util/sss_ldap.c \
      src/providers/data_provider_opts.c \
      src/providers/ldap/ldap_opts.c \
@@ -2264,6 +2266,7 @@ sdap_tests_SOURCES = \
     src/providers/ldap/sdap_range.c \
     src/providers/ldap/ldap_opts.c \
     src/providers/ipa/ipa_opts.c \
+    src/util/sss_sockets.c \
     src/util/sss_ldap.c \
     src/tests/cmocka/test_sdap.c \
     $(NULL)
@@ -2879,6 +2882,7 @@ libsss_ldap_common_la_SOURCES = \
     src/providers/ldap/sdap.c \
     src/providers/ipa/ipa_dn.c \
     src/util/user_info_msg.c \
+    src/util/sss_sockets.c \
     src/util/sss_ldap.c \
     $(NULL)
 libsss_ldap_common_la_CFLAGS = \
diff --git a/src/util/sss_ldap.c b/src/util/sss_ldap.c
index c440d5445133c8b31f662fc69b35e2296c3f1702..7fdaadb5cebf5d3e7fe7f8fb1780f0db3dbcae4a 100644
--- a/src/util/sss_ldap.c
+++ b/src/util/sss_ldap.c
@@ -17,18 +17,13 @@
     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
 
 #include "config.h"
-
-#include "providers/ldap/sdap.h"
-#include "util/sss_ldap.h"
 #include "util/util.h"
+#include "util/sss_sockets.h"
+#include "util/sss_ldap.h"
+
+#include "providers/ldap/sdap.h"
 
 const char* sss_ldap_err2string(int err)
 {
@@ -103,183 +98,6 @@ int sss_ldap_control_create(const char *oid, int iscritical,
 }
 
 #ifdef HAVE_LDAP_INIT_FD
-struct sdap_async_sys_connect_state {
-    long old_flags;
-    struct tevent_fd *fde;
-    int fd;
-    socklen_t addr_len;
-    struct sockaddr_storage addr;
-};
-
-static void sdap_async_sys_connect_done(struct tevent_context *ev,
-                                        struct tevent_fd *fde, uint16_t flags,
-                                        void *priv);
-
-static struct tevent_req *sdap_async_sys_connect_send(TALLOC_CTX *mem_ctx,
-                                                    struct tevent_context *ev,
-                                                    int fd,
-                                                    const struct sockaddr *addr,
-                                                    socklen_t addr_len)
-{
-    struct tevent_req *req;
-    struct sdap_async_sys_connect_state *state;
-    long flags;
-    int ret;
-    int fret;
-
-    flags = fcntl(fd, F_GETFL, 0);
-    if (flags == -1) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_GETFL failed.\n");
-        return NULL;
-    }
-
-    req = tevent_req_create(mem_ctx, &state,
-                            struct sdap_async_sys_connect_state);
-    if (req == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
-        return NULL;
-    }
-
-    state->old_flags = flags;
-    state->fd = fd;
-    state->addr_len = addr_len;
-    memcpy(&state->addr, addr, addr_len);
-
-    ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
-        goto done;
-    }
-
-    ret = connect(fd, addr, addr_len);
-    if (ret == EOK) {
-        goto done;
-    }
-
-    ret = errno;
-    switch(ret) {
-        case EINPROGRESS:
-        case EINTR:
-            state->fde = tevent_add_fd(ev, state, fd,
-                                       TEVENT_FD_READ | TEVENT_FD_WRITE,
-                                       sdap_async_sys_connect_done, req);
-            if (state->fde == NULL) {
-                DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_fd failed.\n");
-                ret = ENOMEM;
-                goto done;
-            }
-
-            return req;
-
-            break;
-        default:
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  "connect failed [%d][%s].\n", ret, strerror(ret));
-    }
-
-done:
-    fret = fcntl(fd, F_SETFL, flags);
-    if (fret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
-    }
-
-    if (ret == EOK) {
-        tevent_req_done(req);
-    } else {
-        tevent_req_error(req, ret);
-    }
-
-    tevent_req_post(req, ev);
-    return req;
-}
-
-static void sdap_async_sys_connect_done(struct tevent_context *ev,
-                                        struct tevent_fd *fde, uint16_t flags,
-                                        void *priv)
-{
-    struct tevent_req *req = talloc_get_type(priv, struct tevent_req);
-    struct sdap_async_sys_connect_state *state = tevent_req_data(req,
-                                          struct sdap_async_sys_connect_state);
-    int ret;
-    int fret;
-
-    errno = 0;
-    ret = connect(state->fd, (struct sockaddr *) &state->addr,
-                  state->addr_len);
-    if (ret != EOK) {
-        ret = errno;
-        if (ret == EINPROGRESS || ret == EINTR) {
-            return; /* Try again later */
-        }
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "connect failed [%d][%s].\n", ret, strerror(ret));
-    }
-
-    talloc_zfree(fde);
-
-    fret = fcntl(state->fd, F_SETFL, state->old_flags);
-    if (fret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
-    }
-
-    if (ret == EOK) {
-        tevent_req_done(req);
-    } else {
-        tevent_req_error(req, ret);
-    }
-
-    return;
-}
-
-static int sdap_async_sys_connect_recv(struct tevent_req *req)
-{
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    return EOK;
-}
-
-static errno_t set_fd_flags_and_opts(int fd)
-{
-    int ret;
-    long flags;
-    int dummy = 1;
-
-    flags = fcntl(fd, F_GETFD, 0);
-    if (flags == -1) {
-        ret = errno;
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "fcntl F_GETFD failed [%d][%s].\n", ret, strerror(ret));
-        return ret;
-    }
-
-    flags = fcntl(fd, F_SETFD, flags| FD_CLOEXEC);
-    if (flags == -1) {
-        ret = errno;
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "fcntl F_SETFD failed [%d][%s].\n", ret, strerror(ret));
-        return ret;
-    }
-
-    /* SO_KEEPALIVE and TCP_NODELAY are set by OpenLDAP client libraries but
-     * failures are ignored.*/
-    ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &dummy, sizeof(dummy));
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(SSSDBG_FUNC_DATA,
-              "setsockopt SO_KEEPALIVE failed.[%d][%s].\n", ret,
-                  strerror(ret));
-    }
-
-    ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &dummy, sizeof(dummy));
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(SSSDBG_FUNC_DATA,
-              "setsockopt TCP_NODELAY failed.[%d][%s].\n", ret,
-                  strerror(ret));
-    }
-
-    return EOK;
-}
 
 #define LDAP_PROTO_TCP 1 /* ldap://  */
 #define LDAP_PROTO_UDP 2 /* reserved */
@@ -289,19 +107,12 @@ static errno_t set_fd_flags_and_opts(int fd)
 extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, LDAP **ld);
 
 static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq);
-static void sdap_async_sys_connect_timeout(struct tevent_context *ev,
-                                           struct tevent_timer *te,
-                                           struct timeval tv, void *pvt);
 #endif
 
 struct sss_ldap_init_state {
     LDAP *ldap;
     int sd;
     const char *uri;
-
-#ifdef HAVE_LDAP_INIT_FD
-    struct tevent_timer *connect_timeout;
-#endif
 };
 
 static int sss_ldap_init_state_destructor(void *data)
@@ -313,14 +124,17 @@ static int sss_ldap_init_state_destructor(void *data)
               "calling ldap_unbind_ext for ldap:[%p] sd:[%d]\n",
               state->ldap, state->sd);
         ldap_unbind_ext(state->ldap, NULL, NULL);
-    } else if (state->sd != -1) {
+    }
+    if (state->sd != -1) {
         DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd);
         close(state->sd);
+        state->sd = -1;
     }
 
     return 0;
 }
 
+
 struct tevent_req *sss_ldap_init_send(TALLOC_CTX *mem_ctx,
                                       struct tevent_context *ev,
                                       const char *uri,
@@ -340,47 +154,16 @@ struct tevent_req *sss_ldap_init_send(TALLOC_CTX *mem_ctx,
     talloc_set_destructor((TALLOC_CTX *)state, sss_ldap_init_state_destructor);
 
     state->ldap = NULL;
+    state->sd = -1;
     state->uri = uri;
 
 #ifdef HAVE_LDAP_INIT_FD
     struct tevent_req *subreq;
-    struct timeval tv;
 
-    state->sd = socket(addr->ss_family, SOCK_STREAM, 0);
-    if (state->sd == -1) {
-        ret = errno;
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "socket failed [%d][%s].\n", ret, strerror(ret));
-        goto fail;
-    }
-
-    ret = set_fd_flags_and_opts(state->sd);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "set_fd_flags_and_opts failed.\n");
-        goto fail;
-    }
-
-    DEBUG(SSSDBG_TRACE_ALL,
-          "Using file descriptor [%d] for LDAP connection.\n", state->sd);
-
-    subreq = sdap_async_sys_connect_send(state, ev, state->sd,
-                                         (struct sockaddr *) addr, addr_len);
+    subreq = sssd_async_socket_init_send(state, ev, addr, addr_len, timeout);
     if (subreq == NULL) {
         ret = ENOMEM;
-        DEBUG(SSSDBG_CRIT_FAILURE, "sdap_async_sys_connect_send failed.\n");
-        goto fail;
-    }
-
-    DEBUG(SSSDBG_TRACE_FUNC,
-          "Setting %d seconds timeout for connecting\n", timeout);
-    tv = tevent_timeval_current_ofs(timeout, 0);
-
-    state->connect_timeout = tevent_add_timer(ev, subreq, tv,
-                                              sdap_async_sys_connect_timeout,
-                                              subreq);
-    if (state->connect_timeout == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
-        ret = ENOMEM;
+        DEBUG(SSSDBG_CRIT_FAILURE, "sssd_async_socket_init_send failed.\n");
         goto fail;
     }
 
@@ -392,7 +175,6 @@ fail:
 #else
     DEBUG(SSSDBG_MINOR_FAILURE, "ldap_init_fd not available, "
               "will use ldap_initialize with uri [%s].\n", uri);
-    state->sd = -1;
     ret = ldap_initialize(&state->ldap, uri);
     if (ret == LDAP_SUCCESS) {
         tevent_req_done(req);
@@ -412,18 +194,6 @@ fail:
 }
 
 #ifdef HAVE_LDAP_INIT_FD
-static void sdap_async_sys_connect_timeout(struct tevent_context *ev,
-                                           struct tevent_timer *te,
-                                           struct timeval tv, void *pvt)
-{
-    struct tevent_req *connection_request;
-
-    DEBUG(SSSDBG_CONF_SETTINGS, "The LDAP connection timed out\n");
-
-    connection_request = talloc_get_type(pvt, struct tevent_req);
-    tevent_req_error(connection_request, ETIMEDOUT);
-}
-
 static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
@@ -433,13 +203,11 @@ static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq)
     int ret;
     int lret;
 
-    talloc_zfree(state->connect_timeout);
-
-    ret = sdap_async_sys_connect_recv(subreq);
+    ret = sssd_async_socket_init_recv(subreq, &state->sd);
     talloc_zfree(subreq);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
-              "sdap_async_sys_connect request failed: [%d]: %s.\n",
+              "sssd_async_socket_init request failed: [%d]: %s.\n",
               ret, sss_strerror(ret));
         goto fail;
     }
diff --git a/src/util/sss_sockets.c b/src/util/sss_sockets.c
new file mode 100644
index 0000000000000000000000000000000000000000..d0283af2d18ad42a13ec00faf7d6c4934eb696d0
--- /dev/null
+++ b/src/util/sss_sockets.c
@@ -0,0 +1,356 @@
+/*
+   SSSD
+
+   Socket utils
+
+   Copyright (C) Simo Sorce <sso...@redhat.com>	2016
+   Copyright (C) Sumit Bose <sb...@redhat.com> 2009
+
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include "util/util.h"
+
+
+static errno_t set_fd_flags_and_opts(int fd)
+{
+    int ret;
+    long flags;
+    int dummy = 1;
+
+    flags = fcntl(fd, F_GETFD, 0);
+    if (flags == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "fcntl F_GETFD failed [%d][%s].\n", ret, strerror(ret));
+        return ret;
+    }
+
+    flags = fcntl(fd, F_SETFD, flags| FD_CLOEXEC);
+    if (flags == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "fcntl F_SETFD failed [%d][%s].\n", ret, strerror(ret));
+        return ret;
+    }
+
+    /* SO_KEEPALIVE and TCP_NODELAY are set by OpenLDAP client libraries but
+     * failures are ignored.*/
+    ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &dummy, sizeof(dummy));
+    if (ret != 0) {
+        ret = errno;
+        DEBUG(SSSDBG_FUNC_DATA,
+              "setsockopt SO_KEEPALIVE failed.[%d][%s].\n", ret,
+                  strerror(ret));
+    }
+
+    ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &dummy, sizeof(dummy));
+    if (ret != 0) {
+        ret = errno;
+        DEBUG(SSSDBG_FUNC_DATA,
+              "setsockopt TCP_NODELAY failed.[%d][%s].\n", ret,
+                  strerror(ret));
+    }
+
+    return EOK;
+}
+
+
+struct sssd_async_connect_state {
+    long old_flags;
+    struct tevent_fd *fde;
+    int fd;
+    socklen_t addr_len;
+    struct sockaddr_storage addr;
+};
+
+static void sssd_async_connect_done(struct tevent_context *ev,
+                                    struct tevent_fd *fde, uint16_t flags,
+                                    void *priv);
+
+struct tevent_req *sssd_async_connect_send(TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           int fd,
+                                           const struct sockaddr *addr,
+                                           socklen_t addr_len)
+{
+    struct tevent_req *req;
+    struct sssd_async_connect_state *state;
+    long flags;
+    int ret;
+    int fret;
+
+    flags = fcntl(fd, F_GETFL, 0);
+    if (flags == -1) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_GETFL failed.\n");
+        return NULL;
+    }
+
+    req = tevent_req_create(mem_ctx, &state,
+                            struct sssd_async_connect_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
+        return NULL;
+    }
+
+    state->old_flags = flags;
+    state->fd = fd;
+    state->addr_len = addr_len;
+    memcpy(&state->addr, addr, addr_len);
+
+    ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
+        goto done;
+    }
+
+    ret = connect(fd, addr, addr_len);
+    if (ret == EOK) {
+        goto done;
+    }
+
+    ret = errno;
+    switch (ret) {
+    case EINPROGRESS:
+    case EINTR:
+        state->fde = tevent_add_fd(ev, state, fd,
+                                   TEVENT_FD_READ | TEVENT_FD_WRITE,
+                                   sssd_async_connect_done, req);
+        if (state->fde == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_fd failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        return req;
+
+        break;
+    default:
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "connect failed [%d][%s].\n", ret, strerror(ret));
+    }
+
+done:
+    fret = fcntl(fd, F_SETFL, flags);
+    if (fret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
+    }
+
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static void sssd_async_connect_done(struct tevent_context *ev,
+                                    struct tevent_fd *fde, uint16_t flags,
+                                    void *priv)
+{
+    struct tevent_req *req = talloc_get_type(priv, struct tevent_req);
+    struct sssd_async_connect_state *state =
+                tevent_req_data(req, struct sssd_async_connect_state);
+    int ret;
+    int fret;
+
+    errno = 0;
+    ret = connect(state->fd, (struct sockaddr *) &state->addr,
+                  state->addr_len);
+    if (ret != EOK) {
+        ret = errno;
+        if (ret == EINPROGRESS || ret == EINTR) {
+            return; /* Try again later */
+        }
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "connect failed [%d][%s].\n", ret, strerror(ret));
+    }
+
+    talloc_zfree(fde);
+
+    fret = fcntl(state->fd, F_SETFL, state->old_flags);
+    if (fret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
+    }
+
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+
+    return;
+}
+
+int sssd_async_connect_recv(struct tevent_req *req)
+{
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
+
+
+static void sssd_async_connect_timeout(struct tevent_context *ev,
+                                       struct tevent_timer *te,
+                                       struct timeval tv, void *pvt)
+{
+    struct tevent_req *connection_request;
+
+    DEBUG(SSSDBG_CONF_SETTINGS, "The connection timed out\n");
+
+    connection_request = talloc_get_type(pvt, struct tevent_req);
+    tevent_req_error(connection_request, ETIMEDOUT);
+}
+
+
+struct sssd_async_socket_state {
+    struct tevent_timer *connect_timeout;
+    int sd;
+};
+
+static int sssd_async_socket_state_destructor(void *data);
+static void sssd_async_socket_init_done(struct tevent_req *subreq);
+
+struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct sockaddr_storage *addr,
+                                               socklen_t addr_len, int timeout)
+{
+    struct sssd_async_socket_state *state;
+    struct tevent_req *req, *subreq;
+    struct timeval tv;
+    int ret;
+
+    req = tevent_req_create(mem_ctx, &state, struct sssd_async_socket_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
+        return NULL;
+    }
+    state->sd = -1;
+
+    talloc_set_destructor((TALLOC_CTX *)state,
+                          sssd_async_socket_state_destructor);
+
+    state->sd = socket(addr->ss_family, SOCK_STREAM, 0);
+    if (state->sd == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "socket failed [%d][%s].\n", ret, strerror(ret));
+        goto fail;
+    }
+
+    ret = set_fd_flags_and_opts(state->sd);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "set_fd_flags_and_opts failed.\n");
+        goto fail;
+    }
+
+    DEBUG(SSSDBG_TRACE_ALL,
+          "Using file descriptor [%d] for LDAP connection.\n", state->sd);
+
+    subreq = sssd_async_connect_send(state, ev, state->sd,
+                                     (struct sockaddr *) addr, addr_len);
+    if (subreq == NULL) {
+        ret = ENOMEM;
+        DEBUG(SSSDBG_CRIT_FAILURE, "sssd_async_connect_send failed.\n");
+        goto fail;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC,
+          "Setting %d seconds timeout for connecting\n", timeout);
+    tv = tevent_timeval_current_ofs(timeout, 0);
+
+    state->connect_timeout = tevent_add_timer(ev, subreq, tv,
+                                              sssd_async_connect_timeout,
+                                              subreq);
+    if (state->connect_timeout == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    tevent_req_set_callback(subreq, sssd_async_socket_init_done, req);
+    return req;
+
+fail:
+    tevent_req_error(req, ret);
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static void sssd_async_socket_init_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req =
+                tevent_req_callback_data(subreq, struct tevent_req);
+    struct sssd_async_socket_state *state =
+                tevent_req_data(req, struct sssd_async_socket_state);
+    int ret;
+
+    /* kill the timeout handler now that we got a reply */
+    talloc_zfree(state->connect_timeout);
+
+    ret = sssd_async_connect_recv(subreq);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "sdap_async_sys_connect request failed: [%d]: %s.\n",
+              ret, sss_strerror(ret));
+        goto fail;
+    }
+
+    tevent_req_done(req);
+    return;
+
+fail:
+    tevent_req_error(req, ret);
+}
+
+int sssd_async_socket_init_recv(struct tevent_req *req, int *sd)
+{
+    struct sssd_async_socket_state *state =
+                tevent_req_data(req, struct sssd_async_socket_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    /* steal the sd and neutralize destructor actions */
+    *sd = state->sd;
+    state->sd = -1;
+
+    return EOK;
+}
+
+static int sssd_async_socket_state_destructor(void *data)
+{
+    struct sssd_async_socket_state *state =
+        talloc_get_type(data, struct sssd_async_socket_state);
+
+    if (state->sd != -1) {
+        DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd);
+        close(state->sd);
+        state->sd = -1;
+    }
+
+    return 0;
+}
diff --git a/src/util/sss_sockets.h b/src/util/sss_sockets.h
new file mode 100644
index 0000000000000000000000000000000000000000..ccb05cb846a7cf520f150a7ba0a5cbd3cf7e3fb5
--- /dev/null
+++ b/src/util/sss_sockets.h
@@ -0,0 +1,39 @@
+/*
+   SSSD
+
+   Socket utils
+
+   Copyright (C) Simo Sorce <sso...@redhat.com>	2016
+
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __SSS_SOCKETS_H__
+#define __SSS_SOCKETS_H__
+
+struct tevent_req *sssd_async_connect_send(TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           int fd,
+                                           const struct sockaddr *addr,
+                                           socklen_t addr_len);
+int sssd_async_connect_recv(struct tevent_req *req);
+
+
+struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct sockaddr_storage *addr,
+                                               socklen_t addr_len, int timeout);
+int sssd_async_socket_init_recv(struct tevent_req *req, int *sd);
+
+#endif /* __SSS_SOCKETS_H__ */
-- 
2.5.0

From bdc65ef92a8dd7bf7542c76cdb838c221c92437a Mon Sep 17 00:00:00 2001
From: Simo Sorce <s...@redhat.com>
Date: Wed, 2 Mar 2016 15:49:27 -0500
Subject: [PATCH 2/3] Util: Set socket options and flags separately

Reorganize functions to set options and flags, all flags can be set at once,
and there is no need to keep old falgs around as nothing ever used that for
anything useful.

Related:
https://fedorahosted.org/sssd/ticket/2968
---
 src/util/sss_sockets.c | 58 +++++++++++++++++++-------------------------------
 1 file changed, 22 insertions(+), 36 deletions(-)

diff --git a/src/util/sss_sockets.c b/src/util/sss_sockets.c
index d0283af2d18ad42a13ec00faf7d6c4934eb696d0..9be9f2edb5f21dad331cc6a707acacf16692dd24 100644
--- a/src/util/sss_sockets.c
+++ b/src/util/sss_sockets.c
@@ -32,28 +32,35 @@
 #include "util/util.h"
 
 
-static errno_t set_fd_flags_and_opts(int fd)
+static errno_t set_fd_flags(int fd, long flags)
 {
     int ret;
-    long flags;
-    int dummy = 1;
+    long cur_flags;
 
-    flags = fcntl(fd, F_GETFD, 0);
-    if (flags == -1) {
+    cur_flags = fcntl(fd, F_GETFD, 0);
+    if (cur_flags == -1) {
         ret = errno;
         DEBUG(SSSDBG_CRIT_FAILURE,
               "fcntl F_GETFD failed [%d][%s].\n", ret, strerror(ret));
         return ret;
     }
 
-    flags = fcntl(fd, F_SETFD, flags| FD_CLOEXEC);
-    if (flags == -1) {
+    cur_flags = fcntl(fd, F_SETFD, cur_flags | flags);
+    if (cur_flags == -1) {
         ret = errno;
         DEBUG(SSSDBG_CRIT_FAILURE,
               "fcntl F_SETFD failed [%d][%s].\n", ret, strerror(ret));
         return ret;
     }
 
+    return EOK;
+}
+
+static errno_t set_fd_common_opts(int fd)
+{
+    int dummy = 1;
+    int ret;
+
     /* SO_KEEPALIVE and TCP_NODELAY are set by OpenLDAP client libraries but
      * failures are ignored.*/
     ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &dummy, sizeof(dummy));
@@ -77,7 +84,6 @@ static errno_t set_fd_flags_and_opts(int fd)
 
 
 struct sssd_async_connect_state {
-    long old_flags;
     struct tevent_fd *fde;
     int fd;
     socklen_t addr_len;
@@ -96,15 +102,7 @@ struct tevent_req *sssd_async_connect_send(TALLOC_CTX *mem_ctx,
 {
     struct tevent_req *req;
     struct sssd_async_connect_state *state;
-    long flags;
     int ret;
-    int fret;
-
-    flags = fcntl(fd, F_GETFL, 0);
-    if (flags == -1) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_GETFL failed.\n");
-        return NULL;
-    }
 
     req = tevent_req_create(mem_ctx, &state,
                             struct sssd_async_connect_state);
@@ -113,17 +111,10 @@ struct tevent_req *sssd_async_connect_send(TALLOC_CTX *mem_ctx,
         return NULL;
     }
 
-    state->old_flags = flags;
     state->fd = fd;
     state->addr_len = addr_len;
     memcpy(&state->addr, addr, addr_len);
 
-    ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
-        goto done;
-    }
-
     ret = connect(fd, addr, addr_len);
     if (ret == EOK) {
         goto done;
@@ -151,11 +142,6 @@ struct tevent_req *sssd_async_connect_send(TALLOC_CTX *mem_ctx,
     }
 
 done:
-    fret = fcntl(fd, F_SETFL, flags);
-    if (fret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
-    }
-
     if (ret == EOK) {
         tevent_req_done(req);
     } else {
@@ -174,7 +160,6 @@ static void sssd_async_connect_done(struct tevent_context *ev,
     struct sssd_async_connect_state *state =
                 tevent_req_data(req, struct sssd_async_connect_state);
     int ret;
-    int fret;
 
     errno = 0;
     ret = connect(state->fd, (struct sockaddr *) &state->addr,
@@ -190,11 +175,6 @@ static void sssd_async_connect_done(struct tevent_context *ev,
 
     talloc_zfree(fde);
 
-    fret = fcntl(state->fd, F_SETFL, state->old_flags);
-    if (fret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
-    }
-
     if (ret == EOK) {
         tevent_req_done(req);
     } else {
@@ -261,9 +241,15 @@ struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
-    ret = set_fd_flags_and_opts(state->sd);
+    ret = set_fd_common_opts(state->sd);
     if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "set_fd_flags_and_opts failed.\n");
+        DEBUG(SSSDBG_CRIT_FAILURE, "set_fd_common_opts failed.\n");
+        goto fail;
+    }
+
+    ret = set_fd_flags(state->sd, O_NONBLOCK|FD_CLOEXEC);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "settting fd flags failed.\n");
         goto fail;
     }
 
-- 
2.5.0

From c266d7bde35483305725d0fb23c1b2699848c75c Mon Sep 17 00:00:00 2001
From: Simo Sorce <s...@redhat.com>
Date: Wed, 2 Mar 2016 17:38:10 -0500
Subject: [PATCH 3/3] Util Sockets: Tidy up connect() handling

The connect() man page says waiting on a non-blocking connect should be done
by checking for writability, so drop checking for readability. Also check
for EALREADY as an acceptable error to retry on.

Related:
https://fedorahosted.org/sssd/ticket/2968
---
 src/util/sss_sockets.c | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/src/util/sss_sockets.c b/src/util/sss_sockets.c
index 9be9f2edb5f21dad331cc6a707acacf16692dd24..d146e5bffde67719815c52cd16990fccb37719fc 100644
--- a/src/util/sss_sockets.c
+++ b/src/util/sss_sockets.c
@@ -124,8 +124,7 @@ struct tevent_req *sssd_async_connect_send(TALLOC_CTX *mem_ctx,
     switch (ret) {
     case EINPROGRESS:
     case EINTR:
-        state->fde = tevent_add_fd(ev, state, fd,
-                                   TEVENT_FD_READ | TEVENT_FD_WRITE,
+        state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE,
                                    sssd_async_connect_done, req);
         if (state->fde == NULL) {
             DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_fd failed.\n");
@@ -135,7 +134,6 @@ struct tevent_req *sssd_async_connect_send(TALLOC_CTX *mem_ctx,
 
         return req;
 
-        break;
     default:
         DEBUG(SSSDBG_CRIT_FAILURE,
               "connect failed [%d][%s].\n", ret, strerror(ret));
@@ -164,13 +162,9 @@ static void sssd_async_connect_done(struct tevent_context *ev,
     errno = 0;
     ret = connect(state->fd, (struct sockaddr *) &state->addr,
                   state->addr_len);
-    if (ret != EOK) {
-        ret = errno;
-        if (ret == EINPROGRESS || ret == EINTR) {
-            return; /* Try again later */
-        }
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "connect failed [%d][%s].\n", ret, strerror(ret));
+    if ((ret != EOK) &&
+        (errno == EALREADY || errno == EINPROGRESS || errno == EINTR)) {
+        return; /* Try again later */
     }
 
     talloc_zfree(fde);
@@ -178,10 +172,10 @@ static void sssd_async_connect_done(struct tevent_context *ev,
     if (ret == EOK) {
         tevent_req_done(req);
     } else {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "connect failed [%d][%s].\n", ret, strerror(ret));
         tevent_req_error(req, ret);
     }
-
-    return;
 }
 
 int sssd_async_connect_recv(struct tevent_req *req)
-- 
2.5.0

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/admin/lists/sssd-devel@lists.fedorahosted.org

Reply via email to