This commit finally gives us multiple wins server groups. We now
authorAndrew Tridgell <tridge@samba.org>
Wed, 26 Jun 2002 12:17:11 +0000 (12:17 +0000)
committerAndrew Tridgell <tridge@samba.org>
Wed, 26 Jun 2002 12:17:11 +0000 (12:17 +0000)
accept an extended syntax for 'wins server' like this:

  wins server = group1:192.168.2.10 group2:192.168.3.99 group1:192.168.0.1

The tags before the IPs don't mean anything, they are just a way of
grouping IPs together. If you use the old syntax (ie. no ':') then
an implicit group name of '*' is used. In general I'd recommend people
use interface names for the group names, but it doesn't matter much.

When we register in nmbd we try to register all our IPs with each group
of WINS servers. We keep trying until all of them are registered with
every group, falling back to the failover WINS servers for each group
as we go.

When we do a WINS lookup we try each of the WINS servers for each group.
If a WINS server for a group gives a negative answer then we give up
on that group and move to the next group. If it times out then
we move to the next failover wins server in the group.

In either case, if a WINS server doesn't respond then we mark it dead
for 10 minutes, to prevent lengthy waits for dead servers.

source/lib/wins_srv.c
source/libsmb/namequery.c
source/nmbd/nmbd_nameregister.c
source/nmbd/nmbd_packets.c
source/nsswitch/winbindd_wins.c
source/nsswitch/wins.c
source/utils/nmblookup.c
source/web/diagnose.c

index c31e7505f0b3dbe7a78a4f8ca3e236a496ee8c7b..95b25b96b23de8f201b1a1da07621827a07cab34 100644 (file)
@@ -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
 
 
 #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 */ ;
 
@@ -91,32 +138,214 @@ unsigned long wins_srv_count(void)
        return count;
 }
 
