]> git.sur5r.net Git - openldap/commitdiff
First cut to truly async connect:
authorPierangelo Masarati <ando@openldap.org>
Sun, 7 Jan 2007 19:20:46 +0000 (19:20 +0000)
committerPierangelo Masarati <ando@openldap.org>
Sun, 7 Jan 2007 19:20:46 +0000 (19:20 +0000)
- after connect(2), if async the connection is in "connecting" state
- the first time a request is sent, "connecting" conns are polled
- in case of success, the request is sent
- in case still connecting, LDAP_X_CONNECTING is returned;
  clients are expected to retry later
- the "async" behavior must be explicitly enabled by setting
  the LDAP_OPT_CONNECT_ASYNC option

"local" connections need work

include/ldap.h
libraries/libldap/ldap-int.h
libraries/libldap/options.c
libraries/libldap/os-ip.c
libraries/libldap/request.c

index 35187aeb6d3c8f2fefbf5608e7592a32b2e9cdda..16f7eaa603051a04d24672d4f7044f220316cd10 100644 (file)
@@ -122,6 +122,7 @@ LDAP_BEGIN_DECL
 #define LDAP_OPT_REFERRAL_URLS      0x5007  /* Referral URLs */
 #define LDAP_OPT_SOCKBUF            0x5008  /* sockbuf */
 #define LDAP_OPT_DEFBASE               0x5009  /* searchbase */
+#define        LDAP_OPT_CONNECT_ASYNC          0x5010  /* create connections asynchronously */
 
 /* OpenLDAP TLS options */
 #define LDAP_OPT_X_TLS                         0x6000
@@ -653,6 +654,7 @@ typedef struct ldapcontrol {
 #define LDAP_MORE_RESULTS_TO_RETURN            (-15)   /* Obsolete */
 #define LDAP_CLIENT_LOOP                               (-16)
 #define LDAP_REFERRAL_LIMIT_EXCEEDED   (-17)
+#define        LDAP_X_CONNECTING                       (-18)
 
 
 /*
index c8a7ba5ca977f8e15b4e9bca2ab2a436f400ee77..e37a7b81c3b148b14066d513342426cdc2c0585e 100644 (file)
@@ -117,6 +117,7 @@ LDAP_BEGIN_DECL
 #define LDAP_BOOL_REFERRALS            0
 #define LDAP_BOOL_RESTART              1
 #define LDAP_BOOL_TLS                  3
+#define        LDAP_BOOL_CONNECT_ASYNC         4
 
 #define LDAP_BOOLEANS  unsigned long
 #define LDAP_BOOL(n)   ((LDAP_BOOLEANS)1 << (n))
@@ -510,6 +511,8 @@ LDAP_F (int) ldap_int_timeval_dup( struct timeval **dest,
        const struct timeval *tm );
 LDAP_F (int) ldap_connect_to_host( LDAP *ld, Sockbuf *sb,
        int proto, const char *host, int port, int async );
+LDAP_F (int) ldap_int_poll( LDAP *ld, ber_socket_t s,
+       struct timeval *tvp );
 
 #if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) || \
        defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
index 9b100447e40d198af3ab37eea11567eb211fc565..029a0a1a9d838f4095e59221c26e0b268957ebf1 100644 (file)
@@ -242,6 +242,10 @@ ldap_get_option(
 
                return LDAP_OPT_SUCCESS;
 
+       case LDAP_OPT_CONNECT_ASYNC:
+               * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_CONNECT_ASYNC);
+               return LDAP_OPT_SUCCESS;
+               
        case LDAP_OPT_RESULT_CODE:
                if(ld == NULL) {
                        /* bad param */
@@ -392,6 +396,14 @@ ldap_set_option(
                        LDAP_BOOL_SET(lo, LDAP_BOOL_RESTART);
                }
                return LDAP_OPT_SUCCESS;
+
+       case LDAP_OPT_CONNECT_ASYNC:
+               if(invalue == LDAP_OPT_OFF) {
+                       LDAP_BOOL_CLR(lo, LDAP_BOOL_CONNECT_ASYNC);
+               } else {
+                       LDAP_BOOL_SET(lo, LDAP_BOOL_CONNECT_ASYNC);
+               }
+               return LDAP_OPT_SUCCESS;
        }
 
        /* options which can withstand invalue == NULL */
index cfd3b20190889d17990760678ff6f382a73084d7..7194c827fb647cc14e41be9bc24486e697db6445 100644 (file)
@@ -214,6 +214,137 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s)
 
 #endif /* HAVE_WINSOCK */
 
