source: vendor/3.6.23/source3/lib/wins_srv.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial 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 3 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, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "includes.h"
23
24/*
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.
29
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
33
34 wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
35
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.
40
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.
46
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.
55
56 confused yet? (tridge)
57*/
58
59/* how long a server is marked dead for */
60#define DEATH_TIME 600
61
62/* The list of dead wins servers is stored in gencache.tdb. Each server is
63 marked dead from the point of view of a given source address. We keep a
64 separate dead list for each src address to cope with multiple interfaces
65 that are not routable to each other.
66 */
67
68#define WINS_SRV_FMT "WINS_SRV_DEAD/%s,%s" /* wins_ip,src_ip */
69
70static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip)
71{
72 char *keystr = NULL, *wins_ip_addr = NULL, *src_ip_addr = NULL;
73
74 wins_ip_addr = SMB_STRDUP(inet_ntoa(wins_ip));
75 src_ip_addr = SMB_STRDUP(inet_ntoa(src_ip));
76
77 if ( !wins_ip_addr || !src_ip_addr ) {
78 DEBUG(0,("wins_srv_keystr: malloc error\n"));
79 goto done;
80 }
81
82 if (asprintf(&keystr, WINS_SRV_FMT, wins_ip_addr, src_ip_addr) == -1) {
83 DEBUG(0, (": ns_srv_keystr: malloc error for key string\n"));
84 }
85
86done:
87 SAFE_FREE(wins_ip_addr);
88 SAFE_FREE(src_ip_addr);
89
90 return keystr;
91}
92
93/*
94 see if an ip is on the dead list
95*/
96
97bool wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
98{
99 char *keystr = wins_srv_keystr(wins_ip, src_ip);
100 bool result;
101
102 /* If the key exists then the WINS server has been marked as dead */
103
104 result = gencache_get(keystr, NULL, NULL);
105 SAFE_FREE(keystr);
106
107 DEBUG(4, ("wins_srv_is_dead: %s is %s\n", inet_ntoa(wins_ip),
108 result ? "dead" : "alive"));
109
110 return result;
111}
112
113
114/*
115 mark a wins server as being alive (for the moment)
116*/
117void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
118{
119 char *keystr = wins_srv_keystr(wins_ip, src_ip);
120
121 gencache_del(keystr);
122 SAFE_FREE(keystr);
123
124 DEBUG(4, ("wins_srv_alive: marking wins server %s alive\n",
125 inet_ntoa(wins_ip)));
126}
127
128/*
129 mark a wins server as temporarily dead
130*/
131void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
132{
133 char *keystr;
134
135 if (is_zero_ip_v4(wins_ip) || wins_srv_is_dead(wins_ip, src_ip))
136 return;
137
138 keystr = wins_srv_keystr(wins_ip, src_ip);
139
140 gencache_set(keystr, "DOWN", time(NULL) + DEATH_TIME);
141
142 SAFE_FREE(keystr);
143
144 DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
145 inet_ntoa(wins_ip), DEATH_TIME, inet_ntoa(src_ip)));
146}
147
148/*
149 return the total number of wins servers, dead or not
150*/
151unsigned wins_srv_count(void)
152{
153 const char **list;
154 int count = 0;
155
156 if (lp_wins_support()) {
157 /* simple - just talk to ourselves */
158 return 1;
159 }
160
161 list = lp_wins_server_list();
162 for (count=0; list && list[count]; count++)
163 /* nop */ ;
164
165 return count;
166}
167
168/* an internal convenience structure for an IP with a short string tag
169 attached */
170struct tagged_ip {
171 fstring tag;
172 struct in_addr ip;
173};
174
175/*
176 parse an IP string that might be in tagged format
177 the result is a tagged_ip structure containing the tag
178 and the ip in in_addr format. If there is no tag then
179 use the tag '*'
180*/
181static void parse_ip(struct tagged_ip *ip, const char *str)
182{
183 char *s = strchr(str, ':');
184 if (!s) {
185 fstrcpy(ip->tag, "*");
186 ip->ip = interpret_addr2(str);
187 return;
188 }
189
190 ip->ip = interpret_addr2(s+1);
191 fstrcpy(ip->tag, str);
192 s = strchr(ip->tag, ':');
193 if (s) {
194 *s = 0;
195 }
196}
197
198
199
200/*
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.
206*/
207char **wins_srv_tags(void)
208{
209 char **ret = NULL;
210 int count=0, i, j;
211 const char **list;
212
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 = SMB_MALLOC_ARRAY(char *, 2);
217 if (!ret) return NULL;
218 ret[0] = SMB_STRDUP("*");
219 ret[1] = NULL;
220 return ret;
221 }
222
223 list = lp_wins_server_list();
224 if (!list)
225 return NULL;
226
227 /* yes, this is O(n^2) but n is very small */
228 for (i=0;list[i];i++) {
229 struct tagged_ip t_ip;
230
231 parse_ip(&t_ip, list[i]);
232
233 /* see if we already have it */
234 for (j=0;j<count;j++) {
235 if (strcmp(ret[j], t_ip.tag) == 0) {
236 break;
237 }
238 }
239
240 if (j != count) {
241 /* we already have it. Move along */
242 continue;
243 }
244
245 /* add it to the list */
246 ret = SMB_REALLOC_ARRAY(ret, char *, count+2);
247 if (!ret) {
248 return NULL;
249 }
250 ret[count] = SMB_STRDUP(t_ip.tag);
251 if (!ret[count]) break;
252 count++;
253 }
254
255 if (count) {
256 /* make sure we null terminate */
257 ret[count] = NULL;
258 }
259
260 return ret;
261}
262
263/* free a list of wins server tags given by wins_srv_tags */
264void wins_srv_tags_free(char **list)
265{
266 int i;
267 if (!list) return;
268 for (i=0; list[i]; i++) {
269 free(list[i]);
270 }
271 free(list);
272}
273
274
275/*
276 return the IP of the currently active wins server for the given tag,
277 or the zero IP otherwise
278*/
279struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
280{
281 const char **list;
282 int i;
283 struct tagged_ip t_ip;
284
285 /* if we are a wins server then we always just talk to ourselves */
286 if (lp_wins_support()) {
287 struct in_addr loopback_ip;
288 loopback_ip.s_addr = htonl(INADDR_LOOPBACK);
289 return loopback_ip;
290 }
291
292 list = lp_wins_server_list();
293 if (!list || !list[0]) {
294 struct in_addr ip;
295 zero_ip_v4(&ip);
296 return ip;
297 }
298
299 /* find the first live one for this tag */
300 for (i=0; list[i]; i++) {
301 parse_ip(&t_ip, list[i]);
302 if (strcmp(tag, t_ip.tag) != 0) {
303 /* not for the right tag. Move along */
304 continue;
305 }
306 if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
307 fstring src_name;
308 fstrcpy(src_name, inet_ntoa(src_ip));
309 DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n",
310 tag,
311 src_name,
312 inet_ntoa(t_ip.ip)));
313 return t_ip.ip;
314 }
315 }
316
317 /* they're all dead - try the first one until they revive */
318 for (i=0; list[i]; i++) {
319 parse_ip(&t_ip, list[i]);
320 if (strcmp(tag, t_ip.tag) != 0) {
321 continue;
322 }
323 return t_ip.ip;
324 }
325
326 /* this can't happen?? */
327 zero_ip_v4(&t_ip.ip);
328 return t_ip.ip;
329}
330
331
332/*
333 return a count of the number of IPs for a particular tag, including
334 dead ones
335*/
336unsigned wins_srv_count_tag(const char *tag)
337{
338 const char **list;
339 int i, count=0;
340
341 /* if we are a wins server then we always just talk to ourselves */
342 if (lp_wins_support()) {
343 return 1;
344 }
345
346 list = lp_wins_server_list();
347 if (!list || !list[0]) {
348 return 0;
349 }
350
351 /* find the first live one for this tag */
352 for (i=0; list[i]; i++) {
353 struct tagged_ip t_ip;
354 parse_ip(&t_ip, list[i]);
355 if (strcmp(tag, t_ip.tag) == 0) {
356 count++;
357 }
358 }
359
360 return count;
361}
Note: See TracBrowser for help on using the repository browser.