4 Copyright (C) Amitay Isaacs 2015
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/>.
21 #include "system/network.h"
22 #include "system/filesys.h"
28 #include "common/reqid.h"
29 #include "common/srvid.h"
30 #include "common/comm.h"
31 #include "common/logging.h"
33 #include "lib/util/tevent_unix.h"
34 #include "lib/util/debug.h"
36 #include "protocol/protocol.h"
37 #include "protocol/protocol_api.h"
39 #include "client/client_private.h"
40 #include "client/client.h"
41 #include "client/client_sync.h"
43 static void client_read_handler(uint8_t *buf
, size_t buflen
,
45 static void client_dead_handler(void *private_data
);
47 struct ctdb_client_init_state
{
48 struct ctdb_client_context
*client
;
51 static int ctdb_client_context_destructor(struct ctdb_client_context
*client
);
52 static void ctdb_client_init_done(struct tevent_req
*subreq
);
54 struct tevent_req
*ctdb_client_init_send(TALLOC_CTX
*mem_ctx
,
55 struct tevent_context
*ev
,
58 struct tevent_req
*req
, *subreq
;
59 struct ctdb_client_init_state
*state
;
60 struct ctdb_client_context
*client
;
61 struct ctdb_req_control request
;
62 struct sockaddr_un addr
;
66 req
= tevent_req_create(mem_ctx
, &state
,
67 struct ctdb_client_init_state
);
72 if (sockpath
== NULL
) {
73 D_ERR("socket path cannot be NULL\n");
74 tevent_req_error(req
, EINVAL
);
75 return tevent_req_post(req
, ev
);
78 client
= talloc_zero(state
, struct ctdb_client_context
);
79 if (tevent_req_nomem(client
, req
)) {
80 return tevent_req_post(req
, ev
);
83 ret
= reqid_init(client
, INT_MAX
-200, &client
->idr
);
85 D_ERR("reqid_init() failed, ret=%d\n", ret
);
87 tevent_req_error(req
, ret
);
88 return tevent_req_post(req
, ev
);
91 ret
= srvid_init(client
, &client
->srv
);
93 DEBUG(DEBUG_ERR
, ("srvid_init() failed, ret=%d\n", ret
));
95 tevent_req_error(req
, ret
);
96 return tevent_req_post(req
, ev
);
99 ret
= srvid_init(client
, &client
->tunnels
);
101 DEBUG(DEBUG_ERR
, ("srvid_init() failed, ret=%d\n", ret
));
103 tevent_req_error(req
, ret
);
104 return tevent_req_post(req
, ev
);
107 memset(&addr
, 0, sizeof(addr
));
108 addr
.sun_family
= AF_UNIX
;
109 len
= strlcpy(addr
.sun_path
, sockpath
, sizeof(addr
.sun_path
));
110 if (len
!= strlen(sockpath
)) {
111 D_ERR("socket path too long, len=%zu\n", strlen(sockpath
));
113 tevent_req_error(req
, ENAMETOOLONG
);
114 return tevent_req_post(req
, ev
);
117 client
->fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
118 if (client
->fd
== -1) {
120 D_ERR("socket() failed, errno=%d\n", ret
);
122 tevent_req_error(req
, ret
);
123 return tevent_req_post(req
, ev
);
126 ret
= connect(client
->fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
129 DEBUG(DEBUG_ERR
, ("connect() failed, errno=%d\n", ret
));
132 tevent_req_error(req
, ret
);
133 return tevent_req_post(req
, ev
);
136 ret
= comm_setup(client
, ev
, client
->fd
, client_read_handler
, client
,
137 client_dead_handler
, client
, &client
->comm
);
139 DEBUG(DEBUG_ERR
, ("comm_setup() failed, ret=%d\n", ret
));
142 tevent_req_error(req
, ret
);
143 return tevent_req_post(req
, ev
);
146 client
->pnn
= CTDB_UNKNOWN_PNN
;
148 talloc_set_destructor(client
, ctdb_client_context_destructor
);
150 state
->client
= client
;
152 ctdb_req_control_get_pnn(&request
);
153 subreq
= ctdb_client_control_send(state
, ev
, client
,
155 tevent_timeval_zero(),
157 if (tevent_req_nomem(subreq
, req
)) {
158 TALLOC_FREE(state
->client
);
159 return tevent_req_post(req
, ev
);
161 tevent_req_set_callback(subreq
, ctdb_client_init_done
, req
);
166 static int ctdb_client_context_destructor(struct ctdb_client_context
*client
)
168 if (client
->fd
!= -1) {
175 static void ctdb_client_init_done(struct tevent_req
*subreq
)
177 struct tevent_req
*req
= tevent_req_callback_data(
178 subreq
, struct tevent_req
);
179 struct ctdb_client_init_state
*state
= tevent_req_data(
180 req
, struct ctdb_client_init_state
);
181 struct ctdb_reply_control
*reply
;
185 status
= ctdb_client_control_recv(subreq
, &ret
, state
, &reply
);
188 tevent_req_error(req
, ret
);
192 ret
= ctdb_reply_control_get_pnn(reply
, &state
->client
->pnn
);
194 tevent_req_error(req
, ret
);
198 tevent_req_done(req
);
201 bool ctdb_client_init_recv(struct tevent_req
*req
, int *perr
,
203 struct ctdb_client_context
**result
)
205 struct ctdb_client_init_state
*state
= tevent_req_data(
206 req
, struct ctdb_client_init_state
);
209 if (tevent_req_is_unix_error(req
, &ret
)) {
216 *result
= talloc_steal(mem_ctx
, state
->client
);
221 int ctdb_client_init(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
222 const char *sockpath
, struct ctdb_client_context
**out
)
224 struct tevent_req
*req
;
228 req
= ctdb_client_init_send(mem_ctx
, ev
, sockpath
);
233 tevent_req_poll(req
, ev
);
235 status
= ctdb_client_init_recv(req
, &ret
, mem_ctx
, out
);
244 static void client_read_handler(uint8_t *buf
, size_t buflen
,
247 struct ctdb_client_context
*client
= talloc_get_type_abort(
248 private_data
, struct ctdb_client_context
);
249 struct ctdb_req_header hdr
;
253 ret
= ctdb_req_header_pull(buf
, buflen
, &hdr
, &np
);
255 DEBUG(DEBUG_WARNING
, ("invalid header, ret=%d\n", ret
));
259 if (buflen
!= hdr
.length
) {
260 DEBUG(DEBUG_WARNING
, ("packet size mismatch %zu != %d\n",
261 buflen
, hdr
.length
));
265 ret
= ctdb_req_header_verify(&hdr
, 0);
267 DEBUG(DEBUG_WARNING
, ("invalid header, ret=%d\n", ret
));
271 switch (hdr
.operation
) {
272 case CTDB_REPLY_CALL
:
273 ctdb_client_reply_call(client
, buf
, buflen
, hdr
.reqid
);
276 case CTDB_REQ_MESSAGE
:
277 ctdb_client_req_message(client
, buf
, buflen
, hdr
.reqid
);
280 case CTDB_REPLY_CONTROL
:
281 ctdb_client_reply_control(client
, buf
, buflen
, hdr
.reqid
);
284 case CTDB_REQ_TUNNEL
:
285 ctdb_client_req_tunnel(client
, buf
, buflen
, hdr
.reqid
);
293 static void client_dead_handler(void *private_data
)
295 struct ctdb_client_context
*client
= talloc_get_type_abort(
296 private_data
, struct ctdb_client_context
);
297 ctdb_client_callback_func_t callback
= client
->callback
;
298 void *callback_data
= client
->private_data
;
300 if (callback
!= NULL
) {
301 callback(callback_data
);
305 DEBUG(DEBUG_NOTICE
, ("connection to daemon closed, exiting\n"));
309 void ctdb_client_set_disconnect_callback(struct ctdb_client_context
*client
,
310 ctdb_client_callback_func_t callback
,
313 client
->callback
= callback
;
314 client
->private_data
= private_data
;
317 uint32_t ctdb_client_pnn(struct ctdb_client_context
*client
)
322 void ctdb_client_wait(struct tevent_context
*ev
, bool *done
)
325 tevent_loop_once(ev
);
329 static void ctdb_client_wait_timeout_handler(struct tevent_context
*ev
,
330 struct tevent_timer
*te
,
334 bool *timed_out
= (bool *)private_data
;
339 int ctdb_client_wait_func_timeout(struct tevent_context
*ev
,
340 bool (*done_func
)(void *private_data
),
342 struct timeval timeout
)
345 struct tevent_timer
*timer
;
346 bool timed_out
= false;
348 mem_ctx
= talloc_new(ev
);
349 if (mem_ctx
== NULL
) {
353 timer
= tevent_add_timer(ev
, mem_ctx
, timeout
,
354 ctdb_client_wait_timeout_handler
,
357 talloc_free(mem_ctx
);
361 while (! (done_func(private_data
)) && ! timed_out
) {
362 tevent_loop_once(ev
);
365 talloc_free(mem_ctx
);
374 static bool client_wait_done(void *private_data
)
376 bool *done
= (bool *)private_data
;
381 int ctdb_client_wait_timeout(struct tevent_context
*ev
,
383 struct timeval timeout
)
388 ret
= ctdb_client_wait_func_timeout(ev
,
396 struct ctdb_recovery_wait_state
{
397 struct tevent_context
*ev
;
398 struct ctdb_client_context
*client
;
401 static void ctdb_recovery_wait_recmode(struct tevent_req
*subreq
);
402 static void ctdb_recovery_wait_retry(struct tevent_req
*subreq
);
404 struct tevent_req
*ctdb_recovery_wait_send(TALLOC_CTX
*mem_ctx
,
405 struct tevent_context
*ev
,
406 struct ctdb_client_context
*client
)
408 struct tevent_req
*req
, *subreq
;
409 struct ctdb_recovery_wait_state
*state
;
410 struct ctdb_req_control request
;
412 req
= tevent_req_create(mem_ctx
, &state
,
413 struct ctdb_recovery_wait_state
);
419 state
->client
= client
;
421 ctdb_req_control_get_recmode(&request
);
422 subreq
= ctdb_client_control_send(state
, ev
, client
, client
->pnn
,
423 tevent_timeval_zero(), &request
);
424 if (tevent_req_nomem(subreq
, req
)) {
425 return tevent_req_post(req
, ev
);
427 tevent_req_set_callback(subreq
, ctdb_recovery_wait_recmode
, req
);
432 static void ctdb_recovery_wait_recmode(struct tevent_req
*subreq
)
434 struct tevent_req
*req
= tevent_req_callback_data(
435 subreq
, struct tevent_req
);
436 struct ctdb_recovery_wait_state
*state
= tevent_req_data(
437 req
, struct ctdb_recovery_wait_state
);
438 struct ctdb_reply_control
*reply
;
443 status
= ctdb_client_control_recv(subreq
, &ret
, state
, &reply
);
446 tevent_req_error(req
, ret
);
450 ret
= ctdb_reply_control_get_recmode(reply
, &recmode
);
452 tevent_req_error(req
, ret
);
456 if (recmode
== CTDB_RECOVERY_NORMAL
) {
457 tevent_req_done(req
);
461 subreq
= tevent_wakeup_send(state
, state
->ev
,
462 tevent_timeval_current_ofs(1, 0));
463 if (tevent_req_nomem(subreq
, req
)) {
466 tevent_req_set_callback(subreq
, ctdb_recovery_wait_retry
, req
);
469 static void ctdb_recovery_wait_retry(struct tevent_req
*subreq
)
471 struct tevent_req
*req
= tevent_req_callback_data(
472 subreq
, struct tevent_req
);
473 struct ctdb_recovery_wait_state
*state
= tevent_req_data(
474 req
, struct ctdb_recovery_wait_state
);
475 struct ctdb_req_control request
;
478 status
= tevent_wakeup_recv(subreq
);
481 tevent_req_error(req
, ENOMEM
);
485 ctdb_req_control_get_recmode(&request
);
486 subreq
= ctdb_client_control_send(state
, state
->ev
, state
->client
,
488 tevent_timeval_zero(), &request
);
489 if (tevent_req_nomem(subreq
, req
)) {
492 tevent_req_set_callback(subreq
, ctdb_recovery_wait_recmode
, req
);
495 bool ctdb_recovery_wait_recv(struct tevent_req
*req
, int *perr
)
499 if (tevent_req_is_unix_error(req
, &err
)) {
509 bool ctdb_recovery_wait(struct tevent_context
*ev
,
510 struct ctdb_client_context
*client
)
513 struct tevent_req
*req
;
516 mem_ctx
= talloc_new(client
);
517 if (mem_ctx
== NULL
) {
521 req
= ctdb_recovery_wait_send(mem_ctx
, ev
, client
);
526 tevent_req_poll(req
, ev
);
528 status
= ctdb_recovery_wait_recv(req
, NULL
);
530 talloc_free(mem_ctx
);