+/* NOTE: this is identical to analogous code in os-local.c */
+int
+ldap_int_poll(
+       LDAP *ld,
+       ber_socket_t s,
+       struct timeval *tvp )
+{
+       int             timeout = INFTIM;
+       struct timeval  tv = { 0 };
+       int             rc;
+               
+       if ( tvp != NULL ) {
+               tv = *tvp;
+               timeout = TV2MILLISEC( tvp );
+       }
+
+       osip_debug(ld, "ldap_int_poll: fd: %d tm: %ld\n",
+               s, tvp ? tvp->tv_sec : -1L, 0);
+
+#ifdef HAVE_POLL
+       {
+               struct pollfd fd;
+
+               fd.fd = s;
+               fd.events = POLL_WRITE;
+
+               do {
+                       fd.revents = 0;
+                       rc = poll( &fd, 1, timeout );
+               
+               } while ( rc == AC_SOCKET_ERROR && errno == EINTR &&
+                       LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) );
+
+               if ( rc == AC_SOCKET_ERROR ) {
+                       return rc;
+               }
+
+               if ( timeout == 0 && rc == 0 ) {
+                       return -2;
+               }
+
+               if ( fd.revents & POLL_WRITE ) {
+                       if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
+                               return -1;
+                       }
+
+                       if ( ldap_pvt_ndelay_off( ld, s ) == -1 ) {
+                               return -1;
+                       }
+                       return 0;
+               }
+       }
+#else
+       {
+               fd_set          wfds, *z = NULL;
+#ifdef HAVE_WINSOCK
+               fd_set          efds;
+#endif
+
+#if defined( FD_SETSIZE ) && !defined( HAVE_WINSOCK )
+               if ( s >= FD_SETSIZE ) {
+                       rc = AC_SOCKET_ERROR;
+                       tcp_close( s );
+                       ldap_pvt_set_errno( EMFILE );
+                       return rc;
+               }
+#endif
+
+               do {
+                       FD_ZERO(&wfds);
+                       FD_SET(s, &wfds );
+
+#ifdef HAVE_WINSOCK
+                       FD_ZERO(&efds);
+                       FD_SET(s, &efds );
+#endif
+
+                       rc = select( ldap_int_tblsize, z, &wfds,
+#ifdef HAVE_WINSOCK
+                               &efds,
+#else
+                               z,
+#endif
+                               tvp ? &tv : NULL );
+               } while ( rc == AC_SOCKET_ERROR && errno == EINTR &&
+                       LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) );
+
+               if ( rc == AC_SOCKET_ERROR ) {
+                       return rc;
+               }
+
+               if ( timeout == 0 && rc == 0 ) {
+                       return -2;
+               }
+
+#ifdef HAVE_WINSOCK
+               /* This means the connection failed */
+               if ( FD_ISSET(s, &efds) ) {
+                       int so_errno;
+                       int dummy = sizeof(so_errno);
+                       if ( getsockopt( s, SOL_SOCKET, SO_ERROR,
+                               (char *) &so_errno, &dummy ) == AC_SOCKET_ERROR || !so_errno )
+                       {
+                               /* impossible */
+                               so_errno = WSAGetLastError();
+                       }
+                       ldap_pvt_set_errno( so_errno );
+                       osip_debug(ld, "ldap_int_poll: error on socket %d: "
+                              "errno: %d (%s)\n", s, errno, sock_errstr( errno ));
+                       return -1;
+               }
+#endif
+               if ( FD_ISSET(s, &wfds) ) {
+#ifndef HAVE_WINSOCK
+                       if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
+                               return -1;
+                       }
+#endif
+                       if ( ldap_pvt_ndelay_off(ld, s) == -1 ) {
+                               return -1;
+                       }
+                       return 0;
+               }
+       }
+#endif
+
+       osip_debug(ld, "ldap_int_poll: timed out\n",0,0,0);
+       ldap_pvt_set_errno( ETIMEDOUT );
+       return -1;
+}
+
 static int
 ldap_pvt_connect(LDAP *ld, ber_socket_t s,
        struct sockaddr *sin, socklen_t addrlen,
@@ -240,7 +371,7 @@ ldap_pvt_connect(LDAP *ld, ber_socket_t s,
                tv = *opt_tv;
        }
 
-       osip_debug(ld, "ldap_connect_timeout: fd: %d tm: %ld async: %d\n",
+       osip_debug(ld, "ldap_pvt_connect: fd: %d tm: %ld async: %d\n",
                        s, opt_tv ? tv.tv_sec : -1L, async);
 
        if ( opt_tv && ldap_pvt_ndelay_on(ld, s) == -1 )
@@ -257,10 +388,14 @@ ldap_pvt_connect(LDAP *ld, ber_socket_t s,
                return ( -1 );
        }
        
-#ifdef notyet
-       if ( async ) return ( -2 );
-#endif
+       if ( async ) {
+               /* caller will call ldap_int_poll() as appropriate? */
+               return ( -2 );
+       }
+
+       rc = ldap_int_poll( ld, s, opt_tv );
 
+#if 0
 #ifdef HAVE_POLL
        {
                struct pollfd fd;
@@ -349,9 +484,10 @@ ldap_pvt_connect(LDAP *ld, ber_socket_t s,
        }
 #endif
 
-       osip_debug(ld, "ldap_connect_timeout: timed out\n",0,0,0);
-       ldap_pvt_set_errno( ETIMEDOUT );
-       return -1;
+#endif
+
+       osip_debug(ld, "ldap_pvt_connect: %d\n", rc, 0, 0);
+       return rc;
 }
 
 #ifndef HAVE_INET_ATON
@@ -482,7 +618,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
 
                rc = ldap_pvt_connect( ld, s,
                        sai->ai_addr, sai->ai_addrlen, async );
-               if ( (rc == 0) || (rc == -2) ) {
+               if ( rc == 0 || rc == -2 ) {
                        ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s );
                        break;
                }
index daab508c8a595c81fe05aa5b1d0fb0a766aa8718..bf81bd6f442f43426dfcfe63894b253ec3b9c96d 100644 (file)
@@ -209,11 +209,37 @@ ldap_send_server_request(
                }
        }
 
+       /* async connect... */
+       if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) {
+               ber_socket_t    sd = AC_SOCKET_ERROR;
+               struct timeval  tv = { 0 };
+
+               ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd );
+
+               /* poll ... */
+               switch ( ldap_int_poll( ld, sd, &tv ) ) {
+               case 0:
+                       /* go on! */
+                       lc->lconn_status = LDAP_CONNST_CONNECTED;
+                       break;
+
+               case -2:
+                       /* caller will have to call again */
+                       ld->ld_errno = LDAP_X_CONNECTING;
+                       /* fallthru */
+
+               default:
+                       /* error */
+                       break;
+               }
+       }
+
        if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
