VirtualBox

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

Last change on this file since 69496 was 69496, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

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