packaging updates from Buchan
[Samba.git] / source / lib / wins_srv.c
blob3372f74dcbe967c2730d331a0009a7f46e747b28
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
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.
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.
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.
23 #include "includes.h"
26 This is pretty much a complete rewrite of the earlier code. The main
27 aim of the rewrite is to add support for having multiple wins server
28 lists, so Samba can register with multiple groups of wins servers
29 and each group has a failover list of wins servers.
31 Central to the way it all works is the idea of a wins server
32 'tag'. A wins tag is a label for a group of wins servers. For
33 example if you use
35 wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
37 then you would have two groups of wins servers, one tagged with the
38 name 'fred' and the other with the name 'mary'. I would usually
39 recommend using interface names instead of 'fred' and 'mary' but
40 they can be any alpha string.
42 Now, how does it all work. Well, nmbd needs to register each of its
43 IPs with each of its names once with each group of wins servers. So
44 it tries registering with the first one mentioned in the list, then
45 if that fails it marks that WINS server dead and moves onto the next
46 one.
48 In the client code things are a bit different. As each of the groups
49 of wins servers is a separate name space we need to try each of the
50 groups until we either succeed or we run out of wins servers to
51 try. If we get a negative response from a wins server then that
52 means the name doesn't exist in that group, so we give up on that
53 group and move to the next group. If we don't get a response at all
54 then maybe the wins server is down, in which case we need to
55 failover to the next one for that group.
57 confused yet? (tridge)
60 /* how long a server is marked dead for */
61 #define DEATH_TIME 600
63 /* The list of dead wins servers is stored in gencache.tdb. Each server is
64 marked dead from the point of view of a given source address. We keep a
65 separate dead list for each src address to cope with multiple interfaces
66 that are not routable to each other.
69 #define WINS_SRV_FMT "WINS_SRV_DEAD/%s,%s" /* wins_ip,src_ip */
71 static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip)
73 char *keystr;
75 if (asprintf(&keystr, WINS_SRV_FMT, inet_ntoa(wins_ip),
76 inet_ntoa(src_ip)) == -1) {
77 DEBUG(0, ("wins_srv_is_dead: malloc error\n"));
78 return NULL;
81 return keystr;
85 see if an ip is on the dead list
88 BOOL wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
90 char *keystr = wins_srv_keystr(wins_ip, src_ip);
91 BOOL result;
93 /* If the key exists then the WINS server has been marked as dead */
95 result = gencache_get(keystr, NULL, NULL);
96 SAFE_FREE(keystr);
98 DEBUG(4, ("wins_srv_is_dead: %s is %s\n", inet_ntoa(wins_ip),
99 result ? "dead" : "alive"));
101 return result;
106 mark a wins server as being alive (for the moment)
108 void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
110 char *keystr = wins_srv_keystr(wins_ip, src_ip);
112 gencache_del(keystr);
113 SAFE_FREE(keystr);
115 DEBUG(4, ("wins_srv_alive: marking wins server %s alive\n",
116 inet_ntoa(wins_ip)));
120 mark a wins server as temporarily dead
122 void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
124 char *keystr;
126 if (is_zero_ip(wins_ip) || wins_srv_is_dead(wins_ip, src_ip))
127 return;
129 keystr = wins_srv_keystr(wins_ip, src_ip);
131 gencache_set(keystr, "DOWN", time(NULL) + DEATH_TIME);
133 SAFE_FREE(keystr);
135 DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
136 inet_ntoa(wins_ip), DEATH_TIME, inet_ntoa(src_ip)));
140 return the total number of wins servers, dead or not
142 unsigned wins_srv_count(void)
144 const char **list;
145 int count = 0;
147 if (lp_wins_support()) {
148 /* simple - just talk to ourselves */
149 return 1;
152 list = lp_wins_server_list();
153 for (count=0; list && list[count]; count++)
154 /* nop */ ;
156 return count;
159 /* an internal convenience structure for an IP with a short string tag
160 attached */
161 struct tagged_ip {
162 fstring tag;
163 struct in_addr ip;
167 parse an IP string that might be in tagged format
168 the result is a tagged_ip structure containing the tag
169 and the ip in in_addr format. If there is no tag then
170 use the tag '*'
172 static void parse_ip(struct tagged_ip *ip, const char *str)
174 char *s = strchr(str, ':');
175 if (!s) {
176 fstrcpy(ip->tag, "*");
177 ip->ip = *interpret_addr2(str);
178 return;
181 ip->ip = *interpret_addr2(s+1);
182 fstrcpy(ip->tag, str);
183 s = strchr(ip->tag, ':');
184 if (s) *s = 0;
190 return the list of wins server tags. A 'tag' is used to distinguish
191 wins server as either belonging to the same name space or a separate
192 name space. Usually you would setup your 'wins server' option to
193 list one or more wins server per interface and use the interface
194 name as your tag, but you are free to use any tag you like.
196 char **wins_srv_tags(void)
198 char **ret = NULL;
199 int count=0, i, j;
200 const char **list;
202 if (lp_wins_support()) {
203 /* give the caller something to chew on. This makes
204 the rest of the logic simpler (ie. less special cases) */
205 ret = (char **)malloc(sizeof(char *)*2);
206 if (!ret) return NULL;
207 ret[0] = strdup("*");
208 ret[1] = NULL;
209 return ret;
212 list = lp_wins_server_list();
213 if (!list)
214 return NULL;
216 /* yes, this is O(n^2) but n is very small */
217 for (i=0;list[i];i++) {
218 struct tagged_ip t_ip;
220 parse_ip(&t_ip, list[i]);
222 /* see if we already have it */
223 for (j=0;j<count;j++) {
224 if (strcmp(ret[j], t_ip.tag) == 0) {
225 break;
229 if (j != count) {
230 /* we already have it. Move along */
231 continue;
234 /* add it to the list */
235 ret = (char **)Realloc(ret, (count+2) * sizeof(char *));
236 ret[count] = strdup(t_ip.tag);
237 if (!ret[count]) break;
238 count++;
241 if (count) {
242 /* make sure we null terminate */
243 ret[count] = NULL;
246 return ret;
249 /* free a list of wins server tags given by wins_srv_tags */
250 void wins_srv_tags_free(char **list)
252 int i;
253 if (!list) return;
254 for (i=0; list[i]; i++) {
255 free(list[i]);
257 free(list);
262 return the IP of the currently active wins server for the given tag,
263 or the zero IP otherwise
265 struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
267 const char **list;
268 int i;
269 struct tagged_ip t_ip;
271 /* if we are a wins server then we always just talk to ourselves */
272 if (lp_wins_support()) {
273 extern struct in_addr loopback_ip;
274 return loopback_ip;
277 list = lp_wins_server_list();
278 if (!list || !list[0]) {
279 struct in_addr ip;
280 zero_ip(&ip);
281 return ip;
284 /* find the first live one for this tag */
285 for (i=0; list[i]; i++) {
286 parse_ip(&t_ip, list[i]);
287 if (strcmp(tag, t_ip.tag) != 0) {
288 /* not for the right tag. Move along */
289 continue;
291 if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
292 fstring src_name;
293 fstrcpy(src_name, inet_ntoa(src_ip));
294 DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n",
295 tag,
296 src_name,
297 inet_ntoa(t_ip.ip)));
298 return t_ip.ip;
302 /* they're all dead - try the first one until they revive */
303 for (i=0; list[i]; i++) {
304 parse_ip(&t_ip, list[i]);
305 if (strcmp(tag, t_ip.tag) != 0) {
306 continue;
308 return t_ip.ip;
311 /* this can't happen?? */
312 zero_ip(&t_ip.ip);
313 return t_ip.ip;
318 return a count of the number of IPs for a particular tag, including
319 dead ones
321 unsigned wins_srv_count_tag(const char *tag)
323 const char **list;
324 int i, count=0;
326 /* if we are a wins server then we always just talk to ourselves */
327 if (lp_wins_support()) {
328 return 1;
331 list = lp_wins_server_list();
332 if (!list || !list[0]) {
333 return 0;
336 /* find the first live one for this tag */
337 for (i=0; list[i]; i++) {
338 struct tagged_ip t_ip;
339 parse_ip(&t_ip, list[i]);
340 if (strcmp(tag, t_ip.tag) == 0) {
341 count++;
345 return count;