-               ber_free( ber, 1 );
                if ( ld->ld_errno == LDAP_SUCCESS ) {
                        ld->ld_errno = LDAP_SERVER_DOWN;
                }
+
+               ber_free( ber, 1 );
                if ( incparent ) {
                        /* Forget about the bind */
                        --parentreq->lr_outrefcnt; 
@@ -312,6 +338,7 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
        int connect, LDAPreqinfo *bind )
 {
        LDAPConn        *lc;
+       int             async = 0;
 
        Debug( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n",
                use_ldsb, connect, (bind != NULL) );
@@ -341,8 +368,10 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
        if ( connect ) {
                LDAPURLDesc     **srvp, *srv = NULL;
 
+               async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );
+
                for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) {
-                       if ( ldap_int_open_connection( ld, lc, *srvp, ) != -1 )
+                       if ( ldap_int_open_connection( ld, lc, *srvp, async) != -1 )
                        {
                                srv = *srvp;
 
@@ -366,7 +395,7 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
                lc->lconn_server = ldap_url_dup( srv );
        }
 
-       lc->lconn_status = LDAP_CONNST_CONNECTED;
+       lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED;
 #ifdef LDAP_R_COMPILE
        ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex );
 #endif
@@ -663,8 +692,9 @@ ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
                }
                Debug( LDAP_DEBUG_TRACE, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
                        ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET )
-                       ?  "NeedSocket" : ( lc->lconn_status == LDAP_CONNST_CONNECTING )
-                       ? "Connecting" : "Connected", 0 );
+                               ? "NeedSocket" :
+                               ( lc->lconn_status == LDAP_CONNST_CONNECTING )
+                                       ? "Connecting" : "Connected", 0 );
                Debug( LDAP_DEBUG_TRACE, "  last used: %s%s\n",
                        ldap_pvt_ctime( &lc->lconn_lastused, timebuf ),
                        lc->lconn_rebind_inprogress ? "  rebind in progress" : "", 0 );