0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/* $Id$ */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/** @file
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * TCP socket driver implementing the IStream interface.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/*
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Copyright (C) 2006-2015 Oracle Corporation.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * This file was contributed by Alexey Eromenko (derived from DrvNamedPipe)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * available from http://www.virtualbox.org. This file is free software;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * you can redistribute it and/or modify it under the terms of the GNU
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * General Public License (GPL) as published by the Free Software
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/*******************************************************************************
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync* Header Files *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync*******************************************************************************/
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#define LOG_GROUP LOG_GROUP_DRV_TCP
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#include <VBox/vmm/pdmdrv.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#include <iprt/assert.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#include <iprt/file.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#include <iprt/stream.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#include <iprt/alloc.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#include <iprt/string.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#include <iprt/semaphore.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#include <iprt/uuid.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#include <stdlib.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#include "VBoxDD.h"
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#ifdef RT_OS_WINDOWS
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# include <ws2tcpip.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#else /* !RT_OS_WINDOWS */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# include <errno.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# include <unistd.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# include <sys/types.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# include <sys/socket.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# include <netinet/in.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# include <netdb.h>
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# ifndef SHUT_RDWR /* OS/2 */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# define SHUT_RDWR 3
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# endif
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#endif /* !RT_OS_WINDOWS */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#ifndef SHUT_RDWR
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# ifdef SD_BOTH
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# define SHUT_RDWR SD_BOTH
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# else
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# define SHUT_RDWR 2
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync# endif
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#endif
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/*******************************************************************************
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync* Defined Constants And Macros *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync*******************************************************************************/
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/** Converts a pointer to DRVTCP::IMedia to a PDRVTCP. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#define PDMISTREAM_2_DRVTCP(pInterface) ( (PDRVTCP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTCP, IStream)) )
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/*******************************************************************************
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync* Structures and Typedefs *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync*******************************************************************************/
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/**
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * TCP driver instance data.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * @implements PDMISTREAM
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsynctypedef struct DRVTCP
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync{
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /** The stream interface. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDMISTREAM IStream;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /** Pointer to the driver instance. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PPDMDRVINS pDrvIns;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /** Pointer to the TCP server address:port or port only. (Freed by MM) */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync char *pszLocation;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /** Flag whether VirtualBox represents the server or client side. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync bool fIsServer;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /** Socket handle of the TCP socket for server. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int TCPServer;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /** Socket handle of the TCP socket connection. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int TCPConnection;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /** Thread for listening for new connections. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync RTTHREAD ListenThread;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /** Flag to signal listening thread to shut down. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync bool volatile fShutdown;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync} DRVTCP, *PDRVTCP;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/*******************************************************************************
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync* Internal Functions *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync*******************************************************************************/
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/** @copydoc PDMISTREAM::pfnRead */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsyncstatic DECLCALLBACK(int) drvTCPRead(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync{
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int rc = VINF_SUCCESS;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDRVTCP pThis = PDMISTREAM_2_DRVTCP(pInterface);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogFlow(("%s: pvBuf=%p *pcbRead=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbRead, pThis->pszLocation));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync Assert(pvBuf);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (pThis->TCPConnection != -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync ssize_t cbReallyRead;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync unsigned cbBuf = (unsigned)*pcbRead;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync cbReallyRead = recv(pThis->TCPConnection, (char *)pvBuf, cbBuf, 0);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (cbReallyRead == 0)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int tmp = pThis->TCPConnection;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->TCPConnection = -1;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#ifdef RT_OS_WINDOWS
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync closesocket(tmp);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#else
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync close(tmp);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#endif
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync else if (cbReallyRead == -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync cbReallyRead = 0;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync rc = RTErrConvertFromErrno(errno);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *pcbRead = cbReallyRead;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync else
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync RTThreadSleep(100);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *pcbRead = 0;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogFlow(("%s: *pcbRead=%zu returns %Rrc\n", __FUNCTION__, *pcbRead, rc));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return rc;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync}
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/** @copydoc PDMISTREAM::pfnWrite */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsyncstatic DECLCALLBACK(int) drvTCPWrite(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync{
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int rc = VINF_SUCCESS;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDRVTCP pThis = PDMISTREAM_2_DRVTCP(pInterface);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogFlow(("%s: pvBuf=%p *pcbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbWrite, pThis->pszLocation));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync Assert(pvBuf);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (pThis->TCPConnection != -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync ssize_t cbWritten;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync unsigned cbBuf = (unsigned)*pcbWrite;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync cbWritten = send(pThis->TCPConnection, (const char *)pvBuf, cbBuf, 0);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (cbWritten == 0)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int tmp = pThis->TCPConnection;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->TCPConnection = -1;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#ifdef RT_OS_WINDOWS
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync closesocket(tmp);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#else
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync close(tmp);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#endif
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync else if (cbWritten == -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync cbWritten = 0;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync rc = RTErrConvertFromErrno(errno);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *pcbWrite = cbWritten;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return rc;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync}
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/**
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsyncstatic DECLCALLBACK(void *) drvTCPQueryInterface(PPDMIBASE pInterface, const char *pszIID)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync{
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMISTREAM, &pThis->IStream);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return NULL;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync}
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/* -=-=-=-=- listen thread -=-=-=-=- */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/**
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Receive thread loop.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * @returns 0 on success.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * @param ThreadSelf Thread handle to this thread.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * @param pvUser User argument.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsyncstatic DECLCALLBACK(int) drvTCPListenLoop(RTTHREAD ThreadSelf, void *pvUser)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync{
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDRVTCP pThis = (PDRVTCP)pvUser;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int rc = VINF_SUCCESS;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync while (RT_LIKELY(!pThis->fShutdown))
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (listen(pThis->TCPServer, 0) == -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync rc = RTErrConvertFromErrno(errno);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogRel(("DrvTCP%d: listen failed, rc=%Rrc\n", pThis->pDrvIns->iInstance, rc));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync break;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int s = accept(pThis->TCPServer, NULL, NULL);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (s == -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync rc = RTErrConvertFromErrno(errno);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogRel(("DrvTCP%d: accept failed, rc=%Rrc\n", pThis->pDrvIns->iInstance, rc));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync break;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (pThis->TCPConnection != -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogRel(("DrvTCP%d: only single connection supported\n", pThis->pDrvIns->iInstance));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#ifdef RT_OS_WINDOWS
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync closesocket(s);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#else
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync close(s);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#endif
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync else
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->TCPConnection = s;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return VINF_SUCCESS;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync}
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/**
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Common worker for drvTCPPowerOff and drvTCPDestructor.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * @param pThis The instance data.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsyncstatic void drvTCPShutdownListener(PDRVTCP pThis)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync{
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /*
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Signal shutdown of the listener thread.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->fShutdown = true;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if ( pThis->fIsServer
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync && pThis->TCPServer != -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int rc = shutdown(pThis->TCPServer, SHUT_RDWR);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync AssertRC(rc == 0); NOREF(rc);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#ifdef RT_OS_WINDOWS
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync rc = closesocket(pThis->TCPServer);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#else
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync rc = close(pThis->TCPServer);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#endif
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync AssertRC(rc == 0);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->TCPServer = -1;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync}
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/**
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Power off a TCP socket stream driver instance.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * This does most of the destruction work, to avoid ordering dependencies.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * @param pDrvIns The driver instance data.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsyncstatic DECLCALLBACK(void) drvTCPPowerOff(PPDMDRVINS pDrvIns)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync{
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync drvTCPShutdownListener(pThis);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync}
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/**
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Destruct a TCP socket stream driver instance.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Most VM resources are freed by the VM. This callback is provided so that
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * any non-VM resources can be freed correctly.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * @param pDrvIns The driver instance data.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsyncstatic DECLCALLBACK(void) drvTCPDestruct(PPDMDRVINS pDrvIns)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync{
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync drvTCPShutdownListener(pThis);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /*
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * While the thread exits, clean up as much as we can.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync Assert(pThis->TCPServer == -1);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (pThis->TCPConnection != -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int rc = shutdown(pThis->TCPConnection, SHUT_RDWR);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync AssertRC(rc == 0); NOREF(rc);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#ifdef RT_OS_WINDOWS
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync rc = closesocket(pThis->TCPConnection);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#else
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync rc = close(pThis->TCPConnection);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync#endif
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync Assert(rc == 0);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->TCPConnection = -1;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if ( pThis->fIsServer
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync && pThis->pszLocation)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync RTFileDelete(pThis->pszLocation);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync MMR3HeapFree(pThis->pszLocation);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->pszLocation = NULL;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /*
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Wait for the thread.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (pThis->ListenThread != NIL_RTTHREAD)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int rc = RTThreadWait(pThis->ListenThread, 30000, NULL);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (RT_SUCCESS(rc))
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->ListenThread = NIL_RTTHREAD;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync else
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogRel(("DrvTCP%d: listen thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync}
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/**
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Construct a TCP socket stream driver instance.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync *
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * @copydoc FNPDMDRVCONSTRUCT
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsyncstatic DECLCALLBACK(int) drvTCPConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync{
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /*
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Init the static parts.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->pDrvIns = pDrvIns;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->pszLocation = NULL;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->fIsServer = false;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->TCPServer = -1;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->TCPConnection = -1;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->ListenThread = NIL_RTTHREAD;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->fShutdown = false;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* IBase */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pDrvIns->IBase.pfnQueryInterface = drvTCPQueryInterface;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* IStream */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->IStream.pfnRead = drvTCPRead;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->IStream.pfnWrite = drvTCPWrite;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /*
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Validate and read the configuration.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "Location|IsServer", "");
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int rc = CFGMR3QueryStringAlloc(pCfg, "Location", &pThis->pszLocation);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (RT_FAILURE(rc))
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync N_("Configuration error: querying \"Location\" resulted in %Rrc"), rc);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync rc = CFGMR3QueryBool(pCfg, "IsServer", &pThis->fIsServer);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (RT_FAILURE(rc))
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync N_("Configuration error: querying \"IsServer\" resulted in %Rrc"), rc);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /*
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * Create/Open the socket.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync int s = socket(PF_INET, SOCK_STREAM, 0);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (s == -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync N_("DrvTCP#%d failed to create socket"), pDrvIns->iInstance);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync struct sockaddr_in addr;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync memset(&addr, 0, sizeof(addr));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync addr.sin_family = AF_INET;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (pThis->fIsServer)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync addr.sin_addr.s_addr = INADDR_ANY;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync addr.sin_port = htons(/*PORT*/ atoi(pThis->pszLocation));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* Bind address to the telnet socket. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->TCPServer = s;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync RTFileDelete(pThis->pszLocation);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync N_("DrvTCP#%d failed to bind to socket %s"),
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pDrvIns->iInstance, pThis->pszLocation);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync rc = RTThreadCreate(&pThis->ListenThread, drvTCPListenLoop, (void *)pThis, 0,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "DrvTCPStream");
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (RT_FAILURE(rc))
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync N_("DrvTCP#%d failed to create listening thread"), pDrvIns->iInstance);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync else
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync char *token;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync const char *delim = ":";
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync struct hostent *server;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync token = strtok(pThis->pszLocation, delim);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if(token) {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync server = gethostbyname(token);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync memmove((char *)&addr.sin_addr.s_addr,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync (char *)server->h_addr,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync server->h_length);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync token = strtok(NULL, delim);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if(token) {
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync addr.sin_port = htons(/*PORT*/ atoi(token));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* Connect to the telnet socket. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pThis->TCPConnection = s;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync N_("DrvTCP#%d failed to connect to socket %s"),
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync pDrvIns->iInstance, pThis->pszLocation);
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync }
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync LogRel(("DrvTCP: %s, %s\n", pThis->pszLocation, pThis->fIsServer ? "server" : "client"));
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync return VINF_SUCCESS;
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync}
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync/**
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync * TCP stream driver registration record.
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsyncconst PDMDRVREG g_DrvTCP =
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync{
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* u32Version */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDM_DRVREG_VERSION,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* szName */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync "TCP",
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* szRCMod */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync "",
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* szR0Mod */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync "",
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pszDescription */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync "TCP serial stream driver.",
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* fFlags */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* fClass. */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDM_DRVREG_CLASS_STREAM,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* cMaxInstances */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync ~0U,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* cbInstance */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync sizeof(DRVTCP),
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnConstruct */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync drvTCPConstruct,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnDestruct */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync drvTCPDestruct,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnRelocate */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync NULL,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnIOCtl */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync NULL,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnPowerOn */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync NULL,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnReset */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync NULL,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnSuspend */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync NULL,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnResume */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync NULL,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnAttach */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync NULL,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnDetach */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync NULL,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnPowerOff */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync drvTCPPowerOff,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* pfnSoftReset */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync NULL,
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync /* u32EndVersion */
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync PDM_DRVREG_VERSION
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync};
0dd04aaaddd3b919138a2c0223403806e0fd4ca1vboxsync