s3:wscript_build - fix TDB dependency for source3/lib/util.c
[nivanova/samba-autobuild/.git] / source3 / 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    Copyright (C) Marc VanHeyningen      2008
10    Copyright (C) Volker Lendecke        2009
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26
27 #include "includes.h"
28
29 /**
30  * @file
31  * Negative connection cache implemented in terms of gencache API
32  *
33  * The negative connection cache stores names of servers which have
34  * been unresponsive so that we don't waste time repeatedly trying
35  * to contact them.  It used to use an in-memory linked list, but
36  * this limited its utility to a single process
37  */
38
39
40 /**
41  * Marshalls the domain and server name into the key for the gencache
42  * record
43  *
44  * @param[in] domain required
45  * @param[in] server may be a FQDN or an IP address
46  * @return the resulting string, which the caller is responsible for
47  *   SAFE_FREE()ing
48  * @retval NULL returned on error
49  */
50 static char *negative_conn_cache_keystr(const char *domain, const char *server)
51 {
52         char *keystr = NULL;
53
54         if (domain == NULL) {
55                 return NULL;
56         }
57         if (server == NULL)
58                 server = "";
59
60         keystr = talloc_asprintf(talloc_tos(), "NEG_CONN_CACHE/%s,%s",
61                                  domain, server);
62         if (keystr == NULL) {
63                 DEBUG(0, ("negative_conn_cache_keystr: malloc error\n"));
64         }
65
66         return keystr;
67 }
68
69 /**
70  * Marshalls the NT status into a printable value field for the gencache
71  * record
72  *
73  * @param[in] status
74  * @return the resulting string, which the caller is responsible for
75  *   SAFE_FREE()ing
76  * @retval NULL returned on error
77  */
78 static char *negative_conn_cache_valuestr(NTSTATUS status)
79 {
80         char *valuestr = NULL;
81
82         valuestr = talloc_asprintf(talloc_tos(), "%x", NT_STATUS_V(status));
83         if (valuestr == NULL) {
84                 DEBUG(0, ("negative_conn_cache_valuestr: malloc error\n"));
85         }
86
87         return valuestr;
88 }
89
90 /**
91  * Un-marshalls the NT status from a printable field for the gencache
92  * record
93  *
94  * @param[in] value  The value field from the record
95  * @return the decoded NT status
96  * @retval NT_STATUS_OK returned on error
97  */
98 static NTSTATUS negative_conn_cache_valuedecode(const char *value)
99 {
100         unsigned int v = NT_STATUS_V(NT_STATUS_INTERNAL_ERROR);
101
102         if (value == NULL) {
103                 return NT_STATUS_INTERNAL_ERROR;
104         }
105         if (sscanf(value, "%x", &v) != 1) {
106                 DEBUG(0, ("negative_conn_cache_valuedecode: unable to parse "
107                           "value field '%s'\n", value));
108         }
109         return NT_STATUS(v);
110 }
111
112 /**
113  * Function passed to gencache_iterate to remove any matching items
114  * from the list
115  *
116  * @param[in] key Key to the record found and to be deleted
117  * @param[in] value Value to the record (ignored)
118  * @param[in] timeout Timeout remaining for the record (ignored)
119  * @param[in] dptr Handle for passing additional data (ignored)
120  */
121 static void delete_matches(const char *key, const char *value,
122     time_t timeout, void *dptr)
123 {
124         gencache_del(key);
125 }
126
127
128 /**
129  * Checks for a given domain/server record in the negative cache
130  *
131  * @param[in] domain
132  * @param[in] server may be either a FQDN or an IP address
133  * @return The cached failure status
134  * @retval NT_STATUS_OK returned if no record is found or an error occurs
135  */
136 NTSTATUS check_negative_conn_cache( const char *domain, const char *server)
137 {
138         NTSTATUS result = NT_STATUS_OK;
139         char *key = NULL;
140         char *value = NULL;
141
142         key = negative_conn_cache_keystr(domain, server);
143         if (key == NULL)
144                 goto done;
145
146         if (gencache_get(key, &value, NULL))
147                 result = negative_conn_cache_valuedecode(value);
148  done:
149         DEBUG(9,("check_negative_conn_cache returning result %d for domain %s "
150                   "server %s\n", NT_STATUS_V(result), domain, server));
151         TALLOC_FREE(key);
152         SAFE_FREE(value);
153         return result;
154 }
155
156 /**
157  * Add an entry to the failed connection cache
158  *
159  * @param[in] domain
160  * @param[in] server may be a FQDN or an IP addr in printable form
161  * @param[in] result error to cache; must not be NT_STATUS_OK
162  */
163 void add_failed_connection_entry(const char *domain, const char *server,
164     NTSTATUS result)
165 {
166         char *key = NULL;
167         char *value = NULL;
168
169         if (NT_STATUS_IS_OK(result)) {
170                 /* Nothing failed here */
171                 return;
172         }
173
174         key = negative_conn_cache_keystr(domain, server);
175         if (key == NULL) {
176                 DEBUG(0, ("add_failed_connection_entry: key creation error\n"));
177                 goto done;
178         }
179
180         value = negative_conn_cache_valuestr(result);
181         if (value == NULL) {
182                 DEBUG(0, ("add_failed_connection_entry: value creation error\n"));
183                 goto done;
184         }
185
186         if (gencache_set(key, value,
187                          time(NULL) + FAILED_CONNECTION_CACHE_TIMEOUT))
188                 DEBUG(9,("add_failed_connection_entry: added domain %s (%s) "
189                           "to failed conn cache\n", domain, server ));
190         else
191                 DEBUG(1,("add_failed_connection_entry: failed to add "
192                           "domain %s (%s) to failed conn cache\n",
193                           domain, server));
194
195  done:
196         TALLOC_FREE(key);
197         TALLOC_FREE(value);
198         return;
199 }
200
201 /**
202  * Deletes all records for a specified domain from the negative connection
203  * cache
204  *
205  * @param[in] domain String to match against domain portion of keys, or "*"
206  *  to match all domains
207  */
208 void flush_negative_conn_cache_for_domain(const char *domain)
209 {
210         char *key_pattern = NULL;
211
212         key_pattern = negative_conn_cache_keystr(domain,"*");
213         if (key_pattern == NULL) {
214                 DEBUG(0, ("flush_negative_conn_cache_for_domain: "
215                           "key creation error\n"));
216                 goto done;
217         }
218
219         gencache_iterate(delete_matches, NULL, key_pattern);
220         DEBUG(8, ("flush_negative_conn_cache_for_domain: flushed domain %s\n",
221                   domain));
222
223  done:
224         TALLOC_FREE(key_pattern);
225         return;
226 }