+/*
+  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;
 }
index c85c8c48df228349db36ca4366cca4fc17b5ae20..2cdcd49b910a19d36f052883aff3c4f5bf44057e 100644 (file)
@@ -302,10 +302,12 @@ BOOL name_register(int fd, const char *name, int name_type,
  Do a netbios name query to find someones IP.
  Returns an array of IP addresses or NULL if none.
  *count will be set to the number of addresses returned.
+ *timed_out is set if we failed by timing out
 ****************************************************************************/
 struct in_addr *name_query(int fd,const char *name,int name_type, 
                           BOOL bcast,BOOL recurse,
-                          struct in_addr to_ip, int *count, int *flags)
+                          struct in_addr to_ip, int *count, int *flags,
+                          BOOL *timed_out)
 {
        BOOL found=False;
        int i, retries = 3;
@@ -315,6 +317,10 @@ struct in_addr *name_query(int fd,const char *name,int name_type,
        struct packet_struct *p2;
        struct nmb_packet *nmb = &p.packet.nmb;
        struct in_addr *ip_list = NULL;
+
+       if (timed_out) {
+               *timed_out = False;
+       }
        
        memset((char *)&p,'\0',sizeof(p));
        (*count) = 0;
@@ -465,10 +471,8 @@ struct in_addr *name_query(int fd,const char *name,int name_type,
                }
        }
 
-       /* Reach here if we've timed out waiting for replies.. */
-       if (!bcast && !found) {
-               /* Timed out wating for WINS server to respond.  Mark it dead. */
-               wins_srv_died( to_ip );
+       if (timed_out) {
+               *timed_out = True;
        }
 
        return ip_list;
@@ -619,7 +623,7 @@ BOOL name_resolve_bcast(const char *name, int name_type,
                /* Done this way to fix compiler error on IRIX 5.x */
                sendto_ip = *iface_n_bcast(i);
                *return_ip_list = name_query(sock, name, name_type, True, 
-                                   True, sendto_ip, return_count, &flags);
+                                   True, sendto_ip, return_count, &flags, NULL);
                if(*return_ip_list != NULL) {
                        close(sock);
                        return True;
@@ -637,59 +641,80 @@ BOOL name_resolve_bcast(const char *name, int name_type,
 static BOOL resolve_wins(const char *name, int name_type,
                          struct in_addr **return_iplist, int *return_count)
 {
-       int sock;
-       struct in_addr wins_ip;
-       BOOL wins_ismyip;
+       int sock, t, i;
+       char **wins_tags;
 
        *return_iplist = NULL;
        *return_count = 0;
        
-       /*
-        * "wins" means do a unicast lookup to the WINS server.
-        * Ignore if there is no WINS server specified or if the
-        * WINS server is one of our interfaces (if we're being
-        * called from within nmbd - we can't do this call as we
-        * would then block).
-        */
-
        DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
 
-       if (lp_wins_support()) {
-               /*
-                * We're providing WINS support. Call ourselves so
-                * long as we're not nmbd.
-                */
-               extern struct in_addr loopback_ip;
-               wins_ip = loopback_ip;
-               wins_ismyip = True;
-       } else if( wins_srv_count() < 1 ) {
+       if (wins_srv_count() < 1) {
                DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n"));
                return False;
-       } else {
-               wins_ip     = wins_srv_ip();
-               wins_ismyip = ismyip(wins_ip);
        }
 
-       DEBUG(3, ("resolve_wins: WINS server == <%s>\n", inet_ntoa(wins_ip)) );
-       if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
-               int flags;
-               sock = open_socket_in(  SOCK_DGRAM, 0, 3,
-                                       interpret_addr(lp_socket_address()),
-                                       True );
-               if (sock != -1) {
-                       *return_iplist = name_query( sock,      name,
-                                                    name_type, False, 
-                                                    True,      wins_ip,
-                                                    return_count, &flags);
-                       if(*return_iplist != NULL) {
-                               close(sock);
-                               return True;
+       /* we try a lookup on each of the WINS tags in turn */
+       wins_tags = wins_srv_tags();
+
+       if (!wins_tags) {
+               /* huh? no tags?? give up in disgust */
+               return False;
+       }
+
+       /* in the worst case we will try every wins server with every
+          tag! */
+       for (t=0; wins_tags && wins_tags[t]; t++) {
+               for (i=0; i<wins_srv_count_tag(wins_tags[t]); i++) {
+                       struct in_addr wins_ip;
+                       int flags;
+                       BOOL timed_out;
+
+                       wins_ip = wins_srv_ip_tag(wins_tags[t]);
+
+                       if (global_in_nmbd && ismyip(wins_ip)) {
+                               /* yikes! we'll loop forever */
+                               continue;
+                       }
+
+                       /* skip any that have been unresponsive lately */
+                       if (wins_srv_is_dead(wins_ip)) {
+                               continue;
+                       }
+
+                       DEBUG(3,("resolve_wins: using WINS server %s and tag '%s'\n", inet_ntoa(wins_ip), wins_tags[t]));
+
+                       sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True);
+                       if (sock == -1) {
+                               continue;
+                       }
+
+                       *return_iplist = name_query(sock,name,name_type, False, 
+                                                   True, wins_ip, return_count, &flags, 
+                                                   &timed_out);
+                       if (*return_iplist != NULL) {
+                               goto success;
                        }
                        close(sock);
+
+                       if (timed_out) {
+                               /* Timed out wating for WINS server to respond.  Mark it dead. */
+                               wins_srv_died(wins_ip);
+                       } else {
+                               /* The name definately isn't in this
+                                  group of WINS servers. goto the next group  */
+                               break;
+                       }
                }
        }
 
+       wins_srv_tags_free(wins_tags);
        return False;
+
+success:
+       wins_srv_tags_free(wins_tags);
+       close(sock);
+       return True;
 }
 
 /********************************************************
index fc16db9e4998a5a3cec31c0c592b394f2e300b2a..91b6f8b19003c988fc805e1482d336c6e5ef3908 100644 (file)
@@ -155,131 +155,193 @@ name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->su
   remove_response_record(subrec, rrec);
 }
 
+
+/****************************************************************************
+ Deal with a timeout of a WINS registration request
+****************************************************************************/
+static void wins_registration_timeout(struct subnet_record *subrec,
+                                     struct response_record *rrec)
+{
+       struct userdata_struct *userdata = rrec->userdata;
+
+       DEBUG(2,("register_name_timeout_response: WINS server at address %s is not responding.\n", 
+                inet_ntoa(rrec->packet->ip)));
+
+       /* mark it temporarily dead */
+       wins_srv_died(rrec->packet->ip);
+
+       /* if we have some userdata then use that to work out what
+          wins server to try next */
+       if (userdata) {
+               const char *tag = (const char *)userdata->data;
+               struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+               struct nmb_name *nmbname = &sent_nmb->question.question_name;
+
+               /* and try the next wins server in our failover list */
+               rrec->packet->ip = wins_srv_ip_tag(tag);
+
+               /* also update the UNICODE subnet IPs */
+               subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->ip;
+
+               DEBUG(6,("Retrying register of name %s with WINS server %s using tag '%s'\n",
+                        nmb_namestr(nmbname), inet_ntoa(rrec->packet->ip), tag));
+       }
+
+       /* Keep trying to contact the WINS server periodically. This allows
+          us to work correctly if the WINS server is down temporarily when
+          we come up. */
+       
+       /* Reset the number of attempts to zero and double the interval between
+          retries. Max out at 5 minutes. */
+       rrec->repeat_count = 3;
+       rrec->repeat_interval *= 2;
+       if(rrec->repeat_interval > (5 * 60))
+               rrec->repeat_interval = (5 * 60);
+       rrec->repeat_time = time(NULL) + rrec->repeat_interval;
+       rrec->in_expiration_processing = False;
+       
+       DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n",
+                (int)rrec->repeat_interval));
+
+       /* notice that we don't remove the response record. This keeps
+          us trying to register with each of our failover wins
+          servers until we succeed */  
+}
+
+
 /****************************************************************************
  Deal with a timeout when registering one of our names.
 ****************************************************************************/
 
 static void register_name_timeout_response(struct subnet_record *subrec,
-                       struct response_record *rrec)
+                                          struct response_record *rrec)
 {
-  /*
-   * If we are registering unicast, then NOT getting a response is an
-   * error - we do not have the name. If we are registering broadcast,
-   * then we don't expect to get a response.
-   */
+       /*
+        * If we are registering unicast, then NOT getting a response is an
+        * error - we do not have the name. If we are registering broadcast,
+        * then we don't expect to get a response.
+        */
+
+       struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+       BOOL bcast = sent_nmb->header.nm_flags.bcast;
+       BOOL success = False;
+       struct nmb_name *question_name = &sent_nmb->question.question_name;
+       uint16 nb_flags = 0;
+       int ttl = 0;
+       struct in_addr registered_ip;
+       
+       if (bcast) {
+               if(rrec->num_msgs == 0) {
+                       /* Not receiving a message is success for broadcast registration. */
+                       success = True; 
+
+                       /* Pull the success values from the original request packet. */
+                       nb_flags = get_nb_flags(sent_nmb->additional->rdata);
+                       ttl = sent_nmb->additional->ttl;
+                       putip(&registered_ip,&sent_nmb->additional->rdata[2]);
+               }
+       } else {
+               /* Unicast - if no responses then it's an error. */
+               if(rrec->num_msgs == 0) {
+                       wins_registration_timeout(subrec, rrec);
+                       return;
+               }
 
-  struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
-  BOOL bcast = sent_nmb->header.nm_flags.bcast;
-  BOOL success = False;
-  struct nmb_name *question_name = &sent_nmb->question.question_name;
-  uint16 nb_flags = 0;
-  int ttl = 0;
-  struct in_addr registered_ip;
+               /* we got responses, but timed out?? bizarre. Treat it as failure. */
+       }
 
-  if(bcast)
-  {
-    if(rrec->num_msgs == 0)
-    {
-      /* Not receiving a message is success for broadcast registration. */
-      success = True; 
+       DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n",
+                success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name));
+       if(success) {
+               /* Enter the registered name into the subnet name database before calling
+                  the success function. */
+               standard_success_register(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
+               if( rrec->success_fn)
+                       (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
+       } else {
+               if( rrec->fail_fn)
+                       (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
+               /* Remove the name. */
+               standard_fail_register( subrec, rrec, question_name);
+       }
 
-      /* Pull the success values from the original request packet. */
-      nb_flags = get_nb_flags(sent_nmb->additional->rdata);
-      ttl = sent_nmb->additional->ttl;
-      putip(&registered_ip,&sent_nmb->additional->rdata[2]);
-    }
-  }
-  else
-  {
-    /* Unicast - if no responses then it's an error. */
-    if(rrec->num_msgs == 0)
-    {
-      DEBUG(2,("register_name_timeout_response: WINS server at address %s is not \
-responding.\n", inet_ntoa(rrec->packet->ip)));
-
-      /* mark it temporarily dead */
-      wins_srv_died(rrec->packet->ip);
-
-      /* and try the next wins server in our failover list */
-      rrec->packet->ip = wins_srv_ip();
-
-      /* also update the UNICODE subnet IPs */
-      subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->ip;
-
-      /* Keep trying to contact the WINS server periodically. This allows
-         us to work correctly if the WINS server is down temporarily when
-         we come up. */
-
-      /* Reset the number of attempts to zero and double the interval between
-         retries. Max out at 5 minutes. */
-      rrec->repeat_count = 3;
-      rrec->repeat_interval *= 2;
-      if(rrec->repeat_interval > (5 * 60))
-        rrec->repeat_interval = (5 * 60);
-      rrec->repeat_time = time(NULL) + rrec->repeat_interval;
-      rrec->in_expiration_processing = False;
-
-      DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n",
-              (int)rrec->repeat_interval));
-      return; /* Don't remove the response record. */
-    }
-  }
+       /* Ensure we don't retry. */
+       remove_response_record(subrec, rrec);
+}
 
-  DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n",
-        success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name));
-  if(success)
-  {
-    /* Enter the registered name into the subnet name database before calling
-       the success function. */
-    standard_success_register(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
-    if( rrec->success_fn)
-      (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
-  }
-  else
-  {
-    if( rrec->fail_fn)
-      (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
-    /* Remove the name. */
-    standard_fail_register( subrec, rrec, question_name);
-  }
 
-  /* Ensure we don't retry. */
-  remove_response_record(subrec, rrec);
+/****************************************************************************
+initiate one multi-homed name registration packet
+****************************************************************************/
+static void multihomed_register_one(struct nmb_name *nmbname,
+                                   uint16 nb_flags,
+                                   register_name_success_function success_fn,
+                                   register_name_fail_function fail_fn,
+                                   struct in_addr ip,
+                                   const char *tag)
+{
+       struct userdata_struct *userdata;
+       struct in_addr wins_ip = wins_srv_ip_tag(tag);
+
+       userdata = (struct userdata_struct *)malloc(sizeof(*userdata) + strlen(tag) + 1);
+       if (!userdata) {
+               DEBUG(0,("Failed to allocate userdata structure!\n"));
+               return;
+       }
+       ZERO_STRUCTP(userdata);
+       userdata->userdata_len = strlen(tag) + 1;
+       strlcpy(userdata->data, tag, userdata->userdata_len);   
+
+       DEBUG(6,("Registering name %s with WINS server %s using tag '%s'\n",
+                nmb_namestr(nmbname), inet_ntoa(wins_ip), tag));
+
+       if (queue_register_multihomed_name(unicast_subnet,
+                                          register_name_response,
+                                          register_name_timeout_response,
+                                          success_fn,
+                                          fail_fn,
+                                          userdata,
+                                          nmbname,
+                                          nb_flags,
+                                          ip,
+                                          wins_ip) == NULL) {
+               DEBUG(0,("multihomed_register_one: Failed to send packet trying to register name %s IP %s\n", 
+                        nmb_namestr(nmbname), inet_ntoa(ip)));         
+       }
 }
 
 /****************************************************************************
  Try and register one of our names on the unicast subnet - multihomed.
 ****************************************************************************/
-
 static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
                                       register_name_success_function success_fn,
                                       register_name_fail_function fail_fn)
 {
-  /*
-     If we are adding a group name, we just send multiple
-     register name packets to the WINS server (this is an
-     internet group name.
-
-     If we are adding a unique name, We need first to add 
-     our names to the unicast subnet namelist. This is 
-     because when a WINS server receives a multihomed 
-     registration request, the first thing it does is to 
-     send a name query to the registering machine, to see 
-     if it has put the name in it's local namelist.
-     We need the name there so the query response code in
-     nmbd_incomingrequests.c will find it.
-
-     We are adding this name prematurely (we don't really
-     have it yet), but as this is on the unicast subnet
-     only we will get away with this (only the WINS server
-     will ever query names from us on this subnet).
-   */
-
+       /*
+         If we are adding a group name, we just send multiple
+         register name packets to the WINS server (this is an
+         internet group name.
+
+         If we are adding a unique name, We need first to add 
+         our names to the unicast subnet namelist. This is 
+         because when a WINS server receives a multihomed 
+         registration request, the first thing it does is to 
+         send a name query to the registering machine, to see 
+         if it has put the name in it's local namelist.
+         We need the name there so the query response code in
+         nmbd_incomingrequests.c will find it.
+
+         We are adding this name prematurely (we don't really
+         have it yet), but as this is on the unicast subnet
+         only we will get away with this (only the WINS server
+         will ever query names from us on this subnet).
+       */
        int num_ips=0;
-       int i;
+       int i, t;
        struct in_addr *ip_list = NULL;
        struct subnet_record *subrec;
-       
+       char **wins_tags;
+
        for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
                num_ips++;
        
@@ -288,7 +350,7 @@ static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
                return True;
        }
 
-       forsubrec = FIRST_SUBNET, i = 0; 
+       for (subrec = FIRST_SUBNET, i = 0; 
             subrec;
             subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec), i++ ) {
                ip_list[i] = subrec->myip;
@@ -298,26 +360,20 @@ static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
                                  nb_flags, lp_max_ttl(), SELF_NAME,
                                  num_ips, ip_list);
 
-       /* Now try and register the name, num_ips times. On the last time use
-          the given success and fail functions. */
-       
-       for (i = 0; i < num_ips; i++) {
-               if (queue_register_multihomed_name( unicast_subnet,
-                                                   register_name_response,
-                                                   register_name_timeout_response,
-                                                   (i == num_ips - 1) ? success_fn : NULL,
-                                                   (i == num_ips - 1) ? fail_fn : NULL,
-                                                   NULL,
-                                                   nmbname,
-                                                   nb_flags,
-                                                   ip_list[i]) == NULL) {
-                       DEBUG(0,("multihomed_register_name: Failed to send packet trying to \
-register name %s IP %s\n", nmb_namestr(nmbname), inet_ntoa(ip_list[i]) ));
-                       
-                       SAFE_FREE(ip_list);
-                       return True;
+       /* get the list of wins tags - we try to register for each of them */
+       wins_tags = wins_srv_tags();
+
+       /* Now try and register the name, num_ips times for each wins tag. */
+       for (t=0; wins_tags[t]; t++) {
+               for (i = 0; i < num_ips; i++) {
+                       multihomed_register_one(nmbname, nb_flags,
+                                               success_fn, fail_fn,
+                                               ip_list[i],
+                                               wins_tags[t]);
                }
        }
+
+       wins_srv_tags_free(wins_tags);
        
        SAFE_FREE(ip_list);
        
index b5741caae09e20d7abd11ed120e649299479bc01..f0c8b755c9df9199e323e62473928278955cadaf 100644 (file)
@@ -519,64 +519,61 @@ struct response_record *queue_register_name( struct subnet_record *subrec,
 }
 
 /****************************************************************************
- Queue a multihomed register name packet to the broadcast address of a subnet.
+ Queue a multihomed register name packet to a given WINS server IP
 ****************************************************************************/
 
 struct response_record *queue_register_multihomed_name( struct subnet_record *subrec,
-                          response_function resp_fn,
-                          timeout_response_function timeout_fn,
-                          register_name_success_function success_fn,
-                          register_name_fail_function fail_fn,
-                          struct userdata_struct *userdata,
-                          struct nmb_name *nmbname,
-                          uint16 nb_flags,
-                          struct in_addr register_ip)
+                                                       response_function resp_fn,
+                                                       timeout_response_function timeout_fn,
+                                                       register_name_success_function success_fn,
+                                                       register_name_fail_function fail_fn,
+                                                       struct userdata_struct *userdata,
+                                                       struct nmb_name *nmbname,
+                                                       uint16 nb_flags,
+                                                       struct in_addr register_ip,
+                                                       struct in_addr wins_ip)
 {
-  struct packet_struct *p;
-  struct response_record *rrec;
-  BOOL ret;
-     
-  /* Sanity check. */
-  if(subrec != unicast_subnet)
-  {
-    DEBUG(0,("queue_register_multihomed_name: should only be done on \
+       struct packet_struct *p;
+       struct response_record *rrec;
+       BOOL ret;
+       
+       /* Sanity check. */
+       if(subrec != unicast_subnet) {
+               DEBUG(0,("queue_register_multihomed_name: should only be done on \
 unicast subnet. subnet is %s\n.", subrec->subnet_name ));
-    return NULL;
-  }
+               return NULL;
+       }
 
-  if(assert_check_subnet(subrec))
-    return NULL;
+       if(assert_check_subnet(subrec))
+               return NULL;
      
-  if(( p = create_and_init_netbios_packet(nmbname, False, True,
-                                         subrec->bcast_ip)) == NULL)
-    return NULL;
-
-  if (nb_flags & NB_GROUP)
-    ret = initiate_name_register_packet( p, nb_flags, &register_ip);
-  else
-    ret = initiate_multihomed_name_register_packet( p, nb_flags, &register_ip);
-
-  if(ret == False)
-  {  
-    p->locked = False;
-    free_packet(p);
-    return NULL;
-  }  
+       if ((p = create_and_init_netbios_packet(nmbname, False, True, wins_ip)) == NULL)
+               return NULL;
+
+       if (nb_flags & NB_GROUP)
+               ret = initiate_name_register_packet( p, nb_flags, &register_ip);
+       else
+               ret = initiate_multihomed_name_register_packet(p, nb_flags, &register_ip);
+
+       if (ret == False) {  
+               p->locked = False;
+               free_packet(p);
+               return NULL;
+       }  
   
-  if((rrec = make_response_record(subrec,    /* subnet record. */
-                p,                     /* packet we sent. */
-                resp_fn,               /* function to call on response. */
-                timeout_fn,            /* function to call on timeout. */
-                (success_function)success_fn,            /* function to call on operation success. */
-                (fail_function)fail_fn,               /* function to call on operation fail. */
-                userdata)) == NULL)
-  {  
-    p->locked = False;
-    free_packet(p);
-    return NULL;
-  }  
-  
-  return rrec;
+       if ((rrec = make_response_record(subrec,    /* subnet record. */
+                                        p,                     /* packet we sent. */
+                                        resp_fn,               /* function to call on response. */
+                                        timeout_fn,            /* function to call on timeout. */
+                                        (success_function)success_fn, /* function to call on operation success. */
+                                        (fail_function)fail_fn,       /* function to call on operation fail. */
+                                        userdata)) == NULL) {  
+               p->locked = False;
+               free_packet(p);
+               return NULL;
+       }  
+       
+       return rrec;
 }
 
 /****************************************************************************
index a8b4566ba0ef1d5091a5ed2d7a8f51dac5a42aef..75d04349e69e0672c5b4f480f1e7f30f4585e553 100644 (file)
@@ -92,20 +92,14 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count)
 
        *count = 0;
 
-       fd = wins_lookup_open_socket_in();
-       if (fd == -1)
-               return NULL;
-
-       p = wins_srv_ip();
-       if( !is_zero_ip(p) ) {
-               ret = name_query(fd,name,0x20,False,True, p, count, &flags);
-               goto out;
+       /* always try with wins first */
+       if (resolve_wins(name,0x20,&ret,count)) {
+               return ret;
        }
 
-       if (lp_wins_support()) {
-               /* we are our own WINS server */
-               ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count, &flags);
-               goto out;
+       fd = wins_lookup_open_socket_in();
+       if (fd == -1) {
+               return NULL;
        }
 
        /* uggh, we have to broadcast to each interface in turn */
@@ -113,12 +107,11 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count)
             j >= 0;
             j--) {
                struct in_addr *bcast = iface_n_bcast(j);
-               ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags);
+               ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags, NULL);
                if (ret) break;
        }
 
  out:
