summaryrefslogtreecommitdiffstats
path: root/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp')
-rw-r--r--src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp849
1 files changed, 849 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..a4118fa8
--- /dev/null
+++ b/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp
@@ -0,0 +1,849 @@
+/* $Id: VBoxNetBaseService.cpp $ */
+/** @file
+ * VBoxNetBaseService - common services for VBoxNetDHCP and VBoxNetNAT.
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* 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 <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<PRTGETOPTDEF> 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"
+ "(C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
+ "All rights reserved.\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"));
+ 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(const PRTGETOPTDEF 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)
+ {
+ PRTGETOPTDEF pOpt = m->m_vecOptionDefs[i];
+ memcpy(&pOptArray[i], pOpt, sizeof(*pOpt));
+ }
+ return pOptArray;
+}