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
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 this is pretty much a complete rewrite of the earlier code. The main
26 aim of the rewrite is to add support for having multiple wins server
27 lists, so Samba can register with multiple groups of wins servers
28 and each group has a failover list of wins servers.
30 Central to the way it all works is the idea of a wins server
31 'tag'. A wins tag is a label for a group of wins servers. For
34 wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
36 then you would have two groups of wins servers, one tagged with the
37 name 'fred' and the other with the name 'mary'. I would usually
38 recommend using interface names instead of 'fred' and 'mary' but
39 they can be any alpha string.
41 Now, how does it all work. Well, nmbd needs to register each of its
42 IPs with each of its names once with each group of wins servers. So
43 it tries registering with the first one mentioned in the list, then
44 if that fails it marks that WINS server dead and moves onto the next
47 In the client code things are a bit different. As each of the groups
48 of wins servers is a separate name space we need to try each of the
49 groups until we either succeed or we run out of wins servers to
50 try. If we get a negative response from a wins server then that
51 means the name doesn't exist in that group, so we give up on that
52 group and move to the next group. If we don't get a response at all
53 then maybe the wins server is down, in which case we need to
54 failover to the next one for that group.
56 confused yet? (tridge)
60 /* how long a server is marked dead for */
61 #define DEATH_TIME 600
63 /* a list of wins server that are marked dead. */
64 static struct wins_dead {
66 time_t revival; /* when it will be revived */
67 struct wins_dead *next, *prev;
71 /* an internal convenience structure for an IP with a short string tag
79 see if an ip is on the dead list
81 BOOL wins_srv_is_dead(struct in_addr ip)
84 for (d=dead_servers; d; d=d->next) {
85 if (ip_equal(ip, d->ip)) {
86 /* it might be due for revival */
87 if (d->revival <= time(NULL)) {
88 DEBUG(4,("Reviving wins server %s\n", inet_ntoa(ip)));
89 DLIST_REMOVE(dead_servers, d);
100 mark a wins server as temporarily dead
102 void wins_srv_died(struct in_addr ip)
106 if (is_zero_ip(ip) || wins_srv_is_dead(ip)) {
110 d = (struct wins_dead *)malloc(sizeof(*d));
114 d->revival = time(NULL) + DEATH_TIME;
116 DEBUG(4,("Marking wins server %s dead for %u seconds\n", inet_ntoa(ip), DEATH_TIME));
118 DLIST_ADD(dead_servers, d);
122 return the total number of wins servers, dead or not
124 unsigned wins_srv_count(void)
129 if (lp_wins_support()) {
130 /* simple - just talk to ourselves */
134 list = lp_wins_server_list();
135 for (count=0; list && list[count]; count++) /* nop */ ;
137 DEBUG(6,("Found %u wins servers in list\n", count));
142 parse an IP string that might be in tagged format
143 the result is a tagged_ip structure containing the tag
144 and the ip in in_addr format. If there is no tag then
147 static void parse_ip(struct tagged_ip *ip, const char *str)
149 char *s = strchr(str, ':');
151 fstrcpy(ip->tag, "*");
152 ip->ip = *interpret_addr2(str);
156 ip->ip = *interpret_addr2(s+1);
157 fstrcpy(ip->tag, str);
158 s = strchr(ip->tag, ':');
164 return the IP of the currently active wins server, or the zero IP otherwise
166 struct in_addr wins_srv_ip(void)
170 struct tagged_ip t_ip;
172 /* if we are a wins server then we always just talk to ourselves */
173 if (lp_wins_support()) {
174 extern struct in_addr loopback_ip;
178 list = lp_wins_server_list();
179 if (!list || !list[0]) {
184 /* find the first live one */
185 for (i=0; list[i]; i++) {
186 parse_ip(&t_ip, list[i]);
187 if (!wins_srv_is_dead(t_ip.ip)) {
188 DEBUG(6,("Current wins server is %s\n", inet_ntoa(t_ip.ip)));
193 /* damn, they are all dead. Keep trying the primary until they revive */
194 parse_ip(&t_ip, list[0]);
201 return the list of wins server tags. A 'tag' is used to distinguish
202 wins server as either belonging to the same name space or a separate
203 name space. Usually you would setup your 'wins server' option to
204 list one or more wins server per interface and use the interface
205 name as your tag, but you are free to use any tag you like.
207 char **wins_srv_tags(void)
213 if (lp_wins_support()) {
214 /* give the caller something to chew on. This makes
215 the rest of the logic simpler (ie. less special cases) */
216 ret = (char **)malloc(sizeof(char *)*2);
217 if (!ret) return NULL;
218 ret[0] = strdup("*");
223 list = lp_wins_server_list();
224 if (!list) return NULL;
226 /* yes, this is O(n^2) but n is very small */
227 for (i=0;list[i];i++) {
228 struct tagged_ip t_ip;
230 parse_ip(&t_ip, list[i]);
232 /* see if we already have it */
233 for (j=0;j<count;j++) {
234 if (strcmp(ret[j], t_ip.tag) == 0) {
240 /* we already have it. Move along */
244 /* add it to the list */
245 ret = (char **)Realloc(ret, (count+1) * sizeof(char *));
246 ret[count] = strdup(t_ip.tag);
247 if (!ret[count]) break;
252 /* make sure we null terminate */
259 /* free a list of wins server tags given by wins_srv_tags */
260 void wins_srv_tags_free(char **list)
264 for (i=0; list[i]; i++) {
272 return the IP of the currently active wins server for the given tag,
273 or the zero IP otherwise
275 struct in_addr wins_srv_ip_tag(const char *tag)
279 struct tagged_ip t_ip;
281 /* if we are a wins server then we always just talk to ourselves */
282 if (lp_wins_support()) {
283 extern struct in_addr loopback_ip;
287 list = lp_wins_server_list();
288 if (!list || !list[0]) {
294 /* find the first live one for this tag */
295 for (i=0; list[i]; i++) {
296 parse_ip(&t_ip, list[i]);
297 if (strcmp(tag, t_ip.tag) != 0) {
298 /* not for the right tag. Move along */
301 if (!wins_srv_is_dead(t_ip.ip)) {
302 DEBUG(6,("Current wins server for tag '%s' is %s\n", tag, inet_ntoa(t_ip.ip)));
307 /* they're all dead - try the first one until they revive */
308 for (i=0; list[i]; i++) {
309 parse_ip(&t_ip, list[i]);
310 if (strcmp(tag, t_ip.tag) != 0) {
316 /* this can't happen?? */
323 return a count of the number of IPs for a particular tag, including
326 unsigned wins_srv_count_tag(const char *tag)
331 /* if we are a wins server then we always just talk to ourselves */
332 if (lp_wins_support()) {
336 list = lp_wins_server_list();
337 if (!list || !list[0]) {
341 /* find the first live one for this tag */
342 for (i=0; list[i]; i++) {
343 struct tagged_ip t_ip;
344 parse_ip(&t_ip, list[i]);
345 if (strcmp(tag, t_ip.tag) == 0) {