Solve low hanging reliability and maintainability issues (#7403)

* Add missing atom ctor init

* Init members with `None`

* Use in-class init and delcare getter inside if init

* Temp revert of changes ahead of unit test repair

* Move IPC header to shared, restore X clipboard test, simplify test cmake, new X clipboard unit test

* Suppress sonar for undefs

* Remove base dir include

* Revert "Temp revert of changes ahead of unit test repair"

This reverts commit 8f84b6ea5d5828f1be1362de3809279bcacb8cc8.

* Use new accessor

* Use default dtor

* Beef up to 32 core

* Use enum class

* Make IPC protocol headers const at all levels

* Use enum class and const char for better type safety

* Use unique_ptr for m_clipboard

* Use `-j` instead of `-j8` to utilize full parallelism

* Increase thread count for sonar-scanner

* Use 32 threads

* Use in-class init for IpcClientProxy members

* Use const instead of #define

* Remove ctor member inits

* Use unique_ptr on win

* Implement temp bin dir for windows with more robust post-build copy

* Fixed missing iostream

* Add warning about copy errors

* Only run clean-gcda on Linux

* Use in-class init for IPC mutex

* Do no-op on Windows

* Hide clean-gcda task

* Move flakey test to integtests

* Delete dead code

* Test

* Temp disable post_config_all

* Disable post config step

* Revert "Disable post config step"

This reverts commit 2f956a7714ba9bedacd4b39d4ae00940c3d565d6.

* Revert "Temp disable post_config_all"

This reverts commit b44ed72e44f838bfe1309f6e9672d2f1c6f21b75.

* Restore -j8

* Simplify error handling

* Use const for test port

* Remove python check

* Update changelog

* Fixed order

* Fixed bad issue number

* Fixed bin copy source path

* Remove redundant except
This commit is contained in:
Nick Bolton
2024-07-18 08:04:39 +01:00
committed by GitHub
parent 47849db4d9
commit 6399feb324
62 changed files with 814 additions and 698 deletions

View File

@ -19,7 +19,7 @@ jobs:
sonarcloud-analysis:
if: ${{ vars.SONAR_SCANNER_ENABLED }}
runs-on: ubuntu-24.04-16-core-x64
runs-on: ubuntu-24.04-32-core-x64
container: symless/synergy-core:ubuntu-22.04-amd64
timeout-minutes: 20
@ -27,6 +27,7 @@ jobs:
SONAR_SCANNER_VERSION: 6.1.0.4477
SONAR_SCANNER_OPTS: -server
SONAR_SCANNER_URL_BASE: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli
SONAR_SCANNER_THREADS: 32
steps:
- name: Checkout
@ -83,7 +84,7 @@ jobs:
-Dsonar.cfamily.build-wrapper-output=bw-output \
-Dsonar.host.url=https://sonarcloud.io \
-Dsonar.coverageReportPaths=build/coverage.xml \
-Dsonar.cfamily.threads=2
-Dsonar.cfamily.threads=${{ env.SONAR_SCANNER_THREADS }}
env:
SONAR_TOKEN: ${{secrets.SONAR_TOKEN}}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored
View File

@ -1,6 +1,5 @@
# temp dirs created during build
/build
/bin
/dist
/deps
/tmp

27
.vscode/tasks.json vendored
View File

@ -14,9 +14,9 @@
},
{
"type": "cmake",
"label": "coverage",
"label": "clean",
"command": "build",
"targets": ["coverage"],
"targets": ["clean"],
"preset": "${command:cmake.activeBuildPresetName}",
"group": "build"
},
@ -32,6 +32,17 @@
"command": "${workspaceFolder}/build/bin/synergy",
"dependsOn": ["build"]
},
{
"label": "clean-gcda",
"type": "shell",
"command": "find . -name '*.gcda' -delete",
"windows": {
"command": "$null" // no-op
},
"presentation": {
"reveal": "silent"
}
},
{
"label": "unittests (current)",
"type": "shell",
@ -42,7 +53,7 @@
"--ignore-return-code",
"--filter-file=${file}"
],
"dependsOn": ["build"]
"dependsOn": ["build", "clean-gcda"]
},
{
"label": "integtests (current)",
@ -54,21 +65,21 @@
"--ignore-return-code",
"--filter-file=${file}"
],
"dependsOn": ["build"]
"dependsOn": ["build", "clean-gcda"]
},
{
"label": "unittests (all)",
"type": "shell",
"command": "python",
"args": ["./scripts/tests.py", "--unit-tests", "--ignore-return-code"],
"dependsOn": ["build"]
"dependsOn": ["build", "clean-gcda"]
},
{
"label": "integtests (all)",
"type": "shell",
"command": "python",
"args": ["./scripts/tests.py", "--integ-tests", "--ignore-return-code"],
"dependsOn": ["build"]
"dependsOn": ["build", "clean-gcda"]
},
{
"label": "unittests (current, valgrind)",
@ -81,7 +92,7 @@
"--filter-file=${file}",
"--valgrind"
],
"dependsOn": ["build"]
"dependsOn": ["build", "clean-gcda"]
},
{
"label": "integtests (current, valgrind)",
@ -94,7 +105,7 @@
"--filter-file=${file}",
"--valgrind"
],
"dependsOn": ["build"]
"dependsOn": ["build", "clean-gcda"]
}
]
}

View File

@ -19,6 +19,7 @@ project(synergy-core C CXX)
include(cmake/Version.cmake)
include(cmake/Definitions.cmake)
include(cmake/Build.cmake)
include(cmake/Libraries.cmake)
include(cmake/Packaging.cmake)
@ -28,3 +29,5 @@ configure_libs()
configure_packaging()
add_subdirectory(src)
post_config_all()

View File

@ -24,7 +24,7 @@ Enhancements:
- #7326 Restore lpDesktop assignment in Windows daemon
- #7327 Only use Ninja to build on Windows
- #7328 Reset error state before calling Process32Next
- #1177 Split CMake presets into debug and release
- #7330 Split CMake presets into debug and release
- #7331 Script to install deps (Windows only for now)
- #7332 Static link OpenSSL libs in CMake preset for Windows
- #7333 Update VS Code config for Windows daemon debugging
@ -50,10 +50,11 @@ Enhancements:
- #7380 Add `qt6-qpa-plugins` Qt dependency for Debian
- #7381 Set macOS min version to macOS 12.0
- #7382 Re-run `macdeployqt6` to copy missing Qt 6 dependencies
- #7383 Solve SonarCloud security hotspots and bugs
- #7384 Run `install_deps.py` script when building containers weekly
- #7389 Correct Qt macOS target and drop `Core5Compat` lib
- #7383 Solve SonarCloud security hotspots and bugs
- #7401 Run Valgrind on unit tests in CI to detect memory leaks
- #7403 Solve low hanging reliability and maintainability issues
# 1.14.6

61
cmake/Build.cmake Normal file
View File

