s3: Remove some unnecessary variables from libsmb/conn_cache.c
[ira/wip.git] / source3 / libsmb / conncache.c
index 790ad47fa5df14417835844f515131ef019d10ce..c4c53d068100942e6def75ed67ce607a16e12842 100644 (file)
@@ -6,7 +6,9 @@
    Copyright (C) Tim Potter            2001
    Copyright (C) Andrew Bartlett       2002
    Copyright (C) Gerald (Jerry) Carter         2003
-   
+   Copyright (C) Marc VanHeyningen      2008
+   Copyright (C) Volker Lendecke       2009
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 
 #include "includes.h"
 
-#define CONNCACHE_ADDR         1
-#define CONNCACHE_NAME         2
-
-/* cache entry contains either a server name **or** and IP address as 
-   the key.  This means that a server could have two entries (one for each key) */
-   
-struct failed_connection_cache {
-       fstring         domain_name;
-       fstring         controller;
-       time_t          lookup_time;
-       NTSTATUS        nt_status;
-       struct failed_connection_cache *prev, *next;
-};
-
-static struct failed_connection_cache *failed_connection_cache;
-
-/**********************************************************************
- Check for a previously failed connection.
- failed_cache_timeout is an a absolute number of seconds after which
- we should time this out. If failed_cache_timeout == 0 then time out
- immediately. If failed_cache_timeout == -1 then never time out.
-**********************************************************************/
-
-NTSTATUS check_negative_conn_cache_timeout( const char *domain, const char *server, unsigned int failed_cache_timeout )
+/**
+ * @file
+ * Negative connection cache implemented in terms of gencache API
+ *
+ * The negative connection cache stores names of servers which have
+ * been unresponsive so that we don't waste time repeatedly trying
+ * to contact them.  It used to use an in-memory linked list, but
+ * this limited its utility to a single process
+ */
+
+
+/**
+ * Marshalls the domain and server name into the key for the gencache
+ * record
+ *
+ * @param[in] domain required
+ * @param[in] server may be a FQDN or an IP address
+ * @return the resulting string, which the caller is responsible for
+ *   SAFE_FREE()ing
+ * @retval NULL returned on error
+ */
+static char *negative_conn_cache_keystr(const char *domain, const char *server)
 {
-       struct failed_connection_cache *fcc;
-       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       
-       /* can't check if we don't have strings */
-       
-       if ( !domain || !server )
-               return NT_STATUS_OK;
+       char *keystr = NULL;
 
-       for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
-       
-               if (!(strequal(domain, fcc->domain_name) && strequal(server, fcc->controller))) {
-                       continue; /* no match; check the next entry */
-               }
-               
-               /* we have a match so see if it is still current */
-               if (failed_cache_timeout != (unsigned int)-1) {
-                       if (failed_cache_timeout == 0 ||
-                                       (time(NULL) - fcc->lookup_time) > (time_t)failed_cache_timeout) {
-                               /* Cache entry has expired, delete it */
+       if (domain == NULL) {
+               return NULL;
+       }
+       if (server == NULL)
+               server = "";
+
+       keystr = talloc_asprintf(talloc_tos(), "NEG_CONN_CACHE/%s,%s",
+                                domain, server);
+       if (keystr == NULL) {
+               DEBUG(0, ("negative_conn_cache_keystr: malloc error\n"));
+       }
 
-                               DEBUG(10, ("check_negative_conn_cache: cache entry expired for %s, %s\n", 
-                                       domain, server ));
+       return keystr;
+}
 
-                               DLIST_REMOVE(failed_connection_cache, fcc);
-                               SAFE_FREE(fcc);
+/**
+ * Marshalls the NT status into a printable value field for the gencache
+ * record
+ *
+ * @param[in] status
+ * @return the resulting string, which the caller is responsible for
+ *   SAFE_FREE()ing
+ * @retval NULL returned on error
+ */
+static char *negative_conn_cache_valuestr(NTSTATUS status)
+{
+       char *valuestr = NULL;
 
-                               return NT_STATUS_OK;
-                       }
-               }
+       valuestr = talloc_asprintf(talloc_tos(), "%x", NT_STATUS_V(status));
+       if (valuestr == NULL) {
+               DEBUG(0, ("negative_conn_cache_valuestr: malloc error\n"));
+       }
 
-               /* The timeout hasn't expired yet so return false */
+       return valuestr;
+}
 
