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
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
62 changed files with 814 additions and 698 deletions

View file

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

1
.gitignore vendored
View file

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

27
.vscode/tasks.json vendored
View file

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

View file

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

View file

@ -24,7 +24,7 @@ Enhancements:
- #7326 Restore lpDesktop assignment in Windows daemon - #7326 Restore lpDesktop assignment in Windows daemon
- #7327 Only use Ninja to build on Windows - #7327 Only use Ninja to build on Windows
- #7328 Reset error state before calling Process32Next - #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) - #7331 Script to install deps (Windows only for now)
- #7332 Static link OpenSSL libs in CMake preset for Windows - #7332 Static link OpenSSL libs in CMake preset for Windows
- #7333 Update VS Code config for Windows daemon debugging - #7333 Update VS Code config for Windows daemon debugging
@ -50,10 +50,11 @@ Enhancements:
- #7380 Add `qt6-qpa-plugins` Qt dependency for Debian - #7380 Add `qt6-qpa-plugins` Qt dependency for Debian
- #7381 Set macOS min version to macOS 12.0 - #7381 Set macOS min version to macOS 12.0
- #7382 Re-run `macdeployqt6` to copy missing Qt 6 dependencies - #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 - #7384 Run `install_deps.py` script when building containers weekly
- #7389 Correct Qt macOS target and drop `Core5Compat` lib - #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 - #7401 Run Valgrind on unit tests in CI to detect memory leaks
- #7403 Solve low hanging reliability and maintainability issues
# 1.14.6 # 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_ninja()
configure_options() configure_options()
configure_python()
if("${VERSION_URL}" STREQUAL "") if("${VERSION_URL}" STREQUAL "")
set(VERSION_URL "https://api.symless.com/version?version=v1") set(VERSION_URL "https://api.symless.com/version?version=v1")
@ -58,17 +59,20 @@ macro(configure_definitions)
add_definitions(-DNDEBUG) add_definitions(-DNDEBUG)
endif() 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) if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW) cmake_policy(SET CMP0003 NEW)
cmake_policy(SET CMP0005 NEW) cmake_policy(SET CMP0005 NEW)
endif() endif()
# TODO: explain why we're adding headers to sources.
if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles") if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")
set(SYNERGY_ADD_HEADERS FALSE) set(ADD_HEADERS_TO_SOURCES FALSE)
else() else()
set(SYNERGY_ADD_HEADERS TRUE) set(ADD_HEADERS_TO_SOURCES TRUE)
endif() endif()
set(BIN_TEMP_DIR ${CMAKE_BINARY_DIR}/temp/bin)
endmacro() endmacro()
macro(configure_ninja) macro(configure_ninja)

View file

