31
31
#include "vmxrpc.h"
32
32
#include "xdrutil.h"
34
/** Internal state of a channel. */
35
typedef struct RpcChannelInt {
39
GMainContext *mainCtx;
42
RpcChannelCallback resetReg;
43
RpcChannelResetCb resetCb;
34
50
/** Max number of times to attempt a channel restart. */
35
51
#define RPCIN_MAX_RESTARTS 60
69
85
RpcChannelRestart(gpointer _chan)
71
RpcChannel *chan = _chan;
87
RpcChannelInt *chan = _chan;
74
if (!chan->start(chan)) {
89
RpcChannel_Stop(&chan->impl);
90
if (!RpcChannel_Start(&chan->impl)) {
75
91
g_warning("Channel restart failed [%d]\n", chan->rpcErrorCount);
76
92
if (chan->resetCb != NULL) {
77
chan->resetCb(chan, FALSE, chan->resetData);
93
chan->resetCb(&chan->impl, FALSE, chan->resetData);
80
96
chan->rpcError = FALSE;
97
113
RpcChannelCheckReset(gpointer _chan)
99
115
static int channelTimeoutAttempts = RPCIN_MAX_RESTARTS;
100
RpcChannel *chan = _chan;
116
RpcChannelInt *chan = _chan;
102
118
/* Check the channel state. */
103
119
if (chan->rpcError) {
107
123
g_warning("Failed to reset channel after %u attempts\n",
108
124
chan->rpcErrorCount - 1);
109
125
if (chan->resetCb != NULL) {
110
chan->resetCb(chan, FALSE, chan->resetData);
126
chan->resetCb(&chan->impl, FALSE, chan->resetData);
126
142
chan->rpcErrorCount = 0;
128
144
if (chan->resetCb != NULL) {
129
chan->resetCb(chan, TRUE, chan->resetData);
145
chan->resetCb(&chan->impl, TRUE, chan->resetData);
148
164
RpcChannelReset(RpcInData *data)
151
RpcChannel *chan = data->clientData;
167
RpcChannelInt *chan = data->clientData;
153
169
if (chan->resetCheck == NULL) {
154
170
chan->resetCheck = g_idle_source_new();
320
* Creates a new RpcChannel without any implementation.
322
* This is mainly for use of code that is implementing a custom RpcChannel.
323
* Such implementations should provide their own "constructor"-type function
324
* which should then call this function to get an RpcChannel instance. They
325
* should then fill in the function pointers that provide the implementation
326
* for the channel before making the channel available to the callers.
328
* @return A new RpcChannel instance.
332
RpcChannel_Create(void)
334
RpcChannelInt *chan = g_new0(RpcChannelInt, 1);
304
340
* Dispatches the given RPC to the registered handler. This mimics the behavior
305
341
* of the RpcIn library (but is not tied to that particular implementation of
306
342
* an RPC channel).
320
356
RpcChannelCallback *rpc = NULL;
321
RpcChannel *chan = data->clientData;
357
RpcChannelInt *chan = data->clientData;
323
359
name = StrUtil_GetNextToken(&index, data->args, " ");
324
360
if (name == NULL) {
370
406
RpcChannel_Destroy(RpcChannel *chan)
409
RpcChannelInt *cdata = (RpcChannelInt *) chan;
374
if (chan->shutdown != NULL) {
375
chan->shutdown(chan);
411
if (cdata->impl.shutdown != NULL) {
412
cdata->impl.shutdown(chan);
378
RpcChannel_UnregisterCallback(chan, &chan->resetReg);
415
RpcChannel_UnregisterCallback(chan, &cdata->resetReg);
379
416
for (i = 0; i < ARRAYSIZE(gRpcHandlers); i++) {
380
417
RpcChannel_UnregisterCallback(chan, &gRpcHandlers[i]);
383
if (chan->rpcs != NULL) {
384
g_hash_table_destroy(chan->rpcs);
388
chan->resetCb = NULL;
389
chan->resetData = NULL;
392
g_free(chan->appName);
393
chan->appName = NULL;
395
g_main_context_unref(chan->mainCtx);
396
chan->mainCtx = NULL;
398
if (chan->resetCheck != NULL) {
399
g_source_destroy(chan->resetCheck);
400
chan->resetCheck = NULL;
420
if (cdata->rpcs != NULL) {
421
g_hash_table_destroy(cdata->rpcs);
425
cdata->resetCb = NULL;
426
cdata->resetData = NULL;
427
cdata->appCtx = NULL;
429
g_free(cdata->appName);
430
cdata->appName = NULL;
432
if (cdata->mainCtx != NULL) {
433
g_main_context_unref(cdata->mainCtx);
434
cdata->mainCtx = NULL;
437
if (cdata->resetCheck != NULL) {
438
g_source_destroy(cdata->resetCheck);
439
cdata->resetCheck = NULL;
417
456
RpcChannel_Error(void *_chan,
418
457
char const *status)
420
RpcChannel *chan = _chan;
459
RpcChannelInt *chan = _chan;
421
460
chan->rpcError = TRUE;
422
461
g_warning("Error in the RPC receive loop: %s.\n", status);
433
* Initializes the RPC channel for use. This function must be called before
434
* starting the channel.
472
* Initializes the RPC channel for inbound operations.
474
* This function must be called before starting the channel if the application
475
* wants to receive messages on the channel. Applications don't need to call it
476
* if only using the outbound functionality.
436
478
* @param[in] chan The RPC channel.
437
479
* @param[in] appName TCLO application name.
450
492
gpointer resetData)
454
chan->appName = g_strdup(appName);
455
chan->appCtx = appCtx;
456
chan->mainCtx = g_main_context_ref(mainCtx);
457
chan->resetCb = resetCb;
458
chan->resetData = resetData;
460
chan->resetReg.name = "reset";
461
chan->resetReg.callback = RpcChannelReset;
462
chan->resetReg.clientData = chan;
495
RpcChannelInt *cdata = (RpcChannelInt *) chan;
497
cdata->appName = g_strdup(appName);
498
cdata->appCtx = appCtx;
499
cdata->mainCtx = g_main_context_ref(mainCtx);
500
cdata->resetCb = resetCb;
501
cdata->resetData = resetData;
503
cdata->resetReg.name = "reset";
504
cdata->resetReg.callback = RpcChannelReset;
505
cdata->resetReg.clientData = chan;
464
507
/* Register the callbacks handled by the rpcChannel library. */
465
RpcChannel_RegisterCallback(chan, &chan->resetReg);
508
RpcChannel_RegisterCallback(chan, &cdata->resetReg);
467
510
for (i = 0; i < ARRAYSIZE(gRpcHandlers); i++) {
468
511
RpcChannel_RegisterCallback(chan, &gRpcHandlers[i]);
514
if (cdata->impl.setup != NULL) {
515
cdata->impl.setup(&cdata->impl, mainCtx, appName, appCtx);
475
521
* Sets the result of the given RPC context to the given value. The result
476
522
* should be a NULL-terminated string.
508
554
RpcChannel_RegisterCallback(RpcChannel *chan,
509
555
RpcChannelCallback *rpc)
557
RpcChannelInt *cdata = (RpcChannelInt *) chan;
511
558
ASSERT(rpc->name != NULL && strlen(rpc->name) > 0);
512
559
ASSERT(rpc->callback);
513
560
ASSERT(rpc->xdrIn == NULL || rpc->xdrInSize > 0);
514
if (chan->rpcs == NULL) {
515
chan->rpcs = g_hash_table_new(g_str_hash, g_str_equal);
561
if (cdata->rpcs == NULL) {
562
cdata->rpcs = g_hash_table_new(g_str_hash, g_str_equal);
517
if (g_hash_table_lookup(chan->rpcs, rpc->name) != NULL) {
564
if (g_hash_table_lookup(cdata->rpcs, rpc->name) != NULL) {
518
565
g_error("Trying to overwrite existing RPC registration for %s!\n", rpc->name);
520
g_hash_table_insert(chan->rpcs, (gpointer) rpc->name, rpc);
567
g_hash_table_insert(cdata->rpcs, (gpointer) rpc->name, rpc);
533
580
RpcChannel_UnregisterCallback(RpcChannel *chan,
534
581
RpcChannelCallback *rpc)
536
if (chan->rpcs != NULL) {
537
g_hash_table_remove(chan->rpcs, rpc->name);
583
RpcChannelInt *cdata = (RpcChannelInt *) chan;
584
if (cdata->rpcs != NULL) {
585
g_hash_table_remove(cdata->rpcs, rpc->name);