~n-muench/ubuntu/precise/open-vm-tools/open-vm-tools-precise.sid-merge1

« back to all changes in this revision

Viewing changes to lib/rpcChannel/rpcChannel.c

  • Committer: Evan Broder
  • Date: 2010-03-21 23:26:53 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: broder@mit.edu-20100321232653-5a57r7v7ch4o6byv
Merging shared upstream rev into target branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
#include "vmxrpc.h"
32
32
#include "xdrutil.h"
33
33
 
 
34
/** Internal state of a channel. */
 
35
typedef struct RpcChannelInt {
 
36
   RpcChannel              impl;
 
37
   gchar                  *appName;
 
38
   GHashTable             *rpcs;
 
39
   GMainContext           *mainCtx;
 
40
   GSource                *resetCheck;
 
41
   gpointer                appCtx;
 
42
   RpcChannelCallback      resetReg;
 
43
   RpcChannelResetCb       resetCb;
 
44
   gpointer                resetData;
 
45
   gboolean                rpcError;
 
46
   guint                   rpcErrorCount;
 
47
} RpcChannelInt;
 
48
 
 
49
 
34
50
/** Max number of times to attempt a channel restart. */
35
51
#define RPCIN_MAX_RESTARTS 60
36
52
 
68
84
static gboolean
69
85
RpcChannelRestart(gpointer _chan)
70
86
{
71
 
   RpcChannel *chan = _chan;
 
87
   RpcChannelInt *chan = _chan;
72
88
 
73
 
   chan->stop(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);
78
94
      }
79
95
   } else {
80
96
      chan->rpcError = FALSE;
97
113
RpcChannelCheckReset(gpointer _chan)
98
114
{
99
115
   static int channelTimeoutAttempts = RPCIN_MAX_RESTARTS;
100
 
   RpcChannel *chan = _chan;
 
116
   RpcChannelInt *chan = _chan;
101
117
 
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);
111
127
         }
112
128
         goto exit;
113
129
      }
126
142
   chan->rpcErrorCount = 0;
127
143
 
128
144
   if (chan->resetCb != NULL) {
129
 
      chan->resetCb(chan, TRUE, chan->resetData);
 
145
      chan->resetCb(&chan->impl, TRUE, chan->resetData);
130
146
   }
131
147
 
