-
-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor getBestPublicIp for all valid ips #1132
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
#include <vector> | ||
#include <map> | ||
#include <cstdint> | ||
#include "common.h" | ||
|
||
namespace kiwix | ||
{ | ||
|
@@ -216,14 +217,23 @@ std::map<std::string, std::string> getNetworkInterfaces(); | |
/** Provides the best IP address | ||
* This function provides the best IP address from the list given by getNetworkInterfacesIPv4Or6() | ||
*/ | ||
std::string getBestPublicIp(bool ipv6); | ||
IpAddress getBestPublicIps(IpMode mode); | ||
|
||
/** Provides the best IPv4 adddress | ||
* Equivalent to getBestPublicIp(false). Provided for backward compatibility | ||
* with libkiwix v13.1.0. | ||
*/ | ||
std::string getBestPublicIp(); | ||
|
||
/** Checks if IP address is available | ||
* | ||
* Check if the given IP address is configured on any network interface of the system | ||
* | ||
* @param addr the IP address to check. | ||
* @return true if the IP address is available on the system. | ||
*/ | ||
bool ipAvailable(const IpAddress& addr); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think it can be a useful function to have available
Current use case was to check only one ip (in the case of the user giving one). I will refactor it to take as a parameter the mode as well and check accordingly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When dealing with public API that's not a good argument. Public API is a commitment. Exposing something just because it's useful may lead to unjustified maintenance overhead (like having to deal with backward compatibility issues). Let's not bloat our public API without necessity. |
||
|
||
/** Converts file size to human readable format. | ||
* | ||
* This function will convert a number to its equivalent size using units. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -407,7 +407,7 @@ | |
|
||
InternalServer::InternalServer(LibraryPtr library, | ||
std::shared_ptr<NameMapper> nameMapper, | ||
std::string addr, | ||
IpAddress addr, | ||
int port, | ||
std::string root, | ||
int nbThreads, | ||
|
@@ -461,19 +461,22 @@ | |
sockAddr6.sin6_family = AF_INET6; | ||
sockAddr6.sin6_port = htons(m_port); | ||
|
||
if (m_addr.empty()) { | ||
if (0 != INADDR_ANY) { | ||
sockAddr6.sin6_addr = in6addr_any; | ||
sockAddr4.sin_addr.s_addr = htonl(INADDR_ANY); | ||
} | ||
m_addr = kiwix::getBestPublicIp(m_ipMode == IpMode::ipv6 || m_ipMode == IpMode::all); | ||
if (m_addr.addr.empty() && m_addr.addr6.empty()) { // No specific ip address provided | ||
sockAddr6.sin6_addr = in6addr_any; | ||
sockAddr4.sin_addr.s_addr = htonl(INADDR_ANY); | ||
m_addr = kiwix::getBestPublicIps(m_ipMode); | ||
} else { | ||
bool ipv6 = inet_pton(AF_INET6, m_addr.c_str(), &(sockAddr6.sin6_addr.s6_addr)) == 1; | ||
bool ipv4 = inet_pton(AF_INET, m_addr.c_str(), &(sockAddr4.sin_addr.s_addr)) == 1; | ||
if (ipv6){ | ||
m_ipMode = IpMode::all; | ||
} else if (!ipv4) { | ||
std::cerr << "Ip address " << m_addr << " is not a valid ip address" << std::endl; | ||
bool ipv6 = inet_pton(AF_INET6, m_addr.addr6.c_str(), &(sockAddr6.sin6_addr.s6_addr)) == 1; | ||
bool ipv4 = inet_pton(AF_INET, m_addr.addr.c_str(), &(sockAddr4.sin_addr.s_addr)) == 1; | ||
|
||
if (!ipv4 && !ipv6) { | ||
const std::string& addr = m_addr.addr.empty() ? m_addr.addr6 : m_addr.addr; | ||
std::cerr << "IP address " << addr << " is not valid" << std::endl; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please restore the previous text of the error message |
||
return false; | ||
} | ||
|
||
if (!ipAvailable(m_addr)) { | ||
std::cerr << "IP address " << (m_addr.addr.empty() ? m_addr.addr6 : m_addr.addr) << " is not available on this system" << std::endl; | ||
return false; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -211,40 +211,51 @@ | |
return result; | ||
} | ||
|
||
|
||
std::string getBestPublicIp(bool ipv6) { | ||
IpAddress bestPublicIp = IpAddress{"127.0.0.1","::1"}; | ||
IpAddress getBestPublicIps(IpMode mode) { | ||
IpAddress bestPublicIps = IpAddress{"127.0.0.1", "::1"}; | ||
std::map<std::string, IpAddress> interfaces = getNetworkInterfacesIPv4Or6(); | ||
|
||
bool validMode4 = (mode == IpMode::ipv4 || mode == IpMode::all); // Mode is valid to support ipv4 | ||
bool validMode6 = (mode == IpMode::ipv6 || mode == IpMode::all); // Mode is valid to support ipv6 | ||
Comment on lines
+217
to
+218
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that these can be moved to the bottom of the function. The function will consist of two parts
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am debating whether we should do a mode check inside this function at all. The name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree. In fact, when writing my previous comment I considered proposing to package the first part (covered by the first bullet) into a separate function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Indeed, you did. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this has been all over the place, but let me correct it to close this up. |
||
#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() && !(ipv6 && (*it).second.addr6.empty())) { | ||
bestPublicIp = (*it).second; | ||
break; | ||
} | ||
const char* const prioritizedNames[] = { "eth0", "eth1", "wlan0", "wlan1", "en0", "en1" }; | ||
for(const auto& name: prioritizedNames) { | ||
const auto it = interfaces.find(name); | ||
if(it == interfaces.end()) continue; | ||
const IpAddress& interfaceIps = it->second; | ||
if(!bestPublicIps.addr.empty() && validMode4 && !interfaceIps.addr.empty()) | ||
bestPublicIps.addr = interfaceIps.addr; | ||
sgourdas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if(!bestPublicIps.addr6.empty() && validMode6 && !interfaceIps.addr6.empty()) | ||
bestPublicIps.addr6 = interfaceIps.addr6; | ||
} | ||
#endif | ||
|
||
const char* const prefixes[] = { "192.168", "172.16.", "10.0" }; | ||
for(auto prefix : prefixes){ | ||
for(auto& itr : interfaces) { | ||
std::string interfaceIp(itr.second.addr); | ||
if (interfaceIp.find(prefix) == 0 && !(ipv6 && itr.second.addr6.empty())) { | ||
bestPublicIp = itr.second; | ||
break; | ||
} | ||
for (const auto& prefix : prefixes) { | ||
for (const auto& [_, interfaceIps] : interfaces) { | ||
if (!bestPublicIps.addr.empty() && validMode4 && !interfaceIps.addr.empty() && interfaceIps.addr.find(prefix) == 0) | ||
bestPublicIps.addr = interfaceIps.addr; | ||
if (!bestPublicIps.addr6.empty() && validMode6 && !interfaceIps.addr6.empty()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the reason it is omitted is because we only provide v4 prefixes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be beneficial to provide some for v6? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The purpose of this piece of code is to select an IP address from a local network, though I am not sure why the
According to https://en.wikipedia.org/wiki/Link-local_address#IPv6
however, unfortunately, it seems like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok so if I understand correctly, for this point, I should just add |
||
bestPublicIps.addr6 = interfaceIps.addr6; | ||
} | ||
} | ||
return ipv6 ? bestPublicIp.addr6 : bestPublicIp.addr; | ||
} | ||
|
||
return bestPublicIps; | ||
} | ||
|
||
std::string getBestPublicIp() | ||
{ | ||
return getBestPublicIp(false); | ||
return getBestPublicIps(IpMode::ipv4).addr; | ||
} | ||
|
||
bool ipAvailable(const IpAddress& addr) | ||
{ | ||
auto interfaces = kiwix::getNetworkInterfacesIPv4Or6(); | ||
for (const auto& interface : interfaces) { | ||
IpAddress interfaceIps = interface.second; | ||
if (!interfaceIps.addr.empty() && interfaceIps.addr == addr.addr) return true; | ||
if (!interfaceIps.addr6.empty() && interfaceIps.addr6 == addr.addr6) return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
} // namespace kiwix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me
flex
is not an intuitive term for the intended mode of operation.In the coding style that I got used to,
enum
members names must be in UPPERCASE. In this case that would have helped to avoid the problem withauto
being a keyword in C++. Please rename existing members ofIpMode
in a separate commit, then add a new memberIpMode::AUTO
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the feeling I have missed something... what is his "glex" option!? Where does it come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kelson42 It started from here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume we are ok to proceed right?