VirtualBox

Changeset 60279 in vbox for trunk/src/VBox/ValidationKit


Ignore:
Timestamp:
Mar 31, 2016 6:57:37 PM (9 years ago)
Author:
vboxsync
Message:

ValidationKit/usb: Early commit of the new remote USB test configuration and execution server. It will replace the current approach of using TXS to configure the gadgets because that approach is not suitable for multiple clients accessing the same gadget (software devices exported over USB/IP). Non functional and heavily work in progress

Location:
trunk/src/VBox/ValidationKit/utils/usb
Files:
2 added
1 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/utils/usb/Makefile.kmk

    r56295 r60279  
    3131# USB Linux test frontend.
    3232#
    33 PROGRAMS += UsbTest
    34 UsbTest_TEMPLATE = VBoxValidationKitR3
    35 UsbTest_SOURCES  = UsbTest.cpp
     33ifeq ($(KBUILD_TARGET),linux)
     34 PROGRAMS += UsbTest
     35 UsbTest_TEMPLATE = VBoxValidationKitR3
     36 UsbTest_SOURCES  = UsbTest.cpp
     37endif
     38
     39PROGRAMS += UsbTestService
     40UsbTestService_TEMPLATE = VBoxValidationKitR3
     41UsbTestService_DEFS = \
     42        KBUILD_TARGET=\"$(KBUILD_TARGET)\" \
     43        KBUILD_TARGET_ARCH=\"$(KBUILD_TARGET_ARCH)\"
     44UsbTestService_SOURCES = \
     45        UsbTestService.cpp \
     46        UsbTestServiceTcp.cpp
    3647
    3748$(evalcall def_vbox_validationkit_process_python_sources)
  • trunk/src/VBox/ValidationKit/utils/usb/UsbTestService.cpp

    r60266 r60279  
    11/* $Id$ */
    22/** @file
    3  * TestExecServ - Basic Remote Execution Service.
     3 * UsbTestService - Remote USB test configuration and execution server.
    44 */
    55
    66/*
    7  * Copyright (C) 2010-2015 Oracle Corporation
     7 * Copyright (C) 2010-2016 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3333#include <iprt/asm.h>
    3434#include <iprt/assert.h>
    35 #include <iprt/cdrom.h>
    3635#include <iprt/critsect.h>
    3736#include <iprt/crc.h>
     
    4039#include <iprt/env.h>
    4140#include <iprt/err.h>
    42 #include <iprt/file.h>
    4341#include <iprt/getopt.h>
    4442#include <iprt/handle.h>
    4543#include <iprt/initterm.h>
     44#include <iprt/list.h>
    4645#include <iprt/log.h>
    4746#include <iprt/mem.h>
     
    5453#include <iprt/stream.h>
    5554#include <iprt/string.h>
    56 #include <iprt/system.h>
    5755#include <iprt/thread.h>
    58 #include <iprt/time.h>
    59 #include <iprt/uuid.h>
    60 
    61 #ifndef RT_OS_WINDOWS
    62 # include <iprt/zip.h>
    63 #endif
    64 
    65 #include "TestExecServiceInternal.h"
     56
     57#include "UsbTestServiceInternal.h"
    6658
    6759
     
    7062*   Structures and Typedefs                                                                                                      *
    7163*********************************************************************************************************************************/
    72 /**
    73  * Handle IDs used by txsDoExec for the poll set.
    74  */
    75 typedef enum TXSEXECHNDID
    76 {
    77     TXSEXECHNDID_STDIN = 0,
    78     TXSEXECHNDID_STDOUT,
    79     TXSEXECHNDID_STDERR,
    80     TXSEXECHNDID_TESTPIPE,
    81     TXSEXECHNDID_STDIN_WRITABLE,
    82     TXSEXECHNDID_TRANSPORT,
    83     TXSEXECHNDID_THREAD
    84 } TXSEXECHNDID;
    85 
    86 
    87 /**
    88  * For buffering process input supplied by the client.
    89  */
    90 typedef struct TXSEXECSTDINBUF
    91 {
    92     /** The mount of buffered data. */
    93     size_t  cb;
    94     /** The current data offset. */
    95     size_t  off;
    96     /** The data buffer. */
    97     char   *pch;
    98     /** The amount of allocated buffer space. */
    99     size_t  cbAllocated;
    100     /** Send further input into the bit bucket (stdin is dead). */
    101     bool    fBitBucket;
    102     /** The CRC-32 for standard input (received part). */
    103     uint32_t uCrc32;
    104 } TXSEXECSTDINBUF;
    105 /** Pointer to a standard input buffer. */
    106 typedef TXSEXECSTDINBUF *PTXSEXECSTDINBUF;
    107 
    108 /**
    109  * TXS child process info.
    110  */
    111 typedef struct TXSEXEC
    112 {
    113     PCTXSPKTHDR     pPktHdr;
    114     RTMSINTERVAL    cMsTimeout;
    115     int             rcReplySend;
    116 
    117     RTPOLLSET       hPollSet;
    118     RTPIPE          hStdInW;
    119     RTPIPE          hStdOutR;
    120     RTPIPE          hStdErrR;
    121     RTPIPE          hTestPipeR;
    122     RTPIPE          hWakeUpPipeR;
    123     RTTHREAD        hThreadWaiter;
    124 
    125     /** @name For the setup phase
    126      * @{ */
    127     struct StdPipe
    128     {
    129         RTHANDLE    hChild;
    130         PRTHANDLE   phChild;
    131     }               StdIn,
    132                     StdOut,
    133                     StdErr;
    134     RTPIPE          hTestPipeW;
    135     RTENV           hEnv;
    136     /** @} */
    137 
    138     /** For serializating some access. */
    139     RTCRITSECT      CritSect;
    140     /** @name Members protected by the critical section.
    141      * @{ */
    142     RTPROCESS       hProcess;
    143     /** The process status.  Only valid when fProcessAlive is cleared. */
    144     RTPROCSTATUS    ProcessStatus;
    145     /** Set when the process is alive, clear when dead. */
    146     bool volatile   fProcessAlive;
    147     /** The end of the pipe that hThreadWaiter writes to. */
    148     RTPIPE          hWakeUpPipeW;
    149     /** @} */
    150 } TXSEXEC;
    151 /** Pointer to a the TXS child process info. */
    152 typedef TXSEXEC *PTXSEXEC;
    153 
     64
     65/**
     66 * UTS client instance.
     67 */
     68typedef struct UTSCLIENT
     69{
     70    /** List node for new clients. */
     71    RTLISTNODE             NdLst;
     72    /** Transport backend specific data. */
     73    PUTSTRANSPORTCLIENT    pTransportClient;
     74} UTSCLIENT;
     75/** Pointer to a UTS client instance. */
     76typedef UTSCLIENT *PUTSCLIENT;
    15477
    15578/*********************************************************************************************************************************
     
    15982 * Transport layers.
    16083 */
    161 static const PCTXSTRANSPORT g_apTransports[] =
     84static const PCUTSTRANSPORT g_apTransports[] =
    16285{
    16386    &g_TcpTransport,
     
    16992
    17093/** The select transport layer. */
    171 static PCTXSTRANSPORT       g_pTransport;
     94static PCUTSTRANSPORT       g_pTransport;
    17295/** The scratch path. */
    17396static char                 g_szScratchPath[RTPATH_MAX];
     
    190113/** The shell script suffix. */
    191114static char                 g_szScriptSuff[8];
    192 /** UUID identifying this TXS instance.  This can be used to see if TXS
    193  * has been restarted or not. */
    194 static RTUUID               g_InstanceUuid;
    195115/** Whether to display the output of the child process or not.  */
    196116static bool                 g_fDisplayOutput = true;
     
    198118 * @todo implement signals and stuff.  */
    199119static bool volatile        g_fTerminate = false;
     120/** Pipe for communicating with the serving thread about new clients. - read end */
     121static RTPIPE               g_hPipeR;
     122/** Pipe for communicating with the serving thread about new clients. - write end */
     123static RTPIPE               g_hPipeW;
     124/** Thread serving connected clients. */
     125static RTTHREAD             g_hThreadServing;
     126/** Critical section protecting the list of new clients. */
     127static RTCRITSECT           g_CritSectClients;
     128/** List of new clients waiting to be picked up by the client worker thread. */
     129static RTLISTANCHOR         g_LstClientsNew;
     130
    200131
    201132/**
     
    203134 *
    204135 * @returns IPRT status code.
     136 * @param   pClient             The UTS client structure.
    205137 * @param   pPkt                The packet to send.  Must point to a correctly
    206138 *                              aligned buffer.
    207139 */
    208 static int txsSendPkt(PTXSPKTHDR pPkt)
     140static int utsSendPkt(PUTSCLIENT pClient, PUTSPKTHDR pPkt)
    209141{
    210142    Assert(pPkt->cb >= sizeof(*pPkt));
    211     pPkt->uCrc32 = RTCrc32(pPkt->achOpcode, pPkt->cb - RT_OFFSETOF(TXSPKTHDR, achOpcode));
    212     if (pPkt->cb != RT_ALIGN_32(pPkt->cb, TXSPKT_ALIGNMENT))
    213         memset((uint8_t *)pPkt + pPkt->cb, '\0', RT_ALIGN_32(pPkt->cb, TXSPKT_ALIGNMENT) - pPkt->cb);
    214 
    215     Log(("txsSendPkt: cb=%#x opcode=%.8s\n", pPkt->cb, pPkt->achOpcode));
     143    pPkt->uCrc32 = RTCrc32(pPkt->achOpcode, pPkt->cb - RT_OFFSETOF(UTSPKTHDR, achOpcode));
     144    if (pPkt->cb != RT_ALIGN_32(pPkt->cb, UTSPKT_ALIGNMENT))
     145        memset((uint8_t *)pPkt + pPkt->cb, '\0', RT_ALIGN_32(pPkt->cb, UTSPKT_ALIGNMENT) - pPkt->cb);
     146
     147    Log(("utsSendPkt: cb=%#x opcode=%.8s\n", pPkt->cb, pPkt->achOpcode));
    216148    Log2(("%.*Rhxd\n", RT_MIN(pPkt->cb, 256), pPkt));
    217     int rc = g_pTransport->pfnSendPkt(pPkt);
     149    int rc = g_pTransport->pfnSendPkt(pClient->pTransportClient, pPkt);
    218150    while (RT_UNLIKELY(rc == VERR_INTERRUPTED) && !g_fTerminate)
    219         rc = g_pTransport->pfnSendPkt(pPkt);
     151        rc = g_pTransport->pfnSendPkt(pClient->pTransportClient, pPkt);
    220152    if (RT_FAILURE(rc))
    221         Log(("txsSendPkt: rc=%Rrc\n", rc));
     153        Log(("utsSendPkt: rc=%Rrc\n", rc));
    222154
    223155    return rc;
     
    227159 * Sends a babble reply and disconnects the client (if applicable).
    228160 *
     161 * @param   pClient             The UTS client structure.
    229162 * @param   pszOpcode           The BABBLE opcode.
    230163 */
    231 static void txsReplyBabble(const char *pszOpcode)
    232 {
    233     TXSPKTHDR Reply;
     164static void utsReplyBabble(PUTSCLIENT pClient, const char *pszOpcode)
     165{
     166    UTSPKTHDR Reply;
    234167    Reply.cb     = sizeof(Reply);
    235168    Reply.uCrc32 = 0;
    236169    memcpy(Reply.achOpcode, pszOpcode, sizeof(Reply.achOpcode));
    237170
    238     g_pTransport->pfnBabble(&Reply, 20*1000);
     171    g_pTransport->pfnBabble(pClient->pTransportClient, &Reply, 20*1000);
    239172}
    240173
     
    246179 *
    247180 * @returns IPRT status code.
     181 * @param   pClient             The UTS client structure.
    248182 * @param   ppPktHdr            Where to return the packet on success.  Free
    249183 *                              with RTMemFree.
    250184 * @param   fAutoRetryOnFailure Whether to retry on error.
    251185 */
    252 static int txsRecvPkt(PPTXSPKTHDR ppPktHdr, bool fAutoRetryOnFailure)
     186static int utsRecvPkt(PUTSCLIENT pClient, PPUTSPKTHDR ppPktHdr, bool fAutoRetryOnFailure)
    253187{
    254188    for (;;)
    255189    {
    256         PTXSPKTHDR pPktHdr;
    257         int rc = g_pTransport->pfnRecvPkt(&pPktHdr);
     190        PUTSPKTHDR pPktHdr;
     191        int rc = g_pTransport->pfnRecvPkt(pClient->pTransportClient, &pPktHdr);
    258192        if (RT_SUCCESS(rc))
    259193        {
    260194            /* validate the packet. */
    261             if (   pPktHdr->cb >= sizeof(TXSPKTHDR)
    262                 && pPktHdr->cb < TXSPKT_MAX_SIZE)
     195            if (   pPktHdr->cb >= sizeof(UTSPKTHDR)
     196                && pPktHdr->cb < UTSPKT_MAX_SIZE)
    263197            {
    264                 Log2(("txsRecvPkt: pPktHdr=%p cb=%#x crc32=%#x opcode=%.8s\n"
     198                Log2(("utsRecvPkt: pPktHdr=%p cb=%#x crc32=%#x opcode=%.8s\n"
    265199                      "%.*Rhxd\n",
    266200                      pPktHdr, pPktHdr->cb, pPktHdr->uCrc32, pPktHdr->achOpcode, RT_MIN(pPktHdr->cb, 256), pPktHdr));
    267201                uint32_t uCrc32Calc = pPktHdr->uCrc32 != 0
    268                                     ? RTCrc32(&pPktHdr->achOpcode[0], pPktHdr->cb - RT_OFFSETOF(TXSPKTHDR, achOpcode))
     202                                    ? RTCrc32(&pPktHdr->achOpcode[0], pPktHdr->cb - RT_OFFSETOF(UTSPKTHDR, achOpcode))
    269203                                    : 0;
    270204                if (pPktHdr->uCrc32 == uCrc32Calc)
    271205                {
    272                     AssertCompileMemberSize(TXSPKTHDR, achOpcode, 8);
     206                    AssertCompileMemberSize(UTSPKTHDR, achOpcode, 8);
    273207                    if (   RT_C_IS_UPPER(pPktHdr->achOpcode[0])
    274208                        && RT_C_IS_UPPER(pPktHdr->achOpcode[1])
     
    281215                       )
    282216                    {
    283                         Log(("txsRecvPkt: cb=%#x opcode=%.8s\n", pPktHdr->cb, pPktHdr->achOpcode));
     217                        Log(("utsRecvPkt: cb=%#x opcode=%.8s\n", pPktHdr->cb, pPktHdr->achOpcode));
    284218                        *ppPktHdr = pPktHdr;
    285219                        return rc;
     
    290224                else
    291225                {
    292                     Log(("txsRecvPkt: cb=%#x opcode=%.8s crc32=%#x actual=%#x\n",
     226                    Log(("utsRecvPkt: cb=%#x opcode=%.8s crc32=%#x actual=%#x\n",
    293227                         pPktHdr->cb, pPktHdr->achOpcode, pPktHdr->uCrc32, uCrc32Calc));
    294228                    rc = VERR_IO_CRC;
     
    301235               connection oriented. */
    302236            if (rc == VERR_IO_BAD_LENGTH)
    303                 txsReplyBabble("BABBLE L");
     237                utsReplyBabble(pClient, "BABBLE L");
    304238            else if (rc == VERR_IO_CRC)
    305                 txsReplyBabble("BABBLE C");
     239                utsReplyBabble(pClient, "BABBLE C");
    306240            else if (rc == VERR_IO_BAD_COMMAND)
    307                 txsReplyBabble("BABBLE O");
     241                utsReplyBabble(pClient, "BABBLE O");
    308242            else
    309                 txsReplyBabble("BABBLE  ");
     243                utsReplyBabble(pClient, "BABBLE  ");
    310244            RTMemFree(pPktHdr);
    311245        }
     
    317251            )
    318252        {
    319             Log(("txsRecvPkt: rc=%Rrc\n", rc));
     253            Log(("utsRecvPkt: rc=%Rrc\n", rc));
    320254            return rc;
    321255        }
     
    327261 *
    328262 * @returns IPRT status code of the send.
     263 * @param   pClient             The UTS client structure.
    329264 * @param   pReply              The reply packet.
    330265 * @param   pszOpcode           The status opcode.  Exactly 8 chars long, padd
     
    332267 * @param   cbExtra             Bytes in addition to the header.
    333268 */
    334 static int txsReplyInternal(PTXSPKTHDR pReply, const char *pszOpcode, size_t cbExtra)
     269static int utsReplyInternal(PUTSCLIENT pClient, PUTSPKTSTS pReply, const char *pszOpcode, size_t cbExtra)
    335270{
    336271    /* copy the opcode, don't be too strict in case of a padding screw up. */
    337272    size_t cchOpcode = strlen(pszOpcode);
    338     if (RT_LIKELY(cchOpcode == sizeof(pReply->achOpcode)))
    339         memcpy(pReply->achOpcode, pszOpcode, sizeof(pReply->achOpcode));
     273    if (RT_LIKELY(cchOpcode == sizeof(pReply->Hdr.achOpcode)))
     274        memcpy(pReply->Hdr.achOpcode, pszOpcode, sizeof(pReply->Hdr.achOpcode));
    340275    else
    341276    {
    342         Assert(cchOpcode == sizeof(pReply->achOpcode));
     277        Assert(cchOpcode == sizeof(pReply->Hdr.achOpcode));
    343278        while (cchOpcode > 0 && pszOpcode[cchOpcode - 1] == ' ')
    344279            cchOpcode--;
    345         AssertMsgReturn(cchOpcode < sizeof(pReply->achOpcode), ("%d/'%.8s'\n", cchOpcode, pszOpcode), VERR_INTERNAL_ERROR_4);
    346         memcpy(pReply->achOpcode, pszOpcode, cchOpcode);
    347         memset(&pReply->achOpcode[cchOpcode], ' ', sizeof(pReply->achOpcode) - cchOpcode);
    348     }
    349 
    350     pReply->cb     = (uint32_t)sizeof(TXSPKTHDR) + (uint32_t)cbExtra;
    351     pReply->uCrc32 = 0;
    352 
    353     return txsSendPkt(pReply);
     280        AssertMsgReturn(cchOpcode < sizeof(pReply->Hdr.achOpcode), ("%d/'%.8s'\n", cchOpcode, pszOpcode), VERR_INTERNAL_ERROR_4);
     281        memcpy(pReply->Hdr.achOpcode, pszOpcode, cchOpcode);
     282        memset(&pReply->Hdr.achOpcode[cchOpcode], ' ', sizeof(pReply->Hdr.achOpcode) - cchOpcode);
     283    }
     284
     285    pReply->Hdr.cb     = (uint32_t)sizeof(UTSPKTSTS) + (uint32_t)cbExtra;
     286    pReply->Hdr.uCrc32 = 0;
     287
     288    return utsSendPkt(pClient, &pReply->Hdr);
    354289}
    355290
     
    358293 *
    359294 * @returns IPRT status code of the send.
     295 * @param   pClient             The UTS client structure.
    360296 * @param   pPktHdr             The original packet (for future use).
    361297 * @param   pszOpcode           The status opcode.  Exactly 8 chars long, padd
    362298 *                              with space.
    363299 */
    364 static int txsReplySimple(PCTXSPKTHDR pPktHdr, const char *pszOpcode)
    365 {
    366     TXSPKTHDR Pkt;
     300static int utsReplySimple(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr, const char *pszOpcode)
     301{
     302    UTSPKTSTS Pkt;
     303
     304    RT_ZERO(Pkt);
     305    Pkt.rcReq = VINF_SUCCESS;
     306    Pkt.cchStsMsg = 0;
    367307    NOREF(pPktHdr);
    368     return txsReplyInternal(&Pkt, pszOpcode, 0);
     308    return utsReplyInternal(pClient, &Pkt, pszOpcode, 0);
    369309}
    370310
     
    373313 *
    374314 * @returns IPRT status code of the send.
     315 * @param   pClient             The UTS client structure.
    375316 * @param   pPktHdr             The original packet (for future use).
    376317 */
    377 static int txsReplyAck(PCTXSPKTHDR pPktHdr)
    378 {
    379     return txsReplySimple(pPktHdr, "ACK     ");
     318static int utsReplyAck(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr)
     319{
     320    return utsReplySimple(pClient, pPktHdr, "ACK     ");
    380321}
    381322
     
    384325 *
    385326 * @returns IPRT status code of the send.
     327 * @param   pClient             The UTS client structure.
    386328 * @param   pPktHdr             The original packet (for future use).
     329 * @param   rcReq               Status code.
    387330 * @param   pszOpcode           The status opcode.  Exactly 8 chars long, padd
    388331 *                              with space.
     
    391334 * @param   va                  Format arguments.
    392335 */
    393 static int txsReplyFailureV(PCTXSPKTHDR pPktHdr, const char *pszOpcode, const char *pszDetailFmt, va_list va)
     336static int utsReplyFailureV(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr, const char *pszOpcode, int rcReq, const char *pszDetailFmt, va_list va)
    394337{
    395338    NOREF(pPktHdr);
    396339    union
    397340    {
    398         TXSPKTHDR   Hdr;
     341        UTSPKTSTS   Hdr;
    399342        char        ach[256];
    400343    } uPkt;
    401344
    402     size_t cchDetail = RTStrPrintfV(&uPkt.ach[sizeof(TXSPKTHDR)],
    403                                     sizeof(uPkt) - sizeof(TXSPKTHDR),
     345    RT_ZERO(uPkt);
     346    size_t cchDetail = RTStrPrintfV(&uPkt.ach[sizeof(UTSPKTSTS)],
     347                                    sizeof(uPkt) - sizeof(UTSPKTSTS),
    404348                                    pszDetailFmt, va);
    405     return txsReplyInternal(&uPkt.Hdr, pszOpcode, cchDetail + 1);
     349    uPkt.Hdr.rcReq = rcReq;
     350    uPkt.Hdr.cchStsMsg = cchDetail;
     351    return utsReplyInternal(pClient, &uPkt.Hdr, pszOpcode, cchDetail + 1);
    406352}
    407353
     
    410356 *
    411357 * @returns IPRT status code of the send.
     358 * @param   pClient             The UTS client structure.
    412359 * @param   pPktHdr             The original packet (for future use).
     360 * @param   rcReq               Status code.
    413361 * @param   pszOpcode           The status opcode.  Exactly 8 chars long, padd
    414362 *                              with space.
     
    417365 * @param   ...                 Format arguments.
    418366 */
    419 static int txsReplyFailure(PCTXSPKTHDR pPktHdr, const char *pszOpcode, const char *pszDetailFmt, ...)
     367static int utsReplyFailure(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr, const char *pszOpcode, int rcReq, const char *pszDetailFmt, ...)
    420368{
    421369    va_list va;
    422370    va_start(va, pszDetailFmt);
    423     int rc = txsReplyFailureV(pPktHdr, pszOpcode, pszDetailFmt, va);
     371    int rc = utsReplyFailureV(pClient, pPktHdr, pszOpcode, rcReq, pszDetailFmt, va);
    424372    va_end(va);
    425373    return rc;
     
    430378 *
    431379 * @returns IPRT status code of the send.
     380 * @param   pClient             The UTS client structure.
    432381 * @param   pPktHdr             The packet to reply to.
    433382 * @param   rcOperation         The status code to report.
     
    436385 * @param   ...                 Arguments to the format string.
    437386 */
    438 static int txsReplyRC(PCTXSPKTHDR pPktHdr, int rcOperation, const char *pszOperationFmt, ...)
     387static int utsReplyRC(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr, int rcOperation, const char *pszOperationFmt, ...)
    439388{
    440389    if (RT_SUCCESS(rcOperation))
    441         return txsReplyAck(pPktHdr);
     390        return utsReplyAck(pClient, pPktHdr);
    442391
    443392    char    szOperation[128];
     
    447396    va_end(va);
    448397
    449     return txsReplyFailure(pPktHdr, "FAILED  ", "%s failed with rc=%Rrc (opcode '%.8s')",
    450                            szOperation, rcOperation, pPktHdr->achOpcode);
     398    return utsReplyFailure(pClient, pPktHdr, "FAILED  ", rcOperation, "%s failed with rc=%Rrc (opcode '%.8s')",
     399                           rcOperation, szOperation, rcOperation, pPktHdr->achOpcode);
    451400}
    452401
     
    455404 *
    456405 * @returns IPRT status code of the send.
     406 * @param   pClient             The UTS client structure.
    457407 * @param   pPktHdr             The packet to reply to.
    458408 * @param   cbMin               The minimum size.
    459409 */
    460 static int txsReplyBadMinSize(PCTXSPKTHDR pPktHdr, size_t cbMin)
    461 {
    462     return txsReplyFailure(pPktHdr, "BAD SIZE", "Expected at least %zu bytes, got %u (opcode '%.8s')",
     410static int utsReplyBadMinSize(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr, size_t cbMin)
     411{
     412    return utsReplyFailure(pClient, pPktHdr, "BAD SIZE", VERR_INVALID_PARAMETER, "Expected at least %zu bytes, got %u (opcode '%.8s')",
    463413                           cbMin, pPktHdr->cb, pPktHdr->achOpcode);
    464414}
     
    468418 *
    469419 * @returns IPRT status code of the send.
     420 * @param   pClient             The UTS client structure.
    470421 * @param   pPktHdr             The packet to reply to.
    471422 * @param   cb                  The wanted size.
    472423 */
    473 static int txsReplyBadSize(PCTXSPKTHDR pPktHdr, size_t cb)
    474 {
    475     return txsReplyFailure(pPktHdr, "BAD SIZE", "Expected at %zu bytes, got %u  (opcode '%.8s')",
     424static int utsReplyBadSize(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr, size_t cb)
     425{
     426    return utsReplyFailure(pClient, pPktHdr, "BAD SIZE", VERR_INVALID_PARAMETER, "Expected at %zu bytes, got %u  (opcode '%.8s')",
    476427                           cb, pPktHdr->cb, pPktHdr->achOpcode);
    477428}
     
    480431 * Deals with a command that isn't implemented yet.
    481432 * @returns IPRT status code of the send.
     433 * @param   pClient             The UTS client structure.
    482434 * @param   pPktHdr             The packet which opcode isn't implemented.
    483435 */
    484 static int txsReplyNotImplemented(PCTXSPKTHDR pPktHdr)
    485 {
    486     return txsReplyFailure(pPktHdr, "NOT IMPL", "Opcode '%.8s' is not implemented", pPktHdr->achOpcode);
     436static int utsReplyNotImplemented(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr)
     437{
     438    return utsReplyFailure(pClient, pPktHdr, "NOT IMPL", VERR_NOT_IMPLEMENTED, "Opcode '%.8s' is not implemented", pPktHdr->achOpcode);
    487439}
    488440
     
    490442 * Deals with a unknown command.
    491443 * @returns IPRT status code of the send.
     444 * @param   pClient             The UTS client structure.
    492445 * @param   pPktHdr             The packet to reply to.
    493446 */
    494 static int txsReplyUnknown(PCTXSPKTHDR pPktHdr)
    495 {
    496     return txsReplyFailure(pPktHdr, "UNKNOWN ", "Opcode '%.8s' is not known", pPktHdr->achOpcode);
    497 }
    498 
    499 /**
    500  * Replaces a variable with its value.
    501  *
    502  * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY.
    503  * @param   ppszNew             In/Out.
    504  * @param   pcchNew             In/Out. (Messed up on failure.)
    505  * @param   offVar              Variable offset.
    506  * @param   cchVar              Variable length.
    507  * @param   pszValue            The value.
    508  * @param   cchValue            Value length.
    509  */
    510 static int txsReplaceStringVariable(char **ppszNew, size_t *pcchNew, size_t offVar, size_t cchVar,
    511                                     const char *pszValue, size_t cchValue)
    512 {
    513     size_t const cchAfter = *pcchNew - offVar - cchVar;
    514     if (cchVar < cchValue)
    515     {
    516         *pcchNew += cchValue - cchVar;
    517         int rc = RTStrRealloc(ppszNew, *pcchNew + 1);
    518         if (RT_FAILURE(rc))
    519             return rc;
    520     }
    521 
    522     char *pszNew = *ppszNew;
    523     memmove(&pszNew[offVar + cchValue], &pszNew[offVar + cchVar], cchAfter + 1);
    524     memcpy(&pszNew[offVar], pszValue, cchValue);
    525     return VINF_SUCCESS;
    526 }
    527 
    528 /**
    529  * Replace the variables found in the source string, returning a new string that
    530  * lives on the string heap.
    531  *
    532  * @returns Boolean success indicator.  Will reply to the client with all the
    533  *          gory detail on failure.
    534  * @param   pPktHdr             The packet the string relates to.  For replying
    535  *                              on error.
    536  * @param   pszSrc              The source string.
    537  * @param   ppszNew             Where to return the new string.
    538  * @param   prcSend             Where to return the status code of the send on
    539  *                              failure.
    540  */
    541 static int txsReplaceStringVariables(PCTXSPKTHDR pPktHdr, const char *pszSrc, char **ppszNew, int *prcSend)
    542 {
    543     /* Lazy approach that employs memmove.  */
    544     size_t  cchNew    = strlen(pszSrc);
    545     char   *pszNew    = RTStrDup(pszSrc);
    546     char   *pszDollar = pszNew;
    547     while ((pszDollar = strchr(pszDollar, '$')) != NULL)
    548     {
    549         if (pszDollar[1] == '{')
    550         {
    551             const char *pszEnd = strchr(&pszDollar[2], '}');
    552             if (pszEnd)
    553             {
    554 #define IF_VARIABLE_DO(pszDollar, szVarExpr, pszValue) \
    555     if (   cchVar == sizeof(szVarExpr) - 1 \
    556         && !memcmp(pszDollar, szVarExpr, sizeof(szVarExpr) - 1) ) \
    557     { \
    558         size_t const cchValue = strlen(pszValue); \
    559         rc = txsReplaceStringVariable(&pszNew, &cchNew, offDollar, \
    560                                       sizeof(szVarExpr) - 1, pszValue, cchValue); \
    561         offDollar += cchValue; \
    562     }
    563                 int          rc;
    564                 size_t const cchVar    = pszEnd - pszDollar + 1; /* includes "${}" */
    565                 size_t       offDollar = pszDollar - pszNew;
    566                      IF_VARIABLE_DO(pszDollar, "${CDROM}",   g_szCdRomPath)
    567                 else IF_VARIABLE_DO(pszDollar, "${SCRATCH}", g_szScratchPath)
    568                 else IF_VARIABLE_DO(pszDollar, "${ARCH}",    g_szArchShortName)
    569                 else IF_VARIABLE_DO(pszDollar, "${OS}",      g_szOsShortName)
    570                 else IF_VARIABLE_DO(pszDollar, "${OS.ARCH}", g_szOsDotArchShortName)
    571                 else IF_VARIABLE_DO(pszDollar, "${OS/ARCH}", g_szOsSlashArchShortName)
    572                 else IF_VARIABLE_DO(pszDollar, "${EXESUFF}", g_szExeSuff)
    573                 else IF_VARIABLE_DO(pszDollar, "${SCRIPTSUFF}", g_szScriptSuff)
    574                 else
    575                 {
    576                     RTStrFree(pszNew);
    577                     *prcSend = txsReplyFailure(pPktHdr, "UNKN VAR", "Unknown variable '%.*s' encountered in '%s'",
    578                                                cchVar, pszDollar, pszSrc);
    579                     *ppszNew = NULL;
    580                     return false;
    581                 }
    582                 pszDollar = &pszNew[offDollar];
    583 
    584                 if (RT_FAILURE(rc))
    585                 {
    586                     RTStrFree(pszNew);
    587                     *prcSend = txsReplyRC(pPktHdr, rc, "RTStrRealloc");
    588                     *ppszNew = NULL;
    589                     return false;
    590                 }
    591 #undef IF_VARIABLE_DO
    592             }
    593         }
    594     }
    595 
    596     *ppszNew = pszNew;
    597     *prcSend = VINF_SUCCESS;
    598     return true;
    599 }
    600 
    601 /**
    602  * Checks if the string is valid and returns the expanded version.
    603  *
    604  * @returns true if valid, false if invalid.
    605  * @param   pPktHdr             The packet being unpacked.
    606  * @param   pszArgName           The argument name.
    607  * @param   psz                 Pointer to the string within pPktHdr.
    608  * @param   ppszExp             Where to return the expanded string.  Must be
    609  *                              freed by calling RTStrFree().
    610  * @param   ppszNext            Where to return the pointer to the next field.
    611  *                              If NULL, then we assume this string is at the
    612  *                              end of the packet and will make sure it has the
    613  *                              advertised length.
    614  * @param   prcSend             Where to return the status code of the send on
    615  *                              failure.
    616  */
    617 static bool txsIsStringValid(PCTXSPKTHDR pPktHdr, const char *pszArgName, const char *psz,
    618                              char **ppszExp, const char **ppszNext, int *prcSend)
    619 {
    620     *ppszExp = NULL;
    621     if (ppszNext)
    622         *ppszNext = NULL;
    623 
    624     size_t const    off = psz - (const char *)pPktHdr;
    625     if (pPktHdr->cb <= off)
    626     {
    627         *prcSend = txsReplyFailure(pPktHdr, "STR MISS", "Missing string argument '%s' in '%.8s'",
    628                                    pszArgName, pPktHdr->achOpcode);
    629         return false;
    630     }
    631 
    632     size_t const    cchMax = pPktHdr->cb - off;
    633     const char     *pszEnd = RTStrEnd(psz, cchMax);
    634     if (!pszEnd)
    635     {
    636         *prcSend = txsReplyFailure(pPktHdr, "STR TERM", "The string argument '%s' in '%.8s' is unterminated",
    637                                    pszArgName, pPktHdr->achOpcode);
    638         return false;
    639     }
    640 
    641     if (!ppszNext && (size_t)(pszEnd - psz) != cchMax - 1)
    642     {
    643         *prcSend = txsReplyFailure(pPktHdr, "STR SHRT", "The string argument '%s' in '%.8s' is shorter than advertised",
    644                                    pszArgName, pPktHdr->achOpcode);
    645         return false;
    646     }
    647 
    648     if (!txsReplaceStringVariables(pPktHdr, psz, ppszExp, prcSend))
    649         return false;
    650     if (ppszNext)
    651         *ppszNext = pszEnd + 1;
    652     return true;
    653 }
    654 
    655 /**
    656  * Validates a packet with a single string after the header.
    657  *
    658  * @returns true if valid, false if invalid.
    659  * @param   pPktHdr             The packet.
    660  * @param   pszArgName          The argument name.
    661  * @param   ppszExp             Where to return the string pointer.  Variables
    662  *                              will be replaced and it must therefore be freed
    663  *                              by calling RTStrFree().
    664  * @param   prcSend             Where to return the status code of the send on
    665  *                              failure.
    666  */
    667 static bool txsIsStringPktValid(PCTXSPKTHDR pPktHdr, const char *pszArgName, char **ppszExp, int *prcSend)
    668 {
    669     if (pPktHdr->cb < sizeof(TXSPKTHDR) + 2)
    670     {
    671         *ppszExp = NULL;
    672         *prcSend = txsReplyBadMinSize(pPktHdr, sizeof(TXSPKTHDR) + 2);
    673         return false;
    674     }
    675 
    676     return txsIsStringValid(pPktHdr, pszArgName, (const char *)(pPktHdr + 1), ppszExp, NULL, prcSend);
     447static int utsReplyUnknown(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr)
     448{
     449    return utsReplyFailure(pClient, pPktHdr, "UNKNOWN ", VERR_NOT_FOUND, "Opcode '%.8s' is not known", pPktHdr->achOpcode);
    677450}
    678451
     
    685458 *                              to be the whole 8 chars long.
    686459 */
    687 DECLINLINE(bool) txsIsSameOpcode(PCTXSPKTHDR pPktHdr, const char *pszOpcode2)
     460DECLINLINE(bool) utsIsSameOpcode(PCUTSPKTHDR pPktHdr, const char *pszOpcode2)
    688461{
    689462    if (pPktHdr->achOpcode[0] != pszOpcode2[0])
     
    693466
    694467    unsigned i = 2;
    695     while (   i < RT_SIZEOFMEMB(TXSPKTHDR, achOpcode)
     468    while (   i < RT_SIZEOFMEMB(UTSPKTHDR, achOpcode)
    696469           && pszOpcode2[i] != '\0')
    697470    {
     
    701474    }
    702475
    703     if (   i < RT_SIZEOFMEMB(TXSPKTHDR, achOpcode)
     476    if (   i < RT_SIZEOFMEMB(UTSPKTHDR, achOpcode)
    704477        && pszOpcode2[i] == '\0')
    705478    {
    706         while (   i < RT_SIZEOFMEMB(TXSPKTHDR, achOpcode)
     479        while (   i < RT_SIZEOFMEMB(UTSPKTHDR, achOpcode)
    707480               && pPktHdr->achOpcode[i] == ' ')
    708481            i++;
    709482    }
    710483
    711     return i == RT_SIZEOFMEMB(TXSPKTHDR, achOpcode);
    712 }
    713 
    714 /**
    715  * Used by txsDoGetFile to wait for a reply ACK from the client.
    716  *
    717  * @returns VINF_SUCCESS on ACK, VERR_GENERAL_FAILURE on NACK,
    718  *          VERR_NET_NOT_CONNECTED on unknown response (sending a bable reply),
    719  *          or whatever txsRecvPkt returns.
    720  * @param   pPktHdr             The original packet (for future use).
    721  */
    722 static int txsWaitForAck(PCTXSPKTHDR pPktHdr)
    723 {
    724     NOREF(pPktHdr);
    725     /** @todo timeout? */
    726     PTXSPKTHDR pReply;
    727     int rc = txsRecvPkt(&pReply, false /*fAutoRetryOnFailure*/);
     484    return i == RT_SIZEOFMEMB(UTSPKTHDR, achOpcode);
     485}
     486
     487/**
     488 * Verifies and acknowledges a "BYE" request.
     489 *
     490 * @returns IPRT status code.
     491 * @param   pClient             The UTS client structure.
     492 * @param   pPktHdr             The howdy packet.
     493 */
     494static int utsDoBye(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr)
     495{
     496    int rc;
     497    if (pPktHdr->cb == sizeof(UTSPKTHDR))
     498        rc = utsReplyAck(pClient, pPktHdr);
     499    else
     500        rc = utsReplyBadSize(pClient, pPktHdr, sizeof(UTSPKTHDR));
     501    g_pTransport->pfnNotifyBye(pClient->pTransportClient);
     502    return rc;
     503}
     504
     505/**
     506 * Verifies and acknowledges a "HOWDY" request.
     507 *
     508 * @returns IPRT status code.
     509 * @param   pClient             The UTS client structure.
     510 * @param   pPktHdr             The howdy packet.
     511 */
     512static int utsDoHowdy(PUTSCLIENT pClient, PCUTSPKTHDR pPktHdr)
     513{
     514    if (pPktHdr->cb != sizeof(UTSPKTHDR))
     515        return utsReplyBadSize(pClient, pPktHdr, sizeof(UTSPKTHDR));
     516    int rc = utsReplyAck(pClient, pPktHdr);
    728517    if (RT_SUCCESS(rc))
    729518    {
    730         if (txsIsSameOpcode(pReply, "ACK"))
    731             rc = VINF_SUCCESS;
    732         else if (txsIsSameOpcode(pReply, "NACK"))
    733             rc = VERR_GENERAL_FAILURE;
    734         else
     519        g_pTransport->pfnNotifyHowdy(pClient->pTransportClient);
     520        RTDirRemoveRecursive(g_szScratchPath, RTDIRRMREC_F_CONTENT_ONLY);
     521    }
     522    return rc;
     523}
     524
     525/**
     526 * Main request processing routine for each client.
     527 *
     528 * @returns IPRT status code.
     529 * @param   pClient             The UTS client structure sending the request.
     530 */
     531static int utsClientReqProcess(PUTSCLIENT pClient)
     532{
     533    /*
     534     * Read client command packet and process it.
     535     */
     536    PUTSPKTHDR pPktHdr;
     537    int rc = utsRecvPkt(pClient, &pPktHdr, true /*fAutoRetryOnFailure*/);
     538    if (RT_FAILURE(rc))
     539        return rc;
     540
     541    /*
     542     * Do a string switch on the opcode bit.
     543     */
     544    /* Connection: */
     545    if (     utsIsSameOpcode(pPktHdr, UTSPKT_OPCODE_HOWDY))
     546        rc = utsDoHowdy(pClient, pPktHdr);
     547    else if (utsIsSameOpcode(pPktHdr, UTSPKT_OPCODE_BYE))
     548        rc = utsDoBye(pClient, pPktHdr);
     549    /* Misc: */
     550    else
     551        rc = utsReplyUnknown(pClient, pPktHdr);
     552
     553    RTMemFree(pPktHdr);
     554
     555    return rc;
     556}
     557
     558/**
     559 * Destroys a client instance.
     560 *
     561 * @returns nothing.
     562 * @param   pClient             The UTS client structure.
     563 */
     564static void utsClientDestroy(PUTSCLIENT pClient)
     565{
     566    RTMemFree(pClient);
     567}
     568
     569/**
     570 * The main thread worker serving the clients.
     571 */
     572static DECLCALLBACK(int) utsClientWorker(RTTHREAD hThread, void *pvUser)
     573{
     574    unsigned   cClientsMax = 0;
     575    unsigned   cClientsCur = 0;
     576    PUTSCLIENT *papClients = NULL;
     577    RTPOLLSET hPollSet;
     578
     579    int rc = RTPollSetCreate(&hPollSet);
     580    if (RT_FAILURE(rc))
     581        return rc;
     582
     583    /* Add the pipe to the poll set. */
     584    rc = RTPollSetAddPipe(hPollSet, g_hPipeR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, 0);
     585    if (RT_SUCCESS(rc))
     586    {
     587        while (!g_fTerminate)
    735588        {
    736             txsReplyBabble("BABBLE  ");
    737             rc = VERR_NET_NOT_CONNECTED;
    738         }
    739         RTMemFree(pReply);
    740     }
    741     return rc;
    742 }
    743 
    744 #ifndef RT_OS_WINDOWS
    745 /**
    746  * Unpacks a tar file.
    747  *
    748  * @returns IPRT status code from send.
    749  * @param   pPktHdr             The unpack file packet.
    750  */
    751 static int txsDoUnpackFile(PCTXSPKTHDR pPktHdr)
    752 {
    753     int rc;
    754     char *pszFile = NULL;
    755     char *pszDirectory = NULL;
    756 
    757     /* Packet cursor. */
    758     const char *pchEnd = (const char *)pPktHdr + pPktHdr->cb;
    759     const char *pch = (const char *)(pPktHdr + 1);
    760 
    761     if (txsIsStringValid(pPktHdr, "file", pch, &pszFile, &pch, &rc))
    762     {
    763         if (txsIsStringValid(pPktHdr, "directory", pch, &pszDirectory, &pch, &rc))
    764         {
    765             char *pszSuff = RTPathSuffix(pszFile);
    766 
    767             const char *apszArgs[7];
    768             unsigned cArgs = 0;
    769 
    770             apszArgs[cArgs++] = "RTTar";
    771             apszArgs[cArgs++] = "--extract";
    772 
    773             apszArgs[cArgs++] = "--file";
    774             apszArgs[cArgs++] = pszFile;
    775 
    776             apszArgs[cArgs++] = "--directory";
    777             apszArgs[cArgs++] = pszDirectory;
    778 
    779             if (   pszSuff
    780                 && (   !RTStrICmp(pszSuff, ".gz")
    781                     || !RTStrICmp(pszSuff, ".tgz")))
    782                 apszArgs[cArgs++] = "--gunzip";
    783 
    784             RTEXITCODE rcExit = RTZipTarCmd(cArgs, (char **)apszArgs);
    785             if (rcExit != RTEXITCODE_SUCCESS)
    786                 rc = VERR_GENERAL_FAILURE; /** @todo proper return code. */
    787             else
    788                 rc = VINF_SUCCESS;
    789 
    790             rc = txsReplyRC(pPktHdr, rc, "RTZipTarCmd(\"%s\",\"%s\")",
    791                             pszFile, pszDirectory);
    792 
    793             RTStrFree(pszDirectory);
    794         }
    795         RTStrFree(pszFile);
    796     }
    797 
    798     return rc;
    799 }
    800 #endif
    801 
    802 /**
    803  * Downloads a file to the client.
    804  *
    805  * The transfer sends a stream of DATA packets (0 or more) and ends it all with
    806  * a ACK packet.  If an error occurs, a FAILURE packet is sent and the transfer
    807  * aborted.
    808  *
    809  * @returns IPRT status code from send.
    810  * @param   pPktHdr             The get file packet.
    811  */
    812 static int txsDoGetFile(PCTXSPKTHDR pPktHdr)
    813 {
    814     int rc;
    815     char *pszPath;
    816     if (!txsIsStringPktValid(pPktHdr, "file", &pszPath, &rc))
    817         return rc;
    818 
    819     RTFILE hFile;
    820     rc = RTFileOpen(&hFile, pszPath, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN);
    821     if (RT_SUCCESS(rc))
    822     {
    823         uint32_t uMyCrc32 = RTCrc32Start();
    824         for (;;)
    825         {
    826             struct
     589            uint32_t fEvts;
     590            uint32_t uId;
     591            rc = RTPoll(hPollSet, RT_INDEFINITE_WAIT, &fEvts, &uId);
     592            if (RT_SUCCESS(rc))
    827593            {
    828                 TXSPKTHDR   Hdr;
    829                 uint32_t    uCrc32;
    830                 char        ab[_64K];
    831                 char        abPadding[TXSPKT_ALIGNMENT];
    832             }       Pkt;
    833             size_t  cbRead;
    834             rc = RTFileRead(hFile, &Pkt.ab[0], _64K, &cbRead);
    835             if (RT_FAILURE(rc) || cbRead == 0)
    836             {
    837                 if (rc == VERR_EOF || (RT_SUCCESS(rc) && cbRead == 0))
     594                if (uId == 0)
    838595                {
    839                     Pkt.uCrc32 = RTCrc32Finish(uMyCrc32);
    840                     rc = txsReplyInternal(&Pkt.Hdr, "DATA EOF", sizeof(uint32_t));
    841                     if (RT_SUCCESS(rc))
    842                         rc = txsWaitForAck(&Pkt.Hdr);
    843                 }
    844                 else
    845                     rc = txsReplyRC(pPktHdr, rc, "RTFileRead");
    846                 break;
    847             }
    848 
    849             uMyCrc32   = RTCrc32Process(uMyCrc32, &Pkt.ab[0], cbRead);
    850             Pkt.uCrc32 = RTCrc32Finish(uMyCrc32);
    851             rc = txsReplyInternal(&Pkt.Hdr, "DATA    ", cbRead + sizeof(uint32_t));
    852             if (RT_FAILURE(rc))
    853                 break;
    854             rc = txsWaitForAck(&Pkt.Hdr);
    855             if (RT_FAILURE(rc))
    856                 break;
    857         }
    858 
    859         RTFileClose(hFile);
    860     }
    861     else
    862         rc = txsReplyRC(pPktHdr, rc, "RTFileOpen(,\"%s\",)", pszPath);
    863 
    864     RTStrFree(pszPath);
    865     return rc;
    866 }
    867 
    868 /**
    869  * Uploads a file from the client.
    870  *
    871  * The transfer sends a stream of DATA packets (0 or more) and ends it all with
    872  * a DATA EOF packet.  We ACK each of these, so that if a write error occurs we
    873  * can abort the transfer straight away.
    874  *
    875  * @returns IPRT status code from send.
    876  * @param   pPktHdr             The put file packet.
    877  */
    878 static int txsDoPutFile(PCTXSPKTHDR pPktHdr)
    879 {
    880     int rc;
    881     char *pszPath;
    882     if (!txsIsStringPktValid(pPktHdr, "file", &pszPath, &rc))
    883         return rc;
    884 
    885     RTFILE hFile;
    886     rc = RTFileOpen(&hFile, pszPath, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE);
    887     if (RT_SUCCESS(rc))
    888     {
    889         bool fSuccess = false;
    890         rc = txsReplyAck(pPktHdr);
    891         if (RT_SUCCESS(rc))
    892         {
    893             /*
    894              * Read client command packets and process them.
    895              */
    896             uint32_t uMyCrc32 = RTCrc32Start();
    897             for (;;)
    898             {
    899                 PTXSPKTHDR pDataPktHdr;
    900                 rc = txsRecvPkt(&pDataPktHdr, false /*fAutoRetryOnFailure*/);
    901                 if (RT_FAILURE(rc))
    902                     break;
    903 
    904                 if (txsIsSameOpcode(pDataPktHdr, "DATA"))
    905                 {
    906                     size_t const cbMin = sizeof(TXSPKTHDR) + sizeof(uint32_t);
    907                     if (pDataPktHdr->cb >= cbMin)
     596                    if (fEvts & RTPOLL_EVT_ERROR)
     597                        break;
     598
     599                    /* We got woken up because of a new client. */
     600                    Assert(fEvts & RTPOLL_EVT_READ);
     601
     602                    uint8_t bRead;
     603                    rc = RTPipeRead(g_hPipeR, &bRead, 1, NULL);
     604                    AssertRC(rc);
     605
     606                    RTCritSectEnter(&g_CritSectClients);
     607                    /* Walk the list and add all new clients. */
     608                    PUTSCLIENT pIt, pItNext;
     609                    RTListForEachSafe(&g_LstClientsNew, pIt, pItNext, UTSCLIENT, NdLst)
    908610                    {
    909                         size_t      cbData = pDataPktHdr->cb - cbMin;
    910                         const void *pvData = (const char *)pDataPktHdr + cbMin;
    911                         uint32_t    uCrc32 = *(uint32_t const *)(pDataPktHdr + 1);
    912 
    913                         uMyCrc32 = RTCrc32Process(uMyCrc32, pvData, cbData);
    914                         if (RTCrc32Finish(uMyCrc32) == uCrc32)
     611                        RTListNodeRemove(&pIt->NdLst);
     612                        Assert(cClientsCur <= cClientsMax);
     613                        if (cClientsCur == cClientsMax)
    915614                        {
    916                             rc = RTFileWrite(hFile, pvData, cbData, NULL);
     615                            /* Realloc to accommodate for the new clients. */
     616                            PUTSCLIENT *papClientsNew = (PUTSCLIENT *)RTMemRealloc(papClients, (cClientsMax + 10) * sizeof(PUTSCLIENT));
     617                            if (RT_LIKELY(papClientsNew))
     618                            {
     619                                cClientsMax += 10;
     620                                papClients = papClientsNew;
     621                            }
     622                        }
     623
     624                        if (cClientsCur < cClientsMax)
     625                        {
     626                            /* Find a free slot in the client array. */
     627                            unsigned idxSlt = 0;
     628                            while (   idxSlt < cClientsMax
     629                                   && papClients[idxSlt] != NULL)
     630                                idxSlt++;
     631
     632                            rc = g_pTransport->pfnPollSetAdd(hPollSet, pIt->pTransportClient, idxSlt + 1);
    917633                            if (RT_SUCCESS(rc))
    918634                            {
    919                                 rc = txsReplyAck(pDataPktHdr);
    920                                 RTMemFree(pDataPktHdr);
    921                                 continue;
     635                                cClientsCur++;
     636                                papClients[idxSlt] = pIt;
    922637                            }
    923 
    924                             rc = txsReplyRC(pDataPktHdr, rc, "RTFileWrite");
     638                            else
     639                            {
     640                                g_pTransport->pfnNotifyBye(pIt->pTransportClient);
     641                                utsClientDestroy(pIt);
     642                            }
    925643                        }
    926644                        else
    927                             rc = txsReplyFailure(pDataPktHdr, "BAD DCRC", "mycrc=%#x your=%#x", uMyCrc32, uCrc32);
     645                        {
     646                            g_pTransport->pfnNotifyBye(pIt->pTransportClient);
     647                            utsClientDestroy(pIt);
     648                        }
    928649                    }
    929                     else
    930                         rc = txsReplyBadMinSize(pPktHdr, cbMin);
    931                 }
    932                 else if (txsIsSameOpcode(pDataPktHdr, "DATA EOF"))
    933                 {
    934                     if (pDataPktHdr->cb == sizeof(TXSPKTHDR) + sizeof(uint32_t))
    935                     {
    936                         uint32_t    uCrc32 = *(uint32_t const *)(pDataPktHdr + 1);
    937                         if (RTCrc32Finish(uMyCrc32) == uCrc32)
    938                         {
    939                             rc = txsReplyAck(pDataPktHdr);
    940                             fSuccess = RT_SUCCESS(rc);
    941                         }
    942                         else
    943                             rc = txsReplyFailure(pDataPktHdr, "BAD DCRC", "mycrc=%#x your=%#x", uMyCrc32, uCrc32);
    944                     }
    945                     else
    946                         rc = txsReplyAck(pDataPktHdr);
    947                 }
    948                 else if (txsIsSameOpcode(pDataPktHdr, "ABORT"))
    949                     rc = txsReplyAck(pDataPktHdr);
    950                 else
    951                     rc = txsReplyFailure(pDataPktHdr, "UNKNOWN ", "Opcode '%.8s' is not known or not recognized during PUT FILE", pDataPktHdr->achOpcode);
    952                 RTMemFree(pDataPktHdr);
    953                 break;
    954             }
    955         }
    956 
    957         RTFileClose(hFile);
    958 
    959         /*
    960          * Delete the file on failure.
    961          */
    962         if (!fSuccess)
    963             RTFileDelete(pszPath);
    964     }
    965     else
    966         rc = txsReplyRC(pPktHdr, rc, "RTFileOpen(,\"%s\",)", pszPath);
    967 
    968     RTStrFree(pszPath);
    969     return rc;
    970 }
    971 
    972 /**
    973  * List the entries in the specified directory.
    974  *
    975  * @returns IPRT status code from send.
    976  * @param   pPktHdr             The list packet.
    977  */
    978 static int txsDoList(PCTXSPKTHDR pPktHdr)
    979 {
    980     int rc;
    981     char *pszPath;
    982     if (!txsIsStringPktValid(pPktHdr, "dir", &pszPath, &rc))
    983         return rc;
    984 
    985     rc = txsReplyNotImplemented(pPktHdr);
    986 
    987     RTStrFree(pszPath);
    988     return rc;
    989 }
    990 
    991 
    992 /**
    993  * Get info about a file system object, following all but the symbolic links
    994  * except in the final path component.
    995  *
    996  * @returns IPRT status code from send.
    997  * @param   pPktHdr             The lstat packet.
    998  */
    999 static int txsDoLStat(PCTXSPKTHDR pPktHdr)
    1000 {
    1001     int rc;
    1002     char *pszPath;
    1003     if (!txsIsStringPktValid(pPktHdr, "path", &pszPath, &rc))
    1004         return rc;
    1005 
    1006     RTFSOBJINFO Info;
    1007     rc = RTPathQueryInfoEx(pszPath, &Info, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
    1008     if (RT_SUCCESS(rc))
    1009         /** @todo figure out how to format the return buffer here. */
    1010         rc = txsReplyNotImplemented(pPktHdr);
    1011     else
    1012         rc = txsReplyRC(pPktHdr, rc, "RTPathQueryInfoEx(\"%s\",,UNIX,ON_LINK)",  pszPath);
    1013 
    1014     RTStrFree(pszPath);
    1015     return rc;
    1016 }
    1017 
    1018 /**
    1019  * Get info about a file system object, following all symbolic links.
    1020  *
    1021  * @returns IPRT status code from send.
    1022  * @param   pPktHdr             The stat packet.
    1023  */
    1024 static int txsDoStat(PCTXSPKTHDR pPktHdr)
    1025 {
    1026     int rc;
    1027     char *pszPath;
    1028     if (!txsIsStringPktValid(pPktHdr, "path", &pszPath, &rc))
    1029         return rc;
    1030 
    1031     RTFSOBJINFO Info;
    1032     rc = RTPathQueryInfoEx(pszPath, &Info, RTFSOBJATTRADD_UNIX, RTPATH_F_FOLLOW_LINK);
    1033     if (RT_SUCCESS(rc))
    1034         /** @todo figure out how to format the return buffer here. */
    1035         rc = txsReplyNotImplemented(pPktHdr);
    1036     else
    1037         rc = txsReplyRC(pPktHdr, rc, "RTPathQueryInfoEx(\"%s\",,UNIX,FOLLOW_LINK)",  pszPath);
    1038 
    1039     RTStrFree(pszPath);
    1040     return rc;
    1041 }
    1042 
    1043 /**
    1044  * Checks if the specified path is a symbolic link.
    1045  *
    1046  * @returns IPRT status code from send.
    1047  * @param   pPktHdr             The issymlnk packet.
    1048  */
    1049 static int txsDoIsSymlnk(PCTXSPKTHDR pPktHdr)
    1050 {
    1051     int rc;
    1052     char *pszPath;
    1053     if (!txsIsStringPktValid(pPktHdr, "symlink", &pszPath, &rc))
    1054         return rc;
    1055 
    1056     RTFSOBJINFO Info;
    1057     rc = RTPathQueryInfoEx(pszPath, &Info, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
    1058     if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(Info.Attr.fMode))
    1059         rc = txsReplySimple(pPktHdr, "TRUE    ");
    1060     else
    1061         rc = txsReplySimple(pPktHdr, "FALSE   ");
    1062 
    1063     RTStrFree(pszPath);
    1064     return rc;
    1065 }
    1066 
    1067 /**
    1068  * Checks if the specified path is a file or not.
    1069  *
    1070  * If the final path element is a symbolic link to a file, we'll return
    1071  * FALSE.
    1072  *
    1073  * @returns IPRT status code from send.
    1074  * @param   pPktHdr             The isfile packet.
    1075  */
    1076 static int txsDoIsFile(PCTXSPKTHDR pPktHdr)
    1077 {
    1078     int rc;
    1079     char *pszPath;
    1080     if (!txsIsStringPktValid(pPktHdr, "dir", &pszPath, &rc))
    1081         return rc;
    1082 
    1083     RTFSOBJINFO Info;
    1084     rc = RTPathQueryInfoEx(pszPath, &Info, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
    1085     if (RT_SUCCESS(rc) && RTFS_IS_FILE(Info.Attr.fMode))
    1086         rc = txsReplySimple(pPktHdr, "TRUE    ");
    1087     else
    1088         rc = txsReplySimple(pPktHdr, "FALSE   ");
    1089 
    1090     RTStrFree(pszPath);
    1091     return rc;
    1092 }
    1093 
    1094 /**
    1095  * Checks if the specified path is a directory or not.
    1096  *
    1097  * If the final path element is a symbolic link to a directory, we'll return
    1098  * FALSE.
    1099  *
    1100  * @returns IPRT status code from send.
    1101  * @param   pPktHdr             The isdir packet.
    1102  */
    1103 static int txsDoIsDir(PCTXSPKTHDR pPktHdr)
    1104 {
    1105     int rc;
    1106     char *pszPath;
    1107     if (!txsIsStringPktValid(pPktHdr, "dir", &pszPath, &rc))
    1108         return rc;
    1109 
    1110     RTFSOBJINFO Info;
    1111     rc = RTPathQueryInfoEx(pszPath, &Info, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
    1112     if (RT_SUCCESS(rc) && RTFS_IS_DIRECTORY(Info.Attr.fMode))
    1113         rc = txsReplySimple(pPktHdr, "TRUE    ");
    1114     else
    1115         rc = txsReplySimple(pPktHdr, "FALSE   ");
    1116 
    1117     RTStrFree(pszPath);
    1118     return rc;
    1119 }
    1120 
    1121 /**
    1122  * Changes the group of a file, directory of symbolic link.
    1123  *
    1124  * @returns IPRT status code from send.
    1125  * @param   pPktHdr             The chmod packet.
    1126  */
    1127 static int txsDoChGrp(PCTXSPKTHDR pPktHdr)
    1128 {
    1129     return txsReplyNotImplemented(pPktHdr);
    1130 }
    1131 
    1132 /**
    1133  * Changes the owner of a file, directory of symbolic link.
    1134  *
    1135  * @returns IPRT status code from send.
    1136  * @param   pPktHdr             The chmod packet.
    1137  */
    1138 static int txsDoChOwn(PCTXSPKTHDR pPktHdr)
    1139 {
    1140     return txsReplyNotImplemented(pPktHdr);
    1141 }
    1142 
    1143 /**
    1144  * Changes the mode of a file or directory.
    1145  *
    1146  * @returns IPRT status code from send.
    1147  * @param   pPktHdr             The chmod packet.
    1148  */
    1149 static int txsDoChMod(PCTXSPKTHDR pPktHdr)
    1150 {
    1151     return txsReplyNotImplemented(pPktHdr);
    1152 }
    1153 
    1154 /**
    1155  * Removes a directory tree.
    1156  *
    1157  * @returns IPRT status code from send.
    1158  * @param   pPktHdr             The rmtree packet.
    1159  */
    1160 static int txsDoRmTree(PCTXSPKTHDR pPktHdr)
    1161 {
    1162     int rc;
    1163     char *pszPath;
    1164     if (!txsIsStringPktValid(pPktHdr, "dir", &pszPath, &rc))
    1165         return rc;
    1166 
    1167     rc = RTDirRemoveRecursive(pszPath, 0 /*fFlags*/);
    1168 
    1169     rc = txsReplyRC(pPktHdr, rc, "RTDirRemoveRecusive(\"%s\",0)", pszPath);
    1170     RTStrFree(pszPath);
    1171     return rc;
    1172 }
    1173 
    1174 /**
    1175  * Removes a symbolic link.
    1176  *
    1177  * @returns IPRT status code from send.
    1178  * @param   pPktHdr             The rmsymlink packet.
    1179  */
    1180 static int txsDoRmSymlnk(PCTXSPKTHDR pPktHdr)
    1181 {
    1182     int rc;
    1183     char *pszPath;
    1184     if (!txsIsStringPktValid(pPktHdr, "symlink", &pszPath, &rc))
    1185         return rc;
    1186 
    1187     rc = VERR_NOT_IMPLEMENTED; /// @todo RTSymlinkDelete(pszPath);
    1188 
    1189     rc = txsReplyRC(pPktHdr, rc, "RTSymlinkDelete(\"%s\")", pszPath);
    1190     RTStrFree(pszPath);
    1191     return rc;
    1192 }
    1193 
    1194 /**
    1195  * Removes a file.
    1196  *
    1197  * @returns IPRT status code from send.
    1198  * @param   pPktHdr             The rmfile packet.
    1199  */
    1200 static int txsDoRmFile(PCTXSPKTHDR pPktHdr)
    1201 {
    1202     int rc;
    1203     char *pszPath;
    1204     if (!txsIsStringPktValid(pPktHdr, "file", &pszPath, &rc))
    1205         return rc;
    1206 
    1207     rc = RTFileDelete(pszPath);
    1208 
    1209     rc = txsReplyRC(pPktHdr, rc, "RTFileDelete(\"%s\")", pszPath);
    1210     RTStrFree(pszPath);
    1211     return rc;
    1212 }
    1213 
    1214 /**
    1215  * Removes a directory.
    1216  *
    1217  * @returns IPRT status code from send.
    1218  * @param   pPktHdr             The rmdir packet.
    1219  */
    1220 static int txsDoRmDir(PCTXSPKTHDR pPktHdr)
    1221 {
    1222     int rc;
    1223     char *pszPath;
    1224     if (!txsIsStringPktValid(pPktHdr, "dir", &pszPath, &rc))
    1225         return rc;
    1226 
    1227     rc = RTDirRemove(pszPath);
    1228 
    1229     rc = txsReplyRC(pPktHdr, rc, "RTDirRemove(\"%s\")", pszPath);
    1230     RTStrFree(pszPath);
    1231     return rc;
    1232 }
    1233 
    1234 /**
    1235  * Creates a symbolic link.
    1236  *
    1237  * @returns IPRT status code from send.
    1238  * @param   pPktHdr             The mksymlnk packet.
    1239  */
    1240 static int txsDoMkSymlnk(PCTXSPKTHDR pPktHdr)
    1241 {
    1242     return txsReplyNotImplemented(pPktHdr);
    1243 }
    1244 
    1245 /**
    1246  * Creates a directory and all its parents.
    1247  *
    1248  * @returns IPRT status code from send.
    1249  * @param   pPktHdr             The mkdir -p packet.
    1250  */
    1251 static int txsDoMkDrPath(PCTXSPKTHDR pPktHdr)
    1252 {
    1253     /* The same format as the MKDIR command. */
    1254     if (pPktHdr->cb < sizeof(TXSPKTHDR) + sizeof(RTFMODE) + 2)
    1255         return txsReplyBadMinSize(pPktHdr, sizeof(TXSPKTHDR) + sizeof(RTFMODE) + 2);
    1256 
    1257     int     rc;
    1258     char   *pszPath;
    1259     if (!txsIsStringValid(pPktHdr, "dir", (const char *)(pPktHdr + 1) + sizeof(RTFMODE), &pszPath, NULL, &rc))
    1260         return rc;
    1261 
    1262     RTFMODE fMode = *(RTFMODE const *)(pPktHdr + 1);
    1263     rc = RTDirCreateFullPath(pszPath, fMode);
    1264 
    1265     rc = txsReplyRC(pPktHdr, rc, "RTDirCreateFullPath(\"%s\", %#x)", pszPath, fMode);
    1266     RTStrFree(pszPath);
    1267     return rc;
    1268 }
    1269 
    1270 /**
    1271  * Creates a directory.
    1272  *
    1273  * @returns IPRT status code from send.
    1274  * @param   pPktHdr             The mkdir packet.
    1275  */
    1276 static int txsDoMkDir(PCTXSPKTHDR pPktHdr)
    1277 {
    1278     /* After the packet header follows a mode mask and the remainder of
    1279        the packet is the zero terminated directory name. */
    1280     size_t const cbMin = sizeof(TXSPKTHDR) + sizeof(RTFMODE) + 2;
    1281     if (pPktHdr->cb < cbMin)
    1282         return txsReplyBadMinSize(pPktHdr, cbMin);
    1283 
    1284     int     rc;
    1285     char   *pszPath;
    1286     if (!txsIsStringValid(pPktHdr, "dir", (const char *)(pPktHdr + 1) + sizeof(RTFMODE), &pszPath, NULL, &rc))
    1287         return rc;
    1288 
    1289     RTFMODE fMode = *(RTFMODE const *)(pPktHdr + 1);
    1290     rc = RTDirCreate(pszPath, fMode, 0);
    1291 
    1292     rc = txsReplyRC(pPktHdr, rc, "RTDirCreate(\"%s\", %#x)", pszPath, fMode);
    1293     RTStrFree(pszPath);
    1294     return rc;
    1295 }
    1296 
    1297 /**
    1298  * Cleans up the scratch area.
    1299  *
    1300  * @returns IPRT status code from send.
    1301  * @param   pPktHdr             The shutdown packet.
    1302  */
    1303 static int txsDoCleanup(PCTXSPKTHDR pPktHdr)
    1304 {
    1305     int rc = RTDirRemoveRecursive(g_szScratchPath, RTDIRRMREC_F_CONTENT_ONLY);
    1306     return txsReplyRC(pPktHdr, rc, "RTDirRemoveRecursive(\"%s\", CONTENT_ONLY)", g_szScratchPath);
    1307 }
    1308 
    1309 /**
    1310  * Ejects the specified DVD/CD drive.
    1311  *
    1312  * @returns IPRT status code from send.
    1313  * @param   pPktHdr             The eject packet.
    1314  */
    1315 static int txsDoCdEject(PCTXSPKTHDR pPktHdr)
    1316 {
    1317     /* After the packet header follows a uint32_t ordinal. */
    1318     size_t const cbExpected = sizeof(TXSPKTHDR) + sizeof(uint32_t);
    1319     if (pPktHdr->cb != cbExpected)
    1320         return txsReplyBadSize(pPktHdr, cbExpected);
    1321     uint32_t iOrdinal = *(uint32_t const *)(pPktHdr + 1);
    1322 
    1323     RTCDROM hCdrom;
    1324     int rc = RTCdromOpenByOrdinal(iOrdinal, RTCDROM_O_CONTROL, &hCdrom);
    1325     if (RT_FAILURE(rc))
    1326         return txsReplyRC(pPktHdr, rc, "RTCdromOpenByOrdinal(%u, RTCDROM_O_CONTROL, )", iOrdinal);
    1327     rc = RTCdromEject(hCdrom, true /*fForce*/);
    1328     RTCdromRelease(hCdrom);
    1329 
    1330     return txsReplyRC(pPktHdr, rc, "RTCdromEject(ord=%u, fForce=true)", iOrdinal);
    1331 }
    1332 
    1333 /**
    1334  * Common worker for txsDoShutdown and txsDoReboot.
    1335  *
    1336  * @returns IPRT status code from send.
    1337  * @param   pPktHdr             The reboot packet.
    1338  * @param   fAction             Which action to take.
    1339  */
    1340 static int txsCommonShutdownReboot(PCTXSPKTHDR pPktHdr, uint32_t fAction)
    1341 {
    1342     /*
    1343      * We ACK the reboot & shutdown before actually performing them, then we
    1344      * terminate the transport layer.
    1345      *
    1346      * This is to make sure the client isn't stuck with a dead connection. The
    1347      * transport layer termination also make sure we won't accept new
    1348      * connections in case the client is too eager to reconnect to a rebooted
    1349      * test victim.  On the down side, we cannot easily report RTSystemShutdown
    1350      * failures failures this way.  But the client can kind of figure it out by
    1351      * reconnecting and seeing that our UUID was unchanged.
    1352      */
    1353     int rc;
    1354     if (pPktHdr->cb != sizeof(TXSPKTHDR))
    1355         return txsReplyBadSize(pPktHdr, sizeof(TXSPKTHDR));
    1356     g_pTransport->pfnNotifyReboot();
    1357     rc = txsReplyAck(pPktHdr);
    1358     RTThreadSleep(2560);                /* fudge factor */
    1359     g_pTransport->pfnTerm();
    1360 
    1361     /*
    1362      * Do the job, if it fails we'll restart the transport layer.
    1363      */
    1364 #if 0
    1365     rc = VINF_SUCCESS;
    1366 #else
    1367     rc = RTSystemShutdown(0 /*cMsDelay*/,
    1368                           fAction | RTSYSTEM_SHUTDOWN_PLANNED | RTSYSTEM_SHUTDOWN_FORCE,
    1369                           "Test Execution Service");
    1370 #endif
    1371     if (RT_SUCCESS(rc))
    1372     {
    1373         RTMsgInfo(fAction == RTSYSTEM_SHUTDOWN_REBOOT ? "Rebooting...\n" : "Shutting down...\n");
    1374         g_fTerminate = true;
    1375     }
    1376     else
    1377     {
    1378         RTMsgError("RTSystemShutdown w/ fAction=%#x failed: %Rrc", fAction, rc);
    1379 
    1380         int rc2 = g_pTransport->pfnInit();
    1381         if (RT_FAILURE(rc2))
    1382         {
    1383             g_fTerminate = true;
    1384             rc = rc2;
    1385         }
    1386     }
    1387     return rc;
    1388 }
    1389 
    1390 /**
    1391  * Shuts down the machine, powering it off if possible.
    1392  *
    1393  * @returns IPRT status code from send.
    1394  * @param   pPktHdr             The shutdown packet.
    1395  */
    1396 static int txsDoShutdown(PCTXSPKTHDR pPktHdr)
    1397 {
    1398     return txsCommonShutdownReboot(pPktHdr, RTSYSTEM_SHUTDOWN_POWER_OFF_HALT);
    1399 }
    1400 
    1401 /**
    1402  * Reboots the machine.
    1403  *
    1404  * @returns IPRT status code from send.
    1405  * @param   pPktHdr             The reboot packet.
    1406  */
    1407 static int txsDoReboot(PCTXSPKTHDR pPktHdr)
    1408 {
    1409     return txsCommonShutdownReboot(pPktHdr, RTSYSTEM_SHUTDOWN_REBOOT);
    1410 }
    1411 
    1412 /**
    1413  * Verifies and acknowledges a "UUID" request.
    1414  *
    1415  * @returns IPRT status code.
    1416  * @param   pPktHdr             The howdy packet.
    1417  */
    1418 static int txsDoUuid(PCTXSPKTHDR pPktHdr)
    1419 {
    1420     if (pPktHdr->cb != sizeof(TXSPKTHDR))
    1421         return txsReplyBadSize(pPktHdr, sizeof(TXSPKTHDR));
    1422 
    1423     struct
    1424     {
    1425         TXSPKTHDR   Hdr;
    1426         char        szUuid[RTUUID_STR_LENGTH];
    1427         char        abPadding[TXSPKT_ALIGNMENT];
    1428     } Pkt;
    1429 
    1430     int rc = RTUuidToStr(&g_InstanceUuid, Pkt.szUuid, sizeof(Pkt.szUuid));
    1431     if (RT_FAILURE(rc))
    1432         return txsReplyRC(pPktHdr, rc, "RTUuidToStr");
    1433     return txsReplyInternal(&Pkt.Hdr, "ACK UUID", strlen(Pkt.szUuid) + 1);
    1434 }
    1435 
    1436 /**
    1437  * Verifies and acknowledges a "BYE" request.
    1438  *
    1439  * @returns IPRT status code.
    1440  * @param   pPktHdr             The howdy packet.
    1441  */
    1442 static int txsDoBye(PCTXSPKTHDR pPktHdr)
    1443 {
    1444     int rc;
    1445     if (pPktHdr->cb == sizeof(TXSPKTHDR))
    1446         rc = txsReplyAck(pPktHdr);
    1447     else
    1448         rc = txsReplyBadSize(pPktHdr, sizeof(TXSPKTHDR));
    1449     g_pTransport->pfnNotifyBye();
    1450     return rc;
    1451 }
    1452 
    1453 /**
    1454  * Verifies and acknowledges a "HOWDY" request.
    1455  *
    1456  * @returns IPRT status code.
    1457  * @param   pPktHdr             The howdy packet.
    1458  */
    1459 static int txsDoHowdy(PCTXSPKTHDR pPktHdr)
    1460 {
    1461     if (pPktHdr->cb != sizeof(TXSPKTHDR))
    1462         return txsReplyBadSize(pPktHdr, sizeof(TXSPKTHDR));
    1463     int rc = txsReplyAck(pPktHdr);
    1464     if (RT_SUCCESS(rc))
    1465     {
    1466         g_pTransport->pfnNotifyHowdy();
    1467         RTDirRemoveRecursive(g_szScratchPath, RTDIRRMREC_F_CONTENT_ONLY);
    1468     }
    1469     return rc;
    1470 }
    1471 
    1472 /**
    1473  * Replies according to the return code.
    1474  *
    1475  * @returns rcOperation and pTxsExec->rcReplySend.
    1476  * @param   pTxsExec            The TXSEXEC instance.
    1477  * @param   rcOperation         The status code to report.
    1478  * @param   pszOperationFmt     The operation that failed.  Typically giving the
    1479  *                              function call with important arguments.
    1480  * @param   ...                 Arguments to the format string.
    1481  */
    1482 static int txsExecReplyRC(PTXSEXEC pTxsExec, int rcOperation, const char *pszOperationFmt, ...)
    1483 {
    1484     AssertStmt(RT_FAILURE_NP(rcOperation), rcOperation = VERR_IPE_UNEXPECTED_INFO_STATUS);
    1485 
    1486     char    szOperation[128];
    1487     va_list va;
    1488     va_start(va, pszOperationFmt);
    1489     RTStrPrintfV(szOperation, sizeof(szOperation), pszOperationFmt, va);
    1490     va_end(va);
    1491 
    1492     pTxsExec->rcReplySend = txsReplyFailure(pTxsExec->pPktHdr, "FAILED  ",
    1493                                             "%s failed with rc=%Rrc (opcode '%.8s')",
    1494                                             szOperation, rcOperation, pTxsExec->pPktHdr->achOpcode);
    1495     return rcOperation;
    1496 }
    1497 
    1498 
    1499 /**
    1500  * Sends the process exit status reply to the TXS client.
    1501  *
    1502  * @returns IPRT status code of the send.
    1503  * @param   pTxsExec            The TXSEXEC instance.
    1504  * @param   fProcessAlive       Whether the process is still alive (against our
    1505  *                              will).
    1506  * @param   fProcessTimedOut    Whether the process timed out.
    1507  * @param   MsProcessKilled     When the process was killed, UINT64_MAX if not.
    1508  */
    1509 static int txsExecSendExitStatus(PTXSEXEC pTxsExec, bool fProcessAlive, bool fProcessTimedOut, uint64_t MsProcessKilled)
    1510 {
    1511     int rc;
    1512     if (     fProcessTimedOut  && !fProcessAlive && MsProcessKilled != UINT64_MAX)
    1513     {
    1514         rc = txsReplySimple(pTxsExec->pPktHdr, "PROC TOK");
    1515         if (g_fDisplayOutput)
    1516             RTPrintf("txs: Process timed out and was killed\n");
    1517     }
    1518     else if (fProcessTimedOut  &&  fProcessAlive && MsProcessKilled != UINT64_MAX)
    1519     {
    1520         rc = txsReplySimple(pTxsExec->pPktHdr, "PROC TOA");
    1521         if (g_fDisplayOutput)
    1522             RTPrintf("txs: Process timed out and was not killed successfully\n");
    1523     }
    1524     else if (g_fTerminate && (fProcessAlive || MsProcessKilled != UINT64_MAX))
    1525         rc = txsReplySimple(pTxsExec->pPktHdr, "PROC DWN");
    1526     else if (fProcessAlive)
    1527     {
    1528         rc = txsReplyFailure(pTxsExec->pPktHdr, "PROC DOO", "Doofus! process is alive when it should not");
    1529         AssertFailed();
    1530     }
    1531     else if (MsProcessKilled != UINT64_MAX)
    1532     {
    1533         rc = txsReplyFailure(pTxsExec->pPktHdr, "PROC DOO", "Doofus! process has been killed when it should not");
    1534         AssertFailed();
    1535     }
    1536     else if (   pTxsExec->ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL
    1537              && pTxsExec->ProcessStatus.iStatus   == 0)
    1538     {
    1539         rc = txsReplySimple(pTxsExec->pPktHdr, "PROC OK ");
    1540         if (g_fDisplayOutput)
    1541             RTPrintf("txs: Process exited with status: 0\n");
    1542     }
    1543     else if (pTxsExec->ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL)
    1544     {
    1545         rc = txsReplyFailure(pTxsExec->pPktHdr, "PROC NOK", "%d", pTxsExec->ProcessStatus.iStatus);
    1546         if (g_fDisplayOutput)
    1547             RTPrintf("txs: Process exited with status: %d\n", pTxsExec->ProcessStatus.iStatus);
    1548     }
    1549     else if (pTxsExec->ProcessStatus.enmReason == RTPROCEXITREASON_SIGNAL)
    1550     {
    1551         rc = txsReplyFailure(pTxsExec->pPktHdr, "PROC SIG", "%d", pTxsExec->ProcessStatus.iStatus);
    1552         if (g_fDisplayOutput)
    1553             RTPrintf("txs: Process exited with status: signal %d\n", pTxsExec->ProcessStatus.iStatus);
    1554     }
    1555     else if (pTxsExec->ProcessStatus.enmReason == RTPROCEXITREASON_ABEND)
    1556     {
    1557         rc = txsReplyFailure(pTxsExec->pPktHdr, "PROC ABD", "");
    1558         if (g_fDisplayOutput)
    1559             RTPrintf("txs: Process exited with status: abend\n");
    1560     }
    1561     else
    1562     {
    1563         rc = txsReplyFailure(pTxsExec->pPktHdr, "PROC DOO", "enmReason=%d iStatus=%d",
    1564                              pTxsExec->ProcessStatus.enmReason, pTxsExec->ProcessStatus.iStatus);
    1565         AssertMsgFailed(("enmReason=%d iStatus=%d", pTxsExec->ProcessStatus.enmReason, pTxsExec->ProcessStatus.iStatus));
    1566     }
    1567     return rc;
    1568 }
    1569 
    1570 /**
    1571  * Handle pending output data or error on standard out, standard error or the
    1572  * test pipe.
    1573  *
    1574  * @returns IPRT status code from client send.
    1575  * @param   hPollSet            The polling set.
    1576  * @param   fPollEvt            The event mask returned by RTPollNoResume.
    1577  * @param   phPipeR             The pipe handle.
    1578  * @param   pu32Crc             The current CRC-32 of the stream. (In/Out)
    1579  * @param   enmHndId            The handle ID.
    1580  * @param   pszOpcode           The opcode for the data upload.
    1581  *
    1582  * @todo    Put the last 4 parameters into a struct!
    1583  */
    1584 static int txsDoExecHlpHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phPipeR,
    1585                                          uint32_t *puCrc32, TXSEXECHNDID enmHndId, const char *pszOpcode)
    1586 {
    1587     Log(("txsDoExecHlpHandleOutputEvent: %s fPollEvt=%#x\n", pszOpcode, fPollEvt));
    1588 
    1589     /*
    1590      * Try drain the pipe before acting on any errors.
    1591      */
    1592     int rc = VINF_SUCCESS;
    1593     struct
    1594     {
    1595         TXSPKTHDR   Hdr;
    1596         uint32_t    uCrc32;
    1597         char        abBuf[_64K];
    1598         char        abPadding[TXSPKT_ALIGNMENT];
    1599     }       Pkt;
    1600     size_t  cbRead;
    1601     int     rc2 = RTPipeRead(*phPipeR, Pkt.abBuf, sizeof(Pkt.abBuf), &cbRead);
    1602     if (RT_SUCCESS(rc2) && cbRead)
    1603     {
    1604         Log(("Crc32=%#x ", *puCrc32));
    1605         *puCrc32 = RTCrc32Process(*puCrc32, Pkt.abBuf, cbRead);
    1606         Log(("cbRead=%#x Crc32=%#x \n", cbRead, *puCrc32));
    1607         Pkt.uCrc32 = RTCrc32Finish(*puCrc32);
    1608         if (g_fDisplayOutput)
    1609         {
    1610             if (enmHndId == TXSEXECHNDID_STDOUT)
    1611                 RTStrmPrintf(g_pStdErr, "%.*s", cbRead, Pkt.abBuf);
    1612             else if (enmHndId == TXSEXECHNDID_STDERR)
    1613                 RTStrmPrintf(g_pStdErr, "%.*s", cbRead, Pkt.abBuf);
    1614         }
    1615 
    1616         rc = txsReplyInternal(&Pkt.Hdr, pszOpcode, cbRead + sizeof(uint32_t));
    1617 
    1618         /* Make sure we go another poll round in case there was too much data
    1619            for the buffer to hold. */
    1620         fPollEvt &= RTPOLL_EVT_ERROR;
    1621     }
    1622     else if (RT_FAILURE(rc2))
    1623     {
    1624         fPollEvt |= RTPOLL_EVT_ERROR;
    1625         AssertMsg(rc2 == VERR_BROKEN_PIPE, ("%Rrc\n", rc));
    1626     }
    1627 
    1628     /*
    1629      * If an error was raised signalled,
    1630      */
    1631     if (fPollEvt & RTPOLL_EVT_ERROR)
    1632     {
    1633         rc2 = RTPollSetRemove(hPollSet, enmHndId);
    1634         AssertRC(rc2);
    1635 
    1636         rc2 = RTPipeClose(*phPipeR);
    1637         AssertRC(rc2);
    1638         *phPipeR = NIL_RTPIPE;
    1639     }
    1640     return rc;
    1641 }
    1642 
    1643 /**
    1644  * Try write some more data to the standard input of the child.
    1645  *
    1646  * @returns IPRT status code.
    1647  * @param   pStdInBuf           The standard input buffer.
    1648  * @param   hStdInW             The standard input pipe.
    1649  */
    1650 static int txsDoExecHlpWriteStdIn(PTXSEXECSTDINBUF pStdInBuf, RTPIPE hStdInW)
    1651 {
    1652     size_t  cbToWrite = pStdInBuf->cb - pStdInBuf->off;
    1653     size_t  cbWritten;
    1654     int     rc = RTPipeWrite(hStdInW, &pStdInBuf->pch[pStdInBuf->off], cbToWrite, &cbWritten);
    1655     if (RT_SUCCESS(rc))
    1656     {
    1657         Assert(cbWritten == cbToWrite);
    1658         pStdInBuf->off += cbWritten;
    1659     }
    1660     return rc;
    1661 }
    1662 
    1663 /**
    1664  * Handle an error event on standard input.
    1665  *
    1666  * @param   hPollSet            The polling set.
    1667  * @param   fPollEvt            The event mask returned by RTPollNoResume.
    1668  * @param   phStdInW            The standard input pipe handle.
    1669  * @param   pStdInBuf           The standard input buffer.
    1670  */
    1671 static void txsDoExecHlpHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW,
    1672                                               PTXSEXECSTDINBUF pStdInBuf)
    1673 {
    1674     NOREF(fPollEvt);
    1675     int rc2;
    1676     if (pStdInBuf->off < pStdInBuf->cb)
    1677     {
    1678         rc2 = RTPollSetRemove(hPollSet, TXSEXECHNDID_STDIN_WRITABLE);
    1679         AssertRC(rc2);
    1680     }
    1681 
    1682     rc2 = RTPollSetRemove(hPollSet, TXSEXECHNDID_STDIN);
    1683     AssertRC(rc2);
    1684 
    1685     rc2 = RTPipeClose(*phStdInW);
    1686     AssertRC(rc2);
    1687     *phStdInW = NIL_RTPIPE;
    1688 
    1689     RTMemFree(pStdInBuf->pch);
    1690     pStdInBuf->pch          = NULL;
    1691     pStdInBuf->off          = 0;
    1692     pStdInBuf->cb           = 0;
    1693     pStdInBuf->cbAllocated  = 0;
    1694     pStdInBuf->fBitBucket   = true;
    1695 }
    1696 
    1697 /**
    1698  * Handle an event indicating we can write to the standard input pipe of the
    1699  * child process.
    1700  *
    1701  * @param   hPollSet            The polling set.
    1702  * @param   fPollEvt            The event mask returned by RTPollNoResume.
    1703  * @param   phStdInW            The standard input pipe.
    1704  * @param   pStdInBuf           The standard input buffer.
    1705  */
    1706 static void txsDoExecHlpHandleStdInWritableEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW,
    1707                                                  PTXSEXECSTDINBUF pStdInBuf)
    1708 {
    1709     int rc;
    1710     if (!(fPollEvt & RTPOLL_EVT_ERROR))
    1711     {
    1712         rc = txsDoExecHlpWriteStdIn(pStdInBuf, *phStdInW);
    1713         if (RT_FAILURE(rc) && rc != VERR_BAD_PIPE)
    1714         {
    1715             /** @todo do we need to do something about this error condition? */
    1716             AssertRC(rc);
    1717         }
    1718 
    1719         if (pStdInBuf->off < pStdInBuf->cb)
    1720         {
    1721             rc = RTPollSetRemove(hPollSet, TXSEXECHNDID_STDIN_WRITABLE);
    1722             AssertRC(rc);
    1723         }
    1724     }
    1725     else
    1726         txsDoExecHlpHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW, pStdInBuf);
    1727 }
    1728 
    1729 /**
    1730  * Handle a transport event or successful pfnPollIn() call.
    1731  *
    1732  * @returns IPRT status code from client send.
    1733  * @retval  VINF_EOF indicates ABORT command.
    1734  *
    1735  * @param   hPollSet            The polling set.
    1736  * @param   fPollEvt            The event mask returned by RTPollNoResume.
    1737  * @param   idPollHnd           The handle ID.
    1738  * @param   hStdInW             The standard input pipe.
    1739  * @param   pStdInBuf           The standard input buffer.
    1740  */
    1741 static int txsDoExecHlpHandleTransportEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, uint32_t idPollHnd,
    1742                                             PRTPIPE phStdInW, PTXSEXECSTDINBUF pStdInBuf)
    1743 {
    1744     /* ASSUMES the transport layer will detect or clear any error condition. */
    1745     NOREF(fPollEvt); NOREF(idPollHnd);
    1746     Log(("txsDoExecHlpHandleTransportEvent\n"));
    1747     /** @todo Use a callback for this case? */
    1748 
    1749     /*
    1750      * Read client command packet and process it.
    1751      */
    1752     /** @todo Sometimes this hangs on windows because there isn't any data pending.
    1753      * We probably get woken up at the wrong time or in the wrong way, i.e. RTPoll()
    1754      * is busted for sockets.
    1755      *
    1756      * Temporary workaround: Poll for input before trying to read it. */
    1757     if (!g_pTransport->pfnPollIn())
    1758     {
    1759         Log(("Bad transport event\n"));
    1760         RTThreadYield();
    1761         return VINF_SUCCESS;
    1762     }
    1763     PTXSPKTHDR pPktHdr;
    1764     int rc = txsRecvPkt(&pPktHdr, false /*fAutoRetryOnFailure*/);
    1765     if (RT_FAILURE(rc))
    1766         return rc;
    1767     Log(("Bad transport event\n"));
    1768 
    1769     /*
    1770      * The most common thing here would be a STDIN request with data
    1771      * for the child process.
    1772      */
    1773     if (txsIsSameOpcode(pPktHdr, "STDIN"))
    1774     {
    1775         if (   !pStdInBuf->fBitBucket
    1776             && pPktHdr->cb >= sizeof(TXSPKTHDR) + sizeof(uint32_t))
    1777         {
    1778             uint32_t    uCrc32  = *(uint32_t *)(pPktHdr + 1);
    1779             const char *pch     = (const char *)(pPktHdr + 1) + sizeof(uint32_t);
    1780             size_t      cb      = pPktHdr->cb - sizeof(TXSPKTHDR) - sizeof(uint32_t);
    1781 
    1782             /* Check the CRC */
    1783             pStdInBuf->uCrc32 = RTCrc32Process(pStdInBuf->uCrc32, pch, cb);
    1784             if (pStdInBuf->uCrc32 == uCrc32)
    1785             {
    1786 
    1787                 /* Rewind the buffer if it's empty. */
    1788                 size_t      cbInBuf   = pStdInBuf->cb - pStdInBuf->off;
    1789                 bool const  fAddToSet = cbInBuf == 0;
    1790                 if (fAddToSet)
    1791                     pStdInBuf->cb = pStdInBuf->off = 0;
    1792 
    1793                 /* Try and see if we can simply append the data. */
    1794                 if (cb + pStdInBuf->cb <= pStdInBuf->cbAllocated)
    1795                 {
    1796                     memcpy(&pStdInBuf->pch[pStdInBuf->cb], pch, cb);
    1797                     pStdInBuf->cb += cb;
    1798                     rc = txsReplyAck(pPktHdr);
     650                    RTCritSectLeave(&g_CritSectClients);
    1799651                }
    1800652                else
    1801653                {
    1802                     /* Try write a bit or two before we move+realloc the buffer. */
    1803                     if (cbInBuf > 0)
    1804                         txsDoExecHlpWriteStdIn(pStdInBuf, *phStdInW);
    1805 
    1806                     /* Move any buffered data to the front. */
    1807                     cbInBuf = pStdInBuf->cb - pStdInBuf->off;
    1808                     if (cbInBuf == 0)
    1809                         pStdInBuf->cb = pStdInBuf->off = 0;
    1810                     else
     654                    /* Client sends a request, pick the right client and process it. */
     655                    PUTSCLIENT pClient = papClients[uId - 1];
     656                    if (fEvts & RTPOLL_EVT_READ)
     657                        rc = utsClientReqProcess(pClient);
     658
     659                    if (   (fEvts & RTPOLL_EVT_ERROR)
     660                        || RT_FAILURE(rc))
    1811661                    {
    1812                         memmove(pStdInBuf->pch, &pStdInBuf->pch[pStdInBuf->off], cbInBuf);
    1813                         pStdInBuf->cb  = cbInBuf;
    1814                         pStdInBuf->off = 0;
     662                        /* Close connection and remove client from array. */
     663                        g_pTransport->pfnNotifyBye(pClient->pTransportClient);
     664                        papClients[uId - 1] = NULL;
     665                        cClientsCur--;
     666                        utsClientDestroy(pClient);
    1815667                    }
    1816 
    1817                     /* Do we need to grow the buffer? */
    1818                     if (cb + pStdInBuf->cb > pStdInBuf->cbAllocated)
    1819                     {
    1820                         size_t cbAlloc = pStdInBuf->cb + cb;
    1821                         cbAlloc = RT_ALIGN_Z(cbAlloc, _64K);
    1822                         void *pvNew = RTMemRealloc(pStdInBuf->pch, cbAlloc);
    1823                         if (pvNew)
    1824                         {
    1825                             pStdInBuf->pch         = (char *)pvNew;
    1826                             pStdInBuf->cbAllocated = cbAlloc;
    1827                         }
    1828                     }
    1829 
    1830                     /* Finally, copy the data. */
    1831                     if (cb + pStdInBuf->cb <= pStdInBuf->cbAllocated)
    1832                     {
    1833                         memcpy(&pStdInBuf->pch[pStdInBuf->cb], pch, cb);
    1834                         pStdInBuf->cb += cb;
    1835                         rc = txsReplyAck(pPktHdr);
    1836                     }
    1837                     else
    1838                         rc = txsReplySimple(pPktHdr, "STDINMEM");
    1839                 }
    1840 
    1841                 /*
    1842                  * Flush the buffered data and add/remove the standard input
    1843                  * handle from the set.
    1844                  */
    1845                 txsDoExecHlpWriteStdIn(pStdInBuf, *phStdInW);
    1846                 if (fAddToSet && pStdInBuf->off < pStdInBuf->cb)
    1847                 {
    1848                     int rc2 = RTPollSetAddPipe(hPollSet, *phStdInW, RTPOLL_EVT_WRITE, TXSEXECHNDID_STDIN_WRITABLE);
    1849                     AssertRC(rc2);
    1850                 }
    1851                 else if (!fAddToSet && pStdInBuf->off >= pStdInBuf->cb)
    1852                 {
    1853                     int rc2 = RTPollSetRemove(hPollSet, TXSEXECHNDID_STDIN_WRITABLE);
    1854                     AssertRC(rc2);
    1855668                }
    1856669            }
    1857             else
    1858                 rc = txsReplySimple(pPktHdr, "STDINCRC");
    1859670        }
    1860         else if (pPktHdr->cb < sizeof(TXSPKTHDR) + sizeof(uint32_t))
    1861             rc = txsReplySimple(pPktHdr, "STDINBAD");
     671    }
     672
     673    RTPollSetDestroy(hPollSet);
     674
     675    return rc;
     676}
     677
     678/**
     679 * The main loop.
     680 *
     681 * @returns exit code.
     682 */
     683static RTEXITCODE utsMainLoop(void)
     684{
     685    RTEXITCODE enmExitCode = RTEXITCODE_SUCCESS;
     686    while (!g_fTerminate)
     687    {
     688        /*
     689         * Wait for new connection and spin off a new thread
     690         * for every new client.
     691         */
     692        PUTSTRANSPORTCLIENT pTransportClient;
     693        int rc = g_pTransport->pfnWaitForConnect(&pTransportClient);
     694        if (RT_FAILURE(rc))
     695            continue;
     696
     697        /*
     698         * New connection, create new client structure and spin of
     699         * the request handling thread.
     700         */
     701        PUTSCLIENT pClient = (PUTSCLIENT)RTMemAllocZ(sizeof(PUTSCLIENT));
     702        if (RT_LIKELY(pClient))
     703        {
     704            pClient->pTransportClient = pTransportClient;
     705        }
    1862706        else
    1863             rc = txsReplySimple(pPktHdr, "STDINIGN");
    1864     }
    1865     /*
    1866      * The only other two requests are connection oriented and we return a error
    1867      * code so that we unwind the whole EXEC shebang and start afresh.
    1868      */
    1869     else if (txsIsSameOpcode(pPktHdr, "BYE"))
    1870     {
    1871         rc = txsDoBye(pPktHdr);
    1872         if (RT_SUCCESS(rc))
    1873             rc = VERR_NET_NOT_CONNECTED;
    1874     }
    1875     else if (txsIsSameOpcode(pPktHdr, "HOWDY"))
    1876     {
    1877         rc = txsDoHowdy(pPktHdr);
    1878         if (RT_SUCCESS(rc))
    1879             rc = VERR_NET_NOT_CONNECTED;
    1880     }
    1881     else if (txsIsSameOpcode(pPktHdr, "ABORT"))
    1882     {
    1883         rc = txsReplyAck(pPktHdr);
    1884         if (RT_SUCCESS(rc))
    1885             rc = VINF_EOF;              /* this is but ugly! */
    1886     }
    1887     else
    1888         rc = txsReplyFailure(pPktHdr, "UNKNOWN ", "Opcode '%.8s' is not known or not recognized during EXEC", pPktHdr->achOpcode);
    1889 
    1890     RTMemFree(pPktHdr);
    1891     return rc;
    1892 }
    1893 
    1894 /**
    1895  * Handles the output and input of the process, waits for it finish up.
    1896  *
    1897  * @returns IPRT status code from reply send.
    1898  * @param   pTxsExec            The TXSEXEC instance.
    1899  */
    1900 static int txsDoExecHlp2(PTXSEXEC pTxsExec)
    1901 {
    1902     int                 rc;             /* client send. */
    1903     int                 rc2;
    1904     TXSEXECSTDINBUF     StdInBuf            = { 0, 0, NULL, 0, pTxsExec->hStdInW == NIL_RTPIPE, RTCrc32Start() };
    1905     uint32_t            uStdOutCrc32        = RTCrc32Start();
    1906     uint32_t            uStdErrCrc32        = uStdOutCrc32;
    1907     uint32_t            uTestPipeCrc32      = uStdOutCrc32;
    1908     uint64_t const      MsStart             = RTTimeMilliTS();
    1909     bool                fProcessTimedOut    = false;
    1910     uint64_t            MsProcessKilled     = UINT64_MAX;
    1911     RTMSINTERVAL const  cMsPollBase         = g_pTransport->pfnPollSetAdd || pTxsExec->hStdInW == NIL_RTPIPE
    1912                                             ? 5000 : 100;
    1913     RTMSINTERVAL        cMsPollCur          = 0;
    1914 
    1915     /*
    1916      * Before entering the loop, tell the client that we've started the guest
    1917      * and that it's now OK to send input to the process.  (This is not the
    1918      * final ACK, so the packet header is NULL ... kind of bogus.)
    1919      */
    1920     rc = txsReplyAck(NULL);
    1921 
    1922     /*
    1923      * Process input, output, the test pipe and client requests.
    1924      */
    1925     while (   RT_SUCCESS(rc)
    1926            && RT_UNLIKELY(!g_fTerminate))
    1927     {
    1928         /*
    1929          * Wait/Process all pending events.
    1930          */
    1931         uint32_t idPollHnd;
    1932         uint32_t fPollEvt;
    1933         Log3(("Calling RTPollNoResume(,%u,)...\n", cMsPollCur));
    1934         rc2 = RTPollNoResume(pTxsExec->hPollSet, cMsPollCur, &fPollEvt, &idPollHnd);
    1935         Log3(("RTPollNoResume -> fPollEvt=%#x idPollHnd=%u\n", fPollEvt, idPollHnd));
    1936         if (g_fTerminate)
    1937             continue;
    1938         cMsPollCur = 0;                 /* no rest until we've checked everything. */
    1939 
    1940         if (RT_SUCCESS(rc2))
    1941707        {
    1942             switch (idPollHnd)
    1943             {
    1944                 case TXSEXECHNDID_STDOUT:
    1945                     rc = txsDoExecHlpHandleOutputEvent(pTxsExec->hPollSet, fPollEvt, &pTxsExec->hStdOutR, &uStdOutCrc32,
    1946                                                        TXSEXECHNDID_STDOUT, "STDOUT  ");
    1947                     break;
    1948 
    1949                 case TXSEXECHNDID_STDERR:
    1950                     rc = txsDoExecHlpHandleOutputEvent(pTxsExec->hPollSet, fPollEvt, &pTxsExec->hStdErrR, &uStdErrCrc32,
    1951                                                        TXSEXECHNDID_STDERR, "STDERR  ");
    1952                     break;
    1953 
    1954                 case TXSEXECHNDID_TESTPIPE:
    1955                     rc = txsDoExecHlpHandleOutputEvent(pTxsExec->hPollSet, fPollEvt, &pTxsExec->hTestPipeR, &uTestPipeCrc32,
    1956                                                        TXSEXECHNDID_TESTPIPE, "TESTPIPE");
    1957                     break;
    1958 
    1959                 case TXSEXECHNDID_STDIN:
    1960                     txsDoExecHlpHandleStdInErrorEvent(pTxsExec->hPollSet, fPollEvt, &pTxsExec->hStdInW, &StdInBuf);
    1961                     break;
    1962 
    1963                 case TXSEXECHNDID_STDIN_WRITABLE:
    1964                     txsDoExecHlpHandleStdInWritableEvent(pTxsExec->hPollSet, fPollEvt, &pTxsExec->hStdInW, &StdInBuf);
    1965                     break;
    1966 
    1967                 case TXSEXECHNDID_THREAD:
    1968                     rc2 = RTPollSetRemove(pTxsExec->hPollSet, TXSEXECHNDID_THREAD); AssertRC(rc2);
    1969                     break;
    1970 
    1971                 default:
    1972                     rc = txsDoExecHlpHandleTransportEvent(pTxsExec->hPollSet, fPollEvt, idPollHnd, &pTxsExec->hStdInW,
    1973                                                           &StdInBuf);
    1974                     break;
    1975             }
    1976             if (RT_FAILURE(rc) || rc == VINF_EOF)
    1977                 break; /* abort command, or client dead or something */
    1978             continue;
     708            RTMsgError("Creating new client structure failed with out of memory error\n");
     709            g_pTransport->pfnNotifyBye(pTransportClient);
    1979710        }
    1980711
    1981         /*
    1982          * Check for incoming data.
    1983          */
    1984         if (g_pTransport->pfnPollIn())
    1985         {
    1986             rc = txsDoExecHlpHandleTransportEvent(pTxsExec->hPollSet, 0, UINT32_MAX, &pTxsExec->hStdInW, &StdInBuf);
    1987             if (RT_FAILURE(rc) || rc == VINF_EOF)
    1988                 break; /* abort command, or client dead or something */
    1989             continue;
    1990         }
    1991 
    1992         /*
    1993          * If the process has terminated, we're should head out.
    1994          */
    1995         if (!ASMAtomicReadBool(&pTxsExec->fProcessAlive))
    1996             break;
    1997 
    1998         /*
    1999          * Check for timed out, killing the process.
    2000          */
    2001         uint32_t cMilliesLeft = RT_INDEFINITE_WAIT;
    2002         if (pTxsExec->cMsTimeout != RT_INDEFINITE_WAIT)
    2003         {
    2004             uint64_t u64Now = RTTimeMilliTS();
    2005             uint64_t cMsElapsed = u64Now - MsStart;
    2006             if (cMsElapsed >= pTxsExec->cMsTimeout)
    2007             {
    2008                 fProcessTimedOut = true;
    2009                 if (    MsProcessKilled == UINT64_MAX
    2010                     ||  u64Now - MsProcessKilled > 1000)
    2011                 {
    2012                     if (u64Now - MsProcessKilled > 20*60*1000)
    2013                         break; /* give up after 20 mins */
    2014                     RTCritSectEnter(&pTxsExec->CritSect);
    2015                     if (pTxsExec->fProcessAlive)
    2016                         RTProcTerminate(pTxsExec->hProcess);
    2017                     RTCritSectLeave(&pTxsExec->CritSect);
    2018                     MsProcessKilled = u64Now;
    2019                     continue;
    2020                 }
    2021                 cMilliesLeft = 10000;
    2022             }
    2023             else
    2024                 cMilliesLeft = pTxsExec->cMsTimeout - (uint32_t)cMsElapsed;
    2025         }
    2026 
    2027         /* Reset the polling interval since we've done all pending work. */
    2028         cMsPollCur = cMilliesLeft >= cMsPollBase ? cMsPollBase : cMilliesLeft;
    2029     }
    2030 
    2031     /*
    2032      * At this point we should hopefully only have to wait 0 ms on the thread
    2033      * to release the handle... But if for instance the process refuses to die,
    2034      * we'll have to try kill it again. Bothersome.
    2035      */
    2036     for (size_t i = 0; i < 22; i++)
    2037     {
    2038         rc2 = RTThreadWait(pTxsExec->hThreadWaiter, 500, NULL);
     712
     713    }
     714
     715    return enmExitCode;
     716}
     717
     718/**
     719 * Initializes the global UTS state.
     720 *
     721 * @returns IPRT status code.
     722 */
     723static int utsInit(void)
     724{
     725    int rc = VINF_SUCCESS;
     726
     727    RTListInit(&g_LstClientsNew);
     728
     729    rc = RTCritSectInit(&g_CritSectClients);
     730    if (RT_SUCCESS(rc))
     731    {
     732        rc = RTPipeCreate(&g_hPipeR, &g_hPipeW, 0);
    2039733        if (RT_SUCCESS(rc))
    2040734        {
    2041             pTxsExec->hThreadWaiter = NIL_RTTHREAD;
    2042             Assert(!pTxsExec->fProcessAlive);
    2043             break;
    2044         }
    2045         if (i == 0 || i == 10 || i == 15 || i == 18 || i > 20)
    2046         {
    2047             RTCritSectEnter(&pTxsExec->CritSect);
    2048             if (pTxsExec->fProcessAlive)
    2049                 RTProcTerminate(pTxsExec->hProcess);
    2050             RTCritSectLeave(&pTxsExec->CritSect);
    2051         }
    2052     }
    2053 
    2054     /*
    2055      * If we don't have a client problem (RT_FAILURE(rc) we'll reply to the
    2056      * clients exec packet now.
    2057      */
    2058     if (RT_SUCCESS(rc))
    2059         rc = txsExecSendExitStatus(pTxsExec, pTxsExec->fProcessAlive, fProcessTimedOut, MsProcessKilled);
    2060 
    2061     RTMemFree(StdInBuf.pch);
    2062     return rc;
    2063 }
    2064 
    2065 /**
    2066  * Creates a poll set for the pipes and let the transport layer add stuff to it
    2067  * as well.
    2068  *
    2069  * @returns IPRT status code, reply to client made on error.
    2070  * @param   pTxsExec            The TXSEXEC instance.
    2071  */
    2072 static int txsExecSetupPollSet(PTXSEXEC pTxsExec)
    2073 {
    2074     int rc = RTPollSetCreate(&pTxsExec->hPollSet);
    2075     if (RT_FAILURE(rc))
    2076         return txsExecReplyRC(pTxsExec, rc, "RTPollSetCreate");
    2077 
    2078     rc = RTPollSetAddPipe(pTxsExec->hPollSet, pTxsExec->hStdInW, RTPOLL_EVT_ERROR, TXSEXECHNDID_STDIN);
    2079     if (RT_FAILURE(rc))
    2080         return txsExecReplyRC(pTxsExec, rc, "RTPollSetAddPipe/stdin");
    2081 
    2082     rc = RTPollSetAddPipe(pTxsExec->hPollSet, pTxsExec->hStdOutR,   RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
    2083                           TXSEXECHNDID_STDOUT);
    2084     if (RT_FAILURE(rc))
    2085         return txsExecReplyRC(pTxsExec, rc, "RTPollSetAddPipe/stdout");
    2086 
    2087     rc = RTPollSetAddPipe(pTxsExec->hPollSet, pTxsExec->hStdErrR,   RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
    2088                           TXSEXECHNDID_STDERR);
    2089     if (RT_FAILURE(rc))
    2090         return txsExecReplyRC(pTxsExec, rc, "RTPollSetAddPipe/stderr");
    2091 
    2092     rc = RTPollSetAddPipe(pTxsExec->hPollSet, pTxsExec->hTestPipeR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
    2093                           TXSEXECHNDID_TESTPIPE);
    2094     if (RT_FAILURE(rc))
    2095         return txsExecReplyRC(pTxsExec, rc, "RTPollSetAddPipe/test");
    2096 
    2097     rc = RTPollSetAddPipe(pTxsExec->hPollSet, pTxsExec->hWakeUpPipeR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
    2098                           TXSEXECHNDID_THREAD);
    2099     if (RT_FAILURE(rc))
    2100         return txsExecReplyRC(pTxsExec, rc, "RTPollSetAddPipe/wakeup");
    2101 
    2102     if (g_pTransport->pfnPollSetAdd)
    2103     {
    2104         rc = g_pTransport->pfnPollSetAdd(pTxsExec->hPollSet, TXSEXECHNDID_TRANSPORT);
    2105         if (RT_FAILURE(rc))
    2106             return txsExecReplyRC(pTxsExec, rc, "%s->pfnPollSetAdd/stdin", g_pTransport->szName);
    2107     }
    2108 
    2109     return VINF_SUCCESS;
    2110 }
    2111 
    2112 /**
    2113  * Thread that calls RTProcWait and signals the main thread when it returns.
    2114  *
    2115  * The thread is created before the process is started and is waiting for a user
    2116  * signal from the main thread before it calls RTProcWait.
    2117  *
    2118  * @returns VINF_SUCCESS (ignored).
    2119  * @param   hThreadSelf         The thread handle.
    2120  * @param   pvUser              The TXEEXEC structure.
    2121  */
    2122 static DECLCALLBACK(int) txsExecWaitThreadProc(RTTHREAD hThreadSelf, void *pvUser)
    2123 {
    2124     PTXSEXEC pTxsExec = (PTXSEXEC)pvUser;
    2125 
    2126     /* Wait for the go ahead... */
    2127     int rc = RTThreadUserWait(hThreadSelf, RT_INDEFINITE_WAIT); AssertRC(rc);
    2128 
    2129     RTCritSectEnter(&pTxsExec->CritSect);
    2130     for (;;)
    2131     {
    2132         RTCritSectLeave(&pTxsExec->CritSect);
    2133         rc = RTProcWaitNoResume(pTxsExec->hProcess, RTPROCWAIT_FLAGS_BLOCK, &pTxsExec->ProcessStatus);
    2134         RTCritSectEnter(&pTxsExec->CritSect);
    2135 
    2136         /* If the pipe is NIL, the destructor wants us to get lost ASAP. */
    2137         if (pTxsExec->hWakeUpPipeW == NIL_RTPIPE)
    2138             break;
    2139 
    2140         if (RT_FAILURE(rc))
    2141         {
    2142             rc = RTProcWait(pTxsExec->hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &pTxsExec->ProcessStatus);
    2143             if (rc == VERR_PROCESS_RUNNING)
    2144                 continue;
    2145 
    2146             if (RT_FAILURE(rc))
    2147             {
    2148                 AssertRC(rc);
    2149                 pTxsExec->ProcessStatus.iStatus   = rc;
    2150                 pTxsExec->ProcessStatus.enmReason = RTPROCEXITREASON_ABEND;
    2151             }
    2152         }
    2153 
    2154         /* The process finished, signal the main thread over the pipe. */
    2155         ASMAtomicWriteBool(&pTxsExec->fProcessAlive, false);
    2156         size_t cbIgnored;
    2157         RTPipeWrite(pTxsExec->hWakeUpPipeW, "done", 4, &cbIgnored);
    2158         RTPipeClose(pTxsExec->hWakeUpPipeW);
    2159         pTxsExec->hWakeUpPipeW = NIL_RTPIPE;
    2160         break;
    2161     }
    2162     RTCritSectLeave(&pTxsExec->CritSect);
    2163 
    2164     return VINF_SUCCESS;
    2165 }
    2166 
    2167 /**
    2168  * Sets up the thread that waits for the process to complete.
    2169  *
    2170  * @returns IPRT status code, reply to client made on error.
    2171  * @param   pTxsExec            The TXSEXEC instance.
    2172  */
    2173 static int txsExecSetupThread(PTXSEXEC pTxsExec)
    2174 {
    2175     int rc = RTPipeCreate(&pTxsExec->hWakeUpPipeR, &pTxsExec->hWakeUpPipeW, 0 /*fFlags*/);
    2176     if (RT_FAILURE(rc))
    2177     {
    2178         pTxsExec->hWakeUpPipeR = pTxsExec->hWakeUpPipeW = NIL_RTPIPE;
    2179         return txsExecReplyRC(pTxsExec, rc, "RTPipeCreate/wait");
    2180     }
    2181 
    2182     rc = RTThreadCreate(&pTxsExec->hThreadWaiter, txsExecWaitThreadProc,
    2183                         pTxsExec, 0 /*cbStack */, RTTHREADTYPE_DEFAULT,
    2184                         RTTHREADFLAGS_WAITABLE, "TxsProcW");
    2185     if (RT_FAILURE(rc))
    2186     {
    2187         pTxsExec->hThreadWaiter = NIL_RTTHREAD;
    2188         return txsExecReplyRC(pTxsExec, rc, "RTThreadCreate");
    2189     }
    2190 
    2191     return VINF_SUCCESS;
    2192 }
    2193 
    2194 /**
    2195  * Sets up the test pipe.
    2196  *
    2197  * @returns IPRT status code, reply to client made on error.
    2198  * @param   pTxsExec            The TXSEXEC instance.
    2199  * @param   pszTestPipe         How to set up the test pipe.
    2200  */
    2201 static int txsExecSetupTestPipe(PTXSEXEC pTxsExec, const char *pszTestPipe)
    2202 {
    2203     if (strcmp(pszTestPipe, "|"))
    2204         return VINF_SUCCESS;
    2205 
    2206     int rc = RTPipeCreate(&pTxsExec->hTestPipeR, &pTxsExec->hTestPipeW, RTPIPE_C_INHERIT_WRITE);
    2207     if (RT_FAILURE(rc))
    2208     {
    2209         pTxsExec->hTestPipeR = pTxsExec->hTestPipeW = NIL_RTPIPE;
    2210         return txsExecReplyRC(pTxsExec, rc, "RTPipeCreate/test/%s", pszTestPipe);
    2211     }
    2212 
    2213     char szVal[64];
    2214     RTStrPrintf(szVal, sizeof(szVal), "%#llx", (uint64_t)RTPipeToNative(pTxsExec->hTestPipeW));
    2215     rc = RTEnvSetEx(pTxsExec->hEnv, "IPRT_TEST_PIPE", szVal);
    2216     if (RT_FAILURE(rc))
    2217         return txsExecReplyRC(pTxsExec, rc, "RTEnvSetEx/test/%s", pszTestPipe);
    2218 
    2219     return VINF_SUCCESS;
    2220 }
    2221 
    2222 /**
    2223  * Sets up the redirection / pipe / nothing for one of the standard handles.
    2224  *
    2225  * @returns IPRT status code, reply to client made on error.
    2226  * @param   pTxsExec            The TXSEXEC instance.
    2227  * @param   pszHowTo            How to set up this standard handle.
    2228  * @param   fd                  Which standard handle it is (0 == stdin, 1 ==
    2229  *                              stdout, 2 == stderr).
    2230  * @param   ph                  The generic handle that @a pph may be set
    2231  *                              pointing to.  Always set.
    2232  * @param   pph                 Pointer to the RTProcCreateExec argument.
    2233  *                              Always set.
    2234  * @param   phPipe              Where to return the end of the pipe that we
    2235  *                              should service.  Always set.
    2236  */
    2237 static int txsExecSetupRedir(PTXSEXEC pTxsExec, const char *pszHowTo, const char *pszStdWhat, int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe)
    2238 {
    2239     ph->enmType = RTHANDLETYPE_PIPE;
    2240     ph->u.hPipe = NIL_RTPIPE;
    2241     *pph        = NULL;
    2242     *phPipe     = NIL_RTPIPE;
    2243 
    2244     int rc;
    2245     if (!strcmp(pszHowTo, "|"))
    2246     {
    2247         /*
    2248          * Setup a pipe for forwarding to/from the client.
    2249          */
    2250         if (fd == 0)
    2251             rc = RTPipeCreate(&ph->u.hPipe, phPipe, RTPIPE_C_INHERIT_READ);
    2252         else
    2253             rc = RTPipeCreate(phPipe, &ph->u.hPipe, RTPIPE_C_INHERIT_WRITE);
    2254         if (RT_FAILURE(rc))
    2255             return txsExecReplyRC(pTxsExec, rc, "RTPipeCreate/%s/%s", pszStdWhat, pszHowTo);
    2256         ph->enmType = RTHANDLETYPE_PIPE;
    2257         *pph = ph;
    2258     }
    2259     else if (!strcmp(pszHowTo, "/dev/null"))
    2260     {
    2261         /*
    2262          * Redirect to/from /dev/null.
    2263          */
    2264         RTFILE hFile;
    2265         rc = RTFileOpenBitBucket(&hFile, fd == 0 ? RTFILE_O_READ : RTFILE_O_WRITE);
    2266         if (RT_FAILURE(rc))
    2267             return txsExecReplyRC(pTxsExec, rc, "RTFileOpenBitBucket/%s/%s", pszStdWhat, pszHowTo);
    2268 
    2269         ph->enmType = RTHANDLETYPE_FILE;
    2270         ph->u.hFile = hFile;
    2271         *pph = ph;
    2272     }
    2273     else if (*pszHowTo)
    2274     {
    2275         /*
    2276          * Redirect to/from file.
    2277          */
    2278         uint32_t fFlags;
    2279         if (fd == 0)
    2280             fFlags = RTFILE_O_READ  | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN;
    2281         else
    2282         {
    2283             if (pszHowTo[0] != '>' || pszHowTo[1] != '>')
    2284                 fFlags = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE;
     735            /* Spin off the thread serving connections. */
     736            rc = RTThreadCreate(&g_hThreadServing, utsClientWorker, NULL, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
     737                                "USBTSTSRV");
     738            if (RT_SUCCESS(rc))
     739                return VINF_SUCCESS;
    2285740            else
    2286             {
    2287                 /* append */
    2288                 pszHowTo += 2;
    2289                 fFlags = RTFILE_O_WRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND;
    2290             }
    2291         }
    2292 
    2293         RTFILE hFile;
    2294         rc = RTFileOpen(&hFile, pszHowTo, fFlags);
    2295         if (RT_FAILURE(rc))
    2296             return txsExecReplyRC(pTxsExec, rc, "RTFileOpen/%s/%s", pszStdWhat, pszHowTo);
    2297 
    2298         ph->enmType = RTHANDLETYPE_FILE;
    2299         ph->u.hFile = hFile;
    2300         *pph = ph;
    2301     }
    2302     else
    2303         /* same as parent (us) */
    2304         rc = VINF_SUCCESS;
    2305     return rc;
    2306 }
    2307 
    2308 /**
    2309  * Create the environment.
    2310  *
    2311  * @returns IPRT status code, reply to client made on error.
    2312  * @param   pTxsExec            The TXSEXEC instance.
    2313  * @param   cEnvVars            The number of environment variables.
    2314  * @param   papszEnv            The environment variables (var=value).
    2315  */
    2316 static int txsExecSetupEnv(PTXSEXEC pTxsExec, uint32_t cEnvVars, const char * const *papszEnv)
    2317 {
    2318     /*
    2319      * Create the environment.
    2320      */
    2321     int rc = RTEnvClone(&pTxsExec->hEnv, RTENV_DEFAULT);
    2322     if (RT_FAILURE(rc))
    2323         return txsExecReplyRC(pTxsExec, rc, "RTEnvClone");
    2324 
    2325     for (size_t i = 0; i < cEnvVars; i++)
    2326     {
    2327         rc = RTEnvPutEx(pTxsExec->hEnv, papszEnv[i]);
    2328         if (RT_FAILURE(rc))
    2329             return txsExecReplyRC(pTxsExec, rc, "RTEnvPutEx(,'%s')", papszEnv[i]);
    2330     }
    2331     return VINF_SUCCESS;
    2332 }
    2333 
    2334 /**
    2335  * Deletes the TXSEXEC structure and frees the memory backing it.
    2336  *
    2337  * @param   pTxsExec            The structure to destroy.
    2338  */
    2339 static void txsExecDestroy(PTXSEXEC pTxsExec)
    2340 {
    2341     int rc2;
    2342 
    2343     rc2 = RTEnvDestroy(pTxsExec->hEnv);             AssertRC(rc2);
    2344     pTxsExec->hEnv              = NIL_RTENV;
    2345     rc2 = RTPipeClose(pTxsExec->hTestPipeW);        AssertRC(rc2);
    2346     pTxsExec->hTestPipeW        = NIL_RTPIPE;
    2347     rc2 = RTHandleClose(pTxsExec->StdErr.phChild);  AssertRC(rc2);
    2348     pTxsExec->StdErr.phChild    = NULL;
    2349     rc2 = RTHandleClose(pTxsExec->StdOut.phChild);  AssertRC(rc2);
    2350     pTxsExec->StdOut.phChild    = NULL;
    2351     rc2 = RTHandleClose(pTxsExec->StdIn.phChild);   AssertRC(rc2);
    2352     pTxsExec->StdIn.phChild     = NULL;
    2353 
    2354     rc2 = RTPipeClose(pTxsExec->hTestPipeR);        AssertRC(rc2);
    2355     pTxsExec->hTestPipeR        = NIL_RTPIPE;
    2356     rc2 = RTPipeClose(pTxsExec->hStdErrR);          AssertRC(rc2);
    2357     pTxsExec->hStdErrR          = NIL_RTPIPE;
    2358     rc2 = RTPipeClose(pTxsExec->hStdOutR);          AssertRC(rc2);
    2359     pTxsExec->hStdOutR          = NIL_RTPIPE;
    2360     rc2 = RTPipeClose(pTxsExec->hStdInW);           AssertRC(rc2);
    2361     pTxsExec->hStdInW           = NIL_RTPIPE;
    2362 
    2363     RTPollSetDestroy(pTxsExec->hPollSet);
    2364     pTxsExec->hPollSet          = NIL_RTPOLLSET;
    2365 
    2366     /*
    2367      * If the process is still running we're in a bit of a fix...  Try kill it,
    2368      * although that's potentially racing process termination and reusage of
    2369      * the pid.
    2370      */
    2371     RTCritSectEnter(&pTxsExec->CritSect);
    2372 
    2373     RTPipeClose(pTxsExec->hWakeUpPipeW);
    2374     pTxsExec->hWakeUpPipeW      = NIL_RTPIPE;
    2375     RTPipeClose(pTxsExec->hWakeUpPipeR);
    2376     pTxsExec->hWakeUpPipeR      = NIL_RTPIPE;
    2377 
    2378     if (   pTxsExec->hProcess != NIL_RTPROCESS
    2379         && pTxsExec->fProcessAlive)
    2380         RTProcTerminate(pTxsExec->hProcess);
    2381 
    2382     RTCritSectLeave(&pTxsExec->CritSect);
    2383 
    2384     int rcThread = VINF_SUCCESS;
    2385     if (pTxsExec->hThreadWaiter != NIL_RTTHREAD)
    2386         rcThread = RTThreadWait(pTxsExec->hThreadWaiter, 5000, NULL);
    2387     if (RT_SUCCESS(rcThread))
    2388     {
    2389         pTxsExec->hThreadWaiter = NIL_RTTHREAD;
    2390         RTCritSectDelete(&pTxsExec->CritSect);
    2391         RTMemFree(pTxsExec);
    2392     }
    2393     /* else: leak it or RTThreadWait may cause heap corruption later. */
    2394 }
    2395 
    2396 /**
    2397  * Initializes the TXSEXEC structure.
    2398  *
    2399  * @returns VINF_SUCCESS and non-NULL *ppTxsExec on success, reply send status
    2400  *        and *ppTxsExec set to NULL on failure.
    2401  * @param   pPktHdr             The exec packet.
    2402  * @param   cMsTimeout          The time parameter.
    2403  * @param   ppTxsExec           Where to return the structure.
    2404  */
    2405 static int txsExecCreate(PCTXSPKTHDR pPktHdr, RTMSINTERVAL cMsTimeout, PTXSEXEC *ppTxsExec)
    2406 {
    2407     *ppTxsExec = NULL;
    2408 
    2409     /*
    2410      * Allocate the basic resources.
    2411      */
    2412     PTXSEXEC pTxsExec = (PTXSEXEC)RTMemAlloc(sizeof(*pTxsExec));
    2413     if (!pTxsExec)
    2414         return txsReplyRC(pPktHdr, VERR_NO_MEMORY, "RTMemAlloc(%zu)", sizeof(*pTxsExec));
    2415     int rc = RTCritSectInit(&pTxsExec->CritSect);
    2416     if (RT_FAILURE(rc))
    2417     {
    2418         RTMemFree(pTxsExec);
    2419         return txsReplyRC(pPktHdr, rc, "RTCritSectInit");
    2420     }
    2421 
    2422     /*
    2423      * Initialize the member to NIL values.
    2424      */
    2425     pTxsExec->pPktHdr           = pPktHdr;
    2426     pTxsExec->cMsTimeout        = cMsTimeout;
    2427     pTxsExec->rcReplySend       = VINF_SUCCESS;
    2428 
    2429     pTxsExec->hPollSet          = NIL_RTPOLLSET;
    2430     pTxsExec->hStdInW           = NIL_RTPIPE;
    2431     pTxsExec->hStdOutR          = NIL_RTPIPE;
    2432     pTxsExec->hStdErrR          = NIL_RTPIPE;
    2433     pTxsExec->hTestPipeR        = NIL_RTPIPE;
    2434     pTxsExec->hWakeUpPipeR      = NIL_RTPIPE;
    2435     pTxsExec->hThreadWaiter     = NIL_RTTHREAD;
    2436 
    2437     pTxsExec->StdIn.phChild     = NULL;
    2438     pTxsExec->StdOut.phChild    = NULL;
    2439     pTxsExec->StdErr.phChild    = NULL;
    2440     pTxsExec->hTestPipeW        = NIL_RTPIPE;
    2441     pTxsExec->hEnv              = NIL_RTENV;
    2442 
    2443     pTxsExec->hProcess          = NIL_RTPROCESS;
    2444     pTxsExec->ProcessStatus.iStatus   = 254;
    2445     pTxsExec->ProcessStatus.enmReason = RTPROCEXITREASON_ABEND;
    2446     pTxsExec->fProcessAlive     = false;
    2447     pTxsExec->hWakeUpPipeW      = NIL_RTPIPE;
    2448 
    2449     *ppTxsExec = pTxsExec;
    2450     return VINF_SUCCESS;
    2451 }
    2452 
    2453 /**
    2454  * txsDoExec helper that takes over when txsDoExec has expanded the packet.
    2455  *
    2456  * @returns IPRT status code from send.
    2457  * @param   pPktHdr             The exec packet.
    2458  * @param   fFlags              Flags, reserved for future use.
    2459  * @param   pszExecName         The executable name.
    2460  * @param   cArgs               The argument count.
    2461  * @param   papszArgs           The arguments.
    2462  * @param   cEnvVars            The environment variable count.
    2463  * @param   papszEnv            The environment variables.
    2464  * @param   pszStdIn            How to deal with standard in.
    2465  * @param   pszStdOut           How to deal with standard out.
    2466  * @param   pszStdErr           How to deal with standard err.
    2467  * @param   pszTestPipe         How to deal with the test pipe.
    2468  * @param   pszUsername         The user to run the program as.
    2469  * @param   cMillies            The process time limit in milliseconds.
    2470  */
    2471 static int txsDoExecHlp(PCTXSPKTHDR pPktHdr, uint32_t fFlags, const char *pszExecName,
    2472                         uint32_t cArgs,    const char * const *papszArgs,
    2473                         uint32_t cEnvVars, const char * const *papszEnv,
    2474                         const char *pszStdIn, const char *pszStdOut, const char *pszStdErr, const char *pszTestPipe,
    2475                         const char *pszUsername, RTMSINTERVAL cMillies)
    2476 {
    2477     int     rc2;
    2478 
    2479     /*
    2480      * Input validation, filter out things we don't yet support..
    2481      */
    2482     Assert(!fFlags);
    2483     if (!*pszExecName)
    2484         return txsReplyFailure(pPktHdr, "STR ZERO", "Executable name is empty");
    2485     if (!*pszStdIn)
    2486         return txsReplyFailure(pPktHdr, "STR ZERO", "The stdin howto is empty");
    2487     if (!*pszStdOut)
    2488         return txsReplyFailure(pPktHdr, "STR ZERO", "The stdout howto is empty");
    2489     if (!*pszStdErr)
    2490         return txsReplyFailure(pPktHdr, "STR ZERO", "The stderr howto is empty");
    2491     if (!*pszTestPipe)
    2492         return txsReplyFailure(pPktHdr, "STR ZERO", "The testpipe howto is empty");
    2493     if (strcmp(pszTestPipe, "|") && strcmp(pszTestPipe,  "/dev/null"))
    2494         return txsReplyFailure(pPktHdr, "BAD TSTP", "Only \"|\" and \"/dev/null\" are allowed as testpipe howtos ('%s')",
    2495                                pszTestPipe);
    2496     if (*pszUsername)
    2497         return txsReplyFailure(pPktHdr, "NOT IMPL", "Executing as a specific user is not implemented ('%s')", pszUsername);
    2498 
    2499     /*
    2500      * Prepare for process launch.
    2501      */
    2502     PTXSEXEC pTxsExec;
    2503     int rc = txsExecCreate(pPktHdr, cMillies, &pTxsExec);
    2504     if (pTxsExec == NULL)
    2505         return rc;
    2506     rc = txsExecSetupEnv(pTxsExec, cEnvVars, papszEnv);
    2507     if (RT_SUCCESS(rc))
    2508         rc = txsExecSetupRedir(pTxsExec, pszStdIn, "StdIn",   0, &pTxsExec->StdIn.hChild,  &pTxsExec->StdIn.phChild,  &pTxsExec->hStdInW);
    2509     if (RT_SUCCESS(rc))
    2510         rc = txsExecSetupRedir(pTxsExec, pszStdOut, "StdOut", 1, &pTxsExec->StdOut.hChild, &pTxsExec->StdOut.phChild, &pTxsExec->hStdOutR);
    2511     if (RT_SUCCESS(rc))
    2512         rc = txsExecSetupRedir(pTxsExec, pszStdErr, "StdErr", 2, &pTxsExec->StdErr.hChild, &pTxsExec->StdErr.phChild, &pTxsExec->hStdErrR);
    2513     if (RT_SUCCESS(rc))
    2514         rc = txsExecSetupTestPipe(pTxsExec, pszTestPipe);
    2515     if (RT_SUCCESS(rc))
    2516         rc = txsExecSetupThread(pTxsExec);
    2517     if (RT_SUCCESS(rc))
    2518         rc = txsExecSetupPollSet(pTxsExec);
    2519     if (RT_SUCCESS(rc))
    2520     {
    2521         /*
    2522          * Create the process.
    2523          */
    2524         if (g_fDisplayOutput)
    2525         {
    2526             RTPrintf("txs: Executing \"%s\": ", pszExecName);
    2527             for (uint32_t i = 0; i < cArgs; i++)
    2528                 RTPrintf(" \"%s\"", papszArgs[i]);
    2529             RTPrintf("\n");
    2530         }
    2531         rc = RTProcCreateEx(pszExecName, papszArgs, pTxsExec->hEnv, 0 /*fFlags*/,
    2532                             pTxsExec->StdIn.phChild, pTxsExec->StdOut.phChild, pTxsExec->StdErr.phChild,
    2533                             *pszUsername ? pszUsername : NULL, NULL,
    2534                             &pTxsExec->hProcess);
    2535         if (RT_SUCCESS(rc))
    2536         {
    2537             ASMAtomicWriteBool(&pTxsExec->fProcessAlive, true);
    2538             rc2 = RTThreadUserSignal(pTxsExec->hThreadWaiter); AssertRC(rc2);
    2539 
    2540             /*
    2541              * Close the child ends of any pipes and redirected files.
    2542              */
    2543             rc2 = RTHandleClose(pTxsExec->StdIn.phChild);   AssertRC(rc2);
    2544             pTxsExec->StdIn.phChild     = NULL;
    2545             rc2 = RTHandleClose(pTxsExec->StdOut.phChild);  AssertRC(rc2);
    2546             pTxsExec->StdOut.phChild    = NULL;
    2547             rc2 = RTHandleClose(pTxsExec->StdErr.phChild);  AssertRC(rc2);
    2548             pTxsExec->StdErr.phChild    = NULL;
    2549             rc2 = RTPipeClose(pTxsExec->hTestPipeW);        AssertRC(rc2);
    2550             pTxsExec->hTestPipeW        = NIL_RTPIPE;
    2551 
    2552             /*
    2553              * Let another worker function funnel output and input to the
    2554              * client as well as the process exit code.
    2555              */
    2556             rc = txsDoExecHlp2(pTxsExec);
     741                RTMsgError("Creating the client worker thread failed with %Rrc\n", rc);
     742
     743            RTPipeClose(g_hPipeR);
     744            RTPipeClose(g_hPipeW);
    2557745        }
    2558746        else
    2559             rc = txsReplyFailure(pPktHdr, "FAILED  ", "Executing process \"%s\" failed with %Rrc",
    2560                                  pszExecName, rc);
     747            RTMsgError("Creating communications pipe failed with %Rrc\n", rc);
     748
     749        RTCritSectDelete(&g_CritSectClients);
    2561750    }
    2562751    else
    2563         rc = pTxsExec->rcReplySend;
    2564     txsExecDestroy(pTxsExec);
     752        RTMsgError("Creating global critical section failed with %Rrc\n", rc);
     753
    2565754    return rc;
    2566755}
    2567756
    2568757/**
    2569  * Execute a program.
    2570  *
    2571  * @returns IPRT status code from send.
    2572  * @param   pPktHdr             The exec packet.
    2573  */
    2574 static int txsDoExec(PCTXSPKTHDR pPktHdr)
    2575 {
    2576     /*
    2577      * This packet has a lot of parameters, most of which are zero terminated
    2578      * strings.  The strings used in items 7 thru 10 are either file names,
    2579      * "/dev/null" or a pipe char (|).
    2580      *
    2581      * Packet content:
    2582      *    1. Flags reserved for future use (32-bit unsigned).
    2583      *    2. The executable name (string).
    2584      *    3. The argument count given as a 32-bit unsigned integer.
    2585      *    4. The arguments strings.
    2586      *    5. The number of environment strings (32-bit unsigned).
    2587      *    6. The environment strings (var=val) to apply the environment.
    2588      *    7. What to do about standard in (string).
    2589      *    8. What to do about standard out (string).
    2590      *    9. What to do about standard err (string).
    2591      *   10. What to do about the test pipe (string).
    2592      *   11. The name of the user to run the program as (string).  Empty string
    2593      *       means running it as the current user.
    2594      *   12. Process time limit in milliseconds (32-bit unsigned).  Max == no limit.
    2595      */
    2596     size_t const cbMin = sizeof(TXSPKTHDR)
    2597                        + sizeof(uint32_t) /* flags */ + 2
    2598                        + sizeof(uint32_t) /* argc */  + 2 /* argv */
    2599                        + sizeof(uint32_t) + 0 /* environ */
    2600                        + 4 * 1
    2601                        + sizeof(uint32_t) /* timeout */;
    2602     if (pPktHdr->cb < cbMin)
    2603         return txsReplyBadMinSize(pPktHdr, cbMin);
    2604 
    2605     /* unpack the packet */
    2606     char const     *pchEnd = (char const *)pPktHdr + pPktHdr->cb;
    2607     char const     *pch    = (char const *)(pPktHdr + 1); /* cursor */
    2608 
    2609     /* 1. flags */
    2610     uint32_t const  fFlags = *(uint32_t const *)pch;
    2611     pch                   += sizeof(uint32_t);
    2612     if (fFlags != 0)
    2613         return txsReplyFailure(pPktHdr, "BAD FLAG", "Invalid EXEC flags %#x, expected 0", fFlags);
    2614 
    2615     /* 2. exec name */
    2616     int             rc;
    2617     char           *pszExecName = NULL;
    2618     if (!txsIsStringValid(pPktHdr, "execname", pch, &pszExecName, &pch, &rc))
    2619         return rc;
    2620 
    2621     /* 3. argc */
    2622     uint32_t const  cArgs  = (size_t)(pchEnd - pch) > sizeof(uint32_t) ? *(uint32_t const *)pch : 0xff;
    2623     pch                   += sizeof(uint32_t);
    2624     if (cArgs * 1 >= (size_t)(pchEnd - pch))
    2625         rc = txsReplyFailure(pPktHdr, "BAD ARGC", "Bad or missing argument count (%#x)", cArgs);
    2626     else if (cArgs > 128)
    2627         rc = txsReplyFailure(pPktHdr, "BAD ARGC", "Too many arguments (%#x)", cArgs);
    2628     else
    2629     {
    2630         char **papszArgs = (char **)RTMemTmpAllocZ(sizeof(char *) * (cArgs + 1));
    2631         if (papszArgs)
    2632         {
    2633             /* 4. argv */
    2634             bool fOk = true;
    2635             for (size_t i = 0; i < cArgs && fOk; i++)
    2636             {
    2637                 fOk = txsIsStringValid(pPktHdr, "argvN", pch, &papszArgs[i], &pch, &rc);
    2638                 if (!fOk)
    2639                     break;
    2640             }
    2641             if (fOk)
    2642             {
    2643                 /* 5. cEnvVars */
    2644                 uint32_t const  cEnvVars = (size_t)(pchEnd - pch) > sizeof(uint32_t) ? *(uint32_t const *)pch : 0xfff;
    2645                 pch                     += sizeof(uint32_t);
    2646                 if (cEnvVars * 1 >= (size_t)(pchEnd - pch))
    2647                     rc = txsReplyFailure(pPktHdr, "BAD ENVC", "Bad or missing environment variable count (%#x)", cEnvVars);
    2648                 else if (cEnvVars > 256)
    2649                     rc = txsReplyFailure(pPktHdr, "BAD ENVC", "Too many environment variables (%#x)", cEnvVars);
    2650                 else
    2651                 {
    2652                     char **papszEnv = (char **)RTMemTmpAllocZ(sizeof(char *) * (cEnvVars + 1));
    2653                     if (papszEnv)
    2654                     {
    2655                         /* 6. environ */
    2656                         for (size_t i = 0; i < cEnvVars && fOk; i++)
    2657                         {
    2658                             fOk = txsIsStringValid(pPktHdr, "envN", pch, &papszEnv[i], &pch, &rc);
    2659                             if (!fOk) /* Bail out on error. */
    2660                                 break;
    2661                         }
    2662                         if (fOk)
    2663                         {
    2664                             /* 7. stdout */
    2665                             char *pszStdIn;
    2666                             if (txsIsStringValid(pPktHdr, "stdin", pch, &pszStdIn, &pch, &rc))
    2667                             {
    2668                                 /* 8. stdout */
    2669                                 char *pszStdOut;
    2670                                 if (txsIsStringValid(pPktHdr, "stdout", pch, &pszStdOut, &pch, &rc))
    2671                                 {
    2672                                     /* 9. stderr */
    2673                                     char *pszStdErr;
    2674                                     if (txsIsStringValid(pPktHdr, "stderr", pch, &pszStdErr, &pch, &rc))
    2675                                     {
    2676                                         /* 10. testpipe */
    2677                                         char *pszTestPipe;
    2678                                         if (txsIsStringValid(pPktHdr, "testpipe", pch, &pszTestPipe, &pch, &rc))
    2679                                         {
    2680                                             /* 11. username */
    2681                                             char *pszUsername;
    2682                                             if (txsIsStringValid(pPktHdr, "username", pch, &pszUsername, &pch, &rc))
    2683                                             {
    2684                                                 /** @todo No password value? */
    2685 
    2686                                                 /* 12. time limit */
    2687                                                 uint32_t const  cMillies = (size_t)(pchEnd - pch) >= sizeof(uint32_t)
    2688                                                                          ? *(uint32_t const *)pch
    2689                                                                          : 0;
    2690                                                 if ((size_t)(pchEnd - pch) > sizeof(uint32_t))
    2691                                                     rc = txsReplyFailure(pPktHdr, "BAD END ", "Timeout argument not at end of packet (%#x)", (size_t)(pchEnd - pch));
    2692                                                 else if ((size_t)(pchEnd - pch) < sizeof(uint32_t))
    2693                                                     rc = txsReplyFailure(pPktHdr, "BAD NOTO", "No timeout argument");
    2694                                                 else if (cMillies < 1000)
    2695                                                     rc = txsReplyFailure(pPktHdr, "BAD TO  ", "Timeout is less than a second (%#x)", cMillies);
    2696                                                 else
    2697                                                 {
    2698                                                     pch += sizeof(uint32_t);
    2699 
    2700                                                     /*
    2701                                                      * Time to employ a helper here before we go way beyond
    2702                                                      * the right margin...
    2703                                                      */
    2704                                                     rc = txsDoExecHlp(pPktHdr, fFlags, pszExecName,
    2705                                                                       cArgs,    papszArgs,
    2706                                                                       cEnvVars, papszEnv,
    2707                                                                       pszStdIn, pszStdOut, pszStdErr, pszTestPipe,
    2708                                                                       pszUsername,
    2709                                                                       cMillies == UINT32_MAX ? RT_INDEFINITE_WAIT : cMillies);
    2710                                                 }
    2711                                                 RTStrFree(pszUsername);
    2712                                             }
    2713                                             RTStrFree(pszTestPipe);
    2714                                         }
    2715                                         RTStrFree(pszStdErr);
    2716                                     }
    2717                                     RTStrFree(pszStdOut);
    2718                                 }
    2719                                 RTStrFree(pszStdIn);
    2720                             }
    2721                         }
    2722                         for (size_t i = 0; i < cEnvVars; i++)
    2723                             RTStrFree(papszEnv[i]);
    2724                         RTMemTmpFree(papszEnv);
    2725                     }
    2726                     else
    2727                         rc = txsReplyFailure(pPktHdr, "NO MEM  ", "Failed to allocate %zu bytes environ", sizeof(char *) * (cEnvVars + 1));
    2728                 }
    2729             }
    2730             for (size_t i = 0; i < cArgs; i++)
    2731                 RTStrFree(papszArgs[i]);
    2732             RTMemTmpFree(papszArgs);
    2733         }
    2734         else
    2735             rc = txsReplyFailure(pPktHdr, "NO MEM  ", "Failed to allocate %zu bytes for argv", sizeof(char *) * (cArgs + 1));
    2736     }
    2737     RTStrFree(pszExecName);
    2738 
    2739     return rc;
    2740 }
    2741 
    2742 /**
    2743  * The main loop.
    2744  *
    2745  * @returns exit code.
    2746  */
    2747 static RTEXITCODE txsMainLoop(void)
    2748 {
    2749     RTEXITCODE enmExitCode = RTEXITCODE_SUCCESS;
    2750     while (!g_fTerminate)
    2751     {
    2752         /*
    2753          * Read client command packet and process it.
    2754          */
    2755         PTXSPKTHDR pPktHdr;
    2756         int rc = txsRecvPkt(&pPktHdr, true /*fAutoRetryOnFailure*/);
    2757         if (RT_FAILURE(rc))
    2758             continue;
    2759 
    2760         /*
    2761          * Do a string switch on the opcode bit.
    2762          */
    2763         /* Connection: */
    2764         if (     txsIsSameOpcode(pPktHdr, "HOWDY   "))
    2765             rc = txsDoHowdy(pPktHdr);
    2766         else if (txsIsSameOpcode(pPktHdr, "BYE     "))
    2767             rc = txsDoBye(pPktHdr);
    2768         else if (txsIsSameOpcode(pPktHdr, "UUID    "))
    2769             rc = txsDoUuid(pPktHdr);
    2770         /* Process: */
    2771         else if (txsIsSameOpcode(pPktHdr, "EXEC    "))
    2772             rc = txsDoExec(pPktHdr);
    2773         /* Admin: */
    2774         else if (txsIsSameOpcode(pPktHdr, "REBOOT  "))
    2775             rc = txsDoReboot(pPktHdr);
    2776         else if (txsIsSameOpcode(pPktHdr, "SHUTDOWN"))
    2777             rc = txsDoShutdown(pPktHdr);
    2778         /* CD/DVD control: */
    2779         else if (txsIsSameOpcode(pPktHdr, "CD EJECT"))
    2780             rc = txsDoCdEject(pPktHdr);
    2781         /* File system: */
    2782         else if (txsIsSameOpcode(pPktHdr, "CLEANUP "))
    2783             rc = txsDoCleanup(pPktHdr);
    2784         else if (txsIsSameOpcode(pPktHdr, "MKDIR   "))
    2785             rc = txsDoMkDir(pPktHdr);
    2786         else if (txsIsSameOpcode(pPktHdr, "MKDRPATH"))
    2787             rc = txsDoMkDrPath(pPktHdr);
    2788         else if (txsIsSameOpcode(pPktHdr, "MKSYMLNK"))
    2789             rc = txsDoMkSymlnk(pPktHdr);
    2790         else if (txsIsSameOpcode(pPktHdr, "RMDIR   "))
    2791             rc = txsDoRmDir(pPktHdr);
    2792         else if (txsIsSameOpcode(pPktHdr, "RMFILE  "))
    2793             rc = txsDoRmFile(pPktHdr);
    2794         else if (txsIsSameOpcode(pPktHdr, "RMSYMLNK"))
    2795             rc = txsDoRmSymlnk(pPktHdr);
    2796         else if (txsIsSameOpcode(pPktHdr, "RMTREE  "))
    2797             rc = txsDoRmTree(pPktHdr);
    2798         else if (txsIsSameOpcode(pPktHdr, "CHMOD   "))
    2799             rc = txsDoChMod(pPktHdr);
    2800         else if (txsIsSameOpcode(pPktHdr, "CHOWN   "))
    2801             rc = txsDoChOwn(pPktHdr);
    2802         else if (txsIsSameOpcode(pPktHdr, "CHGRP   "))
    2803             rc = txsDoChGrp(pPktHdr);
    2804         else if (txsIsSameOpcode(pPktHdr, "ISDIR   "))
    2805             rc = txsDoIsDir(pPktHdr);
    2806         else if (txsIsSameOpcode(pPktHdr, "ISFILE  "))
    2807             rc = txsDoIsFile(pPktHdr);
    2808         else if (txsIsSameOpcode(pPktHdr, "ISSYMLNK"))
    2809             rc = txsDoIsSymlnk(pPktHdr);
    2810         else if (txsIsSameOpcode(pPktHdr, "STAT    "))
    2811             rc = txsDoStat(pPktHdr);
    2812         else if (txsIsSameOpcode(pPktHdr, "LSTAT   "))
    2813             rc = txsDoLStat(pPktHdr);
    2814         else if (txsIsSameOpcode(pPktHdr, "LIST    "))
    2815             rc = txsDoList(pPktHdr);
    2816         else if (txsIsSameOpcode(pPktHdr, "PUT FILE"))
    2817             rc = txsDoPutFile(pPktHdr);
    2818         else if (txsIsSameOpcode(pPktHdr, "GET FILE"))
    2819             rc = txsDoGetFile(pPktHdr);
    2820 #ifndef RT_OS_WINDOWS
    2821         else if (txsIsSameOpcode(pPktHdr, "UNPKFILE"))
    2822             rc = txsDoUnpackFile(pPktHdr);
    2823 #endif
    2824         /* Misc: */
    2825         else
    2826             rc = txsReplyUnknown(pPktHdr);
    2827 
    2828         RTMemFree(pPktHdr);
    2829     }
    2830 
    2831     return enmExitCode;
    2832 }
    2833 
    2834 
    2835 /**
    2836  * Finalizes the scratch directory, making sure it exists.
    2837  *
    2838  * @returns exit code.
    2839  */
    2840 static RTEXITCODE txsFinalizeScratch(void)
    2841 {
    2842     RTPathStripTrailingSlash(g_szScratchPath);
    2843     char *pszFilename = RTPathFilename(g_szScratchPath);
    2844     if (!pszFilename)
    2845         return RTMsgErrorExit(RTEXITCODE_FAILURE, "cannot use root for scratch (%s)\n", g_szScratchPath);
    2846 
    2847     int rc;
    2848     if (strchr(pszFilename, 'X'))
    2849     {
    2850         char ch = *pszFilename;
    2851         rc = RTDirCreateFullPath(g_szScratchPath, 0700);
    2852         *pszFilename = ch;
    2853         if (RT_SUCCESS(rc))
    2854             rc = RTDirCreateTemp(g_szScratchPath, 0700);
    2855     }
    2856     else
    2857     {
    2858         if (RTDirExists(g_szScratchPath))
    2859             rc = VINF_SUCCESS;
    2860         else
    2861             rc = RTDirCreateFullPath(g_szScratchPath, 0700);
    2862     }
    2863     if (RT_FAILURE(rc))
    2864         return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to create scratch directory: %Rrc (%s)\n", rc, g_szScratchPath);
    2865     return RTEXITCODE_SUCCESS;
    2866 }
    2867 
    2868 /**
    2869  * Attempts to complete an upgrade by updating the original and relaunching
    2870  * ourselves from there again.
    2871  *
    2872  * On failure, we'll continue running as the temporary copy.
    2873  *
    2874  * @returns Exit code. Exit if this is non-zero or @a *pfExit is set.
    2875  * @param   argc                The number of arguments.
    2876  * @param   argv                The argument vector.
    2877  * @param   pfExit              For indicating exit when the exit code is zero.
    2878  */
    2879 static RTEXITCODE txsAutoUpdateStage2(int argc, char **argv, bool *pfExit, const char *pszUpgrading)
    2880 {
    2881     /*
    2882      * Copy the current executable onto the original.
    2883      * Note that we're racing the original program on some platforms, thus the
    2884      * 60 sec sleep mess.
    2885      */
    2886     char szUpgradePath[RTPATH_MAX];
    2887     if (!RTProcGetExecutablePath(szUpgradePath, sizeof(szUpgradePath)))
    2888     {
    2889         RTMsgError("RTProcGetExecutablePath failed (step 2)\n");
    2890         return RTEXITCODE_SUCCESS;
    2891     }
    2892     void    *pvUpgrade;
    2893     size_t   cbUpgrade;
    2894     int rc = RTFileReadAll(szUpgradePath, &pvUpgrade, &cbUpgrade);
    2895     if (RT_FAILURE(rc))
    2896     {
    2897         RTMsgError("RTFileReadAllEx(\"%s\"): %Rrc (step 2)\n", szUpgradePath, rc);
    2898         return RTEXITCODE_SUCCESS;
    2899     }
    2900 
    2901     uint64_t StartMilliTS = RTTimeMilliTS();
    2902     RTFILE  hFile;
    2903     rc = RTFileOpen(&hFile, pszUpgrading,
    2904                     RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE
    2905                     | (0755 << RTFILE_O_CREATE_MODE_SHIFT));
    2906     while (   RT_FAILURE(rc)
    2907            && RTTimeMilliTS() - StartMilliTS < 60000)
    2908     {
    2909         RTThreadSleep(1000);
    2910         rc = RTFileOpen(&hFile, pszUpgrading,
    2911                         RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE
    2912                         | (0755 << RTFILE_O_CREATE_MODE_SHIFT));
    2913     }
    2914     if (RT_SUCCESS(rc))
    2915     {
    2916         rc = RTFileWrite(hFile, pvUpgrade, cbUpgrade, NULL);
    2917         RTFileClose(hFile);
    2918         if (RT_SUCCESS(rc))
    2919         {
    2920             /*
    2921              * Relaunch the service with the original name, foricbly barring
    2922              * further upgrade cycles in case of bugs (and simplifying the code).
    2923              */
    2924             const char **papszArgs = (const char **)RTMemAlloc((argc + 1 + 1) * sizeof(char **));
    2925             if (papszArgs)
    2926             {
    2927                 papszArgs[0] = pszUpgrading;
    2928                 for (int i = 1; i < argc; i++)
    2929                     papszArgs[i] = argv[i];
    2930                 papszArgs[argc] = "--no-auto-upgrade";
    2931                 papszArgs[argc + 1] = NULL;
    2932 
    2933                 RTMsgInfo("Launching upgraded image: \"%s\"\n", pszUpgrading);
    2934                 RTPROCESS hProc;
    2935                 rc = RTProcCreate(pszUpgrading, papszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &hProc);
    2936                 if (RT_SUCCESS(rc))
    2937                     *pfExit = true;
    2938                 else
    2939                     RTMsgError("RTProcCreate(\"%s\"): %Rrc (upgrade stage 2)\n", pszUpgrading, rc);
    2940                 RTMemFree(papszArgs);
    2941             }
    2942             else
    2943                 RTMsgError("RTMemAlloc failed during upgrade attempt (stage 2)\n");
    2944         }
    2945         else
    2946             RTMsgError("RTFileWrite(%s,,%zu): %Rrc (step 2) - BAD\n", pszUpgrading, cbUpgrade, rc);
    2947     }
    2948     else
    2949         RTMsgError("RTFileOpen(,%s,): %Rrc\n", pszUpgrading, rc);
    2950     RTFileReadAllFree(pvUpgrade, cbUpgrade);
    2951     return RTEXITCODE_SUCCESS;
    2952 }
    2953 
    2954 /**
    2955  * Checks for an upgrade and respawns if there is.
    2956  *
    2957  * @returns Exit code. Exit if this is non-zero or @a *pfExit is set.
    2958  * @param   argc                The number of arguments.
    2959  * @param   argv                The argument vector.
    2960  * @param   pfExit              For indicating exit when the exit code is zero.
    2961  */
    2962 static RTEXITCODE txsAutoUpdateStage1(int argc, char **argv, bool *pfExit)
    2963 {
    2964     /*
    2965      * Figure names of the current service image and the potential upgrade.
    2966      */
    2967     char szOrgPath[RTPATH_MAX];
    2968     if (!RTProcGetExecutablePath(szOrgPath, sizeof(szOrgPath)))
    2969     {
    2970         RTMsgError("RTProcGetExecutablePath failed\n");
    2971         return RTEXITCODE_SUCCESS;
    2972     }
    2973 
    2974     char szUpgradePath[RTPATH_MAX];
    2975     int rc = RTPathJoin(szUpgradePath, sizeof(szUpgradePath), g_szCdRomPath, g_szOsSlashArchShortName);
    2976     if (RT_SUCCESS(rc))
    2977         rc = RTPathAppend(szUpgradePath, sizeof(szUpgradePath), RTPathFilename(szOrgPath));
    2978     if (RT_FAILURE(rc))
    2979     {
    2980         RTMsgError("Failed to construct path to potential service upgrade: %Rrc\n", rc);
    2981         return RTEXITCODE_SUCCESS;
    2982     }
    2983 
    2984     /*
    2985      * Query information about the two images and read the entire potential source file.
    2986      */
    2987     RTFSOBJINFO UpgradeInfo;
    2988     rc = RTPathQueryInfo(szUpgradePath, &UpgradeInfo, RTFSOBJATTRADD_NOTHING);
    2989     if (    rc == VERR_FILE_NOT_FOUND
    2990         ||  rc == VERR_PATH_NOT_FOUND
    2991         ||  rc == VERR_MEDIA_NOT_PRESENT
    2992         ||  rc == VERR_MEDIA_NOT_RECOGNIZED)
    2993         return RTEXITCODE_SUCCESS;
    2994     if (RT_FAILURE(rc))
    2995     {
    2996         RTMsgError("RTPathQueryInfo(\"%s\"): %Rrc (upgrade)\n", szUpgradePath, rc);
    2997         return RTEXITCODE_SUCCESS;
    2998     }
    2999 
    3000     RTFSOBJINFO OrgInfo;
    3001     rc = RTPathQueryInfo(szOrgPath, &OrgInfo, RTFSOBJATTRADD_NOTHING);
    3002     if (RT_FAILURE(rc))
    3003     {
    3004         RTMsgError("RTPathQueryInfo(\"%s\"): %Rrc (old)\n", szOrgPath, rc);
    3005         return RTEXITCODE_SUCCESS;
    3006     }
    3007 
    3008     void    *pvUpgrade;
    3009     size_t   cbUpgrade;
    3010     rc = RTFileReadAllEx(szUpgradePath, 0, UpgradeInfo.cbObject, RTFILE_RDALL_O_DENY_NONE, &pvUpgrade, &cbUpgrade);
    3011     if (RT_FAILURE(rc))
    3012     {
    3013         RTMsgError("RTPathQueryInfo(\"%s\"): %Rrc (old)\n", szOrgPath, rc);
    3014         return RTEXITCODE_SUCCESS;
    3015     }
    3016 
    3017     /*
    3018      * Compare and see if we've got a different service image or not.
    3019      */
    3020     if (OrgInfo.cbObject == UpgradeInfo.cbObject)
    3021     {
    3022         /* must compare bytes. */
    3023         void    *pvOrg;
    3024         size_t   cbOrg;
    3025         rc = RTFileReadAllEx(szOrgPath, 0, OrgInfo.cbObject, RTFILE_RDALL_O_DENY_NONE, &pvOrg, &cbOrg);
    3026         if (RT_FAILURE(rc))
    3027         {
    3028             RTMsgError("RTFileReadAllEx(\"%s\"): %Rrc\n", szOrgPath, rc);
    3029             RTFileReadAllFree(pvUpgrade, cbUpgrade);
    3030             return RTEXITCODE_SUCCESS;
    3031         }
    3032         bool fSame = !memcmp(pvUpgrade, pvOrg, OrgInfo.cbObject);
    3033         RTFileReadAllFree(pvOrg, cbOrg);
    3034         if (fSame)
    3035         {
    3036             RTFileReadAllFree(pvUpgrade, cbUpgrade);
    3037             return RTEXITCODE_SUCCESS;
    3038         }
    3039     }
    3040 
    3041     /*
    3042      * Should upgrade.  Start by creating an executable copy of the update
    3043      * image in the scratch area.
    3044      */
    3045     RTEXITCODE rcExit = txsFinalizeScratch();
    3046     if (rcExit == RTEXITCODE_SUCCESS)
    3047     {
    3048         char szTmpPath[RTPATH_MAX];
    3049         rc = RTPathJoin(szTmpPath, sizeof(szTmpPath), g_szScratchPath, RTPathFilename(szOrgPath));
    3050         if (RT_SUCCESS(rc))
    3051         {
    3052             RTFileDelete(szTmpPath); /* shouldn't hurt. */
    3053 
    3054             RTFILE hFile;
    3055             rc = RTFileOpen(&hFile, szTmpPath,
    3056                             RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE
    3057                             | (0755 << RTFILE_O_CREATE_MODE_SHIFT));
    3058             if (RT_SUCCESS(rc))
    3059             {
    3060                 rc = RTFileWrite(hFile, pvUpgrade, UpgradeInfo.cbObject, NULL);
    3061                 RTFileClose(hFile);
    3062                 if (RT_SUCCESS(rc))
    3063                 {
    3064                     /*
    3065                      * Try execute the new image and quit if it works.
    3066                      */
    3067                     const char **papszArgs = (const char **)RTMemAlloc((argc + 2 + 1) * sizeof(char **));
    3068                     if (papszArgs)
    3069                     {
    3070                         papszArgs[0] = szTmpPath;
    3071                         for (int i = 1; i < argc; i++)
    3072                             papszArgs[i] = argv[i];
    3073                         papszArgs[argc] = "--upgrading";
    3074                         papszArgs[argc + 1] = szOrgPath;
    3075                         papszArgs[argc + 2] = NULL;
    3076 
    3077                         RTMsgInfo("Launching intermediate automatic upgrade stage: \"%s\"\n", szTmpPath);
    3078                         RTPROCESS hProc;
    3079                         rc = RTProcCreate(szTmpPath, papszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &hProc);
    3080                         if (RT_SUCCESS(rc))
    3081                             *pfExit = true;
    3082                         else
    3083                             RTMsgError("RTProcCreate(\"%s\"): %Rrc (upgrade stage 1)\n", szTmpPath, rc);
    3084                         RTMemFree(papszArgs);
    3085                     }
    3086                     else
    3087                         RTMsgError("RTMemAlloc failed during upgrade attempt (stage)\n");
    3088                 }
    3089                 else
    3090                     RTMsgError("RTFileWrite(%s,,%zu): %Rrc\n", szTmpPath, UpgradeInfo.cbObject, rc);
    3091             }
    3092             else
    3093                 RTMsgError("RTFileOpen(,%s,): %Rrc\n", szTmpPath, rc);
    3094         }
    3095         else
    3096             RTMsgError("Failed to construct path to temporary upgrade image: %Rrc\n", rc);
    3097     }
    3098 
    3099     RTFileReadAllFree(pvUpgrade, cbUpgrade);
    3100     return rcExit;
    3101 }
    3102 
    3103 /**
    3104758 * Determines the default configuration.
    3105759 */
    3106 static void txsSetDefaults(void)
     760static void utsSetDefaults(void)
    3107761{
    3108762    /*
     
    3155809    if (RT_SUCCESS(rc))
    3156810#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) || defined(RT_OS_DOS)
    3157         rc = RTPathAppend(g_szDefScratchPath, sizeof(g_szDefScratchPath), "txs-XXXX.tmp");
     811        rc = RTPathAppend(g_szDefScratchPath, sizeof(g_szDefScratchPath), "uts-XXXX.tmp");
    3158812#else
    3159         rc = RTPathAppend(g_szDefScratchPath, sizeof(g_szDefScratchPath), "txs-XXXXXXXXX.tmp");
     813        rc = RTPathAppend(g_szDefScratchPath, sizeof(g_szDefScratchPath), "uts-XXXXXXXXX.tmp");
    3160814#endif
    3161815    if (RT_FAILURE(rc))
    3162816    {
    3163817        RTMsgError("RTPathTemp/Append failed when constructing scratch path: %Rrc\n", rc);
    3164         strcpy(g_szDefScratchPath, "/tmp/txs-XXXX.tmp");
     818        strcpy(g_szDefScratchPath, "/tmp/uts-XXXX.tmp");
    3165819    }
    3166820    strcpy(g_szScratchPath, g_szDefScratchPath);
     
    3178832 * @param   pszArgv0            The program name (argv[0]).
    3179833 */
    3180 static void txsUsage(PRTSTREAM pStrm, const char *argv0)
     834static void utsUsage(PRTSTREAM pStrm, const char *argv0)
    3181835{
    3182836    RTStrmPrintf(pStrm,
     
    3201855    RTStrmPrintf(pStrm, "      Default: %s\n", g_pTransport->szName);
    3202856    RTStrmPrintf(pStrm,
    3203                  "  --auto-upgrade, --no-auto-upgrade\n"
    3204                  "      To enable or disable the automatic upgrade mechanism where any different\n"
    3205                  "      version found on the CD-ROM on startup will replace the initial copy.\n"
    3206                  "      Default: --auto-upgrade\n"
    3207                  "  --upgrading <org-path>\n"
    3208                  "      Internal use only.\n");
    3209     RTStrmPrintf(pStrm,
    3210857                 "  --display-output, --no-display-output\n"
    3211858                 "      Display the output and the result of all child processes.\n");
     
    3237884 * @param   pfExit              For indicating exit when the exit code is zero.
    3238885 */
    3239 static RTEXITCODE txsParseArgv(int argc, char **argv, bool *pfExit)
     886static RTEXITCODE utsParseArgv(int argc, char **argv, bool *pfExit)
    3240887{
    3241888    *pfExit = false;
     
    3244891     * Storage for locally handled options.
    3245892     */
    3246     bool        fAutoUpgrade    = true;
    3247893    bool        fDaemonize      = true;
    3248894    bool        fDaemonized     = false;
    3249     bool        fTransportFixed = false;
    3250     const char *pszUpgrading    = NULL;
    3251895
    3252896    /*
     
    3258902        { "--cdrom",            'c', RTGETOPT_REQ_STRING  },
    3259903        { "--scratch",          's', RTGETOPT_REQ_STRING  },
    3260         { "--auto-upgrade",     'a', RTGETOPT_REQ_NOTHING },
    3261         { "--no-auto-upgrade",  'A', RTGETOPT_REQ_NOTHING },
    3262         { "--upgrading",        'U', RTGETOPT_REQ_STRING  },
    3263904        { "--display-output",   'd', RTGETOPT_REQ_NOTHING  },
    3264905        { "--no-display-output",'D', RTGETOPT_REQ_NOTHING  },
     
    3296937        switch (ch)
    3297938        {
    3298             case 'a':
    3299                 fAutoUpgrade = true;
    3300                 break;
    3301 
    3302             case 'A':
    3303                 fAutoUpgrade = false;
    3304                 break;
    3305 
    3306939            case 'c':
    3307940                rc = RTStrCopy(g_szCdRomPath, sizeof(g_szCdRomPath), Val.psz);
     
    3323956
    3324957            case 'h':
    3325                 txsUsage(g_pStdOut, argv[0]);
     958                utsUsage(g_pStdOut, argv[0]);
    3326959                *pfExit = true;
    3327960                return RTEXITCODE_SUCCESS;
     
    3335968            case 't':
    3336969            {
    3337                 PCTXSTRANSPORT pTransport = NULL;
     970                PCUTSTRANSPORT pTransport = NULL;
    3338971                for (size_t i = 0; RT_ELEMENTS(g_apTransports); i++)
    3339972                    if (!strcmp(g_apTransports[i]->szName, Val.psz))
     
    3347980                break;
    3348981            }
    3349 
    3350             case 'U':
    3351                 pszUpgrading = Val.psz;
    3352                 break;
    3353982
    3354983            case 'V':
     
    33881017
    33891018    /*
    3390      * Handle automatic upgrading of the service.
    3391      */
    3392     if (fAutoUpgrade && !*pfExit)
    3393     {
    3394         RTEXITCODE rcExit;
    3395         if (pszUpgrading)
    3396             rcExit = txsAutoUpdateStage2(argc, argv, pfExit, pszUpgrading);
    3397         else
    3398             rcExit = txsAutoUpdateStage1(argc, argv, pfExit);
    3399         if (   *pfExit
    3400             || rcExit != RTEXITCODE_SUCCESS)
    3401             return rcExit;
    3402     }
    3403 
    3404     /*
    34051019     * Daemonize ourselves if asked to.
    34061020     */
     
    34291043     * Determine defaults and parse the arguments.
    34301044     */
    3431     txsSetDefaults();
     1045    utsSetDefaults();
    34321046    bool fExit;
    3433     RTEXITCODE rcExit = txsParseArgv(argc, argv, &fExit);
     1047    RTEXITCODE rcExit = utsParseArgv(argc, argv, &fExit);
    34341048    if (rcExit != RTEXITCODE_SUCCESS || fExit)
    34351049        return rcExit;
    34361050
    34371051    /*
    3438      * Generate a UUID for this TXS instance.
    3439      */
    3440     rc = RTUuidCreate(&g_InstanceUuid);
     1052     * Initialize global state.
     1053     */
     1054    rc = utsInit();
    34411055    if (RT_FAILURE(rc))
    3442         return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTUuidCreate failed: %Rrc", rc);
    3443 
    3444     /*
    3445      * Finalize the scratch directory and initialize the transport layer.
    3446      */
    3447     rcExit = txsFinalizeScratch();
    3448     if (rcExit != RTEXITCODE_SUCCESS)
    3449         return rcExit;
    3450 
     1056        return RTEXITCODE_FAILURE;
     1057
     1058    /*
     1059     * Initialize the transport layer.
     1060     */
    34511061    rc = g_pTransport->pfnInit();
    34521062    if (RT_FAILURE(rc))
     
    34561066     * Ok, start working
    34571067     */
    3458     rcExit = txsMainLoop();
     1068    rcExit = utsMainLoop();
    34591069
    34601070    /*
  • trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceTcp.cpp

    r60266 r60279  
    11/* $Id$ */
    22/** @file
    3  * TestExecServ - Basic Remote Execution Service, TCP/IP Transport Layer.
     3 * UsbTestService - Remote USB test configuration and execution server, TCP/IP Transport Layer.
    44 */
    55
    66/*
    7  * Copyright (C) 2010-2015 Oracle Corporation
     7 * Copyright (C) 2010-2016 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    4343#include <iprt/time.h>
    4444
    45 #include "TestExecServiceInternal.h"
     45#include "UsbTestServiceInternal.h"
    4646
    4747
     
    5050*********************************************************************************************************************************/
    5151/** The default server port. */
    52 #define TXS_TCP_DEF_BIND_PORT                   5042
    53 /** The default client port. */
    54 #define TXS_TCP_DEF_CONNECT_PORT                5048
    55 
     52#define UTS_TCP_DEF_BIND_PORT                   6042
    5653/** The default server bind address. */
    57 #define TXS_TCP_DEF_BIND_ADDRESS                ""
    58 /** The default client connect address (i.e. of the host server). */
    59 #define TXS_TCP_DEF_CONNECT_ADDRESS             "10.0.2.2"
    60 
     54#define UTS_TCP_DEF_BIND_ADDRESS                ""
     55
     56
     57/*********************************************************************************************************************************
     58*   Structures and Typedefs                                                                                                      *
     59*********************************************************************************************************************************/
     60
     61/**
     62 * TCP specific client data.
     63 */
     64typedef struct UTSTRANSPORTCLIENT
     65{
     66    /** Socket of the current client. */
     67    RTSOCKET             hTcpClient;
     68    /** The size of the stashed data. */
     69    size_t               cbTcpStashed;
     70    /** The size of the stashed data allocation. */
     71    size_t               cbTcpStashedAlloced;
     72    /** The stashed data. */
     73    uint8_t             *pbTcpStashed;
     74} UTSTRANSPORTCLIENT;
    6175
    6276/*********************************************************************************************************************************
     
    6579/** @name TCP Parameters
    6680 * @{ */
    67 static enum  { TXSTCPMODE_BOTH, TXSTCPMODE_CLIENT, TXSTCPMODE_SERVER }
    68                             g_enmTcpMode            = TXSTCPMODE_BOTH;
    69 
    7081/** The addresses to bind to.  Empty string means any.  */
    71 static char                 g_szTcpBindAddr[256]    = TXS_TCP_DEF_BIND_ADDRESS;
     82static char                 g_szTcpBindAddr[256]    = UTS_TCP_DEF_BIND_ADDRESS;
    7283/** The TCP port to listen to. */
    73 static uint32_t             g_uTcpBindPort          = TXS_TCP_DEF_BIND_PORT;
    74 /** The addresses to connect to if fRevesedSetupMode is @c true. */
    75 static char                 g_szTcpConnectAddr[256] = TXS_TCP_DEF_CONNECT_ADDRESS;
    76 /** The TCP port to listen to. */
    77 static uint32_t             g_uTcpConnectPort       = TXS_TCP_DEF_CONNECT_PORT;
     84static uint32_t             g_uTcpBindPort          = UTS_TCP_DEF_BIND_PORT;
    7885/** @} */
    7986
    80 /** Critical section for serializing access to the next few variables. */
    81 static RTCRITSECT           g_TcpCritSect;
    8287/** Pointer to the TCP server instance. */
    8388static PRTTCPSERVER         g_pTcpServer            = NULL;
    84 /** Thread calling RTTcpServerListen2. */
    85 static RTTHREAD             g_hThreadTcpServer      = NIL_RTTHREAD;
    86 /** Thread calling RTTcpClientConnect. */
    87 static RTTHREAD             g_hThreadTcpConnect     = NIL_RTTHREAD;
    88 /** The main thread handle (for signalling). */
    89 static RTTHREAD             g_hThreadMain           = NIL_RTTHREAD;
    9089/** Stop connecting attempts when set. */
    9190static bool                 g_fTcpStopConnecting    = false;
    92 /** Connect cancel cookie. */
    93 static PRTTCPCLIENTCONNECTCANCEL volatile g_pTcpConnectCancelCookie = NULL;
    94 
    95 /** Socket of the current client. */
    96 static RTSOCKET             g_hTcpClient            = NIL_RTSOCKET;
    97 /** Indicates whether g_hTcpClient comes from the server or from a client
    98  * connect (relevant when closing it). */
    99 static bool                 g_fTcpClientFromServer  = false;
    100 /** The size of the stashed data. */
    101 static size_t               g_cbTcpStashed          = 0;
    102 /** The size of the stashed data allocation. */
    103 static size_t               g_cbTcpStashedAlloced   = 0;
    104 /** The stashed data. */
    105 static uint8_t             *g_pbTcpStashed          = NULL;
    106 
    107 
    108 
    109 /**
    110  * Disconnects the current client.
    111  */
    112 static void txsTcpDisconnectClient(void)
     91
     92
     93
     94/**
     95 * Disconnects the current client and frees its data structure.
     96 */
     97static void utsTcpDisconnectClient(PUTSTRANSPORTCLIENT pClient)
     98{
     99    int rc = RTTcpServerDisconnectClient2(pClient->hTcpClient);
     100    AssertRCSuccess(rc);
     101    if (pClient->pbTcpStashed)
     102        RTMemFree(pClient->pbTcpStashed);
     103    RTMemFree(pClient);
     104}
     105
     106/**
     107 * @interface_method_impl{UTSTRANSPORT,pfnWaitForConnect}
     108 */
     109static int utsTcpWaitForConnect(PPUTSTRANSPORTCLIENT ppClientNew)
    113110{
    114111    int rc;
    115     if (g_fTcpClientFromServer)
    116         rc = RTTcpServerDisconnectClient2(g_hTcpClient);
    117     else
    118         rc = RTTcpClientClose(g_hTcpClient);
    119     AssertRCSuccess(rc);
    120     g_hTcpClient = NIL_RTSOCKET;
    121 }
    122 
    123 /**
    124  * Sets the current client socket in a safe manner.
    125  *
    126  * @returns NIL_RTSOCKET if consumed, other wise hTcpClient.
    127  * @param   hTcpClient      The client socket.
    128  * @param   fFromServer     Set if server type connection.
    129  */
    130 static RTSOCKET txsTcpSetClient(RTSOCKET hTcpClient, bool fFromServer)
    131 {
    132     RTCritSectEnter(&g_TcpCritSect);
    133     if (   g_hTcpClient  == NIL_RTSOCKET
    134         && !g_fTcpStopConnecting
    135         && g_hThreadMain != NIL_RTTHREAD
    136        )
    137     {
    138         g_fTcpClientFromServer = true;
    139         g_hTcpClient = hTcpClient;
    140         int rc = RTThreadUserSignal(g_hThreadMain); AssertRC(rc);
    141         hTcpClient = NIL_RTSOCKET;
    142     }
    143     RTCritSectLeave(&g_TcpCritSect);
    144     return hTcpClient;
    145 }
    146 
    147 /**
    148  * Server mode connection thread.
    149  *
    150  * @returns iprt status code.
    151  * @param   hSelf           Thread handle. Ignored.
    152  * @param   pvUser          Ignored.
    153  */
    154 static DECLCALLBACK(int) txsTcpServerConnectThread(RTTHREAD hSelf, void *pvUser)
    155 {
    156     RTSOCKET hTcpClient;
    157     int rc = RTTcpServerListen2(g_pTcpServer, &hTcpClient);
    158     Log(("txsTcpConnectServerThread: RTTcpServerListen2 -> %Rrc\n", rc));
     112    RTSOCKET hClientNew;
     113
     114    rc = RTTcpServerListen2(g_pTcpServer, &hClientNew);
     115    Log(("utsTcpWaitForConnect: RTTcpServerListen2 -> %Rrc\n", rc));
     116
    159117    if (RT_SUCCESS(rc))
    160118    {
    161         hTcpClient = txsTcpSetClient(hTcpClient, true /*fFromServer*/);
    162         RTTcpServerDisconnectClient2(hTcpClient);
     119        PUTSTRANSPORTCLIENT pClient = (PUTSTRANSPORTCLIENT)RTMemAllocZ(sizeof(UTSTRANSPORTCLIENT));
     120        if (RT_LIKELY(pClient))
     121        {
     122            pClient->hTcpClient          = hClientNew;
     123            pClient->cbTcpStashed        = 0;
     124            pClient->cbTcpStashedAlloced = 0;
     125            pClient->pbTcpStashed        = NULL;
     126            *ppClientNew = pClient;
     127        }
     128        else
     129        {
     130            RTTcpServerDisconnectClient2(hClientNew);
     131            rc = VERR_NO_MEMORY;
     132        }
    163133    }
    164134
     
    167137
    168138/**
    169  * Checks if it's a fatal RTTcpClientConnect return code.
    170  *
    171  * @returns true / false.
    172  * @param   rc              The IPRT status code.
    173  */
    174 static bool txsTcpIsFatalClientConnectStatus(int rc)
    175 {
    176     return rc != VERR_NET_UNREACHABLE
    177         && rc != VERR_NET_HOST_DOWN
    178         && rc != VERR_NET_HOST_UNREACHABLE
    179         && rc != VERR_NET_CONNECTION_REFUSED
    180         && rc != VERR_TIMEOUT
    181         && rc != VERR_NET_CONNECTION_TIMED_OUT;
    182 }
    183 
    184 /**
    185  * Client mode connection thread.
    186  *
    187  * @returns iprt status code.
    188  * @param   hSelf           Thread handle. Use to sleep on. The main thread will
    189  *                          signal it to speed up thread shutdown.
    190  * @param   pvUser          Ignored.
    191  */
    192 static DECLCALLBACK(int) txsTcpClientConnectThread(RTTHREAD hSelf, void *pvUser)
    193 {
    194     for (;;)
    195     {
    196         /* Stop? */
    197         RTCritSectEnter(&g_TcpCritSect);
    198         bool fStop = g_fTcpStopConnecting;
    199         RTCritSectLeave(&g_TcpCritSect);
    200         if (fStop)
    201             return VINF_SUCCESS;
    202 
    203         /* Try connect. */ /** @todo make cancelable! */
    204         RTSOCKET hTcpClient;
    205         Log2(("Calling RTTcpClientConnect(%s, %u,)...\n", g_szTcpConnectAddr, g_uTcpConnectPort));
    206         int rc = RTTcpClientConnectEx(g_szTcpConnectAddr, g_uTcpConnectPort, &hTcpClient,
    207                                       RT_SOCKETCONNECT_DEFAULT_WAIT, &g_pTcpConnectCancelCookie);
    208         Log(("txsTcpRecvPkt: RTTcpClientConnect -> %Rrc\n", rc));
    209         if (RT_SUCCESS(rc))
    210         {
    211             hTcpClient = txsTcpSetClient(hTcpClient, true /*fFromServer*/);
    212             RTTcpClientCloseEx(hTcpClient, true /* fGracefulShutdown*/);
    213             break;
    214         }
    215 
    216         if (txsTcpIsFatalClientConnectStatus(rc))
    217             return rc;
    218 
    219         /* Delay a wee bit before retrying. */
    220         RTThreadUserWait(hSelf, 1536);
    221     }
    222     return VINF_SUCCESS;
    223 }
    224 
    225 /**
    226  * Wait on the threads to complete.
    227  *
    228  * @returns Thread status (if collected), otherwise VINF_SUCCESS.
    229  * @param   cMillies        The period to wait on each thread.
    230  */
    231 static int txsTcpConnectWaitOnThreads(RTMSINTERVAL cMillies)
    232 {
    233     int rcRet = VINF_SUCCESS;
    234 
    235     if (g_hThreadTcpConnect != NIL_RTTHREAD)
    236     {
    237         int rcThread;
    238         int rc2 = RTThreadWait(g_hThreadTcpConnect, cMillies, &rcThread);
    239         if (RT_SUCCESS(rc2))
    240         {
    241             g_hThreadTcpConnect = NIL_RTTHREAD;
    242             rcRet = rcThread;
    243         }
    244     }
    245 
    246     if (g_hThreadTcpServer != NIL_RTTHREAD)
    247     {
    248         int rcThread;
    249         int rc2 = RTThreadWait(g_hThreadTcpServer, cMillies, &rcThread);
    250         if (RT_SUCCESS(rc2))
    251         {
    252             g_hThreadTcpServer = NIL_RTTHREAD;
    253             if (RT_SUCCESS(rc2))
    254                 rcRet = rcThread;
    255         }
    256     }
    257     return rcRet;
    258 }
    259 
    260 /**
    261  * Connects to the peer.
    262  *
    263  * @returns VBox status code. Updates g_hTcpClient and g_fTcpClientFromServer on
    264  *          success
    265  */
    266 static int txsTcpConnect(void)
    267 {
    268     int rc;
    269     if (g_enmTcpMode == TXSTCPMODE_SERVER)
    270     {
    271         g_fTcpClientFromServer = true;
    272         rc = RTTcpServerListen2(g_pTcpServer, &g_hTcpClient);
    273         Log(("txsTcpRecvPkt: RTTcpServerListen2 -> %Rrc\n", rc));
    274     }
    275     else if (g_enmTcpMode == TXSTCPMODE_CLIENT)
    276     {
    277         g_fTcpClientFromServer = false;
    278         for (;;)
    279         {
    280             Log2(("Calling RTTcpClientConnect(%s, %u,)...\n", g_szTcpConnectAddr, g_uTcpConnectPort));
    281             rc = RTTcpClientConnect(g_szTcpConnectAddr, g_uTcpConnectPort, &g_hTcpClient);
    282             Log(("txsTcpRecvPkt: RTTcpClientConnect -> %Rrc\n", rc));
    283             if (RT_SUCCESS(rc) || txsTcpIsFatalClientConnectStatus(rc))
    284                 break;
    285 
    286             /* Delay a wee bit before retrying. */
    287             RTThreadSleep(1536);
    288         }
    289     }
    290     else
    291     {
    292         Assert(g_enmTcpMode == TXSTCPMODE_BOTH);
    293         RTTHREAD hSelf = RTThreadSelf();
    294 
    295         /*
    296          * Create client threads.
    297          */
    298         RTCritSectEnter(&g_TcpCritSect);
    299         RTThreadUserReset(hSelf);
    300         g_hThreadMain        = hSelf;
    301         g_fTcpStopConnecting = false;
    302         RTCritSectLeave(&g_TcpCritSect);
    303 
    304         txsTcpConnectWaitOnThreads(32);
    305 
    306         rc = VINF_SUCCESS;
    307         if (g_hThreadTcpConnect == NIL_RTTHREAD)
    308         {
    309             g_pTcpConnectCancelCookie = NULL;
    310             rc = RTThreadCreate(&g_hThreadTcpConnect, txsTcpClientConnectThread, NULL, 0, RTTHREADTYPE_DEFAULT,
    311                                 RTTHREADFLAGS_WAITABLE, "tcpconn");
    312         }
    313         if (g_hThreadTcpServer == NIL_RTTHREAD && RT_SUCCESS(rc))
    314             rc = RTThreadCreate(&g_hThreadTcpServer, txsTcpServerConnectThread, NULL, 0, RTTHREADTYPE_DEFAULT,
    315                                 RTTHREADFLAGS_WAITABLE, "tcpserv");
    316 
    317         RTCritSectEnter(&g_TcpCritSect);
    318 
    319         /*
    320          * Wait for connection to be established.
    321          */
    322         while (   RT_SUCCESS(rc)
    323                && g_hTcpClient == NIL_RTSOCKET)
    324         {
    325             RTCritSectLeave(&g_TcpCritSect);
    326             RTThreadUserWait(hSelf, 1536);
    327             rc = txsTcpConnectWaitOnThreads(0);
    328             RTCritSectEnter(&g_TcpCritSect);
    329         }
    330 
    331         /*
    332          * Cancel the threads.
    333          */
    334         g_hThreadMain        = NIL_RTTHREAD;
    335         g_fTcpStopConnecting = true;
    336 
    337         RTCritSectLeave(&g_TcpCritSect);
    338         RTTcpClientCancelConnect(&g_pTcpConnectCancelCookie);
    339     }
    340 
    341     AssertMsg(RT_SUCCESS(rc) ? g_hTcpClient != NIL_RTSOCKET : g_hTcpClient == NIL_RTSOCKET, ("%Rrc %p\n", rc, g_hTcpClient));
    342     g_cbTcpStashed = 0;
    343     return rc;
    344 }
    345 
    346 /**
    347  * @interface_method_impl{TXSTRANSPORT,txsTcpNotifyReboot}
    348  */
    349 static DECLCALLBACK(void) txsTcpNotifyReboot(void)
    350 {
    351     Log(("txsTcpNotifyReboot: RTTcpServerDestroy(%p)\n", g_pTcpServer));
     139 * @interface_method_impl{UTSTRANSPORT,pfnNotifyReboot}
     140 */
     141static DECLCALLBACK(void) utsTcpNotifyReboot(void)
     142{
     143    Log(("utsTcpNotifyReboot: RTTcpServerDestroy(%p)\n", g_pTcpServer));
    352144    if (g_pTcpServer)
    353145    {
    354146        int rc = RTTcpServerDestroy(g_pTcpServer);
    355147        if (RT_FAILURE(rc))
    356             RTMsgInfo("RTTcpServerDestroy failed in txsTcpNotifyReboot: %Rrc", rc);
     148            RTMsgInfo("RTTcpServerDestroy failed in utsTcpNotifyReboot: %Rrc", rc);
    357149        g_pTcpServer = NULL;
    358150    }
     
    360152
    361153/**
    362  * @interface_method_impl{TXSTRANSPORT,pfnNotifyBye}
    363  */
    364 static DECLCALLBACK(void) txsTcpNotifyBye(void)
    365 {
    366     Log(("txsTcpNotifyBye: txsTcpDisconnectClient %RTsock\n", g_hTcpClient));
    367     txsTcpDisconnectClient();
    368 }
    369 
    370 /**
    371  * @interface_method_impl{TXSTRANSPORT,pfnNotifyHowdy}
    372  */
    373 static DECLCALLBACK(void) txsTcpNotifyHowdy(void)
     154 * @interface_method_impl{UTSTRANSPORT,pfnNotifyBye}
     155 */
     156static DECLCALLBACK(void) utsTcpNotifyBye(PUTSTRANSPORTCLIENT pClient)
     157{
     158    Log(("utsTcpNotifyBye: utsTcpDisconnectClient %RTsock\n", pClient->hTcpClient));
     159    utsTcpDisconnectClient(pClient);
     160}
     161
     162/**
     163 * @interface_method_impl{UTSTRANSPORT,pfnNotifyHowdy}
     164 */
     165static DECLCALLBACK(void) utsTcpNotifyHowdy(PUTSTRANSPORTCLIENT pClient)
    374166{
    375167    /* nothing to do here */
     
    377169
    378170/**
    379  * @interface_method_impl{TXSTRANSPORT,pfnBabble}
    380  */
    381 static DECLCALLBACK(void) txsTcpBabble(PCTXSPKTHDR pPktHdr, RTMSINTERVAL cMsSendTimeout)
    382 {
    383     /*
    384      * Quietly ignore already disconnected client.
    385      */
    386     RTSOCKET hTcpClient = g_hTcpClient;
    387     if (hTcpClient == NIL_RTSOCKET)
    388         return;
    389 
     171 * @interface_method_impl{UTSTRANSPORT,pfnBabble}
     172 */
     173static DECLCALLBACK(void) utsTcpBabble(PUTSTRANSPORTCLIENT pClient, PCUTSPKTHDR pPktHdr, RTMSINTERVAL cMsSendTimeout)
     174{
    390175    /*
    391176     * Try send the babble reply.
     
    393178    NOREF(cMsSendTimeout); /** @todo implement the timeout here; non-blocking write + select-on-write. */
    394179    int     rc;
    395     size_t  cbToSend = RT_ALIGN_Z(pPktHdr->cb, TXSPKT_ALIGNMENT);
    396     do  rc = RTTcpWrite(hTcpClient, pPktHdr, cbToSend);
     180    size_t  cbToSend = RT_ALIGN_Z(pPktHdr->cb, UTSPKT_ALIGNMENT);
     181    do  rc = RTTcpWrite(pClient->hTcpClient, pPktHdr, cbToSend);
    397182    while (rc == VERR_INTERRUPTED);
    398183
     
    400185     * Disconnect the client.
    401186     */
    402     Log(("txsTcpBabble: txsTcpDisconnectClient(%RTsock) (RTTcpWrite rc=%Rrc)\n", g_hTcpClient, rc));
    403     txsTcpDisconnectClient();
    404 }
    405 
    406 /**
    407  * @interface_method_impl{TXSTRANSPORT,pfnSendPkt}
    408  */
    409 static DECLCALLBACK(int) txsTcpSendPkt(PCTXSPKTHDR pPktHdr)
    410 {
    411     Assert(pPktHdr->cb >= sizeof(TXSPKTHDR));
    412 
    413     /*
    414      * Fail if no client connection.
    415      */
    416     RTSOCKET hTcpClient = g_hTcpClient;
    417     if (hTcpClient == NIL_RTSOCKET)
    418         return VERR_NET_NOT_CONNECTED;
     187    Log(("utsTcpBabble: utsTcpDisconnectClient(%RTsock) (RTTcpWrite rc=%Rrc)\n", pClient->hTcpClient, rc));
     188    utsTcpDisconnectClient(pClient);
     189}
     190
     191/**
     192 * @interface_method_impl{UTSTRANSPORT,pfnSendPkt}
     193 */
     194static DECLCALLBACK(int) utsTcpSendPkt(PUTSTRANSPORTCLIENT pClient, PCUTSPKTHDR pPktHdr)
     195{
     196    Assert(pPktHdr->cb >= sizeof(UTSPKTHDR));
    419197
    420198    /*
    421199     * Write it.
    422200     */
    423     size_t cbToSend = RT_ALIGN_Z(pPktHdr->cb, TXSPKT_ALIGNMENT);
    424     int rc = RTTcpWrite(hTcpClient, pPktHdr, cbToSend);
     201    size_t cbToSend = RT_ALIGN_Z(pPktHdr->cb, UTSPKT_ALIGNMENT);
     202    int rc = RTTcpWrite(pClient->hTcpClient, pPktHdr, cbToSend);
    425203    if (    RT_FAILURE(rc)
    426204        &&  rc != VERR_INTERRUPTED)
    427205    {
    428206        /* assume fatal connection error. */
    429         Log(("RTTcpWrite -> %Rrc -> txsTcpDisconnectClient(%RTsock)\n", rc, g_hTcpClient));
    430         txsTcpDisconnectClient();
     207        Log(("RTTcpWrite -> %Rrc -> utsTcpDisconnectClient(%RTsock)\n", rc, pClient->hTcpClient));
     208        utsTcpDisconnectClient(pClient);
    431209    }
    432210
     
    435213
    436214/**
    437  * @interface_method_impl{TXSTRANSPORT,pfnRecvPkt}
    438  */
    439 static DECLCALLBACK(int) txsTcpRecvPkt(PPTXSPKTHDR ppPktHdr)
     215 * @interface_method_impl{UTSTRANSPORT,pfnRecvPkt}
     216 */
     217static DECLCALLBACK(int) utsTcpRecvPkt(PUTSTRANSPORTCLIENT pClient, PPUTSPKTHDR ppPktHdr)
    440218{
    441219    int rc = VINF_SUCCESS;
    442220    *ppPktHdr = NULL;
    443 
    444     /*
    445      * Do we have to wait for a client to connect?
    446      */
    447     RTSOCKET hTcpClient = g_hTcpClient;
    448     if (hTcpClient == NIL_RTSOCKET)
    449     {
    450         rc = txsTcpConnect();
    451         if (RT_FAILURE(rc))
    452             return rc;
    453         hTcpClient = g_hTcpClient; Assert(hTcpClient != NIL_RTSOCKET);
    454     }
    455221
    456222    /*
     
    465231     * Any stashed data?
    466232     */
    467     if (g_cbTcpStashedAlloced)
    468     {
    469         offData               = g_cbTcpStashed;
    470         cbDataAlloced         = g_cbTcpStashedAlloced;
    471         pbData                = g_pbTcpStashed;
    472 
    473         g_cbTcpStashed        = 0;
    474         g_cbTcpStashedAlloced = 0;
    475         g_pbTcpStashed        = NULL;
     233    if (pClient->cbTcpStashedAlloced)
     234    {
     235        offData               = pClient->cbTcpStashed;
     236        cbDataAlloced         = pClient->cbTcpStashedAlloced;
     237        pbData                = pClient->pbTcpStashed;
     238
     239        pClient->cbTcpStashed        = 0;
     240        pClient->cbTcpStashedAlloced = 0;
     241        pClient->pbTcpStashed        = NULL;
    476242    }
    477243    else
    478244    {
    479         cbDataAlloced = RT_ALIGN_Z(64,  TXSPKT_ALIGNMENT);
     245        cbDataAlloced = RT_ALIGN_Z(64,  UTSPKT_ALIGNMENT);
    480246        pbData = (uint8_t *)RTMemAlloc(cbDataAlloced);
    481247        if (!pbData)
     
    489255    {
    490256        size_t cbRead;
    491         rc = RTTcpRead(hTcpClient, pbData + offData, sizeof(uint32_t) - offData, &cbRead);
     257        rc = RTTcpRead(pClient->hTcpClient, pbData + offData, sizeof(uint32_t) - offData, &cbRead);
    492258        if (RT_FAILURE(rc))
    493259            break;
    494260        if (cbRead == 0)
    495261        {
    496             Log(("txsTcpRecvPkt: RTTcpRead -> %Rrc / cbRead=0 -> VERR_NET_NOT_CONNECTED (#1)\n", rc));
     262            Log(("utsTcpRecvPkt: RTTcpRead -> %Rrc / cbRead=0 -> VERR_NET_NOT_CONNECTED (#1)\n", rc));
    497263            rc = VERR_NET_NOT_CONNECTED;
    498264            break;
     
    504270        ASMCompilerBarrier(); /* paranoia^3 */
    505271        cbData = *(uint32_t volatile *)pbData;
    506         if (cbData >= sizeof(TXSPKTHDR) && cbData <= TXSPKT_MAX_SIZE)
     272        if (cbData >= sizeof(UTSPKTHDR) && cbData <= UTSPKT_MAX_SIZE)
    507273        {
    508274            /*
    509275             * Align the length and reallocate the return packet it necessary.
    510276             */
    511             cbData = RT_ALIGN_Z(cbData, TXSPKT_ALIGNMENT);
     277            cbData = RT_ALIGN_Z(cbData, UTSPKT_ALIGNMENT);
    512278            if (cbData > cbDataAlloced)
    513279            {
     
    529295                {
    530296                    size_t cbRead;
    531                     rc = RTTcpRead(hTcpClient, pbData + offData, cbData - offData, &cbRead);
     297                    rc = RTTcpRead(pClient->hTcpClient, pbData + offData, cbData - offData, &cbRead);
    532298                    if (RT_FAILURE(rc))
    533299                        break;
    534300                    if (cbRead == 0)
    535301                    {
    536                         Log(("txsTcpRecvPkt: RTTcpRead -> %Rrc / cbRead=0 -> VERR_NET_NOT_CONNECTED (#2)\n", rc));
     302                        Log(("utsTcpRecvPkt: RTTcpRead -> %Rrc / cbRead=0 -> VERR_NET_NOT_CONNECTED (#2)\n", rc));
    537303                        rc = VERR_NET_NOT_CONNECTED;
    538304                        break;
     
    546312    }
    547313    if (RT_SUCCESS(rc))
    548         *ppPktHdr = (PTXSPKTHDR)pbData;
     314        *ppPktHdr = (PUTSPKTHDR)pbData;
    549315    else
    550316    {
     
    555321        {
    556322            /* stash it away for the next call. */
    557             g_cbTcpStashed        = cbData;
    558             g_cbTcpStashedAlloced = cbDataAlloced;
    559             g_pbTcpStashed        = pbData;
     323            pClient->cbTcpStashed        = cbData;
     324            pClient->cbTcpStashedAlloced = cbDataAlloced;
     325            pClient->pbTcpStashed        = pbData;
    560326        }
    561327        else
     
    564330
    565331            /* assume fatal connection error. */
    566             Log(("txsTcpRecvPkt: RTTcpRead -> %Rrc -> txsTcpDisconnectClient(%RTsock)\n", rc, g_hTcpClient));
    567             txsTcpDisconnectClient();
     332            Log(("utsTcpRecvPkt: RTTcpRead -> %Rrc -> utsTcpDisconnectClient(%RTsock)\n", rc, pClient->hTcpClient));
     333            utsTcpDisconnectClient(pClient);
    568334        }
    569335    }
     
    573339
    574340/**
    575  * @interface_method_impl{TXSTRANSPORT,pfnPollSetAdd}
    576  */
    577 static DECLCALLBACK(int) txsTcpPollSetAdd(RTPOLLSET hPollSet, uint32_t idStart)
    578 {
    579     return RTPollSetAddSocket(hPollSet, g_hTcpClient, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, idStart);
    580 }
    581 
    582 /**
    583  * @interface_method_impl{TXSTRANSPORT,pfnPollIn}
    584  */
    585 static DECLCALLBACK(bool) txsTcpPollIn(void)
    586 {
    587     RTSOCKET hTcpClient = g_hTcpClient;
    588     if (hTcpClient == NIL_RTSOCKET)
    589         return false;
    590     int rc = RTTcpSelectOne(hTcpClient, 0/*cMillies*/);
     341 * @interface_method_impl{UTSTRANSPORT,pfnPollSetAdd}
     342 */
     343static DECLCALLBACK(int) utsTcpPollSetAdd(RTPOLLSET hPollSet, PUTSTRANSPORTCLIENT pClient, uint32_t idStart)
     344{
     345    return RTPollSetAddSocket(hPollSet, pClient->hTcpClient, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, idStart);
     346}
     347
     348/**
     349 * @interface_method_impl{UTSTRANSPORT,pfnPollIn}
     350 */
     351static DECLCALLBACK(bool) utsTcpPollIn(PUTSTRANSPORTCLIENT pClient)
     352{
     353    int rc = RTTcpSelectOne(pClient->hTcpClient, 0/*cMillies*/);
    591354    return RT_SUCCESS(rc);
    592355}
    593356
    594357/**
    595  * @interface_method_impl{TXSTRANSPORT,pfnTerm}
    596  */
    597 static DECLCALLBACK(void) txsTcpTerm(void)
    598 {
    599     /* Signal thread */
    600     if (RTCritSectIsInitialized(&g_TcpCritSect))
    601     {
    602         RTCritSectEnter(&g_TcpCritSect);
    603         g_fTcpStopConnecting = true;
    604         RTCritSectLeave(&g_TcpCritSect);
    605     }
    606 
    607     if (g_hThreadTcpConnect != NIL_RTTHREAD)
    608     {
    609         RTThreadUserSignal(g_hThreadTcpConnect);
    610         RTTcpClientCancelConnect(&g_pTcpConnectCancelCookie);
    611     }
    612 
     358 * @interface_method_impl{UTSTRANSPORT,pfnTerm}
     359 */
     360static DECLCALLBACK(void) utsTcpTerm(void)
     361{
    613362    /* Shut down the server (will wake up thread). */
    614363    if (g_pTcpServer)
    615364    {
    616         Log(("txsTcpTerm: Destroying server...\n"));
     365        Log(("utsTcpTerm: Destroying server...\n"));
    617366        int rc = RTTcpServerDestroy(g_pTcpServer);
    618367        if (RT_FAILURE(rc))
    619             RTMsgInfo("RTTcpServerDestroy failed in txsTcpTerm: %Rrc", rc);
     368            RTMsgInfo("RTTcpServerDestroy failed in utsTcpTerm: %Rrc", rc);
    620369        g_pTcpServer        = NULL;
    621370    }
    622371
    623     /* Shut down client */
    624     if (g_hTcpClient != NIL_RTSOCKET)
    625     {
    626         if (g_fTcpClientFromServer)
    627         {
    628             Log(("txsTcpTerm: Disconnecting client...\n"));
    629             int rc = RTTcpServerDisconnectClient2(g_hTcpClient);
    630             if (RT_FAILURE(rc))
    631                 RTMsgInfo("RTTcpServerDisconnectClient2(%RTsock) failed in txsTcpTerm: %Rrc", g_hTcpClient, rc);
    632         }
    633         else
    634         {
    635             int rc = RTTcpClientClose(g_hTcpClient);
    636             if (RT_FAILURE(rc))
    637                 RTMsgInfo("RTTcpClientClose(%RTsock) failed in txsTcpTerm: %Rrc", g_hTcpClient, rc);
    638         }
    639         g_hTcpClient        = NIL_RTSOCKET;
    640     }
    641 
    642     /* Clean up stashing. */
    643     RTMemFree(g_pbTcpStashed);
    644     g_pbTcpStashed          = NULL;
    645     g_cbTcpStashed          = 0;
    646     g_cbTcpStashedAlloced   = 0;
    647 
    648     /* Wait for the thread (they should've had some time to quit by now). */
    649     txsTcpConnectWaitOnThreads(15000);
    650 
    651     /* Finally, clean up the critical section. */
    652     if (RTCritSectIsInitialized(&g_TcpCritSect))
    653         RTCritSectDelete(&g_TcpCritSect);
    654 
    655     Log(("txsTcpTerm: done\n"));
    656 }
    657 
    658 /**
    659  * @interface_method_impl{TXSTRANSPORT,pfnInit}
    660  */
    661 static DECLCALLBACK(int) txsTcpInit(void)
    662 {
    663     int rc = RTCritSectInit(&g_TcpCritSect);
    664     if (RT_SUCCESS(rc) && g_enmTcpMode != TXSTCPMODE_CLIENT)
    665     {
    666         rc = RTTcpServerCreateEx(g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, &g_pTcpServer);
     372    Log(("utsTcpTerm: done\n"));
     373}
     374
     375/**
     376 * @interface_method_impl{UTSTRANSPORT,pfnInit}
     377 */
     378static DECLCALLBACK(int) utsTcpInit(void)
     379{
     380    int rc = RTTcpServerCreateEx(g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, &g_pTcpServer);
     381    if (RT_FAILURE(rc))
     382    {
     383        if (rc == VERR_NET_DOWN)
     384        {
     385            RTMsgInfo("RTTcpServerCreateEx(%s, %u,) failed: %Rrc, retrying for 20 seconds...\n",
     386                      g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, rc);
     387            uint64_t StartMs = RTTimeMilliTS();
     388            do
     389            {
     390                RTThreadSleep(1000);
     391                rc = RTTcpServerCreateEx(g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, &g_pTcpServer);
     392            } while (   rc == VERR_NET_DOWN
     393                     && RTTimeMilliTS() - StartMs < 20000);
     394            if (RT_SUCCESS(rc))
     395                RTMsgInfo("RTTcpServerCreateEx succceeded.\n");
     396        }
    667397        if (RT_FAILURE(rc))
    668398        {
    669             if (rc == VERR_NET_DOWN)
    670             {
    671                 RTMsgInfo("RTTcpServerCreateEx(%s, %u,) failed: %Rrc, retrying for 20 seconds...\n",
    672                           g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, rc);
    673                 uint64_t StartMs = RTTimeMilliTS();
    674                 do
    675                 {
    676                     RTThreadSleep(1000);
    677                     rc = RTTcpServerCreateEx(g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, &g_pTcpServer);
    678                 } while (   rc == VERR_NET_DOWN
    679                          && RTTimeMilliTS() - StartMs < 20000);
    680                 if (RT_SUCCESS(rc))
    681                     RTMsgInfo("RTTcpServerCreateEx succceeded.\n");
    682             }
    683             if (RT_FAILURE(rc))
    684             {
    685                 g_pTcpServer = NULL;
    686                 RTCritSectDelete(&g_TcpCritSect);
    687                 RTMsgError("RTTcpServerCreateEx(%s, %u,) failed: %Rrc\n",
    688                            g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, rc);
    689             }
     399            g_pTcpServer = NULL;
     400            RTMsgError("RTTcpServerCreateEx(%s, %u,) failed: %Rrc\n",
     401                       g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, rc);
    690402        }
    691403    }
     
    695407
    696408/** Options  */
    697 enum TXSTCPOPT
    698 {
    699     TXSTCPOPT_MODE = 1000,
    700     TXSTCPOPT_BIND_ADDRESS,
    701     TXSTCPOPT_BIND_PORT,
    702     TXSTCPOPT_CONNECT_ADDRESS,
    703     TXSTCPOPT_CONNECT_PORT,
    704 
    705     /* legacy: */
    706     TXSTCPOPT_LEGACY_PORT,
    707     TXSTCPOPT_LEGACY_CONNECT
     409enum UTSTCPOPT
     410{
     411    UTSTCPOPT_BIND_ADDRESS = 1000,
     412    UTSTCPOPT_BIND_PORT
    708413};
    709414
    710415/**
    711  * @interface_method_impl{TXSTRANSPORT,pfnOption}
    712  */
    713 static DECLCALLBACK(int) txsTcpOption(int ch, PCRTGETOPTUNION pVal)
     416 * @interface_method_impl{UTSTRANSPORT,pfnOption}
     417 */
     418static DECLCALLBACK(int) utsTcpOption(int ch, PCRTGETOPTUNION pVal)
    714419{
    715420    int rc;
     
    717422    switch (ch)
    718423    {
    719         case TXSTCPOPT_MODE:
    720             if (!strcmp(pVal->psz, "both"))
    721                 g_enmTcpMode = TXSTCPMODE_BOTH;
    722             else if (!strcmp(pVal->psz, "client"))
    723                  g_enmTcpMode = TXSTCPMODE_CLIENT;
    724             else if (!strcmp(pVal->psz, "server"))
    725                  g_enmTcpMode = TXSTCPMODE_SERVER;
    726             else
    727                 return RTMsgErrorRc(VERR_INVALID_PARAMETER, "Invalid TCP mode: '%s'\n", pVal->psz);
    728             return VINF_SUCCESS;
    729 
    730         case TXSTCPOPT_BIND_ADDRESS:
     424        case UTSTCPOPT_BIND_ADDRESS:
    731425            rc = RTStrCopy(g_szTcpBindAddr, sizeof(g_szTcpBindAddr), pVal->psz);
    732426            if (RT_FAILURE(rc))
     
    734428            return VINF_SUCCESS;
    735429
    736         case TXSTCPOPT_BIND_PORT:
    737             g_uTcpBindPort = pVal->u16 == 0 ? TXS_TCP_DEF_BIND_PORT : pVal->u16;
     430        case UTSTCPOPT_BIND_PORT:
     431            g_uTcpBindPort = pVal->u16 == 0 ? UTS_TCP_DEF_BIND_PORT : pVal->u16;
    738432            return VINF_SUCCESS;
    739 
    740         case TXSTCPOPT_LEGACY_CONNECT:
    741             g_enmTcpMode = TXSTCPMODE_CLIENT;
    742             /* fall thru */
    743         case TXSTCPOPT_CONNECT_ADDRESS:
    744             rc = RTStrCopy(g_szTcpConnectAddr, sizeof(g_szTcpConnectAddr), pVal->psz);
    745             if (RT_FAILURE(rc))
    746                 return RTMsgErrorRc(VERR_INVALID_PARAMETER, "TCP connect address is too long (%Rrc)", rc);
    747             if (!g_szTcpConnectAddr[0])
    748                 strcpy(g_szTcpConnectAddr, TXS_TCP_DEF_CONNECT_ADDRESS);
    749             return VINF_SUCCESS;
    750 
    751         case TXSTCPOPT_CONNECT_PORT:
    752             g_uTcpConnectPort = pVal->u16 == 0 ? TXS_TCP_DEF_CONNECT_PORT : pVal->u16;
    753             return VINF_SUCCESS;
    754 
    755         case TXSTCPOPT_LEGACY_PORT:
    756             if (pVal->u16 == 0)
    757             {
    758                 g_uTcpBindPort      = TXS_TCP_DEF_BIND_PORT;
    759                 g_uTcpConnectPort   = TXS_TCP_DEF_CONNECT_PORT;
    760             }
    761             else
    762             {
    763                 g_uTcpBindPort      = pVal->u16;
    764                 g_uTcpConnectPort   = pVal->u16;
    765             }
    766             return VINF_SUCCESS;
    767433    }
    768434    return VERR_TRY_AGAIN;
     
    770436
    771437/**
    772  * @interface_method_impl{TXSTRANSPORT,pfnUsage}
    773  */
    774 DECLCALLBACK(void) txsTcpUsage(PRTSTREAM pStream)
     438 * @interface_method_impl{UTSTRANSPORT,pfnUsage}
     439 */
     440DECLCALLBACK(void) utsTcpUsage(PRTSTREAM pStream)
    775441{
    776442    RTStrmPrintf(pStream,
    777                  "  --tcp-mode <both|client|server>\n"
    778                  "       Selects the mode of operation.\n"
    779                  "       Default: both\n"
    780443                 "  --tcp-bind-address <address>\n"
    781444                 "       The address(es) to listen to TCP connection on.  Empty string\n"
     
    784447                 "       The port to listen to TCP connections on.\n"
    785448                 "       Default: %u\n"
    786                  "  --tcp-connect-address <address>\n"
    787                  "       The address of the server to try connect to in client mode.\n"
    788                  "       Default: " TXS_TCP_DEF_CONNECT_ADDRESS "\n"
    789                  "  --tcp-connect-port <port>\n"
    790                  "       The port on the server to connect to in client mode.\n"
    791                  "       Default: %u\n"
    792                  , TXS_TCP_DEF_BIND_PORT, TXS_TCP_DEF_CONNECT_PORT);
     449                 , UTS_TCP_DEF_BIND_PORT);
    793450}
    794451
     
    796453static const RTGETOPTDEF  g_TcpOpts[] =
    797454{
    798     { "--tcp-mode",             TXSTCPOPT_MODE,             RTGETOPT_REQ_STRING },
    799     { "--tcp-bind-address",     TXSTCPOPT_BIND_ADDRESS,     RTGETOPT_REQ_STRING },
    800     { "--tcp-bind-port",        TXSTCPOPT_BIND_PORT,        RTGETOPT_REQ_UINT16 },
    801     { "--tcp-connect-address",  TXSTCPOPT_CONNECT_ADDRESS,  RTGETOPT_REQ_STRING },
    802     { "--tcp-connect-port",     TXSTCPOPT_CONNECT_PORT,     RTGETOPT_REQ_UINT16 },
    803 
    804     /* legacy */
    805     { "--tcp-port",             TXSTCPOPT_LEGACY_PORT,      RTGETOPT_REQ_UINT16 },
    806     { "--tcp-connect",          TXSTCPOPT_LEGACY_CONNECT,   RTGETOPT_REQ_STRING },
     455    { "--tcp-bind-address",     UTSTCPOPT_BIND_ADDRESS,     RTGETOPT_REQ_STRING },
     456    { "--tcp-bind-port",        UTSTCPOPT_BIND_PORT,        RTGETOPT_REQ_UINT16 }
    807457};
    808458
    809459/** TCP/IP transport layer. */
    810 const TXSTRANSPORT g_TcpTransport =
    811 {
    812     /* .szName          = */ "tcp",
    813     /* .pszDesc         = */ "TCP/IP",
    814     /* .cOpts           = */ &g_TcpOpts[0],
    815     /* .paOpts          = */ RT_ELEMENTS(g_TcpOpts),
    816     /* .pfnUsage        = */ txsTcpUsage,
    817     /* .pfnOption       = */ txsTcpOption,
    818     /* .pfnInit         = */ txsTcpInit,
    819     /* .pfnTerm         = */ txsTcpTerm,
    820     /* .pfnPollIn       = */ txsTcpPollIn,
    821     /* .pfnPollSetAdd   = */ txsTcpPollSetAdd,
    822     /* .pfnRecvPkt      = */ txsTcpRecvPkt,
    823     /* .pfnSendPkt      = */ txsTcpSendPkt,
    824     /* .pfnBabble       = */ txsTcpBabble,
    825     /* .pfnNotifyHowdy  = */ txsTcpNotifyHowdy,
    826     /* .pfnNotifyBye    = */ txsTcpNotifyBye,
    827     /* .pfnNotifyReboot = */ txsTcpNotifyReboot,
    828     /* .u32EndMarker    = */ UINT32_C(0x12345678)
     460const UTSTRANSPORT g_TcpTransport =
     461{
     462    /* .szName            = */ "tcp",
     463    /* .pszDesc           = */ "TCP/IP",
     464    /* .cOpts             = */ &g_TcpOpts[0],
     465    /* .paOpts            = */ RT_ELEMENTS(g_TcpOpts),
     466    /* .pfnUsage          = */ utsTcpUsage,
     467    /* .pfnOption         = */ utsTcpOption,
     468    /* .pfnInit           = */ utsTcpInit,
     469    /* .pfnTerm           = */ utsTcpTerm,
     470    /* .pfnWaitForConnect = */ utsTcpWaitForConnect,
     471    /* .pfnPollIn         = */ utsTcpPollIn,
     472    /* .pfnPollSetAdd     = */ utsTcpPollSetAdd,
     473    /* .pfnRecvPkt        = */ utsTcpRecvPkt,
     474    /* .pfnSendPkt        = */ utsTcpSendPkt,
     475    /* .pfnBabble         = */ utsTcpBabble,
     476    /* .pfnNotifyHowdy    = */ utsTcpNotifyHowdy,
     477    /* .pfnNotifyBye      = */ utsTcpNotifyBye,
     478    /* .pfnNotifyReboot   = */ utsTcpNotifyReboot,
     479    /* .u32EndMarker      = */ UINT32_C(0x12345678)
    829480};
    830 
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