diff options
Diffstat (limited to 'src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp')
-rw-r--r-- | src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp | 858 |
1 files changed, 858 insertions, 0 deletions
diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp b/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp new file mode 100644 index 00000000..1700c0d1 --- /dev/null +++ b/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp @@ -0,0 +1,858 @@ +/* $Id: VBoxNetBaseService.cpp $ */ +/** @file + * VBoxNetBaseService - common services for VBoxNetDHCP and VBoxNetNAT. + */ + +/* + * Copyright (C) 2009-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_NET_SERVICE + +#include <VBox/com/com.h> +#include <VBox/com/listeners.h> +#include <VBox/com/string.h> +#include <VBox/com/Guid.h> +#include <VBox/com/array.h> +#include <VBox/com/ErrorInfo.h> +#include <VBox/com/errorprint.h> +#include <VBox/com/VirtualBox.h> +#include <VBox/com/NativeEventQueue.h> + +#include <iprt/alloca.h> +#include <iprt/buildconfig.h> +#include <iprt/err.h> +#include <iprt/net.h> /* must come before getopt.h. */ +#include <iprt/getopt.h> +#include <iprt/initterm.h> +#include <iprt/param.h> +#include <iprt/path.h> +#include <iprt/process.h> +#include <iprt/stream.h> +#include <iprt/string.h> +#include <iprt/time.h> +#include <iprt/thread.h> +#include <iprt/mem.h> +#include <iprt/message.h> + +#include <VBox/sup.h> +#include <VBox/intnet.h> +#include <VBox/intnetinline.h> +#include <VBox/vmm/vmm.h> +#include <VBox/version.h> + +#include <vector> +#include <iprt/sanitized/string> + +#include <VBox/err.h> +#include <VBox/log.h> + +#include "VBoxNetLib.h" +#include "VBoxNetBaseService.h" + +#ifdef RT_OS_WINDOWS /* WinMain */ +# include <iprt/win/windows.h> +# include <stdlib.h> +#endif + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +struct VBoxNetBaseService::Data +{ + Data(const std::string& aServiceName, const std::string& aNetworkName): + m_ServiceName(aServiceName), + m_NetworkName(aNetworkName), + m_enmTrunkType(kIntNetTrunkType_WhateverNone), + m_pSession(NIL_RTR0PTR), + m_cbSendBuf(128 * _1K), + m_cbRecvBuf(256 * _1K), + m_hIf(INTNET_HANDLE_INVALID), + m_pIfBuf(NULL), + m_cVerbosity(0), + m_fNeedMain(false), + m_EventQ(NULL), + m_hThrRecv(NIL_RTTHREAD), + fShutdown(false) + { + int rc = RTCritSectInit(&m_csThis); + AssertRC(rc); + }; + + std::string m_ServiceName; + std::string m_NetworkName; + std::string m_TrunkName; + INTNETTRUNKTYPE m_enmTrunkType; + + RTMAC m_MacAddress; + RTNETADDRIPV4 m_Ipv4Address; + RTNETADDRIPV4 m_Ipv4Netmask; + + PSUPDRVSESSION m_pSession; + uint32_t m_cbSendBuf; + uint32_t m_cbRecvBuf; + INTNETIFHANDLE m_hIf; /**< The handle to the network interface. */ + PINTNETBUF m_pIfBuf; /**< Interface buffer. */ + + std::vector<PCRTGETOPTDEF> m_vecOptionDefs; + + int32_t m_cVerbosity; + + /* cs for syncing */ + RTCRITSECT m_csThis; + + /* Controls whether service will connect SVC for runtime needs */ + bool m_fNeedMain; + /* Event Queue */ + com::NativeEventQueue *m_EventQ; + + /** receiving thread, used only if main is used */ + RTTHREAD m_hThrRecv; + + bool fShutdown; + static DECLCALLBACK(int) recvLoop(RTTHREAD, void *); +}; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/* Commonly used options for network configuration */ +static RTGETOPTDEF g_aGetOptDef[] = +{ + { "--name", 'N', RTGETOPT_REQ_STRING }, + { "--network", 'n', RTGETOPT_REQ_STRING }, + { "--trunk-name", 't', RTGETOPT_REQ_STRING }, + { "--trunk-type", 'T', RTGETOPT_REQ_STRING }, + { "--mac-address", 'a', RTGETOPT_REQ_MACADDR }, + { "--ip-address", 'i', RTGETOPT_REQ_IPV4ADDR }, + { "--netmask", 'm', RTGETOPT_REQ_IPV4ADDR }, + { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, + { "--need-main", 'M', RTGETOPT_REQ_BOOL }, +}; + + +DECLCALLBACK(int) VBoxNetBaseService::Data::recvLoop(RTTHREAD, void *pvUser) +{ + VBoxNetBaseService *pThis = static_cast<VBoxNetBaseService *>(pvUser); + + HRESULT hrc = com::Initialize(); + AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); + + pThis->doReceiveLoop(); + + return VINF_SUCCESS; +} + + +VBoxNetBaseService::VBoxNetBaseService(const std::string& aName, const std::string& aNetworkName):m(NULL) +{ + m = new VBoxNetBaseService::Data(aName, aNetworkName); + + for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i) + m->m_vecOptionDefs.push_back(&g_aGetOptDef[i]); +} + + +VBoxNetBaseService::~VBoxNetBaseService() +{ + /* + * Close the interface connection. + */ + if (m) + { + shutdown(); + if (m->m_hIf != INTNET_HANDLE_INVALID) + { + INTNETIFCLOSEREQ CloseReq; + CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; + CloseReq.Hdr.cbReq = sizeof(CloseReq); + CloseReq.pSession = m->m_pSession; + CloseReq.hIf = m->m_hIf; + m->m_hIf = INTNET_HANDLE_INVALID; + int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_CLOSE, 0, &CloseReq.Hdr); + AssertRC(rc); + } + + if (m->m_pSession != NIL_RTR0PTR) + { + SUPR3Term(false /*fForced*/); + m->m_pSession = NIL_RTR0PTR; + } + + RTCritSectDelete(&m->m_csThis); + + delete m; + m = NULL; + } +} + + +int VBoxNetBaseService::init() +{ + if (isMainNeeded()) + { + HRESULT hrc = com::Initialize(); + AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); + + hrc = virtualboxClient.createInprocObject(CLSID_VirtualBoxClient); + AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); + + hrc = virtualboxClient->COMGETTER(VirtualBox)(virtualbox.asOutParam()); + AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); + } + + return VINF_SUCCESS; +} + + +bool VBoxNetBaseService::isMainNeeded() const +{ + return m->m_fNeedMain; +} + + +int VBoxNetBaseService::run() +{ + /** + * If the child class needs Main we start the receving thread which calls + * doReceiveLoop and enter to event polling loop. For other clients we do + * receiving on the current (main) thread. + */ + if (isMainNeeded()) + return startReceiveThreadAndEnterEventLoop(); + + doReceiveLoop(); + return VINF_SUCCESS; +} + +/** + * Parse the arguments. + * + * @returns 0 on success, fully bitched exit code on failure. + * + * @param argc Argument count. + * @param argv Argument vector. + * + * @todo r=bird: The --help and --version options shall not return a + * non-zero exit code. So, this method need to grow some + * complexity. I'm to blame for that blunder :/ + */ +int VBoxNetBaseService::parseArgs(int argc, char **argv) +{ + + RTGETOPTSTATE State; + PRTGETOPTDEF paOptionArray = getOptionsPtr(); + int rc = RTGetOptInit(&State, argc, argv, paOptionArray, m->m_vecOptionDefs.size(), 0, 0 /*fFlags*/); + AssertRCReturn(rc, 49); +#if 0 + /* default initialization */ + m_enmTrunkType = kIntNetTrunkType_WhateverNone; +#endif + Log2(("BaseService: parseArgs enter\n")); + + for (;;) + { + RTGETOPTUNION Val; + rc = RTGetOpt(&State, &Val); + if (!rc) + break; + switch (rc) + { + case 'N': // --name + m->m_ServiceName = Val.psz; + break; + + case 'n': // --network + m->m_NetworkName = Val.psz; + break; + + case 't': //--trunk-name + m->m_TrunkName = Val.psz; + break; + + case 'T': //--trunk-type + if (!strcmp(Val.psz, "none")) + m->m_enmTrunkType = kIntNetTrunkType_None; + else if (!strcmp(Val.psz, "whatever")) + m->m_enmTrunkType = kIntNetTrunkType_WhateverNone; + else if (!strcmp(Val.psz, "netflt")) + m->m_enmTrunkType = kIntNetTrunkType_NetFlt; + else if (!strcmp(Val.psz, "netadp")) + m->m_enmTrunkType = kIntNetTrunkType_NetAdp; + else if (!strcmp(Val.psz, "srvnat")) + m->m_enmTrunkType = kIntNetTrunkType_SrvNat; + else + { + RTStrmPrintf(g_pStdErr, "Invalid trunk type '%s'\n", Val.psz); + return RTEXITCODE_SYNTAX; + } + break; + + case 'a': // --mac-address + m->m_MacAddress = Val.MacAddr; + break; + + case 'i': // --ip-address + m->m_Ipv4Address = Val.IPv4Addr; + break; + + case 'm': // --netmask + m->m_Ipv4Netmask = Val.IPv4Addr; + break; + + case 'v': // --verbose + m->m_cVerbosity++; + break; + + case 'V': // --version (missed) + RTPrintf("%sr%u\n", RTBldCfgVersion(), RTBldCfgRevision()); + return 1; /** @todo this exit code is wrong, of course. :/ */ + + case 'M': // --need-main + m->m_fNeedMain = true; + break; + + case 'h': // --help (missed) + RTPrintf("%s Version %sr%u\n" + "Copyright (C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n" + "\n" + "Usage: %s <options>\n" + "\n" + "Options:\n", + RTProcShortName(), + RTBldCfgVersion(), + RTBldCfgRevision(), + RTProcShortName()); + for (unsigned int i = 0; i < m->m_vecOptionDefs.size(); i++) + RTPrintf(" -%c, %s\n", m->m_vecOptionDefs[i]->iShort, m->m_vecOptionDefs[i]->pszLong); + usage(); /* to print Service Specific usage */ + return 1; /** @todo this exit code is wrong, of course. :/ */ + + default: + { + int rc1 = parseOpt(rc, Val); + if (RT_FAILURE(rc1)) + { + RTEXITCODE rcExit = RTGetOptPrintError(rc, &Val); + RTPrintf("Use --help for more information.\n"); + return rcExit; + } + break; + } + } + } + + RTMemFree(paOptionArray); + return RTEXITCODE_SUCCESS; +} + + +int VBoxNetBaseService::tryGoOnline(void) +{ + /* + * Open the session, load ring-0 and issue the request. + */ + int rc = SUPR3Init(&m->m_pSession); + if (RT_FAILURE(rc)) + { + m->m_pSession = NIL_RTR0PTR; + LogRel(("VBoxNetBaseService: SUPR3Init -> %Rrc\n", rc)); + return rc; + } + + char szPath[RTPATH_MAX]; + rc = RTPathExecDir(szPath, sizeof(szPath) - sizeof("/VMMR0.r0")); + if (RT_FAILURE(rc)) + { + LogRel(("VBoxNetBaseService: RTPathExecDir -> %Rrc\n", rc)); + return rc; + } + + rc = SUPR3LoadVMM(strcat(szPath, "/VMMR0.r0"), NULL); + if (RT_FAILURE(rc)) + { + LogRel(("VBoxNetBaseService: SUPR3LoadVMM(\"%s\") -> %Rrc\n", szPath, rc)); + return rc; + } + + /* + * Create the open request. + */ + PINTNETBUF pBuf; + INTNETOPENREQ OpenReq; + OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; + OpenReq.Hdr.cbReq = sizeof(OpenReq); + OpenReq.pSession = m->m_pSession; + RTStrCopy(OpenReq.szNetwork, sizeof(OpenReq.szNetwork), m->m_NetworkName.c_str()); + OpenReq.szNetwork[sizeof(OpenReq.szNetwork) - 1] = '\0'; + RTStrCopy(OpenReq.szTrunk, sizeof(OpenReq.szTrunk), m->m_TrunkName.c_str()); + OpenReq.szTrunk[sizeof(OpenReq.szTrunk) - 1] = '\0'; + OpenReq.enmTrunkType = m->m_enmTrunkType; + OpenReq.fFlags = 0; /** @todo check this */ + OpenReq.cbSend = m->m_cbSendBuf; + OpenReq.cbRecv = m->m_cbRecvBuf; + OpenReq.hIf = INTNET_HANDLE_INVALID; + + /* + * Issue the request. + */ + Log2(("attempting to open/create network \"%s\"...\n", OpenReq.szNetwork)); + rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_OPEN, 0, &OpenReq.Hdr); + if (RT_FAILURE(rc)) + { + Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_OPEN,) failed, rc=%Rrc\n", rc)); + return rc; + } + m->m_hIf = OpenReq.hIf; + Log2(("successfully opened/created \"%s\" - hIf=%#x\n", OpenReq.szNetwork, m->m_hIf)); + + /* + * Get the ring-3 address of the shared interface buffer. + */ + INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq; + GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; + GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq); + GetBufferPtrsReq.pSession = m->m_pSession; + GetBufferPtrsReq.hIf = m->m_hIf; + GetBufferPtrsReq.pRing3Buf = NULL; + GetBufferPtrsReq.pRing0Buf = NIL_RTR0PTR; + rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, 0, &GetBufferPtrsReq.Hdr); + if (RT_FAILURE(rc)) + { + Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS,) failed, rc=%Rrc\n", rc)); + return rc; + } + pBuf = GetBufferPtrsReq.pRing3Buf; + Log2(("pBuf=%p cbBuf=%d cbSend=%d cbRecv=%d\n", + pBuf, pBuf->cbBuf, pBuf->cbSend, pBuf->cbRecv)); + m->m_pIfBuf = pBuf; + + /* + * Activate the interface. + */ + INTNETIFSETACTIVEREQ ActiveReq; + ActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; + ActiveReq.Hdr.cbReq = sizeof(ActiveReq); + ActiveReq.pSession = m->m_pSession; + ActiveReq.hIf = m->m_hIf; + ActiveReq.fActive = true; + rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SET_ACTIVE, 0, &ActiveReq.Hdr); + if (RT_SUCCESS(rc)) + return 0; + + /* bail out */ + Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE,) failed, rc=%Rrc\n", rc)); + + /* ignore this error */ + return VINF_SUCCESS; +} + + +void VBoxNetBaseService::shutdown(void) +{ + syncEnter(); + if (!m->fShutdown) + { + m->fShutdown = true; + if (m->m_hThrRecv != NIL_RTTHREAD) + { + int rc = abortWait(); + AssertRC(rc == VINF_SUCCESS || rc == VERR_SEM_DESTROYED); + rc = m->m_EventQ->interruptEventQueueProcessing(); + if (RT_SUCCESS(rc)) + { + rc = RTThreadWait(m->m_hThrRecv, 60000, NULL); + if (RT_FAILURE(rc)) + Log1WarningFunc(("RTThreadWait(%RTthrd) -> %Rrc\n", m->m_hThrRecv, rc)); + } + else + { + AssertMsgFailed(("interruptEventQueueProcessing() failed\n")); + RTThreadWait(m->m_hThrRecv , 0, NULL); + } + } + } + syncLeave(); +} + + +int VBoxNetBaseService::syncEnter() +{ + return RTCritSectEnter(&m->m_csThis); +} + + +int VBoxNetBaseService::syncLeave() +{ + return RTCritSectLeave(&m->m_csThis); +} + + +int VBoxNetBaseService::waitForIntNetEvent(int cMillis) +{ + INTNETIFWAITREQ WaitReq; + LogFlowFunc(("ENTER:cMillis: %d\n", cMillis)); + WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; + WaitReq.Hdr.cbReq = sizeof(WaitReq); + WaitReq.pSession = m->m_pSession; + WaitReq.hIf = m->m_hIf; + WaitReq.cMillies = cMillis; + + int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_WAIT, 0, &WaitReq.Hdr); + LogFlowFuncLeaveRC(rc); + return rc; +} + + +int VBoxNetBaseService::abortWait() +{ + INTNETIFABORTWAITREQ AbortReq; + LogFlowFunc(("ENTER:\n")); + AbortReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; + AbortReq.Hdr.cbReq = sizeof(AbortReq); + AbortReq.pSession = m->m_pSession; + AbortReq.hIf = m->m_hIf; + AbortReq.fNoMoreWaits = true; + + int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_ABORT_WAIT, 0, &AbortReq.Hdr); + LogFlowFuncLeaveRC(rc); + return rc; +} + + +/* S/G API */ +int VBoxNetBaseService::sendBufferOnWire(PCINTNETSEG paSegs, size_t cSegs, size_t cbFrame) +{ + /* Allocate frame */ + PINTNETHDR pHdr = NULL; + uint8_t *pbFrame = NULL; + int rc = IntNetRingAllocateFrame(&m->m_pIfBuf->Send, (uint32_t)cbFrame, &pHdr, (void **)&pbFrame); + AssertRCReturn(rc, rc); + + /* Now we fill pvFrame with S/G above */ + size_t offFrame = 0; + for (size_t idxSeg = 0; idxSeg < cSegs; ++idxSeg) + { + memcpy(&pbFrame[offFrame], paSegs[idxSeg].pv, paSegs[idxSeg].cb); + offFrame += paSegs[idxSeg].cb; + } + + /* Commit */ + IntNetRingCommitFrameEx(&m->m_pIfBuf->Send, pHdr, cbFrame); + + LogFlowFuncLeaveRC(rc); + return rc; +} + +/** + * forcible ask for send packet on the "wire" + */ +void VBoxNetBaseService::flushWire() +{ + INTNETIFSENDREQ SendReq; + SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; + SendReq.Hdr.cbReq = sizeof(SendReq); + SendReq.pSession = m->m_pSession; + SendReq.hIf = m->m_hIf; + int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SEND, 0, &SendReq.Hdr); + AssertRCReturnVoid(rc); + LogFlowFuncLeave(); +} + + +int VBoxNetBaseService::hlpUDPBroadcast(unsigned uSrcPort, unsigned uDstPort, + void const *pvData, size_t cbData) const +{ + return VBoxNetUDPBroadcast(m->m_pSession, m->m_hIf, m->m_pIfBuf, + m->m_Ipv4Address, &m->m_MacAddress, uSrcPort, + uDstPort, pvData, cbData); + +} + + +const std::string VBoxNetBaseService::getServiceName() const +{ + return m->m_ServiceName; +} + + +void VBoxNetBaseService::setServiceName(const std::string& aName) +{ + m->m_ServiceName = aName; +} + + +const std::string VBoxNetBaseService::getNetworkName() const +{ + return m->m_NetworkName; +} + + +void VBoxNetBaseService::setNetworkName(const std::string& aName) +{ + m->m_NetworkName = aName; +} + + +const RTMAC VBoxNetBaseService::getMacAddress() const +{ + return m->m_MacAddress; +} + + +void VBoxNetBaseService::setMacAddress(const RTMAC& aMac) +{ + m->m_MacAddress = aMac; +} + + +const RTNETADDRIPV4 VBoxNetBaseService::getIpv4Address() const +{ + return m->m_Ipv4Address; +} + + +void VBoxNetBaseService::setIpv4Address(const RTNETADDRIPV4& aAddress) +{ + m->m_Ipv4Address = aAddress; +} + + +const RTNETADDRIPV4 VBoxNetBaseService::getIpv4Netmask() const +{ + return m->m_Ipv4Netmask; +} + + +void VBoxNetBaseService::setIpv4Netmask(const RTNETADDRIPV4& aNetmask) +{ + m->m_Ipv4Netmask = aNetmask; +} + + +uint32_t VBoxNetBaseService::getSendBufSize() const +{ + return m->m_cbSendBuf; +} + + +void VBoxNetBaseService::setSendBufSize(uint32_t cbBuf) +{ + m->m_cbSendBuf = cbBuf; +} + + +uint32_t VBoxNetBaseService::getRecvBufSize() const +{ + return m->m_cbRecvBuf; +} + + +void VBoxNetBaseService::setRecvBufSize(uint32_t cbBuf) +{ + m->m_cbRecvBuf = cbBuf; +} + + +int32_t VBoxNetBaseService::getVerbosityLevel() const +{ + return m->m_cVerbosity; +} + + +void VBoxNetBaseService::setVerbosityLevel(int32_t aVerbosity) +{ + m->m_cVerbosity = aVerbosity; +} + + +void VBoxNetBaseService::addCommandLineOption(PCRTGETOPTDEF optDef) +{ + m->m_vecOptionDefs.push_back(optDef); +} + + +void VBoxNetBaseService::doReceiveLoop() +{ + int rc; + /* Well we're ready */ + PINTNETRINGBUF pRingBuf = &m->m_pIfBuf->Recv; + + for (;;) + { + /* + * Wait for a packet to become available. + */ + rc = waitForIntNetEvent(2000); + if (rc == VERR_SEM_DESTROYED) + break; + + if (RT_FAILURE(rc)) + { + if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED) + { + /* do we want interrupt anyone ??? */ + continue; + } + LogRel(("VBoxNetBaseService: waitForIntNetEvent returned %Rrc\n", rc)); + AssertRCReturnVoid(rc); + } + + /* + * Process the receive buffer. + */ + PCINTNETHDR pHdr; + while ((pHdr = IntNetRingGetNextFrameToRead(pRingBuf)) != NULL) + { + uint8_t const u8Type = pHdr->u8Type; + size_t cbFrame = pHdr->cbFrame; + switch (u8Type) + { + case INTNETHDR_TYPE_FRAME: + { + void *pvFrame = IntNetHdrGetFramePtr(pHdr, m->m_pIfBuf); + rc = processFrame(pvFrame, cbFrame); + if (RT_FAILURE(rc) && rc == VERR_IGNORED) + { + /* XXX: UDP + ARP for DHCP */ + VBOXNETUDPHDRS Hdrs; + size_t cb; + void *pv = VBoxNetUDPMatch(m->m_pIfBuf, RTNETIPV4_PORT_BOOTPS, &m->m_MacAddress, + VBOXNETUDP_MATCH_UNICAST + | VBOXNETUDP_MATCH_BROADCAST + | VBOXNETUDP_MATCH_CHECKSUM + | (m->m_cVerbosity > 2 ? VBOXNETUDP_MATCH_PRINT_STDERR : 0), + &Hdrs, &cb); + if (pv && cb) + processUDP(pv, cb); + else + VBoxNetArpHandleIt(m->m_pSession, m->m_hIf, m->m_pIfBuf, &m->m_MacAddress, m->m_Ipv4Address); + } + break; + } + case INTNETHDR_TYPE_GSO: + { + PCPDMNETWORKGSO pGso = IntNetHdrGetGsoContext(pHdr, m->m_pIfBuf); + rc = processGSO(pGso, cbFrame); + if (RT_FAILURE(rc) && rc == VERR_IGNORED) + break; + break; + } + + case INTNETHDR_TYPE_PADDING: + break; + + default: + break; + } + IntNetRingSkipFrame(&m->m_pIfBuf->Recv); + } /* loop */ + } +} + + +int VBoxNetBaseService::startReceiveThreadAndEnterEventLoop() +{ + AssertMsgReturn(isMainNeeded(), ("It's expected that we need Main"), VERR_INTERNAL_ERROR); + + /* start receiving thread */ + int rc = RTThreadCreate(&m->m_hThrRecv, /* thread handle*/ + &VBoxNetBaseService::Data::recvLoop, /* routine */ + this, /* user data */ + 128 * _1K, /* stack size */ + RTTHREADTYPE_IO, /* type */ + RTTHREADFLAGS_WAITABLE, /* flags */ + "RECV"); + AssertRCReturn(rc, rc); + + m->m_EventQ = com::NativeEventQueue::getMainEventQueue(); + AssertPtrReturn(m->m_EventQ, VERR_INTERNAL_ERROR); + + while (!m->fShutdown) + { + rc = m->m_EventQ->processEventQueue(RT_INDEFINITE_WAIT); + if (rc == VERR_INTERRUPTED) + { + LogFlow(("Event queue processing ended with rc=%Rrc\n", rc)); + break; + } + } + + return VINF_SUCCESS; +} + + +void VBoxNetBaseService::debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const +{ + if (iMinLevel <= m->m_cVerbosity) + { + va_list va; + va_start(va, pszFmt); + debugPrintV(iMinLevel, fMsg, pszFmt, va); + va_end(va); + } +} + + +/** + * Print debug message depending on the m_cVerbosity level. + * + * @param iMinLevel The minimum m_cVerbosity level for this message. + * @param fMsg Whether to dump parts for the current service message. + * @param pszFmt The message format string. + * @param va Optional arguments. + */ +void VBoxNetBaseService::debugPrintV(int iMinLevel, bool fMsg, const char *pszFmt, va_list va) const +{ + RT_NOREF(fMsg); + if (iMinLevel <= m->m_cVerbosity) + { + va_list vaCopy; /* This dude is *very* special, thus the copy. */ + va_copy(vaCopy, va); + RTStrmPrintf(g_pStdErr, "%s: %s: %N\n", + RTProcShortName(), + iMinLevel >= 2 ? "debug" : "info", + pszFmt, + &vaCopy); + va_end(vaCopy); + } +} + + +PRTGETOPTDEF VBoxNetBaseService::getOptionsPtr() +{ + PRTGETOPTDEF pOptArray = NULL; + pOptArray = (PRTGETOPTDEF)RTMemAlloc(sizeof(RTGETOPTDEF) * m->m_vecOptionDefs.size()); + if (!pOptArray) + return NULL; + for (unsigned int i = 0; i < m->m_vecOptionDefs.size(); ++i) + { + PCRTGETOPTDEF pOpt = m->m_vecOptionDefs[i]; + memcpy(&pOptArray[i], pOpt, sizeof(*pOpt)); + } + return pOptArray; +} |