@ -0,0 +1,61 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
macro(post_config)
# Build to a temp bin dir on Windows and then copy to the final bin dir
# (ignore copy fail). It is neccesary to do this. Since the binary may already
# be running and you can't write to a running binary (on Windows). It's common
# to use Synergy to develop Synergy (i.e. eating your own dog food immediately
# making it).
if(WIN32)
if(NOT target)
message(FATAL_ERROR "target not set")
endif()
set_target_properties(${target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY
${BIN_TEMP_DIR})
endif()
endmacro()
macro(post_config_all)
# Always try to copy the files to the bin directory after every build, even if
# there was nothing to do. This is because the copy may have failed last time
# due to the file being in use, and we'll usually want to try again.
if(WIN32)
if(NOT EXISTS ${PYTHON_BIN})
message(FATAL_ERROR "Python not found at: ${PYTHON_BIN}")
endif()
add_custom_target(
run_post_build ALL
COMMAND ${PYTHON_BIN} ${CMAKE_SOURCE_DIR}/scripts/fancy_copy.py
${BIN_TEMP_DIR} ${CMAKE_BINARY_DIR}/bin --ignore-errors
VERBATIM
COMMENT "Copying files to bin dir")
add_dependencies(
run_post_build
synergy
synergyc
synergys
synergyd)
endif()
endmacro()

View File

@ -28,6 +28,7 @@ macro(configure_definitions)
configure_ninja()
configure_options()
configure_python()
if("${VERSION_URL}" STREQUAL "")
set(VERSION_URL "https://api.symless.com/version?version=v1")
@ -58,17 +59,20 @@ macro(configure_definitions)
add_definitions(-DNDEBUG)
endif()
# TODO: find out why we need these, and remove them if we don't
# TODO: find out why we need these, and remove them if we don't.
if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
cmake_policy(SET CMP0005 NEW)
endif()
# TODO: explain why we're adding headers to sources.
if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")
set(SYNERGY_ADD_HEADERS FALSE)
set(ADD_HEADERS_TO_SOURCES FALSE)
else()
set(SYNERGY_ADD_HEADERS TRUE)
set(ADD_HEADERS_TO_SOURCES TRUE)
endif()
set(BIN_TEMP_DIR ${CMAKE_BINARY_DIR}/temp/bin)
endmacro()
macro(configure_ninja)

View File

@ -361,3 +361,11 @@ macro(update_submodules)
endif()
endmacro()
macro(configure_python)
if(WIN32)
set(PYTHON_BIN "${CMAKE_BINARY_DIR}/python/Scripts/python.exe")
else()
set(PYTHON_BIN "${CMAKE_BINARY_DIR}/python/bin/python")
endif()
endmacro()

41
scripts/fancy_copy.py Normal file
View File

@ -0,0 +1,41 @@
#!/usr/bin/env python3
import argparse
import lib.env as env
import lib.file_utils as file_utils
def main():
"""
Cross platform script to copy files and directories.
This script was mostly created beause the default `copy` command on Windows is too noisy.
If this becomes complex it must be replaced with a library.
"""
# important: load venv before loading modules that install deps.
env.ensure_in_venv(__file__)
parser = argparse.ArgumentParser()
parser.add_argument("source", help="Source pattern to copy from")
parser.add_argument("target", help="Destination pattern to copy to")
parser.add_argument(
"--ignore-errors", action="store_true", help="Ignore errors when copying"
)
parser.add_argument(
"--verbose", action="store_true", help="Print more information to the console"
)
args = parser.parse_args()
options = file_utils.CopyOptions(args.ignore_errors, args.verbose)
try:
file_utils.copy(args.source, args.target, options)
except Exception as e:
if not args.ignore_errors:
raise e
else:
print(f"Error: {e}")
if __name__ == "__main__":
main()

80
scripts/lib/file_utils.py Normal file
View File

@ -0,0 +1,80 @@
import glob, os, shutil, sys
import colorama # type: ignore
from colorama import Fore # type: ignore
colorama.init()
class CopyOptions:
def __init__(self, ignore_errors, verbose):
self.ignore_errors = ignore_errors
self.verbose = verbose
class CopyContext:
def __init__(self):
self.errors = 0
self.permission_error = False
def copy(source, target, options):
"""Copy files and directories from source to target."""
context = CopyContext()
if options.verbose:
print(f"Copying files from {source} to {target}")
for match in glob.glob(source):
if os.path.isfile(match):
copy_file(match, target, options, context)
elif os.path.isdir(match):
copy_dir(match, target, options, context)
else:
raise RuntimeError(f"Path {match} is not a file or directory")
if context.errors and options.ignore_errors:
print(
f"{Fore.YELLOW}WARNING:{Fore.RESET} Ignored {context.errors} copy error(s)"
)
if context.permission_error:
print(
f"{Fore.BLUE}HINT:{Fore.RESET} A permission error may mean that the file is in use"
)
def copy_dir(match, target, options, context):
if options.verbose:
print(f"Copying directory {match} to {target}")
try:
shutil.copytree(match, target, dirs_exist_ok=True)
except PermissionError as e:
context.permission_error = True
handle_copy_error(e, options, context)
except Exception as e:
handle_copy_error(e, options, context)
def copy_file(match, target, options, context):
if options.verbose:
print(f"Copying file {match} to {target}")
try:
shutil.copy(match, target)
except PermissionError as e:
context.permission_error = True
handle_copy_error(e, options, context)
except Exception as e:
handle_copy_error(e, options, context)
def handle_copy_error(e, options, context):
context.errors += 1
if not options.ignore_errors:
raise e
else:
print(f"{Fore.YELLOW}WARNING:{Fore.RESET} Copy failed: {e}", file=sys.stderr)

View File

@ -1,14 +1,13 @@
import os
import subprocess
import sys
import argparse
import glob
import os, sys, time, subprocess, argparse, glob
import lib.windows as windows
import lib.file_utils as file_utils
import psutil
BIN_NAME = "synergyd"
SOURCE_BIN_DIR = os.path.join("build", "bin")
TARGET_BIN_DIR = "bin"
DEFAULT_BIN_NAME = "synergyd"
DEFAULT_SOURCE_DIR = os.path.join("build", "temp", "bin")
DEFAULT_TARGET_DIR = os.path.join("build", "bin")
SERVICE_NOT_RUNNING_ERROR = 2
ERROR_ACCESS_VIOLATION = 0xC0000005
def main():
@ -16,10 +15,9 @@ def main():
parser = argparse.ArgumentParser()
parser.add_argument("--pause-on-exit", action="store_true")
parser.add_argument("--source-bin-dir", default=SOURCE_BIN_DIR)
parser.add_argument("--target-bin-dir", default=TARGET_BIN_DIR)
parser.add_argument("--source-bin-name", default=BIN_NAME)
parser.add_argument("--target-bin-name", default=BIN_NAME)
parser.add_argument("--source-dir", default=DEFAULT_SOURCE_DIR)
parser.add_argument("--target-dir", default=DEFAULT_TARGET_DIR)
parser.add_argument("--bin-name", default=DEFAULT_BIN_NAME)
args = parser.parse_args()
if not windows.is_admin():
@ -28,19 +26,18 @@ def main():
try:
reinstall(
args.source_bin_dir,
args.target_bin_dir,
args.source_bin_name,
args.target_bin_name,
args.source_dir,
args.target_dir,
args.bin_name,
)
except Exception as e:
print(f"Error: {e}")
print(f"Error: {e}", file=sys.stderr)
if args.pause_on_exit:
input("Press enter to continue...")
def reinstall(source_bin_dir, target_bin_dir, source_bin_name, target_bin_name):
def reinstall(source_dir, target_dir, bin_name):
"""Stops the running daemon service, copies files, and reinstalls."""
print("Stopping daemon service")
@ -52,43 +49,64 @@ def reinstall(source_bin_dir, target_bin_dir, source_bin_name, target_bin_name):
else:
raise e
copy_bin_files(source_bin_dir, target_bin_dir, source_bin_name, target_bin_name)
source_bin_path = f"{os.path.join(source_dir, bin_name)}.exe"
target_bin_file = f"{os.path.join(target_bin_dir, target_bin_name)}.exe"
# Wait for Windows to release the file handles after process termination.
while is_any_process_running(target_dir):
print("Waiting for file handles to release")
time.sleep(1)
options = file_utils.CopyOptions(ignore_errors=True, verbose=False)
print(f"Copying files from {source_dir} to {target_dir}")
file_utils.copy(f"{source_dir}/*", target_dir, options)
print("Removing old daemon service")
subprocess.run([target_bin_file, "/uninstall"], shell=True, check=True)
try:
subprocess.run([source_bin_path, "/uninstall"], shell=True, check=True)
except subprocess.CalledProcessError as e:
check_access_violation(e.returncode, source_bin_path)
if e.returncode != 0:
print(
f"Warning: Uninstall failed, return code: {e.returncode}",
file=sys.stderr,
)
print("Installing daemon service")
subprocess.run([target_bin_file, "/install"], shell=True, check=True)
target_bin_path = os.path.join(target_dir, bin_name + ".exe")
try:
print("Installing daemon service")
subprocess.run([target_bin_path, "/install"], shell=True, check=True)
except subprocess.CalledProcessError as e:
check_access_violation(e.returncode, target_bin_path)
if e.returncode != 0:
print(f"Warning: Install failed, return code: {e.returncode}")
def copy_bin_files(source_bin_dir, target_bin_dir, source_bin_name, target_bin_name):
if not os.path.isdir(source_bin_dir):
raise RuntimeError(f"Invalid source bin dir: {source_bin_dir}")
print(f"Persisting dir: {target_bin_dir}")
os.makedirs(target_bin_dir, exist_ok=True)
source_bin_glob = f"{source_bin_name}*"
source_files = glob.glob(os.path.join(source_bin_dir, source_bin_glob))
if not source_files:
raise RuntimeError(
f"No files found in {source_bin_dir} matching {source_bin_glob}"
def check_access_violation(return_code, bin_path):
if return_code == ERROR_ACCESS_VIOLATION:
print(
f"Warning: Process crashed with memory access violation: {bin_path}",
file=sys.stderr,
)
for source_file in source_files:
base_name = os.path.basename(source_file)
base_name = base_name.replace(source_bin_name, target_bin_name)
target_file = os.path.join(target_bin_dir, base_name)
print(f"Copying {source_file} to {target_file}")
# use the copy command; shutil.copy gives us a permission denied error.
def is_any_process_running(dir):
"""Check if there is any running process that contains the given directory."""
print(f"Checking if any process is running in: {dir}")
for proc in psutil.process_iter(attrs=["name", "exe"]):
exe = proc.info["exe"]
if not exe:
continue
try:
subprocess.run(["copy", source_file, target_file], shell=True, check=True)
except subprocess.CalledProcessError as e:
print(f"Copy failed: {e}")
if dir.lower() in exe.lower():
print(f"Process found: {exe}")
return True
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
return False
main()

View File

@ -44,7 +44,7 @@ endif()
list(APPEND sources ${arch_sources})
list(APPEND headers ${arch_headers})
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()
@ -69,3 +69,5 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(TARGETS ${target} DESTINATION bin)
endif()
post_config()

View File

@ -38,3 +38,5 @@ target_link_libraries(
synlib
shared
${libs})
post_config()

View File

@ -44,7 +44,7 @@ endif()
list(APPEND sources ${arch_sources})
list(APPEND headers ${arch_headers})
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()
@ -69,3 +69,5 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(TARGETS ${target} DESTINATION bin)
endif()
post_config()

View File

@ -1,3 +1,20 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package 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, see <http://www.gnu.org/licenses/>.
set(target synergy)
find_package(
Qt6
COMPONENTS Core Widgets Network
@ -33,7 +50,7 @@ if(WIN32)
endif()
add_executable(
synergy WIN32
${target} WIN32
${GUI_SOURCE_FILES}
${GUI_UI_FILES}
${GUI_RC_FILES}
@ -41,16 +58,16 @@ add_executable(
${QM_FILES})
include_directories(./src)
target_link_libraries(synergy shared)
target_link_libraries(${target} shared)
target_link_libraries(synergy Qt6::Core Qt6::Widgets Qt6::Network)
target_link_libraries(${target} Qt6::Core Qt6::Widgets Qt6::Network)
target_compile_definitions(
synergy PRIVATE -DSYNERGY_VERSION_STAGE="${SYNERGY_VERSION_STAGE}")
target_compile_definitions(synergy
${target} PRIVATE -DSYNERGY_VERSION_STAGE="${SYNERGY_VERSION_STAGE}")
target_compile_definitions(${target}
PRIVATE -DSYNERGY_REVISION="${SYNERGY_REVISION}")
if(WIN32)
set_target_properties(synergy PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT")
set_target_properties(${target} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT")
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@ -61,13 +78,13 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(MACDEPLOYQT_CMD
"${MACDEPLOYQT_BIN} ${SYNERGY_BUNDLE_APP_DIR} -always-overwrite")
install(TARGETS synergy DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
install(TARGETS ${target} DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
install(CODE "MESSAGE (\"Running: ${MACDEPLOYQT_CMD}\")")
install(CODE "execute_process(COMMAND ${MACDEPLOYQT_CMD})")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(TARGETS synergy DESTINATION bin)
install(TARGETS ${target} DESTINATION bin)
elseif(WIN32)
@ -96,7 +113,7 @@ elseif(WIN32)
if(TARGET Qt6::windeployqt)
# execute windeployqt in a tmp directory after build
add_custom_command(
TARGET synergy
TARGET ${target}
POST_BUILD
COMMAND set PATH=%PATH%$<SEMICOLON>${qt6_install_prefix}/bin
COMMAND Qt6::windeployqt
@ -104,3 +121,5 @@ elseif(WIN32)
endif()
endif()
post_config()

View File

@ -22,8 +22,8 @@
// command line argument to synergy core, determines if the server restarts
// when switching Windows desktops (e.g. when Windows UAC dialog pops up).
// The second, passed as a boolean flag to Synergyd over the IPC inside
// kIpcCommandMessage, determines whether Synergy should be started with
// elevated privileges.
// IpcMessageType::CommandMessage, determines whether Synergy should be started
// with elevated privileges.
//
// The matrix for these two behaviours is as follows:
// SodS Elevate

View File

@ -17,7 +17,7 @@
*/
#include "IpcReader.h"
#include "Ipc.h"
#include "shared/Ipc.h"
#include <QByteArray>
#include <QMutex>
#include <QTcpSocket>

View File

@ -31,13 +31,12 @@
#include "AppConfig.h"
#include "ClientConnection.h"
#include "ConfigWriter.h"
#include "Ipc.h"
#include "QIpcClient.h"
#include "ServerConfig.h"
#include "ServerConnection.h"
#include "VersionChecker.h"
#include "TrayIcon.h"
#include "VersionChecker.h"
#include "shared/Ipc.h"
class QAction;
class QMenu;
@ -169,8 +168,7 @@ protected:
bool clientArgs(QStringList &args, QString &app);
bool serverArgs(QStringList &args, QString &app);
void setStatus(const QString &status);
void
sendIpcMessage(qIpcMessageType type, const char *buffer, bool showErrors);
void sendIpcMessage(IpcMessageType type, const char *buffer, bool showErrors);
void updateFromLogLine(const QString &line);
QString getIPAddresses();
void stopService();

View File

@ -16,12 +16,13 @@
*/
#include "QIpcClient.h"
#include "Ipc.h"
#include "IpcReader.h"
#include "shared/Ipc.h"
#include <QDataStream>
#include <QHostAddress>
#include <QTimer>
#include <qglobal.h>
QIpcClient::QIpcClient(const StreamProvider &streamProvider)
: m_ReaderStarted(false),
@ -61,7 +62,8 @@ void QIpcClient::connectToHost() {
m_Enabled = true;
infoMessage("connecting to service...");
m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT);
const auto port = static_cast<quint16>(kIpcPort);
m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), port);
if (!m_ReaderStarted) {
m_Reader->start();
@ -105,7 +107,7 @@ void QIpcClient::sendHello() {
stream->writeRawData(kIpcMsgHello, 4);
char typeBuf[1];
typeBuf[0] = kIpcClientGui;
typeBuf[0] = static_cast<char>(IpcClientType::GUI);
stream->writeRawData(typeBuf, 1);
}

View File

@ -17,7 +17,7 @@
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()
@ -33,7 +33,7 @@ endif()
list(APPEND sources ${arch_sources})
list(APPEND headers ${arch_headers})
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -17,7 +17,7 @@
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -212,40 +212,3 @@ void FileLogOutputter::open(const char *title) {}
void FileLogOutputter::close() {}
void FileLogOutputter::show(bool showIfEmpty) {}
//
// MesssageBoxLogOutputter
//
MesssageBoxLogOutputter::MesssageBoxLogOutputter() {
// do nothing
}
MesssageBoxLogOutputter::~MesssageBoxLogOutputter() {
// do nothing
}
void MesssageBoxLogOutputter::open(const char *title) {
// do nothing
}
void MesssageBoxLogOutputter::close() {
// do nothing
}
void MesssageBoxLogOutputter::show(bool showIfEmpty) {
// do nothing
}
bool MesssageBoxLogOutputter::write(ELevel level, const char *msg) {
// don't spam user with messages.
if (level > kERROR) {
return true;
}
#if SYSAPI_WIN32
MessageBox(NULL, msg, CLOG->getFilterName(level), MB_OK);
#endif
return true;
}

View File

@ -160,19 +160,3 @@ private:
UInt32 m_maxBufferSize;
Buffer m_buffer;
};
//! Write log to message box
/*!
The level for each message is ignored.
*/
class MesssageBoxLogOutputter : public ILogOutputter {
public:
MesssageBoxLogOutputter();
virtual ~MesssageBoxLogOutputter();
// ILogOutputter overrides
virtual void open(const char *title);
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char *message);
};

View File

@ -17,7 +17,7 @@
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -17,7 +17,7 @@
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -17,7 +17,7 @@
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -17,7 +17,7 @@
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,16 +17,16 @@
#include "ipc/IpcClient.h"
#include "base/TMethodEventJob.h"
#include "ipc/Ipc.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServerProxy.h"
#include "shared/Ipc.h"
//
// IpcClient
//
IpcClient::IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer)
: m_serverAddress(NetworkAddress(IPC_HOST, IPC_PORT)),
: m_serverAddress(NetworkAddress(kIpcHost, kIpcPort)),
m_socket(events, socketMultiplexer),
m_server(nullptr),
m_events(events) {
@ -36,7 +35,7 @@ IpcClient::IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer)
IpcClient::IpcClient(
IEventQueue *events, SocketMultiplexer *socketMultiplexer, int port)
: m_serverAddress(NetworkAddress(IPC_HOST, port)),
: m_serverAddress(NetworkAddress(kIpcHost, port)),
m_socket(events, socketMultiplexer),
m_server(nullptr),
m_events(events) {
@ -81,7 +80,7 @@ void IpcClient::handleConnected(const Event &, void *) {
m_events->forIpcClient().connected(), this, m_server,
Event::kDontFreeData));
IpcHelloMessage message(kIpcClientNode);
IpcHelloMessage message(IpcClientType::Node);
send(message);
}

View File

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,13 +17,12 @@
#include "ipc/IpcClientProxy.h"
#include "arch/Arch.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "io/IStream.h"
#include "ipc/Ipc.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcSettingMessage.h"
#include "shared/Ipc.h"
#include "synergy/ProtocolUtil.h"
//
@ -33,10 +31,6 @@
IpcClientProxy::IpcClientProxy(synergy::IStream &stream, IEventQueue *events)
: m_stream(stream),
m_clientType(kIpcClientUnknown),
m_disconnecting(false),
m_readMutex(ARCH->newMutex()),
m_writeMutex(ARCH->newMutex()),
m_events(events) {
m_events->adoptHandler(
m_events->forIStream().inputReady(), stream.getEventTarget(),
@ -135,7 +129,7 @@ void IpcClientProxy::send(const IpcMessage &message) {
LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
switch (message.type()) {
case kIpcLogLine: {
case IpcMessageType::LogLine: {
const IpcLogLineMessage &llm =
static_cast<const IpcLogLineMessage &>(message);
const String logLine = llm.logLine();
@ -143,11 +137,11 @@ void IpcClientProxy::send(const IpcMessage &message) {
break;
}
case kIpcShutdown:
case IpcMessageType::Shutdown:
ProtocolUtil::writef(&m_stream, kIpcMsgShutdown);
break;
case kIpcHelloBack:
case IpcMessageType::HelloBack:
ProtocolUtil::writef(&m_stream, kIpcMsgHelloBack);
break;
@ -161,7 +155,7 @@ IpcHelloMessage *IpcClientProxy::parseHello() {
UInt8 type;
ProtocolUtil::readf(&m_stream, kIpcMsgHello + 4, &type);
m_clientType = static_cast<EIpcClientType>(type);
m_clientType = static_cast<IpcClientType>(type);
// must be deleted by event handler.
return new IpcHelloMessage(m_clientType);

View File

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,10 +17,11 @@
#pragma once
#include "arch/Arch.h"
#include "arch/IArchMultithread.h"
#include "base/Event.h"
#include "base/EventTypes.h"
#include "ipc/Ipc.h"
#include "shared/Ipc.h"
namespace synergy {
class IStream;
@ -56,9 +56,9 @@ private:
private:
synergy::IStream &m_stream;
EIpcClientType m_clientType;
bool m_disconnecting;
ArchMutex m_readMutex;
ArchMutex m_writeMutex;
IEventQueue *m_events;
IpcClientType m_clientType = IpcClientType::Unknown;
bool m_disconnecting = false;
ArchMutex m_readMutex = ARCH->newMutex();
ArchMutex m_writeMutex = ARCH->newMutex();
};

View File

@ -24,11 +24,11 @@
#include "base/EventQueue.h"
#include "base/TMethodEventJob.h"
#include "base/TMethodJob.h"
#include "ipc/Ipc.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServer.h"
#include "mt/Thread.h"
#include "shared/Ipc.h"
enum EIpcLogOutputter {
kBufferMaxSize = 1000,
@ -38,7 +38,7 @@ enum EIpcLogOutputter {
};
IpcLogOutputter::IpcLogOutputter(
IpcServer &ipcServer, EIpcClientType clientType, bool useThread)
IpcServer &ipcServer, IpcClientType clientType, bool useThread)
: m_ipcServer(ipcServer),
m_bufferMutex(ARCH->newMutex()),
m_sending(false),
@ -179,7 +179,7 @@ void IpcLogOutputter::sendBuffer() {
IpcLogLineMessage message(getChunk(kMaxSendLines));
m_sending = true;
m_ipcServer.send(message, kIpcClientGui);
m_ipcServer.send(message, IpcClientType::GUI);
m_sending = false;
}

View File

@ -21,7 +21,7 @@
#include "arch/Arch.h"
#include "arch/IArchMultithread.h"
#include "base/ILogOutputter.h"
#include "ipc/Ipc.h"
#include "shared/Ipc.h"
#include <deque>
@ -41,7 +41,7 @@ public:
using the \c sendBuffer() function.
*/
IpcLogOutputter(
IpcServer &ipcServer, EIpcClientType clientType, bool useThread);
IpcServer &ipcServer, IpcClientType clientType, bool useThread);
IpcLogOutputter(IpcLogOutputter const &) = delete;
virtual ~IpcLogOutputter();
@ -115,6 +115,6 @@ private:
double m_bufferRateTimeLimit;
UInt16 m_bufferWriteCount;
double m_bufferRateStart;
EIpcClientType m_clientType;
IpcClientType m_clientType;
ArchMutex m_runningMutex;
};

View File

@ -17,35 +17,25 @@
*/
#include "ipc/IpcMessage.h"
#include "ipc/Ipc.h"
#include "shared/Ipc.h"
IpcMessage::IpcMessage(UInt8 type) : m_type(type) {}
IpcMessage::IpcMessage(IpcMessageType type) : m_type(type) {}
IpcMessage::~IpcMessage() {}
IpcHelloMessage::IpcHelloMessage(EIpcClientType clientType)
: IpcMessage(kIpcHello),
IpcHelloMessage::IpcHelloMessage(IpcClientType clientType)
: IpcMessage(IpcMessageType::Hello),
m_clientType(clientType) {}
IpcHelloMessage::~IpcHelloMessage() {}
IpcHelloBackMessage::IpcHelloBackMessage()
: IpcMessage(IpcMessageType::HelloBack) {}
IpcHelloBackMessage::IpcHelloBackMessage() : IpcMessage(kIpcHelloBack) {}
IpcHelloBackMessage::~IpcHelloBackMessage() {}
IpcShutdownMessage::IpcShutdownMessage() : IpcMessage(kIpcShutdown) {}
IpcShutdownMessage::~IpcShutdownMessage() {}
IpcShutdownMessage::IpcShutdownMessage()
: IpcMessage(IpcMessageType::Shutdown) {}
IpcLogLineMessage::IpcLogLineMessage(const String &logLine)
: IpcMessage(kIpcLogLine),
: IpcMessage(IpcMessageType::LogLine),
m_logLine(logLine) {}
IpcLogLineMessage::~IpcLogLineMessage() {}
IpcCommandMessage::IpcCommandMessage(const String &command, bool elevate)
: IpcMessage(kIpcCommand),
: IpcMessage(IpcMessageType::Command),
m_command(command),
m_elevate(elevate) {}
IpcCommandMessage::~IpcCommandMessage() {}

View File

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -19,52 +18,51 @@
#pragma once
#include "base/Event.h"
#include "base/EventTypes.h"
#include "base/String.h"
#include "ipc/Ipc.h"
#include "shared/Ipc.h"
class IpcMessage : public EventData {
public:
virtual ~IpcMessage();
~IpcMessage() override = default;
//! Gets the message type ID.
UInt8 type() const { return m_type; }
IpcMessageType type() const { return m_type; }
protected:
IpcMessage(UInt8 type);
explicit IpcMessage(IpcMessageType type);
private:
UInt8 m_type;
IpcMessageType m_type;
};
class IpcHelloMessage : public IpcMessage {
public:
IpcHelloMessage(EIpcClientType clientType);
virtual ~IpcHelloMessage();
explicit IpcHelloMessage(IpcClientType clientType);
~IpcHelloMessage() override = default;
//! Gets the message type ID.
EIpcClientType clientType() const { return m_clientType; }
IpcClientType clientType() const { return m_clientType; }
private:
EIpcClientType m_clientType;
IpcClientType m_clientType;
};
class IpcHelloBackMessage : public IpcMessage {
public:
IpcHelloBackMessage();
virtual ~IpcHelloBackMessage();
explicit IpcHelloBackMessage();
~IpcHelloBackMessage() override = default;
};
class IpcShutdownMessage : public IpcMessage {
public:
IpcShutdownMessage();
virtual ~IpcShutdownMessage();
explicit IpcShutdownMessage();
~IpcShutdownMessage() override = default;
};
class IpcLogLineMessage : public IpcMessage {
public:
IpcLogLineMessage(const String &logLine);
virtual ~IpcLogLineMessage();
explicit IpcLogLineMessage(const String &logLine);
~IpcLogLineMessage() override = default;
//! Gets the log line.
String logLine() const { return m_logLine; }
@ -75,8 +73,8 @@ private:
class IpcCommandMessage : public IpcMessage {
public:
IpcCommandMessage(const String &command, bool elevate);
virtual ~IpcCommandMessage();
explicit IpcCommandMessage(const String &command, bool elevate);
~IpcCommandMessage() override = default;
//! Gets the command.
String command() const { return m_command; }

View File

@ -23,10 +23,10 @@
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "io/IStream.h"
#include "ipc/Ipc.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
#include "net/IDataSocket.h"
#include "shared/Ipc.h"
//
// IpcServer
@ -37,7 +37,7 @@ IpcServer::IpcServer(IEventQueue *events, SocketMultiplexer *socketMultiplexer)
m_events(events),
m_socketMultiplexer(socketMultiplexer),
m_socket(nullptr),
m_address(NetworkAddress(IPC_HOST, IPC_PORT)) {
m_address(NetworkAddress(kIpcHost, kIpcPort)) {
init();
}
@ -46,7 +46,7 @@ IpcServer::IpcServer(
: m_mock(false),
m_events(events),
m_socketMultiplexer(socketMultiplexer),
m_address(NetworkAddress(IPC_HOST, port)) {
m_address(NetworkAddress(kIpcHost, port)) {
init();
}
@ -135,7 +135,7 @@ void IpcServer::deleteClient(IpcClientProxy *proxy) {
delete proxy;
}
bool IpcServer::hasClients(EIpcClientType clientType) const {
bool IpcServer::hasClients(IpcClientType clientType) const {
ArchMutexLock lock(m_clientsMutex);
if (m_clients.empty()) {
@ -155,7 +155,7 @@ bool IpcServer::hasClients(EIpcClientType clientType) const {
return false;
}
void IpcServer::send(const IpcMessage &message, EIpcClientType filterType) {
void IpcServer::send(const IpcMessage &message, IpcClientType filterType) {
ArchMutexLock lock(m_clientsMutex);
ClientList::iterator it;

View File

@ -20,9 +20,9 @@
#include "arch/Arch.h"
#include "base/EventTypes.h"
#include "ipc/Ipc.h"
#include "net/NetworkAddress.h"
#include "net/TCPListenSocket.h"
#include "shared/Ipc.h"
#include <list>
@ -58,14 +58,14 @@ public:
virtual void listen();
//! Send a message to all clients matching the filter type.
virtual void send(const IpcMessage &message, EIpcClientType filterType);
virtual void send(const IpcMessage &message, IpcClientType filterType);
//@}
//! @name accessors
//@{
//! Returns true when there are clients of the specified type connected.
virtual bool hasClients(EIpcClientType clientType) const;
virtual bool hasClients(IpcClientType clientType) const;
//@}

View File

@ -21,8 +21,8 @@
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "io/IStream.h"
#include "ipc/Ipc.h"
#include "ipc/IpcMessage.h"
#include "shared/Ipc.h"
#include "synergy/ProtocolUtil.h"
//
@ -78,13 +78,13 @@ void IpcServerProxy::send(const IpcMessage &message) {
LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
switch (message.type()) {
case kIpcHello: {
case IpcMessageType::Hello: {
const IpcHelloMessage &hm = static_cast<const IpcHelloMessage &>(message);
ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType());
break;
}
case kIpcCommand: {
case IpcMessageType::Command: {
const IpcCommandMessage &cm =
static_cast<const IpcCommandMessage &>(message);
const String command = cm.command();

View File

@ -20,7 +20,7 @@
IpcSettingMessage::IpcSettingMessage(
const std::string &name, const std::string &value)
: IpcMessage(kIpcSetting),
: IpcMessage(IpcMessageType::Setting),
m_name(name),
m_value(value) {}

View File

@ -17,7 +17,7 @@
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -17,7 +17,7 @@
file(GLOB headers "*.h" "InverseSockets/*.h")
file(GLOB sources "*.cpp" "InverseSockets/*.cpp")
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -31,7 +31,7 @@ elseif(UNIX)
file(GLOB sources "XWindows*.cpp")
endif()
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -23,11 +23,11 @@
#include "base/Log.h"
#include "base/TMethodJob.h"
#include "base/log_outputters.h"
#include "ipc/Ipc.h"
#include "ipc/IpcLogOutputter.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServer.h"
#include "mt/Thread.h"
#include "shared/Ipc.h"
#include "synergy/App.h"
#include "synergy/ArgsBase.h"
@ -510,7 +510,7 @@ void MSWindowsWatchdog::shutdownProcess(HANDLE handle, DWORD pid, int timeout) {
}
IpcShutdownMessage shutdown;
m_ipcServer.send(shutdown, kIpcClientNode);
m_ipcServer.send(shutdown, IpcClientType::Node);
// wait for process to exit gracefully.
double start = ARCH->time();

View File

@ -21,8 +21,8 @@
#include "arch/Arch.h"
#include "base/Log.h"
#include "base/Stopwatch.h"
#include "common/basic_types.h"
#include "common/stdvector.h"
#include "mt/Thread.h"
#include "platform/XWindowsClipboardBMPConverter.h"
#include "platform/XWindowsClipboardHTMLConverter.h"
#include "platform/XWindowsClipboardTextConverter.h"
@ -534,13 +534,13 @@ bool XWindowsClipboard::icccmGetSelection(
assert(data != nullptr);
// request data conversion
CICCCMGetClipboard getter(m_window, m_time, m_atomData);
if (!getter.readClipboard(
if (CICCCMGetClipboard getter(m_window, m_time, m_atomData);
!getter.readClipboard(
m_display, m_selection, target, actualTarget, data)) {
LOG(
(CLOG_DEBUG1 "can't get data for selection target %s",
XWindowsUtil::atomToString(m_display, target).c_str()));
LOGC(getter.m_error, (CLOG_WARN "icccm violation by clipboard owner"));
LOGC(getter.error(), (CLOG_WARN "icccm violation by clipboard owner"));
return false;
} else if (*actualTarget == None) {
LOG(
@ -630,7 +630,7 @@ bool XWindowsClipboard::motifOwnsClipboard() const {
if (data.size() >= sizeof(MotifClipHeader)) {
MotifClipHeader header;
std::memcpy(&header, data.data(), sizeof(header));
if ((header.m_id == kMotifClipHeader) &&
if ((header.m_id == MotifClip::Header) &&
(static_cast<Window>(header.m_selectionOwner) == owner)) {
return true;
}
@ -658,7 +658,7 @@ void XWindowsClipboard::motifFillCache() {
return;
}
std::memcpy(&header, data.data(), sizeof(header));
if (header.m_id != kMotifClipHeader || header.m_numItems < 1) {
if (header.m_id != MotifClip::Header || header.m_numItems < 1) {
return;
}
@ -678,7 +678,7 @@ void XWindowsClipboard::motifFillCache() {
return;
}
std::memcpy(&item, data.data(), sizeof(item));
if (item.m_id != kMotifClipItem ||
if (item.m_id != MotifClip::Item ||
item.m_numFormats - item.m_numDeletedFormats < 1) {
return;
}
@ -707,7 +707,7 @@ void XWindowsClipboard::motifFillCache() {
continue;
}
std::memcpy(&motifFormat, data.data(), sizeof(motifFormat));
if (motifFormat.m_id != kMotifClipFormat || motifFormat.m_length < 0 ||
if (motifFormat.m_id != MotifClip::Format || motifFormat.m_length < 0 ||
motifFormat.m_type == None || motifFormat.m_deleted != 0) {
continue;
}
@ -1197,18 +1197,7 @@ XWindowsClipboard::CICCCMGetClipboard::CICCCMGetClipboard(
Window requestor, Time time, Atom property)
: m_requestor(requestor),
m_time(time),
m_property(property),
m_incr(false),
m_failed(false),
m_done(false),
m_reading(false),
m_error(false) {
// do nothing
}
XWindowsClipboard::CICCCMGetClipboard::~CICCCMGetClipboard() {
// do nothing
}
m_property(property) {}
bool XWindowsClipboard::CICCCMGetClipboard::readClipboard(
Display *display, Atom selection, Atom target, Atom *actualTarget,

View File

@ -132,6 +132,7 @@ private:
void fillCache() const;
void doFillCache();
protected:
//
// helper classes
//
@ -140,7 +141,7 @@ private:
class CICCCMGetClipboard {
public:
CICCCMGetClipboard(Window requestor, Time time, Atom property);
~CICCCMGetClipboard();
~CICCCMGetClipboard() = default;
// convert the given selection to the given type. returns
// true iff the conversion was successful or the conversion
@ -156,16 +157,16 @@ private:
Window m_requestor;
Time m_time;
Atom m_property;
bool m_incr;
bool m_failed;
bool m_done;
bool m_incr = false;
bool m_failed = false;
bool m_done = false;
// atoms needed for the protocol
Atom m_atomNone; // NONE, not None
Atom m_atomIncr;
Atom m_atomNone = None;
Atom m_atomIncr = None;
// true iff we've received the selection notify
bool m_reading;
bool m_reading = false;
// the converted selection data
String *m_data = nullptr;
@ -174,18 +175,20 @@ private:
// selection owner cannot convert to the requested type.
Atom *m_actualTarget = nullptr;
public:
// true iff the selection owner didn't follow ICCCM conventions
bool m_error;
bool m_error = false;
public:
bool error() const { return m_error; }
};
// Motif structure IDs
enum { kMotifClipFormat = 1, kMotifClipItem, kMotifClipHeader };
enum class MotifClip : SInt32 { Format = 1, Item = 2, Header = 3 };
// _MOTIF_CLIP_HEADER structure
class MotifClipHeader {
public:
SInt32 m_id; // kMotifClipHeader
MotifClip m_id;
SInt32 m_pad1[3];
SInt32 m_item;
SInt32 m_pad2[4];
@ -198,7 +201,7 @@ private:
// Motif clip item structure
class MotifClipItem {
public:
SInt32 m_id; // kMotifClipItem
MotifClip m_id;
SInt32 m_pad1[5];
SInt32 m_size;
SInt32 m_numFormats;
@ -209,7 +212,7 @@ private:
// Motif clip format structure
class MotifClipFormat {
public:
SInt32 m_id; // kMotifClipFormat
MotifClip m_id;
SInt32 m_pad1[6];
SInt32 m_length;
SInt32 m_data;

View File

@ -17,7 +17,7 @@
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -17,7 +17,7 @@
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -16,11 +15,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ipc/Ipc.h"
#include "Ipc.h"
const char *kIpcMsgHello = "IHEL%1i";
const char *kIpcMsgHelloBack = "IHEL";
const char *kIpcMsgLogLine = "ILOG%s";
const char *kIpcMsgCommand = "ICMD%s%1i";
const char *kIpcMsgShutdown = "ISDN";
const char *kIpcMsgSetting = "SSET%s%s";
const char *const kIpcHost = "127.0.0.1";
const int kIpcPort = 24801;
const char *const kIpcMsgHello = "IHEL%1i";
const char *const kIpcMsgHelloBack = "IHEL";
const char *const kIpcMsgLogLine = "ILOG%s";
const char *const kIpcMsgCommand = "ICMD%s%1i";
const char *const kIpcMsgShutdown = "ISDN";
const char *const kIpcMsgSetting = "SSET%s%s";

View File

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,42 +17,44 @@
#pragma once
#define IPC_HOST "127.0.0.1"
#define IPC_PORT 24801
#include "common/basic_types.h"
enum EIpcMessage {
kIpcHello,
kIpcHelloBack,
kIpcLogLine,
kIpcCommand,
kIpcShutdown,
kIpcSetting
enum class IpcMessageType : UInt8 {
Hello,
HelloBack,
LogLine,
Command,
Shutdown,
Setting
};
enum EIpcClientType { kIpcClientUnknown, kIpcClientGui, kIpcClientNode };
enum class IpcClientType { Unknown, GUI, Node };
extern const char *const kIpcHost;
extern const int kIpcPort;
// handshake: node/gui -> daemon
// $1 = type, the client identifies it's self as gui or node (synergyc/s).
extern const char *kIpcMsgHello;
extern const char *const kIpcMsgHello;
// handshake: daemon -> node/gui
// the daemon responds to the handshake.
extern const char *kIpcMsgHelloBack;
extern const char *const kIpcMsgHelloBack;
// log line: daemon -> gui
// $1 = aggregate log lines collected from synergys/c or the daemon itself.
extern const char *kIpcMsgLogLine;
extern const char *const kIpcMsgLogLine;
// command: gui -> daemon
// $1 = command; the command for the daemon to launch, typically the full
// path to synergys/c. $2 = true when process must be elevated on ms windows.
extern const char *kIpcMsgCommand;
extern const char *const kIpcMsgCommand;
// shutdown: daemon -> node
// the daemon tells synergys/c to shut down gracefully.
extern const char *kIpcMsgShutdown;
extern const char *const kIpcMsgShutdown;
// set setting: gui -> daemon
// $1 = setting name
// $2 = setting value
extern const char *kIpcMsgSetting;
extern const char *const kIpcMsgSetting;

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
@ -27,9 +27,9 @@
#include "base/XBase.h"
#include "base/log_outputters.h"
#include "common/Version.h"
#include "ipc/Ipc.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServerProxy.h"
#include "shared/Ipc.h"
#include "synergy/ArgsBase.h"
#include "synergy/XSynergy.h"
#include "synergy/protocol_types.h"
@ -230,7 +230,7 @@ void App::cleanupIpcClient() {
void App::handleIpcMessage(const Event &e, void *) {
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
if (m->type() == kIpcShutdown) {
if (m->type() == IpcMessageType::Shutdown) {
LOG((CLOG_INFO "got ipc shutdown message"));
m_events->addEvent(Event(Event::kQuit));
}

View File

@ -39,7 +39,7 @@ endif()
list(APPEND sources ${arch_sources})
list(APPEND headers ${arch_headers})
if(SYNERGY_ADD_HEADERS)
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()

View File

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -25,41 +24,43 @@
#include "base/EventQueue.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "base/TMethodJob.h"
#include "base/log_outputters.h"
#include "ipc/Ipc.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcLogOutputter.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcSettingMessage.h"
#include "net/SocketMultiplexer.h"
#include "shared/Ipc.h"
#include "synergy/App.h"
#include "synergy/ArgParser.h"
#include "synergy/ClientArgs.h"
#include "synergy/ServerArgs.h"
#include "synergy/protocol_types.h"
#if SYSAPI_WIN32
#include "arch/win32/ArchMiscWindows.h"
#include "arch/win32/XArchWindows.h"
#include "platform/MSWindowsDebugOutputter.h"
#include "platform/MSWindowsEventQueueBuffer.h"
#include "platform/MSWindowsScreen.h"
#include "platform/MSWindowsWatchdog.h"
#include "synergy/Screen.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#endif
#elif SYSAPI_UNIX
#include <iostream>
#endif
#include <memory>
#include <sstream>
#include <string>
using namespace std;
const char *const kLogFilename = "synergyd.log";
namespace {
void updateSetting(const IpcMessage &message) {
try {
@ -84,7 +85,7 @@ bool isServerCommandLine(const std::vector<String> &cmd) {
} // namespace
DaemonApp *DaemonApp::s_instance = NULL;
DaemonApp *DaemonApp::s_instance = nullptr;
int mainLoopStatic() {
DaemonApp::s_instance->mainLoop(true);
@ -99,18 +100,9 @@ int winMainLoopStatic(int, const char **) {
}
#endif
DaemonApp::DaemonApp()
: m_ipcServer(nullptr),
m_ipcLogOutputter(nullptr),
#if SYSAPI_WIN32
m_watchdog(nullptr),
#endif
m_events(nullptr),
m_fileLogOutputter(nullptr) {
s_instance = this;
}
DaemonApp::DaemonApp() { s_instance = this; }
DaemonApp::~DaemonApp() {}
DaemonApp::~DaemonApp() { s_instance = nullptr; }
int DaemonApp::run(int argc, char **argv) {
#if SYSAPI_WIN32
@ -122,8 +114,7 @@ int DaemonApp::run(int argc, char **argv) {
arch.init();
Log log;
EventQueue events;
m_events = &events;
m_events = std::make_unique<EventQueue>();
bool uninstall = false;
try {
@ -134,8 +125,7 @@ int DaemonApp::run(int argc, char **argv) {
#endif
// default log level to system setting.
string logLevel = arch.setting("LogLevel");
if (logLevel != "")
if (string logLevel = arch.setting("LogLevel"); logLevel != "")
log.setFilter(logLevel.c_str());
bool foreground = false;
@ -210,8 +200,9 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground) {
DAEMON_RUNNING(true);
if (logToFile) {
m_fileLogOutputter = new FileLogOutputter(logFilename().c_str());
CLOG->insert(m_fileLogOutputter);
m_fileLogOutputter =
std::make_unique<FileLogOutputter>(logFilename().c_str());
CLOG->insert(m_fileLogOutputter.get());
}
// create socket multiplexer. this must happen after daemonization
@ -219,20 +210,21 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground) {
SocketMultiplexer multiplexer;
// uses event queue, must be created here.
m_ipcServer = new IpcServer(m_events, &multiplexer);
m_ipcServer = std::make_unique<IpcServer>(m_events.get(), &multiplexer);
// send logging to gui via ipc, log system adopts outputter.
m_ipcLogOutputter = new IpcLogOutputter(*m_ipcServer, kIpcClientGui, true);
CLOG->insert(m_ipcLogOutputter);
m_ipcLogOutputter = std::make_unique<IpcLogOutputter>(
*m_ipcServer, IpcClientType::GUI, true);
CLOG->insert(m_ipcLogOutputter.get());
#if SYSAPI_WIN32
m_watchdog = new MSWindowsWatchdog(
m_watchdog = std::make_unique<MSWindowsWatchdog>(
false, *m_ipcServer, *m_ipcLogOutputter, foreground);
m_watchdog->setFileLogOutputter(m_fileLogOutputter);
m_watchdog->setFileLogOutputter(m_fileLogOutputter.get());
#endif
m_events->adoptHandler(
m_events->forIpcServer().messageReceived(), m_ipcServer,
m_events->forIpcServer().messageReceived(), m_ipcServer.get(),
new TMethodEventJob<DaemonApp>(this, &DaemonApp::handleIpcMessage));
m_ipcServer->listen();
@ -240,7 +232,7 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground) {
#if SYSAPI_WIN32
// install the platform event queue to handle service stop events.
m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events));
m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events.get()));
String command = ARCH->setting("Command");
bool elevate = ARCH->setting("Elevate") == "1";
@ -255,15 +247,12 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground) {
#if SYSAPI_WIN32
m_watchdog->stop();
delete m_watchdog;
#endif
m_events->removeHandler(
m_events->forIpcServer().messageReceived(), m_ipcServer);
m_events->forIpcServer().messageReceived(), m_ipcServer.get());
CLOG->remove(m_ipcLogOutputter);
delete m_ipcLogOutputter;
delete m_ipcServer;
CLOG->remove(m_ipcLogOutputter.get());
DAEMON_RUNNING(false);
} catch (std::exception &e) {
@ -287,7 +276,7 @@ std::string DaemonApp::logFilename() {
if (logFilename.empty()) {
logFilename = ARCH->getLogDirectory();
logFilename.append("/");
logFilename.append(LOG_FILENAME);
logFilename.append(kLogFilename);
}
return logFilename;
@ -296,7 +285,7 @@ std::string DaemonApp::logFilename() {
void DaemonApp::handleIpcMessage(const Event &e, void *) {
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
switch (m->type()) {
case kIpcCommand: {
case IpcMessageType::Command: {
IpcCommandMessage *cm = static_cast<IpcCommandMessage *>(m);
String command = cm->command();
@ -361,14 +350,14 @@ void DaemonApp::handleIpcMessage(const Event &e, void *) {
break;
}
case kIpcHello: {
case IpcMessageType::Hello: {
IpcHelloMessage *hm = static_cast<IpcHelloMessage *>(m);
String type;
switch (hm->clientType()) {
case kIpcClientGui:
case IpcClientType::GUI:
type = "gui";
break;
case kIpcClientNode:
case IpcClientType::Node:
type = "node";
break;
default:
@ -379,7 +368,7 @@ void DaemonApp::handleIpcMessage(const Event &e, void *) {
LOG((CLOG_DEBUG "ipc hello, type=%s", type.c_str()));
// TODO: implement hello back handling in s1 gui and node (server/client).
if (hm->clientType() == kIpcClientGui) {
if (hm->clientType() == IpcClientType::GUI) {
LOG((CLOG_DEBUG "sending ipc hello back"));
IpcHelloBackMessage hbm;
m_ipcServer->send(hbm, hm->clientType());
@ -394,7 +383,7 @@ void DaemonApp::handleIpcMessage(const Event &e, void *) {
break;
}
case kIpcSetting:
case IpcMessageType::Setting:
updateSetting(*m);
break;
}

View File

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -18,9 +17,9 @@
#pragma once
#include "arch/Arch.h"
#include "ipc/IpcServer.h"
#include <memory>
#include <string>
class Event;
@ -31,11 +30,13 @@ class FileLogOutputter;
class MSWindowsWatchdog;
#endif
extern const char *const kLogFilename;
class DaemonApp {
public:
DaemonApp();
virtual ~DaemonApp();
~DaemonApp();
int run(int argc, char **argv);
void mainLoop(bool logToFile, bool foreground = false);
@ -49,14 +50,12 @@ public:
static DaemonApp *s_instance;
#if SYSAPI_WIN32
MSWindowsWatchdog *m_watchdog;
std::unique_ptr<MSWindowsWatchdog> m_watchdog;
#endif
private:
IpcServer *m_ipcServer;
IpcLogOutputter *m_ipcLogOutputter;
IEventQueue *m_events;
FileLogOutputter *m_fileLogOutputter;
std::unique_ptr<IpcServer> m_ipcServer;
std::unique_ptr<IpcLogOutputter> m_ipcLogOutputter;
std::unique_ptr<IEventQueue> m_events;
std::unique_ptr<FileLogOutputter> m_fileLogOutputter;
};
#define LOG_FILENAME "synergyd.log"

View File

@ -14,18 +14,158 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
include_directories(
../../ext/googletest/googletest ../../ext/googletest/googletest/include
../../ext/googletest/googlemock ../../ext/googletest/googlemock/include)
macro(config_all_tests)
add_library(gtest STATIC ../../ext/googletest/googletest/src/gtest-all.cc)
add_library(gmock STATIC ../../ext/googletest/googlemock/src/gmock-all.cc)
set(base_dir ${CMAKE_SOURCE_DIR})
set(src_dir ${base_dir}/src)
set(test_base_dir ${src_dir}/test)
set(ext_dir ${base_dir}/ext)
set(gtest_base_dir ${ext_dir}/googletest)
set(gui_dir ${src_dir}/gui/src)
if(UNIX)
# ignore warnings in gtest and gmock
set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w")
set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w")
endif()
config_test_deps()
add_subdirectory(integtests)
add_subdirectory(unittests)
add_subdirectory(integtests)
add_subdirectory(unittests)
endmacro()
macro(config_test)
include_directories(
${test_base_dir}
${src_dir}
${src_dir}/lib
${gui_dir}
${ext_dir})
set_sources()
endmacro()
macro(set_sources)
file(GLOB_RECURSE headers ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
file(GLOB_RECURSE sources ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE shared_headers ${test_base_dir}/shared/*.h)
file(GLOB_RECURSE shared_sources ${test_base_dir}/shared/*.cpp)
list(APPEND headers ${shared_headers})
list(APPEND sources ${shared_sources})
file(GLOB_RECURSE mock_headers ${test_base_dir}/mock/*.h)
file(GLOB_RECURSE mock_sources ${test_base_dir}/mock/*.cpp)
list(APPEND headers ${mock_headers})
list(APPEND sources ${mock_sources})
file(GLOB_RECURSE gui_sources ${gui_dir}/*.cpp)
file(GLOB activation_sources ${gui_dir}/*Activation* ${gui_dir}/*License*)
if(NOT ENABLE_LICENSING)
list(REMOVE_ITEM gui_sources ${activation_sources})
endif()
# remove main gui as the test already has its own main.
file(GLOB gui_main ${gui_dir}/main.cpp)
list(REMOVE_ITEM gui_sources ${gui_main})
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
file(GLOB mac_gui_sources ${gui_dir}/*.mm)
list(APPEND gui_sources ${mac_gui_sources})
endif()
list(APPEND sources ${gui_sources})
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()
if(WIN32)
list(APPEND sources ${CMAKE_BINARY_DIR}/src/version.rc)
endif()
add_platform_sources()
endmacro()
macro(add_platform_sources)
set(platform_dir ${CMAKE_CURRENT_SOURCE_DIR}/platform)
# Remove platform files so that specific platform files can be added later.
# This is a bit weird, but it's simpler to include everything, remove all
# platform files, then only include the platforms we need.
file(GLOB_RECURSE all_platform_files ${platform_dir}/*)
list(REMOVE_ITEM headers ${all_platform_files})
list(REMOVE_ITEM sources ${all_platform_files})
if(WIN32)
file(GLOB platform_sources ${platform_dir}/MSWindows*.cpp)
file(GLOB platform_headers ${platform_dir}/MSWindows*.h)
elseif(APPLE)
file(GLOB platform_sources ${platform_dir}/OSX*.cpp)
file(GLOB platform_headers ${platform_dir}/OSX*.h)
elseif(UNIX)
file(GLOB platform_sources ${platform_dir}/XWindows*.cpp)
file(GLOB platform_headers ${platform_dir}/XWindows*.h)
endif()
list(APPEND sources ${platform_sources})
list(APPEND headers ${platform_headers})
endmacro()
macro(config_test_deps)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(
Qt6
COMPONENTS Core Widgets Network Test
REQUIRED)
set(gtest_dir ${gtest_base_dir}/googletest)
set(gmock_dir ${gtest_base_dir}/googlemock)
include_directories(${gtest_dir} ${gmock_dir} ${gtest_dir}/include
${gmock_dir}/include)
add_library(gtest STATIC ${gtest_dir}/src/gtest-all.cc)
add_library(gmock STATIC ${gmock_dir}/src/gmock-all.cc)
if(UNIX)
# ignore warnings in gtest and gmock
set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w")
set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w")
endif()
set(test_libs
arch
base
client
server
common
io
net
platform
server
synlib
mt
ipc
gtest
gmock
shared
Qt6::Core
Qt6::Widgets
Qt6::Network
Qt6::Test
${libs})
endmacro()
config_all_tests()

View File

@ -14,67 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
file(GLOB_RECURSE headers "*.h")
file(GLOB_RECURSE sources "*.cpp")
# remove platform files (specific platform added later).
file(GLOB_RECURSE remove_platform "platform/*")
list(REMOVE_ITEM headers ${remove_platform})
list(REMOVE_ITEM sources ${remove_platform})
# platform
if(WIN32)
file(GLOB platform_sources "platform/MSWindows*.cpp")
file(GLOB platform_headers "platform/MSWindows*.h")
elseif(APPLE)
file(GLOB platform_sources "platform/OSX*.cpp")
file(GLOB platform_headers "platform/OSX*.h")
elseif(UNIX)
file(GLOB platform_sources "platform/XWindows*.cpp")
file(GLOB platform_headers "platform/XWindows*.h")
endif()
list(APPEND sources ${platform_sources})
list(APPEND headers ${platform_headers})
file(GLOB_RECURSE shared_headers "../../test/shared/*.h")
file(GLOB_RECURSE shared_sources "../../test/shared/*.cpp")
list(APPEND headers ${shared_headers})
list(APPEND sources ${shared_sources})
file(GLOB_RECURSE mock_headers "../../test/mock/*.h")
file(GLOB_RECURSE mock_sources "../../test/mock/*.cpp")
list(APPEND headers ${mock_headers})
list(APPEND sources ${mock_sources})
if(SYNERGY_ADD_HEADERS)
list(APPEND sources ${headers})
endif()
if(WIN32)
list(APPEND sources ${CMAKE_BINARY_DIR}/src/version.rc)
endif()
include_directories(
../../ ../../lib/ ../../../ext/googletest/googletest/include
../../../ext/googletest/googlemock/include)
add_executable(integtests ${sources})
target_link_libraries(
integtests
arch
base
client
common
io
ipc
mt
net
platform
server
synlib
gtest
gmock
${libs})
config_test()
set(target integtests)
add_executable(${target} ${sources})
target_link_libraries(${target} ${test_libs})

View File

@ -27,7 +27,6 @@
#include "base/String.h"
#include "base/TMethodEventJob.h"
#include "base/TMethodJob.h"
#include "ipc/Ipc.h"
#include "ipc/IpcClient.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
@ -35,11 +34,12 @@
#include "ipc/IpcServerProxy.h"
#include "mt/Thread.h"
#include "net/SocketMultiplexer.h"
#include "shared/Ipc.h"
#include "test/shared/TestEventQueue.h"
#include <gtest/gtest.h>
#define TEST_IPC_PORT 24802
const int kTestPort = 24802;
class IpcTests : public ::testing::Test {
public:
@ -65,7 +65,7 @@ public:
TEST_F(IpcTests, connectToServer) {
SocketMultiplexer socketMultiplexer;
IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT);
IpcServer server(&m_events, &socketMultiplexer, kTestPort);
server.listen();
m_connectToServer_server = &server;
@ -74,7 +74,7 @@ TEST_F(IpcTests, connectToServer) {
new TMethodEventJob<IpcTests>(
this, &IpcTests::connectToServer_handleMessageReceived));
IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT);
IpcClient client(&m_events, &socketMultiplexer, kTestPort);
client.connect();
m_events.initQuitTimeout(5);
@ -88,7 +88,7 @@ TEST_F(IpcTests, connectToServer) {
TEST_F(IpcTests, sendMessageToServer) {
SocketMultiplexer socketMultiplexer;
IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT);
IpcServer server(&m_events, &socketMultiplexer, kTestPort);
server.listen();
// event handler sends "test" command to server.
@ -97,7 +97,7 @@ TEST_F(IpcTests, sendMessageToServer) {
new TMethodEventJob<IpcTests>(
this, &IpcTests::sendMessageToServer_serverHandleMessageReceived));
IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT);
IpcClient client(&m_events, &socketMultiplexer, kTestPort);
client.connect();
m_sendMessageToServer_client = &client;
@ -111,7 +111,7 @@ TEST_F(IpcTests, sendMessageToServer) {
TEST_F(IpcTests, sendMessageToClient) {
SocketMultiplexer socketMultiplexer;
IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT);
IpcServer server(&m_events, &socketMultiplexer, kTestPort);
server.listen();
m_sendMessageToClient_server = &server;
@ -121,7 +121,7 @@ TEST_F(IpcTests, sendMessageToClient) {
new TMethodEventJob<IpcTests>(
this, &IpcTests::sendMessageToClient_serverHandleClientConnected));
IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT);
IpcClient client(&m_events, &socketMultiplexer, kTestPort);
client.connect();
m_events.adoptHandler(
@ -149,9 +149,9 @@ IpcTests::~IpcTests() {}
void IpcTests::connectToServer_handleMessageReceived(const Event &e, void *) {
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
if (m->type() == kIpcHello) {
if (m->type() == IpcMessageType::Hello) {
m_connectToServer_hasClientNode =
m_connectToServer_server->hasClients(kIpcClientNode);
m_connectToServer_server->hasClients(IpcClientType::Node);
m_connectToServer_helloMessageReceived = true;
m_events.raiseQuitEvent();
}
@ -160,11 +160,11 @@ void IpcTests::connectToServer_handleMessageReceived(const Event &e, void *) {
void IpcTests::sendMessageToServer_serverHandleMessageReceived(
const Event &e, void *) {
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
if (m->type() == kIpcHello) {
if (m->type() == IpcMessageType::Hello) {
LOG((CLOG_DEBUG "client said hello, sending test to server"));
IpcCommandMessage m("test", true);
m_sendMessageToServer_client->send(m);
} else if (m->type() == kIpcCommand) {
} else if (m->type() == IpcMessageType::Command) {
IpcCommandMessage *cm = static_cast<IpcCommandMessage *>(m);
LOG((CLOG_DEBUG "got ipc command message, %d", cm->command().c_str()));
m_sendMessageToServer_receivedString = cm->command();
@ -175,17 +175,17 @@ void IpcTests::sendMessageToServer_serverHandleMessageReceived(
void IpcTests::sendMessageToClient_serverHandleClientConnected(
const Event &e, void *) {
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
if (m->type() == kIpcHello) {
if (m->type() == IpcMessageType::Hello) {
LOG((CLOG_DEBUG "client said hello, sending test to client"));
IpcLogLineMessage m("test");
m_sendMessageToClient_server->send(m, kIpcClientNode);
m_sendMessageToClient_server->send(m, IpcClientType::Node);
}
}
void IpcTests::sendMessageToClient_clientHandleMessageReceived(
const Event &e, void *) {
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
if (m->type() == kIpcLogLine) {
if (m->type() == IpcMessageType::LogLine) {
IpcLogLineMessage *llm = static_cast<IpcLogLineMessage *>(m);
LOG((CLOG_DEBUG "got ipc log message, %d", llm->logLine().c_str()));
m_sendMessageToClient_receivedString = llm->logLine();

View File

@ -16,142 +16,122 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// TODO: fix tests - compile error on linux
#if 0
#include "platform/XWindowsClipboard.h"
#include "test/shared/undef_x11_macros.h"
#include <gtest/gtest.h>
#include <iostream>
#include <memory>
class CXWindowsClipboardTests : public ::testing::Test
{
class XWindowsClipboardTests : public ::testing::Test {
protected:
virtual void
SetUp()
{
m_display = XOpenDisplay(NULL);
int screen = DefaultScreen(m_display);
Window root = XRootWindow(m_display, screen);
XSetWindowAttributes attr;
attr.do_not_propagate_mask = 0;
attr.override_redirect = True;
attr.cursor = Cursor();
m_window = XCreateWindow(
m_display, root, 0, 0, 1, 1, 0, 0,
InputOnly, CopyFromParent, 0, &attr);
}
void SetUp() override {
m_display = XOpenDisplay(nullptr);
int screen = DefaultScreen(m_display);
Window root = XRootWindow(m_display, screen);
virtual void
TearDown()
{
XDestroyWindow(m_display, m_window);
XCloseDisplay(m_display);
}
XSetWindowAttributes attr;
attr.do_not_propagate_mask = 0;
attr.override_redirect = True;
attr.cursor = Cursor();
CXWindowsClipboard&
createClipboard()
{
CXWindowsClipboard* clipboard;
clipboard = new CXWindowsClipboard(m_display, m_window, 0);
clipboard->open(0); // needed to empty the clipboard
clipboard->empty(); // needed to own the clipboard
return *clipboard;
}
m_window = XCreateWindow(
m_display, root, 0, 0, 1, 1, 0, 0, InputOnly, nullptr, 0, &attr);
Display* m_display;
Window m_window;
m_clipboard = std::make_unique<XWindowsClipboard>(m_display, m_window, 0);
m_clipboard->open(0);
m_clipboard->empty();
}
void TearDown() override {
XDestroyWindow(m_display, m_window);
XCloseDisplay(m_display);
}
XWindowsClipboard &getClipboard() { return *m_clipboard; }
private:
Display *m_display;
Window m_window;
std::unique_ptr<XWindowsClipboard> m_clipboard;
};
TEST_F(CXWindowsClipboardTests, empty_openCalled_returnsTrue)
{
CXWindowsClipboard clipboard = createClipboard();
bool actual = clipboard.empty();
EXPECT_EQ(true, actual);
TEST_F(XWindowsClipboardTests, empty_openCalled_returnsTrue) {
XWindowsClipboard &clipboard = getClipboard();
bool actual = clipboard.empty();
EXPECT_EQ(true, actual);
}
TEST_F(CXWindowsClipboardTests, empty_singleFormat_hasReturnsFalse)
{
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(CXWindowsClipboard::kText, "synergy rocks!");
clipboard.empty();
bool actual = clipboard.has(CXWindowsClipboard::kText);
EXPECT_FALSE(actual);
TEST_F(XWindowsClipboardTests, empty_singleFormat_hasReturnsFalse) {
XWindowsClipboard &clipboard = getClipboard();
clipboard.add(XWindowsClipboard::kText, "synergy rocks!");
clipboard.empty();
bool actual = clipboard.has(XWindowsClipboard::kText);
EXPECT_FALSE(actual);
}
TEST_F(CXWindowsClipboardTests, add_newValue_valueWasStored)
{
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!");
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("synergy rocks!", actual);
TEST_F(XWindowsClipboardTests, add_newValue_valueWasStored) {
XWindowsClipboard &clipboard = getClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!");
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("synergy rocks!", actual);
}
TEST_F(CXWindowsClipboardTests, add_replaceValue_valueWasReplaced)
{
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!");
clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding.
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("maxivista sucks", actual);
TEST_F(XWindowsClipboardTests, add_replaceValue_valueWasReplaced) {
XWindowsClipboard &clipboard = getClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!");
clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding.
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("maxivista sucks", actual);
}
TEST_F(CXWindowsClipboardTests, close_isOpen_noErrors)
{
CXWindowsClipboard clipboard = createClipboard();
// clipboard opened in createClipboard()
clipboard.close();
// can't assert anything
TEST_F(XWindowsClipboardTests, close_isOpen_noErrors) {
XWindowsClipboard &clipboard = getClipboard();
// clipboard opened in createClipboard()
clipboard.close();
// can't assert anything
}
TEST_F(CXWindowsClipboardTests, has_withFormatAdded_returnsTrue)
{
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!");
bool actual = clipboard.has(IClipboard::kText);
EXPECT_EQ(true, actual);
TEST_F(XWindowsClipboardTests, has_withFormatAdded_returnsTrue) {
XWindowsClipboard &clipboard = getClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!");
bool actual = clipboard.has(IClipboard::kText);
EXPECT_EQ(true, actual);
}
TEST_F(CXWindowsClipboardTests, has_withNoFormats_returnsFalse)
{
CXWindowsClipboard clipboard = createClipboard();
bool actual = clipboard.has(IClipboard::kText);
EXPECT_FALSE(actual);
TEST_F(XWindowsClipboardTests, has_withNoFormats_returnsFalse) {
XWindowsClipboard &clipboard = getClipboard();
bool actual = clipboard.has(IClipboard::kText);
EXPECT_FALSE(actual);
}
TEST_F(CXWindowsClipboardTests, get_withNoFormats_returnsEmpty)
{
CXWindowsClipboard clipboard = createClipboard();
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("", actual);
TEST_F(XWindowsClipboardTests, get_withNoFormats_returnsEmpty) {
XWindowsClipboard &clipboard = getClipboard();
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("", actual);
}
TEST_F(CXWindowsClipboardTests, get_withFormatAdded_returnsExpected)
{
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!");
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("synergy rocks!", actual);
}
TEST_F(XWindowsClipboardTests, get_withFormatAdded_returnsExpected) {
XWindowsClipboard &clipboard = getClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!");
#endif
String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("synergy rocks!", actual);
}

View File

@ -45,8 +45,8 @@ public:
}
MOCK_METHOD(void, listen, (), (override));
MOCK_METHOD(void, send, (const IpcMessage &, EIpcClientType), (override));
MOCK_METHOD(bool, hasClients, (EIpcClientType), (const, override));
MOCK_METHOD(void, send, (const IpcMessage &, IpcClientType), (override));
MOCK_METHOD(bool, hasClients, (IpcClientType), (const, override));
void delegateToFake() {
ON_CALL(*this, send(_, _))
@ -56,7 +56,7 @@ public:
void waitForSend() { ARCH->waitCondVar(m_sendCond, m_sendMutex, 5); }
private:
void mockSend(const IpcMessage &, EIpcClientType) {
void mockSend(const IpcMessage &, IpcClientType) {
ArchMutexLock lock(m_sendMutex);
ARCH->broadcastCondVar(m_sendCond);
}

View File

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2024 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -16,11 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// this class is a duplicate of /src/lib/ipc/Ipc.cpp
/**
* This header fixes conflicts between X11 and Google Test.
*
* It should be included after headers of code under test (that use X11)
* and before including Google Test headers.
*/
#include "Ipc.h"
const char *kIpcMsgHello = "IHEL%1i";
const char *kIpcMsgLogLine = "ILOG%s";
const char *kIpcMsgCommand = "ICMD%s%1i";
const char *kIpcMsgShutdown = "ISDN";
#undef None // NOSONAR
#undef Bool // NOSONAR

View File

@ -14,110 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
config_test()
set(target unittests)
file(GLOB_RECURSE headers "*.h" "languages/*.h")
file(GLOB_RECURSE sources "*.cpp" "languages/*.cpp")
file(GLOB_RECURSE remove_platform "platform/*")
list(REMOVE_ITEM headers ${remove_platform})
list(REMOVE_ITEM sources ${remove_platform})
file(GLOB_RECURSE shared_headers "../../test/shared/*.h")
file(GLOB_RECURSE shared_sources "../../test/shared/*.cpp")
list(APPEND headers ${shared_headers})
list(APPEND sources ${shared_sources})
file(GLOB_RECURSE mock_headers "../../test/mock/*.h")
file(GLOB_RECURSE mock_sources "../../test/mock/*.cpp")
list(APPEND headers ${mock_headers})
list(APPEND sources ${mock_sources})
set(gui_dir "../../gui/src")
file(GLOB_RECURSE gui_sources "${gui_dir}/*.cpp")
file(GLOB activation_sources "${gui_dir}/*Activation*" "${gui_dir}/*License*")
if(NOT ENABLE_LICENSING)
list(REMOVE_ITEM gui_sources ${activation_sources})
endif()
# remove main gui as the test already has its own main.
file(GLOB gui_main "${gui_dir}/main.cpp")
list(REMOVE_ITEM gui_sources ${gui_main})
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
file(GLOB mac_gui_sources "${gui_dir}/*.mm")
list(APPEND gui_sources ${mac_gui_sources})
endif()
list(APPEND sources ${gui_sources})
# platform
if(WIN32)
file(GLOB platform_sources "platform/MSWindows*.cpp")
file(GLOB platform_headers "platform/MSWindows*.h")
elseif(APPLE)
file(GLOB platform_sources "platform/OSX*.cpp")
file(GLOB platform_headers "platform/OSX*.h")
elseif(UNIX)
file(GLOB platform_sources "platform/XWindows*.cpp")
file(GLOB platform_headers "platform/XWindows*.h")
endif()
list(APPEND sources ${platform_sources})
list(APPEND headers ${platform_headers})
set(ext_dir "../../../ext")
include_directories(
"../.."
"../../lib"
${ext_dir}
${gui_dir}
"${ext_dir}/gtest/include"
"${ext_dir}/gmock/include")
if(SYNERGY_ADD_HEADERS)
list(APPEND sources ${headers})
endif()
if(WIN32)
list(APPEND sources ${CMAKE_BINARY_DIR}/src/version.rc)
endif()
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(
Qt6
COMPONENTS Core Widgets Network Test
REQUIRED)
add_executable(${target} ${sources})
target_link_libraries(
${target}
arch
base
client
server
common
io
net
platform
server
synlib
mt
ipc
gtest
gmock
shared
Qt6::Core
Qt6::Widgets
Qt6::Network
Qt6::Test
${libs})
target_link_libraries(${target} ${test_libs})

View File

@ -62,7 +62,7 @@ using namespace synergy;
// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock
// 2\n"), _)).Times(1);
//
// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, true);
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, true);
// outputter.write(kNOTE, "mock 1");
// mockServer.waitForSend();
// outputter.write(kNOTE, "mock 2");
@ -78,7 +78,7 @@ using namespace synergy;
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\nmock 3\n"),
// _)).Times(1);
//
// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false);
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, false);
// outputter.bufferMaxSize(2);
//
// // log more lines than the buffer can contain
@ -98,7 +98,7 @@ using namespace synergy;
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"),
// _)).Times(1);
//
// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false);
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, false);
// outputter.bufferMaxSize(2);
//
// // log more lines than the buffer can contain
@ -156,7 +156,7 @@ using namespace synergy;
// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock
// 3\nmock 4\n"), _)).Times(1);
//
// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false);
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, false);
// outputter.bufferRateLimit(4, 1); // 1s (should be plenty of time)
//
// // log 1 more line than the buffer can accept in time limit.

View File

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2024 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -16,27 +15,24 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// this class is a duplicate of /src/lib/ipc/Ipc.h
#include "platform/XWindowsClipboard.h"
#pragma once
#include "test/shared/undef_x11_macros.h"
#define IPC_HOST "127.0.0.1"
#define IPC_PORT 24801
#include <gtest/gtest.h>
enum qIpcMessageType {
kIpcHello,
kIpcLogLine,
kIpcCommand,
kIpcShutdown,
const auto None = 0L;
class TestXWindowsClipboard : public XWindowsClipboard {
public:
class TestCICCCMGetClipboard : public CICCCMGetClipboard {
public:
TestCICCCMGetClipboard() : CICCCMGetClipboard(None, None, None) {}
};
};
enum qIpcClientType {
kIpcClientUnknown,
kIpcClientGui,
kIpcClientNode,
};
TEST(XWindowsClipboardTests_CICCCMGetClipboard, ctor_default_errorNone) {
TestXWindowsClipboard::TestCICCCMGetClipboard clipboard;
extern const char *kIpcMsgHello;
extern const char *kIpcMsgLogLine;
extern const char *kIpcMsgCommand;
extern const char *kIpcMsgShutdown;
EXPECT_EQ(None, clipboard.error());
}