First cut toward adding WINS server failover.
authorChristopher R. Hertel <crh@samba.org>
Wed, 19 Jul 2000 01:21:30 +0000 (01:21 +0000)
committerChristopher R. Hertel <crh@samba.org>
Wed, 19 Jul 2000 01:21:30 +0000 (01:21 +0000)
*Note: failover doesn't actually work yet!*  It's just that the code I'm
adding provides all of the pieces necessary.

I do have one big question.  Something that I'll have to ask Jeremy, I'm
thinkin'.  In nmbd/nmbd_subnetdb.c the IP of the WINS server is used to
set up the Unicast subnet.

...so what happens if the WINS server changes?

My guess is either:
  a) nothing.
  b) I'd have to change the unicast subnet entry whenever the WINS server
     changes.

Urq.

BTW, the lp_wins_server() function no longer returns the WINS server name
or IP.  It returns the list of WINS servers entered in smb.conf.  To get
the currently 'live' WINS server, use the wins_srv() function.

Fun, eh?

Chris -)-----
(This used to be commit cc08bdc74f4cd111fdc582ee7babef47ed8a950d)

source3/Makefile.in
source3/include/proto.h
source3/lib/wins_srv.c [new file with mode: 0644]
source3/libsmb/namequery.c
source3/nmbd/nmbd_subnetdb.c
source3/nsswitch/wins.c
source3/param/loadparm.c

index 07a6fbbe940a43d97a17ee06639b088d7f862663..fa80957aacdbb2d5a9ec2f643f64fd95baf8456d 100644 (file)
@@ -103,7 +103,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \
           lib/interfaces.o lib/pidfile.o lib/replace.o \
           lib/signal.o lib/slprintf.o lib/system.o lib/doscalls.o lib/time.o \
          lib/ufc.o lib/genrand.o lib/username.o lib/access.o lib/smbrun.o \
-         lib/bitmap.o lib/crc32.o lib/snprintf.o \
+         lib/bitmap.o lib/crc32.o lib/snprintf.o lib/wins_srv.o \
          lib/util_array.o lib/util_str.o lib/util_sid.o \
          lib/util_unistr.o lib/util_file.o \
          lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o \
index 2335b8f07debd878ef5cf7b32141efa5eb2a61a1..1b7225d6b97987c3b0f007bf3bde3be29eb66522 100644 (file)
@@ -410,16 +410,6 @@ char **file_lines_pload(char *syscmd, int *numlines);
 void file_lines_free(char **lines);
 void file_lines_slashcont(char **lines);
 
