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