source: trunk-3.0/source/lib/wins_srv.c@ 102

Last change on this file since 102 was 1, checked in by Paul Smedley, 18 years ago

Initial code import

File size: 8.7 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Samba wins server helper functions
4 Copyright (C) Andrew Tridgell 1992-2002
5 Copyright (C) Christopher R. Hertel 2000
6 Copyright (C) Tim Potter 2003
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23#include "includes.h"
24
25extern struct in_addr loopback_ip;
26
27/*
28 This is pretty much a complete rewrite of the earlier code. The main
29 aim of the rewrite is to add support for having multiple wins server
30 lists, so Samba can register with multiple groups of wins servers
31 and each group has a failover list of wins servers.
32
33 Central to the way it all works is the idea of a wins server
34 'tag'. A wins tag is a label for a group of wins servers. For
35 example if you use
36
37 wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
38
39 then you would have two groups of wins servers, one tagged with the
40 name 'fred' and the other with the name 'mary'. I would usually
41 recommend using interface names instead of 'fred' and 'mary' but
42 they can be any alpha string.
43
44 Now, how does it all work. Well, nmbd needs to register each of its
45 IPs with each of its names once with each group of wins servers. So
46 it tries registering with the first one mentioned in the list, then
47 if that fails it marks that WINS server dead and moves onto the next
48 one.
49
50 In the client code things are a bit different. As each of the groups
51 of wins servers is a separate name space we need to try each of the
52 groups until we either succeed or we run out of wins servers to
53 try. If we get a negative response from a wins server then that
54 means the name doesn't exist in that group, so we give up on that
55 group and move to the next group. If we don't get a response at all
56 then maybe the wins server is down, in which case we need to
57 failover to the next one for that group.
58
59 confused yet? (tridge)
60*/
61
62/* how long a server is marked dead for */
63#define DEATH_TIME 600
64
65/* The list of dead wins servers is stored in gencache.tdb. Each server is
66 marked dead from the point of view of a given source address. We keep a
67 separate dead list for each src address to cope with multiple interfaces
68 that are not routable to each other.
69 */
70
71#define WINS_SRV_FMT "WINS_SRV_DEAD/%s,%s" /* wins_ip,src_ip */
72
73static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip)
74{
75 char *keystr = NULL, *wins_ip_addr = NULL, *src_ip_addr = NULL;
76
77 wins_ip_addr = SMB_STRDUP(inet_ntoa(wins_ip));
78 src_ip_addr = SMB_STRDUP(inet_ntoa(src_ip));
79
80 if ( !wins_ip_addr || !src_ip_addr ) {
81 DEBUG(0,("wins_srv_keystr: malloc error\n"));
82 goto done;
83 }
84
85 if (asprintf(&keystr, WINS_SRV_FMT, wins_ip_addr, src_ip_addr) == -1) {
86 DEBUG(0, (": ns_srv_keystr: malloc error for key string\n"));
87 }
88
89done:
90 SAFE_FREE(wins_ip_addr);
91 SAFE_FREE(src_ip_addr);
92
93 return keystr;
94}
95
96/*
97 see if an ip is on the dead list
98*/
99
100BOOL wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
101{
102 char *keystr = wins_srv_keystr(wins_ip, src_ip);
103 BOOL result;
104
105 /* If the key exists then the WINS server has been marked as dead */
106
107 result = gencache_get(keystr, NULL, NULL);
108 SAFE_FREE(keystr);
109
110 DEBUG(4, ("wins_srv_is_dead: %s is %s\n", inet_ntoa(wins_ip),
111 result ? "dead" : "alive"));
112
113 return result;
114}
115
116
117/*
118 mark a wins server as being alive (for the moment)
119*/
120void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
121{
122 char *keystr = wins_srv_keystr(wins_ip, src_ip);
123
124 gencache_del(keystr);
125 SAFE_FREE(keystr);
126
127 DEBUG(4, ("wins_srv_alive: marking wins server %s alive\n",
128 inet_ntoa(wins_ip)));
129}
130
131/*
132 mark a wins server as temporarily dead
133*/
134void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
135{
136 char *keystr;
137
138 if (is_zero_ip(wins_ip) || wins_srv_is_dead(wins_ip, src_ip))
139 return;
140
141 keystr = wins_srv_keystr(wins_ip, src_ip);
142
143 gencache_set(keystr, "DOWN", time(NULL) + DEATH_TIME);
144
145 SAFE_FREE(keystr);
146
147 DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
148 inet_ntoa(wins_ip), DEATH_TIME, inet_ntoa(src_ip)));
149}
150
151/*
152 return the total number of wins servers, dead or not
153*/
154unsigned wins_srv_count(void)
155{
156 const char **list;
157 int count = 0;
158
159 if (lp_wins_support()) {
160 /* simple - just talk to ourselves */
161 return 1;
162 }
163
164 list = lp_wins_server_list();
165 for (count=0; list && list[count]; count++)
166 /* nop */ ;
167
168 return count;
169}
170
171/* an internal convenience structure for an IP with a short string tag
172 attached */
173struct tagged_ip {
174 fstring tag;
175 struct in_addr ip;
176};
177
178/*
179 parse an IP string that might be in tagged format
180 the result is a tagged_ip structure containing the tag
181 and the ip in in_addr format. If there is no tag then
182 use the tag '*'
183*/
184static void parse_ip(struct tagged_ip *ip, const char *str)
185{
186 char *s = strchr(str, ':');
187 if (!s) {
188 fstrcpy(ip->tag, "*");
189 ip->ip = *interpret_addr2(str);
190 return;
191 }
192
193 ip->ip = *interpret_addr2(s+1);
194 fstrcpy(ip->tag, str);
195 s = strchr(ip->tag, ':');
196 if (s) *s = 0;
197}
198
199
200
201/*
202 return the list of wins server tags. A 'tag' is used to distinguish
203 wins server as either belonging to the same name space or a separate
204 name space. Usually you would setup your 'wins server' option to
205 list one or more wins server per interface and use the interface
206 name as your tag, but you are free to use any tag you like.
207*/
208char **wins_srv_tags(void)
209{
210 char **ret = NULL;
211 int count=0, i, j;
212 const char **list;
213
214 if (lp_wins_support()) {
215 /* give the caller something to chew on. This makes
216 the rest of the logic simpler (ie. less special cases) */
217 ret = SMB_MALLOC_ARRAY(char *, 2);
218 if (!ret) return NULL;
219 ret[0] = SMB_STRDUP("*");
220 ret[1] = NULL;
221 return ret;
222 }
223
224 list = lp_wins_server_list();
225 if (!list)
226 return NULL;
227
228 /* yes, this is O(n^2) but n is very small */
229 for (i=0;list[i];i++) {
230 struct tagged_ip t_ip;
231
232 parse_ip(&t_ip, list[i]);
233
234 /* see if we already have it */
235 for (j=0;j<count;j++) {
236 if (strcmp(ret[j], t_ip.tag) == 0) {
237 break;
238 }
239 }
240
241 if (j != count) {
242 /* we already have it. Move along */
243 continue;
244 }
245
246 /* add it to the list */
247 ret = SMB_REALLOC_ARRAY(ret, char *, count+2);
248 if (!ret) {
249 return NULL;
250 }
251 ret[count] = SMB_STRDUP(t_ip.tag);
252 if (!ret[count]) break;
253 count++;
254 }
255
256 if (count) {
257 /* make sure we null terminate */
258 ret[count] = NULL;
259 }
260
261 return ret;
262}
263
264/* free a list of wins server tags given by wins_srv_tags */
265void wins_srv_tags_free(char **list)
266{
267 int i;
268 if (!list) return;
269 for (i=0; list[i]; i++) {
270 free(list[i]);
271 }
272 free(list);
273}
274
275
276/*
277 return the IP of the currently active wins server for the given tag,
278 or the zero IP otherwise
279*/
280struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
281{
282 const char **list;
283 int i;
284 struct tagged_ip t_ip;
285
286 /* if we are a wins server then we always just talk to ourselves */
287 if (lp_wins_support()) {
288 return loopback_ip;
289 }
290
291 list = lp_wins_server_list();
292 if (!list || !list[0]) {
293 struct in_addr ip;
294 zero_ip(&ip);
295 return ip;
296 }
297
298 /* find the first live one for this tag */
299 for (i=0; list[i]; i++) {
300 parse_ip(&t_ip, list[i]);
301 if (strcmp(tag, t_ip.tag) != 0) {
302 /* not for the right tag. Move along */
303 continue;
304 }
305 if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
306 fstring src_name;
307 fstrcpy(src_name, inet_ntoa(src_ip));
308 DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n",
309 tag,
310 src_name,
311 inet_ntoa(t_ip.ip)));
312 return t_ip.ip;
313 }
314 }
315
316 /* they're all dead - try the first one until they revive */
317 for (i=0; list[i]; i++) {
318 parse_ip(&t_ip, list[i]);
319 if (strcmp(tag, t_ip.tag) != 0) {
320 continue;
321 }
322 return t_ip.ip;
323 }
324
325 /* this can't happen?? */
326 zero_ip(&t_ip.ip);
327 return t_ip.ip;
328}
329
330
331/*
332 return a count of the number of IPs for a particular tag, including
333 dead ones
334*/
335unsigned wins_srv_count_tag(const char *tag)
336{
337 const char **list;
338 int i, count=0;
339
340 /* if we are a wins server then we always just talk to ourselves */
341 if (lp_wins_support()) {
342 return 1;
343 }
344
345 list = lp_wins_server_list();
346 if (!list || !list[0]) {
347 return 0;
348 }
349
350 /* find the first live one for this tag */
351 for (i=0; list[i]; i++) {
352 struct tagged_ip t_ip;
353 parse_ip(&t_ip, list[i]);
354 if (strcmp(tag, t_ip.tag) == 0) {
355 count++;
356 }
357 }
358
359 return count;
360}
Note: See TracBrowser for help on using the repository browser.