VirtualBox

Changeset 89962 in vbox


Ignore:
Timestamp:
Jun 30, 2021 7:02:07 AM (4 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

Location:
trunk/src/VBox
Files:
13 edited

Legend:

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

    r89803 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? */
     23
    2324#include <iprt/alloca.h>
    2425#include <iprt/asm.h>
     
    3031#include <iprt/env.h>
    3132#include <iprt/err.h>
     33#include <iprt/file.h>
    3234#include <iprt/getopt.h>
    3335#include <iprt/handle.h>
     
    4749#include <iprt/thread.h>
    4850
     51#include <VBox/log.h>
     52
    4953#include "AudioTestService.h"
    5054#include "AudioTestServiceInternal.h"
     
    5458*   Structures and Typedefs                                                                                                      *
    5559*********************************************************************************************************************************/
     60/**
     61 * A generic ATS reply, used by the client
     62 * to process the incoming packets.
     63 */
     64typedef struct ATSSRVREPLY
     65{
     66    char   szOp[ATSPKT_OPCODE_MAX_LEN];
     67    void  *pvPayload;
     68    size_t cbPayload;
     69} ATSSRVREPLY;
     70/** Pointer to a generic ATS reply. */
     71typedef struct ATSSRVREPLY *PATSSRVREPLY;
    5672
    5773
     
    6278 * Transport layers.
    6379 */
    64 static const PCATSTRANSPORT g_apTransports[] =
     80const PCATSTRANSPORT g_apTransports[] =
    6581{
    6682    &g_TcpTransport
    6783};
     84/** Number of transport layers in \a g_apTransports. */
     85const size_t g_cTransports = RT_ELEMENTS(g_apTransports);
    6886
    6987/**
     
    99117} ATSCLIENTINST;
    100118/** Pointer to a ATS client instance. */
    101 typedef ATSCLIENTINST *PATSCLIENTINST;
     119typedef ATSCLIENTINST *PATSSERVERINST;
    102120
    103121/**
     
    130148 * @returns IPRT status code.
    131149 * @param   pThis               The ATS instance.
    132  * @param   pClient             The ATS client structure.
     150 * @param   pInst               The ATS client structure.
    133151 * @param   pPkt                The packet to send.  Must point to a correctly
    134152 *                              aligned buffer.
    135153 */
    136 static int atsSendPkt(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPkt)
     154static int atsSendPkt(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPkt)
    137155{
    138156    Assert(pPkt->cb >= sizeof(*pPkt));
     
    142160
    143161    LogFlowFunc(("cb=%RU32 (%#x), payload=%RU32 (%#x), opcode=%.8s\n",
    144             pPkt->cb, pPkt->cb, pPkt->cb - sizeof(ATSPKTHDR), pPkt->cb - sizeof(ATSPKTHDR), pPkt->achOpcode));
    145     LogFlowFunc(("%.*Rhxd\n", RT_MIN(pPkt->cb, 256), pPkt));
    146     int rc = pThis->pTransport->pfnSendPkt(&pThis->TransportInst, pClient->pTransportClient, pPkt);
     162                 pPkt->cb, pPkt->cb, pPkt->cb - sizeof(ATSPKTHDR), pPkt->cb - sizeof(ATSPKTHDR), pPkt->achOpcode));
     163    int rc = pThis->pTransport->pfnSendPkt(pThis->pTransportInst, pInst->pTransportClient, pPkt);
    147164    while (RT_UNLIKELY(rc == VERR_INTERRUPTED) && !pThis->fTerminate)
    148         rc = pThis->pTransport->pfnSendPkt(&pThis->TransportInst, pClient->pTransportClient, pPkt);
     165        rc = pThis->pTransport->pfnSendPkt(pThis->pTransportInst, pInst->pTransportClient, pPkt);
    149166
    150167    return rc;
     
    155172 *
    156173 * @param   pThis               The ATS instance.
    157  * @param   pClient             The ATS client structure.
     174 * @param   pInst               The ATS server instance.
    158175 * @param   pszOpcode           The BABBLE opcode.
    159176 */
    160 static void atsReplyBabble(PATSSERVER pThis, PATSCLIENTINST pClient, const char *pszOpcode)
     177static void atsReplyBabble(PATSSERVER pThis, PATSSERVERINST pInst, const char *pszOpcode)
    161178{
    162179    ATSPKTHDR Reply;
     
    165182    memcpy(Reply.achOpcode, pszOpcode, sizeof(Reply.achOpcode));
    166183
    167     pThis->pTransport->pfnBabble(&pThis->TransportInst, pClient->pTransportClient, &Reply, 20*1000);
     184    pThis->pTransport->pfnBabble(pThis->pTransportInst, pInst->pTransportClient, &Reply, 20*1000);
    168185}
    169186
     
    176193 * @returns IPRT status code.
    177194 * @param   pThis               The ATS instance.
    178  * @param   pClient             The ATS client structure.
     195 * @param   pInst               The opaque ATS instance structure.
    179196 * @param   ppPktHdr            Where to return the packet on success.  Free
    180197 *                              with RTMemFree.
    181198 * @param   fAutoRetryOnFailure Whether to retry on error.
    182199 */
    183 static int atsRecvPkt(PATSSERVER pThis, PATSCLIENTINST pClient, PPATSPKTHDR ppPktHdr, bool fAutoRetryOnFailure)
     200static int atsRecvPkt(PATSSERVER pThis, PATSSERVERINST pInst, PPATSPKTHDR ppPktHdr, bool fAutoRetryOnFailure)
    184201{
    185202    for (;;)
    186203    {
    187204        PATSPKTHDR pPktHdr;
    188         int rc = pThis->pTransport->pfnRecvPkt(&pThis->TransportInst, pClient->pTransportClient, &pPktHdr);
     205        int rc = pThis->pTransport->pfnRecvPkt(pThis->pTransportInst, pInst->pTransportClient, &pPktHdr);
    189206        if (RT_SUCCESS(rc))
    190207        {
     
    193210                && pPktHdr->cb < ATSPKT_MAX_SIZE)
    194211            {
    195                 Log2(("atsRecvPkt: pPktHdr=%p cb=%#x crc32=%#x opcode=%.8s\n"
    196                       "%.*Rhxd\n",
    197                       pPktHdr, pPktHdr->cb, pPktHdr->uCrc32, pPktHdr->achOpcode, RT_MIN(pPktHdr->cb, 256), pPktHdr));
     212                Log2Func(("pPktHdr=%p cb=%#x crc32=%#x opcode=%.8s\n",
     213                          pPktHdr, pPktHdr->cb, pPktHdr->uCrc32, pPktHdr->achOpcode));
    198214                uint32_t uCrc32Calc = pPktHdr->uCrc32 != 0
    199215                                    ? RTCrc32(&pPktHdr->achOpcode[0], pPktHdr->cb - RT_UOFFSETOF(ATSPKTHDR, achOpcode))
     
    212228                       )
    213229                    {
    214                         Log(("atsRecvPkt: cb=%#x opcode=%.8s\n", pPktHdr->cb, pPktHdr->achOpcode));
     230                        Log(("cb=%#x opcode=%.8s\n", pPktHdr->cb, pPktHdr->achOpcode));
    215231                        *ppPktHdr = pPktHdr;
    216232                        return rc;
     
    221237                else
    222238                {
    223                     Log(("atsRecvPkt: cb=%#x opcode=%.8s crc32=%#x actual=%#x\n",
     239                    Log(("cb=%#x opcode=%.8s crc32=%#x actual=%#x\n",
    224240                         pPktHdr->cb, pPktHdr->achOpcode, pPktHdr->uCrc32, uCrc32Calc));
    225241                    rc = VERR_IO_CRC;
     
    232248               connection oriented. */
    233249            if (rc == VERR_IO_BAD_LENGTH)
    234                 atsReplyBabble(pThis, pClient, "BABBLE L");
     250                atsReplyBabble(pThis, pInst, "BABBLE L");
    235251            else if (rc == VERR_IO_CRC)
    236                 atsReplyBabble(pThis, pClient, "BABBLE C");
     252                atsReplyBabble(pThis, pInst, "BABBLE C");
    237253            else if (rc == VERR_IO_BAD_COMMAND)
    238                 atsReplyBabble(pThis, pClient, "BABBLE O");
     254                atsReplyBabble(pThis, pInst, "BABBLE O");
    239255            else
    240                 atsReplyBabble(pThis, pClient, "BABBLE  ");
     256                atsReplyBabble(pThis, pInst, "BABBLE  ");
    241257            RTMemFree(pPktHdr);
    242258        }
     
    248264            )
    249265        {
    250             Log(("atsRecvPkt: rc=%Rrc\n", rc));
     266            Log(("rc=%Rrc\n", rc));
    251267            return rc;
    252268        }
     
    259275 * @returns IPRT status code of the send.
    260276 * @param   pThis               The ATS instance.
    261  * @param   pClient             The ATS client structure.
     277 * @param   pInst               The opaque ATS instance structure.
    262278 * @param   pReply              The reply packet.
    263279 * @param   pszOpcode           The status opcode.  Exactly 8 chars long, padd
     
    265281 * @param   cbExtra             Bytes in addition to the header.
    266282 */
    267 static int atsReplyInternal(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pReply, const char *pszOpcode, size_t cbExtra)
     283static int atsReplyInternal(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pReply, const char *pszOpcode, size_t cbExtra)
    268284{
    269285    /* copy the opcode, don't be too strict in case of a padding screw up. */
     
    284300    pReply->uCrc32 = 0;
    285301
    286     return atsSendPkt(pThis, pClient, pReply);
     302    return atsSendPkt(pThis, pInst, pReply);
    287303}
    288304
     
    292308 * @returns IPRT status code of the send.
    293309 * @param   pThis               The ATS instance.
    294  * @param   pClient             The ATS client structure.
     310 * @param   pInst               The opaque ATS instance structure.
    295311 * @param   pPktHdr             The original packet (for future use).
    296312 * @param   pszOpcode           The status opcode.  Exactly 8 chars long, padd
    297313 *                              with space.
    298314 */
    299 static int atsReplySimple(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr, const char *pszOpcode)
    300 {
    301     return atsReplyInternal(pThis, pClient, pPktHdr, pszOpcode, 0);
     315static int atsReplySimple(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr, const char *pszOpcode)
     316{
     317    return atsReplyInternal(pThis, pInst, pPktHdr, pszOpcode, 0);
    302318}
    303319
     
    307323 * @returns IPRT status code of the send.
    308324 * @param   pThis               The ATS instance.
    309  * @param   pClient             The ATS client structure.
     325 * @param   pInst               The opaque ATS instance structure.
    310326 * @param   pPktHdr             The original packet (for future use).
    311327 */
    312 static int atsReplyAck(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
    313 {
    314     return atsReplySimple(pThis, pClient, pPktHdr, "ACK     ");
     328static int atsReplyAck(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
     329{
     330    return atsReplySimple(pThis, pInst, pPktHdr, "ACK     ");
    315331}
    316332
     
    320336 * @returns IPRT status code of the send.
    321337 * @param   pThis               The ATS instance.
    322  * @param   pClient             The ATS client structure.
     338 * @param   pInst               The opaque ATS instance structure.
    323339 * @param   pPktHdr             The original packet (for future use).
    324340 * @param   pszOpcode           The status opcode.  Exactly 8 chars long, padd
     
    328344 * @param   va                  Format arguments.
    329345 */
    330 static int atsReplyFailureV(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr,
     346static int atsReplyFailureV(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr,
    331347                            const char *pszOpcode, int rcReq, const char *pszDetailFmt, va_list va)
    332348{
     
    346362    uPkt.rc = rcReq;
    347363
    348     return atsReplyInternal(pThis, pClient, &uPkt.Hdr, pszOpcode, sizeof(int) + cchDetail + 1);
     364    return atsReplyInternal(pThis, pInst, &uPkt.Hdr, pszOpcode, sizeof(int) + cchDetail + 1);
    349365}
    350366
     
    354370 * @returns IPRT status code of the send.
    355371 * @param   pThis               The ATS instance.
    356  * @param   pClient             The ATS client structure.
     372 * @param   pInst               The opaque ATS instance structure.
    357373 * @param   pPktHdr             The original packet (for future use).
    358374 * @param   pszOpcode           The status opcode.  Exactly 8 chars long, padd
     
    362378 * @param   ...                 Format arguments.
    363379 */
    364 static int atsReplyFailure(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr,
     380static int atsReplyFailure(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr,
    365381                           const char *pszOpcode, int rcReq, const char *pszDetailFmt, ...)
    366382{
    367383    va_list va;
    368384    va_start(va, pszDetailFmt);
    369     int rc = atsReplyFailureV(pThis, pClient, pPktHdr, pszOpcode, rcReq, pszDetailFmt, va);
     385    int rc = atsReplyFailureV(pThis, pInst, pPktHdr, pszOpcode, rcReq, pszDetailFmt, va);
    370386    va_end(va);
    371387    return rc;
     
    377393 * @returns IPRT status code of the send.
    378394 * @param   pThis               The ATS instance.
    379  * @param   pClient             The ATS client structure.
     395 * @param   pInst               The opaque ATS instance structure.
    380396 * @param   pPktHdr             The packet to reply to.
    381397 * @param   rcOperation         The status code to report.
     
    385401 */
    386402static int atsReplyRC(PATSSERVER pThis,
    387                       PATSCLIENTINST pClient, PATSPKTHDR pPktHdr, int rcOperation, const char *pszOperationFmt, ...)
     403                      PATSSERVERINST pInst, PATSPKTHDR pPktHdr, int rcOperation, const char *pszOperationFmt, ...)
    388404{
    389405    if (RT_SUCCESS(rcOperation))
    390         return atsReplyAck(pThis, pClient, pPktHdr);
     406        return atsReplyAck(pThis, pInst, pPktHdr);
    391407
    392408    char    szOperation[128];
     
    396412    va_end(va);
    397413
    398     return atsReplyFailure(pThis, pClient, pPktHdr, "FAILED  ", rcOperation, "%s failed with rc=%Rrc (opcode '%.8s')",
     414    return atsReplyFailure(pThis, pInst, pPktHdr, "FAILED  ", rcOperation, "%s failed with rc=%Rrc (opcode '%.8s')",
    399415                           szOperation, rcOperation, pPktHdr->achOpcode);
    400416}
     
    405421 * @returns IPRT status code of the send.
    406422 * @param   pThis               The ATS instance.
    407  * @param   pClient             The ATS client structure.
     423 * @param   pInst               The opaque ATS instance structure.
    408424 * @param   pPktHdr             The packet to reply to.
    409425 * @param   cb                  The wanted size.
    410426 */
    411 static int atsReplyBadSize(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr, size_t cb)
    412 {
    413     return atsReplyFailure(pThis, pClient, pPktHdr, "BAD SIZE", VERR_INVALID_PARAMETER, "Expected at %zu bytes, got %u  (opcode '%.8s')",
     427static int atsReplyBadSize(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr, size_t cb)
     428{
     429    return atsReplyFailure(pThis, pInst, pPktHdr, "BAD SIZE", VERR_INVALID_PARAMETER, "Expected at %zu bytes, got %u  (opcode '%.8s')",
    414430                           cb, pPktHdr->cb, pPktHdr->achOpcode);
    415431}
     
    420436 * @returns IPRT status code of the send.
    421437 * @param   pThis               The ATS instance.
    422  * @param   pClient             The ATS client structure.
     438 * @param   pInst               The opaque ATS instance structure.
    423439 * @param   pPktHdr             The packet to reply to.
    424440 */
    425 static int atsReplyUnknown(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
    426 {
    427     return atsReplyFailure(pThis, pClient, pPktHdr, "UNKNOWN ", VERR_NOT_FOUND, "Opcode '%.8s' is not known", pPktHdr->achOpcode);
    428 }
    429 
    430 #if 0
    431 /**
    432  * Deals with a command which contains an unterminated string.
     441static int atsReplyUnknown(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
     442{
     443    return atsReplyFailure(pThis, pInst, pPktHdr, "UNKNOWN ", VERR_NOT_FOUND, "Opcode '%.8s' is not known", pPktHdr->achOpcode);
     444}
     445
     446/**
     447 * Deals with a command sent in an invalid client state.
    433448 *
    434449 * @returns IPRT status code of the send.
    435  * @param   pClient             The ATS client structure.
     450 * @param   pThis               The ATS instance.
     451 * @param   pInst               The opaque ATS instance structure.
    436452 * @param   pPktHdr             The packet containing the unterminated string.
    437453 */
    438 static int atsReplyBadStrTermination(PATSCLIENT pClient, PATSPKTHDR pPktHdr)
    439 {
    440     return atsReplyFailure(pClient, pPktHdr, "BAD TERM", VERR_INVALID_PARAMETER, "Opcode '%.8s' contains an unterminated string", pPktHdr->achOpcode);
    441 }
    442 #endif
    443 
    444 /**
    445  * Deals with a command sent in an invalid client state.
    446  *
    447  * @returns IPRT status code of the send.
    448  * @param   pThis               The ATS instance.
    449  * @param   pClient             The ATS client structure.
    450  * @param   pPktHdr             The packet containing the unterminated string.
    451  */
    452 static int atsReplyInvalidState(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
    453 {
    454     return atsReplyFailure(pThis, pClient, pPktHdr, "INVSTATE", VERR_INVALID_STATE, "Opcode '%.8s' is not supported at client state '%s",
    455                            pPktHdr->achOpcode, atsClientStateStringify(pClient->enmState));
     454static int atsReplyInvalidState(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
     455{
     456    return atsReplyFailure(pThis, pInst, pPktHdr, "INVSTATE", VERR_INVALID_STATE, "Opcode '%.8s' is not supported at client state '%s",
     457                           pPktHdr->achOpcode, atsClientStateStringify(pInst->enmState));
    456458}
    457459
     
    461463 * @returns IPRT status code.
    462464 * @param   pThis               The ATS instance.
    463  * @param   pClient             The ATS client structure.
     465 * @param   pInst               The opaque ATS instance structure.
    464466 * @param   pPktHdr             The bye packet.
    465467 */
    466 static int atsDoBye(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
     468static int atsDoBye(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
    467469{
    468470    int rc;
    469471    if (pPktHdr->cb == sizeof(ATSPKTHDR))
    470472    {
    471         rc = atsReplyAck(pThis, pClient, pPktHdr);
     473        rc = atsReplyAck(pThis, pInst, pPktHdr);
    472474    }
    473475    else
    474         rc = atsReplyBadSize(pThis, pClient, pPktHdr, sizeof(ATSPKTHDR));
     476        rc = atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTHDR));
    475477    return rc;
    476478}
     
    481483 * @returns IPRT status code.
    482484 * @param   pThis               The ATS instance.
    483  * @param   pClient             The ATS client structure.
     485 * @param   pInst               The opaque ATS instance structure.
    484486 * @param   pPktHdr             The howdy packet.
    485487 */
    486 static int atsDoHowdy(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
     488static int atsDoHowdy(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
    487489{
    488490    int rc = VINF_SUCCESS;
    489491
    490492    if (pPktHdr->cb != sizeof(ATSPKTREQHOWDY))
    491         return atsReplyBadSize(pThis, pClient, pPktHdr, sizeof(ATSPKTREQHOWDY));
    492 
    493     if (pClient->enmState != ATSCLIENTSTATE_INITIALISING)
    494         return atsReplyInvalidState(pThis, pClient, pPktHdr);
     493        return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQHOWDY));
     494
     495    if (pInst->enmState != ATSCLIENTSTATE_INITIALISING)
     496        return atsReplyInvalidState(pThis, pInst, pPktHdr);
    495497
    496498    PATSPKTREQHOWDY pReq = (PATSPKTREQHOWDY)pPktHdr;
    497499
    498500    if (pReq->uVersion != ATS_PROTOCOL_VS)
    499         return atsReplyRC(pThis, pClient, pPktHdr, VERR_VERSION_MISMATCH, "The given version %#x is not supported", pReq->uVersion);
     501        return atsReplyRC(pThis, pInst, pPktHdr, VERR_VERSION_MISMATCH, "The given version %#x is not supported", pReq->uVersion);
    500502
    501503    ATSPKTREPHOWDY Rep;
     
    504506    Rep.uVersion = ATS_PROTOCOL_VS;
    505507
    506     rc = atsReplyInternal(pThis, pClient, &Rep.Hdr, "ACK     ", sizeof(Rep) - sizeof(ATSPKTHDR));
     508    rc = atsReplyInternal(pThis, pInst, &Rep.Hdr, "ACK     ", sizeof(Rep) - sizeof(ATSPKTHDR));
    507509    if (RT_SUCCESS(rc))
    508510    {
    509         pThis->pTransport->pfnNotifyHowdy(&pThis->TransportInst, pClient->pTransportClient);
    510         pClient->enmState = ATSCLIENTSTATE_READY;
     511        pThis->pTransport->pfnNotifyHowdy(pThis->pTransportInst, pInst->pTransportClient);
     512        pInst->enmState = ATSCLIENTSTATE_READY;
    511513    }
    512514
     
    519521 * @returns IPRT status code.
    520522 * @param   pThis               The ATS instance.
    521  * @param   pClient             The ATS client structure.
     523 * @param   pInst               The opaque ATS instance structure.
    522524 * @param   pPktHdr             The test set begin packet.
    523525 */
    524 static int atsDoTestSetBegin(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
     526static int atsDoTestSetBegin(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
    525527{
    526528    if (pPktHdr->cb != sizeof(ATSPKTREQTSETBEG))
    527         return atsReplyBadSize(pThis, pClient, pPktHdr, sizeof(ATSPKTREQTSETBEG));
     529        return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQTSETBEG));
    528530
    529531    PATSPKTREQTSETBEG pReq = (PATSPKTREQTSETBEG)pPktHdr;
     
    535537        rc = pThis->Callbacks.pfnTestSetBegin(pThis->Callbacks.pvUser, pReq->szTag);
    536538        if (RT_FAILURE(rc))
    537             return atsReplyRC(pThis, pClient, pPktHdr, rc, "Beginning test set '%s' failed", pReq->szTag);
     539            return atsReplyRC(pThis, pInst, pPktHdr, rc, "Beginning test set '%s' failed", pReq->szTag);
    538540    }
    539541
    540542    if (RT_SUCCESS(rc))
    541543    {
    542         rc = atsReplyAck(pThis, pClient, pPktHdr);
     544        rc = atsReplyAck(pThis, pInst, pPktHdr);
    543545    }
    544546    else
    545         rc = atsReplyRC(pThis, pClient, pPktHdr, rc, "Beginning test set failed");
     547        rc = atsReplyRC(pThis, pInst, pPktHdr, rc, "Beginning test set failed");
    546548
    547549    return rc;
     
    553555 * @returns IPRT status code.
    554556 * @param   pThis               The ATS instance.
    555  * @param   pClient             The ATS client structure.
     557 * @param   pInst               The opaque ATS instance structure.
    556558 * @param   pPktHdr             The test set end packet.
    557559 */
    558 static int atsDoTestSetEnd(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
     560static int atsDoTestSetEnd(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
    559561{
    560562    if (pPktHdr->cb != sizeof(ATSPKTREQTSETEND))
    561         return atsReplyBadSize(pThis, pClient, pPktHdr, sizeof(ATSPKTREQTSETEND));
     563        return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQTSETEND));
    562564
    563565    PATSPKTREQTSETEND pReq = (PATSPKTREQTSETEND)pPktHdr;
     
    569571        rc = pThis->Callbacks.pfnTestSetEnd(pThis->Callbacks.pvUser, pReq->szTag);
    570572        if (RT_FAILURE(rc))
    571             return atsReplyRC(pThis, pClient, pPktHdr, rc, "Ending test set '%s' failed", pReq->szTag);
     573            return atsReplyRC(pThis, pInst, pPktHdr, rc, "Ending test set '%s' failed", pReq->szTag);
    572574    }
    573575    if (RT_SUCCESS(rc))
    574576    {
    575         rc = atsReplyAck(pThis, pClient, pPktHdr);
     577        rc = atsReplyAck(pThis, pInst, pPktHdr);
    576578    }
    577579    else
    578         rc = atsReplyRC(pThis, pClient, pPktHdr, rc, "Ending test set failed");
     580        rc = atsReplyRC(pThis, pInst, pPktHdr, rc, "Ending test set failed");
    579581
    580582    return rc;
     
    588590 *          or whatever atsRecvPkt returns.
    589591 * @param   pThis               The ATS instance.
    590  * @param   pClient             The ATS client structure.
     592 * @param   pInst               The opaque ATS instance structure.
    591593 * @param   pPktHdr             The original packet (for future use).
    592594 */
    593 static int atsWaitForAck(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
     595static int atsWaitForAck(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
    594596{
    595597    RT_NOREF(pPktHdr);
    596598    /** @todo timeout? */
    597599    PATSPKTHDR pReply;
    598     int rc = atsRecvPkt(pThis, pClient, &pReply, false /*fAutoRetryOnFailure*/);
     600    int rc = atsRecvPkt(pThis, pInst, &pReply, false /*fAutoRetryOnFailure*/);
    599601    if (RT_SUCCESS(rc))
    600602    {
     
    605607        else
    606608        {
    607             atsReplyBabble(pThis, pClient, "BABBLE  ");
     609            atsReplyBabble(pThis, pInst, "BABBLE  ");
    608610            rc = VERR_NET_NOT_CONNECTED;
    609611        }
     
    618620 * @returns IPRT status code.
    619621 * @param   pThis               The ATS instance.
    620  * @param   pClient             The ATS client structure.
     622 * @param   pInst               The opaque ATS instance structure.
    621623 * @param   pPktHdr             The test set end packet.
    622624 */
    623 static int atsDoTestSetSend(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
     625static int atsDoTestSetSend(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
    624626{
    625627    if (pPktHdr->cb != sizeof(ATSPKTREQTSETSND))
    626         return atsReplyBadSize(pThis, pClient, pPktHdr, sizeof(ATSPKTREQTSETSND));
     628        return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQTSETSND));
    627629
    628630    PATSPKTREQTSETSND pReq = (PATSPKTREQTSETSND)pPktHdr;
     
    631633
    632634    if (!pThis->Callbacks.pfnTestSetSendRead)
    633         return atsReplyRC(pThis, pClient, pPktHdr, VERR_NOT_SUPPORTED, "Sending test set not implemented");
     635        return atsReplyRC(pThis, pInst, pPktHdr, VERR_NOT_SUPPORTED, "Sending test set not implemented");
    634636
    635637    if (pThis->Callbacks.pfnTestSetSendBegin)
     
    637639        rc = pThis->Callbacks.pfnTestSetSendBegin(pThis->Callbacks.pvUser, pReq->szTag);
    638640        if (RT_FAILURE(rc))
    639             return atsReplyRC(pThis, pClient, pPktHdr, rc, "Beginning sending test set '%s' failed", pReq->szTag);
     641            return atsReplyRC(pThis, pInst, pPktHdr, rc, "Beginning sending test set '%s' failed", pReq->szTag);
    640642    }
    641643
     
    650652            char        abPadding[ATSPKT_ALIGNMENT];
    651653        }       Pkt;
     654#ifdef DEBUG
     655        RT_ZERO(Pkt);
     656#endif
    652657        size_t  cbRead = 0;
    653658        rc = pThis->Callbacks.pfnTestSetSendRead(pThis->Callbacks.pvUser, pReq->szTag, &Pkt.ab, sizeof(Pkt.ab), &cbRead);
     
    659664            {
    660665                Pkt.uCrc32 = RTCrc32Finish(uMyCrc32);
    661                 rc = atsReplyInternal(pThis, pClient, &Pkt.Hdr, "DATA EOF", sizeof(uint32_t) /* uCrc32 */);
     666                rc = atsReplyInternal(pThis, pInst, &Pkt.Hdr, "DATA EOF", sizeof(uint32_t) /* uCrc32 */);
    662667                if (RT_SUCCESS(rc))
    663                     rc = atsWaitForAck(pThis, pClient, &Pkt.Hdr);
     668                    rc = atsWaitForAck(pThis, pInst, &Pkt.Hdr);
    664669            }
    665670            else
    666                 rc = atsReplyRC(pThis, pClient, pPktHdr, rc, "Sending data for test set '%s' failed", pReq->szTag);
     671                rc = atsReplyRC(pThis, pInst, pPktHdr, rc, "Sending data for test set '%s' failed", pReq->szTag);
    667672            break;
    668673        }
     
    671676        Pkt.uCrc32 = RTCrc32Finish(uMyCrc32);
    672677
     678        Log2Func(("cbRead=%zu -> uCrc32=%#x\n", cbRead, Pkt.uCrc32));
     679
    673680        Assert(cbRead <= sizeof(Pkt.ab));
    674681
    675         rc = atsReplyInternal(pThis, pClient, &Pkt.Hdr, "DATA    ", sizeof(uint32_t) /* uCrc32 */ + cbRead);
     682        rc = atsReplyInternal(pThis, pInst, &Pkt.Hdr, "DATA    ", sizeof(uint32_t) /* uCrc32 */ + cbRead);
    676683        if (RT_FAILURE(rc))
    677684            break;
    678685
    679         rc = atsWaitForAck(pThis, pClient, &Pkt.Hdr);
     686        rc = atsWaitForAck(pThis, pInst, &Pkt.Hdr);
    680687        if (RT_FAILURE(rc))
    681688            break;
     
    686693        int rc2 = pThis->Callbacks.pfnTestSetSendEnd(pThis->Callbacks.pvUser, pReq->szTag);
    687694        if (RT_FAILURE(rc2))
    688             return atsReplyRC(pThis, pClient, pPktHdr, rc2, "Ending sending test set '%s' failed", pReq->szTag);
     695            return atsReplyRC(pThis, pInst, pPktHdr, rc2, "Ending sending test set '%s' failed", pReq->szTag);
    689696    }
    690697
     
    697704 * @returns IPRT status code.
    698705 * @param   pThis               The ATS instance.
    699  * @param   pClient             The ATS client structure.
     706 * @param   pInst               The opaque ATS instance structure.
    700707 * @param   pPktHdr             The packet header.
    701708 */
    702 static int atsDoTonePlay(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
     709static int atsDoTonePlay(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
    703710{
    704711    int rc = VINF_SUCCESS;
    705712
    706713    if (pPktHdr->cb < sizeof(ATSPKTREQTONEPLAY))
    707         return atsReplyBadSize(pThis, pClient, pPktHdr, sizeof(ATSPKTREQTONEPLAY));
    708 
    709     if (pClient->enmState != ATSCLIENTSTATE_READY)
    710         return atsReplyInvalidState(pThis, pClient, pPktHdr);
     714        return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQTONEPLAY));
     715
     716    if (pInst->enmState != ATSCLIENTSTATE_READY)
     717        return atsReplyInvalidState(pThis, pInst, pPktHdr);
    711718
    712719    if (!pThis->Callbacks.pfnTonePlay)
    713         return atsReplyRC(pThis, pClient, pPktHdr, VERR_NOT_SUPPORTED, "Playing tones not supported");
     720        return atsReplyRC(pThis, pInst, pPktHdr, VERR_NOT_SUPPORTED, "Playing tones not supported");
    714721
    715722    PATSPKTREQTONEPLAY pReq = (PATSPKTREQTONEPLAY)pPktHdr;
    716723    rc = pThis->Callbacks.pfnTonePlay(pThis->Callbacks.pvUser, &pReq->ToneParms);
    717724
    718     int rc2 = atsReplyAck(pThis, pClient, pPktHdr);
     725    int rc2 = atsReplyAck(pThis, pInst, pPktHdr);
    719726    if (RT_SUCCESS(rc))
    720727        rc = rc2;
     
    728735 * @returns IPRT status code.
    729736 * @param   pThis               The ATS instance.
    730  * @param   pClient             The ATS client structure.
     737 * @param   pInst               The opaque ATS instance structure.
    731738 * @param   pPktHdr             The packet header.
    732739 */
    733 static int atsDoToneRecord(PATSSERVER pThis, PATSCLIENTINST pClient, PATSPKTHDR pPktHdr)
     740static int atsDoToneRecord(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
    734741{
    735742    int rc = VINF_SUCCESS;
    736743
    737744    if (pPktHdr->cb < sizeof(ATSPKTREQTONEREC))
    738         return atsReplyBadSize(pThis, pClient, pPktHdr, sizeof(ATSPKTREQTONEREC));
    739 
    740     if (pClient->enmState != ATSCLIENTSTATE_READY)
    741         return atsReplyInvalidState(pThis, pClient, pPktHdr);
     745        return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQTONEREC));
     746
     747    if (pInst->enmState != ATSCLIENTSTATE_READY)
     748        return atsReplyInvalidState(pThis, pInst, pPktHdr);
    742749
    743750    if (!pThis->Callbacks.pfnToneRecord)
    744         return atsReplyRC(pThis, pClient, pPktHdr, VERR_NOT_SUPPORTED, "Recording tones not supported");
     751        return atsReplyRC(pThis, pInst, pPktHdr, VERR_NOT_SUPPORTED, "Recording tones not supported");
    745752
    746753    PATSPKTREQTONEREC pReq = (PATSPKTREQTONEREC)pPktHdr;
    747754    rc = pThis->Callbacks.pfnToneRecord(pThis->Callbacks.pvUser, &pReq->ToneParms);
    748755
    749     int rc2 = atsReplyAck(pThis, pClient, pPktHdr);
     756    int rc2 = atsReplyAck(pThis, pInst, pPktHdr);
    750757    if (RT_SUCCESS(rc))
    751758        rc = rc2;
     
    759766 * @returns IPRT status code.
    760767 * @param   pThis               The ATS instance.
    761  * @param   pClient             The ATS client structure sending the request.
    762  */
    763 static int atsClientReqProcess(PATSSERVER pThis, PATSCLIENTINST pClient)
     768 * @param   pInst             The ATS client structure sending the request.
     769 */
     770static int atsClientReqProcess(PATSSERVER pThis, PATSSERVERINST pInst)
    764771{
    765772    /*
     
    767774     */
    768775    PATSPKTHDR pPktHdr = NULL;
    769     int rc = atsRecvPkt(pThis, pClient, &pPktHdr, true /*fAutoRetryOnFailure*/);
     776    int rc = atsRecvPkt(pThis, pInst, &pPktHdr, true /*fAutoRetryOnFailure*/);
    770777    if (RT_FAILURE(rc))
    771778        return rc;
     
    776783    /* Connection: */
    777784    if (     atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_HOWDY))
    778         rc = atsDoHowdy(pThis, pClient, pPktHdr);
     785        rc = atsDoHowdy(pThis, pInst, pPktHdr);
    779786    else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_BYE))
    780         rc = atsDoBye(pThis, pClient, pPktHdr);
     787        rc = atsDoBye(pThis, pInst, pPktHdr);
    781788    /* Test set handling: */
    782789    else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_TESTSET_BEGIN))
    783         rc = atsDoTestSetBegin(pThis, pClient, pPktHdr);
     790        rc = atsDoTestSetBegin(pThis, pInst, pPktHdr);
    784791    else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_TESTSET_END))
    785         rc = atsDoTestSetEnd(pThis, pClient, pPktHdr);
     792        rc = atsDoTestSetEnd(pThis, pInst, pPktHdr);
    786793    else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_TESTSET_SEND))
    787         rc = atsDoTestSetSend(pThis, pClient, pPktHdr);
     794        rc = atsDoTestSetSend(pThis, pInst, pPktHdr);
    788795    /* Audio testing: */
    789796    else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_TONE_PLAY))
    790         rc = atsDoTonePlay(pThis, pClient, pPktHdr);
     797        rc = atsDoTonePlay(pThis, pInst, pPktHdr);
    791798    else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_TONE_RECORD))
    792         rc = atsDoToneRecord(pThis, pClient, pPktHdr);
     799        rc = atsDoToneRecord(pThis, pInst, pPktHdr);
    793800    /* Misc: */
    794801    else
    795         rc = atsReplyUnknown(pThis, pClient, pPktHdr);
     802        rc = atsReplyUnknown(pThis, pInst, pPktHdr);
    796803
    797804    RTMemFree(pPktHdr);
     
    804811 *
    805812 * @returns nothing.
    806  * @param   pClient             The ATS client structure.
    807  */
    808 static void atsClientDestroy(PATSCLIENTINST pClient)
    809 {
    810     if (pClient->pszHostname)
    811         RTStrFree(pClient->pszHostname);
    812     RTMemFree(pClient);
     813 * @param   pInst               The opaque ATS instance structure.
     814 */
     815static void atsClientDestroy(PATSSERVERINST pInst)
     816{
     817    if (pInst->pszHostname)
     818        RTStrFree(pInst->pszHostname);
     819    RTMemFree(pInst);
    813820}
    814821
     
    825832    unsigned    cClientsMax = 0;
    826833    unsigned    cClientsCur = 0;
    827     PATSCLIENTINST *papClients  = NULL;
     834    PATSSERVERINST *papInsts  = NULL;
    828835
    829836    /* Add the pipe to the poll set. */
     
    853860                    RTCritSectEnter(&pThis->CritSectClients);
    854861                    /* Walk the list and add all new clients. */
    855                     PATSCLIENTINST pIt, pItNext;
     862                    PATSSERVERINST pIt, pItNext;
    856863                    RTListForEachSafe(&pThis->LstClientsNew, pIt, pItNext, ATSCLIENTINST, NdLst)
    857864                    {
     
    861868                        {
    862869                            /* Realloc to accommodate for the new clients. */
    863                             PATSCLIENTINST *papClientsNew = (PATSCLIENTINST *)RTMemRealloc(papClients, (cClientsMax + 10) * sizeof(PATSCLIENTINST));
    864                             if (RT_LIKELY(papClientsNew))
     870                            PATSSERVERINST *papInstsNew = (PATSSERVERINST *)RTMemRealloc(papInsts, (cClientsMax + 10) * sizeof(PATSSERVERINST));
     871                            if (RT_LIKELY(papInstsNew))
    865872                            {
    866873                                cClientsMax += 10;
    867                                 papClients = papClientsNew;
     874                                papInsts = papInstsNew;
    868875                            }
    869876                        }
     
    873880                            unsigned idxSlt = 0;
    874881                            while (   idxSlt < cClientsMax
    875                                    && papClients[idxSlt] != NULL)
     882                                   && papInsts[idxSlt] != NULL)
    876883                                idxSlt++;
    877884
    878                             rc = pThis->pTransport->pfnPollSetAdd(&pThis->TransportInst, pThis->hPollSet, pIt->pTransportClient, idxSlt + 1);
     885                            rc = pThis->pTransport->pfnPollSetAdd(pThis->pTransportInst, pThis->hPollSet, pIt->pTransportClient, idxSlt + 1);
    879886                            if (RT_SUCCESS(rc))
    880887                            {
    881888                                cClientsCur++;
    882                                 papClients[idxSlt] = pIt;
     889                                papInsts[idxSlt] = pIt;
    883890                            }
    884891                            else
    885892                            {
    886                                 pThis->pTransport->pfnNotifyBye(&pThis->TransportInst, pIt->pTransportClient);
     893                                pThis->pTransport->pfnNotifyBye(pThis->pTransportInst, pIt->pTransportClient);
    887894                                atsClientDestroy(pIt);
    888895                            }
     
    890897                        else
    891898                        {
    892                             pThis->pTransport->pfnNotifyBye(&pThis->TransportInst, pIt->pTransportClient);
     899                            pThis->pTransport->pfnNotifyBye(pThis->pTransportInst, pIt->pTransportClient);
    893900                            atsClientDestroy(pIt);
    894901                        }
     
    899906                {
    900907                    /* Client sends a request, pick the right client and process it. */
    901                     PATSCLIENTINST pClient = papClients[uId - 1];
    902                     AssertPtr(pClient);
     908                    PATSSERVERINST pInst = papInsts[uId - 1];
     909                    AssertPtr(pInst);
    903910                    if (fEvts & RTPOLL_EVT_READ)
    904                         rc = atsClientReqProcess(pThis, pClient);
     911                        rc = atsClientReqProcess(pThis, pInst);
    905912
    906913                    if (   (fEvts & RTPOLL_EVT_ERROR)
     
    908915                    {
    909916                        /* Close connection and remove client from array. */
    910                         rc = pThis->pTransport->pfnPollSetRemove(&pThis->TransportInst, pThis->hPollSet, pClient->pTransportClient, uId);
     917                        rc = pThis->pTransport->pfnPollSetRemove(pThis->pTransportInst, pThis->hPollSet, pInst->pTransportClient, uId);
    911918                        AssertRC(rc);
    912919
    913                         pThis->pTransport->pfnNotifyBye(&pThis->TransportInst, pClient->pTransportClient);
    914                         papClients[uId - 1] = NULL;
     920                        pThis->pTransport->pfnNotifyBye(pThis->pTransportInst, pInst->pTransportClient);
     921                        papInsts[uId - 1] = NULL;
    915922                        cClientsCur--;
    916                         atsClientDestroy(pClient);
     923                        atsClientDestroy(pInst);
    917924                    }
    918925                }
     
    929936 * @returns VBox status code.
    930937 */
    931 static DECLCALLBACK(int) atsMainThread(RTTHREAD hThread, void *pvUser)
     938static DECLCALLBACK(int) atsConnectThread(RTTHREAD hThread, void *pvUser)
    932939{
    933940    RT_NOREF(hThread);
     
    946953         */
    947954        PATSTRANSPORTCLIENT pTransportClient;
    948         rc = pThis->pTransport->pfnWaitForConnect(&pThis->TransportInst, &pTransportClient);
     955        rc = pThis->pTransport->pfnWaitForConnect(pThis->pTransportInst, &pTransportClient);
    949956        if (RT_FAILURE(rc))
    950957            continue;
     
    954961         * the request handling thread.
    955962         */
    956         PATSCLIENTINST pClient = (PATSCLIENTINST)RTMemAllocZ(sizeof(ATSCLIENTINST));
    957         if (RT_LIKELY(pClient))
     963        PATSSERVERINST pInst = (PATSSERVERINST)RTMemAllocZ(sizeof(ATSCLIENTINST));
     964        if (RT_LIKELY(pInst))
    958965        {
    959             pClient->enmState         = ATSCLIENTSTATE_INITIALISING;
    960             pClient->pTransportClient = pTransportClient;
    961             pClient->pszHostname      = NULL;
     966            pInst->enmState         = ATSCLIENTSTATE_INITIALISING;
     967            pInst->pTransportClient = pTransportClient;
     968            pInst->pszHostname      = NULL;
    962969
    963970            /* Add client to the new list and inform the worker thread. */
    964971            RTCritSectEnter(&pThis->CritSectClients);
    965             RTListAppend(&pThis->LstClientsNew, &pClient->NdLst);
     972            RTListAppend(&pThis->LstClientsNew, &pInst->NdLst);
    966973            RTCritSectLeave(&pThis->CritSectClients);
    967974
     
    974981        {
    975982            RTMsgError("Creating new client structure failed with out of memory error\n");
    976             pThis->pTransport->pfnNotifyBye(&pThis->TransportInst, pTransportClient);
     983            pThis->pTransport->pfnNotifyBye(pThis->pTransportInst, pTransportClient);
    977984        }
    978985    }
     
    982989
    983990/**
    984  * Initializes the global ATS state.
     991 * Creates an ATS instance.
    985992 *
    986993 * @returns VBox status code.
    987  * @param   pThis               The ATS instance.
    988  * @param   pszBindAddr         Bind address. Empty means any address.
    989  *                              If set to NULL, "127.0.0.1" will be used.
    990  * @param   uBindPort           Bind port. If set to 0, ATS_DEFAULT_PORT is being used.
    991  * @param   pCallbacks          The callbacks table to use.
    992  *  */
    993 int AudioTestSvcInit(PATSSERVER pThis,
    994                      const char *pszBindAddr, uint32_t uBindPort, PCATSCALLBACKS pCallbacks)
    995 {
    996     memcpy(&pThis->Callbacks, pCallbacks, sizeof(ATSCALLBACKS));
    997 
    998     pThis->fStarted   = false;
    999     pThis->fTerminate = false;
    1000 
    1001     pThis->hPipeR     = NIL_RTPIPE;
    1002     pThis->hPipeW     = NIL_RTPIPE;
    1003 
    1004     RTListInit(&pThis->LstClientsNew);
    1005 
     994 * @param   pThis               The ATS instance to create.
     995 */
     996int AudioTestSvcCreate(PATSSERVER pThis)
     997{
    1006998    /*
    1007999     * The default transporter is the first one.
    10081000     */
    1009     pThis->pTransport = g_apTransports[0];
     1001    pThis->pTransport = g_apTransports[0]; /** @todo Make this dynamic. */
     1002
     1003    return pThis->pTransport->pfnCreate(&pThis->pTransportInst);
     1004}
     1005
     1006/**
     1007 * Initializes an ATS instance.
     1008 *
     1009 * @returns VBox status code.
     1010 * @param   pThis               The ATS instance.
     1011 * @param   pCallbacks          The callbacks table to use.
     1012 */
     1013int AudioTestSvcInit(PATSSERVER pThis, PCATSCALLBACKS pCallbacks)
     1014{
     1015    memcpy(&pThis->Callbacks, pCallbacks, sizeof(ATSCALLBACKS));
     1016
     1017    pThis->fStarted   = false;
     1018    pThis->fTerminate = false;
     1019
     1020    pThis->hPipeR     = NIL_RTPIPE;
     1021    pThis->hPipeW     = NIL_RTPIPE;
     1022
     1023    RTListInit(&pThis->LstClientsNew);
    10101024
    10111025    /*
    10121026     * Initialize the transport layer.
    10131027     */
    1014     int rc = pThis->pTransport->pfnInit(&pThis->TransportInst, pszBindAddr ? pszBindAddr : ATS_TCP_HOST_DEFAULT_ADDR_STR,
    1015                                          uBindPort ? uBindPort : ATS_TCP_HOST_DEFAULT_PORT);
     1028    int rc = RTCritSectInit(&pThis->CritSectClients);
    10161029    if (RT_SUCCESS(rc))
    10171030    {
    1018         rc = RTCritSectInit(&pThis->CritSectClients);
     1031        rc = RTPollSetCreate(&pThis->hPollSet);
    10191032        if (RT_SUCCESS(rc))
    10201033        {
    1021             rc = RTPollSetCreate(&pThis->hPollSet);
     1034            rc = RTPipeCreate(&pThis->hPipeR, &pThis->hPipeW, 0);
    10221035            if (RT_SUCCESS(rc))
    10231036            {
    1024                 rc = RTPipeCreate(&pThis->hPipeR, &pThis->hPipeW, 0);
     1037                /* Spin off the thread serving connections. */
     1038                rc = RTThreadCreate(&pThis->hThreadServing, atsClientWorker, pThis, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
     1039                                    "AUDTSTSRVC");
    10251040                if (RT_SUCCESS(rc))
    1026                 {
    1027                     /* Spin off the thread serving connections. */
    1028                     rc = RTThreadCreate(&pThis->hThreadServing, atsClientWorker, pThis, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
    1029                                         "AUDTSTSRVC");
    1030                     if (RT_SUCCESS(rc))
    1031                         return VINF_SUCCESS;
    1032                     else
    1033                         RTMsgError("Creating the client worker thread failed with %Rrc\n", rc);
    1034 
    1035                     RTPipeClose(pThis->hPipeR);
    1036                     RTPipeClose(pThis->hPipeW);
    1037                 }
     1041                    return VINF_SUCCESS;
    10381042                else
    1039                     RTMsgError("Creating communications pipe failed with %Rrc\n", rc);
    1040 
    1041                 RTPollSetDestroy(pThis->hPollSet);
     1043                    RTMsgError("Creating the client worker thread failed with %Rrc\n", rc);
     1044
     1045                RTPipeClose(pThis->hPipeR);
     1046                RTPipeClose(pThis->hPipeW);
    10421047            }
    10431048            else
    1044                 RTMsgError("Creating pollset failed with %Rrc\n", rc);
    1045 
    1046             RTCritSectDelete(&pThis->CritSectClients);
     1049                RTMsgError("Creating communications pipe failed with %Rrc\n", rc);
     1050
     1051            RTPollSetDestroy(pThis->hPollSet);
    10471052        }
    10481053        else
    1049             RTMsgError("Creating global critical section failed with %Rrc\n", rc);
     1054            RTMsgError("Creating pollset failed with %Rrc\n", rc);
     1055
     1056        RTCritSectDelete(&pThis->CritSectClients);
    10501057    }
    10511058    else
    1052         RTMsgError("Initializing the transport layer failed with %Rrc\n", rc);
    1053 
    1054     return rc;
     1059        RTMsgError("Creating global critical section failed with %Rrc\n", rc);
     1060
     1061    return rc;
     1062}
     1063
     1064/**
     1065 * Handles a command line option.
     1066 *
     1067 * @returns VBox status code.
     1068 * @param   pThis               The ATS instance to handle option for.
     1069 * @param   ch                  Option (short) to handle.
     1070 * @param   pVal                Option union to store the result in on success.
     1071 */
     1072int AudioTestSvcHandleOption(PATSSERVER pThis, int ch, PCRTGETOPTUNION pVal)
     1073{
     1074    AssertPtrReturn(pThis->pTransport, VERR_WRONG_ORDER); /* Must be creatd first. */
     1075    if (!pThis->pTransport->pfnOption)
     1076        return VERR_GETOPT_UNKNOWN_OPTION;
     1077    return pThis->pTransport->pfnOption(pThis->pTransportInst, ch, pVal);
    10551078}
    10561079
     
    10591082 *
    10601083 * @returns VBox status code.
    1061  * @param   pThis               The ATS instance.
     1084 * @param   pThis               The ATS instance to start.
    10621085 */
    10631086int AudioTestSvcStart(PATSSERVER pThis)
    10641087{
    1065     /* Spin off the main thread. */
    1066     int rc = RTThreadCreate(&pThis->hThreadMain, atsMainThread, pThis, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
     1088    int rc = pThis->pTransport->pfnStart(pThis->pTransportInst);
     1089    if (RT_SUCCESS(rc))
     1090    {
     1091        /* Spin off the connection thread. */
     1092        rc = RTThreadCreate(&pThis->hThreadMain, atsConnectThread, pThis, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
    10671093                            "AUDTSTSRVM");
    1068     if (RT_SUCCESS(rc))
    1069     {
    1070         rc = RTThreadUserWait(pThis->hThreadMain, RT_MS_30SEC);
    10711094        if (RT_SUCCESS(rc))
    1072             pThis->fStarted = true;
     1095        {
     1096            rc = RTThreadUserWait(pThis->hThreadMain, RT_MS_30SEC);
     1097            if (RT_SUCCESS(rc))
     1098                pThis->fStarted = true;
     1099        }
    10731100    }
    10741101
     
    10901117
    10911118    if (pThis->pTransport)
    1092         pThis->pTransport->pfnTerm(&pThis->TransportInst);
     1119        pThis->pTransport->pfnTerm(pThis->pTransportInst);
    10931120
    10941121    size_t cbWritten;
     
    11491176    pThis->pTransport = NULL;
    11501177
    1151     PATSCLIENTINST pIt, pItNext;
     1178    PATSSERVERINST pIt, pItNext;
    11521179    RTListForEachSafe(&pThis->LstClientsNew, pIt, pItNext, ATSCLIENTINST, NdLst)
    11531180    {
     
    11751202int AudioTestSvcDestroy(PATSSERVER pThis)
    11761203{
    1177     return audioTestSvcDestroyInternal(pThis);
    1178 }
    1179 
     1204    int rc = audioTestSvcDestroyInternal(pThis);
     1205    if (RT_SUCCESS(rc))
     1206    {
     1207        if (pThis->pTransport)
     1208        {
     1209            if (   pThis->pTransport->pfnDestroy
     1210                && pThis->pTransportInst)
     1211            {
     1212                pThis->pTransport->pfnDestroy(pThis->pTransportInst);
     1213                pThis->pTransportInst = NULL;
     1214            }
     1215        }
     1216    }
     1217
     1218    return rc;
     1219}
  • trunk/src/VBox/Devices/Audio/AudioTestService.h

    r89614 r89962  
    2222#endif
    2323
     24#include <iprt/tcp.h>
     25
    2426#include "AudioTestServiceInternal.h"
    2527
     28extern const PCATSTRANSPORT g_apTransports[];
     29extern const size_t         g_cTransports;
    2630
    27 /** Default TCP/IP port the host ATS (Audio Test Service) is running on. */
    28 #define ATS_TCP_HOST_DEFAULT_PORT        6052
    29 /** Default TCP/IP address the host ATS (Audio Test Service) is running on. */
    30 #define ATS_TCP_HOST_DEFAULT_ADDR_STR    "127.0.0.1"
    31 /** Default TCP/IP port the guest ATS (Audio Test Service) is running on. */
    32 #define ATS_TCP_GUEST_DEFAULT_PORT       6042
     31/** Default TCP/IP bind port the guest ATS (Audio Test Service) is listening on. */
     32#define ATS_TCP_DEF_BIND_PORT_GUEST       6052
     33/** Default TCP/IP bind port the host ATS is listening on. */
     34#define ATS_TCP_DEF_BIND_PORT_HOST        6042
     35/** Default TCP/IP ATS bind port the ValidationKit Audio Driver ATS is listening on. */
     36#define ATS_TCP_DEF_BIND_PORT_VALKIT      6052
     37/** Default TCP/IP port the guest ATS is connecting to. */
     38#define ATS_TCP_DEF_CONNECT_PORT_GUEST    ATS_TCP_DEF_BIND_PORT_HOST
     39/** Default TCP/IP port the host ATS is connecting to the guest (needs NAT port forwarding). */
     40#define ATS_TCP_DEF_CONNECT_PORT_HOST_PORT_FWD     6062
     41/** Default TCP/IP port the host ATS is connecting to. */
     42#define ATS_TCP_DEF_CONNECT_PORT_VALKIT   ATS_TCP_DEF_BIND_PORT_VALKIT
     43/** Default TCP/IP address the host is connecting to. */
     44#define ATS_TCP_DEF_CONNECT_HOST_ADDR_STR "127.0.0.1"
     45/** Default TCP/IP address the guest ATS connects to when
     46 *  running in client mode (reversed mode, needed for NATed VMs). */
     47#define ATS_TCP_DEF_CONNECT_GUEST_STR     "10.0.2.2"
    3348
    3449/**
     
    110125
    111126/**
    112  * Structure for keeping Audio Test Service (ATS) transport instance-specific data.
    113  *
    114  * Currently only TCP/IP is supported.
    115  */
    116 typedef struct ATSTRANSPORTINST
    117 {
    118     /** The addresses to bind to.  Empty string means any. */
    119     char                 szTcpBindAddr[256];
    120     /** The TCP port to listen to. */
    121     uint32_t             uTcpBindPort;
    122     /** Pointer to the TCP server instance. */
    123     PRTTCPSERVER         pTcpServer;
    124 } ATSTRANSPORTINST;
    125 /** Pointer to an Audio Test Service (ATS) TCP/IP transport instance. */
    126 typedef ATSTRANSPORTINST *PATSTRANSPORTINSTTCP;
    127 
    128 /**
    129127 * Structure for keeping an Audio Test Service (ATS) instance.
    130128 */
    131129typedef struct ATSSERVER
    132130{
    133     /** The selected transport layer. */
     131    /** Pointer to the selected transport layer. */
    134132    PCATSTRANSPORT       pTransport;
    135     /** The transport instance. */
    136     ATSTRANSPORTINST     TransportInst;
     133    /** Pointer to the transport instance. */
     134    PATSTRANSPORTINST    pTransportInst;
    137135    /** The callbacks table. */
    138136    ATSCALLBACKS         Callbacks;
     
    159157typedef ATSSERVER *PATSSERVER;
    160158
    161 int AudioTestSvcInit(PATSSERVER pThis, const char *pszBindAddr, uint32_t uBindPort, PCATSCALLBACKS pCallbacks);
     159int AudioTestSvcCreate(PATSSERVER pThis);
     160int AudioTestSvcInit(PATSSERVER pThis, PCATSCALLBACKS pCallbacks);
    162161int AudioTestSvcDestroy(PATSSERVER pThis);
     162int AudioTestSvcHandleOption(PATSSERVER pThis, int ch, PCRTGETOPTUNION pVal);
    163163int AudioTestSvcStart(PATSSERVER pThis);
    164164int AudioTestSvcShutdown(PATSSERVER pThis);
    165165
     166/** TCP/IP options for the ATS server.
     167 *  @todo Make this more abstract later. */
     168enum ATSTCPOPT
     169{
     170    ATSTCPOPT_MODE = 5000,
     171    ATSTCPOPT_BIND_ADDRESS,
     172    ATSTCPOPT_BIND_PORT,
     173    ATSTCPOPT_CONNECT_ADDRESS,
     174    ATSTCPOPT_CONNECT_PORT
     175};
     176
    166177#endif /* !VBOX_INCLUDED_SRC_Audio_AudioTestService_h */
    167178
  • trunk/src/VBox/Devices/Audio/AudioTestServiceClient.cpp

    r89807 r89962  
    2222*   Header Files                                                                                                                 *
    2323*********************************************************************************************************************************/
    24 #define LOG_GROUP RTLOGGROUP_DEFAULT
    25 #include <VBox/log.h>
     24#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO /** @todo Add an own log group for this? */
    2625
    2726#include <iprt/crc.h>
     
    3231#include <iprt/tcp.h>
    3332
     33#include <VBox/log.h>
     34
    3435#include "AudioTestService.h"
    35 #include "AudioTestServiceProtocol.h"
     36#include "AudioTestServiceInternal.h"
    3637#include "AudioTestServiceClient.h"
    3738
     
    4546{
    4647    char   szOp[ATSPKT_OPCODE_MAX_LEN];
     48    /** Pointer to payload data.
     49     *  This does *not* include the header! */
    4750    void  *pvPayload;
     51    /** Size (in bytes) of the payload data.
     52     *  This does *not* include the header! */
    4853    size_t cbPayload;
    4954} ATSSRVREPLY;
     
    5964static void audioTestSvcClientInit(PATSCLIENT pClient)
    6065{
    61     pClient->cbHdr = 0;
    62     pClient->hSock = NIL_RTSOCKET;
     66    RT_BZERO(pClient, sizeof(ATSCLIENT));
    6367}
    6468
     
    9498static int audioTestSvcClientRecvReply(PATSCLIENT pClient, PATSSRVREPLY pReply, bool fNoDataOk)
    9599{
    96     int rc;
    97 
    98100    LogFlowFuncEnter();
    99101
    100     ATSPKTHDR Hdr;
    101     RT_ZERO(Hdr);
    102     size_t    cbHdr = 0;
    103     if (pClient->cbHdr) /* Header already received? */
     102    PATSPKTHDR pPktHdr;
     103    int rc = pClient->pTransport->pfnRecvPkt(pClient->pTransportInst, pClient->pTransportClient, &pPktHdr);
     104    if (RT_SUCCESS(rc))
    104105    {
    105         memcpy(&Hdr, &pClient->abHdr, sizeof(Hdr));
    106         cbHdr = pClient->cbHdr;
    107         pClient->cbHdr = 0;
    108         rc = VINF_SUCCESS;
    109     }
    110     else /* No, receive header. */
    111     {
    112         rc = RTTcpRead(pClient->hSock, &Hdr, sizeof(Hdr), &cbHdr);
    113     }
    114 
    115     LogFlowFunc(("rc=%Rrc, hdr=%zu, hdr.cb=%zu, %.8s -> %.*Rhxd\n", rc, cbHdr, Hdr.cb, Hdr.achOpcode, RT_MIN(cbHdr, sizeof(ATSPKTHDR)), &Hdr));
    116 
    117     if (RT_FAILURE(rc))
    118         return rc;
    119 
    120     if (cbHdr != sizeof(Hdr)) /* Check for bad packet sizes. */
    121     {
    122         AssertMsgFailed(("Packet is invalid (%RU32 bytes), must be at least %zu bytes\n", cbHdr, sizeof(Hdr)));
    123         return VERR_NET_INCOMPLETE_TX_PACKET;
    124     }
    125 
    126     if (Hdr.cb < sizeof(ATSPKTHDR))
    127     {
    128         AssertMsgFailed(("Packet is too small (%RU32 bytes), must be at least %zu bytes\n", Hdr.cb, sizeof(Hdr)));
    129         return VERR_NET_INCOMPLETE_TX_PACKET;
    130     }
    131 
    132     if (Hdr.cb > ATSPKT_MAX_SIZE)
    133     {
    134         AssertMsgFailed(("Packet is %RU32 bytes, only %zu bytes allowed\n", Hdr.cb, ATSPKT_MAX_SIZE));
    135         return VERR_BUFFER_OVERFLOW;
    136     }
    137 
    138     if (Hdr.cb > ATSPKT_MAX_SIZE)
    139     {
    140         AssertMsgFailed(("Packet is %RU32 bytes, only %zu bytes allowed\n", Hdr.cb, ATSPKT_MAX_SIZE));
    141         return VERR_BUFFER_OVERFLOW;
    142     }
    143 
    144     pReply->cbPayload = Hdr.cb - sizeof(ATSPKTHDR);
    145     Log3Func(("cbHdr=%zu, Hdr.szOp=%s, Hdr.cb=%RU32 -> %zu bytes payload\n", cbHdr, Hdr.achOpcode, Hdr.cb, pReply->cbPayload));
    146     if (pReply->cbPayload)
    147     {
    148         pReply->pvPayload = RTMemAlloc(pReply->cbPayload);
    149         if (pReply->pvPayload)
     106        AssertReturn(pPktHdr->cb >= sizeof(ATSPKTHDR), VERR_NET_PROTOCOL_ERROR);
     107        pReply->cbPayload = pPktHdr->cb - sizeof(ATSPKTHDR);
     108        Log3Func(("szOp=%.8s, cb=%RU32\n", pPktHdr->achOpcode, pPktHdr->cb));
     109        if (pReply->cbPayload)
    150110        {
    151             uint32_t cbPayloadRead = 0;
    152             while (cbPayloadRead < pReply->cbPayload)
    153             {
    154                 size_t cbRead = 0;
    155                 rc = RTTcpRead(pClient->hSock, (uint8_t *)pReply->pvPayload + cbPayloadRead, pReply->cbPayload - cbPayloadRead, &cbRead);
    156                 if (RT_SUCCESS(rc))
    157                 {
    158                     if (!cbRead)
    159                     {
    160                         memcpy(&pClient->abHdr, &Hdr, sizeof(pClient->abHdr));
    161                         if (!fNoDataOk)
    162                             rc = VERR_NET_PROTOCOL_ERROR;
    163                     }
    164 
    165                     cbPayloadRead += (uint32_t)cbRead;
    166                     Assert(cbPayloadRead <= pReply->cbPayload);
    167                 }
    168             }
    169 
    170             if (RT_SUCCESS(rc))
    171             {
    172                 Assert(cbPayloadRead == pReply->cbPayload);
    173                 if (Hdr.uCrc32) /* Checksum given? */
    174                 {
    175                     uint32_t uMyCrc32 = RTCrc32Start();
    176                              uMyCrc32 = RTCrc32Process(uMyCrc32, Hdr.achOpcode, sizeof(Hdr.achOpcode));
    177                              uMyCrc32 = RTCrc32Process(uMyCrc32, pReply->pvPayload, pReply->cbPayload);
    178 
    179                     if (Hdr.uCrc32 != RTCrc32Finish(uMyCrc32))
    180                         AssertFailedStmt(rc = VERR_TAR_CHKSUM_MISMATCH /** @todo Fudge! */);
    181 
    182                     if (RT_SUCCESS(rc))
    183                     {
    184                         /* Make sure to align the payload data (if not done by the sender already). */
    185                         size_t const cbRestAlignment = RT_ALIGN_Z(pReply->cbPayload, ATSPKT_ALIGNMENT) - pReply->cbPayload;
    186                         if (cbRestAlignment)
    187                         {
    188                             uint8_t abAlignment[ATSPKT_ALIGNMENT];
    189                             rc = RTTcpRead(pClient->hSock, abAlignment, RT_MIN(cbRestAlignment, sizeof(abAlignment)), NULL);
    190                         }
    191                     }
    192                 }
    193             }
    194 
    195             if (RT_FAILURE(rc))
    196                 audioTestSvcClientReplyDestroy(pReply);
     111            pReply->pvPayload = RTMemDup((uint8_t *)pPktHdr + sizeof(ATSPKTHDR), pReply->cbPayload);
    197112        }
    198113        else
    199             rc = VERR_NO_MEMORY;
     114            pReply->pvPayload = NULL;
     115
     116        if (   !pReply->cbPayload
     117            && !fNoDataOk)
     118        {
     119            rc = VERR_NET_PROTOCOL_ERROR;
     120        }
     121        else
     122        {
     123            memcpy(&pReply->szOp, &pPktHdr->achOpcode, sizeof(pReply->szOp));
     124        }
     125
     126        RTMemFree(pPktHdr);
     127        pPktHdr = NULL;
    200128    }
    201 
    202     if (RT_SUCCESS(rc))
    203         memcpy(pReply->szOp, Hdr.achOpcode, sizeof(pReply->szOp));
    204129
    205130    LogFlowFuncLeaveRC(rc);
     
    232157
    233158/**
    234  * Sends data over the transport to the server.
    235  * For now only TCP/IP is implemented.
    236  *
    237  * @returns VBox status code.
    238  * @param   pClient             Client to send data for.
    239  * @param   pvData              Pointer to data to send.
    240  * @param   cbData              Size (in bytes) of \a pvData to send.
    241  */
    242 static int audioTestSvcClientSend(PATSCLIENT pClient, const void *pvData, size_t cbData)
    243 {
    244     return RTTcpWrite(pClient->hSock, pvData, cbData);
    245 }
    246 
    247 /**
    248159 * Sends a message plus optional payload to an ATS server.
    249160 *
     
    252163 * @param   pvHdr               Pointer to header data to send.
    253164 * @param   cbHdr               Size (in bytes) of \a pvHdr to send.
    254  * @param   pvPayload           Pointer to payload to send. Optional.
    255  * @param   cbPayload           Size (in bytes) of \a pvPayload to send. Set to 0 if no payload needed.
    256  */
    257 static int audioTestSvcClientSendMsg(PATSCLIENT pClient,
    258                                      void *pvHdr, size_t cbHdr, const void *pvPayload, size_t cbPayload)
    259 {
    260     int rc = audioTestSvcClientSend(pClient, pvHdr, cbHdr);
    261     if (   RT_SUCCESS(rc)
    262         && cbPayload)
    263     {
    264         rc = audioTestSvcClientSend(pClient, (uint8_t *)pvPayload, cbPayload);
    265     }
    266 
    267     return rc;
     165 */
     166static int audioTestSvcClientSendMsg(PATSCLIENT pClient, void *pvHdr, size_t cbHdr)
     167{
     168    RT_NOREF(cbHdr);
     169    AssertPtrReturn(pClient->pTransport,       VERR_WRONG_ORDER);
     170    AssertPtrReturn(pClient->pTransportInst,   VERR_WRONG_ORDER);
     171    AssertPtrReturn(pClient->pTransportClient, VERR_NET_NOT_CONNECTED);
     172    return pClient->pTransport->pfnSendPkt(pClient->pTransportInst, pClient->pTransportClient, (PCATSPKTHDR)pvHdr);
    268173}
    269174
     
    304209    audioTestSvcClientReqHdrInit(&Req, sizeof(Req), "ACK     ", 0);
    305210
    306     return audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
     211    return audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req));
    307212}
    308213
     
    318223    Req.uVersion = ATS_PROTOCOL_VS;
    319224    audioTestSvcClientReqHdrInit(&Req.Hdr, sizeof(Req), ATSPKT_OPCODE_HOWDY, 0);
    320     int rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
     225    int rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req));
    321226    if (RT_SUCCESS(rc))
    322227        rc = audioTestSvcClientRecvAck(pClient);
     
    325230
    326231/**
    327  * Sends a disconnect command to an ATS server.
    328  *
    329  * @returns VBox status code.
    330  * @param   pClient             Client to send command for.
    331  */
    332 static int audioTestSvcClientDoBye(PATSCLIENT pClient)
    333 {
    334     ATSPKTHDR Hdr;
    335     audioTestSvcClientReqHdrInit(&Hdr, sizeof(Hdr), ATSPKT_OPCODE_BYE, 0);
    336     int rc = audioTestSvcClientSendMsg(pClient, &Hdr, sizeof(Hdr), NULL, 0);
    337     if (RT_SUCCESS(rc))
    338         rc = audioTestSvcClientRecvAck(pClient);
    339 
    340     return rc;
    341 }
    342 
    343 /**
    344  * Connects to an ATS server.
     232 * Creates an ATS client.
     233 *
     234 * @returns VBox status code.
     235 * @param   pClient             Client to create.
     236 */
     237int AudioTestSvcClientCreate(PATSCLIENT pClient)
     238{
     239    audioTestSvcClientInit(pClient);
     240
     241    /*
     242     * The default transporter is the first one.
     243     */
     244    pClient->pTransport = g_apTransports[0]; /** @todo Make this dynamic. */
     245
     246    return pClient->pTransport->pfnCreate(&pClient->pTransportInst);
     247}
     248
     249/**
     250 * Destroys an ATS client.
     251 *
     252 * @returns VBox status code.
     253 * @param   pClient             Client to destroy.
     254 */
     255void AudioTestSvcClientDestroy(PATSCLIENT pClient)
     256{
     257    if (pClient->pTransport)
     258        pClient->pTransport->pfnTerm(pClient->pTransportInst);
     259}
     260
     261/**
     262 * Handles a command line option.
     263 *
     264 * @returns VBox status code.
     265 * @param   pClient             Client to handle option for.
     266 * @param   ch                  Option (short) to handle.
     267 * @param   pVal                Option union to store the result in on success.
     268 */
     269int AudioTestSvcClientHandleOption(PATSCLIENT pClient, int ch, PCRTGETOPTUNION pVal)
     270{
     271    AssertPtrReturn(pClient->pTransport, VERR_WRONG_ORDER); /* Must be created first via AudioTestSvcClientCreate(). */
     272    if (!pClient->pTransport->pfnOption)
     273        return VERR_GETOPT_UNKNOWN_OPTION;
     274    return pClient->pTransport->pfnOption(pClient->pTransportInst, ch, pVal);
     275}
     276
     277/**
     278 * Connects to an ATS peer.
    345279 *
    346280 * @returns VBox status code.
    347281 * @param   pClient             Client to connect.
    348  * @param   pszAddr             Address to connect to. If NULL, 127.0.0.1 (localhost) will be used.
    349  * @param   uPort               Port to connect. If set to 0, port 6052 (ATS_DEFAULT_PORT) will be used.
    350  */
    351 int AudioTestSvcClientConnect(PATSCLIENT pClient, const char *pszAddr, uint32_t uPort)
    352 {
    353     audioTestSvcClientInit(pClient);
    354 
    355     int rc = RTTcpClientConnect(pszAddr ? pszAddr : ATS_TCP_HOST_DEFAULT_ADDR_STR, uPort == 0 ? ATS_TCP_HOST_DEFAULT_PORT : uPort, &pClient->hSock);
     282 */
     283int AudioTestSvcClientConnect(PATSCLIENT pClient)
     284{
     285    int rc = pClient->pTransport->pfnStart(pClient->pTransportInst);
    356286    if (RT_SUCCESS(rc))
    357287    {
    358         rc = audioTestSvcClientDoGreet(pClient);
     288        rc = pClient->pTransport->pfnWaitForConnect(pClient->pTransportInst, &pClient->pTransportClient);
     289        if (RT_SUCCESS(rc))
     290        {
     291            rc = audioTestSvcClientDoGreet(pClient);
     292        }
    359293    }
    360294
     
    378312    audioTestSvcClientReqHdrInit(&Req.Hdr, sizeof(Req), ATSPKT_OPCODE_TESTSET_BEGIN, 0);
    379313
    380     rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
     314    rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req));
    381315    if (RT_SUCCESS(rc))
    382316        rc = audioTestSvcClientRecvAck(pClient);
     
    401335    audioTestSvcClientReqHdrInit(&Req.Hdr, sizeof(Req), ATSPKT_OPCODE_TESTSET_END, 0);
    402336
    403     rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
     337    rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req));
    404338    if (RT_SUCCESS(rc))
    405339        rc = audioTestSvcClientRecvAck(pClient);
     
    424358    audioTestSvcClientReqHdrInit(&Req.Hdr, sizeof(Req), ATSPKT_OPCODE_TONE_PLAY, 0);
    425359
    426     int rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
     360    int rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req));
    427361    if (RT_SUCCESS(rc))
    428362        rc = audioTestSvcClientRecvAck(pClient);
     
    447381    audioTestSvcClientReqHdrInit(&Req.Hdr, sizeof(Req), ATSPKT_OPCODE_TONE_RECORD, 0);
    448382
    449     int rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
     383    int rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req));
    450384    if (RT_SUCCESS(rc))
    451385        rc = audioTestSvcClientRecvAck(pClient);
     
    476410    AssertRCReturn(rc, rc);
    477411
    478     rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
     412    rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req));
    479413    while (RT_SUCCESS(rc))
    480414    {
    481415        ATSSRVREPLY Reply;
    482416        RT_ZERO(Reply);
     417
    483418        rc = audioTestSvcClientRecvReply(pClient, &Reply, false /* fNoDataOk */);
    484419        if (RT_SUCCESS(rc))
    485420        {
    486             /* Calculate and validate checksum. */
    487             uint32_t uDataCrc32;
    488             memcpy(&uDataCrc32, Reply.pvPayload, sizeof(uint32_t));
    489 
    490             if (   uDataCrc32
    491                 && uDataCrc32 != RTCrc32((uint8_t *)Reply.pvPayload + 4, Reply.cbPayload - 4))
    492                 rc = VERR_TAR_CHKSUM_MISMATCH; /** @todo Fudge! */
     421            /* Extract received CRC32 checksum. */
     422            const size_t cbCrc32 = sizeof(uint32_t); /* Skip CRC32 in payload for actual CRC verification. */
     423
     424            uint32_t uSrcCrc32;
     425            memcpy(&uSrcCrc32, Reply.pvPayload, cbCrc32);
     426
     427            if (uSrcCrc32)
     428            {
     429                const uint32_t uDstCrc32 = RTCrc32((uint8_t *)Reply.pvPayload + cbCrc32, Reply.cbPayload - cbCrc32);
     430
     431                Log2Func(("uSrcCrc32=%#x, cbRead=%zu -> uDstCrc32=%#x\n"
     432                          "%.*Rhxd\n",
     433                          uSrcCrc32, Reply.cbPayload - cbCrc32, uDstCrc32,
     434                          RT_MIN(64, Reply.cbPayload - cbCrc32), (uint8_t *)Reply.pvPayload + cbCrc32));
     435
     436                if (uSrcCrc32 != uDstCrc32)
     437                    rc = VERR_TAR_CHKSUM_MISMATCH; /** @todo Fudge! */
     438            }
    493439
    494440            if (RT_SUCCESS(rc))
     
    498444                    && Reply.cbPayload)
    499445                {
    500                     rc = RTFileWrite(hFile, (uint8_t *)Reply.pvPayload + 4, Reply.cbPayload - 4, NULL);
     446                    rc = RTFileWrite(hFile, (uint8_t *)Reply.pvPayload + cbCrc32, Reply.cbPayload - cbCrc32, NULL);
    501447                }
    502448                else if (RTStrNCmp(Reply.szOp, "DATA EOF", ATSPKT_OPCODE_MAX_LEN) == 0)
     
    537483int AudioTestSvcClientClose(PATSCLIENT pClient)
    538484{
    539     int rc = audioTestSvcClientDoBye(pClient);
    540     if (RT_SUCCESS(rc))
    541         rc = RTTcpClientClose(pClient->hSock);
    542 
    543     return rc;
    544 }
    545 
     485    pClient->pTransport->pfnNotifyBye(pClient->pTransportInst, pClient->pTransportClient);
     486
     487    return VINF_SUCCESS;
     488}
     489
  • trunk/src/VBox/Devices/Audio/AudioTestServiceClient.h

    r89614 r89962  
    2222#endif
    2323
     24#include "AudioTestServiceInternal.h"
     25
     26/**
     27 * Structure for maintaining an ATS client.
     28 */
    2429typedef struct ATSCLIENT
    2530{
    26     uint8_t  abHdr[16];
    27     uint16_t cbHdr;
    28     RTSOCKET hSock;
     31    /** Pointer to the selected transport layer. */
     32    PCATSTRANSPORT      pTransport;
     33    /** Pointer to the selected transport instance to use. */
     34    PATSTRANSPORTINST   pTransportInst;
     35    /** The opaque client instance. */
     36    PATSTRANSPORTCLIENT pTransportClient;
    2937} ATSCLIENT;
     38/** Pointer to an ATS client. */
    3039typedef ATSCLIENT *PATSCLIENT;
    3140
    32 int AudioTestSvcClientConnect(PATSCLIENT pClient, const char *pszAddr, uint32_t uPort);
     41int AudioTestSvcClientCreate(PATSCLIENT pClient);
     42void AudioTestSvcClientDestroy(PATSCLIENT pClient);
     43int AudioTestSvcClientConnect(PATSCLIENT pClient);
     44int AudioTestSvcClientHandleOption(PATSCLIENT pClient, int ch, PCRTGETOPTUNION pVal);
    3345int AudioTestSvcClientTestSetBegin(PATSCLIENT pClient, const char *pszTag);
    3446int AudioTestSvcClientTestSetEnd(PATSCLIENT pClient, const char *pszTag);
  • trunk/src/VBox/Devices/Audio/AudioTestServiceInternal.h

    r89541 r89962  
    4646    /** The description. */
    4747    const char     *pszDesc;
    48 
    49     /**
    50      * Initializes the transport layer.
     48    /** Pointer to an array of options. */
     49    PCRTGETOPTDEF   paOpts;
     50    /** The number of options in the array. */
     51    size_t          cOpts;
     52
     53    /**
     54     * Print the usage information for this transport layer.
     55     *
     56     * @param   pStream             The stream to print the usage info to.
     57     *
     58     * @remarks This is only required if TXSTRANSPORT::cOpts is greater than 0.
     59     */
     60    DECLR3CALLBACKMEMBER(void, pfnUsage,(PRTSTREAM pStream));
     61
     62    /**
     63     * Creates a transport instance.
    5164     *
    5265     * @returns IPRT status code.  On errors, the transport layer shall call
    5366     *          RTMsgError to display the error details to the user.
    54      * @param   pThis               The transport instance.
    55      * @param   pszBindAddr         Bind address. Empty means any address.
    56      * @param   uBindPort           Bind port. If set to 0, ATS_DEFAULT_PORT is being used.
    57      */
    58     DECLR3CALLBACKMEMBER(int, pfnInit, (PATSTRANSPORTINST pThis, const char *pszBindAddr, uint32_t uBindPort));
    59 
    60     /**
    61      * Terminate the transport layer, closing and freeing resources.
     67     * @param   ppThis              Where to return the created transport instance on success.
     68     */
     69    DECLR3CALLBACKMEMBER(int, pfnCreate, (PPATSTRANSPORTINST ppThis));
     70
     71    /**
     72     * Destroys a transport instance.
     73     *
     74     * On errors, the transport layer shall call RTMsgError to display the error
     75     * details to the user.
     76     *
     77     * @returns IPRT status code.  On errors, the transport layer shall call
     78     *          RTMsgError to display the error details to the user.
     79     * @param   pThis               The transport instance.
     80     *                              The pointer will be invalid on return.
     81     */
     82    DECLR3CALLBACKMEMBER(int, pfnDestroy, (PATSTRANSPORTINST pThis));
     83
     84    /**
     85     * Handle an option.
     86     *
     87     * When encountering an options that is not part of the base options, we'll call
     88     * this method for each transport layer until one handles it.
     89     *
     90     * @retval  VINF_SUCCESS if handled.
     91     * @retval  VERR_TRY_AGAIN if not handled.
     92     * @retval  VERR_INVALID_PARAMETER if we should exit with a non-zero status.
     93     *
     94     * @param   pThis               Transport instance to set options for.
     95     * @param   ch                  The short option value.
     96     * @param   pVal                Pointer to the value union.
     97     *
     98     * @remarks This is only required if TXSTRANSPORT::cOpts is greater than 0.
     99     */
     100    DECLR3CALLBACKMEMBER(int, pfnOption,(PATSTRANSPORTINST pThis, int ch, PCRTGETOPTUNION pVal));
     101
     102    /**
     103     * Starts a transport instance.
     104     *
     105     * @returns IPRT status code.  On errors, the transport layer shall call
     106     *          RTMsgError to display the error details to the user.
     107     * @param   pThis               Transport instance to initialize.
     108     */
     109    DECLR3CALLBACKMEMBER(int, pfnStart, (PATSTRANSPORTINST pThis));
     110
     111    /**
     112     * Terminate a transport instance, closing and freeing resources.
    62113     *
    63114     * On errors, the transport layer shall call RTMsgError to display the error
  • 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,
  • trunk/src/VBox/Devices/Audio/DrvHostAudioValidationKit.cpp

    r89890 r89962  
    10241024
    10251025    /** @todo Make this configurable via CFGM. */
    1026     const char *pszTcpAddr = ATS_TCP_HOST_DEFAULT_ADDR_STR;
    1027        uint32_t uTcpPort   = ATS_TCP_HOST_DEFAULT_PORT;
     1026    const char *pszTcpAddr = "127.0.0.1"; /* Only reachable for localhost for now. */
     1027    uint32_t    uTcpPort   = ATS_TCP_DEF_BIND_PORT_VALKIT;
    10281028
    10291029    LogRel(("ValKit: Starting Audio Test Service (ATS) at %s:%RU32...\n",
    10301030            pszTcpAddr, uTcpPort));
    10311031
    1032     rc = AudioTestSvcInit(&pThis->Srv,
    1033                           /* We only allow connections from localhost for now. */
    1034                           pszTcpAddr, uTcpPort, &Callbacks);
    1035     if (RT_SUCCESS(rc))
    1036         rc = AudioTestSvcStart(&pThis->Srv);
     1032    rc = AudioTestSvcCreate(&pThis->Srv);
     1033    if (RT_SUCCESS(rc))
     1034    {
     1035        RTGETOPTUNION Val;
     1036        RT_ZERO(Val);
     1037
     1038        Val.psz = "server"; /** @ŧodo No client connection mode needed here (yet). Make this configurable via CFGM. */
     1039        rc = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_MODE, &Val);
     1040        AssertRC(rc);
     1041
     1042        Val.psz = pszTcpAddr;
     1043        rc = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_BIND_ADDRESS, &Val);
     1044        AssertRC(rc);
     1045
     1046        Val.u16 = uTcpPort;
     1047        rc = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_BIND_PORT, &Val);
     1048        AssertRC(rc);
     1049
     1050        rc = AudioTestSvcInit(&pThis->Srv, &Callbacks);
     1051        if (RT_SUCCESS(rc))
     1052            rc = AudioTestSvcStart(&pThis->Srv);
     1053    }
    10371054
    10381055    if (RT_SUCCESS(rc))
  • trunk/src/VBox/Devices/Audio/testcase/tstAudioTestService.cpp

    r89805 r89962  
    7676
    7777    ATSSERVER Srv;
    78     rc = AudioTestSvcInit(&Srv, "127.0.0.1", ATS_TCP_HOST_DEFAULT_PORT, &Callbacks);
     78    rc = AudioTestSvcCreate(&Srv);
    7979    RTTEST_CHECK_RC_OK(hTest, rc);
    8080    if (RT_SUCCESS(rc))
    8181    {
    82         rc = AudioTestSvcStart(&Srv);
     82        rc = AudioTestSvcInit(&Srv, &Callbacks);
    8383        RTTEST_CHECK_RC_OK(hTest, rc);
    8484        if (RT_SUCCESS(rc))
    8585        {
    86             rc = AudioTestSvcClientConnect(&Client, "127.0.0.1", ATS_TCP_HOST_DEFAULT_PORT);
     86            rc = AudioTestSvcStart(&Srv);
    8787            RTTEST_CHECK_RC_OK(hTest, rc);
     88            if (RT_SUCCESS(rc))
     89            {
     90                RTGETOPTUNION Val;
     91                RT_ZERO(Val);
     92
     93                Val.psz = ATS_TCP_DEF_CONNECT_HOST_ADDR_STR;
     94                rc = AudioTestSvcClientHandleOption(&Client, ATSTCPOPT_CONNECT_ADDRESS, &Val);
     95                AssertRC(rc);
     96
     97                Val.u16 = ATS_TCP_DEF_CONNECT_PORT_HOST_PORT_FWD;
     98                rc = AudioTestSvcClientHandleOption(&Client, ATSTCPOPT_CONNECT_PORT, &Val);
     99                AssertRC(rc);
     100
     101                rc = AudioTestSvcClientConnect(&Client);
     102                RTTEST_CHECK_RC_OK(hTest, rc);
     103            }
    88104        }
    89105    }
  • trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp

    r89891 r89962  
    635635    RT_ZERO(TstEnv);
    636636
     637    int rc = AudioTestSvcCreate(&TstEnv.u.Guest.Srv);
     638
    637639    const char *pszDevice     = NULL; /* Custom device to use. Can be NULL if not being used. */
    638640    const char *pszTag        = NULL; /* Custom tag to use. Can be NULL if not being used. */
     
    645647
    646648    const char *pszGuestTcpAddr  = NULL;
    647     uint16_t    uGuestTcpPort    = ATS_TCP_GUEST_DEFAULT_PORT;
     649    uint16_t    uGuestTcpPort    = ATS_TCP_DEF_BIND_PORT_GUEST;
    648650    const char *pszValKitTcpAddr = NULL;
    649     uint16_t    uValKitTcpPort   = ATS_TCP_HOST_DEFAULT_PORT;
    650 
    651     int           rc;
     651    uint16_t    uValKitTcpPort   = ATS_TCP_DEF_BIND_PORT_VALKIT;
     652
     653    int           ch;
    652654    RTGETOPTUNION ValueUnion;
    653     while ((rc = RTGetOpt(pGetState, &ValueUnion)))
    654     {
    655         switch (rc)
     655    while ((ch = RTGetOpt(pGetState, &ValueUnion)))
     656    {
     657        switch (ch)
    656658        {
    657659            case 'a':
     
    757759
    758760            default:
    759                 return RTGetOptPrintError(rc, &ValueUnion);
     761                rc = AudioTestSvcHandleOption(&TstEnv.u.Guest.Srv, ch, &ValueUnion);
     762                if (RT_FAILURE(rc))
     763                    return RTGetOptPrintError(rc, &ValueUnion);
    760764        }
    761765    }
     
    774778        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No test mode (--mode) specified!\n");
    775779
    776     if (TstEnv.enmMode == AUDIOTESTMODE_HOST)
    777     {
    778         if (!pszGuestTcpAddr)
    779             return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No guest ATS address (--guest-ats-addr) specified!\n");
    780     }
    781 
    782780    /* For now all tests have the same test environment. */
    783     rc = audioTestEnvInit(&TstEnv, pDrvReg, fWithDrvAudio,
    784                           pszValKitTcpAddr, uValKitTcpPort,
    785                           pszGuestTcpAddr, uGuestTcpPort);
     781    rc = audioTestEnvInit(&TstEnv, pDrvReg, fWithDrvAudio);
    786782    if (RT_SUCCESS(rc))
    787783        rc = audioTestWorker(&TstEnv);
     
    806802    g_aCmdTestOptions,
    807803    RT_ELEMENTS(g_aCmdTestOptions),
    808     audioTestCmdTestHelp
     804    audioTestCmdTestHelp,
     805    true /* fNeedsTransport */
    809806};
    810807
     
    985982    RT_ELEMENTS(g_aCmdVerifyOptions),
    986983    NULL,
     984    false /* fNeedsTransport */
    987985};
    988986
     
    10671065                RTStrmPrintf(pStrm, "    %s\n", pszHelp);
    10681066        }
     1067
     1068        if (pCmd->fNeedsTransport)
     1069        {
     1070            for (uintptr_t iTx = 0; iTx < g_cTransports; iTx++)
     1071                g_apTransports[iTx]->pfnUsage(pStrm);
     1072        }
    10691073    }
    10701074
     
    11551159                    if (strcmp(ValueUnion.psz, pCmd->pszCommand) == 0)
    11561160                    {
    1157                         size_t const cCombinedOptions  = pCmd->cOptions + RT_ELEMENTS(g_aCmdCommonOptions);
     1161                        size_t cCombinedOptions  = pCmd->cOptions + RT_ELEMENTS(g_aCmdCommonOptions);
     1162                        if (pCmd->fNeedsTransport)
     1163                        {
     1164                            for (uintptr_t iTx = 0; iTx < g_cTransports; iTx++)
     1165                                cCombinedOptions += g_apTransports[iTx]->cOpts;
     1166                        }
    11581167                        PRTGETOPTDEF paCombinedOptions = (PRTGETOPTDEF)RTMemAlloc(cCombinedOptions * sizeof(RTGETOPTDEF));
    11591168                        if (paCombinedOptions)
    11601169                        {
     1170                            unsigned idxOpts = 0;
    11611171                            memcpy(paCombinedOptions, g_aCmdCommonOptions, sizeof(g_aCmdCommonOptions));
    1162                             memcpy(&paCombinedOptions[RT_ELEMENTS(g_aCmdCommonOptions)],
    1163                                    pCmd->paOptions, pCmd->cOptions * sizeof(RTGETOPTDEF));
     1172                            idxOpts += RT_ELEMENTS(g_aCmdCommonOptions);
     1173                            memcpy(&paCombinedOptions[idxOpts], pCmd->paOptions, pCmd->cOptions * sizeof(RTGETOPTDEF));
     1174                            idxOpts += pCmd->cOptions;
     1175                            if (pCmd->fNeedsTransport)
     1176                            {
     1177                                for (uintptr_t iTx = 0; iTx < g_cTransports; iTx++)
     1178                                {
     1179                                    memcpy(&paCombinedOptions[idxOpts],
     1180                                           g_apTransports[iTx]->paOpts, g_apTransports[iTx]->cOpts * sizeof(RTGETOPTDEF));
     1181                                    idxOpts += g_apTransports[iTx]->cOpts;
     1182                                }
     1183                            }
    11641184
    11651185                            rc = RTGetOptInit(&GetState, argc, argv, paCombinedOptions, cCombinedOptions,
  • trunk/src/VBox/ValidationKit/utils/audio/vkatCmdGeneric.cpp

    r89643 r89962  
    157157    RT_ELEMENTS(g_aCmdEnumOptions),
    158158    audioTestCmdEnumHelp,
     159    false /* fNeedsTransport */
    159160};
    160161
     
    486487    RT_ELEMENTS(g_aCmdPlayOptions),
    487488    audioTestCmdPlayHelp,
     489    false /* fNeedsTransport */
    488490};
    489491
     
    866868    RT_ELEMENTS(g_aCmdRecOptions),
    867869    audioTestCmdRecHelp,
     870    false /* fNeedsTransport */
    868871};
    869872
  • trunk/src/VBox/ValidationKit/utils/audio/vkatCmdSelfTest.cpp

    r89890 r89962  
    7777                      2 /* 16-bit */, true  /* fSigned */, 2 /* cChannels */, 44100 /* uHz */);
    7878
    79     rc = audioTestEnvInit(pTstEnvGst, pTstEnvGst->DrvStack.pDrvReg, pCtx->fWithDrvAudio,
    80                           pCtx->Host.szValKitAtsAddr, pCtx->Host.uValKitAtsPort,
    81                           pCtx->Guest.szAtsAddr, pCtx->Guest.uAtsPort);
     79    rc = audioTestEnvInit(pTstEnvGst, pTstEnvGst->DrvStack.pDrvReg, pCtx->fWithDrvAudio);
    8280    if (RT_SUCCESS(rc))
    8381    {
     
    159157        pTstEnvHst->enmMode = AUDIOTESTMODE_HOST;
    160158
    161         rc = audioTestEnvInit(pTstEnvHst, &g_DrvHostValidationKitAudio, true /* fWithDrvAudio */,
    162                               pCtx->Host.szValKitAtsAddr, pCtx->Host.uValKitAtsPort,
    163                               pCtx->Host.szGuestAtsAddr, pCtx->Host.uGuestAtsPort);
     159        rc = audioTestEnvInit(pTstEnvHst, &g_DrvHostValidationKitAudio, true /* fWithDrvAudio */);
    164160        if (RT_SUCCESS(rc))
    165161        {
     
    346342    RT_ELEMENTS(s_aCmdSelftestOptions),
    347343    audioTestCmdSelftestHelp,
     344    true /* fNeedsTransport */
    348345};
    349346
  • trunk/src/VBox/ValidationKit/utils/audio/vkatCommon.cpp

    r89892 r89962  
    574574*********************************************************************************************************************************/
    575575
    576 int audioTestEnvConnectToHostAts(PAUDIOTESTENV pTstEnv,
    577                                  const char *pszHostTcpAddr, uint32_t uHostTcpPort)
    578 {
    579     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Connecting to host ATS at %s:%RU32 ...\n",
    580                  (pszHostTcpAddr && *pszHostTcpAddr) ? pszHostTcpAddr : ATS_TCP_HOST_DEFAULT_ADDR_STR,
    581                  uHostTcpPort ? uHostTcpPort : ATS_TCP_HOST_DEFAULT_PORT);
    582 
    583     int rc = AudioTestSvcClientConnect(&pTstEnv->u.Host.AtsClValKit, pszHostTcpAddr, uHostTcpPort);
     576/**
     577 * Connects an ATS client via TCP/IP to a peer.
     578 *
     579 * @returns VBox status code.
     580 * @param   pTstEnv             Test environment to use.
     581 * @param   pClient             Client to connect.
     582 * @param   pszWhat             Hint of what to connect to where.
     583 * @param   pszTcpBindAddr      TCP/IP bind address. Optionl and can be NULL.
     584 *                              Server mode will be disabled then.
     585 * @param   uTcpBindPort        TCP/IP bind port. Optionl and can be 0.
     586 *                              Server mode will be disabled then. *
     587 * @param   pszTcpConnectAddr   TCP/IP connect address. Optionl and can be NULL.
     588 *                              Client mode will be disabled then.
     589 * @param   uTcpConnectPort     TCP/IP connect port. Optionl and can be 0.
     590 *                              Client mode will be disabled then.
     591 */
     592int audioTestEnvConnectViaTcp(PAUDIOTESTENV pTstEnv, PATSCLIENT pClient, const char *pszWhat,
     593                              const char *pszTcpBindAddr, uint16_t uTcpBindPort,
     594                              const char *pszTcpConnectAddr, uint16_t uTcpConnectPort)
     595{
     596    RT_NOREF(pTstEnv);
     597
     598    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Connecting %s ...\n", pszWhat);
     599
     600    RTGETOPTUNION Val;
     601    RT_ZERO(Val);
     602
     603    int rc;
     604
     605    if (   !pszTcpBindAddr
     606        || !uTcpBindPort)
     607    {
     608        Val.psz = "client";
     609    }
     610    else if (   !pszTcpConnectAddr
     611             || !uTcpConnectPort)
     612    {
     613        Val.psz = "server";
     614    }
     615    else
     616        Val.psz = "both";
     617
     618    rc = AudioTestSvcClientHandleOption(pClient, ATSTCPOPT_MODE, &Val);
     619    AssertRCReturn(rc, rc);
     620
     621    if (   !RTStrCmp(Val.psz, "client")
     622        || !RTStrCmp(Val.psz, "both"))
     623           RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Connecting at %s:%RU32\n", pszTcpConnectAddr, uTcpConnectPort);
     624
     625    if (   !RTStrCmp(Val.psz, "server")
     626        || !RTStrCmp(Val.psz, "both"))
     627        RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Listening at %s:%RU32\n", pszTcpBindAddr ? pszTcpBindAddr : "<None>", uTcpBindPort);
     628
     629    if (pszTcpBindAddr)
     630    {
     631        Val.psz = pszTcpBindAddr;
     632        rc = AudioTestSvcClientHandleOption(pClient, ATSTCPOPT_BIND_ADDRESS, &Val);
     633        AssertRCReturn(rc, rc);
     634    }
     635
     636    if (uTcpBindPort)
     637    {
     638        Val.u16 = uTcpBindPort;
     639        rc = AudioTestSvcClientHandleOption(pClient, ATSTCPOPT_BIND_PORT, &Val);
     640        AssertRCReturn(rc, rc);
     641    }
     642
     643    if (pszTcpConnectAddr)
     644    {
     645        Val.psz = pszTcpConnectAddr;
     646        rc = AudioTestSvcClientHandleOption(pClient, ATSTCPOPT_CONNECT_ADDRESS, &Val);
     647        AssertRCReturn(rc, rc);
     648    }
     649
     650    if (uTcpConnectPort)
     651    {
     652        Val.u16 = uTcpConnectPort;
     653        rc = AudioTestSvcClientHandleOption(pClient, ATSTCPOPT_CONNECT_PORT, &Val);
     654        AssertRCReturn(rc, rc);
     655    }
     656
     657    rc = AudioTestSvcClientConnect(pClient);
    584658    if (RT_FAILURE(rc))
    585659    {
    586         RTTestFailed(g_hTest, "Connecting to host ATS failed with %Rrc\n", rc);
     660        RTTestFailed(g_hTest, "Connecting %s failed with %Rrc\n", pszWhat, rc);
    587661        return rc;
    588662    }
    589663
    590     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Connected to host ATS\n");
    591     return rc;
    592 }
    593 
    594 int audioTestEnvConnectToGuestAts(PAUDIOTESTENV pTstEnv,
    595                                   const char *pszGuestTcpAddr, uint32_t uGuestTcpPort)
    596 {
    597     RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Connecting to guest ATS at %s:%RU32 ...\n",
    598                  (pszGuestTcpAddr && *pszGuestTcpAddr) ? pszGuestTcpAddr : "127.0.0.1",
    599                  uGuestTcpPort ? uGuestTcpPort : ATS_TCP_GUEST_DEFAULT_PORT);
    600 
    601     int rc = AudioTestSvcClientConnect(&pTstEnv->u.Host.AtsClGuest, pszGuestTcpAddr, uGuestTcpPort);
     664    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Connected %s\n", pszWhat);
     665    return rc;
     666}
     667
     668/**
     669 * Configures and starts an ATS TCP/IP server.
     670 *
     671 * @returns VBox status code.
     672 * @param   pSrv                ATS server instance to configure and start.
     673 * @param   pCallbacks          ATS callback table to use.
     674 * @param   pszDesc             Hint of server type which is being started.
     675 * @param   pszTcpBindAddr      TCP/IP bind address. Optionl and can be NULL.
     676 *                              Server mode will be disabled then.
     677 * @param   uTcpBindPort        TCP/IP bind port. Optionl and can be 0.
     678 *                              Server mode will be disabled then. *
     679 * @param   pszTcpConnectAddr   TCP/IP connect address. Optionl and can be NULL.
     680 *                              Client mode will be disabled then.
     681 * @param   uTcpConnectPort     TCP/IP connect port. Optionl and can be 0.
     682 *                              Client mode will be disabled then.
     683 */
     684int audioTestEnvConfigureAndStartTcpServer(PATSSERVER pSrv, PCATSCALLBACKS pCallbacks, const char *pszDesc,
     685                                           const char *pszTcpBindAddr, uint16_t uTcpBindPort,
     686                                           const char *pszTcpConnectAddr, uint16_t uTcpConnectPort)
     687{
     688    RTGETOPTUNION Val;
     689    RT_ZERO(Val);
     690
     691    if (pszTcpBindAddr)
     692    {
     693        Val.psz = pszTcpBindAddr;
     694        AudioTestSvcHandleOption(pSrv, ATSTCPOPT_BIND_ADDRESS, &Val);
     695    }
     696
     697    if (uTcpBindPort)
     698    {
     699        Val.u16 = uTcpBindPort;
     700        AudioTestSvcHandleOption(pSrv, ATSTCPOPT_BIND_PORT, &Val);
     701    }
     702
     703    if (pszTcpConnectAddr)
     704    {
     705        Val.psz = pszTcpConnectAddr;
     706        AudioTestSvcHandleOption(pSrv, ATSTCPOPT_CONNECT_ADDRESS, &Val);
     707    }
     708
     709    if (uTcpConnectPort)
     710    {
     711        Val.u16 = uTcpConnectPort;
     712        AudioTestSvcHandleOption(pSrv, ATSTCPOPT_CONNECT_PORT, &Val);
     713    }
     714
     715    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Starting server for %s at %s:%RU32 ...\n",
     716                 pszDesc, pszTcpBindAddr[0] ? pszTcpBindAddr : "0.0.0.0", uTcpBindPort);
     717    if (pszTcpConnectAddr[0])
     718        RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Trying %s to connect as client to %s:%RU32 ...\n",
     719                     pszDesc, pszTcpConnectAddr[0] ? pszTcpConnectAddr : "0.0.0.0", uTcpConnectPort);
     720
     721    int rc = AudioTestSvcInit(pSrv, pCallbacks);
     722    if (RT_SUCCESS(rc))
     723        rc = AudioTestSvcStart(pSrv);
     724
    602725    if (RT_FAILURE(rc))
    603     {
    604         RTTestFailed(g_hTest, "Connecting to guest ATS failed with %Rrc\n", rc);
    605         return rc;
    606     }
    607 
    608     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Connected to guest ATS\n");
     726        RTTestFailed(g_hTest, "Starting server for %s failed with %Rrc\n", pszDesc, rc);
     727
    609728    return rc;
    610729}
     
    616735 * @param   pDrvReg             Audio driver to use.
    617736 * @param   fWithDrvAudio       Whether to include DrvAudio in the stack or not.
    618  * @param   pszHostTcpAddr      Host ATS TCP/IP address to connect to.
    619  *                              If NULL, ATS_TCP_HOST_DEFAULT_ADDR_STR will be used.
    620  * @param   uHostTcpPort        Host ATS TCP/IP port to connect to.
    621  *                              If 0, ATS_TCP_HOST_DEFAULT_PORT will be used.
    622  * @param   pszGuestTcpAddr     Guest ATS TCP/IP address to connect to.
    623  *                              If NULL, any address (0.0.0.0) will be used.
    624  * @param   uGuestTcpPort       Guest ATS TCP/IP port to connect to.
    625  *                              If 0, ATS_TCP_GUEST_DEFAULT_PORT will be used.
    626737 */
    627738int audioTestEnvInit(PAUDIOTESTENV pTstEnv,
    628                      PCPDMDRVREG pDrvReg, bool fWithDrvAudio,
    629                      const char *pszHostTcpAddr, uint32_t uHostTcpPort,
    630                      const char *pszGuestTcpAddr, uint32_t uGuestTcpPort)
     739                     PCPDMDRVREG pDrvReg, bool fWithDrvAudio)
    631740{
    632741    int rc = VINF_SUCCESS;
     
    656765    if (!pDrvReg)
    657766        pDrvReg = AudioTestGetDefaultBackend();
    658 
    659     if (!uHostTcpPort)
    660         uHostTcpPort = ATS_TCP_HOST_DEFAULT_PORT;
    661 
    662     if (!uGuestTcpPort)
    663         uGuestTcpPort = ATS_TCP_GUEST_DEFAULT_PORT;
    664767
    665768    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Initializing environment for mode '%s'\n", pTstEnv->enmMode == AUDIOTESTMODE_HOST ? "host" : "guest");
     
    732835        return rc;
    733836
    734     /** @todo Implement NAT mode like we do for TxS later? */
    735837    if (pTstEnv->enmMode == AUDIOTESTMODE_GUEST)
    736838    {
     
    749851        Callbacks.pvUser              = &Ctx;
    750852
     853        if (!pTstEnv->u.Guest.TcpOpts.uTcpBindPort)
     854            pTstEnv->u.Guest.TcpOpts.uTcpBindPort = ATS_TCP_DEF_BIND_PORT_GUEST;
     855
     856        if (!pTstEnv->u.Guest.TcpOpts.szTcpBindAddr[0])
     857            RTStrCopy(pTstEnv->u.Guest.TcpOpts.szTcpBindAddr, sizeof(pTstEnv->u.Guest.TcpOpts.szTcpBindAddr), "0.0.0.0");
     858
     859        if (!pTstEnv->u.Guest.TcpOpts.uTcpConnectPort)
     860            pTstEnv->u.Guest.TcpOpts.uTcpConnectPort = ATS_TCP_DEF_CONNECT_PORT_GUEST;
     861
     862        if (!pTstEnv->u.Guest.TcpOpts.szTcpConnectAddr[0])
     863            RTStrCopy(pTstEnv->u.Guest.TcpOpts.szTcpConnectAddr, sizeof(pTstEnv->u.Guest.TcpOpts.szTcpConnectAddr), "10.0.2.2");
     864
    751865        /*
    752866         * Start the ATS (Audio Test Service) on the guest side.
     
    756870         * Note that we have to bind to "0.0.0.0" by default so that the host can connect to it.
    757871         */
    758         RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Starting guest ATS at %s:%RU32...\n",
    759                      (pszGuestTcpAddr && *pszGuestTcpAddr) ? pszGuestTcpAddr : "0.0.0.0", uGuestTcpPort);
    760         rc = AudioTestSvcInit(&pTstEnv->u.Guest.Srv,
    761                               (pszGuestTcpAddr && *pszGuestTcpAddr) ? pszGuestTcpAddr : "0.0.0.0", uGuestTcpPort, &Callbacks);
     872        rc = audioTestEnvConfigureAndStartTcpServer(&pTstEnv->u.Guest.Srv, &Callbacks, "Guest ATS",
     873                                                    pTstEnv->u.Guest.TcpOpts.szTcpBindAddr, pTstEnv->u.Guest.TcpOpts.uTcpBindPort,
     874                                                    pTstEnv->u.Guest.TcpOpts.szTcpConnectAddr, pTstEnv->u.Guest.TcpOpts.uTcpConnectPort);
     875
     876    }
     877    else /* Host mode */
     878    {
     879
     880        ATSCALLBACKCTX Ctx;
     881        Ctx.pTstEnv = pTstEnv;
     882
     883        ATSCALLBACKS Callbacks;
     884        RT_ZERO(Callbacks);
     885        Callbacks.pvUser              = &Ctx;
     886
     887        if (!pTstEnv->u.Host.TcpOpts.uTcpBindPort)
     888            pTstEnv->u.Host.TcpOpts.uTcpBindPort = ATS_TCP_DEF_BIND_PORT_HOST;
     889
     890        if (!pTstEnv->u.Host.TcpOpts.szTcpBindAddr[0])
     891            RTStrCopy(pTstEnv->u.Host.TcpOpts.szTcpBindAddr, sizeof(pTstEnv->u.Host.TcpOpts.szTcpBindAddr), "0.0.0.0");
     892
     893        if (!pTstEnv->u.Host.TcpOpts.uTcpConnectPort)
     894            pTstEnv->u.Host.TcpOpts.uTcpConnectPort = ATS_TCP_DEF_CONNECT_PORT_HOST_PORT_FWD;
     895
     896        if (!pTstEnv->u.Host.TcpOpts.szTcpConnectAddr[0])
     897            RTStrCopy(pTstEnv->u.Host.TcpOpts.szTcpConnectAddr, sizeof(pTstEnv->u.Host.TcpOpts.szTcpConnectAddr),
     898                      ATS_TCP_DEF_CONNECT_HOST_ADDR_STR); /** @todo Get VM IP? Needs port forwarding. */
     899
     900        /* We need to start a server on the host so that VMs configured with NAT networking
     901         * can connect to it as well. */
     902        rc = AudioTestSvcClientCreate(&pTstEnv->u.Host.AtsClGuest);
    762903        if (RT_SUCCESS(rc))
    763             rc = AudioTestSvcStart(&pTstEnv->u.Guest.Srv);
    764 
    765         if (RT_FAILURE(rc))
    766             RTTestFailed(g_hTest, "Starting ATS failed with %Rrc\n", rc);
    767     }
    768     else /* Host mode */
    769     {
    770         rc = audioTestEnvConnectToHostAts(pTstEnv, pszHostTcpAddr, uHostTcpPort);
     904            rc = audioTestEnvConnectViaTcp(pTstEnv, &pTstEnv->u.Host.AtsClGuest,
     905                                           "Host -> Guest ATS",
     906                                           pTstEnv->u.Host.TcpOpts.szTcpBindAddr, pTstEnv->u.Host.TcpOpts.uTcpBindPort,
     907                                           pTstEnv->u.Host.TcpOpts.szTcpConnectAddr, pTstEnv->u.Host.TcpOpts.uTcpConnectPort);
    771908        if (RT_SUCCESS(rc))
    772             rc = audioTestEnvConnectToGuestAts(pTstEnv, pszGuestTcpAddr, uGuestTcpPort);
     909        {
     910            if (!pTstEnv->ValKitTcpOpts.uTcpConnectPort)
     911                pTstEnv->ValKitTcpOpts.uTcpConnectPort = ATS_TCP_DEF_CONNECT_PORT_VALKIT;
     912
     913            if (!pTstEnv->ValKitTcpOpts.szTcpConnectAddr[0])
     914                RTStrCopy(pTstEnv->ValKitTcpOpts.szTcpConnectAddr, sizeof(pTstEnv->ValKitTcpOpts.szTcpConnectAddr),
     915                          ATS_TCP_DEF_CONNECT_HOST_ADDR_STR);
     916
     917            rc = AudioTestSvcClientCreate(&pTstEnv->u.Host.AtsClValKit);
     918            if (RT_SUCCESS(rc))
     919                rc = audioTestEnvConnectViaTcp(pTstEnv, &pTstEnv->u.Host.AtsClValKit,
     920                                               "Host -> Validation Kit Host Audio Driver ATS",
     921                                               pTstEnv->ValKitTcpOpts.szTcpBindAddr, pTstEnv->ValKitTcpOpts.uTcpBindPort,
     922                                               pTstEnv->ValKitTcpOpts.szTcpConnectAddr, pTstEnv->ValKitTcpOpts.uTcpConnectPort);
     923        }
    773924    }
    774925
  • trunk/src/VBox/ValidationKit/utils/audio/vkatInternal.h

    r89890 r89962  
    173173/** Maximum audio streams a test environment can handle. */
    174174#define AUDIOTESTENV_MAX_STREAMS 8
     175
     176/**
     177 * Structure for keeping TCP/IP-specific options.
     178 */
     179typedef struct AUDIOTESTENVTCPOPTS
     180{
     181    /** Bind address (server mode). When empty, "0.0.0.0" (any host) will be used. */
     182    char            szTcpBindAddr[128];
     183    /** Bind port (server mode). */
     184    uint16_t        uTcpBindPort;
     185    /** Connection address (client mode). */
     186    char            szTcpConnectAddr[128];
     187    /** Connection port (client mode). */
     188    uint16_t        uTcpConnectPort;
     189} AUDIOTESTENVTCPOPTS;
     190typedef AUDIOTESTENVTCPOPTS *PAUDIOTESTENVTCPOPTS;
    175191
    176192/**
     
    218234        struct
    219235        {
     236            AUDIOTESTENVTCPOPTS TcpOpts;
    220237            /** ATS instance to use. */
    221             ATSSERVER       Srv;
     238            ATSSERVER           Srv;
    222239        } Guest;
    223240        struct
    224241        {
     242            AUDIOTESTENVTCPOPTS TcpOpts;
     243            /** ATS instance to use. */
     244            ATSSERVER           Srv;
    225245            /** Client connected to the ATS on the guest side. */
    226246            ATSCLIENT       AtsClGuest;
     
    233253        } Host;
    234254    } u;
     255    AUDIOTESTENVTCPOPTS         ValKitTcpOpts;
    235256} AUDIOTESTENV;
    236257
     
    312333    /** Gets help for an option. */
    313334    DECLCALLBACKMEMBER(const char *, pfnOptionHelp,(PCRTGETOPTDEF pOpt));
     335    /** Flag indicating if the command needs the ATS transport layer.
     336     *  Needed for command line parsing. */
     337    bool            fNeedsTransport;
    314338} VKATCMD;
    315339/** Pointer to a const VKAT command entry. */
     
    423447/** @name ATS routines
    424448 * @{ */
    425 int         audioTestEnvConnectToHostAts(PAUDIOTESTENV pTstEnv,
     449int         audioTestEnvConnectToValKitAts(PAUDIOTESTENV pTstEnv,
    426450                                         const char *pszHostTcpAddr, uint32_t uHostTcpPort);
    427451/** @}  */
     
    429453/** @name Test environment handling
    430454 * @{ */
    431 int         audioTestEnvInit(PAUDIOTESTENV pTstEnv, PCPDMDRVREG pDrvReg, bool fWithDrvAudio, const char *pszHostTcpAddr, uint32_t uHostTcpPort, const char *pszGuestTcpAddr, uint32_t uGuestTcpPort);
     455int         audioTestEnvInit(PAUDIOTESTENV pTstEnv, PCPDMDRVREG pDrvReg, bool fWithDrvAudio);
    432456void        audioTestEnvDestroy(PAUDIOTESTENV pTstEnv);
    433457int         audioTestEnvPrologue(PAUDIOTESTENV pTstEnv, bool fPack, char *pszPackFile, size_t cbPackFile);
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