r23779: Change from v2 or later to v3 or later.
[samba.git] / source3 / lib / wins_srv.c
index 95b25b96b23de8f201b1a1da07621827a07cab34..bbde3f85b8c492a9761a81fde38c588744c41549 100644 (file)
@@ -3,10 +3,11 @@
    Samba wins server helper functions
    Copyright (C) Andrew Tridgell 1992-2002
    Copyright (C) Christopher R. Hertel 2000
+   Copyright (C) Tim Potter 2003
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
 
 #include "includes.h"
 
+extern struct in_addr loopback_ip;
+
 /*
-  this is pretty much a complete rewrite of the earlier code. The main
+  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.
   confused yet? (tridge)
 */
 
-
 /* how long a server is marked dead for */
 #define DEATH_TIME 600
 
-/* a list of wins server that are marked dead. */
-static struct wins_dead {
-       struct in_addr ip;
-       time_t revival; /* when it will be revived */
-       struct wins_dead *next, *prev;
-} *dead_servers;
+/* The list of dead wins servers is stored in gencache.tdb.  Each server is
+   marked dead from the point of view of a given source address. We keep a 
+   separate dead list for each src address to cope with multiple interfaces 
+   that are not routable to each other.
+  */
 
+#define WINS_SRV_FMT "WINS_SRV_DEAD/%s,%s" /* wins_ip,src_ip */
 
-/* an internal convenience structure for an IP with a short string tag
-   attached */
-struct tagged_ip {
-       fstring tag;
-       struct in_addr ip;
-};
+static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip)
+{
+       char *keystr = NULL, *wins_ip_addr = NULL, *src_ip_addr = NULL;
+
+       wins_ip_addr = SMB_STRDUP(inet_ntoa(wins_ip));
+       src_ip_addr = SMB_STRDUP(inet_ntoa(src_ip));
+
+       if ( !wins_ip_addr || !src_ip_addr ) {
+               DEBUG(0,("wins_srv_keystr: malloc error\n"));
+               goto done;
+       }
+
+       if (asprintf(&keystr, WINS_SRV_FMT, wins_ip_addr, src_ip_addr) == -1) {
+               DEBUG(0, (": ns_srv_keystr: malloc error for key string\n"));
+       }
+
+done:
+       SAFE_FREE(wins_ip_addr);
+       SAFE_FREE(src_ip_addr);
+
+       return keystr;
+}
 
 /*
   see if an ip is on the dead list
 */
-BOOL wins_srv_is_dead(struct in_addr ip)
+
+BOOL wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
 {
-       struct wins_dead *d;
-       for (d=dead_servers; d; d=d->next) {
-               if (ip_equal(ip, d->ip)) {
-                       /* it might be due for revival */
-                       if (d->revival <= time(NULL)) {
-                               DEBUG(4,("Reviving wins server %s\n", inet_ntoa(ip)));
-                               DLIST_REMOVE(dead_servers, d);
-                               free(d);
-                               return False;
-                       }
-                       return True;
-               }
-       }
-       return False;
+       char *keystr = wins_srv_keystr(wins_ip, src_ip);
+       BOOL result;
+
+       /* If the key exists then the WINS server has been marked as dead */
+
+       result = gencache_get(keystr, NULL, NULL);
+       SAFE_FREE(keystr);
+
+       DEBUG(4, ("wins_srv_is_dead: %s is %s\n", inet_ntoa(wins_ip),
+                 result ? "dead" : "alive"));
+
+       return result;
+}
+
+
+/*
+  mark a wins server as being alive (for the moment)
+*/
+void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
+{
+       char *keystr = wins_srv_keystr(wins_ip, src_ip);
+
+       gencache_del(keystr);
+       SAFE_FREE(keystr);
+
+       DEBUG(4, ("wins_srv_alive: marking wins server %s alive\n", 
+                 inet_ntoa(wins_ip)));
 }
 
 /*
   mark a wins server as temporarily dead
 */
