r12608: Remove some unused #include lines.
[kai/samba.git] / source4 / wrepl_server / wrepl_scavenging.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    WINS Replication server
5    
6    Copyright (C) Stefan Metzmacher      2005
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
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"
30
31 static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
32 {
33         NTSTATUS status;
34         struct winsdb_record *rec = NULL;
35         struct ldb_result *res = NULL;
36         const char *filter;
37         uint32_t i;
38         int ret;
39         time_t now = time(NULL);
40         const char *now_timestr;
41         const char *action;
42         const char *old_state;
43         uint32_t modify_flags;
44         BOOL modify_record;
45         BOOL delete_record;
46         BOOL delete_tombstones;
47         struct timeval tombstone_extra_time;
48
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);
59
60         tombstone_extra_time = timeval_add(&service->startup_time,
61                                            service->config.tombstone_extra_timeout,
62                                            0);
63         delete_tombstones = timeval_expired(&tombstone_extra_time);
64
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);
68
69                 if (rec->is_static) {
70                         DEBUG(0,("%s: corrupted record: %s\n",
71                                 __location__, nbt_name_string(rec, rec->name)));
72                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
73                 }
74
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;
79                 }
80
81                 modify_flags    = 0;
82                 modify_record   = False;
83                 delete_record   = False;
84
85                 switch (rec->state) {
86                 case WREPL_STATE_ACTIVE:
87                         old_state       = "active";
88                         rec->state      = WREPL_STATE_RELEASED;
89                         rec->expire_time= service->config.tombstone_interval + now;
90                         modify_flags    = 0;
91                         modify_record   = True;
92                         break;
93
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;
99                         modify_record   = True;
100                         break;
101
102                 case WREPL_STATE_TOMBSTONE:
103                         old_state       = "tombstone";
104                         if (!delete_tombstones) break;
105                         delete_record = True;
106                         break;
107
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;
112                 }
113
114                 if (modify_record) {
115                         action = "modify";
116                         ret = winsdb_modify(service->wins_db, rec, modify_flags);
117                 } else if (delete_record) {
118                         action = "delete";
119                         ret = winsdb_delete(service->wins_db, rec);
120                 } else {
121                         action = "skip";
122                         ret = NBT_RCODE_OK;
123                 }
124
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));
128                 } else {
129                         DEBUG(4,("WINS scavenging: %s name: %s (owned:%s)\n",
130                                 action, nbt_name_string(rec, rec->name), old_state));
131                 }
132
133                 talloc_free(rec);
134         }
135
136         return NT_STATUS_OK;
137 }
138
139 static NTSTATUS wreplsrv_scavenging_replica_non_active_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
140 {
141         NTSTATUS status;
142         struct winsdb_record *rec = NULL;
143         struct ldb_result *res = NULL;
144         const char *filter;
145         uint32_t i;
146         int ret;
147         time_t now = time(NULL);
148         const char *now_timestr;
149         const char *action;
150         const char *old_state;
151         uint32_t modify_flags;
152         BOOL modify_record;
153         BOOL delete_record;
154         BOOL delete_tombstones;
155         struct timeval tombstone_extra_time;
156
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);
167
168         tombstone_extra_time = timeval_add(&service->startup_time,
169                                            service->config.tombstone_extra_timeout,
170                                            0);
171         delete_tombstones = timeval_expired(&tombstone_extra_time);
172
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);
176
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;
181                 }
182
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;
187                 }
188
189                 modify_flags    = 0;
190                 modify_record   = False;
191                 delete_record   = False;
192
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;
198
199                 case WREPL_STATE_RELEASED:
200                         old_state       = "released";
201                         rec->state      = WREPL_STATE_TOMBSTONE;
202                         rec->expire_time= service->config.tombstone_timeout + now;
203                         modify_flags    = 0;
204                         modify_record   = True;
205                         break;
206
207                 case WREPL_STATE_TOMBSTONE:
208                         old_state       = "tombstone";
209                         if (!delete_tombstones) break;
210                         delete_record = True;
211                         break;
212
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;
217                 }
218
219                 if (modify_record) {
220                         action = "modify";
221                         ret = winsdb_modify(service->wins_db, rec, modify_flags);
222                 } else if (delete_record) {
223                         action = "delete";
224                         ret = winsdb_delete(service->wins_db, rec);
225                 } else {
226                         action = "skip";
227                         ret = NBT_RCODE_OK;
228                 }
229
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));
233                 } else {
234                         DEBUG(4,("WINS scavenging: %s name: %s (replica:%s)\n",
235                                 action, nbt_name_string(rec, rec->name), old_state));
236                 }
237
238                 talloc_free(rec);
239         }
240
241         return NT_STATUS_OK;
242 }
243
244 static NTSTATUS wreplsrv_scavenging_replica_active_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
245 {
246         NTSTATUS status;
247         struct winsdb_record *rec = NULL;
248         struct ldb_result *res = NULL;
249         const char *filter;
250         uint32_t i;
251         int ret;
252         time_t now = time(NULL);
253         const char *now_timestr;
254         const char *action;
255         const char *old_state;
256         BOOL modify_flags;
257         BOOL modify_record;
258         BOOL delete_record;
259
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);
270
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);
274
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;
279                 }
280
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;
285                 }
286
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;
291                 }
292
293                 old_state = "active";
294
295                 modify_flags    = 0;
296                 modify_record   = False;
297                 delete_record   = False;
298
299                 /* 
300                  * TODO: ask the owning wins server if the record still exists,
301                  *       if not delete the record
302                  */
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));
305
306                 if (modify_record) {
307                         action = "modify";
308                         ret = winsdb_modify(service->wins_db, rec, modify_flags);
309                 } else if (delete_record) {
310                         action = "delete";
311                         ret = winsdb_delete(service->wins_db, rec);
312                 } else {
313                         action = "skip";
314                         ret = NBT_RCODE_OK;
315                 }
316
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));
320                 } else {
321                         DEBUG(4,("WINS scavenging: %s name: %s (replica:%s)\n",
322                                 action, nbt_name_string(rec, rec->name), old_state));
323                 }
324
325                 talloc_free(rec);
326         }
327
328         return NT_STATUS_OK;
329 }
330
331 NTSTATUS wreplsrv_scavenging_run(struct wreplsrv_service *service)
332 {
333         NTSTATUS status;
334         TALLOC_CTX *tmp_mem;
335
336         if (!timeval_expired(&service->scavenging.next_run)) {
337                 return NT_STATUS_OK;
338         }
339
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);
343
344         if (service->scavenging.processing) {
345                 return NT_STATUS_OK;
346         }
347
348         DEBUG(4,("wreplsrv_scavenging_run(): start\n"));
349
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);
356
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);
363
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);
370
371         DEBUG(4,("wreplsrv_scavenging_run(): end\n"));
372
373         return NT_STATUS_OK;
374 }