richard: server/perl-kolab/lib/Kolab/LDAP/Backend syncrepl.pm, 1.3, 1.4

cvs at kolab.org cvs at kolab.org
Thu Oct 16 20:58:25 CEST 2008


Author: richard

Update of /kolabrepository/server/perl-kolab/lib/Kolab/LDAP/Backend
In directory doto:/tmp/cvs-serv31582/lib/Kolab/LDAP/Backend

Modified Files:
	syncrepl.pm 
Log Message:
Updated with changes provided by Mathieu Parent. See kolab/issue1755



Index: syncrepl.pm
===================================================================
RCS file: /kolabrepository/server/perl-kolab/lib/Kolab/LDAP/Backend/syncrepl.pm,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- syncrepl.pm	17 Jul 2008 10:01:10 -0000	1.3
+++ syncrepl.pm	16 Oct 2008 18:58:23 -0000	1.4
@@ -21,8 +21,13 @@
 use warnings;
 use Kolab;
 use Kolab::LDAP;
-use Net::LDAP;
+use Net::LDAP qw(
+	LDAP_USER_CANCELED
+	LDAP_SYNC_REFRESH_ONLY
+	LDAP_SYNC_REFRESH_AND_PERSIST
+);
 use Net::LDAP::Control;
+use Net::LDAP::Control::SyncRequest;
 use Net::LDAP::Entry;
 use vars qw($ldap $cookie $disconnected);
 my $cookie = '';
@@ -45,97 +50,13 @@
     
 );
 
-our $VERSION = '0.1';
-
-# LDAP Content Synchronization Operation -- RFC 4533
-use constant LDAP_SYNC_OID => "1.3.6.1.4.1.4203.1.9.1";
-use constant {
-	LDAP_CONTROL_SYNC => LDAP_SYNC_OID.".1",
-	LDAP_CONTROL_SYNC_STATE => LDAP_SYNC_OID.".2",
-	LDAP_CONTROL_SYNC_DONE => LDAP_SYNC_OID.".3",
-	LDAP_SYNC_INFO => LDAP_SYNC_OID.".4",
-
-	LDAP_SYNC_NONE => 0x00,
-	LDAP_SYNC_REFRESH_ONLY => 0x01,
-	LDAP_SYNC_RESERVED => 0x02,
-	LDAP_SYNC_REFRESH_AND_PERSIST => 0x03,
-
-	LDAP_SYNC_REFRESH_PRESENTS => 0,
-	LDAP_SYNC_REFRESH_DELETES => 1,
-
-	LDAP_TAG_SYNC_NEW_COOKIE => 0x80,
-	LDAP_TAG_SYNC_REFRESH_DELETE => 0xa1,
-	LDAP_TAG_SYNC_REFRESH_PRESENT => 0xa2,
-	LDAP_TAG_SYNC_ID_SET => 0xa3,
-
-	LDAP_TAG_SYNC_COOKIE => 0x04,
-	LDAP_TAG_REFRESHDELETES => 0x01,
-	LDAP_TAG_REFRESHDONE => 0x01,
-	LDAP_TAG_RELOAD_HINT => 0x01,
-
-	LDAP_SYNC_PRESENT => 0,
-	LDAP_SYNC_ADD => 1,
-	LDAP_SYNC_MODIFY => 2,
-	LDAP_SYNC_DELETE => 3,
-};
-
-use Convert::ASN1;
-use Data::Dumper;
-
-my $asn = Convert::ASN1->new;
-
-$asn->prepare(<<'LDAP_ASN') or die $asn->error;
-syncUUID ::= OCTET STRING -- (SIZE(16))
-
-syncCookie ::= OCTET STRING
-
-syncRequestValue ::= SEQUENCE {
-    mode ENUMERATED {
-        -- 0 unused
-        refreshOnly       (1),
-        -- 2 reserved
-        refreshAndPersist (3)
-    }
-    cookie     syncCookie OPTIONAL,
-    reloadHint BOOLEAN -- DEFAULT FALSE
-}
-
-syncStateValue ::= SEQUENCE {
-    state ENUMERATED {
-        present (0),
-        add (1),
-        modify (2),
-        delete (3)
-    }
-    entryUUID syncUUID,
-    cookie    syncCookie OPTIONAL
-}
-
-syncDoneValue ::= SEQUENCE {
-    cookie          syncCookie OPTIONAL,
-    refreshDeletes  BOOLEAN -- DEFAULT FALSE
-}
+our $VERSION = '0.2';
 
