VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 22 months ago

Copyright year updates by scm.

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