X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=libraries%2Flibldap%2Fresult.c;h=0e6f4bf80f13b784eeb35a7f29ec49d53a05b6fb;hb=a2c6a984270a536432d027a1b5f4830ae3f44176;hp=814b471e33724b857d67a0205c136ed1c4b7bfa8;hpb=005a2f7aec9a9b8bde4c461ad45c9889eb0e9d18;p=openldap diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index 814b471e33..0e6f4bf80f 100644 --- a/libraries/libldap/result.c +++ b/libraries/libldap/result.c @@ -63,6 +63,7 @@ static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, Sockbuf *sb, LDAPConn *lc, LDAPMessage **result )); static ber_tag_t build_result_ber LDAP_P(( LDAP *ld, BerElement **bp, LDAPRequest *lr )); static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )); +static LDAPMessage * chkResponseList LDAP_P(( LDAP *ld, int msgid, int all)); /* @@ -73,9 +74,11 @@ static void merge_error_info LDAP_P(( LDAP *ld, LDAPRequest *parentr, LDAPReques * with msgid. If all is LDAP_MSG_ONE (0) the first message with id * msgid will be accepted, otherwise, ldap_result will wait for all * responses with id msgid and then return a pointer to the entire list - * of messages. This is only useful for search responses, which can be - * of two message types (zero or more entries, followed by an - * ldap result). The type of the first message received is returned. + * of messages. In general, this is only useful for search responses, + * which can be of three message types (zero or more entries, zero or + * search references, followed by an ldap result). An extension to + * LDAPv3 allows partial extended responses to be returned in response + * to any request. The type of the first message received is returned. * When waiting, any messages that have been abandoned are discarded. * * Example: @@ -89,12 +92,12 @@ ldap_result( struct timeval *timeout, LDAPMessage **result ) { - LDAPMessage *lm, *lastlm, *nextlm; + LDAPMessage *lm; assert( ld != NULL ); assert( result != NULL ); - Debug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "ldap_result msgid %d\n", msgid, 0, 0 ); if( ld == NULL ) { return -1; @@ -105,22 +108,46 @@ ldap_result( return -1; } - /* - * First, look through the list of responses we have received on + lm = chkResponseList(ld, msgid, all); + + if ( lm == NULL ) { + return( wait4msg( ld, msgid, all, timeout, result ) ); + } + + *result = lm; + ld->ld_errno = LDAP_SUCCESS; + return( lm->lm_msgtype ); +} + +static LDAPMessage * +chkResponseList( + LDAP *ld, + int msgid, + int all) +{ + LDAPMessage *lm, *lastlm, *nextlm; + /* + * Look through the list of responses we have received on * this association and see if the response we're interested in * is there. If it is, return it. If not, call wait4msg() to * wait until it arrives or timeout occurs. */ - *result = NULL; + Debug( LDAP_DEBUG_TRACE, + "ldap_chkResponseList for msgid=%d, all=%d\n", + msgid, all, 0 ); lastlm = NULL; for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) { nextlm = lm->lm_next; if ( ldap_abandoned( ld, lm->lm_msgid ) ) { + Debug( LDAP_DEBUG_TRACE, + "ldap_chkResponseList msg abandoned, msgid %d\n", + msgid, 0, 0 ); ldap_mark_abandoned( ld, lm->lm_msgid ); if ( lastlm == NULL ) { + /* Remove first entry in list */ ld->ld_responses = lm->lm_next; } else { lastlm->lm_next = nextlm; @@ -134,16 +161,17 @@ ldap_result( if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) { LDAPMessage *tmp; - if ( all == LDAP_MSG_ONE - || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT - && lm->lm_msgtype != LDAP_RES_SEARCH_REFERENCE /* LDAPv3 */ - && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY - && lm->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL) ) + if ( all == LDAP_MSG_ONE || msgid == LDAP_RES_UNSOLICITED ) { break; + } for ( tmp = lm; tmp != NULL; tmp = tmp->lm_chain ) { - if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT ) + if ( tmp->lm_msgtype != LDAP_RES_SEARCH_ENTRY + && tmp->lm_msgtype != LDAP_RES_SEARCH_REFERENCE + && tmp->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL ) + { break; + } } if ( tmp == NULL ) { @@ -154,27 +182,34 @@ ldap_result( } lastlm = lm; } - if ( lm == NULL ) { - return( wait4msg( ld, msgid, all, timeout, result ) ); - } - if ( lastlm == NULL ) { - ld->ld_responses = (all == LDAP_MSG_ONE && lm->lm_chain != NULL - ? lm->lm_chain : lm->lm_next); + if ( lm != NULL ) { + /* Found an entry, remove it from the list */ + if ( lastlm == NULL ) { + ld->ld_responses = (all == LDAP_MSG_ONE && lm->lm_chain != NULL + ? lm->lm_chain : lm->lm_next); + } else { + lastlm->lm_next = (all == LDAP_MSG_ONE && lm->lm_chain != NULL + ? lm->lm_chain : lm->lm_next); + } + if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) { + lm->lm_chain->lm_next = lm->lm_next; + lm->lm_chain = NULL; + } + lm->lm_next = NULL; + } + +#ifdef LDAP_DEBUG + if( lm == NULL) { + Debug( LDAP_DEBUG_TRACE, + "ldap_chkResponseList returns NULL\n", 0, 0, 0); } else { - lastlm->lm_next = (all == LDAP_MSG_ONE && lm->lm_chain != NULL - ? lm->lm_chain : lm->lm_next); - } - if ( all == LDAP_MSG_ONE && lm->lm_chain != NULL ) - { - lm->lm_chain->lm_next = lm->lm_next; - lm->lm_chain = NULL; + Debug( LDAP_DEBUG_TRACE, + "ldap_chkResponseList returns msgid %d, type 0x%02lu\n", + lm->lm_msgid, (unsigned long) lm->lm_msgtype, 0); } - lm->lm_next = NULL; - - *result = lm; - ld->ld_errno = LDAP_SUCCESS; - return( lm->lm_msgtype ); +#endif + return lm; } static int @@ -196,11 +231,11 @@ wait4msg( #ifdef LDAP_DEBUG if ( timeout == NULL ) { - Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n", - 0, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout), msgid %d\n", + msgid, 0, 0 ); } else { - Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n", - (long) timeout->tv_sec, (long) timeout->tv_usec, 0 ); + Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec), msgid %d\n", + (long) timeout->tv_sec, (long) timeout->tv_usec, msgid ); } #endif /* LDAP_DEBUG */ @@ -215,57 +250,65 @@ wait4msg( rc = -2; while ( rc == -2 ) { #ifdef LDAP_DEBUG + Debug( LDAP_DEBUG_TRACE, "wait4msg continue, msgid %d, all %d\n", + msgid, all, 0 ); if ( ldap_debug & LDAP_DEBUG_TRACE ) { ldap_dump_connection( ld, ld->ld_conns, 1 ); ldap_dump_requests_and_responses( ld ); } #endif /* LDAP_DEBUG */ - for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { - if ( ber_sockbuf_ctrl( lc->lconn_sb, - LBER_SB_OPT_DATA_READY, NULL ) ) { - rc = try_read1msg( ld, msgid, all, lc->lconn_sb, - lc, result ); - break; - } - } - if ( lc == NULL ) { - rc = do_ldap_select( ld, tvp ); + if( (*result = chkResponseList(ld, msgid, all)) != NULL ) { + rc = (*result)->lm_msgtype; + } else { + + for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { + if ( ber_sockbuf_ctrl( lc->lconn_sb, + LBER_SB_OPT_DATA_READY, NULL ) ) { + rc = try_read1msg( ld, msgid, all, lc->lconn_sb, + lc, result ); + break; + } + } + + if ( lc == NULL ) { + rc = ldap_int_select( ld, tvp ); #ifdef LDAP_DEBUG - if ( rc == -1 ) { - Debug( LDAP_DEBUG_TRACE, - "do_ldap_select returned -1: errno %d\n", - errno, 0, 0 ); - } + if ( rc == -1 ) { + Debug( LDAP_DEBUG_TRACE, + "ldap_int_select returned -1: errno %d\n", + errno, 0, 0 ); + } #endif - if ( rc == 0 || ( rc == -1 && ( - !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART) - || errno != EINTR ))) - { - ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : - LDAP_TIMEOUT); - return( rc ); - } - - if ( rc == -1 ) { - rc = -2; /* select interrupted: loop */ - } else { - rc = -2; - for ( lc = ld->ld_conns; rc == -2 && lc != NULL; - lc = nextlc ) { - nextlc = lc->lconn_next; - if ( lc->lconn_status == - LDAP_CONNST_CONNECTED && - ldap_is_read_ready( ld, - lc->lconn_sb )) { - rc = try_read1msg( ld, msgid, all, - lc->lconn_sb, lc, result ); - } - } - } + if ( rc == 0 || ( rc == -1 && ( + !LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART) + || errno != EINTR ))) + { + ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : + LDAP_TIMEOUT); + return( rc ); + } + + if ( rc == -1 ) { + rc = -2; /* select interrupted: loop */ + } else { + rc = -2; + for ( lc = ld->ld_conns; rc == -2 && lc != NULL; + lc = nextlc ) { + nextlc = lc->lconn_next; + if ( lc->lconn_status == + LDAP_CONNST_CONNECTED && + ldap_is_read_ready( ld, + lc->lconn_sb )) { + rc = try_read1msg( ld, msgid, all, + lc->lconn_sb, lc, result ); + } + } + } + } } if ( rc == -2 && tvp != NULL ) { @@ -292,7 +335,7 @@ try_read1msg( ber_int_t msgid, int all, Sockbuf *sb, - LDAPConn *lc, + LDAPConn *lc, LDAPMessage **result ) { BerElement *ber; @@ -314,7 +357,7 @@ try_read1msg( assert( ld != NULL ); assert( lc != NULL ); - Debug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "read1msg: msgid %d, all %d\n", msgid, all, 0 ); if ( lc->lconn_ber == NULL ) { lc->lconn_ber = ldap_alloc_ber_with_options(ld); @@ -325,10 +368,16 @@ try_read1msg( } ber = lc->lconn_ber; - assert( BER_VALID (ber) ); + assert( LBER_VALID (ber) ); /* get the next message */ errno = 0; +#ifdef LDAP_CONNECTIONLESS + if ( LDAP_IS_UDP(ld) ) { + struct sockaddr from; + ber_int_sb_read(sb, &from, sizeof(struct sockaddr)); + } +#endif if ( (tag = ber_get_next( sb, &len, ber )) != LDAP_TAG_MESSAGE ) { if ( tag == LBER_DEFAULT) { @@ -376,7 +425,14 @@ try_read1msg( ber_free( ber, 1 ); return( -2 ); /* continue looking */ } - +#ifdef LDAP_CONNECTIONLESS + if (LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) { + char *blank; + ber_scanf(ber, "a{", &blank); + if (blank) + ber_memfree(blank); + } +#endif /* the message type */ if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) { ld->ld_errno = LDAP_DECODING_ERROR; @@ -384,7 +440,8 @@ try_read1msg( return( -1 ); } - Debug( LDAP_DEBUG_TRACE, "ldap_read: message type %s msgid %ld, original id %ld\n", + Debug( LDAP_DEBUG_TRACE, + "ldap_read: message type %s msgid %ld, original id %ld\n", ldap_int_msgtype2str( tag ), (long) lr->lr_msgid, (long) lr->lr_origid ); @@ -416,7 +473,7 @@ try_read1msg( } else { /* Note: refs arrary is freed by ldap_chase_v3referrals */ refer_cnt = ldap_chase_v3referrals( ld, lr, refs, - &lr->lr_res_error, &hadref ); + 1, &lr->lr_res_error, &hadref ); if ( refer_cnt > 0 ) { /* sucessfully chased reference */ /* If haven't got end search, set chasing referrals */ if( lr->lr_status != LDAP_REQST_COMPLETED) { @@ -455,7 +512,7 @@ try_read1msg( * Note: refs arrary is freed by ldap_chase_v3referrals */ refer_cnt = ldap_chase_v3referrals( ld, lr, refs, - &lr->lr_res_error, &hadref ); + 0, &lr->lr_res_error, &hadref ); lr->lr_status = LDAP_REQST_COMPLETED; Debug( LDAP_DEBUG_TRACE, "read1msg: referral chased, mark request completed, id = %d\n", @@ -492,14 +549,13 @@ try_read1msg( tmpber = *ber; /* struct copy */ if ( v3ref == 1 ) { ; /* V3 search reference or V3 referral sucessfully chased */ - } else - if ( ber_scanf( &tmpber, "{iaa}", &lderr, + } else if ( ber_scanf( &tmpber, "{iaa}", &lderr, &lr->lr_res_matched, &lr->lr_res_error ) != LBER_ERROR ) { if ( lderr != LDAP_SUCCESS ) { /* referrals are in error string */ refer_cnt = ldap_chase_referrals( ld, lr, - &lr->lr_res_error, &hadref ); + &lr->lr_res_error, -1, &hadref ); lr->lr_status = LDAP_REQST_COMPLETED; Debug( LDAP_DEBUG_TRACE, "read1msg: V2 referral chased, mark request completed, id = %d\n", lr->lr_msgid, 0, 0); @@ -555,9 +611,12 @@ Debug( LDAP_DEBUG_TRACE, } /* Check if all requests are finished, lr is now parent */ - for(tmplr=lr ; tmplr != NULL; tmplr=tmplr->lr_refnext) { + tmplr = lr; + if (tmplr->lr_status == LDAP_REQST_COMPLETED) { + for(tmplr=lr->lr_child; tmplr != NULL; tmplr=tmplr->lr_refnext) { if( tmplr->lr_status != LDAP_REQST_COMPLETED) { break; + } } }