VirtualBox

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

Last change on this file since 48854 was 43899, checked in by vboxsync, 12 years ago

HostServices/HostChannel: code cleanup.

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