Merge branch 'master' into SYNERGY-936-UI-issues-and-use-cases

This commit is contained in:
Serhii Hadzhilov 2021-04-28 10:44:28 +03:00
commit 4c5c0608d4
7 changed files with 136 additions and 51 deletions

View file

@ -10,6 +10,7 @@ Bug fixes:
- #6975 Fix server stop working
- #6976 Fix windows builds
- #6979 Manual config error in client mode
- #6983 Fix that mac client listens on ipv4 only
Enhancements:
- #6954 Move language selection to advanced section
@ -18,7 +19,7 @@ Enhancements:
- #6973 Update synergy UI. Main window
- #6977 Update synergy UI. Configure server
- #6978 Update synergy UI. Settings window
- #6981 Update synergy UI. Setup client configuration
- #6981 | #6987 Update synergy UI. Setup client configuration
- #6984 Update synergy UI. Client error messages
- #6962 | #6965 Add macOS 10.13 builder
===========

View file

@ -461,8 +461,7 @@ void MainWindow::checkConnected(const QString& line)
m_pLabelClientState->updateClientState(line);
}
if (line.contains("connected to server") ||
line.contains("accepted client connection"))
if (line.contains("connected to server") || line.contains("has connected"))
{
setSynergyState(synergyConnected);
@ -838,6 +837,15 @@ QString MainWindow::configFilename()
QString MainWindow::address() const
{
QString i = appConfig().networkInterface();
// if interface is IPv6 - ensure that ip is in square brackets
if (i.count(':') > 1) {
if(i[0] != '[') {
i.insert(0, '[');
}
if(i[i.size() - 1] != ']') {
i.push_back(']');
}
}
return (!i.isEmpty() ? i : "") + ":" + QString::number(appConfig().port());
}
@ -1053,7 +1061,7 @@ QString MainWindow::getIPAddresses()
for (const auto& address : addresses) {
if (address.protocol() == QAbstractSocket::IPv4Protocol &&
address != QHostAddress(QHostAddress::LocalHost) &&
!address.isLinkLocal()) {
!address.isInSubnet(QHostAddress::parseSubnet("169.254.0.0/16"))) {
// usually 192.168.x.x is a useful ip for the user, so indicate
// this by making it bold.

View file

@ -70,18 +70,16 @@ ServerConfigDialog::ServerConfigDialog(QWidget* parent, ServerConfig& config) :
m_pScreenSetupView->setModel(&m_ScreenSetupModel);
if (serverConfig().numScreens() == 0) {
auto& screens = serverConfig().screens();
auto server = std::find_if(screens.begin(), screens.end(), [this](const Screen& screen){ return (screen.name() == serverConfig().getServerName());});
if (server == screens.end()) {
Screen serverScreen(serverConfig().getServerName());
serverScreen.markAsServer();
model().screen(serverConfig().numColumns() / 2, serverConfig().numRows() / 2) = serverScreen;
}
else {
for (auto& screen : serverConfig().screens()) {
if (screen.name() == serverConfig().getServerName()) {
screen.markAsServer();
break;
}
}
server->markAsServer();
}
m_pButtonAddComputer->setEnabled(!model().isFull());

View file

@ -61,6 +61,8 @@ void ServerConnection::addClient(const QString& clientName)
{
if (!m_parent.serverConfig().isFull() && checkMainWindow())
{
m_parent.stopSynergy();
QMessageBox message(&m_parent);
message.addButton(QObject::tr("Ignore"), QMessageBox::RejectRole);
message.addButton(QObject::tr("Accept and configure"), QMessageBox::AcceptRole);
@ -74,6 +76,8 @@ void ServerConnection::addClient(const QString& clientName)
{
m_ignoredClients.append(clientName);
}
m_parent.startSynergy();
}
}
@ -84,6 +88,4 @@ void ServerConnection::configureClient(const QString& clientName)
ServerConfigDialog dlg(&m_parent, config);
dlg.exec();
m_parent.restartSynergy();
}

View file

@ -679,14 +679,27 @@ ArchNetworkBSD::nameToAddr(const std::string& name)
char ipstr[INET6_ADDRSTRLEN];
struct addrinfo hints;
struct addrinfo *p;
struct in6_addr serveraddr;
int ret;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (inet_pton(AF_INET, name.c_str(), &serveraddr) == 1) {
hints.ai_family = AF_INET;
hints.ai_flags |= AI_NUMERICHOST;
}
else if (inet_pton(AF_INET6, name.c_str(), &serveraddr) == 1) {
hints.ai_family = AF_INET6;
hints.ai_flags |= AI_NUMERICHOST;
}
// done with static buffer
ARCH->lockMutex(m_mutex);
if ((ret = getaddrinfo(name.c_str(), NULL, &hints, &p)) != 0) {
ret = getaddrinfo(name.c_str(), nullptr, &hints, &p);
if (ret != 0) {
ARCH->unlockMutex(m_mutex);
delete addr;
throwNameError(ret);
@ -697,6 +710,7 @@ ArchNetworkBSD::nameToAddr(const std::string& name)
} else {
addr->m_len = (socklen_t)sizeof(struct sockaddr_in6);
}
memcpy(&addr->m_addr, p->ai_addr, addr->m_len);
freeaddrinfo(p);
ARCH->unlockMutex(m_mutex);
@ -992,4 +1006,4 @@ ArchNetworkBSD::throwNameError(int err)
default:
throw XArchNetworkName(s_msg[4]);
}
}
}

View file

@ -22,6 +22,7 @@
#include "arch/Arch.h"
#include "arch/XArch.h"
#include <algorithm>
#include <cstdlib>
//
@ -62,46 +63,53 @@ 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;
}
//detect internet protocol version with colom count
auto isColomPredicate = [](char c){return c == ':';};
auto colomCount = std::count_if(m_hostname.begin(), m_hostname.end(), isColomPredicate);
if(colomCount == 1) {
//ipv4 with port part
auto hostIt = m_hostname.find(':');
try {
m_port = std::stoi(m_hostname.substr(hostIt + 1));
} catch(...) {
throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port);
}
// 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);
auto endHostnameIt = static_cast<int>(hostIt);
m_hostname = m_hostname.substr(0, endHostnameIt > 0 ? endHostnameIt : 0);
}
else if (colomCount > 1) {
//ipv6 part
if (m_hostname[0] == '[') {
//ipv6 with port part
String portDelimeter = "]:";
auto hostIt = m_hostname.find(portDelimeter);
//bad syntax of ipv6 with port
if (hostIt == String::npos) {
throw XSocketAddress(XSocketAddress::kUnknown, m_hostname, m_port);
}
// trim port from hostname
m_hostname.erase(i);
auto portSuffix = m_hostname.substr(hostIt + portDelimeter.size());
//port is implied but omitted
if (portSuffix.empty()) {
throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port);
}
try {
m_port = std::stoi(portSuffix);
} catch(...) {
//port is not a number
throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port);
}
// save port
m_port = static_cast<int>(suffixPort);
auto endHostnameIt = static_cast<int>(hostIt) - 1;
m_hostname = m_hostname.substr(1, endHostnameIt > 0 ? endHostnameIt : 0);
}
// ensure that ipv6 link-local adress ended with scope id
if (m_hostname.rfind("fe80:", 0) == 0 && m_hostname.find('%') == String::npos) {
throw XSocketAddress(XSocketAddress::kUnknown, m_hostname, m_port);
}
}

