From c758482ece08e7b393e343464bf9a2c2d74bf34f Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sun, 22 Feb 2015 10:51:16 +0100 Subject: cNetwork: Added EnumLocalIPAddresses() function. --- MCServer/Plugins/APIDump/Classes/Network.lua | 1 + MCServer/Plugins/NetworkTest/Info.lua | 6 ++ MCServer/Plugins/NetworkTest/NetworkTest.lua | 13 +++ src/Bindings/ManualBindings_Network.cpp | 35 ++++++-- src/OSSupport/CMakeLists.txt | 1 + src/OSSupport/Network.h | 3 + src/OSSupport/NetworkInterfaceEnum.cpp | 129 +++++++++++++++++++++++++++ 7 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 src/OSSupport/NetworkInterfaceEnum.cpp diff --git a/MCServer/Plugins/APIDump/Classes/Network.lua b/MCServer/Plugins/APIDump/Classes/Network.lua index 797788661..c7626562d 100644 --- a/MCServer/Plugins/APIDump/Classes/Network.lua +++ b/MCServer/Plugins/APIDump/Classes/Network.lua @@ -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.
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." }, diff --git a/MCServer/Plugins/NetworkTest/Info.lua b/MCServer/Plugins/NetworkTest/Info.lua index 52422d427..d8c3095fe 100644 --- a/MCServer/Plugins/NetworkTest/Info.lua +++ b/MCServer/Plugins/NetworkTest/Info.lua @@ -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", diff --git a/MCServer/Plugins/NetworkTest/NetworkTest.lua b/MCServer/Plugins/NetworkTest/NetworkTest.lua index daab0a4bf..22056d4e9 100644 --- a/MCServer/Plugins/NetworkTest/NetworkTest.lua +++ b/MCServer/Plugins/NetworkTest/NetworkTest.lua @@ -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" diff --git a/src/Bindings/ManualBindings_Network.cpp b/src/Bindings/ManualBindings_Network.cpp index a628eb9ca..628cda7f0 100644 --- a/src/Bindings/ManualBindings_Network.cpp +++ b/src/Bindings/ManualBindings_Network.cpp @@ -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) { @@ -903,11 +927,12 @@ void ManualBindings::BindNetwork(lua_State * tolua_S) // Fill in the functions (alpha-sorted): 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, "HostnameToIP", tolua_cNetwork_HostnameToIP); - tolua_function(tolua_S, "IPToHostname", tolua_cNetwork_IPToHostname); - tolua_function(tolua_S, "Listen", tolua_cNetwork_Listen); + 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); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cServerHandle"); diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt index 81b37ef0e..0d3c9a63e 100644 --- a/src/OSSupport/CMakeLists.txt +++ b/src/OSSupport/CMakeLists.txt @@ -13,6 +13,7 @@ SET (SRCS HostnameLookup.cpp IPLookup.cpp IsThread.cpp + NetworkInterfaceEnum.cpp NetworkSingleton.cpp Semaphore.cpp ServerHandleImpl.cpp diff --git a/src/OSSupport/Network.h b/src/OSSupport/Network.h index 5dd596223..95a935bbe 100644 --- a/src/OSSupport/Network.h +++ b/src/OSSupport/Network.h @@ -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); }; diff --git a/src/OSSupport/NetworkInterfaceEnum.cpp b/src/OSSupport/NetworkInterfaceEnum.cpp new file mode 100644 index 000000000..675769065 --- /dev/null +++ b/src/OSSupport/NetworkInterfaceEnum.cpp @@ -0,0 +1,129 @@ + +// NetworkInterfaceEnum.cpp + +// Implements the cNetwork::EnumLocalIPAddresses() interface enumeration function + +#include "Globals.h" +#include "Network.h" +#include "event2/util.h" +#ifdef _WIN32 + #include + #pragma comment(lib, "IPHLPAPI.lib") +#else // _WIN32 +#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(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(a_Addr.lpSockaddr); + evutil_inet_ntop(a_Addr.lpSockaddr->sa_family, &(sin->sin6_addr), IP, sizeof(IP)); + break; + } + default: + { + IP[0] = 0; + break; + } + } + return AString(IP); +} + +#endif // _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(&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 != 1) + { + // 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 + + // TODO: Enumerate network interfaces on Linux + + #endif // else _WIN32 + + return res; +} + + + + -- cgit v1.2.3