2 Unix SMB/CIFS implementation.
4 WINS Replication server
6 Copyright (C) Stefan Metzmacher 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "librpc/gen_ndr/ndr_winsrepl.h"
25 #include "wrepl_server/wrepl_server.h"
26 #include "nbt_server/wins/winsdb.h"
27 #include "ldb/include/ldb.h"
28 #include "ldb/include/ldb_errors.h"
29 #include "system/time.h"
31 static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
34 struct winsdb_record *rec = NULL;
35 struct ldb_result *res = NULL;
39 time_t now = time(NULL);
40 const char *now_timestr;
42 const char *old_state;
43 uint32_t modify_flags;
46 BOOL delete_tombstones;
47 struct timeval tombstone_extra_time;
49 now_timestr = ldb_timestring(tmp_mem, now);
50 NT_STATUS_HAVE_NO_MEMORY(now_timestr);
51 filter = talloc_asprintf(tmp_mem,
52 "(&(winsOwner=%s)(objectClass=winsRecord)"
53 "(expireTime<=%s)(!(isStatic=1)))",
54 WINSDB_OWNER_LOCAL, now_timestr);
55 NT_STATUS_HAVE_NO_MEMORY(filter);
56 ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
57 if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
58 talloc_steal(tmp_mem, res);
60 tombstone_extra_time = timeval_add(&service->startup_time,
61 service->config.tombstone_extra_timeout,
63 delete_tombstones = timeval_expired(&tombstone_extra_time);
65 for (i=0; i < res->count; i++) {
66 status = winsdb_record(res->msgs[i], tmp_mem, &rec);
67 NT_STATUS_NOT_OK_RETURN(status);
70 DEBUG(0,("%s: corrupted record: %s\n",
71 __location__, nbt_name_string(rec, rec->name)));
72 return NT_STATUS_INTERNAL_DB_CORRUPTION;
75 if (rec->expire_time > now) {
76 DEBUG(0,("%s: corrupted record: %s\n",
77 __location__, nbt_name_string(rec, rec->name)));
78 return NT_STATUS_INTERNAL_DB_CORRUPTION;
82 modify_record = False;
83 delete_record = False;
86 case WREPL_STATE_ACTIVE:
88 rec->state = WREPL_STATE_RELEASED;
89 rec->expire_time= service->config.tombstone_interval + now;
94 case WREPL_STATE_RELEASED:
95 old_state = "released";
96 rec->state = WREPL_STATE_TOMBSTONE;
97 rec->expire_time= service->config.tombstone_timeout + now;
98 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
102 case WREPL_STATE_TOMBSTONE:
103 old_state = "tombstone";
104 if (!delete_tombstones) break;
105 delete_record = True;
108 case WREPL_STATE_RESERVED:
109 DEBUG(0,("%s: corrupted record: %s\n",
110 __location__, nbt_name_string(rec, rec->name)));
111 return NT_STATUS_INTERNAL_DB_CORRUPTION;
116 ret = winsdb_modify(service->wins_db, rec, modify_flags);
117 } else if (delete_record) {
119 ret = winsdb_delete(service->wins_db, rec);
125 if (ret != NBT_RCODE_OK) {
126 DEBUG(1,("WINS scavenging: failed to %s name %s (owned:%s): error:%u\n",
127 action, nbt_name_string(rec, rec->name), old_state, ret));
129 DEBUG(4,("WINS scavenging: %s name: %s (owned:%s)\n",
130 action, nbt_name_string(rec, rec->name), old_state));
139 static NTSTATUS wreplsrv_scavenging_replica_non_active_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
142 struct winsdb_record *rec = NULL;
143 struct ldb_result *res = NULL;
147 time_t now = time(NULL);
148 const char *now_timestr;
150 const char *old_state;
151 uint32_t modify_flags;
154 BOOL delete_tombstones;
155 struct timeval tombstone_extra_time;
157 now_timestr = ldb_timestring(tmp_mem, now);
158 NT_STATUS_HAVE_NO_MEMORY(now_timestr);
159 filter = talloc_asprintf(tmp_mem,
160 "(&(!(winsOwner=%s))(objectClass=winsRecord)"
161 "(!(recordState=%u))(expireTime<=%s)(!(isStatic=1)))",
162 WINSDB_OWNER_LOCAL, WREPL_STATE_ACTIVE, now_timestr);
163 NT_STATUS_HAVE_NO_MEMORY(filter);
164 ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
165 if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
166 talloc_steal(tmp_mem, res);
168 tombstone_extra_time = timeval_add(&service->startup_time,
169 service->config.tombstone_extra_timeout,
171 delete_tombstones = timeval_expired(&tombstone_extra_time);
173 for (i=0; i < res->count; i++) {
174 status = winsdb_record(res->msgs[i], tmp_mem, &rec);
175 NT_STATUS_NOT_OK_RETURN(status);
177 if (rec->is_static) {
178 DEBUG(0,("%s: corrupted record: %s\n",
179 __location__, nbt_name_string(rec, rec->name)));
180 return NT_STATUS_INTERNAL_DB_CORRUPTION;
183 if (rec->expire_time > now) {
184 DEBUG(0,("%s: corrupted record: %s\n",
185 __location__, nbt_name_string(rec, rec->name)));
186 return NT_STATUS_INTERNAL_DB_CORRUPTION;
190 modify_record = False;
191 delete_record = False;
193 switch (rec->state) {
194 case WREPL_STATE_ACTIVE:
195 DEBUG(0,("%s: corrupted record: %s\n",
196 __location__, nbt_name_string(rec, rec->name)));
197 return NT_STATUS_INTERNAL_DB_CORRUPTION;
199 case WREPL_STATE_RELEASED:
200 old_state = "released";
201 rec->state = WREPL_STATE_TOMBSTONE;
202 rec->expire_time= service->config.tombstone_timeout + now;
204 modify_record = True;
207 case WREPL_STATE_TOMBSTONE:
208 old_state = "tombstone";
209 if (!delete_tombstones) break;
210 delete_record = True;
213 case WREPL_STATE_RESERVED:
214 DEBUG(0,("%s: corrupted record: %s\n",
215 __location__, nbt_name_string(rec, rec->name)));
216 return NT_STATUS_INTERNAL_DB_CORRUPTION;
221 ret = winsdb_modify(service->wins_db, rec, modify_flags);
222 } else if (delete_record) {
224 ret = winsdb_delete(service->wins_db, rec);
230 if (ret != NBT_RCODE_OK) {
231 DEBUG(1,("WINS scavenging: failed to %s name %s (replica:%s): error:%u\n",
232 action, nbt_name_string(rec, rec->name), old_state, ret));
234 DEBUG(4,("WINS scavenging: %s name: %s (replica:%s)\n",
235 action, nbt_name_string(rec, rec->name), old_state));
244 static NTSTATUS wreplsrv_scavenging_replica_active_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
247 struct winsdb_record *rec = NULL;
248 struct ldb_result *res = NULL;
252 time_t now = time(NULL);
253 const char *now_timestr;
255 const char *old_state;
260 now_timestr = ldb_timestring(tmp_mem, now);
261 NT_STATUS_HAVE_NO_MEMORY(now_timestr);
262 filter = talloc_asprintf(tmp_mem,
263 "(&(!(winsOwner=%s))(objectClass=winsRecord)"
264 "(recordState=%u)(expireTime<=%s)(!(isStatic=1)))",
265 WINSDB_OWNER_LOCAL, WREPL_STATE_ACTIVE, now_timestr);
266 NT_STATUS_HAVE_NO_MEMORY(filter);
267 ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
268 if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
269 talloc_steal(tmp_mem, res);
271 for (i=0; i < res->count; i++) {
272 status = winsdb_record(res->msgs[i], tmp_mem, &rec);
273 NT_STATUS_NOT_OK_RETURN(status);
275 if (rec->is_static) {
276 DEBUG(0,("%s: corrupted record: %s\n",
277 __location__, nbt_name_string(rec, rec->name)));
278 return NT_STATUS_INTERNAL_DB_CORRUPTION;
281 if (rec->expire_time > now) {
282 DEBUG(0,("%s: corrupted record: %s\n",
283 __location__, nbt_name_string(rec, rec->name)));
284 return NT_STATUS_INTERNAL_DB_CORRUPTION;
287 if (rec->state != WREPL_STATE_ACTIVE) {
288 DEBUG(0,("%s: corrupted record: %s\n",
289 __location__, nbt_name_string(rec, rec->name)));
290 return NT_STATUS_INTERNAL_DB_CORRUPTION;
293 old_state = "active";
296 modify_record = False;
297 delete_record = False;
300 * TODO: ask the owning wins server if the record still exists,
301 * if not delete the record
303 DEBUG(0,("TODO: ask wins server '%s' if '%s' with version_id:%llu still exists\n",
304 rec->wins_owner, nbt_name_string(rec, rec->name), rec->version));
308 ret = winsdb_modify(service->wins_db, rec, modify_flags);
309 } else if (delete_record) {
311 ret = winsdb_delete(service->wins_db, rec);
317 if (ret != NBT_RCODE_OK) {
318 DEBUG(1,("WINS scavenging: failed to %s name %s (replica:%s): error:%u\n",
319 action, nbt_name_string(rec, rec->name), old_state, ret));
321 DEBUG(4,("WINS scavenging: %s name: %s (replica:%s)\n",
322 action, nbt_name_string(rec, rec->name), old_state));
331 NTSTATUS wreplsrv_scavenging_run(struct wreplsrv_service *service)
336 if (!timeval_expired(&service->scavenging.next_run)) {
340 service->scavenging.next_run = timeval_current_ofs(service->config.scavenging_interval, 0);
341 status = wreplsrv_periodic_schedule(service, service->config.scavenging_interval);
342 NT_STATUS_NOT_OK_RETURN(status);
344 if (service->scavenging.processing) {
348 DEBUG(4,("wreplsrv_scavenging_run(): start\n"));
350 tmp_mem = talloc_new(service);
351 service->scavenging.processing = True;
352 status = wreplsrv_scavenging_owned_records(service,tmp_mem);
353 service->scavenging.processing = False;
354 talloc_free(tmp_mem);
355 NT_STATUS_NOT_OK_RETURN(status);
357 tmp_mem = talloc_new(service);
358 service->scavenging.processing = True;
359 status = wreplsrv_scavenging_replica_non_active_records(service, tmp_mem);
360 service->scavenging.processing = False;
361 talloc_free(tmp_mem);
362 NT_STATUS_NOT_OK_RETURN(status);
364 tmp_mem = talloc_new(service);
365 service->scavenging.processing = True;
366 status = wreplsrv_scavenging_replica_active_records(service, tmp_mem);
367 service->scavenging.processing = False;
368 talloc_free(tmp_mem);
369 NT_STATUS_NOT_OK_RETURN(status);
371 DEBUG(4,("wreplsrv_scavenging_run(): end\n"));