-syncInfoValue ::= CHOICE {
-      newcookie      [0] syncCookie,
-      refreshDelete  [1] SEQUENCE {
-          refreshDeleteCookie         syncCookie OPTIONAL,
-          refreshDeleteDone    BOOLEAN -- DEFAULT TRUE
-      }
-      refreshPresent [2] SEQUENCE {
-          refreshDeletecookie         syncCookie OPTIONAL,
-          refreshDeleteDone    BOOLEAN -- DEFAULT TRUE
-      }
-      syncIdSet      [3] SEQUENCE {
-          cookie         syncCookie OPTIONAL,
-          refreshDeletes BOOLEAN, -- DEFAULT FALSE
-          syncUUIDs      SET OF syncUUID
-      }
+sub mode { 
+  LDAP_SYNC_REFRESH_ONLY;
+  #LDAP_SYNC_REFRESH_AND_PERSIST;
 }
 
-LDAP_ASN
-
-
 sub startup { 1; }
 
 sub shutdown
@@ -184,22 +105,17 @@
     Kolab::LDAP::ensureAsync($ldap);
     Kolab::log('SYNCREPL', 'Async checked', KOLAB_DEBUG);
 
-    Kolab::log('SYNCREPL', "Cookie: $cookie", KOLAB_DEBUG);
-
     while($ldap and not $disconnected) {
-	    #sync control
-      my $asn_syncRequestValue = $asn->find('syncRequestValue');
-	    my $ctrl = Net::LDAP::Control->new(type  => LDAP_CONTROL_SYNC, 
-		                                     value => $asn_syncRequestValue->encode(mode       => LDAP_SYNC_REFRESH_ONLY,
-                                                                                cookie     => $cookie,
-                                                                                reloadHint => 0
-                                                                               ),
-                                         critical   => 0
-	                                      );
-      Kolab::log('SYNCREPL', 'Control created', KOLAB_DEBUG);
-    
-	    #search
-	    my $mesg = $ldap->search(base     => $Kolab::config{'base_dn'},
+      my $ctrl = Net::LDAP::Control::SyncRequest->new(
+        mode       => Kolab::LDAP::Backend::syncrepl::mode,
+        cookie     => $cookie,
+        reloadHint => 0);
+      Kolab::log('SYNCREPL', 'Control created: mode='.$ctrl->mode().
+      	'; cookie='.$ctrl->cookie().
+      	'; reloadHint='.$ctrl->reloadHint(), KOLAB_DEBUG);
+
+      #search
+      my $mesg = $ldap->search(base     => $Kolab::config{'base_dn'},
                                scope    => 'sub',
                                control  => [ $ctrl ],
                                callback => \&searchCallback, # call for each entry
@@ -210,7 +126,7 @@
                                              $Kolab::config{'user_field_quota'},
                                              $Kolab::config{'user_field_deleted'},
                                            ],
-				                      );
+                              );
       Kolab::log('SYNCREPL', 'Search created', KOLAB_DEBUG);
       $mesg->sync;
       Kolab::log('SYNCREPL', "Finished Net::LDAP::Search::sync sleeping 10s", KOLAB_DEBUG);
@@ -223,37 +139,53 @@
 #search callback
 sub searchCallback {
   my $mesg = shift;
-  my $entry = shift;
-  my $issearch = $mesg->isa("Net::LDAP::Search");
+  my $param2 = shift; # might be entry or intermediate
   my @controls = $mesg->control;
-  if(not $issearch) {
-    Kolab::log('SYNCREPL', 'mesg is not a search object, testing code...', KOLAB_DEBUG);
-    if ($mesg->code == 88) {
-        Kolab::log('SYNCREPL', 'searchCallback() -> Exit code received, returning', KOLAB_DEBUG);
-        return;
-    } elsif ($mesg->code) {
-        Kolab::log('SYNCREPL', "Not a search: mesg->code = `" . $mesg->code . "', mesg->msg = `" . $mesg->error . "'", KOLAB_DEBUG);
-        &abort;
-    }   
-  } elsif(@controls == 0) {
-    if ($mesg->code == 1) {
-        Kolab::log('SYNCREPL', 'No control: Communications Error: disconnecting', KOLAB_DEBUG);
-        $disconnected = 1;
-        return;
-    } elsif ($mesg->code) {
-      Kolab::log('SYNCREPL', "No control: mesg->code = `" . $mesg->code . "', mesg->msg = `" . $mesg->error . "'", KOLAB_DEBUG);
-        &abort;
-    }   
-  } elsif($controls[0]->type eq LDAP_CONTROL_SYNC_STATE) {
-    Kolab::log('SYNCREPL', 'Received Sync State Control', KOLAB_DEBUG);
-    Kolab::log('SYNCREPL', "Entry (".$entry->changetype."): ".$entry->dn(), KOLAB_DEBUG);
-  } elsif($controls[0]->type eq LDAP_CONTROL_SYNC_DONE) {
-    Kolab::log('SYNCREPL', 'Received Sync Done Control', KOLAB_DEBUG);
-    my $asn_syncDoneValue = $asn->find('syncDoneValue');
-    my $out = $asn_syncDoneValue->decode($controls[0]->value);
+  my @sync_controls = ();
+  if($param2 && $param2->isa("Net::LDAP::Entry")) {
+    Kolab::log('SYNCREPL', 'Received Search Entry', KOLAB_DEBUG);
+    #retrieve Sync State Control
+    foreach my $ctrl (@controls) {
+      push(@sync_controls, $ctrl)
+        if $ctrl->isa('Net::LDAP::Control::SyncState');
+    }
+    if(@sync_controls>1) {
+      Kolab::log('SYNCREPL', 'Got search entry with multiple Sync State controls',
+        KOLAB_DEBUG);
+      return;
+    }
+    if(!@sync_controls) {
+      Kolab::log('SYNCREPL', 'Got search entry without Sync State control',
+        KOLAB_DEBUG);
+      return;
+    }
+    if(!$sync_controls[0]->entryUUID) {
+      Kolab::log('SYNCREPL', 'Got empty entryUUID',
+        KOLAB_DEBUG);
+      return;
+    }
+    Kolab::log('SYNCREPL', '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')
+	, KOLAB_DEBUG);
+    if(defined($sync_controls[0]->cookie)) {
+      $cookie = $sync_controls[0]->cookie;
+      Kolab::log('SYNCREPL',"New cookie: $cookie", KOLAB_DEBUG);
+    }
+    Kolab::log('SYNCREPL', "Entry (".$param2->changetype."): ".$param2->dn(), KOLAB_DEBUG);
+  } elsif($param2 && $param2->isa("Net::LDAP::Reference")) {
+    Kolab::log('SYNCREPL', 'Received Search Reference', KOLAB_DEBUG);
+    return;
+  #if it not first control?
+  } elsif($controls[0] and $controls[0]->isa('Net::LDAP::Control::SyncDone')) {
+    Kolab::log('SYNCREPL', 'Received Sync Done Control: '.
+      	'cookie='.(defined($controls[0]->cookie()) ? $controls[0]->cookie() : 'UNDEF').
+      	'; refreshDeletes='.$controls[0]->refreshDeletes()
+	, KOLAB_DEBUG);
 	  #we have a new cookie
-	  if(defined($out->{cookie}) and not $out->{cookie} eq '' and not $out->{cookie} eq $cookie) {
-		  $cookie = $out->{cookie};
+	  if(defined($controls[0]->cookie()) and not $controls[0]->cookie() eq '' and not $controls[0]->cookie() eq $cookie) {
+		  $cookie = $controls[0]->cookie();
 		  Kolab::log('SYNCREPL', "New cookie: $cookie", KOLAB_DEBUG);
       Kolab::log('SYNCREPL', "Calling Kolab::LDAP::sync", KOLAB_DEBUG);
       Kolab::LDAP::sync;
@@ -261,8 +193,47 @@
       Kolab::log('SYNCREPL', "Finished Kolab::LDAP::sync sleeping 1s", KOLAB_DEBUG);
       sleep 1; # we get too many bogus change notifications!
 	  } 
+  } elsif($param2 && $param2->isa("Net::LDAP::Intermediate")) {
+    Kolab::log('SYNCREPL', 'Received Intermediate Message', KOLAB_DEBUG);
+    my $attrs = $param2->{asn};
+    if($attrs->{newcookie}) {
+      $cookie = $attrs->{newcookie};
+      Kolab::log('SYNCREPL', "New cookie: $cookie", KOLAB_DEBUG);
+    } elsif(my $refreshInfos = ($attrs->{refreshDelete} || $attrs->{refreshPresent})) {
+      $cookie = $refreshInfos->{cookie} if defined($refreshInfos->{cookie});
+      Kolab::log('SYNCREPL', 
+        (defined($refreshInfos->{cookie}) ? 'New ' : 'Empty ').
+        "cookie from ".
+        ($attrs->{refreshDelete} ? 'refreshDelete' : 'refreshPresent').
+        " (refreshDone=".$refreshInfos->{refreshDone}."): $cookie", KOLAB_DEBUG);
+    } elsif(my $syncIdSetInfos = $attrs->{syncIdSet}) {
+      $cookie = $syncIdSetInfos->{cookie} if defined($syncIdSetInfos->{cookie});
+      Kolab::log('SYNCREPL', 
+        (defined($syncIdSetInfos->{cookie}) ? 'Empty ' : 'New ').
+        "cookie from syncIdSet".
+        " (refreshDeletes=".$syncIdSetInfos->{refreshDeletes}."): $cookie", KOLAB_DEBUG);
+      foreach my $syncUUID ($syncIdSetInfos->{syncUUIDs}) {
+        Kolab::log('SYNCREPL', 'entryUUID='.
+          unpack("H*",$syncUUID), KOLAB_DEBUG);
+      }
+    }
+  } elsif($mesg->code) {
+    if ($mesg->code == 1) {
+      Kolab::log('SYNCREPL', 'Communication Error: disconnecting', KOLAB_DEBUG);
+      $disconnected = 1;
+      return 0;
+    } elsif ($mesg->code == LDAP_USER_CANCELED) {
+        Kolab::log('SYNCREPL', 'searchCallback() -> Exit code received, returning', KOLAB_DEBUG);
+        return;
+    } elsif ($mesg->code == 4096) {
+        Kolab::log('SYNCREPL', 'Refresh required', KOLAB_DEBUG);
+        $cookie = '';
+    } else {
+        Kolab::log('SYNCREPL', "searchCallback: mesg->code = `" . $mesg->code . "', mesg->msg = `" . $mesg->error . "'", KOLAB_DEBUG);
+        &abort;
+    }   
   } else {
-    Kolab::log('SYNCREPL', 'Received unknown control: '.$controls[0]->type, KOLAB_DEBUG);
+    Kolab::log('SYNCREPL', 'Received something else', KOLAB_DEBUG);
   }
   return 0;
 }
@@ -315,4 +286,4 @@
 
 
 
-=cut
+=cut
\ No newline at end of file





More information about the commits mailing list