Initial import
[samba] / source / libsmb / conncache.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon connection manager
5
6    Copyright (C) Tim Potter             2001
7    Copyright (C) Andrew Bartlett        2002
8    Copyright (C) Gerald (Jerry) Carter  2003
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25
26 #include "includes.h"
27
28 #define FAILED_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
29
30 #define CONNCACHE_ADDR          1
31 #define CONNCACHE_NAME          2
32
33 /* cache entry contains either a server name **or** and IP address as 
34    the key.  This means that a server could have two entries (one for each key) */
35    
36 struct failed_connection_cache {
37         fstring         domain_name;
38         fstring         controller;
39         time_t          lookup_time;
40         NTSTATUS        nt_status;
41         struct failed_connection_cache *prev, *next;
42 };
43
44 static struct failed_connection_cache *failed_connection_cache;
45
46 /**********************************************************************
47  Check for a previously failed connection
48 **********************************************************************/
49
50 NTSTATUS check_negative_conn_cache( const char *domain, const char *server )
51 {
52         struct failed_connection_cache *fcc;
53         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
54         
55         /* can't check if we don't have strings */
56         
57         if ( !domain || !server )
58                 return NT_STATUS_OK;
59
60         for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
61         
62                 if ( !(strequal(domain, fcc->domain_name) && strequal(server, fcc->controller)) )
63                         continue; /* no match; check the next entry */
64                 
65                 /* we have a match so see if it is still current */
66
67                 if ((time(NULL) - fcc->lookup_time) > FAILED_CONNECTION_CACHE_TIMEOUT) 
68                 {
69                         /* Cache entry has expired, delete it */
70
71                         DEBUG(10, ("check_negative_conn_cache: cache entry expired for %s, %s\n", 
72                                 domain, server ));
73
74                         DLIST_REMOVE(failed_connection_cache, fcc);
75                         SAFE_FREE(fcc);
76
77                         return NT_STATUS_OK;
78                 }
79
80                 /* The timeout hasn't expired yet so return false */
81
82                 DEBUG(10, ("check_negative_conn_cache: returning negative entry for %s, %s\n", 
83                         domain, server ));
84
85                 result = fcc->nt_status;
86                 return result;
87         }
88
89         /* end of function means no cache entry */      
90         return NT_STATUS_OK;
91 }
92
93 /**********************************************************************
94  Add an entry to the failed conneciton cache (aither a name of dotted 
95  decimal IP
96 **********************************************************************/
97
98 void add_failed_connection_entry(const char *domain, const char *server, NTSTATUS result) 
99 {
100         struct failed_connection_cache *fcc;
101
102         SMB_ASSERT(!NT_STATUS_IS_OK(result));
103
104         /* Check we already aren't in the cache.  We always have to have 
105            a domain, but maybe not a specific DC name. */
106
107         for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {                     
108                 if ( strequal(fcc->domain_name, domain) && strequal(fcc->controller, server) ) {
109                         DEBUG(10, ("add_failed_connection_entry: domain %s (%s) already tried and failed\n",
110                                    domain, server ));
111                         /* Update the failed time. */
112                         fcc->lookup_time = time(NULL);
113                         return;
114                 }
115         }
116
117         /* Create negative lookup cache entry for this domain and controller */
118
119         if ( !(fcc = SMB_MALLOC_P(struct failed_connection_cache)) ) {
120                 DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
121                 return;
122         }
123         
124         ZERO_STRUCTP(fcc);
125         
126         fstrcpy( fcc->domain_name, domain );
127         fstrcpy( fcc->controller, server );
128         fcc->lookup_time = time(NULL);
129         fcc->nt_status = result;
130         
131         DEBUG(10,("add_failed_connection_entry: added domain %s (%s) to failed conn cache\n",
132                 domain, server ));
133         
134         DLIST_ADD(failed_connection_cache, fcc);
135 }
136
137 /****************************************************************************
138 ****************************************************************************/
139  
140 void flush_negative_conn_cache( void )
141 {
142         struct failed_connection_cache *fcc;
143         
144         fcc = failed_connection_cache;
145
146         while (fcc) {
147                 struct failed_connection_cache *fcc_next;
148
149                 fcc_next = fcc->next;
150                 DLIST_REMOVE(failed_connection_cache, fcc);
151                 free(fcc);
152
153                 fcc = fcc_next;
154         }
155
156 }