Changeset 89962 in vbox for trunk/src/VBox/Devices/Audio/AudioTestServiceTcp.cpp
- Timestamp:
- Jun 30, 2021 7:02:07 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/AudioTestServiceTcp.cpp
r89614 r89962 20 20 * Header Files * 21 21 *********************************************************************************************************************************/ 22 #define LOG_GROUP RTLOGGROUP_DEFAULT22 #define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO /** @todo Add an own log group for this? */ 23 23 #include <iprt/asm.h> 24 24 #include <iprt/assert.h> … … 34 34 #include <iprt/time.h> 35 35 36 #include <VBox/log.h> 37 36 38 #include "AudioTestService.h" 37 39 #include "AudioTestServiceInternal.h" … … 46 48 * Structures and Typedefs * 47 49 *********************************************************************************************************************************/ 48 49 50 /** 50 51 * TCP specific client data. … … 53 54 { 54 55 /** Socket of the current client. */ 55 RTSOCKET hTcpClient; 56 RTSOCKET hTcpClient; 57 /** Indicates whether \a hTcpClient comes from the server or from a client 58 * connect (relevant when closing it). */ 59 bool fFromServer; 56 60 /** The size of the stashed data. */ 57 size_t cbTcpStashed;61 size_t cbTcpStashed; 58 62 /** The size of the stashed data allocation. */ 59 size_t cbTcpStashedAlloced;63 size_t cbTcpStashedAlloced; 60 64 /** The stashed data. */ 61 uint8_t *pbTcpStashed;65 uint8_t *pbTcpStashed; 62 66 } ATSTRANSPORTCLIENT; 67 68 /** 69 * Enumeration for the TCP/IP connection mode. 70 */ 71 typedef enum ATSTCPMODE 72 { 73 /** Both: Uses parallel client and server connection methods (via threads). */ 74 ATSTCPMODE_BOTH = 0, 75 /** Client only: Connects to a server. */ 76 ATSTCPMODE_CLIENT, 77 /** Server only: Listens for new incoming client connections. */ 78 ATSTCPMODE_SERVER 79 } ATSTCPMODE; 80 81 /** 82 * Structure for keeping Audio Test Service (ATS) transport instance-specific data. 83 */ 84 typedef struct ATSTRANSPORTINST 85 { 86 /** Critical section for serializing access. */ 87 RTCRITSECT CritSect; 88 /** Connection mode to use. */ 89 ATSTCPMODE enmMode; 90 /** The addresses to bind to. Empty string means any. */ 91 char szBindAddr[256]; 92 /** The TCP port to listen to. */ 93 uint32_t uBindPort; 94 /** The addresses to connect to if running in reversed (VM NATed) mode. */ 95 char szConnectAddr[256]; 96 /** The TCP port to connect to if running in reversed (VM NATed) mode. */ 97 uint32_t uConnectPort; 98 /** Pointer to the TCP server instance. */ 99 PRTTCPSERVER pTcpServer; 100 /** Thread calling RTTcpServerListen2. */ 101 RTTHREAD hThreadServer; 102 /** Thread calling RTTcpClientConnect. */ 103 RTTHREAD hThreadConnect; 104 /** The main thread handle (for signalling). */ 105 RTTHREAD hThreadMain; 106 /** Stop connecting attempts when set. */ 107 bool fStopConnecting; 108 /** Connect cancel cookie. */ 109 PRTTCPCLIENTCONNECTCANCEL volatile pConnectCancelCookie; 110 } ATSTRANSPORTINST; 111 /** Pointer to an Audio Test Service (ATS) TCP/IP transport instance. */ 112 typedef ATSTRANSPORTINST *PATSTRANSPORTINST; 113 114 /** 115 * Structure holding an ATS connection context, which is 116 * required when connecting a client via server (listening) or client (connecting). 117 */ 118 typedef struct ATSCONNCTX 119 { 120 /** Pointer to transport instance to use. */ 121 PATSTRANSPORTINST pInst; 122 /** Pointer to transport client to connect. */ 123 PATSTRANSPORTCLIENT pClient; 124 } ATSCONNCTX; 125 /** Pointer to an Audio Test Service (ATS) TCP/IP connection context. */ 126 typedef ATSCONNCTX *PATSCONNCTX; 63 127 64 128 … … 76 140 if (pClient->hTcpClient != NIL_RTSOCKET) 77 141 { 78 int rc = RTTcpServerDisconnectClient2(pClient->hTcpClient); 142 int rc; 143 if (pClient->fFromServer) 144 rc = RTTcpServerDisconnectClient2(pClient->hTcpClient); 145 else 146 rc = RTTcpClientClose(pClient->hTcpClient); 79 147 pClient->hTcpClient = NIL_RTSOCKET; 80 148 AssertRCSuccess(rc); … … 89 157 90 158 /** 159 * Sets the current client socket in a safe manner. 160 * 161 * @returns NIL_RTSOCKET if consumed, other wise hTcpClient. 162 * @param pThis Transport instance. 163 * @param pClient Client to set the socket for. 164 * @param fFromServer Whether the socket is from a server (listening) or client (connecting) call. 165 * Important when closing / disconnecting. 166 * @param hTcpClient The client socket. 167 */ 168 static RTSOCKET atsTcpSetClient(PATSTRANSPORTINST pThis, PATSTRANSPORTCLIENT pClient, bool fFromServer, RTSOCKET hTcpClient) 169 { 170 RTCritSectEnter(&pThis->CritSect); 171 if ( pClient->hTcpClient == NIL_RTSOCKET 172 && !pThis->fStopConnecting) 173 { 174 LogFunc(("New client connected\n")); 175 176 pClient->fFromServer = fFromServer; 177 pClient->hTcpClient = hTcpClient; 178 hTcpClient = NIL_RTSOCKET; /* Invalidate, as pClient has now ownership. */ 179 } 180 RTCritSectLeave(&pThis->CritSect); 181 return hTcpClient; 182 } 183 184 /** 185 * Checks if it's a fatal RTTcpClientConnect return code. 186 * 187 * @returns true / false. 188 * @param rc The IPRT status code. 189 */ 190 static bool atsTcpIsFatalClientConnectStatus(int rc) 191 { 192 return rc != VERR_NET_UNREACHABLE 193 && rc != VERR_NET_HOST_DOWN 194 && rc != VERR_NET_HOST_UNREACHABLE 195 && rc != VERR_NET_CONNECTION_REFUSED 196 && rc != VERR_TIMEOUT 197 && rc != VERR_NET_CONNECTION_TIMED_OUT; 198 } 199 200 /** 201 * Server mode connection thread. 202 * 203 * @returns iprt status code. 204 * @param hSelf Thread handle. Ignored. 205 * @param pvUser Pointer to ATSTRANSPORTINST the thread is bound to. 206 */ 207 static DECLCALLBACK(int) atsTcpServerConnectThread(RTTHREAD hSelf, void *pvUser) 208 { 209 RT_NOREF(hSelf); 210 211 PATSCONNCTX pConnCtx = (PATSCONNCTX)pvUser; 212 PATSTRANSPORTINST pThis = pConnCtx->pInst; 213 PATSTRANSPORTCLIENT pClient = pConnCtx->pClient; 214 215 RTSOCKET hTcpClient; 216 int rc = RTTcpServerListen2(pThis->pTcpServer, &hTcpClient); 217 if (RT_SUCCESS(rc)) 218 { 219 hTcpClient = atsTcpSetClient(pThis, pClient, true /* fFromServer */, hTcpClient); 220 RTTcpServerDisconnectClient2(hTcpClient); 221 } 222 223 return rc; 224 } 225 226 /** 227 * Client mode connection thread. 228 * 229 * @returns iprt status code. 230 * @param hSelf Thread handle. Use to sleep on. The main thread will 231 * signal it to speed up thread shutdown. 232 * @param pvUser Pointer to a connection context (PATSCONNCTX) the thread is bound to. 233 */ 234 static DECLCALLBACK(int) atsTcpClientConnectThread(RTTHREAD hSelf, void *pvUser) 235 { 236 PATSCONNCTX pConnCtx = (PATSCONNCTX)pvUser; 237 PATSTRANSPORTINST pThis = pConnCtx->pInst; 238 PATSTRANSPORTCLIENT pClient = pConnCtx->pClient; 239 240 for (;;) 241 { 242 /* Stop? */ 243 RTCritSectEnter(&pThis->CritSect); 244 bool fStop = pThis->fStopConnecting; 245 RTCritSectLeave(&pThis->CritSect); 246 if (fStop) 247 return VINF_SUCCESS; 248 249 /* Try connect. */ /** @todo make cancelable! */ 250 RTSOCKET hTcpClient; 251 int rc = RTTcpClientConnectEx(pThis->szConnectAddr, pThis->uConnectPort, &hTcpClient, 252 RT_SOCKETCONNECT_DEFAULT_WAIT, &pThis->pConnectCancelCookie); 253 if (RT_SUCCESS(rc)) 254 { 255 hTcpClient = atsTcpSetClient(pThis, pClient, false /* fFromServer */, hTcpClient); 256 RTTcpClientCloseEx(hTcpClient, true /* fGracefulShutdown*/); 257 break; 258 } 259 260 if (atsTcpIsFatalClientConnectStatus(rc)) 261 return rc; 262 263 /* Delay a wee bit before retrying. */ 264 RTThreadUserWait(hSelf, 1536); 265 } 266 return VINF_SUCCESS; 267 } 268 269 /** 270 * Wait on the threads to complete. 271 * 272 * @returns Thread status (if collected), otherwise VINF_SUCCESS. 273 * @param pThis Transport instance. 274 * @param cMillies The period to wait on each thread. 275 */ 276 static int atsTcpConnectWaitOnThreads(PATSTRANSPORTINST pThis, RTMSINTERVAL cMillies) 277 { 278 int rcRet = VINF_SUCCESS; 279 280 if (pThis->hThreadConnect != NIL_RTTHREAD) 281 { 282 int rcThread; 283 int rc2 = RTThreadWait(pThis->hThreadConnect, cMillies, &rcThread); 284 if (RT_SUCCESS(rc2)) 285 { 286 pThis->hThreadConnect = NIL_RTTHREAD; 287 rcRet = rcThread; 288 } 289 } 290 291 if (pThis->hThreadServer != NIL_RTTHREAD) 292 { 293 int rcThread; 294 int rc2 = RTThreadWait(pThis->hThreadServer, cMillies, &rcThread); 295 if (RT_SUCCESS(rc2)) 296 { 297 pThis->hThreadServer = NIL_RTTHREAD; 298 if (RT_SUCCESS(rc2)) 299 rcRet = rcThread; 300 } 301 } 302 return rcRet; 303 } 304 305 /** 91 306 * @interface_method_impl{ATSTRANSPORT,pfnWaitForConnect} 92 307 */ 93 308 static DECLCALLBACK(int) atsTcpWaitForConnect(PATSTRANSPORTINST pThis, PPATSTRANSPORTCLIENT ppClientNew) 94 309 { 310 PATSTRANSPORTCLIENT pClient = (PATSTRANSPORTCLIENT)RTMemAllocZ(sizeof(ATSTRANSPORTCLIENT)); 311 AssertPtrReturn(pClient, VERR_NO_MEMORY); 312 95 313 int rc; 96 RTSOCKET hClientNew; 97 98 rc = RTTcpServerListen2(pThis->pTcpServer, &hClientNew); 99 Log(("atsTcpWaitForConnect: RTTcpServerListen2 -> %Rrc\n", rc)); 314 315 if (pThis->enmMode == ATSTCPMODE_SERVER) 316 { 317 pClient->fFromServer = true; 318 rc = RTTcpServerListen2(pThis->pTcpServer, &pClient->hTcpClient); 319 LogFunc(("RTTcpServerListen2 -> %Rrc\n", rc)); 320 } 321 else if (pThis->enmMode == ATSTCPMODE_CLIENT) 322 { 323 pClient->fFromServer = false; 324 for (;;) 325 { 326 Log2Func(("Calling RTTcpClientConnect(%s, %u,)...\n", pThis->szConnectAddr, pThis->uConnectPort)); 327 rc = RTTcpClientConnect(pThis->szConnectAddr, pThis->uConnectPort, &pClient->hTcpClient); 328 LogFunc(("RTTcpClientConnect -> %Rrc\n", rc)); 329 if (RT_SUCCESS(rc) || atsTcpIsFatalClientConnectStatus(rc)) 330 break; 331 332 /* Delay a wee bit before retrying. */ 333 RTThreadSleep(1536); 334 } 335 } 336 else 337 { 338 Assert(pThis->enmMode == ATSTCPMODE_BOTH); 339 340 /* 341 * Create client threads. 342 */ 343 RTCritSectEnter(&pThis->CritSect); 344 345 pThis->fStopConnecting = false; 346 RTCritSectLeave(&pThis->CritSect); 347 348 atsTcpConnectWaitOnThreads(pThis, 32 /* cMillies */); 349 350 ATSCONNCTX ConnCtx; 351 RT_ZERO(ConnCtx); 352 ConnCtx.pInst = pThis; 353 ConnCtx.pClient = pClient; 354 355 rc = VINF_SUCCESS; 356 if (pThis->hThreadConnect == NIL_RTTHREAD) 357 { 358 pThis->pConnectCancelCookie = NULL; 359 rc = RTThreadCreate(&pThis->hThreadConnect, atsTcpClientConnectThread, &ConnCtx, 0, RTTHREADTYPE_DEFAULT, 360 RTTHREADFLAGS_WAITABLE, "tcpconn"); 361 } 362 if (pThis->hThreadServer == NIL_RTTHREAD && RT_SUCCESS(rc)) 363 rc = RTThreadCreate(&pThis->hThreadServer, atsTcpServerConnectThread, &ConnCtx, 0, RTTHREADTYPE_DEFAULT, 364 RTTHREADFLAGS_WAITABLE, "tcpserv"); 365 366 RTCritSectEnter(&pThis->CritSect); 367 368 /* 369 * Wait for connection to be established. 370 */ 371 while ( RT_SUCCESS(rc) 372 && pClient->hTcpClient == NIL_RTSOCKET) 373 { 374 RTCritSectLeave(&pThis->CritSect); 375 rc = atsTcpConnectWaitOnThreads(pThis, 10 /* cMillies */); 376 RTCritSectEnter(&pThis->CritSect); 377 } 378 379 /* 380 * Cancel the threads. 381 */ 382 pThis->fStopConnecting = true; 383 384 RTCritSectLeave(&pThis->CritSect); 385 RTTcpClientCancelConnect(&pThis->pConnectCancelCookie); 386 } 100 387 101 388 if (RT_SUCCESS(rc)) 102 389 { 103 PATSTRANSPORTCLIENT pClient = (PATSTRANSPORTCLIENT)RTMemAllocZ(sizeof(ATSTRANSPORTCLIENT)); 104 if (RT_LIKELY(pClient)) 105 { 106 pClient->hTcpClient = hClientNew; 107 pClient->cbTcpStashed = 0; 108 pClient->cbTcpStashedAlloced = 0; 109 pClient->pbTcpStashed = NULL; 110 *ppClientNew = pClient; 111 } 112 else 113 { 114 RTTcpServerDisconnectClient2(hClientNew); 115 rc = VERR_NO_MEMORY; 390 *ppClientNew = pClient; 391 } 392 else 393 { 394 if (pClient) 395 { 396 RTTcpServerDisconnectClient2(pClient->hTcpClient); 397 398 RTMemFree(pClient); 399 pClient = NULL; 116 400 } 117 401 } … … 125 409 static DECLCALLBACK(void) atsTcpNotifyReboot(PATSTRANSPORTINST pThis) 126 410 { 127 Log (("atsTcpNotifyReboot:RTTcpServerDestroy(%p)\n", pThis->pTcpServer));411 LogFunc(("RTTcpServerDestroy(%p)\n", pThis->pTcpServer)); 128 412 if (pThis->pTcpServer) 129 413 { … … 140 424 static DECLCALLBACK(void) atsTcpNotifyBye(PATSTRANSPORTINST pThis, PATSTRANSPORTCLIENT pClient) 141 425 { 142 Log (("atsTcpNotifyBye:atsTcpDisconnectClient %RTsock\n", pClient->hTcpClient));426 LogFunc(("atsTcpDisconnectClient %RTsock\n", pClient->hTcpClient)); 143 427 atsTcpDisconnectClient(pThis, pClient); 144 428 RTMemFree(pClient); … … 171 455 * Disconnect the client. 172 456 */ 173 Log (("atsTcpBabble:atsTcpDisconnectClient(%RTsock) (RTTcpWrite rc=%Rrc)\n", pClient->hTcpClient, rc));457 LogFunc(("atsTcpDisconnectClient(%RTsock) (RTTcpWrite rc=%Rrc)\n", pClient->hTcpClient, rc)); 174 458 atsTcpDisconnectClient(pThis, pClient); 175 459 } … … 180 464 static DECLCALLBACK(int) atsTcpSendPkt(PATSTRANSPORTINST pThis, PATSTRANSPORTCLIENT pClient, PCATSPKTHDR pPktHdr) 181 465 { 182 Assert (pPktHdr->cb >= sizeof(ATSPKTHDR));466 AssertReturn(pPktHdr->cb >= sizeof(ATSPKTHDR), VERR_INVALID_PARAMETER); 183 467 184 468 /* … … 186 470 */ 187 471 size_t cbToSend = RT_ALIGN_Z(pPktHdr->cb, ATSPKT_ALIGNMENT); 188 LogFlowFunc(("%RU32 -> %zu\n", pPktHdr->cb, cbToSend)); 472 473 Log3Func(("%RU32 -> %zu\n", pPktHdr->cb, cbToSend)); 474 475 Log3Func(("Header:\n" 476 "%.*Rhxd\n", RT_MIN(sizeof(ATSPKTHDR), cbToSend), pPktHdr)); 477 478 if (cbToSend > sizeof(ATSPKTHDR)) 479 Log3Func(("Payload:\n" 480 "%.*Rhxd\n", 481 RT_MIN(64, cbToSend - sizeof(ATSPKTHDR)), (uint8_t *)pPktHdr + sizeof(ATSPKTHDR))); 482 189 483 int rc = RTTcpWrite(pClient->hTcpClient, pPktHdr, cbToSend); 190 484 if ( RT_FAILURE(rc) … … 192 486 { 193 487 /* assume fatal connection error. */ 194 Log (("RTTcpWrite -> %Rrc -> atsTcpDisconnectClient(%RTsock)\n", rc, pClient->hTcpClient));488 LogFunc(("RTTcpWrite -> %Rrc -> atsTcpDisconnectClient(%RTsock)\n", rc, pClient->hTcpClient)); 195 489 atsTcpDisconnectClient(pThis, pClient); 196 490 } … … 237 531 238 532 /* 239 * Read and valid the length.533 * Read and validate the length. 240 534 */ 241 535 while (offData < sizeof(uint32_t)) … … 247 541 if (cbRead == 0) 248 542 { 249 Log (("atsTcpRecvPkt:RTTcpRead -> %Rrc / cbRead=0 -> VERR_NET_NOT_CONNECTED (#1)\n", rc));543 LogFunc(("RTTcpRead -> %Rrc / cbRead=0 -> VERR_NET_NOT_CONNECTED (#1)\n", rc)); 250 544 rc = VERR_NET_NOT_CONNECTED; 251 545 break; … … 287 581 if (cbRead == 0) 288 582 { 289 Log (("atsTcpRecvPkt:RTTcpRead -> %Rrc / cbRead=0 -> VERR_NET_NOT_CONNECTED (#2)\n", rc));583 LogFunc(("RTTcpRead -> %Rrc / cbRead=0 -> VERR_NET_NOT_CONNECTED (#2)\n", rc)); 290 584 rc = VERR_NET_NOT_CONNECTED; 291 585 break; 292 586 } 587 293 588 offData += cbRead; 294 589 } 590 591 Log3Func(("Header:\n" 592 "%.*Rhxd\n", sizeof(ATSPKTHDR), pbData)); 593 594 if ( RT_SUCCESS(rc) 595 && cbData > sizeof(ATSPKTHDR)) 596 Log3Func(("Payload:\n" 597 "%.*Rhxd\n", RT_MIN(64, cbData - sizeof(ATSPKTHDR)), (uint8_t *)pbData + sizeof(ATSPKTHDR))); 295 598 } 296 599 } … … 317 620 318 621 /* assume fatal connection error. */ 319 Log (("atsTcpRecvPkt:RTTcpRead -> %Rrc -> atsTcpDisconnectClient(%RTsock)\n", rc, pClient->hTcpClient));622 LogFunc(("RTTcpRead -> %Rrc -> atsTcpDisconnectClient(%RTsock)\n", rc, pClient->hTcpClient)); 320 623 atsTcpDisconnectClient(pThis, pClient); 321 624 } … … 358 661 static DECLCALLBACK(void) atsTcpTerm(PATSTRANSPORTINST pThis) 359 662 { 663 /* Signal thread */ 664 if (RTCritSectIsInitialized(&pThis->CritSect)) 665 { 666 RTCritSectEnter(&pThis->CritSect); 667 pThis->fStopConnecting = true; 668 RTCritSectLeave(&pThis->CritSect); 669 } 670 671 if (pThis->hThreadConnect != NIL_RTTHREAD) 672 { 673 RTThreadUserSignal(pThis->hThreadConnect); 674 RTTcpClientCancelConnect(&pThis->pConnectCancelCookie); 675 } 676 360 677 /* Shut down the server (will wake up thread). */ 361 678 if (pThis->pTcpServer) 362 679 { 363 Log (("atsTcpTerm:Destroying server...\n"));680 LogFunc(("Destroying server...\n")); 364 681 int rc = RTTcpServerDestroy(pThis->pTcpServer); 365 682 if (RT_FAILURE(rc)) … … 368 685 } 369 686 370 Log(("atsTcpTerm: done\n")); 371 } 372 373 /** 374 * @interface_method_impl{ATSTRANSPORT,pfnInit} 375 */ 376 static DECLCALLBACK(int) atsTcpInit(PATSTRANSPORTINST pThis, const char *pszBindAddr, uint32_t uBindPort) 377 { 378 int rc = RTTcpServerCreateEx(pszBindAddr[0] ? pszBindAddr : NULL, uBindPort, &pThis->pTcpServer); 379 if (RT_FAILURE(rc)) 380 { 381 if (rc == VERR_NET_DOWN) 382 { 383 RTMsgInfo("RTTcpServerCreateEx(%s, %u,) failed: %Rrc, retrying for 20 seconds...\n", 384 pszBindAddr[0] ? pszBindAddr : NULL, uBindPort, rc); 385 uint64_t StartMs = RTTimeMilliTS(); 386 do 687 /* Wait for the thread (they should've had some time to quit by now). */ 688 atsTcpConnectWaitOnThreads(pThis, 15000); 689 690 /* Finally, clean up the critical section. */ 691 if (RTCritSectIsInitialized(&pThis->CritSect)) 692 RTCritSectDelete(&pThis->CritSect); 693 694 LogFunc(("Done\n")); 695 } 696 697 /** 698 * @interface_method_impl{ATSTRANSPORT,pfnCreate} 699 */ 700 static DECLCALLBACK(int) atsTcpCreate(PATSTRANSPORTINST *ppThis) 701 { 702 PATSTRANSPORTINST pThis = (PATSTRANSPORTINST)RTMemAllocZ(sizeof(ATSTRANSPORTINST)); 703 AssertPtrReturn(pThis, VERR_NO_MEMORY); 704 705 *ppThis = pThis; 706 return VINF_SUCCESS; 707 } 708 709 /** 710 * @interface_method_impl{ATSTRANSPORT,pfnDestroy} 711 */ 712 static DECLCALLBACK(int) atsTcpDestroy(PATSTRANSPORTINST pThis) 713 { 714 /** @todo Anything else to do here? */ 715 RTMemFree(pThis); 716 717 return VINF_SUCCESS; 718 } 719 720 /** 721 * @interface_method_impl{ATSTRANSPORT,pfnStart} 722 */ 723 static DECLCALLBACK(int) atsTcpStart(PATSTRANSPORTINST pThis) 724 { 725 int rc = RTCritSectInit(&pThis->CritSect); 726 if (RT_SUCCESS(rc) && pThis->enmMode != ATSTCPMODE_CLIENT) 727 { 728 rc = RTTcpServerCreateEx(pThis->szBindAddr[0] ? pThis->szBindAddr : NULL, pThis->uBindPort, &pThis->pTcpServer); 729 if (RT_FAILURE(rc)) 730 { 731 if (rc == VERR_NET_DOWN) 387 732 { 388 RTThreadSleep(1000); 389 rc = RTTcpServerCreateEx(pszBindAddr[0] ? pszBindAddr : NULL, uBindPort, &pThis->pTcpServer); 390 } while ( rc == VERR_NET_DOWN 391 && RTTimeMilliTS() - StartMs < 20000); 392 if (RT_SUCCESS(rc)) 393 RTMsgInfo("RTTcpServerCreateEx succceeded.\n"); 394 } 395 if (RT_FAILURE(rc)) 396 { 397 pThis->pTcpServer = NULL; 398 RTMsgError("RTTcpServerCreateEx(%s, %u,) failed: %Rrc\n", 399 pszBindAddr[0] ? pszBindAddr : NULL, uBindPort, rc); 733 RTMsgInfo("RTTcpServerCreateEx(%s, %u,) failed: %Rrc, retrying for 20 seconds...\n", 734 pThis->szBindAddr[0] ? pThis->szBindAddr : NULL, pThis->uBindPort, rc); 735 uint64_t StartMs = RTTimeMilliTS(); 736 do 737 { 738 RTThreadSleep(1000); 739 rc = RTTcpServerCreateEx(pThis->szBindAddr[0] ? pThis->szBindAddr : NULL, pThis->uBindPort, &pThis->pTcpServer); 740 } while ( rc == VERR_NET_DOWN 741 && RTTimeMilliTS() - StartMs < 20000); 742 if (RT_SUCCESS(rc)) 743 RTMsgInfo("RTTcpServerCreateEx succceeded.\n"); 744 } 745 746 if (RT_FAILURE(rc)) 747 { 748 RTMsgError("RTTcpServerCreateEx(%s, %u,) failed: %Rrc\n", 749 pThis->szBindAddr[0] ? pThis->szBindAddr : NULL, pThis->uBindPort, rc); 750 } 400 751 } 401 752 } … … 403 754 return rc; 404 755 } 756 757 /** 758 * @interface_method_impl{ATSTRANSPORT,pfnOption} 759 */ 760 static DECLCALLBACK(int) atsTcpOption(PATSTRANSPORTINST pThis, int ch, PCRTGETOPTUNION pVal) 761 { 762 int rc; 763 764 switch (ch) 765 { 766 case ATSTCPOPT_MODE: 767 if (!strcmp(pVal->psz, "both")) 768 pThis->enmMode = ATSTCPMODE_BOTH; 769 else if (!strcmp(pVal->psz, "client")) 770 pThis->enmMode = ATSTCPMODE_CLIENT; 771 else if (!strcmp(pVal->psz, "server")) 772 pThis->enmMode = ATSTCPMODE_SERVER; 773 else 774 return RTMsgErrorRc(VERR_INVALID_PARAMETER, "Invalid TCP mode: '%s'\n", pVal->psz); 775 return VINF_SUCCESS; 776 777 case ATSTCPOPT_BIND_ADDRESS: 778 rc = RTStrCopy(pThis->szBindAddr, sizeof(pThis->szBindAddr), pVal->psz); 779 if (RT_FAILURE(rc)) 780 return RTMsgErrorRc(VERR_INVALID_PARAMETER, "TCP bind address is too long (%Rrc)", rc); 781 return VINF_SUCCESS; 782 783 case ATSTCPOPT_BIND_PORT: 784 pThis->uBindPort = pVal->u16 == 0 ? ATS_TCP_DEF_BIND_PORT_GUEST : pVal->u16; 785 return VINF_SUCCESS; 786 787 case ATSTCPOPT_CONNECT_ADDRESS: 788 rc = RTStrCopy(pThis->szConnectAddr, sizeof(pThis->szConnectAddr), pVal->psz); 789 if (RT_FAILURE(rc)) 790 return RTMsgErrorRc(VERR_INVALID_PARAMETER, "TCP connect address is too long (%Rrc)", rc); 791 if (!pThis->szConnectAddr[0]) 792 strcpy(pThis->szConnectAddr, ATS_TCP_DEF_CONNECT_GUEST_STR); 793 return VINF_SUCCESS; 794 795 case ATSTCPOPT_CONNECT_PORT: 796 pThis->uConnectPort = pVal->u16 == 0 ? ATS_TCP_DEF_BIND_PORT_GUEST : pVal->u16; 797 return VINF_SUCCESS; 798 799 default: 800 break; 801 } 802 return VERR_TRY_AGAIN; 803 } 804 805 /** 806 * @interface_method_impl{ATSTRANSPORT,pfnUsage} 807 */ 808 DECLCALLBACK(void) atsTcpUsage(PRTSTREAM pStream) 809 { 810 RTStrmPrintf(pStream, 811 " --tcp-mode <both|client|server>\n" 812 " Selects the mode of operation.\n" 813 " Default: both\n" 814 " --tcp-bind-address <address>\n" 815 " The address(es) to listen to TCP connection on. Empty string\n" 816 " means any address, this is the default.\n" 817 " --tcp-bind-port <port>\n" 818 " The port to listen to TCP connections on.\n" 819 " Default: %u\n" 820 " --tcp-connect-address <address>\n" 821 " The address of the server to try connect to in client mode.\n" 822 " Default: " ATS_TCP_DEF_CONNECT_GUEST_STR "\n" 823 " --tcp-connect-port <port>\n" 824 " The port on the server to connect to in client mode.\n" 825 " Default: %u\n" 826 , ATS_TCP_DEF_BIND_PORT_GUEST, ATS_TCP_DEF_CONNECT_PORT_GUEST); 827 } 828 829 /** Command line options for the TCP/IP transport layer. */ 830 static const RTGETOPTDEF g_TcpOpts[] = 831 { 832 { "--tcp-mode", ATSTCPOPT_MODE, RTGETOPT_REQ_STRING }, 833 { "--tcp-bind-address", ATSTCPOPT_BIND_ADDRESS, RTGETOPT_REQ_STRING }, 834 { "--tcp-bind-port", ATSTCPOPT_BIND_PORT, RTGETOPT_REQ_UINT16 }, 835 { "--tcp-connect-address", ATSTCPOPT_CONNECT_ADDRESS, RTGETOPT_REQ_STRING }, 836 { "--tcp-connect-port", ATSTCPOPT_CONNECT_PORT, RTGETOPT_REQ_UINT16 } 837 }; 405 838 406 839 /** TCP/IP transport layer. */ … … 409 842 /* .szName = */ "tcp", 410 843 /* .pszDesc = */ "TCP/IP", 411 /* .pfnInit = */ atsTcpInit, 844 /* .cOpts = */ &g_TcpOpts[0], 845 /* .paOpts = */ RT_ELEMENTS(g_TcpOpts), 846 /* .pfnUsage = */ atsTcpUsage, 847 /* .pfnCreate = */ atsTcpCreate, 848 /* .pfnDestroy = */ atsTcpDestroy, 849 /* .pfnOption = */ atsTcpOption, 850 /* .pfnStart = */ atsTcpStart, 412 851 /* .pfnTerm = */ atsTcpTerm, 413 852 /* .pfnWaitForConnect = */ atsTcpWaitForConnect,
Note:
See TracChangeset
for help on using the changeset viewer.