VirtualBox

source: vbox/trunk/src/VBox/HostServices/HostChannel/service.cpp@ 43421

Last change on this file since 43421 was 43352, checked in by vboxsync, 13 years ago

HostServices: Host Channel service.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.0 KB
Line 
1/* $Id: service.cpp 43352 2012-09-18 15:21:58Z vboxsync $ */
2/* @file
3 * Host Channel: Host service entry points.
4 */
5
6/*
7 * Copyright (C) 2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*
20 * The HostChannel host service provides a generic proxy between a host's
21 * channel provider and a client running in the guest.
22 *
23 * Host providers must register via a HostCall.
24 *
25 * A guest client can connect to a host provider and send/receive data.
26 *
27 * GuestCalls:
28 * * Attach - attach to a host channel
29 * * Detach - completely detach from a channel
30 * * Send - send data from the guest to the channel
31 * * Recv - non blocking read of available data from the channel
32 * * Control - generic channel specific command exchange
33 * * EventWait - wait for a host event
34 * * EventCancel - make the blocking EventWait call to return
35 * HostCalls:
36 * * Register - register a host channel
37 * * Unregister - unregister it
38 *
39 * The guest HGCM client connects to the service. The client can attach multiple channels.
40 *
41 */
42
43#include <iprt/alloc.h>
44#include <iprt/string.h>
45#include <iprt/assert.h>
46#include <iprt/critsect.h>
47#include <VBox/vmm/ssm.h>
48
49#include "HostChannel.h"
50
51
52static void VBoxHGCMParmUInt32Set(VBOXHGCMSVCPARM *pParm, uint32_t u32)
53{
54 pParm->type = VBOX_HGCM_SVC_PARM_32BIT;
55 pParm->u.uint32 = u32;
56}
57
58static int VBoxHGCMParmUInt32Get(VBOXHGCMSVCPARM *pParm, uint32_t *pu32)
59{
60 if (pParm->type == VBOX_HGCM_SVC_PARM_32BIT)
61 {
62 *pu32 = pParm->u.uint32;
63 return VINF_SUCCESS;
64 }
65
66 AssertFailed();
67 return VERR_INVALID_PARAMETER;
68}
69
70static void VBoxHGCMParmPtrSet(VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb)
71{
72 pParm->type = VBOX_HGCM_SVC_PARM_PTR;
73 pParm->u.pointer.size = cb;
74 pParm->u.pointer.addr = pv;
75}
76
77static int VBoxHGCMParmPtrGet(VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb)
78{
79 if (pParm->type == VBOX_HGCM_SVC_PARM_PTR)
80 {
81 *ppv = pParm->u.pointer.addr;
82 *pcb = pParm->u.pointer.size;
83 return VINF_SUCCESS;
84 }
85
86 AssertFailed();
87 return VERR_INVALID_PARAMETER;
88}
89
90
91static PVBOXHGCMSVCHELPERS g_pHelpers = NULL;
92
93static RTCRITSECT g_critsect;
94
95/*
96 * Helpers.
97 */
98
99int vboxHostChannelLock(void)
100{
101 return RTCritSectEnter(&g_critsect);
102}
103
104void vboxHostChannelUnlock(void)
105{
106 RTCritSectLeave(&g_critsect);
107}
108
109/* This is called under the lock. */
110void vboxHostChannelReportAsync(VBOXHOSTCHCLIENT *pClient,
111 uint32_t u32ChannelHandle,
112 uint32_t u32Id,
113 const void *pvEvent,
114 uint32_t cbEvent)
115{
116 if (cbEvent > 0)
117 {
118 void *pvParm = NULL;
119 uint32_t cbParm = 0;
120
121 VBoxHGCMParmPtrGet(&pClient->async.paParms[2], &pvParm, &cbParm);
122
123 uint32_t cbToCopy = RT_MIN(cbParm, cbEvent);
124 if (cbToCopy > 0)
125 {
126 memcpy(pvParm, pvEvent, cbToCopy);
127 }
128 }
129
130 VBoxHGCMParmUInt32Set(&pClient->async.paParms[0], u32ChannelHandle);
131 VBoxHGCMParmUInt32Set(&pClient->async.paParms[1], u32Id);
132 VBoxHGCMParmUInt32Set(&pClient->async.paParms[3], cbEvent);
133
134 LogRelFlow(("svcCall: CallComplete for pending\n"));
135
136 g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS);
137}
138
139
140/*
141 * Service entry points.
142 */
143
144static DECLCALLBACK(int) svcUnload(void *pvService)
145{
146 NOREF(pvService);
147 vboxHostChannelDestroy();
148 RTCritSectDelete(&g_critsect);
149 return VINF_SUCCESS;
150}
151
152static DECLCALLBACK(int) svcDisconnect(void *pvService, uint32_t u32ClientID, void *pvClient)
153{
154 NOREF(pvService);
155
156 VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
157
158 vboxHostChannelClientDisconnect(pClient);
159
160 memset(pClient, 0, sizeof(VBOXHOSTCHCLIENT));
161
162 return VINF_SUCCESS;
163}
164
165static DECLCALLBACK(int) svcConnect(void *pvService, uint32_t u32ClientID, void *pvClient)
166{
167 VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
168
169 int rc = VINF_SUCCESS;
170
171 /* Register the client. */
172 memset(pClient, 0, sizeof(VBOXHOSTCHCLIENT));
173
174 pClient->u32ClientID = u32ClientID;
175
176 rc = vboxHostChannelClientConnect(pClient);
177
178 LogRel2(("svcConnect: rc = %Rrc\n", rc));
179
180 return rc;
181}
182
183static DECLCALLBACK(void) svcCall(void *pvService,
184 VBOXHGCMCALLHANDLE callHandle,
185 uint32_t u32ClientID,
186 void *pvClient,
187 uint32_t u32Function,
188 uint32_t cParms,
189 VBOXHGCMSVCPARM paParms[])
190{
191 NOREF(pvService);
192
193 int rc = VINF_SUCCESS;
194
195 LogRel2(("svcCall: u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
196 u32ClientID, u32Function, cParms, paParms));
197
198 VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
199
200 bool fAsynchronousProcessing = false;
201
202#ifdef DEBUG
203 uint32_t i;
204
205 for (i = 0; i < cParms; i++)
206 {
207 /** @todo parameters other than 32 bit */
208 LogRel2((" pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32));
209 }
210#endif
211
212 switch (u32Function)
213 {
214 case VBOX_HOST_CHANNEL_FN_ATTACH:
215 {
216 LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_ATTACH\n"));
217
218 if (cParms != 3)
219 {
220 rc = VERR_INVALID_PARAMETER;
221 }
222 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* name */
223 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* flags */
224 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* handle */
225 )
226 {
227 rc = VERR_INVALID_PARAMETER;
228 }
229 else
230 {
231 uint32_t u32Flags;
232 void *pvName;
233 uint32_t cbName;
234
235 rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
236
237 if (RT_SUCCESS(rc))
238 {
239 rc = VBoxHGCMParmUInt32Get(&paParms[1], &u32Flags);
240
241 if (RT_SUCCESS(rc))
242 {
243 uint32_t u32Handle = 0;
244
245 rc = vboxHostChannelAttach(pClient, &u32Handle, (const char *)pvName, u32Flags);
246
247 if (RT_SUCCESS(rc))
248 {
249 VBoxHGCMParmUInt32Set(&paParms[2], u32Handle);
250 }
251 }
252 }
253 }
254 } break;
255
256 case VBOX_HOST_CHANNEL_FN_DETACH:
257 {
258 LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_DETACH\n"));
259
260 if (cParms != 1)
261 {
262 rc = VERR_INVALID_PARAMETER;
263 }
264 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* handle */
265 )
266 {
267 rc = VERR_INVALID_PARAMETER;
268 }
269 else
270 {
271 uint32_t u32Handle;
272
273 rc = VBoxHGCMParmUInt32Get(&paParms[0], &u32Handle);
274
275 if (RT_SUCCESS(rc))
276 {
277 rc = vboxHostChannelDetach(pClient, u32Handle);
278 }
279 }
280 } break;
281
282 case VBOX_HOST_CHANNEL_FN_SEND:
283 {
284 LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_SEND\n"));
285
286 if (cParms != 2)
287 {
288 rc = VERR_INVALID_PARAMETER;
289 }
290 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* handle */
291 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* data */
292 )
293 {
294 rc = VERR_INVALID_PARAMETER;
295 }
296 else
297 {
298 uint32_t u32Handle;
299 void *pvData;
300 uint32_t cbData;
301
302 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Handle);
303
304 if (RT_SUCCESS (rc))
305 {
306 rc = VBoxHGCMParmPtrGet (&paParms[1], &pvData, &cbData);
307
308 if (RT_SUCCESS (rc))
309 {
310 rc = vboxHostChannelSend(pClient, u32Handle, pvData, cbData);
311 }
312 }
313 }
314 } break;
315
316 case VBOX_HOST_CHANNEL_FN_RECV:
317 {
318 LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_RECV\n"));
319
320 if (cParms != 4)
321 {
322 rc = VERR_INVALID_PARAMETER;
323 }
324 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* handle */
325 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* data */
326 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* sizeReceived */
327 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* sizeRemaining */
328 )
329 {
330 rc = VERR_INVALID_PARAMETER;
331 }
332 else
333 {
334 uint32_t u32Handle;
335 void *pvData;
336 uint32_t cbData;
337
338 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Handle);
339
340 if (RT_SUCCESS (rc))
341 {
342 rc = VBoxHGCMParmPtrGet (&paParms[1], &pvData, &cbData);
343
344 if (RT_SUCCESS (rc))
345 {
346 uint32_t u32SizeReceived = 0;
347 uint32_t u32SizeRemaining = 0;
348
349 rc = vboxHostChannelRecv(pClient, u32Handle,
350 pvData, cbData,
351 &u32SizeReceived, &u32SizeRemaining);
352
353 if (RT_SUCCESS(rc))
354 {
355 VBoxHGCMParmUInt32Set(&paParms[2], u32SizeReceived);
356 VBoxHGCMParmUInt32Set(&paParms[3], u32SizeRemaining);
357 }
358 }
359 }
360 }
361 } break;
362
363 case VBOX_HOST_CHANNEL_FN_CONTROL:
364 {
365 LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_CONTROL\n"));
366
367 if (cParms != 5)
368 {
369 rc = VERR_INVALID_PARAMETER;
370 }
371 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* handle */
372 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* code */
373 || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* parm */
374 || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR /* data */
375 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* sizeDataReturned */
376 )
377 {
378 rc = VERR_INVALID_PARAMETER;
379 }
380 else
381 {
382 uint32_t u32Handle;
383 uint32_t u32Code;
384 void *pvParm;
385 uint32_t cbParm;
386 void *pvData;
387 uint32_t cbData;
388
389 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Handle);
390
391 if (RT_SUCCESS (rc))
392 {
393 rc = VBoxHGCMParmUInt32Get (&paParms[1], &u32Code);
394
395 if (RT_SUCCESS (rc))
396 {
397 rc = VBoxHGCMParmPtrGet (&paParms[2], &pvParm, &cbParm);
398
399 if (RT_SUCCESS (rc))
400 {
401 rc = VBoxHGCMParmPtrGet (&paParms[3], &pvData, &cbData);
402
403 if (RT_SUCCESS (rc))
404 {
405 uint32_t u32SizeDataReturned = 0;
406
407 rc = vboxHostChannelControl(pClient, u32Handle, u32Code,
408 pvParm, cbParm,
409 pvData, cbData, &u32SizeDataReturned);
410 if (RT_SUCCESS(rc))
411 {
412 VBoxHGCMParmUInt32Set(&paParms[4], u32SizeDataReturned);
413 }
414 }
415 }
416 }
417 }
418 }
419 } break;
420
421 case VBOX_HOST_CHANNEL_FN_EVENT_WAIT:
422 {
423 LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_EVENT_WAIT\n"));
424
425 if (cParms != 4)
426 {
427 rc = VERR_INVALID_PARAMETER;
428 }
429 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* handle */
430 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* id */
431 || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* parm */
432 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* sizeReturned */
433 )
434 {
435 rc = VERR_INVALID_PARAMETER;
436 }
437 else
438 {
439 void *pvParm;
440 uint32_t cbParm;
441
442 rc = VBoxHGCMParmPtrGet(&paParms[2], &pvParm, &cbParm);
443
444 if (RT_SUCCESS(rc))
445 {
446 /* This is accessed from the SVC thread and other threads. */
447 rc = vboxHostChannelLock();
448
449 if (RT_SUCCESS(rc))
450 {
451 if (pClient->fAsync)
452 {
453 /* If there is a wait request already, cancel it. */
454 vboxHostChannelReportAsync(pClient, 0, VBOX_HOST_CHANNEL_EVENT_CANCELLED, NULL, 0);
455
456 pClient->fAsync = false;
457 }
458
459 bool fEvent = false;
460 uint32_t u32Handle = 0;
461 uint32_t u32Id = 0;
462 uint32_t cbParmOut = 0;
463
464 rc = vboxHostChannelQueryEvent(pClient, &fEvent, &u32Handle, &u32Id,
465 pvParm, cbParm, &cbParmOut);
466
467 if (RT_SUCCESS(rc))
468 {
469 if (fEvent)
470 {
471 VBoxHGCMParmUInt32Set(&paParms[0], u32Handle);
472 VBoxHGCMParmUInt32Set(&paParms[1], u32Id);
473 VBoxHGCMParmUInt32Set(&paParms[3], cbParmOut);
474 }
475 else
476 {
477 /* No event available at the time. Process asynchronously. */
478 fAsynchronousProcessing = true;
479
480 pClient->fAsync = true;
481 pClient->async.callHandle = callHandle;
482 pClient->async.paParms = paParms;
483
484 LogRel2(("svcCall: async.\n"));
485 }
486 }
487
488 vboxHostChannelUnlock();
489 }
490 }
491 }
492 } break;
493
494 case VBOX_HOST_CHANNEL_FN_EVENT_CANCEL:
495 {
496 LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_EVENT_CANCEL\n"));
497
498 if (cParms != 0)
499 {
500 rc = VERR_INVALID_PARAMETER;
501 }
502 else
503 {
504 /* This is accessed from the SVC thread and other threads. */
505 rc = vboxHostChannelLock();
506
507 if (RT_SUCCESS(rc))
508 {
509 if (pClient->fAsync)
510 {
511 /* If there is a wait request alredy, cancel it. */
512 vboxHostChannelReportAsync(pClient, 0, VBOX_HOST_CHANNEL_EVENT_CANCELLED, NULL, 0);
513
514 pClient->fAsync = false;
515 }
516
517 vboxHostChannelUnlock();
518 }
519 }
520 } break;
521
522 default:
523 {
524 rc = VERR_NOT_IMPLEMENTED;
525 }
526 }
527
528 LogRelFlow(("svcCall: rc = %Rrc, async %d\n", rc, fAsynchronousProcessing));
529
530 if (!fAsynchronousProcessing)
531 {
532 g_pHelpers->pfnCallComplete(callHandle, rc);
533 }
534}
535
536static DECLCALLBACK(int) svcHostCall(void *pvService,
537 uint32_t u32Function,
538 uint32_t cParms,
539 VBOXHGCMSVCPARM paParms[])
540{
541 NOREF(pvService);
542
543 int rc = VINF_SUCCESS;
544
545 LogRel2(("svcHostCall: fn = %d, cParms = %d, pparms = %d\n",
546 u32Function, cParms, paParms));
547
548 switch (u32Function)
549 {
550 case VBOX_HOST_CHANNEL_HOST_FN_REGISTER:
551 {
552 LogRel2(("svcCall: VBOX_HOST_CHANNEL_HOST_FN_REGISTER\n"));
553
554 if (cParms != 2)
555 {
556 rc = VERR_INVALID_PARAMETER;
557 }
558 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* name */
559 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* iface */
560 )
561 {
562 rc = VERR_INVALID_PARAMETER;
563 }
564 else
565 {
566 void *pvName;
567 uint32_t cbName;
568 void *pvInterface;
569 uint32_t cbInterface;
570
571 rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
572
573 if (RT_SUCCESS(rc))
574 {
575 rc = VBoxHGCMParmPtrGet(&paParms[1], &pvInterface, &cbInterface);
576
577 if (RT_SUCCESS(rc))
578 {
579 rc = vboxHostChannelRegister((const char *)pvName,
580 (VBOXHOSTCHANNELINTERFACE *)pvInterface, cbInterface);
581 }
582 }
583 }
584 } break;
585
586 case VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER:
587 {
588 LogRel2(("svcCall: VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER\n"));
589
590 if (cParms != 1)
591 {
592 rc = VERR_INVALID_PARAMETER;
593 }
594 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* name */
595 )
596 {
597 rc = VERR_INVALID_PARAMETER;
598 }
599 else
600 {
601 void *pvName;
602 uint32_t cbName;
603
604 rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
605
606 if (RT_SUCCESS(rc))
607 {
608 rc = vboxHostChannelUnregister((const char *)pvName);
609 }
610 }
611 } break;
612
613 default:
614 break;
615 }
616
617 LogRelFlow(("svcHostCall: rc = %Rrc\n", rc));
618 return rc;
619}
620
621#if 0
622/** If the client in the guest is waiting for a read operation to complete
623 * then complete it, otherwise return. See the protocol description in the
624 * shared clipboard module description. */
625void vboxSvcClipboardCompleteReadData(VBOXHOSTCHCLIENT *pClient, int rc, uint32_t cbActual)
626{
627 VBOXHGCMCALLHANDLE callHandle = NULL;
628 VBOXHGCMSVCPARM *paParms = NULL;
629 bool fReadPending = false;
630 if (vboxSvcClipboardLock()) /* if not can we do anything useful? */
631 {
632 callHandle = pClient->asyncRead.callHandle;
633 paParms = pClient->asyncRead.paParms;
634 fReadPending = pClient->fReadPending;
635 pClient->fReadPending = false;
636 vboxSvcClipboardUnlock();
637 }
638 if (fReadPending)
639 {
640 VBoxHGCMParmUInt32Set (&paParms[2], cbActual);
641 g_pHelpers->pfnCallComplete (callHandle, rc);
642 }
643}
644
645/**
646 * SSM descriptor table for the VBOXHOSTCHCLIENT structure.
647 */
648static SSMFIELD const g_aClipboardClientDataFields[] =
649{
650 SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, u32ClientID), /* for validation purposes */
651 SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgQuit),
652 SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgReadData),
653 SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgFormats),
654 SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, u32RequestedFormat),
655 SSMFIELD_ENTRY_TERM()
656};
657
658static DECLCALLBACK(int) svcSaveState(void *pvService, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
659{
660 NOREF(pvService);
661
662 /* If there are any pending requests, they must be completed here. Since
663 * the service is single threaded, there could be only requests
664 * which the service itself has postponed.
665 *
666 * HGCM knows that the state is being saved and that the pfnComplete
667 * calls are just clean ups. These requests are saved by the VMMDev.
668 *
669 * When the state will be restored, these requests will be reissued
670 * by VMMDev. The service therefore must save state as if there were no
671 * pending request.
672 */
673 LogRel2 (("svcSaveState: u32ClientID = %d\n", u32ClientID));
674
675 VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
676
677 /* This field used to be the length. We're using it as a version field
678 with the high bit set. */
679 SSMR3PutU32 (pSSM, UINT32_C (0x80000002));
680 int rc = SSMR3PutStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
681 AssertRCReturn (rc, rc);
682
683 if (pClient->fAsync)
684 {
685 g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS /* error code is not important here. */);
686 pClient->fAsync = false;
687 }
688
689 vboxSvcClipboardCompleteReadData (pClient, VINF_SUCCESS, 0);
690
691 return VINF_SUCCESS;
692}
693
694/**
695 * This structure corresponds to the original layout of the
696 * VBOXHOSTCHCLIENT structure. As the structure was saved as a whole
697 * when saving state, we need to remember it forever in order to preserve
698 * compatibility.
699 *
700 * (Starting with 3.1 this is no longer used.)
701 *
702 * @remarks Putting this outside svcLoadState to avoid visibility warning caused
703 * by -Wattributes.
704 */
705typedef struct CLIPSAVEDSTATEDATA
706{
707 struct CLIPSAVEDSTATEDATA *pNext;
708 struct CLIPSAVEDSTATEDATA *pPrev;
709
710 VBOXCLIPBOARDCONTEXT *pCtx;
711
712 uint32_t u32ClientID;
713
714 bool fAsync: 1; /* Guest is waiting for a message. */
715
716 bool fMsgQuit: 1;
717 bool fMsgReadData: 1;
718 bool fMsgFormats: 1;
719
720 struct {
721 VBOXHGCMCALLHANDLE callHandle;
722 VBOXHGCMSVCPARM *paParms;
723 } async;
724
725 struct {
726 void *pv;
727 uint32_t cb;
728 uint32_t u32Format;
729 } data;
730
731 uint32_t u32AvailableFormats;
732 uint32_t u32RequestedFormat;
733
734} CLIPSAVEDSTATEDATA;
735
736static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
737{
738 LogRel2 (("svcLoadState: u32ClientID = %d\n", u32ClientID));
739
740 VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
741
742 /* Existing client can not be in async state yet. */
743 Assert (!pClient->fAsync);
744
745 /* Save the client ID for data validation. */
746 /** @todo isn't this the same as u32ClientID? Playing safe for now... */
747 uint32_t const u32ClientIDOld = pClient->u32ClientID;
748
749 /* Restore the client data. */
750 uint32_t lenOrVer;
751 int rc = SSMR3GetU32 (pSSM, &lenOrVer);
752 AssertRCReturn (rc, rc);
753 if (lenOrVer == UINT32_C (0x80000002))
754 {
755 rc = SSMR3GetStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
756 AssertRCReturn (rc, rc);
757 }
758 else if (lenOrVer == (SSMR3HandleHostBits (pSSM) == 64 ? 72 : 48))
759 {
760 /**
761 * SSM descriptor table for the CLIPSAVEDSTATEDATA structure.
762 */
763 static SSMFIELD const s_aClipSavedStateDataFields30[] =
764 {
765 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, pNext),
766 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, pPrev),
767 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, pCtx),
768 SSMFIELD_ENTRY( CLIPSAVEDSTATEDATA, u32ClientID),
769 SSMFIELD_ENTRY_CUSTOM(fMsgQuit+fMsgReadData+fMsgFormats, RT_OFFSETOF(CLIPSAVEDSTATEDATA, u32ClientID) + 4, 4),
770 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, async.callHandle),
771 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, async.paParms),
772 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, data.pv),
773 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, data.cb),
774 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, data.u32Format),
775 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, u32AvailableFormats),
776 SSMFIELD_ENTRY( CLIPSAVEDSTATEDATA, u32RequestedFormat),
777 SSMFIELD_ENTRY_TERM()
778 };
779
780 CLIPSAVEDSTATEDATA savedState;
781 RT_ZERO (savedState);
782 rc = SSMR3GetStructEx (pSSM, &savedState, sizeof(savedState), SSMSTRUCT_FLAGS_MEM_BAND_AID,
783 &s_aClipSavedStateDataFields30[0], NULL);
784 AssertRCReturn (rc, rc);
785
786 pClient->fMsgQuit = savedState.fMsgQuit;
787 pClient->fMsgReadData = savedState.fMsgReadData;
788 pClient->fMsgFormats = savedState.fMsgFormats;
789 pClient->u32RequestedFormat = savedState.u32RequestedFormat;
790 }
791 else
792 {
793 LogRel (("Client data size mismatch: got %#x\n", lenOrVer));
794 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
795 }
796
797 /* Verify the client ID. */
798 if (pClient->u32ClientID != u32ClientIDOld)
799 {
800 LogRel (("Client ID mismatch: expected %d, got %d\n", u32ClientIDOld, pClient->u32ClientID));
801 pClient->u32ClientID = u32ClientIDOld;
802 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
803 }
804
805 /* Actual host data are to be reported to guest (SYNC). */
806 vboxClipboardSync (pClient);
807
808 return VINF_SUCCESS;
809}
810#endif
811
812static int svcInit(void)
813{
814 int rc = RTCritSectInit(&g_critsect);
815
816 if (RT_SUCCESS (rc))
817 {
818 rc = vboxHostChannelInit();
819
820 /* Clean up on failure, because 'svnUnload' will not be called
821 * if the 'svcInit' returns an error.
822 */
823 if (RT_FAILURE(rc))
824 {
825 RTCritSectDelete(&g_critsect);
826 }
827 }
828
829 return rc;
830}
831
832extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
833{
834 int rc = VINF_SUCCESS;
835
836 LogRelFlowFunc(("pTable = %p\n", pTable));
837
838 if (!pTable)
839 {
840 rc = VERR_INVALID_PARAMETER;
841 }
842 else
843 {
844 LogRel2(("VBoxHGCMSvcLoad: pTable->cbSize = %d, pTable->u32Version = 0x%08X\n",
845 pTable->cbSize, pTable->u32Version));
846
847 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
848 || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
849 {
850 rc = VERR_INVALID_PARAMETER;
851 }
852 else
853 {
854 g_pHelpers = pTable->pHelpers;
855
856 pTable->cbClient = sizeof(VBOXHOSTCHCLIENT);
857
858 pTable->pfnUnload = svcUnload;
859 pTable->pfnConnect = svcConnect;
860 pTable->pfnDisconnect = svcDisconnect;
861 pTable->pfnCall = svcCall;
862 pTable->pfnHostCall = svcHostCall;
863 pTable->pfnSaveState = NULL; // svcSaveState;
864 pTable->pfnLoadState = NULL; // svcLoadState;
865 pTable->pfnRegisterExtension = NULL;
866 pTable->pvService = NULL;
867
868 /* Service specific initialization. */
869 rc = svcInit();
870 }
871 }
872
873 return rc;
874}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette