sorted out various timer delay bugs: nameannounce.c nameserv.c
[Samba.git] / source / nameannounce.c
blob63dfc1555b0428c90494ec830d37c9ef9e74922c
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1995
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 Revision History:
23 14 jan 96: lkcl@pires.co.uk
24 added multiple workgroup domain master support
28 #include "includes.h"
30 #define TEST_CODE
32 extern int DEBUGLEVEL;
33 extern BOOL CanRecurse;
35 extern struct in_addr ipzero;
37 extern pstring myname;
39 extern int ClientDGRAM;
40 extern int ClientNMB;
42 /* this is our domain/workgroup/server database */
43 extern struct subnet_record *subnetlist;
45 /* machine comment for host announcements */
46 extern pstring ServerComment;
48 extern int updatecount;
49 extern int workgroup_count;
51 /* what server type are we currently */
53 /****************************************************************************
54 send a announce request to the local net
55 **************************************************************************/
56 void announce_request(struct work_record *work, struct in_addr ip)
58 pstring outbuf;
59 char *p;
61 if (!work) return;
63 work->needannounce = True;
65 DEBUG(2,("sending announce request to %s for workgroup %s\n",
66 inet_ntoa(ip),work->work_group));
68 bzero(outbuf,sizeof(outbuf));
69 p = outbuf;
70 CVAL(p,0) = ANN_AnnouncementRequest;
71 p++;
73 CVAL(p,0) = work->token; /* (local) unique workgroup token id */
74 p++;
75 StrnCpy(p,myname,16);
76 strupper(p);
77 p = skip_string(p,1);
79 /* XXXX note: if we sent the announcement request to 0x1d instead
80 of 0x1e, then we could get the master browser to announce to
81 us instead of the members of the workgroup. wha-hey! */
83 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
84 myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
88 /****************************************************************************
89 request an announcement
90 **************************************************************************/
91 void do_announce_request(char *info, char *to_name, int announce_type,
92 int from,
93 int to, struct in_addr dest_ip)
95 pstring outbuf;
96 char *p;
98 bzero(outbuf,sizeof(outbuf));
99 p = outbuf;
100 CVAL(p,0) = announce_type;
101 p++;
103 DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
104 announce_type, info, inet_ntoa(dest_ip),to_name,to));
106 StrnCpy(p,info,16);
107 strupper(p);
108 p = skip_string(p,1);
110 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
111 myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
115 /****************************************************************************
116 find a server responsible for a workgroup, and sync browse lists
117 control ends up back here via response_name_query.
118 **************************************************************************/
119 void sync_server(enum state_type state, char *serv_name, char *work_name,
120 int name_type,
121 struct in_addr ip)
123 add_browser_entry(serv_name, name_type, work_name, 0, ip);
125 if (state == NAME_STATUS_PDC_SRV_CHK)
127 /* announce ourselves as a master browser to serv_name */
128 do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
129 0x20, 0, ip);
134 /****************************************************************************
135 construct a host announcement unicast
137 this function should not be used heavily, and only when we are _not_
138 a master browser and _not_ a primary domain controller.
140 **************************************************************************/
141 void announce_backup(void)
143 static time_t lastrun = 0;
144 time_t t = time(NULL);
145 pstring outbuf;
146 char *p;
147 struct subnet_record *d1;
148 int tok;
150 if (!lastrun) lastrun = t;
151 if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60)
152 return;
153 lastrun = t;
155 for (tok = 0; tok <= workgroup_count; tok++)
157 for (d1 = subnetlist; d1; d1 = d1->next)
159 struct work_record *work;
160 struct subnet_record *d;
162 /* search for unique workgroup: only the name matters */
163 for (work = d1->workgrouplist;
164 work && (tok != work->token);
165 work = work->next);
167 if (!work) continue;
169 if (AM_MASTER(work) && AM_DOMCTL(work)) continue;
171 /* found one: announce it across all domains */
172 for (d = subnetlist; d; d = d->next)
175 DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
176 inet_ntoa(d->bcast_ip),work->work_group,
177 work->token));
179 bzero(outbuf,sizeof(outbuf));
180 p = outbuf;
181 CVAL(p,0) = ANN_GetBackupListReq;
182 p++;
184 CVAL(p,0) = 1; /* count? */
185 SIVAL(p,1,work->token); /* workgroup unique key index */
186 p += 5;
187 p++;
189 if (!AM_DOMCTL(work))
191 /* only ask for a list of backup domain controllers
192 if we are not a domain controller ourselves */
194 send_mailslot_reply(BROWSE_MAILSLOT,
195 ClientDGRAM,outbuf,
196 PTR_DIFF(p,outbuf),
197 myname, work->work_group,
198 0x0,0x1b,d->bcast_ip,
199 *iface_ip(d->bcast_ip));
202 if (!AM_MASTER(work))
204 /* only ask for a list of master browsers if we
205 are not a master browser ourselves */
207 send_mailslot_reply(BROWSE_MAILSLOT,
208 ClientDGRAM,outbuf,
209 PTR_DIFF(p,outbuf),
210 myname, work->work_group,
211 0x0,0x1b,d->bcast_ip,
212 *iface_ip(d->bcast_ip));
220 /****************************************************************************
221 send a host announcement packet
222 **************************************************************************/
223 static void do_announce_host(int command,
224 char *from_name, int from_type, struct in_addr from_ip,
225 char *to_name , int to_type , struct in_addr to_ip,
226 time_t announce_interval,
227 char *server_name, int server_type, char *server_comment)
229 pstring outbuf;
230 char *p;
232 bzero(outbuf,sizeof(outbuf));
233 p = outbuf+1;
235 /* command type */
236 CVAL(outbuf,0) = command;
238 /* announcement parameters */
239 CVAL(p,0) = updatecount;
240 SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
242 StrnCpy(p+5,server_name,16);
243 strupper(p+5);
245 CVAL(p,21) = 0x02; /* major version */
246 CVAL(p,22) = 0x02; /* minor version */
248 SIVAL(p,23,server_type);
249 SSVAL(p,27,0xaa55); /* browse signature */
250 SSVAL(p,29,0x001f); /* browse version: CIFS draft 1.0 indicates 0x001f */
252 strcpy(p+31,server_comment);
253 p += 31;
254 p = skip_string(p,1);
256 /* send the announcement */
257 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
258 PTR_DIFF(p,outbuf),
259 from_name, to_name,
260 from_type, to_type,
261 to_ip, from_ip);
265 /****************************************************************************
266 remove all samba's server entries
267 ****************************************************************************/
268 void remove_my_servers(void)
270 struct subnet_record *d;
271 for (d = subnetlist; d; d = d->next)
273 struct work_record *work;
274 for (work = d->workgrouplist; work; work = work->next)
276 struct server_record *s;
277 for (s = work->serverlist; s; s = s->next)
279 if (!strequal(myname,s->serv.name)) continue;
280 announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
287 /****************************************************************************
288 announce a server entry
289 ****************************************************************************/
290 void announce_server(struct subnet_record *d, struct work_record *work,
291 char *name, char *comment, time_t ttl, int server_type)
293 if (AM_MASTER(work))
295 DEBUG(3,("sending local master announce to %s for %s(1e)\n",
296 inet_ntoa(d->bcast_ip),work->work_group));
298 do_announce_host(ANN_LocalMasterAnnouncement,
299 name , 0x00, d->myip,
300 work->work_group, 0x1e, d->bcast_ip,
301 ttl*1000,
302 name, server_type, comment);
304 DEBUG(3,("sending domain announce to %s for %s\n",
305 inet_ntoa(d->bcast_ip),work->work_group));
307 /* XXXX should we do a domain-announce-kill? */
308 if (server_type != 0)
310 do_announce_host(ANN_DomainAnnouncement,
311 work->work_group, 0x00, d->myip,
312 MSBROWSE , 0x01, d->bcast_ip,
313 ttl*1000,
314 name, server_type ? SV_TYPE_DOMAIN_ENUM : 0, comment);
317 else
319 DEBUG(3,("sending host announce to %s for %s(1d)\n",
320 inet_ntoa(d->bcast_ip),work->work_group));
322 do_announce_host(ANN_HostAnnouncement,
323 name , 0x00, d->myip,
324 work->work_group, 0x1d, d->bcast_ip,
325 ttl*1000,
326 name, server_type, comment);
330 /****************************************************************************
331 construct a host announcement unicast
332 **************************************************************************/
333 void announce_host(void)
335 time_t t = time(NULL);
336 struct subnet_record *d;
337 pstring comment;
338 char *my_name;
340 StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
342 my_name = *myname ? myname : "NoName";
344 for (d = subnetlist; d; d = d->next)
346 struct work_record *work;
348 for (work = d->workgrouplist; work; work = work->next)
350 uint32 stype = work->ServerType;
351 struct server_record *s;
352 BOOL announce = False;
354 /* must work on the code that does announcements at up to
355 30 seconds later if a master browser sends us a request
356 announce.
359 if (work->needannounce) {
360 /* drop back to a max 3 minute announce - this is to prevent a
361 single lost packet from stuffing things up for too long */
362 work->announce_interval = MIN(work->announce_interval,
363 CHECK_TIME_MIN_HOST_ANNCE*60);
364 work->lastannounce_time = t - (work->announce_interval+1);
367 /* announce every minute at first then progress to every 12 mins */
368 if (work->lastannounce_time &&
369 (t - work->lastannounce_time) < work->announce_interval)
370 continue;
372 if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
373 work->announce_interval += 60;
375 work->lastannounce_time = t;
377 if (!d->my_interface) {
378 stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
379 SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
380 SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
383 for (s = work->serverlist; s; s = s->next) {
384 if (strequal(myname, s->serv.name)) {
385 announce = True;
386 break;
390 if (announce)
392 announce_server(d,work,my_name,comment,work->announce_interval,stype);
395 if (work->needannounce)
397 work->needannounce = False;
398 break;
399 /* sorry: can't do too many announces. do some more later */
406 /****************************************************************************
407 announce myself as a master to all other primary domain conrollers.
409 BIG NOTE: this code will remain untested until some kind soul that has access
410 to a couple of windows NT advanced servers runs this version of nmbd for at
411 least 15 minutes.
413 this actually gets done in search_and_sync_workgroups() via the
414 NAME_QUERY_PDC_SRV_CHK command, if there is a response from the
415 name query initiated here. see response_name_query()
416 **************************************************************************/
417 void announce_master(void)
419 struct subnet_record *d;
420 static time_t last=0;
421 time_t t = time(NULL);
422 BOOL am_master = False; /* are we a master of some sort? :-) */
424 if (!last) last = t;
425 if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
426 return;
428 last = t;
430 for (d = subnetlist; d; d = d->next)
432 struct work_record *work;
433 for (work = d->workgrouplist; work; work = work->next)
435 if (AM_MASTER(work))
437 am_master = True;
442 if (!am_master) return; /* only proceed if we are a master browser */
444 for (d = subnetlist; d; d = d->next)
446 struct work_record *work;
447 for (work = d->workgrouplist; work; work = work->next)
449 struct server_record *s;
450 for (s = work->serverlist; s; s = s->next)
452 if (strequal(s->serv.name, myname)) continue;
454 /* all PDCs (which should also be master browsers) */
455 if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
457 /* check the existence of a pdc for this workgroup, and if
458 one exists at the specified ip, sync with it and announce
459 ourselves as a master browser to it */
461 if (!*lp_domain_controller() ||
462 !strequal(lp_domain_controller(), s->serv.name))
464 if (!lp_wins_support() && *lp_wins_server())
466 struct in_addr ip;
467 ip = ipzero;
469 queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
470 NAME_QUERY_PDC_SRV_CHK,
471 work->work_group,0x1b,0,0,
472 False, False, ip, ip);
474 else
476 struct subnet_record *d2;
477 for (d2 = subnetlist; d2; d2 = d2->next)
479 queue_netbios_packet(d,ClientNMB,NMB_QUERY,
480 NAME_QUERY_PDC_SRV_CHK,
481 work->work_group,0x1b,0,0,
482 True, False, d2->bcast_ip, d2->bcast_ip);
489 /* now do primary domain controller - the one that's not
490 necessarily in our browse lists, although it ought to be
491 this pdc is the one that we get TOLD about through smb.conf.
492 basically, if it's on a subnet that we know about, it may end
493 up in our browse lists (which is why it's explicitly excluded
494 in the code above) */
496 if (*lp_domain_controller())
498 struct in_addr ip;
499 BOOL bcast = False;
501 ip = *interpret_addr2(lp_domain_controller());
503 if (zero_ip(ip)) {
504 ip = d->bcast_ip;
505 bcast = True;
508 DEBUG(2, ("Searching for PDC %s at %s\n",
509 lp_domain_controller(), inet_ntoa(ip)));
511 /* check the existence of a pdc for this workgroup, and if
512 one exists at the specified ip, sync with it and announce
513 ourselves as a master browser to it */
514 queue_netbios_pkt_wins(d,ClientNMB, NMB_QUERY,NAME_QUERY_PDC_SRV_CHK,
515 work->work_group,0x1b, 0, 0,
516 bcast, False, ip, ip);