VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 2 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.0 KB
Line 
1/* $Id: VBoxHostChannelSvc.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/* @file
3 * Host Channel: Host service entry points.
4 */
5
6/*
7 * Copyright (C) 2012-2024 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 rc = VERR_INVALID_PARAMETER;
248 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* name */
249 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* flags */
250 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* handle */
251 )
252 rc = VERR_INVALID_PARAMETER;
253 else
254 {
255 uint32_t u32Flags = 0; /* Shut up msvc*/
256 const char *pszName;
257 uint32_t cbName;
258
259 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **)&pszName, &cbName);
260 if ( RT_SUCCESS(rc)
261 && pszName[cbName - 1] != '\0')
262 rc = VERR_INVALID_PARAMETER;
263 if (RT_SUCCESS(rc))
264 rc = VBoxHGCMParmUInt32Get(&paParms[1], &u32Flags);
265 if (RT_SUCCESS(rc))
266 {
267 uint32_t u32Handle = 0;
268 rc = vboxHostChannelAttach(pClient, &u32Handle, pszName, u32Flags);
269 if (RT_SUCCESS(rc))
270 VBoxHGCMParmUInt32Set(&paParms[2], u32Handle);
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 const char *pszName;
509 uint32_t cbName;
510 uint32_t u32Code = 0; /* Shut up msvc*/
511 void *pvParm = NULL; /* Shut up msvc*/
512 uint32_t cbParm = 0; /* Shut up msvc*/
513 void *pvData = NULL; /* Shut up msvc*/
514 uint32_t cbData = 0; /* Shut up msvc*/
515
516 rc = VBoxHGCMParmPtrGet(&paParms[0], (void **)&pszName, &cbName);
517 if ( RT_SUCCESS(rc)
518 && pszName[cbName - 1] != '\0')
519 rc = VERR_INVALID_PARAMETER;
520
521 if (RT_SUCCESS(rc))
522 rc = VBoxHGCMParmUInt32Get(&paParms[1], &u32Code);
523 if (RT_SUCCESS (rc))
524 rc = VBoxHGCMParmPtrGet(&paParms[2], &pvParm, &cbParm);
525 if (RT_SUCCESS (rc))
526 rc = VBoxHGCMParmPtrGet(&paParms[3], &pvData, &cbData);
527 if (RT_SUCCESS (rc))
528 {
529 uint32_t u32SizeDataReturned = 0;
530 rc = vboxHostChannelQuery(pClient, pszName, u32Code,
531 pvParm, cbParm,
532 pvData, cbData, &u32SizeDataReturned);
533 if (RT_SUCCESS(rc))
534 VBoxHGCMParmUInt32Set(&paParms[4], u32SizeDataReturned);
535 }
536 }
537 } break;
538
539 default:
540 {
541 rc = VERR_NOT_IMPLEMENTED;
542 }
543 }
544
545 LogRelFlow(("svcCall: rc = %Rrc, async %d\n", rc, fAsynchronousProcessing));
546
547 if (!fAsynchronousProcessing)
548 {
549 g_pHelpers->pfnCallComplete(callHandle, rc);
550 }
551}
552
553static DECLCALLBACK(int) svcHostCall(void *pvService,
554 uint32_t u32Function,
555 uint32_t cParms,
556 VBOXHGCMSVCPARM paParms[])
557{
558 NOREF(pvService);
559
560 int rc = VINF_SUCCESS;
561
562 LogRel2(("svcHostCall: fn = %d, cParms = %d, pparms = %d\n",
563 u32Function, cParms, paParms));
564
565 switch (u32Function)
566 {
567 case VBOX_HOST_CHANNEL_HOST_FN_REGISTER:
568 {
569 LogRel2(("svcCall: VBOX_HOST_CHANNEL_HOST_FN_REGISTER\n"));
570
571 if (cParms != 2)
572 {
573 rc = VERR_INVALID_PARAMETER;
574 }
575 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* name */
576 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* iface */
577 )
578 {
579 rc = VERR_INVALID_PARAMETER;
580 }
581 else
582 {
583 void *pvName;
584 uint32_t cbName;
585 void *pvInterface;
586 uint32_t cbInterface;
587
588 rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
589
590 if (RT_SUCCESS(rc))
591 {
592 rc = VBoxHGCMParmPtrGet(&paParms[1], &pvInterface, &cbInterface);
593
594 if (RT_SUCCESS(rc))
595 {
596 rc = vboxHostChannelRegister((const char *)pvName,
597 (VBOXHOSTCHANNELINTERFACE *)pvInterface, cbInterface);
598 }
599 }
600 }
601 } break;
602
603 case VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER:
604 {
605 LogRel2(("svcCall: VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER\n"));
606
607 if (cParms != 1)
608 {
609 rc = VERR_INVALID_PARAMETER;
610 }
611 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* name */
612 )
613 {
614 rc = VERR_INVALID_PARAMETER;
615 }
616 else
617 {
618 void *pvName;
619 uint32_t cbName;
620
621 rc = VBoxHGCMParmPtrGet(&paParms[0], &pvName, &cbName);
622
623 if (RT_SUCCESS(rc))
624 {
625 rc = vboxHostChannelUnregister((const char *)pvName);
626 }
627 }
628 } break;
629
630 default:
631 break;
632 }
633
634 LogRelFlow(("svcHostCall: rc = %Rrc\n", rc));
635 return rc;
636}
637
638#if 0
639/** If the client in the guest is waiting for a read operation to complete
640 * then complete it, otherwise return. See the protocol description in the
641 * shared clipboard module description. */
642void vboxSvcClipboardCompleteReadData(VBOXHOSTCHCLIENT *pClient, int rc, uint32_t cbActual)
643{
644 VBOXHGCMCALLHANDLE callHandle = NULL;
645 VBOXHGCMSVCPARM *paParms = NULL;
646 bool fReadPending = false;
647 if (vboxSvcClipboardLock()) /* if not can we do anything useful? */
648 {
649 callHandle = pClient->asyncRead.callHandle;
650 paParms = pClient->asyncRead.paParms;
651 fReadPending = pClient->fReadPending;
652 pClient->fReadPending = false;
653 vboxSvcClipboardUnlock();
654 }
655 if (fReadPending)
656 {
657 VBoxHGCMParmUInt32Set (&paParms[2], cbActual);
658 g_pHelpers->pfnCallComplete (callHandle, rc);
659 }
660}
661
662/**
663 * SSM descriptor table for the VBOXHOSTCHCLIENT structure.
664 */
665static SSMFIELD const g_aClipboardClientDataFields[] =
666{
667 SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, u32ClientID), /* for validation purposes */
668 SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgQuit),
669 SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgReadData),
670 SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, fMsgFormats),
671 SSMFIELD_ENTRY(VBOXHOSTCHCLIENT, u32RequestedFormat),
672 SSMFIELD_ENTRY_TERM()
673};
674
675static DECLCALLBACK(int) svcSaveState(void *pvService, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
676{
677 NOREF(pvService);
678
679 /* If there are any pending requests, they must be completed here. Since
680 * the service is single threaded, there could be only requests
681 * which the service itself has postponed.
682 *
683 * HGCM knows that the state is being saved and that the pfnComplete
684 * calls are just clean ups. These requests are saved by the VMMDev.
685 *
686 * When the state will be restored, these requests will be reissued
687 * by VMMDev. The service therefore must save state as if there were no
688 * pending request.
689 */
690 LogRel2 (("svcSaveState: u32ClientID = %d\n", u32ClientID));
691
692 VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
693
694 /* This field used to be the length. We're using it as a version field
695 with the high bit set. */
696 SSMR3PutU32 (pSSM, UINT32_C (0x80000002));
697 int rc = SSMR3PutStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
698 AssertRCReturn (rc, rc);
699
700 if (pClient->fAsync)
701 {
702 g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS /* error code is not important here. */);
703 pClient->fAsync = false;
704 }
705
706 vboxSvcClipboardCompleteReadData (pClient, VINF_SUCCESS, 0);
707
708 return VINF_SUCCESS;
709}
710
711/**
712 * This structure corresponds to the original layout of the
713 * VBOXHOSTCHCLIENT structure. As the structure was saved as a whole
714 * when saving state, we need to remember it forever in order to preserve
715 * compatibility.
716 *
717 * (Starting with 3.1 this is no longer used.)
718 *
719 * @remarks Putting this outside svcLoadState to avoid visibility warning caused
720 * by -Wattributes.
721 */
722typedef struct CLIPSAVEDSTATEDATA
723{
724 struct CLIPSAVEDSTATEDATA *pNext;
725 struct CLIPSAVEDSTATEDATA *pPrev;
726
727 VBOXCLIPBOARDCONTEXT *pCtx;
728
729 uint32_t u32ClientID;
730
731 bool fAsync: 1; /* Guest is waiting for a message. */
732
733 bool fMsgQuit: 1;
734 bool fMsgReadData: 1;
735 bool fMsgFormats: 1;
736
737 struct {
738 VBOXHGCMCALLHANDLE callHandle;
739 VBOXHGCMSVCPARM *paParms;
740 } async;
741
742 struct {
743 void *pv;
744 uint32_t cb;
745 uint32_t u32Format;
746 } data;
747
748 uint32_t u32AvailableFormats;
749 uint32_t u32RequestedFormat;
750
751} CLIPSAVEDSTATEDATA;
752
753static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
754{
755 LogRel2 (("svcLoadState: u32ClientID = %d\n", u32ClientID));
756
757 VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvClient;
758
759 /* Existing client can not be in async state yet. */
760 Assert (!pClient->fAsync);
761
762 /* Save the client ID for data validation. */
763 /** @todo isn't this the same as u32ClientID? Playing safe for now... */
764 uint32_t const u32ClientIDOld = pClient->u32ClientID;
765
766 /* Restore the client data. */
767 uint32_t lenOrVer;
768 int rc = SSMR3GetU32 (pSSM, &lenOrVer);
769 AssertRCReturn (rc, rc);
770 if (lenOrVer == UINT32_C (0x80000002))
771 {
772 rc = SSMR3GetStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
773 AssertRCReturn (rc, rc);
774 }
775 else if (lenOrVer == (SSMR3HandleHostBits (pSSM) == 64 ? 72 : 48))
776 {
777 /**
778 * SSM descriptor table for the CLIPSAVEDSTATEDATA structure.
779 */
780 static SSMFIELD const s_aClipSavedStateDataFields30[] =
781 {
782 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, pNext),
783 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, pPrev),
784 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, pCtx),
785 SSMFIELD_ENTRY( CLIPSAVEDSTATEDATA, u32ClientID),
786 SSMFIELD_ENTRY_CUSTOM(fMsgQuit+fMsgReadData+fMsgFormats, RT_OFFSETOF(CLIPSAVEDSTATEDATA, u32ClientID) + 4, 4),
787 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, async.callHandle),
788 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, async.paParms),
789 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, data.pv),
790 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, data.cb),
791 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, data.u32Format),
792 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, u32AvailableFormats),
793 SSMFIELD_ENTRY( CLIPSAVEDSTATEDATA, u32RequestedFormat),
794 SSMFIELD_ENTRY_TERM()
795 };
796
797 CLIPSAVEDSTATEDATA savedState;
798 RT_ZERO (savedState);
799 rc = SSMR3GetStructEx (pSSM, &savedState, sizeof(savedState), SSMSTRUCT_FLAGS_MEM_BAND_AID,
800 &s_aClipSavedStateDataFields30[0], NULL);
801 AssertRCReturn (rc, rc);
802
803 pClient->fMsgQuit = savedState.fMsgQuit;
804 pClient->fMsgReadData = savedState.fMsgReadData;
805 pClient->fMsgFormats = savedState.fMsgFormats;
806 pClient->u32RequestedFormat = savedState.u32RequestedFormat;
807 }
808 else
809 {
810 LogRel (("Client data size mismatch: got %#x\n", lenOrVer));
811 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
812 }
813
814 /* Verify the client ID. */
815 if (pClient->u32ClientID != u32ClientIDOld)
816 {
817 LogRel (("Client ID mismatch: expected %d, got %d\n", u32ClientIDOld, pClient->u32ClientID));
818 pClient->u32ClientID = u32ClientIDOld;
819 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
820 }
821
822 /* Actual host data are to be reported to guest (SYNC). */
823 vboxClipboardSync (pClient);
824
825 return VINF_SUCCESS;
826}
827#endif
828
829static int svcInit(void)
830{
831 int rc = RTCritSectInit(&g_critsect);
832
833 if (RT_SUCCESS (rc))
834 {
835 rc = vboxHostChannelInit();
836
837 /* Clean up on failure, because 'svnUnload' will not be called
838 * if the 'svcInit' returns an error.
839 */
840 if (RT_FAILURE(rc))
841 {
842 RTCritSectDelete(&g_critsect);
843 }
844 }
845
846 return rc;
847}
848
849extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
850{
851 int rc = VINF_SUCCESS;
852
853 LogRelFlowFunc(("pTable = %p\n", pTable));
854
855 if (!pTable)
856 {
857 rc = VERR_INVALID_PARAMETER;
858 }
859 else
860 {
861 LogRel2(("VBoxHGCMSvcLoad: pTable->cbSize = %d, pTable->u32Version = 0x%08X\n",
862 pTable->cbSize, pTable->u32Version));
863
864 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
865 || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
866 {
867 rc = VERR_INVALID_PARAMETER;
868 }
869 else
870 {
871 g_pHelpers = pTable->pHelpers;
872
873 pTable->cbClient = sizeof(VBOXHOSTCHCLIENT);
874
875 pTable->pfnUnload = svcUnload;
876 pTable->pfnConnect = svcConnect;
877 pTable->pfnDisconnect = svcDisconnect;
878 pTable->pfnCall = svcCall;
879 pTable->pfnHostCall = svcHostCall;
880 pTable->pfnSaveState = NULL; // svcSaveState;
881 pTable->pfnLoadState = NULL; // svcLoadState;
882 pTable->pfnRegisterExtension = NULL;
883 pTable->pvService = NULL;
884
885 /* Service specific initialization. */
886 rc = svcInit();
887 }
888 }
889
890 return rc;
891}
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