sorted out various timer delay bugs: nameannounce.c nameserv.c
authorSamba Release Account <samba-bugs@samba.org>
Tue, 9 Jul 1996 18:01:46 +0000 (18:01 +0000)
committerSamba Release Account <samba-bugs@samba.org>
Tue, 9 Jul 1996 18:01:46 +0000 (18:01 +0000)
namedbname.c:search_for_name() wasn't looking for 0x1b as well as
0x0 and 0x20 name types.

reduced number of retransmissions of packets from 4 to 3 times.

added code that ensures remote lmhosts entries don't get deleted when
a master browser cannot be found on a remote subnet. stopped forcing
an election on remote subnets if a master browser cannot be found.

stopped browse list and wins list from being written out too frequently.

only add samba's names to local interfaces.

add 0x1c name if we are a domain logon machine (needs more exploration).

why bother reloading services when receiving a SIGTERM?

sort out add_my_name_entry() and remove_name_entry() to deal with
broadcast, samba as a WINS and samba using a WINS. properly.

added extra debug information to help with expected response queue code.
updated debug comments in become_master().

altered dump_names() DEBUG format. it looks prettier.
altered wins.dat format to match DEBUG format.

lkcl
(This used to be commit 429f1f975e2936f2e220b656c51c211d48d47047)

source3/nameannounce.c
source3/namedbname.c
source3/namedbresp.c
source3/namedbserver.c
source3/namedbsubnet.c
source3/namedbwork.c
source3/nameelect.c
source3/namepacket.c
source3/nameresp.c
source3/nameserv.c
source3/namework.c

index e4ef868bb6f4362e693d4d65de410122c1402369..63dfc1555b0428c90494ec830d37c9ef9e74922c 100644 (file)
@@ -421,7 +421,8 @@ void announce_master(void)
   time_t t = time(NULL);
   BOOL am_master = False; /* are we a master of some sort? :-) */
 
-  if (last && (t-last < CHECK_TIME_MST_ANNOUNCE * 60))
+  if (!last) last = t;
+  if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
        return;
 
   last = t;
index 3bff6dae7a109dc5200acab87eeb6f7680e25469..82b19077f9d1d1eb66f20bc2d3f9a2d03359a61f 100644 (file)
@@ -222,21 +222,21 @@ void dump_names(void)
       /* XXXX i have little imagination as to how to output nb_flags as
          anything other than as a hexadecimal number :-) */
 
-        sprintf(data, "%s#%02x %s %ld %2x",
+        sprintf(data, "%s#%02x %s %2x %ld",
               n->name.name,n->name.name_type, /* XXXX ignore the scope for now */
               inet_ntoa(n->ip),
-              n->death_time,
-              n->nb_flags);
+              n->nb_flags,
+              n->death_time);
            fprintf(f, "%s\n", data);
       }
 
          DEBUG(3,("%15s ", inet_ntoa(d->bcast_ip)));
          DEBUG(3,("%15s ", inet_ntoa(d->mask_ip)));
-      DEBUG(3,("%s %15s TTL=%15d NBFLAGS=%2x\n",
+      DEBUG(3,("%-19s %15s NB=%2x TTL=%ld \n",
               namestr(&n->name),
               inet_ntoa(n->ip),
-           n->death_time?n->death_time-t:0,
-              n->nb_flags));
+              n->nb_flags,
+           n->death_time?n->death_time-t:0));
     }
 
   fclose(f);
