preparing for release of 1.9.16p4
[samba.git] / source3 / namebrowse.c
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
6    
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.
11    
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.
16    
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.
20    
21    Revision History:
22
23    14 jan 96: lkcl@pires.co.uk
24    added multiple workgroup domain master support
25
26 */
27
28 #include "includes.h"
29 #include "smb.h"
30
31 extern int ClientNMB;
32
33 extern int DEBUGLEVEL;
34
35 /* this is our browse master/backup cache database */
36 static struct browse_cache_record *browserlist = NULL;
37
38
39 /***************************************************************************
40   add a browser into the list
41   **************************************************************************/
42 static void add_browse_cache(struct browse_cache_record *b)
43 {
44   struct browse_cache_record *b2;
45
46   if (!browserlist)
47     {
48       browserlist = b;
49       b->prev = NULL;
50       b->next = NULL;
51       return;
52     }
53   
54   for (b2 = browserlist; b2->next; b2 = b2->next) ;
55   
56   b2->next = b;
57   b->next = NULL;
58   b->prev = b2;
59 }
60
61
62 /*******************************************************************
63   remove old browse entries
64   ******************************************************************/
65 void expire_browse_cache(time_t t)
66 {
67   struct browse_cache_record *b;
68   struct browse_cache_record *nextb;
69   
70   /* expire old entries in the serverlist */
71   for (b = browserlist; b; b = nextb)
72     {
73       if (b->synced && b->sync_time < t)
74         {
75           DEBUG(3,("Removing dead cached browser %s\n",b->name));
76           nextb = b->next;
77           
78           if (b->prev) b->prev->next = b->next;
79           if (b->next) b->next->prev = b->prev;
80           
81           if (browserlist == b) browserlist = b->next; 
82           
83           free(b);
84         }
85       else
86         {
87           nextb = b->next;
88         }
89     }
90 }
91
92
93 /****************************************************************************
94   add a browser entry
95   ****************************************************************************/
96 struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
97                                               time_t ttl, struct in_addr ip, BOOL local)
98 {
99   BOOL newentry=False;
100   
101   struct browse_cache_record *b;
102
103   /* search for the entry: if it's already in the cache, update that entry */
104   for (b = browserlist; b; b = b->next)
105     {
106       if (ip_equal(ip,b->ip) && strequal(b->group, wg)) break;
107     }
108   
109   if (b && b->synced)
110     {
111       /* entries get left in the cache for a while. this stops sync'ing too
112          often if the network is large */
113       DEBUG(4, ("browser %s %s %s already sync'd at time %d\n",
114                 b->name, b->group, inet_ntoa(b->ip), b->sync_time));
115       return NULL;
116     }
117   
118   if (!b)
119     {
120       newentry = True;
121       b = (struct browse_cache_record *)malloc(sizeof(*b));
122       
123       if (!b) return(NULL);
124       
125       bzero((char *)b,sizeof(*b));
126     }
127   
128   /* update the entry */
129   ttl = time(NULL)+ttl;
130   
131   StrnCpy(b->name ,name,sizeof(b->name )-1);
132   StrnCpy(b->group,wg  ,sizeof(b->group)-1);
133   strupper(b->name);
134   strupper(b->group);
135   
136   b->ip     = ip;
137   b->type   = type;
138   b->local  = local; /* local server list sync or complete sync required */
139   
140   if (newentry || ttl < b->sync_time) 
141     b->sync_time = ttl;
142   
143   if (newentry)
144     {
145       b->synced = False;
146       add_browse_cache(b);
147       
148       DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n",
149                wg, name, type, inet_ntoa(ip),ttl));
150     }
151   else
152     {
153       DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n",
154                wg, name, type, inet_ntoa(ip),ttl));
155     }
156   
157   return(b);
158 }
159
160
161 /****************************************************************************
162 find a server responsible for a workgroup, and sync browse lists
163 **************************************************************************/
164 static void start_sync_browse_entry(struct browse_cache_record *b)
165 {                     
166   struct subnet_record *d;
167   struct work_record *work;
168
169   if (!(d = find_subnet(b->ip))) return;
170
171   if (!(work = find_workgroupstruct(d, b->group, False))) return;
172
173   /* only sync if we are the master */
174   if (AM_MASTER(work)) {
175
176       /* first check whether the group we intend to sync with exists. if it
177          doesn't, the server must have died. o dear. */
178
179       /* see response_netbios_packet() or expire_netbios_response_entries() */
180       queue_netbios_packet(d,ClientNMB,NMB_QUERY,
181                        b->local?NAME_QUERY_SYNC_LOCAL:NAME_QUERY_SYNC_REMOTE,
182                                            b->group,0x20,0,0,0,NULL,NULL,
183                                            False,False,b->ip,b->ip);
184   }
185
186   b->synced = True;
187 }
188
189
190 /****************************************************************************
191   search through browser list for an entry to sync with
192   **************************************************************************/
193 void do_browser_lists(time_t t)
194 {
195   struct browse_cache_record *b;
196   static time_t last = 0;
197   
198   if (t-last < 20) return; /* don't do too many of these at once! */
199                            /* XXXX equally this period should not be too long
200                               the server may die in the intervening gap */
201   
202   last = t;
203   
204   /* pick any entry in the list, preferably one whose time is up */
205   for (b = browserlist; b && b->next; b = b->next)
206     {
207       if (b->sync_time < t && b->synced == False) break;
208     }
209   
210   if (b && !b->synced)
211   {
212     /* sync with the selected entry then remove some dead entries */
213     start_sync_browse_entry(b);
214     expire_browse_cache(t - 60);
215   }
216
217 }
218