View file

@ -16,6 +16,7 @@
*/
#include "lib/server/Config.h"
#include "net/XSocket.h"
#include "test/global/gtest.h"
class OnlySystemFilter: public InputFilter::Condition {
@ -84,6 +85,59 @@ TEST(ServerConfigTests, serverconfig_will_deem_equal_configs_with_same_cell_name
EXPECT_TRUE(b == a);
}
TEST(NetworkAddress, hostname_valid_parsing)
{
const int validPort = 24900;
const String portStr = std::to_string(validPort);
//list of test cases. 1 param - hostname for parsing, 2 param - port, 3 param - expected hostname
const std::initializer_list<std::tuple<String, int, String>> validTestCases = {
std::make_tuple(String("127.0.0.1"), validPort, "127.0.0.1"),
std::make_tuple(String("127.0.0.1:") + portStr, 0, "127.0.0.1"),
std::make_tuple(String(":") + portStr, 0, ""),
std::make_tuple(String("localhost"), validPort, "localhost"),
std::make_tuple(String("localhost:") + portStr, 0, "localhost"),
std::make_tuple(String(""), validPort, ""),
std::make_tuple(String("[::1]:") + portStr, 0, "::1"),
std::make_tuple(String("[fe80::a156:9f36:793:7bfb%14]:") + portStr, 0, "fe80::a156:9f36:793:7bfb%14"),
std::make_tuple(String("::1"), validPort, "::1"),
std::make_tuple(String("fe80::a156:9f36:793:7bfb%14"), validPort, "fe80::a156:9f36:793:7bfb%14"),
std::make_tuple(String("fe80:0000:0000:0000:a156:9f36:793:7bfb%14"), validPort, "fe80:0000:0000:0000:a156:9f36:793:7bfb%14"),
};
for (const auto &caseParams : validTestCases) {
NetworkAddress addr(std::get<0>(caseParams), std::get<1>(caseParams));
addr.resolve();
EXPECT_TRUE(addr.getHostname() == std::get<2>(caseParams));
EXPECT_TRUE(addr.getPort() == validPort);
EXPECT_TRUE(addr.getAddress() != nullptr);
}
//list of non valid hostnames
const std::initializer_list<String> nonValidTestCases = {
":nonValidPort",
":",
"[::1]:",
"[::1]:nonValidPort",
"fe80::1",
"[::1]:-1",
"[::1]:65536"
};
for (const auto &caseParam : nonValidTestCases) {
bool flag = false;
try {
NetworkAddress addr(caseParam, validPort);
} catch (const XSocketAddress&) {
flag = true;
}
EXPECT_TRUE(flag);
}
}
TEST(ServerConfigTests, serverconfig_will_deem_different_configs_with_same_cell_names_different_options)
{
Config a(nullptr);