-/*The following definitions come from  lib/util_list.c  */
-
-BOOL copy_policy_hnd (POLICY_HND *dest, const POLICY_HND *src);
-BOOL compare_rpc_hnd_node(const RPC_HND_NODE *x, 
-                         const RPC_HND_NODE *y);
-BOOL RpcHndList_set_connection(const POLICY_HND *hnd, 
-                              struct cli_connection *con);
-BOOL RpcHndList_del_connection(const POLICY_HND *hnd);
-struct cli_connection* RpcHndList_get_connection(const POLICY_HND *hnd);
-
 /*The following definitions come from  lib/util_seaccess.c  */
 
 BOOL se_access_check(SEC_DESC *sd, struct current_user *user,
@@ -603,6 +593,13 @@ void split_at_last_component_w(smb_ucs2_t *path, smb_ucs2_t *front, smb_ucs2_t s
 smb_ucs2_t *octal_string_w(int i);
 smb_ucs2_t *string_truncate_w(smb_ucs2_t *s, size_t length);
 
+/*The following definitions come from  lib/wins_srv.c  */
+
+BOOL wins_srv_load_list( char *src );
+char *wins_srv( void );
+void wins_srv_died( char *boothill );
+unsigned long wins_srv_count( void );
+
 /*The following definitions come from  libsmb/cliconnect.c  */
 
 BOOL cli_session_setup(struct cli_state *cli, 
diff --git a/source3/lib/wins_srv.c b/source3/lib/wins_srv.c
new file mode 100644 (file)
index 0000000..e84ac34
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   Samba utility functions
+   Copyright (C) Andrew Tridgell 1992-1998
+
+   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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* -------------------------------------------------------------------------- **
+ * Discussion...
+ *
+ * This module implements WINS failover.
+ *
+ * Microsoft's WINS servers provide a feature called WINS replication,
+ * which synchronises the WINS name databases between two or more servers. 
+ * This means that the two servers can be used interchangably (more or
+ * less). WINS replication is particularly useful if you are trying to
+ * synchronise the WINS namespace between servers in remote locations, or
+ * if your WINS servers tend to crash a lot. 
+ *
+ * WINS failover allows the client to 'switch' to a different WINS server
+ * if the current WINS server mysteriously disappears.  On Windows
+ * systems, this is typically represented as 'primary' and 'secondary'
+ * WINS servers. 
+ *
+ * Failover only works if the WINS servers are synced.  If they are not,
+ * then
+ *   a) if the primary WINS server never fails the client will never 'see'
+ *      the secondary (or tertiary or...) WINS server name space.
+ *   b) if the primary *does* fail, the client will be entering an
+ *      unfamiliar namespace.  The client itself will not be registered in
+ *      that namespace and any names which match names in the previous
+ *      space will likely resolve to different host IP addresses.
+ *
+ * One key thing to remember regarding WINS failover is that Samba does
+ * not (yet) implement WINS replication.  For those interested, sniff port
+ * 42 (TCP? UDP? ...dunno off hand) and see what two MS WINS servers do. 
+ *
+ * At this stage, only failover is implemented.  The next thing is to add
+ * support for multi-WINS server registration and query
+ * (multi-membership).
+ *
+ * Multi-membership is a little wierd.  The idea is that the client can
+ * register itself with multiple non-replicated WINS servers, and query
+ * all of those servers (in a prescribed sequence) to resolve a name. 
+ *
+ * The implications of multi-membership are not quite clear.  Worth
+ * trying, I suppose.  Changes will be needed in the name query and
+ * registration code to accomodate this feature.  Also, there will need to
+ * be some sort of syntax extension for the 'wins server' parameter in
+ * smb.conf.  I'm thinking that a colon could be used as a separator. 
+ *
+ * Of course, for each WINS namespace there might be multiple, synced WINS
+ * servers.  The change to this module would likely be the addition of a
+ * linked list of linked lists.
+ *
+ * crh@samba.org
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Defines... 
+ *
+ *   NECROMANCYCLE - The dead server retry period, in seconds.  When a WINS
+ *                   server is declared dead, wait this many seconds before
+ *                   attempting to communicate with it.
+ */
+
+#define NECROMANCYCLE 600   /* 600 seconds == 10 minutes. */
+
+/* -------------------------------------------------------------------------- **
+ * Typedefs...
+ */
+
+typedef struct
+  {
+  ubi_slNode node;      /* Linked list node structure.                        */
+  time_t     mourning;  /* If greater than current time server is dead, Jim.  */
+  char      *server;    /* DNS name or IP of NBNS server to query.            */
+  } list_entry;
+
+/* -------------------------------------------------------------------------- **
+ * Private, static variables.
+ */
+
+static ubi_slNewList( wins_srv_list );
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+
+BOOL wins_srv_load_list( char *src )
+  /* ------------------------------------------------------------------------ **
+   * Create or recreate the linked list of failover WINS servers.
+   */
+  {
+  list_entry   *entry;
+  char         *p = src;
+  pstring       wins_id_bufr;
+  unsigned long count;
+
+  /* Empty the list. */
+  while( NULL != (entry =(list_entry *)ubi_slRemHead( wins_srv_list )) )
+    {
+    if( entry->server )
+      free( entry->server );
+    free( entry );
+    }
+  (void)ubi_slInitList( wins_srv_list );  /* shouldn't be needed */
+
+  /* Parse out the DNS names or IP addresses of the WINS servers. */
+  DEBUG( 4, ("wins_srv: Building WINS server list:\n") );
+  while( next_token( &p, wins_id_bufr, LIST_SEP, sizeof( wins_id_bufr ) ) )
+    {
+    entry = (list_entry *)malloc( sizeof( list_entry ) );
+    if( NULL == entry )
+      {
+      DEBUG( 0, ("wins_srv_load_list(): malloc(list_entry) failed.\n") );
+      }
+    else
+      {
+      entry->mourning = 0;
+      if( NULL == (entry->server = strdup( wins_id_bufr )) )
+        {
+        free( entry );
+        DEBUG( 0, ("wins_srv_load_list(): strdup(\"%s\") failed.\n", wins_id_bufr) );
+        }
+      else
+        {
+        /* Add server to list. */
+        (void)ubi_slAddTail( wins_srv_list, entry );
+        DEBUGADD( 4, ("\t\t%s,\n", wins_id_bufr) );
+        }
+      }
+    }
+
+  count = ubi_slCount( wins_srv_list );
+  DEBUGADD( 4, ( "\t\t%d WINS server%s listed.\n", count, (1==count)?"":"s" ) );
+
+  return( (count > 0) ? True : False );
+  } /* wins_srv_load_list */
+
+
+char *wins_srv( void )
+  /* ------------------------------------------------------------------------ **
+   */
+  {
+  time_t      now     = time(NULL);
+  list_entry *entry   = (list_entry *)ubi_slFirst( wins_srv_list );
+  list_entry *coldest = entry;
+
+  /* Go through the list.  Look for the first live entry. */
+  while( (NULL != entry) && (now < entry->mourning) )
+    {
+    entry = (list_entry *)ubi_slNext( entry );
+    if( entry->mourning < coldest->mourning )
+      coldest = entry;
+    }
+
+  /* If they were all dead, then return the one that's been dead longest. */
+  if( NULL == entry )
+    {
+    entry = coldest;
+    DEBUG( 4, ("wins_srv: All WINS servers appear to have failed.\n") );
+    }
+
+  /* The list could be empty.  Check it. */
+  if( NULL == entry )
+    return( NULL );
+  return( entry->server );
+  } /* wins_srv */
+
+
+void wins_srv_died( char *boothill )
+  /* ------------------------------------------------------------------------ **
+   * Called to indicate that a specific WINS server has died.
+   */
+  {
+  list_entry *entry = (list_entry *)ubi_slFirst( wins_srv_list );
+
+  while( NULL != entry )
+    {
+    /* Match based on server ID [DNS name or IP]. */
+    if( 0 == strcmp( boothill, entry->server ) )
+      {
+      entry->mourning = time(NULL) + NECROMANCYCLE;
+      DEBUG( 2, ("wins_srv: WINS server %s appears to be down.\n", boothill) );
+      return;
+      }
+    entry = (list_entry *)ubi_slNext( entry );
+    }
+  } /* wins_srv_died */
+
+
+unsigned long wins_srv_count( void )
+  /* ------------------------------------------------------------------------ **
+   * Return the total number of entries in the list, dead or alive.
+   */
+  {
+  return( ubi_slCount( wins_srv_list ) );
+  } /* wins_srv_count */
+
+/* ========================================================================== */
index 193731768f4b017df806c5e4461570903aecfc29..0237a9752f8fbc86a637eb875186e805b0f0f918 100644 (file)
@@ -529,12 +529,12 @@ static BOOL resolve_wins(const char *name, int name_type,
 
        DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
 
-       if(!*lp_wins_server()) {
-               DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS server present.\n"));
+       if( wins_srv_count() < 1 ) {
+               DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n"));
                return False;
        }
 
-       wins_ip = *interpret_addr2(lp_wins_server());
+       wins_ip = *interpret_addr2( wins_srv() );
        wins_ismyip = ismyip(wins_ip);
 
        DEBUG(3, ("resolve_wins: WINS server == <%s>\n", inet_ntoa(wins_ip)) );
index 330be4057f1320207212c31c373194d0e7a858ae..57f937148e8630b2ab982c51aa812460d01611ab 100644 (file)
@@ -271,12 +271,16 @@ BOOL create_subnets(void)
    * get the ip address of it here. If we are the WINS server then
    * set the unicast subnet address to be the first of our own real
    * addresses.
+   *
+   * NOTE: I'm not sure of the implications of WINS server failover
+   *       on this bit of code.  Because of failover, the WINS
+   *       server address can change.
    */
 
   if(*lp_wins_server())
   {
     struct in_addr real_wins_ip;
-    real_wins_ip = *interpret_addr2(lp_wins_server());
+    real_wins_ip = *interpret_addr2( wins_srv() );
 
     if (!zero_ip(real_wins_ip))
     {
index f8a05a9fbf20c79383ca9ce8a3035c5993c74b10..41b71c64bbd73f47973f36239bf60d9a2ddd62a6 100644 (file)
@@ -56,7 +56,7 @@ struct in_addr *lookup_backend(const char *name, int *count)
 
        set_socket_options(fd,"SO_BROADCAST");
 
-       p = lp_wins_server();
+       p = wins_srv();
        if (p && *p) {
                ret = name_query(fd,name,0x20,False,True, *interpret_addr2(p), count);
                goto out;
index 3650d4edd3ad80ac3a18b1aaed6af5449696133e..61e38bea602d42cd064ac91c21ba26d26be7508a 100644 (file)
@@ -509,6 +509,7 @@ static BOOL handle_vfs_object(char *pszParmValue, char **ptr);
 static BOOL handle_source_env(char *pszParmValue, char **ptr);
 static BOOL handle_netbios_name(char *pszParmValue, char **ptr);
 static BOOL handle_winbind_id(char *pszParmValue, char **ptr);
+static BOOL handle_wins_server_list(char *pszParmValue, char **ptr);
 
 static void set_server_role(void);
 static void set_default_server_announce_type(void);
@@ -863,7 +864,7 @@ static struct parm_struct parm_table[] = {
        {"dns proxy", P_BOOL, P_GLOBAL, &Globals.bDNSproxy, NULL, NULL, 0},
        {"wins proxy", P_BOOL, P_GLOBAL, &Globals.bWINSproxy, NULL, NULL, 0},
        
-       {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, NULL, NULL, FLAG_BASIC},
+       {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, handle_wins_server_list, NULL, FLAG_BASIC},
        {"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL, NULL, FLAG_BASIC},
        {"wins hook", P_STRING, P_GLOBAL, &Globals.szWINSHook, NULL, NULL, 0},
 
@@ -2372,6 +2373,19 @@ static BOOL handle_winbind_id(char *pszParmValue, char **ptr)
        return True;
 }
 
+/***************************************************************************
+ Handle the WINS SERVER list
+***************************************************************************/
+static BOOL handle_wins_server_list( char *pszParmValue, char **ptr )
+  {
+  if( !wins_srv_load_list( pszParmValue ) )
+    return( False );  /* Parse failed. */
+
+  string_set( ptr, pszParmValue );
+  return( True );
+  }
+
+
 /***************************************************************************
 initialise a copymap
 ***************************************************************************/