tools/ctdb: Pass memory context for returning nodes in parse_nodestring
[Samba/wip.git] / ctdb / libctdb / messages.c
blob254df028eb6dfd6f90cae2511a125af95c953cff
1 /*
2 core of libctdb
4 Copyright (C) Rusty Russell 2010
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/>.
20 #include <sys/socket.h>
21 #include "libctdb_private.h"
22 #include "messages.h"
23 #include "io_elem.h"
24 #include <ctdb.h>
25 #include <tdb.h>
26 #include <ctdb_protocol.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
31 /* Remove type-safety macros. */
32 #undef ctdb_set_message_handler_send
33 #undef ctdb_set_message_handler_recv
34 #undef ctdb_remove_message_handler_send
36 struct message_handler_info {
37 struct message_handler_info *next, *prev;
39 uint64_t srvid;
40 ctdb_message_fn_t handler;
41 void *handler_data;
44 void deliver_message(struct ctdb_connection *ctdb, struct ctdb_req_header *hdr)
46 struct message_handler_info *i;
47 struct ctdb_req_message *msg = (struct ctdb_req_message *)hdr;
48 TDB_DATA data;
49 bool found;
51 data.dptr = msg->data;
52 data.dsize = msg->datalen;
54 /* Note: we want to call *every* handler: there may be more than one */
55 for (i = ctdb->message_handlers; i; i = i->next) {
56 if (i->srvid == msg->srvid) {
57 i->handler(ctdb, msg->srvid, data, i->handler_data);
58 found = true;
61 if (!found) {
62 DEBUG(ctdb, LOG_WARNING,
63 "ctdb_service: messsage for unregistered srvid %llu",
64 (unsigned long long)msg->srvid);
68 void remove_message_handlers(struct ctdb_connection *ctdb)
70 struct message_handler_info *i;
72 /* ctdbd should unregister automatically when we close fd, so we don't
73 need to do that here. */
74 while ((i = ctdb->message_handlers) != NULL) {
75 DLIST_REMOVE(ctdb->message_handlers, i);
76 free(i);
80 static void free_info(struct ctdb_connection *ctdb, struct ctdb_request *req);
82 struct ctdb_request *
83 ctdb_set_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid,
84 ctdb_message_fn_t handler, void *handler_data,
85 ctdb_callback_t callback, void *private_data)
87 struct message_handler_info *info;
88 struct ctdb_request *req;
90 info = malloc(sizeof(*info));
91 if (!info) {
92 DEBUG(ctdb, LOG_ERR,
93 "ctdb_set_message_handler_send: allocating info");
94 return NULL;
97 req = new_ctdb_control_request(ctdb, CTDB_CONTROL_REGISTER_SRVID,
98 CTDB_CURRENT_NODE, NULL, 0,
99 callback, private_data);
100 if (!req) {
101 DEBUG(ctdb, LOG_ERR,
102 "ctdb_set_message_handler_send: allocating request");
103 free(info);
104 return NULL;
106 req->extra = info;
107 req->extra_destructor = free_info;
108 req->hdr.control->srvid = srvid;
110 info->srvid = srvid;
111 info->handler = handler;
112 info->handler_data = handler_data;
114 DEBUG(ctdb, LOG_DEBUG,
115 "ctdb_set_message_handler_send: sending request %u for id %llx",
116 req->hdr.hdr->reqid, (unsigned long long)srvid);
117 return req;
120 static void free_info(struct ctdb_connection *ctdb, struct ctdb_request *req)
122 free(req->extra);
125 bool ctdb_set_message_handler_recv(struct ctdb_connection *ctdb,
126 struct ctdb_request *req)
128 struct message_handler_info *info = req->extra;
129 struct ctdb_reply_control *reply;
131 reply = unpack_reply_control(req, CTDB_CONTROL_REGISTER_SRVID);
132 if (!reply) {
133 return false;
135 if (reply->status != 0) {
136 DEBUG(ctdb, LOG_ERR,
137 "ctdb_set_message_handler_recv: status %i",
138 reply->status);
139 return false;
142 /* Put ourselves in list of handlers. */
143 DLIST_ADD(ctdb->message_handlers, info);
144 /* Keep safe from destructor */
145 req->extra = NULL;
146 return true;
149 struct ctdb_request *
150 ctdb_remove_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid,
151 ctdb_message_fn_t handler, void *hdata,
152 ctdb_callback_t callback, void *cbdata)
154 struct message_handler_info *i;
155 struct ctdb_request *req;
157 for (i = ctdb->message_handlers; i; i = i->next) {
158 if (i->srvid == srvid
159 && i->handler == handler && i->handler_data == hdata) {
160 break;
163 if (!i) {
164 DEBUG(ctdb, LOG_ALERT,
165 "ctdb_remove_message_handler_send: no such handler");
166 errno = ENOENT;
167 return NULL;
170 req = new_ctdb_control_request(ctdb, CTDB_CONTROL_DEREGISTER_SRVID,
171 CTDB_CURRENT_NODE, NULL, 0,
172 callback, cbdata);
173 if (!req) {
174 DEBUG(ctdb, LOG_ERR,
175 "ctdb_remove_message_handler_send: allocating request");
176 return NULL;
178 req->hdr.control->srvid = srvid;
179 req->extra = i;
181 DEBUG(ctdb, LOG_DEBUG,
182 "ctdb_set_remove_handler_send: sending request %u for id %llu",
183 req->hdr.hdr->reqid, (unsigned long long)srvid);
184 return req;
187 bool ctdb_remove_message_handler_recv(struct ctdb_connection *ctdb,
188 struct ctdb_request *req)
190 struct message_handler_info *handler = req->extra;
191 struct ctdb_reply_control *reply;
193 reply = unpack_reply_control(req, CTDB_CONTROL_DEREGISTER_SRVID);
194 if (!reply) {
195 return false;
197 if (reply->status != 0) {
198 DEBUG(ctdb, LOG_ERR,
199 "ctdb_remove_message_handler_recv: status %i",
200 reply->status);
201 return false;
204 /* Remove ourselves from list of handlers. */
205 DLIST_REMOVE(ctdb->message_handlers, handler);
206 free(handler);
207 /* Crash if they call this again! */
208 req->extra = NULL;
209 return true;
212 bool ctdb_send_message(struct ctdb_connection *ctdb,
213 uint32_t pnn, uint64_t srvid,
214 TDB_DATA data)
216 struct ctdb_request *req;
217 struct ctdb_req_message *pkt;
219 /* We just discard it once it's finished: no reply. */
220 req = new_ctdb_request(
221 ctdb, offsetof(struct ctdb_req_message, data) + data.dsize,
222 ctdb_cancel_callback, NULL);
223 if (!req) {
224 DEBUG(ctdb, LOG_ERR, "ctdb_set_message: allocating message");
225 return false;
228 io_elem_init_req_header(req->io,
229 CTDB_REQ_MESSAGE, pnn, new_reqid(ctdb));
231 pkt = req->hdr.message;
232 pkt->srvid = srvid;
233 pkt->datalen = data.dsize;
234 memcpy(pkt->data, data.dptr, data.dsize);
235 DLIST_ADD_END(ctdb->outq, req, struct ctdb_request);
236 return true;