X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fconnection.c;h=7d14e0c81875bdfd0ff815b358c1f78308a8e38e;hb=a05cbba77a94875ac00c207344d819513ff6499d;hp=bab511c586f098110b6dbd6371d68d1bdf6073b5;hpb=f11fcf47d26ae413a64d65a2ba951e7c59d52fa4;p=openldap diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index bab511c586..7d14e0c818 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-2009 The OpenLDAP Foundation. + * Copyright 1998-2011 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,6 +39,10 @@ #include "lutil.h" #include "slap.h" +#ifdef LDAP_CONNECTIONLESS +#include "../../libraries/liblber/lber-int.h" /* ber_int_sb_read() */ +#endif + #ifdef LDAP_SLAPI #include "slapi/slapi.h" #endif @@ -48,33 +52,19 @@ static ldap_pvt_thread_mutex_t connections_mutex; static Connection *connections = NULL; static ldap_pvt_thread_mutex_t conn_nextid_mutex; -static unsigned long conn_nextid = 0; +static unsigned long conn_nextid = SLAPD_SYNC_SYNCCONN_OFFSET; static const char conn_lost_str[] = "connection lost"; -/* structure state (protected by connections_mutex) */ -#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) */ -#define SLAP_C_INACTIVE 0x01 /* zero threads */ -#define SLAP_C_ACTIVE 0x02 /* one or more threads */ -#define SLAP_C_BINDING 0x03 /* binding */ -#define SLAP_C_CLOSING 0x04 /* closing */ -#define SLAP_C_CLIENT 0x05 /* outbound client conn */ - const char * connection_state2str( int state ) { switch( state ) { case SLAP_C_INVALID: return "!"; case SLAP_C_INACTIVE: return "|"; + case SLAP_C_CLOSING: return "C"; case SLAP_C_ACTIVE: return ""; case SLAP_C_BINDING: return "B"; - case SLAP_C_CLOSING: return "C"; case SLAP_C_CLIENT: return "L"; } @@ -235,33 +225,59 @@ int connections_timeout_idle(time_t now) */ if(( c->c_n_ops_executing && !c->c_writewaiter) || c->c_conn_state == SLAP_C_CLIENT ) { + connection_done( c ); continue; } - if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) { + if( global_idletimeout && + difftime( c->c_activitytime+global_idletimeout, now) < 0 ) { /* close it */ connection_closing( c, "idletimeout" ); connection_close( c ); i++; continue; } - if ( c->c_writewaiter ) { + if ( c->c_writewaiter && global_writetimeout ) { writers = 1; if( difftime( c->c_activitytime+global_writetimeout, now) < 0 ) { /* close it */ connection_closing( c, "writetimeout" ); connection_close( c ); i++; + continue; } } + connection_done( c ); } - connection_done( c ); - if ( !writers ) + if ( old && !writers ) slapd_clr_writetime( old ); return i; } +/* Drop all client connections */ +void connections_drop() +{ + Connection* c; + int connindex; + + for( c = connection_first( &connindex ); + c != NULL; + c = connection_next( c, &connindex ) ) + { + /* Don't close a slow-running request or a persistent + * outbound connection. + */ + if(( c->c_n_ops_executing && !c->c_writewaiter) + || c->c_conn_state == SLAP_C_CLIENT ) { + connection_done( c ); + continue; + } + connection_closing( c, "dropping" ); + connection_close( c ); + } +} + static Connection* connection_get( ber_socket_t s ) { Connection *c; @@ -285,12 +301,11 @@ static Connection* connection_get( ber_socket_t s ) 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( c->c_sd == AC_SOCKET_INVALID ); - Debug( LDAP_DEBUG_CONNS, "connection_get(%d): connection not used\n", s, 0, 0 ); + assert( c->c_conn_state == SLAP_C_INVALID ); + assert( c->c_sd == AC_SOCKET_INVALID ); ldap_pvt_thread_mutex_unlock( &c->c_mutex ); return NULL; @@ -556,9 +571,9 @@ Connection * connection_init( slap_sasl_external( c, ssf, authid ); slapd_add_internal( s, 1 ); - ldap_pvt_thread_mutex_unlock( &c->c_mutex ); backend_connection_init(c); + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); return c; } @@ -695,19 +710,15 @@ connection_destroy( Connection *c ) } } -int connection_state_closing( Connection *c ) +int connection_valid( Connection *c ) { /* c_mutex must be locked by caller */ - int state; assert( c != NULL ); - assert( c->c_struct_state == SLAP_C_USED ); - - state = c->c_conn_state; - - assert( state != SLAP_C_INVALID ); - return state == SLAP_C_CLOSING; + return c->c_struct_state == SLAP_C_USED && + c->c_conn_state >= SLAP_C_ACTIVE && + c->c_conn_state <= SLAP_C_CLIENT; } static void connection_abandon( Connection *c ) @@ -716,7 +727,6 @@ static void connection_abandon( Connection *c ) Operation *o, *next, op = {0}; Opheader ohdr = {0}; - SlapReply rs = {0}; op.o_hdr = &ohdr; op.o_conn = c; @@ -724,6 +734,8 @@ static void connection_abandon( Connection *c ) op.o_tag = LDAP_REQ_ABANDON; for ( o = LDAP_STAILQ_FIRST( &c->c_ops ); o; o=next ) { + SlapReply rs = {REP_RESULT}; + next = LDAP_STAILQ_NEXT( o, o_next ); op.orn_msgid = o->o_msgid; o->o_abandon = 1; @@ -752,11 +764,39 @@ static void connection_abandon( Connection *c ) } } +static void +connection_wake_writers( Connection *c ) +{ + /* wake write blocked operations */ + ldap_pvt_thread_mutex_lock( &c->c_write1_mutex ); + if ( c->c_writers > 0 ) { + c->c_writers = -c->c_writers; + ldap_pvt_thread_cond_broadcast( &c->c_write1_cv ); + ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex ); + if ( c->c_writewaiter ) { + ldap_pvt_thread_mutex_lock( &c->c_write2_mutex ); + ldap_pvt_thread_cond_signal( &c->c_write2_cv ); + slapd_clr_write( c->c_sd, 1 ); + ldap_pvt_thread_mutex_unlock( &c->c_write2_mutex ); + } + ldap_pvt_thread_mutex_lock( &c->c_write1_mutex ); + while ( c->c_writers ) { + ldap_pvt_thread_cond_wait( &c->c_write1_cv, &c->c_write1_mutex ); + } + ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex ); + } else { + ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex ); + slapd_clr_write( c->c_sd, 1 ); + } +} + void connection_closing( Connection *c, const char *why ) { assert( connections != NULL ); assert( c != NULL ); - assert( c->c_struct_state == SLAP_C_USED ); + + if ( c->c_struct_state != SLAP_C_USED ) return; + assert( c->c_conn_state != SLAP_C_INVALID ); /* c_mutex must be locked by caller */ @@ -776,26 +816,7 @@ void connection_closing( Connection *c, const char *why ) connection_abandon( c ); /* wake write blocked operations */ - ldap_pvt_thread_mutex_lock( &c->c_write1_mutex ); - if ( c->c_writers > 0 ) { - c->c_writers = -c->c_writers; - ldap_pvt_thread_cond_broadcast( &c->c_write1_cv ); - ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex ); - if ( c->c_writewaiter ) { - ldap_pvt_thread_mutex_lock( &c->c_write2_mutex ); - ldap_pvt_thread_cond_signal( &c->c_write2_cv ); - slapd_clr_write( c->c_sd, 1 ); - ldap_pvt_thread_mutex_unlock( &c->c_write2_mutex ); - } - ldap_pvt_thread_mutex_lock( &c->c_write1_mutex ); - while ( c->c_writers ) { - ldap_pvt_thread_cond_wait( &c->c_write1_cv, &c->c_write1_mutex ); - } - ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex ); - } else { - ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex ); - slapd_clr_write( c->c_sd, 1 ); - } + connection_wake_writers( c ); } else if( why == NULL && c->c_close_reason == conn_lost_str ) { /* Client closed connection after doing Unbind. */ @@ -808,7 +829,9 @@ connection_close( Connection *c ) { assert( connections != NULL ); assert( c != NULL ); - assert( c->c_struct_state == SLAP_C_USED ); + + if ( c->c_struct_state != SLAP_C_USED ) return; + assert( c->c_conn_state == SLAP_C_CLOSING ); /* NOTE: c_mutex should be locked by caller */ @@ -1021,7 +1044,7 @@ conn_counter_init( Operation *op, void *ctx ) static void * connection_operation( void *ctx, void *arg_v ) { - int rc = LDAP_OTHER; + int rc = LDAP_OTHER, cancel; Operation *op = arg_v; SlapReply rs = {REP_RESULT}; ber_tag_t tag = op->o_tag; @@ -1125,22 +1148,32 @@ operations_error: INCR_OP_COMPLETED( opidx ); } - if ( op->o_cancel == SLAP_CANCEL_REQ ) { - if ( rc == SLAPD_ABANDON ) { - op->o_cancel = SLAP_CANCEL_ACK; - } else { - op->o_cancel = LDAP_TOO_LATE; + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + + if ( opidx == SLAP_OP_BIND && conn->c_conn_state == SLAP_C_BINDING ) + conn->c_conn_state = SLAP_C_ACTIVE; + + cancel = op->o_cancel; + if ( cancel != SLAP_CANCEL_NONE && cancel != SLAP_CANCEL_DONE ) { + if ( cancel == SLAP_CANCEL_REQ ) { + op->o_cancel = rc == SLAPD_ABANDON + ? SLAP_CANCEL_ACK : LDAP_TOO_LATE; } - } - while ( op->o_cancel != SLAP_CANCEL_NONE && - op->o_cancel != SLAP_CANCEL_DONE ) - { - ldap_pvt_thread_yield(); + do { + /* Fake a cond_wait with thread_yield, then + * verify the result properly mutex-protected. + */ + ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); + do { + ldap_pvt_thread_yield(); + } while ( (cancel = op->o_cancel) != SLAP_CANCEL_NONE + && cancel != SLAP_CANCEL_DONE ); + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); + } while ( (cancel = op->o_cancel) != SLAP_CANCEL_NONE + && cancel != SLAP_CANCEL_DONE ); } - ldap_pvt_thread_mutex_lock( &conn->c_mutex ); - ber_set_option( op->o_ber, LBER_OPT_BER_MEMCTX, &memctx_null ); LDAP_STAILQ_REMOVE( &conn->c_ops, op, Operation, o_next); @@ -1259,6 +1292,11 @@ int connection_read_activate( ber_socket_t s ) if ( rc ) return rc; + /* Don't let blocked writers block a pause request */ + if ( connections[s].c_writewaiter && + ldap_pvt_thread_pool_pausing( &connection_pool )) + connection_wake_writers( &connections[s] ); + rc = ldap_pvt_thread_pool_submit( &connection_pool, connection_read_thread, (void *)(long)s ); @@ -1271,24 +1309,6 @@ int connection_read_activate( ber_socket_t s ) return rc; } -void -connection_hangup( ber_socket_t s ) -{ - Connection *c; - - c = connection_get( s ); - if ( c ) { - if ( c->c_conn_state == SLAP_C_CLIENT ) { - connection_return( c ); - connection_read_activate( s ); - } else { - connection_closing( c, "connection lost" ); - connection_close( c ); - connection_return( c ); - } - } -} - static int connection_read( ber_socket_t s, conn_readinfo *cri ) { @@ -1371,6 +1391,11 @@ connection_read( ber_socket_t s, conn_readinfo *cri ) c->c_connid, (int) s, c->c_tls_ssf, c->c_ssf, 0 ); slap_sasl_external( c, c->c_tls_ssf, &authid ); if ( authid.bv_val ) free( authid.bv_val ); + } else if ( rc == 1 && ber_sockbuf_ctrl( c->c_sb, + LBER_SB_OPT_NEEDS_WRITE, NULL )) { /* need to retry */ + slapd_set_write( s, 1 ); + connection_return( c ); + return 0; } /* if success and data is ready, fall thru to data input loop */ @@ -1475,12 +1500,20 @@ connection_input( Connection *conn , conn_readinfo *cri ) #ifdef LDAP_CONNECTIONLESS if ( conn->c_is_udp ) { char peername[sizeof("IP=255.255.255.255:65336")]; + const char *peeraddr_string = NULL; len = ber_int_sb_read(conn->c_sb, &peeraddr, sizeof(struct sockaddr)); if (len != sizeof(struct sockaddr)) return 1; +#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) + char addr[INET_ADDRSTRLEN]; + peeraddr_string = inet_ntop( AF_INET, &peeraddr.sa_in_addr.sin_addr, + addr, sizeof(addr) ); +#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ + peeraddr_string = inet_ntoa( peeraddr.sa_in_addr.sin_addr ); +#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ sprintf( peername, "IP=%s:%d", - inet_ntoa( peeraddr.sa_in_addr.sin_addr ), + peeraddr_string, (unsigned) ntohs( peeraddr.sa_in_addr.sin_port ) ); Statslog( LDAP_DEBUG_STATS, "conn=%lu UDP request from %s (%s) accepted.\n", @@ -1526,8 +1559,8 @@ connection_input( Connection *conn , conn_readinfo *cri ) #ifdef LDAP_CONNECTIONLESS if( conn->c_is_udp ) { if( tag == LBER_OCTETSTRING ) { - ber_get_stringa( ber, &cdn ); - tag = ber_peek_tag(ber, &len); + if ( (tag = ber_get_stringa( ber, &cdn )) != LBER_ERROR ) + tag = ber_peek_tag( ber, &len ); } if( tag != LDAP_REQ_ABANDON && tag != LDAP_REQ_SEARCH ) { Debug( LDAP_DEBUG_ANY, "invalid req for UDP 0x%lx\n", tag, 0, 0 ); @@ -1545,6 +1578,9 @@ connection_input( Connection *conn , conn_readinfo *cri ) ctx = cri->ctx; op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++, ctx ); + Debug( LDAP_DEBUG_TRACE, "op tag 0x%lx, time %ld\n", tag, + (long) op->o_time, 0); + op->o_conn = conn; /* clear state if the connection is being reused from inactive */ if ( conn->c_conn_state == SLAP_C_INACTIVE ) { @@ -1730,8 +1766,6 @@ static int connection_bind_cleanup_cb( Operation *op, SlapReply *rs ) 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 ); @@ -1869,6 +1903,14 @@ int connection_write(ber_socket_t s) return -1; } +#ifdef HAVE_TLS + if ( c->c_is_tls && c->c_needs_tls_accept ) { + connection_return( c ); + connection_read_activate( s ); + return 0; + } +#endif + c->c_n_write++; Debug( LDAP_DEBUG_TRACE,