122
113
/* The size of the result */
123
114
size_t last_resultLen;
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
125
Bool inLoop; // RpcInLoop is running.
126
Bool shouldStop; // Stop the channel the next time RpcInLoop exits.
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.
134
137
#if !defined(VMTOOLS_USE_GLIB)
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
155
return RPCIN_SETRETVALS(data, "", TRUE);
163
return RpcIn_SetRetVals(result, resultLen, "", TRUE);
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;
267
p->next = in->callbacks;
274
*-----------------------------------------------------------------------------
276
* RpcIn_RegisterCallbackEx --
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.
289
*-----------------------------------------------------------------------------
292
RpcIn_RegisterCallbackEx(RpcIn *in, // IN
293
const char *name, // IN
294
RpcIn_Callback cb, // IN
295
void *clientData) // IN
297
RpcInCallbackList *p;
299
Debug("Registering callback '%s'\n", name);
304
ASSERT(RpcInLookupCallback(in, name) == NULL); // not there yet
306
p = (RpcInCallbackList *) malloc(sizeof(RpcInCallbackList));
307
ASSERT_NOT_IMPLEMENTED(p);
309
p->length = strlen(name);
310
p->name = strdup(name);
311
p->type = RPCIN_CB_NEW;
312
p->callback.newCb = cb;
313
272
p->clientData = clientData;
315
274
p->next = in->callbacks;
501
460
*-----------------------------------------------------------------------------
505
* Stop the background loop that receives RPC from VMware
464
* Stop the RPC channel.
512
* Try to send the last result and to close the channel
470
* Sends the last result back to the host.
514
472
*-----------------------------------------------------------------------------
518
RpcIn_stop(RpcIn *in) // IN
476
RpcInStop(RpcIn *in) // IN
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);
483
g_source_destroy(in->nextEvent);
486
g_source_unref(in->nextEvent);
531
488
EventManager_Remove(in->nextEvent);
536
493
if (in->channel) {
537
494
/* The channel is open */
539
495
if (in->mustSend) {
540
496
/* There is a final result to send back. Try to send it */
541
if (RpcInSend(in) == FALSE) {
545
498
ASSERT(in->mustSend == FALSE);
548
501
/* Try to close the channel */
549
502
if (Message_Close(in->channel) == FALSE) {
550
503
Debug("RpcIn: couldn't close channel\n");
554
506
in->channel = NULL;
512
*-----------------------------------------------------------------------------
516
* Stop the RPC channel.
522
* Sends the last result to the host, if one exists.
524
*-----------------------------------------------------------------------------
528
RpcIn_stop(RpcIn *in) // IN
531
in->shouldStop = TRUE;
566
* The background loop that receives RPC from VMware
569
* Always FALSE for the glib implementation (to force unregistration of the
570
* timer; this function will re-schedule the callback).
572
* FALSE on failure (never happens in this implementation)
575
* May call the error routine in which case the loop is
543
* Receives an RPC from the host.
546
* For the Event Manager implementation, always TRUE.
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.
552
* Stops the RPC channel on error.
578
554
*-----------------------------------------------------------------------------
589
565
char const *errmsg;
590
566
char const *reply;
568
Bool resched = FALSE;
569
unsigned int current;
593
571
in = (RpcIn *)clientData;
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);
575
ASSERT(in->mustSend);
577
#if !defined(VMTOOLS_USE_GLIB)
579
* The event has fired: it is no longer valid. Note that this is
580
* not true in the glib case!
601
582
in->nextEvent = NULL;
603
/* This is very important: this is the only way to signal the existence
604
of this guest application to VMware */
606
ASSERT(in->mustSend);
590
* This is very important: this is the only way to signal the existence of
591
* this guest application to VMware.
607
593
if (RpcInSend(in) == FALSE) {
608
594
errmsg = "RpcIn: Unable to send";
612
if (Message_Receive(in->channel, (unsigned char **)(char**)&reply, &repLen)
598
if (Message_Receive(in->channel, (unsigned char **)&reply, &repLen) == FALSE) {
614
599
errmsg = "RpcIn: Unable to receive";
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,
653
RpcInData data = { cb->name,
661
status = cb->callback.newCb(&data);
662
result = data.result;
663
resultLen = data.resultLen;
664
freeResult = data.freeResult;
633
status = cb->callback((char const **) &result, &resultLen, cb->name,
634
reply + cb->length, repLen - cb->length,
693
662
memcpy(in->last_result, statusStr, statusLen);
694
663
memcpy(in->last_result + statusLen, result, resultLen);
695
664
in->last_resultLen = statusLen + resultLen;
697
666
if (freeResult) {
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);
705
Debug("Tclo: reply string too long to display\n");
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;
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) {
710
g_source_unref(in->nextEvent);
711
RPCIN_SCHED_EVENT(in, VMTools_CreateTimer(in->delay * 10));
748
in->nextEvent = EventManager_Add(gTimerEventQueue, in->delay, RpcInLoop, in);
714
in->nextEvent = EventManager_Add(gTimerEventQueue, in->delay, RpcInLoop, in);
750
if (in->nextEvent == NULL) {
751
errmsg = "RpcIn: Unable to run the loop";
716
if (in->nextEvent == NULL) {
717
errmsg = "RpcIn: Unable to run the loop";
722
* We need to return FALSE in this case so that the g_main_loop will
723
* release its reference to the source.
729
if (in->shouldStop) {
731
in->shouldStop = FALSE;
755
736
#if defined(VMTOOLS_USE_GLIB)
764
743
/* Call the error routine */
765
744
(*in->errorFunc)(in->errorData, errmsg);
767
#if defined(VMTOOLS_USE_GLIB)
745
in->shouldStop = TRUE;
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));
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);
845
RpcIn_RegisterCallbackEx(in, "ping", RpcInPingCallback, NULL);
820
RpcIn_RegisterCallback(in, "ping", RpcInPingCallback, NULL);
858
*-----------------------------------------------------------------------------
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.
874
*-----------------------------------------------------------------------------
878
RpcIn_restart(RpcIn *in) // IN
882
if (RpcIn_stop(in) == FALSE) {
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");
893
if (in->last_result) {
894
free(in->last_result);
895
in->last_result = NULL;
897
in->last_resultLen = 0;
900
ASSERT(in->nextEvent == NULL);
901
#if defined(VMTOOLS_USE_GLIB)
902
RPCIN_SCHED_EVENT(in, g_idle_source_new());
904
in->nextEvent = EventManager_Add(gTimerEventQueue, 0, RpcInLoop, in);
906
if (in->nextEvent == NULL) {
907
Debug("RpcIn_restart: couldn't start the loop\n");
915
831
#if !defined(VMTOOLS_USE_GLIB)
917
833
*-----------------------------------------------------------------------------