diff --git a/include/server.h b/include/server.h index b1c3a4232..8572003a9 100644 --- a/include/server.h +++ b/include/server.h @@ -60,7 +60,9 @@ namespace kiwix { m_withTaskbar = withTaskbar; m_withLibraryButton = withLibraryButton; } void setBlockExternalLinks(bool blockExternalLinks) { m_blockExternalLinks = blockExternalLinks; } - + int getPort(); + std::string getAddress(); + protected: Library* mp_library; NameMapper* mp_nameMapper; diff --git a/include/tools.h b/include/tools.h index 967e22ed3..45f06ca77 100644 --- a/include/tools.h +++ b/include/tools.h @@ -22,6 +22,7 @@ #include #include +#include namespace kiwix { @@ -194,5 +195,17 @@ bool fileExists(const std::string& path); * @return mimetype from filename in string format. */ std::string getMimeTypeForFile(const std::string& filename); + +/** Provides all available network interfaces + * + * This function provides the available IPv4 network interfaces + */ +std::map getNetworkInterfaces(); + +/** Provides the best IP address + * This function provides the best IP address from the list given by getNetworkInterfaces + */ +std::string getBestPublicIp(); + } #endif // KIWIX_TOOLS_H diff --git a/src/meson.build b/src/meson.build index b3238ae18..43f863e07 100644 --- a/src/meson.build +++ b/src/meson.build @@ -26,7 +26,6 @@ kiwix_sources = [ 'server/etag.cpp', 'server/request_context.cpp', 'server/response.cpp', - 'server/networkTools.cpp', 'server/internalServer.cpp', 'server/internalServer_catalog_v2.cpp', 'opds_catalog.cpp' diff --git a/src/server.cpp b/src/server.cpp index 255f88883..e630515ce 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -71,4 +71,14 @@ void Server::setRoot(const std::string& root) } } +int Server::getPort() +{ + return mp_server->getPort(); +} + +std::string Server::getAddress() +{ + return mp_server->getAddress(); +} + } diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index c66856ee1..14d03e1ef 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -48,6 +48,7 @@ extern "C" { #include "tools/regexTools.h" #include "tools/stringTools.h" #include "tools/archiveTools.h" +#include "tools/networkTools.h" #include "library.h" #include "name_mapper.h" #include "entry.h" @@ -159,8 +160,9 @@ bool InternalServer::start() { sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons(m_port); if (m_addr.empty()) { - if (0 != INADDR_ANY) + if (0 != INADDR_ANY) { sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); + } m_addr = kiwix::getBestPublicIp(); } else { if (inet_pton(AF_INET, m_addr.c_str(), &(sockAddr.sin_addr.s_addr)) == 0) { @@ -168,11 +170,6 @@ bool InternalServer::start() { return false; } } - - std::string url = "http://" + m_addr + ":" + std::to_string(m_port) + "/"; - std::cout << "The Kiwix server is running and can be accessed in the local network at : " - << url << std::endl; - mp_daemon = MHD_start_daemon(flags, m_port, NULL, diff --git a/src/server/internalServer.h b/src/server/internalServer.h index 38bd94b12..3a7d98c26 100644 --- a/src/server/internalServer.h +++ b/src/server/internalServer.h @@ -35,7 +35,6 @@ extern "C" { #include "server/request_context.h" #include "server/response.h" -#include "networkTools.h" namespace kiwix { @@ -68,6 +67,8 @@ class InternalServer { void** cont_cls); bool start(); void stop(); + std::string getAddress() { return m_addr; } + int getPort() { return m_port; } private: // functions std::unique_ptr handle_request(const RequestContext& request); diff --git a/src/server/networkTools.cpp b/src/server/networkTools.cpp deleted file mode 100644 index ab2c4af3b..000000000 --- a/src/server/networkTools.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2012 Emmanuel Engelhart - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include "networkTools.h" - -std::map kiwix::getNetworkInterfaces() { - std::map interfaces; - -#ifdef _WIN32 - SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); - if (sd == SOCKET_ERROR) { - std::cerr << "Failed to get a socket. Error " << WSAGetLastError() << - std::endl; - return interfaces; - } - - INTERFACE_INFO InterfaceList[20]; - unsigned long nBytesReturned; - if (WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, - sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR) { - std::cerr << "Failed calling WSAIoctl: error " << WSAGetLastError() << - std::endl; - return interfaces; - } - - int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO); - for (int i = 0; i < nNumInterfaces; ++i) { - sockaddr_in *pAddress; - pAddress = (sockaddr_in *) & (InterfaceList[i].iiAddress); - - /* Add to the map */ - std::string interfaceName = std::string(inet_ntoa(pAddress->sin_addr)); - std::string interfaceIp = std::string(inet_ntoa(pAddress->sin_addr)); - interfaces.insert(std::pair(interfaceName, interfaceIp)); - } -#else - /* Get Network interfaces information */ - char buf[16384]; - struct ifconf ifconf; - int fd = socket(PF_INET, SOCK_DGRAM, 0); /* Only IPV4 */ - ifconf.ifc_len=sizeof buf; - ifconf.ifc_buf=buf; - if(ioctl(fd, SIOCGIFCONF, &ifconf)!=0) { - perror("ioctl(SIOCGIFCONF)"); - exit(EXIT_FAILURE); - } - - /* Go through each interface */ - int i; - size_t len; - struct ifreq *ifreq; - ifreq = ifconf.ifc_req; - for (i = 0; i < ifconf.ifc_len; ) { - if (ifreq->ifr_addr.sa_family == AF_INET) { - /* Get the network interface ip */ - char host[128] = { 0 }; - const int error = getnameinfo(&(ifreq->ifr_addr), sizeof ifreq->ifr_addr, - host, sizeof host, - 0, 0, NI_NUMERICHOST); - if (!error) { - std::string interfaceName = std::string(ifreq->ifr_name); - std::string interfaceIp = std::string(host); - /* Add to the map */ - interfaces.insert(std::pair(interfaceName, interfaceIp)); - } else { - perror("getnameinfo()"); - } - } - - /* some systems have ifr_addr.sa_len and adjust the length that - * way, but not mine. weird */ -#ifndef __linux__ - len=IFNAMSIZ + ifreq->ifr_addr.sa_len; -#else - len=sizeof *ifreq; -#endif - ifreq=(struct ifreq*)((char*)ifreq+len); - i+=len; - } -#endif - return interfaces; -} - -std::string kiwix::getBestPublicIp() { - std::map interfaces = kiwix::getNetworkInterfaces(); - -#ifndef _WIN32 - const char* const prioritizedNames[] = - { "eth0", "eth1", "wlan0", "wlan1", "en0", "en1" }; - const int count = (sizeof prioritizedNames) / (sizeof prioritizedNames[0]); - for (int i = 0; i < count; ++i) { - std::map::const_iterator it = - interfaces.find(prioritizedNames[i]); - if (it != interfaces.end()) - return it->second; - } -#endif - - for (std::map::iterator iter = interfaces.begin(); - iter != interfaces.end(); ++iter) { - std::string interfaceIp = iter->second; - if (interfaceIp.length() >= 7 && interfaceIp.substr(0, 7) == "192.168") - return interfaceIp; - } - - for (std::map::iterator iter = interfaces.begin(); - iter != interfaces.end(); ++iter) { - std::string interfaceIp = iter->second; - if (interfaceIp.length() >= 7 && interfaceIp.substr(0, 7) == "172.16.") - return interfaceIp; - } - - for (std::map::iterator iter = interfaces.begin(); - iter != interfaces.end(); ++iter) { - std::string interfaceIp = iter->second; - if (interfaceIp.length() >= 3 && interfaceIp.substr(0, 3) == "10.") - return interfaceIp; - } - - return "127.0.0.1"; -} diff --git a/src/server/networkTools.h b/src/server/networkTools.h deleted file mode 100644 index 8bf700078..000000000 --- a/src/server/networkTools.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2012 Emmanuel Engelhart - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#ifndef KIWIX_NETWORKTOOLS_H -#define KIWIX_NETWORKTOOLS_H - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#include -#include -#include -#include - -namespace kiwix { - std::map getNetworkInterfaces(); - std::string getBestPublicIp(); -} - -#endif diff --git a/src/tools/networkTools.cpp b/src/tools/networkTools.cpp index 746fbfcae..42de314fb 100644 --- a/src/tools/networkTools.cpp +++ b/src/tools/networkTools.cpp @@ -1,5 +1,6 @@ /* * Copyright 2012 Emmanuel Engelhart + * Copyright 2021 Nikhil Tanwar <2002nikhiltanwar@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +18,7 @@ * MA 02110-1301, USA. */ +#include "tools.h" #include #include @@ -29,6 +31,17 @@ #include #include +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif size_t write_callback_to_iss(char* ptr, size_t size, size_t nmemb, void* userdata) { @@ -57,3 +70,104 @@ std::string kiwix::download(const std::string& url) { } return ss.str(); } + +std::map kiwix::getNetworkInterfaces() { + std::map interfaces; + +#ifdef _WIN32 + SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); + if (sd == SOCKET_ERROR) { + std::cerr << "Failed to get a socket. Error " << WSAGetLastError() << std::endl; + return interfaces; + } + + INTERFACE_INFO InterfaceList[20]; + unsigned long nBytesReturned; + if (WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, + sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR) { + std::cerr << "Failed calling WSAIoctl: error " << WSAGetLastError() << std::endl; + return interfaces; + } + + int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO); + for (int i = 0; i < nNumInterfaces; ++i) { + sockaddr_in *pAddress; + pAddress = (sockaddr_in *) & (InterfaceList[i].iiAddress.AddressIn); + if(pAddress->sin_family == AF_INET) { + /* Add to the map */ + std::string interfaceName = std::string(inet_ntoa(pAddress->sin_addr)); + interfaces[interfaceName] = interfaceName; + } + } +#else + /* Get Network interfaces information */ + char buf[16384]; + struct ifconf ifconf; + int fd = socket(PF_INET, SOCK_DGRAM, 0); /* Only IPV4 */ + ifconf.ifc_len = sizeof(buf); + ifconf.ifc_buf=buf; + if(ioctl(fd, SIOCGIFCONF, &ifconf)!=0) { + perror("ioctl(SIOCGIFCONF)"); + } + + /* Go through each interface */ + struct ifreq *ifreq; + ifreq = ifconf.ifc_req; + for (int i = 0; i < ifconf.ifc_len; ) { + if (ifreq->ifr_addr.sa_family == AF_INET) { + /* Get the network interface ip */ + char host[128] = { 0 }; + const int error = getnameinfo(&(ifreq->ifr_addr), sizeof(ifreq->ifr_addr), + host, sizeof(host), + 0, 0, NI_NUMERICHOST); + if (!error) { + std::string interfaceName = std::string(ifreq->ifr_name); + std::string interfaceIp = std::string(host); + /* Add to the map */ + interfaces[interfaceName] = interfaceIp; + } else { + perror("getnameinfo()"); + } + } + + /* some systems have ifr_addr.sa_len and adjust the length that + * way, but not mine. weird */ + size_t len; +#ifndef __linux__ + len = IFNAMSIZ + ifreq->ifr_addr.sa_len; +#else + len = sizeof(*ifreq); +#endif + ifreq = (struct ifreq*)((char*)ifreq+len); + i += len; + } +#endif + return interfaces; +} + +std::string kiwix::getBestPublicIp() { + auto interfaces = getNetworkInterfaces(); + +#ifndef _WIN32 + const char* const prioritizedNames[] = + { "eth0", "eth1", "wlan0", "wlan1", "en0", "en1" }; + for(auto name: prioritizedNames) { + auto it = interfaces.find(name); + if(it != interfaces.end()) { + return it->second; + } + } +#endif + + const char* const prefixes[] = { "192.168", "172.16.", "10.0" }; + for(auto prefix : prefixes){ + for(auto& itr : interfaces) { + auto interfaceIp = itr.second; + if (interfaceIp.find(prefix) == 0) { + return interfaceIp; + } + } + } + + return "127.0.0.1"; +}