diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
---|---|---|
committer | <> | 2014-05-08 15:03:54 +0000 |
commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/NetworkServices/NetLib | |
parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
download | VirtualBox-master.tar.gz |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/NetworkServices/NetLib')
-rw-r--r-- | src/VBox/NetworkServices/NetLib/ComHostUtils.cpp | 215 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/VBoxNetARP.cpp | 4 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp | 619 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/VBoxNetBaseService.h | 144 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/VBoxNetIntIf.cpp | 2 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/VBoxNetLib.h | 2 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp | 349 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/VBoxNetUDP.cpp | 8 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/VBoxPortForwardString.h | 56 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/cpp/utils.h | 34 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/shared_ptr.h | 82 | ||||
-rw-r--r-- | src/VBox/NetworkServices/NetLib/utils.h | 133 |
12 files changed, 1520 insertions, 128 deletions
diff --git a/src/VBox/NetworkServices/NetLib/ComHostUtils.cpp b/src/VBox/NetworkServices/NetLib/ComHostUtils.cpp new file mode 100644 index 00000000..33452364 --- /dev/null +++ b/src/VBox/NetworkServices/NetLib/ComHostUtils.cpp @@ -0,0 +1,215 @@ +/* $Id: ComHostUtils.cpp $ */ +/** @file + * ComHostUtils.cpp + */ + +/* + * Copyright (C) 2013 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 * +*******************************************************************************/ +#ifdef RT_OS_WINDOWS +# define VBOX_COM_OUTOFPROC_MODULE +#endif +#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/EventQueue.h> +#include <VBox/com/VirtualBox.h> + +#include <iprt/alloca.h> +#include <iprt/buildconfig.h> +#include <iprt/err.h> +#include <iprt/net.h> /* must come before getopt */ +#include <iprt/getopt.h> +#include <iprt/initterm.h> +#include <iprt/message.h> +#include <iprt/param.h> +#include <iprt/path.h> +#include <iprt/stream.h> +#include <iprt/time.h> +#include <iprt/string.h> + + +#include "../NetLib/VBoxNetLib.h" +#include "../NetLib/shared_ptr.h" + +#include <vector> +#include <list> +#include <string> +#include <map> + +#include "../NetLib/VBoxNetBaseService.h" + +#ifdef RT_OS_WINDOWS /* WinMain */ +# include <Windows.h> +# include <stdlib.h> +# ifdef INET_ADDRSTRLEN +/* On Windows INET_ADDRSTRLEN defined as 22 Ws2ipdef.h, because it include port number */ +# undef INET_ADDRSTRLEN +# endif +# define INET_ADDRSTRLEN 16 +#else +# include <netinet/in.h> +#endif + +#include "utils.h" + + +VBOX_LISTENER_DECLARE(NATNetworkListenerImpl) + + +int localMappings(const ComNatPtr& nat, AddressToOffsetMapping& mapping) +{ + mapping.clear(); + + ComBstrArray strs; + int cStrs; + HRESULT hrc = nat->COMGETTER(LocalMappings)(ComSafeArrayAsOutParam(strs)); + if ( SUCCEEDED(hrc) + && (cStrs = strs.size())) + { + for (int i = 0; i < cStrs; ++i) + { + char szAddr[17]; + RTNETADDRIPV4 ip4addr; + char *pszTerm; + uint32_t u32Off; + com::Utf8Str strLo2Off(strs[i]); + const char *pszLo2Off = strLo2Off.c_str(); + + RT_ZERO(szAddr); + + pszTerm = RTStrStr(pszLo2Off, "="); + + if ( pszTerm + && (pszTerm - pszLo2Off) <= INET_ADDRSTRLEN) + { + memcpy(szAddr, pszLo2Off, (pszTerm - pszLo2Off)); + int rc = RTNetStrToIPv4Addr(szAddr, &ip4addr); + if (RT_SUCCESS(rc)) + { + u32Off = RTStrToUInt32(pszTerm + 1); + if (u32Off != 0) + mapping.insert( + AddressToOffsetMapping::value_type(ip4addr, u32Off)); + } + } + } + } + else + return VERR_NOT_FOUND; + + return VINF_SUCCESS; +} + +/** + * @note: const dropped here, because of map<K,V>::operator[] which isn't const, map<K,V>::at() has const + * variant but it's C++11. + */ +int hostDnsServers(const ComHostPtr& host, const RTNETADDRIPV4& networkid, + /*const*/ AddressToOffsetMapping& mapping, AddressList& servers) +{ + servers.clear(); + + ComBstrArray strs; + if (SUCCEEDED(host->COMGETTER(NameServers)(ComSafeArrayAsOutParam(strs)))) + { + RTNETADDRIPV4 addr; + int rc; + + for (unsigned int i = 0; i < strs.size(); ++i) + { + rc = RTNetStrToIPv4Addr(com::Utf8Str(strs[i]).c_str(), &addr); + if (RT_SUCCESS(rc)) + { + if (addr.au8[0] == 127) + { + /* XXX: here we want map<K,V>::at(const K& k) const */ + if (mapping[addr] != 0) + { + addr.u = RT_H2N_U32(RT_N2H_U32(networkid.u) + + mapping[addr]); + } + else + continue; /* XXX: Warning here (local mapping wasn't registered) */ + } + + servers.push_back(addr); + } + } + } + else + return VERR_NOT_FOUND; + + return VINF_SUCCESS; +} + + +int hostDnsSearchList(const ComHostPtr& host, std::vector<std::string>& strings) +{ + strings.clear(); + + ComBstrArray strs; + if (SUCCEEDED(host->COMGETTER(SearchStrings)(ComSafeArrayAsOutParam(strs)))) + { + for (unsigned int i = 0; i < strs.size(); ++i) + { + strings.push_back(com::Utf8Str(strs[i]).c_str()); + } + } + else + return VERR_NOT_FOUND; + + return VINF_SUCCESS; +} + + +int hostDnsDomain(const ComHostPtr& host, std::string& domainStr) +{ + com::Bstr domain; + if (SUCCEEDED(host->COMGETTER(DomainName)(domain.asOutParam()))) + { + domainStr = com::Utf8Str(domain).c_str(); + return VINF_SUCCESS; + } + + return VERR_NOT_FOUND; +} + + +int createNatListener(ComNatListenerPtr& listener, const ComVirtualBoxPtr& vboxptr, + NATNetworkEventAdapter *adapter, /* const */ ComEventTypeArray& events) +{ + ComObjPtr<NATNetworkListenerImpl> obj; + HRESULT hrc = obj.createObject(); + AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); + + hrc = obj->init(new NATNetworkListener(), adapter); + AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); + + ComPtr<IEventSource> esVBox; + hrc = vboxptr->COMGETTER(EventSource)(esVBox.asOutParam()); + AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); + + listener = obj; + + hrc = esVBox->RegisterListener(listener, ComSafeArrayAsInParam(events), true); + AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); + + return VINF_SUCCESS; +} diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetARP.cpp b/src/VBox/NetworkServices/NetLib/VBoxNetARP.cpp index ec5ed275..9cced5d2 100644 --- a/src/VBox/NetworkServices/NetLib/VBoxNetARP.cpp +++ b/src/VBox/NetworkServices/NetLib/VBoxNetARP.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -43,7 +43,7 @@ bool VBoxNetArpHandleIt(PSUPDRVSESSION pSession, INTNETIFHANDLE hIf, PINTNETBUF */ PCINTNETHDR pHdr = IntNetRingGetNextFrameToRead(&pBuf->Recv); if ( !pHdr - || pHdr->u16Type != INTNETHDR_TYPE_FRAME) + || pHdr->u8Type != INTNETHDR_TYPE_FRAME) return false; size_t cbFrame = pHdr->cbFrame; diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp b/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp index 435a1cb8..8e0cfd27 100644 --- a/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp +++ b/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp @@ -21,6 +21,16 @@ *******************************************************************************/ #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> @@ -29,19 +39,24 @@ #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" @@ -56,6 +71,65 @@ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ +struct VBoxNetBaseService::Data +{ + Data(const std::string& aName, const std::string& aNetworkName): + m_Name(aName), + m_Network(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_Name; + std::string m_Network; + 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 int recvLoop(RTTHREAD, void *); +}; + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/* Commonly used options for network configuration */ static RTGETOPTDEF g_aGetOptDef[] = { { "--name", 'N', RTGETOPT_REQ_STRING }, @@ -64,50 +138,104 @@ static RTGETOPTDEF g_aGetOptDef[] = { "--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 }, }; -VBoxNetBaseService::VBoxNetBaseService() + + +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_hIf != INTNET_HANDLE_INVALID) + if (m != NULL) { - INTNETIFCLOSEREQ CloseReq; - CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; - CloseReq.Hdr.cbReq = sizeof(CloseReq); - CloseReq.pSession = m_pSession; - CloseReq.hIf = m_hIf; - m_hIf = INTNET_HANDLE_INVALID; - int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_RTCPUID, VMMR0_DO_INTNET_IF_CLOSE, 0, &CloseReq.Hdr); - AssertRC(rc); - } + 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_RTCPUID, VMMR0_DO_INTNET_IF_CLOSE, 0, &CloseReq.Hdr); + AssertRC(rc); + } - if (m_pSession) - { - SUPR3Term(false /*fForced*/); - m_pSession = NIL_RTR0PTR; + 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() { - /* numbers from DrvIntNet */ - m_cbSendBuf = 36 * _1K; - m_cbRecvBuf = 218 * _1K; - m_hIf = INTNET_HANDLE_INVALID; - m_pIfBuf = NULL; + if (isMainNeeded()) + { + HRESULT hrc = com::Initialize(); + AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); + + hrc = virtualbox.createLocalObject(CLSID_VirtualBox); + AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); + } - m_cVerbosity = 0; - m_Name = "VBoxNetNAT"; - m_Network = "intnet"; - for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i) - m_vecOptionDefs.push_back(&g_aGetOptDef[i]); return VINF_SUCCESS; } + + +bool VBoxNetBaseService::isMainNeeded() const +{ + return m->m_fNeedMain; +} + + +int VBoxNetBaseService::run() +{ + /** + * If child class need Main we start receving thread which calls doReceiveLoop and enter to event polling loop + * and for the rest clients we do receiving on the current (main) thread. + */ + if (isMainNeeded()) + return startReceiveThreadAndEnterEventLoop(); + else + { + doReceiveLoop(); + return VINF_SUCCESS; + } +} + /** * Parse the arguments. * @@ -121,8 +249,12 @@ int VBoxNetBaseService::parseArgs(int argc, char **argv) RTGETOPTSTATE State; PRTGETOPTDEF paOptionArray = getOptionsPtr(); - int rc = RTGetOptInit(&State, argc, argv, paOptionArray, m_vecOptionDefs.size(), 0, 0 /*fFlags*/); + 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 (;;) @@ -133,58 +265,74 @@ int VBoxNetBaseService::parseArgs(int argc, char **argv) break; switch (rc) { - case 'N': - m_Name = Val.psz; + case 'N': // --name + m->m_Name = Val.psz; break; - case 'n': - m_Network = Val.psz; + + case 'n': // --network + m->m_Network = Val.psz; break; - case 't': - m_TrunkName = Val.psz; + + case 't': //--trunk-name + m->m_TrunkName = Val.psz; break; - case 'T': + + case 'T': //--trunk-type if (!strcmp(Val.psz, "none")) - m_enmTrunkType = kIntNetTrunkType_None; + m->m_enmTrunkType = kIntNetTrunkType_None; else if (!strcmp(Val.psz, "whatever")) - m_enmTrunkType = kIntNetTrunkType_WhateverNone; + m->m_enmTrunkType = kIntNetTrunkType_WhateverNone; else if (!strcmp(Val.psz, "netflt")) - m_enmTrunkType = kIntNetTrunkType_NetFlt; + m->m_enmTrunkType = kIntNetTrunkType_NetFlt; else if (!strcmp(Val.psz, "netadp")) - m_enmTrunkType = kIntNetTrunkType_NetAdp; + m->m_enmTrunkType = kIntNetTrunkType_NetAdp; else if (!strcmp(Val.psz, "srvnat")) - m_enmTrunkType = kIntNetTrunkType_SrvNat; + m->m_enmTrunkType = kIntNetTrunkType_SrvNat; else { RTStrmPrintf(g_pStdErr, "Invalid trunk type '%s'\n", Val.psz); return 1; } break; - case 'a': - m_MacAddress = Val.MacAddr; + + case 'a': // --mac-address + m->m_MacAddress = Val.MacAddr; break; - case 'i': - m_Ipv4Address = Val.IPv4Addr; + + case 'i': // --ip-address + m->m_Ipv4Address = Val.IPv4Addr; break; - case 'v': - m_cVerbosity++; + case 'm': // --netmask + m->m_Ipv4Netmask = Val.IPv4Addr; break; - case 'V': + case 'v': // --verbose + m->m_cVerbosity++; + break; + + case 'V': // --version (missed) RTPrintf("%sr%u\n", RTBldCfgVersion(), RTBldCfgRevision()); return 1; - case 'h': - RTPrintf("VBoxNetDHCP Version %s\n" + 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: VBoxNetDHCP <options>\n" + "Usage: %s <options>\n" "\n" "Options:\n", - RTBldCfgVersion()); - for (unsigned int i = 0; i < m_vecOptionDefs.size(); i++) - RTPrintf(" -%c, %s\n", m_vecOptionDefs[i]->iShort, m_vecOptionDefs[i]->pszLong); + 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; @@ -203,17 +351,18 @@ int VBoxNetBaseService::parseArgs(int argc, char **argv) return rc; } + int VBoxNetBaseService::tryGoOnline(void) { /* * Open the session, load ring-0 and issue the request. */ - int rc = SUPR3Init(&m_pSession); + int rc = SUPR3Init(&m->m_pSession); if (RT_FAILURE(rc)) { - m_pSession = NIL_RTR0PTR; + m->m_pSession = NIL_RTR0PTR; LogRel(("VBoxNetBaseService: SUPR3Init -> %Rrc\n", rc)); - return 1; + return rc; } char szPath[RTPATH_MAX]; @@ -221,14 +370,14 @@ int VBoxNetBaseService::tryGoOnline(void) if (RT_FAILURE(rc)) { LogRel(("VBoxNetBaseService: RTPathExecDir -> %Rrc\n", rc)); - return 1; + return rc; } rc = SUPR3LoadVMM(strcat(szPath, "/VMMR0.r0")); if (RT_FAILURE(rc)) { LogRel(("VBoxNetBaseService: SUPR3LoadVMM(\"%s\") -> %Rrc\n", szPath, rc)); - return 1; + return rc; } /* @@ -238,15 +387,15 @@ int VBoxNetBaseService::tryGoOnline(void) INTNETOPENREQ OpenReq; OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; OpenReq.Hdr.cbReq = sizeof(OpenReq); - OpenReq.pSession = m_pSession; - strncpy(OpenReq.szNetwork, m_Network.c_str(), sizeof(OpenReq.szNetwork)); + OpenReq.pSession = m->m_pSession; + strncpy(OpenReq.szNetwork, m->m_Network.c_str(), sizeof(OpenReq.szNetwork)); OpenReq.szNetwork[sizeof(OpenReq.szNetwork) - 1] = '\0'; - strncpy(OpenReq.szTrunk, m_TrunkName.c_str(), sizeof(OpenReq.szTrunk)); + strncpy(OpenReq.szTrunk, m->m_TrunkName.c_str(), sizeof(OpenReq.szTrunk)); OpenReq.szTrunk[sizeof(OpenReq.szTrunk) - 1] = '\0'; - OpenReq.enmTrunkType = m_enmTrunkType; + OpenReq.enmTrunkType = m->m_enmTrunkType; OpenReq.fFlags = 0; /** @todo check this */ - OpenReq.cbSend = m_cbSendBuf; - OpenReq.cbRecv = m_cbRecvBuf; + OpenReq.cbSend = m->m_cbSendBuf; + OpenReq.cbRecv = m->m_cbRecvBuf; OpenReq.hIf = INTNET_HANDLE_INVALID; /* @@ -257,10 +406,10 @@ int VBoxNetBaseService::tryGoOnline(void) if (RT_FAILURE(rc)) { Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_OPEN,) failed, rc=%Rrc\n", rc)); - goto bad; + return rc; } - m_hIf = OpenReq.hIf; - Log2(("successfully opened/created \"%s\" - hIf=%#x\n", OpenReq.szNetwork, m_hIf)); + 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. @@ -268,20 +417,20 @@ int VBoxNetBaseService::tryGoOnline(void) INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq; GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq); - GetBufferPtrsReq.pSession = m_pSession; - GetBufferPtrsReq.hIf = m_hIf; + 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)); - goto bad; + return rc; } pBuf = GetBufferPtrsReq.pRing3Buf; Log2(("pBuf=%p cbBuf=%d cbSend=%d cbRecv=%d\n", pBuf, pBuf->cbBuf, pBuf->cbSend, pBuf->cbRecv)); - m_pIfBuf = pBuf; + m->m_pIfBuf = pBuf; /* * Activate the interface. @@ -289,8 +438,8 @@ int VBoxNetBaseService::tryGoOnline(void) INTNETIFSETACTIVEREQ ActiveReq; ActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; ActiveReq.Hdr.cbReq = sizeof(ActiveReq); - ActiveReq.pSession = m_pSession; - ActiveReq.hIf = m_hIf; + 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)) @@ -299,26 +448,313 @@ int VBoxNetBaseService::tryGoOnline(void) /* bail out */ Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE,) failed, rc=%Rrc\n", rc)); - return 0; - bad: - return 1; + return VINF_SUCCESS; } + void VBoxNetBaseService::shutdown(void) { + syncEnter(); + m->fShutdown = true; + syncLeave(); +} + + +int VBoxNetBaseService::syncEnter() +{ + return RTCritSectEnter(&m->m_csThis); +} + + +int VBoxNetBaseService::syncLeave() +{ + return RTCritSectLeave(&m->m_csThis); +} + + +int VBoxNetBaseService::waitForIntNetEvent(int cMillis) +{ + int rc = VINF_SUCCESS; + 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; + + rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_WAIT, 0, &WaitReq.Hdr); + LogFlowFuncLeaveRC(rc); + return rc; +} + +/* S/G API */ +int VBoxNetBaseService::sendBufferOnWire(PCINTNETSEG pcSg, int cSg, size_t cbFrame) +{ + PINTNETHDR pHdr = NULL; + uint8_t *pu8Frame = NULL; + + /* Allocate frame */ + int rc = IntNetRingAllocateFrame(&m->m_pIfBuf->Send, cbFrame, &pHdr, (void **)&pu8Frame); + AssertRCReturn(rc, rc); + + /* Now we fill pvFrame with S/G above */ + int offFrame = 0; + for (int idxSg = 0; idxSg < cSg; ++idxSg) + { + memcpy(&pu8Frame[offFrame], pcSg[idxSg].pv, pcSg[idxSg].cb); + offFrame+=pcSg[idxSg].cb; + } + + /* Commit */ + IntNetRingCommitFrameEx(&m->m_pIfBuf->Send, pHdr, cbFrame); + + LogFlowFuncLeaveRC(rc); + return rc; } /** - * 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 DHCP message. - * @param pszFmt The message format string. - * @param ... Optional arguments. + * forcible ask for send packet on the "wire" */ -inline void VBoxNetBaseService::debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const +void VBoxNetBaseService::flushWire() { - if (iMinLevel <= m_cVerbosity) + int rc = VINF_SUCCESS; + INTNETIFSENDREQ SendReq; + SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; + SendReq.Hdr.cbReq = sizeof(SendReq); + SendReq.pSession = m->m_pSession; + SendReq.hIf = m->m_hIf; + 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::getName() const +{ + return m->m_Name; +} + + +void VBoxNetBaseService::setName(const std::string& aName) +{ + m->m_Name = aName; +} + + +const std::string VBoxNetBaseService::getNetwork() const +{ + return m->m_Network; +} + + +void VBoxNetBaseService::setNetwork(const std::string& aNetwork) +{ + m->m_Network = aNetwork; +} + + +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. + */ + /* 2. waiting for request for */ + rc = waitForIntNetEvent(2000); + if (RT_FAILURE(rc)) + { + if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED) + { + /* do we want interrupt anyone ??? */ + continue; + } + LogRel(("VBoxNetNAT: 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 */ + 0, /* flags, @todo: waitable ?*/ + "RECV"); + AssertRCReturn(rc,rc); + + m->m_EventQ = com::NativeEventQueue::getMainEventQueue(); + AssertPtrReturn(m->m_EventQ, VERR_INTERNAL_ERROR); + + while(true) + { + m->m_EventQ->processEventQueue(0); + + if (m->fShutdown) + break; + + m->m_EventQ->processEventQueue(500); + } + + 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); @@ -332,32 +768,37 @@ inline void VBoxNetBaseService::debugPrint(int32_t iMinLevel, bool fMsg, const c * 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 DHCP 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 { - if (iMinLevel <= m_cVerbosity) + if (iMinLevel <= m->m_cVerbosity) { va_list vaCopy; /* This dude is *very* special, thus the copy. */ va_copy(vaCopy, va); - RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: %s: %N\n", iMinLevel >= 2 ? "debug" : "info", pszFmt, &vaCopy); + 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_vecOptionDefs.size()); + pOptArray = (PRTGETOPTDEF)RTMemAlloc(sizeof(RTGETOPTDEF) * m->m_vecOptionDefs.size()); if (!pOptArray) return NULL; - for (unsigned int i = 0; i < m_vecOptionDefs.size(); ++i) + for (unsigned int i = 0; i < m->m_vecOptionDefs.size(); ++i) { - PRTGETOPTDEF pOpt = m_vecOptionDefs[i]; - memcpy(&pOptArray[i], m_vecOptionDefs[i], sizeof(RTGETOPTDEF)); + PRTGETOPTDEF pOpt = m->m_vecOptionDefs[i]; + memcpy(&pOptArray[i], m->m_vecOptionDefs[i], sizeof(RTGETOPTDEF)); } return pOptArray; } diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.h b/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.h index eab9a515..a551bc88 100644 --- a/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.h +++ b/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -17,45 +17,127 @@ #ifndef ___VBoxNetBaseService_h___ #define ___VBoxNetBaseService_h___ -class VBoxNetBaseService + +#include <iprt/critsect.h> + + +class VBoxNetHlpUDPService { public: - VBoxNetBaseService(); +virtual int hlpUDPBroadcast(unsigned uSrcPort, unsigned uDstPort, + void const *pvData, size_t cbData) const = 0; +}; + + +class VBoxNetLockee +{ +public: + virtual int syncEnter() = 0; + virtual int syncLeave() = 0; +}; + + +class VBoxNetALock +{ +public: + VBoxNetALock(VBoxNetLockee *a_lck):m_lck(a_lck) + { + if (m_lck) + m_lck->syncEnter(); + } + + ~VBoxNetALock() + { + if (m_lck) + m_lck->syncLeave(); + } + +private: + VBoxNetLockee *m_lck; +}; + +# ifndef BASE_SERVICES_ONLY +class VBoxNetBaseService: public VBoxNetHlpUDPService, public VBoxNetLockee +{ +public: + VBoxNetBaseService(const std::string& aName, const std::string& aNetworkName); virtual ~VBoxNetBaseService(); int parseArgs(int argc, char **argv); int tryGoOnline(void); void shutdown(void); + int syncEnter(); + int syncLeave(); + int waitForIntNetEvent(int cMillis); + int sendBufferOnWire(PCINTNETSEG pSg, int cSg, size_t cbBuffer); + void flushWire(); + + virtual int hlpUDPBroadcast(unsigned uSrcPort, unsigned uDstPort, + void const *pvData, size_t cbData) const; virtual void usage(void) = 0; - virtual void run(void) = 0; - virtual int init(void); virtual int parseOpt(int rc, const RTGETOPTUNION& getOptVal) = 0; + virtual int processFrame(void *, size_t) = 0; + virtual int processGSO(PCPDMNETWORKGSO, size_t) = 0; + virtual int processUDP(void *, size_t) = 0; - inline void debugPrint( int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const; - void debugPrintV(int32_t iMinLevel, bool fMsg, const char *pszFmt, va_list va) const; -public: - /** @name The server configuration data members. - * @{ */ - std::string m_Name; - std::string m_Network; - std::string m_TrunkName; - INTNETTRUNKTYPE m_enmTrunkType; - RTMAC m_MacAddress; - RTNETADDRIPV4 m_Ipv4Address; - /** @} */ - /** @name The network interface - * @{ */ - 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; - /** @} */ - /** @name Debug stuff - * @{ */ - int32_t m_cVerbosity; -private: + + virtual int init(void); + virtual int run(void); + virtual bool isMainNeeded() const; + +protected: + const std::string getName() const; + void setName(const std::string&); + + const std::string getNetwork() const; + void setNetwork(const std::string&); + + const RTMAC getMacAddress() const; + void setMacAddress(const RTMAC&); + + const RTNETADDRIPV4 getIpv4Address() const; + void setIpv4Address(const RTNETADDRIPV4&); + + const RTNETADDRIPV4 getIpv4Netmask() const; + void setIpv4Netmask(const RTNETADDRIPV4&); + + uint32_t getSendBufSize() const; + void setSendBufSize(uint32_t); + + uint32_t getRecvBufSize() const; + void setRecvBufSize(uint32_t); + + int32_t getVerbosityLevel() const; + void setVerbosityLevel(int32_t); + + void addCommandLineOption(const PRTGETOPTDEF); + + /** + * 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 DHCP message. + * @param pszFmt The message format string. + * @param ... Optional arguments. + */ + void debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const; + virtual void debugPrintV(int32_t iMinLevel, bool fMsg, const char *pszFmt, va_list va) const; + + private: + void doReceiveLoop(); + + /** starts receiving thread and enter event polling loop. */ + int startReceiveThreadAndEnterEventLoop(); + + protected: + /* VirtualBox instance */ + ComPtr<IVirtualBox> virtualbox; + + private: + struct Data; + Data *m; + + private: PRTGETOPTDEF getOptionsPtr(); - /** @} */ }; +# endif #endif diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetIntIf.cpp b/src/VBox/NetworkServices/NetLib/VBoxNetIntIf.cpp index 74a3998a..f9f7388f 100644 --- a/src/VBox/NetworkServices/NetLib/VBoxNetIntIf.cpp +++ b/src/VBox/NetworkServices/NetLib/VBoxNetIntIf.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetLib.h b/src/VBox/NetworkServices/NetLib/VBoxNetLib.h index e1150bfb..2f7f699d 100644 --- a/src/VBox/NetworkServices/NetLib/VBoxNetLib.h +++ b/src/VBox/NetworkServices/NetLib/VBoxNetLib.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp b/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp new file mode 100644 index 00000000..c5333025 --- /dev/null +++ b/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp @@ -0,0 +1,349 @@ +/* $Id: VBoxNetPortForwardString.cpp $ */ +/** @file + * VBoxNetPortForwardString - Routines for managing port-forward strings. + */ + +/* + * Copyright (C) 2006-2013 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 * +*******************************************************************************/ +#ifndef RT_OS_WINDOWS +#include <netinet/in.h> +#else +# include <Winsock2.h> +# include <Ws2ipdef.h> +#endif + +#include <iprt/cdefs.h> +#include <iprt/cidr.h> +#include <iprt/param.h> +#include <iprt/path.h> +#include <iprt/stream.h> +#include <iprt/string.h> +#include <iprt/net.h> +#include <iprt/getopt.h> +#include <iprt/ctype.h> + + +#include <VBox/log.h> + +#include "VBoxPortForwardString.h" + + +#define PF_FIELD_SEPARATOR ':' +#define PF_ADDRESS_FIELD_STARTS '[' +#define PF_ADDRESS_FIELD_ENDS ']' + +#define PF_STR_FIELD_SEPARATOR ":" +#define PF_STR_ADDRESS_FIELD_STARTS "[" +#define PF_STR_ADDRESS_FIELD_ENDS "]" + +static int netPfStrAddressParse(char *pszRaw, int cbRaw, + char *pszAddress, int cbAddress, + bool fEmptyAcceptable) +{ + int idxRaw = 0; + int cbField = 0; + + AssertPtrReturn(pszRaw, -1); + AssertPtrReturn(pszAddress, -1); + AssertReturn(pszRaw[0] == PF_ADDRESS_FIELD_STARTS, -1); + + if (pszRaw[0] == PF_ADDRESS_FIELD_STARTS) + { + /* shift pszRaw to next symbol */ + pszRaw++; + cbRaw--; + + + /* we shouldn't face with ending here */ + AssertReturn(cbRaw > 0, VERR_INVALID_PARAMETER); + + char *pszEndOfAddress = RTStrStr(pszRaw, PF_STR_ADDRESS_FIELD_ENDS); + + /* no pair closing sign */ + AssertPtrReturn(pszEndOfAddress, VERR_INVALID_PARAMETER); + + cbField = pszEndOfAddress - pszRaw; + + /* field should be less then the rest of the string */ + AssertReturn(cbField < cbRaw, VERR_INVALID_PARAMETER); + + if (cbField != 0) + RTStrCopy(pszAddress, RT_MIN(cbField + 1, cbAddress), pszRaw); + else if (!fEmptyAcceptable) + return -1; + } + + AssertReturn(pszRaw[cbField] == PF_ADDRESS_FIELD_ENDS, -1); + + return cbField + 2; /* length of the field and closing braces */ +} + + +static int netPfStrPortParse(char *pszRaw, int cbRaw, uint16_t *pu16Port) +{ + char *pszEndOfPort = NULL; + uint16_t u16Port = 0; + int idxRaw = 1; /* we increment pszRaw after checks. */ + int cbRest = 0; + size_t cbPort = 0; + + AssertPtrReturn(pszRaw, -1); + AssertPtrReturn(pu16Port, -1); + AssertReturn(pszRaw[0] == PF_FIELD_SEPARATOR, -1); + + pszRaw++; /* skip line separator */ + cbRaw --; + + pszEndOfPort = RTStrStr(pszRaw, ":"); + if (!pszEndOfPort) + { + cbRest = strlen(pszRaw); + + Assert(cbRaw == cbRest); + + /* XXX: Assumption that if string is too big, it will be reported by + * RTStrToUint16. + */ + if (cbRest > 0) + { + pszEndOfPort = pszRaw + cbRest; + cbPort = cbRest; + } + else + return -1; + } + else + cbPort = pszEndOfPort - pszRaw; + + + idxRaw += cbPort; + + Assert(cbRest || pszRaw[idxRaw - 1] == PF_FIELD_SEPARATOR); /* we are 1 char ahead */ + + char szPort[10]; + RT_ZERO(szPort); + + Assert(idxRaw > 0); + RTStrCopy(szPort, RT_MIN(sizeof(szPort), (size_t)(cbPort) + 1), pszRaw); + + if (!(u16Port = RTStrToUInt16(szPort))) + return -1; + + *pu16Port = u16Port; + + return idxRaw; +} + + +static int netPfStrAddressPortPairParse(char *pszRaw, int cbRaw, + char *pszAddress, int cbAddress, + bool fEmptyAddressAcceptable, + uint16_t *pu16Port) +{ + int idxRaw = 0; + int idxRawTotal = 0; + + AssertPtrReturn(pszRaw, -1); + AssertPtrReturn(pszAddress, -1); + AssertPtrReturn(pu16Port, -2); + + /* XXX: Here we should check 0 - ':' and 1 - '[' */ + Assert( pszRaw[0] == PF_FIELD_SEPARATOR + && pszRaw[1] == PF_ADDRESS_FIELD_STARTS); + + pszRaw++; /* field separator skip */ + cbRaw--; + AssertReturn(cbRaw > 0, VERR_INVALID_PARAMETER); + + idxRaw = 0; + + if (pszRaw[0] == PF_ADDRESS_FIELD_STARTS) + { + idxRaw += netPfStrAddressParse(pszRaw, + cbRaw - idxRaw, + pszAddress, + cbAddress, + fEmptyAddressAcceptable); + if (idxRaw == -1) + return -1; + + Assert(pszRaw[idxRaw] == PF_FIELD_SEPARATOR); + } + else return -1; + + pszRaw += idxRaw; + idxRawTotal += idxRaw; + cbRaw -= idxRaw; + + AssertReturn(cbRaw > 0, VERR_INVALID_PARAMETER); + + idxRaw = 0; + + Assert(pszRaw[0] == PF_FIELD_SEPARATOR); + + if (pszRaw[0] == PF_FIELD_SEPARATOR) + { + idxRaw = netPfStrPortParse(pszRaw, strlen(pszRaw), pu16Port); + + Assert(strlen(&pszRaw[idxRaw]) == 0 || pszRaw[idxRaw] == PF_FIELD_SEPARATOR); + + if (idxRaw == -1) + return -2; + + idxRawTotal += idxRaw; + + return idxRawTotal + 1; + } + else return -1; /* trailing garbage in the address */ +} + +/* XXX: Having fIPv6 we might emprove adress verification comparing address length + * with INET[6]_ADDRLEN + */ +int netPfStrToPf(const char *pcszStrPortForward, int fIPv6, PPORTFORWARDRULE pPfr) +{ + char *pszName; + int proto; + char *pszHostAddr; + char *pszGuestAddr; + uint16_t u16HostPort; + uint16_t u16GuestPort; + bool fTcpProto = false; + + char *pszRawBegin = NULL; + char *pszRaw = NULL; + int idxRaw = 0; + int cbToken = 0; + int cbRaw = 0; + int rc = VINF_SUCCESS; + + AssertPtrReturn(pcszStrPortForward, VERR_INVALID_PARAMETER); + AssertPtrReturn(pPfr, VERR_INVALID_PARAMETER); + + memset(pPfr, 0, sizeof(PORTFORWARDRULE)); + + pszHostAddr = &pPfr->szPfrHostAddr[0]; + pszGuestAddr = &pPfr->szPfrGuestAddr[0]; + pszName = &pPfr->szPfrName[0]; + + cbRaw = strlen(pcszStrPortForward); + + /* Minimal rule ":tcp:[]:0:[]:0" has got lenght 14 */ + AssertReturn(cbRaw > 14, VERR_INVALID_PARAMETER); + + pszRaw = RTStrDup(pcszStrPortForward); + + AssertPtrReturn(pszRaw, VERR_NO_MEMORY); + + pszRawBegin = pszRaw; + + /* name */ + if (pszRaw[idxRaw] == PF_FIELD_SEPARATOR) + idxRaw = 1; /* begin of the next segment */ + else + { + char *pszEndOfName = RTStrStr(pszRaw + 1, PF_STR_FIELD_SEPARATOR); + if (!pszEndOfName) + goto invalid_parameter; + + cbToken = (pszEndOfName) - pszRaw; /* don't take : into account */ + /* XXX it's unacceptable to have only name entry in PF */ + AssertReturn(cbToken < cbRaw, VERR_INVALID_PARAMETER); + + if ( cbToken < 0 + || (size_t)cbToken >= PF_NAMELEN) + goto invalid_parameter; + + RTStrCopy(pszName, + RT_MIN((size_t)cbToken + 1, PF_NAMELEN), + pszRaw); + pszRaw += cbToken; /* move to separator */ + } + + AssertReturn(pszRaw[0] == PF_FIELD_SEPARATOR, VERR_INVALID_PARAMETER); + /* protocol */ + + pszRaw++; /* skip separator */ + idxRaw = 0; + + cbRaw--; + + if ( (( fTcpProto = (RTStrNICmp(pszRaw, "tcp", 3) == 0) + || (RTStrNICmp(pszRaw, "udp", 3) == 0)) + && (pszRaw[3] == PF_FIELD_SEPARATOR))) + { + proto = (fTcpProto ? IPPROTO_TCP : IPPROTO_UDP); + idxRaw = 3; + } + else + goto invalid_parameter; + + pszRaw += idxRaw; + cbRaw -= idxRaw; + idxRaw = 0; + + idxRaw = netPfStrAddressPortPairParse(pszRaw, cbRaw, + pszHostAddr, INET6_ADDRSTRLEN, + true, &u16HostPort); + if (idxRaw < 0) + return VERR_INVALID_PARAMETER; + + pszRaw += idxRaw; + cbRaw -= idxRaw; + + Assert(pszRaw[0] == PF_FIELD_SEPARATOR); + + idxRaw = 0; + + idxRaw = netPfStrAddressPortPairParse(pszRaw, cbRaw, + pszGuestAddr, + INET6_ADDRSTRLEN, + false, + &u16GuestPort); + + if (idxRaw < 0) + goto invalid_parameter; + + /* XXX: fill the rule */ + pPfr->fPfrIPv6 = fIPv6; + pPfr->iPfrProto = proto; + + pPfr->u16PfrHostPort = u16HostPort; + + if (*pszGuestAddr == '\0') + goto invalid_parameter; /* guest address should be defined */ + + pPfr->u16PfrGuestPort = u16GuestPort; + + Log(("name: %s\n" + "proto: %d\n" + "host address: %s\n" + "host port: %d\n" + "guest address: %s\n" + "guest port:%d\n", + pszName, proto, + pszHostAddr, u16HostPort, + pszGuestAddr, u16GuestPort)); + + RTStrFree(pszRawBegin); + return VINF_SUCCESS; + +invalid_parameter: + RTStrFree(pszRawBegin); + if (pPfr) + memset(pPfr, 0, sizeof(PORTFORWARDRULE)); + return VERR_INVALID_PARAMETER; +} diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetUDP.cpp b/src/VBox/NetworkServices/NetLib/VBoxNetUDP.cpp index 79c40c27..508e07d8 100644 --- a/src/VBox/NetworkServices/NetLib/VBoxNetUDP.cpp +++ b/src/VBox/NetworkServices/NetLib/VBoxNetUDP.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -61,14 +61,14 @@ void *VBoxNetUDPMatch(PINTNETBUF pBuf, unsigned uDstPort, PCRTMAC pDstMac, uint3 */ PCINTNETHDR pHdr = IntNetRingGetNextFrameToRead(&pBuf->Recv); if ( !pHdr - || ( pHdr->u16Type != INTNETHDR_TYPE_FRAME - && pHdr->u16Type != INTNETHDR_TYPE_GSO)) + || ( pHdr->u8Type != INTNETHDR_TYPE_FRAME + && pHdr->u8Type != INTNETHDR_TYPE_GSO)) return NULL; size_t cbFrame = pHdr->cbFrame; const void *pvFrame = IntNetHdrGetFramePtr(pHdr, pBuf); PCPDMNETWORKGSO pGso = NULL; - if (pHdr->u16Type == INTNETHDR_TYPE_GSO) + if (pHdr->u8Type == INTNETHDR_TYPE_GSO) { pGso = (PCPDMNETWORKGSO)pvFrame; if (!PDMNetGsoIsValid(pGso, cbFrame, cbFrame - sizeof(*pGso))) diff --git a/src/VBox/NetworkServices/NetLib/VBoxPortForwardString.h b/src/VBox/NetworkServices/NetLib/VBoxPortForwardString.h new file mode 100644 index 00000000..30264526 --- /dev/null +++ b/src/VBox/NetworkServices/NetLib/VBoxPortForwardString.h @@ -0,0 +1,56 @@ +/* $Id: VBoxPortForwardString.h $ */ +/** @file + * VBoxPortForwardString + */ + +/* + * Copyright (C) 2009-2010 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. + */ + +#ifndef ___VBoxPortForwardString_h___ +#define ___VBoxPortForwardString_h___ + +#include <iprt/net.h> +#include <VBox/intnet.h> + +RT_C_DECLS_BEGIN + +#define PF_NAMELEN 64 +/* + * TBD: Here is shared implementation of parsing port-forward string + * of format: + * name:[ipv4 or ipv6 address]:host-port:[ipv4 or ipv6 guest addr]:guest port + * + * This code supposed to be used in NetService and Frontend and perhaps in corresponding + * services. + * + * Note: ports are in host format. + */ + +typedef struct PORTFORWARDRULE +{ + char szPfrName[PF_NAMELEN]; + /* true if ipv6 and false otherwise */ + int fPfrIPv6; + /* IPPROTO_{UDP,TCP} */ + int iPfrProto; + char szPfrHostAddr[INET6_ADDRSTRLEN]; + uint16_t u16PfrHostPort; + char szPfrGuestAddr[INET6_ADDRSTRLEN]; + uint16_t u16PfrGuestPort; +} PORTFORWARDRULE, *PPORTFORWARDRULE; + +int netPfStrToPf(const char *pcszStrPortForward,int fIPv6, PPORTFORWARDRULE pPfr); + +RT_C_DECLS_END + +#endif + diff --git a/src/VBox/NetworkServices/NetLib/cpp/utils.h b/src/VBox/NetworkServices/NetLib/cpp/utils.h new file mode 100644 index 00000000..21224b36 --- /dev/null +++ b/src/VBox/NetworkServices/NetLib/cpp/utils.h @@ -0,0 +1,34 @@ +/* $Id$ */ +/** @file + * NetLib/cpp/utils.h + */ + +/* + * Copyright (C) 2013 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. + */ + +#ifndef _NETLIB_CPP_UTILS_H_ +# define _NETLIB_CPP_UTILS_H_ + +/* less operator for IPv4 addresess */ +static bool operator <(const RTNETADDRIPV4& a, const RTNETADDRIPV4& b) +{ + return (RT_N2H_U32(a.u) < RT_N2H_U32(b.u)); +} + +/* Compares MAC addresses */ +static bool operator== (const RTMAC& lhs, const RTMAC& rhs) +{ + return ( lhs.au16[0] == rhs.au16[0] + && lhs.au16[1] == rhs.au16[1] + && lhs.au16[2] == rhs.au16[2]); +} +#endif diff --git a/src/VBox/NetworkServices/NetLib/shared_ptr.h b/src/VBox/NetworkServices/NetLib/shared_ptr.h new file mode 100644 index 00000000..ad892de7 --- /dev/null +++ b/src/VBox/NetworkServices/NetLib/shared_ptr.h @@ -0,0 +1,82 @@ +#ifndef __SHARED_PTR_H__ +#define __SHARED_PTR_H__ + +#ifdef __cplusplus +template<typename T> +class SharedPtr +{ + struct imp + { + imp(T *pTrg = NULL, int cnt = 1): ptr(pTrg),refcnt(cnt){} + ~imp() { if (ptr) delete ptr;} + + T *ptr; + int refcnt; + }; + + + public: + SharedPtr(T *t = NULL):p(NULL) + { + p = new imp(t); + } + + ~SharedPtr() + { + p->refcnt--; + + if (p->refcnt == 0) + delete p; + } + + + SharedPtr(const SharedPtr& rhs) + { + p = rhs.p; + p->refcnt++; + } + + const SharedPtr& operator= (const SharedPtr& rhs) + { + if (p == rhs.p) return *this; + + p->refcnt--; + if (p->refcnt == 0) + delete p; + + p = rhs.p; + p->refcnt++; + + return *this; + } + + + T *get() const + { + return p->ptr; + } + + + T *operator->() + { + return p->ptr; + } + + + const T*operator->() const + { + return p->ptr; + } + + + int use_count() + { + return p->refcnt; + } + + private: + imp *p; +}; +#endif + +#endif diff --git a/src/VBox/NetworkServices/NetLib/utils.h b/src/VBox/NetworkServices/NetLib/utils.h new file mode 100644 index 00000000..d96b5c03 --- /dev/null +++ b/src/VBox/NetworkServices/NetLib/utils.h @@ -0,0 +1,133 @@ +/* $Id: utils.h $ */ +/** @file + * ComHostUtils.cpp + */ + +/* + * Copyright (C) 2013 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 * +*******************************************************************************/ +#ifndef _NETLIB_UTILS_H_ +#define _NETLIB_UTILS_H_ + +#include "cpp/utils.h" + +typedef ComPtr<IVirtualBox> ComVirtualBoxPtr; +typedef ComPtr<IDHCPServer> ComDhcpServerPtr; +typedef ComPtr<IHost> ComHostPtr; +typedef ComPtr<INATNetwork> ComNatPtr; +typedef com::SafeArray<BSTR> ComBstrArray; + +typedef std::vector<RTNETADDRIPV4> AddressList; +typedef std::map<RTNETADDRIPV4, int> AddressToOffsetMapping; + + +inline bool isDhcpRequired(const ComNatPtr& nat) +{ + BOOL fNeedDhcpServer = false; + if (FAILED(nat->COMGETTER(NeedDhcpServer)(&fNeedDhcpServer))) + return false; + + return fNeedDhcpServer; +} + + +inline int findDhcpServer(const ComVirtualBoxPtr& vbox, const std::string& name, ComDhcpServerPtr& dhcp) +{ + HRESULT hrc = vbox->FindDHCPServerByNetworkName(com::Bstr(name.c_str()).raw(), + dhcp.asOutParam()); + AssertComRCReturn(hrc, VERR_NOT_FOUND); + + return VINF_SUCCESS; +} + + +inline int findNatNetwork(const ComVirtualBoxPtr& vbox, const std::string& name, ComNatPtr& nat) +{ + HRESULT hrc = vbox->FindNATNetworkByName(com::Bstr(name.c_str()).raw(), + nat.asOutParam()); + + AssertComRCReturn(hrc, VERR_NOT_FOUND); + + return VINF_SUCCESS; +} + + +inline RTNETADDRIPV4 networkid(const RTNETADDRIPV4& addr, const RTNETADDRIPV4& netmask) +{ + RTNETADDRIPV4 netid; + netid.u = addr.u & netmask.u; + return netid; +} + + +int localMappings(const ComNatPtr&, AddressToOffsetMapping&); +int hostDnsServers(const ComHostPtr&, const RTNETADDRIPV4&,/* const */ AddressToOffsetMapping&, AddressList&); +int hostDnsSearchList(const ComHostPtr&, std::vector<std::string>&); +int hostDnsDomain(const ComHostPtr&, std::string& domainStr); + + +class NATNetworkEventAdapter +{ + public: + virtual HRESULT HandleEvent(VBoxEventType_T aEventType, IEvent *pEvent) = 0; +}; + + +class NATNetworkListener +{ + public: + NATNetworkListener():m_pNAT(NULL){} + + HRESULT init(NATNetworkEventAdapter *pNAT) + { + AssertPtrReturn(pNAT, E_INVALIDARG); + + m_pNAT = pNAT; + return S_OK; + } + + HRESULT init() + { + m_pNAT = NULL; + return S_OK; + } + + void uninit() { m_pNAT = NULL; } + + HRESULT HandleEvent(VBoxEventType_T aEventType, IEvent *pEvent) + { + if (m_pNAT) + return m_pNAT->HandleEvent(aEventType, pEvent); + else + return E_FAIL; + } + + private: + NATNetworkEventAdapter *m_pNAT; +}; +typedef ListenerImpl<NATNetworkListener, NATNetworkEventAdapter*> NATNetworkListenerImpl; + +# if VBOX_WITH_XPCOM +class NS_CLASSINFO_NAME(NATNetworkListenerImpl); +# endif + +typedef ComPtr<NATNetworkListenerImpl> ComNatListenerPtr; +typedef com::SafeArray<VBoxEventType_T> ComEventTypeArray; + +/* XXX: const is commented out because of compilation erro on Windows host, but it's intended that this function + isn't modify event type array */ +int createNatListener(ComNatListenerPtr& listener, const ComVirtualBoxPtr& vboxptr, + NATNetworkEventAdapter *adapter, /* const */ ComEventTypeArray& events); +#endif |