autorid: reserve 500 IDs at the top of the ALLOC range.
[Samba/wip.git] / source3 / lib / serverid.c
blob48b09f71f50ec6172ece7264934bf5c6a36f756f
1 /*
2 Unix SMB/CIFS implementation.
3 Implementation of a reliable server_exists()
4 Copyright (C) Volker Lendecke 2010
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "system/filesys.h"
22 #include "serverid.h"
23 #include "util_tdb.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_open.h"
26 #include "lib/tdb_wrap/tdb_wrap.h"
27 #include "lib/param/param.h"
28 #include "ctdbd_conn.h"
29 #include "messages.h"
31 struct serverid_key {
32 pid_t pid;
33 uint32_t task_id;
34 uint32_t vnn;
37 struct serverid_data {
38 uint64_t unique_id;
39 uint32_t msg_flags;
42 bool serverid_parent_init(TALLOC_CTX *mem_ctx)
44 struct tdb_wrap *db;
45 struct loadparm_context *lp_ctx;
46 const char *fname;
48 lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
49 if (lp_ctx == NULL) {
50 DEBUG(0, ("loadparm_init_s3 failed\n"));
51 return false;
55 * Open the tdb in the parent process (smbd) so that our
56 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
57 * work.
60 fname = lock_path("serverid.tdb");
62 db = tdb_wrap_open(mem_ctx, fname,
63 lpcfg_tdb_hash_size(lp_ctx, fname),
64 lpcfg_tdb_flags(lp_ctx,
65 TDB_DEFAULT|TDB_CLEAR_IF_FIRST|
66 TDB_INCOMPATIBLE_HASH),
67 O_RDWR|O_CREAT, 0644);
68 talloc_unlink(mem_ctx, lp_ctx);
69 if (db == NULL) {
70 DEBUG(1, ("could not open serverid.tdb: %s\n",
71 strerror(errno)));
72 return false;
74 return true;
77 static struct db_context *serverid_db(void)
79 static struct db_context *db;
81 if (db != NULL) {
82 return db;
84 db = db_open(NULL, lock_path("serverid.tdb"), 0,
85 TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
86 O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2,
87 DBWRAP_FLAG_NONE);
88 return db;
91 static void serverid_fill_key(const struct server_id *id,
92 struct serverid_key *key)
94 ZERO_STRUCTP(key);
95 key->pid = id->pid;
96 key->task_id = id->task_id;
97 key->vnn = id->vnn;
100 bool serverid_register(const struct server_id id, uint32_t msg_flags)
102 struct db_context *db;
103 struct serverid_key key;
104 struct serverid_data data;
105 struct db_record *rec;
106 TDB_DATA tdbkey, tdbdata;
107 NTSTATUS status;
108 bool ret = false;
110 db = serverid_db();
111 if (db == NULL) {
112 return false;
115 serverid_fill_key(&id, &key);
116 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
118 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
119 if (rec == NULL) {
120 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
121 return false;
124 ZERO_STRUCT(data);
125 data.unique_id = id.unique_id;
126 data.msg_flags = msg_flags;
128 tdbdata = make_tdb_data((uint8_t *)&data, sizeof(data));
129 status = dbwrap_record_store(rec, tdbdata, 0);
130 if (!NT_STATUS_IS_OK(status)) {
131 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
132 nt_errstr(status)));
133 goto done;
136 if (lp_clustering() &&
137 ctdb_serverids_exist_supported(messaging_ctdbd_connection()))
139 register_with_ctdbd(messaging_ctdbd_connection(), id.unique_id);
142 ret = true;
143 done:
144 TALLOC_FREE(rec);
145 return ret;
148 bool serverid_register_msg_flags(const struct server_id id, bool do_reg,
149 uint32_t msg_flags)
151 struct db_context *db;
152 struct serverid_key key;
153 struct serverid_data *data;
154 struct db_record *rec;
155 TDB_DATA tdbkey;
156 TDB_DATA value;
157 NTSTATUS status;
158 bool ret = false;
160 db = serverid_db();
161 if (db == NULL) {
162 return false;
165 serverid_fill_key(&id, &key);
166 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
168 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
169 if (rec == NULL) {
170 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
171 return false;
174 value = dbwrap_record_get_value(rec);
176 if (value.dsize != sizeof(struct serverid_data)) {
177 DEBUG(1, ("serverid record has unexpected size %d "
178 "(wanted %d)\n", (int)value.dsize,
179 (int)sizeof(struct serverid_data)));
180 goto done;
183 data = (struct serverid_data *)value.dptr;
185 if (do_reg) {
186 data->msg_flags |= msg_flags;
187 } else {
188 data->msg_flags &= ~msg_flags;
191 status = dbwrap_record_store(rec, value, 0);
192 if (!NT_STATUS_IS_OK(status)) {
193 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
194 nt_errstr(status)));
195 goto done;
197 ret = true;
198 done:
199 TALLOC_FREE(rec);
200 return ret;
203 bool serverid_deregister(struct server_id id)
205 struct db_context *db;
206 struct serverid_key key;
207 struct db_record *rec;
208 TDB_DATA tdbkey;
209 NTSTATUS status;
210 bool ret = false;
212 db = serverid_db();
213 if (db == NULL) {
214 return false;
217 serverid_fill_key(&id, &key);
218 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
220 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
221 if (rec == NULL) {
222 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
223 return false;
226 status = dbwrap_record_delete(rec);
227 if (!NT_STATUS_IS_OK(status)) {
228 DEBUG(1, ("Deleting serverid.tdb record failed: %s\n",
229 nt_errstr(status)));
230 goto done;
232 ret = true;
233 done:
234 TALLOC_FREE(rec);
235 return ret;
238 struct serverid_exists_state {
239 const struct server_id *id;
240 bool exists;
243 static void server_exists_parse(TDB_DATA key, TDB_DATA data, void *priv)
245 struct serverid_exists_state *state =
246 (struct serverid_exists_state *)priv;
248 if (data.dsize != sizeof(struct serverid_data)) {
249 state->exists = false;
250 return;
254 * Use memcmp, not direct compare. data.dptr might not be
255 * aligned.
257 state->exists = (memcmp(&state->id->unique_id, data.dptr,
258 sizeof(state->id->unique_id)) == 0);
261 bool serverid_exists(const struct server_id *id)
263 bool result = false;
264 bool ok = false;
266 ok = serverids_exist(id, 1, &result);
267 if (!ok) {
268 return false;
271 return result;
274 bool serverids_exist(const struct server_id *ids, int num_ids, bool *results)
276 int *todo_idx = NULL;
277 struct server_id *todo_ids = NULL;
278 bool *todo_results = NULL;
279 int todo_num = 0;
280 int *remote_idx = NULL;
281 int remote_num = 0;
282 int *verify_idx = NULL;
283 int verify_num = 0;
284 int t, idx;
285 bool result = false;
286 struct db_context *db;
288 db = serverid_db();
289 if (db == NULL) {
290 return false;
293 todo_idx = talloc_array(talloc_tos(), int, num_ids);
294 if (todo_idx == NULL) {
295 goto fail;
297 todo_ids = talloc_array(talloc_tos(), struct server_id, num_ids);
298 if (todo_ids == NULL) {
299 goto fail;
301 todo_results = talloc_array(talloc_tos(), bool, num_ids);
302 if (todo_results == NULL) {
303 goto fail;
306 remote_idx = talloc_array(talloc_tos(), int, num_ids);
307 if (remote_idx == NULL) {
308 goto fail;
310 verify_idx = talloc_array(talloc_tos(), int, num_ids);
311 if (verify_idx == NULL) {
312 goto fail;
315 for (idx=0; idx<num_ids; idx++) {
316 results[idx] = false;
318 if (server_id_is_disconnected(&ids[idx])) {
319 continue;
322 if (procid_is_me(&ids[idx])) {
323 results[idx] = true;
324 continue;
327 if (procid_is_local(&ids[idx])) {
328 bool exists = process_exists_by_pid(ids[idx].pid);
330 if (!exists) {
331 continue;
334 if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
335 results[idx] = true;
336 continue;
339 verify_idx[verify_num] = idx;
340 verify_num += 1;
341 continue;
344 if (!lp_clustering()) {
345 continue;
348 remote_idx[remote_num] = idx;
349 remote_num += 1;
352 if (remote_num != 0 &&
353 ctdb_serverids_exist_supported(messaging_ctdbd_connection()))
355 int old_remote_num = remote_num;
357 remote_num = 0;
358 todo_num = 0;
360 for (t=0; t<old_remote_num; t++) {
361 idx = remote_idx[t];
363 if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
364 remote_idx[remote_num] = idx;
365 remote_num += 1;
366 continue;
369 todo_idx[todo_num] = idx;
370 todo_ids[todo_num] = ids[idx];
371 todo_results[todo_num] = false;
372 todo_num += 1;
376 * Note: this only uses CTDB_CONTROL_CHECK_SRVIDS
377 * to verify that the server_id still exists,
378 * which means only the server_id.unique_id and
379 * server_id.vnn are verified, while server_id.pid
380 * is not verified at all.
382 * TODO: do we want to verify server_id.pid somehow?
384 if (!ctdb_serverids_exist(messaging_ctdbd_connection(),
385 todo_ids, todo_num, todo_results))
387 goto fail;
390 for (t=0; t<todo_num; t++) {
391 idx = todo_idx[t];
393 results[idx] = todo_results[t];
397 if (remote_num != 0) {
398 todo_num = 0;
400 for (t=0; t<remote_num; t++) {
401 idx = remote_idx[t];
402 todo_idx[todo_num] = idx;
403 todo_ids[todo_num] = ids[idx];
404 todo_results[todo_num] = false;
405 todo_num += 1;
408 if (!ctdb_processes_exist(messaging_ctdbd_connection(),
409 todo_ids, todo_num,
410 todo_results)) {
411 goto fail;
414 for (t=0; t<todo_num; t++) {
415 idx = todo_idx[t];
417 if (!todo_results[t]) {
418 continue;
421 if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
422 results[idx] = true;
423 continue;
426 verify_idx[verify_num] = idx;
427 verify_num += 1;
431 for (t=0; t<verify_num; t++) {
432 struct serverid_exists_state state;
433 struct serverid_key key;
434 TDB_DATA tdbkey;
435 NTSTATUS status;
437 idx = verify_idx[t];
439 serverid_fill_key(&ids[idx], &key);
440 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
442 state.id = &ids[idx];
443 state.exists = false;
444 status = dbwrap_parse_record(db, tdbkey, server_exists_parse, &state);
445 if (!NT_STATUS_IS_OK(status)) {
446 results[idx] = false;
447 continue;
449 results[idx] = state.exists;
452 result = true;
453 fail:
454 TALLOC_FREE(verify_idx);
455 TALLOC_FREE(remote_idx);
456 TALLOC_FREE(todo_results);
457 TALLOC_FREE(todo_ids);
458 TALLOC_FREE(todo_idx);
459 return result;
462 static bool serverid_rec_parse(const struct db_record *rec,
463 struct server_id *id, uint32_t *msg_flags)
465 struct serverid_key key;
466 struct serverid_data data;
467 TDB_DATA tdbkey;
468 TDB_DATA tdbdata;
470 tdbkey = dbwrap_record_get_key(rec);
471 tdbdata = dbwrap_record_get_value(rec);
473 if (tdbkey.dsize != sizeof(key)) {
474 DEBUG(1, ("Found invalid key length %d in serverid.tdb\n",
475 (int)tdbkey.dsize));
476 return false;
478 if (tdbdata.dsize != sizeof(data)) {
479 DEBUG(1, ("Found invalid value length %d in serverid.tdb\n",
480 (int)tdbdata.dsize));
481 return false;
484 memcpy(&key, tdbkey.dptr, sizeof(key));
485 memcpy(&data, tdbdata.dptr, sizeof(data));
487 id->pid = key.pid;
488 id->task_id = key.task_id;
489 id->vnn = key.vnn;
490 id->unique_id = data.unique_id;
491 *msg_flags = data.msg_flags;
492 return true;
495 struct serverid_traverse_read_state {
496 int (*fn)(const struct server_id *id, uint32_t msg_flags,
497 void *private_data);
498 void *private_data;
501 static int serverid_traverse_read_fn(struct db_record *rec, void *private_data)
503 struct serverid_traverse_read_state *state =
504 (struct serverid_traverse_read_state *)private_data;
505 struct server_id id;
506 uint32_t msg_flags;
508 if (!serverid_rec_parse(rec, &id, &msg_flags)) {
509 return 0;
511 return state->fn(&id, msg_flags,state->private_data);
514 bool serverid_traverse_read(int (*fn)(const struct server_id *id,
515 uint32_t msg_flags, void *private_data),
516 void *private_data)
518 struct db_context *db;
519 struct serverid_traverse_read_state state;
520 NTSTATUS status;
522 db = serverid_db();
523 if (db == NULL) {
524 return false;
526 state.fn = fn;
527 state.private_data = private_data;
529 status = dbwrap_traverse_read(db, serverid_traverse_read_fn, &state,
530 NULL);
531 return NT_STATUS_IS_OK(status);
534 struct serverid_traverse_state {
535 int (*fn)(struct db_record *rec, const struct server_id *id,
536 uint32_t msg_flags, void *private_data);
537 void *private_data;
540 static int serverid_traverse_fn(struct db_record *rec, void *private_data)
542 struct serverid_traverse_state *state =
543 (struct serverid_traverse_state *)private_data;
544 struct server_id id;
545 uint32_t msg_flags;
547 if (!serverid_rec_parse(rec, &id, &msg_flags)) {
548 return 0;
550 return state->fn(rec, &id, msg_flags, state->private_data);
553 bool serverid_traverse(int (*fn)(struct db_record *rec,
554 const struct server_id *id,
555 uint32_t msg_flags, void *private_data),
556 void *private_data)
558 struct db_context *db;
559 struct serverid_traverse_state state;
560 NTSTATUS status;
562 db = serverid_db();
563 if (db == NULL) {
564 return false;
566 state.fn = fn;
567 state.private_data = private_data;
569 status = dbwrap_traverse(db, serverid_traverse_fn, &state, NULL);
570 return NT_STATUS_IS_OK(status);
573 uint64_t serverid_get_random_unique_id(void)
575 uint64_t unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
577 while (unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
578 generate_random_buffer((uint8_t *)&unique_id,
579 sizeof(unique_id));
582 return unique_id;