~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libsmb/conncache.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
   
 
11
   This program is free software; you can redistribute it and/or modify
 
12
   it under the terms of the GNU General Public License as published by
 
13
   the Free Software Foundation; either version 3 of the License, or
 
14
   (at your option) any later version.
 
15
   
 
16
   This program is distributed in the hope that it will be useful,
 
17
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
   GNU General Public License for more details.
 
20
   
 
21
   You should have received a copy of the GNU General Public License
 
22
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
23
*/
 
24
 
 
25
 
 
26
#include "includes.h"
 
27
 
 
28
/**
 
29
 * @file
 
30
 * Negative connection cache implemented in terms of gencache API
 
31
 *
 
32
 * The negative connection cache stores names of servers which have
 
33
 * been unresponsive so that we don't waste time repeatedly trying
 
34
 * to contact them.  It used to use an in-memory linked list, but
 
35
 * this limited its utility to a single process
 
36
 */
 
37
 
 
38
 
 
39
/**
 
40
 * prefix used for all entries put into the general cache
 
41
 */
 
42
static const char NEGATIVE_CONN_CACHE_PREFIX[] = "NEG_CONN_CACHE";
 
43
 
 
44
/**
 
45
 * Marshalls the domain and server name into the key for the gencache
 
46
 * record
 
47
 *
 
48
 * @param[in] domain required
 
49
 * @param[in] server may be a FQDN or an IP address
 
50
 * @return the resulting string, which the caller is responsible for
 
51
 *   SAFE_FREE()ing
 
52
 * @retval NULL returned on error
 
53
 */
 
54
static char *negative_conn_cache_keystr(const char *domain, const char *server)
 
55
{
 
56
        const char NEGATIVE_CONN_CACHE_KEY_FMT[] = "%s/%s,%s";
 
57
        char *keystr = NULL;
 
58
 
 
59
        SMB_ASSERT(domain != NULL);
 
60
        if (server == NULL)
 
61
                server = "";
 
62
 
 
63
        keystr = talloc_asprintf(talloc_tos(),NEGATIVE_CONN_CACHE_KEY_FMT,
 
64
                                 NEGATIVE_CONN_CACHE_PREFIX, domain, server);
 
65
        if (keystr == NULL) {
 
66
                DEBUG(0, ("negative_conn_cache_keystr: malloc error\n"));
 
67
        }
 
68
 
 
69
        return keystr;
 
70
}
 
71
 
 
72
/**
 
73
 * Marshalls the NT status into a printable value field for the gencache
 
74
 * record
 
75
 *
 
76
 * @param[in] status
 
77
 * @return the resulting string, which the caller is responsible for
 
78
 *   SAFE_FREE()ing
 
79
 * @retval NULL returned on error
 
80
 */
 
81
static char *negative_conn_cache_valuestr(NTSTATUS status)
 
82
{
 
83
        char *valuestr = NULL;
 
84
 
 
85
        valuestr = talloc_asprintf(talloc_tos(), "%x", NT_STATUS_V(status));
 
86
        if (valuestr == NULL) {
 
87
                DEBUG(0, ("negative_conn_cache_valuestr: malloc error\n"));
 
88
        }
 
89
 
 
90
        return valuestr;
 
91
}
 
92
 
 
93
/**
 
94
 * Un-marshalls the NT status from a printable field for the gencache
 
95
 * record
 
96
 *
 
97
 * @param[in] value  The value field from the record
 
98
 * @return the decoded NT status
 
99
 * @retval NT_STATUS_OK returned on error
 
100
 */
 
101
static NTSTATUS negative_conn_cache_valuedecode(const char *value)
 
