VirtualBox

Ignore:
Timestamp:
Jun 30, 2021 7:02:07 AM (3 years ago)
Author:
vboxsync
Message:

Audio/ValKit: Initial implementation / support for NATed VMs by using reversed (server) connections. The ATS client now also makes use of the transport layer and now can also be configured more flexible on a per-transport layer basis. bugref:10008

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/AudioTestServiceTcp.cpp

    r89614 r89962  
    2020*   Header Files                                                                                                                 *
    2121*********************************************************************************************************************************/
    22 #define LOG_GROUP RTLOGGROUP_DEFAULT
     22#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO /** @todo Add an own log group for this? */
    2323#include <iprt/asm.h>
    2424#include <iprt/assert.h>
     
    3434#include <iprt/time.h>
    3535
     36#include <VBox/log.h>
     37
    3638#include "AudioTestService.h"
    3739#include "AudioTestServiceInternal.h"
     
    4648*   Structures and Typedefs                                                                                                      *
    4749*********************************************************************************************************************************/
    48 
    4950/**
    5051 * TCP specific client data.
     
    5354{
    5455    /** 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;
    5660    /** The size of the stashed data. */
    57     size_t               cbTcpStashed;
     61    size_t                             cbTcpStashed;
    5862    /** The size of the stashed data allocation. */
    59     size_t               cbTcpStashedAlloced;
     63    size_t                             cbTcpStashedAlloced;
    6064    /** The stashed data. */
    61     uint8_t             *pbTcpStashed;
     65    uint8_t                           *pbTcpStashed;
    6266} ATSTRANSPORTCLIENT;
     67
     68/**
     69 * Enumeration for the TCP/IP connection mode.
     70 */
     71typedef 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 */
     84typedef 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. */
     112typedef 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 */
     118typedef 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. */
     126typedef ATSCONNCTX *PATSCONNCTX;
    63127
    64128
     
    76140    if (pClient->hTcpClient != NIL_RTSOCKET)
    77141    {
    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);
    79147        pClient->hTcpClient = NIL_RTSOCKET;
    80148        AssertRCSuccess(rc);
     
    89157
    90158/**
     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 */
     168static 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 */
     190static 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 */
     207static 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 */
     234static 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 */
     276static 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/**
    91306 * @interface_method_impl{ATSTRANSPORT,pfnWaitForConnect}
    92307 */
    93308static DECLCALLBACK(int) atsTcpWaitForConnect(PATSTRANSPORTINST pThis, PPATSTRANSPORTCLIENT ppClientNew)
    94309{
     310    PATSTRANSPORTCLIENT pClient = (PATSTRANSPORTCLIENT)RTMemAllocZ(sizeof(ATSTRANSPORTCLIENT));
     311    AssertPtrReturn(pClient, VERR_NO_MEMORY);
     312
    95313    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    }
    100387
    101388    if (RT_SUCCESS(rc))
    102389    {
    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;
    116400        }
    117401    }
     
    125409static DECLCALLBACK(void) atsTcpNotifyReboot(PATSTRANSPORTINST pThis)
    126410{
    127     Log(("atsTcpNotifyReboot: RTTcpServerDestroy(%p)\n", pThis->pTcpServer));
     411    LogFunc(("RTTcpServerDestroy(%p)\n", pThis->pTcpServer));
    128412    if (pThis->pTcpServer)
    129413    {
     
    140424static DECLCALLBACK(void) atsTcpNotifyBye(PATSTRANSPORTINST pThis, PATSTRANSPORTCLIENT pClient)
    141425{
    142     Log(("atsTcpNotifyBye: atsTcpDisconnectClient %RTsock\n", pClient->hTcpClient));
     426    LogFunc(("atsTcpDisconnectClient %RTsock\n", pClient->hTcpClient));
    143427    atsTcpDisconnectClient(pThis, pClient);
    144428    RTMemFree(pClient);
     
    171455     * Disconnect the client.
    172456     */
    173     Log(("atsTcpBabble: atsTcpDisconnectClient(%RTsock) (RTTcpWrite rc=%Rrc)\n", pClient->hTcpClient, rc));
     457    LogFunc(("atsTcpDisconnectClient(%RTsock) (RTTcpWrite rc=%Rrc)\n", pClient->hTcpClient, rc));
    174458    atsTcpDisconnectClient(pThis, pClient);
    175459}
     
    180464static DECLCALLBACK(int) atsTcpSendPkt(PATSTRANSPORTINST pThis, PATSTRANSPORTCLIENT pClient, PCATSPKTHDR pPktHdr)
    181465{
    182     Assert(pPktHdr->cb >= sizeof(ATSPKTHDR));
     466    AssertReturn(pPktHdr->cb >= sizeof(ATSPKTHDR), VERR_INVALID_PARAMETER);
    183467
    184468    /*
     
    186470     */
    187471    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
    189483    int rc = RTTcpWrite(pClient->hTcpClient, pPktHdr, cbToSend);
    190484    if (    RT_FAILURE(rc)
     
    192486    {
    193487        /* assume fatal connection error. */
    194         Log(("RTTcpWrite -> %Rrc -> atsTcpDisconnectClient(%RTsock)\n", rc, pClient->hTcpClient));
     488        LogFunc(("RTTcpWrite -> %Rrc -> atsTcpDisconnectClient(%RTsock)\n", rc, pClient->hTcpClient));
    195489        atsTcpDisconnectClient(pThis, pClient);
    196490    }
     
    237531
    238532    /*
    239      * Read and valid the length.
     533     * Read and validate the length.
    240534     */
    241535    while (offData < sizeof(uint32_t))
     
    247541        if (cbRead == 0)
    248542        {
    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));
    250544            rc = VERR_NET_NOT_CONNECTED;
    251545            break;
     
    287581                    if (cbRead == 0)
    288582                    {
    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));
    290584                        rc = VERR_NET_NOT_CONNECTED;
    291585                        break;
    292586                    }
     587
    293588                    offData += cbRead;
    294589                }
     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)));
    295598            }
    296599        }
     
    317620
    318621            /* 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));
    320623            atsTcpDisconnectClient(pThis, pClient);
    321624        }
     
    358661static DECLCALLBACK(void) atsTcpTerm(PATSTRANSPORTINST pThis)
    359662{
     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
    360677    /* Shut down the server (will wake up thread). */
    361678    if (pThis->pTcpServer)
    362679    {
    363         Log(("atsTcpTerm: Destroying server...\n"));
     680        LogFunc(("Destroying server...\n"));
    364681        int rc = RTTcpServerDestroy(pThis->pTcpServer);
    365682        if (RT_FAILURE(rc))
     
    368685    }
    369686
    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 */
     700static 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 */
     712static 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 */
     723static 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)
    387732            {
    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            }
    400751        }
    401752    }
     
    403754    return rc;
    404755}
     756
     757/**
     758 * @interface_method_impl{ATSTRANSPORT,pfnOption}
     759 */
     760static 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 */
     808DECLCALLBACK(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. */
     830static 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};
    405838
    406839/** TCP/IP transport layer. */
     
    409842    /* .szName            = */ "tcp",
    410843    /* .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,
    412851    /* .pfnTerm           = */ atsTcpTerm,
    413852    /* .pfnWaitForConnect = */ atsTcpWaitForConnect,
Note: See TracChangeset for help on using the changeset viewer.

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