@@ -490,6 +490,8 @@ struct name_record *search_for_name(struct subnet_record **d,
   
   if (*d == NULL) return NULL;
 
+  DEBUG(4,("subnet %s ", inet_ntoa((*d)->bcast_ip)));
+
   /* now try DNS lookup. */
   if (!n)
     {
@@ -497,7 +499,7 @@ struct name_record *search_for_name(struct subnet_record **d,
       unsigned long a;
       
       /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
-      if (!dns_type)
+      if (!dns_type && name_type != 0x1b)
        {
          DEBUG(3,("types 0x20 0x1b 0x0 only: name not found\n"));
          return NULL;
index a9abc5d9b5415f0473cd6c7d1605e26693bf73ef..c453d9bbec2fbd64fe4b9f83b133c072019b8a80 100644 (file)
@@ -50,6 +50,9 @@ void add_response_record(struct subnet_record *d,
 
   num_response_packets++; /* count of total number of packets still around */
 
+  DEBUG(4,("adding response record id:%d num_records:%d\n",
+                   n->response_id, num_response_packets));
+
   if (!d->responselist)
     {
       d->responselist = n;
@@ -89,7 +92,7 @@ void remove_response_record(struct subnet_record *d,
   create a name query response record
   **************************************************************************/
 struct response_record *make_response_queue_record(enum state_type state,
-                               int id,int fd,
+                               int id,uint16 fd,
                                int quest_type, char *name,int type, int nb_flags, time_t ttl,
                                BOOL bcast,BOOL recurse,
                                struct in_addr send_ip, struct in_addr reply_to_ip)
@@ -114,8 +117,8 @@ struct response_record *make_response_queue_record(enum state_type state,
   n->reply_to_ip = reply_to_ip;
 
   n->repeat_interval = 1; /* XXXX should be in ms */
-  n->repeat_count = 4;
-  n->repeat_time = time(NULL) + n->repeat_interval;
+  n->repeat_count = 3; /* 3 retries */
+  n->repeat_time = time(NULL) + n->repeat_interval; /* initial retry time */
 
   n->num_msgs = 0;
 
@@ -138,6 +141,8 @@ struct response_record *find_response_record(struct subnet_record **d,
     for (n = (*d)->responselist; n; n = n->next)
     {
       if (n->response_id == id) {
+         DEBUG(4, ("found response record on %s: %d\n",
+                                       inet_ntoa((*d)->bcast_ip), id));
          return n;
       }
     }
index 74c7a96baa9b56fa82cd0f8aed02959a6cd3a59c..de0cda79cce998f74f8184ca256705220e6f15d7 100644 (file)
@@ -46,9 +46,11 @@ extern BOOL updatedlists;
 
 /*******************************************************************
   expire old servers in the serverlist
-  time of -1 indicates everybody dies
+  time of -1 indicates everybody dies except those with time of 0
+  remove_all_servers indicates everybody dies.
   ******************************************************************/
-void remove_old_servers(struct work_record *work, time_t t)
+void remove_old_servers(struct work_record *work, time_t t,
+                                       BOOL remove_all)
 {
   struct server_record *s;
   struct server_record *nexts;
@@ -56,7 +58,7 @@ void remove_old_servers(struct work_record *work, time_t t)
   /* expire old entries in the serverlist */
   for (s = work->serverlist; s; s = nexts)
     {
-      if (t == -1 || (s->death_time && s->death_time < t))
+      if (remove_all || (s->death_time && (t == -1 || s->death_time < t)))
        {
          DEBUG(3,("Removing dead server %s\n",s->serv.name));
          updatedlists = True;
@@ -195,7 +197,7 @@ void expire_servers(time_t t)
       
       for (work = d->workgrouplist; work; work = work->next)
        {
-         remove_old_servers(work, t);
+         remove_old_servers(work, t, False);
        }
     }
 }
index 5ede7b0b81475b328f3c8b4114b2bdee7d2bcee9..6b187b21bb8a10db9f01ff194b38a2907046dd28 100644 (file)
@@ -272,18 +272,22 @@ struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
 void write_browse_list(void)
 {
   struct subnet_record *d;
-  
   pstring fname,fnamenew;
   FILE *f;
+
+  static time_t lasttime = 0;
+  time_t t = time(NULL);
+
+  if (!lasttime) lasttime = t;
+  if (!updatedlists || t - lasttime < 5) return;
   
-  if (!updatedlists) return;
+  lasttime = t;
+  updatedlists = False;
+  updatecount++;
   
   dump_names();
   dump_workgroups();
   
-  updatedlists = False;
-  updatecount++;
-  
   strcpy(fname,lp_lockdir());
   trim_string(fname,NULL,"/");
   strcat(fname,"/");
@@ -337,4 +341,3 @@ void write_browse_list(void)
   DEBUG(3,("Wrote browse list %s\n",fname));
 }
 
-
index 7937aa4512cbd3d775c9e712f9764af412ace79b..88f66a7b156e7946b2de293056d0155ed708a214 100644 (file)
@@ -134,7 +134,8 @@ static struct work_record *make_workgroup(char *name)
   remove workgroups
   ******************************************************************/
 struct work_record *remove_workgroup(struct subnet_record *d, 
-                                    struct work_record *work)
+                                    struct work_record *work,
+                                        BOOL remove_all_servers)
 {
   struct work_record *ret_work = NULL;
   
@@ -142,16 +143,19 @@ struct work_record *remove_workgroup(struct subnet_record *d,
   
   DEBUG(3,("Removing old workgroup %s\n", work->work_group));
   
-  remove_old_servers(work, -1);
-  
   ret_work = work->next;
+
+  remove_old_servers(work, -1, remove_all_servers);
   
-  if (work->prev) work->prev->next = work->next;
-  if (work->next) work->next->prev = work->prev;
+  if (!work->serverlist)
+  {
+    if (work->prev) work->prev->next = work->next;
+    if (work->next) work->next->prev = work->prev;
   
-  if (d->workgrouplist == work) d->workgrouplist = work->next; 
+    if (d->workgrouplist == work) d->workgrouplist = work->next; 
   
-  free(work);
+    free(work);
+  }
   
   return ret_work;
 }
index 386e7b0bab3c75d381e038273149cff0d7e9ca01..e115b0d88185d7ae138f0f9bb8d3df6a4bb53443 100644 (file)
@@ -96,31 +96,32 @@ void browser_gone(char *work_name, struct in_addr ip)
   struct subnet_record *d = find_subnet(ip);
   struct work_record *work = find_workgroupstruct(d, work_name, False);
 
+  /* i don't know about this workgroup, therefore i don't care */
   if (!work || !d) return;
-
-  if (strequal(work->work_group, lp_workgroup()) &&
-      ismybcast(d->bcast_ip))
-    {
+  if (strequal(work->work_group, lp_workgroup()) && d->my_interface)
+  {
 
       DEBUG(2,("Forcing election on %s %s\n",
               work->work_group,inet_ntoa(d->bcast_ip)));
 
       /* we can attempt to become master browser */
       work->needelection = True;
-    }
+  }
   else
-    {
-      /* XXXX note: this will delete entries that have been added in by
-        lmhosts as well. a flag to ensure that these are not deleted may
-        be considered */
-      
-      /* workgroup with no master browser is not the default workgroup:
-        it's also not on our subnet. therefore delete it: it can be
-        recreated dynamically */
-      
-      send_election(d, work->work_group, 0, 0, myname);
-      remove_workgroup(d, work);      
-    }
+  {
+     /* local interfaces: force an election */
+     if (d->my_interface)
+       send_election(d, work->work_group, 0, 0, myname);
+
+     /* only removes workgroup completely on a local interface or
+        if there are no server entries on the remote interface.
+        (persistent lmhost entries on a remote interface will stop
+        the workgroup being removed. persistent lmhosts entries on
+        a local interface _will_ be removed).
+      */
+     remove_workgroup(d, work, d->my_interface);      
+  }
 }
 
 
@@ -247,7 +248,8 @@ void become_master(struct subnet_record *d, struct work_record *work)
 
   if (!work) return;
   
-  DEBUG(2,("Becoming master for %s (stage %d)",work->work_group,work->state));
+  DEBUG(2,("Becoming master for %s (currently at stage %d)\n",
+                                       work->work_group,work->state));
   
   switch (work->state)
   {
@@ -261,7 +263,7 @@ void become_master(struct subnet_record *d, struct work_record *work)
       work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
       add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
 
-      DEBUG(2,("first stage: register ^1^2__MSBROWSE__^2^1\n"));
+      DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n"));
 
       /* add special browser name */
       add_my_name_entry(d,MSBROWSE        ,0x01,NB_ACTIVE|NB_GROUP);
@@ -275,7 +277,7 @@ void become_master(struct subnet_record *d, struct work_record *work)
       /* add server entry on successful registration of MSBROWSE */
       add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
 
-      DEBUG(2,("second stage: register as master browser\n"));
+      DEBUG(3,("go to second stage: register as master browser\n"));
 
       /* add master name */
       add_my_name_entry(d,work->work_group,0x1d,NB_ACTIVE         );
@@ -298,13 +300,13 @@ void become_master(struct subnet_record *d, struct work_record *work)
 
       if (lp_domain_master())
       {
-        DEBUG(2,("third stage: register as domain master\n"));
+        DEBUG(3,("third stage: register as domain master\n"));
         /* add domain master name */
         add_my_name_entry(d,work->work_group,0x1b,NB_ACTIVE         );
       }
       else
       {
-        DEBUG(2,("samba not configured as a domain master: no third stage.\n"));
+        DEBUG(3,("samba not configured as a domain master: no third stage.\n"));
       }
   
       break;
@@ -323,7 +325,7 @@ void become_master(struct subnet_record *d, struct work_record *work)
              work->ServerType |= SV_TYPE_DOMAIN_CTRL;
              work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
            }
-        DEBUG(2,("fourth stage: samba is now a domain master.\n"));
+        DEBUG(3,("fourth stage: samba is now a domain master.\n"));
         add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
       }
   
@@ -332,7 +334,7 @@ void become_master(struct subnet_record *d, struct work_record *work)
     case MST_DOMAIN:
     {
       /* nothing else to become, at the moment: we are top-dog. */
-      DEBUG(2,("fifth stage: there isn't one yet!\n"));
+      DEBUG(3,("fifth stage: there isn't one yet!\n"));
       break;
     }
   }
index 38b8ed06535b740bed92824542facba64f9f439d..5afdb8af0eda8545a8feaee4d4f1bb324c0c46eb 100644 (file)
@@ -81,9 +81,10 @@ void initiate_netbios_packet(uint16 *id,
 
   bzero((char *)&p,sizeof(p));
 
-  update_name_trn_id();
-
-  if (*id == 0xffff) *id = name_trn_id; /* allow resending with same id */
+  if (*id == 0xffff) {
+    update_name_trn_id();
+    *id = name_trn_id; /* allow resending with same id */
+  }
 
   nmb->header.name_trn_id = *id;
   nmb->header.opcode = opcode;
index 0b38c4bb9a66ae68a0ee42a2efcb1ee3b15ed2f1..3a9d46bf9d8ae163a51dc004f4de3a0ec6d5e442 100644 (file)
@@ -35,8 +35,6 @@ extern pstring scope;
 extern struct in_addr ipzero;
 extern struct in_addr ipgrp;
 
-extern int num_response_packets;
-
 
 /***************************************************************************
   deals with an entry before it dies
@@ -174,14 +172,17 @@ static void dead_netbios_entry(struct subnet_record *d,
   ******************************************************************/
 void expire_netbios_response_entries()
 {
-  struct response_record *n;
-  struct response_record *nextn;
   struct subnet_record *d;
 
   for (d = subnetlist; d; d = d->next)
-   for (n = d->responselist; n; n = nextn)
+  {
+    struct response_record *n, *nextn;
+
+    for (n = d->responselist; n; n = nextn)
     {
-      if (n->repeat_time < time(NULL))
+         nextn = n->next;
+
+      if (n->repeat_time <= time(NULL))
          {
                  if (n->repeat_count > 0)
                  {
@@ -192,10 +193,13 @@ void expire_netbios_response_entries()
 
             n->repeat_time += n->repeat_interval; /* XXXX ms needed */
             n->repeat_count--;
+
                  }
                  else
                  {
-                         nextn = n->next;
+              DEBUG(4,("timeout response %d for %s %s\n",
+                                               n->response_id, namestr(&n->name),
+                        inet_ntoa(n->send_ip)));
 
                          dead_netbios_entry    (d,n); /* process the non-response */
               remove_response_record(d,n); /* remove the non-response */
@@ -203,8 +207,8 @@ void expire_netbios_response_entries()
                          continue;
                   }
          }
-         nextn = n->next;
     }
+  }
 }
 
 
@@ -274,7 +278,10 @@ struct response_record *queue_netbios_packet(struct subnet_record *d,
   initiate_netbios_packet(&id, fd, quest_type, name, name_type,
                                      nb_flags, bcast, recurse, send_ip);
 
-  if (id == 0xffff) return NULL;
+  if (id == 0xffff) {
+    DEBUG(4,("did not initiate netbios packet: %s\n", inet_ntoa(send_ip)));
+    return NULL;
+  }
   
   if ((n = make_response_queue_record(state,id,fd,
                                                quest_type,name,name_type,nb_flags,ttl,
index 056c943cd6fed86c18542aef8ab3899794382d33..9fc578d009f5cc396ec89d6c0c4f765e1d16e3f9 100644 (file)
@@ -45,6 +45,10 @@ extern struct subnet_record *subnetlist;
 
 /****************************************************************************
   remove an entry from the name list
+
+  note: the name will _always_ be removed: it's just a matter of when.
+  XXXX at present, the name is removed _even_ if a WINS server says keep it.
+
   ****************************************************************************/
 void remove_name_entry(struct subnet_record *d, char *name,int type)
 {
@@ -52,43 +56,62 @@ void remove_name_entry(struct subnet_record *d, char *name,int type)
       a de-registration packet to the local subnet before removing the
       name from its local-subnet name database. */
 
-  if (lp_wins_support())
+  struct name_record n;
+  struct name_record *n2=NULL;
+      
+  make_nmb_name(&n.name,name,type,scope);
+
+  if ((n2 = find_name_search(&d, &n.name, FIND_SELF, ipzero)))
+  {
+    /* check name isn't already being de-registered */
+    if (NAME_DEREG(n2->nb_flags))
+      return;
+
+    /* mark the name as in the process of deletion. */
+    n2->nb_flags &= NB_DEREG;
+  }
+
+  if (ip_equal(d->bcast_ip, ipgrp))
+  {
+    if (lp_wins_support())
     {
-      /* we are a WINS server. */
-      /* XXXX assume that if we are a WINS server that we are therefore
-         not pointing to another WINS server as well. this may later NOT
-         actually be true */
-      remove_netbios_name(d,name,type,SELF,ipzero);
+        /* we are a WINS server. */
+        /* XXXX assume that if we are a WINS server that we are therefore
+           not pointing to another WINS server as well. this may later NOT
+           actually be true
+         */
+        remove_netbios_name(d,name,type,SELF,ipzero);
     }
-  else
+    else
     {
       /* not a WINS server: cannot just remove our own names: we have to
-         ask permission from the WINS server, or if no reply is received,
-                _then_ we can remove the name */
-
-         struct name_record n;
-         struct name_record *n2=NULL;
-      
-      make_nmb_name(&n.name,name,type,scope);
+         release them on the network first. ask permission from the WINS
+         server, or if no reply is received, then we can remove the name */
 
-      if ((n2 = find_name_search(&d, &n.name, FIND_SELF, ipzero)))
-      {
-        /* check name isn't already being de-registered */
-               if (NAME_DEREG(n2->nb_flags))
-          return;
+        queue_netbios_pkt_wins(d,ClientNMB,NMB_REL,NAME_RELEASE,
+                 name, type, 0, 0,
+                 False, True, ipzero, ipzero);
+    }
+  }
+  else
+  {
+     /* local interface: cannot just remove our own names: we have to
+        release them on the network first. once no reply is received,
+        then we can remove the name. */
 
-               /* mark the name as in the process of deletion. */
-         n2->nb_flags &= NB_DEREG;
-      }
-      queue_netbios_pkt_wins(d,ClientNMB,NMB_REL,NAME_RELEASE,
+     queue_netbios_packet(d,ClientNMB,NMB_REL,NAME_RELEASE,
                             name, type, 0, 0,
-                            False, True, ipzero, ipzero);
-    }
+                            True, True, d->bcast_ip, d->bcast_ip);
+  }
 }
 
 
 /****************************************************************************
   add an entry to the name list
+  
+  big note: our name will _always_ be added (if there are no objections).
+  it's just a matter of when this will be done (e.g after a time-out).
+
   ****************************************************************************/
 void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags)
 {
@@ -104,28 +127,38 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags)
   if (find_name(d->namelist, &n, SELF, ipzero))
        re_reg = True;
 
-  /* always add our own entries */
-  /* a time-to-live allows us to refresh this name with the WINS server. */
-  add_netbios_entry(d,name,type,
-                               nb_flags,GET_TTL(0),
-                               SELF,ipzero,False,lp_wins_support());
-
   /* XXXX BUG: if samba is offering WINS support, it should still add the
      name entry to a local-subnet name database. see rfc1001.txt 15.1.1 p28
      regarding the point about M-nodes. */
 
-  if (!lp_wins_support())
+  if (ip_equal(d->bcast_ip, ipgrp))
   {
-    /* samba isn't supporting WINS itself: register the name using broadcast
-       or with another WINS server.
-       XXXX note: we may support WINS and also know about other WINS servers
-       in the future.
-     */
-      
-    queue_netbios_pkt_wins(d,ClientNMB,
+    if (lp_wins_support())
+    {
+      /* we are a WINS server. */
+      /* XXXX assume that if we are a WINS server that we are therefore
+         not pointing to another WINS server as well. this may later NOT
+         actually be true
+       */
+
+      add_netbios_entry(d,name,type,nb_flags,0,
+                               SELF,ipzero,False,lp_wins_support());
+    }
+    else
+    {
+      /* a time-to-live allows us to refresh this name with the WINS server. */
+         queue_netbios_pkt_wins(d,ClientNMB,
                                 re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
                             name, type, nb_flags, GET_TTL(0),
                             False, True, ipzero, ipzero);
+    }
+  }
+  else
+  {
+       queue_netbios_packet(d,ClientNMB,
+                                re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
+                            name, type, nb_flags, GET_TTL(0),
+                            True, True, d->bcast_ip, d->bcast_ip);
   }
 }
 
@@ -148,6 +181,8 @@ void add_my_names(void)
 
   for (d = subnetlist; d; d = d->next)
   {
+    if (!d->my_interface) continue;
+
     /* these names need to be refreshed with the WINS server */
        add_my_name_entry(d, myname,0x20,NB_ACTIVE);
        add_my_name_entry(d, myname,0x03,NB_ACTIVE);
@@ -160,8 +195,8 @@ void add_my_names(void)
        add_netbios_entry(d,"__SAMBA__",0x20,NB_ACTIVE,0,SELF,ip,False,wins);
        add_netbios_entry(d,"__SAMBA__",0x00,NB_ACTIVE,0,SELF,ip,False,wins);
 
-    if (wins) {
-       /* the 0x1c name gets added by any WINS server it seems */
+    if (lp_domain_logons() && lp_domain_master()) {
+       /* XXXX the 0x1c is apparently something to do with domain logons */
          add_my_name_entry(d, my_workgroup(),0x1c,NB_ACTIVE|NB_GROUP);
     }
   }
@@ -246,8 +281,11 @@ void query_refresh_names(void)
 
        if (!d) return;
 
+    if (!lasttime) lasttime = t;
        if (t - lasttime < NAME_POLL_INTERVAL) return;
 
+    lasttime = time(NULL);
+
        for (n = d->namelist; n; n = n->next)
        {
                /* only do unique, registered names */
@@ -277,3 +315,4 @@ void query_refresh_names(void)
                n->refresh_time += name_refresh_time;
        }
 }
+
index d6a94f17aa4ee07ccc97b01b18f036c5188fed6c..85a07a7dc94f39e5bfe1ef4a1fd3f492da9b3781 100644 (file)
@@ -622,7 +622,7 @@ static void process_reset_browser(struct packet_struct *p,char *buf)
       for (d = subnetlist; d; d = d->next)
        {
          struct work_record *work;
-         for (work=d->workgrouplist;work;work=remove_workgroup(d,work));
+         for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
        }
       add_my_subnets(lp_workgroup());
     }