X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fconnection.c;h=957662fde75bcd0d98cbf263d9f2c70ab6db3850;hb=7a296e605128cc84012f9c783179453797fe2685;hp=ec8a14c343ccd269f779d5abb69367bdd6e13a81;hpb=577bfc477e02695fa6b33b5d59ff5e03aaf22cda;p=openldap diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index ec8a14c343..957662fde7 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2005 The OpenLDAP Foundation. + * Copyright 1998-2007 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,31 +43,10 @@ #include "slapi/slapi.h" #endif - -#ifdef SLAP_MULTI_CONN_ARRAY -/* for Multiple Connection Arrary (MCA) Support */ -static ldap_pvt_thread_mutex_t* connections_mutex; -static Connection **connections = NULL; - -/* set to the number of processors */ -# define NUM_CONNECTION_ARRAY 4 - -/* partition the array in a modulo manner */ -# define MCA_conn_array_id(fd) ((int)(fd)%NUM_CONNECTION_ARRAY) -# define MCA_conn_array_element_id(fd) ((int)(fd)/NUM_CONNECTION_ARRAY) -# define MCA_GET_CONNECTION(fd) (&(connections[MCA_conn_array_id(fd)])\ - [MCA_conn_array_element_id(fd)]) -# define MCA_GET_CONN_MUTEX(fd) (&connections_mutex[MCA_conn_array_id(fd)]) - -#else /* protected by connections_mutex */ static ldap_pvt_thread_mutex_t connections_mutex; static Connection *connections = NULL; -# define MCA_GET_CONNECTION(fd) (&connections[s]) -# define MCA_GET_CONN_MUTEX(fd) (&connections_mutex) -#endif - static ldap_pvt_thread_mutex_t conn_nextid_mutex; static unsigned long conn_nextid = 0; @@ -77,6 +56,7 @@ static const char conn_lost_str[] = "connection lost"; #define SLAP_C_UNINITIALIZED 0x00 /* MUST BE ZERO (0) */ #define SLAP_C_UNUSED 0x01 #define SLAP_C_USED 0x02 +#define SLAP_C_PENDING 0x03 /* connection state (protected by c_mutex ) */ #define SLAP_C_INVALID 0x00 /* MUST BE ZERO (0) */ @@ -103,17 +83,19 @@ connection_state2str( int state ) static Connection* connection_get( ber_socket_t s ); -#ifdef SLAP_LIGHTWEIGHT_LISTENER -static int connection_input( Connection *c, Operation** op ); -#else -static int connection_input( Connection *c ); -#endif +typedef struct conn_readinfo { + Operation *op; + ldap_pvt_thread_start_t *func; + void *arg; + void *ctx; + int nullop; +} conn_readinfo; + +static int connection_input( Connection *c, conn_readinfo *cri ); static void connection_close( Connection *c ); static int connection_op_activate( Operation *op ); -#ifdef SLAP_LIGHTWEIGHT_LISTENER static void connection_op_queue( Operation *op ); -#endif static int connection_resched( Connection *conn ); static void connection_abandon( Connection *conn ); static void connection_destroy( Connection *c ); @@ -124,65 +106,6 @@ static ldap_pvt_thread_start_t connection_operation; * Initialize connection management infrastructure. */ int connections_init(void) -#ifdef SLAP_MULTI_CONN_ARRAY -{ - int i, j; - Connection* conn; - - assert( connections == NULL ); - - if( connections != NULL) { - Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n", - 0, 0, 0 ); - return -1; - } - - connections_mutex = (ldap_pvt_thread_mutex_t*) ch_calloc( NUM_CONNECTION_ARRAY, sizeof(ldap_pvt_thread_mutex_t) ); - if( connections_mutex == NULL ) { - Debug( LDAP_DEBUG_ANY, - "connections_init: allocation of connection mutex[%d] failed\n", i, 0, 0 ); - return -1; - } - - connections = (Connection**) ch_calloc( NUM_CONNECTION_ARRAY, sizeof(Connection*)); - if( connections == NULL ) { - Debug( LDAP_DEBUG_ANY, - "connections_init: allocation of connection[%d] failed\n", 0, 0, 0 ); - return -1; - } - - for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) { - ldap_pvt_thread_mutex_init( connections_mutex+i ); - connections[i] = (Connection*) ch_calloc( (dtblsize/NUM_CONNECTION_ARRAY), sizeof(Connection) ); - if( connections[i] == NULL ) { - Debug( LDAP_DEBUG_ANY, - "connections_init: allocation (%d*%ld) of connection array[%d] failed\n", - dtblsize, (long) sizeof(Connection), i ); - return -1; - } - } - - /* should check return of every call */ - ldap_pvt_thread_mutex_init( &conn_nextid_mutex ); - - assert( connections[0]->c_struct_state == SLAP_C_UNINITIALIZED ); - assert( connections[NUM_CONNECTION_ARRAY-1]->c_struct_state == SLAP_C_UNINITIALIZED ); - - for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) { - conn = connections[i]; - for ( j = 0; j < (dtblsize/NUM_CONNECTION_ARRAY); j++ ) { - conn[j].c_conn_idx = j; - } - } - - /* - * per entry initialization of the Connection array initialization - * will be done by connection_init() - */ - - return 0; -} -#else { int i; @@ -201,8 +124,8 @@ int connections_init(void) connections = (Connection *) ch_calloc( dtblsize, sizeof(Connection) ); if( connections == NULL ) { - Debug( LDAP_DEBUG_ANY, - "connections_init: allocation (%d*%ld) of connection array failed\n", + Debug( LDAP_DEBUG_ANY, "connections_init: " + "allocation (%d*%ld) of connection array failed\n", dtblsize, (long) sizeof(Connection), 0 ); return -1; } @@ -219,55 +142,12 @@ int connections_init(void) return 0; } -#endif /* * Destroy connection management infrastructure. */ int connections_destroy(void) -#ifdef SLAP_MULTI_CONN_ARRAY -{ - int i; - ber_socket_t j; - - if( connections == NULL) { - Debug( LDAP_DEBUG_ANY, "connections_destroy: nothing to destroy.\n", - 0, 0, 0 ); - return -1; - } - - for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) { - Connection* conn = connections[i]; - for ( j = 0; j < (dtblsize/NUM_CONNECTION_ARRAY); j++ ) { - if( conn[j].c_struct_state != SLAP_C_UNINITIALIZED ) { - ber_sockbuf_free( conn[j].c_sb ); - ldap_pvt_thread_mutex_destroy( &conn[j].c_mutex ); - ldap_pvt_thread_mutex_destroy( &conn[j].c_write_mutex ); - ldap_pvt_thread_cond_destroy( &conn[j].c_write_cv ); -#ifdef LDAP_SLAPI - /* FIX ME!! */ - if ( slapi_plugins_used ) { - slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION, - &connections[i] ); - } -#endif - } - } - } - - for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) { - free( connections[i] ); - connections[i] = NULL; - ldap_pvt_thread_mutex_destroy( &connections_mutex[i] ); - } - - ldap_pvt_thread_mutex_destroy( &conn_nextid_mutex ); - - return 0; - -} -#else { ber_socket_t i; @@ -301,75 +181,35 @@ int connections_destroy(void) ldap_pvt_thread_mutex_destroy( &conn_nextid_mutex ); return 0; } -#endif /* * shutdown all connections */ int connections_shutdown(void) -#ifdef SLAP_MULTI_CONN_ARRAY -{ - int i; - ber_socket_t j; - - for ( i = 0; i < NUM_CONNECTION_ARRAY; i++ ) { - Connection* conn = connections[i]; - ldap_pvt_thread_mutex_lock( &connections_mutex[i] ); - for ( j = 0; j < (dtblsize/NUM_CONNECTION_ARRAY); j++ ) { - if( conn[j].c_struct_state != SLAP_C_USED ) { - continue; - } - /* give persistent clients a chance to cleanup */ - if( conn[j].c_conn_state == SLAP_C_CLIENT ) { - ldap_pvt_thread_pool_submit( &connection_pool, - conn[j].c_clientfunc, conn[j].c_clientarg ); - continue; - } - - ldap_pvt_thread_mutex_lock( &conn[j].c_mutex ); - /* connections_mutex and c_mutex are locked */ - connection_closing( &conn[j], "connection shutdown" ); - connection_close( &conn[j] ); - ldap_pvt_thread_mutex_unlock( &conn[j].c_mutex ); - } - - ldap_pvt_thread_mutex_unlock( &connections_mutex[i] ); - } - - return 0; - -} -#else { ber_socket_t i; - ldap_pvt_thread_mutex_lock( &connections_mutex ); - for ( i = 0; i < dtblsize; i++ ) { - if( connections[i].c_struct_state != SLAP_C_USED ) { - continue; - } - /* give persistent clients a chance to cleanup */ - if( connections[i].c_conn_state == SLAP_C_CLIENT ) { - ldap_pvt_thread_pool_submit( &connection_pool, - connections[i].c_clientfunc, connections[i].c_clientarg ); - continue; + if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) { + ldap_pvt_thread_mutex_lock( &connections[i].c_mutex ); + if( connections[i].c_struct_state == SLAP_C_USED ) { + + /* give persistent clients a chance to cleanup */ + if( connections[i].c_conn_state == SLAP_C_CLIENT ) { + ldap_pvt_thread_pool_submit( &connection_pool, + connections[i].c_clientfunc, connections[i].c_clientarg ); + } else { + /* c_mutex is locked */ + connection_closing( &connections[i], "slapd shutdown" ); + connection_close( &connections[i] ); + } + } + ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex ); } - - ldap_pvt_thread_mutex_lock( &connections[i].c_mutex ); - - /* connections_mutex and c_mutex are locked */ - connection_closing( &connections[i], "slapd shutdown" ); - connection_close( &connections[i] ); - - ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex ); } - ldap_pvt_thread_mutex_unlock( &connections_mutex ); - return 0; } -#endif /* * Timeout idle connections. @@ -386,8 +226,9 @@ int connections_timeout_idle(time_t now) { /* Don't timeout a slow-running request or a persistent * outbound connection */ - if( c->c_n_ops_executing || - c->c_conn_state == SLAP_C_CLIENT ) continue; + if( c->c_n_ops_executing || c->c_conn_state == SLAP_C_CLIENT ) { + continue; + } if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) { /* close it */ @@ -403,8 +244,6 @@ int connections_timeout_idle(time_t now) static Connection* connection_get( ber_socket_t s ) { - /* connections_mutex should be locked by caller */ - Connection *c; Debug( LDAP_DEBUG_ARGS, @@ -413,59 +252,21 @@ static Connection* connection_get( ber_socket_t s ) assert( connections != NULL ); - if(s == AC_SOCKET_INVALID) { - return NULL; - } - -#ifndef HAVE_WINSOCK - c = MCA_GET_CONNECTION(s); - - assert( c->c_struct_state != SLAP_C_UNINITIALIZED ); - -#else - c = NULL; - { - ber_socket_t i, sd; - - for(i=0; i unused by resched, - * so don't assert details here. - */ - - if( sd == s ) { - c = &connections[i]; - break; - } - } - } -#endif + assert( s < dtblsize ); + c = &connections[s]; if( c != NULL ) { - ber_socket_t sd; - ldap_pvt_thread_mutex_lock( &c->c_mutex ); - ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); + assert( c->c_struct_state != SLAP_C_UNINITIALIZED ); + if( c->c_struct_state != SLAP_C_USED ) { /* connection must have been closed due to resched */ assert( c->c_conn_state == SLAP_C_INVALID ); - assert( sd == AC_SOCKET_INVALID ); + assert( c->c_sd == AC_SOCKET_INVALID ); Debug( LDAP_DEBUG_TRACE, "connection_get(%d): connection not used\n", @@ -483,7 +284,7 @@ static Connection* connection_get( ber_socket_t s ) assert( c->c_struct_state == SLAP_C_USED ); assert( c->c_conn_state != SLAP_C_INVALID ); - assert( sd != AC_SOCKET_INVALID ); + assert( c->c_sd != AC_SOCKET_INVALID ); #ifndef SLAPD_MONITOR if ( global_idletimeout > 0 ) @@ -501,17 +302,20 @@ static void connection_return( Connection *c ) ldap_pvt_thread_mutex_unlock( &c->c_mutex ); } -long connection_init( +Connection * connection_init( ber_socket_t s, Listener *listener, const char* dnsname, const char* peername, int flags, slap_ssf_t ssf, - struct berval *authid ) + struct berval *authid + LDAP_PF_LOCAL_SENDMSG_ARG(struct berval *peerbv)) { unsigned long id; Connection *c; + int doinit = 0; + ber_socket_t sfd = SLAP_FD2SOCK(s); assert( connections != NULL ); @@ -520,79 +324,30 @@ long connection_init( assert( peername != NULL ); #ifndef HAVE_TLS - assert( flags != CONN_IS_TLS ); + assert( !( flags & CONN_IS_TLS )); #endif if( s == AC_SOCKET_INVALID ) { Debug( LDAP_DEBUG_ANY, "connection_init: init of socket %ld invalid.\n", (long)s, 0, 0 ); - return -1; + return NULL; } assert( s >= 0 ); -#ifndef HAVE_WINSOCK assert( s < dtblsize ); -#endif - - ldap_pvt_thread_mutex_lock( MCA_GET_CONN_MUTEX(s) ); - -#ifndef HAVE_WINSOCK - c = MCA_GET_CONNECTION(s); -#else - { - ber_socket_t i; - c = NULL; - - for( i=0; i < dtblsize; i++) { - ber_socket_t sd; - - if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) { - assert( connections[i].c_sb == 0 ); - c = &connections[i]; - break; - } - - sd = AC_SOCKET_INVALID; - if (connections[i].c_sb != NULL) { - ber_sockbuf_ctrl( connections[i].c_sb, - LBER_SB_OPT_GET_FD, &sd ); - } - - if( connections[i].c_struct_state == SLAP_C_UNUSED ) { - assert( sd == AC_SOCKET_INVALID ); - c = &connections[i]; - break; - } - - if( connections[i].c_conn_state == SLAP_C_CLIENT ) { - continue; - } - - assert( connections[i].c_struct_state == SLAP_C_USED ); - assert( connections[i].c_conn_state != SLAP_C_INVALID ); - assert( sd != AC_SOCKET_INVALID ); - } - - if( c == NULL ) { - Debug( LDAP_DEBUG_ANY, - "connection_init(%d): connection table full " - "(%d/%d)\n", s, i, dtblsize); - ldap_pvt_thread_mutex_unlock( &connections_mutex ); - return -1; - } + c = &connections[s]; + if( c->c_struct_state == SLAP_C_UNINITIALIZED ) { + doinit = 1; + } else { + assert( c->c_struct_state == SLAP_C_UNUSED ); } -#endif - assert( c != NULL ); - - if( c->c_struct_state == SLAP_C_UNINITIALIZED ) { + if( doinit ) { c->c_send_ldap_result = slap_send_ldap_result; c->c_send_search_entry = slap_send_search_entry; c->c_send_search_reference = slap_send_search_reference; c->c_send_ldap_extended = slap_send_ldap_extended; -#ifdef LDAP_RES_INTERMEDIATE c->c_send_ldap_intermediate = slap_send_ldap_intermediate; -#endif BER_BVZERO( &c->c_authmech ); BER_BVZERO( &c->c_dn ); @@ -605,6 +360,12 @@ long connection_init( LDAP_STAILQ_INIT(&c->c_ops); LDAP_STAILQ_INIT(&c->c_pending_ops); +#ifdef LDAP_X_TXN + c->c_txn = CONN_TXN_INACTIVE; + c->c_txn_backend = NULL; + LDAP_STAILQ_INIT(&c->c_txn_ops); +#endif + BER_BVZERO( &c->c_sasl_bind_mech ); c->c_sasl_done = 0; c->c_sasl_authctx = NULL; @@ -631,13 +392,10 @@ long connection_init( slapi_int_create_object_extensions( SLAPI_X_EXT_CONNECTION, c ); } #endif - - c->c_struct_state = SLAP_C_UNUSED; } ldap_pvt_thread_mutex_lock( &c->c_mutex ); - assert( c->c_struct_state == SLAP_C_UNUSED ); assert( BER_BVISNULL( &c->c_authmech ) ); assert( BER_BVISNULL( &c->c_dn ) ); assert( BER_BVISNULL( &c->c_ndn ) ); @@ -646,6 +404,11 @@ long connection_init( assert( BER_BVISNULL( &c->c_peer_name ) ); assert( LDAP_STAILQ_EMPTY(&c->c_ops) ); assert( LDAP_STAILQ_EMPTY(&c->c_pending_ops) ); +#ifdef LDAP_X_TXN + assert( c->c_txn == CONN_TXN_INACTIVE ); + assert( c->c_txn_backend == NULL ); + assert( LDAP_STAILQ_EMPTY(&c->c_txn_ops) ); +#endif assert( BER_BVISNULL( &c->c_sasl_bind_mech ) ); assert( c->c_sasl_done == 0 ); assert( c->c_sasl_authctx == NULL ); @@ -656,16 +419,17 @@ long connection_init( assert( c->c_writewaiter == 0); c->c_listener = listener; + c->c_sd = s; - if ( flags == CONN_IS_CLIENT ) { + if ( flags & CONN_IS_CLIENT ) { + c->c_connid = 0; c->c_conn_state = SLAP_C_CLIENT; c->c_struct_state = SLAP_C_USED; c->c_close_reason = "?"; /* should never be needed */ - ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s ); + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &sfd ); ldap_pvt_thread_mutex_unlock( &c->c_mutex ); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); - return 0; + return c; } ber_str2bv( dnsname, 0, 1, &c->c_peer_domain ); @@ -692,25 +456,39 @@ long connection_init( #ifdef LDAP_CONNECTIONLESS c->c_is_udp = 0; - if( flags == CONN_IS_UDP ) { + if( flags & CONN_IS_UDP ) { c->c_is_udp = 1; #ifdef LDAP_DEBUG ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void*)"udp_" ); #endif ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_udp, - LBER_SBIOD_LEVEL_PROVIDER, (void *)&s ); + LBER_SBIOD_LEVEL_PROVIDER, (void *)&sfd ); ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_readahead, LBER_SBIOD_LEVEL_PROVIDER, NULL ); } else +#endif /* LDAP_CONNECTIONLESS */ +#ifdef LDAP_PF_LOCAL + if ( flags & CONN_IS_IPC ) { +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_PROVIDER, (void*)"ipc_" ); +#endif + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_fd, + LBER_SBIOD_LEVEL_PROVIDER, (void *)&sfd ); +#ifdef LDAP_PF_LOCAL_SENDMSG + if ( !BER_BVISEMPTY( peerbv )) + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_UNGET_BUF, peerbv ); #endif + } else +#endif /* LDAP_PF_LOCAL */ { #ifdef LDAP_DEBUG ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, LBER_SBIOD_LEVEL_PROVIDER, (void*)"tcp_" ); #endif ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp, - LBER_SBIOD_LEVEL_PROVIDER, (void *)&s ); + LBER_SBIOD_LEVEL_PROVIDER, (void *)&sfd ); } #ifdef LDAP_DEBUG @@ -738,7 +516,7 @@ long connection_init( c->c_tls_ssf = 0; #ifdef HAVE_TLS - if ( flags == CONN_IS_TLS ) { + if ( flags & CONN_IS_TLS ) { c->c_is_tls = 1; c->c_needs_tls_accept = 1; } else { @@ -750,12 +528,12 @@ long connection_init( slap_sasl_open( c, 0 ); slap_sasl_external( c, ssf, authid ); + slapd_add_internal( s, 1 ); ldap_pvt_thread_mutex_unlock( &c->c_mutex ); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); backend_connection_init(c); - return id; + return c; } void connection2anonymous( Connection *c ) @@ -794,22 +572,32 @@ void connection2anonymous( Connection *c ) static void connection_destroy( Connection *c ) { - /* note: connections_mutex should be locked by caller */ - ber_socket_t sd; unsigned long connid; const char *close_reason; + Sockbuf *sb; + ber_socket_t sd; assert( connections != NULL ); assert( c != NULL ); assert( c->c_struct_state != SLAP_C_UNUSED ); assert( c->c_conn_state != SLAP_C_INVALID ); assert( LDAP_STAILQ_EMPTY(&c->c_ops) ); + assert( LDAP_STAILQ_EMPTY(&c->c_pending_ops) ); +#ifdef LDAP_X_TXN + assert( c->c_txn == CONN_TXN_INACTIVE ); + assert( c->c_txn_backend == NULL ); + assert( LDAP_STAILQ_EMPTY(&c->c_txn_ops) ); +#endif assert( c->c_writewaiter == 0); /* only for stats (print -1 as "%lu" may give unexpected results ;) */ connid = c->c_connid; close_reason = c->c_close_reason; + ldap_pvt_thread_mutex_lock( &connections_mutex ); + c->c_struct_state = SLAP_C_PENDING; + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + backend_connection_destroy(c); c->c_protocol = 0; @@ -842,35 +630,41 @@ connection_destroy( Connection *c ) c->c_currentber = NULL; } - ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); - if ( sd != AC_SOCKET_INVALID ) { - slapd_remove( sd, 1, 0 ); - Statslog( LDAP_DEBUG_STATS, (close_reason - ? "conn=%lu fd=%ld closed (%s)\n" - : "conn=%lu fd=%ld closed\n"), - connid, (long) sd, close_reason, 0, 0 ); +#ifdef LDAP_SLAPI + /* call destructors, then constructors; avoids unnecessary allocation */ + if ( slapi_plugins_used ) { + slapi_int_clear_object_extensions( SLAPI_X_EXT_CONNECTION, c ); } +#endif - ber_sockbuf_free( c->c_sb ); + sd = c->c_sd; + c->c_sd = AC_SOCKET_INVALID; + c->c_conn_state = SLAP_C_INVALID; + c->c_struct_state = SLAP_C_UNUSED; + c->c_close_reason = "?"; /* should never be needed */ + sb = c->c_sb; c->c_sb = ber_sockbuf_alloc( ); - { ber_len_t max = sockbuf_max_incoming; ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max ); } - c->c_conn_state = SLAP_C_INVALID; - c->c_struct_state = SLAP_C_UNUSED; - c->c_close_reason = "?"; /* should never be needed */ + /* c must be fully reset by this point; when we call slapd_remove + * it may get immediately reused by a new connection. + */ + if ( sd != AC_SOCKET_INVALID ) { + slapd_remove( sd, sb, 1, 0, 0 ); -#ifdef LDAP_SLAPI - /* call destructors, then constructors; avoids unnecessary allocation */ - if ( slapi_plugins_used ) { - slapi_int_clear_object_extensions( SLAPI_X_EXT_CONNECTION, c ); + if ( close_reason == NULL ) { + Statslog( LDAP_DEBUG_STATS, "conn=%lu fd=%ld closed\n", + connid, (long) sd, 0, 0, 0 ); + } else { + Statslog( LDAP_DEBUG_STATS, "conn=%lu fd=%ld closed (%s)\n", + connid, (long) sd, close_reason, 0, 0 ); + } } -#endif } int connection_state_closing( Connection *c ) @@ -900,6 +694,7 @@ static void connection_abandon( Connection *c ) op.o_conn = c; op.o_connid = c->c_connid; op.o_tag = LDAP_REQ_ABANDON; + for ( o = LDAP_STAILQ_FIRST( &c->c_ops ); o; o=next ) { next = LDAP_STAILQ_NEXT( o, o_next ); op.orn_msgid = o->o_msgid; @@ -908,11 +703,24 @@ static void connection_abandon( Connection *c ) frontendDB->be_abandon( &op, &rs ); } +#ifdef LDAP_X_TXN + /* remove operations in pending transaction */ + while ( (o = LDAP_STAILQ_FIRST( &c->c_txn_ops )) != NULL) { + LDAP_STAILQ_REMOVE_HEAD( &c->c_txn_ops, o_next ); + LDAP_STAILQ_NEXT(o, o_next) = NULL; + slap_op_free( o, NULL ); + } + + /* clear transaction */ + c->c_txn_backend = NULL; + c->c_txn = CONN_TXN_INACTIVE; +#endif + /* remove pending operations */ while ( (o = LDAP_STAILQ_FIRST( &c->c_pending_ops )) != NULL) { LDAP_STAILQ_REMOVE_HEAD( &c->c_pending_ops, o_next ); LDAP_STAILQ_NEXT(o, o_next) = NULL; - slap_op_free( o ); + slap_op_free( o, NULL ); } } @@ -926,57 +734,68 @@ void connection_closing( Connection *c, const char *why ) /* c_mutex must be locked by caller */ if( c->c_conn_state != SLAP_C_CLOSING ) { - ber_socket_t sd; - - ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); Debug( LDAP_DEBUG_TRACE, "connection_closing: readying conn=%lu sd=%d for close\n", - c->c_connid, sd, 0 ); + c->c_connid, c->c_sd, 0 ); /* update state to closing */ c->c_conn_state = SLAP_C_CLOSING; c->c_close_reason = why; /* don't listen on this port anymore */ - slapd_clr_read( sd, 1 ); + slapd_clr_read( c->c_sd, 0 ); /* abandon active operations */ connection_abandon( c ); /* wake write blocked operations */ - slapd_clr_write( sd, 1 ); if ( c->c_writewaiter ) { ldap_pvt_thread_cond_signal( &c->c_write_cv ); + /* ITS#4667 this may allow another thread to drop into + * connection_resched / connection_close before we + * finish, but that's OK. + */ + slapd_clr_write( c->c_sd, 1 ); ldap_pvt_thread_mutex_unlock( &c->c_mutex ); - ldap_pvt_thread_yield(); + ldap_pvt_thread_mutex_lock( &c->c_write_mutex ); ldap_pvt_thread_mutex_lock( &c->c_mutex ); + ldap_pvt_thread_mutex_unlock( &c->c_write_mutex ); + } else { + slapd_clr_write( c->c_sd, 1 ); } + } else if( why == NULL && c->c_close_reason == conn_lost_str ) { /* Client closed connection after doing Unbind. */ c->c_close_reason = NULL; } } -static void connection_close( Connection *c ) +static void +connection_close( Connection *c ) { - ber_socket_t sd; - assert( connections != NULL ); assert( c != NULL ); + + /* ITS#4667 we may have gotten here twice */ + if ( c->c_conn_state == SLAP_C_INVALID ) + return; + assert( c->c_struct_state == SLAP_C_USED ); assert( c->c_conn_state == SLAP_C_CLOSING ); - /* note: connections_mutex and c_mutex should be locked by caller */ + /* NOTE: c_mutex should be locked by caller */ - ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); - if( !LDAP_STAILQ_EMPTY(&c->c_ops) ) { + if ( !LDAP_STAILQ_EMPTY(&c->c_ops) || + !LDAP_STAILQ_EMPTY(&c->c_pending_ops) ) + { Debug( LDAP_DEBUG_TRACE, "connection_close: deferring conn=%lu sd=%d\n", - c->c_connid, sd, 0 ); + c->c_connid, c->c_sd, 0 ); return; } Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%lu sd=%d\n", - c->c_connid, sd, 0 ); + c->c_connid, c->c_sd, 0 ); + connection_destroy( c ); } @@ -996,135 +815,71 @@ unsigned long connections_nextid(void) Connection* connection_first( ber_socket_t *index ) { -#ifdef SLAP_MULTI_CONN_ARRAY - int conn_array_id; -#endif - assert( connections != NULL ); assert( index != NULL ); -#ifdef SLAP_MULTI_CONN_ARRAY - for ( conn_array_id = 0; - conn_array_id < NUM_CONNECTION_ARRAY; - conn_array_id++ ) - { - ldap_pvt_thread_mutex_lock( &connections_mutex[ conn_array_id ] ); - } -#else ldap_pvt_thread_mutex_lock( &connections_mutex ); -#endif - - *index = 0; - - return connection_next(NULL, index); -} - -Connection* connection_next( Connection *c, ber_socket_t *index ) -#ifdef SLAP_MULTI_CONN_ARRAY -{ - Connection* conn; - - assert( connections != NULL ); - assert( index != NULL ); - assert( *index <= (dtblsize/NUM_CONNECTION_ARRAY) ); - - if( c != NULL ) { - ldap_pvt_thread_mutex_unlock( &c->c_mutex ); - } - - c = NULL; - - for(; *index < dtblsize; (*index)++) { - conn = MCA_GET_CONNECTION(*index); - if( conn->c_struct_state == SLAP_C_UNINITIALIZED ) { - assert( conn->c_conn_state == SLAP_C_INVALID ); -#ifndef HAVE_WINSOCK - continue; -#else + for( *index = 0; *index < dtblsize; (*index)++) { + if( connections[*index].c_struct_state != SLAP_C_UNINITIALIZED ) { break; -#endif } - - if( conn->c_struct_state == SLAP_C_USED ) { - assert( conn->c_conn_state != SLAP_C_INVALID ); - c = conn; - (*index)++; - break; - } - - assert( conn->c_struct_state == SLAP_C_UNUSED ); - assert( conn->c_conn_state == SLAP_C_INVALID ); } + ldap_pvt_thread_mutex_unlock( &connections_mutex ); - if( c != NULL ) { - ldap_pvt_thread_mutex_lock( &c->c_mutex ); - } - - return c; - + return connection_next(NULL, index); } -#else + +Connection* connection_next( Connection *c, ber_socket_t *index ) { assert( connections != NULL ); assert( index != NULL ); assert( *index <= dtblsize ); - if( c != NULL ) { - ldap_pvt_thread_mutex_unlock( &c->c_mutex ); - } + if( c != NULL ) ldap_pvt_thread_mutex_unlock( &c->c_mutex ); c = NULL; + ldap_pvt_thread_mutex_lock( &connections_mutex ); for(; *index < dtblsize; (*index)++) { + int c_struct; if( connections[*index].c_struct_state == SLAP_C_UNINITIALIZED ) { assert( connections[*index].c_conn_state == SLAP_C_INVALID ); -#ifndef HAVE_WINSOCK continue; -#else - break; -#endif } if( connections[*index].c_struct_state == SLAP_C_USED ) { assert( connections[*index].c_conn_state != SLAP_C_INVALID ); c = &connections[(*index)++]; + if ( ldap_pvt_thread_mutex_trylock( &c->c_mutex )) { + /* avoid deadlock */ + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + ldap_pvt_thread_mutex_lock( &connections_mutex ); + if ( c->c_struct_state != SLAP_C_USED ) { + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + c = NULL; + continue; + } + } break; } - assert( connections[*index].c_struct_state == SLAP_C_UNUSED ); + c_struct = connections[*index].c_struct_state; + if ( c_struct == SLAP_C_PENDING ) + continue; + assert( c_struct == SLAP_C_UNUSED ); assert( connections[*index].c_conn_state == SLAP_C_INVALID ); } - if( c != NULL ) { - ldap_pvt_thread_mutex_lock( &c->c_mutex ); - } - + ldap_pvt_thread_mutex_unlock( &connections_mutex ); return c; } -#endif void connection_done( Connection *c ) { -#ifdef SLAP_MULTI_CONN_ARRAY - int conn_array_id; -#endif - assert( connections != NULL ); - if( c != NULL ) { - ldap_pvt_thread_mutex_unlock( &c->c_mutex ); - } - -#ifdef SLAP_MULTI_CONN_ARRAY - for ( conn_array_id = 0; - conn_array_id < NUM_CONNECTION_ARRAY; - conn_array_id++ ) - { - ldap_pvt_thread_mutex_unlock( &connections_mutex[ conn_array_id ] ); - } -#else - ldap_pvt_thread_mutex_unlock( &connections_mutex ); -#endif + if( c != NULL ) ldap_pvt_thread_mutex_unlock( &c->c_mutex ); } /* @@ -1137,44 +892,100 @@ void connection_done( Connection *c ) /* FIXME: returns 0 in case of failure */ #define INCR_OP_INITIATED(index) \ do { \ - ldap_pvt_thread_mutex_lock( &slap_counters.sc_ops_mutex ); \ - ldap_pvt_mp_add_ulong(slap_counters.sc_ops_initiated_[(index)], 1); \ - ldap_pvt_thread_mutex_unlock( &slap_counters.sc_ops_mutex ); \ + ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex ); \ + ldap_pvt_mp_add_ulong(op->o_counters->sc_ops_initiated_[(index)], 1); \ + ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex ); \ } while (0) #define INCR_OP_COMPLETED(index) \ do { \ - ldap_pvt_thread_mutex_lock( &slap_counters.sc_ops_mutex ); \ - ldap_pvt_mp_add_ulong(slap_counters.sc_ops_completed, 1); \ - ldap_pvt_mp_add_ulong(slap_counters.sc_ops_completed_[(index)], 1); \ - ldap_pvt_thread_mutex_unlock( &slap_counters.sc_ops_mutex ); \ + ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex ); \ + ldap_pvt_mp_add_ulong(op->o_counters->sc_ops_completed, 1); \ + ldap_pvt_mp_add_ulong(op->o_counters->sc_ops_completed_[(index)], 1); \ + ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex ); \ } while (0) #else /* !SLAPD_MONITOR */ #define INCR_OP_INITIATED(index) do { } while (0) #define INCR_OP_COMPLETED(index) \ do { \ - ldap_pvt_thread_mutex_lock( &slap_counters.sc_ops_mutex ); \ - ldap_pvt_mp_add_ulong(slap_counters.sc_ops_completed, 1); \ - ldap_pvt_thread_mutex_unlock( &slap_counters.sc_ops_mutex ); \ + ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex ); \ + ldap_pvt_mp_add_ulong(op->o_counters->sc_ops_completed, 1); \ + ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex ); \ } while (0) #endif /* !SLAPD_MONITOR */ /* * NOTE: keep in sync with enum in slapd.h */ -static int (*opfun[])( Operation *op, SlapReply *rs ) = { +static BI_op_func *opfun[] = { do_bind, do_unbind, + do_search, + do_compare, + do_modify, + do_modrdn, do_add, do_delete, - do_modrdn, - do_modify, - do_compare, - do_search, do_abandon, do_extended, NULL }; +/* Counters are per-thread, not per-connection. + */ +static void +conn_counter_destroy( void *key, void *data ) +{ + slap_counters_t **prev, *sc; + + ldap_pvt_thread_mutex_lock( &slap_counters.sc_mutex ); + for ( prev = &slap_counters.sc_next, sc = slap_counters.sc_next; sc; + prev = &sc->sc_next, sc = sc->sc_next ) { + if ( sc == data ) { + int i; + + *prev = sc->sc_next; + /* Copy data to main counter */ + ldap_pvt_mp_add( slap_counters.sc_bytes, sc->sc_bytes ); + ldap_pvt_mp_add( slap_counters.sc_pdu, sc->sc_pdu ); + ldap_pvt_mp_add( slap_counters.sc_entries, sc->sc_entries ); + ldap_pvt_mp_add( slap_counters.sc_refs, sc->sc_refs ); + ldap_pvt_mp_add( slap_counters.sc_ops_initiated, sc->sc_ops_initiated ); + ldap_pvt_mp_add( slap_counters.sc_ops_completed, sc->sc_ops_completed ); +#ifdef SLAPD_MONITOR + for ( i = 0; i < SLAP_OP_LAST; i++ ) { + ldap_pvt_mp_add( slap_counters.sc_ops_initiated_[ i ], sc->sc_ops_initiated_[ i ] ); + ldap_pvt_mp_add( slap_counters.sc_ops_initiated_[ i ], sc->sc_ops_completed_[ i ] ); + } +#endif /* SLAPD_MONITOR */ + slap_counters_destroy( sc ); + ber_memfree_x( data, NULL ); + break; + } + } + ldap_pvt_thread_mutex_unlock( &slap_counters.sc_mutex ); +} + +static void +conn_counter_init( Operation *op, void *ctx ) +{ + slap_counters_t *sc; + void *vsc = NULL; + + if ( ldap_pvt_thread_pool_getkey( ctx, conn_counter_init, &vsc, NULL ) || !vsc ) { + vsc = ch_malloc( sizeof( slap_counters_t )); + sc = vsc; + slap_counters_init( sc ); + ldap_pvt_thread_pool_setkey( ctx, conn_counter_init, vsc, + conn_counter_destroy ); + + ldap_pvt_thread_mutex_lock( &slap_counters.sc_mutex ); + sc->sc_next = slap_counters.sc_next; + slap_counters.sc_next = sc; + ldap_pvt_thread_mutex_unlock( &slap_counters.sc_mutex ); + } + op->o_counters = vsc; +} + static void * connection_operation( void *ctx, void *arg_v ) { @@ -1182,18 +993,20 @@ connection_operation( void *ctx, void *arg_v ) Operation *op = arg_v; SlapReply rs = {REP_RESULT}; ber_tag_t tag = op->o_tag; - int opidx = -1; + slap_op_t opidx = SLAP_OP_LAST; Connection *conn = op->o_conn; void *memctx = NULL; void *memctx_null = NULL; ber_len_t memsiz; - ldap_pvt_thread_mutex_lock( &slap_counters.sc_ops_mutex ); + conn_counter_init( op, ctx ); + ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex ); /* FIXME: returns 0 in case of failure */ - ldap_pvt_mp_add_ulong(slap_counters.sc_ops_initiated, 1); - ldap_pvt_thread_mutex_unlock( &slap_counters.sc_ops_mutex ); + ldap_pvt_mp_add_ulong(op->o_counters->sc_ops_initiated, 1); + ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex ); op->o_threadctx = ctx; + op->o_tid = ldap_pvt_thread_pool_tid( ctx ); switch ( tag ) { case LDAP_REQ_BIND: @@ -1229,6 +1042,20 @@ connection_operation( void *ctx, void *arg_v ) goto operations_error; } +#ifdef LDAP_X_TXN + if (( conn->c_txn == CONN_TXN_SPECIFY ) && ( + ( tag == LDAP_REQ_ADD ) || + ( tag == LDAP_REQ_DELETE ) || + ( tag == LDAP_REQ_MODIFY ) || + ( tag == LDAP_REQ_MODRDN ))) + { + /* Disable SLAB allocator for all update operations + issued inside of a transaction */ + op->o_tmpmemctx = NULL; + op->o_tmpmfuncs = &ch_mfuncs; + } else +#endif + { /* We can use Thread-Local storage for most mallocs. We can * also use TL for ber parsing, but not on Add or Modify. */ @@ -1238,7 +1065,7 @@ connection_operation( void *ctx, void *arg_v ) #endif memsiz = SLAP_SLAB_SIZE; - memctx = slap_sl_mem_create( memsiz, SLAP_SLAB_STACK, ctx ); + memctx = slap_sl_mem_create( memsiz, SLAP_SLAB_STACK, ctx, 1 ); op->o_tmpmemctx = memctx; op->o_tmpmfuncs = &slap_sl_mfuncs; if ( tag != LDAP_REQ_ADD && tag != LDAP_REQ_MODIFY ) { @@ -1248,54 +1075,10 @@ connection_operation( void *ctx, void *arg_v ) */ ber_set_option( op->o_ber, LBER_OPT_BER_MEMCTX, &memctx ); } - - switch ( tag ) { - case LDAP_REQ_BIND: - opidx = SLAP_OP_BIND; - break; - - case LDAP_REQ_UNBIND: - opidx = SLAP_OP_UNBIND; - break; - - case LDAP_REQ_ADD: - opidx = SLAP_OP_ADD; - break; - - case LDAP_REQ_DELETE: - opidx = SLAP_OP_DELETE; - break; - - case LDAP_REQ_MODRDN: - opidx = SLAP_OP_MODRDN; - break; - - case LDAP_REQ_MODIFY: - opidx = SLAP_OP_MODIFY; - break; - - case LDAP_REQ_COMPARE: - opidx = SLAP_OP_COMPARE; - break; - - case LDAP_REQ_SEARCH: - opidx = SLAP_OP_SEARCH; - break; - - case LDAP_REQ_ABANDON: - opidx = SLAP_OP_ABANDON; - break; - - case LDAP_REQ_EXTENDED: - opidx = SLAP_OP_EXTENDED; - break; - - default: - /* not reachable */ - assert( 0 ); } - assert( opidx > -1 ); + opidx = slap_req2op( tag ); + assert( opidx != SLAP_OP_LAST ); INCR_OP_INITIATED( opidx ); rc = (*(opfun[opidx]))( op, &rs ); @@ -1303,7 +1086,7 @@ operations_error: if ( rc == SLAPD_DISCONNECT ) { tag = LBER_ERROR; - } else if ( opidx > -1 ) { + } else if ( opidx != SLAP_OP_LAST ) { /* increment completed operations count * only if operation was initiated * and rc != SLAPD_DISCONNECT */ @@ -1311,11 +1094,13 @@ operations_error: } if ( op->o_cancel == SLAP_CANCEL_REQ ) { - if ( rc == SLAPD_ABANDON ) + if ( rc == SLAPD_ABANDON ) { op->o_cancel = SLAP_CANCEL_ACK; - else + } else { op->o_cancel = LDAP_TOO_LATE; + } } + while ( op->o_cancel != SLAP_CANCEL_NONE && op->o_cancel != SLAP_CANCEL_DONE ) { @@ -1326,9 +1111,8 @@ operations_error: ber_set_option( op->o_ber, LBER_OPT_BER_MEMCTX, &memctx_null ); - LDAP_STAILQ_REMOVE( &conn->c_ops, op, slap_op, o_next); + LDAP_STAILQ_REMOVE( &conn->c_ops, op, Operation, o_next); LDAP_STAILQ_NEXT(op, o_next) = NULL; - slap_op_free( op ); conn->c_n_ops_executing--; conn->c_n_ops_completed++; @@ -1336,57 +1120,51 @@ operations_error: case LBER_ERROR: case LDAP_REQ_UNBIND: /* c_mutex is locked */ - connection_closing( - conn, tag == LDAP_REQ_UNBIND ? NULL : "operations error" ); + connection_closing( conn, + tag == LDAP_REQ_UNBIND ? NULL : "operations error" ); break; - - case LDAP_REQ_BIND: - conn->c_sasl_bind_in_progress = - rc == LDAP_SASL_BIND_IN_PROGRESS ? 1 : 0; - - if( conn->c_conn_state == SLAP_C_BINDING) { - conn->c_conn_state = SLAP_C_ACTIVE; - } } connection_resched( conn ); ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + slap_op_free( op, ctx ); return NULL; } static const Listener dummy_list = { BER_BVC(""), BER_BVC("") }; -int connection_client_setup( +Connection *connection_client_setup( ber_socket_t s, ldap_pvt_thread_start_t *func, void *arg ) { - int rc; Connection *c; + ber_socket_t sfd = SLAP_SOCKNEW( s ); - rc = connection_init( s, (Listener *)&dummy_list, "", "", - CONN_IS_CLIENT, 0, NULL ); - if ( rc < 0 ) return -1; + c = connection_init( sfd, (Listener *)&dummy_list, "", "", + CONN_IS_CLIENT, 0, NULL + LDAP_PF_LOCAL_SENDMSG_ARG(NULL)); + if ( c ) { + c->c_clientfunc = func; + c->c_clientarg = arg; - c = connection_get( s ); - c->c_clientfunc = func; - c->c_clientarg = arg; - connection_return( c ); - slapd_add_internal( s, 0 ); - slapd_set_read( s, 1 ); - return 0; + slapd_add_internal( sfd, 0 ); + slapd_set_read( sfd, 1 ); + } + return c; } void connection_client_enable( - ber_socket_t s ) + Connection *c ) { - slapd_set_read( s, 1 ); + slapd_set_read( c->c_sd, 1 ); } void connection_client_stop( - ber_socket_t s ) + Connection *c ) { - Connection *c; + Sockbuf *sb; + ber_socket_t s = c->c_sd; /* get (locked) connection */ c = connection_get( s ); @@ -1396,85 +1174,80 @@ void connection_client_stop( c->c_listener = NULL; c->c_conn_state = SLAP_C_INVALID; c->c_struct_state = SLAP_C_UNUSED; + c->c_sd = AC_SOCKET_INVALID; c->c_close_reason = "?"; /* should never be needed */ - ber_sockbuf_free( c->c_sb ); + sb = c->c_sb; c->c_sb = ber_sockbuf_alloc( ); { ber_len_t max = sockbuf_max_incoming; ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max ); } + slapd_remove( s, sb, 0, 1, 0 ); connection_return( c ); - slapd_remove( s, 0, 1 ); } -#ifdef SLAP_LIGHTWEIGHT_LISTENER +static int connection_read( ber_socket_t s, conn_readinfo *cri ); + static void* connection_read_thread( void* ctx, void* argv ) { int rc ; - Operation* new_op = NULL; - ber_socket_t s = (ber_socket_t)argv; + conn_readinfo cri = { NULL, NULL, NULL, NULL, 0 }; + ber_socket_t s = (long)argv; /* * read incoming LDAP requests. If there is more than one, * the first one is returned with new_op */ - if( ( rc = connection_read( s, &new_op ) ) < 0 ) { - Debug( LDAP_DEBUG_TRACE, "connection_read(%d) error\n", s, 0, 0 ); - tcp_close( s ); - return (void*)rc; + cri.ctx = ctx; + if( ( rc = connection_read( s, &cri ) ) < 0 ) { + Debug( LDAP_DEBUG_CONNS, "connection_read(%d) error\n", s, 0, 0 ); + return (void*)(long)rc; } - /* execute the queued request in the same thread */ - if( new_op ) { - rc = (int)connection_operation( - ldap_pvt_thread_pool_context(), new_op ); + /* execute a single queued request in the same thread */ + if( cri.op && !cri.nullop ) { + rc = (long)connection_operation( ctx, cri.op ); + } else if ( cri.func ) { + rc = (long)cri.func( ctx, cri.arg ); } - return (void*)rc; + return (void*)(long)rc; } int connection_read_activate( ber_socket_t s ) { - int status; + int rc; /* * suspend reading on this file descriptor until a connection processing * thread reads data on it. Otherwise the listener thread will repeatedly * submit the same event on it to the pool. */ - if( !slapd_suspend( s ) ) return 0; + rc = slapd_clr_read( s, 0 ); + if ( rc ) + return rc; - status = ldap_pvt_thread_pool_submit( &connection_pool, - connection_read_thread, (void *) s ); + rc = ldap_pvt_thread_pool_submit( &connection_pool, + connection_read_thread, (void *)(long)s ); - if( status != 0 ) { - Debug( LDAP_DEBUG_ANY, "connection_processing_activiate(%d): " - "ldap_pvt_thread_pool_submit failed\n", - s, 0, 0 ); - return -1; + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "connection_read_activate(%d): submit failed (%d)\n", + s, rc, 0 ); } - return 1; + return rc; } -#endif -#ifdef SLAP_LIGHTWEIGHT_LISTENER -int connection_read( ber_socket_t s, Operation** op ) -#else -int connection_read(ber_socket_t s) -#endif +static int +connection_read( ber_socket_t s, conn_readinfo *cri ) { int rc = 0; Connection *c; -#ifdef SLAP_LIGHTWEIGHT_LISTENER - int need_resume = 1; -#endif assert( connections != NULL ); - ldap_pvt_thread_mutex_lock( MCA_GET_CONN_MUTEX(s) ); - /* get (locked) connection */ c = connection_get( s ); @@ -1482,9 +1255,7 @@ int connection_read(ber_socket_t s) Debug( LDAP_DEBUG_ANY, "connection_read(%ld): no connection!\n", (long) s, 0, 0 ); - slapd_remove(s, 1, 0); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); return -1; } @@ -1495,24 +1266,14 @@ int connection_read(ber_socket_t s) "connection_read(%d): closing, ignoring input for id=%lu\n", s, c->c_connid, 0 ); connection_return( c ); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); - -#ifdef SLAP_LIGHTWEIGHT_LISTENER - slapd_resume( s, 1 ); -#endif return 0; } if ( c->c_conn_state == SLAP_C_CLIENT ) { -#ifdef SLAP_LIGHTWEIGHT_LISTENER - slapd_resume( s, 1 ); -#endif - slapd_clr_read( s, 0 ); - ldap_pvt_thread_pool_submit( &connection_pool, - c->c_clientfunc, c->c_clientarg ); - + cri->func = c->c_clientfunc; + cri->arg = c->c_clientarg; + /* read should already be cleared */ connection_return( c ); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); return 0; } @@ -1525,34 +1286,16 @@ int connection_read(ber_socket_t s) rc = ldap_pvt_tls_accept( c->c_sb, slap_tls_ctx ); if ( rc < 0 ) { Debug( LDAP_DEBUG_TRACE, - "connection_read(%d): TLS accept error " + "connection_read(%d): TLS accept failure " "error=%d id=%lu, closing\n", s, rc, c->c_connid ); c->c_needs_tls_accept = 0; - /* connections_mutex and c_mutex are locked */ + /* c_mutex is locked */ connection_closing( c, "TLS negotiation failure" ); - -#if 0 - { - struct timeval tv; - fd_set rfd; - /* Drain input before close, to allow SSL error codes - * to propagate to client. */ - FD_ZERO(&rfd); - FD_SET(s, &rfd); - for (rc=1; rc>0;) { - tv.tv_sec = 1; - tv.tv_usec = 0; - rc = select(s+1, &rfd, NULL, NULL, &tv); - if (rc == 1) { - ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_DRAIN, NULL); - } - } - } -#endif - connection_close( c ); + connection_return( c ); + return 0; } else if ( rc == 0 ) { void *ssl; @@ -1582,15 +1325,10 @@ int connection_read(ber_socket_t s) } /* if success and data is ready, fall thru to data input loop */ - if( rc != 0 || - !ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_DATA_READY, NULL ) ) + if( !ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_DATA_READY, NULL ) ) { + slapd_set_read( s, 1 ); connection_return( c ); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); - -#ifdef SLAP_LIGHTWEIGHT_LISTENER - slapd_resume( s, 1 ); -#endif return 0; } } @@ -1600,12 +1338,8 @@ int connection_read(ber_socket_t s) if ( c->c_sasl_layers ) { /* If previous layer is not removed yet, give up for now */ if ( !c->c_sasl_sockctx ) { + slapd_set_read( s, 1 ); connection_return( c ); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); - -#ifdef SLAP_LIGHTWEIGHT_LISTENER - slapd_resume( s, 1 ); -#endif return 0; } @@ -1618,15 +1352,10 @@ int connection_read(ber_socket_t s) "error=%d id=%lu, closing\n", s, rc, c->c_connid ); - /* connections_mutex and c_mutex are locked */ - -#ifdef SLAP_LIGHTWEIGHT_LISTENER - slapd_resume( s, 1 ); -#endif + /* c_mutex is locked */ connection_closing( c, "SASL layer install failure" ); connection_close( c ); connection_return( c ); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); return 0; } } @@ -1637,68 +1366,40 @@ int connection_read(ber_socket_t s) do { /* How do we do this without getting into a busy loop ? */ -#ifdef SLAP_LIGHTWEIGHT_LISTENER - rc = connection_input( c, op ); -#else - rc = connection_input( c ); -#endif - -#ifdef SLAP_LIGHTWEIGHT_LISTENER - if( *op && (*op)->o_tag == LDAP_REQ_UNBIND ) { - /* - * After the reception of an unbind request, - * no more incoming requests via the connection - * is expected. Therefore, don't resume connection reading. - */ - need_resume = 0; - } -#endif + rc = connection_input( c, cri ); } #ifdef DATA_READY_LOOP while( !rc && ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_DATA_READY, NULL )); -#elif CONNECTION_INPUT_LOOP +#elif defined CONNECTION_INPUT_LOOP while(!rc); #else while(0); #endif if( rc < 0 ) { - Debug( LDAP_DEBUG_TRACE, + Debug( LDAP_DEBUG_CONNS, "connection_read(%d): input error=%d id=%lu, closing.\n", s, rc, c->c_connid ); - /* connections_mutex and c_mutex are locked */ + /* c_mutex is locked */ connection_closing( c, conn_lost_str ); connection_close( c ); connection_return( c ); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); return 0; } -#ifdef SLAP_LIGHTWEIGHT_LISTENER - if ( need_resume ) slapd_resume( s, 1 ); -#endif - - if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_READ, NULL ) ) { - slapd_set_read( s, 1 ); - } - if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) { - slapd_set_write( s, 1 ); + slapd_set_write( s, 0 ); } + slapd_set_read( s, 1 ); connection_return( c ); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); return 0; } static int -#ifdef SLAP_LIGHTWEIGHT_LISTENER -connection_input( Connection *conn , Operation** c_op ) -#else -connection_input( Connection *conn ) -#endif +connection_input( Connection *conn , conn_readinfo *cri ) { Operation *op; ber_tag_t tag; @@ -1711,6 +1412,7 @@ connection_input( Connection *conn ) char *cdn = NULL; #endif char *defer = NULL; + void *ctx; if ( conn->c_currentber == NULL && ( conn->c_currentber = ber_alloc()) == NULL ) @@ -1719,7 +1421,7 @@ connection_input( Connection *conn ) return -1; } - errno = 0; + sock_errset(0); #ifdef LDAP_CONNECTIONLESS if ( conn->c_is_udp ) { @@ -1739,16 +1441,13 @@ connection_input( Connection *conn ) tag = ber_get_next( conn->c_sb, &len, conn->c_currentber ); if ( tag != LDAP_TAG_MESSAGE ) { - int err = errno; - ber_socket_t sd; - - ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); + int err = sock_errno(); - Debug( LDAP_DEBUG_TRACE, - "ber_get_next on fd %d failed errno=%d (%s)\n", - sd, err, sock_errstr(err) ); if ( err != EWOULDBLOCK && err != EAGAIN ) { /* log, close and send error */ + Debug( LDAP_DEBUG_TRACE, + "ber_get_next on fd %d failed errno=%d (%s)\n", + conn->c_sd, err, sock_errstr(err) ); ber_free( conn->c_currentber, 1 ); conn->c_currentber = NULL; @@ -1794,7 +1493,8 @@ connection_input( Connection *conn ) connection_abandon( conn ); } - op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ ); + ctx = cri->ctx; + op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++, ctx ); op->o_conn = conn; /* clear state if the connection is being reused from inactive */ @@ -1884,19 +1584,22 @@ connection_input( Connection *conn ) } else { conn->c_n_ops_executing++; -#ifdef SLAP_LIGHTWEIGHT_LISTENER /* * The first op will be processed in the same thread context, + * as long as there is only one op total. * Subsequent ops will be submitted to the pool by * calling connection_op_activate() */ - if ( *c_op == NULL ) { + if ( cri->op == NULL ) { /* the first incoming request */ connection_op_queue( op ); - *c_op = op; - } else -#endif - { + cri->op = op; + } else { + if ( !cri->nullop ) { + cri->nullop = 1; + rc = ldap_pvt_thread_pool_submit( &connection_pool, + connection_operation, (void *) cri->op ); + } connection_op_activate( op ); } } @@ -1918,39 +1621,10 @@ connection_resched( Connection *conn ) Operation *op; if( conn->c_conn_state == SLAP_C_CLOSING ) { - int rc; - ber_socket_t sd; - ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); - - /* use trylock to avoid possible deadlock */ - rc = ldap_pvt_thread_mutex_trylock( MCA_GET_CONN_MUTEX( sd ) ); - - if( rc ) { - Debug( LDAP_DEBUG_TRACE, - "connection_resched: reaquiring locks conn=%lu sd=%d\n", - conn->c_connid, sd, 0 ); - /* - * reaquire locks in the right order... - * this may allow another thread to close this connection, - * so recheck state below. - */ - ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); - ldap_pvt_thread_mutex_lock( MCA_GET_CONN_MUTEX ( sd ) ); - ldap_pvt_thread_mutex_lock( &conn->c_mutex ); - } - - if( conn->c_conn_state != SLAP_C_CLOSING ) { - Debug( LDAP_DEBUG_TRACE, "connection_resched: " - "closed by other thread conn=%lu sd=%d\n", - conn->c_connid, sd, 0 ); - } else { - Debug( LDAP_DEBUG_TRACE, "connection_resched: " - "attempting closing conn=%lu sd=%d\n", - conn->c_connid, sd, 0 ); - connection_close( conn ); - } - - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX( sd ) ); + Debug( LDAP_DEBUG_TRACE, "connection_resched: " + "attempting closing conn=%lu sd=%d\n", + conn->c_connid, conn->c_sd, 0 ); + connection_close( conn ); return 0; } @@ -1991,12 +1665,88 @@ connection_init_log_prefix( Operation *op ) } } +static int connection_bind_cleanup_cb( Operation *op, SlapReply *rs ) +{ + op->o_conn->c_sasl_bindop = NULL; + + ch_free( op->o_callback ); + op->o_callback = NULL; + + return SLAP_CB_CONTINUE; +} + +static int connection_bind_cb( Operation *op, SlapReply *rs ) +{ + ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); + if ( op->o_conn->c_conn_state == SLAP_C_BINDING ) + op->o_conn->c_conn_state = SLAP_C_ACTIVE; + op->o_conn->c_sasl_bind_in_progress = + ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS ); + + /* Moved here from bind.c due to ITS#4158 */ + op->o_conn->c_sasl_bindop = NULL; + if ( op->orb_method == LDAP_AUTH_SASL ) { + if( rs->sr_err == LDAP_SUCCESS ) { + ber_dupbv(&op->o_conn->c_dn, &op->orb_edn); + if( !BER_BVISEMPTY( &op->orb_edn ) ) { + /* edn is always normalized already */ + ber_dupbv( &op->o_conn->c_ndn, &op->o_conn->c_dn ); + } + op->o_tmpfree( op->orb_edn.bv_val, op->o_tmpmemctx ); + BER_BVZERO( &op->orb_edn ); + op->o_conn->c_authmech = op->o_conn->c_sasl_bind_mech; + BER_BVZERO( &op->o_conn->c_sasl_bind_mech ); + + op->o_conn->c_sasl_ssf = op->orb_ssf; + if( op->orb_ssf > op->o_conn->c_ssf ) { + op->o_conn->c_ssf = op->orb_ssf; + } + + if( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) { + ber_len_t max = sockbuf_max_incoming_auth; + ber_sockbuf_ctrl( op->o_conn->c_sb, + LBER_SB_OPT_SET_MAX_INCOMING, &max ); + } + + /* log authorization identity */ + Statslog( LDAP_DEBUG_STATS, + "%s BIND dn=\"%s\" mech=%s sasl_ssf=%d ssf=%d\n", + op->o_log_prefix, + BER_BVISNULL( &op->o_conn->c_dn ) ? "" : op->o_conn->c_dn.bv_val, + op->o_conn->c_authmech.bv_val, + op->orb_ssf, op->o_conn->c_ssf ); + + Debug( LDAP_DEBUG_TRACE, + "do_bind: SASL/%s bind: dn=\"%s\" sasl_ssf=%d\n", + op->o_conn->c_authmech.bv_val, + BER_BVISNULL( &op->o_conn->c_dn ) ? "" : op->o_conn->c_dn.bv_val, + op->orb_ssf ); + + } else if ( rs->sr_err != LDAP_SASL_BIND_IN_PROGRESS ) { + if ( !BER_BVISNULL( &op->o_conn->c_sasl_bind_mech ) ) { + free( op->o_conn->c_sasl_bind_mech.bv_val ); + BER_BVZERO( &op->o_conn->c_sasl_bind_mech ); + } + } + } + ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); + + ch_free( op->o_callback ); + op->o_callback = NULL; + + return SLAP_CB_CONTINUE; +} + static void connection_op_queue( Operation *op ) { - int status; ber_tag_t tag = op->o_tag; if (tag == LDAP_REQ_BIND) { + slap_callback *sc = ch_calloc( 1, sizeof( slap_callback )); + sc->sc_response = connection_bind_cb; + sc->sc_cleanup = connection_bind_cleanup_cb; + sc->sc_next = op->o_callback; + op->o_callback = sc; op->o_conn->c_conn_state = SLAP_C_BINDING; } @@ -2033,22 +1783,21 @@ static void connection_op_queue( Operation *op ) static int connection_op_activate( Operation *op ) { - int status; - ber_tag_t tag = op->o_tag; + int rc; connection_op_queue( op ); - status = ldap_pvt_thread_pool_submit( &connection_pool, + rc = ldap_pvt_thread_pool_submit( &connection_pool, connection_operation, (void *) op ); - if ( status != 0 ) { + if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, - "ldap_pvt_thread_pool_submit: failed (%d) for conn=%lu\n", - status, op->o_connid, 0 ); + "connection_op_activate: submit failed (%d) for conn=%lu\n", + rc, op->o_connid, 0 ); /* should move op to pending list */ } - return status; + return rc; } int connection_write(ber_socket_t s) @@ -2058,19 +1807,16 @@ int connection_write(ber_socket_t s) assert( connections != NULL ); - ldap_pvt_thread_mutex_lock( MCA_GET_CONN_MUTEX( s ) ); + slapd_clr_write( s, 0 ); c = connection_get( s ); if( c == NULL ) { Debug( LDAP_DEBUG_ANY, "connection_write(%ld): no connection!\n", (long)s, 0, 0 ); - slapd_remove(s, 1, 0); - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX( s ) ); return -1; } - slapd_clr_write( s, 0); c->c_n_write++; Debug( LDAP_DEBUG_TRACE, @@ -2105,20 +1851,82 @@ int connection_write(ber_socket_t s) break; } + connection_return( c ); + return 0; +} - ldap_pvt_thread_mutex_unlock( MCA_GET_CONN_MUTEX(s) ); +#ifdef LDAP_SLAPI +typedef struct conn_fake_extblock { + void *eb_conn; + void *eb_op; +} conn_fake_extblock; - return 0; +static void +connection_fake_destroy( + void *key, + void *data ) +{ + Connection conn = {0}; + Operation op = {0}; + Opheader ohdr = {0}; + + conn_fake_extblock *eb = data; + + op.o_hdr = &ohdr; + op.o_hdr->oh_extensions = eb->eb_op; + conn.c_extensions = eb->eb_conn; + op.o_conn = &conn; + conn.c_connid = -1; + op.o_connid = -1; + + ber_memfree_x( eb, NULL ); + slapi_int_free_object_extensions( SLAPI_X_EXT_OPERATION, &op ); + slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION, &conn ); } +#endif void connection_fake_init( Connection *conn, - Operation *op, + OperationBuffer *opbuf, void *ctx ) { + connection_fake_init2( conn, opbuf, ctx, 1 ); +} + +void +operation_fake_init( + Connection *conn, + Operation *op, + void *ctx, + int newmem ) +{ + /* set memory context */ + op->o_tmpmemctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, + newmem ); + op->o_tmpmfuncs = &slap_sl_mfuncs; + op->o_threadctx = ctx; + op->o_tid = ldap_pvt_thread_pool_tid( ctx ); + + op->o_counters = &slap_counters; + op->o_conn = conn; + op->o_connid = op->o_conn->c_connid; + connection_init_log_prefix( op ); +} + + +void +connection_fake_init2( + Connection *conn, + OperationBuffer *opbuf, + void *ctx, + int newmem ) +{ + Operation *op = (Operation *) opbuf; + conn->c_connid = -1; + conn->c_conn_idx = -1; conn->c_send_ldap_result = slap_send_ldap_result; conn->c_send_search_entry = slap_send_search_entry; conn->c_send_search_reference = slap_send_search_reference; @@ -2126,17 +1934,34 @@ connection_fake_init( conn->c_peer_domain = slap_empty_bv; conn->c_peer_name = slap_empty_bv; - memset(op, 0, OPERATION_BUFFER_SIZE); - op->o_hdr = (Opheader *)(op+1); - op->o_controls = (void **)(op->o_hdr+1); - /* set memory context */ - op->o_tmpmemctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx); - op->o_tmpmfuncs = &slap_sl_mfuncs; - op->o_threadctx = ctx; + memset( opbuf, 0, sizeof( *opbuf )); + op->o_hdr = &opbuf->ob_hdr; + op->o_controls = opbuf->ob_controls; - op->o_conn = conn; - op->o_connid = op->o_conn->c_connid; - connection_init_log_prefix( op ); + operation_fake_init( conn, op, ctx, newmem ); + +#ifdef LDAP_SLAPI + if ( slapi_plugins_used ) { + conn_fake_extblock *eb; + void *ebx = NULL; + + /* Use thread keys to make sure these eventually get cleaned up */ + if ( ldap_pvt_thread_pool_getkey( ctx, connection_fake_init, &ebx, + NULL )) { + eb = ch_malloc( sizeof( *eb )); + slapi_int_create_object_extensions( SLAPI_X_EXT_CONNECTION, conn ); + slapi_int_create_object_extensions( SLAPI_X_EXT_OPERATION, op ); + eb->eb_conn = conn->c_extensions; + eb->eb_op = op->o_hdr->oh_extensions; + ldap_pvt_thread_pool_setkey( ctx, connection_fake_init, eb, + connection_fake_destroy ); + } else { + eb = ebx; + conn->c_extensions = eb->eb_conn; + op->o_hdr->oh_extensions = eb->eb_op; + } + } +#endif /* LDAP_SLAPI */ slap_op_time( &op->o_time, &op->o_tincr ); }