-
        close(fd);
        return ret;
 }
index 2ecdbf1c51559b341d70467be602d3e0866cde7d..8b629f113225b30416dd982e372018cad20c3e87 100644 (file)
@@ -115,7 +115,7 @@ static struct node_status *lookup_byaddr_backend(char *addr, int *count)
 
 static struct in_addr *lookup_byname_backend(const char *name, int *count)
 {
-       int fd;
+       int fd = -1;
        struct in_addr *ret = NULL;
        struct in_addr  p;
        int j, flags = 0;
@@ -126,33 +126,24 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count)
 
        *count = 0;
 
-       fd = wins_lookup_open_socket_in();
-       if (fd == -1)
-               return NULL;
-
-       p = wins_srv_ip();
-       if( !is_zero_ip(p) ) {
-               ret = name_query(fd,name,0x20,False,True, p, count, &flags);
-               goto out;
+       /* always try with wins first */
+       if (resolve_wins(name,0x20,&ret,count)) {
+               return ret;
        }
 
-       if (lp_wins_support()) {
-               /* we are our own WINS server */
-               ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count, &flags);
-               goto out;
+       fd = wins_lookup_open_socket_in();
+       if (fd == -1) {
+               return NULL;
        }
 
        /* uggh, we have to broadcast to each interface in turn */
-       for (j=iface_count() - 1;
-            j >= 0;
-            j--) {
+       for (j=iface_count() - 1;j >= 0;j--) {
                struct in_addr *bcast = iface_n_bcast(j);
-               ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags);
+               ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags, NULL);
                if (ret) break;
        }
 
