From 8f02beada9ef54a5264baae6352fda7c7fbcb63b Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Mon, 22 Mar 1999 07:14:54 +0000 Subject: [PATCH] PROTOTYPE: New connection management infrastructure designed to remove race conditions on connection close. BROKEN: various counters for dn=monitor. Initial testing on FreeBSD (with and without pthreads) was successfull. Have not yet tested preemptive threading environments. Have not built against backends other than LDBM. --- servers/slapd/abandon.c | 13 +- servers/slapd/acl.c | 7 +- servers/slapd/add.c | 6 +- servers/slapd/back-ldbm/dbcache.c | 4 +- servers/slapd/back-ldbm/search.c | 7 +- servers/slapd/bind.c | 12 +- servers/slapd/connection.c | 555 +++++++++++++++++++++++++++--- servers/slapd/daemon.c | 539 +++++++++++++++++------------ servers/slapd/init.c | 32 +- servers/slapd/main.c | 143 ++------ servers/slapd/modify.c | 7 +- servers/slapd/monitor.c | 89 ++--- servers/slapd/operation.c | 15 +- servers/slapd/proto-slap.h | 55 ++- servers/slapd/repl.c | 2 +- servers/slapd/result.c | 136 +++----- servers/slapd/slap.h | 83 +++-- servers/slapd/tools/Makefile.in | 8 +- servers/slapd/tools/mimic.c | 48 +++ servers/slapd/unbind.c | 3 - 20 files changed, 1169 insertions(+), 595 deletions(-) create mode 100644 servers/slapd/tools/mimic.c diff --git a/servers/slapd/abandon.c b/servers/slapd/abandon.c index ea29321b3f..4a55d34e11 100644 --- a/servers/slapd/abandon.c +++ b/servers/slapd/abandon.c @@ -49,19 +49,28 @@ do_abandon( * flag and abort the operation at a convenient time. */ - ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + for ( o = conn->c_ops; o != NULL; o = o->o_next ) { + if ( o->o_msgid == id ) + goto found_op; + } + for ( o = conn->c_pending_ops; o != NULL; o = o->o_next ) { if ( o->o_msgid == id ) break; } +found_op: + if ( o != NULL ) { ldap_pvt_thread_mutex_lock( &o->o_abandonmutex ); o->o_abandon = 1; ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex ); + } else { Debug( LDAP_DEBUG_TRACE, "do_abandon: op not found\n", 0, 0, 0 ); } - ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); + + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); } diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index f029d3ccfd..483aba6dd6 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -287,7 +287,9 @@ acl_access_allowed( } } if ( b->a_addrpat != NULL ) { - if ( regex_matches( b->a_addrpat, conn->c_addr, edn, matches ) ) { + if ( regex_matches( b->a_addrpat, conn->c_client_addr, + edn, matches ) ) + { Debug( LDAP_DEBUG_ACL, "<= acl_access_allowed: matched by clause #%d access %s\n", i, (b->a_access & ~ACL_SELF) >= access ? @@ -299,7 +301,8 @@ acl_access_allowed( if ( b->a_domainpat != NULL ) { Debug( LDAP_DEBUG_ARGS, "<= check a_domainpath: %s\n", b->a_domainpat, 0, 0 ); - if ( regex_matches( b->a_domainpat, conn->c_domain, edn, matches ) ) + if ( regex_matches( b->a_domainpat, conn->c_client_name, + edn, matches ) ) { Debug( LDAP_DEBUG_ACL, "<= acl_access_allowed: matched by clause #%d access %s\n", diff --git a/servers/slapd/add.c b/servers/slapd/add.c index 7dcd020f92..16eed3a63c 100644 --- a/servers/slapd/add.c +++ b/servers/slapd/add.c @@ -151,6 +151,7 @@ add_created_attrs( Operation *op, Entry *e ) Attribute **a, **next; Attribute *tmp; struct tm *ltm; + time_t currenttime; Debug( LDAP_DEBUG_TRACE, "add_created_attrs\n", 0, 0, 0 ); @@ -181,7 +182,8 @@ add_created_attrs( Operation *op, Entry *e ) } attr_merge( e, "creatorsname", bvals ); - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); + currenttime = slap_get_time(); + ldap_pvt_thread_mutex_lock( &gmtime_mutex ); #ifndef LDAP_LOCALTIME ltm = gmtime( ¤ttime ); strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm ); @@ -189,7 +191,7 @@ add_created_attrs( Operation *op, Entry *e ) ltm = localtime( ¤ttime ); strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm ); #endif - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); + ldap_pvt_thread_mutex_unlock( &gmtime_mutex ); bv.bv_val = buf; bv.bv_len = strlen( bv.bv_val ); diff --git a/servers/slapd/back-ldbm/dbcache.c b/servers/slapd/back-ldbm/dbcache.c index f563cb61c1..58b7b8571d 100644 --- a/servers/slapd/back-ldbm/dbcache.c +++ b/servers/slapd/back-ldbm/dbcache.c @@ -41,9 +41,7 @@ ldbm_cache_open( flags, li->li_mode ); lru = 0; - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); - curtime = currenttime; - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); + curtime = slap_get_time(); oldtime = curtime; ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); diff --git a/servers/slapd/back-ldbm/search.c b/servers/slapd/back-ldbm/search.c index 5def38a2b3..04e0593193 100644 --- a/servers/slapd/back-ldbm/search.c +++ b/servers/slapd/back-ldbm/search.c @@ -139,6 +139,7 @@ ldbm_back_search( rcur = strchr( rbuf, '\0' ); for ( id = idl_firstid( candidates ); id != NOID; id = idl_nextid( candidates, id ) ) { + /* check for abandon */ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); if ( op->o_abandon ) { @@ -153,10 +154,7 @@ ldbm_back_search( ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); /* check time limit */ - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); - time( ¤ttime ); - if ( tlimit != -1 && currenttime > stoptime ) { - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); + if ( tlimit != -1 && slap_get_time() > stoptime ) { send_ldap_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf : NULL, nentries ); @@ -167,7 +165,6 @@ ldbm_back_search( } return( 0 ); } - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); /* get the entry with reader lock */ if ( (e = id2entry_r( be, id )) == NULL ) { diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c index cf0b2af328..223401aa1b 100644 --- a/servers/slapd/bind.c +++ b/servers/slapd/bind.c @@ -135,7 +135,7 @@ do_bind( free( cred.bv_val ); } - ldap_pvt_thread_mutex_lock( &conn->c_dnmutex ); + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); conn->c_protocol = version; @@ -149,7 +149,7 @@ do_bind( conn->c_dn = NULL; } - ldap_pvt_thread_mutex_unlock( &conn->c_dnmutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); return; @@ -168,7 +168,7 @@ do_bind( free( cred.bv_val ); } if ( cred.bv_len == 0 ) { - ldap_pvt_thread_mutex_lock( &conn->c_dnmutex ); + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); conn->c_protocol = version; @@ -182,7 +182,7 @@ do_bind( conn->c_dn = NULL; } - ldap_pvt_thread_mutex_unlock( &conn->c_dnmutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); @@ -203,7 +203,7 @@ do_bind( ndn = suffixAlias( ndn, op, be ); if ( (*be->be_bind)( be, conn, op, ndn, method, &cred, &edn ) == 0 ) { - ldap_pvt_thread_mutex_lock( &conn->c_dnmutex ); + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); conn->c_protocol = version; @@ -228,7 +228,7 @@ do_bind( Debug( LDAP_DEBUG_TRACE, "do_bind: bound \"%s\" to \"%s\"\n", conn->c_cdn, conn->c_dn, method ); - ldap_pvt_thread_mutex_unlock( &conn->c_dnmutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); /* send this here to avoid a race condition */ send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 7587147733..4f2a5cec00 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -10,6 +10,16 @@ #include "slap.h" +/* protected by connections_mutex */ +static ldap_pvt_thread_mutex_t connections_mutex; +static Connection *connections = NULL; +static int conn_index = -1; +static long conn_nextid = 0; + +static Connection* connection_get( int s ); + +static int connection_input( Connection *c ); + static int connection_op_activate( Connection *conn, Operation *op ); static int connection_resched( Connection *conn ); @@ -18,6 +28,360 @@ struct co_arg { Operation *co_op; }; +/* + * Initialize connection management infrastructure. + */ +int connections_init(void) +{ + int i; + + assert( connections == NULL ); + + if( connections != NULL) { /* probably should assert this */ + Debug( LDAP_DEBUG_ANY, "connections_init: already initialized.\n", + 0, 0, 0 ); + return -1; + } + + /* should check return of every call */ + ldap_pvt_thread_mutex_init( &connections_mutex ); + + connections = (Connection *) calloc( dtblsize, sizeof(Connection) ); + + if( connections == NULL ) { + Debug( LDAP_DEBUG_ANY, + "connections_init: allocation (%d*%ld) of connection array failed.\n", + dtblsize, (long) sizeof(Connection), 0 ); + return -1; + } + + /* + * per entry initialization of the Connection array initialization + * will be done by connection_init() + */ + + return 0; +} + +static Connection* connection_get( int s ) +{ + Connection *c = NULL; + + assert( connections != NULL ); + + if(s < 0) { + return NULL; + } + +#ifndef HAVE_WINSOCK + assert( connections[s].c_struct_state == SLAP_C_USED ); + assert( connections[s].c_conn_state != SLAP_C_INVALID ); + assert( connections[s].c_sb.sb_sd != -1 ); + + c = &connections[s]; +#else + { + int i; + + for(i=0; ic_mutex ); + } + return c; +} + +static void connection_return( Connection *c ) +{ + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); +} + +long connection_init( + int s, + const char* name, + const char* addr) +{ + long id; + Connection *c; + assert( connections != NULL ); + + if( s < 0 ) { + return -1; + } + + assert( s >= 0 ); +#ifndef HAVE_WINSOCK + assert( s < dtblsize ); +#endif + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + +#ifndef HAVE_WINSOCK + c = &connections[s]; + +#else + { + int i; + + for( i=0; i < dtblsize; i++ { + if( connections[i].c_struct_state == SLAP_C_UNINITIALIZED ) { + assert( connections[i].c_sb.sb_sd == 0 ); + c = &connections[i]; + break; + } + + if( connections[i].c_struct_state == SLAP_C_UNUSED ) { + assert( connections[i].c_sb.sb_sd == -1 ); + c = &connections[i]; + break; + } + + assert( connections[i].c_struct_state == SLAP_C_USED ); + assert( connections[i].c_conn_state != SLAP_C_INVALID ); + assert( connections[i].c_sb.sb_sd != -1 ); + } + + if( c == NULL ) { + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return -1; + } + } +#endif + + assert( c != NULL ); + assert( c->c_struct_state != SLAP_C_USED ); + assert( c->c_conn_state == SLAP_C_INVALID ); + + if( c->c_struct_state == SLAP_C_UNINITIALIZED ) { + c->c_dn = NULL; + c->c_cdn = NULL; + c->c_client_name = NULL; + c->c_client_addr = NULL; + c->c_ops = NULL; + c->c_pending_ops = NULL; + + lber_pvt_sb_init( &c->c_sb ); + + /* should check status of thread calls */ + ldap_pvt_thread_mutex_init( &c->c_mutex ); + ldap_pvt_thread_mutex_init( &c->c_write_mutex ); + ldap_pvt_thread_cond_init( &c->c_write_cv ); + + c->c_struct_state = SLAP_C_UNUSED; + } + + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + + assert( c->c_struct_state == SLAP_C_UNUSED ); + assert( c->c_dn == NULL ); + assert( c->c_cdn == NULL ); + assert( c->c_client_name == NULL ); + assert( c->c_client_addr == NULL ); + assert( c->c_ops == NULL ); + assert( c->c_pending_ops == NULL ); + + c->c_client_name = ch_strdup( name == NULL ? "" : name ); + c->c_client_addr = ch_strdup( addr ); + + c->c_n_ops_received = 0; +#ifdef LDAP_COUNTERS + c->c_n_ops_executing = 0; + c->c_n_ops_pending = 0; + c->c_n_ops_completed = 0; +#endif + + c->c_starttime = slap_get_time(); + + lber_pvt_sb_set_desc( &c->c_sb, s ); + lber_pvt_sb_set_io( &c->c_sb, &lber_pvt_sb_io_tcp, NULL ); + + if( lber_pvt_sb_set_nonblock( &c->c_sb, 1 ) < 0 ) { + Debug( LDAP_DEBUG_ANY, + "connection_init(%d, %s, %s): set nonblocking failed\n", + s, c->c_client_name, c->c_client_addr); + } + + id = c->c_connid = conn_nextid++; + + c->c_conn_state = SLAP_C_INACTIVE; + c->c_struct_state = SLAP_C_USED; + + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + + return id; +} + +static void +connection_destroy( Connection *c ) +{ + assert( connections != NULL ); + assert( c != NULL ); + assert( c->c_struct_state != SLAP_C_UNUSED ); + assert( c->c_conn_state != SLAP_C_INVALID ); + assert( c->c_ops == NULL ); + + c->c_struct_state = SLAP_C_UNUSED; + c->c_conn_state = SLAP_C_INVALID; + + c->c_version = 0; + c->c_protocol = 0; + + c->c_starttime = 0; + + if(c->c_dn != NULL) { + free(c->c_dn); + c->c_dn = NULL; + } + if(c->c_cdn != NULL) { + free(c->c_cdn); + c->c_cdn = NULL; + } + if(c->c_client_name != NULL) { + free(c->c_client_name); + c->c_client_name = NULL; + } + if(c->c_client_addr != NULL) { + free(c->c_client_addr); + c->c_client_addr = NULL; + } + + if ( lber_pvt_sb_in_use(&c->c_sb) ) { + int sd = lber_pvt_sb_get_desc(&c->c_sb); + + slapd_remove( sd ); + lber_pvt_sb_close( &c->c_sb ); + + Statslog( LDAP_DEBUG_STATS, + "conn=%d fd=%d closed.\n", + c->c_connid, sd, 0, 0, 0 ); + } + + lber_pvt_sb_destroy( &c->c_sb ); +} + +static void connection_close( Connection *c ) +{ + assert( connections != NULL ); + assert( c != NULL ); + assert( c->c_struct_state == SLAP_C_USED ); + assert( c->c_conn_state == SLAP_C_CLOSING ); + + if( c->c_ops != NULL ) { + Debug( LDAP_DEBUG_TRACE, + "connection_close: deferring conn=%ld sd=%d.\n", + c->c_connid, c->c_sb.sb_sd, 0 ); + + return; + } + + Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%ld sd=%d.\n", + c->c_connid, c->c_sb.sb_sd, 0 ); + + connection_destroy( c ); +} + +long connections_nextid(void) +{ + long id; + assert( connections != NULL ); + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + + id = conn_nextid; + + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + + return id; +} + +Connection* connection_first(void) +{ + assert( connections != NULL ); + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + + assert( conn_index == -1 ); + conn_index = 0; + + return connection_next(NULL); +} + +Connection* connection_next(Connection *c) +{ + assert( connections != NULL ); + assert( conn_index != -1 ); + assert( conn_index <= dtblsize ); + + if( c != NULL ) { + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + } + + c = NULL; + + for(; conn_index < dtblsize; conn_index++) { + if( connections[conn_index].c_struct_state == SLAP_C_UNINITIALIZED ) { + assert( connections[conn_index].c_conn_state == SLAP_C_INVALID ); +#ifndef HAVE_WINSOCK + continue; +#else + break; +#endif + } + + if( connections[conn_index].c_struct_state == SLAP_C_USED ) { + assert( connections[conn_index].c_conn_state != SLAP_C_INVALID ); + c = &connections[conn_index++]; + break; + } + + assert( connections[conn_index].c_struct_state == SLAP_C_UNUSED ); + assert( connections[conn_index].c_conn_state == SLAP_C_INVALID ); + } + + if( c != NULL ) { + ldap_pvt_thread_mutex_lock( &c->c_mutex ); + } + + return c; +} + +void connection_done(Connection *c) +{ + assert( connections != NULL ); + assert( conn_index != -1 ); + assert( conn_index <= dtblsize ); + + if( c != NULL ) { + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + } + + conn_index = -1; + ldap_pvt_thread_mutex_unlock( &connections_mutex ); +} + /* * connection_activity - handle the request operation op on connection * conn. This routine figures out what kind of operation it is and @@ -31,13 +395,11 @@ connection_operation( void *arg_v ) int tag = arg->co_op->o_tag; Connection *conn = arg->co_conn; - ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); - conn->c_ops_received++; - ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); - +#ifdef LDAP_COUNTERS ldap_pvt_thread_mutex_lock( &ops_mutex ); ops_initiated++; ldap_pvt_thread_mutex_unlock( &ops_mutex ); +#endif switch ( tag ) { case LDAP_REQ_BIND: @@ -91,12 +453,17 @@ connection_operation( void *arg_v ) break; } +#ifdef LDAP_COUNTERS ldap_pvt_thread_mutex_lock( &ops_mutex ); ops_completed++; ldap_pvt_thread_mutex_unlock( &ops_mutex ); +#endif + + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); - ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); +#ifdef LDAP_COUNTERS conn->c_ops_completed++; +#endif slap_op_remove( &conn->c_ops, arg->co_op ); slap_op_free( arg->co_op ); @@ -105,11 +472,27 @@ connection_operation( void *arg_v ) free( (char *) arg ); arg = NULL; - if((tag == LDAP_REQ_BIND) && (conn->c_state == SLAP_C_BINDING)) { - conn->c_state = SLAP_C_ACTIVE; + switch( tag ) { +#ifdef LDAP_COMPAT30 + case LDAP_REQ_UNBIND_30: +#endif + case LDAP_REQ_UNBIND: + conn->c_conn_state = SLAP_C_CLOSING; + break; + + case LDAP_REQ_BIND: + if( conn->c_conn_state == SLAP_C_BINDING) { + conn->c_conn_state = SLAP_C_ACTIVE; + } } - ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); + if( conn->c_conn_state == SLAP_C_CLOSING ) { + Debug( LDAP_DEBUG_TRACE, + "connection_operation: attempting closing conn=%ld sd=%d.\n", + conn->c_connid, conn->c_sb.sb_sd, 0 ); + + connection_close( conn ); + } ldap_pvt_thread_mutex_lock( &active_threads_mutex ); active_threads--; @@ -120,11 +503,58 @@ connection_operation( void *arg_v ) connection_resched( conn ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + return NULL; } -void -connection_activity( +int connection_read(int s) +{ + int rc = 0; + Connection *c; + assert( connections != NULL ); + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + + c = connection_get( s ); + if( c == NULL ) { + Debug( LDAP_DEBUG_ANY, + "connection_read(%d): no connection!\n", + s, 0, 0 ); + return -1; + } + + Debug( LDAP_DEBUG_TRACE, + "connection_read(%d): checking for input on id=%ld\n", + s, c->c_connid, 0 ); + +#define CONNECTION_INPUT_LOOP 1 + +#ifdef DATA_READY_LOOP + while(!rc && lber_pvt_sb_data_ready(&c->c_sb)) +#elif CONNECTION_INPUT_LOOP + while(!rc) +#endif + { + rc = connection_input( c ); + } + + if( rc < 0 ) { + Debug( LDAP_DEBUG_TRACE, + "connection_read(%d): input error id=%ld, closing.\n", + s, c->c_connid, 0 ); + + c->c_conn_state = SLAP_C_CLOSING; + connection_close( c ); + } + + connection_return( c ); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return 0; +} + +static int +connection_input( Connection *conn ) { @@ -136,30 +566,32 @@ connection_activity( if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc()) == NULL ) { Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 ); - return; + return -1; } errno = 0; if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber )) - != LDAP_TAG_MESSAGE ) { + != LDAP_TAG_MESSAGE ) + { Debug( LDAP_DEBUG_TRACE, - "ber_get_next on fd %d failed errno %d (%s)\n", - lber_pvt_sb_get_desc(&conn->c_sb), errno, errno > -1 && errno < sys_nerr ? - sys_errlist[errno] : "unknown" ); - Debug( LDAP_DEBUG_TRACE, "*** got %ld of %lu so far\n", - (long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf), - conn->c_currentber->ber_len, 0 ); + "ber_get_next on fd %d failed errno %d (%s)\n", + lber_pvt_sb_get_desc(&conn->c_sb), errno, + errno > -1 && errno < sys_nerr ? sys_errlist[errno] : "unknown" ); + Debug( LDAP_DEBUG_TRACE, "\t*** got %ld of %lu so far\n", + (long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf), + conn->c_currentber->ber_len, 0 ); if ( errno != EWOULDBLOCK && errno != EAGAIN ) { /* log, close and send error */ ber_free( conn->c_currentber, 1 ); conn->c_currentber = NULL; - close_connection( conn, conn->c_connid, -1 ); + return -1; } - return; + return 1; } + ber = conn->c_currentber; conn->c_currentber = NULL; @@ -168,9 +600,7 @@ connection_activity( Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0, 0 ); ber_free( ber, 1 ); - - close_connection( conn, conn->c_connid, -1 ); - return; + return -1; } if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) { @@ -179,8 +609,7 @@ connection_activity( 0 ); ber_free( ber, 1 ); - close_connection( conn, conn->c_connid, -1 ); - return; + return -1; } #ifdef LDAP_COMPAT30 @@ -189,22 +618,27 @@ connection_activity( } #endif - op = slap_op_alloc( ber, msgid, tag, - conn->c_ops_received, conn->c_connid ); - - if ( conn->c_state == SLAP_C_BINDING ) { - /* connection is binding to a dn, make 'em wait */ - ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); - slap_op_add( &conn->c_pending_ops, op ); + op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ ); + if ( conn->c_conn_state == SLAP_C_BINDING + || conn->c_conn_state == SLAP_C_CLOSING ) + { Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 ); + slap_op_add( &conn->c_pending_ops, op ); - ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); + } else { + connection_op_activate( conn, op ); + } - return; +#ifdef NO_THREADS + if ( conn->c_struct_state != SLAP_C_USED ) { + /* connection must have got closed underneath us */ + return 1; } +#endif + assert( conn->c_struct_state == SLAP_C_USED ); - connection_op_activate( conn, op ); + return 0; } static int @@ -212,29 +646,21 @@ connection_resched( Connection *conn ) { Operation *op; - if( conn->c_state != SLAP_C_ACTIVE ) { + if( conn->c_conn_state != SLAP_C_ACTIVE ) { /* other states need different handling */ return; } - ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); - for( op = slap_op_pop( &conn->c_pending_ops ); op != NULL; op = slap_op_pop( &conn->c_pending_ops ) ) { - ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); - connection_op_activate( conn, op ); - ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); - - if ( conn->c_state == SLAP_C_BINDING ) { + if ( conn->c_conn_state == SLAP_C_BINDING ) { break; } } - - ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); } static int connection_op_activate( Connection *conn, Operation *op ) @@ -244,13 +670,11 @@ static int connection_op_activate( Connection *conn, Operation *op ) int status; unsigned long tag = op->o_tag; - ldap_pvt_thread_mutex_lock( &conn->c_dnmutex ); if ( conn->c_dn != NULL ) { tmpdn = ch_strdup( conn->c_dn ); } else { tmpdn = NULL; } - ldap_pvt_thread_mutex_unlock( &conn->c_dnmutex ); arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) ); arg->co_conn = conn; @@ -259,16 +683,12 @@ static int connection_op_activate( Connection *conn, Operation *op ) arg->co_op->o_dn = ch_strdup( tmpdn != NULL ? tmpdn : "" ); arg->co_op->o_ndn = dn_normalize_case( ch_strdup( arg->co_op->o_dn ) ); - ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); - slap_op_add( &conn->c_ops, arg->co_op ); if(tag == LDAP_REQ_BIND) { - conn->c_state = SLAP_C_BINDING; + conn->c_conn_state = SLAP_C_BINDING; } - ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); - if ( tmpdn != NULL ) { free( tmpdn ); } @@ -281,8 +701,37 @@ static int connection_op_activate( Connection *conn, Operation *op ) connection_operation, (void *) arg ); if ( status != 0 ) { - Debug( LDAP_DEBUG_ANY, "ldap_pvt_thread_create failed (%d)\n", status, 0, 0 ); + Debug( LDAP_DEBUG_ANY, + "ldap_pvt_thread_create failed (%d)\n", status, 0, 0 ); + + /* should move op to pending list */ } return status; } + +int connection_write(int s) +{ + Connection *c; + assert( connections != NULL ); + + ldap_pvt_thread_mutex_lock( &connections_mutex ); + + c = connection_get( s ); + if( c == NULL ) { + Debug( LDAP_DEBUG_ANY, + "connection_write(%d): no connection!\n", + s, 0, 0 ); + return -1; + } + + Debug( LDAP_DEBUG_TRACE, + "connection_write(%d): waking output for id=%ld\n", + s, c->c_connid, 0 ); + + ldap_pvt_thread_cond_signal( &c->c_write_cv ); + + connection_return( c ); + ldap_pvt_thread_mutex_unlock( &connections_mutex ); + return 0; +} diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 4596840b00..6294f4fb4a 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -1,10 +1,3 @@ - -/* Revision history - * - * 5-Jun-96 hodges - * Added locking of new_conn_mutex when traversing the c[] array. - */ - #include "portable.h" #include @@ -33,26 +26,113 @@ int allow_severity = LOG_INFO; int deny_severity = LOG_NOTICE; #endif /* TCP Wrappers */ -int dtblsize; -Connection *c; +/* globals */ +int dtblsize; +static ldap_pvt_thread_t listener_tid; static volatile sig_atomic_t slapd_shutdown = 0; -/* a link to the slapd.conf configuration parameters */ -extern char *slapd_pid_file; -extern char *slapd_args_file; +struct slap_daemon { + ldap_pvt_thread_mutex_t sd_mutex; + + int sd_nactives; + +#ifndef HAVE_WINSOCK + /* In winsock, accept() returns values higher than dtblsize + so don't bother with this optimization */ + int sd_nfds; +#endif + + fd_set sd_actives; + fd_set sd_readers; + fd_set sd_writers; +} slap_daemon; + +/* + * Add a descriptor to daemon control + */ +static void slapd_add(int s) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + assert( !FD_ISSET( s, &slap_daemon.sd_actives )); + assert( !FD_ISSET( s, &slap_daemon.sd_readers )); + assert( !FD_ISSET( s, &slap_daemon.sd_writers )); + + if (s >= slap_daemon.sd_nfds) { + slap_daemon.sd_nfds = s + 1; + } + + FD_SET( s, &slap_daemon.sd_actives ); + FD_SET( s, &slap_daemon.sd_readers ); + + Debug( LDAP_DEBUG_CONNS, "daemon: added %d%s%s\n", s, + FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "", + FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); +} + +/* + * Remove the descriptor from daemon control + */ +void slapd_remove(int s) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + assert( s < slap_daemon.sd_nfds ); + assert( FD_ISSET( s, &slap_daemon.sd_actives )); + + Debug( LDAP_DEBUG_CONNS, "daemon: removing %d%s%s\n", s, + FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "", + FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" ); + + FD_CLR( s, &slap_daemon.sd_actives ); + FD_CLR( s, &slap_daemon.sd_readers ); + FD_CLR( s, &slap_daemon.sd_writers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); +} + +void slapd_clr_write(int s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + assert( s < slap_daemon.sd_nfds ); + assert( FD_ISSET( s, &slap_daemon.sd_actives) ); + assert( FD_ISSET( s, &slap_daemon.sd_writers) ); + FD_SET( s, &slap_daemon.sd_writers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + + if( wake ) { + ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 ); + } +} + +void slapd_set_write(int s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + FD_SET( s, &slap_daemon.sd_writers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); -void * -slapd_daemon( + if( wake ) { + ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 ); + } +} + +static void slapd_close(int s) { + slapd_remove(s); + + Debug( LDAP_DEBUG_CONNS, "daemon: closing %d\n", s, 0, 0 ); + close(s); +} + +static void * +slapd_daemon_task( void *ptr ) { struct sockaddr_in *addr = ptr; - int i; - int tcps, ns; - fd_set readfds; - fd_set writefds; - FILE *fp; + int tcps = -1; #ifdef HAVE_SYSCONF dtblsize = sysconf( _SC_OPEN_MAX ); @@ -68,179 +148,201 @@ slapd_daemon( } #endif /* !FD_SETSIZE */ - c = (Connection *) ch_calloc( (size_t) dtblsize, sizeof(Connection) ); - - for ( i = 0; i < dtblsize; i++ ) { - c[i].c_dn = NULL; - c[i].c_cdn = NULL; - c[i].c_addr = NULL; - c[i].c_domain = NULL; - c[i].c_ops = NULL; - lber_pvt_sb_init( &c[i].c_sb ); - ldap_pvt_thread_mutex_init( &c[i].c_dnmutex ); - ldap_pvt_thread_mutex_init( &c[i].c_opsmutex ); - ldap_pvt_thread_mutex_init( &c[i].c_pdumutex ); - ldap_pvt_thread_cond_init( &c[i].c_wcv ); - } + connections_init(); - if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) { - Debug( LDAP_DEBUG_ANY, "socket() failed errno %d (%s)", errno, - errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - exit( 1 ); - } + ldap_pvt_thread_mutex_init( &slap_daemon.sd_mutex ); + FD_ZERO( &slap_daemon.sd_readers ); + FD_ZERO( &slap_daemon.sd_writers ); - i = 1; - if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR, (char *) &i, - sizeof(i) ) == -1 ) { - Debug( LDAP_DEBUG_ANY, "setsockopt() failed errno %d (%s)", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - } + if( addr != NULL ) { + int tmp; - if ( bind( tcps, (struct sockaddr *) addr, sizeof(*addr) ) == -1 ) { - Debug( LDAP_DEBUG_ANY, "bind() failed errno %d (%s)\n", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - exit( 1 ); - } + if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) { + Debug( LDAP_DEBUG_ANY, + "daemon: socket() failed errno %d (%s)", errno, + errno > -1 && errno < sys_nerr ? sys_errlist[errno] : + "unknown", 0 ); + exit( 1 ); + } - if ( listen( tcps, 5 ) == -1 ) { - Debug( LDAP_DEBUG_ANY, "listen() failed errno %d (%s)", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - exit( 1 ); - } +#ifndef HAVE_WINSOCK + if ( tcps >= dtblsize ) { + Debug( LDAP_DEBUG_ANY, + "daemon: listener descriptor %d is too great", + tcps, dtblsize, 0 ); + exit( 1 ); + } +#endif - Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 ); + tmp = 1; + if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR, + (char *) &tmp, sizeof(tmp) ) == -1 ) + { + Debug( LDAP_DEBUG_ANY, + "slapd(%d): setsockopt() failed errno %d (%s)", + tcps, errno, + errno > -1 && errno < sys_nerr + ? sys_errlist[errno] : "unknown" ); + + errno = 0; + } - if (( slapd_pid_file != NULL ) && - (( fp = fopen( slapd_pid_file, "w" )) != NULL )) { - fprintf( fp, "%d\n", (int) getpid() ); - fclose( fp ); - } + if ( bind( tcps, (struct sockaddr *) addr, sizeof(*addr) ) == -1 ) { + Debug( LDAP_DEBUG_ANY, "daemon: bind(%d) failed errno %d (%s)\n", + tcps, errno, + errno > -1 && errno < sys_nerr + ? sys_errlist[errno] : "unknown" ); + exit( 1 ); + } + + if ( listen( tcps, 5 ) == -1 ) { + Debug( LDAP_DEBUG_ANY, + "daemon: listen(%d, 5) failed errno %d (%s)\n", + tcps, errno, + errno > -1 && errno < sys_nerr + ? sys_errlist[errno] : "unknown" ); + exit( 1 ); + } + + slapd_add( tcps ); - if (( slapd_args_file != NULL ) && - (( fp = fopen( slapd_args_file, "w" )) != NULL )) { - for ( i = 0; i < g_argc; i++ ) { - fprintf( fp, "%s ", g_argv[i] ); + } else { + if( connection_init( 0, NULL, NULL ) ) { + Debug( LDAP_DEBUG_ANY, + "connection_init(%d) failed.\n", + 0, 0, 0 ); + + exit( 1 ); } - fprintf( fp, "\n" ); - fclose( fp ); + + slapd_add( 0 ); } while ( !slapd_shutdown ) { + int i, ns, nfds; + + fd_set readfds; + fd_set writefds; + struct sockaddr_in from; struct hostent *hp; struct timeval zero; struct timeval *tvp; - int len; - int data_ready; char *client_name; char *client_addr; FD_ZERO( &writefds ); FD_ZERO( &readfds ); - FD_SET( tcps, &readfds ); zero.tv_sec = 0; zero.tv_usec = 0; - ldap_pvt_thread_mutex_lock( &active_threads_mutex ); - Debug( LDAP_DEBUG_CONNS, - "listening for connections on %d, activity on:", - tcps, 0, 0 ); - - data_ready = 0; + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); - ldap_pvt_thread_mutex_lock( &new_conn_mutex ); - for ( i = 0; i < dtblsize; i++ ) { - if ( (c[i].c_state != SLAP_C_INACTIVE) - && (c[i].c_state != SLAP_C_CLOSING) ) - { - assert(lber_pvt_sb_in_use( &c[i].c_sb )); - - FD_SET( lber_pvt_sb_get_desc(&c[i].c_sb), - &readfds ); - if (lber_pvt_sb_data_ready(&c[i].c_sb)) - data_ready = 1; - if ( c[i].c_writewaiter ) { - FD_SET( lber_pvt_sb_get_desc(&c[i].c_sb), - &writefds ); - } - Debug( LDAP_DEBUG_CONNS, " %dr%s", i, - c[i].c_writewaiter ? "w" : "", 0 ); +#ifdef FD_SET_MANUAL_COPY + for( s = 0; s < nfds; s++ ) { + if(FD_ISSET( &slap_sd_writers, s )) { + FD_SET( &writefds, s ); + } + if(FD_ISSET( &slap_sd_writers, s )) { + FD_SET( &writefds, s ); } } +#else + memcpy( &readfds, &slap_daemon.sd_readers, sizeof(fd_set) ); + memcpy( &writefds, &slap_daemon.sd_writers, sizeof(fd_set) ); +#endif - Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 ); - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); + FD_SET( tcps, &readfds ); + +#ifndef HAVE_WINSOCK + nfds = slap_daemon.sd_nfds; +#else + nfds = dtblsize; +#endif + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); - Debug( LDAP_DEBUG_CONNS, "before select active_threads %d\n", - active_threads, 0, 0 ); + ldap_pvt_thread_mutex_lock( &active_threads_mutex ); #if defined( HAVE_YIELDING_SELECT ) || defined( NO_THREADS ) - tvp = (data_ready) ? &zero : NULL; + tvp = NULL; #else - tvp = (active_threads || data_ready) ? &zero : NULL; + tvp = active_threads ? &zero : NULL; #endif + + Debug( LDAP_DEBUG_CONNS, + "daemon: select: tcps=%d active_threads=%d tvp=%s\n", + tcps, active_threads, + tvp == NULL ? "NULL" : "zero" ); + + ldap_pvt_thread_mutex_unlock( &active_threads_mutex ); - switch ( i = select( dtblsize, &readfds, &writefds, 0, tvp ) ) { + switch(ns = select( nfds, &readfds, &writefds, 0, tvp )) { case -1: /* failure - try again */ - Debug( LDAP_DEBUG_CONNS, - "select failed errno %d (%s)\n", - errno, errno > -1 && errno < sys_nerr ? - sys_errlist[errno] : "unknown", 0 ); + if( errno != EINTR ) { + Debug( LDAP_DEBUG_CONNS, + "daemon: select failed (%d): %s\n", + errno, + errno >= 0 && errno < sys_nerr + ? sys_errlist[errno] : "unknown", + 0 ); + + slapd_shutdown = -1; + } + errno = 0; continue; case 0: /* timeout - let threads run */ - Debug( LDAP_DEBUG_CONNS, "select timeout - yielding\n", + Debug( LDAP_DEBUG_CONNS, "daemon: select timeout - yielding\n", 0, 0, 0 ); - if (!data_ready) - ldap_pvt_thread_yield(); + ldap_pvt_thread_yield(); continue; default: /* something happened - deal with it */ - Debug( LDAP_DEBUG_CONNS, "select activity on %d descriptors\n", i, 0, 0 ); - ; /* FALL */ + Debug( LDAP_DEBUG_CONNS, "daemon: activity on %d descriptors\n", + ns, 0, 0 ); + /* FALL THRU */ } - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); - time( ¤ttime ); - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); - /* new connection */ - ldap_pvt_thread_mutex_lock( &new_conn_mutex ); + slap_set_time(); + if ( FD_ISSET( tcps, &readfds ) ) { - len = sizeof(from); - if ( (ns = accept( tcps, (struct sockaddr *) &from, - &len )) == -1 ) { + int s; + int len = sizeof(from); + long id; + + if ( (s = accept( tcps, + (struct sockaddr *) &from, &len )) == -1 ) + { Debug( LDAP_DEBUG_ANY, - "accept() failed errno %d (%s)", errno, - errno > -1 && errno < sys_nerr ? - sys_errlist[errno] : "unknown", 0 ); - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); + "daemon: accept(%d) failed errno %d (%s)", errno, + tcps, errno >= 0 && errno < sys_nerr ? + sys_errlist[errno] : "unknown"); continue; } + assert( !FD_ISSET( 0, &slap_daemon.sd_actives) ); + assert( !FD_ISSET( 0, &slap_daemon.sd_readers) ); + assert( !FD_ISSET( 0, &slap_daemon.sd_writers) ); + +#ifndef HAVE_WINSOCK /* make sure descriptor number isn't too great */ - if ( ns >= dtblsize ) { + if ( s >= dtblsize ) { Debug( LDAP_DEBUG_ANY, - "new connection on %d beyond descriptor table size %d\n", - ns, dtblsize, 0 ); - close(ns); - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); + "daemon: %d beyond descriptor table size %d\n", + s, dtblsize, 0 ); + close(s); continue; } +#endif - Debug( LDAP_DEBUG_CONNS, "new connection on %d\n", ns, - 0, 0 ); + Debug( LDAP_DEBUG_CONNS, "daemon: new connection on %d\n", + s, 0, 0 ); len = sizeof(from); - - if ( getpeername( ns, (struct sockaddr *) &from, &len ) - == 0 ) { - char *s; + if ( getpeername( s, (struct sockaddr *) &from, &len ) == 0 ) { client_addr = inet_ntoa( from.sin_addr ); #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD) @@ -249,11 +351,12 @@ slapd_daemon( sizeof(from.sin_addr.s_addr), AF_INET ); if(hp) { + char *p; client_name = hp->h_name; /* normalize the domain */ - for ( s = client_name; *s; s++ ) { - *s = TOLOWER( (unsigned char) *s ); + for ( p = client_name; *p; p++ ) { + *p = TOLOWER( (unsigned char) *p ); } } else { @@ -277,72 +380,42 @@ slapd_daemon( /* DENY ACCESS */ Statslog( LDAP_DEBUG_ANY, "fd=%d connection from %s (%s) denied.\n", - ns, - client_name == NULL ? "unknown" : client_name, - client_addr == NULL ? "unknown" : client_addr, + s, + client_name == NULL ? "unknown" : client_name, + client_addr == NULL ? "unknown" : client_addr, 0, 0 ); - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); + close(s); continue; } #endif /* HAVE_TCPD */ - - ldap_pvt_thread_mutex_lock( &ops_mutex ); - c[ns].c_connid = num_conns++; - ldap_pvt_thread_mutex_unlock( &ops_mutex ); - - Statslog( LDAP_DEBUG_STATS, - "conn=%d fd=%d connection from %s (%s) accepted.\n", - c[ns].c_connid, ns, + if( (id = connection_init(s, client_name, client_addr)) < 0 ) { + Debug( LDAP_DEBUG_ANY, + "daemon: connection_init(%d, %s, %s) failed.\n", + s, client_name == NULL ? "unknown" : client_name, - client_addr == NULL ? "unknown" : client_addr, - 0 ); - - if ( c[ns].c_addr != NULL ) { - free( c[ns].c_addr ); - } - c[ns].c_addr = ch_strdup( client_addr ); - - if ( c[ns].c_domain != NULL ) { - free( c[ns].c_domain ); - } - - c[ns].c_domain = ch_strdup( client_name == NULL - ? "" : client_name ); - - ldap_pvt_thread_mutex_lock( &c[ns].c_dnmutex ); - if ( c[ns].c_dn != NULL ) { - free( c[ns].c_dn ); - c[ns].c_dn = NULL; - } - if ( c[ns].c_cdn != NULL ) { - free( c[ns].c_cdn ); - c[ns].c_cdn = NULL; + client_addr == NULL ? "unknown" : client_addr); + close(s); + continue; } - ldap_pvt_thread_mutex_unlock( &c[ns].c_dnmutex ); - c[ns].c_starttime = currenttime; - c[ns].c_ops_received = 0; - c[ns].c_ops_executing = 0; - c[ns].c_ops_pending = 0; - c[ns].c_ops_completed = 0; - - lber_pvt_sb_set_desc( &c[ns].c_sb, ns ); - lber_pvt_sb_set_io( &c[ns].c_sb, &lber_pvt_sb_io_tcp, NULL ); - - if (lber_pvt_sb_set_nonblock( &c[ns].c_sb, 1)<0) { - Debug( LDAP_DEBUG_ANY, - "FIONBIO ioctl on %d failed\n", ns, 0, 0 ); - } + Statslog( LDAP_DEBUG_STATS, + "daemon: conn=%d fd=%d connection from %s (%s) accepted.\n", + id, s, + client_name == NULL ? "unknown" : client_name, + client_addr == NULL ? "unknown" : client_addr, + 0 ); - c[ns].c_state = SLAP_C_ACTIVE; + slapd_add( s ); + continue; } - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); - Debug( LDAP_DEBUG_CONNS, "activity on:", 0, 0, 0 ); - for ( i = 0; i < dtblsize; i++ ) { - int r, w; +#ifdef LDAP_DEBUG + Debug( LDAP_DEBUG_CONNS, "daemon: activity on:", 0, 0, 0 ); + + for ( i = 0; i < nfds; i++ ) { + int a, r, w; r = FD_ISSET( i, &readfds ); w = FD_ISSET( i, &writefds ); @@ -351,42 +424,70 @@ slapd_daemon( r ? "r" : "", w ? "w" : "" ); } } + Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 ); +#endif - for ( i = 0; i < dtblsize; i++ ) { - if ( i == tcps || (! FD_ISSET( i, &readfds ) && - ! FD_ISSET( i, &writefds )) ) { + /* loop through the writers */ + for ( i = 0; i < nfds; i++ ) { + if ( i == tcps ) { continue; } if ( FD_ISSET( i, &writefds ) ) { Debug( LDAP_DEBUG_CONNS, - "signaling write waiter on %d\n", i, 0, 0 ); + "daemon: signaling write waiter on %d\n", i, 0, 0 ); + + assert( FD_ISSET( 0, &slap_daemon.sd_actives) ); - ldap_pvt_thread_mutex_lock( &active_threads_mutex ); - active_threads++; - c[i].c_writewaiter = 0; - ldap_pvt_thread_cond_signal( &c[i].c_wcv ); - ldap_pvt_thread_mutex_unlock( &active_threads_mutex ); + /* clear the write flag */ + slapd_clr_write( i, 0 ); + + if( connection_write( i ) < 0 ) { + FD_CLR( i, &readfds ); + slapd_close( i ); + } + } + } + + for ( i = 0; i < nfds; i++ ) { + if ( i == tcps ) { + continue; } - if ( FD_ISSET( i, &readfds ) || - lber_pvt_sb_data_ready( &c[i].c_sb ) ) { + if ( FD_ISSET( i, &readfds ) ) { Debug( LDAP_DEBUG_CONNS, - "read activity on %d\n", i, 0, 0 ); + "daemon: read activity on %d\n", i, 0, 0 ); + + assert( FD_ISSET( i, &slap_daemon.sd_actives) ); - connection_activity( &c[i] ); + if( connection_read( i ) < 0) { + slapd_close( i ); + } } } ldap_pvt_thread_yield(); } - Debug( LDAP_DEBUG_TRACE, - "slapd shutdown: shutdown initiated.\n", - 0, 0, 0 ); + if( slapd_shutdown > 0 ) { + Debug( LDAP_DEBUG_TRACE, + "daemon: shutdown requested and initiated.\n", + 0, 0, 0 ); + + } else if ( slapd_shutdown < 0 ) { + Debug( LDAP_DEBUG_TRACE, + "daemon: abnormal condition, shutdown initiated.\n", + 0, 0, 0 ); + } else { + Debug( LDAP_DEBUG_TRACE, + "daemon: no active streams, shutdown initiated.\n", + 0, 0, 0 ); + } - close( tcps ); + if( tcps >= 0 ) { + close( tcps ); + } ldap_pvt_thread_mutex_lock( &active_threads_mutex ); Debug( LDAP_DEBUG_ANY, @@ -400,10 +501,28 @@ slapd_daemon( return NULL; } +int slapd_daemon( struct sockaddr_in *addr ) +{ + int status; + + status = ldap_pvt_thread_create( &listener_tid, 0, + slapd_daemon_task, addr ); + + if ( status != 0 ) { + Debug( LDAP_DEBUG_ANY, + "listener ldap_pvt_thread_create failed (%d)\n", status, 0, 0 ); + return -1; + } else { + /* wait for the listener thread to complete */ + ldap_pvt_thread_join( listener_tid, (void *) NULL ); + } + + return 0; +} + void slap_set_shutdown( int sig ) { - Debug( LDAP_DEBUG_ANY, "slapd got shutdown signal %d\n", sig, 0, 0 ); slapd_shutdown = 1; ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 ); @@ -414,8 +533,6 @@ slap_set_shutdown( int sig ) void slap_do_nothing( int sig ) { - Debug( LDAP_DEBUG_TRACE, "slapd got do_nothing signal %d\n", sig, 0, 0 ); - /* reinstall self */ (void) SIGNAL( sig, slap_do_nothing ); } diff --git a/servers/slapd/init.c b/servers/slapd/init.c index dca72737b5..f464c61e93 100644 --- a/servers/slapd/init.c +++ b/servers/slapd/init.c @@ -8,7 +8,6 @@ #include #include -#include "portable.h" #include "slap.h" /* @@ -25,8 +24,6 @@ int ldap_syslog; int ldap_syslog_level = LOG_DEBUG; char *default_referral; -time_t starttime; -ldap_pvt_thread_t listener_tid; int g_argc; char **g_argv; @@ -37,11 +34,7 @@ int active_threads; ldap_pvt_thread_mutex_t active_threads_mutex; ldap_pvt_thread_cond_t active_threads_cond; -time_t currenttime; -ldap_pvt_thread_mutex_t currenttime_mutex; - -ldap_pvt_thread_mutex_t new_conn_mutex; - +ldap_pvt_thread_mutex_t gmtime_mutex; #ifdef SLAPD_CRYPT ldap_pvt_thread_mutex_t crypt_mutex; #endif @@ -64,6 +57,9 @@ ldap_pvt_thread_mutex_t replog_mutex; static char* slap_name; int slapMode = SLAP_UNDEFINED_MODE; +static time_t currenttime; +static ldap_pvt_thread_mutex_t currenttime_mutex; + int slap_init( int mode, char *name ) { @@ -98,12 +94,13 @@ slap_init( int mode, char *name ) ldap_pvt_thread_mutex_init( &active_threads_mutex ); ldap_pvt_thread_cond_init( &active_threads_cond ); - ldap_pvt_thread_mutex_init( &new_conn_mutex ); ldap_pvt_thread_mutex_init( ¤ttime_mutex ); ldap_pvt_thread_mutex_init( &entry2str_mutex ); ldap_pvt_thread_mutex_init( &replog_mutex ); ldap_pvt_thread_mutex_init( &ops_mutex ); ldap_pvt_thread_mutex_init( &num_sent_mutex ); + + ldap_pvt_thread_mutex_init( &gmtime_mutex ); #ifdef SLAPD_CRYPT ldap_pvt_thread_mutex_init( &crypt_mutex ); #endif @@ -162,3 +159,20 @@ int slap_destroy(void) return rc; } +/* should create a utils.c for these */ + +void slap_set_time(void) +{ + ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); + time( ¤ttime ); + ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); +} + +time_t slap_get_time(void) +{ + time_t t; + ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); + t = currenttime; + ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); + return t; +} diff --git a/servers/slapd/main.c b/servers/slapd/main.c index f7b4469390..5cbe810193 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -56,13 +56,15 @@ usage( char *name ) fprintf( stderr, "\n" ); } +time_t starttime; + int main( int argc, char **argv ) { int i; int inetd = 0; - int rc = 0; - struct sockaddr_in bind_addr; + int status, rc; + struct sockaddr_in bind_addr, *slapd_addr; int udp; #ifdef LOG_LOCAL4 int syslogUser = DEFAULT_SYSLOG_USER; @@ -207,130 +209,61 @@ main( int argc, char **argv ) goto destroy; } - if ( slap_startup(-1) != 0 ) { - rc = 1; - goto shutdown; - } - - if ( ! inetd ) { - int status; - - (void) SIGNAL( LDAP_SIGUSR1, slap_do_nothing ); - (void) SIGNAL( LDAP_SIGUSR2, slap_set_shutdown ); + (void) SIGNAL( LDAP_SIGUSR1, slap_do_nothing ); + (void) SIGNAL( LDAP_SIGUSR2, slap_set_shutdown ); #ifdef SIGPIPE - (void) SIGNAL( SIGPIPE, SIG_IGN ); + (void) SIGNAL( SIGPIPE, SIG_IGN ); #endif #ifdef SIGHUP - (void) SIGNAL( SIGHUP, slap_set_shutdown ); + (void) SIGNAL( SIGHUP, slap_set_shutdown ); #endif - (void) SIGNAL( SIGINT, slap_set_shutdown ); - (void) SIGNAL( SIGTERM, slap_set_shutdown ); + (void) SIGNAL( SIGINT, slap_set_shutdown ); + (void) SIGNAL( SIGTERM, slap_set_shutdown ); + if(!inetd) { #ifdef LDAP_DEBUG lutil_detach( ldap_debug, 0 ); #else lutil_detach( 0, 0 ); #endif + } - time( &starttime ); + if ( slap_startup(-1) != 0 ) { + rc = 1; + goto shutdown; + } - status = ldap_pvt_thread_create( &listener_tid, 0, - slapd_daemon, &bind_addr ); - if ( status != 0 ) - { - Debug( LDAP_DEBUG_ANY, - "listener ldap_pvt_thread_create failed (%d)\n", status, 0, 0 ); + if(!inetd) { + FILE *fp; - rc = 1; + slapd_addr = &bind_addr; - } else { - /* wait for the listener thread to complete */ - ldap_pvt_thread_join( listener_tid, (void *) NULL ); - } + Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 ); - } else { - Connection c; - BerElement ber; - unsigned long len, tag; - long msgid; - int flen; - struct sockaddr_in from; - struct hostent *hp; - - c.c_dn = NULL; - c.c_cdn = NULL; - c.c_ops = NULL; - - lber_pvt_sb_init( &c.c_sb ); - lber_pvt_sb_set_desc( &c.c_sb, 0 ); - lber_pvt_sb_set_io( &c.c_sb, - (udp) ? &lber_pvt_sb_io_udp : &lber_pvt_sb_io_tcp, - NULL ); - /* FIXME: handle udp here */ - - ldap_pvt_thread_mutex_init( &c.c_dnmutex ); - ldap_pvt_thread_mutex_init( &c.c_opsmutex ); - ldap_pvt_thread_mutex_init( &c.c_pdumutex ); -#ifdef notdefcldap - c.c_sb.sb_addrs = (void **) saddrlist; - c.c_sb.sb_fromaddr = &faddr; - c.c_sb.sb_useaddr = saddrlist[ 0 ] = &saddr; -#endif - flen = sizeof(from); - if ( getpeername( 0, (struct sockaddr *) &from, &flen ) == 0 ) { -#ifdef SLAPD_RLOOKUPS - hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr), - sizeof(from.sin_addr.s_addr), AF_INET ); -#else - hp = NULL; -#endif - - Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n", - hp == NULL ? "unknown" : hp->h_name, - inet_ntoa( from.sin_addr ), 0 ); - - c.c_addr = inet_ntoa( from.sin_addr ); - c.c_domain = ch_strdup( hp == NULL ? "" : hp->h_name ); - } else { - Debug( LDAP_DEBUG_ARGS, "connection from unknown\n", - 0, 0, 0 ); + if (( slapd_pid_file != NULL ) && + (( fp = fopen( slapd_pid_file, "w" )) != NULL )) + { + fprintf( fp, "%d\n", (int) getpid() ); + fclose( fp ); } - c.c_state = SLAP_C_ACTIVE; - - ber_init_w_nullc( &ber, 0 ); - - while ( (tag = ber_get_next( &c.c_sb, &len, &ber )) - == LDAP_TAG_MESSAGE ) { - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); - time( ¤ttime ); - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); - - if ( (tag = ber_get_int( &ber, &msgid )) - != LDAP_TAG_MSGID ) { - /* log and send error */ - Debug( LDAP_DEBUG_ANY, - "ber_get_int returns 0x%lx\n", tag, 0, 0 ); - ber_free( &ber, 1 ); - return 1; + if (( slapd_args_file != NULL ) && + (( fp = fopen( slapd_args_file, "w" )) != NULL )) + { + for ( i = 0; i < g_argc; i++ ) { + fprintf( fp, "%s ", g_argv[i] ); } + fprintf( fp, "\n" ); + fclose( fp ); + } - if ( (tag = ber_peek_tag( &ber, &len )) - == LBER_ERROR ) { - /* log, close and send error */ - Debug( LDAP_DEBUG_ANY, - "ber_peek_tag returns 0x%lx\n", tag, 0, 0 ); - ber_free( &ber, 1 ); - lber_pvt_sb_close( &c.c_sb ); - lber_pvt_sb_destroy( &c.c_sb ); - return 1; - } + } else { + slapd_addr = NULL; + } - connection_activity( &c ); + time( &starttime ); - ber_free( &ber, 1 ); - } - } + rc = slapd_daemon( slapd_addr ); shutdown: /* remember an error during shutdown */ diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index 918c97a278..c3b5fc9cc8 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -206,6 +206,7 @@ add_lastmods( Operation *op, LDAPModList **modlist ) LDAPModList **m; LDAPModList *tmp; struct tm *ltm; + time_t currenttime; Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 ); @@ -249,7 +250,8 @@ add_lastmods( Operation *op, LDAPModList **modlist ) tmp->ml_next = *modlist; *modlist = tmp; - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); + currenttime = slap_get_time(); + ldap_pvt_thread_mutex_lock( &gmtime_mutex ); #ifndef LDAP_LOCALTIME ltm = gmtime( ¤ttime ); strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm ); @@ -257,7 +259,8 @@ add_lastmods( Operation *op, LDAPModList **modlist ) ltm = localtime( ¤ttime ); strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm ); #endif - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); + ldap_pvt_thread_mutex_unlock( &gmtime_mutex ); + bv.bv_val = buf; bv.bv_len = strlen( bv.bv_val ); tmp = (LDAPModList *) ch_calloc( 1, sizeof(LDAPModList) ); diff --git a/servers/slapd/monitor.c b/servers/slapd/monitor.c index 5554d81c3d..65594af183 100644 --- a/servers/slapd/monitor.c +++ b/servers/slapd/monitor.c @@ -10,13 +10,6 @@ * is provided ``as is'' without express or implied warranty. */ -/* Revision history - * - * 5-Jun-96 jeff.hodges@stanford.edu - * Added locking of new_conn_mutex when traversing the c[] array. - * Added locking of currenttime_mutex to protect call(s) to localtime(). - */ - #include "portable.h" #include @@ -40,6 +33,8 @@ monitor_info( Connection *conn, Operation *op ) int i, nconns, nwritewaiters, nreadwaiters; struct tm *ltm; char *p; + Connection *c; + time_t currenttime; vals[0] = &val; vals[1] = NULL; @@ -59,7 +54,9 @@ monitor_info( Connection *conn, Operation *op ) } attr_merge( e, "version", vals ); + ldap_pvt_thread_mutex_lock( &active_threads_mutex ); sprintf( buf, "%d", active_threads ); + ldap_pvt_thread_mutex_unlock( &active_threads_mutex ); val.bv_val = buf; val.bv_len = strlen( buf ); attr_merge( e, "threads", vals ); @@ -68,49 +65,49 @@ monitor_info( Connection *conn, Operation *op ) nwritewaiters = 0; nreadwaiters = 0; - ldap_pvt_thread_mutex_lock( &new_conn_mutex ); - for ( i = 0; i < dtblsize; i++ ) { - if ( lber_pvt_sb_in_use(&(c[i].c_sb)) ) { - nconns++; - if ( c[i].c_writewaiter ) { - nwritewaiters++; - } - if ( c[i].c_gettingber ) { - nreadwaiters++; - } - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); +#ifdef LDAP_COUNTERS + /* loop through the connections */ + for ( c = connection_first() ; c != NULL; c = connection_next(c) ) { + nconns++; + if ( c->c_writewaiter ) { + nwritewaiters++; + } + if ( c->c_currentber != NULL ) { + nreadwaiters++; + } + + ldap_pvt_thread_mutex_lock( &gmtime_mutex ); #ifndef LDAP_LOCALTIME - ltm = gmtime( &c[i].c_starttime ); - strftime( buf2, sizeof(buf2), "%Y%m%d%H%M%SZ", ltm ); + ltm = gmtime( &c->c_starttime ); + strftime( buf2, sizeof(buf2), "%Y%m%d%H%M%SZ", ltm ); #else - ltm = localtime( &c[i].c_starttime ); - strftime( buf2, sizeof(buf2), "%y%m%d%H%M%SZ", ltm ); + ltm = localtime( &c->.c_starttime ); + strftime( buf2, sizeof(buf2), "%y%m%d%H%M%SZ", ltm ); #endif - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); - - ldap_pvt_thread_mutex_lock( &c[i].c_dnmutex ); - sprintf( buf, "%d : %s : %d : %d : %s : %s%s%s%s", i, - buf2, c[i].c_ops_received, c[i].c_ops_completed, - c[i].c_cdn ? c[i].c_cdn : "NULLDN", - c[i].c_gettingber ? "r" : "", - c[i].c_writewaiter ? "w" : "", - c[i].c_ops_executing ? "x" : "", - c[i].c_ops_pending ? "p" : "" - ); - ldap_pvt_thread_mutex_unlock( &c[i].c_dnmutex ); - val.bv_val = buf; - val.bv_len = strlen( buf ); - attr_merge( e, "connection", vals ); - } + ldap_pvt_thread_mutex_unlock( &gmtime_mutex ); + + sprintf( buf, "%d : %s : %d : %d : %s : %s%s%s%s", i, + buf2, c[i].c_ops_received, c[i].c_ops_completed, + c[i].c_cdn ? c[i].c_cdn : "NULLDN", + c[i].c_gettingber ? "r" : "", + c[i].c_writewaiter ? "w" : "", + c[i].c_ops_executing ? "x" : "", + c[i].c_ops_pending ? "p" : "" + ); + + val.bv_val = buf; + val.bv_len = strlen( buf ); + attr_merge( e, "connection", vals ); } - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); + connection_done(c); +#endif sprintf( buf, "%d", nconns ); val.bv_val = buf; val.bv_len = strlen( buf ); attr_merge( e, "currentconnections", vals ); - sprintf( buf, "%d", num_conns ); + sprintf( buf, "%ld", connections_nextid() ); val.bv_val = buf; val.bv_len = strlen( buf ); attr_merge( e, "totalconnections", vals ); @@ -130,6 +127,7 @@ monitor_info( Connection *conn, Operation *op ) val.bv_len = strlen( buf ); attr_merge( e, "readwaiters", vals ); +#ifdef LDAP_COUNTERS sprintf( buf, "%ld", ops_initiated ); val.bv_val = buf; val.bv_len = strlen( buf ); @@ -149,8 +147,12 @@ monitor_info( Connection *conn, Operation *op ) val.bv_val = buf; val.bv_len = strlen( buf ); attr_merge( e, "bytessent", vals ); +#endif - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); + slap_set_time(); + currenttime = slap_get_time(); + + ldap_pvt_thread_mutex_lock( &gmtime_mutex ); #ifndef LDAP_LOCALTIME ltm = gmtime( ¤ttime ); strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm ); @@ -158,12 +160,10 @@ monitor_info( Connection *conn, Operation *op ) ltm = localtime( ¤ttime ); strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm ); #endif - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); val.bv_val = buf; val.bv_len = strlen( buf ); attr_merge( e, "currenttime", vals ); - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); #ifndef LDAP_LOCALTIME ltm = gmtime( &starttime ); strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm ); @@ -171,7 +171,8 @@ monitor_info( Connection *conn, Operation *op ) ltm = localtime( &starttime ); strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm ); #endif - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); + ldap_pvt_thread_mutex_unlock( &gmtime_mutex ); + val.bv_val = buf; val.bv_len = strlen( buf ); attr_merge( e, "starttime", vals ); diff --git a/servers/slapd/operation.c b/servers/slapd/operation.c index 7848357a93..44c821845e 100644 --- a/servers/slapd/operation.c +++ b/servers/slapd/operation.c @@ -15,8 +15,6 @@ slap_op_free( Operation *op ) { assert( op->o_next == NULL ); - ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); - if ( op->o_ber != NULL ) { ber_free( op->o_ber, 1 ); } @@ -27,8 +25,8 @@ slap_op_free( Operation *op ) free( op->o_ndn ); } - ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); ldap_pvt_thread_mutex_destroy( &op->o_abandonmutex ); + free( (char *) op ); } @@ -37,8 +35,7 @@ slap_op_alloc( BerElement *ber, unsigned long msgid, unsigned long tag, - int id, - int connid + long id ) { Operation *op; @@ -46,19 +43,17 @@ slap_op_alloc( op = (Operation *) ch_calloc( 1, sizeof(Operation) ); ldap_pvt_thread_mutex_init( &op->o_abandonmutex ); + op->o_abandon = 0; + op->o_ber = ber; op->o_msgid = msgid; op->o_tag = tag; - op->o_abandon = 0; op->o_dn = NULL; op->o_ndn = NULL; - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); - op->o_time = currenttime; - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); + op->o_time = slap_get_time(); op->o_opid = id; - op->o_connid = connid; op->o_next = NULL; return( op ); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 18fd25614b..e2876c74d7 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -109,8 +109,20 @@ int read_config LDAP_P(( char *fname )); /* * connection.c */ +int connections_init LDAP_P((void)); -void connection_activity LDAP_P(( Connection *conn )); +long connection_init LDAP_P(( + int s, + const char* name, const char* addr)); + +int connection_write LDAP_P((int s)); +int connection_read LDAP_P((int s)); + +long connections_nextid(void); + +Connection* connection_first LDAP_P((void)); +Connection* connection_next LDAP_P((Connection *)); +void connection_done LDAP_P((Connection *)); /* * dn.c @@ -173,7 +185,7 @@ void monitor_info LDAP_P(( Connection *conn, Operation *op )); void slap_op_free LDAP_P(( Operation *op )); Operation * slap_op_alloc LDAP_P(( BerElement *ber, unsigned long msgid, - unsigned long tag, int id, int connid )); + unsigned long tag, long id )); int slap_op_add LDAP_P(( Operation **olist, Operation *op )); int slap_op_remove LDAP_P(( Operation **olist, Operation *op )); @@ -202,7 +214,8 @@ void send_ldap_result LDAP_P(( Connection *conn, Operation *op, int err, char *m char *text )); void send_ldap_search_result LDAP_P(( Connection *conn, Operation *op, int err, char *matched, char *text, int nentries )); -void close_connection LDAP_P(( Connection *conn, int opconnid, int opid )); + +void do_close( Connection *conn, long opid ); /* * schema.c @@ -244,7 +257,6 @@ char *suffixAlias LDAP_P(( char *dn, Operation *op, Backend *be )); * Other... */ -extern char **g_argv; extern char *default_referral; extern char *replogfile; extern char Versionstr[]; @@ -257,35 +269,48 @@ extern int global_lastmod; extern int global_schemacheck; extern int lber_debug; extern int ldap_syslog; -extern int num_conns; + +#ifdef LDAP_COUNTERS +extern ldap_pvt_thread_mutex_t num_sent_mutex; extern long num_bytes_sent; + extern long num_entries_sent; + +extern ldap_pvt_thread_mutex_t ops_mutex; extern long ops_completed; extern long ops_initiated; +#endif + +extern char *slapd_pid_file; +extern char *slapd_args_file; +extern char **g_argv; +extern time_t starttime; + +time_t slap_get_time LDAP_P((void)); +void slap_set_time LDAP_P((void)); extern ldap_pvt_thread_mutex_t active_threads_mutex; extern ldap_pvt_thread_cond_t active_threads_cond; -extern ldap_pvt_thread_mutex_t currenttime_mutex; extern ldap_pvt_thread_mutex_t entry2str_mutex; -extern ldap_pvt_thread_mutex_t new_conn_mutex; -extern ldap_pvt_thread_mutex_t num_sent_mutex; -extern ldap_pvt_thread_mutex_t ops_mutex; extern ldap_pvt_thread_mutex_t replog_mutex; + #ifdef SLAPD_CRYPT extern ldap_pvt_thread_mutex_t crypt_mutex; #endif -extern ldap_pvt_thread_t listener_tid; +extern ldap_pvt_thread_mutex_t gmtime_mutex; + extern struct acl *global_acl; extern struct objclass *global_oc; -extern time_t currenttime; extern int slap_init LDAP_P((int mode, char* name)); extern int slap_startup LDAP_P((int dbnum)); extern int slap_shutdown LDAP_P((int dbnum)); extern int slap_destroy LDAP_P((void)); -extern void * slapd_daemon LDAP_P((void *port)); +struct sockaddr_in; +extern int slapd_daemon LDAP_P((struct sockaddr_in *addr)); + extern void slap_set_shutdown LDAP_P((int sig)); extern void slap_do_nothing LDAP_P((int sig)); @@ -303,11 +328,7 @@ extern void do_unbind LDAP_P((Connection *conn, Operation *op)); extern int send_search_entry LDAP_P((Backend *be, Connection *conn, Operation *op, Entry *e, char **attrs, int attrsonly)); extern int str2result LDAP_P(( char *s, int *code, char **matched, char **info )); -#if defined( SLAPD_MONITOR_DN ) -extern Connection *c; -extern int dtblsize; -extern time_t starttime; -#endif +extern int dtblsize; #endif /* _proto_slap */ diff --git a/servers/slapd/repl.c b/servers/slapd/repl.c index 773687a3d2..f0e79084ad 100644 --- a/servers/slapd/repl.c +++ b/servers/slapd/repl.c @@ -46,7 +46,7 @@ replog( i++ ) { fprintf( fp, "replica: %s\n", be->be_replica[i] ); } - fprintf( fp, "time: %ld\n", (long) currenttime ); + fprintf( fp, "time: %ld\n", (long) slap_get_time() ); fprintf( fp, "dn: %s\n", dn ); switch ( optype ) { diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 6d30c29b6d..152af69f7f 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -13,7 +13,6 @@ #include "slap.h" - static void send_ldap_result2( Connection *conn, @@ -25,7 +24,7 @@ send_ldap_result2( ) { BerElement *ber; - int rc; + int rc, tmp; unsigned long tag, bytes; if ( err == LDAP_PARTIAL_RESULTS && (text == NULL || *text == '\0') ) @@ -52,12 +51,14 @@ send_ldap_result2( break; } + #ifdef LDAP_COMPAT30 if ( (ber = ber_alloc_t( conn->c_version == 30 ? 0 : LBER_USE_DER )) - == NULLBER ) { + == NULLBER ) #else - if ( (ber = der_alloc()) == NULLBER ) { + if ( (ber = der_alloc()) == NULLBER ) #endif + { Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 ); return; } @@ -83,14 +84,15 @@ send_ldap_result2( } /* write only one pdu at a time - wait til it's our turn */ - ldap_pvt_thread_mutex_lock( &conn->c_pdumutex ); + ldap_pvt_thread_mutex_lock( &conn->c_write_mutex ); + + /* lock the connection */ + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); /* write the pdu */ bytes = ber->ber_ptr - ber->ber_buf; - ldap_pvt_thread_mutex_lock( &new_conn_mutex ); - while ( conn->c_connid == op->o_connid && ber_flush( &conn->c_sb, ber, - 1 ) != 0 ) { - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); + + while ( ber_flush( &conn->c_sb, ber, 1 ) != 0 ) { /* * we got an error. if it's ewouldblock, we need to * wait on the socket being writable. otherwise, figure @@ -102,35 +104,29 @@ send_ldap_result2( : "unknown", 0 ); if ( errno != EWOULDBLOCK && errno != EAGAIN ) { - close_connection( conn, op->o_connid, op->o_opid ); + conn->c_conn_state = SLAP_C_CLOSING; - ldap_pvt_thread_mutex_unlock( &conn->c_pdumutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); return; } /* wait for socket to be write-ready */ - ldap_pvt_thread_mutex_lock( &active_threads_mutex ); - active_threads--; conn->c_writewaiter = 1; + slapd_set_write( conn->c_sb.sb_sd, 1 ); - ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 ); - - ldap_pvt_thread_cond_wait( &conn->c_wcv, &active_threads_mutex ); - - if( active_threads < 1 ) { - ldap_pvt_thread_cond_signal(&active_threads_cond); - } - ldap_pvt_thread_mutex_unlock( &active_threads_mutex ); - - ldap_pvt_thread_yield(); - ldap_pvt_thread_mutex_lock( &new_conn_mutex ); + ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex ); + conn->c_writewaiter = 0; } - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); - ldap_pvt_thread_mutex_unlock( &conn->c_pdumutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); + +#ifdef LDAP_COUNTERS ldap_pvt_thread_mutex_lock( &num_sent_mutex ); num_bytes_sent += bytes; ldap_pvt_thread_mutex_unlock( &num_sent_mutex ); +#endif Statslog( LDAP_DEBUG_STATS, "conn=%d op=%d RESULT err=%d tag=%lu nentries=%d\n", conn->c_connid, @@ -186,7 +182,7 @@ send_search_entry( { BerElement *ber; Attribute *a; - int i, rc, bytes; + int i, rc=-1, bytes; struct acl *acl; char *edn; @@ -261,7 +257,7 @@ send_search_entry( continue; } - if ( ber_printf( ber, "{s[", a->a_type ) == -1 ) { + if (( rc = ber_printf( ber, "{s[", a->a_type )) == -1 ) { Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); ber_free( ber, 1 ); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, @@ -278,9 +274,9 @@ send_search_entry( continue; } - if ( ber_printf( ber, "o", + if (( rc = ber_printf( ber, "o", a->a_vals[i]->bv_val, - a->a_vals[i]->bv_len ) == -1 ) + a->a_vals[i]->bv_len )) == -1 ) { Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); @@ -293,7 +289,7 @@ send_search_entry( } } - if ( ber_printf( ber, "]}" ) == -1 ) { + if (( rc = ber_printf( ber, "]}" )) == -1 ) { Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 ); ber_free( ber, 1 ); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, @@ -317,14 +313,16 @@ send_search_entry( return( 1 ); } + bytes = ber->ber_ptr - ber->ber_buf; + /* write only one pdu at a time - wait til it's our turn */ - ldap_pvt_thread_mutex_lock( &conn->c_pdumutex ); + ldap_pvt_thread_mutex_lock( &conn->c_write_mutex ); - bytes = ber->ber_ptr - ber->ber_buf; - ldap_pvt_thread_mutex_lock( &new_conn_mutex ); - while ( conn->c_connid == op->o_connid && ber_flush( &conn->c_sb, ber, - 1 ) != 0 ) { - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); + /* lock the connection */ + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + + /* write the pdu */ + while ( ber_flush( &conn->c_sb, ber, 1 ) != 0 ) { /* * we got an error. if it's ewouldblock, we need to * wait on the socket being writable. otherwise, figure @@ -336,51 +334,40 @@ send_search_entry( : "unknown", 0 ); if ( errno != EWOULDBLOCK && errno != EAGAIN ) { - close_connection( conn, op->o_connid, op->o_opid ); + conn->c_conn_state = SLAP_C_CLOSING; - ldap_pvt_thread_mutex_unlock( &conn->c_pdumutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); return( -1 ); } /* wait for socket to be write-ready */ - ldap_pvt_thread_mutex_lock( &active_threads_mutex ); - active_threads--; conn->c_writewaiter = 1; - ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 ); - ldap_pvt_thread_cond_wait( &conn->c_wcv, &active_threads_mutex ); - - if( active_threads < 1 ) { - ldap_pvt_thread_cond_signal(&active_threads_cond); - } - ldap_pvt_thread_mutex_unlock( &active_threads_mutex ); + slapd_set_write( conn->c_sb.sb_sd, 1 ); - ldap_pvt_thread_yield(); - ldap_pvt_thread_mutex_lock( &new_conn_mutex ); + ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex ); + conn->c_writewaiter = 0; } - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); - ldap_pvt_thread_mutex_unlock( &conn->c_pdumutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex ); + +#ifdef LDAP_COUNTERS ldap_pvt_thread_mutex_lock( &num_sent_mutex ); num_bytes_sent += bytes; num_entries_sent++; ldap_pvt_thread_mutex_unlock( &num_sent_mutex ); +#endif - ldap_pvt_thread_mutex_lock( &new_conn_mutex ); - if ( conn->c_connid == op->o_connid ) { - rc = 0; - Statslog( LDAP_DEBUG_STATS2, "conn=%d op=%d ENTRY dn=\"%s\"\n", - conn->c_connid, op->o_opid, e->e_dn, 0, 0 ); - } else { - rc = -1; - } - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); + Statslog( LDAP_DEBUG_STATS2, "conn=%d op=%d ENTRY dn=\"%s\"\n", + conn->c_connid, op->o_opid, e->e_dn, 0, 0 ); Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 ); - return( rc ); + rc = 0; error_return:; - return( 1 ); + return( rc ); } int @@ -436,26 +423,3 @@ str2result( return( rc ); } - -/* - * close_connection - close a connection. takes the connection to close, - * the connid associated with the operation generating the close (so we - * don't accidentally close a connection that's not ours), and the opid - * of the operation generating the close (for logging purposes). - */ -void -close_connection( Connection *conn, int opconnid, int opid ) -{ - ldap_pvt_thread_mutex_lock( &new_conn_mutex ); - if ( lber_pvt_sb_in_use(&conn->c_sb) && conn->c_connid == opconnid ) { - Statslog( LDAP_DEBUG_STATS, - "conn=%d op=%d fd=%d closed errno=%d\n", conn->c_connid, - opid, lber_pvt_sb_get_desc(&conn->c_sb), errno, 0 ); - lber_pvt_sb_close( &conn->c_sb ); - lber_pvt_sb_destroy( &conn->c_sb ); - conn->c_version = 0; - conn->c_protocol = 0; - conn->c_state = SLAP_C_INACTIVE; - } - ldap_pvt_thread_mutex_unlock( &new_conn_mutex ); -} diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 837de9025b..dabf8c7bec 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -380,27 +380,33 @@ struct backend_info { */ typedef struct slap_op { + long o_opid; /* id of this operation */ + long o_msgid; /* msgid of the request */ + + ldap_pvt_thread_t o_tid; /* thread handling this op */ + BerElement *o_ber; /* ber of the request */ - long o_msgid; /* msgid of the request */ + unsigned long o_tag; /* tag of the request */ time_t o_time; /* time op was initiated */ char *o_dn; /* dn bound when op was initiated */ char *o_ndn; /* normalized dn bound when op was initiated */ - int o_authtype; /* auth method used to bind dn */ + int o_authtype; /* auth method used to bind dn */ /* values taken from ldap.h */ /* LDAP_AUTH_* */ - int o_opid; /* id of this operation */ - int o_connid; /* id of conn initiating this op */ + +/* long o_connid; *//* id of conn initiating this op */ + #ifdef LDAP_CONNECTIONLESS int o_cldap; /* != 0 if this came in via CLDAP */ struct sockaddr o_clientaddr; /* client address if via CLDAP */ char o_searchbase; /* search base if via CLDAP */ #endif - struct slap_op *o_next; /* next operation in list */ - ldap_pvt_thread_t o_tid; /* thread handling this op */ - int o_abandon; /* signals op has been abandoned */ - ldap_pvt_thread_mutex_t o_abandonmutex; /* signals op has been abandoned */ + ldap_pvt_thread_mutex_t o_abandonmutex; /* protects o_abandon */ + int o_abandon; /* abandon flag */ + + struct slap_op *o_next; /* next operation in list */ void *o_private; /* anything the backend needs */ } Operation; @@ -408,41 +414,56 @@ typedef struct slap_op { * represents a connection from an ldap client */ -#define SLAP_C_INACTIVE 0x0 -#define SLAP_C_ACTIVE 0x1 -#define SLAP_C_BINDING 0x2 -#define SLAP_C_CLOSING 0x3 + +/* structure state (protected by connections_mutex) */ +#define SLAP_C_UNINITIALIZED 0x0 /* MUST BE ZERO (0) */ +#define SLAP_C_UNUSED 0x1 +#define SLAP_C_USED 0x2 + +/* connection state (protected by c_mutex ) */ +#define SLAP_C_INVALID 0x0 /* MUST BE ZERO (0) */ +#define SLAP_C_INACTIVE 0x1 /* zero threads */ +#define SLAP_C_ACTIVE 0x2 /* one or more threads */ +#define SLAP_C_BINDING 0x3 /* binding */ +#define SLAP_C_CLOSING 0x4 /* closing */ typedef struct slap_conn { - int c_state; /* connection state */ + int c_struct_state; /* structure management state */ + int c_conn_state; /* connection state */ + + ldap_pvt_thread_mutex_t c_mutex; /* protect the connection */ Sockbuf c_sb; /* ber connection stuff */ - char *c_cdn; /* DN provided by the client */ - char *c_dn; /* DN bound to this conn */ - ldap_pvt_thread_mutex_t c_dnmutex; /* mutex for c_dn field */ + + /* only can be changed by connect_init */ + time_t c_starttime; /* when the connection was opened */ + long c_connid; /* id of this connection for stats*/ + char *c_client_addr; /* address of client */ + char *c_client_name; /* name of client */ + + /* only can be changed by binding thread */ + char *c_cdn; /* DN provided by the client */ + char *c_dn; /* DN bound to this conn */ int c_protocol; /* version of the LDAP protocol used by client */ int c_authtype; /* auth method used to bind c_dn */ #ifdef LDAP_COMPAT int c_version; /* for compatibility w/2.0, 3.0 */ #endif - char *c_addr; /* address of client on this conn */ - char *c_domain; /* domain of client on this conn */ + Operation *c_ops; /* list of operations being processed */ Operation *c_pending_ops; /* list of pending operations */ - ldap_pvt_thread_mutex_t c_opsmutex; /* mutex for c_ops list & stats */ - ldap_pvt_thread_mutex_t c_pdumutex; /* only one pdu written at a time */ - ldap_pvt_thread_cond_t c_wcv; /* used to wait for sd write-ready*/ - int c_gettingber; /* in the middle of ber_get_next */ - BerElement *c_currentber; /* ber we're getting */ - int c_writewaiter; /* signals write-ready sd waiter */ - int c_pduwaiters; /* signals threads waiting 4 pdu */ - time_t c_starttime; /* when the connection was opened */ - long c_connid; /* id of this connection for stats*/ + ldap_pvt_thread_mutex_t c_write_mutex; /* only one pdu written at a time */ + ldap_pvt_thread_cond_t c_write_cv; /* used to wait for sd write-ready*/ - long c_ops_received; /* num of ops received (next op_id) */ - long c_ops_executing; /* num of ops currently executing */ - long c_ops_pending; /* num of ops pending execution */ - long c_ops_completed; /* num of ops completed */ + BerElement *c_currentber; /* ber we're attempting to read */ + int c_writewaiter; /* true if writer is waiting */ + + long c_n_ops_received; /* num of ops received (next op_id) */ +#ifdef LDAP_COUNTERS + long c_n_ops_executing; /* num of ops currently executing */ + long c_n_ops_pending; /* num of ops pending execution */ + long c_n_ops_completed; /* num of ops completed */ +#endif } Connection; #if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG) diff --git a/servers/slapd/tools/Makefile.in b/servers/slapd/tools/Makefile.in index f53ed41629..f8e8195e38 100644 --- a/servers/slapd/tools/Makefile.in +++ b/servers/slapd/tools/Makefile.in @@ -31,7 +31,8 @@ PROGRAMS2=ldif2index-bdb2 ldif2ldbm-bdb2 \ ldif2id2entry-bdb2 ldif2id2children-bdb2 SRCS = centipede.c ldbmcat.c ldbmtest.c sizecount.c \ - ldif.c ldif2id2children.c ldif2id2entry.c ldif2index.c ldif2ldbm.c + ldif.c ldif2id2children.c ldif2id2entry.c ldif2index.c ldif2ldbm.c \ + mimic.c SRCS2 = ldif2id2children-bdb2.c ldif2id2entry-bdb2.c \ ldif2index-bdb2.c ldif2ldbm-bdb2.c @@ -41,8 +42,9 @@ XSRCS = edb2-vers.c EDB2LDIFSRCS = edb2ldif.c ldapsyntax.c EDB2LDIFOBJS = edb2ldif.o ldapsyntax.o -OBJS2 = ../config.o ../ch_malloc.o ../backend.o ../charray.o \ - ../aclparse.o ../schema.o ../result.o ../filterentry.o \ +OBJS2 = mimic.o \ + ../config.o ../ch_malloc.o ../backend.o ../charray.o \ + ../aclparse.o ../schema.o ../filterentry.o \ ../acl.o ../phonetic.o ../attr.o ../value.o ../entry.o \ ../dn.o ../filter.o ../str2filter.o ../ava.o ../init.o \ ../schemaparse.o diff --git a/servers/slapd/tools/mimic.c b/servers/slapd/tools/mimic.c new file mode 100644 index 0000000000..87359d3136 --- /dev/null +++ b/servers/slapd/tools/mimic.c @@ -0,0 +1,48 @@ +/* + * Mimic unused interfaces of slapd... + * needed for linking. + */ +#include "portable.h" + +#include + +#include "../slap.h" + +void +send_ldap_result( + Connection *conn, + Operation *op, + int err, + char *matched, + char *text +) +{ + assert(0); +} + +void +send_ldap_search_result( + Connection *conn, + Operation *op, + int err, + char *matched, + char *text, + int nentries +) +{ + assert(0); +} + +int +send_search_entry( + Backend *be, + Connection *conn, + Operation *op, + Entry *e, + char **attrs, + int attrsonly +) +{ + assert(0); + return -1; +} diff --git a/servers/slapd/unbind.c b/servers/slapd/unbind.c index 1416393343..f351e55409 100644 --- a/servers/slapd/unbind.c +++ b/servers/slapd/unbind.c @@ -41,7 +41,4 @@ do_unbind( /* pass the unbind to all backends */ backend_unbind( conn, op ); - - /* close the connection to the client */ - close_connection( conn, op->o_connid, op->o_opid ); } -- 2.39.5