VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/service.cpp@ 34981

Last change on this file since 34981 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.8 KB
Line 
1/** @file
2 *
3 * Shared Clipboard:
4 * Host service entry points.
5 */
6
7/*
8 * Copyright (C) 2006-2007 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/** @page pg_hostclip The Shared Clipboard Host Service
21 *
22 * The shared clipboard host service provides a proxy between the host's
23 * clipboard and a similar proxy running on a guest. The service is split
24 * into a platform-independent core and platform-specific backends. The
25 * service defines two communication protocols - one to communicate with the
26 * clipboard service running on the guest, and one to communicate with the
27 * backend. These will be described in a very skeletal fashion here.
28 *
29 * @section sec_hostclip_guest_proto The guest communication protocol
30 *
31 * The guest clipboard service communicates with the host service via HGCM
32 * (the host service runs as an HGCM service). The guest clipboard must
33 * connect to the host service before all else (Windows hosts currently only
34 * support one simultaneous connection). Once it has connected, it can send
35 * HGCM messages to the host services, some of which will receive replies from
36 * the host. The host can only reply to a guest message, it cannot initiate
37 * any communication. The guest can in theory send any number of messages in
38 * parallel (see the descriptions of the messages for the practice), and the
39 * host will receive these in sequence, and may reply to them at once
40 * (releasing the caller in the guest) or defer the reply until later.
41 *
42 * There are currently four messages defined. The first is
43 * VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG, which waits for a message from the
44 * host. Host messages currently defined are
45 * VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT (unused),
46 * VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA (request that the guest send the
47 * contents of its clipboard to the host) and
48 * VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS (to notify the guest that new
49 * clipboard data is available). If a host message is sent while the guest is
50 * not waiting, it will be queued until the guest requests it. At most one
51 * host message of each type will be kept in the queue. The host code only
52 * supports a single simultaneous VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG call
53 * from the guest.
54 *
55 * The second guest message is VBOX_SHARED_CLIPBOARD_FN_FORMATS, which tells
56 * the host that the guest has new clipboard data available. The third is
57 * VBOX_SHARED_CLIPBOARD_FN_READ_DATA, which asks the host to send its
58 * clipboard data and waits until it arrives. The host supports at most one
59 * simultaneous VBOX_SHARED_CLIPBOARD_FN_READ_DATA call from the guest - if a
60 * second call is made before the first has returned, the first will be
61 * aborted.
62 *
63 * The last guest message is VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA, which is
64 * used to send the contents of the guest clipboard to the host. This call
65 * should be used after the host has requested data from the guest.
66 *
67 * @section sec_hostclip_backend_proto The communication protocol with the
68 * platform-specific backend
69 *
70 * This section may be written in the future :)
71 */
72
73#include <VBox/HostServices/VBoxClipboardSvc.h>
74#include <VBox/HostServices/VBoxClipboardExt.h>
75
76#include <iprt/alloc.h>
77#include <iprt/string.h>
78#include <iprt/assert.h>
79#include <iprt/critsect.h>
80#include <VBox/ssm.h>
81
82#include "VBoxClipboard.h"
83
84static void VBoxHGCMParmUInt32Set (VBOXHGCMSVCPARM *pParm, uint32_t u32)
85{
86 pParm->type = VBOX_HGCM_SVC_PARM_32BIT;
87 pParm->u.uint32 = u32;
88}
89
90static int VBoxHGCMParmUInt32Get (VBOXHGCMSVCPARM *pParm, uint32_t *pu32)
91{
92 if (pParm->type == VBOX_HGCM_SVC_PARM_32BIT)
93 {
94 *pu32 = pParm->u.uint32;
95 return VINF_SUCCESS;
96 }
97
98 return VERR_INVALID_PARAMETER;
99}
100
101#if 0
102static void VBoxHGCMParmPtrSet (VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb)
103{
104 pParm->type = VBOX_HGCM_SVC_PARM_PTR;
105 pParm->u.pointer.size = cb;
106 pParm->u.pointer.addr = pv;
107}
108#endif
109
110static int VBoxHGCMParmPtrGet (VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb)
111{
112 if (pParm->type == VBOX_HGCM_SVC_PARM_PTR)
113 {
114 *ppv = pParm->u.pointer.addr;
115 *pcb = pParm->u.pointer.size;
116 return VINF_SUCCESS;
117 }
118
119 return VERR_INVALID_PARAMETER;
120}
121
122static PVBOXHGCMSVCHELPERS g_pHelpers;
123
124static RTCRITSECT critsect;
125static uint32_t g_u32Mode;
126
127static PFNHGCMSVCEXT g_pfnExtension;
128static void *g_pvExtension;
129
130static VBOXCLIPBOARDCLIENTDATA *g_pClient;
131
132/* Serialization of data reading and format announcements from the RDP client. */
133static bool g_fReadingData = false;
134static bool g_fDelayedAnnouncement = false;
135static uint32_t g_u32DelayedFormats = 0;
136
137static uint32_t vboxSvcClipboardMode (void)
138{
139 return g_u32Mode;
140}
141
142static void vboxSvcClipboardModeSet (uint32_t u32Mode)
143{
144 switch (u32Mode)
145 {
146 case VBOX_SHARED_CLIPBOARD_MODE_OFF:
147 case VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST:
148 case VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST:
149 case VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL:
150 g_u32Mode = u32Mode;
151 break;
152
153 default:
154 g_u32Mode = VBOX_SHARED_CLIPBOARD_MODE_OFF;
155 }
156}
157
158bool vboxSvcClipboardLock (void)
159{
160 return RT_SUCCESS(RTCritSectEnter (&critsect));
161}
162
163void vboxSvcClipboardUnlock (void)
164{
165 RTCritSectLeave (&critsect);
166}
167
168/* Set the HGCM parameters according to pending messages.
169 * Executed under the clipboard lock.
170 */
171static bool vboxSvcClipboardReturnMsg (VBOXCLIPBOARDCLIENTDATA *pClient, VBOXHGCMSVCPARM paParms[])
172{
173 /* Message priority is taken into account. */
174 if (pClient->fMsgQuit)
175 {
176 LogRelFlow(("vboxSvcClipboardReturnMsg: Quit\n"));
177 VBoxHGCMParmUInt32Set (&paParms[0], VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT);
178 VBoxHGCMParmUInt32Set (&paParms[1], 0);
179 pClient->fMsgQuit = false;
180 }
181 else if (pClient->fMsgReadData)
182 {
183 LogRelFlow(("vboxSvcClipboardReturnMsg: ReadData %02X\n", pClient->u32RequestedFormat));
184 VBoxHGCMParmUInt32Set (&paParms[0], VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA);
185 VBoxHGCMParmUInt32Set (&paParms[1], pClient->u32RequestedFormat);
186 pClient->fMsgReadData = false;
187 }
188 else if (pClient->fMsgFormats)
189 {
190 LogRelFlow(("vboxSvcClipboardReturnMsg: Formats %02X\n", pClient->u32AvailableFormats));
191 VBoxHGCMParmUInt32Set (&paParms[0], VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS);
192 VBoxHGCMParmUInt32Set (&paParms[1], pClient->u32AvailableFormats);
193 pClient->fMsgFormats = false;
194 }
195 else
196 {
197 /* No pending messages. */
198 LogRelFlow(("vboxSvcClipboardReturnMsg: no message\n"));
199 return false;
200 }
201
202 /* Message information assigned. */
203 return true;
204}
205
206void vboxSvcClipboardReportMsg (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Msg, uint32_t u32Formats)
207{
208 if (vboxSvcClipboardLock ())
209 {
210 switch (u32Msg)
211 {
212 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
213 {
214 LogRelFlow(("vboxSvcClipboardReportMsg: Quit\n"));
215 pClient->fMsgQuit = true;
216 } break;
217 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
218 {
219 if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST
220 && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
221 {
222 /* Skip the message. */
223 break;
224 }
225
226 LogRelFlow(("vboxSvcClipboardReportMsg: ReadData %02X\n", u32Formats));
227 pClient->u32RequestedFormat = u32Formats;
228 pClient->fMsgReadData = true;
229 } break;
230 case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
231 {
232 if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST
233 && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
234 {
235 /* Skip the message. */
236 break;
237 }
238
239 LogRelFlow(("vboxSvcClipboardReportMsg: Formats %02X\n", u32Formats));
240 pClient->u32AvailableFormats = u32Formats;
241 pClient->fMsgFormats = true;
242 } break;
243 default:
244 {
245 /* Invalid message. */
246 LogRelFlow(("vboxSvcClipboardReportMsg: invalid message %d\n", u32Msg));
247 } break;
248 }
249
250 if (pClient->fAsync)
251 {
252 /* The client waits for a response. */
253 bool fMessageReturned = vboxSvcClipboardReturnMsg (pClient, pClient->async.paParms);
254
255 /* Make a copy of the handle. */
256 VBOXHGCMCALLHANDLE callHandle = pClient->async.callHandle;
257
258 if (fMessageReturned)
259 {
260 /* There is a response. */
261 pClient->fAsync = false;
262 }
263
264 vboxSvcClipboardUnlock ();
265
266 if (fMessageReturned)
267 {
268 LogRelFlow(("vboxSvcClipboardReportMsg: CallComplete\n"));
269 g_pHelpers->pfnCallComplete (callHandle, VINF_SUCCESS);
270 }
271 }
272 else
273 {
274 vboxSvcClipboardUnlock ();
275 }
276 }
277}
278
279static int svcInit (void)
280{
281 int rc = RTCritSectInit (&critsect);
282
283 if (RT_SUCCESS (rc))
284 {
285 vboxSvcClipboardModeSet (VBOX_SHARED_CLIPBOARD_MODE_OFF);
286
287 rc = vboxClipboardInit ();
288
289 /* Clean up on failure, because 'svnUnload' will not be called
290 * if the 'svcInit' returns an error.
291 */
292 if (RT_FAILURE (rc))
293 {
294 RTCritSectDelete (&critsect);
295 }
296 }
297
298 return rc;
299}
300
301static DECLCALLBACK(int) svcUnload (void *)
302{
303 vboxClipboardDestroy ();
304 RTCritSectDelete (&critsect);
305 return VINF_SUCCESS;
306}
307
308/**
309 * Disconnect the host side of the shared clipboard and send a "host disconnected" message
310 * to the guest side.
311 */
312static DECLCALLBACK(int) svcDisconnect (void *, uint32_t u32ClientID, void *pvClient)
313{
314 VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
315
316 vboxSvcClipboardReportMsg (pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT, 0);
317
318 vboxClipboardDisconnect (pClient);
319
320 memset (pClient, 0, sizeof (*pClient));
321
322 g_pClient = NULL;
323
324 return VINF_SUCCESS;
325}
326
327static DECLCALLBACK(int) svcConnect (void *, uint32_t u32ClientID, void *pvClient)
328{
329 VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
330
331 int rc = VINF_SUCCESS;
332
333 /* If there is already a client connected then we want to release it first. */
334 if (g_pClient != NULL)
335 {
336 uint32_t u32OldClientID = g_pClient->u32ClientID;
337
338 svcDisconnect(NULL, u32OldClientID, g_pClient);
339 /* And free the resources in the hgcm subsystem. */
340 g_pHelpers->pfnDisconnectClient(g_pHelpers->pvInstance, u32OldClientID);
341 }
342
343 /* Register the client. */
344 memset (pClient, 0, sizeof (*pClient));
345
346 pClient->u32ClientID = u32ClientID;
347
348 rc = vboxClipboardConnect (pClient);
349
350 if (RT_SUCCESS (rc))
351 {
352 g_pClient = pClient;
353 }
354
355 LogRel2(("vboxClipboardConnect: rc = %Rrc\n", rc));
356
357 return rc;
358}
359
360static DECLCALLBACK(void) svcCall (void *,
361 VBOXHGCMCALLHANDLE callHandle,
362 uint32_t u32ClientID,
363 void *pvClient,
364 uint32_t u32Function,
365 uint32_t cParms,
366 VBOXHGCMSVCPARM paParms[])
367{
368 int rc = VINF_SUCCESS;
369
370 LogRel2(("svcCall: u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
371 u32ClientID, u32Function, cParms, paParms));
372
373 VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
374
375 bool fAsynchronousProcessing = false;
376
377#ifdef DEBUG
378 uint32_t i;
379
380 for (i = 0; i < cParms; i++)
381 {
382 /** @todo parameters other than 32 bit */
383 LogRel2((" pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32));
384 }
385#endif
386
387 switch (u32Function)
388 {
389 case VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG:
390 {
391 /* The quest requests a host message. */
392 LogRel2(("svcCall: VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG\n"));
393
394 if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_GET_HOST_MSG)
395 {
396 rc = VERR_INVALID_PARAMETER;
397 }
398 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* msg */
399 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* formats */
400 )
401 {
402 rc = VERR_INVALID_PARAMETER;
403 }
404 else
405 {
406 /* Atomically verify the client's state. */
407 if (vboxSvcClipboardLock ())
408 {
409 bool fMessageReturned = vboxSvcClipboardReturnMsg (pClient, paParms);
410
411 if (fMessageReturned)
412 {
413 /* Just return to the caller. */
414 pClient->fAsync = false;
415 }
416 else
417 {
418 /* No event available at the time. Process asynchronously. */
419 fAsynchronousProcessing = true;
420
421 pClient->fAsync = true;
422 pClient->async.callHandle = callHandle;
423 pClient->async.paParms = paParms;
424
425 LogRel2(("svcCall: async.\n"));
426 }
427
428 vboxSvcClipboardUnlock ();
429 }
430 else
431 {
432 rc = VERR_NOT_SUPPORTED;
433 }
434 }
435 } break;
436
437 case VBOX_SHARED_CLIPBOARD_FN_FORMATS:
438 {
439 /* The guest reports that some formats are available. */
440 LogRel2(("svcCall: VBOX_SHARED_CLIPBOARD_FN_FORMATS\n"));
441
442 if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_FORMATS)
443 {
444 rc = VERR_INVALID_PARAMETER;
445 }
446 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* formats */
447 )
448 {
449 rc = VERR_INVALID_PARAMETER;
450 }
451 else
452 {
453 uint32_t u32Formats;
454
455 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Formats);
456
457 if (RT_SUCCESS (rc))
458 {
459 if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST
460 && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
461 {
462 rc = VERR_NOT_SUPPORTED;
463 break;
464 }
465
466 if (g_pfnExtension)
467 {
468 VBOXCLIPBOARDEXTPARMS parms;
469
470 parms.u32Format = u32Formats;
471
472 g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE, &parms, sizeof (parms));
473 }
474 else
475 {
476 vboxClipboardFormatAnnounce (pClient, u32Formats);
477 }
478 }
479 }
480 } break;
481
482 case VBOX_SHARED_CLIPBOARD_FN_READ_DATA:
483 {
484 /* The guest wants to read data in the given format. */
485 LogRel2(("svcCall: VBOX_SHARED_CLIPBOARD_FN_READ_DATA\n"));
486
487 if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_READ_DATA)
488 {
489 rc = VERR_INVALID_PARAMETER;
490 }
491 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* format */
492 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* ptr */
493 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* size */
494 )
495 {
496 rc = VERR_INVALID_PARAMETER;
497 }
498 else
499 {
500 uint32_t u32Format;
501 void *pv;
502 uint32_t cb;
503
504 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Format);
505
506 if (RT_SUCCESS (rc))
507 {
508 rc = VBoxHGCMParmPtrGet (&paParms[1], &pv, &cb);
509
510 if (RT_SUCCESS (rc))
511 {
512 if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST
513 && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
514 {
515 rc = VERR_NOT_SUPPORTED;
516 break;
517 }
518
519 uint32_t cbActual = 0;
520
521 if (g_pfnExtension)
522 {
523 VBOXCLIPBOARDEXTPARMS parms;
524
525 parms.u32Format = u32Format;
526 parms.u.pvData = pv;
527 parms.cbData = cb;
528
529 g_fReadingData = true;
530 rc = g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_READ, &parms, sizeof (parms));
531 LogRelFlow(("DATA: g_fDelayedAnnouncement = %d, g_u32DelayedFormats = 0x%x\n", g_fDelayedAnnouncement, g_u32DelayedFormats));
532 if (g_fDelayedAnnouncement)
533 {
534 vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, g_u32DelayedFormats);
535 g_fDelayedAnnouncement = false;
536 g_u32DelayedFormats = 0;
537 }
538 g_fReadingData = false;
539
540 if (RT_SUCCESS (rc))
541 {
542 cbActual = parms.cbData;
543 }
544 }
545 else
546 {
547 /* Release any other pending read, as we only
548 * support one pending read at one time. */
549 vboxSvcClipboardCompleteReadData(pClient, VERR_NO_DATA, 0);
550 rc = vboxClipboardReadData (pClient, u32Format, pv, cb, &cbActual);
551 }
552
553 /* Remember our read request until it is completed.
554 * See the protocol description above for more
555 * information. */
556 if (rc == VINF_HGCM_ASYNC_EXECUTE)
557 {
558 if (vboxSvcClipboardLock())
559 {
560 pClient->asyncRead.callHandle = callHandle;
561 pClient->asyncRead.paParms = paParms;
562 pClient->fReadPending = true;
563 fAsynchronousProcessing = true;
564 vboxSvcClipboardUnlock();
565 }
566 else
567 rc = VERR_NOT_SUPPORTED;
568 }
569 else if (RT_SUCCESS (rc))
570 {
571 VBoxHGCMParmUInt32Set (&paParms[2], cbActual);
572 }
573 }
574 }
575 }
576 } break;
577
578 case VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA:
579 {
580 /* The guest writes the requested data. */
581 LogRel2(("svcCall: VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA\n"));
582
583 if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_WRITE_DATA)
584 {
585 rc = VERR_INVALID_PARAMETER;
586 }
587 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* format */
588 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* ptr */
589 )
590 {
591 rc = VERR_INVALID_PARAMETER;
592 }
593 else
594 {
595 void *pv;
596 uint32_t cb;
597 uint32_t u32Format;
598
599 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Format);
600
601 if (RT_SUCCESS (rc))
602 {
603 rc = VBoxHGCMParmPtrGet (&paParms[1], &pv, &cb);
604
605 if (RT_SUCCESS (rc))
606 {
607 if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST
608 && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
609 {
610 rc = VERR_NOT_SUPPORTED;
611 break;
612 }
613
614 if (g_pfnExtension)
615 {
616 VBOXCLIPBOARDEXTPARMS parms;
617
618 parms.u32Format = u32Format;
619 parms.u.pvData = pv;
620 parms.cbData = cb;
621
622 g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_WRITE, &parms, sizeof (parms));
623 }
624 else
625 {
626 vboxClipboardWriteData (pClient, pv, cb, u32Format);
627 }
628 }
629 }
630 }
631 } break;
632
633 default:
634 {
635 rc = VERR_NOT_IMPLEMENTED;
636 }
637 }
638
639 LogRelFlow(("svcCall: rc = %Rrc\n", rc));
640
641 if (!fAsynchronousProcessing)
642 {
643 g_pHelpers->pfnCallComplete (callHandle, rc);
644 }
645}
646
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(VBOXCLIPBOARDCLIENTDATA *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 * We differentiate between a function handler for the guest and one for the host.
672 */
673static DECLCALLBACK(int) svcHostCall (void *,
674 uint32_t u32Function,
675 uint32_t cParms,
676 VBOXHGCMSVCPARM paParms[])
677{
678 int rc = VINF_SUCCESS;
679
680 LogRel2(("svcHostCall: fn = %d, cParms = %d, pparms = %d\n",
681 u32Function, cParms, paParms));
682
683 switch (u32Function)
684 {
685 case VBOX_SHARED_CLIPBOARD_HOST_FN_SET_MODE:
686 {
687 LogRel2(("svcCall: VBOX_SHARED_CLIPBOARD_HOST_FN_SET_MODE\n"));
688
689 if (cParms != 1)
690 {
691 rc = VERR_INVALID_PARAMETER;
692 }
693 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* mode */
694 )
695 {
696 rc = VERR_INVALID_PARAMETER;
697 }
698 else
699 {
700 uint32_t u32Mode = VBOX_SHARED_CLIPBOARD_MODE_OFF;
701
702 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Mode);
703
704 /* The setter takes care of invalid values. */
705 vboxSvcClipboardModeSet (u32Mode);
706 }
707 } break;
708
709 default:
710 break;
711 }
712
713 LogRelFlow(("svcHostCall: rc = %Rrc\n", rc));
714 return rc;
715}
716
717/**
718 * SSM descriptor table for the VBOXCLIPBOARDCLIENTDATA structure.
719 */
720static SSMFIELD const g_aClipboardClientDataFields[] =
721{
722 SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTDATA, u32ClientID), /* for validation purposes */
723 SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTDATA, fMsgQuit),
724 SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTDATA, fMsgReadData),
725 SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTDATA, fMsgFormats),
726 SSMFIELD_ENTRY(VBOXCLIPBOARDCLIENTDATA, u32RequestedFormat),
727 SSMFIELD_ENTRY_TERM()
728};
729
730static DECLCALLBACK(int) svcSaveState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
731{
732 /* If there are any pending requests, they must be completed here. Since
733 * the service is single threaded, there could be only requests
734 * which the service itself has postponed.
735 *
736 * HGCM knows that the state is being saved and that the pfnComplete
737 * calls are just clean ups. These requests are saved by the VMMDev.
738 *
739 * When the state will be restored, these requests will be reissued
740 * by VMMDev. The service therefore must save state as if there were no
741 * pending request.
742 */
743 LogRel2 (("svcSaveState: u32ClientID = %d\n", u32ClientID));
744
745 VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
746
747 /* This field used to be the length. We're using it as a version field
748 with the high bit set. */
749 SSMR3PutU32 (pSSM, UINT32_C (0x80000002));
750 int rc = SSMR3PutStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
751 AssertRCReturn (rc, rc);
752
753 if (pClient->fAsync)
754 {
755 g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS /* error code is not important here. */);
756 pClient->fAsync = false;
757 }
758
759 vboxSvcClipboardCompleteReadData (pClient, VINF_SUCCESS, 0);
760
761 return VINF_SUCCESS;
762}
763
764/**
765 * This structure corresponds to the original layout of the
766 * VBOXCLIPBOARDCLIENTDATA structure. As the structure was saved as a whole
767 * when saving state, we need to remember it forever in order to preserve
768 * compatibility.
769 *
770 * (Starting with 3.1 this is no longer used.)
771 *
772 * @remarks Putting this outside svcLoadState to avoid visibility warning caused
773 * by -Wattributes.
774 */
775typedef struct CLIPSAVEDSTATEDATA
776{
777 struct CLIPSAVEDSTATEDATA *pNext;
778 struct CLIPSAVEDSTATEDATA *pPrev;
779
780 VBOXCLIPBOARDCONTEXT *pCtx;
781
782 uint32_t u32ClientID;
783
784 bool fAsync: 1; /* Guest is waiting for a message. */
785
786 bool fMsgQuit: 1;
787 bool fMsgReadData: 1;
788 bool fMsgFormats: 1;
789
790 struct {
791 VBOXHGCMCALLHANDLE callHandle;
792 VBOXHGCMSVCPARM *paParms;
793 } async;
794
795 struct {
796 void *pv;
797 uint32_t cb;
798 uint32_t u32Format;
799 } data;
800
801 uint32_t u32AvailableFormats;
802 uint32_t u32RequestedFormat;
803
804} CLIPSAVEDSTATEDATA;
805
806static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
807{
808 LogRel2 (("svcLoadState: u32ClientID = %d\n", u32ClientID));
809
810 VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
811
812 /* Existing client can not be in async state yet. */
813 Assert (!pClient->fAsync);
814
815 /* Save the client ID for data validation. */
816 /** @todo isn't this the same as u32ClientID? Playing safe for now... */
817 uint32_t const u32ClientIDOld = pClient->u32ClientID;
818
819 /* Restore the client data. */
820 uint32_t lenOrVer;
821 int rc = SSMR3GetU32 (pSSM, &lenOrVer);
822 AssertRCReturn (rc, rc);
823 if (lenOrVer == UINT32_C (0x80000002))
824 {
825 rc = SSMR3GetStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
826 AssertRCReturn (rc, rc);
827 }
828 else if (lenOrVer == (SSMR3HandleHostBits (pSSM) == 64 ? 72 : 48))
829 {
830 /**
831 * SSM descriptor table for the CLIPSAVEDSTATEDATA structure.
832 */
833 static SSMFIELD const s_aClipSavedStateDataFields30[] =
834 {
835 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, pNext),
836 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, pPrev),
837 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, pCtx),
838 SSMFIELD_ENTRY( CLIPSAVEDSTATEDATA, u32ClientID),
839 SSMFIELD_ENTRY_CUSTOM(fMsgQuit+fMsgReadData+fMsgFormats, RT_OFFSETOF(CLIPSAVEDSTATEDATA, u32ClientID) + 4, 4),
840 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, async.callHandle),
841 SSMFIELD_ENTRY_IGN_HCPTR( CLIPSAVEDSTATEDATA, async.paParms),
842 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, data.pv),
843 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, data.cb),
844 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, data.u32Format),
845 SSMFIELD_ENTRY_IGNORE( CLIPSAVEDSTATEDATA, u32AvailableFormats),
846 SSMFIELD_ENTRY( CLIPSAVEDSTATEDATA, u32RequestedFormat),
847 SSMFIELD_ENTRY_TERM()
848 };
849
850 CLIPSAVEDSTATEDATA savedState;
851 RT_ZERO (savedState);
852 rc = SSMR3GetStructEx (pSSM, &savedState, sizeof(savedState), SSMSTRUCT_FLAGS_MEM_BAND_AID,
853 &s_aClipSavedStateDataFields30[0], NULL);
854 AssertRCReturn (rc, rc);
855
856 pClient->fMsgQuit = savedState.fMsgQuit;
857 pClient->fMsgReadData = savedState.fMsgReadData;
858 pClient->fMsgFormats = savedState.fMsgFormats;
859 pClient->u32RequestedFormat = savedState.u32RequestedFormat;
860 }
861 else
862 {
863 LogRel (("Client data size mismatch: got %#x\n", lenOrVer));
864 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
865 }
866
867 /* Verify the client ID. */
868 if (pClient->u32ClientID != u32ClientIDOld)
869 {
870 LogRel (("Client ID mismatch: expected %d, got %d\n", u32ClientIDOld, pClient->u32ClientID));
871 pClient->u32ClientID = u32ClientIDOld;
872 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
873 }
874
875 /* Actual host data are to be reported to guest (SYNC). */
876 vboxClipboardSync (pClient);
877
878 return VINF_SUCCESS;
879}
880
881static DECLCALLBACK(int) extCallback (uint32_t u32Function, uint32_t u32Format, void *pvData, uint32_t cbData)
882{
883 if (g_pClient != NULL)
884 {
885 switch (u32Function)
886 {
887 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
888 {
889 LogRelFlow(("ANNOUNCE: g_fReadingData = %d\n", g_fReadingData));
890 if (g_fReadingData)
891 {
892 g_fDelayedAnnouncement = true;
893 g_u32DelayedFormats = u32Format;
894 }
895 else
896 {
897 vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, u32Format);
898 }
899 } break;
900
901 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
902 {
903 vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
904 } break;
905
906 default:
907 return VERR_NOT_SUPPORTED;
908 }
909 }
910
911 return VINF_SUCCESS;
912}
913
914static DECLCALLBACK(int) svcRegisterExtension(void *, PFNHGCMSVCEXT pfnExtension, void *pvExtension)
915{
916 LogRelFlowFunc(("pfnExtension = %p\n", pfnExtension));
917
918 VBOXCLIPBOARDEXTPARMS parms;
919
920 if (pfnExtension)
921 {
922 /* Install extension. */
923 g_pfnExtension = pfnExtension;
924 g_pvExtension = pvExtension;
925
926 parms.u.pfnCallback = extCallback;
927 g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof (parms));
928 }
929 else
930 {
931 if (g_pfnExtension)
932 {
933 parms.u.pfnCallback = NULL;
934 g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof (parms));
935 }
936
937 /* Uninstall extension. */
938 g_pfnExtension = NULL;
939 g_pvExtension = NULL;
940 }
941
942 return VINF_SUCCESS;
943}
944
945extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable)
946{
947 int rc = VINF_SUCCESS;
948
949 LogRelFlowFunc(("ptable = %p\n", ptable));
950
951 if (!ptable)
952 {
953 rc = VERR_INVALID_PARAMETER;
954 }
955 else
956 {
957 LogRel2(("VBoxHGCMSvcLoad: ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
958
959 if ( ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
960 || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
961 {
962 rc = VERR_INVALID_PARAMETER;
963 }
964 else
965 {
966 g_pHelpers = ptable->pHelpers;
967
968 ptable->cbClient = sizeof (VBOXCLIPBOARDCLIENTDATA);
969
970 ptable->pfnUnload = svcUnload;
971 ptable->pfnConnect = svcConnect;
972 ptable->pfnDisconnect = svcDisconnect;
973 ptable->pfnCall = svcCall;
974 ptable->pfnHostCall = svcHostCall;
975 ptable->pfnSaveState = svcSaveState;
976 ptable->pfnLoadState = svcLoadState;
977 ptable->pfnRegisterExtension = svcRegisterExtension;
978 ptable->pvService = NULL;
979
980 /* Service specific initialization. */
981 rc = svcInit ();
982 }
983 }
984
985 return rc;
986}
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