-               DEBUG(10, ("check_negative_conn_cache: returning negative entry for %s, %s\n", 
-                       domain, server ));
+/**
+ * Un-marshalls the NT status from a printable field for the gencache
+ * record
+ *
+ * @param[in] value  The value field from the record
+ * @return the decoded NT status
+ * @retval NT_STATUS_OK returned on error
+ */
+static NTSTATUS negative_conn_cache_valuedecode(const char *value)
+{
+       unsigned int v = NT_STATUS_V(NT_STATUS_INTERNAL_ERROR);;
 
-               result = fcc->nt_status;
-               return result;
+       if (value != NULL) {
+               return NT_STATUS_INTERNAL_ERROR;
        }
+       if (sscanf(value, "%x", &v) != 1) {
+               DEBUG(0, ("negative_conn_cache_valuedecode: unable to parse "
+                         "value field '%s'\n", value));
+       }
+       return NT_STATUS(v);
+}
 
-       /* end of function means no cache entry */      
-       return NT_STATUS_OK;
+/**
+ * Function passed to gencache_iterate to remove any matching items
+ * from the list
+ *
+ * @param[in] key Key to the record found and to be deleted
+ * @param[in] value Value to the record (ignored)
+ * @param[in] timeout Timeout remaining for the record (ignored)
+ * @param[in] dptr Handle for passing additional data (ignored)
+ */
+static void delete_matches(const char *key, const char *value,
+    time_t timeout, void *dptr)
+{
+       gencache_del(key);
 }
 
+
+/**
+ * Checks for a given domain/server record in the negative cache
+ *
+ * @param[in] domain
+ * @param[in] server may be either a FQDN or an IP address
+ * @return The cached failure status
+ * @retval NT_STATUS_OK returned if no record is found or an error occurs
+ */
 NTSTATUS check_negative_conn_cache( const char *domain, const char *server)
 {
-       return check_negative_conn_cache_timeout(domain, server, FAILED_CONNECTION_CACHE_TIMEOUT);
+       NTSTATUS result = NT_STATUS_OK;
+       char *key = NULL;
+       char *value = NULL;
+
+       key = negative_conn_cache_keystr(domain, server);
+       if (key == NULL)
+               goto done;
+
+       if (gencache_get(key, &value, NULL))
+               result = negative_conn_cache_valuedecode(value);
+ done:
+       DEBUG(9,("check_negative_conn_cache returning result %d for domain %s "
+                 "server %s\n", NT_STATUS_V(result), domain, server));
+       TALLOC_FREE(key);
+       SAFE_FREE(value);
+       return result;
 }
 
-/**********************************************************************
- Add an entry to the failed conneciton cache (aither a name of dotted 
- decimal IP
-**********************************************************************/
-
-void add_failed_connection_entry(const char *domain, const char *server, NTSTATUS result) 
+/**
+ * Delete any negative cache entry for the given domain/server
+ *
+ * @param[in] domain
+ * @param[in] server may be either a FQDN or an IP address
+ */
+void delete_negative_conn_cache(const char *domain, const char *server)
 {
-       struct failed_connection_cache *fcc;
+       char *key = NULL;
+
+       key = negative_conn_cache_keystr(domain, server);
+       if (key == NULL)
+               goto done;
+
+       gencache_del(key);
+       DEBUG(9,("delete_negative_conn_cache removing domain %s server %s\n",
+                 domain, server));
+ done:
+       TALLOC_FREE(key);
+       return;
+}
 
-       SMB_ASSERT(!NT_STATUS_IS_OK(result));
 
