static int wait4msg( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout, LDAPMessage **result ) { int rc; struct timeval tv = { 0 }, tv0 = { 0 }, start_time_tv = { 0 }, *tvp = NULL; LDAPConn *lc; assert( ld != NULL ); assert( result != NULL ); #ifdef LDAP_R_COMPILE LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); #endif if ( timeout == NULL && ld->ld_options.ldo_tm_api.tv_sec >= 0 ) { tv = ld->ld_options.ldo_tm_api; timeout = &tv; } #ifdef LDAP_DEBUG if ( timeout == NULL ) { Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (infinite timeout)\n", (void *)ld, msgid, 0 ); } else { Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (timeout %ld usec)\n", (void *)ld, msgid, (long)timeout->tv_sec * 1000000 + timeout->tv_usec ); } #endif /* LDAP_DEBUG */ if ( timeout != NULL ) { tv0 = *timeout; tv = *timeout; tvp = &tv; #ifdef HAVE_GETTIMEOFDAY gettimeofday( &start_time_tv, NULL ); #else /* ! HAVE_GETTIMEOFDAY */ time( &start_time_tv.tv_sec ); start_time_tv.tv_usec = 0; #endif /* ! HAVE_GETTIMEOFDAY */ } rc = LDAP_MSG_X_KEEP_LOOKING; while ( rc == LDAP_MSG_X_KEEP_LOOKING ) { #ifdef LDAP_DEBUG if ( ldap_debug & LDAP_DEBUG_TRACE ) { Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n", (void *)ld, msgid, all ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); #endif ldap_dump_connection( ld, ld->ld_conns, 1 ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif ldap_dump_requests_and_responses( ld ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); #endif } #endif /* LDAP_DEBUG */ if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) { rc = (*result)->lm_msgtype; } else { int lc_ready = 0; #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); #endif for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) { #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); #endif rc = try_read1msg( ld, msgid, all, &lc, result ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); #endif lc_ready = 1; break; } } #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); #endif if ( !lc_ready ) { rc = ldap_int_select( ld, tvp ); #ifdef LDAP_DEBUG if ( rc == -1 ) { Debug( LDAP_DEBUG_TRACE, "ldap_int_select returned -1: errno %d\n", sock_errno(), 0, 0 ); } #endif if ( rc == 0 || ( rc == -1 && ( !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART) || sock_errno() != EINTR ) ) ) { ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : LDAP_TIMEOUT); return( rc ); } if ( rc == -1 ) { rc = LDAP_MSG_X_KEEP_LOOKING; /* select interrupted: loop */ } else { rc = LDAP_MSG_X_KEEP_LOOKING; #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); #endif if ( ld->ld_requests && ld->ld_requests->lr_status == LDAP_REQST_WRITING && ldap_is_write_ready( ld, ld->ld_requests->lr_conn->lconn_sb ) ) { ldap_int_flush_request( ld, ld->ld_requests ); } #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); #endif for ( lc = ld->ld_conns; rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; ) { if ( lc->lconn_status == LDAP_CONNST_CONNECTED && ldap_is_read_ready( ld, lc->lconn_sb ) ) { #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); #endif rc = try_read1msg( ld, msgid, all, &lc, result ); #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ld->ld_conn_mutex ); #endif if ( lc == NULL ) { /* if lc gets free()'d, * there's no guarantee * lc->lconn_next is still * sane; better restart * (ITS#4405) */ lc = ld->ld_conns; /* don't get to next conn! */ break; } } /* next conn */ lc = lc->lconn_next; } #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_conn_mutex ); #endif } } } if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) { struct timeval curr_time_tv = { 0 }, delta_time_tv = { 0 }; #ifdef HAVE_GETTIMEOFDAY gettimeofday( &curr_time_tv, NULL ); #else /* ! HAVE_GETTIMEOFDAY */ time( &curr_time_tv.tv_sec ); curr_time_tv.tv_usec = 0; #endif /* ! HAVE_GETTIMEOFDAY */ /* delta_time = tmp_time - start_time */ delta_time_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec; delta_time_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec; if ( delta_time_tv.tv_usec < 0 ) { delta_time_tv.tv_sec--; delta_time_tv.tv_usec += 1000000; } /* tv0 < delta_time ? */ if ( ( tv0.tv_sec < delta_time_tv.tv_sec ) || ( ( tv0.tv_sec == delta_time_tv.tv_sec ) && ( tv0.tv_usec < delta_time_tv.tv_usec ) ) ) { rc = 0; /* timed out */ ld->ld_errno = LDAP_TIMEOUT; break; } /* tv0 -= delta_time */ tv0.tv_sec -= delta_time_tv.tv_sec; tv0.tv_usec -= delta_time_tv.tv_usec; if ( tv0.tv_usec < 0 ) { tv0.tv_sec--; tv0.tv_usec += 1000000; } tv.tv_sec = tv0.tv_sec; tv.tv_usec = tv0.tv_usec; Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld s %ld us to go\n", (void *)ld, (long) tv.tv_sec, (long) tv.tv_usec ); start_time_tv.tv_sec = curr_time_tv.tv_sec; start_time_tv.tv_usec = curr_time_tv.tv_usec; } } return( rc ); }
/* protected by res_mutex */ static int wait4msg( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout, LDAPMessage **result ) { int rc; struct timeval tv = { 0 }, tv0 = { 0 }, start_time_tv = { 0 }, *tvp = NULL; LDAPConn *lc; assert( ld != NULL ); assert( result != NULL ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); if ( timeout == NULL && ld->ld_options.ldo_tm_api.tv_sec >= 0 ) { tv = ld->ld_options.ldo_tm_api; timeout = &tv; } #ifdef LDAP_DEBUG if ( timeout == NULL ) { Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (infinite timeout)\n", (void *)ld, msgid, 0 ); } else { Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (timeout %ld usec)\n", (void *)ld, msgid, (long)timeout->tv_sec * 1000000 + timeout->tv_usec ); } #endif /* LDAP_DEBUG */ if ( timeout != NULL && timeout->tv_sec != -1 ) { tv0 = *timeout; tv = *timeout; tvp = &tv; #ifdef HAVE_GETTIMEOFDAY gettimeofday( &start_time_tv, NULL ); #else /* ! HAVE_GETTIMEOFDAY */ start_time_tv.tv_sec = time( NULL ); start_time_tv.tv_usec = 0; #endif /* ! HAVE_GETTIMEOFDAY */ } rc = LDAP_MSG_X_KEEP_LOOKING; while ( rc == LDAP_MSG_X_KEEP_LOOKING ) { #ifdef LDAP_DEBUG if ( ldap_debug & LDAP_DEBUG_TRACE ) { Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n", (void *)ld, msgid, all ); ldap_dump_connection( ld, ld->ld_conns, 1 ); LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); ldap_dump_requests_and_responses( ld ); LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); } #endif /* LDAP_DEBUG */ if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) { rc = (*result)->lm_msgtype; } else { int lc_ready = 0; LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) { lc_ready = 2; /* ready at ber level, not socket level */ break; } } if ( !lc_ready ) { int err; rc = ldap_int_select( ld, tvp ); if ( rc == -1 ) { err = sock_errno(); #ifdef LDAP_DEBUG Debug( LDAP_DEBUG_TRACE, "ldap_int_select returned -1: errno %d\n", err, 0, 0 ); #endif } if ( rc == 0 || ( rc == -1 && ( !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART) || err != EINTR ) ) ) { ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : LDAP_TIMEOUT); LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return( rc ); } if ( rc == -1 ) { rc = LDAP_MSG_X_KEEP_LOOKING; /* select interrupted: loop */ } else { lc_ready = 1; } } if ( lc_ready ) { LDAPConn *lnext; int serviced = 0; rc = LDAP_MSG_X_KEEP_LOOKING; LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); if ( ld->ld_requests && ld->ld_requests->lr_status == LDAP_REQST_WRITING && ldap_is_write_ready( ld, ld->ld_requests->lr_conn->lconn_sb ) ) { serviced = 1; ldap_int_flush_request( ld, ld->ld_requests ); } for ( lc = ld->ld_conns; rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; lc = lnext ) { if ( lc->lconn_status == LDAP_CONNST_CONNECTED && ldap_is_read_ready( ld, lc->lconn_sb ) ) { serviced = 1; /* Don't let it get freed out from under us */ ++lc->lconn_refcnt; rc = try_read1msg( ld, msgid, all, lc, result ); lnext = lc->lconn_next; /* Only take locks if we're really freeing */ if ( lc->lconn_refcnt <= 1 ) { ldap_free_connection( ld, lc, 0, 1 ); } else { --lc->lconn_refcnt; } } else { lnext = lc->lconn_next; } } LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); /* Quit looping if no one handled any socket events */ if (!serviced && lc_ready == 1) rc = -1; } LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); } if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) { struct timeval curr_time_tv = { 0 }, delta_time_tv = { 0 }; #ifdef HAVE_GETTIMEOFDAY gettimeofday( &curr_time_tv, NULL ); #else /* ! HAVE_GETTIMEOFDAY */ curr_time_tv.tv_sec = time( NULL ); curr_time_tv.tv_usec = 0; #endif /* ! HAVE_GETTIMEOFDAY */ /* delta_time = tmp_time - start_time */ delta_time_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec; delta_time_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec; if ( delta_time_tv.tv_usec < 0 ) { delta_time_tv.tv_sec--; delta_time_tv.tv_usec += 1000000; } /* tv0 < delta_time ? */ if ( ( tv0.tv_sec < delta_time_tv.tv_sec ) || ( ( tv0.tv_sec == delta_time_tv.tv_sec ) && ( tv0.tv_usec < delta_time_tv.tv_usec ) ) ) { rc = 0; /* timed out */ ld->ld_errno = LDAP_TIMEOUT; break; } /* tv0 -= delta_time */ tv0.tv_sec -= delta_time_tv.tv_sec; tv0.tv_usec -= delta_time_tv.tv_usec; if ( tv0.tv_usec < 0 ) { tv0.tv_sec--; tv0.tv_usec += 1000000; } tv.tv_sec = tv0.tv_sec; tv.tv_usec = tv0.tv_usec; Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld s %ld us to go\n", (void *)ld, (long) tv.tv_sec, (long) tv.tv_usec ); start_time_tv.tv_sec = curr_time_tv.tv_sec; start_time_tv.tv_usec = curr_time_tv.tv_usec; } } return( rc ); }