102
{
 
103
        NTSTATUS result = NT_STATUS_OK;
 
104
 
 
105
        SMB_ASSERT(value != NULL);
 
106
        if (sscanf(value, "%x", &(NT_STATUS_V(result))) != 1)
 
107
                DEBUG(0, ("negative_conn_cache_valuestr: unable to parse "
 
108
                          "value field '%s'\n", value));
 
109
        return result;
 
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, (time_t *) 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
 * Delete any negative cache entry for the given domain/server
 
158
 *
 
159
 * @param[in] domain
 
160
 * @param[in] server may be either a FQDN or an IP address
 
161
 */
 
162
void delete_negative_conn_cache(const char *domain, const char *server)
 
163
{
 
164
        char *key = NULL;
 
165
 
 
166
        key = negative_conn_cache_keystr(domain, server);
 
167
        if (key == NULL)
 
168
                goto done;
 
169
 
 
170
        gencache_del(key);
 
171
        DEBUG(9,("delete_negative_conn_cache removing domain %s server %s\n",
 
172
                  domain, server));
 
173
 done:
 
174
        TALLOC_FREE(key);
 
175
        return;
 
176
}
 
177
 
 
178
 
 
179
/**
 
180
 * Add an entry to the failed connection cache
 
181
 *
 
182
 * @param[in] domain
 
183
 * @param[in] server may be a FQDN or an IP addr in printable form
 
184
 * @param[in] result error to cache; must not be NT_STATUS_OK
 
185
 */
 
186
void add_failed_connection_entry(const char *domain, const char *server,
 
187
    NTSTATUS result)
 
188
{
 
189
        char *key = NULL;
 
190
        char *value = NULL;
 
191
 
 
192
        SMB_ASSERT(!NT_STATUS_IS_OK(result));
 
193
 
 
194
        key = negative_conn_cache_keystr(domain, server);
 
195
        if (key == NULL) {
 
196
                DEBUG(0, ("add_failed_connection_entry: key creation error\n"));
 
197
                goto done;
 
198
        }
 
199
 
 
200
        value = negative_conn_cache_valuestr(result);
 
201
        if (value == NULL) {
 
202
                DEBUG(0, ("add_failed_connection_entry: value creation error\n"));
 
203
                goto done;
 
204
        }
 
205
 
 
206
        if (gencache_set(key, value,
 
207
                         time((time_t *) NULL)
 
208
                         + FAILED_CONNECTION_CACHE_TIMEOUT))
 
209
                DEBUG(9,("add_failed_connection_entry: added domain %s (%s) "
 
210
                          "to failed conn cache\n", domain, server ));
 
211
        else
 
212
                DEBUG(1,("add_failed_connection_entry: failed to add "
 
213
                          "domain %s (%s) to failed conn cache\n",
 
214
                          domain, server));
 
215
        
 
216
 done:
 
217
        TALLOC_FREE(key);
 
218
        TALLOC_FREE(value);
 
219
        return;
 
220
}
 
221
 
 
222
/**
 
223
 * Deletes all records from the negative connection cache in all domains
 
224
 */
 
225
void flush_negative_conn_cache( void )
 
226
{
 
227
        flush_negative_conn_cache_for_domain("*");
 
228
}
 
229
 
 
230
 
 
231
/**
 
232
 * Deletes all records for a specified domain from the negative connection
 
233
 * cache
 
234
 *
 
235
 * @param[in] domain String to match against domain portion of keys, or "*"
 
236
 *  to match all domains
 
237
 */
 
238
void flush_negative_conn_cache_for_domain(const char *domain)
 
239
{
 
240
        char *key_pattern = NULL;
 
241
 
 
242
        key_pattern = negative_conn_cache_keystr(domain,"*");
 
243
        if (key_pattern == NULL) {
 
244
                DEBUG(0, ("flush_negative_conn_cache_for_domain: "
 
245
                          "key creation error\n"));
 
246
                goto done;
 
247
        }
 
248
 
 
249
        gencache_iterate(delete_matches, (void *) NULL, key_pattern);
 
250
        DEBUG(8, ("flush_negative_conn_cache_for_domain: flushed domain %s\n",
 
251
                  domain));
 
252
        
 
253
 done:
 
254
        TALLOC_FREE(key_pattern);
 
255
        return;
 
256
}