]> git.sur5r.net Git - openldap/commitdiff
Connect callbacks need error recovery checks
authorHoward Chu <hyc@openldap.org>
Fri, 15 Aug 2008 10:23:29 +0000 (10:23 +0000)
committerHoward Chu <hyc@openldap.org>
Fri, 15 Aug 2008 10:23:29 +0000 (10:23 +0000)
libraries/libldap/ldap-int.h
libraries/libldap/os-ip.c
libraries/libldap/os-local.c

index 62043d60cd2c561948759908cb9208556c2af976..4b61a212455a186a8ba345c6c2134ba51cc9b80b 100644 (file)
@@ -531,6 +531,9 @@ LDAP_F (void) ldap_mark_select_clear( LDAP *ld, Sockbuf *sb );
 LDAP_F (int) ldap_is_read_ready( LDAP *ld, Sockbuf *sb );
 LDAP_F (int) ldap_is_write_ready( LDAP *ld, Sockbuf *sb );
 
+LDAP_F (int) ldap_int_connect_cbs( LDAP *ld, Sockbuf *sb,
+       ber_socket_t *s, const char *name, struct sockaddr *addr );
+
 /*
  * in os-local.c
  */
index 8946c0561f0ce2e07f5986944be1ed14e4e4ac0e..bda0f18a2296957a49c525208f82587800a5ad55 100644 (file)
@@ -424,6 +424,56 @@ ldap_pvt_inet_aton( const char *host, struct in_addr *in)
 }
 #endif
 
+int
+ldap_int_connect_cbs(LDAP *ld, Sockbuf *sb, ber_socket_t *s, const char *host, struct sockaddr *addr)
+{
+       struct ldapoptions *lo;
+       ldaplist *ll;
+       ldap_conncb *cb;
+       int rc;
+
+       ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, s );
+
+       /* Invoke all handle-specific callbacks first */
+       lo = &ld->ld_options;
+       for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
+               cb = ll->ll_data;
+               rc = cb->lc_add( ld, sb, host, addr, cb );
+               /* on any failure, call the teardown functions for anything
+                * that previously succeeded
+                */
+               if ( rc ) {
+                       ldaplist *l2;
+                       for (l2 = lo->ldo_conn_cbs; l2 != ll; l2 = l2->ll_next) {
+                               cb = l2->ll_data;
+                               cb->lc_del( ld, sb, cb );
+                       }
+                       /* a failure might have implicitly closed the fd */
+                       ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, s );
+                       return rc;
+               }
+       }
+       lo = LDAP_INT_GLOBAL_OPT();
+       for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
+               cb = ll->ll_data;
+               rc = cb->lc_add( ld, sb, host, addr, cb );
+               if ( rc ) {
+                       ldaplist *l2;
+                       for (l2 = lo->ldo_conn_cbs; l2 != ll; l2 = l2->ll_next) {
+                               cb = l2->ll_data;
+                               cb->lc_del( ld, sb, cb );
+                       }
+                       lo = &ld->ld_options;
+                       for (l2 = lo->ldo_conn_cbs; l2; l2 = l2->ll_next) {
+                               cb = l2->ll_data;
+                               cb->lc_del( ld, sb, cb );
+                       }
+                       ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, s );
+                       return rc;
+               }
+       }
+       return 0;
+}
 
 int
 ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
@@ -537,20 +587,11 @@ 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 ) {
-                       ldaplist *ll;
-                       struct ldapoptions *lo;
-                       ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s );
-                       lo = &ld->ld_options;
-                       for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
-                               ldap_conncb *cb = ll->ll_data;
-                               cb->lc_add( ld, sb, host, sai->ai_addr, cb );
-                       }
-                       lo = LDAP_INT_GLOBAL_OPT();
-                       for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
-                               ldap_conncb *cb = ll->ll_data;
-                               cb->lc_add( ld, sb, host, sai->ai_addr, cb );
-                       }
-                       break;
+                       err = ldap_int_connect_cbs( ld, sb, &s, host, sai->ai_addr );
+                       if ( err )
+                               rc = err;
+                       else
+                               break;
                }
                ldap_pvt_close_socket(ld, s);
        }
@@ -621,20 +662,11 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
                        async);
    
                if ( (rc == 0) || (rc == -2) ) {
-                       ldaplist *ll;
-                       struct ldapoptions *lo;
-                       ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, &s );
-                       lo = &ld->ld_options;
-                       for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
-                               ldap_conncb *cb = ll->ll_data;
-                               cb->lc_add( ld, sb, host, (struct sockaddr *)&sin, cb );
-                       }
-                       lo = LDAP_INT_GLOBAL_OPT();
-                       for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
-                               ldap_conncb *cb = ll->ll_data;
-                               cb->lc_add( ld, sb, host, (struct sockaddr *)&sin, cb );
-                       }
-                       break;
+                       i = ldap_int_connect_cbs( ld, sb, &s, host, (struct sockaddr *)&sin );
+                       if ( i )
+                               rc = i;
+                       else
+                               break;
                }
 
                ldap_pvt_close_socket(ld, s);
index c0f21430bb99eae5ee08ef1559669f7405068806..3a05f90c03205f90d706aee1c6790caea3762ca6 100644 (file)
@@ -350,20 +350,12 @@ ldap_connect_to_path(LDAP *ld, Sockbuf *sb, const char *path, int async)
        rc = ldap_pvt_connect(ld, s, &server, async);
 
        if (rc == 0) {
-               ldaplist *ll;
-               struct ldapoptions *lo;
-               ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, (void *)&s );
-               lo = &ld->ld_options;
-               for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
-                       ldap_conncb *cb = ll->ll_data;
-                       cb->lc_add( ld, sb, path, (struct sockaddr *)&server, cb );
-               }
-               lo = LDAP_INT_GLOBAL_OPT();
-               for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) {
-                       ldap_conncb *cb = ll->ll_data;
-                       cb->lc_add( ld, sb, path, (struct sockaddr *)&server, cb );
-               }
-       } else {
+               int err;
+               err = ldap_int_connect_cbs( ld, sb, &s, path, (struct sockaddr *)&server );
+               if ( err )
+                       rc = err;
+       }
+       if ( rc ) {
                ldap_pvt_close_socket(ld, s);
        }
        return rc;