254be93f45da851f8cf053d72deff43a7148f9fa
[sahlberg/ctdb.git] / libctdb / libctdb.c
1 /* 
2    ctdb database library
3    Utility functions to connect to the ctdb daemon
4
5    Copyright (C) Andrew Tridgell  2006
6    Copyright (C) Ronnie sahlberg  2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <poll.h>
23 #include "includes.h"
24 #include "lib/events/events.h"
25 #include "include/ctdb.h"
26 #include "include/ctdb_protocol.h"
27 #include "include/ctdb_private.h"
28
29 struct ctdb_context *ctdb_connect(const char *addr)
30 {
31         struct event_context *ev;
32         struct ctdb_context *ctdb;
33         int ret;
34
35         ev = event_context_init(NULL);
36
37         /* initialise ctdb */
38         ctdb = ctdb_init(ev);
39         if (ctdb == NULL) {
40                 fprintf(stderr, "Failed to init ctdb\n");
41                 exit(1);
42         }
43
44         ret = ctdb_set_socketname(ctdb, addr);
45         if (ret == -1) {
46                 fprintf(stderr, __location__ " ctdb_set_socketname failed - %s\n", ctdb_errstr(ctdb));
47                 talloc_free(ctdb);
48                 exit(1);
49         }
50
51         ret = ctdb_socket_connect(ctdb);
52         if (ret != 0) {
53                 fprintf(stderr, __location__ " Failed to connect to daemon\n");
54                 talloc_free(ctdb);
55                 return NULL;
56         }
57
58         return ctdb;
59 }
60
61
62 int ctdb_get_fd(struct ctdb_context *ctdb)
63 {
64         return ctdb->daemon.sd;
65 }
66
67 int ctdb_which_events(struct ctdb_context *ctdb)
68 {
69         if (ctdb_queue_length(ctdb->daemon.queue) > 0) {
70                 return POLLIN|POLLOUT;
71         }
72
73         return POLLIN;
74 }
75
76
77
78 /*
79   initialise the ctdb daemon for client applications
80 */
81 struct ctdb_context *ctdb_init(struct event_context *ev)
82 {
83         int ret;
84         struct ctdb_context *ctdb;
85
86         ctdb = talloc_zero(ev, struct ctdb_context);
87         if (ctdb == NULL) {
88                 DEBUG(DEBUG_ERR,(__location__ " talloc_zero failed.\n"));
89                 return NULL;
90         }
91         ctdb->ev  = ev;
92         ctdb->idr = idr_init(ctdb);
93         CTDB_NO_MEMORY_NULL(ctdb, ctdb->idr);
94
95         ret = ctdb_set_socketname(ctdb, CTDB_PATH);
96         if (ret != 0) {
97                 DEBUG(DEBUG_ERR,(__location__ " ctdb_set_socketname failed.\n"));
98                 talloc_free(ctdb);
99                 return NULL;
100         }
101
102
103
104         return ctdb;
105 }
106
107
108
109 /* Ouch.
110  * This is a bit hairy. due to the way ctdbd uses events.
111  * ctdbd quite frequently uses 
112  *     event_add_timed(... timeval_zero() ...)
113  *
114  * for example once it has finished reading off a full pdu off the
115  * domain socket, before calling the actual recdeive function.
116  *
117  * we probably need a new event function to handle these timed events
118  * event_loop_all_queued() or similar
119  */
120 int ctdb_service(struct ctdb_context *ctdb)
121 {
122         int ret;
123
124         ret = event_loop_once(ctdb->ev);
125         ret = event_loop_once(ctdb->ev);
126
127         return 0;
128 }
129
130
131
132 int ctdb_cancel(ctdb_handle *handle)
133 {
134         talloc_free(handle);
135         return 0;
136 }
137
138 struct ctdb_control_cb_data {
139         void *callback;
140         void *private_data;
141 };
142
143 static void
144 ctdb_getrecmaster_recv_cb(struct ctdb_client_control_state *state)
145 {
146         struct ctdb_control_cb_data *cb_data = state->async.private_data;
147         ctdb_get_recmaster_cb callback = (ctdb_get_recmaster_cb)cb_data->callback;
148
149         callback(0, state->status, cb_data->private_data);
150 }
151
152
153 /*
154   get the recovery master of a remote node
155  */
156 ctdb_handle *
157 ctdb_getrecmaster_send(struct ctdb_context *ctdb,
158                         uint32_t destnode,
159                         ctdb_get_recmaster_cb callback,
160                         void *private_data)
161 {
162         struct ctdb_client_control_state *state;
163         struct ctdb_control_cb_data *cb_data;
164
165         state = ctdb_control_send(ctdb, destnode, 0, 
166                            CTDB_CONTROL_GET_RECMASTER, 0, tdb_null, 
167                            ctdb, NULL, NULL);
168
169         if (state == NULL) {
170                 DEBUG(DEBUG_ERR,(__location__ " Failed to send GET_RECMASTER control\n"));
171                 return NULL;
172         }
173
174         if (callback != NULL) {
175                 cb_data = talloc(state, struct ctdb_control_cb_data);
176                 cb_data->callback     = callback;
177                 cb_data->private_data = private_data;
178
179                 state->async.fn           = ctdb_getrecmaster_recv_cb;
180                 state->async.private_data = cb_data;
181         }
182
183         return (ctdb_handle *)state;
184 }
185
186 int ctdb_getrecmaster_recv(struct ctdb_context *ctdb, ctdb_handle *handle, uint32_t *recmaster)
187 {
188         struct ctdb_client_control_state *state = talloc_get_type(handle, struct ctdb_client_control_state);
189         int ret;
190         int32_t res;
191
192         ret = ctdb_control_recv(ctdb, state, state, NULL, &res, NULL);
193         if (ret != 0) {
194                 DEBUG(DEBUG_ERR,(__location__ " ctdb_getrecmaster_recv failed\n"));
195                 return -1;
196         }
197
198         if (recmaster) {
199                 *recmaster = (uint32_t)res;
200         }
201
202         return state->status;
203 }
204
205 int ctdb_getrecmaster(struct ctdb_context *ctdb, uint32_t destnode, uint32_t *recmaster)
206 {
207         struct ctdb_client_control_state *state;
208         
209         state = ctdb_getrecmaster_send(ctdb, destnode, NULL, recmaster);
210         if (state == NULL) {
211                 DEBUG(DEBUG_ERR,(__location__ " ctdb_getrecmaster_send() failed.\n"));
212                 return -1;
213         }
214
215         return ctdb_getrecmaster_recv(ctdb, state, recmaster);
216 }
217
218
219 static void
220 ctdb_set_message_handler_recv_cb(struct ctdb_client_control_state *state)
221 {
222         struct ctdb_control_cb_data *cb_data = state->async.private_data;
223         ctdb_set_message_handler_cb callback = (ctdb_set_message_handler_cb)cb_data->callback;
224
225         callback(state->status, cb_data->private_data);
226 }
227
228
229 /*
230   tell the daemon what messaging srvid we will use, and register the message
231   handler function in the client
232 */
233 ctdb_handle *
234 ctdb_set_message_handler_send(struct ctdb_context *ctdb, uint64_t srvid, 
235                              ctdb_set_message_handler_cb callback,
236                              ctdb_message_fn_t handler,
237                              void *private_data)
238                                     
239 {
240         struct ctdb_client_control_state *state;
241         struct ctdb_control_cb_data *cb_data;
242
243         if (ctdb_register_message_handler(ctdb, ctdb, srvid, handler, private_data) != 0) {
244                 return NULL;
245         }
246
247         state = ctdb_control_send(ctdb, CTDB_CURRENT_NODE, srvid, 
248                            CTDB_CONTROL_REGISTER_SRVID, 0, tdb_null, 
249                            ctdb, NULL, NULL);
250
251         if (state == NULL) {
252                 DEBUG(DEBUG_ERR,(__location__ " Failed to send REGISTER_SRVID control\n"));
253                 return NULL;
254         }
255
256         if (callback != NULL) {
257                 cb_data = talloc(state, struct ctdb_control_cb_data);
258                 cb_data->callback     = callback;
259                 cb_data->private_data = private_data;
260
261                 state->async.fn           = ctdb_set_message_handler_recv_cb;
262                 state->async.private_data = cb_data;
263         }
264
265         return (ctdb_handle *)state;
266 }
267
268 int ctdb_set_message_handler_recv(struct ctdb_context *ctdb, ctdb_handle *handle)
269 {
270         struct ctdb_client_control_state *state = talloc_get_type(handle, struct ctdb_client_control_state);
271         int ret;
272         int32_t res;
273
274         ret = ctdb_control_recv(ctdb, state, state, NULL, &res, NULL);
275         if (ret != 0 || res != 0) {
276                 DEBUG(DEBUG_ERR,(__location__ " ctdb_set_message_handler_recv failed\n"));
277                 return -1;
278         }
279
280         return state->status;
281 }
282
283 int ctdb_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, ctdb_message_fn_t handler, void *private_data)
284 {
285         struct ctdb_client_control_state *state;
286         
287         state = ctdb_set_message_handler_send(ctdb, srvid, NULL, handler, private_data);
288         if (state == NULL) {
289                 DEBUG(DEBUG_ERR,(__location__ " ctdb_set_message_handler_send() failed.\n"));
290                 return -1;
291         }
292
293         return ctdb_set_message_handler_recv(ctdb, state);
294 }
295
296
297
298 static void
299 ctdb_remove_message_handler_recv_cb(struct ctdb_client_control_state *state)
300 {
301         struct ctdb_control_cb_data *cb_data = state->async.private_data;
302         ctdb_remove_message_handler_cb callback = (ctdb_remove_message_handler_cb)cb_data->callback;
303
304         callback(state->status, cb_data->private_data);
305 }
306
307
308 ctdb_handle *
309 ctdb_remove_message_handler_send(struct ctdb_context *ctdb, uint64_t srvid, 
310                              ctdb_remove_message_handler_cb callback,
311                              void *private_data)
312                                     
313 {
314         struct ctdb_client_control_state *state;
315         struct ctdb_control_cb_data *cb_data;
316
317         if (ctdb_deregister_message_handler(ctdb, srvid, private_data)) {
318                 return NULL;
319         }
320
321         state = ctdb_control_send(ctdb, CTDB_CURRENT_NODE, srvid, 
322                            CTDB_CONTROL_DEREGISTER_SRVID, 0, tdb_null, 
323                            ctdb, NULL, NULL);
324
325         if (state == NULL) {
326                 DEBUG(DEBUG_ERR,(__location__ " Failed to send DEREGISTER_SRVID control\n"));
327                 return NULL;
328         }
329
330         if (callback != NULL) {
331                 cb_data = talloc(state, struct ctdb_control_cb_data);
332                 cb_data->callback     = callback;
333                 cb_data->private_data = private_data;
334
335                 state->async.fn           = ctdb_remove_message_handler_recv_cb;
336                 state->async.private_data = cb_data;
337         }
338
339         return (ctdb_handle *)state;
340 }
341
342
343 int ctdb_remove_message_handler_recv(struct ctdb_context *ctdb, ctdb_handle *handle)
344 {
345         struct ctdb_client_control_state *state = talloc_get_type(handle, struct ctdb_client_control_state);
346         int ret;
347         int32_t res;
348
349         ret = ctdb_control_recv(ctdb, state, state, NULL, &res, NULL);
350         if (ret != 0 || res != 0) {
351                 DEBUG(DEBUG_ERR,(__location__ " ctdb_remove_message_handler_recv failed\n"));
352                 return -1;
353         }
354
355         return state->status;
356 }
357
358 /*
359   tell the daemon we no longer want a srvid
360 */
361 int ctdb_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data)
362 {
363         struct ctdb_client_control_state *state;
364         
365         state = ctdb_remove_message_handler_send(ctdb, srvid, NULL, private_data);
366         if (state == NULL) {
367                 DEBUG(DEBUG_ERR,(__location__ " ctdb_remove_message_handler_send() failed.\n"));
368                 return -1;
369         }
370
371         return ctdb_remove_message_handler_recv(ctdb, state);
372 }