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;
/* 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);
if (*d == NULL) return NULL;
+ DEBUG(4,("subnet %s ", inet_ntoa((*d)->bcast_ip)));
+
/* now try DNS lookup. */
if (!n)
{
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;
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;
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)
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;
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;
}
}
/*******************************************************************
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;
/* 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;
for (work = d->workgrouplist; work; work = work->next)
{
- remove_old_servers(work, t);
+ remove_old_servers(work, t, False);
}
}
}
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,"/");
DEBUG(3,("Wrote browse list %s\n",fname));
}
-
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;
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;
}
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);
+ }
}
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)
{
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);
/* 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 );
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;
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);
}
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;
}
}
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;
extern struct in_addr ipzero;
extern struct in_addr ipgrp;
-extern int num_response_packets;
-
/***************************************************************************
deals with an entry before it dies
******************************************************************/
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)
{
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 */
continue;
}
}
- nextn = n->next;
}
+ }
}
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,
/****************************************************************************
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)
{
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)
{
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);
}
}
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);
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);
}
}
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 */
n->refresh_time += name_refresh_time;
}
}
+
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());
}