Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

syncrepl not working in mode REFRESH_AND_PERSIST

19 views
Skip to first unread message

Mathieu Parent

unread,
Dec 3, 2009, 2:55:01 PM12/3/09
to perl...@perl.org
Hello,

(OK, this is my code, so this is probably my fault, but it appears to
be above my knowledge.)

While trying to test REFRESH_AND_PERSIST mode:
- the intial results come (Search Entry with Sync State Control modify)
- then a Intermediate SyncInfo Message (with refreshDone=1)
- then nothing, even when changing entries in the LDAP.


Any idea?

As my explanation is probably insufficient, see the code below, the
attached output and http://www.ietf.org/rfc/rfc4533.txt

Mathieu Parent

=== CODE ===
#!/usr/bin/perl
#BEGIN {
# push @INC, './perl-ldap/lib';
#}
use Data::Dumper;
use Net::LDAP;
use Net::LDAP::Control::SyncRequest;
use Net::LDAP::Constant qw(
LDAP_SYNC_REFRESH_ONLY
LDAP_SYNC_REFRESH_AND_PERSIST
LDAP_USER_CANCELED
LDAP_SUCCESS );

use warnings;
use strict;

$| = 1;

my $cookie = undef;
my $ldap = Net::LDAP->new( "ldap://192.168.0.15",
async => 1,
onerror => 'die',
#debug => 15,
);
die $! if !$ldap;
my $req = Net::LDAP::Control::SyncRequest->new( mode =>
LDAP_SYNC_REFRESH_AND_PERSIST );
my $mesg2 = $ldap->search(base=> 'dc=local,dc=tld',
scope => 'sub',
control => [ $req ],
callback => \&searchCallback, # call for each entry
filter => "(objectClass=*)",
attrs => [ '*,+'],
);
while(!$mesg2->done()) {
$ldap->process();
sleep(1);
print ".\n";
}

print "END\n";

