1
0

Merge pull request #1761 from mc-server/NetworkIPEnum

cNetwork: Added EnumLocalIPAddresses() function.
This commit is contained in:
Mattes D 2015-03-12 13:35:45 +01:00
commit f9991c9f92
7 changed files with 239 additions and 5 deletions

View File

@ -289,6 +289,7 @@ g_Server = nil
{
Connect = { Params = "Host, Port, LinkCallbacks", Return = "bool", Notes = "(STATIC) Begins establishing a (client) TCP connection to the specified host. Uses the LinkCallbacks table to report progress, success, errors and incoming data. Returns false if it fails immediately (bad port value, bad hostname format), true otherwise. Host can be either an IP address or a hostname." },
CreateUDPEndpoint = { Params = "Port, UDPCallbacks", Return = "{{cUDPEndpoint|UDPEndpoint}}", Notes = "(STATIC) Creates a UDP endpoint that listens for incoming datagrams on the specified port, and can be used to send or broadcast datagrams. Uses the UDPCallbacks to report incoming datagrams or errors. If the endpoint cannot be created, the OnError callback is called with the error details and the returned endpoint will report IsOpen() == false. The plugin needs to store the returned endpoint object for as long as it needs the UDP port open; if the endpoint is garbage-collected by Lua, the socket will be closed and no more incoming data will be reported.<br>If the Port is zero, the OS chooses an available UDP port for the endpoint; use {{cUDPEndpoint}}:GetPort() to query the port number in such case." },
EnumLocalIPAddresses = { Params = "", Return = "array-table of strings", Notes = "(STATIC) Returns all local IP addresses for network interfaces currently available on the machine." },
HostnameToIP = { Params = "Host, LookupCallbacks", Return = "bool", Notes = "(STATIC) Begins a DNS lookup to find the IP address(es) for the specified host. Uses the LookupCallbacks table to report progress, success or errors. Returns false if it fails immediately (bad hostname format), true if the lookup started successfully. Host can be either a hostname or an IP address." },
IPToHostname = { Params = "Address, LookupCallbacks", Return = "bool", Notes = "(STATIC) Begins a reverse-DNS lookup to find out the hostname for the specified IP address. Uses the LookupCallbacks table to report progress, success or errors. Returns false if it fails immediately (bad address format), true if the lookup started successfully." },
Listen = { Params = "Port, ListenCallbacks", Return = "{{cServerHandle|ServerHandle}}", Notes = "(STATIC) Starts listening on the specified port. Uses the ListenCallbacks to report incoming connections or errors. Returns a {{cServerHandle}} object representing the server. If the listen operation failed, the OnError callback is called with the error details and the returned server handle will report IsListening() == false. The plugin needs to store the server handle object for as long as it needs the server running, if the server handle is garbage-collected by Lua, the listening socket will be closed and all current connections dropped." },

View File

@ -50,6 +50,12 @@ g_PluginInfo =
}, -- ParameterCombinations
}, -- close
ips =
{
HelpString = "Prints all locally available IP addresses",
Handler = HandleConsoleNetIps,
}, -- ips
listen =
{
HelpString = "Creates a new listening socket on the specified port with the specified service attached to it",

View File

@ -288,6 +288,19 @@ end
function HandleConsoleNetIps(a_Split)
local Addresses = cNetwork:EnumLocalIPAddresses()
LOG("IP addresses enumerated, " .. #Addresses .. " found")
for idx, addr in ipairs(Addresses) do
LOG(" IP #" .. idx .. ": " .. addr)
end
return true
end
function HandleConsoleNetLookup(a_Split)
-- Get the name to look up:
local Addr = a_Split[3] or "google.com"

View File

@ -129,6 +129,30 @@ static int tolua_cNetwork_CreateUDPEndpoint(lua_State * L)
/** Binds cNetwork::EnumLocalIPAddresses */
static int tolua_cNetwork_EnumLocalIPAddresses(lua_State * L)
{
// Function signature:
// cNetwork:EnumLocalIPAddresses() -> {string, ...}
cLuaState S(L);
if (
!S.CheckParamUserTable(1, "cNetwork") ||
!S.CheckParamEnd(2)
)
{
return 0;
}
// Push the enumerated addresses:
S.Push(cNetwork::EnumLocalIPAddresses());
return 1;
}
/** Binds cNetwork::HostnameToIP */
static int tolua_cNetwork_HostnameToIP(lua_State * L)
{
@ -905,6 +929,7 @@ void ManualBindings::BindNetwork(lua_State * tolua_S)
tolua_beginmodule(tolua_S, "cNetwork");
tolua_function(tolua_S, "Connect", tolua_cNetwork_Connect);
tolua_function(tolua_S, "CreateUDPEndpoint", tolua_cNetwork_CreateUDPEndpoint);
tolua_function(tolua_S, "EnumLocalIPAddresses", tolua_cNetwork_EnumLocalIPAddresses);
tolua_function(tolua_S, "HostnameToIP", tolua_cNetwork_HostnameToIP);
tolua_function(tolua_S, "IPToHostname", tolua_cNetwork_IPToHostname);
tolua_function(tolua_S, "Listen", tolua_cNetwork_Listen);

View File

@ -13,6 +13,7 @@ SET (SRCS
HostnameLookup.cpp
IPLookup.cpp
IsThread.cpp
NetworkInterfaceEnum.cpp
NetworkSingleton.cpp
Semaphore.cpp
ServerHandleImpl.cpp

View File

@ -318,6 +318,9 @@ public:
If a_Port is 0, the OS is free to assign any port number it likes to the endpoint.
Returns the endpoint object that can be interacted with. */
static cUDPEndpointPtr CreateUDPEndpoint(UInt16 a_Port, cUDPEndpoint::cCallbacks & a_Callbacks);
/** Returns all local IP addresses for network interfaces currently available. */
static AStringVector EnumLocalIPAddresses(void);
};

View File

@ -0,0 +1,185 @@
// NetworkInterfaceEnum.cpp
// Implements the cNetwork::EnumLocalIPAddresses() interface enumeration function
#include "Globals.h"
#include "Network.h"
#include "event2/util.h"
#ifdef _WIN32
#include <IPHlpApi.h>
#pragma comment(lib, "IPHLPAPI.lib")
#else // _WIN32
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif // else _WIN32
#ifdef SELF_TEST
static class cEnumIPAddressTest
{
public:
cEnumIPAddressTest(void)
{
printf("Enumerating all IP addresses...\n");
auto IPs = cNetwork::EnumLocalIPAddresses();
for (auto & ip: IPs)
{
printf(" %s\n", ip.c_str());
}
printf("Done.\n");
}
} g_EnumIPAddressTest;
#endif // SELF_TEST
#ifdef _WIN32
/** Converts the SOCKET_ADDRESS structure received from the OS into an IP address string. */
static AString PrintAddress(SOCKET_ADDRESS & a_Addr)
{
char IP[128];
switch (a_Addr.lpSockaddr->sa_family)
{
case AF_INET:
{
auto sin = reinterpret_cast<const sockaddr_in *>(a_Addr.lpSockaddr);
evutil_inet_ntop(a_Addr.lpSockaddr->sa_family, &(sin->sin_addr), IP, sizeof(IP));
break;
}
case AF_INET6:
{
auto sin = reinterpret_cast<const sockaddr_in6 *>(a_Addr.lpSockaddr);
evutil_inet_ntop(a_Addr.lpSockaddr->sa_family, &(sin->sin6_addr), IP, sizeof(IP));
break;
}
default:
{
IP[0] = 0;
break;
}
}
return IP;
}
#else // _WIN32
static AString PrintAddress(ifaddrs * InterfaceAddress)
{
switch (InterfaceAddress->ifa_addr->sa_family)
{
case AF_INET:
{ // IPv4
char AddressBuffer[INET_ADDRSTRLEN];
sockaddr_in InternetSocket;
std::memcpy(&InternetSocket, InterfaceAddress->ifa_addr, sizeof(InternetSocket));
inet_ntop(AF_INET, &InternetSocket.sin_addr, AddressBuffer, INET_ADDRSTRLEN);
return AddressBuffer;
}
case AF_INET6:
{ // IPv6
char AddressBuffer[INET6_ADDRSTRLEN];
sockaddr_in6 InternetSocket;
std::memcpy(&InternetSocket, InterfaceAddress->ifa_addr, sizeof(InternetSocket));
inet_ntop(AF_INET6, &InternetSocket.sin6_addr, AddressBuffer, INET6_ADDRSTRLEN);
return AddressBuffer;
}
default:
{
LOG("Unknown address family: %i", InterfaceAddress->ifa_addr->sa_family);
return "";
}
}
}
#endif // else _WIN32
AStringVector cNetwork::EnumLocalIPAddresses(void)
{
AStringVector res;
#ifdef _WIN32
// Query the OS for all adapters' addresses:
char buffer[64 KiB]; // A buffer backing the address list
PIP_ADAPTER_ADDRESSES pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer);
ULONG outBufLen = sizeof(buffer);
DWORD dwRetVal = GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, nullptr,
pAddresses, &outBufLen
);
if (dwRetVal != ERROR_SUCCESS)
{
LOG("GetAdaptersAddresses() failed: %u", dwRetVal);
return res;
}
// Enumerate all active adapters
for (auto pCurrAddresses = pAddresses; pCurrAddresses != nullptr; pCurrAddresses = pCurrAddresses->Next)
{
if (pCurrAddresses->OperStatus != IfOperStatusUp)
{
// Adapter not active, skip it:
continue;
}
// Collect all IP addresses on this adapter:
for (auto pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast != nullptr; pUnicast = pUnicast->Next)
{
auto Address = PrintAddress(pUnicast->Address);
if (!Address.empty())
{
res.push_back(Address);
}
} // for pUnicast
} // for pCurrAddresses
#else // _WIN32
struct ifaddrs * ifAddrStruct = nullptr;
getifaddrs(&ifAddrStruct);
for (auto ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == nullptr)
{
continue;
}
auto Address = PrintAddress(ifa);
if (!Address.empty())
{
res.emplace_back(Address);
}
}
if (ifAddrStruct != nullptr)
{
freeifaddrs(ifAddrStruct);
}
#endif // else _WIN32
return res;
}