2
* Copyright (c) 2012 David Vossel <dvossel@redhat.com>
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2.1 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
#include <crm_internal.h>
22
#include <lrmd_private.h>
28
#include <crm/msg_xml.h>
29
#include <crm/services.h>
30
#include <crm/common/mainloop.h>
31
#include <crm/common/ipc.h>
32
#include <crm/common/ipcs.h>
33
#include <crm/cib/internal.h>
35
static qb_ipcs_service_t *cib_ro = NULL;
36
static qb_ipcs_service_t *cib_rw = NULL;
37
static qb_ipcs_service_t *cib_shm = NULL;
39
static qb_ipcs_service_t *attrd_ipcs = NULL;
40
static qb_ipcs_service_t *crmd_ipcs = NULL;
41
static qb_ipcs_service_t *stonith_ipcs = NULL;
43
/* ipc providers == crmd clients connecting from cluster nodes */
44
GHashTable *ipc_providers;
45
/* ipc clients == things like cibadmin, crm_resource, connecting locally */
46
GHashTable *ipc_clients;
49
ipc_proxy_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid, const char *ipc_channel)
54
crm_client_t *ipc_proxy = NULL;
58
crm_trace("Connection %p on channel %s", c, ipc_channel);
60
if (g_hash_table_size(ipc_providers) == 0) {
61
crm_err("No ipc providers available for uid %d gid %d", uid, gid);
65
g_hash_table_iter_init(&iter, ipc_providers);
66
if (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
67
/* grab the first provider available, any provider in this
68
* table will work. Usually there will only be one. These are
69
* lrmd client connections originating for a cluster node's crmd. */
72
crm_err("No ipc providers available for uid %d gid %d", uid, gid);
76
/* this new client is a local ipc client on a remote
77
* guest wanting to access the ipc on any available cluster nodes */
78
client = crm_client_new(c, uid, gid);
83
/* This ipc client is bound to a single ipc provider. If the
84
* provider goes away, this client is disconnected */
85
client->userdata = strdup(ipc_proxy->id);
87
g_hash_table_insert(ipc_clients, client->id, client);
89
msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
90
crm_xml_add(msg, F_LRMD_IPC_OP, "new");
91
crm_xml_add(msg, F_LRMD_IPC_IPC_SERVER, ipc_channel);
92
crm_xml_add(msg, F_LRMD_IPC_SESSION, client->id);
93
lrmd_server_send_notify(ipc_proxy, msg);
95
crm_debug("created new ipc proxy with session id %s", client->id);
100
crmd_proxy_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
102
return ipc_proxy_accept(c, uid, gid, CRM_SYSTEM_CRMD);
106
attrd_proxy_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
108
return ipc_proxy_accept(c, uid, gid, T_ATTRD);
112
stonith_proxy_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
114
return ipc_proxy_accept(c, uid, gid, "stonith-ng");
118
cib_proxy_accept_rw(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
120
return ipc_proxy_accept(c, uid, gid, cib_channel_rw);
124
cib_proxy_accept_ro(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
126
return ipc_proxy_accept(c, uid, gid, cib_channel_ro);
130
ipc_proxy_created(qb_ipcs_connection_t * c)
132
crm_trace("Connection %p", c);
136
ipc_proxy_forward_client(crm_client_t *ipc_proxy, xmlNode *xml)
138
const char *session = crm_element_value(xml, F_LRMD_IPC_SESSION);
139
const char *msg_type = crm_element_value(xml, F_LRMD_IPC_OP);
140
xmlNode *msg = get_message_xml(xml, F_LRMD_IPC_MSG);
141
crm_client_t *ipc_client = crm_client_get_by_id(session);
144
if (ipc_client == NULL) {
145
xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
146
crm_xml_add(msg, F_LRMD_IPC_OP, "destroy");
147
crm_xml_add(msg, F_LRMD_IPC_SESSION, session);
148
lrmd_server_send_notify(ipc_proxy, msg);
153
/* This is an event or response from the ipc provider
154
* going to the local ipc client.
156
* Looking at the chain of events.
158
* -----remote node----------------|---- cluster node ------
159
* ipc_client <--1--> this code <--2--> crmd <----3----> ipc server
161
* This function is receiving a msg from connection 2
162
* and forwarding it to connection 1.
164
if (safe_str_eq(msg_type, "event")) {
165
rc = crm_ipcs_send(ipc_client, 0, msg, TRUE);
166
} else if (safe_str_eq(msg_type, "response")) {
168
crm_element_value_int(xml, F_LRMD_IPC_MSG_ID, &msg_id);
169
rc = crm_ipcs_send(ipc_client, msg_id, msg, FALSE);
170
} else if (safe_str_eq(msg_type, "destroy")) {
171
qb_ipcs_disconnect(ipc_client->ipcs);
173
crm_err("Unknown ipc proxy msg type %s" , msg_type);
177
crm_warn("IPC Proxy send to ipc client %s failed, rc = %d", ipc_client->id, rc);
182
ipc_proxy_dispatch(qb_ipcs_connection_t * c, void *data, size_t size)
186
crm_client_t *client = crm_client_get(c);
187
crm_client_t *ipc_proxy = crm_client_get_by_id(client->userdata);
188
xmlNode *request = NULL;
192
qb_ipcs_disconnect(client->ipcs);
196
/* This is a request from the local ipc client going
197
* to the ipc provider.
199
* Looking at the chain of events.
201
* -----remote node----------------|---- cluster node ------
202
* ipc_client <--1--> this code <--2--> crmd <----3----> ipc server
204
* This function is receiving a request from connection
205
* 1 and forwarding it to connection 2.
207
request = crm_ipcs_recv(client, data, size, &id, &flags);
213
CRM_CHECK(client != NULL, crm_err("Invalid client");
215
CRM_CHECK(client->id != NULL, crm_err("Invalid client: %p", client);
218
msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
219
crm_xml_add(msg, F_LRMD_IPC_OP, "request");
220
crm_xml_add(msg, F_LRMD_IPC_SESSION, client->id);
221
crm_xml_add(msg, F_LRMD_IPC_USER, client->user);
222
crm_xml_add_int(msg, F_LRMD_IPC_MSG_ID, id);
223
crm_xml_add_int(msg, F_LRMD_IPC_MSG_FLAGS, flags);
224
add_message_xml(msg, F_LRMD_IPC_MSG, request);
225
lrmd_server_send_notify(ipc_proxy, msg);
232
ipc_proxy_closed(qb_ipcs_connection_t * c)
234
crm_client_t *client = crm_client_get(c);
235
crm_client_t *ipc_proxy = crm_client_get_by_id(client->userdata);
237
crm_trace("Connection %p", c);
240
xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
241
crm_xml_add(msg, F_LRMD_IPC_OP, "destroy");
242
crm_xml_add(msg, F_LRMD_IPC_SESSION, client->id);
243
lrmd_server_send_notify(ipc_proxy, msg);
247
g_hash_table_remove(ipc_clients, client->id);
249
free(client->userdata);
250
client->userdata = NULL;
251
crm_client_destroy(client);
256
ipc_proxy_destroy(qb_ipcs_connection_t * c)
258
crm_trace("Connection %p", c);
261
static struct qb_ipcs_service_handlers crmd_proxy_callbacks = {
262
.connection_accept = crmd_proxy_accept,
263
.connection_created = ipc_proxy_created,
264
.msg_process = ipc_proxy_dispatch,
265
.connection_closed = ipc_proxy_closed,
266
.connection_destroyed = ipc_proxy_destroy
269
static struct qb_ipcs_service_handlers attrd_proxy_callbacks = {
270
.connection_accept = attrd_proxy_accept,
271
.connection_created = ipc_proxy_created,
272
.msg_process = ipc_proxy_dispatch,
273
.connection_closed = ipc_proxy_closed,
274
.connection_destroyed = ipc_proxy_destroy
277
static struct qb_ipcs_service_handlers stonith_proxy_callbacks = {
278
.connection_accept = stonith_proxy_accept,
279
.connection_created = ipc_proxy_created,
280
.msg_process = ipc_proxy_dispatch,
281
.connection_closed = ipc_proxy_closed,
282
.connection_destroyed = ipc_proxy_destroy
285
static struct qb_ipcs_service_handlers cib_proxy_callbacks_ro = {
286
.connection_accept = cib_proxy_accept_ro,
287
.connection_created = ipc_proxy_created,
288
.msg_process = ipc_proxy_dispatch,
289
.connection_closed = ipc_proxy_closed,
290
.connection_destroyed = ipc_proxy_destroy
293
static struct qb_ipcs_service_handlers cib_proxy_callbacks_rw = {
294
.connection_accept = cib_proxy_accept_rw,
295
.connection_created = ipc_proxy_created,
296
.msg_process = ipc_proxy_dispatch,
297
.connection_closed = ipc_proxy_closed,
298
.connection_destroyed = ipc_proxy_destroy
302
ipc_proxy_add_provider(crm_client_t *ipc_proxy)
304
if (ipc_providers == NULL) {
307
g_hash_table_insert(ipc_providers, ipc_proxy->id, ipc_proxy);
311
ipc_proxy_remove_provider(crm_client_t *ipc_proxy)
314
crm_client_t *ipc_client = NULL;
317
if (ipc_providers == NULL) {
321
g_hash_table_remove(ipc_providers, ipc_proxy->id);
323
g_hash_table_iter_init(&iter, ipc_clients);
324
while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & ipc_client)) {
325
const char *proxy_id = ipc_client->userdata;
326
if (safe_str_eq(proxy_id, ipc_proxy->id)) {
327
crm_info("ipc proxy connection for client %s pid %d destroyed because cluster node disconnected.",
328
ipc_client->id, ipc_client->pid);
329
qb_ipcs_disconnect(ipc_client->ipcs);
337
ipc_clients = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, NULL);
338
ipc_providers = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, NULL);
340
cib_ipc_servers_init(&cib_ro,
343
&cib_proxy_callbacks_ro,
344
&cib_proxy_callbacks_rw);
346
attrd_ipc_server_init(&attrd_ipcs, &attrd_proxy_callbacks);
347
stonith_ipc_server_init(&stonith_ipcs, &stonith_proxy_callbacks);
348
crmd_ipcs = crmd_ipc_server_init(&crmd_proxy_callbacks);
349
if (crmd_ipcs == NULL) {
350
crm_err("Failed to create crmd server: exiting and inhibiting respawn.");
351
crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
357
ipc_proxy_cleanup(void)
360
g_hash_table_destroy(ipc_providers);
363
g_hash_table_destroy(ipc_clients);
365
cib_ipc_servers_destroy(cib_ro, cib_rw, cib_shm);
366
qb_ipcs_destroy(attrd_ipcs);
367
qb_ipcs_destroy(stonith_ipcs);
368
qb_ipcs_destroy(crmd_ipcs);
372
ipc_providers = NULL;