~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to lib/rpcIn/rpcin.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
 
47
47
#if defined(VMTOOLS_USE_GLIB)
48
48
#  include "vmware/tools/guestrpc.h"
 
49
#  include "vmware/tools/utils.h"
49
50
#endif
50
51
 
51
52
#include "vmware.h"
71
72
 * The RpcIn object
72
73
 */
73
74
 
74
 
typedef enum {
75
 
    RPCIN_CB_OLD,
76
 
    RPCIN_CB_NEW
77
 
} RpcInCallbackType;
78
 
 
79
 
 
80
75
/* The list of TCLO command callbacks we support */
81
76
typedef struct RpcInCallbackList {
82
77
   const char *name;
83
78
   size_t length; /* Length of name so we don't have to strlen a lot */
84
 
   RpcInCallbackType type;
85
 
   union {
86
 
      RpcIn_CallbackOld oldCb;
87
 
      RpcIn_Callback newCb;
88
 
   } callback;
 
79
   RpcIn_Callback callback;
89
80
   struct RpcInCallbackList *next;
90
81
   void *clientData;
91
82
} RpcInCallbackList;
121
112
 
122
113
   /* The size of the result */
123
114
   size_t last_resultLen;
 
115
 
 
116
   /*
 
117
    * It's possible for a callback dispatched by RpcInLoop to call RpcIn_stop.
 
118
    * When this happens, we corrupt the state of the RpcIn struct, resulting in
 
119
    * a crash the next time RpcInLoop is called. To prevent corruption of the
 
120
    * RpcIn struct, we check inLoop when RpcIn_stop is called, and if it is
 
121
    * true, we set shouldStop to TRUE instead of actually stopping the
 
122
    * channel. When RpcInLoop exits, it will stop the channel if shouldStop is
 
123
    * TRUE.
 
124
    */
 
125
   Bool inLoop;     // RpcInLoop is running.
 
126
   Bool shouldStop; // Stop the channel the next time RpcInLoop exits.
124
127
};
125
128
 
126
129
 
127
 
/* 
 
130
/*
128
131
 * The following functions are only needed in the non-glib version of the
129
132
 * library. The glib version of the library only deals with the transport
130
133
 * aspects of the code - RPC dispatching and other RPC-layer concerns are
131
134
 * handled by the rpcChannel abstraction library, or by the application.
132
135
 */
133
 
 
 
136
 
134
137
#if !defined(VMTOOLS_USE_GLIB)
135
138
 
136
139
/*
150
153
 */
151
154
 
152
155
static Bool
153
 
RpcInPingCallback(RpcInData *data)  // IN
 
156
RpcInPingCallback(char const **result,     // OUT
 
157
                  size_t *resultLen,       // OUT
 
158
                  const char *name,        // IN
 
159
                  const char *args,        // IN
 
160
                  size_t argsSize,         // IN
 
161
                  void *clientData)        // IN
154
162
{
155
 
   return RPCIN_SETRETVALS(data, "", TRUE);
 
163
   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
156
164
}
157
165
 
158
166
 
200
208
 *-----------------------------------------------------------------------------
201
209
 */
202
210
 
203
 
RpcInCallbackList *
 
211
static RpcInCallbackList *
204
212
RpcInLookupCallback(RpcIn *in,        // IN
205
213
                    const char *name) // IN
