X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fconnection.c;h=eecf90409b9cb09c3cf6ed5179cb9609d6463704;hb=fb2e448e877a8a387084dde517362c9f7bf1b6b7;hp=8a2fc55c10b4d3293a0b55db83a377d7ca48a59f;hpb=098153c5bba471a8cfe69aa3d7a1f135a80b26ca;p=openldap diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 8a2fc55c10..eecf90409b 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-2006 The OpenLDAP Foundation. + * Copyright 1998-2007 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -196,23 +196,22 @@ int connections_shutdown(void) ber_socket_t i; 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 ); - - /* c_mutex is locked */ - connection_closing( &connections[i], "slapd shutdown" ); - connection_close( &connections[i] ); - - ldap_pvt_thread_mutex_unlock( &connections[i].c_mutex ); } return 0; @@ -306,11 +305,20 @@ static Connection* connection_get( ber_socket_t s ) if( c != NULL ) { ber_socket_t sd; - assert( c->c_struct_state != SLAP_C_UNINITIALIZED ); - ldap_pvt_thread_mutex_lock( &c->c_mutex ); + assert( c->c_struct_state != SLAP_C_UNINITIALIZED ); + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); +#ifdef HAVE_WINSOCK + /* Avoid race condition after releasing + * connections_mutex + */ + if ( sd != s ) { + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + return NULL; + } +#endif if( c->c_struct_state != SLAP_C_USED ) { /* connection must have been closed due to resched */ @@ -653,7 +661,7 @@ void connection2anonymous( Connection *c ) static void connection_destroy( Connection *c ) { - ber_socket_t sd, inval = AC_SOCKET_INVALID; + ber_socket_t sd; unsigned long connid; const char *close_reason; Sockbuf *sb; @@ -731,23 +739,19 @@ connection_destroy( Connection *c ) } ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); - slapd_sd_lock(); - - ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &inval ); - ber_sockbuf_free( sb ); /* 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, 1, 0, 1 ); + slapd_remove( sd, sb, 1, 0, 0 ); - Statslog( LDAP_DEBUG_STATS, (close_reason - ? "conn=%lu fd=%ld closed (%s)\n" - : "conn=%lu fd=%ld closed\n"), + if ( close_reason == NULL ) { + close_reason = ""; + } + + Statslog( LDAP_DEBUG_STATS, "conn=%lu fd=%ld closed (%s)\n", connid, (long) sd, close_reason, 0, 0 ); - } else { - slapd_sd_unlock(); } } @@ -835,9 +839,19 @@ void connection_closing( Connection *c, const char *why ) 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( sd, 1 ); + ldap_pvt_thread_mutex_unlock( &c->c_mutex ); + 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( sd, 1 ); } } else if( why == NULL && c->c_close_reason == conn_lost_str ) { @@ -846,19 +860,31 @@ void connection_closing( Connection *c, const char *why ) } } -static void connection_close( Connection *c ) +static void +connection_close( Connection *c ) { - ber_socket_t sd; + ber_socket_t sd = AC_SOCKET_INVALID; 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: 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) ) { + /* NOTE: don't get the file descriptor if not needed */ + if ( LogTest( LDAP_DEBUG_TRACE ) ) { + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_GET_FD, &sd ); + } + + 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 ); @@ -867,6 +893,7 @@ static void connection_close( Connection *c ) Debug( LDAP_DEBUG_TRACE, "connection_close: conn=%lu sd=%d\n", c->c_connid, sd, 0 ); + connection_destroy( c ); } @@ -912,9 +939,14 @@ Connection* connection_next( Connection *c, ber_socket_t *index ) 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 ); +#ifdef HAVE_WINSOCK break; +#else + continue; +#endif } if( connections[*index].c_struct_state == SLAP_C_USED ) { @@ -934,7 +966,10 @@ Connection* connection_next( Connection *c, ber_socket_t *index ) 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 ); } @@ -1004,7 +1039,7 @@ 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; @@ -1087,53 +1122,8 @@ connection_operation( void *ctx, void *arg_v ) } } - 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 ); @@ -1141,7 +1131,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 */ @@ -1155,6 +1145,7 @@ operations_error: op->o_cancel = LDAP_TOO_LATE; } } + while ( op->o_cancel != SLAP_CANCEL_NONE && op->o_cancel != SLAP_CANCEL_DONE ) { @@ -1219,7 +1210,7 @@ void connection_client_stop( ber_socket_t s ) { Connection *c; - ber_socket_t inval = AC_SOCKET_INVALID; + Sockbuf *sb; /* get (locked) connection */ c = connection_get( s ); @@ -1230,15 +1221,13 @@ void connection_client_stop( c->c_conn_state = SLAP_C_INVALID; c->c_struct_state = SLAP_C_UNUSED; c->c_close_reason = "?"; /* should never be needed */ - slapd_sd_lock(); - ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &inval ); - ber_sockbuf_free( c->c_sb ); - slapd_remove( s, 0, 1, 1 ); + 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 ); } @@ -1513,7 +1502,7 @@ connection_input( Connection *conn ) return -1; } - errno = 0; + sock_errset(0); #ifdef LDAP_CONNECTIONLESS if ( conn->c_is_udp ) { @@ -1533,16 +1522,16 @@ connection_input( Connection *conn ) tag = ber_get_next( conn->c_sb, &len, conn->c_currentber ); if ( tag != LDAP_TAG_MESSAGE ) { - int err = errno; + int err = sock_errno(); ber_socket_t sd; ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); - 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", + sd, err, sock_errstr(err) ); ber_free( conn->c_currentber, 1 ); conn->c_currentber = NULL; @@ -1770,13 +1759,17 @@ 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 ); - op->o_conn->c_conn_state = SLAP_C_ACTIVE; + 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 );