@ -361,3 +361,11 @@ macro(update_submodules)
endif() endif()
endmacro() 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 os, sys, time, subprocess, argparse, glob
import subprocess
import sys
import argparse
import glob
import lib.windows as windows import lib.windows as windows
import lib.file_utils as file_utils
import psutil
BIN_NAME = "synergyd" DEFAULT_BIN_NAME = "synergyd"
SOURCE_BIN_DIR = os.path.join("build", "bin") DEFAULT_SOURCE_DIR = os.path.join("build", "temp", "bin")
TARGET_BIN_DIR = "bin" DEFAULT_TARGET_DIR = os.path.join("build", "bin")
SERVICE_NOT_RUNNING_ERROR = 2 SERVICE_NOT_RUNNING_ERROR = 2
ERROR_ACCESS_VIOLATION = 0xC0000005
def main(): def main():
@ -16,10 +15,9 @@ def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("--pause-on-exit", action="store_true") parser.add_argument("--pause-on-exit", action="store_true")
parser.add_argument("--source-bin-dir", default=SOURCE_BIN_DIR) parser.add_argument("--source-dir", default=DEFAULT_SOURCE_DIR)
parser.add_argument("--target-bin-dir", default=TARGET_BIN_DIR) parser.add_argument("--target-dir", default=DEFAULT_TARGET_DIR)
parser.add_argument("--source-bin-name", default=BIN_NAME) parser.add_argument("--bin-name", default=DEFAULT_BIN_NAME)
parser.add_argument("--target-bin-name", default=BIN_NAME)
args = parser.parse_args() args = parser.parse_args()
if not windows.is_admin(): if not windows.is_admin():
@ -28,19 +26,18 @@ def main():
try: try:
reinstall( reinstall(
args.source_bin_dir, args.source_dir,
args.target_bin_dir, args.target_dir,
args.source_bin_name, args.bin_name,
args.target_bin_name,
) )
except Exception as e: except Exception as e:
print(f"Error: {e}") print(f"Error: {e}", file=sys.stderr)
if args.pause_on_exit: if args.pause_on_exit:
input("Press enter to continue...") 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.""" """Stops the running daemon service, copies files, and reinstalls."""
print("Stopping daemon service") print("Stopping daemon service")
@ -52,43 +49,64 @@ def reinstall(source_bin_dir, target_bin_dir, source_bin_name, target_bin_name):
else: else:
raise e 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") 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)
print("Installing daemon service") except subprocess.CalledProcessError as e:
subprocess.run([target_bin_file, "/install"], shell=True, check=True) check_access_violation(e.returncode, source_bin_path)
if e.returncode != 0:
print(
def copy_bin_files(source_bin_dir, target_bin_dir, source_bin_name, target_bin_name): f"Warning: Uninstall failed, return code: {e.returncode}",
file=sys.stderr,
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}"
) )
for source_file in source_files: target_bin_path = os.path.join(target_dir, bin_name + ".exe")
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.
try: try:
subprocess.run(["copy", source_file, target_file], shell=True, check=True) print("Installing daemon service")
subprocess.run([target_bin_path, "/install"], shell=True, check=True)
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
print(f"Copy failed: {e}") check_access_violation(e.returncode, target_bin_path)
if e.returncode != 0:
print(f"Warning: Install failed, return code: {e.returncode}")
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,
)
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:
if dir.lower() in exe.lower():
print(f"Process found: {exe}")
return True
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
return False
main() main()

View file

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

View file

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

View file

@ -44,7 +44,7 @@ endif()
list(APPEND sources ${arch_sources}) list(APPEND sources ${arch_sources})
list(APPEND headers ${arch_headers}) list(APPEND headers ${arch_headers})
if(SYNERGY_ADD_HEADERS) if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers}) list(APPEND sources ${headers})
endif() endif()
@ -69,3 +69,5 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(TARGETS ${target} DESTINATION bin) install(TARGETS ${target} DESTINATION bin)
endif() 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( find_package(
Qt6 Qt6
COMPONENTS Core Widgets Network COMPONENTS Core Widgets Network
@ -33,7 +50,7 @@ if(WIN32)
endif() endif()
add_executable( add_executable(
synergy WIN32 ${target} WIN32
${GUI_SOURCE_FILES} ${GUI_SOURCE_FILES}
${GUI_UI_FILES} ${GUI_UI_FILES}
${GUI_RC_FILES} ${GUI_RC_FILES}
@ -41,16 +58,16 @@ add_executable(
${QM_FILES}) ${QM_FILES})
include_directories(./src) 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( target_compile_definitions(
synergy PRIVATE -DSYNERGY_VERSION_STAGE="${SYNERGY_VERSION_STAGE}") ${target} PRIVATE -DSYNERGY_VERSION_STAGE="${SYNERGY_VERSION_STAGE}")
target_compile_definitions(synergy target_compile_definitions(${target}
PRIVATE -DSYNERGY_REVISION="${SYNERGY_REVISION}") PRIVATE -DSYNERGY_REVISION="${SYNERGY_REVISION}")
if(WIN32) if(WIN32)
set_target_properties(synergy PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT") set_target_properties(${target} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT")
endif() endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@ -61,13 +78,13 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(MACDEPLOYQT_CMD set(MACDEPLOYQT_CMD
"${MACDEPLOYQT_BIN} ${SYNERGY_BUNDLE_APP_DIR} -always-overwrite") "${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 "MESSAGE (\"Running: ${MACDEPLOYQT_CMD}\")")
install(CODE "execute_process(COMMAND ${MACDEPLOYQT_CMD})") install(CODE "execute_process(COMMAND ${MACDEPLOYQT_CMD})")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(TARGETS synergy DESTINATION bin) install(TARGETS ${target} DESTINATION bin)
elseif(WIN32) elseif(WIN32)
@ -96,7 +113,7 @@ elseif(WIN32)
if(TARGET Qt6::windeployqt) if(TARGET Qt6::windeployqt)
# execute windeployqt in a tmp directory after build # execute windeployqt in a tmp directory after build
add_custom_command( add_custom_command(
TARGET synergy TARGET ${target}
POST_BUILD POST_BUILD
COMMAND set PATH=%PATH%$<SEMICOLON>${qt6_install_prefix}/bin COMMAND set PATH=%PATH%$<SEMICOLON>${qt6_install_prefix}/bin
COMMAND Qt6::windeployqt COMMAND Qt6::windeployqt
@ -104,3 +121,5 @@ elseif(WIN32)
endif() endif()
endif() endif()
post_config()

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -212,40 +212,3 @@ void FileLogOutputter::open(const char *title) {}
void FileLogOutputter::close() {} void FileLogOutputter::close() {}
void FileLogOutputter::show(bool showIfEmpty) {} 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; UInt32 m_maxBufferSize;
Buffer m_buffer; 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 headers "*.h")
file(GLOB sources "*.cpp") file(GLOB sources "*.cpp")
if(SYNERGY_ADD_HEADERS) if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers}) list(APPEND sources ${headers})
endif() endif()

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,6 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -18,10 +17,11 @@
#pragma once #pragma once
#include "arch/Arch.h"
#include "arch/IArchMultithread.h" #include "arch/IArchMultithread.h"
#include "base/Event.h" #include "base/Event.h"
#include "base/EventTypes.h" #include "base/EventTypes.h"
#include "ipc/Ipc.h" #include "shared/Ipc.h"
namespace synergy { namespace synergy {
class IStream; class IStream;
@ -56,9 +56,9 @@ private:
private: private:
synergy::IStream &m_stream; synergy::IStream &m_stream;
EIpcClientType m_clientType;
bool m_disconnecting;
ArchMutex m_readMutex;
ArchMutex m_writeMutex;
IEventQueue *m_events; 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/EventQueue.h"
#include "base/TMethodEventJob.h" #include "base/TMethodEventJob.h"
#include "base/TMethodJob.h" #include "base/TMethodJob.h"
#include "ipc/Ipc.h"
#include "ipc/IpcClientProxy.h" #include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h" #include "ipc/IpcMessage.h"
#include "ipc/IpcServer.h" #include "ipc/IpcServer.h"
#include "mt/Thread.h" #include "mt/Thread.h"
#include "shared/Ipc.h"
enum EIpcLogOutputter { enum EIpcLogOutputter {
kBufferMaxSize = 1000, kBufferMaxSize = 1000,
@ -38,7 +38,7 @@ enum EIpcLogOutputter {
}; };
IpcLogOutputter::IpcLogOutputter( IpcLogOutputter::IpcLogOutputter(
IpcServer &ipcServer, EIpcClientType clientType, bool useThread) IpcServer &ipcServer, IpcClientType clientType, bool useThread)
: m_ipcServer(ipcServer), : m_ipcServer(ipcServer),
m_bufferMutex(ARCH->newMutex()), m_bufferMutex(ARCH->newMutex()),
m_sending(false), m_sending(false),
@ -179,7 +179,7 @@ void IpcLogOutputter::sendBuffer() {
IpcLogLineMessage message(getChunk(kMaxSendLines)); IpcLogLineMessage message(getChunk(kMaxSendLines));
m_sending = true; m_sending = true;
m_ipcServer.send(message, kIpcClientGui); m_ipcServer.send(message, IpcClientType::GUI);
m_sending = false; m_sending = false;
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -20,9 +20,9 @@
#include "arch/Arch.h" #include "arch/Arch.h"
#include "base/EventTypes.h" #include "base/EventTypes.h"
#include "ipc/Ipc.h"
#include "net/NetworkAddress.h" #include "net/NetworkAddress.h"
#include "net/TCPListenSocket.h" #include "net/TCPListenSocket.h"
#include "shared/Ipc.h"
#include <list> #include <list>
@ -58,14 +58,14 @@ public:
virtual void listen(); virtual void listen();
//! Send a message to all clients matching the filter type. //! 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 //! @name accessors
//@{ //@{
//! Returns true when there are clients of the specified type connected. //! 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/Log.h"
#include "base/TMethodEventJob.h" #include "base/TMethodEventJob.h"
#include "io/IStream.h" #include "io/IStream.h"
#include "ipc/Ipc.h"
#include "ipc/IpcMessage.h" #include "ipc/IpcMessage.h"
#include "shared/Ipc.h"
#include "synergy/ProtocolUtil.h" #include "synergy/ProtocolUtil.h"
// //
@ -78,13 +78,13 @@ void IpcServerProxy::send(const IpcMessage &message) {
LOG((CLOG_DEBUG4 "ipc write: %d", message.type())); LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
switch (message.type()) { switch (message.type()) {
case kIpcHello: { case IpcMessageType::Hello: {
const IpcHelloMessage &hm = static_cast<const IpcHelloMessage &>(message); const IpcHelloMessage &hm = static_cast<const IpcHelloMessage &>(message);
ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType()); ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType());
break; break;
} }
case kIpcCommand: { case IpcMessageType::Command: {
const IpcCommandMessage &cm = const IpcCommandMessage &cm =
static_cast<const IpcCommandMessage &>(message); static_cast<const IpcCommandMessage &>(message);
const String command = cm.command(); const String command = cm.command();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,6 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -18,9 +17,9 @@
#pragma once #pragma once
#include "arch/Arch.h"
#include "ipc/IpcServer.h" #include "ipc/IpcServer.h"
#include <memory>
#include <string> #include <string>
class Event; class Event;
@ -31,11 +30,13 @@ class FileLogOutputter;
class MSWindowsWatchdog; class MSWindowsWatchdog;
#endif #endif
extern const char *const kLogFilename;
class DaemonApp { class DaemonApp {
public: public:
DaemonApp(); DaemonApp();
virtual ~DaemonApp(); ~DaemonApp();
int run(int argc, char **argv); int run(int argc, char **argv);
void mainLoop(bool logToFile, bool foreground = false); void mainLoop(bool logToFile, bool foreground = false);
@ -49,14 +50,12 @@ public:
static DaemonApp *s_instance; static DaemonApp *s_instance;
#if SYSAPI_WIN32 #if SYSAPI_WIN32
MSWindowsWatchdog *m_watchdog; std::unique_ptr<MSWindowsWatchdog> m_watchdog;
#endif #endif
private: private:
IpcServer *m_ipcServer; std::unique_ptr<IpcServer> m_ipcServer;
IpcLogOutputter *m_ipcLogOutputter; std::unique_ptr<IpcLogOutputter> m_ipcLogOutputter;
IEventQueue *m_events; std::unique_ptr<IEventQueue> m_events;
FileLogOutputter *m_fileLogOutputter; 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
include_directories( macro(config_all_tests)
../../ext/googletest/googletest ../../ext/googletest/googletest/include
../../ext/googletest/googlemock ../../ext/googletest/googlemock/include)
add_library(gtest STATIC ../../ext/googletest/googletest/src/gtest-all.cc) set(base_dir ${CMAKE_SOURCE_DIR})
add_library(gmock STATIC ../../ext/googletest/googlemock/src/gmock-all.cc) 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) config_test_deps()
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 # ignore warnings in gtest and gmock
set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w") set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w")
set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w") set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w")
endif() endif()
add_subdirectory(integtests) set(test_libs
add_subdirectory(unittests) 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
file(GLOB_RECURSE headers "*.h") config_test()
file(GLOB_RECURSE sources "*.cpp") set(target integtests)
add_executable(${target} ${sources})
# remove platform files (specific platform added later). target_link_libraries(${target} ${test_libs})
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})

View file

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

View file

@ -16,21 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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 "platform/XWindowsClipboard.h"
#include <gtest/gtest.h> #include "test/shared/undef_x11_macros.h"
#include <iostream>
class CXWindowsClipboardTests : public ::testing::Test #include <gtest/gtest.h>
{ #include <memory>
class XWindowsClipboardTests : public ::testing::Test {
protected: protected:
virtual void void SetUp() override {
SetUp() m_display = XOpenDisplay(nullptr);
{
m_display = XOpenDisplay(NULL);
int screen = DefaultScreen(m_display); int screen = DefaultScreen(m_display);
Window root = XRootWindow(m_display, screen); Window root = XRootWindow(m_display, screen);
@ -40,54 +36,46 @@ protected:
attr.cursor = Cursor(); attr.cursor = Cursor();
m_window = XCreateWindow( m_window = XCreateWindow(
m_display, root, 0, 0, 1, 1, 0, 0, m_display, root, 0, 0, 1, 1, 0, 0, InputOnly, nullptr, 0, &attr);
InputOnly, CopyFromParent, 0, &attr);
m_clipboard = std::make_unique<XWindowsClipboard>(m_display, m_window, 0);
m_clipboard->open(0);
m_clipboard->empty();
} }
virtual void void TearDown() override {
TearDown()
{
XDestroyWindow(m_display, m_window); XDestroyWindow(m_display, m_window);
XCloseDisplay(m_display); XCloseDisplay(m_display);
} }
CXWindowsClipboard& XWindowsClipboard &getClipboard() { return *m_clipboard; }
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;
}
Display* m_display; private:
Display *m_display;
Window m_window; Window m_window;
std::unique_ptr<XWindowsClipboard> m_clipboard;
}; };
TEST_F(CXWindowsClipboardTests, empty_openCalled_returnsTrue) TEST_F(XWindowsClipboardTests, empty_openCalled_returnsTrue) {
{ XWindowsClipboard &clipboard = getClipboard();
CXWindowsClipboard clipboard = createClipboard();
bool actual = clipboard.empty(); bool actual = clipboard.empty();
EXPECT_EQ(true, actual); EXPECT_EQ(true, actual);
} }
TEST_F(CXWindowsClipboardTests, empty_singleFormat_hasReturnsFalse) TEST_F(XWindowsClipboardTests, empty_singleFormat_hasReturnsFalse) {
{ XWindowsClipboard &clipboard = getClipboard();
CXWindowsClipboard clipboard = createClipboard(); clipboard.add(XWindowsClipboard::kText, "synergy rocks!");
clipboard.add(CXWindowsClipboard::kText, "synergy rocks!");
clipboard.empty(); clipboard.empty();
bool actual = clipboard.has(CXWindowsClipboard::kText); bool actual = clipboard.has(XWindowsClipboard::kText);
EXPECT_FALSE(actual); EXPECT_FALSE(actual);
} }
TEST_F(CXWindowsClipboardTests, add_newValue_valueWasStored) TEST_F(XWindowsClipboardTests, add_newValue_valueWasStored) {
{ XWindowsClipboard &clipboard = getClipboard();
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!"); clipboard.add(IClipboard::kText, "synergy rocks!");
@ -95,9 +83,8 @@ TEST_F(CXWindowsClipboardTests, add_newValue_valueWasStored)
EXPECT_EQ("synergy rocks!", actual); EXPECT_EQ("synergy rocks!", actual);
} }
TEST_F(CXWindowsClipboardTests, add_replaceValue_valueWasReplaced) TEST_F(XWindowsClipboardTests, add_replaceValue_valueWasReplaced) {
{ XWindowsClipboard &clipboard = getClipboard();
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!"); clipboard.add(IClipboard::kText, "synergy rocks!");
clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding.
@ -106,9 +93,8 @@ TEST_F(CXWindowsClipboardTests, add_replaceValue_valueWasReplaced)
EXPECT_EQ("maxivista sucks", actual); EXPECT_EQ("maxivista sucks", actual);
} }
TEST_F(CXWindowsClipboardTests, close_isOpen_noErrors) TEST_F(XWindowsClipboardTests, close_isOpen_noErrors) {
{ XWindowsClipboard &clipboard = getClipboard();
CXWindowsClipboard clipboard = createClipboard();
// clipboard opened in createClipboard() // clipboard opened in createClipboard()
clipboard.close(); clipboard.close();
@ -116,9 +102,8 @@ TEST_F(CXWindowsClipboardTests, close_isOpen_noErrors)
// can't assert anything // can't assert anything
} }
TEST_F(CXWindowsClipboardTests, has_withFormatAdded_returnsTrue) TEST_F(XWindowsClipboardTests, has_withFormatAdded_returnsTrue) {
{ XWindowsClipboard &clipboard = getClipboard();
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!"); clipboard.add(IClipboard::kText, "synergy rocks!");
bool actual = clipboard.has(IClipboard::kText); bool actual = clipboard.has(IClipboard::kText);
@ -126,32 +111,27 @@ TEST_F(CXWindowsClipboardTests, has_withFormatAdded_returnsTrue)
EXPECT_EQ(true, actual); EXPECT_EQ(true, actual);
} }
TEST_F(CXWindowsClipboardTests, has_withNoFormats_returnsFalse) TEST_F(XWindowsClipboardTests, has_withNoFormats_returnsFalse) {
{ XWindowsClipboard &clipboard = getClipboard();
CXWindowsClipboard clipboard = createClipboard();
bool actual = clipboard.has(IClipboard::kText); bool actual = clipboard.has(IClipboard::kText);
EXPECT_FALSE(actual); EXPECT_FALSE(actual);
} }
TEST_F(CXWindowsClipboardTests, get_withNoFormats_returnsEmpty) TEST_F(XWindowsClipboardTests, get_withNoFormats_returnsEmpty) {
{ XWindowsClipboard &clipboard = getClipboard();
CXWindowsClipboard clipboard = createClipboard();
String actual = clipboard.get(IClipboard::kText); String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("", actual); EXPECT_EQ("", actual);
} }
TEST_F(CXWindowsClipboardTests, get_withFormatAdded_returnsExpected) TEST_F(XWindowsClipboardTests, get_withFormatAdded_returnsExpected) {
{ XWindowsClipboard &clipboard = getClipboard();
CXWindowsClipboard clipboard = createClipboard();
clipboard.add(IClipboard::kText, "synergy rocks!"); clipboard.add(IClipboard::kText, "synergy rocks!");
String actual = clipboard.get(IClipboard::kText); String actual = clipboard.get(IClipboard::kText);
EXPECT_EQ("synergy rocks!", actual); EXPECT_EQ("synergy rocks!", actual);
} }
#endif

View file

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

View file

@ -1,7 +1,6 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2024 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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/>. * 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" #undef None // NOSONAR
#undef Bool // NOSONAR
const char *kIpcMsgHello = "IHEL%1i";
const char *kIpcMsgLogLine = "ILOG%s";
const char *kIpcMsgCommand = "ICMD%s%1i";
const char *kIpcMsgShutdown = "ISDN";

View file

@ -14,110 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
config_test()
set(target unittests) 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}) add_executable(${target} ${sources})
target_link_libraries(${target} ${test_libs})
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})

View file

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

View file

@ -1,7 +1,6 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2024 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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/>. * 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" #include <gtest/gtest.h>
#define IPC_PORT 24801
enum qIpcMessageType { const auto None = 0L;
kIpcHello,
kIpcLogLine, class TestXWindowsClipboard : public XWindowsClipboard {
kIpcCommand, public:
kIpcShutdown, class TestCICCCMGetClipboard : public CICCCMGetClipboard {
public:
TestCICCCMGetClipboard() : CICCCMGetClipboard(None, None, None) {}
};
}; };
enum qIpcClientType { TEST(XWindowsClipboardTests_CICCCMGetClipboard, ctor_default_errorNone) {
kIpcClientUnknown, TestXWindowsClipboard::TestCICCCMGetClipboard clipboard;
kIpcClientGui,
kIpcClientNode,
};
extern const char *kIpcMsgHello; EXPECT_EQ(None, clipboard.error());
extern const char *kIpcMsgLogLine; }
extern const char *kIpcMsgCommand;
extern const char *kIpcMsgShutdown;