[Date Prev][Date Next] [Chronological] [Thread] [Top]

RE: Infinite chasing of cycled V3 referrals/references (ITS#2894)



Hello Howard.

I've tested the fix you'd made.
I checked out the HEAD sources from the CVS, compiled them and rebuilt my
simple program.
Unfortunately, it still goes into infinite loop while chasing cycled
references.

When I was studying the changes I found that original request (origreq) is
still used as a parent for a child request. 

rc = ldap_send_server_request( ld, ber, id, 
 				(sref && !parent_was_reference) ? origreq :
lr, 
                        srv, NULL, &rinfo );

Assume we're chasing a chain of references, I mean a reference points to the
entries one of which is another reference and so on:

Entry (search - origreq)
  |--entry
  |--sref --[step1]-->|--entry
                          |--entry
                          |--sref --[step2]-->|--entry
                                                 |--sref-->...

Step1. Chasing the first reference in the chain: sref==1,
paren_was_reference==0 (lr actually doesn't have a parent, it is the
original request). So origreq becomes the parent for the new request.

Step2. Chasing the second reference in the chain: serf==1,
parent_was-reference==0, because on the step1 we assigned origreq as the
parent for the new request and
origreq->lr_res_msgtype<>LDAP_RES_SEARCH_REFERENCE actually. Again, origreq
becomes the parent for the new child request. 

Investigating the code I can't understand why you preserved the 'origreq' as
a parent for a child request? Why and how does the using of 'origreq' or
'lr' as a parent depend on 'sref' parameter? I mean that counting of parents
should be correct for search references as well as for result referrals. It
seems I don't understand something in the library's ideology... 

Actually, I tried to fix the issue by myself:
  - replaced the call of the ldap_send_server_request organizing requests
into a tree, not a list:
	rc = ldap_send_server_request( ld, ber, id, lr, srv, NULL, &rinfo );

  - changed the procedure of determining whether or not the request is
completed.

------------------
static LDAPRequest* get_noncompleted_child(LDAPRequest* lr);

/* lr - parent request in a request tree
 * Returns NULL or the non-completed request from the tree
 */
LDAPRequest* get_noncompleted_child(LDAPRequest* lr)
{
    LDAPRequest *childlr = NULL, *tmplr = NULL;
    
    if (lr && lr->lr_status == LDAP_REQST_COMPLETED && lr->lr_outrefcnt <=
0)
    {
		for(childlr = lr->lr_child; childlr != NULL; childlr =
childlr->lr_refnext)
		{
	    	if (childlr->lr_child)	// has an own child?
	    	{
				if(tmplr = get_noncompleted_child(childlr))
		    		return tmplr;
	    	}
	    	else
	    	{
				if(childlr->lr_status !=
LDAP_REQST_COMPLETED || childlr->lr_outrefcnt > 0)
		    		break;
	    	}
		}
		return childlr;
    }
    
    return lr;
}
---------------------------------

The existing procedure verifies a list of requests. I had to add a recursive
function (presented above) and change the code to check a request tree
(result.c, lines 775-...):

/* Check if all requests are finished, lr is now parent */
tmplr = lr;
if (lr->lr_outrefcnt <= 0)	// there is no sense to check if outrefcnt >
0
{
	tmplr = get_noncompleted_child(tmplr);
}

Then I performed testing of chasing cycled references and it worked fine.
But it worked only when the references were placed on a single server. When
I made references from one server to another and back to the first one the
tests failed again: though they didn't go into infinite loop they couldn't
fetch all expected entries. Unfortunately, I didn't have enough time to
finish investigations and complete the fix.

With best regards,
Alexander.

> -----Original Message-----
> From: Howard Chu [mailto:openldap-its@OpenLDAP.org]
> Sent: Sunday, January 25, 2004 11:32 AM
> To: alex_dz@softhome.net
> Subject: Re: Infinite chasing of cycled V3 referrals/references (ITS#2894)
> 
> I've just committed a patch to CVS HEAD for this, please test.