206
214
{
243
251
void
244
252
RpcIn_RegisterCallback(RpcIn *in,               // IN
245
253
                       const char *name,        // IN
246
 
                       RpcIn_CallbackOld cb,    // IN
 
254
                       RpcIn_Callback cb,       // IN
247
255
                       void *clientData)        // IN
248
256
{
249
257
   RpcInCallbackList *p;
260
268
 
261
269
   p->length = strlen(name);
262
270
   p->name = strdup(name);
263
 
   p->type = RPCIN_CB_OLD;
264
 
   p->callback.oldCb = cb;
265
 
   p->clientData = clientData;
266
 
 
267
 
   p->next = in->callbacks;
268
 
 
269
 
   in->callbacks = p;
270
 
}
271
 
 
272
 
 
273
 
/*
274
 
 *-----------------------------------------------------------------------------
275
 
 *
276
 
 * RpcIn_RegisterCallbackEx --
277
 
 *
278
 
 *      Register a callback to happen when a TCLO message is
279
 
 *      received. When a TCLO message beginning with 'name' is
280
 
 *      sent, the callback will be called with an instance of
281
 
 *      "RpcInData" with the information from the request.
282
 
 *
283
 
 * Results:
284
 
 *      None
285
 
 *
286
 
 * Side effects:
287
 
 *      None
288
 
 *
289
 
 *-----------------------------------------------------------------------------
290
 
 */
291
 
void
292
 
RpcIn_RegisterCallbackEx(RpcIn *in,          // IN
293
 
                         const char *name,   // IN
294
 
                         RpcIn_Callback cb,  // IN
295
 
                         void *clientData)   // IN
296
 
{
297
 
   RpcInCallbackList *p;
298
 
 
299
 
   Debug("Registering callback '%s'\n", name);
300
 
 
301
 
   ASSERT(in);
302
 
   ASSERT(name);
303
 
   ASSERT(cb);
304
 
   ASSERT(RpcInLookupCallback(in, name) == NULL); // not there yet
305
 
 
306
 
   p = (RpcInCallbackList *) malloc(sizeof(RpcInCallbackList));
307
 
   ASSERT_NOT_IMPLEMENTED(p);
308
 
 
309
 
   p->length = strlen(name);
310
 
   p->name = strdup(name);
311
 
   p->type = RPCIN_CB_NEW;
312
 
   p->callback.newCb = cb;
 
271
   p->callback = cb;
313
272
   p->clientData = clientData;
314
273
 
315
274
   p->next = in->callbacks;
500
459
/*
501
460
 *-----------------------------------------------------------------------------
502
461
 *
503
 
 * RpcIn_stop --
 
462
 * RpcInStop --
504
463
 *
505
 
 *      Stop the background loop that receives RPC from VMware
 
464
 *      Stop the RPC channel.
506
465
 *
507
466
 * Results:
508
 
 *      TRUE on success
509
 
 *      FALSE on failure
 
467
 *      None
510
468
 *
511
 
 * Side-effects:
512
 
 *      Try to send the last result and to close the channel
 
469
 * Side effects:
 
470
 *      Sends the last result back to the host.
513
471
 *
514
472
 *-----------------------------------------------------------------------------
515
473
 */
516
474
 
517
 
Bool
518
 
RpcIn_stop(RpcIn *in) // IN
 
475
static void
 
476
RpcInStop(RpcIn *in) // IN
519
477
{
520
 
   Bool status;
521
 
 
522
478
   ASSERT(in);
523
 
 
524
 
   status = TRUE;
525
 
 
526
479
   if (in->nextEvent) {
527
480
      /* The loop is started. Stop it */
528
481
#if defined(VMTOOLS_USE_GLIB)
529
 
      g_source_destroy(in->nextEvent);
 
482
      if (!in->inLoop) {
 
483
         g_source_destroy(in->nextEvent);
 
484
      }
 
485
 
 
486
      g_source_unref(in->nextEvent);
530
487
#else
531
488
      EventManager_Remove(in->nextEvent);
532
489
#endif
535
492
 
536
493
   if (in->channel) {
537
494
      /* The channel is open */
538
 
 
539
495
      if (in->mustSend) {
540
496
         /* There is a final result to send back. Try to send it */
541
 
         if (RpcInSend(in) == FALSE) {
542
 
            status = FALSE;
543
 
         }
544
 
 
 
497
         RpcInSend(in);
545
498
         ASSERT(in->mustSend == FALSE);
546
499
      }
547
500
 
548
501
      /* Try to close the channel */
549
502
      if (Message_Close(in->channel) == FALSE) {
550
503
         Debug("RpcIn: couldn't close channel\n");
551
 
         status = FALSE;
552
504
      }
553
505
 
554
506
      in->channel = NULL;
555
507
   }
556
 
 
557
 
   return status;
 
508
}
 
509
 
 
510
 
 
511
/*
 
512
 *-----------------------------------------------------------------------------
 
513
 *
 
514
 * RpcIn_stop --
 
515
 *
 
516
 *      Stop the RPC channel.
 
517
 *
 
518
 * Results:
 
519
 *      None
 
520
 *
 
521
 * Side-effects:
 
522
 *      Sends the last result to the host, if one exists.
 
523
 *
 
524
 *-----------------------------------------------------------------------------
 
525
 */
 
526
 
 
527
void
 
528
RpcIn_stop(RpcIn *in) // IN
 
529
{
 
530
   if (in->inLoop) {
 
531
      in->shouldStop = TRUE;
 
532
   } else {
 
533
      RpcInStop(in);
 
534
   }
558
535
}
559
536
 
560
537
 
563
540
 *
564
541
 * RpcInLoop --
565
542
 *
566
 
 *    The background loop that receives RPC from VMware
567
 
 *
568
 
 * Result
569
 
 *    Always FALSE for the glib implementation (to force unregistration of the
570
 
 *    timer; this function will re-schedule the callback).
571
 
 *    TRUE on success
572
 
 *    FALSE on failure (never happens in this implementation)
573
 
 *
574
 
 * Side-effects
575
 
 *    May call the error routine in which case the loop is
576
 
 *    stopped.
 
543
 *      Receives an RPC from the host.
 
544
 *
 
545
 * Result:
 
546
 *      For the Event Manager implementation, always TRUE.
 
547
 *
 
548
 *      For the glib implementation, returns FALSE if the timer was rescheduled
 
549
 *      so that g_main_loop will unregister the old timer, or TRUE otherwise.
 
550
 *
 
551
 * Side-effects:
 
552
 *      Stops the RPC channel on error.
577
553
 *
578
554
 *-----------------------------------------------------------------------------
579
555
 */
589
565
   char const *errmsg;
590
566
   char const *reply;
591
567
   size_t repLen;
 
568
   Bool resched = FALSE;
 
569
   unsigned int current;
592
570
 
593
571
   in = (RpcIn *)clientData;
594
572
   ASSERT(in);
595
 
 
596
 
   /* The event has fired: it is no longer valid */
597
573
   ASSERT(in->nextEvent);
598
 
#if defined(VMTOOLS_USE_GLIB)
599
 
   g_source_unref(in->nextEvent);
600
 
#endif
 
574
   ASSERT(in->channel);
 
575
   ASSERT(in->mustSend);
 
576
 
 
577
#if !defined(VMTOOLS_USE_GLIB)
 
578
   /*
 
579
    * The event has fired: it is no longer valid. Note that this is
 
580
    * not true in the glib case!
 
581
    */
601
582
   in->nextEvent = NULL;
602
 
 
603
 
   /* This is very important: this is the only way to signal the existence
604
 
      of this guest application to VMware */
605
 
   ASSERT(in->channel);
606
 
   ASSERT(in->mustSend);
 
583
#endif
 
584
 
 
585
   in->inLoop = TRUE;
 
586
 
 
587
   current = in->delay;
 
588
 
 
589
   /*
 
590
    * This is very important: this is the only way to signal the existence of
 
591
    * this guest application to VMware.
 
592
    */
607
593
   if (RpcInSend(in) == FALSE) {
608
594
      errmsg = "RpcIn: Unable to send";
609
595
      goto error;
610
596
   }
611
597
 
612
 
   if (Message_Receive(in->channel, (unsigned char **)(char**)&reply, &repLen)
613
 
          == FALSE) {
 
598
   if (Message_Receive(in->channel, (unsigned char **)&reply, &repLen) == FALSE) {
614
599
      errmsg = "RpcIn: Unable to receive";
615
600
      goto error;
616
601
   }
645
630
         free(cmd);
646
631
         if (cb) {
647
632
            result = NULL;
648
 
            if (cb->type == RPCIN_CB_OLD) {
649
 
               status = cb->callback.oldCb((char const **) &result, &resultLen, cb->name,
650
 
                                           reply + cb->length, repLen - cb->length,
651
 
                                           cb->clientData);
652
 
            } else {
653
 
               RpcInData data = { cb->name,
654
 
                                  reply + cb->length,
655
 
                                  repLen - cb->length,
656
 
                                  NULL,
657
 
                                  0,
658
 
                                  FALSE,
659
 
                                  NULL,
660
 
                                  cb->clientData };
661
 
               status = cb->callback.newCb(&data);
662
 
               result = data.result;
663
 
               resultLen = data.resultLen;
664
 
               freeResult = data.freeResult;
665
 
            }
666
 
 
 
633
            status = cb->callback((char const **) &result, &resultLen, cb->name,
 
634
                                  reply + cb->length, repLen - cb->length,
 
635
                                  cb->clientData);
667
636
            ASSERT(result);
668
637
         } else {
669
638
            status = FALSE;
693
662
      memcpy(in->last_result, statusStr, statusLen);
694
663
      memcpy(in->last_result + statusLen, result, resultLen);
695
664
      in->last_resultLen = statusLen + resultLen;
696
 
      
 
665
 
697
666
      if (freeResult) {
698
667
         free(result);
699
668
      }
700
669
 
701
 
#if 0 /* Costly in non-debug cases --hpreg */
702
 
      if (strlen(reply) <= 128) {
703
 
         Debug("Tclo: Done executing '%s'; result='%s'\n", reply, result);
704
 
      } else {
705
 
         Debug("Tclo: reply string too long to display\n");
706
 
      }
707
 
#endif
708
 
 
709
670
      /*
710
671
       * Run the event pump (in case VMware sends a long sequence of RPCs and
711
672
       * perfoms a time-consuming job) and continue to loop immediately
742
703
   ASSERT(in->mustSend == FALSE);
743
704
   in->mustSend = TRUE;
744
705
 
 
706
   if (!in->shouldStop) {
745
707
#if defined(VMTOOLS_USE_GLIB)
746
 
   RPCIN_SCHED_EVENT(in, g_timeout_source_new(in->delay * 10));
 
708
      if (in->delay != current) {
 
709
         resched = TRUE;
 
710
         g_source_unref(in->nextEvent);
 
711
         RPCIN_SCHED_EVENT(in, VMTools_CreateTimer(in->delay * 10));
 
712
      }
747
713
#else
748
 
   in->nextEvent = EventManager_Add(gTimerEventQueue, in->delay, RpcInLoop, in);
 
714
      in->nextEvent = EventManager_Add(gTimerEventQueue, in->delay, RpcInLoop, in);
749
715
#endif
750
 
   if (in->nextEvent == NULL) {
751
 
      errmsg = "RpcIn: Unable to run the loop";
752
 
      goto error;
753
 
   }
 
716
      if (in->nextEvent == NULL) {
 
717
         errmsg = "RpcIn: Unable to run the loop";
 
718
         goto error;
 
719
      }
 
720
   } else {
 
721
      /*
 
722
       * We need to return FALSE in this case so that the g_main_loop will
 
723
       * release its reference to the source.
 
724
       */
 
725
      resched = TRUE;
 
726
   }
 
727
 
 
728
exit:
 
729
   if (in->shouldStop) {
 
730
      RpcInStop(in);
 
731
      in->shouldStop = FALSE;
 
732
   }
 
733
 
 
734
   in->inLoop = FALSE;
754
735
 
755
736
#if defined(VMTOOLS_USE_GLIB)
756
 
   return FALSE;
 
737
   return !resched;
757
738
#else
758
739
   return TRUE;
759
740
#endif
760
741
 
761
742
error:
762
 
   RpcIn_stop(in);
763
 
 
764
743
   /* Call the error routine */
765
744
   (*in->errorFunc)(in->errorData, errmsg);
766
 
 
767
 
#if defined(VMTOOLS_USE_GLIB)
768
 
   return FALSE;
769
 
#else
770
 
   return TRUE;
771
 
#endif
 
745
   in->shouldStop = TRUE;
 
746
   goto exit;
772
747
}
773
748
 
774
749
 
827
802
 
828
803
   ASSERT(in->nextEvent == NULL);
829
804
#if defined(VMTOOLS_USE_GLIB)
830
 
   RPCIN_SCHED_EVENT(in, g_timeout_source_new(in->delay * 10));
 
805
   RPCIN_SCHED_EVENT(in, VMTools_CreateTimer(in->delay * 10));
831
806
#else
832
807
   in->nextEvent = EventManager_Add(gTimerEventQueue, 0, RpcInLoop, in);
833
808
   if (in->nextEvent == NULL) {
839
814
#if !defined(VMTOOLS_USE_GLIB)
840
815
   /* Register the 'reset' handler */
841
816
   if (resetCallback) {
842
 
      RpcIn_RegisterCallbackEx(in, "reset", resetCallback, resetClientData);
 
817
      RpcIn_RegisterCallback(in, "reset", resetCallback, resetClientData);
843
818
   }
844
819
 
845
 
   RpcIn_RegisterCallbackEx(in, "ping", RpcInPingCallback, NULL);
 
820
   RpcIn_RegisterCallback(in, "ping", RpcInPingCallback, NULL);
846
821
#endif
847
822
 
848
823
   return TRUE;
849
824
 
850
825
error:
851
 
   RpcIn_stop(in);
852
 
 
 
826
   RpcInStop(in);
853
827
   return FALSE;
854
828
}
855
829
 
856
830
 
857
 
/*
858
 
 *-----------------------------------------------------------------------------
859
 
 *
860
 
 * RpcIn_restart --
861
 
 *
862
 
 *    Stops/starts the background loop that receives RPC from VMware.
863
 
 *    Keeps already registered callbacks. Regardless of the value returned,
864
 
 *    callers are still expected to call RpcIn_stop() when done using rpcin,
865
 
 *    to properly release used resources.
866
 
 *
867
 
 * Result
868
 
 *    TRUE on success
869
 
 *    FALSE on failure
870
 
 *
871
 
 * Side-effects
872
 
 *    None
873
 
 *
874
 
 *-----------------------------------------------------------------------------
875
 
 */
876
 
 
877
 
Bool
878
 
RpcIn_restart(RpcIn *in)  // IN
879
 
{
880
 
   ASSERT(in);
881
 
 
882
 
   if (RpcIn_stop(in) == FALSE) {
883
 
      return FALSE;
884
 
   }
885
 
 
886
 
   ASSERT(in->channel == NULL);
887
 
   in->channel = Message_Open(0x4f4c4354);
888
 
   if (in->channel == NULL) {
889
 
      Debug("RpcIn_restart: couldn't open channel with TCLO protocol\n");
890
 
      return FALSE;
891
 
   }
892
 
 
893
 
   if (in->last_result) {
894
 
      free(in->last_result);
895
 
      in->last_result = NULL;
896
 
   }
897
 
   in->last_resultLen = 0;
898
 
   in->mustSend = TRUE;
899
 
 
900
 
   ASSERT(in->nextEvent == NULL);
901
 
#if defined(VMTOOLS_USE_GLIB)
902
 
   RPCIN_SCHED_EVENT(in, g_idle_source_new());
903
 
#else
904
 
   in->nextEvent = EventManager_Add(gTimerEventQueue, 0, RpcInLoop, in);
905
 
#endif
906
 
   if (in->nextEvent == NULL) {
907
 
      Debug("RpcIn_restart: couldn't start the loop\n");
908
 
      return FALSE;
909
 
   }
910
 
 
911
 
   return TRUE;
912
 
}
913
 
 
914
 
 
915
831
#if !defined(VMTOOLS_USE_GLIB)
916
832
/*
917
833
 *-----------------------------------------------------------------------------