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"
42 static int ctdb_client_connect(struct ctdb_client_context
*client
,
43 struct tevent_context
*ev
,
44 const char *sockpath
);
46 static int ctdb_client_context_destructor(struct ctdb_client_context
*client
);
48 int ctdb_client_init(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
49 const char *sockpath
, struct ctdb_client_context
**out
)
51 struct ctdb_client_context
*client
;
54 client
= talloc_zero(mem_ctx
, struct ctdb_client_context
);
56 DEBUG(DEBUG_ERR
, (__location__
" memory allocation error\n"));
60 ret
= reqid_init(client
, INT_MAX
-200, &client
->idr
);
62 DEBUG(DEBUG_ERR
, ("reqid_init() failed, ret=%d\n", ret
));
67 ret
= srvid_init(client
, &client
->srv
);
69 DEBUG(DEBUG_ERR
, ("srvid_init() failed, ret=%d\n", ret
));
75 client
->pnn
= CTDB_UNKNOWN_PNN
;
77 ret
= ctdb_client_connect(client
, ev
, sockpath
);
83 talloc_set_destructor(client
, ctdb_client_context_destructor
);
89 static int ctdb_client_context_destructor(struct ctdb_client_context
*client
)
91 if (client
->fd
!= -1) {
98 static void client_read_handler(uint8_t *buf
, size_t buflen
,
100 static void client_dead_handler(void *private_data
);
102 static int ctdb_client_connect(struct ctdb_client_context
*client
,
103 struct tevent_context
*ev
, const char *sockpath
)
105 struct sockaddr_un addr
;
109 if (sockpath
== NULL
) {
110 DEBUG(DEBUG_ERR
, ("socket path cannot be NULL\n"));
114 memset(&addr
, 0, sizeof(addr
));
115 addr
.sun_family
= AF_UNIX
;
116 len
= strlcpy(addr
.sun_path
, sockpath
, sizeof(addr
.sun_path
));
117 if (len
!= strlen(sockpath
)) {
118 DEBUG(DEBUG_ERR
, ("socket path too long, len=%zu\n",
123 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
126 DEBUG(DEBUG_ERR
, ("socket() failed, errno=%d\n", ret
));
130 ret
= connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
133 DEBUG(DEBUG_ERR
, ("connect() failed, errno=%d\n", ret
));
139 ret
= comm_setup(client
, ev
, fd
, client_read_handler
, client
,
140 client_dead_handler
, client
, &client
->comm
);
142 DEBUG(DEBUG_ERR
, ("comm_setup() failed, ret=%d\n", ret
));
148 ret
= ctdb_ctrl_get_pnn(client
, ev
, client
, CTDB_CURRENT_NODE
,
149 tevent_timeval_zero(), &client
->pnn
);
151 DEBUG(DEBUG_ERR
, ("failed to get current node pnn\n"));
154 TALLOC_FREE(client
->comm
);
161 static void client_read_handler(uint8_t *buf
, size_t buflen
,
164 struct ctdb_client_context
*client
= talloc_get_type_abort(
165 private_data
, struct ctdb_client_context
);
166 struct ctdb_req_header hdr
;
169 ret
= ctdb_req_header_pull(discard_const(buf
), buflen
, &hdr
);
171 DEBUG(DEBUG_WARNING
, ("invalid header, ret=%d\n", ret
));
175 if (buflen
!= hdr
.length
) {
176 DEBUG(DEBUG_WARNING
, ("packet size mismatch %zu != %d\n",
177 buflen
, hdr
.length
));
181 ret
= ctdb_req_header_verify(&hdr
, 0);
183 DEBUG(DEBUG_WARNING
, ("invalid header, ret=%d\n", ret
));
187 switch (hdr
.operation
) {
188 case CTDB_REPLY_CALL
:
189 ctdb_client_reply_call(client
, buf
, buflen
, hdr
.reqid
);
192 case CTDB_REQ_MESSAGE
:
193 ctdb_client_req_message(client
, buf
, buflen
, hdr
.reqid
);
196 case CTDB_REPLY_CONTROL
:
197 ctdb_client_reply_control(client
, buf
, buflen
, hdr
.reqid
);
205 static void client_dead_handler(void *private_data
)
207 struct ctdb_client_context
*client
= talloc_get_type_abort(
208 private_data
, struct ctdb_client_context
);
209 ctdb_client_callback_func_t callback
= client
->callback
;
210 void *callback_data
= client
->private_data
;
213 if (callback
!= NULL
) {
214 callback(callback_data
);
218 DEBUG(DEBUG_NOTICE
, ("connection to daemon closed, exiting\n"));
222 void ctdb_client_set_disconnect_callback(struct ctdb_client_context
*client
,
223 ctdb_client_callback_func_t callback
,
226 client
->callback
= callback
;
227 client
->private_data
= private_data
;
230 uint32_t ctdb_client_pnn(struct ctdb_client_context
*client
)
235 void ctdb_client_wait(struct tevent_context
*ev
, bool *done
)
238 tevent_loop_once(ev
);
242 struct ctdb_recovery_wait_state
{
243 struct tevent_context
*ev
;
244 struct ctdb_client_context
*client
;
247 static void ctdb_recovery_wait_retry(struct tevent_req
*subreq
);
249 struct tevent_req
*ctdb_recovery_wait_send(TALLOC_CTX
*mem_ctx
,
250 struct tevent_context
*ev
,
251 struct ctdb_client_context
*client
)
253 struct tevent_req
*req
, *subreq
;
254 struct ctdb_recovery_wait_state
*state
;
258 req
= tevent_req_create(mem_ctx
, &state
,
259 struct ctdb_recovery_wait_state
);
265 state
->client
= client
;
267 ret
= ctdb_ctrl_get_recmode(client
, ev
, client
, client
->pnn
,
268 tevent_timeval_zero(), &recmode
);
270 tevent_req_error(req
, ret
);
271 return tevent_req_post(req
, ev
);
274 if (recmode
== CTDB_RECOVERY_NORMAL
) {
275 tevent_req_done(req
);
276 return tevent_req_post(req
, ev
);
279 subreq
= tevent_wakeup_send(state
, ev
,
280 tevent_timeval_current_ofs(1, 0));
281 if (tevent_req_nomem(subreq
, req
)) {
282 return tevent_req_post(req
, ev
);
284 tevent_req_set_callback(subreq
, ctdb_recovery_wait_retry
, req
);
289 static void ctdb_recovery_wait_retry(struct tevent_req
*subreq
)
291 struct tevent_req
*req
= tevent_req_callback_data(
292 subreq
, struct tevent_req
);
293 struct ctdb_recovery_wait_state
*state
= tevent_req_data(
294 req
, struct ctdb_recovery_wait_state
);
298 status
= tevent_wakeup_recv(subreq
);
301 tevent_req_error(req
, ENOMEM
);
305 ret
= ctdb_ctrl_get_recmode(state
, state
->ev
, state
->client
,
306 ctdb_client_pnn(state
->client
),
307 tevent_timeval_zero(), &recmode
);
309 tevent_req_error(req
, ret
);
313 if (recmode
== CTDB_RECOVERY_NORMAL
) {
314 tevent_req_done(req
);
318 subreq
= tevent_wakeup_send(state
, state
->ev
,
319 tevent_timeval_current_ofs(1, 0));
320 if (tevent_req_nomem(subreq
, req
)) {
323 tevent_req_set_callback(subreq
, ctdb_recovery_wait_retry
, req
);
326 bool ctdb_recovery_wait_recv(struct tevent_req
*req
, int *perr
)
330 if (tevent_req_is_unix_error(req
, &err
)) {