VirtualBox

source: vbox/trunk/src/VBox/HostServices/HostChannel/VBoxHostChannelSvc.cpp@ 93622

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