VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers-http.cpp@ 87658

Last change on this file since 87658 was 87658, checked in by vboxsync, 4 years ago

Shared Clipboard/Transfers: Rearranged parameter lists of ShClTransferObj[Read|Write](). ​bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.0 KB
Line 
1/* $Id: clipboard-transfers-http.cpp 87658 2021-02-09 13:26:19Z vboxsync $ */
2/** @file
3 * Shared Clipboard: HTTP server implementation for Shared Clipboard transfers on UNIX-y guests / hosts.
4 */
5
6/*
7 * Copyright (C) 2020 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* Header Files *
21*********************************************************************************************************************************/
22#include <signal.h>
23
24#include <iprt/http.h>
25#include <iprt/http-server.h>
26
27#include <iprt/net.h> /* To make use of IPv4Addr in RTGETOPTUNION. */
28
29#include <iprt/asm.h>
30#include <iprt/assert.h>
31#include <iprt/ctype.h>
32#include <iprt/errcore.h>
33#include <iprt/file.h>
34#include <iprt/getopt.h>
35#include <iprt/initterm.h>
36#include <iprt/list.h>
37#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
38#include <iprt/log.h>
39#include <iprt/mem.h>
40#include <iprt/message.h>
41#include <iprt/path.h>
42#include <iprt/rand.h>
43#include <iprt/stream.h>
44#include <iprt/string.h>
45#include <iprt/thread.h>
46#include <iprt/uuid.h>
47#include <iprt/vfs.h>
48
49#include <VBox/HostServices/VBoxClipboardSvc.h>
50#include <VBox/GuestHost/SharedClipboard-x11.h>
51#include <VBox/GuestHost/SharedClipboard-transfers.h>
52
53
54/*********************************************************************************************************************************
55* Definitations *
56*********************************************************************************************************************************/
57
58typedef struct _SHCLHTTPSERVERTRANSFER
59{
60 /** The node list. */
61 RTLISTNODE Node;
62 /** Pointer to associated transfer. */
63 PSHCLTRANSFER pTransfer;
64 /** The (cached) root list of the transfer. NULL if not cached yet. */
65 PSHCLROOTLIST pRootList;
66 /** Critical section for serializing access. */
67 RTCRITSECT CritSect;
68 /** The handle we're going to use for this HTTP transfer. */
69 SHCLOBJHANDLE hObj;
70 /** The virtual path of the HTTP server's root directory for this transfer. */
71 char szPathVirtual[RTPATH_MAX];
72} SHCLHTTPSERVERTRANSFER;
73typedef SHCLHTTPSERVERTRANSFER *PSHCLHTTPSERVERTRANSFER;
74
75
76/*********************************************************************************************************************************
77* Prototypes *
78*********************************************************************************************************************************/
79static int shClTransferHttpServerDestroyInternal(PSHCLHTTPSERVER pThis);
80static const char *shClTransferHttpServerGetHost(PSHCLHTTPSERVER pSrv);
81
82
83/*********************************************************************************************************************************
84* Public Shared Clipboard HTTP transfer functions *
85*********************************************************************************************************************************/
86
87int ShClHttpTransferCreate(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer)
88{
89 int rc = VINF_SUCCESS;
90
91 /* Start the built-in HTTP server to serve file(s). */
92 if (!ShClTransferHttpServerIsRunning(&pCtx->HttpServer)) /* Only one HTTP server per transfer context. */
93 rc = ShClTransferHttpServerCreate(&pCtx->HttpServer, NULL /* puPort */);
94
95 if (RT_SUCCESS(rc))
96 rc = ShClTransferHttpServerRegisterTransfer(&pCtx->HttpServer, pTransfer);
97
98 return rc;
99}
100
101int ShClHttpTransferDestroy(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer)
102{
103 int rc = VINF_SUCCESS;
104
105 if (ShClTransferHttpServerIsRunning(&pCtx->HttpServer))
106 {
107 /* Try unregistering transfer (if it was registered before). */
108 rc = ShClTransferHttpServerUnregisterTransfer(&pCtx->HttpServer, pTransfer);
109 if (RT_SUCCESS(rc))
110 {
111 /* No more registered transfers left? Tear down the HTTP server instance then. */
112 if (ShClTransferHttpServerGetTransferCount(&pCtx->HttpServer) == 0)
113 rc = ShClTransferHttpServerDestroy(&pCtx->HttpServer);
114 }
115 AssertRC(rc);
116 }
117
118 return rc;
119}
120
121
122/*********************************************************************************************************************************
123* Internal Shared Clipboard HTTP transfer functions *
124*********************************************************************************************************************************/
125
126DECLINLINE(void) shClHttpTransferLock(PSHCLHTTPSERVERTRANSFER pSrvTx)
127{
128 int rc2 = RTCritSectEnter(&pSrvTx->CritSect);
129 AssertRC(rc2);
130}
131
132DECLINLINE(void) shClHttpTransferUnlock(PSHCLHTTPSERVERTRANSFER pSrvTx)
133{
134 int rc2 = RTCritSectEnter(&pSrvTx->CritSect);
135 AssertRC(rc2);
136}
137
138/**
139 * Return the HTTP server transfer for a specific transfer ID.
140 *
141 * @returns Pointer to HTTP server transfer if found, NULL if not found.
142 * @param pSrv HTTP server instance.
143 * @param idTransfer Transfer ID to return HTTP server transfer for.
144 */
145static PSHCLHTTPSERVERTRANSFER shClTransferHttpServerGetTransferById(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer)
146{
147 PSHCLHTTPSERVERTRANSFER pSrvTx;
148 RTListForEach(&pSrv->lstTransfers, pSrvTx, SHCLHTTPSERVERTRANSFER, Node) /** @todo Slow O(n) lookup, but does it for now. */
149 {
150 if (pSrvTx->pTransfer->State.uID == idTransfer)
151 return pSrvTx;
152 }
153
154 return NULL;
155}
156
157/**
158 * Returns a HTTP server transfer from a given URL.
159 *
160 * @returns Pointer to HTTP server transfer if found, NULL if not found.
161 * @param pThis HTTP server instance data.
162 * @param pszUrl URL to validate.
163 */
164DECLINLINE(PSHCLHTTPSERVERTRANSFER) shClTransferHttpGetTransferFromUrl(PSHCLHTTPSERVER pThis, const char *pszUrl)
165{
166 AssertPtrReturn(pszUrl, NULL);
167
168 PSHCLHTTPSERVERTRANSFER pSrvTx = NULL;
169
170 PSHCLHTTPSERVERTRANSFER pSrvTxCur;
171 RTListForEach(&pThis->lstTransfers, pSrvTxCur, SHCLHTTPSERVERTRANSFER, Node)
172 {
173 AssertPtr(pSrvTxCur->pTransfer);
174
175 LogFlowFunc(("pSrvTxCur=%s\n", pSrvTxCur->szPathVirtual));
176
177 /* Be picky here, do a case sensitive comparison. */
178 if (RTStrStartsWith(pszUrl, pSrvTxCur->szPathVirtual))
179 {
180 pSrvTx = pSrvTxCur;
181 break;
182 }
183 }
184
185 if (!pSrvTx)
186 LogRel2(("Shared Clipboard: HTTP URL '%s' not valid\n", pszUrl));
187
188 LogFlowFunc(("pszUrl=%s, pSrvTx=%p\n", pszUrl, pSrvTx));
189 return pSrvTx;
190}
191
192/**
193 * Returns a HTTP server transfer from an internal HTTP handle.
194 *
195 * @returns Pointer to HTTP server transfer if found, NULL if not found.
196 * @param pThis HTTP server instance data.
197 * @param pvHandle Handle to return transfer for.
198 */
199DECLINLINE(PSHCLHTTPSERVERTRANSFER) shClTransferHttpGetTransferFromHandle(PSHCLHTTPSERVER pThis, void *pvHandle)
200{
201 AssertPtrReturn(pvHandle, NULL);
202
203 const SHCLTRANSFERID uHandle = *(uint16_t *)pvHandle;
204
205 /** @ŧodo Use a handle lookup table (map) later. */
206 PSHCLHTTPSERVERTRANSFER pSrvTxCur;
207 RTListForEach(&pThis->lstTransfers, pSrvTxCur, SHCLHTTPSERVERTRANSFER, Node)
208 {
209 AssertPtr(pSrvTxCur->pTransfer);
210
211 if (pSrvTxCur->pTransfer->State.uID == uHandle) /** @ŧodo We're using the transfer ID as handle for now. */
212 return pSrvTxCur;
213 }
214
215 return NULL;
216}
217
218static int shClTransferHttpGetTransferRoots(PSHCLHTTPSERVER pThis, PSHCLHTTPSERVERTRANSFER pSrvTx)
219{
220 RT_NOREF(pThis);
221
222 int rc = VINF_SUCCESS;
223
224 if (pSrvTx->pRootList == NULL)
225 {
226 AssertPtr(pSrvTx->pTransfer);
227 rc = ShClTransferRootsGet(pSrvTx->pTransfer, &pSrvTx->pRootList);
228 }
229
230 return rc;
231}
232
233
234/*********************************************************************************************************************************
235* HTTP server callback implementations *
236*********************************************************************************************************************************/
237
238/** @copydoc RTHTTPSERVERCALLBACKS::pfnOpen */
239static DECLCALLBACK(int) shClTransferHttpOpen(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq, void **ppvHandle)
240{
241 PSHCLHTTPSERVER pThis = (PSHCLHTTPSERVER)pData->pvUser;
242 Assert(pData->cbUser == sizeof(SHCLHTTPSERVER));
243
244 int rc;
245
246 PSHCLHTTPSERVERTRANSFER pSrvTx = shClTransferHttpGetTransferFromUrl(pThis, pReq->pszUrl);
247 if (pSrvTx)
248 {
249 shClHttpTransferLock(pSrvTx);
250
251 AssertPtr(pSrvTx->pTransfer);
252
253 SHCLOBJOPENCREATEPARMS openParms;
254 rc = ShClTransferObjOpenParmsInit(&openParms);
255 if (RT_SUCCESS(rc))
256 {
257 openParms.fCreate = SHCL_OBJ_CF_ACCESS_READ
258 | SHCL_OBJ_CF_ACCESS_DENYWRITE;
259
260 rc = RTStrCopy(openParms.pszPath, openParms.cbPath, "foo"); /** @ŧodo BUGBUG !!!! */
261 if (RT_SUCCESS(rc))
262 {
263 rc = ShClTransferObjOpen(pSrvTx->pTransfer, &openParms, &pSrvTx->hObj);
264 if (RT_SUCCESS(rc))
265 {
266 *ppvHandle = &pSrvTx->hObj;
267 LogRel2(("Shared Clipboard: HTTP transfer (handle %RU64) started ...\n", pSrvTx->hObj));
268 }
269 }
270
271 ShClTransferObjOpenParmsDestroy(&openParms);
272 }
273
274 shClHttpTransferUnlock(pSrvTx);
275 }
276 else
277 rc = VERR_NOT_FOUND;
278
279 if (RT_FAILURE(rc))
280 LogRel(("Shared Clipboard: Error starting HTTP transfer for '%s', rc=%Rrc\n", pReq->pszUrl, rc));
281
282 LogFlowFuncLeaveRC(rc);
283 return rc;
284}
285
286/** @copydoc RTHTTPSERVERCALLBACKS::pfnRead */
287static DECLCALLBACK(int) shClTransferHttpRead(PRTHTTPCALLBACKDATA pData, void *pvHandle, void *pvBuf, size_t cbBuf, size_t *pcbRead)
288{
289 PSHCLHTTPSERVER pThis = (PSHCLHTTPSERVER)pData->pvUser;
290 Assert(pData->cbUser == sizeof(SHCLHTTPSERVER));
291
292 RT_NOREF(pvBuf, cbBuf, pcbRead);
293
294 int rc;
295
296 PSHCLHTTPSERVERTRANSFER pSrvTx = shClTransferHttpGetTransferFromHandle(pThis, pvHandle);
297 if (pSrvTx)
298 {
299 Assert(pSrvTx->hObj != SHCLOBJHANDLE_INVALID);
300
301 uint32_t cbRead;
302 rc = ShClTransferObjRead(pSrvTx->pTransfer, pSrvTx->hObj, pvBuf, cbBuf, 0 /* fFlags */, &cbRead);
303 if (RT_SUCCESS(rc))
304 {
305 *pcbRead = (uint32_t)cbRead;
306 }
307
308 if (RT_FAILURE(rc))
309 LogRel(("Shared Clipboard: Error reading HTTP transfer (handle %RU64), rc=%Rrc\n", pSrvTx->hObj, rc));
310 }
311 else
312 rc = VERR_NOT_FOUND;
313
314 LogFlowFuncLeaveRC(rc);
315 return rc;
316}
317
318/** @copydoc RTHTTPSERVERCALLBACKS::pfnClose */
319static DECLCALLBACK(int) shClTransferHttpClose(PRTHTTPCALLBACKDATA pData, void *pvHandle)
320{
321 PSHCLHTTPSERVER pThis = (PSHCLHTTPSERVER)pData->pvUser;
322 Assert(pData->cbUser == sizeof(SHCLHTTPSERVER));
323
324 int rc;
325
326 PSHCLHTTPSERVERTRANSFER pSrvTx = shClTransferHttpGetTransferFromHandle(pThis, pvHandle);
327 if (pSrvTx)
328 {
329 shClHttpTransferLock(pSrvTx);
330
331 Assert(pSrvTx->hObj != SHCLOBJHANDLE_INVALID);
332 rc = ShClTransferObjClose(pSrvTx->pTransfer, pSrvTx->hObj);
333 if (RT_SUCCESS(rc))
334 {
335 pSrvTx->hObj = SHCLOBJHANDLE_INVALID;
336 LogRel2(("Shared Clipboard: HTTP transfer %RU16 done\n", pSrvTx->pTransfer->State.uID));
337 }
338
339 if (RT_FAILURE(rc))
340 LogRel(("Shared Clipboard: Error closing HTTP transfer (handle %RU64), rc=%Rrc\n", pSrvTx->hObj, rc));
341
342 shClHttpTransferUnlock(pSrvTx);
343 }
344 else
345 rc = VERR_NOT_FOUND;
346
347 LogFlowFuncLeaveRC(rc);
348 return rc;
349}
350
351/** @copydoc RTHTTPSERVERCALLBACKS::pfnQueryInfo */
352static DECLCALLBACK(int) shClTransferHttpQueryInfo(PRTHTTPCALLBACKDATA pData,
353 PRTHTTPSERVERREQ pReq, PRTFSOBJINFO pObjInfo, char **ppszMIMEHint)
354{
355 PSHCLHTTPSERVER pThis = (PSHCLHTTPSERVER)pData->pvUser;
356 Assert(pData->cbUser == sizeof(SHCLHTTPSERVER));
357
358 int rc;
359
360 PSHCLHTTPSERVERTRANSFER pSrvTx = shClTransferHttpGetTransferFromUrl(pThis, pReq->pszUrl);
361 if (pSrvTx)
362 {
363 shClHttpTransferLock(pSrvTx);
364
365 rc = shClTransferHttpGetTransferRoots(pThis, pSrvTx);
366
367 shClHttpTransferUnlock(pSrvTx);
368 }
369 else
370 rc = VERR_NOT_FOUND;
371
372 RT_NOREF(pObjInfo, ppszMIMEHint);
373
374 LogFlowFuncLeaveRC(rc);
375 return rc;
376}
377
378/** @copydoc RTHTTPSERVERCALLBACKS::pfnDestroy */
379static DECLCALLBACK(int) shClTransferHttpDestroy(PRTHTTPCALLBACKDATA pData)
380{
381 PSHCLHTTPSERVER pThis = (PSHCLHTTPSERVER)pData->pvUser;
382 Assert(pData->cbUser == sizeof(SHCLHTTPSERVER));
383
384 return shClTransferHttpServerDestroyInternal(pThis);
385}
386
387
388/*********************************************************************************************************************************
389* Internal Shared Clipboard HTTP server functions *
390*********************************************************************************************************************************/
391
392/**
393 * Destroys a Shared Clipboard HTTP server instance, internal version.
394 *
395 * @returns VBox status code.
396 * @param pSrv Shared Clipboard HTTP server instance to destroy.
397 */
398static int shClTransferHttpServerDestroyInternal(PSHCLHTTPSERVER pSrv)
399{
400 PSHCLHTTPSERVERTRANSFER pSrvTx, pSrvTxNext;
401 RTListForEachSafe(&pSrv->lstTransfers, pSrvTx, pSrvTxNext, SHCLHTTPSERVERTRANSFER, Node)
402 {
403 RTListNodeRemove(&pSrvTx->Node);
404
405 RTMemFree(pSrvTx);
406 pSrvTx = NULL;
407 }
408
409 RTHttpServerResponseDestroy(&pSrv->Resp);
410
411 pSrv->hHTTPServer = NIL_RTHTTPSERVER;
412
413 int rc = VINF_SUCCESS;
414
415 if (RTCritSectIsInitialized(&pSrv->CritSect))
416 rc = RTCritSectDelete(&pSrv->CritSect);
417
418 return rc;
419}
420
421/**
422 * Locks the critical section of a Shared Clipboard HTTP server instance.
423 *
424 * @param pSrv Shared Clipboard HTTP server instance to lock.
425 */
426DECLINLINE(void) shClTransferHttpServerLock(PSHCLHTTPSERVER pSrv)
427{
428 int rc2 = RTCritSectEnter(&pSrv->CritSect);
429 AssertRC(rc2);
430}
431
432/**
433 * Unlocks the critical section of a Shared Clipboard HTTP server instance.
434 *
435 * @param pSrv Shared Clipboard HTTP server instance to unlock.
436 */
437DECLINLINE(void) shClTransferHttpServerUnlock(PSHCLHTTPSERVER pSrv)
438{
439 int rc2 = RTCritSectLeave(&pSrv->CritSect);
440 AssertRC(rc2);
441}
442
443/**
444 * Initializes a new Shared Clipboard HTTP server instance.
445 *
446 * @param pSrv HTTP server instance to initialize.
447 */
448static void shClTransferHttpServerInitInternal(PSHCLHTTPSERVER pSrv)
449{
450 pSrv->hHTTPServer = NIL_RTHTTPSERVER;
451 pSrv->uPort = 0;
452 RTListInit(&pSrv->lstTransfers);
453 pSrv->cTransfers = 0;
454 int rc2 = RTHttpServerResponseInit(&pSrv->Resp);
455 AssertRC(rc2);
456}
457
458
459/*********************************************************************************************************************************
460* Public Shared Clipboard HTTP server functions *
461*********************************************************************************************************************************/
462
463/**
464 * Initializes a new Shared Clipboard HTTP server instance.
465 *
466 * @param pSrv HTTP server instance to initialize.
467 */
468void ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv)
469{
470 AssertPtrReturnVoid(pSrv);
471
472 shClTransferHttpServerInitInternal(pSrv);
473}
474
475/**
476 * Creates a new Shared Clipboard HTTP server instance, extended version.
477 *
478 * @returns VBox status code.
479 * @param pSrv HTTP server instance to create.
480 * @param uPort TCP port number to use.
481 */
482int ShClTransferHttpServerCreateEx(PSHCLHTTPSERVER pSrv, uint16_t uPort)
483{
484 AssertPtrReturn(pSrv, VERR_INVALID_POINTER);
485
486 RTHTTPSERVERCALLBACKS Callbacks;
487 RT_ZERO(Callbacks);
488
489 Callbacks.pfnOpen = shClTransferHttpOpen;
490 Callbacks.pfnRead = shClTransferHttpRead;
491 Callbacks.pfnClose = shClTransferHttpClose;
492 Callbacks.pfnQueryInfo = shClTransferHttpQueryInfo;
493 Callbacks.pfnDestroy = shClTransferHttpDestroy;
494
495 /* Note: The server always and *only* runs against the localhost interface. */
496 int rc = RTHttpServerCreate(&pSrv->hHTTPServer, "localhost", uPort, &Callbacks,
497 pSrv, sizeof(SHCLHTTPSERVER));
498 if (RT_SUCCESS(rc))
499 {
500 rc = RTCritSectInit(&pSrv->CritSect);
501 AssertRCReturn(rc, rc);
502
503 pSrv->uPort = uPort;
504
505 LogRel2(("Shared Clipboard: HTTP server running at port %RU16\n", pSrv->uPort));
506 }
507 else
508 {
509 int rc2 = shClTransferHttpServerDestroyInternal(pSrv);
510 AssertRC(rc2);
511 }
512
513 if (RT_FAILURE(rc))
514 LogRel(("Shared Clipboard: HTTP server failed to run, rc=%Rrc\n", rc));
515
516 return rc;
517}
518
519/**
520 * Creates a new Shared Clipboard HTTP server instance.
521 *
522 * This does automatic probing of TCP ports if one already is being used.
523 *
524 * @returns VBox status code.
525 * @param pSrv HTTP server instance to create.
526 * @param puPort Where to return the TCP port number being used on success. Optional.
527 */
528int ShClTransferHttpServerCreate(PSHCLHTTPSERVER pSrv, uint16_t *puPort)
529{
530 AssertPtrReturn(pSrv, VERR_INVALID_POINTER);
531 /* puPort is optional. */
532
533 /** @todo Try favorite ports first (e.g. 8080, 8000, ...)? */
534
535 RTRAND hRand;
536 int rc = RTRandAdvCreateSystemFaster(&hRand); /* Should be good enough for this task. */
537 if (RT_SUCCESS(rc))
538 {
539 uint16_t uPort;
540 for (int i = 0; i < 32; i++)
541 {
542#ifdef DEBUG_andy
543 uPort = 8080; /* Make the port predictable, but only for me, mwahaha! :-). */
544#else
545 uPort = RTRandAdvU32Ex(hRand, 1024, UINT16_MAX);
546#endif
547 rc = ShClTransferHttpServerCreateEx(pSrv, (uint32_t)uPort);
548 if (RT_SUCCESS(rc))
549 {
550 if (puPort)
551 *puPort = uPort;
552 break;
553 }
554 }
555
556 RTRandAdvDestroy(hRand);
557 }
558
559 return rc;
560}
561
562/**
563 * Destroys a Shared Clipboard HTTP server instance.
564 *
565 * @returns VBox status code.
566 * @param pSrv HTTP server instance to destroy.
567 */
568int ShClTransferHttpServerDestroy(PSHCLHTTPSERVER pSrv)
569{
570 AssertPtrReturn(pSrv, VERR_INVALID_POINTER);
571
572 if (pSrv->hHTTPServer == NIL_RTHTTPSERVER)
573 return VINF_SUCCESS;
574
575 Assert(pSrv->cTransfers == 0); /* Sanity. */
576
577 int rc = RTHttpServerDestroy(pSrv->hHTTPServer);
578 if (RT_SUCCESS(rc))
579 rc = shClTransferHttpServerDestroyInternal(pSrv);
580
581 if (RT_SUCCESS(rc))
582 LogRel2(("Shared Clipboard: HTTP server stopped\n"));
583 else
584 LogRel(("Shared Clipboard: HTTP server failed to stop, rc=%Rrc\n", rc));
585
586 return rc;
587}
588
589/**
590 * Registers a Shared Clipboard transfer to a HTTP server instance.
591 *
592 * @returns VBox status code.
593 * @param pSrv HTTP server instance to register transfer for.
594 * @param pTransfer Transfer to register.
595 */
596int ShClTransferHttpServerRegisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer)
597{
598 AssertPtrReturn(pSrv, VERR_INVALID_POINTER);
599 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
600
601 AssertReturn(pTransfer->State.uID, VERR_INVALID_PARAMETER); /* Paranoia. */
602
603 shClTransferHttpServerLock(pSrv);
604
605 PSHCLHTTPSERVERTRANSFER pSrvTx = (PSHCLHTTPSERVERTRANSFER)RTMemAllocZ(sizeof(SHCLHTTPSERVERTRANSFER));
606 AssertPtrReturn(pSrvTx, VERR_NO_MEMORY);
607
608 RTUUID Uuid;
609 int rc = RTUuidCreate(&Uuid);
610 if (RT_SUCCESS(rc))
611 {
612 char szUuid[64];
613 rc = RTUuidToStr(&Uuid, szUuid, sizeof(szUuid));
614 if (RT_SUCCESS(rc))
615 {
616 rc = RTCritSectInit(&pSrvTx->CritSect);
617 AssertRC(rc);
618
619 /* Create the virtual HTTP path for the transfer.
620 * Every transfer has a dedicated HTTP path. */
621#ifdef DEBUG_andy
622 ssize_t cch = RTStrPrintf2(pSrvTx->szPathVirtual, sizeof(pSrvTx->szPathVirtual), "/d1bbda60-80b7-45dc-a41c-ac4686c1d988/10664");
623#else
624 ssize_t cch = RTStrPrintf2(pSrvTx->szPathVirtual, sizeof(pSrvTx->szPathVirtual), "%s/%RU16/", szUuid, pTransfer->State.uID);
625#endif
626 AssertReturn(cch, VERR_BUFFER_OVERFLOW);
627
628 pSrvTx->pTransfer = pTransfer;
629 pSrvTx->pRootList = NULL;
630 pSrvTx->hObj = SHCLOBJHANDLE_INVALID;
631
632 RTListAppend(&pSrv->lstTransfers, &pSrvTx->Node);
633 pSrv->cTransfers++;
634
635 LogFunc(("pTransfer=%p, idTransfer=%RU16, szPath=%s -> %RU32 transfers\n",
636 pSrvTx->pTransfer, pSrvTx->pTransfer->State.uID, pSrvTx->szPathVirtual, pSrv->cTransfers));
637
638 LogRel2(("Shared Clipboard: Registered HTTP transfer %RU16, now %RU32 HTTP transfers total\n",
639 pTransfer->State.uID, pSrv->cTransfers));
640 }
641 }
642
643 if (RT_FAILURE(rc))
644 RTMemFree(pSrvTx);
645
646 shClTransferHttpServerUnlock(pSrv);
647
648 LogFlowFuncLeaveRC(rc);
649 return rc;
650}
651
652/**
653 * Unregisters a formerly registered Shared Clipboard transfer.
654 *
655 * @returns VBox status code.
656 * @param pSrv HTTP server instance to unregister transfer from.
657 * @param pTransfer Transfer to unregister.
658 */
659int ShClTransferHttpServerUnregisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer)
660{
661 AssertPtrReturn(pSrv, VERR_INVALID_POINTER);
662 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
663
664 shClTransferHttpServerLock(pSrv);
665
666 AssertReturn(pSrv->cTransfers, VERR_WRONG_ORDER);
667
668 int rc = VINF_SUCCESS;
669
670 PSHCLHTTPSERVERTRANSFER pSrvTx;
671 RTListForEach(&pSrv->lstTransfers, pSrvTx, SHCLHTTPSERVERTRANSFER, Node)
672 {
673 AssertPtr(pSrvTx->pTransfer);
674 if (pSrvTx->pTransfer->State.uID == pTransfer->State.uID)
675 {
676 RTListNodeRemove(&pSrvTx->Node);
677
678 Assert(pSrv->cTransfers);
679 pSrv->cTransfers--;
680
681 LogFunc(("pTransfer=%p, idTransfer=%RU16, szPath=%s -> %RU32 transfers\n",
682 pSrvTx->pTransfer, pSrvTx->pTransfer->State.uID, pSrvTx->szPathVirtual, pSrv->cTransfers));
683
684 LogRel2(("Shared Clipboard: Unregistered HTTP transfer %RU16, now %RU32 HTTP transfers total\n",
685 pTransfer->State.uID, pSrv->cTransfers));
686
687 rc = RTCritSectDelete(&pSrvTx->CritSect);
688 AssertRC(rc);
689
690 RTMemFree(pSrvTx);
691 pSrvTx = NULL;
692
693 rc = VINF_SUCCESS;
694 break;
695 }
696 }
697
698 shClTransferHttpServerUnlock(pSrv);
699
700 LogFlowFuncLeaveRC(rc);
701 return rc;
702}
703
704/**
705 * Returns whether a specific transfer ID is registered with a HTTP server instance or not.
706 *
707 * @returns \c true if the transfer ID is registered, \c false if not.
708 * @param pSrv HTTP server instance.
709 * @param idTransfer Transfer ID to check for.
710 */
711bool ShClTransferHttpServerHasTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer)
712{
713 AssertPtrReturn(pSrv, false);
714
715 shClTransferHttpServerLock(pSrv);
716
717 const bool fRc = shClTransferHttpServerGetTransferById(pSrv, idTransfer) != NULL;
718
719 shClTransferHttpServerUnlock(pSrv);
720
721 return fRc;
722}
723
724/**
725 * Returns the used TCP port number of a HTTP server instance.
726 *
727 * @returns TCP port number. 0 if not specified yet.
728 * @param pSrv HTTP server instance to return port for.
729 */
730uint16_t ShClTransferHttpServerGetPort(PSHCLHTTPSERVER pSrv)
731{
732 AssertPtrReturn(pSrv, 0);
733
734 shClTransferHttpServerLock(pSrv);
735
736 const uint16_t uPort = pSrv->uPort;
737
738 shClTransferHttpServerUnlock(pSrv);
739
740 return uPort;
741}
742
743/**
744 * Returns the number of registered HTTP server transfers of a HTTP server instance.
745 *
746 * @returns Number of registered transfers.
747 * @param pSrv HTTP server instance to return registered transfers for.
748 */
749uint32_t ShClTransferHttpServerGetTransferCount(PSHCLHTTPSERVER pSrv)
750{
751 AssertPtrReturn(pSrv, 0);
752
753 shClTransferHttpServerLock(pSrv);
754
755 const uint32_t cTransfers = pSrv->cTransfers;
756
757 shClTransferHttpServerUnlock(pSrv);
758
759 return cTransfers;
760}
761
762/**
763 * Returns the host name (scheme) of a HTTP server instance.
764 *
765 * @param pSrv HTTP server instance to return host name (scheme) for.
766 *
767 * @returns Host name (scheme).
768 */
769static const char *shClTransferHttpServerGetHost(PSHCLHTTPSERVER pSrv)
770{
771 RT_NOREF(pSrv);
772 return "http://localhost"; /* Hardcoded for now. */
773}
774
775/**
776 * Returns an allocated string with a HTTP server instance's address.
777 *
778 * @returns Allocated string with a HTTP server instance's address, or NULL on OOM.
779 * Needs to be free'd by the caller using RTStrFree().
780 * @param pSrv HTTP server instance to return address for.
781 */
782char *ShClTransferHttpServerGetAddressA(PSHCLHTTPSERVER pSrv)
783{
784 AssertPtrReturn(pSrv, NULL);
785
786 shClTransferHttpServerLock(pSrv);
787
788 char *pszAddress = RTStrAPrintf2("%s:%RU16", shClTransferHttpServerGetHost(pSrv), pSrv->uPort);
789 AssertPtr(pszAddress);
790
791 shClTransferHttpServerUnlock(pSrv);
792
793 return pszAddress;
794}
795
796/**
797 * Returns an allocated string with the URL of a given Shared Clipboard transfer ID.
798 *
799 * @returns Allocated string with the URL of a given Shared Clipboard transfer ID, or NULL if not found.
800 * Needs to be free'd by the caller using RTStrFree().
801 * @param pSrv HTTP server instance to return URL for.
802 */
803char *ShClTransferHttpServerGetUrlA(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer)
804{
805 AssertPtrReturn(pSrv, NULL);
806 AssertReturn(idTransfer != NIL_SHCLTRANSFERID, NULL);
807
808 shClTransferHttpServerLock(pSrv);
809
810 PSHCLHTTPSERVERTRANSFER pSrvTx = shClTransferHttpServerGetTransferById(pSrv, idTransfer);
811 if (!pSrvTx)
812 {
813 AssertFailed();
814 shClTransferHttpServerUnlock(pSrv);
815 return NULL;
816 }
817
818 AssertReturn(RTStrNLen(pSrvTx->szPathVirtual, RTPATH_MAX), NULL);
819 char *pszUrl = RTStrAPrintf2("%s:%RU16/%s", shClTransferHttpServerGetHost(pSrv), pSrv->uPort, pSrvTx->szPathVirtual);
820 AssertPtr(pszUrl);
821
822 shClTransferHttpServerUnlock(pSrv);
823
824 return pszUrl;
825}
826
827/**
828 * Returns whether a given HTTP server instance is running or not.
829 *
830 * @returns \c true if running, or \c false if not.
831 * @param pSrv HTTP server instance to check running state for.
832 */
833bool ShClTransferHttpServerIsRunning(PSHCLHTTPSERVER pSrv)
834{
835 AssertPtrReturn(pSrv, false);
836
837 return (pSrv->hHTTPServer != NIL_RTHTTPSERVER); /* Seems enough for now. */
838}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette