]> git.mjollnir.org Git - moodle.git/commitdiff
Cache LDAP connections: MDL-18130 Properly handle open LDAP connections.
authoriarenaza <iarenaza>
Sun, 15 Feb 2009 15:03:33 +0000 (15:03 +0000)
committeriarenaza <iarenaza>
Sun, 15 Feb 2009 15:03:33 +0000 (15:03 +0000)
Both CAS and LDAP auth plugins open new connections to the LDAP server
to get the user account details. While this is the desired behaviour
for regular logins (we probably don't have an already open connection
to the LDAP server), this is a ressource hog when we are doing user
synchronization, as the closed connections remain in the TCP_WAIT
state for a while before the server can reuse them. If we are syncing
a lot of users, we can make the server run out of available TCP
ressources.

So we cache the connection the first time we establish it and return
the same connection handle everytime, unless we've closed all the
'open' connections, or the auth object is destroyed.

In addition to that, there were a few missing calls to ldap_close().

auth/cas/auth.php
auth/ldap/auth.php

index fb42870df0bbfab0480d7eae6867e5e40491a6d6..875e71a8b601059ceb7ac65bb9116f6dc65909b4 100644 (file)
@@ -413,7 +413,7 @@ if ( !is_object($PHPCAS_CLIENT) ) {
                 $result[$key] = $ldapval;
             }
         }
-        @ldap_close($ldapconnection);
+        $this->ldap_close($ldapconnection);
         return $result;
     }
     /**
@@ -443,6 +443,16 @@ if ( !is_object($PHPCAS_CLIENT) ) {
      * @return connection result
      */
     function ldap_connect($binddn='',$bindpwd='') {
+        // Cache ldap connections (they are expensive to set up
+        // and can drain the TCP/IP ressources on the server if we 
+        // are syncing a lot of users (as we try to open a new connection
+        // to get the user details). This is the least invasive way
+        // to reuse existing connections without greater code surgery.
+        if(!empty($this->ldapconnection)) {
+            $this->ldapconns++;
+            return $this->ldapconnection;
+        }
+
         //Select bind password, With empty values use
         //ldap_bind_* variables or anonymous bind if ldap_bind_* are empty
         if ($binddn == '' and $bindpwd == '') {
@@ -477,6 +487,10 @@ if ( !is_object($PHPCAS_CLIENT) ) {
                 ldap_set_option($connresult, LDAP_OPT_DEREF, $this->config->opt_deref);
             }
             if ($bindresult) {
+                // Set the connection counter so we can call PHP's ldap_close()
+                // when we call $this->ldap_close() for the last 'open' connection.
+                $this->ldapconns = 1;  
+                $this->ldapconnection = $connresult;
                 return $connresult;
             }
             $debuginfo .= "<br/>Server: '$server' <br/> Connection: '$connresult'<br/> Bind result: '$bindresult'</br>";
@@ -485,6 +499,18 @@ if ( !is_object($PHPCAS_CLIENT) ) {
         print_error('auth_ldap_noconnect_all','auth',$this->config->user_type);
         return false;
     }
+    /**
+     * disconnects from a ldap server
+     *
+     */
+    function ldap_close() {
+        $this->ldapconns--;
+        if($this->ldapconns == 0) {
+            @ldap_close($this->ldapconnection);
+            unset($this->ldapconnection);
+        }
+    }
+
     /**
      * retuns user attribute mappings between moodle and ldap
      *
@@ -609,7 +635,7 @@ if ( !is_object($PHPCAS_CLIENT) ) {
         $ldapconnection = $this->ldap_connect();
 
         if (!$ldapconnection) {
-            @ldap_close($ldapconnection);
+            $this->ldap_close($ldapconnection);
             print get_string('auth_ldap_noconnect','auth',$this->config->host_url);
             exit;
         }
@@ -861,6 +887,7 @@ if ( !is_object($PHPCAS_CLIENT) ) {
         }
 
         $dbman->drop_temp_table($table);
+        $this->ldap_close();
 
         return true;
     }
@@ -1004,6 +1031,7 @@ if (!empty($this->config->attrcreators)) {
                 }
           }
         }
+        $this->ldap_close();
         return $result;
     }
    /**
@@ -1043,6 +1071,7 @@ if (!empty($this->config->attrcreators)) {
                 array_push($fresult, ($users[$i][$this->config->user_attribute][0]) );
             }
         }
+        $this->ldap_close();
         return $fresult;
     }
     /**
index 1a178cfc7ec875802d89738018f4c624136a4c94..4ff533d4dfcf0990dfe2ef39a2977f0d55f32b64 100644 (file)
@@ -141,7 +141,7 @@ class auth_plugin_ldap extends auth_plugin_base {
                     if ($this->ldap_find_userdn($ldapconnection, $extusername)) {
                         $validuser = true;
                     }
-                    ldap_close($ldapconnection);
+                    $this->ldap_close();
                 }
 
                 // Shortcut here - SSO confirmed
@@ -156,19 +156,19 @@ class auth_plugin_ldap extends auth_plugin_base {
 
             //if ldap_user_dn is empty, user does not exist
             if (!$ldap_user_dn) {
-                ldap_close($ldapconnection);
+                $this->ldap_close();
                 return false;
             }
 
             // Try to bind with current username and password
             $ldap_login = @ldap_bind($ldapconnection, $ldap_user_dn, $extpassword);
-            ldap_close($ldapconnection);
+            $this->ldap_close();
             if ($ldap_login) {
                 return true;
             }
         }
         else {
-            @ldap_close($ldapconnection);
+            $this->ldap_close();
             print_error('auth_ldap_noconnect','auth','',$this->config->host_url);
         }
         return false;
@@ -242,7 +242,7 @@ class auth_plugin_ldap extends auth_plugin_base {
             }
         }
 
-        @ldap_close($ldapconnection);
+        $this->ldap_close();
         return $result;
     }
 
@@ -383,7 +383,7 @@ class auth_plugin_ldap extends auth_plugin_base {
             default:
                print_error('auth_ldap_unsupportedusertype','auth','',$this->config->user_type);
         }
-        ldap_close($ldapconnection);
+        $this->ldap_close();
         return $uadd;
 
     }
@@ -568,7 +568,7 @@ class auth_plugin_ldap extends auth_plugin_base {
         $ldapconnection = $this->ldap_connect();
 
         if (!$ldapconnection) {
-            @ldap_close($ldapconnection);
+            $this->ldap_close();
             print get_string('auth_ldap_noconnect','auth',$this->config->host_url);
             exit;
         }
@@ -824,6 +824,7 @@ class auth_plugin_ldap extends auth_plugin_base {
         }
 
         $dbman->drop_temp_table($table);
+        $this->ldap_close();
 
         return true;
     }
@@ -924,7 +925,7 @@ class auth_plugin_ldap extends auth_plugin_base {
                 print_error('user_activatenotsupportusertype', 'auth', '', $this->config->user_type);
         }
         $result = ldap_modify($ldapconnection, $userdn, $newinfo);
-        ldap_close($ldapconnection);
+        $this->ldap_close();
         return $result;
     }
 
@@ -959,7 +960,7 @@ class auth_plugin_ldap extends auth_plugin_base {
                 print_error('user_disablenotsupportusertype', 'auth');
         }
         $result = ldap_modify($ldapconnection, $userdn, $newinfo);
-        ldap_close($ldapconnection);
+        $this->ldap_close();
         return $result;
     }*/
 
@@ -1144,11 +1145,11 @@ class auth_plugin_ldap extends auth_plugin_base {
             }
         } else {
             error_log("ERROR:No user found in LDAP");
-            @ldap_close($ldapconnection);
+            $this->ldap_close();
             return false;
         }
 
-        @ldap_close($ldapconnection);
+        $this->ldap_close();
 
         return true;
 
@@ -1272,7 +1273,7 @@ class auth_plugin_ldap extends auth_plugin_base {
 
         }
 
-        @ldap_close($ldapconnection);
+        $this->ldap_close();
         return $result;
     }
 