-       /* Check we already aren't in the cache.  We always have to have 
-          a domain, but maybe not a specific DC name. */
+/**
+ * Add an entry to the failed connection cache
+ *
+ * @param[in] domain
+ * @param[in] server may be a FQDN or an IP addr in printable form
+ * @param[in] result error to cache; must not be NT_STATUS_OK
+ */
+void add_failed_connection_entry(const char *domain, const char *server,
+    NTSTATUS result)
+{
+       char *key = NULL;
+       char *value = NULL;
 
-       for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {                     
-               if ( strequal(fcc->domain_name, domain) && strequal(fcc->controller, server) ) {
-                       DEBUG(10, ("add_failed_connection_entry: domain %s (%s) already tried and failed\n",
-                                  domain, server ));
-                       /* Update the failed time. */
-                       fcc->lookup_time = time(NULL);
-                       return;
-               }
+       if (NT_STATUS_IS_OK(result)) {
+               /* Nothing failed here */
+               return;
        }
 
-       /* Create negative lookup cache entry for this domain and controller */
+       key = negative_conn_cache_keystr(domain, server);
+       if (key == NULL) {
+               DEBUG(0, ("add_failed_connection_entry: key creation error\n"));
+               goto done;
+       }
 
-       if ( !(fcc = SMB_MALLOC_P(struct failed_connection_cache)) ) {
-               DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
-               return;
+       value = negative_conn_cache_valuestr(result);
+       if (value == NULL) {
+               DEBUG(0, ("add_failed_connection_entry: value creation error\n"));
+               goto done;
        }
+
+       if (gencache_set(key, value,
+                        time(NULL) + FAILED_CONNECTION_CACHE_TIMEOUT))
+               DEBUG(9,("add_failed_connection_entry: added domain %s (%s) "
+                         "to failed conn cache\n", domain, server ));
+       else
+               DEBUG(1,("add_failed_connection_entry: failed to add "
+                         "domain %s (%s) to failed conn cache\n",
+                         domain, server));
        
-       ZERO_STRUCTP(fcc);
-       
-       fstrcpy( fcc->domain_name, domain );
-       fstrcpy( fcc->controller, server );
-       fcc->lookup_time = time(NULL);
-       fcc->nt_status = result;
-       
-       DEBUG(10,("add_failed_connection_entry: added domain %s (%s) to failed conn cache\n",
-               domain, server ));
-       
-       DLIST_ADD(failed_connection_cache, fcc);
+ done:
+       TALLOC_FREE(key);
+       TALLOC_FREE(value);
+       return;
 }
 
-/****************************************************************************
-****************************************************************************/
+/**
+ * Deletes all records from the negative connection cache in all domains
+ */
 void flush_negative_conn_cache( void )
 {
-       struct failed_connection_cache *fcc;
-       
-       fcc = failed_connection_cache;
-
-       while (fcc) {
-               struct failed_connection_cache *fcc_next;
-
-               fcc_next = fcc->next;
-               DLIST_REMOVE(failed_connection_cache, fcc);
-               free(fcc);
-
-               fcc = fcc_next;
-       }
-
+       flush_negative_conn_cache_for_domain("*");
 }
 
-/****************************************************************************
- Remove all negative entries for a domain. Used when going to online state in
- winbindd.
-****************************************************************************/
+
+/**
+ * Deletes all records for a specified domain from the negative connection
+ * cache
+ *
+ * @param[in] domain String to match against domain portion of keys, or "*"
+ *  to match all domains
+ */
 void flush_negative_conn_cache_for_domain(const char *domain)
 {
-       struct failed_connection_cache *fcc;
-       
-       fcc = failed_connection_cache;
-
-       while (fcc) {
-               struct failed_connection_cache *fcc_next;
+       char *key_pattern = NULL;
 
-               fcc_next = fcc->next;
+       key_pattern = negative_conn_cache_keystr(domain,"*");
+       if (key_pattern == NULL) {
+               DEBUG(0, ("flush_negative_conn_cache_for_domain: "
+                         "key creation error\n"));
+               goto done;
+       }
 
-               if (strequal(fcc->domain_name, domain)) {
-                       DEBUG(10,("flush_negative_conn_cache_for_domain: removed server %s "
-                               " from failed cache for domain %s\n",
-                               fcc->controller, domain));
-                       DLIST_REMOVE(failed_connection_cache, fcc);
-                       free(fcc);
-               }
+       gencache_iterate(delete_matches, NULL, key_pattern);
+       DEBUG(8, ("flush_negative_conn_cache_for_domain: flushed domain %s\n",
+                 domain));
 
-               fcc = fcc_next;
-       }
+ done:
+       TALLOC_FREE(key_pattern);
+       return;
 }