summaryrefslogtreecommitdiff
path: root/source3/lib
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib')
-rw-r--r--source3/lib/wins_srv.c261
1 files changed, 245 insertions, 16 deletions
diff --git a/source3/lib/wins_srv.c b/source3/lib/wins_srv.c
index c31e7505f0..95b25b96b2 100644
--- a/source3/lib/wins_srv.c
+++ b/source3/lib/wins_srv.c
@@ -1,6 +1,6 @@
/*
Unix SMB/CIFS implementation.
- Samba utility functions
+ Samba wins server helper functions
Copyright (C) Andrew Tridgell 1992-2002
Copyright (C) Christopher R. Hertel 2000
@@ -21,6 +21,41 @@
#include "includes.h"
+/*
+ this is pretty much a complete rewrite of the earlier code. The main
+ aim of the rewrite is to add support for having multiple wins server
+ lists, so Samba can register with multiple groups of wins servers
+ and each group has a failover list of wins servers.
+
+ Central to the way it all works is the idea of a wins server
+ 'tag'. A wins tag is a label for a group of wins servers. For
+ example if you use
+
+ wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
+
+ then you would have two groups of wins servers, one tagged with the
+ name 'fred' and the other with the name 'mary'. I would usually
+ recommend using interface names instead of 'fred' and 'mary' but
+ they can be any alpha string.
+
+ Now, how does it all work. Well, nmbd needs to register each of its
+ IPs with each of its names once with each group of wins servers. So
+ it tries registering with the first one mentioned in the list, then
+ if that fails it marks that WINS server dead and moves onto the next
+ one.
+
+ In the client code things are a bit different. As each of the groups
+ of wins servers is a separate name space we need to try each of the
+ groups until we either succeed or we run out of wins servers to
+ try. If we get a negative response from a wins server then that
+ means the name doesn't exist in that group, so we give up on that
+ group and move to the next group. If we don't get a response at all
+ then maybe the wins server is down, in which case we need to
+ failover to the next one for that group.
+
+ confused yet? (tridge)
+*/
+
/* how long a server is marked dead for */
#define DEATH_TIME 600
@@ -33,10 +68,17 @@ static struct wins_dead {
} *dead_servers;
+/* an internal convenience structure for an IP with a short string tag
+ attached */
+struct tagged_ip {
+ fstring tag;
+ struct in_addr ip;
+};
+
/*
see if an ip is on the dead list
*/
-static int wins_is_dead(struct in_addr ip)
+BOOL wins_srv_is_dead(struct in_addr ip)
{
struct wins_dead *d;
for (d=dead_servers; d; d=d->next) {
@@ -46,12 +88,12 @@ static int wins_is_dead(struct in_addr ip)
DEBUG(4,("Reviving wins server %s\n", inet_ntoa(ip)));
DLIST_REMOVE(dead_servers, d);
free(d);
- return 0;
+ return False;
}
- return 1;
+ return True;
}
}
- return 0;
+ return False;
}
/*
@@ -61,7 +103,7 @@ void wins_srv_died(struct in_addr ip)
{
struct wins_dead *d;
- if (is_zero_ip(ip) || wins_is_dead(ip)) {
+ if (is_zero_ip(ip) || wins_srv_is_dead(ip)) {
return;
}
@@ -79,11 +121,16 @@ void wins_srv_died(struct in_addr ip)
/*
return the total number of wins servers, dead or not
*/
-unsigned long wins_srv_count(void)
+unsigned wins_srv_count(void)
{
char **list;
int count = 0;
+ if (lp_wins_support()) {
+ /* simple - just talk to ourselves */
+ return 1;
+ }
+
list = lp_wins_server_list();
for (count=0; list && list[count]; count++) /* nop */ ;
@@ -92,31 +139,213 @@ unsigned long wins_srv_count(void)
}
/*
+ parse an IP string that might be in tagged format
+ the result is a tagged_ip structure containing the tag
+ and the ip in in_addr format. If there is no tag then
+ use the tag '*'
+*/
+static void parse_ip(struct tagged_ip *ip, const char *str)
+{
+ char *s = strchr(str, ':');
+ if (!s) {
+ fstrcpy(ip->tag, "*");
+ ip->ip = *interpret_addr2(str);
+ return;
+ }
+
+ ip->ip = *interpret_addr2(s+1);
+ fstrcpy(ip->tag, str);
+ s = strchr(ip->tag, ':');
+ if (s) *s = 0;
+}
+
+
+/*
return the IP of the currently active wins server, or the zero IP otherwise
*/
struct in_addr wins_srv_ip(void)
{
char **list;
- struct in_addr ip;
int i;
+ struct tagged_ip t_ip;
+
+ /* if we are a wins server then we always just talk to ourselves */
+ if (lp_wins_support()) {
+ extern struct in_addr loopback_ip;
+ return loopback_ip;
+ }
list = lp_wins_server_list();
if (!list || !list[0]) {
- zero_ip(&ip);
- return ip;
+ zero_ip(&t_ip.ip);
+ return t_ip.ip;
}
/* find the first live one */
for (i=0; list[i]; i++) {
- ip = *interpret_addr2(list[i]);
- if (!wins_is_dead(ip)) {
- DEBUG(6,("Current wins server is %s\n", inet_ntoa(ip)));
- return ip;
+ parse_ip(&t_ip, list[i]);
+ if (!wins_srv_is_dead(t_ip.ip)) {
+ DEBUG(6,("Current wins server is %s\n", inet_ntoa(t_ip.ip)));
+ return t_ip.ip;
}
}
/* damn, they are all dead. Keep trying the primary until they revive */
- ip = *interpret_addr2(list[0]);
+ parse_ip(&t_ip, list[0]);
+
+ return t_ip.ip;
+}
+
+
+/*
+ return the list of wins server tags. A 'tag' is used to distinguish
+ wins server as either belonging to the same name space or a separate
+ name space. Usually you would setup your 'wins server' option to
+ list one or more wins server per interface and use the interface
+ name as your tag, but you are free to use any tag you like.
+*/
+char **wins_srv_tags(void)
+{
+ char **ret = NULL;
+ int count=0, i, j;
+ char **list;
+
+ if (lp_wins_support()) {
+ /* give the caller something to chew on. This makes
+ the rest of the logic simpler (ie. less special cases) */
+ ret = (char **)malloc(sizeof(char *)*2);
+ if (!ret) return NULL;
+ ret[0] = strdup("*");
+ ret[1] = NULL;
+ return ret;
+ }
+
+ list = lp_wins_server_list();
+ if (!list) return NULL;
+
+ /* yes, this is O(n^2) but n is very small */
+ for (i=0;list[i];i++) {
+ struct tagged_ip t_ip;
+
+ parse_ip(&t_ip, list[i]);
+
+ /* see if we already have it */
+ for (j=0;j<count;j++) {
+ if (strcmp(ret[j], t_ip.tag) == 0) {
+ break;
+ }
+ }
+
+ if (j != count) {
+ /* we already have it. Move along */
+ continue;
+ }
+
+ /* add it to the list */
+ ret = (char **)Realloc(ret, (count+1) * sizeof(char *));
+ ret[count] = strdup(t_ip.tag);
+ if (!ret[count]) break;
+ count++;
+ }
+
+ if (count) {
+ /* make sure we null terminate */
+ ret[count] = NULL;
+ }
+
+ return ret;
+}
+
+/* free a list of wins server tags given by wins_srv_tags */
+void wins_srv_tags_free(char **list)
+{
+ int i;
+ if (!list) return;
+ for (i=0; list[i]; i++) {
+ free(list[i]);
+ }
+ free(list);
+}
- return ip;
+
+/*
+ return the IP of the currently active wins server for the given tag,
+ or the zero IP otherwise
+*/
+struct in_addr wins_srv_ip_tag(const char *tag)
+{
+ char **list;
+ int i;
+ struct tagged_ip t_ip;
+
+ /* if we are a wins server then we always just talk to ourselves */
+ if (lp_wins_support()) {
+ extern struct in_addr loopback_ip;
+ return loopback_ip;
+ }
+
+ list = lp_wins_server_list();
+ if (!list || !list[0]) {
+ struct in_addr ip;
+ zero_ip(&ip);
+ return ip;
+ }
+
+ /* find the first live one for this tag */
+ for (i=0; list[i]; i++) {
+ parse_ip(&t_ip, list[i]);
+ if (strcmp(tag, t_ip.tag) != 0) {
+ /* not for the right tag. Move along */
+ continue;
+ }
+ if (!wins_srv_is_dead(t_ip.ip)) {
+ DEBUG(6,("Current wins server for tag '%s' is %s\n", tag, inet_ntoa(t_ip.ip)));
+ return t_ip.ip;
+ }
+ }
+
+ /* they're all dead - try the first one until they revive */
+ for (i=0; list[i]; i++) {
+ parse_ip(&t_ip, list[i]);
+ if (strcmp(tag, t_ip.tag) != 0) {
+ continue;
+ }
+ return t_ip.ip;
+ }
+
+ /* this can't happen?? */
+ zero_ip(&t_ip.ip);
+ return t_ip.ip;
+}
+
+
+/*
+ return a count of the number of IPs for a particular tag, including
+ dead ones
+*/
+unsigned wins_srv_count_tag(const char *tag)
+{
+ char **list;
+ int i, count=0;
+
+ /* if we are a wins server then we always just talk to ourselves */
+ if (lp_wins_support()) {
+ return 1;
+ }
+
+ list = lp_wins_server_list();
+ if (!list || !list[0]) {
+ return 0;
+ }
+
+ /* find the first live one for this tag */
+ for (i=0; list[i]; i++) {
+ struct tagged_ip t_ip;
+ parse_ip(&t_ip, list[i]);
+ if (strcmp(tag, t_ip.tag) == 0) {
+ count++;
+ }
+ }
+
+ return count;
}