@@ -1517,6 +1518,16 @@ class auth_plugin_ldap extends auth_plugin_base {
      * @return connection result
      */
     function ldap_connect($binddn='',$bindpwd='') {
+        // Cache ldap connections (they are expensive to set up
+        // and can drain the TCP/IP ressources on the server if we 
+        // are syncing a lot of users (as we try to open a new connection
+        // to get the user details). This is the least invasive way
+        // to reuse existing connections without greater code surgery.
+        if(!empty($this->ldapconnection)) {
+            $this->ldapconns++;
+            return $this->ldapconnection;
+        }
+
         //Select bind password, With empty values use
         //ldap_bind_* variables or anonymous bind if ldap_bind_* are empty
         if ($binddn == '' and $bindpwd == '') {
@@ -1563,6 +1574,10 @@ class auth_plugin_ldap extends auth_plugin_base {
             }
 
             if ($bindresult) {
+               // Set the connection counter so we can call PHP's ldap_close()
+               // when we call $this->ldap_close() for the last 'open' connection.
+                $this->ldapconns = 1;  
+                $this->ldapconnection = $connresult;
                 return $connresult;
             }
 
@@ -1574,6 +1589,18 @@ class auth_plugin_ldap extends auth_plugin_base {
         return false;
     }
 
+    /**
+     * disconnects from a ldap server
+     *
+     */
+    function ldap_close() {
+        $this->ldapconns--;
+        if($this->ldapconns == 0) {
+            @ldap_close($this->ldapconnection);
+            unset($this->ldapconnection);
+        }
+    }
+
     /**
      * retuns dn of username
      *