From 80d1dba9017e31811c21ea6f6716b64422f82648 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 14 Aug 2008 04:54:32 +0000 Subject: [PATCH] Add LDAP_OPT_CONNECT_CB connection callbacks --- include/ldap.h | 22 ++++++++++++++++++++++ libraries/libldap/ldap-int.h | 8 ++++++++ libraries/libldap/open.c | 1 + libraries/libldap/options.c | 28 +++++++++++++++++++++++++++- libraries/libldap/os-ip.c | 24 ++++++++++++++++++++++++ libraries/libldap/os-local.c | 12 ++++++++++++ libraries/libldap/request.c | 22 ++++++++++++++++++++++ libraries/libldap/unbind.c | 12 ++++++++++++ 8 files changed, 128 insertions(+), 1 deletion(-) diff --git a/include/ldap.h b/include/ldap.h index fe2934366b..840378c449 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -123,6 +123,7 @@ LDAP_BEGIN_DECL #define LDAP_OPT_SOCKBUF 0x5008 /* sockbuf */ #define LDAP_OPT_DEFBASE 0x5009 /* searchbase */ #define LDAP_OPT_CONNECT_ASYNC 0x5010 /* create connections asynchronously */ +#define LDAP_OPT_CONNECT_CB 0x5011 /* connection callbacks */ /* OpenLDAP TLS options */ #define LDAP_OPT_X_TLS 0x6000 @@ -881,6 +882,27 @@ struct ldap_sync_t { * End of LDAP sync (RFC4533) API */ +/* + * Connection callbacks... + */ +struct ldap_conncb; +struct sockaddr; + +/* Called after a connection is established */ +typedef void (ldap_conn_add_f) LDAP_P(( LDAP *ld, Sockbuf *sb, const char *name, struct sockaddr *addr, + struct ldap_conncb *ctx )); +/* Called before a connection is closed */ +typedef void (ldap_conn_del_f) LDAP_P(( LDAP *ld, Sockbuf *sb, struct ldap_conncb *ctx )); + +/* Callbacks are pushed on a stack. Last one pushed is first one executed. The + * delete callback is called with a NULL Sockbuf just before freeing the LDAP handle. + */ +typedef struct ldap_conncb { + ldap_conn_add_f *lc_add; + ldap_conn_del_f *lc_del; + void *lc_arg; +} ldap_conncb; + /* * The API draft spec says we should declare (or cause to be declared) * 'struct timeval'. We don't. See IETF LDAPext discussions. diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index f13de68fd6..62043d60cd 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -159,6 +159,11 @@ struct ldaptls { }; #endif +typedef struct ldaplist { + struct ldaplist *ll_next; + void *ll_data; +} ldaplist; + /* * structure representing get/set'able options * which have global defaults. @@ -237,6 +242,9 @@ struct ldapoptions { LDAP_URLLIST_PROC *ldo_urllist_proc; void *ldo_urllist_params; + /* LDAP connection callback stack */ + ldaplist *ldo_conn_cbs; + LDAP_BOOLEANS ldo_booleans; /* boolean options */ }; diff --git a/libraries/libldap/open.c b/libraries/libldap/open.c index 6dec230650..8bc8c39350 100644 --- a/libraries/libldap/open.c +++ b/libraries/libldap/open.c @@ -123,6 +123,7 @@ ldap_create( LDAP **ldp ) ld->ld_options.ldo_sctrls = NULL; ld->ld_options.ldo_cctrls = NULL; ld->ld_options.ldo_defludp = NULL; + ld->ld_options.ldo_conn_cbs = NULL; #ifdef HAVE_CYRUS_SASL ld->ld_options.ldo_def_sasl_mech = gopts->ldo_def_sasl_mech diff --git a/libraries/libldap/options.c b/libraries/libldap/options.c index b4224bc1f1..9f1e9f1bc7 100644 --- a/libraries/libldap/options.c +++ b/libraries/libldap/options.c @@ -249,7 +249,22 @@ ldap_get_option( case LDAP_OPT_CONNECT_ASYNC: * (int *) outvalue = (int) LDAP_BOOL_GET(lo, LDAP_BOOL_CONNECT_ASYNC); return LDAP_OPT_SUCCESS; - + + case LDAP_OPT_CONNECT_CB: + { + /* Getting deletes the specified callback */ + ldaplist **ll = &lo->ldo_conn_cbs; + for (;*ll;ll = &(*ll)->ll_next) { + if ((*ll)->ll_data == outvalue) { + ldaplist *lc = *ll; + *ll = lc->ll_next; + LDAP_FREE(lc); + break; + } + } + } + return LDAP_OPT_SUCCESS; + case LDAP_OPT_RESULT_CODE: if(ld == NULL) { /* bad param */ @@ -734,6 +749,17 @@ ldap_set_option( case LDAP_OPT_DEBUG_LEVEL: lo->ldo_debug = * (const int *) invalue; return LDAP_OPT_SUCCESS; + + case LDAP_OPT_CONNECT_CB: + { + /* setting pushes the callback */ + ldaplist *ll; + ll = LDAP_MALLOC( sizeof( *ll )); + ll->ll_data = (void *)invalue; + ll->ll_next = lo->ldo_conn_cbs; + lo->ldo_conn_cbs = ll; + } + return LDAP_OPT_SUCCESS; } return LDAP_OPT_ERROR; } diff --git a/libraries/libldap/os-ip.c b/libraries/libldap/os-ip.c index b70d60dda2..8946c0561f 100644 --- a/libraries/libldap/os-ip.c +++ b/libraries/libldap/os-ip.c @@ -537,7 +537,19 @@ 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; } ldap_pvt_close_socket(ld, s); @@ -609,7 +621,19 @@ 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; } diff --git a/libraries/libldap/os-local.c b/libraries/libldap/os-local.c index 0f3c1ee34d..c0f21430bb 100644 --- a/libraries/libldap/os-local.c +++ b/libraries/libldap/os-local.c @@ -350,7 +350,19 @@ 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 { ldap_pvt_close_socket(ld, s); } diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c index 31d72ca0e2..8d92aa743d 100644 --- a/libraries/libldap/request.c +++ b/libraries/libldap/request.c @@ -642,6 +642,28 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); #endif + /* process connection callbacks */ + { + struct ldapoptions *lo; + ldaplist *ll; + ldap_conncb *cb; + + lo = &ld->ld_options; + if ( lo->ldo_conn_cbs ) { + for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { + cb = ll->ll_data; + cb->lc_del( ld, lc->lconn_sb, cb ); + } + } + lo = LDAP_INT_GLOBAL_OPT(); + if ( lo->ldo_conn_cbs ) { + for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { + cb = ll->ll_data; + cb->lc_del( ld, lc->lconn_sb, cb ); + } + } + } + if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) { ldap_mark_select_clear( ld, lc->lconn_sb ); if ( unbind ) { diff --git a/libraries/libldap/unbind.c b/libraries/libldap/unbind.c index 42277bb6f1..ff975856f6 100644 --- a/libraries/libldap/unbind.c +++ b/libraries/libldap/unbind.c @@ -112,6 +112,18 @@ ldap_ld_free( ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); #endif + /* final close callbacks */ + { + ldaplist *ll, *next; + + for ( ll = ld->ld_options.ldo_conn_cbs; ll; ll = next ) { + ldap_conncb *cb = ll->ll_data; + next = ll->ll_next; + cb->lc_del( ld, NULL, cb ); + LDAP_FREE( ll ); + } + } + if ( ld->ld_error != NULL ) { LDAP_FREE( ld->ld_error ); ld->ld_error = NULL; -- 2.39.5