132
148
exit:
148
164
RpcChannelReset(RpcInData *data)
149
165
{
150
166
   gchar *msg;
151
 
   RpcChannel *chan = data->clientData;
 
167
   RpcChannelInt *chan = data->clientData;
152
168
 
153
169
   if (chan->resetCheck == NULL) {
154
170
      chan->resetCheck = g_idle_source_new();
301
317
 
302
318
 
303
319
/**
 
320
 * Creates a new RpcChannel without any implementation.
 
321
 *
 
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.
 
327
 *
 
328
 * @return A new RpcChannel instance.
 
329
 */
 
330
 
 
331
RpcChannel *
 
332
RpcChannel_Create(void)
 
333
{
 
334
   RpcChannelInt *chan = g_new0(RpcChannelInt, 1);
 
335
   return &chan->impl;
 
336
}
 
337
 
 
338
 
 
339
/**
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).
318
354
   size_t nameLen;
319
355
   Bool status;
320
356
   RpcChannelCallback *rpc = NULL;
321
 
   RpcChannel *chan = data->clientData;
 
357
   RpcChannelInt *chan = data->clientData;
322
358
 
323
359
   name = StrUtil_GetNextToken(&index, data->args, " ");
324
360
   if (name == NULL) {
370
406
RpcChannel_Destroy(RpcChannel *chan)
371
407
{
372
408
   size_t i;
 
409
   RpcChannelInt *cdata = (RpcChannelInt *) chan;
373
410
 
374
 
   if (chan->shutdown != NULL) {
375
 
      chan->shutdown(chan);
 
411
   if (cdata->impl.shutdown != NULL) {
 
412
      cdata->impl.shutdown(chan);
376
413
   }
377
414
 
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]);
381
418
   }
382
419
 
383
 
   if (chan->rpcs != NULL) {
384
 
      g_hash_table_destroy(chan->rpcs);
385
 
      chan->rpcs = NULL;
386
 
   }
387
 
 
388
 
   chan->resetCb = NULL;
389
 
   chan->resetData = NULL;
390
 
   chan->appCtx = NULL;
391
 
 
392
 
   g_free(chan->appName);
393
 
   chan->appName = NULL;
394
 
 
395
 
   g_main_context_unref(chan->mainCtx);
396
 
   chan->mainCtx = NULL;
397
 
 
398
 
   if (chan->resetCheck != NULL) {
399
 
      g_source_destroy(chan->resetCheck);
400
 
      chan->resetCheck = NULL;
401
 
   }
402
 
 
403
 
   g_free(chan);
 
420
   if (cdata->rpcs != NULL) {
 
421
      g_hash_table_destroy(cdata->rpcs);
 
422
      cdata->rpcs = NULL;
 
423
   }
 
424
 
 
425
   cdata->resetCb = NULL;
 
426
   cdata->resetData = NULL;
 
427
   cdata->appCtx = NULL;
 
428
 
 
429
   g_free(cdata->appName);
 
430
   cdata->appName = NULL;
 
431
 
 
432
   if (cdata->mainCtx != NULL) {
 
433
      g_main_context_unref(cdata->mainCtx);
 
434
      cdata->mainCtx = NULL;
 
435
   }
 
436
 
 
437
   if (cdata->resetCheck != NULL) {
 
438
      g_source_destroy(cdata->resetCheck);
 
439
      cdata->resetCheck = NULL;
 
440
   }
 
441
 
 
442
   g_free(cdata);
404
443
   return TRUE;
405
444
}
406
445
 
417
456
RpcChannel_Error(void *_chan,
418
457
                 char const *status)
419
458
{
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);
423
462
 
430
469
 
431
470
 
432
471
/**
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.
 
473
 *
 
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.
435
477
 *
436
478
 * @param[in]  chan        The RPC channel.
437
479
 * @param[in]  appName     TCLO application name.
450
492
                 gpointer resetData)
451
493
{
452
494
   size_t i;
453
 
 
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;
459
 
 
460
 
   chan->resetReg.name = "reset";
461
 
   chan->resetReg.callback = RpcChannelReset;
462
 
   chan->resetReg.clientData = chan;
 
495
   RpcChannelInt *cdata = (RpcChannelInt *) chan;
 
496
 
 
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;
 
502
 
 
503
   cdata->resetReg.name = "reset";
 
504
   cdata->resetReg.callback = RpcChannelReset;
 
505
   cdata->resetReg.clientData = chan;
463
506
 
464
507
   /* Register the callbacks handled by the rpcChannel library. */
465
 
   RpcChannel_RegisterCallback(chan, &chan->resetReg);
 
508
   RpcChannel_RegisterCallback(chan, &cdata->resetReg);
466
509
 
467
510
   for (i = 0; i < ARRAYSIZE(gRpcHandlers); i++) {
468
511
      RpcChannel_RegisterCallback(chan, &gRpcHandlers[i]);
469
512
   }
 
513
 
 
514
   if (cdata->impl.setup != NULL) {
 
515
      cdata->impl.setup(&cdata->impl, mainCtx, appName, appCtx);
 
516
   }
470
517
}
471
518
 
472
519
 
473
 
 
474
520
/**
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)
510
556
{
 
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);
516
563
   }
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);
519
566
   }
520
 
   g_hash_table_insert(chan->rpcs, (gpointer) rpc->name, rpc);
 
567
   g_hash_table_insert(cdata->rpcs, (gpointer) rpc->name, rpc);
521
568
}
522
569
 
523
570
 
533
580
RpcChannel_UnregisterCallback(RpcChannel *chan,
534
581
                              RpcChannelCallback *rpc)
535
582
{
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);
538
586
   }
539
587
}
540
588