From 429f1f975e2936f2e220b656c51c211d48d47047 Mon Sep 17 00:00:00 2001 From: Samba Release Account Date: Tue, 9 Jul 1996 18:01:46 +0000 Subject: [PATCH] sorted out various timer delay bugs: nameannounce.c nameserv.c 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 --- source/nameannounce.c | 3 +- source/namedbname.c | 16 ++++--- source/namedbresp.c | 11 +++-- source/namedbserver.c | 10 +++-- source/namedbsubnet.c | 15 ++++--- source/namedbwork.c | 18 +++++--- source/nameelect.c | 50 +++++++++++---------- source/namepacket.c | 7 +-- source/nameresp.c | 25 +++++++---- source/nameserv.c | 121 +++++++++++++++++++++++++++++++++----------------- source/namework.c | 2 +- 11 files changed, 172 insertions(+), 106 deletions(-) diff --git a/source/nameannounce.c b/source/nameannounce.c index e4ef868bb6f..63dfc1555b0 100644 --- a/source/nameannounce.c +++ b/source/nameannounce.c @@ -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; diff --git a/source/namedbname.c b/source/namedbname.c index 3bff6dae7a1..82b19077f9d 100644 --- a/source/namedbname.c +++ b/source/namedbname.c @@ -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; diff --git a/source/namedbresp.c b/source/namedbresp.c index a9abc5d9b54..c453d9bbec2 100644 --- a/source/namedbresp.c +++ b/source/namedbresp.c @@ -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; } } diff --git a/source/namedbserver.c b/source/namedbserver.c index 74c7a96baa9..de0cda79cce 100644 --- a/source/namedbserver.c +++ b/source/namedbserver.c @@ -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); } } } diff --git a/source/namedbsubnet.c b/source/namedbsubnet.c index 5ede7b0b814..6b187b21bb8 100644 --- a/source/namedbsubnet.c +++ b/source/namedbsubnet.c @@ -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)); } - diff --git a/source/namedbwork.c b/source/namedbwork.c index 7937aa4512c..88f66a7b156 100644 --- a/source/namedbwork.c +++ b/source/namedbwork.c @@ -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; } diff --git a/source/nameelect.c b/source/nameelect.c index 386e7b0bab3..e115b0d8818 100644 --- a/source/nameelect.c +++ b/source/nameelect.c @@ -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; } } diff --git a/source/namepacket.c b/source/namepacket.c index 38b8ed06535..5afdb8af0ed 100644 --- a/source/namepacket.c +++ b/source/namepacket.c @@ -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; diff --git a/source/nameresp.c b/source/nameresp.c index 0b38c4bb9a6..3a9d46bf9d8 100644 --- a/source/nameresp.c +++ b/source/nameresp.c @@ -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, diff --git a/source/nameserv.c b/source/nameserv.c index 056c943cd6f..9fc578d009f 100644 --- a/source/nameserv.c +++ b/source/nameserv.c @@ -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; } } + diff --git a/source/namework.c b/source/namework.c index d6a94f17aa4..85a07a7dc94 100644 --- a/source/namework.c +++ b/source/namework.c @@ -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()); } -- 2.11.4.GIT