VirtualBox

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

Last change on this file since 91933 was 87686, checked in by vboxsync, 3 years ago

Shared Clipboard/Transfers: Renaming. ​bugref:9437

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

© 2023 Oracle
ContactPrivacy policyTerms of Use