ctdb-client: Remove support for SET_RECLOCK
[kai/samba-autobuild/.git] / ctdb / client / client_message.c
1 /*
2    CTDB client code
3
4    Copyright (C) Amitay Isaacs  2015
5
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.
10
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.
15
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/>.
18 */
19
20 #include "replace.h"
21 #include "system/network.h"
22 #include "system/filesys.h"
23
24 #include <talloc.h>
25 #include <tevent.h>
26 #include <tdb.h>
27
28 #include "lib/util/tevent_unix.h"
29
30 #include "common/reqid.h"
31 #include "common/srvid.h"
32 #include "common/comm.h"
33
34 #include "protocol/protocol.h"
35 #include "protocol/protocol_api.h"
36
37 #include "client/client_private.h"
38 #include "client/client.h"
39
40
41 /*
42  * Handle REQ_MESSAGE
43  */
44
45 struct ctdb_client_message_state {
46         struct ctdb_client_context *client;
47         uint32_t reqid;
48 };
49
50 static int ctdb_client_message_state_destructor(
51         struct ctdb_client_message_state *state);
52 static void ctdb_client_message_done(struct tevent_req *subreq);
53
54 struct tevent_req *ctdb_client_message_send(TALLOC_CTX *mem_ctx,
55                                             struct tevent_context *ev,
56                                             struct ctdb_client_context *client,
57                                             uint32_t destnode,
58                                             struct ctdb_req_message *message)
59 {
60         struct tevent_req *req, *subreq;
61         struct ctdb_client_message_state *state;
62         struct ctdb_req_header h;
63         uint32_t reqid;
64         uint8_t *buf;
65         size_t datalen, buflen;
66         int ret;
67
68         req = tevent_req_create(mem_ctx, &state,
69                                 struct ctdb_client_message_state);
70         if (req == NULL) {
71                 return NULL;
72         }
73
74         reqid = reqid_new(client->idr, state);
75         if (reqid == REQID_INVALID) {
76                 talloc_free(req);
77                 return NULL;
78         }
79
80         state->client = client;
81         state->reqid = reqid;
82
83         talloc_set_destructor(state, ctdb_client_message_state_destructor);
84
85         ctdb_req_header_fill(&h, 0, CTDB_REQ_MESSAGE, destnode,
86                              client->pnn, reqid);
87
88         datalen = ctdb_req_message_len(&h, message);
89         ret = ctdb_allocate_pkt(state, datalen, &buf, &buflen);
90         if (ret != 0) {
91                 tevent_req_error(req, ret);
92                 return tevent_req_post(req, ev);
93         }
94
95         ret = ctdb_req_message_push(&h, message, buf, &buflen);
96         if (ret != 0) {
97                 tevent_req_error(req, ret);
98                 return tevent_req_post(req, ev);
99         }
100
101         subreq = comm_write_send(state, ev, client->comm, buf, buflen);
102         if (tevent_req_nomem(subreq, req)) {
103                 return tevent_req_post(req, ev);
104         }
105         tevent_req_set_callback(subreq, ctdb_client_message_done, req);
106
107         return req;
108 }
109
110 static int ctdb_client_message_state_destructor(
111         struct ctdb_client_message_state *state)
112 {
113         reqid_remove(state->client->idr, state->reqid);
114         return 0;
115 }
116
117 static void ctdb_client_message_done(struct tevent_req *subreq)
118 {
119         struct tevent_req *req = tevent_req_callback_data(
120                 subreq, struct tevent_req);
121         int ret;
122         bool status;
123
124         status = comm_write_recv(subreq, &ret);
125         TALLOC_FREE(subreq);
126         if (! status) {
127                 tevent_req_error(req, ret);
128                 return;
129         }
130
131         tevent_req_done(req);
132 }
133
134 bool ctdb_client_message_recv(struct tevent_req *req, int *perr)
135 {
136         int err;
137
138         if (tevent_req_is_unix_error(req, &err)) {
139                 if (perr != NULL) {
140                         *perr = err;
141                 }
142                 return false;
143         }
144
145         return true;
146 }
147
148 void ctdb_client_req_message(struct ctdb_client_context *client,
149                              uint8_t *buf, size_t buflen, uint32_t reqid)
150 {
151         struct ctdb_req_header h;
152         struct ctdb_req_message_data message;
153         TALLOC_CTX *tmp_ctx = talloc_new(client);
154         int ret;
155
156         ret = ctdb_req_message_data_pull(buf, buflen, &h, tmp_ctx, &message);
157         if (ret != 0) {
158                 return;
159         }
160
161         srvid_dispatch(client->srv, message.srvid, CTDB_SRVID_ALL,
162                        message.data);
163         talloc_free(tmp_ctx);
164 }
165
166 /*
167  * Handle multiple nodes
168  */
169
170 struct ctdb_client_message_multi_state {
171         uint32_t *pnn_list;
172         int count;
173         int done;
174         int err;
175         int *err_list;
176 };
177
178 struct message_index_state {
179         struct tevent_req *req;
180         int index;
181 };
182
183 static void ctdb_client_message_multi_done(struct tevent_req *subreq);
184
185 struct tevent_req *ctdb_client_message_multi_send(
186                                 TALLOC_CTX *mem_ctx,
187                                 struct tevent_context *ev,
188                                 struct ctdb_client_context *client,
189                                 uint32_t *pnn_list, int count,
190                                 struct ctdb_req_message *message)
191 {
192         struct tevent_req *req, *subreq;
193         struct ctdb_client_message_multi_state *state;
194         int i;
195
196         if (pnn_list == NULL || count == 0) {
197                 return NULL;
198         }
199
200         req = tevent_req_create(mem_ctx, &state,
201                                 struct ctdb_client_message_multi_state);
202         if (req == NULL) {
203                 return NULL;
204         }
205
206         state->pnn_list = pnn_list;
207         state->count = count;
208         state->done = 0;
209         state->err = 0;
210         state->err_list = talloc_zero_array(state, int, count);
211         if (tevent_req_nomem(state->err_list, req)) {
212                 return tevent_req_post(req, ev);
213         }
214
215         for (i=0; i<count; i++) {
216                 struct message_index_state *substate;
217
218                 subreq = ctdb_client_message_send(state, ev, client,
219                                                   pnn_list[i], message);
220                 if (tevent_req_nomem(subreq, req)) {
221                         return tevent_req_post(req, ev);
222                 }
223
224                 substate = talloc(subreq, struct message_index_state);
225                 if (tevent_req_nomem(substate, req)) {
226                         return tevent_req_post(req, ev);
227                 }
228
229                 substate->req = req;
230                 substate->index = i;
231
232                 tevent_req_set_callback(subreq, ctdb_client_message_multi_done,
233                                         substate);
234         }
235
236         return req;
237 }
238
239 static void ctdb_client_message_multi_done(struct tevent_req *subreq)
240 {
241         struct message_index_state *substate = tevent_req_callback_data(
242                 subreq, struct message_index_state);
243         struct tevent_req *req = substate->req;
244         int idx = substate->index;
245         struct ctdb_client_message_multi_state *state = tevent_req_data(
246                 req, struct ctdb_client_message_multi_state);
247         bool status;
248         int ret;
249
250         status = ctdb_client_message_recv(subreq, &ret);
251         TALLOC_FREE(subreq);
252         if (! status) {
253                 if (state->err == 0) {
254                         state->err = ret;
255                         state->err_list[idx] = state->err;
256                 }
257         }
258
259         state->done += 1;
260
261         if (state->done == state->count) {
262                 tevent_req_done(req);
263         }
264 }
265
266 bool ctdb_client_message_multi_recv(struct tevent_req *req, int *perr,
267                                     TALLOC_CTX *mem_ctx, int **perr_list)
268 {
269         struct ctdb_client_message_multi_state *state = tevent_req_data(
270                 req, struct ctdb_client_message_multi_state);
271         int err;
272
273         if (tevent_req_is_unix_error(req, &err)) {
274                 if (perr != NULL) {
275                         *perr = err;
276                 }
277                 if (perr_list != NULL) {
278                         *perr_list = talloc_steal(mem_ctx, state->err_list);
279                 }
280                 return false;
281         }
282
283         if (perr != NULL) {
284                 *perr = state->err;
285         }
286
287         if (perr_list != NULL) {
288                 *perr_list = talloc_steal(mem_ctx, state->err_list);
289         }
290
291         if (state->err != 0) {
292                 return false;
293         }
294
295         return true;
296 }
297
298 /*
299  * sync version of message send
300  */
301
302 int ctdb_client_message(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
303                         struct ctdb_client_context *client,
304                         uint32_t destnode, struct ctdb_req_message *message)
305 {
306         TALLOC_CTX *tmp_ctx;
307         struct tevent_req *req;
308         int ret;
309         bool status;
310
311         tmp_ctx = talloc_new(client);
312         if (tmp_ctx == NULL) {
313                 return ENOMEM;
314         }
315
316         req = ctdb_client_message_send(tmp_ctx, ev, client, destnode, message);
317         if (req == NULL) {
318                 talloc_free(tmp_ctx);
319                 return ENOMEM;
320         }
321
322         tevent_req_poll(req, ev);
323
324         status = ctdb_client_message_recv(req, &ret);
325         if (! status) {
326                 talloc_free(tmp_ctx);
327                 return ret;
328         }
329
330         talloc_free(tmp_ctx);
331         return 0;
332 }
333
334 struct ctdb_client_set_message_handler_state {
335         struct ctdb_client_context *client;
336         uint64_t srvid;
337         srvid_handler_fn handler;
338         void *private_data;
339 };
340
341 static void ctdb_client_set_message_handler_done(struct tevent_req *subreq);
342
343 struct tevent_req *ctdb_client_set_message_handler_send(
344                                         TALLOC_CTX *mem_ctx,
345                                         struct tevent_context *ev,
346                                         struct ctdb_client_context *client,
347                                         uint64_t srvid,
348                                         srvid_handler_fn handler,
349                                         void *private_data)
350 {
351         struct tevent_req *req, *subreq;
352         struct ctdb_client_set_message_handler_state *state;
353         struct ctdb_req_control request;
354
355         req = tevent_req_create(mem_ctx, &state,
356                                 struct ctdb_client_set_message_handler_state);
357         if (req == NULL) {
358                 return NULL;
359         }
360
361         state->client = client;
362         state->srvid = srvid;
363         state->handler = handler;
364         state->private_data = private_data;
365
366         ctdb_req_control_register_srvid(&request, srvid);
367         subreq = ctdb_client_control_send(state, ev, client, client->pnn,
368                                           tevent_timeval_zero(), &request);
369         if (tevent_req_nomem(subreq, req)) {
370                 return tevent_req_post(req, ev);
371         }
372         tevent_req_set_callback(subreq, ctdb_client_set_message_handler_done,
373                                 req);
374
375         return req;
376 }
377
378 static void ctdb_client_set_message_handler_done(struct tevent_req *subreq)
379 {
380         struct tevent_req *req = tevent_req_callback_data(
381                 subreq, struct tevent_req);
382         struct ctdb_client_set_message_handler_state *state = tevent_req_data(
383                 req, struct ctdb_client_set_message_handler_state);
384         struct ctdb_reply_control *reply;
385         bool status;
386         int ret;
387
388         status = ctdb_client_control_recv(subreq, &ret, state, &reply);
389         TALLOC_FREE(subreq);
390         if (! status) {
391                 tevent_req_error(req, ret);
392                 return;
393         }
394
395         ret = ctdb_reply_control_register_srvid(reply);
396         talloc_free(reply);
397         if (ret != 0) {
398                 tevent_req_error(req, ret);
399                 return;
400         }
401
402         ret = srvid_register(state->client->srv, state->client, state->srvid,
403                              state->handler, state->private_data);
404         if (ret != 0) {
405                 tevent_req_error(req, ret);
406                 return;
407         }
408
409         tevent_req_done(req);
410 }
411
412 bool ctdb_client_set_message_handler_recv(struct tevent_req *req, int *perr)
413 {
414         int err;
415
416         if (tevent_req_is_unix_error(req, &err)) {
417                 if (perr != NULL) {
418                         *perr = err;
419                 }
420                 return false;
421         }
422         return true;
423 }
424
425 struct ctdb_client_remove_message_handler_state {
426         struct ctdb_client_context *client;
427         uint64_t srvid;
428         void *private_data;
429 };
430
431 static void ctdb_client_remove_message_handler_done(struct tevent_req *subreq);
432
433 struct tevent_req *ctdb_client_remove_message_handler_send(
434                                         TALLOC_CTX *mem_ctx,
435                                         struct tevent_context *ev,
436                                         struct ctdb_client_context *client,
437                                         uint64_t srvid,
438                                         void *private_data)
439 {
440         struct tevent_req *req, *subreq;
441         struct ctdb_client_remove_message_handler_state *state;
442         struct ctdb_req_control request;
443
444         req = tevent_req_create(mem_ctx, &state,
445                                 struct ctdb_client_remove_message_handler_state);
446         if (req == NULL) {
447                 return NULL;
448         }
449
450         state->client = client;
451         state->srvid = srvid;
452         state->private_data = private_data;
453
454         ctdb_req_control_deregister_srvid(&request, srvid);
455         subreq = ctdb_client_control_send(state, ev, client, client->pnn,
456                                           tevent_timeval_zero(), &request);
457         if (tevent_req_nomem(subreq, req)) {
458                 return tevent_req_post(req, ev);
459         }
460         tevent_req_set_callback(subreq,
461                                 ctdb_client_remove_message_handler_done, req);
462
463         return req;
464 }
465
466 static void ctdb_client_remove_message_handler_done(struct tevent_req *subreq)
467 {
468         struct tevent_req *req = tevent_req_callback_data(
469                 subreq, struct tevent_req);
470         struct ctdb_client_remove_message_handler_state *state = tevent_req_data(
471                 req, struct ctdb_client_remove_message_handler_state);
472         struct ctdb_reply_control *reply;
473         bool status;
474         int ret;
475
476         status = ctdb_client_control_recv(subreq, &ret, state, &reply);
477         TALLOC_FREE(subreq);
478         if (! status) {
479                 tevent_req_error(req, ret);
480                 return;
481         }
482
483         ret = ctdb_reply_control_deregister_srvid(reply);
484         talloc_free(reply);
485         if (ret != 0) {
486                 tevent_req_error(req, ret);
487                 return;
488         }
489
490         ret = srvid_deregister(state->client->srv, state->srvid,
491                                state->private_data);
492         if (ret != 0) {
493                 tevent_req_error(req, ret);
494                 return;
495         }
496
497         tevent_req_done(req);
498 }
499
500 bool ctdb_client_remove_message_handler_recv(struct tevent_req *req, int *perr)
501 {
502         int err;
503
504         if (tevent_req_is_unix_error(req, &err)) {
505                 if (perr != NULL) {
506                         *perr = err;
507                 }
508                 return false;
509         }
510         return true;
511 }
512
513 int ctdb_client_set_message_handler(struct tevent_context *ev,
514                                     struct ctdb_client_context *client,
515                                     uint64_t srvid, srvid_handler_fn handler,
516                                     void *private_data)
517 {
518         TALLOC_CTX *mem_ctx;
519         int ret;
520
521         mem_ctx = talloc_new(client);
522         if (mem_ctx == NULL) {
523                 return ENOMEM;
524         }
525
526         ret = ctdb_ctrl_register_srvid(mem_ctx, ev, client, client->pnn,
527                                        tevent_timeval_zero(), srvid);
528         talloc_free(mem_ctx);
529         if (ret != 0) {
530                 return ret;
531         }
532
533         return srvid_register(client->srv, client, srvid,
534                               handler, private_data);
535 }
536
537 int ctdb_client_remove_message_handler(struct tevent_context *ev,
538                                        struct ctdb_client_context *client,
539                                        uint64_t srvid, void *private_data)
540 {
541         TALLOC_CTX *mem_ctx;
542         int ret;
543
544         mem_ctx = talloc_new(client);
545         if (mem_ctx == NULL) {
546                 return ENOMEM;
547         }
548
549         ret = ctdb_ctrl_deregister_srvid(mem_ctx, ev, client, client->pnn,
550                                          tevent_timeval_zero(), srvid);
551         talloc_free(mem_ctx);
552         if (ret != 0) {
553                 return ret;
554         }
555
556         return srvid_deregister(client->srv, srvid, private_data);
557 }