VirtualBox

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

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