s3:smb2_server: optimize req->in.vector allocation
[Samba.git] / source3 / lib / serverid.c
blob425988794798a8d3fe9ed09802c12d59d592e324
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;
47 lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
48 if (lp_ctx == NULL) {
49 DEBUG(0, ("loadparm_init_s3 failed\n"));
50 return false;
54 * Open the tdb in the parent process (smbd) so that our
55 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
56 * work.
59 db = tdb_wrap_open(mem_ctx, lock_path("serverid.tdb"),
60 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT,
61 0644, lp_ctx);
62 talloc_unlink(mem_ctx, lp_ctx);
63 if (db == NULL) {
64 DEBUG(1, ("could not open serverid.tdb: %s\n",
65 strerror(errno)));
66 return false;
68 return true;
71 static struct db_context *serverid_db(void)
73 static struct db_context *db;
75 if (db != NULL) {
76 return db;
78 db = db_open(NULL, lock_path("serverid.tdb"), 0,
79 TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
80 O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2,
81 DBWRAP_FLAG_NONE);
82 return db;
85 static void serverid_fill_key(const struct server_id *id,
86 struct serverid_key *key)
88 ZERO_STRUCTP(key);
89 key->pid = id->pid;
90 key->task_id = id->task_id;
91 key->vnn = id->vnn;
94 bool serverid_register(const struct server_id id, uint32_t msg_flags)
96 struct db_context *db;
97 struct serverid_key key;
98 struct serverid_data data;
99 struct db_record *rec;
100 TDB_DATA tdbkey, tdbdata;
101 NTSTATUS status;
102 bool ret = false;
104 db = serverid_db();
105 if (db == NULL) {
106 return false;
109 serverid_fill_key(&id, &key);
110 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
112 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
113 if (rec == NULL) {
114 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
115 return false;
118 ZERO_STRUCT(data);
119 data.unique_id = id.unique_id;
120 data.msg_flags = msg_flags;
122 tdbdata = make_tdb_data((uint8_t *)&data, sizeof(data));
123 status = dbwrap_record_store(rec, tdbdata, 0);
124 if (!NT_STATUS_IS_OK(status)) {
125 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
126 nt_errstr(status)));
127 goto done;
129 #ifdef HAVE_CTDB_CONTROL_CHECK_SRVIDS_DECL
130 if (lp_clustering()) {
131 register_with_ctdbd(messaging_ctdbd_connection(), id.unique_id);
133 #endif
134 ret = true;
135 done:
136 TALLOC_FREE(rec);
137 return ret;
140 bool serverid_register_msg_flags(const struct server_id id, bool do_reg,
141 uint32_t msg_flags)
143 struct db_context *db;
144 struct serverid_key key;
145 struct serverid_data *data;
146 struct db_record *rec;
147 TDB_DATA tdbkey;
148 TDB_DATA value;
149 NTSTATUS status;
150 bool ret = false;
152 db = serverid_db();
153 if (db == NULL) {
154 return false;
157 serverid_fill_key(&id, &key);
158 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
160 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
161 if (rec == NULL) {
162 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
163 return false;
166 value = dbwrap_record_get_value(rec);
168 if (value.dsize != sizeof(struct serverid_data)) {
169 DEBUG(1, ("serverid record has unexpected size %d "
170 "(wanted %d)\n", (int)value.dsize,
171 (int)sizeof(struct serverid_data)));
172 goto done;
175 data = (struct serverid_data *)value.dptr;
177 if (do_reg) {
178 data->msg_flags |= msg_flags;
179 } else {
180 data->msg_flags &= ~msg_flags;
183 status = dbwrap_record_store(rec, value, 0);
184 if (!NT_STATUS_IS_OK(status)) {
185 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
186 nt_errstr(status)));
187 goto done;
189 ret = true;
190 done:
191 TALLOC_FREE(rec);
192 return ret;
195 bool serverid_deregister(struct server_id id)
197 struct db_context *db;
198 struct serverid_key key;
199 struct db_record *rec;
200 TDB_DATA tdbkey;
201 NTSTATUS status;
202 bool ret = false;
204 db = serverid_db();
205 if (db == NULL) {
206 return false;
209 serverid_fill_key(&id, &key);
210 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
212 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
213 if (rec == NULL) {
214 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
215 return false;
218 status = dbwrap_record_delete(rec);
219 if (!NT_STATUS_IS_OK(status)) {
220 DEBUG(1, ("Deleting serverid.tdb record failed: %s\n",
221 nt_errstr(status)));
222 goto done;
224 ret = true;
225 done:
226 TALLOC_FREE(rec);
227 return ret;
230 struct serverid_exists_state {
231 const struct server_id *id;
232 bool exists;
235 static void server_exists_parse(TDB_DATA key, TDB_DATA data, void *priv)
237 struct serverid_exists_state *state =
238 (struct serverid_exists_state *)priv;
240 if (data.dsize != sizeof(struct serverid_data)) {
241 state->exists = false;
242 return;
246 * Use memcmp, not direct compare. data.dptr might not be
247 * aligned.
249 state->exists = (memcmp(&state->id->unique_id, data.dptr,
250 sizeof(state->id->unique_id)) == 0);
253 bool serverid_exists(const struct server_id *id)
255 bool result = false;
256 bool ok = false;
258 ok = serverids_exist(id, 1, &result);
259 if (!ok) {
260 return false;
263 return result;
266 bool serverids_exist(const struct server_id *ids, int num_ids, bool *results)
268 int *todo_idx = NULL;
269 struct server_id *todo_ids = NULL;
270 bool *todo_results = NULL;
271 int todo_num = 0;
272 int *remote_idx = NULL;
273 int remote_num = 0;
274 int *verify_idx = NULL;
275 int verify_num = 0;
276 int t, idx;
277 bool result = false;
278 struct db_context *db;
280 db = serverid_db();
281 if (db == NULL) {
282 return false;
285 todo_idx = talloc_array(talloc_tos(), int, num_ids);
286 if (todo_idx == NULL) {
287 goto fail;
289 todo_ids = talloc_array(talloc_tos(), struct server_id, num_ids);
290 if (todo_ids == NULL) {
291 goto fail;
293 todo_results = talloc_array(talloc_tos(), bool, num_ids);
294 if (todo_results == NULL) {
295 goto fail;
298 remote_idx = talloc_array(talloc_tos(), int, num_ids);
299 if (remote_idx == NULL) {
300 goto fail;
302 verify_idx = talloc_array(talloc_tos(), int, num_ids);
303 if (verify_idx == NULL) {
304 goto fail;
307 for (idx=0; idx<num_ids; idx++) {
308 results[idx] = false;
310 if (server_id_is_disconnected(&ids[idx])) {
311 continue;
314 if (procid_is_me(&ids[idx])) {
315 results[idx] = true;
316 continue;
319 if (procid_is_local(&ids[idx])) {
320 bool exists = process_exists_by_pid(ids[idx].pid);
322 if (!exists) {
323 continue;
326 if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
327 results[idx] = true;
328 continue;
331 verify_idx[verify_num] = idx;
332 verify_num += 1;
333 continue;
336 if (!lp_clustering()) {
337 continue;
340 remote_idx[remote_num] = idx;
341 remote_num += 1;
344 #ifdef HAVE_CTDB_CONTROL_CHECK_SRVIDS_DECL
345 if (remote_num != 0) {
346 int old_remote_num = remote_num;
348 remote_num = 0;
349 todo_num = 0;
351 for (t=0; t<old_remote_num; t++) {
352 idx = remote_idx[t];
354 if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
355 remote_idx[remote_num] = idx;
356 remote_num += 1;
357 continue;
360 todo_idx[todo_num] = idx;
361 todo_ids[todo_num] = ids[idx];
362 todo_results[todo_num] = false;
363 todo_num += 1;
367 * Note: this only uses CTDB_CONTROL_CHECK_SRVIDS
368 * to verify that the server_id still exists,
369 * which means only the server_id.unique_id and
370 * server_id.vnn are verified, while server_id.pid
371 * is not verified at all.
373 * TODO: do we want to verify server_id.pid somehow?
375 if (!ctdb_serverids_exist(messaging_ctdbd_connection(),
376 todo_ids, todo_num, todo_results))
378 goto fail;
381 for (t=0; t<todo_num; t++) {
382 idx = todo_idx[t];
384 results[idx] = todo_results[t];
387 #endif
389 if (remote_num != 0) {
390 todo_num = 0;
392 for (t=0; t<remote_num; t++) {
393 idx = remote_idx[t];
394 todo_idx[todo_num] = idx;
395 todo_ids[todo_num] = ids[idx];
396 todo_results[todo_num] = false;
397 todo_num += 1;
400 #ifdef CLUSTER_SUPPORT
401 if (!ctdb_processes_exist(messaging_ctdbd_connection(),
402 todo_ids, todo_num,
403 todo_results)) {
404 goto fail;
406 #endif
408 for (t=0; t<todo_num; t++) {
409 idx = todo_idx[t];
411 if (!todo_results[t]) {
412 continue;
415 if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
416 results[idx] = true;
417 continue;
420 verify_idx[verify_num] = idx;
421 verify_num += 1;
425 for (t=0; t<verify_num; t++) {
426 struct serverid_exists_state state;
427 struct serverid_key key;
428 TDB_DATA tdbkey;
429 NTSTATUS status;
431 idx = verify_idx[t];
433 serverid_fill_key(&ids[idx], &key);
434 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
436 state.id = &ids[idx];
437 state.exists = false;
438 status = dbwrap_parse_record(db, tdbkey, server_exists_parse, &state);
439 if (!NT_STATUS_IS_OK(status)) {
440 results[idx] = false;
441 continue;
443 results[idx] = state.exists;
446 result = true;
447 fail:
448 TALLOC_FREE(verify_idx);
449 TALLOC_FREE(remote_idx);
450 TALLOC_FREE(todo_results);
451 TALLOC_FREE(todo_ids);
452 TALLOC_FREE(todo_idx);
453 return result;
456 static bool serverid_rec_parse(const struct db_record *rec,
457 struct server_id *id, uint32_t *msg_flags)
459 struct serverid_key key;
460 struct serverid_data data;
461 TDB_DATA tdbkey;
462 TDB_DATA tdbdata;
464 tdbkey = dbwrap_record_get_key(rec);
465 tdbdata = dbwrap_record_get_value(rec);
467 if (tdbkey.dsize != sizeof(key)) {
468 DEBUG(1, ("Found invalid key length %d in serverid.tdb\n",
469 (int)tdbkey.dsize));
470 return false;
472 if (tdbdata.dsize != sizeof(data)) {
473 DEBUG(1, ("Found invalid value length %d in serverid.tdb\n",
474 (int)tdbdata.dsize));
475 return false;
478 memcpy(&key, tdbkey.dptr, sizeof(key));
479 memcpy(&data, tdbdata.dptr, sizeof(data));
481 id->pid = key.pid;
482 id->task_id = key.task_id;
483 id->vnn = key.vnn;
484 id->unique_id = data.unique_id;
485 *msg_flags = data.msg_flags;
486 return true;
489 struct serverid_traverse_read_state {
490 int (*fn)(const struct server_id *id, uint32_t msg_flags,
491 void *private_data);
492 void *private_data;
495 static int serverid_traverse_read_fn(struct db_record *rec, void *private_data)
497 struct serverid_traverse_read_state *state =
498 (struct serverid_traverse_read_state *)private_data;
499 struct server_id id;
500 uint32_t msg_flags;
502 if (!serverid_rec_parse(rec, &id, &msg_flags)) {
503 return 0;
505 return state->fn(&id, msg_flags,state->private_data);
508 bool serverid_traverse_read(int (*fn)(const struct server_id *id,
509 uint32_t msg_flags, void *private_data),
510 void *private_data)
512 struct db_context *db;
513 struct serverid_traverse_read_state state;
514 NTSTATUS status;
516 db = serverid_db();
517 if (db == NULL) {
518 return false;
520 state.fn = fn;
521 state.private_data = private_data;
523 status = dbwrap_traverse_read(db, serverid_traverse_read_fn, &state,
524 NULL);
525 return NT_STATUS_IS_OK(status);
528 struct serverid_traverse_state {
529 int (*fn)(struct db_record *rec, const struct server_id *id,
530 uint32_t msg_flags, void *private_data);
531 void *private_data;
534 static int serverid_traverse_fn(struct db_record *rec, void *private_data)
536 struct serverid_traverse_state *state =
537 (struct serverid_traverse_state *)private_data;
538 struct server_id id;
539 uint32_t msg_flags;
541 if (!serverid_rec_parse(rec, &id, &msg_flags)) {
542 return 0;
544 return state->fn(rec, &id, msg_flags, state->private_data);
547 bool serverid_traverse(int (*fn)(struct db_record *rec,
548 const struct server_id *id,
549 uint32_t msg_flags, void *private_data),
550 void *private_data)
552 struct db_context *db;
553 struct serverid_traverse_state state;
554 NTSTATUS status;
556 db = serverid_db();
557 if (db == NULL) {
558 return false;
560 state.fn = fn;
561 state.private_data = private_data;
563 status = dbwrap_traverse(db, serverid_traverse_fn, &state, NULL);
564 return NT_STATUS_IS_OK(status);
567 uint64_t serverid_get_random_unique_id(void)
569 uint64_t unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
571 while (unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
572 generate_random_buffer((uint8_t *)&unique_id,
573 sizeof(unique_id));
576 return unique_id;