add libctdb getrecmaster control recv function and
[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 "include/libctdb.h"
25 #include "lib/events/events.h"
26 #include "include/ctdb_private.h"
27
28 struct ctdb_context *libctdb_connect(const char *addr)
29 {
30         struct event_context *ev;
31         struct ctdb_context *ctdb;
32         int ret;
33
34         ev = event_context_init(NULL);
35
36         /* initialise ctdb */
37         ctdb = ctdb_init(ev);
38         if (ctdb == NULL) {
39                 fprintf(stderr, "Failed to init ctdb\n");
40                 exit(1);
41         }
42
43         ret = ctdb_set_socketname(ctdb, addr);
44         if (ret == -1) {
45                 fprintf(stderr, __location__ " ctdb_set_socketname failed - %s\n", ctdb_errstr(ctdb));
46                 talloc_free(ctdb);
47                 exit(1);
48         }
49
50         ret = ctdb_socket_connect(ctdb);
51         if (ret != 0) {
52                 fprintf(stderr, __location__ " Failed to connect to daemon\n");
53                 talloc_free(ctdb);
54                 return NULL;
55         }
56
57         return ctdb;
58 }
59
60
61 int libctdb_get_fd(struct ctdb_context *ctdb)
62 {
63         return ctdb->daemon.sd;
64 }
65
66 int libctdb_which_events(struct ctdb_context *ctdb)
67 {
68         if (ctdb_queue_length(ctdb->daemon.queue) > 0) {
69                 return POLLIN|POLLOUT;
70         }
71
72         return POLLIN;
73 }
74
75
76
77 /*
78   initialise the ctdb daemon for client applications
79 */
80 struct ctdb_context *ctdb_init(struct event_context *ev)
81 {
82         int ret;
83         struct ctdb_context *ctdb;
84
85         ctdb = talloc_zero(ev, struct ctdb_context);
86         if (ctdb == NULL) {
87                 DEBUG(DEBUG_ERR,(__location__ " talloc_zero failed.\n"));
88                 return NULL;
89         }
90         ctdb->ev  = ev;
91         ctdb->idr = idr_init(ctdb);
92         CTDB_NO_MEMORY_NULL(ctdb, ctdb->idr);
93
94         ret = ctdb_set_socketname(ctdb, CTDB_PATH);
95         if (ret != 0) {
96                 DEBUG(DEBUG_ERR,(__location__ " ctdb_set_socketname failed.\n"));
97                 talloc_free(ctdb);
98                 return NULL;
99         }
100
101
102
103         return ctdb;
104 }
105
106
107
108 /* Ouch.
109  * This is a bit hairy. due to the way ctdbd uses events.
110  * ctdbd quite frequently uses 
111  *     event_add_timed(... timeval_zero() ...)
112  *
113  * for example once it has finished reading off a full pdu off the
114  * domain socket, before calling the actual recdeive function.
115  *
116  * we probably need a new event function to handle these timed events
117  * event_loop_all_queued() or similar
118  */
119 int libctdb_service(struct ctdb_context *ctdb)
120 {
121         int ret;
122
123         ret = event_loop_once(ctdb->ev);
124         ret = event_loop_once(ctdb->ev);
125
126         return 0;
127 }
128
129
130
131 int libctdb_cancel(libctdb_handle *handle)
132 {
133         talloc_free(handle);
134         return 0;
135 }
136
137 struct libctdb_control_cb_data {
138         void *callback;
139         void *private_data;
140 };
141
142 static void
143 libctdb_getrecmaster_recv_cb(struct ctdb_client_control_state *state)
144 {
145         struct libctdb_control_cb_data *cb_data = state->async.private_data;
146         get_recmaster_cb callback = (get_recmaster_cb)cb_data->callback;
147
148         callback(0, state->status, cb_data->private_data);
149 }
150
151
152 /*
153   get the recovery master of a remote node
154  */
155 libctdb_handle *
156 libctdb_getrecmaster_send(struct ctdb_context *ctdb,
157                         uint32_t destnode,
158                         get_recmaster_cb callback,
159                         void *private_data)
160 {
161         struct ctdb_client_control_state *state;
162         struct libctdb_control_cb_data *cb_data;
163
164         state = ctdb_control_send(ctdb, destnode, 0, 
165                            CTDB_CONTROL_GET_RECMASTER, 0, tdb_null, 
166                            ctdb, NULL, NULL);
167
168         if (callback != NULL) {
169                 cb_data = talloc(state, struct libctdb_control_cb_data);
170                 cb_data->callback     = callback;
171                 cb_data->private_data = private_data;
172
173                 state->async.fn           = libctdb_getrecmaster_recv_cb;
174                 state->async.private_data = cb_data;
175         }
176
177         return (libctdb_handle *)state;
178 }
179
180 int libctdb_getrecmaster_recv(struct ctdb_context *ctdb, libctdb_handle *handle, uint32_t *recmaster)
181 {
182         struct ctdb_client_control_state *state = talloc_get_type(handle, struct ctdb_client_control_state);
183         int ret;
184         int32_t res;
185
186         ret = ctdb_control_recv(ctdb, state, state, NULL, &res, NULL);
187         if (ret != 0) {
188                 DEBUG(DEBUG_ERR,(__location__ " libctdb_getrecmaster_recv failed\n"));
189                 return -1;
190         }
191
192         if (recmaster) {
193                 *recmaster = (uint32_t)res;
194         }
195
196         return 0;
197 }
198
199 int libctdb_getrecmaster(struct ctdb_context *ctdb, uint32_t destnode, uint32_t *recmaster)
200 {
201         struct ctdb_client_control_state *state;
202         
203         state = libctdb_getrecmaster_send(ctdb, destnode, NULL, recmaster);
204         if (state == NULL) {
205                 DEBUG(DEBUG_ERR,(__location__ " libctdb_getrecmaster_send() failed.\n"));
206                 return -1;
207         }
208
209         return libctdb_getrecmaster_recv(ctdb, state, recmaster);
210 }
211
212
213