-void wins_srv_died(struct in_addr ip)
+void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
 {
-       struct wins_dead *d;
+       char *keystr;
 
-       if (is_zero_ip(ip) || wins_srv_is_dead(ip)) {
+       if (is_zero_ip(wins_ip) || wins_srv_is_dead(wins_ip, src_ip))
                return;
-       }
 
-       d = (struct wins_dead *)malloc(sizeof(*d));
-       if (!d) return;
+       keystr = wins_srv_keystr(wins_ip, src_ip);
 
-       d->ip = ip;
-       d->revival = time(NULL) + DEATH_TIME;
+       gencache_set(keystr, "DOWN", time(NULL) + DEATH_TIME);
 
-       DEBUG(4,("Marking wins server %s dead for %u seconds\n", inet_ntoa(ip), DEATH_TIME));
+       SAFE_FREE(keystr);
 
-       DLIST_ADD(dead_servers, d);
+       DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
+                inet_ntoa(wins_ip), DEATH_TIME, inet_ntoa(src_ip)));
 }
 
 /*
@@ -123,7 +153,7 @@ void wins_srv_died(struct in_addr ip)
 */
 unsigned wins_srv_count(void)
 {
-       char **list;
+       const char **list;
        int count = 0;
 
        if (lp_wins_support()) {
@@ -132,12 +162,19 @@ unsigned wins_srv_count(void)
        }
 
        list = lp_wins_server_list();
-       for (count=0; list && list[count]; count++) /* nop */ ;
+       for (count=0; list && list[count]; count++)
+               /* nop */ ;
 
-       DEBUG(6,("Found %u wins servers in list\n", count));
        return count;
 }
 
+/* an internal convenience structure for an IP with a short string tag
+   attached */
+struct tagged_ip {
+       fstring tag;
+       struct in_addr ip;
+};
+
 /*
   parse an IP string that might be in tagged format
   the result is a tagged_ip structure containing the tag
@@ -160,42 +197,6 @@ static void parse_ip(struct tagged_ip *ip, const char *str)
 }
 
 
-/*
-  return the IP of the currently active wins server, or the zero IP otherwise
-*/
-struct in_addr wins_srv_ip(void)
-{
-       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]) {
-               zero_ip(&t_ip.ip);
-               return t_ip.ip;
-       }
-
-       /* find the first live one */
-       for (i=0; list[i]; i++) {
-               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 */
-       parse_ip(&t_ip, list[0]);
-
-       return t_ip.ip;
-}
-
 
 /*
   return the list of wins server tags. A 'tag' is used to distinguish
@@ -208,20 +209,21 @@ char **wins_srv_tags(void)
 {
        char **ret = NULL;
        int count=0, i, j;
-       char **list;
+       const 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);
+               ret = SMB_MALLOC_ARRAY(char *, 2);
                if (!ret) return NULL;
-               ret[0] = strdup("*");
+               ret[0] = SMB_STRDUP("*");
                ret[1] = NULL;
                return ret;
        }
 
        list = lp_wins_server_list();
-       if (!list) return NULL;
+       if (!list)
+               return NULL;
 
        /* yes, this is O(n^2) but n is very small */
        for (i=0;list[i];i++) {
@@ -242,8 +244,11 @@ char **wins_srv_tags(void)
                }
 
                /* add it to the list */
-               ret = (char **)Realloc(ret, (count+1) * sizeof(char *));
-               ret[count] = strdup(t_ip.tag);
+               ret = SMB_REALLOC_ARRAY(ret, char *, count+2);
+               if (!ret) {
+                       return NULL;
+               }
+               ret[count] = SMB_STRDUP(t_ip.tag);
                if (!ret[count]) break;
                count++;
        }
@@ -272,15 +277,14 @@ void wins_srv_tags_free(char **list)
   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)
+struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
 {
-       char **list;
+       const 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;
        }
 
@@ -298,8 +302,13 @@ struct in_addr wins_srv_ip_tag(const char *tag)
                        /* 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)));
+               if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
+                       fstring src_name;
+                       fstrcpy(src_name, inet_ntoa(src_ip));
+                       DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n", 
+                                tag, 
+                                src_name,
+                                inet_ntoa(t_ip.ip)));
                        return t_ip.ip;
                }
        }
@@ -325,7 +334,7 @@ struct in_addr wins_srv_ip_tag(const char *tag)
 */
 unsigned wins_srv_count_tag(const char *tag)
 {
-       char **list;
+       const char **list;
        int i, count=0;
 
        /* if we are a wins server then we always just talk to ourselves */