VirtualBox

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

最後變更 在這個檔案從75500是 75500,由 vboxsync 提交於 6 年 前

VMMDev,Main,HostServices: More profiling of HGCM guest call processing.

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

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