- out:
-
+out:
        close(fd);
        return ret;
 }
index 2373beb0c91d51bcfec2b101df5007ad0e04505d..8e4f5aab0372e936d4d136c7b7d7652f1277c79d 100644 (file)
@@ -159,7 +159,7 @@ static BOOL query_one(char *lookup, unsigned int lookup_type)
                d_printf("querying %s on %s\n", lookup, inet_ntoa(bcast_addr));
                ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast,
                                     use_bcast?True:recursion_desired,
-                                    bcast_addr,&count, &flags);
+                                    bcast_addr,&count, &flags, NULL);
        } else {
                struct in_addr *bcast;
                for (j=iface_count() - 1;
@@ -171,7 +171,7 @@ static BOOL query_one(char *lookup, unsigned int lookup_type)
                        ip_list = name_query(ServerFD,lookup,lookup_type,
                                             use_bcast,
                                             use_bcast?True:recursion_desired,
-                                            *bcast,&count, &flags);
+                                            *bcast,&count, &flags, NULL);
                }
        }
 
index fa550c61b61f69e93859b79da4f00d7d074de475..e822474aab4187c59c6c7fcea50d9949c6c0c210 100644 (file)
@@ -34,7 +34,7 @@ BOOL nmbd_running(void)
                                 interpret_addr("127.0.0.1"), True)) != -1) {
                if ((ip_list = name_query(fd, "__SAMBA__", 0, 
                                          True, True, loopback_ip,
-                                         &count, &flags)) != NULL) {
+                                         &count, &flags, NULL)) != NULL) {
                        SAFE_FREE(ip_list);
                        close(fd);
                        return True;