add another registry rpc (opnum 0x14). Have no idea what it's real name
[Samba.git] / source / lib / wins_srv.c
blobadf405ae7e247b55b1f5e339e26e6cdab8129c90
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
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.
22 #include "includes.h"
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
32 example if you use
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
45 one.
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 from the point of view
64 of a given source address. We keep a separate dead list for each src address
65 to cope with multiple interfaces that are not routable to each other
67 static struct wins_dead {
68 struct in_addr dest_ip;
69 struct in_addr src_ip;
70 time_t revival; /* when it will be revived */
71 struct wins_dead *next, *prev;
72 } *dead_servers;
74 /* an internal convenience structure for an IP with a short string tag
75 attached */
76 struct tagged_ip {
77 fstring tag;
78 struct in_addr ip;
82 see if an ip is on the dead list
84 BOOL wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
86 struct wins_dead *d;
87 for (d=dead_servers; d; d=d->next) {
88 if (ip_equal(wins_ip, d->dest_ip) && ip_equal(src_ip, d->src_ip)) {
89 /* it might be due for revival */
90 if (d->revival <= time(NULL)) {
91 fstring src_name;
92 fstrcpy(src_name, inet_ntoa(src_ip));
93 DEBUG(4,("Reviving wins server %s for source %s\n",
94 inet_ntoa(wins_ip), src_name));
95 DLIST_REMOVE(dead_servers, d);
96 free(d);
97 return False;
99 return True;
102 return False;
107 mark a wins server as being alive (for the moment)
109 void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
111 struct wins_dead *d;
112 for (d=dead_servers; d; d=d->next) {
113 if (ip_equal(wins_ip, d->dest_ip) && ip_equal(src_ip, d->src_ip)) {
114 fstring src_name;
115 fstrcpy(src_name, inet_ntoa(src_ip));
116 DEBUG(4,("Reviving wins server %s for source %s\n",
117 inet_ntoa(wins_ip), src_name));
118 DLIST_REMOVE(dead_servers, d);
119 return;
126 mark a wins server as temporarily dead
128 void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
130 struct wins_dead *d;
131 fstring src_name;
133 if (is_zero_ip(wins_ip) || wins_srv_is_dead(wins_ip, src_ip)) {
134 return;
137 d = (struct wins_dead *)malloc(sizeof(*d));
138 if (!d) return;
140 d->dest_ip = wins_ip;
141 d->src_ip = src_ip;
142 d->revival = time(NULL) + DEATH_TIME;
144 fstrcpy(src_name, inet_ntoa(src_ip));
146 DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
147 inet_ntoa(wins_ip), DEATH_TIME, src_name));
149 DLIST_ADD(dead_servers, d);
153 return the total number of wins servers, dead or not
155 unsigned wins_srv_count(void)
157 char **list;
158 int count = 0;
160 if (lp_wins_support()) {
161 /* simple - just talk to ourselves */
162 return 1;
165 list = lp_wins_server_list();
166 for (count=0; list && list[count]; count++) /* nop */ ;
168 return count;
172 parse an IP string that might be in tagged format
173 the result is a tagged_ip structure containing the tag
174 and the ip in in_addr format. If there is no tag then
175 use the tag '*'
177 static void parse_ip(struct tagged_ip *ip, const char *str)
179 char *s = strchr(str, ':');
180 if (!s) {
181 fstrcpy(ip->tag, "*");
182 ip->ip = *interpret_addr2(str);
183 return;
186 ip->ip = *interpret_addr2(s+1);
187 fstrcpy(ip->tag, str);
188 s = strchr(ip->tag, ':');
189 if (s) *s = 0;
195 return the list of wins server tags. A 'tag' is used to distinguish
196 wins server as either belonging to the same name space or a separate
197 name space. Usually you would setup your 'wins server' option to
198 list one or more wins server per interface and use the interface
199 name as your tag, but you are free to use any tag you like.
201 char **wins_srv_tags(void)
203 char **ret = NULL;
204 int count=0, i, j;
205 char **list;
207 if (lp_wins_support()) {
208 /* give the caller something to chew on. This makes
209 the rest of the logic simpler (ie. less special cases) */
210 ret = (char **)malloc(sizeof(char *)*2);
211 if (!ret) return NULL;
212 ret[0] = strdup("*");
213 ret[1] = NULL;
214 return ret;
217 list = lp_wins_server_list();
218 if (!list) return NULL;
220 /* yes, this is O(n^2) but n is very small */
221 for (i=0;list[i];i++) {
222 struct tagged_ip t_ip;
224 parse_ip(&t_ip, list[i]);
226 /* see if we already have it */
227 for (j=0;j<count;j++) {
228 if (strcmp(ret[j], t_ip.tag) == 0) {
229 break;
233 if (j != count) {
234 /* we already have it. Move along */
235 continue;
238 /* add it to the list */
239 ret = (char **)Realloc(ret, (count+1) * sizeof(char *));
240 ret[count] = strdup(t_ip.tag);
241 if (!ret[count]) break;
242 count++;
245 if (count) {
246 /* make sure we null terminate */
247 ret[count] = NULL;
250 return ret;
253 /* free a list of wins server tags given by wins_srv_tags */
254 void wins_srv_tags_free(char **list)
256 int i;
257 if (!list) return;
258 for (i=0; list[i]; i++) {
259 free(list[i]);
261 free(list);
266 return the IP of the currently active wins server for the given tag,
267 or the zero IP otherwise
269 struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
271 char **list;
272 int i;
273 struct tagged_ip t_ip;
275 /* if we are a wins server then we always just talk to ourselves */
276 if (lp_wins_support()) {
277 extern struct in_addr loopback_ip;
278 return loopback_ip;
281 list = lp_wins_server_list();
282 if (!list || !list[0]) {
283 struct in_addr ip;
284 zero_ip(&ip);
285 return ip;
288 /* find the first live one for this tag */
289 for (i=0; list[i]; i++) {
290 parse_ip(&t_ip, list[i]);
291 if (strcmp(tag, t_ip.tag) != 0) {
292 /* not for the right tag. Move along */
293 continue;
295 if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
296 fstring src_name;
297 fstrcpy(src_name, inet_ntoa(src_ip));
298 DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n",
299 tag,
300 src_name,
301 inet_ntoa(t_ip.ip)));
302 return t_ip.ip;
306 /* they're all dead - try the first one until they revive */
307 for (i=0; list[i]; i++) {
308 parse_ip(&t_ip, list[i]);
309 if (strcmp(tag, t_ip.tag) != 0) {
310 continue;
312 return t_ip.ip;
315 /* this can't happen?? */
316 zero_ip(&t_ip.ip);
317 return t_ip.ip;
322 return a count of the number of IPs for a particular tag, including
323 dead ones
325 unsigned wins_srv_count_tag(const char *tag)
327 char **list;
328 int i, count=0;
330 /* if we are a wins server then we always just talk to ourselves */
331 if (lp_wins_support()) {
332 return 1;
335 list = lp_wins_server_list();
336 if (!list || !list[0]) {
337 return 0;
340 /* find the first live one for this tag */
341 for (i=0; list[i]; i++) {
342 struct tagged_ip t_ip;
343 parse_ip(&t_ip, list[i]);
344 if (strcmp(tag, t_ip.tag) == 0) {
345 count++;
349 return count;