fix ipv6 handling between GUI and barriers/barrierc; zero-fill sockaddr_in(6) structs prior to initializing; update --help output
This commit is contained in:
parent
f4301a7618
commit
9ab77545ee
|
@ -581,7 +581,7 @@ bool MainWindow::clientArgs(QStringList& args, QString& app)
|
|||
if (m_pCheckBoxAutoConfig->isChecked()) {
|
||||
if (m_pComboServerList->count() != 0) {
|
||||
QString serverIp = m_pComboServerList->currentText();
|
||||
args << serverIp + ":" + QString::number(appConfig().port());
|
||||
args << "[" + serverIp + "]:" + QString::number(appConfig().port());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -595,7 +595,7 @@ bool MainWindow::clientArgs(QStringList& args, QString& app)
|
|||
return false;
|
||||
}
|
||||
|
||||
args << m_pLineEditHostname->text() + ":" + QString::number(appConfig().port());
|
||||
args << "[" + m_pLineEditHostname->text() + "]:" + QString::number(appConfig().port());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -637,8 +637,10 @@ QString MainWindow::configFilename()
|
|||
|
||||
QString MainWindow::address()
|
||||
{
|
||||
QString i = appConfig().networkInterface();
|
||||
return (!i.isEmpty() ? i : "") + ":" + QString::number(appConfig().port());
|
||||
QString address = appConfig().networkInterface();
|
||||
if (!address.isEmpty())
|
||||
address = "[" + address + "]";
|
||||
return address + ":" + QString::number(appConfig().port());
|
||||
}
|
||||
|
||||
QString MainWindow::appPath(const QString& name)
|
||||
|
|
|
@ -113,6 +113,11 @@ ArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
|
|||
}
|
||||
try {
|
||||
setBlockingOnSocket(fd, false);
|
||||
if (family == kINET6) {
|
||||
int flag = 0;
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) != 0)
|
||||
throwError(errno);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
close(fd);
|
||||
|
@ -647,8 +652,8 @@ ArchNetworkBSD::newAnyAddr(EAddressFamily family)
|
|||
switch (family) {
|
||||
case kINET: {
|
||||
auto* ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
||||
memset(ipAddr, 0, sizeof(struct sockaddr_in));
|
||||
ipAddr->sin_family = AF_INET;
|
||||
ipAddr->sin_port = 0;
|
||||
ipAddr->sin_addr.s_addr = INADDR_ANY;
|
||||
addr->m_len = (socklen_t)sizeof(struct sockaddr_in);
|
||||
break;
|
||||
|
@ -656,8 +661,8 @@ ArchNetworkBSD::newAnyAddr(EAddressFamily family)
|
|||
|
||||
case kINET6: {
|
||||
auto* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
memset(ipAddr, 0, sizeof(struct sockaddr_in6));
|
||||
ipAddr->sin6_family = AF_INET6;
|
||||
ipAddr->sin6_port = 0;
|
||||
memcpy(&ipAddr->sin6_addr, &in6addr_any, sizeof(in6addr_any));
|
||||
addr->m_len = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
|
|
|
@ -213,10 +213,10 @@ ArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type)
|
|||
}
|
||||
try {
|
||||
setBlockingOnSocket(fd, false);
|
||||
BOOL flag = 0;
|
||||
int size = sizeof(flag);
|
||||
if (setsockopt_winsock(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, size) == SOCKET_ERROR) {
|
||||
throwError(getsockerror_winsock());
|
||||
if (family == kINET6) {
|
||||
int flag = 0;
|
||||
if (setsockopt_winsock(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) == SOCKET_ERROR)
|
||||
throwError(getsockerror_winsock());
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
|
@ -685,8 +685,8 @@ ArchNetworkWinsock::newAnyAddr(EAddressFamily family)
|
|||
case kINET: {
|
||||
addr = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
|
||||
auto* ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
||||
memset(ipAddr, 0, sizeof(struct sockaddr_in));
|
||||
ipAddr->sin_family = AF_INET;
|
||||
ipAddr->sin_port = 0;
|
||||
ipAddr->sin_addr.s_addr = INADDR_ANY;
|
||||
break;
|
||||
}
|
||||
|
@ -694,8 +694,8 @@ ArchNetworkWinsock::newAnyAddr(EAddressFamily family)
|
|||
case kINET6: {
|
||||
addr = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in6));
|
||||
auto* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
memset(ipAddr, 0, sizeof(struct sockaddr_in6));
|
||||
ipAddr->sin6_family = AF_INET6;
|
||||
ipAddr->sin6_port = 0;
|
||||
memcpy(&ipAddr->sin6_addr, &in6addr_any, sizeof(in6addr_any));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -131,9 +131,10 @@ ClientApp::help()
|
|||
<< std::endl
|
||||
<< "Default options are marked with a *" << std::endl
|
||||
<< std::endl
|
||||
<< "The server address is of the form: [<hostname>][:<port>]. The hostname" << std::endl
|
||||
<< "must be the address or hostname of the server. The port overrides the" << std::endl
|
||||
<< "default port, " << kDefaultPort << "." << std::endl;
|
||||
<< "The server address is of the form: [<hostname>][:<port>]. The hostname" << std::endl
|
||||
<< "must be the address or hostname of the server. Placing brackets around" << std::endl
|
||||
<< "an IPv6 address is required when also specifying a port number and " << std::endl
|
||||
<< "optional otherwise. The default port number is " << kDefaultPort << "." << std::endl;
|
||||
|
||||
LOG((CLOG_PRINT "%s", buffer.str().c_str()));
|
||||
}
|
||||
|
|
|
@ -139,8 +139,9 @@ ServerApp::help()
|
|||
<< std::endl
|
||||
<< "The argument for --address is of the form: [<hostname>][:<port>]. The" << std::endl
|
||||
<< "hostname must be the address or hostname of an interface on the system." << std::endl
|
||||
<< "The default is to listen on all interfaces. The port overrides the" << std::endl
|
||||
<< "default port, " << kDefaultPort << "." << std::endl
|
||||
<< "Placing brackets around an IPv6 address is required when also specifying " << std::endl
|
||||
<< "a port number and optional otherwise. The default is to listen on all" << std::endl
|
||||
<< "interfaces using port number " << kDefaultPort << "." << std::endl
|
||||
<< std::endl
|
||||
<< "If no configuration file pathname is provided then the first of the" << std::endl
|
||||
<< "following to load successfully sets the configuration:" << std::endl
|
||||
|
@ -506,6 +507,16 @@ ServerApp::openServerScreen()
|
|||
return screen;
|
||||
}
|
||||
|
||||
static const char* const family_string(IArchNetwork::EAddressFamily family)
|
||||
{
|
||||
if (family == IArchNetwork::kINET)
|
||||
return "IPv4";
|
||||
if (family == IArchNetwork::kINET6)
|
||||
// assume IPv6 sockets are setup to support IPv4 traffic as well
|
||||
return "IPv4/IPv6";
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
bool
|
||||
ServerApp::startServer()
|
||||
{
|
||||
|
@ -531,13 +542,15 @@ ServerApp::startServer()
|
|||
double retryTime;
|
||||
ClientListener* listener = NULL;
|
||||
try {
|
||||
listener = openClientListener(args().m_config->getBarrierAddress());
|
||||
auto listenAddress = args().m_config->getBarrierAddress();
|
||||
auto family = family_string(ARCH->getAddrFamily(listenAddress.getAddress()));
|
||||
listener = openClientListener(listenAddress);
|
||||
m_server = openServer(*args().m_config, m_primaryClient);
|
||||
listener->setServer(m_server);
|
||||
m_server->setListener(listener);
|
||||
m_listener = listener;
|
||||
updateStatus();
|
||||
LOG((CLOG_NOTE "started server, waiting for clients"));
|
||||
LOG((CLOG_NOTE "started server (%s), waiting for clients", family));
|
||||
m_serverState = kStarted;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,45 @@
|
|||
// NetworkAddress
|
||||
//
|
||||
|
||||
static bool parse_address(const std::string& address, std::string& host, int& port)
|
||||
{
|
||||
/* Three cases ---
|
||||
* brackets: parse inside for host, check end for port as :INTEGER. DONE
|
||||
* one colon: ipv4 address with port. DONE
|
||||
* otherwise: all host, no port. DONE
|
||||
*
|
||||
* very, very little error checking. depends on address being trimmed before call.
|
||||
*
|
||||
* does not override port with a default value if no port was found in address.
|
||||
*/
|
||||
|
||||
if (address[0] == '[') {
|
||||
// bracketed host possibly followed by port as :INTEGER
|
||||
auto endBracket = address.find(']', 1);
|
||||
if (endBracket == std::string::npos)
|
||||
return false;
|
||||
host = address.substr(1, endBracket - 1);
|
||||
if (endBracket + 1 < address.length()) {
|
||||
// port follows (or garbage)
|
||||
if (address[endBracket + 1] != ':')
|
||||
return false;
|
||||
port = std::strtol(&address[endBracket + 2], nullptr, 10);
|
||||
}
|
||||
} else {
|
||||
auto colon = address.find(':');
|
||||
if (colon != std::string::npos && address.find(':', colon + 1) == std::string::npos) {
|
||||
// one single colon, must be ipv4 with port
|
||||
host = address.substr(0, colon);
|
||||
port = std::strtol(&address[colon + 1], nullptr, 10);
|
||||
} else {
|
||||
// no colons (ipv4) or more than one colon (ipv6), both without port
|
||||
host = address;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// name re-resolution adapted from a patch by Brent Priddy.
|
||||
|
||||
NetworkAddress::NetworkAddress() :
|
||||
|
@ -62,50 +101,9 @@ NetworkAddress::NetworkAddress(const String& hostname, int port) :
|
|||
m_hostname(hostname),
|
||||
m_port(port)
|
||||
{
|
||||
// check for port suffix
|
||||
String::size_type i = m_hostname.rfind(':');
|
||||
if (i != String::npos && i + 1 < m_hostname.size()) {
|
||||
// found a colon. see if it looks like an IPv6 address.
|
||||
bool colonNotation = false;
|
||||
bool dotNotation = false;
|
||||
bool doubleColon = false;
|
||||
for (String::size_type j = 0; j < i; ++j) {
|
||||
if (m_hostname[j] == ':') {
|
||||
colonNotation = true;
|
||||
dotNotation = false;
|
||||
if (m_hostname[j + 1] == ':') {
|
||||
doubleColon = true;
|
||||
}
|
||||
}
|
||||
else if (m_hostname[j] == '.' && colonNotation) {
|
||||
dotNotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
// port suffix is ambiguous with IPv6 notation if there's
|
||||
// a double colon and the end of the address is not in dot
|
||||
// notation. in that case we assume it's not a port suffix.
|
||||
// the user can replace the double colon with zeros to
|
||||
// disambiguate.
|
||||
if ((!doubleColon || dotNotation) && !colonNotation) {
|
||||
// parse port from hostname
|
||||
char* end;
|
||||
const char* chostname = m_hostname.c_str();
|
||||
long suffixPort = strtol(chostname + i + 1, &end, 10);
|
||||
if (end == chostname + i + 1 || *end != '\0') {
|
||||
throw XSocketAddress(XSocketAddress::kBadPort,
|
||||
m_hostname, m_port);
|
||||
}
|
||||
|
||||
// trim port from hostname
|
||||
m_hostname.erase(i);
|
||||
|
||||
// save port
|
||||
m_port = static_cast<int>(suffixPort);
|
||||
}
|
||||
}
|
||||
|
||||
// check port number
|
||||
if (!parse_address(hostname, m_hostname, m_port))
|
||||
throw XSocketAddress(XSocketAddress::kUnknown,
|
||||
m_hostname, m_port);
|
||||
checkPort();
|
||||
}
|
||||
|
||||
|
@ -145,7 +143,7 @@ NetworkAddress::resolve()
|
|||
// if hostname is empty then use wildcard address otherwise look
|
||||
// up the name.
|
||||
if (m_hostname.empty()) {
|
||||
m_address = ARCH->newAnyAddr(IArchNetwork::kINET);
|
||||
m_address = ARCH->newAnyAddr(IArchNetwork::kINET6);
|
||||
}
|
||||
else {
|
||||
m_address = ARCH->nameToAddr(m_hostname);
|
||||
|
|
Loading…
Reference in New Issue