Add ability to bind synergy client to network interface (#7254)

* Switch client help to use dynamic buffer

* Add the new param into client help

* Parse the new param as a generic param

* Add additional member to store server address

* Bind client socket to network interface

* Update Changelog

* Fix code smell
This commit is contained in:
Serhii Hadzhilov 2023-03-29 11:39:49 +03:00 committed by GitHub
parent 2d434838dc
commit 8587dda4ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 78 additions and 51 deletions

View file

@ -1,3 +1,9 @@
1.14.7
======
Enhancements:
- #7254 Ability to bind synergy client to a network interface.
1.14.6 1.14.6
====== ======

View file

@ -6,7 +6,7 @@ cmake_minimum_required (VERSION 3.4)
set (SYNERGY_VERSION_MAJOR 1) set (SYNERGY_VERSION_MAJOR 1)
set (SYNERGY_VERSION_MINOR 14) set (SYNERGY_VERSION_MINOR 14)
set (SYNERGY_VERSION_PATCH 6) set (SYNERGY_VERSION_PATCH 7)
set (SYNERGY_VERSION_BUILD 1) set (SYNERGY_VERSION_BUILD 1)
set (SYNERGY_VERSION_STAGE "snapshot") set (SYNERGY_VERSION_STAGE "snapshot")

View file

@ -158,6 +158,8 @@ Client::connect(size_t addressIndex)
// create the socket // create the socket
IDataSocket* socket = m_socketFactory->create(m_useSecureNetwork, ARCH->getAddrFamily(m_serverAddress.getAddress())); IDataSocket* socket = m_socketFactory->create(m_useSecureNetwork, ARCH->getAddrFamily(m_serverAddress.getAddress()));
bindNetworkInterface(socket);
// filter socket messages, including a packetizing filter // filter socket messages, including a packetizing filter
m_stream = new PacketStreamFilter(m_events, socket, true); m_stream = new PacketStreamFilter(m_events, socket, true);
@ -836,6 +838,24 @@ Client::onFileRecieveCompleted()
} }
} }
void Client::bindNetworkInterface(IDataSocket *socket) const
{
try {
if (!m_args.m_synergyAddress.empty()) {
LOG((CLOG_DEBUG1 "bind to network interface: %s", m_args.m_synergyAddress.c_str()));
NetworkAddress bindAddress(m_args.m_synergyAddress);
bindAddress.resolve();
socket->bind(bindAddress);
}
}
catch(XBase& e) {
LOG((CLOG_WARN "%s", e.what()));
LOG((CLOG_WARN "operating system will select network interface automatically"));
}
}
void void
Client::handleStopRetry(const Event&, void*) Client::handleStopRetry(const Event&, void*)
{ {

View file

@ -210,6 +210,7 @@ private:
void handleStopRetry(const Event&, void*); void handleStopRetry(const Event&, void*);
void onFileRecieveCompleted(); void onFileRecieveCompleted();
void sendClipboardThread(void*); void sendClipboardThread(void*);
void bindNetworkInterface(IDataSocket* socket) const;
public: public:
bool m_mock; bool m_mock;

View file

@ -238,7 +238,7 @@ void
NetworkAddress::checkPort() NetworkAddress::checkPort()
{ {
// check port number // check port number
if (m_port <= 0 || m_port > 65535) { if (m_port < 0 || m_port > 65535) {
throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port);
} }
} }

View file

@ -49,7 +49,7 @@ public:
is thrown with an error of \c XSocketAddress::kBadPort. The hostname is thrown with an error of \c XSocketAddress::kBadPort. The hostname
is not resolved by the c'tor; use \c resolve to do that. is not resolved by the c'tor; use \c resolve to do that.
*/ */
NetworkAddress(const String& hostname, int port); NetworkAddress(const String& hostname, int port = 0);
NetworkAddress(const NetworkAddress&); NetworkAddress(const NetworkAddress&);

View file

@ -56,10 +56,6 @@ ArgParser::parseServerArgs(lib::synergy::ServerArgs& args, int argc, const char*
++i; ++i;
continue; continue;
} }
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
// save listen address
args.m_synergyAddress = argv[++i];
}
else if (isArg(i, argc, argv, "-c", "--config", 1)) { else if (isArg(i, argc, argv, "-c", "--config", 1)) {
// save configuration file path // save configuration file path
args.m_configFile = argv[++i]; args.m_configFile = argv[++i];
@ -130,7 +126,7 @@ ArgParser::parseClientArgs(lib::synergy::ClientArgs& args, int argc, const char*
} }
else { else {
if (i + 1 == argc) { if (i + 1 == argc) {
args.m_synergyAddress = argv[i]; args.m_serverAddress = argv[i];
return true; return true;
} }
@ -223,7 +219,10 @@ ArgParser::parseToolArgs(ToolArgs& args, int argc, const char* const* argv)
bool bool
ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i) ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i)
{ {
if (isArg(i, argc, argv, "-d", "--debug", 1)) { if (isArg(i, argc, argv, "-a", "--address", 1)) {
argsBase().m_synergyAddress = argv[++i];
}
else if (isArg(i, argc, argv, "-d", "--debug", 1)) {
// change logging level // change logging level
argsBase().m_logFilter = argv[++i]; argsBase().m_logFilter = argv[++i];
} }

View file

@ -52,7 +52,7 @@ namespace lib {
bool m_enableDragDrop = false; /// @brief Should drag drop support be enabled bool m_enableDragDrop = false; /// @brief Should drag drop support be enabled
bool m_shouldExit = false; /// @brief Will cause the application to exit when set to true bool m_shouldExit = false; /// @brief Will cause the application to exit when set to true
String m_synergyAddress; /// @brief Bind to this address //TODO This really should be a ServerArgs String m_synergyAddress; /// @brief Bind to this address
bool m_enableCrypto = false; /// @brief Should the connections be TLS encrypted bool m_enableCrypto = false; /// @brief Should the connections be TLS encrypted
String m_profileDirectory; /// @brief The profile DIR to use for the application String m_profileDirectory; /// @brief The profile DIR to use for the application
String m_pluginDirectory; /// @brief //TODO Plugins? Get set in ARCH but doesn't seem to get used String m_pluginDirectory; /// @brief //TODO Plugins? Get set in ARCH but doesn't seem to get used

View file

@ -59,7 +59,7 @@
#endif #endif
#include <memory> #include <memory>
#include <iostream> #include <sstream>
#include <stdio.h> #include <stdio.h>
#define RETRY_TIME 1.0 #define RETRY_TIME 1.0
@ -87,9 +87,9 @@ ClientApp::parseArgs(int argc, const char* const* argv)
} }
else { else {
// save server address // save server address
if (!args().m_synergyAddress.empty()) { if (!args().m_serverAddress.empty()) {
try { try {
*m_serverAddress = NetworkAddress(args().m_synergyAddress, kDefaultPort); *m_serverAddress = NetworkAddress(args().m_serverAddress, kDefaultPort);
m_serverAddress->resolve(); m_serverAddress->resolve();
} }
catch (XSocketAddress& e) { catch (XSocketAddress& e) {
@ -117,45 +117,41 @@ ClientApp::help()
" --display <display> connect to the X server at <display>\n" \ " --display <display> connect to the X server at <display>\n" \
" --no-xinitthreads do not call XInitThreads()\n" " --no-xinitthreads do not call XInitThreads()\n"
#else #else
# define WINAPI_ARG # define WINAPI_ARG ""
# define WINAPI_INFO # define WINAPI_INFO ""
#endif #endif
static const int buffer_size = 2000; std::stringstream help;
char buffer[buffer_size]; help<< "Usage: " << args().m_pname
snprintf( <<" [--address <address>]"
buffer, <<" [--yscroll <delta>]"
buffer_size, <<" [--sync-language]"
"Usage: %s" <<" [--invert-scroll]"
" [--yscroll <delta>]" <<" [--host]"
" [--sync-language]" <<WINAPI_ARG
" [--invert-scroll]" <<HELP_SYS_ARGS
" [--host]" <<HELP_COMMON_ARGS
WINAPI_ARG <<" <server-address>"
HELP_SYS_ARGS <<"\n\n"
HELP_COMMON_ARGS <<"Connect to a synergy mouse/keyboard sharing server.\n"
" <server-address>" <<"\n"
"\n\n" <<" -a, --address <address> local network interface address.\n"
"Connect to a synergy mouse/keyboard sharing server.\n" <<HELP_COMMON_INFO_1
"\n" <<WINAPI_INFO
HELP_COMMON_INFO_1 <<HELP_SYS_INFO
WINAPI_INFO <<" --yscroll <delta> defines the vertical scrolling delta, which is\n"
HELP_SYS_INFO <<" 120 by default.\n"
" --yscroll <delta> defines the vertical scrolling delta, which is\n" <<" --sync-language set this parameter to enable language synchronization.\n"
" 120 by default.\n" <<" --invert-scroll invert scroll direction on this computer.\n"
" --sync-language set this parameter to enable language synchronization.\n" <<" --host client starts a listener and waits for a server connection.\n"
" --invert-scroll invert scroll direction on this computer.\n" <<HELP_COMMON_INFO_2
" --host client starts a listener and waits for a server connection.\n" <<"\n"
HELP_COMMON_INFO_2 <<"* marks defaults.\n"
"\n" <<"\n"
"* marks defaults.\n" <<"The server address is of the form: [<hostname>][:<port>]. The hostname\n"
"\n" <<"must be the address or hostname of the server. The port overrides the\n"
"The server address is of the form: [<hostname>][:<port>]. The hostname\n" <<"default port, " << kDefaultPort <<".\n";
"must be the address or hostname of the server. The port overrides the\n"
"default port, %d.\n",
args().m_pname, kDefaultPort
);
LOG((CLOG_PRINT "%s", buffer)); LOG((CLOG_PRINT "%s", help.str().c_str()));
} }
const char* const char*

View file

@ -52,6 +52,11 @@ namespace lib {
*/ */
bool m_hostMode = false; bool m_hostMode = false;
/**
* @brief m_serverAddress stores synergy server address
*/
std::string m_serverAddress;
}; };
} }
} }

View file

@ -111,7 +111,7 @@ TEST(ClientArgsParsingTests, parseClientArgs_addressArg_setSynergyAddress)
bool result = argParser.parseClientArgs(clientArgs, argc, kAddressCmd); bool result = argParser.parseClientArgs(clientArgs, argc, kAddressCmd);
EXPECT_EQ("mock_address", clientArgs.m_synergyAddress); EXPECT_EQ("mock_address", clientArgs.m_serverAddress);
EXPECT_EQ(true, result); EXPECT_EQ(true, result);
} }