sub searchCallback {
print "<<Callback start\n";
my $message = shift;
my $param2 = shift; # might be entry or intermediate
my @controls = $message->control;
my @sync_controls;
if($param2 && $param2->isa("Net::LDAP::Entry")) {
print "Received Search Entry\n";
#retrieve Sync State Control
foreach my $ctrl (@controls) {
push(@sync_controls, $ctrl)
if $ctrl->isa('Net::LDAP::Control::SyncState');
}
die 'Got search entry with multiple Sync State controls' if
@sync_controls>1;
die 'Got search entry without Sync State control' if !@sync_controls;
die 'Got empty entryUUID' if !$sync_controls[0]->entryUUID;
print 'Search Entry has Sync State Control: '.
'state='.$sync_controls[0]->state().
'; entryUUID='.unpack("H*",$sync_controls[0]->entryUUID()).
'; cookie='.(defined($sync_controls[0]->cookie()) ?
$sync_controls[0]->cookie() : 'UNDEF')."\n";
if(defined($sync_controls[0]->cookie)) {
$cookie = $sync_controls[0]->cookie;
print "New cookie: ".$cookie."\n";
}
print "Entry (".$param2->changetype."): ".$param2->dn()."\n";
} elsif($param2 && $param2->isa("Net::LDAP::Reference")) {
print "Received Search Reference\n";
return;
#if it not first control?
} elsif($controls[0] and $controls[0]->isa('Net::LDAP::Control::SyncDone')) {
print 'Received Sync Done Control: '.
'cookie='.(defined($controls[0]->cookie()) ?
$controls[0]->cookie() : 'UNDEF').
'; refreshDeletes='.$controls[0]->refreshDeletes()."\n";
#we have a new cookie
if(defined($controls[0]->cookie())
and not $controls[0]->cookie() eq ''
and not $controls[0]->cookie() eq $cookie) {
$cookie = $controls[0]->cookie();
print "New cookie: $cookie \n";
}
} elsif($param2 && $param2->isa("Net::LDAP::Intermediate::SyncInfo")) {
print "Received Intermediate SyncInfo Message\n";
my $attrs = $param2->{asn};
if($attrs->{newcookie}) {
$cookie = $attrs->{newcookie};;
print "New cookie: $cookie\n";
} elsif(my $refreshInfos = ($attrs->{refreshDelete} ||
$attrs->{refreshPresent})) {
$cookie = $refreshInfos->{cookie} if defined($refreshInfos->{cookie});
print (defined($refreshInfos->{cookie}) ? 'New ' : 'Empty ');
print "cookie from ".
($attrs->{refreshDelete} ? 'refreshDelete' : 'refreshPresent').
" (refreshDone=".$refreshInfos->{refreshDone}."): $cookie\n";
} elsif(my $syncIdSetInfos = $attrs->{syncIdSet}) {
$cookie = $syncIdSetInfos->{cookie} if defined($syncIdSetInfos->{cookie});
print (defined($syncIdSetInfos->{cookie}) ? 'Empty ' : 'New ');
print "cookie from syncIdSet".
" (refreshDeletes=".$syncIdSetInfos->{refreshDeletes}."): $cookie\n";
foreach my $syncUUID ($syncIdSetInfos->{syncUUIDs}) {
print 'entryUUID='.unpack("H*",$syncUUID)."\n";
}
}
} elsif($message->code) {
if ($message->code == 1) {
die "Communication Error: disconnecting";
} elsif ($message->code == LDAP_USER_CANCELED) {
print "searchCallback() -> Exit code received, returning\n";
return;
} elsif ($message->code == 4096) {
print "Refresh required\n";
$cookie = '';
} else {
die "searchCallback: mesg->code = `" . $message->code . "',
mesg->msg = `" . $message->error . "'";
}
} else {
die "Received something else.";
}
print "Callback end>>\n";
return 0;
}

out.log

Mathieu Parent

unread,
Dec 3, 2009, 3:42:41 PM12/3/09
to Graham Barr, perl...@perl.org
hi Graham,
Thanks for your fast reply.

On Thu, Dec 3, 2009 at 9:22 PM, Graham Barr <gb...@pobox.com> wrote:


> On Dec 3, 2009, at 1:55 PM, Mathieu Parent wrote:
>> Hello,
>>
>> (OK, this is my code, so this is probably my fault, but it appears to
>> be above my knowledge.)
>>
>> While trying to test REFRESH_AND_PERSIST mode:
>> - the intial results come (Search Entry with Sync State Control modify)
>> - then a Intermediate SyncInfo Message (with refreshDone=1)
>> - then nothing, even when changing entries in the LDAP.
>

> can you verify that the ldap server is actually sending messages, with tcpdump or something ?

Actually not. This is an OpenLDAP (2.4.11-1 from debian lenny) server
that otherwise replicate on slaves:

(slave conf snipset):
syncrepl rid=0
provider=ldap://debian-lenny-native_master.local.tld
type=refreshAndPersist
retry="60 10 300 +"
searchbase="dc=local,dc=tld"
scope=sub
schemachecking=on
binddn="cn=manager,cn=internal,dc=local,dc=tld"
credentials="12345"
bindmethod=simple

So the probem probably comes from the request?

> Graham.
>
>


Mathieu Parent

Mathieu Parent

unread,
Dec 3, 2009, 4:40:45 PM12/3/09
to Graham Barr, perl...@perl.org
A little more info.

The attached capture reproduce the following scenario:
192.168.0.132 is the Net::LDAP test machine
192.168.0.15 is the master
192.168.0.16 is the slave

at 0 the slave slapd is started
at 6 the test script is launched
at 14 a new user is added

We can see that on 14, only the slave is notified.

NB: the user is added using a web interface hosted on the master. This
stream is not captured.


Mathieu Parent

capture.pcap

Mathieu Parent

unread,
Dec 9, 2009, 12:15:25 PM12/9/09
to Graham Barr, perl...@perl.org
Hello,

To ease the analyse, I have added a dissector for rfc4533 in
wireshark. It is here:
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=4309

But I still don't understand the problem. This will probably be easier
while not being sick ;)

Mathieu Parent

Mathieu Parent

unread,
Dec 11, 2009, 6:36:58 PM12/11/09
to Graham Barr, perl...@perl.org
I'm going to be crazy..

Now this works. I have not changed anything!

In the meantime, I have added support for LDAP intermediate response
in Wireshark.

Mathieu Parent

0 new messages