cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/* $Id$ */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** @file
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * TestExecServ - Basic Remote Execution Service, TCP/IP Transport Layer.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Copyright (C) 2010-2014 Oracle Corporation
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * available from http://www.virtualbox.org. This file is free software;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * you can redistribute it and/or modify it under the terms of the GNU
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * General Public License (GPL) as published by the Free Software
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * The contents of this file may alternatively be used under the terms
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * of the Common Development and Distribution License Version 1.0
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * VirtualBox OSE distribution, in which case the provisions of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * CDDL are applicable instead of those of the GPL.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * You may elect to license modified versions of this file under the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * terms and conditions of either the GPL or the CDDL or both.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/*******************************************************************************
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync* Header Files *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync*******************************************************************************/
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#define LOG_GROUP RTLOGGROUP_DEFAULT
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/asm.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/assert.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/critsect.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/err.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/log.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/mem.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/message.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/poll.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/string.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/tcp.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/thread.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include <iprt/time.h>
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#include "TestExecServiceInternal.h"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/*******************************************************************************
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync* Defined Constants And Macros *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync*******************************************************************************/
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The default server port. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#define TXS_TCP_DEF_BIND_PORT 5042
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The default client port. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#define TXS_TCP_DEF_CONNECT_PORT 5048
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The default server bind address. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#define TXS_TCP_DEF_BIND_ADDRESS ""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The default client connect address (i.e. of the host server). */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#define TXS_TCP_DEF_CONNECT_ADDRESS "10.0.2.2"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/*******************************************************************************
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync* Global Variables *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync*******************************************************************************/
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** @name TCP Parameters
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @{ */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic enum { TXSTCPMODE_BOTH, TXSTCPMODE_CLIENT, TXSTCPMODE_SERVER }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_enmTcpMode = TXSTCPMODE_BOTH;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The addresses to bind to. Empty string means any. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic char g_szTcpBindAddr[256] = TXS_TCP_DEF_BIND_ADDRESS;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The TCP port to listen to. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic uint32_t g_uTcpBindPort = TXS_TCP_DEF_BIND_PORT;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The addresses to connect to if fRevesedSetupMode is @c true. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic char g_szTcpConnectAddr[256] = TXS_TCP_DEF_CONNECT_ADDRESS;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The TCP port to listen to. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic uint32_t g_uTcpConnectPort = TXS_TCP_DEF_CONNECT_PORT;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** @} */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** Critical section for serializing access to the next few variables. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic RTCRITSECT g_TcpCritSect;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** Pointer to the TCP server instance. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic PRTTCPSERVER g_pTcpServer = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** Thread calling RTTcpServerListen2. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic RTTHREAD g_hThreadTcpServer = NIL_RTTHREAD;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** Thread calling RTTcpClientConnect. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic RTTHREAD g_hThreadTcpConnect = NIL_RTTHREAD;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The main thread handle (for signalling). */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic RTTHREAD g_hThreadMain = NIL_RTTHREAD;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** Stop connecting attempts when set. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic bool g_fTcpStopConnecting = false;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** Connect cancel cookie. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic PRTTCPCLIENTCONNECTCANCEL volatile g_pTcpConnectCancelCookie = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** Socket of the current client. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic RTSOCKET g_hTcpClient = NIL_RTSOCKET;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** Indicates whether g_hTcpClient comes from the server or from a client
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * connect (relevant when closing it). */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic bool g_fTcpClientFromServer = false;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The size of the stashed data. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic size_t g_cbTcpStashed = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The size of the stashed data allocation. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic size_t g_cbTcpStashedAlloced = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** The stashed data. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic uint8_t *g_pbTcpStashed = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Disconnects the current client.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic void txsTcpDisconnectClient(void)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_fTcpClientFromServer)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTTcpServerDisconnectClient2(g_hTcpClient);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTTcpClientClose(g_hTcpClient);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync AssertRCSuccess(rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_hTcpClient = NIL_RTSOCKET;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Sets the current client socket in a safe manner.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @returns NIL_RTSOCKET if consumed, other wise hTcpClient.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @param hTcpClient The client socket.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @param fFromServer Set if server type connection.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic RTSOCKET txsTcpSetClient(RTSOCKET hTcpClient, bool fFromServer)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectEnter(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if ( g_hTcpClient == NIL_RTSOCKET
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync && !g_fTcpStopConnecting
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync && g_hThreadMain != NIL_RTTHREAD
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync )
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_fTcpClientFromServer = true;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_hTcpClient = hTcpClient;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc = RTThreadUserSignal(g_hThreadMain); AssertRC(rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync hTcpClient = NIL_RTSOCKET;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectLeave(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return hTcpClient;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Server mode connection thread.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @returns iprt status code.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @param hSelf Thread handle. Ignored.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @param pvUser Ignored.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(int) txsTcpServerConnectThread(RTTHREAD hSelf, void *pvUser)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTSOCKET hTcpClient;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc = RTTcpServerListen2(g_pTcpServer, &hTcpClient);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpConnectServerThread: RTTcpServerListen2 -> %Rrc\n", rc));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync hTcpClient = txsTcpSetClient(hTcpClient, true /*fFromServer*/);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTTcpServerDisconnectClient2(hTcpClient);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Checks if it's a fatal RTTcpClientConnect return code.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @returns true / false.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @param rc The iprt status.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic bool txsTcpIsFatalClientConnectStatus(int rc)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return rc != VERR_NET_UNREACHABLE
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync && rc != VERR_NET_HOST_DOWN
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync && rc != VERR_NET_HOST_UNREACHABLE
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync && rc != VERR_NET_CONNECTION_REFUSED
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync && rc != VERR_TIMEOUT
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync && rc != VERR_NET_CONNECTION_TIMED_OUT;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Client mode connection thread.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @returns iprt status code.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @param hSelf Thread handle. Use to sleep on. The main thread will
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * signal it to speed up thread shutdown.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @param pvUser Ignored.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(int) txsTcpClientConnectThread(RTTHREAD hSelf, void *pvUser)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for (;;)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Stop? */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectEnter(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync bool fStop = g_fTcpStopConnecting;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectLeave(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (fStop)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return VINF_SUCCESS;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Try connect. */ /** @todo make cancelable! */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTSOCKET hTcpClient;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log2(("Calling RTTcpClientConnect(%s, %u,)...\n", g_szTcpConnectAddr, g_uTcpConnectPort));
ca7ea74e4145b138179345f2c83316a97452467cvboxsync int rc = RTTcpClientConnectEx(g_szTcpConnectAddr, g_uTcpConnectPort, &hTcpClient,
ca7ea74e4145b138179345f2c83316a97452467cvboxsync RT_SOCKETCONNECT_DEFAULT_WAIT, &g_pTcpConnectCancelCookie);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpRecvPkt: RTTcpClientConnect -> %Rrc\n", rc));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync hTcpClient = txsTcpSetClient(hTcpClient, true /*fFromServer*/);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTTcpClientCloseEx(hTcpClient, true /* fGracefulShutdown*/);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (txsTcpIsFatalClientConnectStatus(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Delay a wee bit before retrying. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTThreadUserWait(hSelf, 1536);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return VINF_SUCCESS;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Wait on the threads to complete.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @returns Thread status (if collected), otherwise VINF_SUCCESS.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @param cMillies The period to wait on each thread.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic int txsTcpConnectWaitOnThreads(RTMSINTERVAL cMillies)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rcRet = VINF_SUCCESS;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_hThreadTcpConnect != NIL_RTTHREAD)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rcThread;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc2 = RTThreadWait(g_hThreadTcpConnect, cMillies, &rcThread);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc2))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_hThreadTcpConnect = NIL_RTTHREAD;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rcRet = rcThread;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_hThreadTcpServer != NIL_RTTHREAD)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rcThread;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc2 = RTThreadWait(g_hThreadTcpServer, cMillies, &rcThread);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc2))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_hThreadTcpServer = NIL_RTTHREAD;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc2))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rcRet = rcThread;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return rcRet;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Connects to the peer.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @returns VBox status code. Updates g_hTcpClient and g_fTcpClientFromServer on
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * success
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic int txsTcpConnect(void)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_enmTcpMode == TXSTCPMODE_SERVER)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_fTcpClientFromServer = true;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTTcpServerListen2(g_pTcpServer, &g_hTcpClient);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpRecvPkt: RTTcpServerListen2 -> %Rrc\n", rc));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else if (g_enmTcpMode == TXSTCPMODE_CLIENT)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_fTcpClientFromServer = false;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for (;;)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log2(("Calling RTTcpClientConnect(%s, %u,)...\n", g_szTcpConnectAddr, g_uTcpConnectPort));
ca7ea74e4145b138179345f2c83316a97452467cvboxsync rc = RTTcpClientConnect(g_szTcpConnectAddr, g_uTcpConnectPort, &g_hTcpClient);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpRecvPkt: RTTcpClientConnect -> %Rrc\n", rc));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc) || txsTcpIsFatalClientConnectStatus(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Delay a wee bit before retrying. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTThreadSleep(1536);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Assert(g_enmTcpMode == TXSTCPMODE_BOTH);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTTHREAD hSelf = RTThreadSelf();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Create client threads.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectEnter(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTThreadUserReset(hSelf);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_hThreadMain = hSelf;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_fTcpStopConnecting = false;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectLeave(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync txsTcpConnectWaitOnThreads(32);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = VINF_SUCCESS;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_hThreadTcpConnect == NIL_RTTHREAD)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_pTcpConnectCancelCookie = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTThreadCreate(&g_hThreadTcpConnect, txsTcpClientConnectThread, NULL, 0, RTTHREADTYPE_DEFAULT,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTTHREADFLAGS_WAITABLE, "tcpconn");
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_hThreadTcpServer == NIL_RTTHREAD && RT_SUCCESS(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTThreadCreate(&g_hThreadTcpServer, txsTcpServerConnectThread, NULL, 0, RTTHREADTYPE_DEFAULT,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTTHREADFLAGS_WAITABLE, "tcpserv");
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectEnter(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Wait for connection to be established.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync while ( RT_SUCCESS(rc)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync && g_hTcpClient == NIL_RTSOCKET)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectLeave(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTThreadUserWait(hSelf, 1536);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = txsTcpConnectWaitOnThreads(0);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectEnter(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Cancel the threads.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_hThreadMain = NIL_RTTHREAD;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_fTcpStopConnecting = true;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectLeave(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTTcpClientCancelConnect(&g_pTcpConnectCancelCookie);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync AssertMsg(RT_SUCCESS(rc) ? g_hTcpClient != NIL_RTSOCKET : g_hTcpClient == NIL_RTSOCKET, ("%Rrc %p\n", rc, g_hTcpClient));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_cbTcpStashed = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,txsTcpNotifyReboot}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(void) txsTcpNotifyReboot(void)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpNotifyReboot: RTTcpServerDestroy(%p)\n", g_pTcpServer));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_pTcpServer)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc = RTTcpServerDestroy(g_pTcpServer);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTMsgInfo("RTTcpServerDestroy failed in txsTcpNotifyReboot: %Rrc", rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_pTcpServer = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnNotifyBye}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(void) txsTcpNotifyBye(void)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpNotifyBye: txsTcpDisconnectClient %RTsock\n", g_hTcpClient));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync txsTcpDisconnectClient();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnNotifyHowdy}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(void) txsTcpNotifyHowdy(void)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* nothing to do here */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnBabble}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(void) txsTcpBabble(PCTXSPKTHDR pPktHdr, RTMSINTERVAL cMsSendTimeout)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Quietly ignore already disconnected client.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTSOCKET hTcpClient = g_hTcpClient;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (hTcpClient == NIL_RTSOCKET)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Try send the babble reply.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync NOREF(cMsSendTimeout); /** @todo implement the timeout here; non-blocking write + select-on-write. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync size_t cbToSend = RT_ALIGN_Z(pPktHdr->cb, TXSPKT_ALIGNMENT);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync do rc = RTTcpWrite(hTcpClient, pPktHdr, cbToSend);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync while (rc == VERR_INTERRUPTED);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Disconnect the client.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpBabble: txsTcpDisconnectClient(%RTsock) (RTTcpWrite rc=%Rrc)\n", g_hTcpClient, rc));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync txsTcpDisconnectClient();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnSendPkt}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(int) txsTcpSendPkt(PCTXSPKTHDR pPktHdr)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Assert(pPktHdr->cb >= sizeof(TXSPKTHDR));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Fail if no client connection.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTSOCKET hTcpClient = g_hTcpClient;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (hTcpClient == NIL_RTSOCKET)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return VERR_NET_NOT_CONNECTED;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Write it.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync size_t cbToSend = RT_ALIGN_Z(pPktHdr->cb, TXSPKT_ALIGNMENT);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc = RTTcpWrite(hTcpClient, pPktHdr, cbToSend);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if ( RT_FAILURE(rc)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync && rc != VERR_INTERRUPTED)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* assume fatal connection error. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("RTTcpWrite -> %Rrc -> txsTcpDisconnectClient(%RTsock)\n", rc, g_hTcpClient));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync txsTcpDisconnectClient();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnRecvPkt}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(int) txsTcpRecvPkt(PPTXSPKTHDR ppPktHdr)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc = VINF_SUCCESS;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *ppPktHdr = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Do we have to wait for a client to connect?
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTSOCKET hTcpClient = g_hTcpClient;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (hTcpClient == NIL_RTSOCKET)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = txsTcpConnect();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync hTcpClient = g_hTcpClient; Assert(hTcpClient != NIL_RTSOCKET);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Read state.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync size_t offData = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync size_t cbData = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync size_t cbDataAlloced;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync uint8_t *pbData = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Any stashed data?
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_cbTcpStashedAlloced)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offData = g_cbTcpStashed;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cbDataAlloced = g_cbTcpStashedAlloced;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync pbData = g_pbTcpStashed;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_cbTcpStashed = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_cbTcpStashedAlloced = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_pbTcpStashed = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cbDataAlloced = RT_ALIGN_Z(64, TXSPKT_ALIGNMENT);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync pbData = (uint8_t *)RTMemAlloc(cbDataAlloced);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (!pbData)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return VERR_NO_MEMORY;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Read and valid the length.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync while (offData < sizeof(uint32_t))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync size_t cbRead;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTTcpRead(hTcpClient, pbData + offData, sizeof(uint32_t) - offData, &cbRead);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (cbRead == 0)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpRecvPkt: RTTcpRead -> %Rrc / cbRead=0 -> VERR_NET_NOT_CONNECTED (#1)\n", rc));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = VERR_NET_NOT_CONNECTED;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offData += cbRead;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ASMCompilerBarrier(); /* paranoia^3 */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cbData = *(uint32_t volatile *)pbData;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (cbData >= sizeof(TXSPKTHDR) && cbData <= TXSPKT_MAX_SIZE)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Align the length and reallocate the return packet it necessary.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cbData = RT_ALIGN_Z(cbData, TXSPKT_ALIGNMENT);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (cbData > cbDataAlloced)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync void *pvNew = RTMemRealloc(pbData, cbData);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (pvNew)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync pbData = (uint8_t *)pvNew;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cbDataAlloced = cbData;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = VERR_NO_MEMORY;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Read the remainder of the data.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync while (offData < cbData)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync size_t cbRead;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTTcpRead(hTcpClient, pbData + offData, cbData - offData, &cbRead);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (cbRead == 0)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpRecvPkt: RTTcpRead -> %Rrc / cbRead=0 -> VERR_NET_NOT_CONNECTED (#2)\n", rc));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = VERR_NET_NOT_CONNECTED;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync offData += cbRead;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = VERR_NET_PROTOCOL_ERROR;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync *ppPktHdr = (PTXSPKTHDR)pbData;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /*
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Deal with errors.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (rc == VERR_INTERRUPTED)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* stash it away for the next call. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_cbTcpStashed = cbData;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_cbTcpStashedAlloced = cbDataAlloced;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_pbTcpStashed = pbData;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTMemFree(pbData);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* assume fatal connection error. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpRecvPkt: RTTcpRead -> %Rrc -> txsTcpDisconnectClient(%RTsock)\n", rc, g_hTcpClient));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync txsTcpDisconnectClient();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnPollSetAdd}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(int) txsTcpPollSetAdd(RTPOLLSET hPollSet, uint32_t idStart)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return RTPollSetAddSocket(hPollSet, g_hTcpClient, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, idStart);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnPollIn}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(bool) txsTcpPollIn(void)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTSOCKET hTcpClient = g_hTcpClient;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (hTcpClient == NIL_RTSOCKET)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return false;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc = RTTcpSelectOne(hTcpClient, 0/*cMillies*/);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return RT_SUCCESS(rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnTerm}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(void) txsTcpTerm(void)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Signal thread */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RTCritSectIsInitialized(&g_TcpCritSect))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectEnter(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_fTcpStopConnecting = true;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectLeave(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_hThreadTcpConnect != NIL_RTTHREAD)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTThreadUserSignal(g_hThreadTcpConnect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTTcpClientCancelConnect(&g_pTcpConnectCancelCookie);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Shut down the server (will wake up thread). */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_pTcpServer)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpTerm: Destroying server...\n"));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc = RTTcpServerDestroy(g_pTcpServer);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTMsgInfo("RTTcpServerDestroy failed in txsTcpTerm: %Rrc", rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_pTcpServer = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Shut down client */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_hTcpClient != NIL_RTSOCKET)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (g_fTcpClientFromServer)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpTerm: Disconnecting client...\n"));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc = RTTcpServerDisconnectClient2(g_hTcpClient);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTMsgInfo("RTTcpServerDisconnectClient2(%RTsock) failed in txsTcpTerm: %Rrc", g_hTcpClient, rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc = RTTcpClientClose(g_hTcpClient);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTMsgInfo("RTTcpClientClose(%RTsock) failed in txsTcpTerm: %Rrc", g_hTcpClient, rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_hTcpClient = NIL_RTSOCKET;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Clean up stashing. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTMemFree(g_pbTcpStashed);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_pbTcpStashed = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_cbTcpStashed = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_cbTcpStashedAlloced = 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Wait for the thread (they should've had some time to quit by now). */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync txsTcpConnectWaitOnThreads(15000);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Finally, clean up the critical section. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RTCritSectIsInitialized(&g_TcpCritSect))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectDelete(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Log(("txsTcpTerm: done\n"));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnInit}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(int) txsTcpInit(void)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc = RTCritSectInit(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc) && g_enmTcpMode != TXSTCPMODE_CLIENT)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTTcpServerCreateEx(g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, &g_pTcpServer);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (rc == VERR_NET_DOWN)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTMsgInfo("RTTcpServerCreateEx(%s, %u,) failed: %Rrc, retrying for 20 seconds...\n",
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync uint64_t StartMs = RTTimeMilliTS();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync do
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTThreadSleep(1000);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTTcpServerCreateEx(g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, &g_pTcpServer);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync } while ( rc == VERR_NET_DOWN
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync && RTTimeMilliTS() - StartMs < 20000);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_SUCCESS(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTMsgInfo("RTTcpServerCreateEx succceeded.\n");
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_pTcpServer = NULL;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTCritSectDelete(&g_TcpCritSect);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTMsgError("RTTcpServerCreateEx(%s, %u,) failed: %Rrc\n",
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_szTcpBindAddr[0] ? g_szTcpBindAddr : NULL, g_uTcpBindPort, rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** Options */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncenum TXSTCPOPT
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TXSTCPOPT_MODE = 1000,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TXSTCPOPT_BIND_ADDRESS,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TXSTCPOPT_BIND_PORT,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TXSTCPOPT_CONNECT_ADDRESS,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TXSTCPOPT_CONNECT_PORT,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* legacy: */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TXSTCPOPT_LEGACY_PORT,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TXSTCPOPT_LEGACY_CONNECT
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync};
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnOption}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic DECLCALLBACK(int) txsTcpOption(int ch, PCRTGETOPTUNION pVal)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int rc;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync switch (ch)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync case TXSTCPOPT_MODE:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (!strcmp(pVal->psz, "both"))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_enmTcpMode = TXSTCPMODE_BOTH;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else if (!strcmp(pVal->psz, "client"))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_enmTcpMode = TXSTCPMODE_CLIENT;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else if (!strcmp(pVal->psz, "server"))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_enmTcpMode = TXSTCPMODE_SERVER;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return RTMsgErrorRc(VERR_INVALID_PARAMETER, "Invalid TCP mode: '%s'\n", pVal->psz);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync case TXSTCPOPT_BIND_ADDRESS:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTStrCopy(g_szTcpBindAddr, sizeof(g_szTcpBindAddr), pVal->psz);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return RTMsgErrorRc(VERR_INVALID_PARAMETER, "TCP bind address is too long (%Rrc)", rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return VINF_SUCCESS;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync case TXSTCPOPT_BIND_PORT:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_uTcpBindPort = pVal->u16 == 0 ? TXS_TCP_DEF_BIND_PORT : pVal->u16;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync case TXSTCPOPT_LEGACY_CONNECT:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_enmTcpMode = TXSTCPMODE_CLIENT;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* fall thru */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync case TXSTCPOPT_CONNECT_ADDRESS:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = RTStrCopy(g_szTcpConnectAddr, sizeof(g_szTcpConnectAddr), pVal->psz);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (RT_FAILURE(rc))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return RTMsgErrorRc(VERR_INVALID_PARAMETER, "TCP connect address is too long (%Rrc)", rc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (!g_szTcpConnectAddr[0])
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync strcpy(g_szTcpConnectAddr, TXS_TCP_DEF_CONNECT_ADDRESS);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return VINF_SUCCESS;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync case TXSTCPOPT_CONNECT_PORT:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_uTcpConnectPort = pVal->u16 == 0 ? TXS_TCP_DEF_CONNECT_PORT : pVal->u16;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync break;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync case TXSTCPOPT_LEGACY_PORT:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (pVal->u16 == 0)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_uTcpBindPort = TXS_TCP_DEF_BIND_PORT;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_uTcpConnectPort = TXS_TCP_DEF_CONNECT_PORT;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync {
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_uTcpBindPort = pVal->u16;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync g_uTcpConnectPort = pVal->u16;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return VINF_SUCCESS;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync }
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return VERR_TRY_AGAIN;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/**
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @interface_method_impl{TXSTRANSPORT,pfnUsage}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncDECLCALLBACK(void) txsTcpUsage(PRTSTREAM pStream)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTStrmPrintf(pStream,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " --tcp-mode <both|client|server>\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " Selects the mode of operation.\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " Default: both\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " --tcp-bind-address <address>\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " The address(es) to listen to TCP connection on. Empty string\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " means any address, this is the default.\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " --tcp-bind-port <port>\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " The port to listen to TCP connections on.\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " Default: %u\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " --tcp-connect-address <address>\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " The address of the server to try connect to in client mode.\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " Default: " TXS_TCP_DEF_CONNECT_ADDRESS "\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " --tcp-connect-port <port>\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " The port on the server to connect to in client mode.\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync " Default: %u\n"
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , TXS_TCP_DEF_BIND_PORT, TXS_TCP_DEF_CONNECT_PORT);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync}
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** Command line options for the TCP/IP transport layer. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic const RTGETOPTDEF g_TcpOpts[] =
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { "--tcp-mode", TXSTCPOPT_MODE, RTGETOPT_REQ_STRING },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { "--tcp-bind-address", TXSTCPOPT_BIND_ADDRESS, RTGETOPT_REQ_STRING },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { "--tcp-bind-port", TXSTCPOPT_BIND_PORT, RTGETOPT_REQ_UINT16 },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { "--tcp-connect-address", TXSTCPOPT_CONNECT_ADDRESS, RTGETOPT_REQ_STRING },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { "--tcp-connect-port", TXSTCPOPT_CONNECT_PORT, RTGETOPT_REQ_UINT16 },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* legacy */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { "--tcp-port", TXSTCPOPT_LEGACY_PORT, RTGETOPT_REQ_UINT16 },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync { "--tcp-connect", TXSTCPOPT_LEGACY_CONNECT, RTGETOPT_REQ_STRING },
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync};
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/** TCP/IP transport layer. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncconst TXSTRANSPORT g_TcpTransport =
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync{
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .szName = */ "tcp",
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pszDesc = */ "TCP/IP",
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .cOpts = */ &g_TcpOpts[0],
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .paOpts = */ RT_ELEMENTS(g_TcpOpts),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnUsage = */ txsTcpUsage,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnOption = */ txsTcpOption,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnInit = */ txsTcpInit,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnTerm = */ txsTcpTerm,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnPollIn = */ txsTcpPollIn,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnPollSetAdd = */ txsTcpPollSetAdd,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnRecvPkt = */ txsTcpRecvPkt,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnSendPkt = */ txsTcpSendPkt,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnBabble = */ txsTcpBabble,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnNotifyHowdy = */ txsTcpNotifyHowdy,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnNotifyBye = */ txsTcpNotifyBye,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .pfnNotifyReboot = */ txsTcpNotifyReboot,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* .u32EndMarker = */ UINT32_C(0x12345678)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync};
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync