Refactored some platform dependent code into a new library,
lib/arch. This should make porting easier. Will probably continue to refactor a little more, moving platform dependent event handling stuff into lib/platform.
This commit is contained in:
parent
62303391a8
commit
f65921bc3f
74
PORTING
74
PORTING
|
@ -10,16 +10,19 @@ The synergy source code organization is:
|
||||||
|
|
||||||
. -- root makefiles, some standard documentation
|
. -- root makefiles, some standard documentation
|
||||||
cmd -- program source code
|
cmd -- program source code
|
||||||
synergy -- synergy client
|
launcher -- synergy launcher for Windows
|
||||||
synergyd -- synergy server
|
synergyc -- synergy client
|
||||||
|
synergys -- synergy server
|
||||||
config -- stuff for autoconf/automake
|
config -- stuff for autoconf/automake
|
||||||
dist -- files for creating distributions
|
dist -- files for creating distributions
|
||||||
rpm -- files for creating RPMs
|
rpm -- files for creating RPMs
|
||||||
doc -- placeholder for documentation
|
doc -- placeholder for documentation
|
||||||
examples -- example files
|
examples -- example files
|
||||||
lib -- library source code
|
lib -- library source code
|
||||||
|
arch -- platform dependent utility library
|
||||||
base -- simple utilities
|
base -- simple utilities
|
||||||
client -- synergy client library
|
client -- synergy client library
|
||||||
|
common -- commonly needed header files
|
||||||
http -- simple http tools
|
http -- simple http tools
|
||||||
io -- I/O
|
io -- I/O
|
||||||
mt -- multithreading
|
mt -- multithreading
|
||||||
|
@ -130,7 +133,7 @@ following these guidelines.
|
||||||
* Other headers in directory, sorted alphabetically
|
* Other headers in directory, sorted alphabetically
|
||||||
* Headers for each library, sorted alphabetically per library
|
* Headers for each library, sorted alphabetically per library
|
||||||
Include headers from the library closest in the dependency graph
|
Include headers from the library closest in the dependency graph
|
||||||
first, then the next farthest, etc. sort alphabetically within
|
first, then the next farthest, etc. Sort alphabetically within
|
||||||
each library.
|
each library.
|
||||||
* System headers
|
* System headers
|
||||||
|
|
||||||
|
@ -181,12 +184,8 @@ following these guidelines.
|
||||||
Inheriting implementation from multiple classes can have unpleasant
|
Inheriting implementation from multiple classes can have unpleasant
|
||||||
consequences in C++ due to it's limited capabilities. Classes can
|
consequences in C++ due to it's limited capabilities. Classes can
|
||||||
inherit from any number of interface classes. An interface class
|
inherit from any number of interface classes. An interface class
|
||||||
provides only pure virtual methods.
|
provides only pure virtual methods. Synergy breaks this rule in
|
||||||
|
IInterface which implements the virtual destructor for convenience.
|
||||||
Synergy breaks this rule in two places. First is that IInterface
|
|
||||||
implements the virtual destructor. However, it's just an empty
|
|
||||||
method so it doesn't really count. Second is MXErrno which provides
|
|
||||||
implementation for exceptions that use the global errno variable.
|
|
||||||
|
|
||||||
* No globals
|
* No globals
|
||||||
Avoid global variables. All global variables must be static, making
|
Avoid global variables. All global variables must be static, making
|
||||||
|
@ -272,18 +271,20 @@ following these guidelines.
|
||||||
* Open brace for function is on a line by itself in first column
|
* Open brace for function is on a line by itself in first column
|
||||||
* Close brace for function lines up with open brace
|
* Close brace for function lines up with open brace
|
||||||
* Always use braces on: if, else, for, while, do, switch
|
* Always use braces on: if, else, for, while, do, switch
|
||||||
* `else {' goes on it's own line
|
* `else {' goes on its own line
|
||||||
* Always explicitly test pointers against NULL
|
* Always explicitly test pointers against NULL
|
||||||
e.g. `if (ptr == NULL)' not `if (ptr)'
|
e.g. `if (ptr == NULL)' not `if (ptr)'
|
||||||
|
* Always explicitly test integral values against 0
|
||||||
|
e.g. `if (i == 0)' not `if (i)'
|
||||||
* Put spaces around binary operators and after statements
|
* Put spaces around binary operators and after statements
|
||||||
e.g. `if (a == b) {' not `if(a==b){'
|
e.g. `if (a == b) {' not `if(a==b){'
|
||||||
* C'tor initializers are one per line, indented one tab stop
|
* C'tor initializers are one per line, indented one tab stop
|
||||||
* Other indentation should follow existing practice
|
* Other indentation should follow existing practice
|
||||||
* Use Qt style comments for extraction by doxygen
|
* Use Qt style comments for extraction by doxygen (i.e. //! and /*!)
|
||||||
* Mark incomplete or buggy code with `FIXME'
|
* Mark incomplete or buggy code with `FIXME'
|
||||||
|
|
||||||
- Other
|
- Other
|
||||||
* calls to log() should always be all on one line (even past column 80)
|
* calls to LOG() should always be all on one line (even past column 80)
|
||||||
|
|
||||||
|
|
||||||
Class Relationships
|
Class Relationships
|
||||||
|
@ -300,4 +301,51 @@ FIXME -- high level overview of class relationships
|
||||||
Portability
|
Portability
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
FIXME -- information about porting to new platforms
|
Porting synergy to a new platform requires the following steps:
|
||||||
|
|
||||||
|
- Setting up the build
|
||||||
|
- Adjusting lib/common/common.h
|
||||||
|
- Implementing lib/arch
|
||||||
|
- Implementing lib/platform
|
||||||
|
- Implementing primary and secondary screens for the platform
|
||||||
|
- Tweaking synergyc and synergys
|
||||||
|
|
||||||
|
Setting up the build:
|
||||||
|
|
||||||
|
The first phase is simply to create the files necessary to build the
|
||||||
|
other files. On Unix, synergy uses autoconf/automake which produces
|
||||||
|
a `configure' script that generates makefiles. On Windows, synergy
|
||||||
|
uses Visual C++ workspace and project files. If you're porting to
|
||||||
|
another Unix variant, you may need to adjust `configure.in',
|
||||||
|
`acinclude.m4', and Unix flavor dependent code in lib/arch.
|
||||||
|
|
||||||
|
Adjusting lib/common/common.h:
|
||||||
|
|
||||||
|
The lib/common/common.h header file is included directly or indirectly
|
||||||
|
by every other file. It prepares some platform dependent macros for
|
||||||
|
integer sizes and defines a macro for conveniently testing which
|
||||||
|
platform we're building on. That macro is named *_LIKE (e.g. UNIX_LIKE)
|
||||||
|
and has the value `1'. Exactly one *_LIKE macro must be defined by
|
||||||
|
common.h.
|
||||||
|
|
||||||
|
Implementing lib/arch:
|
||||||
|
|
||||||
|
Most platform dependent code lives in lib/arch. There are several
|
||||||
|
interface classes there and they must all be implemented for each
|
||||||
|
platform. See the interface header files for more information.
|
||||||
|
|
||||||
|
Implementing lib/platform:
|
||||||
|
|
||||||
|
Most of the remaining platform dependent code lives in lib/platform.
|
||||||
|
The code there implements platform dependent window, clipboard, and
|
||||||
|
screen saver handling. The following interfaces must be implemented:
|
||||||
|
|
||||||
|
FIXME
|
||||||
|
|
||||||
|
Implementing primary and secondary screens for the platform:
|
||||||
|
|
||||||
|
FIXME
|
||||||
|
|
||||||
|
Tweaking synergyc and synergys:
|
||||||
|
|
||||||
|
FIXME
|
||||||
|
|
|
@ -12,8 +12,11 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CPlatform.h"
|
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "ILogOutputter.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "CStringUtil.h"
|
||||||
|
#include "XArch.h"
|
||||||
#include "CAutoStart.h"
|
#include "CAutoStart.h"
|
||||||
#include "LaunchUtil.h"
|
#include "LaunchUtil.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
@ -23,6 +26,37 @@
|
||||||
#define CLIENT_DAEMON_INFO "Shares this system's mouse and keyboard with others."
|
#define CLIENT_DAEMON_INFO "Shares this system's mouse and keyboard with others."
|
||||||
#define SERVER_DAEMON_INFO "Shares this system's mouse and keyboard with others."
|
#define SERVER_DAEMON_INFO "Shares this system's mouse and keyboard with others."
|
||||||
|
|
||||||
|
//
|
||||||
|
// CAutoStartOutputter
|
||||||
|
//
|
||||||
|
// This class detects a message above a certain level and saves it
|
||||||
|
//
|
||||||
|
|
||||||
|
class CAutoStartOutputter : public ILogOutputter {
|
||||||
|
public:
|
||||||
|
CAutoStartOutputter(CString* msg) : m_msg(msg) { }
|
||||||
|
virtual ~CAutoStartOutputter() { }
|
||||||
|
|
||||||
|
// ILogOutputter overrides
|
||||||
|
virtual void open(const char*) { }
|
||||||
|
virtual void close() { }
|
||||||
|
virtual bool write(ELevel level, const char* message);
|
||||||
|
virtual const char* getNewline() const { return ""; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
CString* m_msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
CAutoStartOutputter::write(ELevel level, const char* message)
|
||||||
|
{
|
||||||
|
if (level <= CLog::kERROR) {
|
||||||
|
*m_msg = message;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CAutoStart
|
// CAutoStart
|
||||||
//
|
//
|
||||||
|
@ -51,8 +85,7 @@ void
|
||||||
CAutoStart::doModal()
|
CAutoStart::doModal()
|
||||||
{
|
{
|
||||||
// install our log outputter
|
// install our log outputter
|
||||||
CLog::Outputter oldOutputter = CLog::getOutputter();
|
CLOG->insert(new CAutoStartOutputter(&m_errorMessage));
|
||||||
CLog::setOutputter(&CAutoStart::onLog);
|
|
||||||
|
|
||||||
// reset saved flag
|
// reset saved flag
|
||||||
m_userConfigSaved = false;
|
m_userConfigSaved = false;
|
||||||
|
@ -61,8 +94,8 @@ CAutoStart::doModal()
|
||||||
DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_AUTOSTART),
|
DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_AUTOSTART),
|
||||||
m_parent, dlgProc, (LPARAM)this);
|
m_parent, dlgProc, (LPARAM)this);
|
||||||
|
|
||||||
// restore log outputter
|
// remove log outputter
|
||||||
CLog::setOutputter(oldOutputter);
|
CLOG->pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -74,19 +107,16 @@ CAutoStart::wasUserConfigSaved() const
|
||||||
void
|
void
|
||||||
CAutoStart::update()
|
CAutoStart::update()
|
||||||
{
|
{
|
||||||
// need a platform object
|
|
||||||
CPlatform platform;
|
|
||||||
|
|
||||||
// get installation state
|
// get installation state
|
||||||
const bool installedSystem = platform.isDaemonInstalled(
|
const bool installedSystem = ARCH->isDaemonInstalled(
|
||||||
m_name.c_str(), true);
|
m_name.c_str(), true);
|
||||||
const bool installedUser = platform.isDaemonInstalled(
|
const bool installedUser = ARCH->isDaemonInstalled(
|
||||||
m_name.c_str(), false);
|
m_name.c_str(), false);
|
||||||
|
|
||||||
// get user's permissions
|
// get user's permissions
|
||||||
const bool canInstallSystem = platform.canInstallDaemon(
|
const bool canInstallSystem = ARCH->canInstallDaemon(
|
||||||
m_name.c_str(), true);
|
m_name.c_str(), true);
|
||||||
const bool canInstallUser = platform.canInstallDaemon(
|
const bool canInstallUser = ARCH->canInstallDaemon(
|
||||||
m_name.c_str(), false);
|
m_name.c_str(), false);
|
||||||
|
|
||||||
// update messages
|
// update messages
|
||||||
|
@ -165,22 +195,25 @@ CAutoStart::onInstall(bool allUsers)
|
||||||
m_errorMessage = "";
|
m_errorMessage = "";
|
||||||
|
|
||||||
// install
|
// install
|
||||||
CPlatform platform;
|
try {
|
||||||
if (!platform.installDaemon(m_name.c_str(),
|
ARCH->installDaemon(m_name.c_str(),
|
||||||
m_isServer ? SERVER_DAEMON_INFO : CLIENT_DAEMON_INFO,
|
m_isServer ? SERVER_DAEMON_INFO : CLIENT_DAEMON_INFO,
|
||||||
appPath.c_str(), m_cmdLine.c_str(), allUsers)) {
|
appPath.c_str(), m_cmdLine.c_str(), allUsers);
|
||||||
if (m_errorMessage.empty()) {
|
|
||||||
m_errorMessage = getString(IDS_INSTALL_GENERIC_ERROR);
|
|
||||||
}
|
|
||||||
showError(m_hwnd, m_errorMessage);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
askOkay(m_hwnd, getString(IDS_INSTALL_TITLE),
|
askOkay(m_hwnd, getString(IDS_INSTALL_TITLE),
|
||||||
getString(allUsers ?
|
getString(allUsers ?
|
||||||
IDS_INSTALLED_SYSTEM :
|
IDS_INSTALLED_SYSTEM :
|
||||||
IDS_INSTALLED_USER));
|
IDS_INSTALLED_USER));
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
catch (XArchDaemon& e) {
|
||||||
|
if (m_errorMessage.empty()) {
|
||||||
|
m_errorMessage = CStringUtil::format(
|
||||||
|
getString(IDS_INSTALL_GENERIC_ERROR).c_str(),
|
||||||
|
e.what().c_str());
|
||||||
|
}
|
||||||
|
showError(m_hwnd, m_errorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -190,30 +223,23 @@ CAutoStart::onUninstall(bool allUsers)
|
||||||
m_errorMessage = "";
|
m_errorMessage = "";
|
||||||
|
|
||||||
// uninstall
|
// uninstall
|
||||||
CPlatform platform;
|
try {
|
||||||
if (platform.uninstallDaemon(m_name.c_str(), allUsers) !=
|
ARCH->uninstallDaemon(m_name.c_str(), allUsers);
|
||||||
IPlatform::kSuccess) {
|
|
||||||
if (m_errorMessage.empty()) {
|
|
||||||
m_errorMessage = getString(IDS_UNINSTALL_GENERIC_ERROR);
|
|
||||||
}
|
|
||||||
showError(m_hwnd, m_errorMessage);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
askOkay(m_hwnd, getString(IDS_UNINSTALL_TITLE),
|
askOkay(m_hwnd, getString(IDS_UNINSTALL_TITLE),
|
||||||
getString(allUsers ?
|
getString(allUsers ?
|
||||||
IDS_UNINSTALLED_SYSTEM :
|
IDS_UNINSTALLED_SYSTEM :
|
||||||
IDS_UNINSTALLED_USER));
|
IDS_UNINSTALLED_USER));
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CAutoStart::onLog(int priority, const char* message)
|
|
||||||
{
|
|
||||||
if (priority <= CLog::kERROR) {
|
|
||||||
s_singleton->m_errorMessage = message;
|
|
||||||
}
|
}
|
||||||
return true;
|
catch (XArchDaemon& e) {
|
||||||
|
if (m_errorMessage.empty()) {
|
||||||
|
m_errorMessage = CStringUtil::format(
|
||||||
|
getString(IDS_UNINSTALL_GENERIC_ERROR).c_str(),
|
||||||
|
e.what().c_str());
|
||||||
|
}
|
||||||
|
showError(m_hwnd, m_errorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
|
|
|
@ -57,9 +57,6 @@ private:
|
||||||
bool onInstall(bool allUsers);
|
bool onInstall(bool allUsers);
|
||||||
bool onUninstall(bool allUsers);
|
bool onUninstall(bool allUsers);
|
||||||
|
|
||||||
// log handling
|
|
||||||
static bool onLog(int priority, const char* message);
|
|
||||||
|
|
||||||
// message handling
|
// message handling
|
||||||
BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
|
BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
|
static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CConfig.h"
|
#include "CConfig.h"
|
||||||
#include "CPlatform.h"
|
|
||||||
#include "LaunchUtil.h"
|
#include "LaunchUtil.h"
|
||||||
|
#include "CArch.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#include "stdfstream.h"
|
#include "stdfstream.h"
|
||||||
|
|
||||||
|
@ -107,10 +107,9 @@ CString
|
||||||
getAppPath(const CString& appName)
|
getAppPath(const CString& appName)
|
||||||
{
|
{
|
||||||
// prepare path to app
|
// prepare path to app
|
||||||
CPlatform platform;
|
|
||||||
char myPathname[MAX_PATH];
|
char myPathname[MAX_PATH];
|
||||||
GetModuleFileName(s_instance, myPathname, MAX_PATH);
|
GetModuleFileName(s_instance, myPathname, MAX_PATH);
|
||||||
const char* myBasename = platform.getBasename(myPathname);
|
const char* myBasename = ARCH->getBasename(myPathname);
|
||||||
CString appPath = CString(myPathname, myBasename - myPathname);
|
CString appPath = CString(myPathname, myBasename - myPathname);
|
||||||
appPath += appName;
|
appPath += appName;
|
||||||
return appPath;
|
return appPath;
|
||||||
|
@ -136,24 +135,20 @@ loadConfig(const CString& pathname, CConfig& config)
|
||||||
bool
|
bool
|
||||||
loadConfig(CConfig& config)
|
loadConfig(CConfig& config)
|
||||||
{
|
{
|
||||||
CPlatform platform;
|
|
||||||
|
|
||||||
// load configuration
|
// load configuration
|
||||||
bool configLoaded = false;
|
bool configLoaded = false;
|
||||||
CString path = platform.getUserDirectory();
|
CString path = ARCH->getUserDirectory();
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
CPlatform platform;
|
|
||||||
|
|
||||||
// try loading the user's configuration
|
// try loading the user's configuration
|
||||||
path = platform.addPathComponent(path, CONFIG_NAME);
|
path = ARCH->concatPath(path, CONFIG_NAME);
|
||||||
if (loadConfig(path, config)) {
|
if (loadConfig(path, config)) {
|
||||||
configLoaded = true;
|
configLoaded = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// try the system-wide config file
|
// try the system-wide config file
|
||||||
path = platform.getSystemDirectory();
|
path = ARCH->getSystemDirectory();
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
path = platform.addPathComponent(path, CONFIG_NAME);
|
path = ARCH->concatPath(path, CONFIG_NAME);
|
||||||
if (loadConfig(path, config)) {
|
if (loadConfig(path, config)) {
|
||||||
configLoaded = true;
|
configLoaded = true;
|
||||||
}
|
}
|
||||||
|
@ -183,13 +178,11 @@ saveConfig(const CString& pathname, const CConfig& config)
|
||||||
bool
|
bool
|
||||||
saveConfig(const CConfig& config, bool sysOnly)
|
saveConfig(const CConfig& config, bool sysOnly)
|
||||||
{
|
{
|
||||||
CPlatform platform;
|
|
||||||
|
|
||||||
// try saving the user's configuration
|
// try saving the user's configuration
|
||||||
if (!sysOnly) {
|
if (!sysOnly) {
|
||||||
CString path = platform.getUserDirectory();
|
CString path = ARCH->getUserDirectory();
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
path = platform.addPathComponent(path, CONFIG_NAME);
|
path = ARCH->concatPath(path, CONFIG_NAME);
|
||||||
if (saveConfig(path, config)) {
|
if (saveConfig(path, config)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -198,9 +191,9 @@ saveConfig(const CConfig& config, bool sysOnly)
|
||||||
|
|
||||||
// try the system-wide config file
|
// try the system-wide config file
|
||||||
else {
|
else {
|
||||||
CString path = platform.getSystemDirectory();
|
CString path = ARCH->getSystemDirectory();
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
path = platform.addPathComponent(path, CONFIG_NAME);
|
path = ARCH->concatPath(path, CONFIG_NAME);
|
||||||
if (saveConfig(path, config)) {
|
if (saveConfig(path, config)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
|
|
||||||
#include "CConfig.h"
|
#include "CConfig.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "CPlatform.h"
|
|
||||||
#include "CNetwork.h"
|
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "CStringUtil.h"
|
||||||
|
#include "CArch.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
#include "stdvector.h"
|
#include "stdvector.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
@ -62,10 +62,26 @@ static const char* s_debugName[][2] = {
|
||||||
};
|
};
|
||||||
static const int s_defaultDebug = 3; // INFO
|
static const int s_defaultDebug = 3; // INFO
|
||||||
|
|
||||||
static HWND s_mainWindow;
|
//
|
||||||
static CConfig s_config;
|
// program arguments
|
||||||
static CConfig s_oldConfig;
|
//
|
||||||
static CStringList s_screens;
|
|
||||||
|
#define ARG CArgs::s_instance
|
||||||
|
|
||||||
|
class CArgs {
|
||||||
|
public:
|
||||||
|
CArgs() { s_instance = this; }
|
||||||
|
~CArgs() { s_instance = NULL; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
static CArgs* s_instance;
|
||||||
|
CConfig m_config;
|
||||||
|
CConfig m_oldConfig;
|
||||||
|
CStringList m_screens;
|
||||||
|
};
|
||||||
|
|
||||||
|
CArgs* CArgs::s_instance = NULL;
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
BOOL CALLBACK
|
BOOL CALLBACK
|
||||||
|
@ -117,7 +133,7 @@ static
|
||||||
void
|
void
|
||||||
enableSaveControls(HWND hwnd)
|
enableSaveControls(HWND hwnd)
|
||||||
{
|
{
|
||||||
enableItem(hwnd, IDC_MAIN_SAVE, s_config != s_oldConfig);
|
enableItem(hwnd, IDC_MAIN_SAVE, ARG->m_config != ARG->m_oldConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -171,8 +187,8 @@ updateNeighbor(HWND hwnd, const CString& screen, EDirection direction)
|
||||||
|
|
||||||
// add all screens to combo box
|
// add all screens to combo box
|
||||||
if (!screen.empty()) {
|
if (!screen.empty()) {
|
||||||
for (CConfig::const_iterator index = s_config.begin();
|
for (CConfig::const_iterator index = ARG->m_config.begin();
|
||||||
index != s_config.end(); ++index) {
|
index != ARG->m_config.end(); ++index) {
|
||||||
SendMessage(hwnd, CB_INSERTSTRING,
|
SendMessage(hwnd, CB_INSERTSTRING,
|
||||||
(WPARAM)-1, (LPARAM)index->c_str());
|
(WPARAM)-1, (LPARAM)index->c_str());
|
||||||
}
|
}
|
||||||
|
@ -184,7 +200,7 @@ updateNeighbor(HWND hwnd, const CString& screen, EDirection direction)
|
||||||
// select neighbor in combo box
|
// select neighbor in combo box
|
||||||
LRESULT index = 0;
|
LRESULT index = 0;
|
||||||
if (!screen.empty()) {
|
if (!screen.empty()) {
|
||||||
const CString& neighbor = s_config.getNeighbor(screen, direction);
|
const CString& neighbor = ARG->m_config.getNeighbor(screen, direction);
|
||||||
if (!neighbor.empty()) {
|
if (!neighbor.empty()) {
|
||||||
index = SendMessage(hwnd, CB_FINDSTRINGEXACT,
|
index = SendMessage(hwnd, CB_FINDSTRINGEXACT,
|
||||||
0, (LPARAM)neighbor.c_str());
|
0, (LPARAM)neighbor.c_str());
|
||||||
|
@ -205,7 +221,7 @@ updateNeighbors(HWND hwnd)
|
||||||
HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
|
HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
|
||||||
LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
|
LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
|
||||||
if (index != LB_ERR) {
|
if (index != LB_ERR) {
|
||||||
screen = s_screens[index];
|
screen = ARG->m_screens[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// set neighbor combo boxes
|
// set neighbor combo boxes
|
||||||
|
@ -230,7 +246,7 @@ addScreen(HWND hwnd)
|
||||||
if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
|
if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
|
||||||
hwnd, addDlgProc, (LPARAM)&info) != 0) {
|
hwnd, addDlgProc, (LPARAM)&info) != 0) {
|
||||||
// get current number of screens
|
// get current number of screens
|
||||||
UInt32 i = s_screens.size();
|
UInt32 i = ARG->m_screens.size();
|
||||||
|
|
||||||
// add screen to list control
|
// add screen to list control
|
||||||
HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
|
HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
|
||||||
|
@ -239,15 +255,15 @@ addScreen(HWND hwnd)
|
||||||
SendMessage(child, LB_ADDSTRING, 0, (LPARAM)item.c_str());
|
SendMessage(child, LB_ADDSTRING, 0, (LPARAM)item.c_str());
|
||||||
|
|
||||||
// add screen to screen list
|
// add screen to screen list
|
||||||
s_screens.push_back(info.m_screen);
|
ARG->m_screens.push_back(info.m_screen);
|
||||||
|
|
||||||
// add screen to config
|
// add screen to config
|
||||||
s_config.addScreen(info.m_screen);
|
ARG->m_config.addScreen(info.m_screen);
|
||||||
|
|
||||||
// add aliases to config
|
// add aliases to config
|
||||||
for (CStringList::const_iterator index = info.m_aliases.begin();
|
for (CStringList::const_iterator index = info.m_aliases.begin();
|
||||||
index != info.m_aliases.end(); ++index) {
|
index != info.m_aliases.end(); ++index) {
|
||||||
s_config.addAlias(info.m_screen, *index);
|
ARG->m_config.addAlias(info.m_screen, *index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update neighbors
|
// update neighbors
|
||||||
|
@ -271,9 +287,9 @@ editScreen(HWND hwnd)
|
||||||
|
|
||||||
// fill in screen info
|
// fill in screen info
|
||||||
CScreenInfo info;
|
CScreenInfo info;
|
||||||
info.m_screen = s_screens[index];
|
info.m_screen = ARG->m_screens[index];
|
||||||
for (CConfig::all_const_iterator index = s_config.beginAll();
|
for (CConfig::all_const_iterator index = ARG->m_config.beginAll();
|
||||||
index != s_config.endAll(); ++index) {
|
index != ARG->m_config.endAll(); ++index) {
|
||||||
if (CStringUtil::CaselessCmp::equal(index->second, info.m_screen) &&
|
if (CStringUtil::CaselessCmp::equal(index->second, info.m_screen) &&
|
||||||
!CStringUtil::CaselessCmp::equal(index->second, index->first)) {
|
!CStringUtil::CaselessCmp::equal(index->second, index->first)) {
|
||||||
info.m_aliases.push_back(index->first);
|
info.m_aliases.push_back(index->first);
|
||||||
|
@ -287,21 +303,21 @@ editScreen(HWND hwnd)
|
||||||
if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
|
if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
|
||||||
hwnd, addDlgProc, (LPARAM)&info) != 0) {
|
hwnd, addDlgProc, (LPARAM)&info) != 0) {
|
||||||
// replace screen
|
// replace screen
|
||||||
s_screens[index] = info.m_screen;
|
ARG->m_screens[index] = info.m_screen;
|
||||||
|
|
||||||
// remove old aliases
|
// remove old aliases
|
||||||
for (CStringList::const_iterator index = oldInfo.m_aliases.begin();
|
for (CStringList::const_iterator index = oldInfo.m_aliases.begin();
|
||||||
index != oldInfo.m_aliases.end(); ++index) {
|
index != oldInfo.m_aliases.end(); ++index) {
|
||||||
s_config.removeAlias(*index);
|
ARG->m_config.removeAlias(*index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace name
|
// replace name
|
||||||
s_config.renameScreen(oldInfo.m_screen, info.m_screen);
|
ARG->m_config.renameScreen(oldInfo.m_screen, info.m_screen);
|
||||||
|
|
||||||
// add new aliases
|
// add new aliases
|
||||||
for (CStringList::const_iterator index = info.m_aliases.begin();
|
for (CStringList::const_iterator index = info.m_aliases.begin();
|
||||||
index != info.m_aliases.end(); ++index) {
|
index != info.m_aliases.end(); ++index) {
|
||||||
s_config.addAlias(info.m_screen, *index);
|
ARG->m_config.addAlias(info.m_screen, *index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update list
|
// update list
|
||||||
|
@ -331,16 +347,16 @@ removeScreen(HWND hwnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get screen name
|
// get screen name
|
||||||
CString name = s_screens[index];
|
CString name = ARG->m_screens[index];
|
||||||
|
|
||||||
// remove screen from list control
|
// remove screen from list control
|
||||||
SendMessage(child, LB_DELETESTRING, index, 0);
|
SendMessage(child, LB_DELETESTRING, index, 0);
|
||||||
|
|
||||||
// remove screen from screen list
|
// remove screen from screen list
|
||||||
s_screens.erase(&s_screens[index]);
|
ARG->m_screens.erase(&ARG->m_screens[index]);
|
||||||
|
|
||||||
// remove screen from config (this also removes aliases)
|
// remove screen from config (this also removes aliases)
|
||||||
s_config.removeScreen(name);
|
ARG->m_config.removeScreen(name);
|
||||||
|
|
||||||
// update neighbors
|
// update neighbors
|
||||||
updateNeighbors(hwnd);
|
updateNeighbors(hwnd);
|
||||||
|
@ -361,20 +377,20 @@ changeNeighbor(HWND hwnd, HWND combo, EDirection direction)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get screen name
|
// get screen name
|
||||||
CString screen = s_screens[index];
|
CString screen = ARG->m_screens[index];
|
||||||
|
|
||||||
// get selected neighbor
|
// get selected neighbor
|
||||||
index = SendMessage(combo, CB_GETCURSEL, 0, 0);
|
index = SendMessage(combo, CB_GETCURSEL, 0, 0);
|
||||||
|
|
||||||
// remove old connection
|
// remove old connection
|
||||||
s_config.disconnect(screen, direction);
|
ARG->m_config.disconnect(screen, direction);
|
||||||
|
|
||||||
// add new connection
|
// add new connection
|
||||||
if (index != LB_ERR && index != 0) {
|
if (index != LB_ERR && index != 0) {
|
||||||
LRESULT size = SendMessage(combo, CB_GETLBTEXTLEN, index, 0);
|
LRESULT size = SendMessage(combo, CB_GETLBTEXTLEN, index, 0);
|
||||||
char* neighbor = new char[size + 1];
|
char* neighbor = new char[size + 1];
|
||||||
SendMessage(combo, CB_GETLBTEXT, index, (LPARAM)neighbor);
|
SendMessage(combo, CB_GETLBTEXT, index, (LPARAM)neighbor);
|
||||||
s_config.connect(screen, direction, CString(neighbor));
|
ARG->m_config.connect(screen, direction, CString(neighbor));
|
||||||
delete[] neighbor;
|
delete[] neighbor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,14 +460,14 @@ getCommandLine(HWND hwnd, bool testing)
|
||||||
// get and verify screen name
|
// get and verify screen name
|
||||||
HWND child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
|
HWND child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
|
||||||
CString name = getWindowText(child);
|
CString name = getWindowText(child);
|
||||||
if (!s_config.isValidScreenName(name)) {
|
if (!ARG->m_config.isValidScreenName(name)) {
|
||||||
showError(hwnd, CStringUtil::format(
|
showError(hwnd, CStringUtil::format(
|
||||||
getString(IDS_INVALID_SCREEN_NAME).c_str(),
|
getString(IDS_INVALID_SCREEN_NAME).c_str(),
|
||||||
name.c_str()));
|
name.c_str()));
|
||||||
SetFocus(child);
|
SetFocus(child);
|
||||||
return CString();
|
return CString();
|
||||||
}
|
}
|
||||||
if (!isClient && !s_config.isScreen(name)) {
|
if (!isClient && !ARG->m_config.isScreen(name)) {
|
||||||
showError(hwnd, CStringUtil::format(
|
showError(hwnd, CStringUtil::format(
|
||||||
getString(IDS_UNKNOWN_SCREEN_NAME).c_str(),
|
getString(IDS_UNKNOWN_SCREEN_NAME).c_str(),
|
||||||
name.c_str()));
|
name.c_str()));
|
||||||
|
@ -490,7 +506,7 @@ getCommandLine(HWND hwnd, bool testing)
|
||||||
// check server name
|
// check server name
|
||||||
child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
|
child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
|
||||||
CString server = getWindowText(child);
|
CString server = getWindowText(child);
|
||||||
if (!s_config.isValidScreenName(server)) {
|
if (!ARG->m_config.isValidScreenName(server)) {
|
||||||
showError(hwnd, CStringUtil::format(
|
showError(hwnd, CStringUtil::format(
|
||||||
getString(IDS_INVALID_SERVER_NAME).c_str(),
|
getString(IDS_INVALID_SERVER_NAME).c_str(),
|
||||||
server.c_str()));
|
server.c_str()));
|
||||||
|
@ -649,15 +665,13 @@ static
|
||||||
void
|
void
|
||||||
initMainWindow(HWND hwnd)
|
initMainWindow(HWND hwnd)
|
||||||
{
|
{
|
||||||
CPlatform platform;
|
|
||||||
|
|
||||||
// append version number to title
|
// append version number to title
|
||||||
CString titleFormat = getString(IDS_TITLE);
|
CString titleFormat = getString(IDS_TITLE);
|
||||||
setWindowText(hwnd, CStringUtil::format(titleFormat.c_str(), VERSION));
|
setWindowText(hwnd, CStringUtil::format(titleFormat.c_str(), VERSION));
|
||||||
|
|
||||||
// load configuration
|
// load configuration
|
||||||
bool configLoaded = loadConfig(s_config);
|
bool configLoaded = loadConfig(ARG->m_config);
|
||||||
s_oldConfig = s_config;
|
ARG->m_oldConfig = ARG->m_config;
|
||||||
enableSaveControls(hwnd);
|
enableSaveControls(hwnd);
|
||||||
|
|
||||||
// choose client/server radio buttons
|
// choose client/server radio buttons
|
||||||
|
@ -673,9 +687,9 @@ initMainWindow(HWND hwnd)
|
||||||
if (configLoaded) {
|
if (configLoaded) {
|
||||||
int i = 1;
|
int i = 1;
|
||||||
child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
|
child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
|
||||||
for (CConfig::const_iterator index = s_config.begin();
|
for (CConfig::const_iterator index = ARG->m_config.begin();
|
||||||
index != s_config.end(); ++i, ++index) {
|
index != ARG->m_config.end(); ++i, ++index) {
|
||||||
s_screens.push_back(*index);
|
ARG->m_screens.push_back(*index);
|
||||||
CString item = CStringUtil::print("%d. %s", i, index->c_str());
|
CString item = CStringUtil::print("%d. %s", i, index->c_str());
|
||||||
SendMessage(child, LB_ADDSTRING, 0, (LPARAM)item.c_str());
|
SendMessage(child, LB_ADDSTRING, 0, (LPARAM)item.c_str());
|
||||||
}
|
}
|
||||||
|
@ -687,9 +701,9 @@ initMainWindow(HWND hwnd)
|
||||||
child = getItem(hwnd, IDC_MAIN_ADVANCED_PORT_EDIT);
|
child = getItem(hwnd, IDC_MAIN_ADVANCED_PORT_EDIT);
|
||||||
SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
|
SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
|
||||||
|
|
||||||
CNetwork::gethostname(buffer, sizeof(buffer));
|
CString hostname = ARCH->getHostName();
|
||||||
child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
|
child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
|
||||||
SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
|
SendMessage(child, WM_SETTEXT, 0, (LPARAM)hostname.c_str());
|
||||||
|
|
||||||
child = getItem(hwnd, IDC_MAIN_DEBUG);
|
child = getItem(hwnd, IDC_MAIN_DEBUG);
|
||||||
for (unsigned int i = 0; i < sizeof(s_debugName) /
|
for (unsigned int i = 0; i < sizeof(s_debugName) /
|
||||||
|
@ -746,7 +760,7 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
tokenize(newAliases, getWindowText(child));
|
tokenize(newAliases, getWindowText(child));
|
||||||
|
|
||||||
// name must be valid
|
// name must be valid
|
||||||
if (!s_config.isValidScreenName(newName)) {
|
if (!ARG->m_config.isValidScreenName(newName)) {
|
||||||
showError(hwnd, CStringUtil::format(
|
showError(hwnd, CStringUtil::format(
|
||||||
getString(IDS_INVALID_SCREEN_NAME).c_str(),
|
getString(IDS_INVALID_SCREEN_NAME).c_str(),
|
||||||
newName.c_str()));
|
newName.c_str()));
|
||||||
|
@ -756,7 +770,7 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
// aliases must be valid
|
// aliases must be valid
|
||||||
for (CStringList::const_iterator index = newAliases.begin();
|
for (CStringList::const_iterator index = newAliases.begin();
|
||||||
index != newAliases.end(); ++index) {
|
index != newAliases.end(); ++index) {
|
||||||
if (!s_config.isValidScreenName(*index)) {
|
if (!ARG->m_config.isValidScreenName(*index)) {
|
||||||
showError(hwnd, CStringUtil::format(
|
showError(hwnd, CStringUtil::format(
|
||||||
getString(IDS_INVALID_SCREEN_NAME).c_str(),
|
getString(IDS_INVALID_SCREEN_NAME).c_str(),
|
||||||
index->c_str()));
|
index->c_str()));
|
||||||
|
@ -775,7 +789,7 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
// name must not exist in config but allow same name. also
|
// name must not exist in config but allow same name. also
|
||||||
// allow name if it exists in the old alias list but not the
|
// allow name if it exists in the old alias list but not the
|
||||||
// new one.
|
// new one.
|
||||||
if (s_config.isScreen(newName) &&
|
if (ARG->m_config.isScreen(newName) &&
|
||||||
!CStringUtil::CaselessCmp::equal(newName, info->m_screen) &&
|
!CStringUtil::CaselessCmp::equal(newName, info->m_screen) &&
|
||||||
!isNameInList(info->m_aliases, newName)) {
|
!isNameInList(info->m_aliases, newName)) {
|
||||||
showError(hwnd, CStringUtil::format(
|
showError(hwnd, CStringUtil::format(
|
||||||
|
@ -788,7 +802,7 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
// allow an alias to be the old name.
|
// allow an alias to be the old name.
|
||||||
for (CStringList::const_iterator index = newAliases.begin();
|
for (CStringList::const_iterator index = newAliases.begin();
|
||||||
index != newAliases.end(); ++index) {
|
index != newAliases.end(); ++index) {
|
||||||
if (s_config.isScreen(*index) &&
|
if (ARG->m_config.isScreen(*index) &&
|
||||||
!CStringUtil::CaselessCmp::equal(*index, info->m_screen) &&
|
!CStringUtil::CaselessCmp::equal(*index, info->m_screen) &&
|
||||||
!isNameInList(info->m_aliases, *index)) {
|
!isNameInList(info->m_aliases, *index)) {
|
||||||
showError(hwnd, CStringUtil::format(
|
showError(hwnd, CStringUtil::format(
|
||||||
|
@ -830,7 +844,7 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
switch (LOWORD(wParam)) {
|
switch (LOWORD(wParam)) {
|
||||||
case IDCANCEL:
|
case IDCANCEL:
|
||||||
// test for unsaved data
|
// test for unsaved data
|
||||||
if (s_config != s_oldConfig) {
|
if (ARG->m_config != ARG->m_oldConfig) {
|
||||||
if (!askVerify(hwnd, getString(IDS_UNSAVED_DATA_REALLY_QUIT))) {
|
if (!askVerify(hwnd, getString(IDS_UNSAVED_DATA_REALLY_QUIT))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -846,14 +860,14 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
const bool testing = (LOWORD(wParam) == IDC_MAIN_TEST);
|
const bool testing = (LOWORD(wParam) == IDC_MAIN_TEST);
|
||||||
|
|
||||||
// save data
|
// save data
|
||||||
if (s_config != s_oldConfig) {
|
if (ARG->m_config != ARG->m_oldConfig) {
|
||||||
if (!saveConfig(s_config, false)) {
|
if (!saveConfig(ARG->m_config, false)) {
|
||||||
showError(hwnd, CStringUtil::format(
|
showError(hwnd, CStringUtil::format(
|
||||||
getString(IDS_SAVE_FAILED).c_str(),
|
getString(IDS_SAVE_FAILED).c_str(),
|
||||||
getErrorString(GetLastError()).c_str()));
|
getErrorString(GetLastError()).c_str()));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
s_oldConfig = s_config;
|
ARG->m_oldConfig = ARG->m_config;
|
||||||
enableSaveControls(hwnd);
|
enableSaveControls(hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -892,11 +906,11 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
if (!cmdLine.empty()) {
|
if (!cmdLine.empty()) {
|
||||||
// run dialog
|
// run dialog
|
||||||
CAutoStart autoStart(hwnd,
|
CAutoStart autoStart(hwnd,
|
||||||
isClientChecked(hwnd) ? NULL : &s_config,
|
isClientChecked(hwnd) ? NULL : &ARG->m_config,
|
||||||
cmdLine);
|
cmdLine);
|
||||||
autoStart.doModal();
|
autoStart.doModal();
|
||||||
if (autoStart.wasUserConfigSaved()) {
|
if (autoStart.wasUserConfigSaved()) {
|
||||||
s_oldConfig = s_config;
|
ARG->m_oldConfig = ARG->m_config;
|
||||||
enableSaveControls(hwnd);
|
enableSaveControls(hwnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -904,13 +918,13 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
case IDC_MAIN_SAVE:
|
case IDC_MAIN_SAVE:
|
||||||
if (!saveConfig(s_config, false)) {
|
if (!saveConfig(ARG->m_config, false)) {
|
||||||
showError(hwnd, CStringUtil::format(
|
showError(hwnd, CStringUtil::format(
|
||||||
getString(IDS_SAVE_FAILED).c_str(),
|
getString(IDS_SAVE_FAILED).c_str(),
|
||||||
getErrorString(GetLastError()).c_str()));
|
getErrorString(GetLastError()).c_str()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
s_oldConfig = s_config;
|
ARG->m_oldConfig = ARG->m_config;
|
||||||
enableSaveControls(hwnd);
|
enableSaveControls(hwnd);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -981,10 +995,11 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
int WINAPI
|
int WINAPI
|
||||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
||||||
{
|
{
|
||||||
s_instance = instance;
|
CArch arch;
|
||||||
|
CLOG;
|
||||||
|
CArgs args;
|
||||||
|
|
||||||
// initialize network library
|
s_instance = instance;
|
||||||
CNetwork::init();
|
|
||||||
|
|
||||||
// register main window (dialog) class
|
// register main window (dialog) class
|
||||||
WNDCLASSEX classInfo;
|
WNDCLASSEX classInfo;
|
||||||
|
@ -1009,13 +1024,14 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
||||||
RegisterClassEx(&classInfo);
|
RegisterClassEx(&classInfo);
|
||||||
|
|
||||||
// create main window
|
// create main window
|
||||||
s_mainWindow = CreateDialog(s_instance, MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
|
HWND m_mainWindow = CreateDialog(s_instance,
|
||||||
|
MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
|
||||||
|
|
||||||
// prep window
|
// prep window
|
||||||
initMainWindow(s_mainWindow);
|
initMainWindow(m_mainWindow);
|
||||||
|
|
||||||
// show window
|
// show window
|
||||||
ShowWindow(s_mainWindow, nCmdShow);
|
ShowWindow(m_mainWindow, nCmdShow);
|
||||||
|
|
||||||
// main loop
|
// main loop
|
||||||
MSG msg;
|
MSG msg;
|
||||||
|
@ -1032,7 +1048,7 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (!IsDialogMessage(s_mainWindow, &msg)) {
|
if (!IsDialogMessage(m_mainWindow, &msg)) {
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ RSC=rc.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||||
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
@ -71,7 +71,7 @@ LINK32=link.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||||
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
|
|
@ -241,8 +241,8 @@ BEGIN
|
||||||
"Synergy is not configured to start automatically."
|
"Synergy is not configured to start automatically."
|
||||||
IDS_INSTALL_LABEL "Install"
|
IDS_INSTALL_LABEL "Install"
|
||||||
IDS_UNINSTALL_LABEL "Uninstall"
|
IDS_UNINSTALL_LABEL "Uninstall"
|
||||||
IDS_INSTALL_GENERIC_ERROR "Install failed for an unknown reason."
|
IDS_INSTALL_GENERIC_ERROR "Install failed: %{1}."
|
||||||
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed for an unknown reason."
|
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed: %{1}."
|
||||||
IDS_INSTALL_TITLE "Installed Auto-Start"
|
IDS_INSTALL_TITLE "Installed Auto-Start"
|
||||||
IDS_INSTALLED_SYSTEM "Installed auto-start. Synergy will now automatically start each time you start your computer."
|
IDS_INSTALLED_SYSTEM "Installed auto-start. Synergy will now automatically start each time you start your computer."
|
||||||
IDS_INSTALLED_USER "Installed auto-start. Synergy will now automatically start each time you log in."
|
IDS_INSTALLED_USER "Installed auto-start. Synergy will now automatically start each time you log in."
|
||||||
|
|
|
@ -38,6 +38,7 @@ synergyc_LDADD = \
|
||||||
$(DEPTH)/lib/io/libio.a \
|
$(DEPTH)/lib/io/libio.a \
|
||||||
$(DEPTH)/lib/mt/libmt.a \
|
$(DEPTH)/lib/mt/libmt.a \
|
||||||
$(DEPTH)/lib/base/libbase.a \
|
$(DEPTH)/lib/base/libbase.a \
|
||||||
|
$(DEPTH)/lib/arch/libarch.a \
|
||||||
$(X_LIBS) \
|
$(X_LIBS) \
|
||||||
$(X_PRE_LIBS) \
|
$(X_PRE_LIBS) \
|
||||||
-lXtst \
|
-lXtst \
|
||||||
|
@ -46,6 +47,8 @@ synergyc_LDADD = \
|
||||||
$(X_EXTRA_LIBS) \
|
$(X_EXTRA_LIBS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
|
-I$(VDEPTH)/lib/common \
|
||||||
|
-I$(VDEPTH)/lib/arch \
|
||||||
-I$(VDEPTH)/lib/base \
|
-I$(VDEPTH)/lib/base \
|
||||||
-I$(VDEPTH)/lib/mt \
|
-I$(VDEPTH)/lib/mt \
|
||||||
-I$(VDEPTH)/lib/io \
|
-I$(VDEPTH)/lib/io \
|
||||||
|
|
|
@ -14,11 +14,9 @@
|
||||||
|
|
||||||
#include "CClient.h"
|
#include "CClient.h"
|
||||||
#include "ISecondaryScreenFactory.h"
|
#include "ISecondaryScreenFactory.h"
|
||||||
#include "CPlatform.h"
|
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
#include "XScreen.h"
|
#include "XScreen.h"
|
||||||
#include "CNetwork.h"
|
|
||||||
#include "CNetworkAddress.h"
|
#include "CNetworkAddress.h"
|
||||||
#include "CTCPSocketFactory.h"
|
#include "CTCPSocketFactory.h"
|
||||||
#include "XSocket.h"
|
#include "XSocket.h"
|
||||||
|
@ -28,12 +26,18 @@
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "XThread.h"
|
#include "XThread.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "LogOutputters.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#define DAEMON_RUNNING(running_)
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
#include "CMSWindowsSecondaryScreen.h"
|
#include "CMSWindowsSecondaryScreen.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
#undef DAEMON_RUNNING
|
||||||
|
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
#include "CXWindowsSecondaryScreen.h"
|
#include "CXWindowsSecondaryScreen.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -49,35 +53,33 @@
|
||||||
// program arguments
|
// program arguments
|
||||||
//
|
//
|
||||||
|
|
||||||
static const char* pname = NULL;
|
#define ARG CArgs::s_instance
|
||||||
static bool s_backend = false;
|
|
||||||
static bool s_restartable = true;
|
|
||||||
static bool s_daemon = true;
|
|
||||||
static bool s_camp = true;
|
|
||||||
static const char* s_logFilter = NULL;
|
|
||||||
static CString s_name;
|
|
||||||
static CNetworkAddress s_serverAddress;
|
|
||||||
|
|
||||||
|
class CArgs {
|
||||||
|
public:
|
||||||
|
CArgs() :
|
||||||
|
m_pname(NULL),
|
||||||
|
m_backend(false),
|
||||||
|
m_restartable(true),
|
||||||
|
m_daemon(true),
|
||||||
|
m_camp(true),
|
||||||
|
m_logFilter(NULL)
|
||||||
|
{ s_instance = this; }
|
||||||
|
~CArgs() { s_instance = NULL; }
|
||||||
|
|
||||||
//
|
public:
|
||||||
// logging thread safety
|
static CArgs* s_instance;
|
||||||
//
|
const char* m_pname;
|
||||||
|
bool m_backend;
|
||||||
|
bool m_restartable;
|
||||||
|
bool m_daemon;
|
||||||
|
bool m_camp;
|
||||||
|
const char* m_logFilter;
|
||||||
|
CString m_name;
|
||||||
|
CNetworkAddress m_serverAddress;
|
||||||
|
};
|
||||||
|
|
||||||
static CMutex* s_logMutex = NULL;
|
CArgs* CArgs::s_instance = NULL;
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
logLock(bool lock)
|
|
||||||
{
|
|
||||||
assert(s_logMutex != NULL);
|
|
||||||
|
|
||||||
if (lock) {
|
|
||||||
s_logMutex->lock();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s_logMutex->unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -113,27 +115,17 @@ static CClient* s_client = NULL;
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
realMain(CMutex* mutex)
|
realMain(void)
|
||||||
{
|
{
|
||||||
// caller should have mutex locked on entry
|
|
||||||
|
|
||||||
// initialize threading library
|
|
||||||
CThread::init();
|
|
||||||
|
|
||||||
// make logging thread safe
|
|
||||||
CMutex logMutex;
|
|
||||||
s_logMutex = &logMutex;
|
|
||||||
CLog::setLock(&logLock);
|
|
||||||
|
|
||||||
int result = kExitSuccess;
|
int result = kExitSuccess;
|
||||||
do {
|
do {
|
||||||
bool opened = false;
|
bool opened = false;
|
||||||
bool locked = true;
|
bool locked = true;
|
||||||
try {
|
try {
|
||||||
// create client
|
// create client
|
||||||
s_client = new CClient(s_name);
|
s_client = new CClient(ARG->m_name);
|
||||||
s_client->camp(s_camp);
|
s_client->camp(ARG->m_camp);
|
||||||
s_client->setAddress(s_serverAddress);
|
s_client->setAddress(ARG->m_serverAddress);
|
||||||
s_client->setScreenFactory(new CSecondaryScreenFactory);
|
s_client->setScreenFactory(new CSecondaryScreenFactory);
|
||||||
s_client->setSocketFactory(new CTCPSocketFactory);
|
s_client->setSocketFactory(new CTCPSocketFactory);
|
||||||
s_client->setStreamFilterFactory(NULL);
|
s_client->setStreamFilterFactory(NULL);
|
||||||
|
@ -144,9 +136,7 @@ realMain(CMutex* mutex)
|
||||||
opened = true;
|
opened = true;
|
||||||
|
|
||||||
// run client
|
// run client
|
||||||
if (mutex != NULL) {
|
DAEMON_RUNNING(true);
|
||||||
mutex->unlock();
|
|
||||||
}
|
|
||||||
locked = false;
|
locked = false;
|
||||||
s_client->mainLoop();
|
s_client->mainLoop();
|
||||||
locked = true;
|
locked = true;
|
||||||
|
@ -160,8 +150,8 @@ realMain(CMutex* mutex)
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
#define FINALLY do { \
|
#define FINALLY do { \
|
||||||
if (!locked && mutex != NULL) { \
|
if (!locked) { \
|
||||||
mutex->lock(); \
|
DAEMON_RUNNING(false); \
|
||||||
} \
|
} \
|
||||||
if (s_client != NULL) { \
|
if (s_client != NULL) { \
|
||||||
if (opened) { \
|
if (opened) { \
|
||||||
|
@ -175,8 +165,8 @@ realMain(CMutex* mutex)
|
||||||
}
|
}
|
||||||
catch (XScreenUnavailable& e) {
|
catch (XScreenUnavailable& e) {
|
||||||
// wait before retrying if we're going to retry
|
// wait before retrying if we're going to retry
|
||||||
if (s_restartable) {
|
if (ARG->m_restartable) {
|
||||||
CThread::sleep(e.getRetryTime());
|
ARCH->sleep(e.getRetryTime());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = kExitFailed;
|
result = kExitFailed;
|
||||||
|
@ -189,7 +179,7 @@ realMain(CMutex* mutex)
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
// don't try to restart and fail
|
// don't try to restart and fail
|
||||||
s_restartable = false;
|
ARG->m_restartable = false;
|
||||||
result = kExitFailed;
|
result = kExitFailed;
|
||||||
FINALLY;
|
FINALLY;
|
||||||
}
|
}
|
||||||
|
@ -200,19 +190,10 @@ realMain(CMutex* mutex)
|
||||||
}
|
}
|
||||||
catch (XThread&) {
|
catch (XThread&) {
|
||||||
// terminated
|
// terminated
|
||||||
s_restartable = false;
|
ARG->m_restartable = false;
|
||||||
result = kExitTerminated;
|
result = kExitTerminated;
|
||||||
}
|
}
|
||||||
catch (...) {
|
} while (ARG->m_restartable);
|
||||||
CLog::setLock(NULL);
|
|
||||||
s_logMutex = NULL;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
} while (s_restartable);
|
|
||||||
|
|
||||||
// clean up
|
|
||||||
CLog::setLock(NULL);
|
|
||||||
s_logMutex = NULL;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -233,7 +214,7 @@ version()
|
||||||
LOG((CLOG_PRINT
|
LOG((CLOG_PRINT
|
||||||
"%s %s, protocol version %d.%d\n"
|
"%s %s, protocol version %d.%d\n"
|
||||||
"%s",
|
"%s",
|
||||||
pname,
|
ARG->m_pname,
|
||||||
kVersion,
|
kVersion,
|
||||||
kProtocolMajorVersion,
|
kProtocolMajorVersion,
|
||||||
kProtocolMinorVersion,
|
kProtocolMinorVersion,
|
||||||
|
@ -279,7 +260,7 @@ help()
|
||||||
"\n"
|
"\n"
|
||||||
"Where log messages go depends on the platform and whether or not the\n"
|
"Where log messages go depends on the platform and whether or not the\n"
|
||||||
"client is running as a daemon.",
|
"client is running as a daemon.",
|
||||||
pname, kDefaultPort));
|
ARG->m_pname, kDefaultPort));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +275,7 @@ isArg(int argi, int argc, const char** argv,
|
||||||
// match. check args left.
|
// match. check args left.
|
||||||
if (argi + minRequiredParameters >= argc) {
|
if (argi + minRequiredParameters >= argc) {
|
||||||
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
||||||
pname, argv[argi], pname));
|
ARG->m_pname, argv[argi], ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -308,61 +289,58 @@ static
|
||||||
void
|
void
|
||||||
parse(int argc, const char** argv)
|
parse(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
assert(pname != NULL);
|
assert(ARG->m_pname != NULL);
|
||||||
assert(argv != NULL);
|
assert(argv != NULL);
|
||||||
assert(argc >= 1);
|
assert(argc >= 1);
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
char hostname[256];
|
ARG->m_name = ARCH->getHostName();
|
||||||
if (CNetwork::gethostname(hostname, sizeof(hostname)) != CNetwork::Error) {
|
|
||||||
s_name = hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse options
|
// parse options
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i < argc; ++i) {
|
for (i = 1; i < argc; ++i) {
|
||||||
if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
||||||
// change logging level
|
// change logging level
|
||||||
s_logFilter = argv[++i];
|
ARG->m_logFilter = argv[++i];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
||||||
// save screen name
|
// save screen name
|
||||||
s_name = argv[++i];
|
ARG->m_name = argv[++i];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--camp")) {
|
else if (isArg(i, argc, argv, NULL, "--camp")) {
|
||||||
// enable camping
|
// enable camping
|
||||||
s_camp = true;
|
ARG->m_camp = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--no-camp")) {
|
else if (isArg(i, argc, argv, NULL, "--no-camp")) {
|
||||||
// disable camping
|
// disable camping
|
||||||
s_camp = false;
|
ARG->m_camp = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
||||||
// not a daemon
|
// not a daemon
|
||||||
s_daemon = false;
|
ARG->m_daemon = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
||||||
// daemonize
|
// daemonize
|
||||||
s_daemon = true;
|
ARG->m_daemon = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
||||||
// don't try to restart
|
// don't try to restart
|
||||||
s_restartable = false;
|
ARG->m_restartable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
||||||
// try to restart
|
// try to restart
|
||||||
s_restartable = true;
|
ARG->m_restartable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-z", NULL)) {
|
else if (isArg(i, argc, argv, "-z", NULL)) {
|
||||||
s_backend = true;
|
ARG->m_backend = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-h", "--help")) {
|
else if (isArg(i, argc, argv, "-h", "--help")) {
|
||||||
|
@ -383,7 +361,7 @@ parse(int argc, const char** argv)
|
||||||
|
|
||||||
else if (argv[i][0] == '-') {
|
else if (argv[i][0] == '-') {
|
||||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||||
pname, argv[i], pname));
|
ARG->m_pname, argv[i], ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,49 +374,60 @@ parse(int argc, const char** argv)
|
||||||
// exactly one non-option argument (server-address)
|
// exactly one non-option argument (server-address)
|
||||||
if (i == argc) {
|
if (i == argc) {
|
||||||
LOG((CLOG_PRINT "%s: a server address or name is required" BYE,
|
LOG((CLOG_PRINT "%s: a server address or name is required" BYE,
|
||||||
pname, pname));
|
ARG->m_pname, ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
if (i + 1 != argc) {
|
if (i + 1 != argc) {
|
||||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||||
pname, argv[i], pname));
|
ARG->m_pname, argv[i], ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// save server address
|
// save server address
|
||||||
try {
|
try {
|
||||||
s_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
|
ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
|
||||||
}
|
}
|
||||||
catch (XSocketAddress& e) {
|
catch (XSocketAddress& e) {
|
||||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||||
pname, e.what(), pname));
|
ARG->m_pname, e.what(), ARG->m_pname));
|
||||||
bye(kExitFailed);
|
bye(kExitFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// increase default filter level for daemon. the user must
|
// increase default filter level for daemon. the user must
|
||||||
// explicitly request another level for a daemon.
|
// explicitly request another level for a daemon.
|
||||||
if (s_daemon && s_logFilter == NULL) {
|
if (ARG->m_daemon && ARG->m_logFilter == NULL) {
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
if (CPlatform::isWindows95Family()) {
|
if (CArchMiscWindows::isWindows95Family()) {
|
||||||
// windows 95 has no place for logging so avoid showing
|
// windows 95 has no place for logging so avoid showing
|
||||||
// the log console window.
|
// the log console window.
|
||||||
s_logFilter = "FATAL";
|
ARG->m_logFilter = "FATAL";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
s_logFilter = "NOTE";
|
ARG->m_logFilter = "NOTE";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set log filter
|
// set log filter
|
||||||
if (!CLog::setFilter(s_logFilter)) {
|
if (!CLOG->setFilter(ARG->m_logFilter)) {
|
||||||
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
||||||
pname, s_logFilter, pname));
|
ARG->m_pname, ARG->m_logFilter, ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
useSystemLog()
|
||||||
|
{
|
||||||
|
// redirect log messages
|
||||||
|
ILogOutputter* logger = new CSystemLogOutputter;
|
||||||
|
logger->open(DAEMON_NAME);
|
||||||
|
CLOG->insert(new CStopLogOutputter);
|
||||||
|
CLOG->insert(logger);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// platform dependent entry points
|
// platform dependent entry points
|
||||||
//
|
//
|
||||||
|
@ -449,24 +438,41 @@ parse(int argc, const char** argv)
|
||||||
|
|
||||||
static bool s_hasImportantLogMessages = false;
|
static bool s_hasImportantLogMessages = false;
|
||||||
|
|
||||||
static
|
//
|
||||||
|
// CMessageBoxOutputter
|
||||||
|
//
|
||||||
|
// This class writes severe log messages to a message box
|
||||||
|
//
|
||||||
|
|
||||||
|
class CMessageBoxOutputter : public ILogOutputter {
|
||||||
|
public:
|
||||||
|
CMessageBoxOutputter() { }
|
||||||
|
virtual ~CMessageBoxOutputter() { }
|
||||||
|
|
||||||
|
// ILogOutputter overrides
|
||||||
|
virtual void open(const char*) { }
|
||||||
|
virtual void close() { }
|
||||||
|
virtual bool write(ELevel level, const char* message);
|
||||||
|
virtual const char* getNewline() const { return ""; }
|
||||||
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
logMessageBox(int priority, const char* msg)
|
CMessageBoxOutputter::write(ELevel level, const char* message)
|
||||||
{
|
{
|
||||||
// note any important messages the user may need to know about
|
// note any important messages the user may need to know about
|
||||||
if (priority <= CLog::kWARNING) {
|
if (level <= CLog::kWARNING) {
|
||||||
s_hasImportantLogMessages = true;
|
s_hasImportantLogMessages = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FATAL and PRINT messages get a dialog box if not running as
|
// FATAL and PRINT messages get a dialog box if not running as
|
||||||
// backend. if we're running as a backend the user will have
|
// backend. if we're running as a backend the user will have
|
||||||
// a chance to see the messages when we exit.
|
// a chance to see the messages when we exit.
|
||||||
if (!s_backend && priority <= CLog::kFATAL) {
|
if (!ARG->m_backend && level <= CLog::kFATAL) {
|
||||||
MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING);
|
MessageBox(NULL, message, ARG->m_pname, MB_OK | MB_ICONWARNING);
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +480,7 @@ static
|
||||||
void
|
void
|
||||||
byeThrow(int x)
|
byeThrow(int x)
|
||||||
{
|
{
|
||||||
throw CWin32Platform::CDaemonFailed(x);
|
CArchMiscWindows::daemonFailed(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -486,10 +492,9 @@ daemonStop(void)
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
daemonStartup(IPlatform* iplatform, int argc, const char** argv)
|
daemonStartup(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
// get platform pointer
|
useSystemLog();
|
||||||
CWin32Platform* platform = static_cast<CWin32Platform*>(iplatform);
|
|
||||||
|
|
||||||
// catch errors that would normally exit
|
// catch errors that would normally exit
|
||||||
bye = &byeThrow;
|
bye = &byeThrow;
|
||||||
|
@ -498,35 +503,35 @@ daemonStartup(IPlatform* iplatform, int argc, const char** argv)
|
||||||
parse(argc, argv);
|
parse(argc, argv);
|
||||||
|
|
||||||
// cannot run as backend if running as a service
|
// cannot run as backend if running as a service
|
||||||
s_backend = false;
|
ARG->m_backend = false;
|
||||||
|
|
||||||
// run as a service
|
// run as a service
|
||||||
return platform->runDaemon(realMain, daemonStop);
|
return CArchMiscWindows::runDaemon(realMain, daemonStop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
daemonStartup95(IPlatform*, int, const char**)
|
daemonStartup95(int, const char**)
|
||||||
{
|
{
|
||||||
return realMain(NULL);
|
useSystemLog();
|
||||||
|
return realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
int WINAPI
|
int WINAPI
|
||||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
{
|
{
|
||||||
CPlatform platform;
|
CArch arch;
|
||||||
|
CLOG;
|
||||||
|
CArgs args;
|
||||||
|
|
||||||
// save instance
|
// save instance
|
||||||
CMSWindowsScreen::init(instance);
|
CMSWindowsScreen::init(instance);
|
||||||
|
|
||||||
// get program name
|
// get program name
|
||||||
pname = platform.getBasename(__argv[0]);
|
ARG->m_pname = ARCH->getBasename(__argv[0]);
|
||||||
|
|
||||||
// initialize network library
|
|
||||||
CNetwork::init();
|
|
||||||
|
|
||||||
// send PRINT and FATAL output to a message box
|
// send PRINT and FATAL output to a message box
|
||||||
CLog::setOutputter(&logMessageBox);
|
CLOG->insert(new CMessageBoxOutputter);
|
||||||
|
|
||||||
// windows NT family starts services using no command line options.
|
// windows NT family starts services using no command line options.
|
||||||
// since i'm not sure how to tell the difference between that and
|
// since i'm not sure how to tell the difference between that and
|
||||||
|
@ -534,10 +539,10 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
// arguments and we're on NT then we're being invoked as a service.
|
// arguments and we're on NT then we're being invoked as a service.
|
||||||
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||||
// of the service code path.
|
// of the service code path.
|
||||||
if (__argc <= 1 && !CWin32Platform::isWindows95Family()) {
|
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||||
int result = platform.daemonize(DAEMON_NAME, &daemonStartup);
|
int result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
LOG((CLOG_CRIT "failed to start as a service" BYE, pname));
|
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
||||||
return kExitFailed;
|
return kExitFailed;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -548,38 +553,36 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
|
|
||||||
// daemonize if requested
|
// daemonize if requested
|
||||||
int result;
|
int result;
|
||||||
if (s_daemon) {
|
if (ARG->m_daemon) {
|
||||||
// redirect log messages
|
|
||||||
platform.installDaemonLogger(DAEMON_NAME);
|
|
||||||
|
|
||||||
// start as a daemon
|
// start as a daemon
|
||||||
if (CWin32Platform::isWindows95Family()) {
|
if (CArchMiscWindows::isWindows95Family()) {
|
||||||
result = platform.daemonize(DAEMON_NAME, &daemonStartup95);
|
try {
|
||||||
if (result == -1) {
|
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
||||||
LOG((CLOG_CRIT "failed to start as a service" BYE, pname));
|
}
|
||||||
|
catch (XArchDaemon&) {
|
||||||
|
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
||||||
result = kExitFailed;
|
result = kExitFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// cannot start a service from the command line so just
|
// cannot start a service from the command line so just
|
||||||
// run normally (except with log messages redirected).
|
// run normally (except with log messages redirected).
|
||||||
result = realMain(NULL);
|
useSystemLog();
|
||||||
|
result = realMain();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// run
|
// run
|
||||||
result = realMain(NULL);
|
result = realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
CNetwork::cleanup();
|
|
||||||
|
|
||||||
// let user examine any messages if we're running as a backend
|
// let user examine any messages if we're running as a backend
|
||||||
// by putting up a dialog box before exiting.
|
// by putting up a dialog box before exiting.
|
||||||
if (s_backend && s_hasImportantLogMessages) {
|
if (ARG->m_backend && s_hasImportantLogMessages) {
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
msg[0] = '\0';
|
msg[0] = '\0';
|
||||||
LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0]));
|
LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0]));
|
||||||
MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING);
|
MessageBox(NULL, msg, ARG->m_pname, MB_OK | MB_ICONWARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -589,40 +592,40 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
daemonStartup(IPlatform*, int, const char**)
|
daemonStartup(int, const char**)
|
||||||
{
|
{
|
||||||
return realMain(NULL);
|
useSystemLog();
|
||||||
|
return realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char** argv)
|
main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
CPlatform platform;
|
CArch arch;
|
||||||
|
CLOG;
|
||||||
|
CArgs args;
|
||||||
|
|
||||||
// get program name
|
// get program name
|
||||||
pname = platform.getBasename(argv[0]);
|
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
|
||||||
// initialize network library
|
|
||||||
CNetwork::init();
|
|
||||||
|
|
||||||
// parse command line
|
// parse command line
|
||||||
parse(argc, const_cast<const char**>(argv));
|
parse(argc, const_cast<const char**>(argv));
|
||||||
|
|
||||||
// daemonize if requested
|
// daemonize if requested
|
||||||
int result;
|
int result;
|
||||||
if (s_daemon) {
|
if (ARG->m_daemon) {
|
||||||
result = platform.daemonize(DAEMON_NAME, &daemonStartup);
|
try {
|
||||||
if (result == -1) {
|
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||||
|
}
|
||||||
|
catch (XArchDaemon&) {
|
||||||
LOG((CLOG_CRIT "failed to daemonize"));
|
LOG((CLOG_CRIT "failed to daemonize"));
|
||||||
return kExitFailed;
|
result = kExitFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = realMain(NULL);
|
result = realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
CNetwork::cleanup();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ RSC=rc.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||||
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
@ -54,7 +54,7 @@ BSC32=bscmake.exe
|
||||||
# ADD BSC32 /nologo
|
# ADD BSC32 /nologo
|
||||||
LINK32=link.exe
|
LINK32=link.exe
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"../../Release/synergyc.exe"
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "synergyc - Win32 Debug"
|
!ELSEIF "$(CFG)" == "synergyc - Win32 Debug"
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ LINK32=link.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||||
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
@ -81,7 +81,7 @@ BSC32=bscmake.exe
|
||||||
# ADD BSC32 /nologo
|
# ADD BSC32 /nologo
|
||||||
LINK32=link.exe
|
LINK32=link.exe
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"../../Debug/synergyc.exe" /pdbtype:sept
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||||
|
|
||||||
!ENDIF
|
!ENDIF
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ synergys_LDADD = \
|
||||||
$(DEPTH)/lib/io/libio.a \
|
$(DEPTH)/lib/io/libio.a \
|
||||||
$(DEPTH)/lib/mt/libmt.a \
|
$(DEPTH)/lib/mt/libmt.a \
|
||||||
$(DEPTH)/lib/base/libbase.a \
|
$(DEPTH)/lib/base/libbase.a \
|
||||||
|
$(DEPTH)/lib/arch/libarch.a \
|
||||||
$(X_LIBS) \
|
$(X_LIBS) \
|
||||||
$(X_PRE_LIBS) \
|
$(X_PRE_LIBS) \
|
||||||
-lXtst \
|
-lXtst \
|
||||||
|
@ -47,6 +48,8 @@ synergys_LDADD = \
|
||||||
$(X_EXTRA_LIBS) \
|
$(X_EXTRA_LIBS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
|
-I$(VDEPTH)/lib/common \
|
||||||
|
-I$(VDEPTH)/lib/arch \
|
||||||
-I$(VDEPTH)/lib/base \
|
-I$(VDEPTH)/lib/base \
|
||||||
-I$(VDEPTH)/lib/mt \
|
-I$(VDEPTH)/lib/mt \
|
||||||
-I$(VDEPTH)/lib/io \
|
-I$(VDEPTH)/lib/io \
|
||||||
|
|
|
@ -15,11 +15,9 @@
|
||||||
#include "CServer.h"
|
#include "CServer.h"
|
||||||
#include "CConfig.h"
|
#include "CConfig.h"
|
||||||
#include "IPrimaryScreenFactory.h"
|
#include "IPrimaryScreenFactory.h"
|
||||||
#include "CPlatform.h"
|
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
#include "XScreen.h"
|
#include "XScreen.h"
|
||||||
#include "CNetwork.h"
|
|
||||||
#include "CTCPSocketFactory.h"
|
#include "CTCPSocketFactory.h"
|
||||||
#include "XSocket.h"
|
#include "XSocket.h"
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
|
@ -27,12 +25,18 @@
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "XThread.h"
|
#include "XThread.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "LogOutputters.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
#include "stdfstream.h"
|
#include "stdfstream.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#define DAEMON_RUNNING(running_)
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
#include "CMSWindowsPrimaryScreen.h"
|
#include "CMSWindowsPrimaryScreen.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
#undef DAEMON_RUNNING
|
||||||
|
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
#include "CXWindowsPrimaryScreen.h"
|
#include "CXWindowsPrimaryScreen.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,37 +61,35 @@
|
||||||
// program arguments
|
// program arguments
|
||||||
//
|
//
|
||||||
|
|
||||||
static const char* pname = NULL;
|
#define ARG CArgs::s_instance
|
||||||
static bool s_backend = false;
|
|
||||||
static bool s_restartable = true;
|
|
||||||
static bool s_daemon = true;
|
|
||||||
static const char* s_configFile = NULL;
|
|
||||||
static const char* s_logFilter = NULL;
|
|
||||||
static CString s_name;
|
|
||||||
static CNetworkAddress s_synergyAddress;
|
|
||||||
static CNetworkAddress s_httpAddress;
|
|
||||||
static CConfig s_config;
|
|
||||||
|
|
||||||
|
class CArgs {
|
||||||
|
public:
|
||||||
|
CArgs() :
|
||||||
|
m_pname(NULL),
|
||||||
|
m_backend(false),
|
||||||
|
m_restartable(true),
|
||||||
|
m_daemon(true),
|
||||||
|
m_configFile(NULL),
|
||||||
|
m_logFilter(NULL)
|
||||||
|
{ s_instance = this; }
|
||||||
|
~CArgs() { s_instance = NULL; }
|
||||||
|
|
||||||
//
|
public:
|
||||||
// logging thread safety
|
static CArgs* s_instance;
|
||||||
//
|
const char* m_pname;
|
||||||
|
bool m_backend;
|
||||||
|
bool m_restartable;
|
||||||
|
bool m_daemon;
|
||||||
|
const char* m_configFile;
|
||||||
|
const char* m_logFilter;
|
||||||
|
CString m_name;
|
||||||
|
CNetworkAddress m_synergyAddress;
|
||||||
|
CNetworkAddress m_httpAddress;
|
||||||
|
CConfig m_config;
|
||||||
|
};
|
||||||
|
|
||||||
static CMutex* s_logMutex = NULL;
|
CArgs* CArgs::s_instance = NULL;
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
logLock(bool lock)
|
|
||||||
{
|
|
||||||
assert(s_logMutex != NULL);
|
|
||||||
|
|
||||||
if (lock) {
|
|
||||||
s_logMutex->lock();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s_logMutex->unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -124,18 +126,8 @@ static CServer* s_server = NULL;
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
realMain(CMutex* mutex)
|
realMain(void)
|
||||||
{
|
{
|
||||||
// caller should have mutex locked on entry
|
|
||||||
|
|
||||||
// initialize threading library
|
|
||||||
CThread::init();
|
|
||||||
|
|
||||||
// make logging thread safe
|
|
||||||
CMutex logMutex;
|
|
||||||
s_logMutex = &logMutex;
|
|
||||||
CLog::setLock(&logLock);
|
|
||||||
|
|
||||||
int result = kExitSuccess;
|
int result = kExitSuccess;
|
||||||
do {
|
do {
|
||||||
bool opened = false;
|
bool opened = false;
|
||||||
|
@ -143,28 +135,28 @@ realMain(CMutex* mutex)
|
||||||
try {
|
try {
|
||||||
// if configuration has no screens then add this system
|
// if configuration has no screens then add this system
|
||||||
// as the default
|
// as the default
|
||||||
if (s_config.begin() == s_config.end()) {
|
if (ARG->m_config.begin() == ARG->m_config.end()) {
|
||||||
s_config.addScreen(s_name);
|
ARG->m_config.addScreen(ARG->m_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the contact address, if provided, in the config.
|
// set the contact address, if provided, in the config.
|
||||||
// otherwise, if the config doesn't have an address, use
|
// otherwise, if the config doesn't have an address, use
|
||||||
// the default.
|
// the default.
|
||||||
if (s_synergyAddress.isValid()) {
|
if (ARG->m_synergyAddress.isValid()) {
|
||||||
s_config.setSynergyAddress(s_synergyAddress);
|
ARG->m_config.setSynergyAddress(ARG->m_synergyAddress);
|
||||||
}
|
}
|
||||||
else if (!s_config.getSynergyAddress().isValid()) {
|
else if (!ARG->m_config.getSynergyAddress().isValid()) {
|
||||||
s_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
|
ARG->m_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
|
||||||
}
|
}
|
||||||
|
|
||||||
// set HTTP address if provided
|
// set HTTP address if provided
|
||||||
if (s_httpAddress.isValid()) {
|
if (ARG->m_httpAddress.isValid()) {
|
||||||
s_config.setHTTPAddress(s_httpAddress);
|
ARG->m_config.setHTTPAddress(ARG->m_httpAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create server
|
// create server
|
||||||
s_server = new CServer(s_name);
|
s_server = new CServer(ARG->m_name);
|
||||||
s_server->setConfig(s_config);
|
s_server->setConfig(ARG->m_config);
|
||||||
s_server->setScreenFactory(new CPrimaryScreenFactory);
|
s_server->setScreenFactory(new CPrimaryScreenFactory);
|
||||||
s_server->setSocketFactory(new CTCPSocketFactory);
|
s_server->setSocketFactory(new CTCPSocketFactory);
|
||||||
s_server->setStreamFilterFactory(NULL);
|
s_server->setStreamFilterFactory(NULL);
|
||||||
|
@ -174,18 +166,16 @@ realMain(CMutex* mutex)
|
||||||
s_server->open();
|
s_server->open();
|
||||||
opened = true;
|
opened = true;
|
||||||
|
|
||||||
// run server (unlocked)
|
// run server
|
||||||
if (mutex != NULL) {
|
DAEMON_RUNNING(true);
|
||||||
mutex->unlock();
|
|
||||||
}
|
|
||||||
locked = false;
|
locked = false;
|
||||||
s_server->mainLoop();
|
s_server->mainLoop();
|
||||||
locked = true;
|
locked = true;
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
#define FINALLY do { \
|
#define FINALLY do { \
|
||||||
if (!locked && mutex != NULL) { \
|
if (!locked) { \
|
||||||
mutex->lock(); \
|
DAEMON_RUNNING(false); \
|
||||||
} \
|
} \
|
||||||
if (s_server != NULL) { \
|
if (s_server != NULL) { \
|
||||||
if (opened) { \
|
if (opened) { \
|
||||||
|
@ -199,8 +189,8 @@ realMain(CMutex* mutex)
|
||||||
}
|
}
|
||||||
catch (XScreenUnavailable& e) {
|
catch (XScreenUnavailable& e) {
|
||||||
// wait before retrying if we're going to retry
|
// wait before retrying if we're going to retry
|
||||||
if (s_restartable) {
|
if (ARG->m_restartable) {
|
||||||
CThread::sleep(e.getRetryTime());
|
ARCH->sleep(e.getRetryTime());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = kExitFailed;
|
result = kExitFailed;
|
||||||
|
@ -213,7 +203,7 @@ realMain(CMutex* mutex)
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
// don't try to restart and fail
|
// don't try to restart and fail
|
||||||
s_restartable = false;
|
ARG->m_restartable = false;
|
||||||
result = kExitFailed;
|
result = kExitFailed;
|
||||||
FINALLY;
|
FINALLY;
|
||||||
}
|
}
|
||||||
|
@ -224,19 +214,10 @@ realMain(CMutex* mutex)
|
||||||
}
|
}
|
||||||
catch (XThread&) {
|
catch (XThread&) {
|
||||||
// terminated
|
// terminated
|
||||||
s_restartable = false;
|
ARG->m_restartable = false;
|
||||||
result = kExitTerminated;
|
result = kExitTerminated;
|
||||||
}
|
}
|
||||||
catch (...) {
|
} while (ARG->m_restartable);
|
||||||
CLog::setLock(NULL);
|
|
||||||
s_logMutex = NULL;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
} while (s_restartable);
|
|
||||||
|
|
||||||
// clean up
|
|
||||||
CLog::setLock(NULL);
|
|
||||||
s_logMutex = NULL;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -257,7 +238,7 @@ version()
|
||||||
LOG((CLOG_PRINT
|
LOG((CLOG_PRINT
|
||||||
"%s %s, protocol version %d.%d\n"
|
"%s %s, protocol version %d.%d\n"
|
||||||
"%s",
|
"%s",
|
||||||
pname,
|
ARG->m_pname,
|
||||||
kVersion,
|
kVersion,
|
||||||
kProtocolMajorVersion,
|
kProtocolMajorVersion,
|
||||||
kProtocolMinorVersion,
|
kProtocolMinorVersion,
|
||||||
|
@ -287,8 +268,6 @@ help()
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CPlatform platform;
|
|
||||||
|
|
||||||
LOG((CLOG_PRINT
|
LOG((CLOG_PRINT
|
||||||
"Usage: %s"
|
"Usage: %s"
|
||||||
" [--address <address>]"
|
" [--address <address>]"
|
||||||
|
@ -333,13 +312,13 @@ PLATFORM_EXTRA
|
||||||
"\n"
|
"\n"
|
||||||
"Where log messages go depends on the platform and whether or not the\n"
|
"Where log messages go depends on the platform and whether or not the\n"
|
||||||
"server is running as a daemon.",
|
"server is running as a daemon.",
|
||||||
pname,
|
ARG->m_pname,
|
||||||
kDefaultPort,
|
kDefaultPort,
|
||||||
platform.addPathComponent(
|
ARCH->concatPath(
|
||||||
platform.getUserDirectory(),
|
ARCH->getUserDirectory(),
|
||||||
USR_CONFIG_NAME).c_str(),
|
USR_CONFIG_NAME).c_str(),
|
||||||
platform.addPathComponent(
|
ARCH->concatPath(
|
||||||
platform.getSystemDirectory(),
|
ARCH->getSystemDirectory(),
|
||||||
SYS_CONFIG_NAME).c_str()));
|
SYS_CONFIG_NAME).c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +333,7 @@ isArg(int argi, int argc, const char** argv,
|
||||||
// match. check args left.
|
// match. check args left.
|
||||||
if (argi + minRequiredParameters >= argc) {
|
if (argi + minRequiredParameters >= argc) {
|
||||||
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
||||||
pname, argv[argi], pname));
|
ARG->m_pname, argv[argi], ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -368,32 +347,30 @@ static
|
||||||
void
|
void
|
||||||
parse(int argc, const char** argv)
|
parse(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
assert(pname != NULL);
|
assert(ARG->m_pname != NULL);
|
||||||
assert(argv != NULL);
|
assert(argv != NULL);
|
||||||
assert(argc >= 1);
|
assert(argc >= 1);
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
char hostname[256];
|
ARG->m_name = ARCH->getHostName();
|
||||||
if (CNetwork::gethostname(hostname, sizeof(hostname)) != CNetwork::Error) {
|
|
||||||
s_name = hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse options
|
// parse options
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i < argc; ++i) {
|
for (i = 1; i < argc; ++i) {
|
||||||
if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
||||||
// change logging level
|
// change logging level
|
||||||
s_logFilter = argv[++i];
|
ARG->m_logFilter = argv[++i];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
|
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
|
||||||
// save listen address
|
// save listen address
|
||||||
try {
|
try {
|
||||||
s_synergyAddress = CNetworkAddress(argv[i + 1], kDefaultPort);
|
ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
|
||||||
|
kDefaultPort);
|
||||||
}
|
}
|
||||||
catch (XSocketAddress& e) {
|
catch (XSocketAddress& e) {
|
||||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||||
pname, e.what(), pname));
|
ARG->m_pname, e.what(), ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
|
@ -402,11 +379,12 @@ parse(int argc, const char** argv)
|
||||||
else if (isArg(i, argc, argv, NULL, "--http", 1)) {
|
else if (isArg(i, argc, argv, NULL, "--http", 1)) {
|
||||||
// save listen address
|
// save listen address
|
||||||
try {
|
try {
|
||||||
s_httpAddress = CNetworkAddress(argv[i + 1], kDefaultPort + 1);
|
ARG->m_httpAddress = CNetworkAddress(argv[i + 1],
|
||||||
|
kDefaultPort + 1);
|
||||||
}
|
}
|
||||||
catch (XSocketAddress& e) {
|
catch (XSocketAddress& e) {
|
||||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||||
pname, e.what(), pname));
|
ARG->m_pname, e.what(), ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
|
@ -414,36 +392,36 @@ parse(int argc, const char** argv)
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
||||||
// save screen name
|
// save screen name
|
||||||
s_name = argv[++i];
|
ARG->m_name = argv[++i];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-c", "--config", 1)) {
|
else if (isArg(i, argc, argv, "-c", "--config", 1)) {
|
||||||
// save configuration file path
|
// save configuration file path
|
||||||
s_configFile = argv[++i];
|
ARG->m_configFile = argv[++i];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
||||||
// not a daemon
|
// not a daemon
|
||||||
s_daemon = false;
|
ARG->m_daemon = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
||||||
// daemonize
|
// daemonize
|
||||||
s_daemon = true;
|
ARG->m_daemon = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
||||||
// don't try to restart
|
// don't try to restart
|
||||||
s_restartable = false;
|
ARG->m_restartable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
||||||
// try to restart
|
// try to restart
|
||||||
s_restartable = true;
|
ARG->m_restartable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-z", NULL)) {
|
else if (isArg(i, argc, argv, "-z", NULL)) {
|
||||||
s_backend = true;
|
ARG->m_backend = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-h", "--help")) {
|
else if (isArg(i, argc, argv, "-h", "--help")) {
|
||||||
|
@ -464,7 +442,7 @@ parse(int argc, const char** argv)
|
||||||
|
|
||||||
else if (argv[i][0] == '-') {
|
else if (argv[i][0] == '-') {
|
||||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||||
pname, argv[i], pname));
|
ARG->m_pname, argv[i], ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,30 +455,30 @@ parse(int argc, const char** argv)
|
||||||
// no non-option arguments are allowed
|
// no non-option arguments are allowed
|
||||||
if (i != argc) {
|
if (i != argc) {
|
||||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||||
pname, argv[i], pname));
|
ARG->m_pname, argv[i], ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// increase default filter level for daemon. the user must
|
// increase default filter level for daemon. the user must
|
||||||
// explicitly request another level for a daemon.
|
// explicitly request another level for a daemon.
|
||||||
if (s_daemon && s_logFilter == NULL) {
|
if (ARG->m_daemon && ARG->m_logFilter == NULL) {
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
if (CPlatform::isWindows95Family()) {
|
if (CArchMiscWindows::isWindows95Family()) {
|
||||||
// windows 95 has no place for logging so avoid showing
|
// windows 95 has no place for logging so avoid showing
|
||||||
// the log console window.
|
// the log console window.
|
||||||
s_logFilter = "FATAL";
|
ARG->m_logFilter = "FATAL";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
s_logFilter = "NOTE";
|
ARG->m_logFilter = "NOTE";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set log filter
|
// set log filter
|
||||||
if (!CLog::setFilter(s_logFilter)) {
|
if (!CLOG->setFilter(ARG->m_logFilter)) {
|
||||||
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
||||||
pname, s_logFilter, pname));
|
ARG->m_pname, ARG->m_logFilter, ARG->m_pname));
|
||||||
bye(kExitArgs);
|
bye(kExitArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,14 +496,14 @@ loadConfig(const char* pathname, bool require)
|
||||||
if (!configStream) {
|
if (!configStream) {
|
||||||
throw XConfigRead("cannot open file");
|
throw XConfigRead("cannot open file");
|
||||||
}
|
}
|
||||||
configStream >> s_config;
|
configStream >> ARG->m_config;
|
||||||
LOG((CLOG_DEBUG "configuration read successfully"));
|
LOG((CLOG_DEBUG "configuration read successfully"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (XConfigRead& e) {
|
catch (XConfigRead& e) {
|
||||||
if (require) {
|
if (require) {
|
||||||
LOG((CLOG_PRINT "%s: cannot read configuration '%s': %s",
|
LOG((CLOG_PRINT "%s: cannot read configuration '%s': %s",
|
||||||
pname, pathname, e.what()));
|
ARG->m_pname, pathname, e.what()));
|
||||||
bye(kExitConfig);
|
bye(kExitConfig);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -541,36 +519,46 @@ void
|
||||||
loadConfig()
|
loadConfig()
|
||||||
{
|
{
|
||||||
// load the config file, if specified
|
// load the config file, if specified
|
||||||
if (s_configFile != NULL) {
|
if (ARG->m_configFile != NULL) {
|
||||||
// require the user specified file to load correctly
|
// require the user specified file to load correctly
|
||||||
loadConfig(s_configFile, true);
|
loadConfig(ARG->m_configFile, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the default configuration if no explicit file given
|
// load the default configuration if no explicit file given
|
||||||
else {
|
else {
|
||||||
// get the user's home directory. use the effective user id
|
// get the user's home directory. use the effective user id
|
||||||
// so a user can't get a setuid root program to load his file.
|
// so a user can't get a setuid root program to load his file.
|
||||||
CPlatform platform;
|
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
CString path = platform.getUserDirectory();
|
CString path = ARCH->getUserDirectory();
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
// complete path
|
// complete path
|
||||||
path = platform.addPathComponent(path, USR_CONFIG_NAME);
|
path = ARCH->concatPath(path, USR_CONFIG_NAME);
|
||||||
|
|
||||||
// now try loading the user's configuration
|
// now try loading the user's configuration
|
||||||
loaded = loadConfig(path.c_str(), false);
|
loaded = loadConfig(path.c_str(), false);
|
||||||
}
|
}
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
// try the system-wide config file
|
// try the system-wide config file
|
||||||
path = platform.getSystemDirectory();
|
path = ARCH->getSystemDirectory();
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
path = platform.addPathComponent(path, SYS_CONFIG_NAME);
|
path = ARCH->concatPath(path, SYS_CONFIG_NAME);
|
||||||
loadConfig(path.c_str(), false);
|
loadConfig(path.c_str(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
useSystemLog()
|
||||||
|
{
|
||||||
|
// redirect log messages
|
||||||
|
ILogOutputter* logger = new CSystemLogOutputter;
|
||||||
|
logger->open(DAEMON_NAME);
|
||||||
|
CLOG->insert(new CStopLogOutputter);
|
||||||
|
CLOG->insert(logger);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// platform dependent entry points
|
// platform dependent entry points
|
||||||
//
|
//
|
||||||
|
@ -581,24 +569,41 @@ loadConfig()
|
||||||
|
|
||||||
static bool s_hasImportantLogMessages = false;
|
static bool s_hasImportantLogMessages = false;
|
||||||
|
|
||||||
static
|
//
|
||||||
|
// CMessageBoxOutputter
|
||||||
|
//
|
||||||
|
// This class writes severe log messages to a message box
|
||||||
|
//
|
||||||
|
|
||||||
|
class CMessageBoxOutputter : public ILogOutputter {
|
||||||
|
public:
|
||||||
|
CMessageBoxOutputter() { }
|
||||||
|
virtual ~CMessageBoxOutputter() { }
|
||||||
|
|
||||||
|
// ILogOutputter overrides
|
||||||
|
virtual void open(const char*) { }
|
||||||
|
virtual void close() { }
|
||||||
|
virtual bool write(ELevel level, const char* message);
|
||||||
|
virtual const char* getNewline() const { return ""; }
|
||||||
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
logMessageBox(int priority, const char* msg)
|
CMessageBoxOutputter::write(ELevel level, const char* message)
|
||||||
{
|
{
|
||||||
// note any important messages the user may need to know about
|
// note any important messages the user may need to know about
|
||||||
if (priority <= CLog::kWARNING) {
|
if (level <= CLog::kWARNING) {
|
||||||
s_hasImportantLogMessages = true;
|
s_hasImportantLogMessages = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FATAL and PRINT messages get a dialog box if not running as
|
// FATAL and PRINT messages get a dialog box if not running as
|
||||||
// backend. if we're running as a backend the user will have
|
// backend. if we're running as a backend the user will have
|
||||||
// a chance to see the messages when we exit.
|
// a chance to see the messages when we exit.
|
||||||
if (!s_backend && priority <= CLog::kFATAL) {
|
if (!ARG->m_backend && level <= CLog::kFATAL) {
|
||||||
MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING);
|
MessageBox(NULL, message, ARG->m_pname, MB_OK | MB_ICONWARNING);
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,7 +611,7 @@ static
|
||||||
void
|
void
|
||||||
byeThrow(int x)
|
byeThrow(int x)
|
||||||
{
|
{
|
||||||
throw CWin32Platform::CDaemonFailed(x);
|
CArchMiscWindows::daemonFailed(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -618,10 +623,9 @@ daemonStop(void)
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
daemonStartup(IPlatform* iplatform, int argc, const char** argv)
|
daemonStartup(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
// get platform pointer
|
useSystemLog();
|
||||||
CWin32Platform* platform = static_cast<CWin32Platform*>(iplatform);
|
|
||||||
|
|
||||||
// catch errors that would normally exit
|
// catch errors that would normally exit
|
||||||
bye = &byeThrow;
|
bye = &byeThrow;
|
||||||
|
@ -630,38 +634,38 @@ daemonStartup(IPlatform* iplatform, int argc, const char** argv)
|
||||||
parse(argc, argv);
|
parse(argc, argv);
|
||||||
|
|
||||||
// cannot run as backend if running as a service
|
// cannot run as backend if running as a service
|
||||||
s_backend = false;
|
ARG->m_backend = false;
|
||||||
|
|
||||||
// load configuration
|
// load configuration
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
|
||||||
// run as a service
|
// run as a service
|
||||||
return platform->runDaemon(realMain, daemonStop);
|
return CArchMiscWindows::runDaemon(realMain, daemonStop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
daemonStartup95(IPlatform*, int, const char**)
|
daemonStartup95(int, const char**)
|
||||||
{
|
{
|
||||||
return realMain(NULL);
|
useSystemLog();
|
||||||
|
return realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
int WINAPI
|
int WINAPI
|
||||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
{
|
{
|
||||||
CPlatform platform;
|
CArch arch;
|
||||||
|
CLOG;
|
||||||
|
CArgs args;
|
||||||
|
|
||||||
// save instance
|
// save instance
|
||||||
CMSWindowsScreen::init(instance);
|
CMSWindowsScreen::init(instance);
|
||||||
|
|
||||||
// get program name
|
// get program name
|
||||||
pname = platform.getBasename(__argv[0]);
|
ARG->m_pname = ARCH->getBasename(__argv[0]);
|
||||||
|
|
||||||
// initialize network library
|
|
||||||
CNetwork::init();
|
|
||||||
|
|
||||||
// send PRINT and FATAL output to a message box
|
// send PRINT and FATAL output to a message box
|
||||||
CLog::setOutputter(&logMessageBox);
|
CLOG->insert(new CMessageBoxOutputter);
|
||||||
|
|
||||||
// windows NT family starts services using no command line options.
|
// windows NT family starts services using no command line options.
|
||||||
// since i'm not sure how to tell the difference between that and
|
// since i'm not sure how to tell the difference between that and
|
||||||
|
@ -669,13 +673,14 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
// arguments and we're on NT then we're being invoked as a service.
|
// arguments and we're on NT then we're being invoked as a service.
|
||||||
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||||
// of the service code path.
|
// of the service code path.
|
||||||
if (__argc <= 1 && !CWin32Platform::isWindows95Family()) {
|
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||||
int result = platform.daemonize(DAEMON_NAME, &daemonStartup);
|
try {
|
||||||
if (result == -1) {
|
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||||
LOG((CLOG_CRIT "failed to start as a service" BYE, pname));
|
}
|
||||||
|
catch (XArchDaemon&) {
|
||||||
|
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
||||||
return kExitFailed;
|
return kExitFailed;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse command line
|
// parse command line
|
||||||
|
@ -686,38 +691,36 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
|
|
||||||
// daemonize if requested
|
// daemonize if requested
|
||||||
int result;
|
int result;
|
||||||
if (s_daemon) {
|
if (ARG->m_daemon) {
|
||||||
// redirect log messages
|
|
||||||
platform.installDaemonLogger(DAEMON_NAME);
|
|
||||||
|
|
||||||
// start as a daemon
|
// start as a daemon
|
||||||
if (CWin32Platform::isWindows95Family()) {
|
if (CArchMiscWindows::isWindows95Family()) {
|
||||||
result = platform.daemonize(DAEMON_NAME, &daemonStartup95);
|
try {
|
||||||
if (result == -1) {
|
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
||||||
LOG((CLOG_CRIT "failed to start as a service" BYE, pname));
|
}
|
||||||
|
catch (XArchDaemon&) {
|
||||||
|
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
||||||
result = kExitFailed;
|
result = kExitFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// cannot start a service from the command line so just
|
// cannot start a service from the command line so just
|
||||||
// run normally (except with log messages redirected).
|
// run normally (except with log messages redirected).
|
||||||
result = realMain(NULL);
|
useSystemLog();
|
||||||
|
result = realMain();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// run
|
// run
|
||||||
result = realMain(NULL);
|
result = realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
CNetwork::cleanup();
|
|
||||||
|
|
||||||
// let user examine any messages if we're running as a backend
|
// let user examine any messages if we're running as a backend
|
||||||
// by putting up a dialog box before exiting.
|
// by putting up a dialog box before exiting.
|
||||||
if (s_backend && s_hasImportantLogMessages) {
|
if (ARG->m_backend && s_hasImportantLogMessages) {
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
msg[0] = '\0';
|
msg[0] = '\0';
|
||||||
LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0]));
|
LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0]));
|
||||||
MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING);
|
MessageBox(NULL, msg, ARG->m_pname, MB_OK | MB_ICONWARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -727,21 +730,21 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
daemonStartup(IPlatform*, int, const char**)
|
daemonStartup(int, const char**)
|
||||||
{
|
{
|
||||||
return realMain(NULL);
|
useSystemLog();
|
||||||
|
return realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char** argv)
|
main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
CPlatform platform;
|
CArch arch;
|
||||||
|
CLOG;
|
||||||
|
CArgs args;
|
||||||
|
|
||||||
// get program name
|
// get program name
|
||||||
pname = platform.getBasename(argv[0]);
|
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
|
||||||
// initialize network library
|
|
||||||
CNetwork::init();
|
|
||||||
|
|
||||||
// parse command line
|
// parse command line
|
||||||
parse(argc, const_cast<const char**>(argv));
|
parse(argc, const_cast<const char**>(argv));
|
||||||
|
@ -751,19 +754,19 @@ main(int argc, char** argv)
|
||||||
|
|
||||||
// daemonize if requested
|
// daemonize if requested
|
||||||
int result;
|
int result;
|
||||||
if (s_daemon) {
|
if (ARG->m_daemon) {
|
||||||
result = platform.daemonize(DAEMON_NAME, &daemonStartup);
|
try {
|
||||||
if (result == -1) {
|
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||||
|
}
|
||||||
|
catch (XArchDaemon&) {
|
||||||
LOG((CLOG_CRIT "failed to daemonize"));
|
LOG((CLOG_CRIT "failed to daemonize"));
|
||||||
return kExitFailed;
|
result = kExitFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = realMain(NULL);
|
result = realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
CNetwork::cleanup();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ RSC=rc.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||||
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
@ -70,7 +70,7 @@ LINK32=link.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||||
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
|
|
@ -13,7 +13,7 @@ dnl GNU General Public License for more details.
|
||||||
dnl Process this file with autoconf to produce a configure script.
|
dnl Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
dnl initialize
|
dnl initialize
|
||||||
AC_INIT(lib/base/common.h)
|
AC_INIT(lib/common/common.h)
|
||||||
AC_CONFIG_AUX_DIR(config)
|
AC_CONFIG_AUX_DIR(config)
|
||||||
|
|
||||||
dnl current version
|
dnl current version
|
||||||
|
@ -99,7 +99,9 @@ LIBS="$NANOSLEEP_LIBS $INET_ATON_LIBS $PTHREAD_LIBS $LIBS"
|
||||||
AC_OUTPUT([
|
AC_OUTPUT([
|
||||||
Makefile
|
Makefile
|
||||||
lib/Makefile
|
lib/Makefile
|
||||||
|
lib/arch/Makefile
|
||||||
lib/base/Makefile
|
lib/base/Makefile
|
||||||
|
lib/common/Makefile
|
||||||
lib/mt/Makefile
|
lib/mt/Makefile
|
||||||
lib/io/Makefile
|
lib/io/Makefile
|
||||||
lib/http/Makefile
|
lib/http/Makefile
|
||||||
|
|
|
@ -16,6 +16,8 @@ DEPTH = ..
|
||||||
VDEPTH = ./$(VPATH)/$(DEPTH)
|
VDEPTH = ./$(VPATH)/$(DEPTH)
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
|
common \
|
||||||
|
arch \
|
||||||
base \
|
base \
|
||||||
mt \
|
mt \
|
||||||
io \
|
io \
|
||||||
|
|
|
@ -0,0 +1,576 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
|
||||||
|
#undef ARCH_CONSOLE
|
||||||
|
#undef ARCH_DAEMON
|
||||||
|
#undef ARCH_FILE
|
||||||
|
#undef ARCH_LOG
|
||||||
|
#undef ARCH_MULTITHREAD
|
||||||
|
#undef ARCH_NETWORK
|
||||||
|
#undef ARCH_SLEEP
|
||||||
|
#undef ARCH_STRING
|
||||||
|
#undef ARCH_TIME
|
||||||
|
|
||||||
|
// include appropriate architecture implementation
|
||||||
|
#if WINDOWS_LIKE
|
||||||
|
# include "CArchConsoleWindows.h"
|
||||||
|
# include "CArchDaemonWindows.h"
|
||||||
|
# include "CArchFileWindows.h"
|
||||||
|
# include "CArchLogWindows.h"
|
||||||
|
# include "CArchMultithreadWindows.h"
|
||||||
|
# include "CArchNetworkWinsock.h"
|
||||||
|
# include "CArchSleepWindows.h"
|
||||||
|
# include "CArchStringWindows.h"
|
||||||
|
# include "CArchTimeWindows.h"
|
||||||
|
#elif UNIX_LIKE
|
||||||
|
# include "CArchConsoleUnix.h"
|
||||||
|
# include "CArchDaemonUnix.h"
|
||||||
|
# include "CArchFileUnix.h"
|
||||||
|
# include "CArchLogUnix.h"
|
||||||
|
# if HAVE_PTHREAD
|
||||||
|
# include "CArchMultithreadPosix.h"
|
||||||
|
# endif
|
||||||
|
# include "CArchNetworkBSD.h"
|
||||||
|
# include "CArchSleepUnix.h"
|
||||||
|
# include "CArchStringUnix.h"
|
||||||
|
# include "CArchTimeUnix.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_CONSOLE)
|
||||||
|
# error unsupported platform for console
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_DAEMON)
|
||||||
|
# error unsupported platform for daemon
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_FILE)
|
||||||
|
# error unsupported platform for file
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_LOG)
|
||||||
|
# error unsupported platform for logging
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_MULTITHREAD)
|
||||||
|
# error unsupported platform for multithreading
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_NETWORK)
|
||||||
|
# error unsupported platform for network
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_SLEEP)
|
||||||
|
# error unsupported platform for sleep
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_STRING)
|
||||||
|
# error unsupported platform for string
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_TIME)
|
||||||
|
# error unsupported platform for time
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArch
|
||||||
|
//
|
||||||
|
|
||||||
|
CArch* CArch::s_instance = NULL;
|
||||||
|
|
||||||
|
CArch::CArch(ARCH_ARGS)
|
||||||
|
{
|
||||||
|
// only once instance of CArch
|
||||||
|
assert(s_instance == NULL);
|
||||||
|
s_instance = this;
|
||||||
|
|
||||||
|
// create architecture implementation objects
|
||||||
|
m_mt = new ARCH_MULTITHREAD;
|
||||||
|
m_file = new ARCH_FILE;
|
||||||
|
m_log = new ARCH_LOG;
|
||||||
|
m_net = new ARCH_NETWORK;
|
||||||
|
m_sleep = new ARCH_SLEEP;
|
||||||
|
m_string = new ARCH_STRING;
|
||||||
|
m_time = new ARCH_TIME;
|
||||||
|
m_console = new ARCH_CONSOLE;
|
||||||
|
m_daemon = new ARCH_DAEMON;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArch::~CArch()
|
||||||
|
{
|
||||||
|
// clean up
|
||||||
|
delete m_daemon;
|
||||||
|
delete m_console;
|
||||||
|
delete m_time;
|
||||||
|
delete m_string;
|
||||||
|
delete m_sleep;
|
||||||
|
delete m_net;
|
||||||
|
delete m_log;
|
||||||
|
delete m_file;
|
||||||
|
delete m_mt;
|
||||||
|
|
||||||
|
// no instance
|
||||||
|
s_instance = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArch*
|
||||||
|
CArch::getInstance()
|
||||||
|
{
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::openConsole(const char* title)
|
||||||
|
{
|
||||||
|
m_console->openConsole(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::closeConsole()
|
||||||
|
{
|
||||||
|
m_console->closeConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::writeConsole(const char* str)
|
||||||
|
{
|
||||||
|
m_console->writeConsole(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CArch::getNewlineForConsole()
|
||||||
|
{
|
||||||
|
return m_console->getNewlineForConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::installDaemon(const char* name,
|
||||||
|
const char* description,
|
||||||
|
const char* pathname,
|
||||||
|
const char* commandLine,
|
||||||
|
bool allUsers)
|
||||||
|
{
|
||||||
|
m_daemon->installDaemon(name, description, pathname, commandLine, allUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::uninstallDaemon(const char* name, bool allUsers)
|
||||||
|
{
|
||||||
|
m_daemon->uninstallDaemon(name, allUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArch::daemonize(const char* name, DaemonFunc func)
|
||||||
|
{
|
||||||
|
return m_daemon->daemonize(name, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::canInstallDaemon(const char* name, bool allUsers)
|
||||||
|
{
|
||||||
|
return m_daemon->canInstallDaemon(name, allUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::isDaemonInstalled(const char* name, bool allUsers)
|
||||||
|
{
|
||||||
|
return m_daemon->isDaemonInstalled(name, allUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CArch::getBasename(const char* pathname)
|
||||||
|
{
|
||||||
|
return m_file->getBasename(pathname);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArch::getUserDirectory()
|
||||||
|
{
|
||||||
|
return m_file->getUserDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArch::getSystemDirectory()
|
||||||
|
{
|
||||||
|
return m_file->getSystemDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArch::concatPath(const std::string& prefix, const std::string& suffix)
|
||||||
|
{
|
||||||
|
return m_file->concatPath(prefix, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::openLog(const char* name)
|
||||||
|
{
|
||||||
|
m_log->openLog(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::closeLog()
|
||||||
|
{
|
||||||
|
m_log->closeLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::writeLog(ELevel level, const char* msg)
|
||||||
|
{
|
||||||
|
m_log->writeLog(level, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchCond
|
||||||
|
CArch::newCondVar()
|
||||||
|
{
|
||||||
|
return m_mt->newCondVar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::closeCondVar(CArchCond cond)
|
||||||
|
{
|
||||||
|
m_mt->closeCondVar(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::signalCondVar(CArchCond cond)
|
||||||
|
{
|
||||||
|
m_mt->signalCondVar(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::broadcastCondVar(CArchCond cond)
|
||||||
|
{
|
||||||
|
m_mt->broadcastCondVar(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::waitCondVar(CArchCond cond, CArchMutex mutex, double timeout)
|
||||||
|
{
|
||||||
|
return m_mt->waitCondVar(cond, mutex, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchMutex
|
||||||
|
CArch::newMutex()
|
||||||
|
{
|
||||||
|
return m_mt->newMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::closeMutex(CArchMutex mutex)
|
||||||
|
{
|
||||||
|
m_mt->closeMutex(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::lockMutex(CArchMutex mutex)
|
||||||
|
{
|
||||||
|
m_mt->lockMutex(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::unlockMutex(CArchMutex mutex)
|
||||||
|
{
|
||||||
|
m_mt->unlockMutex(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThread
|
||||||
|
CArch::newThread(ThreadFunc func, void* data)
|
||||||
|
{
|
||||||
|
return m_mt->newThread(func, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThread
|
||||||
|
CArch::newCurrentThread()
|
||||||
|
{
|
||||||
|
return m_mt->newCurrentThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThread
|
||||||
|
CArch::copyThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
return m_mt->copyThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::closeThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
m_mt->closeThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::cancelThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
m_mt->cancelThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::setPriorityOfThread(CArchThread thread, int n)
|
||||||
|
{
|
||||||
|
m_mt->setPriorityOfThread(thread, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::testCancelThread()
|
||||||
|
{
|
||||||
|
m_mt->testCancelThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::wait(CArchThread thread, double timeout)
|
||||||
|
{
|
||||||
|
return m_mt->wait(thread, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::waitForEvent(double timeout)
|
||||||
|
{
|
||||||
|
return m_mt->waitForEvent(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::isSameThread(CArchThread thread1, CArchThread thread2)
|
||||||
|
{
|
||||||
|
return m_mt->isSameThread(thread1, thread2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::isExitedThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
return m_mt->isExitedThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
CArch::getResultOfThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
return m_mt->getResultOfThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
IArchMultithread::ThreadID
|
||||||
|
CArch::getIDOfThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
return m_mt->getIDOfThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSocket
|
||||||
|
CArch::newSocket(EAddressFamily family, ESocketType type)
|
||||||
|
{
|
||||||
|
return m_net->newSocket(family, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSocket
|
||||||
|
CArch::copySocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
return m_net->copySocket(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::closeSocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
m_net->closeSocket(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::closeSocketForRead(CArchSocket s)
|
||||||
|
{
|
||||||
|
m_net->closeSocketForRead(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::closeSocketForWrite(CArchSocket s)
|
||||||
|
{
|
||||||
|
m_net->closeSocketForWrite(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::bindSocket(CArchSocket s, CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
m_net->bindSocket(s, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::listenOnSocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
m_net->listenOnSocket(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSocket
|
||||||
|
CArch::acceptSocket(CArchSocket s, CArchNetAddress* addr)
|
||||||
|
{
|
||||||
|
return m_net->acceptSocket(s, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::connectSocket(CArchSocket s, CArchNetAddress name)
|
||||||
|
{
|
||||||
|
m_net->connectSocket(s, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArch::pollSocket(CPollEntry pe[], int num, double timeout)
|
||||||
|
{
|
||||||
|
return m_net->pollSocket(pe, num, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
CArch::readSocket(CArchSocket s, void* buf, size_t len)
|
||||||
|
{
|
||||||
|
return m_net->readSocket(s, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
CArch::writeSocket(CArchSocket s, const void* buf, size_t len)
|
||||||
|
{
|
||||||
|
return m_net->writeSocket(s, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::throwErrorOnSocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
m_net->throwErrorOnSocket(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::setBlockingOnSocket(CArchSocket s, bool blocking)
|
||||||
|
{
|
||||||
|
return m_net->setBlockingOnSocket(s, blocking);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::setNoDelayOnSocket(CArchSocket s, bool noDelay)
|
||||||
|
{
|
||||||
|
return m_net->setNoDelayOnSocket(s, noDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArch::getHostName()
|
||||||
|
{
|
||||||
|
return m_net->getHostName();
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetAddress
|
||||||
|
CArch::newAnyAddr(EAddressFamily family)
|
||||||
|
{
|
||||||
|
return m_net->newAnyAddr(family);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetAddress
|
||||||
|
CArch::copyAddr(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
return m_net->copyAddr(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetAddress
|
||||||
|
CArch::nameToAddr(const std::string& name)
|
||||||
|
{
|
||||||
|
return m_net->nameToAddr(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::closeAddr(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
m_net->closeAddr(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArch::addrToName(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
return m_net->addrToName(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArch::addrToString(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
return m_net->addrToString(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
IArchNetwork::EAddressFamily
|
||||||
|
CArch::getAddrFamily(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
return m_net->getAddrFamily(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::setAddrPort(CArchNetAddress addr, int port)
|
||||||
|
{
|
||||||
|
m_net->setAddrPort(addr, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArch::getAddrPort(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
return m_net->getAddrPort(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::isAnyAddr(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
return m_net->isAnyAddr(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::sleep(double timeout)
|
||||||
|
{
|
||||||
|
m_sleep->sleep(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArch::vsnprintf(char* str, int size, const char* fmt, va_list ap)
|
||||||
|
{
|
||||||
|
return m_string->vsnprintf(str, size, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchMBState
|
||||||
|
CArch::newMBState()
|
||||||
|
{
|
||||||
|
return m_string->newMBState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::closeMBState(CArchMBState state)
|
||||||
|
{
|
||||||
|
m_string->closeMBState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::initMBState(CArchMBState state)
|
||||||
|
{
|
||||||
|
m_string->initMBState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::isInitMBState(CArchMBState state)
|
||||||
|
{
|
||||||
|
return m_string->isInitMBState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArch::convMBToWC(wchar_t* dst, const char* src, int n, CArchMBState state)
|
||||||
|
{
|
||||||
|
return m_string->convMBToWC(dst, src, n, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArch::convWCToMB(char* dst, wchar_t src, CArchMBState state)
|
||||||
|
{
|
||||||
|
return m_string->convWCToMB(dst, src, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
CArch::time()
|
||||||
|
{
|
||||||
|
return m_time->time();
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCH_H
|
||||||
|
#define CARCH_H
|
||||||
|
|
||||||
|
#include "IArchConsole.h"
|
||||||
|
#include "IArchDaemon.h"
|
||||||
|
#include "IArchFile.h"
|
||||||
|
#include "IArchLog.h"
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
#include "IArchNetwork.h"
|
||||||
|
#include "IArchSleep.h"
|
||||||
|
#include "IArchString.h"
|
||||||
|
#include "IArchTime.h"
|
||||||
|
|
||||||
|
#define ARCH (CArch::getInstance())
|
||||||
|
|
||||||
|
#define ARCH_ARGS
|
||||||
|
|
||||||
|
class CArch : public IArchConsole,
|
||||||
|
public IArchDaemon,
|
||||||
|
public IArchFile,
|
||||||
|
public IArchLog,
|
||||||
|
public IArchMultithread,
|
||||||
|
public IArchNetwork,
|
||||||
|
public IArchSleep,
|
||||||
|
public IArchString,
|
||||||
|
public IArchTime {
|
||||||
|
public:
|
||||||
|
CArch(ARCH_ARGS);
|
||||||
|
~CArch();
|
||||||
|
|
||||||
|
//
|
||||||
|
// accessors
|
||||||
|
//
|
||||||
|
|
||||||
|
static CArch* getInstance();
|
||||||
|
|
||||||
|
// IArchConsole overrides
|
||||||
|
virtual void openConsole(const char*);
|
||||||
|
virtual void closeConsole();
|
||||||
|
virtual void writeConsole(const char*);
|
||||||
|
virtual const char* getNewlineForConsole();
|
||||||
|
|
||||||
|
// IArchDaemon overrides
|
||||||
|
virtual void installDaemon(const char* name,
|
||||||
|
const char* description,
|
||||||
|
const char* pathname,
|
||||||
|
const char* commandLine,
|
||||||
|
bool allUsers);
|
||||||
|
virtual void uninstallDaemon(const char* name, bool allUsers);
|
||||||
|
virtual int daemonize(const char* name, DaemonFunc func);
|
||||||
|
virtual bool canInstallDaemon(const char* name, bool allUsers);
|
||||||
|
virtual bool isDaemonInstalled(const char* name, bool allUsers);
|
||||||
|
|
||||||
|
// IArchFile overrides
|
||||||
|
virtual const char* getBasename(const char* pathname);
|
||||||
|
virtual std::string getUserDirectory();
|
||||||
|
virtual std::string getSystemDirectory();
|
||||||
|
virtual std::string concatPath(const std::string& prefix,
|
||||||
|
const std::string& suffix);
|
||||||
|
|
||||||
|
// IArchLog overrides
|
||||||
|
virtual void openLog(const char*);
|
||||||
|
virtual void closeLog();
|
||||||
|
virtual void writeLog(ELevel, const char*);
|
||||||
|
|
||||||
|
// IArchMultithread overrides
|
||||||
|
virtual CArchCond newCondVar();
|
||||||
|
virtual void closeCondVar(CArchCond);
|
||||||
|
virtual void signalCondVar(CArchCond);
|
||||||
|
virtual void broadcastCondVar(CArchCond);
|
||||||
|
virtual bool waitCondVar(CArchCond, CArchMutex, double timeout);
|
||||||
|
virtual CArchMutex newMutex();
|
||||||
|
virtual void closeMutex(CArchMutex);
|
||||||
|
virtual void lockMutex(CArchMutex);
|
||||||
|
virtual void unlockMutex(CArchMutex);
|
||||||
|
virtual CArchThread newThread(ThreadFunc, void*);
|
||||||
|
virtual CArchThread newCurrentThread();
|
||||||
|
virtual CArchThread copyThread(CArchThread);
|
||||||
|
virtual void closeThread(CArchThread);
|
||||||
|
virtual void cancelThread(CArchThread);
|
||||||
|
virtual void setPriorityOfThread(CArchThread, int n);
|
||||||
|
virtual void testCancelThread();
|
||||||
|
virtual bool wait(CArchThread, double timeout);
|
||||||
|
virtual bool waitForEvent(double timeout);
|
||||||
|
virtual bool isSameThread(CArchThread, CArchThread);
|
||||||
|
virtual bool isExitedThread(CArchThread);
|
||||||
|
virtual void* getResultOfThread(CArchThread);
|
||||||
|
virtual ThreadID getIDOfThread(CArchThread);
|
||||||
|
|
||||||
|
// IArchNetwork overrides
|
||||||
|
virtual CArchSocket newSocket(EAddressFamily, ESocketType);
|
||||||
|
virtual CArchSocket copySocket(CArchSocket s);
|
||||||
|
virtual void closeSocket(CArchSocket s);
|
||||||
|
virtual void closeSocketForRead(CArchSocket s);
|
||||||
|
virtual void closeSocketForWrite(CArchSocket s);
|
||||||
|
virtual void bindSocket(CArchSocket s, CArchNetAddress addr);
|
||||||
|
virtual void listenOnSocket(CArchSocket s);
|
||||||
|
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
|
||||||
|
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
|
||||||
|
virtual int pollSocket(CPollEntry[], int num, double timeout);
|
||||||
|
virtual size_t readSocket(CArchSocket s, void* buf, size_t len);
|
||||||
|
virtual size_t writeSocket(CArchSocket s,
|
||||||
|
const void* buf, size_t len);
|
||||||
|
virtual void throwErrorOnSocket(CArchSocket);
|
||||||
|
virtual bool setBlockingOnSocket(CArchSocket, bool blocking);
|
||||||
|
virtual bool setNoDelayOnSocket(CArchSocket, bool noDelay);
|
||||||
|
virtual std::string getHostName();
|
||||||
|
virtual CArchNetAddress newAnyAddr(EAddressFamily);
|
||||||
|
virtual CArchNetAddress copyAddr(CArchNetAddress);
|
||||||
|
virtual CArchNetAddress nameToAddr(const std::string&);
|
||||||
|
virtual void closeAddr(CArchNetAddress);
|
||||||
|
virtual std::string addrToName(CArchNetAddress);
|
||||||
|
virtual std::string addrToString(CArchNetAddress);
|
||||||
|
virtual EAddressFamily getAddrFamily(CArchNetAddress);
|
||||||
|
virtual void setAddrPort(CArchNetAddress, int port);
|
||||||
|
virtual int getAddrPort(CArchNetAddress);
|
||||||
|
virtual bool isAnyAddr(CArchNetAddress);
|
||||||
|
|
||||||
|
// IArchSleep overrides
|
||||||
|
virtual void sleep(double timeout);
|
||||||
|
|
||||||
|
// IArchString overrides
|
||||||
|
virtual int vsnprintf(char* str,
|
||||||
|
int size, const char* fmt, va_list ap);
|
||||||
|
virtual CArchMBState newMBState();
|
||||||
|
virtual void closeMBState(CArchMBState);
|
||||||
|
virtual void initMBState(CArchMBState);
|
||||||
|
virtual bool isInitMBState(CArchMBState);
|
||||||
|
virtual int convMBToWC(wchar_t*, const char*, int, CArchMBState);
|
||||||
|
virtual int convWCToMB(char*, wchar_t, CArchMBState);
|
||||||
|
|
||||||
|
// IArchTime overrides
|
||||||
|
virtual double time();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static CArch* s_instance;
|
||||||
|
|
||||||
|
IArchConsole* m_console;
|
||||||
|
IArchDaemon* m_daemon;
|
||||||
|
IArchFile* m_file;
|
||||||
|
IArchLog* m_log;
|
||||||
|
IArchMultithread* m_mt;
|
||||||
|
IArchNetwork* m_net;
|
||||||
|
IArchSleep* m_sleep;
|
||||||
|
IArchString* m_string;
|
||||||
|
IArchTime* m_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchConsoleUnix.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchConsoleUnix
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchConsoleUnix::CArchConsoleUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchConsoleUnix::~CArchConsoleUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchConsoleUnix::openConsole(const char*)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchConsoleUnix::closeConsole()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchConsoleUnix::writeConsole(const char* str)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CArchConsoleUnix::getNewlineForConsole()
|
||||||
|
{
|
||||||
|
return "\n";
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHCONSOLEUNIX_H
|
||||||
|
#define CARCHCONSOLEUNIX_H
|
||||||
|
|
||||||
|
#include "IArchConsole.h"
|
||||||
|
|
||||||
|
#define ARCH_CONSOLE CArchConsoleUnix
|
||||||
|
|
||||||
|
class CArchConsoleUnix : public IArchConsole {
|
||||||
|
public:
|
||||||
|
CArchConsoleUnix();
|
||||||
|
virtual ~CArchConsoleUnix();
|
||||||
|
|
||||||
|
// IArchConsole overrides
|
||||||
|
virtual void openConsole(const char* title);
|
||||||
|
virtual void closeConsole();
|
||||||
|
virtual void writeConsole(const char*);
|
||||||
|
virtual const char* getNewlineForConsole();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchConsoleWindows.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchConsoleWindows
|
||||||
|
//
|
||||||
|
|
||||||
|
DWORD CArchConsoleWindows::s_thread = 0;
|
||||||
|
|
||||||
|
CArchConsoleWindows::CArchConsoleWindows() :
|
||||||
|
m_output(NULL)
|
||||||
|
{
|
||||||
|
s_thread = GetCurrentThreadId();
|
||||||
|
|
||||||
|
m_mutex = ARCH->newMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchConsoleWindows::~CArchConsoleWindows()
|
||||||
|
{
|
||||||
|
ARCH->closeMutex(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchConsoleWindows::openConsole(const char* title)
|
||||||
|
{
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
if (m_output == NULL) {
|
||||||
|
if (AllocConsole()) {
|
||||||
|
// get console output handle
|
||||||
|
m_output = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
|
||||||
|
// set console title
|
||||||
|
if (title != NULL) {
|
||||||
|
SetConsoleTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
// prep console. windows 95 and its ilk have braindead
|
||||||
|
// consoles that can't even resize independently of the
|
||||||
|
// buffer size. use a 25 line buffer for those systems.
|
||||||
|
OSVERSIONINFO osInfo;
|
||||||
|
COORD size = { 80, 1000 };
|
||||||
|
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
|
||||||
|
if (GetVersionEx(&osInfo) &&
|
||||||
|
osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
||||||
|
size.Y = 25;
|
||||||
|
SetConsoleScreenBufferSize(m_output, size);
|
||||||
|
SetConsoleTextAttribute(m_output,
|
||||||
|
FOREGROUND_RED |
|
||||||
|
FOREGROUND_GREEN |
|
||||||
|
FOREGROUND_BLUE);
|
||||||
|
|
||||||
|
// catch console signals
|
||||||
|
SetConsoleCtrlHandler(&CArchConsoleWindows::signalHandler, TRUE);
|
||||||
|
|
||||||
|
// reopen stderr to point at console
|
||||||
|
freopen("con", "w", stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchConsoleWindows::closeConsole()
|
||||||
|
{
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
if (m_output != NULL) {
|
||||||
|
if (FreeConsole()) {
|
||||||
|
m_output = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchConsoleWindows::writeConsole(const char* str)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CArchConsoleWindows::getNewlineForConsole()
|
||||||
|
{
|
||||||
|
return "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI
|
||||||
|
CArchConsoleWindows::signalHandler(DWORD)
|
||||||
|
{
|
||||||
|
// terminate cleanly and skip remaining handlers
|
||||||
|
PostThreadMessage(s_thread, WM_QUIT, 0, 0);
|
||||||
|
return TRUE;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHCONSOLEWINDOWS_H
|
||||||
|
#define CARCHCONSOLEWINDOWS_H
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include "IArchConsole.h"
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#define ARCH_CONSOLE CArchConsoleWindows
|
||||||
|
|
||||||
|
class CArchConsoleWindows : public IArchConsole {
|
||||||
|
public:
|
||||||
|
CArchConsoleWindows();
|
||||||
|
virtual ~CArchConsoleWindows();
|
||||||
|
|
||||||
|
// IArchConsole overrides
|
||||||
|
virtual void openConsole(const char* title);
|
||||||
|
virtual void closeConsole();
|
||||||
|
virtual void writeConsole(const char*);
|
||||||
|
virtual const char* getNewlineForConsole();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static BOOL WINAPI signalHandler(DWORD);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static DWORD s_thread;
|
||||||
|
|
||||||
|
CArchMutex m_mutex;
|
||||||
|
HANDLE m_output;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchDaemonNone.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchDaemonNone
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchDaemonNone::CArchDaemonNone()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchDaemonNone::~CArchDaemonNone()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchDaemonNone::installDaemon(const char*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
bool)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchDaemonNone::uninstallDaemon(const char*, bool)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchDaemonNone::daemonize(const char* name, DaemonFunc func)
|
||||||
|
{
|
||||||
|
// simply forward the call to func. obviously, this doesn't
|
||||||
|
// do any daemonizing.
|
||||||
|
return func(1, &name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchDaemonNone::canInstallDaemon(const char*, bool)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchDaemonNone::isDaemonInstalled(const char* name, bool allUsers)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHDAEMONNONE_H
|
||||||
|
#define CARCHDAEMONNONE_H
|
||||||
|
|
||||||
|
#include "IArchDaemon.h"
|
||||||
|
|
||||||
|
#define ARCH_DAEMON CArchDaemonNone
|
||||||
|
|
||||||
|
class CArchDaemonNone : public IArchDaemon {
|
||||||
|
public:
|
||||||
|
CArchDaemonNone();
|
||||||
|
virtual ~CArchDaemonNone();
|
||||||
|
|
||||||
|
// IArchDaemon overrides
|
||||||
|
virtual void installDaemon(const char* name,
|
||||||
|
const char* description,
|
||||||
|
const char* pathname,
|
||||||
|
const char* commandLine,
|
||||||
|
bool allUsers);
|
||||||
|
virtual void uninstallDaemon(const char* name, bool allUsers);
|
||||||
|
virtual int daemonize(const char* name, DaemonFunc func);
|
||||||
|
virtual bool canInstallDaemon(const char* name, bool allUsers);
|
||||||
|
virtual bool isDaemonInstalled(const char* name, bool allUsers);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchDaemonUnix.h"
|
||||||
|
#include "XArchUnix.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
// we derive from CArchDaemonNone
|
||||||
|
#include "CArchDaemonNone.cpp"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchDaemonUnix
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchDaemonUnix::CArchDaemonUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchDaemonUnix::~CArchDaemonUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchDaemonUnix::daemonize(const char* name, DaemonFunc func)
|
||||||
|
{
|
||||||
|
// fork so shell thinks we're done and so we're not a process
|
||||||
|
// group leader
|
||||||
|
switch (fork()) {
|
||||||
|
case -1:
|
||||||
|
// failed
|
||||||
|
throw XArchDaemonFailed(new XArchEvalUnix(errno));
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
// child
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// parent exits
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// become leader of a new session
|
||||||
|
setsid();
|
||||||
|
|
||||||
|
// chdir to root so we don't keep mounted filesystems points busy
|
||||||
|
chdir("/");
|
||||||
|
|
||||||
|
// mask off permissions for any but owner
|
||||||
|
umask(077);
|
||||||
|
|
||||||
|
// close open files. we only expect stdin, stdout, stderr to be open.
|
||||||
|
close(0);
|
||||||
|
close(1);
|
||||||
|
close(2);
|
||||||
|
|
||||||
|
// attach file descriptors 0, 1, 2 to /dev/null so inadvertent use
|
||||||
|
// of standard I/O safely goes in the bit bucket.
|
||||||
|
open("/dev/null", O_RDONLY);
|
||||||
|
open("/dev/null", O_RDWR);
|
||||||
|
dup(1);
|
||||||
|
|
||||||
|
// invoke function
|
||||||
|
return func(1, &name);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHDAEMONUNIX_H
|
||||||
|
#define CARCHDAEMONUNIX_H
|
||||||
|
|
||||||
|
#include "CArchDaemonNone.h"
|
||||||
|
|
||||||
|
#undef ARCH_DAEMON
|
||||||
|
#define ARCH_DAEMON CArchDaemonUnix
|
||||||
|
|
||||||
|
class CArchDaemonUnix : public CArchDaemonNone {
|
||||||
|
public:
|
||||||
|
CArchDaemonUnix();
|
||||||
|
virtual ~CArchDaemonUnix();
|
||||||
|
|
||||||
|
// IArchDaemon overrides
|
||||||
|
virtual int daemonize(const char* name, DaemonFunc func);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHDAEMONWINDOWS_H
|
||||||
|
#define CARCHDAEMONWINDOWS_H
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include "IArchDaemon.h"
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
#include "stdstring.h"
|
||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
|
||||||
|
#define ARCH_DAEMON CArchDaemonWindows
|
||||||
|
|
||||||
|
class CArchDaemonWindows : public IArchDaemon {
|
||||||
|
public:
|
||||||
|
typedef int (*RunFunc)(void);
|
||||||
|
typedef void (*StopFunc)(void);
|
||||||
|
|
||||||
|
CArchDaemonWindows();
|
||||||
|
virtual ~CArchDaemonWindows();
|
||||||
|
|
||||||
|
//! Run the daemon
|
||||||
|
/*!
|
||||||
|
When the client calls \c daemonize(), the \c DaemonFunc should call this
|
||||||
|
function after initialization and argument parsing to perform the
|
||||||
|
daemon processing. The \c runFunc should perform the daemon's
|
||||||
|
main loop, calling \c daemonRunning(true) when it enters the main loop
|
||||||
|
(i.e. after initialization) and \c daemonRunning(false) when it leaves
|
||||||
|
the main loop. The \c stopFunc function is called when the daemon
|
||||||
|
must exit the main loop and must cause \c runFunc to return. This
|
||||||
|
function returns what \c runFunc returns. \c runFunc should call
|
||||||
|
\c daemonFailed() if the daemon fails.
|
||||||
|
*/
|
||||||
|
static int runDaemon(RunFunc runFunc, StopFunc stopFunc);
|
||||||
|
|
||||||
|
//! Indicate daemon is in main loop
|
||||||
|
/*!
|
||||||
|
The \c runFunc passed to \c runDaemon() should call this function
|
||||||
|
to indicate when it has entered (\c running is \c true) or exited
|
||||||
|
(\c running is \c false) the main loop.
|
||||||
|
*/
|
||||||
|
static void daemonRunning(bool running);
|
||||||
|
|
||||||
|
//! Indicate failure of running daemon
|
||||||
|
/*!
|
||||||
|
The \c runFunc passed to \c runDaemon() should call this function
|
||||||
|
to indicate failure. \c result is returned by \c daemonize().
|
||||||
|
*/
|
||||||
|
static void daemonFailed(int result);
|
||||||
|
|
||||||
|
// IArchDaemon overrides
|
||||||
|
virtual void installDaemon(const char* name,
|
||||||
|
const char* description,
|
||||||
|
const char* pathname,
|
||||||
|
const char* commandLine,
|
||||||
|
bool allUsers);
|
||||||
|
virtual void uninstallDaemon(const char* name, bool allUsers);
|
||||||
|
virtual int daemonize(const char* name, DaemonFunc func);
|
||||||
|
virtual bool canInstallDaemon(const char* name, bool allUsers);
|
||||||
|
virtual bool isDaemonInstalled(const char* name, bool allUsers);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static HKEY openKey(HKEY parent, const TCHAR*);
|
||||||
|
static HKEY openKey(HKEY parent, const TCHAR**);
|
||||||
|
static void closeKey(HKEY);
|
||||||
|
static void deleteKey(HKEY, const TCHAR* name);
|
||||||
|
static void deleteValue(HKEY, const TCHAR* name);
|
||||||
|
static void setValue(HKEY, const TCHAR* name,
|
||||||
|
const std::string& value);
|
||||||
|
static std::string readValueString(HKEY, const TCHAR* name);
|
||||||
|
static HKEY openNTServicesKey();
|
||||||
|
static HKEY open95ServicesKey();
|
||||||
|
static HKEY openUserStartupKey();
|
||||||
|
|
||||||
|
int doRunDaemon(RunFunc runFunc, StopFunc stopFunc);
|
||||||
|
void doDaemonRunning(bool running);
|
||||||
|
|
||||||
|
static void setStatus(DWORD state);
|
||||||
|
static void setStatus(DWORD state, DWORD step, DWORD waitHint);
|
||||||
|
static void setStatusError(DWORD error);
|
||||||
|
|
||||||
|
void* runDaemonThread(RunFunc);
|
||||||
|
static void* runDaemonThreadEntry(void*);
|
||||||
|
|
||||||
|
void serviceMain(DWORD, LPTSTR*);
|
||||||
|
static void WINAPI serviceMainEntry(DWORD, LPTSTR*);
|
||||||
|
|
||||||
|
void serviceHandler(DWORD ctrl);
|
||||||
|
static void WINAPI serviceHandlerEntry(DWORD ctrl);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class XArchDaemonRunFailed {
|
||||||
|
public:
|
||||||
|
XArchDaemonRunFailed(int result) : m_result(result) { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
int m_result;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
static CArchDaemonWindows* s_daemon;
|
||||||
|
|
||||||
|
CArchMutex m_serviceMutex;
|
||||||
|
CArchCond m_serviceCondVar;
|
||||||
|
DWORD m_serviceState;
|
||||||
|
bool m_serviceHandlerWaiting;
|
||||||
|
bool m_serviceRunning;
|
||||||
|
StopFunc m_stop;
|
||||||
|
|
||||||
|
DaemonFunc m_daemonFunc;
|
||||||
|
int m_daemonResult;
|
||||||
|
|
||||||
|
SERVICE_STATUS_HANDLE m_statusHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchFileUnix.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchFileUnix
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchFileUnix::CArchFileUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchFileUnix::~CArchFileUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CArchFileUnix::getBasename(const char* pathname)
|
||||||
|
{
|
||||||
|
if (pathname == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* basename = strrchr(pathname, '/');
|
||||||
|
if (basename != NULL) {
|
||||||
|
return basename + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return pathname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchFileUnix::getUserDirectory()
|
||||||
|
{
|
||||||
|
#if HAVE_GETPWUID_R
|
||||||
|
struct passwd pwent;
|
||||||
|
struct passwd* pwentp;
|
||||||
|
#if defined(_SC_GETPW_R_SIZE_MAX)
|
||||||
|
long size = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||||
|
#else
|
||||||
|
long size = BUFSIZ;
|
||||||
|
#endif
|
||||||
|
char* buffer = new char[size];
|
||||||
|
getpwuid_r(getuid(), &pwent, buffer, size, &pwentp);
|
||||||
|
delete[] buffer;
|
||||||
|
#else
|
||||||
|
struct passwd* pwentp = getpwuid(getuid());
|
||||||
|
#endif
|
||||||
|
if (pwentp != NULL && pwentp->pw_dir != NULL) {
|
||||||
|
return pwentp->pw_dir;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchFileUnix::getSystemDirectory()
|
||||||
|
{
|
||||||
|
return "/etc";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchFileUnix::concatPath(const std::string& prefix,
|
||||||
|
const std::string& suffix)
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
path.reserve(prefix.size() + 1 + suffix.size());
|
||||||
|
path += prefix;
|
||||||
|
if (path.size() == 0 || path[path.size() - 1] != '/') {
|
||||||
|
path += '/';
|
||||||
|
}
|
||||||
|
path += suffix;
|
||||||
|
return path;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHFILEUNIX_H
|
||||||
|
#define CARCHFILEUNIX_H
|
||||||
|
|
||||||
|
#include "IArchFile.h"
|
||||||
|
|
||||||
|
#define ARCH_FILE CArchFileUnix
|
||||||
|
|
||||||
|
class CArchFileUnix : public IArchFile {
|
||||||
|
public:
|
||||||
|
CArchFileUnix();
|
||||||
|
virtual ~CArchFileUnix();
|
||||||
|
|
||||||
|
// IArchFile overrides
|
||||||
|
virtual const char* getBasename(const char* pathname);
|
||||||
|
virtual std::string getUserDirectory();
|
||||||
|
virtual std::string getSystemDirectory();
|
||||||
|
virtual std::string concatPath(const std::string& prefix,
|
||||||
|
const std::string& suffix);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchFileWindows.h"
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchFileWindows
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchFileWindows::CArchFileWindows()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchFileWindows::~CArchFileWindows()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CArchFileWindows::getBasename(const char* pathname)
|
||||||
|
{
|
||||||
|
if (pathname == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for last slash
|
||||||
|
const char* basename = strrchr(pathname, '/');
|
||||||
|
if (basename != NULL) {
|
||||||
|
++basename;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
basename = pathname;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for last backslash
|
||||||
|
const char* basename2 = strrchr(pathname, '\\');
|
||||||
|
if (basename2 != NULL && basename2 > basename) {
|
||||||
|
basename = basename2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return basename;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchFileWindows::getUserDirectory()
|
||||||
|
{
|
||||||
|
// try %HOMEPATH%
|
||||||
|
TCHAR dir[MAX_PATH];
|
||||||
|
DWORD size = sizeof(dir) / sizeof(TCHAR);
|
||||||
|
DWORD result = GetEnvironmentVariable(_T("HOMEPATH"), dir, size);
|
||||||
|
if (result != 0 && result <= size) {
|
||||||
|
// sanity check -- if dir doesn't appear to start with a
|
||||||
|
// drive letter and isn't a UNC name then don't use it
|
||||||
|
// FIXME -- allow UNC names
|
||||||
|
if (dir[0] != '\0' && (dir[1] == ':' ||
|
||||||
|
((dir[0] == '\\' || dir[0] == '/') &&
|
||||||
|
(dir[1] == '\\' || dir[1] == '/')))) {
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the location of the personal files. that's as close to
|
||||||
|
// a home directory as we're likely to find.
|
||||||
|
ITEMIDLIST* idl;
|
||||||
|
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &idl))) {
|
||||||
|
TCHAR* path = NULL;
|
||||||
|
if (SHGetPathFromIDList(idl, dir)) {
|
||||||
|
DWORD attr = GetFileAttributes(dir);
|
||||||
|
if (attr != 0xffffffff && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
||||||
|
path = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMalloc* shalloc;
|
||||||
|
if (SUCCEEDED(SHGetMalloc(&shalloc))) {
|
||||||
|
shalloc->Free(idl);
|
||||||
|
shalloc->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path != NULL) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use root of C drive as a default
|
||||||
|
return "C:";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchFileWindows::getSystemDirectory()
|
||||||
|
{
|
||||||
|
// get windows directory
|
||||||
|
char dir[MAX_PATH];
|
||||||
|
if (GetWindowsDirectory(dir, sizeof(dir)) != 0) {
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// can't get it. use C:\ as a default.
|
||||||
|
return "C:";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchFileWindows::concatPath(const std::string& prefix,
|
||||||
|
const std::string& suffix)
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
path.reserve(prefix.size() + 1 + suffix.size());
|
||||||
|
path += prefix;
|
||||||
|
if (path.size() == 0 ||
|
||||||
|
(path[path.size() - 1] != '\\' &&
|
||||||
|
path[path.size() - 1] != '/')) {
|
||||||
|
path += '\\';
|
||||||
|
}
|
||||||
|
path += suffix;
|
||||||
|
return path;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHFILEWINDOWS_H
|
||||||
|
#define CARCHFILEWINDOWS_H
|
||||||
|
|
||||||
|
#include "IArchFile.h"
|
||||||
|
|
||||||
|
#define ARCH_FILE CArchFileWindows
|
||||||
|
|
||||||
|
class CArchFileWindows : public IArchFile {
|
||||||
|
public:
|
||||||
|
CArchFileWindows();
|
||||||
|
virtual ~CArchFileWindows();
|
||||||
|
|
||||||
|
// IArchFile overrides
|
||||||
|
virtual const char* getBasename(const char* pathname);
|
||||||
|
virtual std::string getUserDirectory();
|
||||||
|
virtual std::string getSystemDirectory();
|
||||||
|
virtual std::string concatPath(const std::string& prefix,
|
||||||
|
const std::string& suffix);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
// include appropriate architecture implementation
|
||||||
|
#if WINDOWS_LIKE
|
||||||
|
# include "CArchMiscWindows.cpp"
|
||||||
|
# include "CArchConsoleWindows.cpp"
|
||||||
|
# include "CArchDaemonWindows.cpp"
|
||||||
|
# include "CArchFileWindows.cpp"
|
||||||
|
# include "CArchLogWindows.cpp"
|
||||||
|
# include "CArchMultithreadWindows.cpp"
|
||||||
|
# include "CArchNetworkWinsock.cpp"
|
||||||
|
# include "CArchSleepWindows.cpp"
|
||||||
|
# include "CArchStringWindows.cpp"
|
||||||
|
# include "CArchTimeWindows.cpp"
|
||||||
|
# include "XArchWindows.cpp"
|
||||||
|
#elif UNIX_LIKE
|
||||||
|
# include "CArchConsoleUnix.cpp"
|
||||||
|
# include "CArchDaemonUnix.cpp"
|
||||||
|
# include "CArchFileUnix.cpp"
|
||||||
|
# include "CArchLogUnix.cpp"
|
||||||
|
# if HAVE_PTHREAD
|
||||||
|
# include "CArchMultithreadPosix.cpp"
|
||||||
|
# endif
|
||||||
|
# include "CArchNetworkBSD.cpp"
|
||||||
|
# include "CArchSleepUnix.cpp"
|
||||||
|
# include "CArchStringUnix.cpp"
|
||||||
|
# include "CArchTimeUnix.cpp"
|
||||||
|
# include "XArchUnix.cpp"
|
||||||
|
#endif
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchLogUnix.h"
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchLogUnix
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchLogUnix::CArchLogUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchLogUnix::~CArchLogUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchLogUnix::openLog(const char* name)
|
||||||
|
{
|
||||||
|
openlog(name, 0, LOG_DAEMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchLogUnix::closeLog()
|
||||||
|
{
|
||||||
|
closelog();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchLogUnix::writeLog(ELevel level, const char* msg)
|
||||||
|
{
|
||||||
|
// convert level
|
||||||
|
int priority;
|
||||||
|
switch (level) {
|
||||||
|
case kERROR:
|
||||||
|
priority = LOG_ERR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kWARNING:
|
||||||
|
priority = LOG_WARNING;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kNOTE:
|
||||||
|
priority = LOG_NOTICE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kINFO:
|
||||||
|
priority = LOG_INFO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
priority = LOG_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// log it
|
||||||
|
syslog(priority, "%s", msg);
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHLOGUNIX_H
|
||||||
|
#define CARCHLOGUNIX_H
|
||||||
|
|
||||||
|
#include "IArchLog.h"
|
||||||
|
|
||||||
|
#define ARCH_LOG CArchLogUnix
|
||||||
|
|
||||||
|
class CArchLogUnix : public IArchLog {
|
||||||
|
public:
|
||||||
|
CArchLogUnix();
|
||||||
|
virtual ~CArchLogUnix();
|
||||||
|
|
||||||
|
// IArchLog overrides
|
||||||
|
virtual void openLog(const char* name);
|
||||||
|
virtual void closeLog();
|
||||||
|
virtual void writeLog(ELevel, const char*);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchLogWindows.h"
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchLogWindows
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchLogWindows::CArchLogWindows()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchLogWindows::~CArchLogWindows()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchLogWindows::openLog(const char* name)
|
||||||
|
{
|
||||||
|
if (!CArchMiscWindows::isWindows95Family()) {
|
||||||
|
m_eventLog = RegisterEventSource(NULL, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchLogWindows::closeLog()
|
||||||
|
{
|
||||||
|
if (m_eventLog != NULL) {
|
||||||
|
DeregisterEventSource(m_eventLog);
|
||||||
|
m_eventLog = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchLogWindows::writeLog(ELevel level, const char* msg)
|
||||||
|
{
|
||||||
|
if (m_eventLog != NULL) {
|
||||||
|
// convert priority
|
||||||
|
WORD type;
|
||||||
|
switch (level) {
|
||||||
|
case kERROR:
|
||||||
|
type = EVENTLOG_ERROR_TYPE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kWARNING:
|
||||||
|
type = EVENTLOG_WARNING_TYPE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
type = EVENTLOG_INFORMATION_TYPE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// log it
|
||||||
|
// FIXME -- win32 wants to use a message table to look up event
|
||||||
|
// strings. log messages aren't organized that way so we'll
|
||||||
|
// just dump our string into the raw data section of the event
|
||||||
|
// so users can at least see the message. note that we use our
|
||||||
|
// level as the event category.
|
||||||
|
ReportEvent(m_eventLog, type, static_cast<WORD>(level),
|
||||||
|
0, // event ID
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
strlen(msg + 1), // raw data size
|
||||||
|
NULL,
|
||||||
|
const_cast<char*>(msg));// raw data
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHLOGWINDOWS_H
|
||||||
|
#define CARCHLOGWINDOWS_H
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include "IArchLog.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#define ARCH_LOG CArchLogWindows
|
||||||
|
|
||||||
|
class CArchLogWindows : public IArchLog {
|
||||||
|
public:
|
||||||
|
CArchLogWindows();
|
||||||
|
virtual ~CArchLogWindows();
|
||||||
|
|
||||||
|
// IArchLog overrides
|
||||||
|
virtual void openLog(const char* name);
|
||||||
|
virtual void closeLog();
|
||||||
|
virtual void writeLog(ELevel, const char*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HANDLE m_eventLog;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
|
#include "CArchDaemonWindows.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchMiscWindows
|
||||||
|
//
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMiscWindows::isWindows95Family()
|
||||||
|
{
|
||||||
|
OSVERSIONINFO version;
|
||||||
|
version.dwOSVersionInfoSize = sizeof(version);
|
||||||
|
if (GetVersionEx(&version) == 0) {
|
||||||
|
// cannot determine OS; assume windows 95 family
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchMiscWindows::runDaemon(RunFunc runFunc, StopFunc stopFunc)
|
||||||
|
{
|
||||||
|
return CArchDaemonWindows::runDaemon(runFunc, stopFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMiscWindows::daemonRunning(bool running)
|
||||||
|
{
|
||||||
|
CArchDaemonWindows::daemonRunning(running);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMiscWindows::daemonFailed(int result)
|
||||||
|
{
|
||||||
|
CArchDaemonWindows::daemonFailed(result);
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHMISCWINDOWS_H
|
||||||
|
#define CARCHMISCWINDOWS_H
|
||||||
|
|
||||||
|
class CArchMiscWindows {
|
||||||
|
public:
|
||||||
|
typedef int (*RunFunc)(void);
|
||||||
|
typedef void (*StopFunc)(void);
|
||||||
|
|
||||||
|
//! Test if windows 95, et al.
|
||||||
|
/*!
|
||||||
|
Returns true iff the platform is win95/98/me.
|
||||||
|
*/
|
||||||
|
static bool isWindows95Family();
|
||||||
|
|
||||||
|
//! Run the daemon
|
||||||
|
/*!
|
||||||
|
Delegates to CArchDaemonWindows.
|
||||||
|
*/
|
||||||
|
static int runDaemon(RunFunc runFunc, StopFunc stopFunc);
|
||||||
|
|
||||||
|
//! Indicate daemon is in main loop
|
||||||
|
/*!
|
||||||
|
Delegates to CArchDaemonWindows.
|
||||||
|
*/
|
||||||
|
static void daemonRunning(bool running);
|
||||||
|
|
||||||
|
//! Indicate failure of running daemon
|
||||||
|
/*!
|
||||||
|
Delegates to CArchDaemonWindows.
|
||||||
|
*/
|
||||||
|
static void daemonFailed(int result);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,748 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchMultithreadPosix.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "XArch.h"
|
||||||
|
#include <signal.h>
|
||||||
|
#if TIME_WITH_SYS_TIME
|
||||||
|
# include <sys/time.h>
|
||||||
|
# include <time.h>
|
||||||
|
#else
|
||||||
|
# if HAVE_SYS_TIME_H
|
||||||
|
# include <sys/time.h>
|
||||||
|
# else
|
||||||
|
# include <time.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#define SIGWAKEUP SIGUSR1
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchThreadImpl
|
||||||
|
//
|
||||||
|
|
||||||
|
class CArchThreadImpl {
|
||||||
|
public:
|
||||||
|
CArchThreadImpl();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int m_refCount;
|
||||||
|
pthread_t m_thread;
|
||||||
|
IArchMultithread::ThreadFunc m_func;
|
||||||
|
void* m_userData;
|
||||||
|
bool m_cancel;
|
||||||
|
bool m_cancelling;
|
||||||
|
bool m_exited;
|
||||||
|
void* m_result;
|
||||||
|
};
|
||||||
|
|
||||||
|
CArchThreadImpl::CArchThreadImpl() :
|
||||||
|
m_refCount(1),
|
||||||
|
m_func(NULL),
|
||||||
|
m_userData(NULL),
|
||||||
|
m_cancel(false),
|
||||||
|
m_cancelling(false),
|
||||||
|
m_exited(false),
|
||||||
|
m_result(NULL)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchMultithreadPosix
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchMultithreadPosix* CArchMultithreadPosix::s_instance = NULL;
|
||||||
|
|
||||||
|
CArchMultithreadPosix::CArchMultithreadPosix() :
|
||||||
|
m_newThreadCalled(false)
|
||||||
|
{
|
||||||
|
assert(s_instance == NULL);
|
||||||
|
|
||||||
|
s_instance = this;
|
||||||
|
|
||||||
|
// create mutex for thread list
|
||||||
|
m_threadMutex = newMutex();
|
||||||
|
|
||||||
|
// create thread for calling (main) thread and add it to our
|
||||||
|
// list. no need to lock the mutex since we're the only thread.
|
||||||
|
m_mainThread = new CArchThreadImpl;
|
||||||
|
m_mainThread->m_thread = pthread_self();
|
||||||
|
insert(m_mainThread);
|
||||||
|
|
||||||
|
// install SIGWAKEUP handler. this causes SIGWAKEUP to interrupt
|
||||||
|
// system calls. we use that when cancelling a thread to force it
|
||||||
|
// to wake up immediately if it's blocked in a system call. we
|
||||||
|
// won't need this until another thread is created but it's fine
|
||||||
|
// to install it now.
|
||||||
|
struct sigaction act;
|
||||||
|
sigemptyset(&act.sa_mask);
|
||||||
|
# if defined(SA_INTERRUPT)
|
||||||
|
act.sa_flags = SA_INTERRUPT;
|
||||||
|
# else
|
||||||
|
act.sa_flags = 0;
|
||||||
|
# endif
|
||||||
|
act.sa_handler = &threadCancel;
|
||||||
|
sigaction(SIGWAKEUP, &act, NULL);
|
||||||
|
|
||||||
|
// set desired signal dispositions. let SIGWAKEUP through but
|
||||||
|
// ignore SIGPIPE (we'll handle EPIPE).
|
||||||
|
sigset_t sigset;
|
||||||
|
sigemptyset(&sigset);
|
||||||
|
sigaddset(&sigset, SIGWAKEUP);
|
||||||
|
pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
|
||||||
|
sigemptyset(&sigset);
|
||||||
|
sigaddset(&sigset, SIGPIPE);
|
||||||
|
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchMultithreadPosix::~CArchMultithreadPosix()
|
||||||
|
{
|
||||||
|
assert(s_instance != NULL);
|
||||||
|
|
||||||
|
closeMutex(m_threadMutex);
|
||||||
|
s_instance = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchCond
|
||||||
|
CArchMultithreadPosix::newCondVar()
|
||||||
|
{
|
||||||
|
CArchCondImpl* cond = new CArchCondImpl;
|
||||||
|
int status = pthread_cond_init(&cond->m_cond, NULL);
|
||||||
|
assert(status == 0);
|
||||||
|
return cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::closeCondVar(CArchCond cond)
|
||||||
|
{
|
||||||
|
int status = pthread_cond_destroy(&cond->m_cond);
|
||||||
|
assert(status == 0);
|
||||||
|
delete cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::signalCondVar(CArchCond cond)
|
||||||
|
{
|
||||||
|
int status = pthread_cond_signal(&cond->m_cond);
|
||||||
|
assert(status == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::broadcastCondVar(CArchCond cond)
|
||||||
|
{
|
||||||
|
int status = pthread_cond_broadcast(&cond->m_cond);
|
||||||
|
assert(status == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMultithreadPosix::waitCondVar(CArchCond cond,
|
||||||
|
CArchMutex mutex, double timeout)
|
||||||
|
{
|
||||||
|
// get final time
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
struct timespec finalTime;
|
||||||
|
finalTime.tv_sec = now.tv_sec;
|
||||||
|
finalTime.tv_nsec = now.tv_usec * 1000;
|
||||||
|
if (timeout >= 0.0) {
|
||||||
|
const long timeout_sec = (long)timeout;
|
||||||
|
const long timeout_nsec = (long)(1.0e+9 * (timeout - timeout_sec));
|
||||||
|
finalTime.tv_sec += timeout_sec;
|
||||||
|
finalTime.tv_nsec += timeout_nsec;
|
||||||
|
if (finalTime.tv_nsec >= 1000000000) {
|
||||||
|
finalTime.tv_nsec -= 1000000000;
|
||||||
|
finalTime.tv_sec += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// repeat until we reach the final time
|
||||||
|
int status;
|
||||||
|
for (;;) {
|
||||||
|
// get current time
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
struct timespec endTime;
|
||||||
|
endTime.tv_sec = now.tv_sec;
|
||||||
|
endTime.tv_nsec = now.tv_usec * 1000;
|
||||||
|
|
||||||
|
// done if past final timeout
|
||||||
|
if (timeout >= 0.0) {
|
||||||
|
if (endTime.tv_sec > finalTime.tv_sec ||
|
||||||
|
(endTime.tv_sec == finalTime.tv_sec &&
|
||||||
|
endTime.tv_nsec >= finalTime.tv_nsec)) {
|
||||||
|
status = ETIMEDOUT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute the next timeout
|
||||||
|
endTime.tv_nsec += 50000000;
|
||||||
|
if (endTime.tv_nsec >= 1000000000) {
|
||||||
|
endTime.tv_nsec -= 1000000000;
|
||||||
|
endTime.tv_sec += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't wait past final timeout
|
||||||
|
if (timeout >= 0.0) {
|
||||||
|
if (endTime.tv_sec > finalTime.tv_sec ||
|
||||||
|
(endTime.tv_sec == finalTime.tv_sec &&
|
||||||
|
endTime.tv_nsec >= finalTime.tv_nsec)) {
|
||||||
|
endTime = finalTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if we should cancel this thread
|
||||||
|
testCancelThread();
|
||||||
|
|
||||||
|
// wait
|
||||||
|
status = pthread_cond_timedwait(&cond->m_cond,
|
||||||
|
&mutex->m_mutex, &endTime);
|
||||||
|
|
||||||
|
// check for cancel again
|
||||||
|
testCancelThread();
|
||||||
|
|
||||||
|
// check wait status
|
||||||
|
if (status != ETIMEDOUT && status != EINTR) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case 0:
|
||||||
|
// success
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case ETIMEDOUT:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "condition variable wait error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchMutex
|
||||||
|
CArchMultithreadPosix::newMutex()
|
||||||
|
{
|
||||||
|
CArchMutexImpl* mutex = new CArchMutexImpl;
|
||||||
|
int status = pthread_mutex_init(&mutex->m_mutex, NULL);
|
||||||
|
assert(status == 0);
|
||||||
|
/*
|
||||||
|
status = pthread_mutexattr_settype(&mutex->m_mutex,
|
||||||
|
PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
assert(status == 0);
|
||||||
|
*/
|
||||||
|
return mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::closeMutex(CArchMutex mutex)
|
||||||
|
{
|
||||||
|
int status = pthread_mutex_destroy(&mutex->m_mutex);
|
||||||
|
assert(status == 0);
|
||||||
|
delete mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::lockMutex(CArchMutex mutex)
|
||||||
|
{
|
||||||
|
int status = pthread_mutex_lock(&mutex->m_mutex);
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case 0:
|
||||||
|
// success
|
||||||
|
return;
|
||||||
|
|
||||||
|
case EDEADLK:
|
||||||
|
assert(0 && "lock already owned");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EAGAIN:
|
||||||
|
assert(0 && "too many recursive locks");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "unexpected error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::unlockMutex(CArchMutex mutex)
|
||||||
|
{
|
||||||
|
int status = pthread_mutex_unlock(&mutex->m_mutex);
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case 0:
|
||||||
|
// success
|
||||||
|
return;
|
||||||
|
|
||||||
|
case EPERM:
|
||||||
|
assert(0 && "thread doesn't own a lock");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "unexpected error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThread
|
||||||
|
CArchMultithreadPosix::newThread(ThreadFunc func, void* data)
|
||||||
|
{
|
||||||
|
assert(func != NULL);
|
||||||
|
|
||||||
|
// initialize signal handler. we do this here instead of the
|
||||||
|
// constructor so we can avoid daemonizing (using fork())
|
||||||
|
// when there are multiple threads. clients can safely
|
||||||
|
// use condition variables and mutexes before creating a
|
||||||
|
// new thread and they can safely use the only thread
|
||||||
|
// they have access to, the main thread, so they really
|
||||||
|
// can't tell the difference.
|
||||||
|
if (!m_newThreadCalled) {
|
||||||
|
m_newThreadCalled = true;
|
||||||
|
startSignalHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// create thread impl for new thread
|
||||||
|
CArchThreadImpl* thread = new CArchThreadImpl;
|
||||||
|
thread->m_func = func;
|
||||||
|
thread->m_userData = data;
|
||||||
|
|
||||||
|
// mask some signals in all threads except the main thread
|
||||||
|
sigset_t sigset, oldsigset;
|
||||||
|
sigemptyset(&sigset);
|
||||||
|
sigaddset(&sigset, SIGINT);
|
||||||
|
sigaddset(&sigset, SIGTERM);
|
||||||
|
pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset);
|
||||||
|
|
||||||
|
// create the thread. pthread_create() on RedHat 7.2 smp fails
|
||||||
|
// if passed a NULL attr so use a default attr.
|
||||||
|
pthread_attr_t attr;
|
||||||
|
int status = pthread_attr_init(&attr);
|
||||||
|
if (status == 0) {
|
||||||
|
status = pthread_create(&thread->m_thread, &attr,
|
||||||
|
&CArchMultithreadPosix::threadFunc, thread);
|
||||||
|
pthread_attr_destroy(&attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore signals
|
||||||
|
pthread_sigmask(SIG_SETMASK, &oldsigset, NULL);
|
||||||
|
|
||||||
|
// check if thread was started
|
||||||
|
if (status != 0) {
|
||||||
|
// failed to start thread so clean up
|
||||||
|
delete thread;
|
||||||
|
thread = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// add thread to list
|
||||||
|
insert(thread);
|
||||||
|
|
||||||
|
// increment ref count to account for the thread itself
|
||||||
|
refThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
// note that the child thread will wait until we release this mutex
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThread
|
||||||
|
CArchMultithreadPosix::newCurrentThread()
|
||||||
|
{
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
CArchThreadImpl* thread = find(pthread_self());
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
assert(thread != NULL);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::closeThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
|
||||||
|
// decrement ref count and clean up thread if no more references
|
||||||
|
if (--thread->m_refCount == 0) {
|
||||||
|
// detach from thread (unless it's the main thread)
|
||||||
|
if (thread->m_func != NULL) {
|
||||||
|
pthread_detach(thread->m_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove thread from list
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
assert(findNoRef(thread->m_thread) == thread);
|
||||||
|
erase(thread);
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// done with thread
|
||||||
|
delete thread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThread
|
||||||
|
CArchMultithreadPosix::copyThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
refThread(thread);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::cancelThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
|
||||||
|
// set cancel and wakeup flags if thread can be cancelled
|
||||||
|
bool wakeup = false;
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
if (!thread->m_exited && !thread->m_cancelling) {
|
||||||
|
thread->m_cancel = true;
|
||||||
|
wakeup = true;
|
||||||
|
}
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// force thread to exit system calls if wakeup is true
|
||||||
|
if (wakeup) {
|
||||||
|
pthread_kill(thread->m_thread, SIGWAKEUP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::setPriorityOfThread(CArchThread thread, int /*n*/)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::testCancelThread()
|
||||||
|
{
|
||||||
|
// find current thread
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
CArchThreadImpl* thread = findNoRef(pthread_self());
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// test cancel on thread
|
||||||
|
testCancelThreadImpl(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMultithreadPosix::wait(CArchThread target, double timeout)
|
||||||
|
{
|
||||||
|
assert(target != NULL);
|
||||||
|
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// find current thread
|
||||||
|
CArchThreadImpl* self = findNoRef(pthread_self());
|
||||||
|
|
||||||
|
// ignore wait if trying to wait on ourself
|
||||||
|
if (target == self) {
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ref the target so it can't go away while we're watching it
|
||||||
|
refThread(target);
|
||||||
|
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// do first test regardless of timeout
|
||||||
|
testCancelThreadImpl(self);
|
||||||
|
if (isExitedThread(target)) {
|
||||||
|
closeThread(target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait and repeat test if there's a timeout
|
||||||
|
if (timeout != 0.0) {
|
||||||
|
const double start = ARCH->time();
|
||||||
|
do {
|
||||||
|
// wait a little
|
||||||
|
ARCH->sleep(0.05);
|
||||||
|
|
||||||
|
// repeat test
|
||||||
|
testCancelThreadImpl(self);
|
||||||
|
if (isExitedThread(target)) {
|
||||||
|
closeThread(target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// repeat wait and test until timed out
|
||||||
|
} while (timeout < 0.0 || (ARCH->time() - start) <= timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
closeThread(target);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
closeThread(target);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMultithreadPosix::waitForEvent(double /*timeout*/)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMultithreadPosix::isSameThread(CArchThread thread1, CArchThread thread2)
|
||||||
|
{
|
||||||
|
return (thread1 == thread2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMultithreadPosix::isExitedThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
bool exited = thread->m_exited;
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
return exited;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
CArchMultithreadPosix::getResultOfThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
void* result = thread->m_result;
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
IArchMultithread::ThreadID
|
||||||
|
CArchMultithreadPosix::getIDOfThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ThreadID>(reinterpret_cast<void*>(thread));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::startSignalHandler()
|
||||||
|
{
|
||||||
|
// set signal mask. the main thread blocks these signals and
|
||||||
|
// the signal handler thread will listen for them.
|
||||||
|
sigset_t sigset;
|
||||||
|
sigemptyset(&sigset);
|
||||||
|
sigaddset(&sigset, SIGINT);
|
||||||
|
sigaddset(&sigset, SIGTERM);
|
||||||
|
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
|
||||||
|
|
||||||
|
// fire up the INT and TERM signal handler thread. we could
|
||||||
|
// instead arrange to catch and handle these signals but
|
||||||
|
// we'd be unable to cancel the main thread since no pthread
|
||||||
|
// calls are allowed in a signal handler.
|
||||||
|
pthread_attr_t attr;
|
||||||
|
int status = pthread_attr_init(&attr);
|
||||||
|
if (status == 0) {
|
||||||
|
status = pthread_create(&m_signalThread, &attr,
|
||||||
|
&CArchMultithreadPosix::threadSignalHandler,
|
||||||
|
m_mainThread);
|
||||||
|
pthread_attr_destroy(&attr);
|
||||||
|
}
|
||||||
|
if (status != 0) {
|
||||||
|
// can't create thread to wait for signal so don't block
|
||||||
|
// the signals.
|
||||||
|
sigemptyset(&sigset);
|
||||||
|
sigaddset(&sigset, SIGINT);
|
||||||
|
sigaddset(&sigset, SIGTERM);
|
||||||
|
pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThreadImpl*
|
||||||
|
CArchMultithreadPosix::find(pthread_t thread)
|
||||||
|
{
|
||||||
|
CArchThreadImpl* impl = findNoRef(thread);
|
||||||
|
if (impl != NULL) {
|
||||||
|
refThread(impl);
|
||||||
|
}
|
||||||
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThreadImpl*
|
||||||
|
CArchMultithreadPosix::findNoRef(pthread_t thread)
|
||||||
|
{
|
||||||
|
// linear search
|
||||||
|
for (CThreadList::const_iterator index = m_threadList.begin();
|
||||||
|
index != m_threadList.end(); ++index) {
|
||||||
|
if ((*index)->m_thread == thread) {
|
||||||
|
return *index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::insert(CArchThreadImpl* thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
|
||||||
|
// thread shouldn't already be on the list
|
||||||
|
assert(findNoRef(thread->m_thread) == NULL);
|
||||||
|
|
||||||
|
// append to list
|
||||||
|
m_threadList.push_back(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::erase(CArchThreadImpl* thread)
|
||||||
|
{
|
||||||
|
for (CThreadList::iterator index = m_threadList.begin();
|
||||||
|
index != m_threadList.end(); ++index) {
|
||||||
|
if (*index == thread) {
|
||||||
|
m_threadList.erase(index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::refThread(CArchThreadImpl* thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
assert(findNoRef(thread->m_thread) != NULL);
|
||||||
|
++thread->m_refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::testCancelThreadImpl(CArchThreadImpl* thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
|
||||||
|
// update cancel state
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
bool cancel = false;
|
||||||
|
if (thread->m_cancel && !thread->m_cancelling) {
|
||||||
|
thread->m_cancelling = true;
|
||||||
|
thread->m_cancel = false;
|
||||||
|
cancel = true;
|
||||||
|
}
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// unwind thread's stack if cancelling
|
||||||
|
if (cancel) {
|
||||||
|
throw XThreadCancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
CArchMultithreadPosix::threadFunc(void* vrep)
|
||||||
|
{
|
||||||
|
// get the thread
|
||||||
|
CArchThreadImpl* thread = reinterpret_cast<CArchThreadImpl*>(vrep);
|
||||||
|
|
||||||
|
// setup pthreads
|
||||||
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||||
|
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
|
||||||
|
|
||||||
|
// run thread
|
||||||
|
s_instance->doThreadFunc(thread);
|
||||||
|
|
||||||
|
// terminate the thread
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::doThreadFunc(CArchThread thread)
|
||||||
|
{
|
||||||
|
// default priority is slightly below normal
|
||||||
|
setPriorityOfThread(thread, 1);
|
||||||
|
|
||||||
|
// wait for parent to initialize this object
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
void* result = NULL;
|
||||||
|
try {
|
||||||
|
// go
|
||||||
|
result = (*thread->m_func)(thread->m_userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (XThreadCancel&) {
|
||||||
|
// client called cancel()
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
// note -- don't catch (...) to avoid masking bugs
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
thread->m_exited = true;
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
closeThread(thread);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// thread has exited
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
thread->m_result = result;
|
||||||
|
thread->m_exited = true;
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// done with thread
|
||||||
|
closeThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::threadCancel(int)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
CArchMultithreadPosix::threadSignalHandler(void* vrep)
|
||||||
|
{
|
||||||
|
CArchThreadImpl* mainThread = reinterpret_cast<CArchThreadImpl*>(vrep);
|
||||||
|
|
||||||
|
// detach
|
||||||
|
pthread_detach(pthread_self());
|
||||||
|
|
||||||
|
// add signal to mask
|
||||||
|
sigset_t sigset;
|
||||||
|
sigemptyset(&sigset);
|
||||||
|
sigaddset(&sigset, SIGINT);
|
||||||
|
sigaddset(&sigset, SIGTERM);
|
||||||
|
|
||||||
|
// also wait on SIGABRT. on linux (others?) this thread (process)
|
||||||
|
// will persist after all the other threads evaporate due to an
|
||||||
|
// assert unless we wait on SIGABRT. that means our resources (like
|
||||||
|
// the socket we're listening on) are not released and never will be
|
||||||
|
// until the lingering thread is killed. i don't know why sigwait()
|
||||||
|
// should protect the thread from being killed. note that sigwait()
|
||||||
|
// doesn't actually return if we receive SIGABRT and, for some
|
||||||
|
// reason, we don't have to block SIGABRT.
|
||||||
|
sigaddset(&sigset, SIGABRT);
|
||||||
|
|
||||||
|
// we exit the loop via thread cancellation in sigwait()
|
||||||
|
for (;;) {
|
||||||
|
// wait
|
||||||
|
#if HAVE_POSIX_SIGWAIT
|
||||||
|
int signal;
|
||||||
|
sigwait(&sigset, &signal);
|
||||||
|
#else
|
||||||
|
sigwait(&sigset);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// if we get here then the signal was raised. cancel the main
|
||||||
|
// thread so it can shut down cleanly.
|
||||||
|
ARCH->cancelThread(mainThread);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHMULTITHREADPOSIX_H
|
||||||
|
#define CARCHMULTITHREADPOSIX_H
|
||||||
|
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
#include "stdlist.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#define ARCH_MULTITHREAD CArchMultithreadPosix
|
||||||
|
|
||||||
|
class CArchCondImpl {
|
||||||
|
public:
|
||||||
|
pthread_cond_t m_cond;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CArchMutexImpl {
|
||||||
|
public:
|
||||||
|
pthread_mutex_t m_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CArchMultithreadPosix : public IArchMultithread {
|
||||||
|
public:
|
||||||
|
CArchMultithreadPosix();
|
||||||
|
virtual ~CArchMultithreadPosix();
|
||||||
|
|
||||||
|
// IArchMultithread overrides
|
||||||
|
virtual CArchCond newCondVar();
|
||||||
|
virtual void closeCondVar(CArchCond);
|
||||||
|
virtual void signalCondVar(CArchCond);
|
||||||
|
virtual void broadcastCondVar(CArchCond);
|
||||||
|
virtual bool waitCondVar(CArchCond, CArchMutex, double timeout);
|
||||||
|
virtual CArchMutex newMutex();
|
||||||
|
virtual void closeMutex(CArchMutex);
|
||||||
|
virtual void lockMutex(CArchMutex);
|
||||||
|
virtual void unlockMutex(CArchMutex);
|
||||||
|
virtual CArchThread newThread(ThreadFunc, void*);
|
||||||
|
virtual CArchThread newCurrentThread();
|
||||||
|
virtual CArchThread copyThread(CArchThread);
|
||||||
|
virtual void closeThread(CArchThread);
|
||||||
|
virtual void cancelThread(CArchThread);
|
||||||
|
virtual void setPriorityOfThread(CArchThread, int n);
|
||||||
|
virtual void testCancelThread();
|
||||||
|
virtual bool wait(CArchThread, double timeout);
|
||||||
|
virtual bool waitForEvent(double timeout);
|
||||||
|
virtual bool isSameThread(CArchThread, CArchThread);
|
||||||
|
virtual bool isExitedThread(CArchThread);
|
||||||
|
virtual void* getResultOfThread(CArchThread);
|
||||||
|
virtual ThreadID getIDOfThread(CArchThread);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void startSignalHandler();
|
||||||
|
|
||||||
|
CArchThreadImpl* find(pthread_t thread);
|
||||||
|
CArchThreadImpl* findNoRef(pthread_t thread);
|
||||||
|
void insert(CArchThreadImpl* thread);
|
||||||
|
void erase(CArchThreadImpl* thread);
|
||||||
|
|
||||||
|
void refThread(CArchThreadImpl* rep);
|
||||||
|
void testCancelThreadImpl(CArchThreadImpl* rep);
|
||||||
|
|
||||||
|
void doThreadFunc(CArchThread thread);
|
||||||
|
static void* threadFunc(void* vrep);
|
||||||
|
static void threadCancel(int);
|
||||||
|
static void* threadSignalHandler(void* vrep);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::list<CArchThread> CThreadList;
|
||||||
|
|
||||||
|
static CArchMultithreadPosix* s_instance;
|
||||||
|
|
||||||
|
bool m_newThreadCalled;
|
||||||
|
|
||||||
|
CArchMutex m_threadMutex;
|
||||||
|
CArchThread m_mainThread;
|
||||||
|
CThreadList m_threadList;
|
||||||
|
|
||||||
|
pthread_t m_signalThread;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,648 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(_MT)
|
||||||
|
# error multithreading compile option is required
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "CArchMultithreadWindows.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "XArch.h"
|
||||||
|
#include <process.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// note -- implementation of condition variable taken from:
|
||||||
|
// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
|
||||||
|
// titled "Strategies for Implementing POSIX Condition Variables
|
||||||
|
// on Win32." it also provides an implementation that doesn't
|
||||||
|
// suffer from the incorrectness problem described in our
|
||||||
|
// corresponding header but it is slower, still unfair, and
|
||||||
|
// can cause busy waiting.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchThreadImpl
|
||||||
|
//
|
||||||
|
|
||||||
|
class CArchThreadImpl {
|
||||||
|
public:
|
||||||
|
CArchThreadImpl();
|
||||||
|
~CArchThreadImpl();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int m_refCount;
|
||||||
|
HANDLE m_thread;
|
||||||
|
DWORD m_id;
|
||||||
|
IArchMultithread::ThreadFunc m_func;
|
||||||
|
void* m_userData;
|
||||||
|
HANDLE m_cancel;
|
||||||
|
bool m_cancelling;
|
||||||
|
HANDLE m_exit;
|
||||||
|
void* m_result;
|
||||||
|
};
|
||||||
|
|
||||||
|
CArchThreadImpl::CArchThreadImpl() :
|
||||||
|
m_refCount(1),
|
||||||
|
m_thread(NULL),
|
||||||
|
m_id(0),
|
||||||
|
m_func(NULL),
|
||||||
|
m_userData(NULL),
|
||||||
|
m_cancelling(false),
|
||||||
|
m_result(NULL)
|
||||||
|
{
|
||||||
|
m_exit = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
m_cancel = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThreadImpl::~CArchThreadImpl()
|
||||||
|
{
|
||||||
|
CloseHandle(m_exit);
|
||||||
|
CloseHandle(m_cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchMultithreadWindows
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchMultithreadWindows* CArchMultithreadWindows::s_instance = NULL;
|
||||||
|
|
||||||
|
CArchMultithreadWindows::CArchMultithreadWindows()
|
||||||
|
{
|
||||||
|
assert(s_instance == NULL);
|
||||||
|
s_instance = this;
|
||||||
|
|
||||||
|
// create mutex for thread list
|
||||||
|
m_threadMutex = newMutex();
|
||||||
|
|
||||||
|
// create thread for calling (main) thread and add it to our
|
||||||
|
// list. no need to lock the mutex since we're the only thread.
|
||||||
|
CArchThreadImpl* mainThread = new CArchThreadImpl;
|
||||||
|
mainThread->m_thread = NULL;
|
||||||
|
mainThread->m_id = GetCurrentThreadId();
|
||||||
|
insert(mainThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchMultithreadWindows::~CArchMultithreadWindows()
|
||||||
|
{
|
||||||
|
s_instance = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE
|
||||||
|
CArchMultithreadWindows::getCancelEventForCurrentThread()
|
||||||
|
{
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
CArchThreadImpl* thread = findNoRef(GetCurrentThreadId());
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
return thread->m_cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchMultithreadWindows*
|
||||||
|
CArchMultithreadWindows::getInstance()
|
||||||
|
{
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchCond
|
||||||
|
CArchMultithreadWindows::newCondVar()
|
||||||
|
{
|
||||||
|
CArchCondImpl* cond = new CArchCondImpl;
|
||||||
|
cond->m_events[CArchCondImpl::kSignal] = CreateEvent(NULL,
|
||||||
|
FALSE, FALSE, NULL);
|
||||||
|
cond->m_events[CArchCondImpl::kBroadcast] = CreateEvent(NULL,
|
||||||
|
TRUE, FALSE, NULL);
|
||||||
|
cond->m_waitCountMutex = newMutex();
|
||||||
|
cond->m_waitCount = 0;
|
||||||
|
return cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::closeCondVar(CArchCond cond)
|
||||||
|
{
|
||||||
|
CloseHandle(cond->m_events[CArchCondImpl::kSignal]);
|
||||||
|
CloseHandle(cond->m_events[CArchCondImpl::kBroadcast]);
|
||||||
|
closeMutex(cond->m_waitCountMutex);
|
||||||
|
delete cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::signalCondVar(CArchCond cond)
|
||||||
|
{
|
||||||
|
// is anybody waiting?
|
||||||
|
lockMutex(cond->m_waitCountMutex);
|
||||||
|
const bool hasWaiter = (cond->m_waitCount > 0);
|
||||||
|
unlockMutex(cond->m_waitCountMutex);
|
||||||
|
|
||||||
|
// wake one thread if anybody is waiting
|
||||||
|
if (hasWaiter) {
|
||||||
|
SetEvent(cond->m_events[CArchCondImpl::kSignal]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::broadcastCondVar(CArchCond cond)
|
||||||
|
{
|
||||||
|
// is anybody waiting?
|
||||||
|
lockMutex(cond->m_waitCountMutex);
|
||||||
|
const bool hasWaiter = (cond->m_waitCount > 0);
|
||||||
|
unlockMutex(cond->m_waitCountMutex);
|
||||||
|
|
||||||
|
// wake all threads if anybody is waiting
|
||||||
|
if (hasWaiter) {
|
||||||
|
SetEvent(cond->m_events[CArchCondImpl::kBroadcast]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMultithreadWindows::waitCondVar(CArchCond cond,
|
||||||
|
CArchMutex mutex, double timeout)
|
||||||
|
{
|
||||||
|
// prepare to wait
|
||||||
|
const DWORD winTimeout = (timeout < 0.0) ? INFINITE :
|
||||||
|
static_cast<DWORD>(1000.0 * timeout);
|
||||||
|
|
||||||
|
// make a list of the condition variable events and the cancel event
|
||||||
|
// for the current thread.
|
||||||
|
HANDLE handles[3];
|
||||||
|
handles[0] = cond->m_events[CArchCondImpl::kSignal];
|
||||||
|
handles[1] = cond->m_events[CArchCondImpl::kBroadcast];
|
||||||
|
handles[2] = getCancelEventForCurrentThread();
|
||||||
|
|
||||||
|
// update waiter count
|
||||||
|
lockMutex(cond->m_waitCountMutex);
|
||||||
|
++cond->m_waitCount;
|
||||||
|
unlockMutex(cond->m_waitCountMutex);
|
||||||
|
|
||||||
|
// release mutex. this should be atomic with the wait so that it's
|
||||||
|
// impossible for another thread to signal us between the unlock and
|
||||||
|
// the wait, which would lead to a lost signal on broadcasts.
|
||||||
|
// however, we're using a manual reset event for broadcasts which
|
||||||
|
// stays set until we reset it, so we don't lose the broadcast.
|
||||||
|
unlockMutex(mutex);
|
||||||
|
|
||||||
|
// wait for a signal or broadcast
|
||||||
|
DWORD result = WaitForMultipleObjects(3, handles, FALSE, winTimeout);
|
||||||
|
|
||||||
|
// cancel takes priority
|
||||||
|
if (result != WAIT_OBJECT_0 + 2 &&
|
||||||
|
WaitForSingleObject(handles[2], 0) == WAIT_OBJECT_0) {
|
||||||
|
result = WAIT_OBJECT_0 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the waiter count and check if we're the last waiter
|
||||||
|
lockMutex(cond->m_waitCountMutex);
|
||||||
|
--cond->m_waitCount;
|
||||||
|
const bool last = (result == WAIT_OBJECT_0 + 1 && cond->m_waitCount == 0);
|
||||||
|
unlockMutex(cond->m_waitCountMutex);
|
||||||
|
|
||||||
|
// reset the broadcast event if we're the last waiter
|
||||||
|
if (last) {
|
||||||
|
ResetEvent(cond->m_events[CArchCondImpl::kBroadcast]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reacquire the mutex
|
||||||
|
lockMutex(mutex);
|
||||||
|
|
||||||
|
// cancel thread if necessary
|
||||||
|
if (result == WAIT_OBJECT_0 + 2) {
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return success or failure
|
||||||
|
return (result == WAIT_OBJECT_0 + 0 ||
|
||||||
|
result == WAIT_OBJECT_0 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchMutex
|
||||||
|
CArchMultithreadWindows::newMutex()
|
||||||
|
{
|
||||||
|
CArchMutexImpl* mutex = new CArchMutexImpl;
|
||||||
|
InitializeCriticalSection(&mutex->m_mutex);
|
||||||
|
return mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::closeMutex(CArchMutex mutex)
|
||||||
|
{
|
||||||
|
DeleteCriticalSection(&mutex->m_mutex);
|
||||||
|
delete mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::lockMutex(CArchMutex mutex)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&mutex->m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::unlockMutex(CArchMutex mutex)
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&mutex->m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThread
|
||||||
|
CArchMultithreadWindows::newThread(ThreadFunc func, void* data)
|
||||||
|
{
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// create thread impl for new thread
|
||||||
|
CArchThreadImpl* thread = new CArchThreadImpl;
|
||||||
|
thread->m_func = func;
|
||||||
|
thread->m_userData = data;
|
||||||
|
|
||||||
|
// create thread
|
||||||
|
unsigned int id;
|
||||||
|
thread->m_thread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0,
|
||||||
|
threadFunc, (void*)thread, 0, &id));
|
||||||
|
thread->m_id = static_cast<DWORD>(id);
|
||||||
|
|
||||||
|
// check if thread was started
|
||||||
|
if (thread->m_thread == 0) {
|
||||||
|
// failed to start thread so clean up
|
||||||
|
delete thread;
|
||||||
|
thread = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// add thread to list
|
||||||
|
insert(thread);
|
||||||
|
|
||||||
|
// increment ref count to account for the thread itself
|
||||||
|
refThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
// note that the child thread will wait until we release this mutex
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThread
|
||||||
|
CArchMultithreadWindows::newCurrentThread()
|
||||||
|
{
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
CArchThreadImpl* thread = find(GetCurrentThreadId());
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
assert(thread != NULL);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::closeThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
|
||||||
|
// decrement ref count and clean up thread if no more references
|
||||||
|
if (--thread->m_refCount == 0) {
|
||||||
|
// close the handle (main thread has a NULL handle)
|
||||||
|
if (thread->m_thread != NULL) {
|
||||||
|
CloseHandle(thread->m_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove thread from list
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
assert(findNoRef(thread->m_id) == thread);
|
||||||
|
erase(thread);
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// done with thread
|
||||||
|
delete thread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThread
|
||||||
|
CArchMultithreadWindows::copyThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
refThread(thread);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::cancelThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
|
||||||
|
// set cancel flag
|
||||||
|
SetEvent(thread->m_cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::setPriorityOfThread(CArchThread thread, int n)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
|
||||||
|
DWORD pClass = NORMAL_PRIORITY_CLASS;
|
||||||
|
if (n < 0) {
|
||||||
|
switch (-n) {
|
||||||
|
case 1: n = THREAD_PRIORITY_ABOVE_NORMAL; break;
|
||||||
|
case 2: n = THREAD_PRIORITY_HIGHEST; break;
|
||||||
|
default:
|
||||||
|
pClass = HIGH_PRIORITY_CLASS;
|
||||||
|
switch (-n - 3) {
|
||||||
|
case 0: n = THREAD_PRIORITY_LOWEST; break;
|
||||||
|
case 1: n = THREAD_PRIORITY_BELOW_NORMAL; break;
|
||||||
|
case 2: n = THREAD_PRIORITY_NORMAL; break;
|
||||||
|
case 3: n = THREAD_PRIORITY_ABOVE_NORMAL; break;
|
||||||
|
default: n = THREAD_PRIORITY_HIGHEST; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (n) {
|
||||||
|
case 0: n = THREAD_PRIORITY_NORMAL; break;
|
||||||
|
case 1: n = THREAD_PRIORITY_BELOW_NORMAL; break;
|
||||||
|
case 2: n = THREAD_PRIORITY_LOWEST; break;
|
||||||
|
default: n = THREAD_PRIORITY_IDLE; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetPriorityClass(thread->m_thread, pClass);
|
||||||
|
SetThreadPriority(thread->m_thread, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::testCancelThread()
|
||||||
|
{
|
||||||
|
// find current thread
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
CArchThreadImpl* thread = findNoRef(GetCurrentThreadId());
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// test cancel on thread
|
||||||
|
testCancelThreadImpl(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMultithreadWindows::wait(CArchThread target, double timeout)
|
||||||
|
{
|
||||||
|
assert(target != NULL);
|
||||||
|
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// find current thread
|
||||||
|
CArchThreadImpl* self = findNoRef(GetCurrentThreadId());
|
||||||
|
|
||||||
|
// ignore wait if trying to wait on ourself
|
||||||
|
if (target == self) {
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ref the target so it can't go away while we're watching it
|
||||||
|
refThread(target);
|
||||||
|
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// convert timeout
|
||||||
|
DWORD t;
|
||||||
|
if (timeout < 0.0) {
|
||||||
|
t = INFINITE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
t = (DWORD)(1000.0 * timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for this thread to be cancelled or for the target thread to
|
||||||
|
// terminate.
|
||||||
|
HANDLE handles[2];
|
||||||
|
handles[0] = target->m_exit;
|
||||||
|
handles[1] = self->m_cancel;
|
||||||
|
DWORD result = WaitForMultipleObjects(2, handles, FALSE, t);
|
||||||
|
|
||||||
|
// cancel takes priority
|
||||||
|
if (result != WAIT_OBJECT_0 + 1 &&
|
||||||
|
WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0) {
|
||||||
|
result = WAIT_OBJECT_0 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// release target
|
||||||
|
closeThread(target);
|
||||||
|
|
||||||
|
// handle result
|
||||||
|
switch (result) {
|
||||||
|
case WAIT_OBJECT_0 + 0:
|
||||||
|
// target thread terminated
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case WAIT_OBJECT_0 + 1:
|
||||||
|
// this thread was cancelled. does not return.
|
||||||
|
testCancelThreadImpl(self);
|
||||||
|
|
||||||
|
default:
|
||||||
|
// timeout or error
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMultithreadWindows::waitForEvent(double timeout)
|
||||||
|
{
|
||||||
|
// check if messages are available first. if we don't do this then
|
||||||
|
// MsgWaitForMultipleObjects() will block even if the queue isn't
|
||||||
|
// empty if the messages in the queue were there before the last
|
||||||
|
// call to GetMessage()/PeekMessage().
|
||||||
|
if (HIWORD(GetQueueStatus(QS_ALLINPUT)) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find current thread
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
CArchThreadImpl* self = findNoRef(GetCurrentThreadId());
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
assert(self != NULL);
|
||||||
|
|
||||||
|
// convert timeout
|
||||||
|
DWORD t;
|
||||||
|
if (timeout < 0.0) {
|
||||||
|
t = INFINITE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
t = (DWORD)(1000.0 * timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for this thread to be cancelled or for a message
|
||||||
|
HANDLE handles[1];
|
||||||
|
handles[0] = self->m_cancel;
|
||||||
|
DWORD result = MsgWaitForMultipleObjects(1, handles, FALSE, t, QS_ALLINPUT);
|
||||||
|
|
||||||
|
// handle result
|
||||||
|
switch (result) {
|
||||||
|
case WAIT_OBJECT_0 + 1:
|
||||||
|
// message is available
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case WAIT_OBJECT_0 + 0:
|
||||||
|
// this thread was cancelled. does not return.
|
||||||
|
testCancelThreadImpl(self);
|
||||||
|
|
||||||
|
default:
|
||||||
|
// timeout or error
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMultithreadWindows::isSameThread(CArchThread thread1, CArchThread thread2)
|
||||||
|
{
|
||||||
|
return (thread1 == thread2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMultithreadWindows::isExitedThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
// poll exit event
|
||||||
|
return (WaitForSingleObject(thread->m_exit, 0) == WAIT_OBJECT_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
CArchMultithreadWindows::getResultOfThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
void* result = thread->m_result;
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
IArchMultithread::ThreadID
|
||||||
|
CArchMultithreadWindows::getIDOfThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
return static_cast<ThreadID>(thread->m_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThreadImpl*
|
||||||
|
CArchMultithreadWindows::find(DWORD id)
|
||||||
|
{
|
||||||
|
CArchThreadImpl* impl = findNoRef(id);
|
||||||
|
if (impl != NULL) {
|
||||||
|
refThread(impl);
|
||||||
|
}
|
||||||
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchThreadImpl*
|
||||||
|
CArchMultithreadWindows::findNoRef(DWORD id)
|
||||||
|
{
|
||||||
|
// linear search
|
||||||
|
for (CThreadList::const_iterator index = m_threadList.begin();
|
||||||
|
index != m_threadList.end(); ++index) {
|
||||||
|
if ((*index)->m_id == id) {
|
||||||
|
return *index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::insert(CArchThreadImpl* thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
|
||||||
|
// thread shouldn't already be on the list
|
||||||
|
assert(findNoRef(thread->m_id) == NULL);
|
||||||
|
|
||||||
|
// append to list
|
||||||
|
m_threadList.push_back(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::erase(CArchThreadImpl* thread)
|
||||||
|
{
|
||||||
|
for (CThreadList::iterator index = m_threadList.begin();
|
||||||
|
index != m_threadList.end(); ++index) {
|
||||||
|
if (*index == thread) {
|
||||||
|
m_threadList.erase(index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::refThread(CArchThreadImpl* thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
assert(findNoRef(thread->m_id) != NULL);
|
||||||
|
++thread->m_refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::testCancelThreadImpl(CArchThread thread)
|
||||||
|
{
|
||||||
|
assert(thread != NULL);
|
||||||
|
|
||||||
|
// poll cancel event. return if not set.
|
||||||
|
const DWORD result = WaitForSingleObject(thread->m_cancel, 0);
|
||||||
|
if (result != WAIT_OBJECT_0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update cancel state
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
bool cancel = !thread->m_cancelling;
|
||||||
|
thread->m_cancelling = true;
|
||||||
|
ResetEvent(thread->m_cancel);
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
// unwind thread's stack if cancelling
|
||||||
|
if (cancel) {
|
||||||
|
throw XThreadCancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int __stdcall
|
||||||
|
CArchMultithreadWindows::threadFunc(void* vrep)
|
||||||
|
{
|
||||||
|
// get the thread
|
||||||
|
CArchThreadImpl* thread = reinterpret_cast<CArchThreadImpl*>(vrep);
|
||||||
|
|
||||||
|
// run thread
|
||||||
|
s_instance->doThreadFunc(thread);
|
||||||
|
|
||||||
|
// terminate the thread
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadWindows::doThreadFunc(CArchThread thread)
|
||||||
|
{
|
||||||
|
// default priority is slightly below normal
|
||||||
|
setPriorityOfThread(thread, 1);
|
||||||
|
|
||||||
|
// wait for parent to initialize this object
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
|
||||||
|
void* result = NULL;
|
||||||
|
try {
|
||||||
|
// go
|
||||||
|
result = (*thread->m_func)(thread->m_userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (XThreadCancel&) {
|
||||||
|
// client called cancel()
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
// note -- don't catch (...) to avoid masking bugs
|
||||||
|
SetEvent(thread->m_exit);
|
||||||
|
closeThread(thread);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// thread has exited
|
||||||
|
lockMutex(m_threadMutex);
|
||||||
|
thread->m_result = result;
|
||||||
|
unlockMutex(m_threadMutex);
|
||||||
|
SetEvent(thread->m_exit);
|
||||||
|
|
||||||
|
// done with thread
|
||||||
|
closeThread(thread);
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHMULTITHREADWINDOWS_H
|
||||||
|
#define CARCHMULTITHREADWINDOWS_H
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
#include "stdlist.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#define ARCH_MULTITHREAD CArchMultithreadWindows
|
||||||
|
|
||||||
|
class CArchCondImpl {
|
||||||
|
public:
|
||||||
|
enum { kSignal = 0, kBroadcast };
|
||||||
|
|
||||||
|
HANDLE m_events[2];
|
||||||
|
mutable int m_waitCount;
|
||||||
|
CArchMutex m_waitCountMutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CArchMutexImpl {
|
||||||
|
public:
|
||||||
|
CRITICAL_SECTION m_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CArchMultithreadWindows : public IArchMultithread {
|
||||||
|
public:
|
||||||
|
CArchMultithreadWindows();
|
||||||
|
virtual ~CArchMultithreadWindows();
|
||||||
|
|
||||||
|
//
|
||||||
|
// accessors
|
||||||
|
//
|
||||||
|
|
||||||
|
HANDLE getCancelEventForCurrentThread();
|
||||||
|
|
||||||
|
static CArchMultithreadWindows* getInstance();
|
||||||
|
|
||||||
|
// IArchMultithread overrides
|
||||||
|
virtual CArchCond newCondVar();
|
||||||
|
virtual void closeCondVar(CArchCond);
|
||||||
|
virtual void signalCondVar(CArchCond);
|
||||||
|
virtual void broadcastCondVar(CArchCond);
|
||||||
|
virtual bool waitCondVar(CArchCond, CArchMutex, double timeout);
|
||||||
|
virtual CArchMutex newMutex();
|
||||||
|
virtual void closeMutex(CArchMutex);
|
||||||
|
virtual void lockMutex(CArchMutex);
|
||||||
|
virtual void unlockMutex(CArchMutex);
|
||||||
|
virtual CArchThread newThread(ThreadFunc, void*);
|
||||||
|
virtual CArchThread newCurrentThread();
|
||||||
|
virtual CArchThread copyThread(CArchThread);
|
||||||
|
virtual void closeThread(CArchThread);
|
||||||
|
virtual void cancelThread(CArchThread);
|
||||||
|
virtual void setPriorityOfThread(CArchThread, int n);
|
||||||
|
virtual void testCancelThread();
|
||||||
|
virtual bool wait(CArchThread, double timeout);
|
||||||
|
virtual bool waitForEvent(double timeout);
|
||||||
|
virtual bool isSameThread(CArchThread, CArchThread);
|
||||||
|
virtual bool isExitedThread(CArchThread);
|
||||||
|
virtual void* getResultOfThread(CArchThread);
|
||||||
|
virtual ThreadID getIDOfThread(CArchThread);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CArchThreadImpl* find(DWORD id);
|
||||||
|
CArchThreadImpl* findNoRef(DWORD id);
|
||||||
|
void insert(CArchThreadImpl* thread);
|
||||||
|
void erase(CArchThreadImpl* thread);
|
||||||
|
|
||||||
|
void refThread(CArchThreadImpl* rep);
|
||||||
|
void testCancelThreadImpl(CArchThreadImpl* rep);
|
||||||
|
|
||||||
|
void doThreadFunc(CArchThread thread);
|
||||||
|
static unsigned int __stdcall threadFunc(void* vrep);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::list<CArchThread> CThreadList;
|
||||||
|
|
||||||
|
static CArchMultithreadWindows* s_instance;
|
||||||
|
|
||||||
|
CArchMutex m_threadMutex;
|
||||||
|
|
||||||
|
CThreadList m_threadList;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,847 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchNetworkBSD.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "XArchUnix.h"
|
||||||
|
#if HAVE_SYS_TYPES_H
|
||||||
|
# include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
#if HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#if !defined(TCP_NODELAY)
|
||||||
|
# include <netinet/tcp.h>
|
||||||
|
#endif
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#if HAVE_POLL
|
||||||
|
# include <sys/poll.h>
|
||||||
|
#else
|
||||||
|
# if HAVE_SYS_SELECT_H
|
||||||
|
# include <sys/select.h>
|
||||||
|
# endif
|
||||||
|
# if HAVE_SYS_TIME_H
|
||||||
|
# include <sys/time.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const int s_family[] = {
|
||||||
|
PF_INET
|
||||||
|
};
|
||||||
|
static const int s_type[] = {
|
||||||
|
SOCK_DGRAM,
|
||||||
|
SOCK_STREAM
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchNetworkBSD
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchNetworkBSD::CArchNetworkBSD()
|
||||||
|
{
|
||||||
|
// create mutex to make some calls thread safe
|
||||||
|
m_mutex = ARCH->newMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetworkBSD::~CArchNetworkBSD()
|
||||||
|
{
|
||||||
|
ARCH->closeMutex(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSocket
|
||||||
|
CArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
|
||||||
|
{
|
||||||
|
// allocate socket object
|
||||||
|
CArchSocketImpl* newSocket = new CArchSocketImpl;
|
||||||
|
|
||||||
|
// create socket
|
||||||
|
int fd = socket(s_family[family], s_type[type], 0);
|
||||||
|
if (fd == -1) {
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
newSocket->m_fd = fd;
|
||||||
|
newSocket->m_connected = false;
|
||||||
|
newSocket->m_refCount = 1;
|
||||||
|
return newSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSocket
|
||||||
|
CArchNetworkBSD::copySocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// ref the socket and return it
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
++s->m_refCount;
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::closeSocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// unref the socket and note if it should be released
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
const bool doClose = (--s->m_refCount == 0);
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
|
||||||
|
// close the socket if necessary
|
||||||
|
if (doClose) {
|
||||||
|
do {
|
||||||
|
if (close(s->m_fd) == -1) {
|
||||||
|
// close failed
|
||||||
|
int err = errno;
|
||||||
|
if (err == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore the last ref and throw
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
++s->m_refCount;
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
throwError(err);
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::closeSocketForRead(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
if (shutdown(s->m_fd, 0) == -1) {
|
||||||
|
if (errno != ENOTCONN) {
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::closeSocketForWrite(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
if (shutdown(s->m_fd, 1) == -1) {
|
||||||
|
if (errno != ENOTCONN) {
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::bindSocket(CArchSocket s, CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
if (bind(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::listenOnSocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// hardcoding backlog
|
||||||
|
if (listen(s->m_fd, 3) == -1) {
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSocket
|
||||||
|
CArchNetworkBSD::acceptSocket(CArchSocket s, CArchNetAddress* addr)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// if user passed NULL in addr then use scratch space
|
||||||
|
CArchNetAddress dummy;
|
||||||
|
if (addr == NULL) {
|
||||||
|
addr = &dummy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new socket and address
|
||||||
|
CArchSocketImpl* newSocket = new CArchSocketImpl;
|
||||||
|
*addr = new CArchNetAddressImpl;
|
||||||
|
|
||||||
|
// accept on socket
|
||||||
|
int fd;
|
||||||
|
do {
|
||||||
|
fd = accept(s->m_fd, &(*addr)->m_addr, &(*addr)->m_len);
|
||||||
|
if (fd == -1) {
|
||||||
|
int err = errno;
|
||||||
|
if (err == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (err == ECONNABORTED) {
|
||||||
|
// connection was aborted; try again
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
delete newSocket;
|
||||||
|
delete *addr;
|
||||||
|
*addr = NULL;
|
||||||
|
throwError(err);
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
// initialize socket
|
||||||
|
newSocket->m_fd = fd;
|
||||||
|
newSocket->m_connected = true;
|
||||||
|
newSocket->m_refCount = 1;
|
||||||
|
|
||||||
|
// discard address if not requested
|
||||||
|
if (addr == &dummy) {
|
||||||
|
ARCH->closeAddr(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::connectSocket(CArchSocket s, CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (connect(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errno == EISCONN) {
|
||||||
|
// already connected
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
// connecting
|
||||||
|
throw XArchNetworkConnecting(new XArchEvalUnix(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
s->m_connected = true;
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_POLL
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
|
||||||
|
{
|
||||||
|
assert(pe != NULL || num == 0);
|
||||||
|
|
||||||
|
// return if nothing to do
|
||||||
|
if (num == 0) {
|
||||||
|
if (timeout > 0.0) {
|
||||||
|
ARCH->sleep(timeout);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate space for translated query
|
||||||
|
struct pollfd* pfd = new struct pollfd[num];
|
||||||
|
|
||||||
|
// translate query
|
||||||
|
for (int i = 0; i < num; ++i) {
|
||||||
|
pfd[i].fd = (pe[i].m_socket == NULL) ? -1 : pe[i].m_socket->m_fd;
|
||||||
|
pfd[i].events = 0;
|
||||||
|
if ((pe[i].m_events & kPOLLIN) != 0) {
|
||||||
|
pfd[i].events |= POLLIN;
|
||||||
|
}
|
||||||
|
if ((pe[i].m_events & kPOLLOUT) != 0) {
|
||||||
|
pfd[i].events |= POLLOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the poll
|
||||||
|
int n;
|
||||||
|
do {
|
||||||
|
n = poll(pfd, num, static_cast<int>(1000.0 * timeout));
|
||||||
|
if (n == -1) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
delete[] pfd;
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
// translate back
|
||||||
|
for (int i = 0; i < num; ++i) {
|
||||||
|
pe[i].m_revents = 0;
|
||||||
|
if ((pfd[i].revents & POLLIN) != 0) {
|
||||||
|
pe[i].m_revents |= kPOLLIN;
|
||||||
|
}
|
||||||
|
if ((pfd[i].revents & POLLOUT) != 0) {
|
||||||
|
pe[i].m_revents |= kPOLLOUT;
|
||||||
|
}
|
||||||
|
if ((pfd[i].revents & POLLERR) != 0) {
|
||||||
|
pe[i].m_revents |= kPOLLERR;
|
||||||
|
}
|
||||||
|
if ((pfd[i].revents & POLLNVAL) != 0) {
|
||||||
|
pe[i].m_revents |= kPOLLNVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// done with translated query
|
||||||
|
delete[] pfd;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
|
||||||
|
{
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// prepare sets for select
|
||||||
|
n = 0;
|
||||||
|
fd_set readSet, writeSet, errSet;
|
||||||
|
fd_set* readSetP = NULL;
|
||||||
|
fd_set* writeSetP = NULL;
|
||||||
|
fd_set* errSetP = NULL;
|
||||||
|
FD_ZERO(&readSet);
|
||||||
|
FD_ZERO(&writeSet);
|
||||||
|
FD_ZERO(&errSet);
|
||||||
|
for (i = 0; i < num; ++i) {
|
||||||
|
// reset return flags
|
||||||
|
pe[i].m_revents = 0;
|
||||||
|
|
||||||
|
// set invalid flag if socket is bogus then go to next socket
|
||||||
|
if (pe[i].m_socket == NULL) {
|
||||||
|
pe[i].m_revents |= kPOLLNVAL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdi = pe[i].m_socket->m_fd;
|
||||||
|
if (pe[i].m_events & kPOLLIN) {
|
||||||
|
FD_SET(pe[i].m_socket->m_fd, &readSet);
|
||||||
|
readSetP = &readSet;
|
||||||
|
if (fdi > n) {
|
||||||
|
n = fdi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pe[i].m_events & kPOLLOUT) {
|
||||||
|
FD_SET(pe[i].m_socket->m_fd, &writeSet);
|
||||||
|
writeSetP = &writeSet;
|
||||||
|
if (fdi > n) {
|
||||||
|
n = fdi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (true) {
|
||||||
|
FD_SET(pe[i].m_socket->m_fd, &errSet);
|
||||||
|
errSetP = &errSet;
|
||||||
|
if (fdi > n) {
|
||||||
|
n = fdi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there are no sockets then don't block forever
|
||||||
|
if (n == 0 && timeout < 0.0) {
|
||||||
|
timeout = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare timeout for select
|
||||||
|
struct timeval timeout2;
|
||||||
|
struct timeval* timeout2P;
|
||||||
|
if (timeout < 0) {
|
||||||
|
timeout2P = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
timeout2P = &timeout2;
|
||||||
|
timeout2.tv_sec = static_cast<int>(timeout);
|
||||||
|
timeout2.tv_usec = static_cast<int>(1.0e+6 *
|
||||||
|
(timeout - timeout2.tv_sec));
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the select
|
||||||
|
n = select((SELECT_TYPE_ARG1) n + 1,
|
||||||
|
SELECT_TYPE_ARG234 readSetP,
|
||||||
|
SELECT_TYPE_ARG234 writeSetP,
|
||||||
|
SELECT_TYPE_ARG234 errSetP,
|
||||||
|
SELECT_TYPE_ARG5 timeout2P);
|
||||||
|
|
||||||
|
// handle results
|
||||||
|
if (n == -1) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
n = 0;
|
||||||
|
for (i = 0; i < num; ++i) {
|
||||||
|
if (pe[i].m_socket != NULL) {
|
||||||
|
if (FD_ISSET(pe[i].m_socket->m_fd, &readSet)) {
|
||||||
|
pe[i].m_revents |= kPOLLIN;
|
||||||
|
}
|
||||||
|
if (FD_ISSET(pe[i].m_socket->m_fd, &writeSet)) {
|
||||||
|
pe[i].m_revents |= kPOLLOUT;
|
||||||
|
}
|
||||||
|
if (FD_ISSET(pe[i].m_socket->m_fd, &errSet)) {
|
||||||
|
pe[i].m_revents |= kPOLLERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pe[i].m_revents != 0) {
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t
|
||||||
|
CArchNetworkBSD::readSocket(CArchSocket s, void* buf, size_t len)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
ssize_t n;
|
||||||
|
do {
|
||||||
|
n = read(s->m_fd, buf, len);
|
||||||
|
if (n == -1) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
CArchNetworkBSD::writeSocket(CArchSocket s, const void* buf, size_t len)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
ssize_t n;
|
||||||
|
do {
|
||||||
|
n = write(s->m_fd, buf, len);
|
||||||
|
if (n == -1) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::throwErrorOnSocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// get the error from the socket layer
|
||||||
|
int err = 0;
|
||||||
|
socklen_t size = sizeof(err);
|
||||||
|
if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR, &err, &size) == -1) {
|
||||||
|
err = errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw if there's an error
|
||||||
|
if (err != 0) {
|
||||||
|
throwError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchNetworkBSD::setBlockingOnSocket(CArchSocket s, bool blocking)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
int mode = fcntl(s->m_fd, F_GETFL, 0);
|
||||||
|
if (mode == -1) {
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
bool old = ((mode & O_NDELAY) == 0);
|
||||||
|
if (blocking) {
|
||||||
|
mode &= ~O_NDELAY;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mode |= O_NDELAY;
|
||||||
|
}
|
||||||
|
if (fcntl(s->m_fd, F_SETFL, mode) == -1) {
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchNetworkBSD::setNoDelayOnSocket(CArchSocket s, bool noDelay)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// get old state
|
||||||
|
int oflag;
|
||||||
|
socklen_t size = sizeof(oflag);
|
||||||
|
if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, &oflag, &size) == -1) {
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
int flag = noDelay ? 1 : 0;
|
||||||
|
size = sizeof(flag);
|
||||||
|
if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, &flag, size) == -1) {
|
||||||
|
throwError(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (oflag != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchNetworkBSD::getHostName()
|
||||||
|
{
|
||||||
|
char name[256];
|
||||||
|
if (gethostname(name, sizeof(name)) == -1) {
|
||||||
|
name[0] = '\0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
name[sizeof(name) - 1] = '\0';
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetAddress
|
||||||
|
CArchNetworkBSD::newAnyAddr(EAddressFamily family)
|
||||||
|
{
|
||||||
|
// allocate address
|
||||||
|
CArchNetAddressImpl* addr = new CArchNetAddressImpl;
|
||||||
|
|
||||||
|
// fill it in
|
||||||
|
switch (family) {
|
||||||
|
case kINET: {
|
||||||
|
struct sockaddr_in* ipAddr =
|
||||||
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
|
ipAddr->sin_family = AF_INET;
|
||||||
|
ipAddr->sin_port = 0;
|
||||||
|
ipAddr->sin_addr.s_addr = INADDR_ANY;
|
||||||
|
addr->m_len = sizeof(struct sockaddr_in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
delete addr;
|
||||||
|
assert(0 && "invalid family");
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetAddress
|
||||||
|
CArchNetworkBSD::copyAddr(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
// allocate and copy address
|
||||||
|
return new CArchNetAddressImpl(*addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetAddress
|
||||||
|
CArchNetworkBSD::nameToAddr(const std::string& name)
|
||||||
|
{
|
||||||
|
// allocate address
|
||||||
|
CArchNetAddressImpl* addr = new CArchNetAddressImpl;
|
||||||
|
|
||||||
|
// try to convert assuming an IPv4 dot notation address
|
||||||
|
struct sockaddr_in inaddr;
|
||||||
|
memset(&inaddr, 0, sizeof(inaddr));
|
||||||
|
if (inet_aton(name.c_str(), &inaddr.sin_addr) != 0) {
|
||||||
|
// it's a dot notation address
|
||||||
|
addr->m_len = sizeof(struct sockaddr_in);
|
||||||
|
inaddr.sin_family = AF_INET;
|
||||||
|
inaddr.sin_port = 0;
|
||||||
|
memcpy(&addr->m_addr, &inaddr, addr->m_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// mutexed address lookup (ugh)
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
struct hostent* info = gethostbyname(name.c_str());
|
||||||
|
if (info == NULL) {
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
delete addr;
|
||||||
|
throwNameError(h_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy over address (only IPv4 currently supported)
|
||||||
|
addr->m_len = sizeof(struct sockaddr_in);
|
||||||
|
inaddr.sin_family = info->h_addrtype;
|
||||||
|
inaddr.sin_port = 0;
|
||||||
|
memcpy(&inaddr.sin_addr, info->h_addr_list[0], info->h_length);
|
||||||
|
memcpy(&addr->m_addr, &inaddr, addr->m_len);
|
||||||
|
|
||||||
|
// done with static buffer
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::closeAddr(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
delete addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchNetworkBSD::addrToName(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
// mutexed name lookup (ugh)
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
struct hostent* info = gethostbyaddr(&addr->m_addr, addr->m_len,
|
||||||
|
addr->m_addr.sa_family);
|
||||||
|
if (info == NULL) {
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
throwNameError(h_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save (primary) name
|
||||||
|
std::string name = info->h_name;
|
||||||
|
|
||||||
|
// done with static buffer
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchNetworkBSD::addrToString(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
switch (getAddrFamily(addr)) {
|
||||||
|
case kINET: {
|
||||||
|
struct sockaddr_in* ipAddr =
|
||||||
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
std::string s = inet_ntoa(ipAddr->sin_addr);
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "unknown address family");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IArchNetwork::EAddressFamily
|
||||||
|
CArchNetworkBSD::getAddrFamily(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
switch (addr->m_addr.sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
return kINET;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return kUNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::setAddrPort(CArchNetAddress addr, int port)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
switch (getAddrFamily(addr)) {
|
||||||
|
case kINET: {
|
||||||
|
struct sockaddr_in* ipAddr =
|
||||||
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
|
ipAddr->sin_port = htons(port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "unknown address family");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchNetworkBSD::getAddrPort(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
switch (getAddrFamily(addr)) {
|
||||||
|
case kINET: {
|
||||||
|
struct sockaddr_in* ipAddr =
|
||||||
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
|
return ntohs(ipAddr->sin_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "unknown address family");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchNetworkBSD::isAnyAddr(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
switch (getAddrFamily(addr)) {
|
||||||
|
case kINET: {
|
||||||
|
struct sockaddr_in* ipAddr =
|
||||||
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
|
return (ipAddr->sin_addr.s_addr == INADDR_ANY &&
|
||||||
|
addr->m_len == sizeof(struct sockaddr_in));
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "unknown address family");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::throwError(int err)
|
||||||
|
{
|
||||||
|
switch (err) {
|
||||||
|
case EAGAIN:
|
||||||
|
throw XArchNetworkWouldBlock(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case EACCES:
|
||||||
|
case EPERM:
|
||||||
|
throw XArchNetworkAccess(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case ENFILE:
|
||||||
|
case EMFILE:
|
||||||
|
case ENODEV:
|
||||||
|
case ENOBUFS:
|
||||||
|
case ENOMEM:
|
||||||
|
case ENOSR:
|
||||||
|
case ENETDOWN:
|
||||||
|
throw XArchNetworkResource(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case EPROTOTYPE:
|
||||||
|
case EPROTONOSUPPORT:
|
||||||
|
case EAFNOSUPPORT:
|
||||||
|
case EPFNOSUPPORT:
|
||||||
|
case ESOCKTNOSUPPORT:
|
||||||
|
case EINVAL:
|
||||||
|
case ENOPROTOOPT:
|
||||||
|
case EOPNOTSUPP:
|
||||||
|
case ENOPKG:
|
||||||
|
case ESHUTDOWN:
|
||||||
|
throw XArchNetworkSupport(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case EIO:
|
||||||
|
throw XArchNetworkIO(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case EADDRNOTAVAIL:
|
||||||
|
throw XArchNetworkNoAddress(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case EADDRINUSE:
|
||||||
|
throw XArchNetworkAddressInUse(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case EHOSTUNREACH:
|
||||||
|
case ENETUNREACH:
|
||||||
|
throw XArchNetworkNoRoute(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case ENOTCONN:
|
||||||
|
throw XArchNetworkNotConnected(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case EPIPE:
|
||||||
|
case ECONNABORTED:
|
||||||
|
case ECONNRESET:
|
||||||
|
throw XArchNetworkDisconnected(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case ECONNREFUSED:
|
||||||
|
throw XArchNetworkConnectionRefused(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case EINPROGRESS:
|
||||||
|
case EALREADY:
|
||||||
|
throw XArchNetworkConnecting(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
case EHOSTDOWN:
|
||||||
|
case ETIMEDOUT:
|
||||||
|
throw XArchNetworkTimedOut(new XArchEvalUnix(err));
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw XArchNetwork(new XArchEvalUnix(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::throwNameError(int err)
|
||||||
|
{
|
||||||
|
static const char* s_msg[] = {
|
||||||
|
"The specified host is unknown",
|
||||||
|
"The requested name is valid but does not have an IP address",
|
||||||
|
"A non-recoverable name server error occurred",
|
||||||
|
"A temporary error occurred on an authoritative name server",
|
||||||
|
"An unknown name server error occurred"
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
case HOST_NOT_FOUND:
|
||||||
|
throw XArchNetworkNameUnknown(s_msg[0]);
|
||||||
|
|
||||||
|
case NO_DATA:
|
||||||
|
throw XArchNetworkNameNoAddress(s_msg[1]);
|
||||||
|
|
||||||
|
case NO_RECOVERY:
|
||||||
|
throw XArchNetworkNameFailure(s_msg[2]);
|
||||||
|
|
||||||
|
case TRY_AGAIN:
|
||||||
|
throw XArchNetworkNameUnavailable(s_msg[3]);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw XArchNetworkName(s_msg[4]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHNETWORKBSD_H
|
||||||
|
#define CARCHNETWORKBSD_H
|
||||||
|
|
||||||
|
#include "IArchNetwork.h"
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
#if HAVE_SYS_SOCKET_H
|
||||||
|
# include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(HAVE_SOCKLEN_T)
|
||||||
|
// Darwin is so unsure what to use for socklen_t it makes us choose
|
||||||
|
# if defined(__APPLE__)
|
||||||
|
# if !defined(_BSD_SOCKLEN_T_)
|
||||||
|
# define _BSD_SOCKLEN_T_ int
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
typedef int socklen_t;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ARCH_NETWORK CArchNetworkBSD
|
||||||
|
|
||||||
|
class CArchSocketImpl {
|
||||||
|
public:
|
||||||
|
int m_fd;
|
||||||
|
bool m_connected;
|
||||||
|
int m_refCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CArchNetAddressImpl {
|
||||||
|
public:
|
||||||
|
CArchNetAddressImpl() : m_len(sizeof(m_addr)) { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct sockaddr m_addr;
|
||||||
|
socklen_t m_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CArchNetworkBSD : public IArchNetwork {
|
||||||
|
public:
|
||||||
|
CArchNetworkBSD();
|
||||||
|
virtual ~CArchNetworkBSD();
|
||||||
|
|
||||||
|
// IArchNetwork overrides
|
||||||
|
virtual CArchSocket newSocket(EAddressFamily, ESocketType);
|
||||||
|
virtual CArchSocket copySocket(CArchSocket s);
|
||||||
|
virtual void closeSocket(CArchSocket s);
|
||||||
|
virtual void closeSocketForRead(CArchSocket s);
|
||||||
|
virtual void closeSocketForWrite(CArchSocket s);
|
||||||
|
virtual void bindSocket(CArchSocket s, CArchNetAddress addr);
|
||||||
|
virtual void listenOnSocket(CArchSocket s);
|
||||||
|
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
|
||||||
|
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
|
||||||
|
virtual int pollSocket(CPollEntry[], int num, double timeout);
|
||||||
|
virtual size_t readSocket(CArchSocket s, void* buf, size_t len);
|
||||||
|
virtual size_t writeSocket(CArchSocket s,
|
||||||
|
const void* buf, size_t len);
|
||||||
|
virtual void throwErrorOnSocket(CArchSocket);
|
||||||
|
virtual bool setBlockingOnSocket(CArchSocket, bool blocking);
|
||||||
|
virtual bool setNoDelayOnSocket(CArchSocket, bool noDelay);
|
||||||
|
virtual std::string getHostName();
|
||||||
|
virtual CArchNetAddress newAnyAddr(EAddressFamily);
|
||||||
|
virtual CArchNetAddress copyAddr(CArchNetAddress);
|
||||||
|
virtual CArchNetAddress nameToAddr(const std::string&);
|
||||||
|
virtual void closeAddr(CArchNetAddress);
|
||||||
|
virtual std::string addrToName(CArchNetAddress);
|
||||||
|
virtual std::string addrToString(CArchNetAddress);
|
||||||
|
virtual EAddressFamily getAddrFamily(CArchNetAddress);
|
||||||
|
virtual void setAddrPort(CArchNetAddress, int port);
|
||||||
|
virtual int getAddrPort(CArchNetAddress);
|
||||||
|
virtual bool isAnyAddr(CArchNetAddress);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void throwError(int);
|
||||||
|
void throwNameError(int);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CArchMutex m_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,838 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "CArchNetworkWinsock.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "XArchWindows.h"
|
||||||
|
|
||||||
|
static const int s_family[] = {
|
||||||
|
PF_INET
|
||||||
|
};
|
||||||
|
static const int s_type[] = {
|
||||||
|
SOCK_DGRAM,
|
||||||
|
SOCK_STREAM
|
||||||
|
};
|
||||||
|
|
||||||
|
static SOCKET (PASCAL FAR *accept_winsock)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);
|
||||||
|
static int (PASCAL FAR *bind_winsock)(SOCKET s, const struct sockaddr FAR *addr, int namelen);
|
||||||
|
static int (PASCAL FAR *close_winsock)(SOCKET s);
|
||||||
|
static int (PASCAL FAR *connect_winsock)(SOCKET s, const struct sockaddr FAR *name, int namelen);
|
||||||
|
static int (PASCAL FAR *gethostname_winsock)(char FAR * name, int namelen);
|
||||||
|
static int (PASCAL FAR *getsockerror_winsock)(void);
|
||||||
|
static int (PASCAL FAR *getsockopt_winsock)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen);
|
||||||
|
static u_short (PASCAL FAR *htons_winsock)(u_short v);
|
||||||
|
static char FAR * (PASCAL FAR *inet_ntoa_winsock)(struct in_addr in);
|
||||||
|
static unsigned long (PASCAL FAR *inet_addr_winsock)(const char FAR * cp);
|
||||||
|
static int (PASCAL FAR *ioctl_winsock)(SOCKET s, int cmd, void FAR *);
|
||||||
|
static int (PASCAL FAR *listen_winsock)(SOCKET s, int backlog);
|
||||||
|
static u_short (PASCAL FAR *ntohs_winsock)(u_short v);
|
||||||
|
static int (PASCAL FAR *recv_winsock)(SOCKET s, void FAR * buf, int len, int flags);
|
||||||
|
static int (PASCAL FAR *select_winsock)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
|
||||||
|
static int (PASCAL FAR *send_winsock)(SOCKET s, const void FAR * buf, int len, int flags);
|
||||||
|
static int (PASCAL FAR *setsockopt_winsock)(SOCKET s, int level, int optname, const void FAR * optval, int optlen);
|
||||||
|
static int (PASCAL FAR *shutdown_winsock)(SOCKET s, int how);
|
||||||
|
static SOCKET (PASCAL FAR *socket_winsock)(int af, int type, int protocol);
|
||||||
|
static struct hostent FAR * (PASCAL FAR *gethostbyaddr_winsock)(const char FAR * addr, int len, int type);
|
||||||
|
static struct hostent FAR * (PASCAL FAR *gethostbyname_winsock)(const char FAR * name);
|
||||||
|
static int (PASCAL FAR *WSACleanup_winsock)(void);
|
||||||
|
static int (PASCAL FAR *WSAFDIsSet_winsock)(SOCKET, fd_set FAR *);
|
||||||
|
|
||||||
|
#undef FD_ISSET
|
||||||
|
#define FD_ISSET(fd, set) WSAFDIsSet_winsock((SOCKET)(fd), (fd_set FAR *)(set))
|
||||||
|
|
||||||
|
#define setfunc(var, name, type) var = (type)netGetProcAddress(module, #name)
|
||||||
|
|
||||||
|
static HMODULE s_networkModule = NULL;
|
||||||
|
|
||||||
|
static
|
||||||
|
FARPROC
|
||||||
|
netGetProcAddress(HMODULE module, LPCSTR name)
|
||||||
|
{
|
||||||
|
FARPROC func = ::GetProcAddress(module, name);
|
||||||
|
if (!func) {
|
||||||
|
throw XArchNetworkSupport("");
|
||||||
|
}
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchNetworkWinsock
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchNetworkWinsock::CArchNetworkWinsock()
|
||||||
|
{
|
||||||
|
static const char* s_library[] = { "ws2_32.dll", "wsock32.dll" };
|
||||||
|
|
||||||
|
assert(WSACleanup_winsock == NULL);
|
||||||
|
assert(s_networkModule == NULL);
|
||||||
|
|
||||||
|
// try each winsock library
|
||||||
|
for (size_t i = 0; i < sizeof(s_library) / sizeof(s_library[0]); ++i) {
|
||||||
|
try {
|
||||||
|
init((HMODULE)::LoadLibrary(s_library[i]));
|
||||||
|
m_mutex = ARCH->newMutex();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (XArchNetwork&) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't initialize any library
|
||||||
|
throw XArchNetworkSupport("Cannot load winsock library");
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetworkWinsock::~CArchNetworkWinsock()
|
||||||
|
{
|
||||||
|
if (s_networkModule != NULL) {
|
||||||
|
WSACleanup_winsock();
|
||||||
|
::FreeLibrary(s_networkModule);
|
||||||
|
|
||||||
|
WSACleanup_winsock = NULL;
|
||||||
|
s_networkModule = NULL;
|
||||||
|
}
|
||||||
|
ARCH->closeMutex(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::init(HMODULE module)
|
||||||
|
{
|
||||||
|
assert(module != NULL);
|
||||||
|
|
||||||
|
// get startup function address
|
||||||
|
int (PASCAL FAR *startup)(WORD, LPWSADATA);
|
||||||
|
setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA));
|
||||||
|
|
||||||
|
// startup network library
|
||||||
|
WORD version = MAKEWORD(1 /*major*/, 1 /*minor*/);
|
||||||
|
WSADATA data;
|
||||||
|
int err = startup(version, &data);
|
||||||
|
if (data.wVersion != version) {
|
||||||
|
throw XArchNetworkSupport(new XArchEvalWinsock(err));
|
||||||
|
}
|
||||||
|
if (err != 0) {
|
||||||
|
// some other initialization error
|
||||||
|
throwError(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get function addresses
|
||||||
|
setfunc(accept_winsock, accept, SOCKET (PASCAL FAR *)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen));
|
||||||
|
setfunc(bind_winsock, bind, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *addr, int namelen));
|
||||||
|
setfunc(close_winsock, closesocket, int (PASCAL FAR *)(SOCKET s));
|
||||||
|
setfunc(connect_winsock, connect, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *name, int namelen));
|
||||||
|
setfunc(gethostname_winsock, gethostname, int (PASCAL FAR *)(char FAR * name, int namelen));
|
||||||
|
setfunc(getsockerror_winsock, WSAGetLastError, int (PASCAL FAR *)(void));
|
||||||
|
setfunc(getsockopt_winsock, getsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen));
|
||||||
|
setfunc(htons_winsock, htons, u_short (PASCAL FAR *)(u_short v));
|
||||||
|
setfunc(inet_ntoa_winsock, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
|
||||||
|
setfunc(inet_addr_winsock, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp));
|
||||||
|
setfunc(ioctl_winsock, ioctlsocket, int (PASCAL FAR *)(SOCKET s, int cmd, void FAR *));
|
||||||
|
setfunc(listen_winsock, listen, int (PASCAL FAR *)(SOCKET s, int backlog));
|
||||||
|
setfunc(ntohs_winsock, ntohs, u_short (PASCAL FAR *)(u_short v));
|
||||||
|
setfunc(recv_winsock, recv, int (PASCAL FAR *)(SOCKET s, void FAR * buf, int len, int flags));
|
||||||
|
setfunc(select_winsock, select, int (PASCAL FAR *)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout));
|
||||||
|
setfunc(send_winsock, send, int (PASCAL FAR *)(SOCKET s, const void FAR * buf, int len, int flags));
|
||||||
|
setfunc(setsockopt_winsock, setsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, const void FAR * optval, int optlen));
|
||||||
|
setfunc(shutdown_winsock, shutdown, int (PASCAL FAR *)(SOCKET s, int how));
|
||||||
|
setfunc(socket_winsock, socket, SOCKET (PASCAL FAR *)(int af, int type, int protocol));
|
||||||
|
setfunc(gethostbyaddr_winsock, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
|
||||||
|
setfunc(gethostbyname_winsock, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
|
||||||
|
setfunc(WSACleanup_winsock, WSACleanup, int (PASCAL FAR *)(void));
|
||||||
|
setfunc(WSAFDIsSet_winsock, __WSAFDIsSet, int (PASCAL FAR *)(SOCKET, fd_set FAR *));
|
||||||
|
|
||||||
|
s_networkModule = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSocket
|
||||||
|
CArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type)
|
||||||
|
{
|
||||||
|
// allocate socket object
|
||||||
|
CArchSocketImpl* socket = new CArchSocketImpl;
|
||||||
|
|
||||||
|
// create socket
|
||||||
|
SOCKET fd = socket_winsock(s_family[family], s_type[type], 0);
|
||||||
|
if (fd == INVALID_SOCKET) {
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
|
||||||
|
socket->m_socket = fd;
|
||||||
|
socket->m_connected = false;
|
||||||
|
socket->m_refCount = 1;
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSocket
|
||||||
|
CArchNetworkWinsock::copySocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// ref the socket and return it
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
++s->m_refCount;
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::closeSocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// unref the socket and note if it should be released
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
const bool doClose = (--s->m_refCount == 0);
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
|
||||||
|
// close the socket if necessary
|
||||||
|
if (doClose) {
|
||||||
|
do {
|
||||||
|
if (close_winsock(s->m_socket) == SOCKET_ERROR) {
|
||||||
|
// close failed
|
||||||
|
int err = getsockerror_winsock();
|
||||||
|
if (err == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore the last ref and throw
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
++s->m_refCount;
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
throwError(err);
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::closeSocketForRead(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
if (shutdown_winsock(s->m_socket, SD_RECEIVE) == SOCKET_ERROR) {
|
||||||
|
if (getsockerror_winsock() != WSAENOTCONN) {
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::closeSocketForWrite(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
if (shutdown_winsock(s->m_socket, SD_SEND) == SOCKET_ERROR) {
|
||||||
|
if (getsockerror_winsock() != WSAENOTCONN) {
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::bindSocket(CArchSocket s, CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
if (bind_winsock(s->m_socket, &addr->m_addr, addr->m_len) == SOCKET_ERROR) {
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::listenOnSocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// hardcoding backlog
|
||||||
|
if (listen_winsock(s->m_socket, 3) == SOCKET_ERROR) {
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSocket
|
||||||
|
CArchNetworkWinsock::acceptSocket(CArchSocket s, CArchNetAddress* addr)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// if user passed NULL in addr then use scratch space
|
||||||
|
CArchNetAddress dummy;
|
||||||
|
if (addr == NULL) {
|
||||||
|
addr = &dummy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new socket and address
|
||||||
|
CArchSocketImpl* socket = new CArchSocketImpl;
|
||||||
|
*addr = new CArchNetAddressImpl;
|
||||||
|
|
||||||
|
// accept on socket
|
||||||
|
SOCKET fd;
|
||||||
|
do {
|
||||||
|
fd = accept_winsock(s->m_socket, &(*addr)->m_addr, &(*addr)->m_len);
|
||||||
|
if (fd == INVALID_SOCKET) {
|
||||||
|
int err = getsockerror_winsock();
|
||||||
|
if (err == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (err == WSAECONNABORTED) {
|
||||||
|
// connection was aborted; try again
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
delete socket;
|
||||||
|
delete *addr;
|
||||||
|
*addr = NULL;
|
||||||
|
throwError(err);
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
// initialize socket
|
||||||
|
socket->m_socket = fd;
|
||||||
|
socket->m_connected = true;
|
||||||
|
socket->m_refCount = 1;
|
||||||
|
|
||||||
|
// discard address if not requested
|
||||||
|
if (addr == &dummy) {
|
||||||
|
ARCH->closeAddr(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (connect_winsock(s->m_socket, &addr->m_addr,
|
||||||
|
addr->m_len) == SOCKET_ERROR) {
|
||||||
|
if (getsockerror_winsock() == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getsockerror_winsock() == WSAEISCONN) {
|
||||||
|
// already connected
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getsockerror_winsock() == WSAEWOULDBLOCK) {
|
||||||
|
// connecting
|
||||||
|
throw XArchNetworkConnecting(new XArchEvalWinsock(
|
||||||
|
getsockerror_winsock()));
|
||||||
|
}
|
||||||
|
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
s->m_connected = true;
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
|
||||||
|
{
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// prepare sets for select
|
||||||
|
n = 0;
|
||||||
|
fd_set readSet, writeSet, errSet;
|
||||||
|
fd_set* readSetP = NULL;
|
||||||
|
fd_set* writeSetP = NULL;
|
||||||
|
fd_set* errSetP = NULL;
|
||||||
|
FD_ZERO(&readSet);
|
||||||
|
FD_ZERO(&writeSet);
|
||||||
|
FD_ZERO(&errSet);
|
||||||
|
for (i = 0; i < num; ++i) {
|
||||||
|
// reset return flags
|
||||||
|
pe[i].m_revents = 0;
|
||||||
|
|
||||||
|
// set invalid flag if socket is bogus then go to next socket
|
||||||
|
if (pe[i].m_socket == NULL) {
|
||||||
|
pe[i].m_revents |= kPOLLNVAL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pe[i].m_events & kPOLLIN) {
|
||||||
|
FD_SET(pe[i].m_socket->m_socket, &readSet);
|
||||||
|
readSetP = &readSet;
|
||||||
|
n = 1;
|
||||||
|
}
|
||||||
|
if (pe[i].m_events & kPOLLOUT) {
|
||||||
|
FD_SET(pe[i].m_socket->m_socket, &writeSet);
|
||||||
|
writeSetP = &writeSet;
|
||||||
|
n = 1;
|
||||||
|
}
|
||||||
|
if (true) {
|
||||||
|
FD_SET(pe[i].m_socket->m_socket, &errSet);
|
||||||
|
errSetP = &errSet;
|
||||||
|
n = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there are no sockets then don't block forever
|
||||||
|
if (n == 0 && timeout < 0.0) {
|
||||||
|
timeout = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare timeout for select
|
||||||
|
struct timeval timeout2;
|
||||||
|
struct timeval* timeout2P;
|
||||||
|
if (timeout < 0) {
|
||||||
|
timeout2P = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
timeout2P = &timeout2;
|
||||||
|
timeout2.tv_sec = static_cast<int>(timeout);
|
||||||
|
timeout2.tv_usec = static_cast<int>(1.0e+6 *
|
||||||
|
(timeout - timeout2.tv_sec));
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the select
|
||||||
|
n = select_winsock(0, readSetP, writeSetP, errSetP, timeout2P);
|
||||||
|
|
||||||
|
// handle results
|
||||||
|
if (n == SOCKET_ERROR) {
|
||||||
|
if (getsockerror_winsock() == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
n = 0;
|
||||||
|
for (i = 0; i < num; ++i) {
|
||||||
|
if (pe[i].m_socket != NULL) {
|
||||||
|
if (FD_ISSET(pe[i].m_socket->m_socket, &readSet)) {
|
||||||
|
pe[i].m_revents |= kPOLLIN;
|
||||||
|
}
|
||||||
|
if (FD_ISSET(pe[i].m_socket->m_socket, &writeSet)) {
|
||||||
|
pe[i].m_revents |= kPOLLOUT;
|
||||||
|
}
|
||||||
|
if (FD_ISSET(pe[i].m_socket->m_socket, &errSet)) {
|
||||||
|
pe[i].m_revents |= kPOLLERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pe[i].m_revents != 0) {
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
CArchNetworkWinsock::readSocket(CArchSocket s, void* buf, size_t len)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
int n;
|
||||||
|
do {
|
||||||
|
n = recv_winsock(s->m_socket, buf, len, 0);
|
||||||
|
if (n == SOCKET_ERROR) {
|
||||||
|
if (getsockerror_winsock() == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
return static_cast<size_t>(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
CArchNetworkWinsock::writeSocket(CArchSocket s, const void* buf, size_t len)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
int n;
|
||||||
|
do {
|
||||||
|
n = send_winsock(s->m_socket, buf, len, 0);
|
||||||
|
if (n == SOCKET_ERROR) {
|
||||||
|
if (getsockerror_winsock() == EINTR) {
|
||||||
|
// interrupted system call
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
return static_cast<size_t>(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::throwErrorOnSocket(CArchSocket s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// get the error from the socket layer
|
||||||
|
int err = 0;
|
||||||
|
int size = sizeof(err);
|
||||||
|
if (getsockopt_winsock(s->m_socket, SOL_SOCKET,
|
||||||
|
SO_ERROR, &err, &size) == SOCKET_ERROR) {
|
||||||
|
err = getsockerror_winsock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw if there's an error
|
||||||
|
if (err != 0) {
|
||||||
|
throwError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchNetworkWinsock::setBlockingOnSocket(CArchSocket s, bool blocking)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
int flag = blocking ? 0 : 1;
|
||||||
|
if (ioctl_winsock(s->m_socket, FIONBIO, &flag) == SOCKET_ERROR) {
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
// FIXME -- can't get the current blocking state of socket?
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchNetworkWinsock::setNoDelayOnSocket(CArchSocket s, bool noDelay)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
// get old state
|
||||||
|
BOOL oflag;
|
||||||
|
int size = sizeof(oflag);
|
||||||
|
if (getsockopt_winsock(s->m_socket, IPPROTO_TCP,
|
||||||
|
TCP_NODELAY, &oflag, &size) == SOCKET_ERROR) {
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
|
||||||
|
// set new state
|
||||||
|
BOOL flag = noDelay ? 1 : 0;
|
||||||
|
size = sizeof(flag);
|
||||||
|
if (setsockopt_winsock(s->m_socket, IPPROTO_TCP,
|
||||||
|
TCP_NODELAY, &flag, size) == SOCKET_ERROR) {
|
||||||
|
throwError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (oflag != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchNetworkWinsock::getHostName()
|
||||||
|
{
|
||||||
|
char name[256];
|
||||||
|
if (gethostname_winsock(name, sizeof(name)) == -1) {
|
||||||
|
name[0] = '\0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
name[sizeof(name) - 1] = '\0';
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetAddress
|
||||||
|
CArchNetworkWinsock::newAnyAddr(EAddressFamily family)
|
||||||
|
{
|
||||||
|
// allocate address
|
||||||
|
CArchNetAddressImpl* addr = new CArchNetAddressImpl;
|
||||||
|
|
||||||
|
// fill it in
|
||||||
|
switch (family) {
|
||||||
|
case kINET: {
|
||||||
|
struct sockaddr_in* ipAddr =
|
||||||
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
|
ipAddr->sin_family = AF_INET;
|
||||||
|
ipAddr->sin_port = 0;
|
||||||
|
ipAddr->sin_addr.s_addr = INADDR_ANY;
|
||||||
|
addr->m_len = sizeof(struct sockaddr_in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
delete addr;
|
||||||
|
assert(0 && "invalid family");
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetAddress
|
||||||
|
CArchNetworkWinsock::copyAddr(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
// allocate and copy address
|
||||||
|
return new CArchNetAddressImpl(*addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchNetAddress
|
||||||
|
CArchNetworkWinsock::nameToAddr(const std::string& name)
|
||||||
|
{
|
||||||
|
// allocate address
|
||||||
|
CArchNetAddressImpl* addr = new CArchNetAddressImpl;
|
||||||
|
|
||||||
|
// try to convert assuming an IPv4 dot notation address
|
||||||
|
struct sockaddr_in inaddr;
|
||||||
|
memset(&inaddr, 0, sizeof(inaddr));
|
||||||
|
inaddr.sin_addr.s_addr = inet_addr_winsock(name.c_str());
|
||||||
|
if (inaddr.sin_addr.s_addr != INADDR_NONE) {
|
||||||
|
// it's a dot notation address
|
||||||
|
addr->m_len = sizeof(struct sockaddr_in);
|
||||||
|
inaddr.sin_family = AF_INET;
|
||||||
|
inaddr.sin_port = 0;
|
||||||
|
memcpy(&addr->m_addr, &inaddr, addr->m_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// address lookup
|
||||||
|
struct hostent* info = gethostbyname_winsock(name.c_str());
|
||||||
|
if (info == NULL) {
|
||||||
|
delete addr;
|
||||||
|
throwNameError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy over address (only IPv4 currently supported)
|
||||||
|
addr->m_len = sizeof(struct sockaddr_in);
|
||||||
|
inaddr.sin_family = info->h_addrtype;
|
||||||
|
inaddr.sin_port = 0;
|
||||||
|
memcpy(&inaddr.sin_addr, info->h_addr_list[0], info->h_length);
|
||||||
|
memcpy(&addr->m_addr, &inaddr, addr->m_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::closeAddr(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
delete addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchNetworkWinsock::addrToName(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
// name lookup
|
||||||
|
struct hostent* info = gethostbyaddr_winsock(
|
||||||
|
reinterpret_cast<const char FAR*>(&addr->m_addr),
|
||||||
|
addr->m_len, addr->m_addr.sa_family);
|
||||||
|
if (info == NULL) {
|
||||||
|
throwNameError(getsockerror_winsock());
|
||||||
|
}
|
||||||
|
|
||||||
|
// return (primary) name
|
||||||
|
return info->h_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CArchNetworkWinsock::addrToString(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
switch (getAddrFamily(addr)) {
|
||||||
|
case kINET: {
|
||||||
|
struct sockaddr_in* ipAddr =
|
||||||
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
|
return inet_ntoa_winsock(ipAddr->sin_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "unknown address family");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IArchNetwork::EAddressFamily
|
||||||
|
CArchNetworkWinsock::getAddrFamily(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
switch (addr->m_addr.sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
return kINET;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return kUNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::setAddrPort(CArchNetAddress addr, int port)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
switch (getAddrFamily(addr)) {
|
||||||
|
case kINET: {
|
||||||
|
struct sockaddr_in* ipAddr =
|
||||||
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
|
ipAddr->sin_port = htons_winsock(static_cast<u_short>(port));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "unknown address family");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchNetworkWinsock::getAddrPort(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
switch (getAddrFamily(addr)) {
|
||||||
|
case kINET: {
|
||||||
|
struct sockaddr_in* ipAddr =
|
||||||
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
|
return ntohs_winsock(ipAddr->sin_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "unknown address family");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchNetworkWinsock::isAnyAddr(CArchNetAddress addr)
|
||||||
|
{
|
||||||
|
assert(addr != NULL);
|
||||||
|
|
||||||
|
switch (getAddrFamily(addr)) {
|
||||||
|
case kINET: {
|
||||||
|
struct sockaddr_in* ipAddr =
|
||||||
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
|
return (ipAddr->sin_addr.s_addr == INADDR_ANY &&
|
||||||
|
addr->m_len == sizeof(struct sockaddr_in));
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "unknown address family");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::throwError(int err)
|
||||||
|
{
|
||||||
|
switch (err) {
|
||||||
|
case WSAEWOULDBLOCK:
|
||||||
|
throw XArchNetworkWouldBlock(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAEACCES:
|
||||||
|
throw XArchNetworkAccess(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAEMFILE:
|
||||||
|
case WSAENOBUFS:
|
||||||
|
case WSAENETDOWN:
|
||||||
|
throw XArchNetworkResource(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAEPROTOTYPE:
|
||||||
|
case WSAEPROTONOSUPPORT:
|
||||||
|
case WSAEAFNOSUPPORT:
|
||||||
|
case WSAEPFNOSUPPORT:
|
||||||
|
case WSAESOCKTNOSUPPORT:
|
||||||
|
case WSAEINVAL:
|
||||||
|
case WSAENOPROTOOPT:
|
||||||
|
case WSAEOPNOTSUPP:
|
||||||
|
case WSAESHUTDOWN:
|
||||||
|
case WSANOTINITIALISED:
|
||||||
|
case WSAVERNOTSUPPORTED:
|
||||||
|
case WSASYSNOTREADY:
|
||||||
|
throw XArchNetworkSupport(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAEADDRNOTAVAIL:
|
||||||
|
throw XArchNetworkNoAddress(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAEADDRINUSE:
|
||||||
|
throw XArchNetworkAddressInUse(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAEHOSTUNREACH:
|
||||||
|
case WSAENETUNREACH:
|
||||||
|
throw XArchNetworkNoRoute(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAENOTCONN:
|
||||||
|
throw XArchNetworkNotConnected(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAENETRESET:
|
||||||
|
case WSAEDISCON:
|
||||||
|
case WSAECONNABORTED:
|
||||||
|
case WSAECONNRESET:
|
||||||
|
throw XArchNetworkDisconnected(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAECONNREFUSED:
|
||||||
|
throw XArchNetworkConnectionRefused(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAEINPROGRESS:
|
||||||
|
case WSAEALREADY:
|
||||||
|
throw XArchNetworkConnecting(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAEHOSTDOWN:
|
||||||
|
case WSAETIMEDOUT:
|
||||||
|
throw XArchNetworkTimedOut(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAHOST_NOT_FOUND:
|
||||||
|
throw XArchNetworkNameUnknown(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSANO_DATA:
|
||||||
|
throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSANO_RECOVERY:
|
||||||
|
throw XArchNetworkNameFailure(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSATRY_AGAIN:
|
||||||
|
throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw XArchNetwork(new XArchEvalWinsock(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::throwNameError(int err)
|
||||||
|
{
|
||||||
|
switch (err) {
|
||||||
|
case WSAHOST_NOT_FOUND:
|
||||||
|
throw XArchNetworkNameUnknown(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSANO_DATA:
|
||||||
|
throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSANO_RECOVERY:
|
||||||
|
throw XArchNetworkNameFailure(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSATRY_AGAIN:
|
||||||
|
throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw XArchNetworkName(new XArchEvalWinsock(err));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHNETWORKWINSOCK_H
|
||||||
|
#define CARCHNETWORKWINSOCK_H
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
// declare no functions in winsock2
|
||||||
|
#define INCL_WINSOCK_API_PROTOTYPES 0
|
||||||
|
#define INCL_WINSOCK_API_TYPEDEFS 0
|
||||||
|
|
||||||
|
#include "IArchNetwork.h"
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
#define ARCH_NETWORK CArchNetworkWinsock
|
||||||
|
|
||||||
|
class CArchSocketImpl {
|
||||||
|
public:
|
||||||
|
SOCKET m_socket;
|
||||||
|
bool m_connected;
|
||||||
|
int m_refCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CArchNetAddressImpl {
|
||||||
|
public:
|
||||||
|
CArchNetAddressImpl() : m_len(sizeof(m_addr)) { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct sockaddr m_addr;
|
||||||
|
int m_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CArchNetworkWinsock : public IArchNetwork {
|
||||||
|
public:
|
||||||
|
CArchNetworkWinsock();
|
||||||
|
virtual ~CArchNetworkWinsock();
|
||||||
|
|
||||||
|
// IArchNetwork overrides
|
||||||
|
virtual CArchSocket newSocket(EAddressFamily, ESocketType);
|
||||||
|
virtual CArchSocket copySocket(CArchSocket s);
|
||||||
|
virtual void closeSocket(CArchSocket s);
|
||||||
|
virtual void closeSocketForRead(CArchSocket s);
|
||||||
|
virtual void closeSocketForWrite(CArchSocket s);
|
||||||
|
virtual void bindSocket(CArchSocket s, CArchNetAddress addr);
|
||||||
|
virtual void listenOnSocket(CArchSocket s);
|
||||||
|
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
|
||||||
|
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
|
||||||
|
virtual int pollSocket(CPollEntry[], int num, double timeout);
|
||||||
|
virtual size_t readSocket(CArchSocket s, void* buf, size_t len);
|
||||||
|
virtual size_t writeSocket(CArchSocket s,
|
||||||
|
const void* buf, size_t len);
|
||||||
|
virtual void throwErrorOnSocket(CArchSocket);
|
||||||
|
virtual bool setBlockingOnSocket(CArchSocket, bool blocking);
|
||||||
|
virtual bool setNoDelayOnSocket(CArchSocket, bool noDelay);
|
||||||
|
virtual std::string getHostName();
|
||||||
|
virtual CArchNetAddress newAnyAddr(EAddressFamily);
|
||||||
|
virtual CArchNetAddress copyAddr(CArchNetAddress);
|
||||||
|
virtual CArchNetAddress nameToAddr(const std::string&);
|
||||||
|
virtual void closeAddr(CArchNetAddress);
|
||||||
|
virtual std::string addrToName(CArchNetAddress);
|
||||||
|
virtual std::string addrToString(CArchNetAddress);
|
||||||
|
virtual EAddressFamily getAddrFamily(CArchNetAddress);
|
||||||
|
virtual void setAddrPort(CArchNetAddress, int port);
|
||||||
|
virtual int getAddrPort(CArchNetAddress);
|
||||||
|
virtual bool isAnyAddr(CArchNetAddress);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init(HMODULE);
|
||||||
|
|
||||||
|
void throwError(int);
|
||||||
|
void throwNameError(int);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CArchMutex m_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchSleepUnix.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#if TIME_WITH_SYS_TIME
|
||||||
|
# include <sys/time.h>
|
||||||
|
# include <time.h>
|
||||||
|
#else
|
||||||
|
# if HAVE_SYS_TIME_H
|
||||||
|
# include <sys/time.h>
|
||||||
|
# else
|
||||||
|
# include <time.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !HAVE_NANOSLEEP
|
||||||
|
# if HAVE_SYS_SELECT_H
|
||||||
|
# include <sys/select.h>
|
||||||
|
# endif
|
||||||
|
# if HAVE_SYS_TYPES_H
|
||||||
|
# include <sys/types.h>
|
||||||
|
# endif
|
||||||
|
# if HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchSleepUnix
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchSleepUnix::CArchSleepUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSleepUnix::~CArchSleepUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchSleepUnix::sleep(double timeout)
|
||||||
|
{
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
if (timeout < 0.0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_NANOSLEEP
|
||||||
|
// prep timeout
|
||||||
|
struct timespec t;
|
||||||
|
t.tv_sec = (long)timeout;
|
||||||
|
t.tv_nsec = (long)(1.0e+9 * (timeout - (double)t.tv_sec));
|
||||||
|
|
||||||
|
// wait
|
||||||
|
while (nanosleep(&t, &t) < 0)
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
#else
|
||||||
|
/* emulate nanosleep() with select() */
|
||||||
|
double startTime = time();
|
||||||
|
double timeLeft = timeout;
|
||||||
|
while (timeLeft > 0.0) {
|
||||||
|
struct timeval timeout2;
|
||||||
|
timeout2.tv_sec = static_cast<int>(timeLeft);
|
||||||
|
timeout2.tv_usec = static_cast<int>(1.0e+6 * (timeLeft -
|
||||||
|
timeout2.tv_sec));
|
||||||
|
select((SELECT_TYPE_ARG1) 0,
|
||||||
|
SELECT_TYPE_ARG234 NULL,
|
||||||
|
SELECT_TYPE_ARG234 NULL,
|
||||||
|
SELECT_TYPE_ARG234 NULL,
|
||||||
|
SELECT_TYPE_ARG5 &timeout2);
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
timeLeft = timeout - (time() - startTime);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHSLEEPUNIX_H
|
||||||
|
#define CARCHSLEEPUNIX_H
|
||||||
|
|
||||||
|
#include "IArchSleep.h"
|
||||||
|
|
||||||
|
#define ARCH_SLEEP CArchSleepUnix
|
||||||
|
|
||||||
|
class CArchSleepUnix : public IArchSleep {
|
||||||
|
public:
|
||||||
|
CArchSleepUnix();
|
||||||
|
virtual ~CArchSleepUnix();
|
||||||
|
|
||||||
|
// IArchSleep overrides
|
||||||
|
virtual void sleep(double timeout);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchSleepWindows.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "CArchMultithreadWindows.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchSleepWindows
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchSleepWindows::CArchSleepWindows()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchSleepWindows::~CArchSleepWindows()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchSleepWindows::sleep(double timeout)
|
||||||
|
{
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
if (timeout < 0.0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the cancel event from the current thread. this only
|
||||||
|
// works if we're using the windows multithread object but
|
||||||
|
// this is windows so that's pretty certain; we'll get a
|
||||||
|
// link error if we're not, though.
|
||||||
|
CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
|
||||||
|
if (mt != NULL) {
|
||||||
|
HANDLE cancelEvent = mt->getCancelEventForCurrentThread();
|
||||||
|
WaitForSingleObject(cancelEvent, (DWORD)(1000.0 * timeout));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Sleep((DWORD)(1000.0 * timeout));
|
||||||
|
}
|
||||||
|
ARCH->testCancelThread();
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHSLEEPWINDOWS_H
|
||||||
|
#define CARCHSLEEPWINDOWS_H
|
||||||
|
|
||||||
|
#include "IArchSleep.h"
|
||||||
|
|
||||||
|
#define ARCH_SLEEP CArchSleepWindows
|
||||||
|
|
||||||
|
class CArchSleepWindows : public IArchSleep {
|
||||||
|
public:
|
||||||
|
CArchSleepWindows();
|
||||||
|
virtual ~CArchSleepWindows();
|
||||||
|
|
||||||
|
// IArchSleep overrides
|
||||||
|
virtual void sleep(double timeout);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -12,25 +12,23 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CPLATFORM_H
|
#include "CArchStringUnix.h"
|
||||||
#define CPLATFORM_H
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "CMultibyte.cpp"
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
//
|
||||||
|
// CArchStringUnix
|
||||||
|
//
|
||||||
|
|
||||||
#include "CWin32Platform.h"
|
CArchStringUnix::CArchStringUnix()
|
||||||
typedef CWin32Platform CPlatform;
|
{
|
||||||
|
initMB();
|
||||||
|
}
|
||||||
|
|
||||||
#elif UNIX_LIKE
|
CArchStringUnix::~CArchStringUnix()
|
||||||
|
{
|
||||||
|
cleanMB();
|
||||||
|
}
|
||||||
|
|
||||||
#include "CUnixPlatform.h"
|
#include "vsnprintf.cpp"
|
||||||
typedef CUnixPlatform CPlatform;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#error Unsupported platform
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHSTRINGUNIX_H
|
||||||
|
#define CARCHSTRINGUNIX_H
|
||||||
|
|
||||||
|
#include "IArchString.h"
|
||||||
|
|
||||||
|
#define ARCH_STRING CArchStringUnix
|
||||||
|
|
||||||
|
class CArchStringUnix : public IArchString {
|
||||||
|
public:
|
||||||
|
CArchStringUnix();
|
||||||
|
virtual ~CArchStringUnix();
|
||||||
|
|
||||||
|
// IArchString overrides
|
||||||
|
virtual int vsnprintf(char* str,
|
||||||
|
int size, const char* fmt, va_list ap);
|
||||||
|
virtual CArchMBState newMBState();
|
||||||
|
virtual void closeMBState(CArchMBState);
|
||||||
|
virtual void initMBState(CArchMBState);
|
||||||
|
virtual bool isInitMBState(CArchMBState);
|
||||||
|
virtual int convMBToWC(wchar_t*, const char*, int, CArchMBState);
|
||||||
|
virtual int convWCToMB(char*, wchar_t, CArchMBState);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include "CArchStringWindows.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "CMultibyte.cpp"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchStringWindows
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchStringWindows::CArchStringWindows()
|
||||||
|
{
|
||||||
|
initMB();
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchStringWindows::~CArchStringWindows()
|
||||||
|
{
|
||||||
|
cleanMB();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HAVE_VSNPRINTF 1
|
||||||
|
#define ARCH_VSNPRINTF _vsnprintf
|
||||||
|
#include "vsnprintf.cpp"
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHSTRINGWINDOWS_H
|
||||||
|
#define CARCHSTRINGWINDOWS_H
|
||||||
|
|
||||||
|
#include "IArchString.h"
|
||||||
|
|
||||||
|
#define ARCH_STRING CArchStringWindows
|
||||||
|
|
||||||
|
class CArchStringWindows : public IArchString {
|
||||||
|
public:
|
||||||
|
CArchStringWindows();
|
||||||
|
virtual ~CArchStringWindows();
|
||||||
|
|
||||||
|
// IArchString overrides
|
||||||
|
virtual int vsnprintf(char* str,
|
||||||
|
int size, const char* fmt, va_list ap);
|
||||||
|
virtual CArchMBState newMBState();
|
||||||
|
virtual void closeMBState(CArchMBState);
|
||||||
|
virtual void initMBState(CArchMBState);
|
||||||
|
virtual bool isInitMBState(CArchMBState);
|
||||||
|
virtual int convMBToWC(wchar_t*, const char*, int, CArchMBState);
|
||||||
|
virtual int convWCToMB(char*, wchar_t, CArchMBState);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchTimeUnix.h"
|
||||||
|
#if TIME_WITH_SYS_TIME
|
||||||
|
# include <sys/time.h>
|
||||||
|
# include <time.h>
|
||||||
|
#else
|
||||||
|
# if HAVE_SYS_TIME_H
|
||||||
|
# include <sys/time.h>
|
||||||
|
# else
|
||||||
|
# include <time.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchTimeUnix
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchTimeUnix::CArchTimeUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchTimeUnix::~CArchTimeUnix()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
CArchTimeUnix::time()
|
||||||
|
{
|
||||||
|
struct timeval t;
|
||||||
|
gettimeofday(&t, NULL);
|
||||||
|
return (double)t.tv_sec + 1.0e-6 * (double)t.tv_usec;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHTIMEUNIX_H
|
||||||
|
#define CARCHTIMEUNIX_H
|
||||||
|
|
||||||
|
#include "IArchTime.h"
|
||||||
|
|
||||||
|
#define ARCH_TIME CArchTimeUnix
|
||||||
|
|
||||||
|
class CArchTimeUnix : public IArchTime {
|
||||||
|
public:
|
||||||
|
CArchTimeUnix();
|
||||||
|
virtual ~CArchTimeUnix();
|
||||||
|
|
||||||
|
// IArchTime overrides
|
||||||
|
virtual double time();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// avoid getting a lot a crap from mmsystem.h that we don't need
|
||||||
|
#define MMNODRV // Installable driver support
|
||||||
|
#define MMNOSOUND // Sound support
|
||||||
|
#define MMNOWAVE // Waveform support
|
||||||
|
#define MMNOMIDI // MIDI support
|
||||||
|
#define MMNOAUX // Auxiliary audio support
|
||||||
|
#define MMNOMIXER // Mixer support
|
||||||
|
#define MMNOJOY // Joystick support
|
||||||
|
#define MMNOMCI // MCI support
|
||||||
|
#define MMNOMMIO // Multimedia file I/O support
|
||||||
|
#define MMNOMMSYSTEM // General MMSYSTEM functions
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include "CArchTimeWindows.h"
|
||||||
|
#include <windows.h>
|
||||||
|
#include <mmsystem.h>
|
||||||
|
|
||||||
|
typedef WINMMAPI DWORD (WINAPI *PTimeGetTime)(void);
|
||||||
|
|
||||||
|
static double s_freq = 0.0;
|
||||||
|
static HINSTANCE s_mmInstance = NULL;
|
||||||
|
static PTimeGetTime s_tgt = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// CArchTimeWindows
|
||||||
|
//
|
||||||
|
|
||||||
|
CArchTimeWindows::CArchTimeWindows()
|
||||||
|
{
|
||||||
|
assert(s_freq == 0.0 || s_mmInstance == NULL);
|
||||||
|
|
||||||
|
LARGE_INTEGER freq;
|
||||||
|
if (QueryPerformanceFrequency(&freq) && freq.QuadPart != 0) {
|
||||||
|
s_freq = 1.0 / static_cast<double>(freq.QuadPart);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// load winmm.dll and get timeGetTime
|
||||||
|
s_mmInstance = LoadLibrary("winmm");
|
||||||
|
if (s_mmInstance != NULL) {
|
||||||
|
s_tgt = (PTimeGetTime)GetProcAddress(s_mmInstance, "timeGetTime");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchTimeWindows::~CArchTimeWindows()
|
||||||
|
{
|
||||||
|
s_freq = 0.0;
|
||||||
|
if (s_mmInstance == NULL) {
|
||||||
|
FreeLibrary(reinterpret_cast<HMODULE>(s_mmInstance));
|
||||||
|
s_tgt = NULL;
|
||||||
|
s_mmInstance = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
CArchTimeWindows::time()
|
||||||
|
{
|
||||||
|
// get time. we try three ways, in order of descending precision
|
||||||
|
if (s_freq != 0.0) {
|
||||||
|
LARGE_INTEGER c;
|
||||||
|
QueryPerformanceCounter(&c);
|
||||||
|
return s_freq * static_cast<double>(c.QuadPart);
|
||||||
|
}
|
||||||
|
else if (s_tgt != NULL) {
|
||||||
|
return 0.001 * static_cast<double>(s_tgt());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0.001 * static_cast<double>(GetTickCount());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARCHTIMEWINDOWS_H
|
||||||
|
#define CARCHTIMEWINDOWS_H
|
||||||
|
|
||||||
|
#include "IArchTime.h"
|
||||||
|
|
||||||
|
#define ARCH_TIME CArchTimeWindows
|
||||||
|
|
||||||
|
class CArchTimeWindows : public IArchTime {
|
||||||
|
public:
|
||||||
|
CArchTimeWindows();
|
||||||
|
virtual ~CArchTimeWindows();
|
||||||
|
|
||||||
|
// IArchTime overrides
|
||||||
|
virtual double time();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CMULTIBYTE_H
|
||||||
|
#define CMULTIBYTE_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#if (HAVE_MBSINIT && HAVE_MBRTOWC && HAVE_WCRTOMB) || WINDOWS_LIKE
|
||||||
|
#include "CMultibyteOS.cpp"
|
||||||
|
#else
|
||||||
|
#include "CMultibyteEmu.cpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CArchMBState
|
||||||
|
ARCH_STRING::newMBState()
|
||||||
|
{
|
||||||
|
CArchMBState state = new CArchMBStateImpl;
|
||||||
|
initMBState(state);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ARCH_STRING::closeMBState(CArchMBState state)
|
||||||
|
{
|
||||||
|
delete state;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArch.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
|
class CArchMBStateImpl {
|
||||||
|
public:
|
||||||
|
mbstate_t m_mbstate;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// use C library non-reentrant multibyte conversion with mutex
|
||||||
|
//
|
||||||
|
|
||||||
|
static CArchMutex s_mutex;
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
initMB()
|
||||||
|
{
|
||||||
|
s_mutex = ARCH->newMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
cleanMB()
|
||||||
|
{
|
||||||
|
ARCH->closeMutex(s_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ARCH_STRING::initMBState(CArchMBState state)
|
||||||
|
{
|
||||||
|
memset(&state->m_mbstate, 0, sizeof(state->m_mbstate));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ARCH_STRING::isInitMBState(CArchMBState state)
|
||||||
|
{
|
||||||
|
#if !HAVE_MBSINIT
|
||||||
|
return (mbsinit(&state->m_mbstate) != 0);
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ARCH_STRING::convMBToWC(wchar_t* dst, const char* src, int n, CArchMBState)
|
||||||
|
{
|
||||||
|
wchar_t dummy;
|
||||||
|
ARCH->lockMutex(s_mutex);
|
||||||
|
int result = mbtowc(dst != NULL ? dst : &dummy, src, n);
|
||||||
|
ARCH->unlockMutex(s_mutex);
|
||||||
|
if (result < 0)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ARCH_STRING::convWCToMB(char* dst, wchar_t src, CArchMBState)
|
||||||
|
{
|
||||||
|
char dummy[MB_LEN_MAX];
|
||||||
|
ARCH->lockMutex(s_mutex);
|
||||||
|
int n = wctomb(dst != NULL ? dst : dummy, src);
|
||||||
|
ARCH->unlockMutex(s_mutex);
|
||||||
|
return n;
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
|
class CArchMBStateImpl {
|
||||||
|
public:
|
||||||
|
mbstate_t m_mbstate;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// use C library reentrant multibyte conversion
|
||||||
|
//
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
initMB()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
cleanMB()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ARCH_STRING::initMBState(CArchMBState state)
|
||||||
|
{
|
||||||
|
memset(&state->m_mbstate, 0, sizeof(state->m_mbstate));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ARCH_STRING::isInitMBState(CArchMBState state)
|
||||||
|
{
|
||||||
|
return (mbsinit(&state->m_mbstate) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ARCH_STRING::convMBToWC(wchar_t* dst, const char* src,
|
||||||
|
int n, CArchMBState state)
|
||||||
|
{
|
||||||
|
wchar_t dummy;
|
||||||
|
return static_cast<int>(mbrtowc(dst != NULL ? dst : &dummy,
|
||||||
|
src, static_cast<size_t>(n), &state->m_mbstate));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ARCH_STRING::convWCToMB(char* dst, wchar_t src, CArchMBState state)
|
||||||
|
{
|
||||||
|
char dummy[MB_LEN_MAX];
|
||||||
|
return static_cast<int>(wcrtomb(dst != NULL ? dst : dummy,
|
||||||
|
src, &state->m_mbstate));
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IARCHCONSOLE_H
|
||||||
|
#define IARCHCONSOLE_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
|
||||||
|
class IArchConsole : public IInterface {
|
||||||
|
public:
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Open the console
|
||||||
|
/*!
|
||||||
|
Opens the console for writing. The console is opened automatically
|
||||||
|
on the first write so calling this method is optional. Uses \c title
|
||||||
|
for the console's title if appropriate for the architecture. Calling
|
||||||
|
this method on an already open console must have no effect.
|
||||||
|
*/
|
||||||
|
virtual void openConsole(const char* title) = 0;
|
||||||
|
|
||||||
|
//! Close the console
|
||||||
|
/*!
|
||||||
|
Close the console. Calling this method on an already closed console
|
||||||
|
must have no effect.
|
||||||
|
*/
|
||||||
|
virtual void closeConsole() = 0;
|
||||||
|
|
||||||
|
//! Write to the console
|
||||||
|
/*!
|
||||||
|
Writes the given string to the console, opening it if necessary.
|
||||||
|
*/
|
||||||
|
virtual void writeConsole(const char*) = 0;
|
||||||
|
|
||||||
|
//! Returns the newline sequence for the console
|
||||||
|
/*!
|
||||||
|
Different consoles use different character sequences for newlines.
|
||||||
|
This method returns the appropriate newline sequence for the console.
|
||||||
|
*/
|
||||||
|
virtual const char* getNewlineForConsole() = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IARCHDAEMON_H
|
||||||
|
#define IARCHDAEMON_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
|
||||||
|
//! Interface for architecture dependent daemonizing
|
||||||
|
/*!
|
||||||
|
This interface defines the operations required by synergy for installing
|
||||||
|
uninstalling daeamons and daemonizing a process. Each architecture must
|
||||||
|
implement this interface.
|
||||||
|
*/
|
||||||
|
class IArchDaemon : public IInterface {
|
||||||
|
public:
|
||||||
|
typedef int (*DaemonFunc)(int argc, const char** argv);
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Install daemon
|
||||||
|
/*!
|
||||||
|
Install a daemon. \c name is the name of the daemon passed to the
|
||||||
|
system and \c description is a short human readable description of
|
||||||
|
the daemon. \c pathname is the path to the daemon executable.
|
||||||
|
\c commandLine should \b not include the name of program as the
|
||||||
|
first argument. If \c allUsers is true then the daemon will be
|
||||||
|
installed to start at boot time, otherwise it will be installed to
|
||||||
|
start when the current user logs in. Throws an \c XArchDaemon
|
||||||
|
exception on failure.
|
||||||
|
*/
|
||||||
|
virtual void installDaemon(const char* name,
|
||||||
|
const char* description,
|
||||||
|
const char* pathname,
|
||||||
|
const char* commandLine,
|
||||||
|
bool allUsers) = 0;
|
||||||
|
|
||||||
|
//! Uninstall daemon
|
||||||
|
/*!
|
||||||
|
Uninstall a daemon. Throws an \c XArchDaemon on failure.
|
||||||
|
*/
|
||||||
|
virtual void uninstallDaemon(const char* name, bool allUsers) = 0;
|
||||||
|
|
||||||
|
//! Daemonize the process
|
||||||
|
/*!
|
||||||
|
Daemonize. Throw XArchDaemonFailed on error. \c name is the name
|
||||||
|
of the daemon. Once daemonized, \c func is invoked and daemonize
|
||||||
|
returns when and what it does.
|
||||||
|
|
||||||
|
Exactly what happens when daemonizing depends on the platform.
|
||||||
|
<ul>
|
||||||
|
<li>unix:
|
||||||
|
Detaches from terminal. \c func gets passed one argument, the
|
||||||
|
name passed to daemonize().
|
||||||
|
<li>win32:
|
||||||
|
Becomes a service. Argument 0 is the name of the service
|
||||||
|
and the rest are the arguments passed to StartService().
|
||||||
|
\c func is only called when the service is actually started.
|
||||||
|
\c func must call \c CArchMiscWindows::runDaemon() to finally
|
||||||
|
becoming a service. The \c runFunc function passed to \c runDaemon()
|
||||||
|
must call \c CArchMiscWindows::daemonRunning(true) when it
|
||||||
|
enters the main loop (i.e. after initialization) and
|
||||||
|
\c CArchMiscWindows::daemonRunning(false) when it leaves
|
||||||
|
the main loop. The \c stopFunc function passed to \c runDaemon()
|
||||||
|
is called when the daemon must exit the main loop and it must cause
|
||||||
|
\c runFunc to return. \c func should return what \c runDaemon()
|
||||||
|
returns. \c func or \c runFunc can call
|
||||||
|
\c CArchMiscWindows::daemonFailed() to indicate startup failure.
|
||||||
|
</ul>
|
||||||
|
*/
|
||||||
|
virtual int daemonize(const char* name, DaemonFunc func) = 0;
|
||||||
|
|
||||||
|
//! Check if user has permission to install the daemon
|
||||||
|
/*!
|
||||||
|
Returns true iff the caller has permission to install or
|
||||||
|
uninstall the daemon. Note that even if this method returns
|
||||||
|
true it's possible that installing/uninstalling the service
|
||||||
|
may still fail. This method ignores whether or not the
|
||||||
|
service is already installed.
|
||||||
|
*/
|
||||||
|
virtual bool canInstallDaemon(const char* name, bool allUsers) = 0;
|
||||||
|
|
||||||
|
//! Check if the daemon is installed
|
||||||
|
/*!
|
||||||
|
Returns true iff the daemon is installed.
|
||||||
|
*/
|
||||||
|
virtual bool isDaemonInstalled(const char* name, bool allUsers) = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IARCHFILE_H
|
||||||
|
#define IARCHFILE_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
#include "stdstring.h"
|
||||||
|
|
||||||
|
class IArchFile : public IInterface {
|
||||||
|
public:
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Extract base name
|
||||||
|
/*!
|
||||||
|
Find the base name in the given \c pathname.
|
||||||
|
*/
|
||||||
|
virtual const char* getBasename(const char* pathname) = 0;
|
||||||
|
|
||||||
|
//! Get user's home directory
|
||||||
|
/*!
|
||||||
|
Returns the user's home directory. Returns the empty string if
|
||||||
|
this cannot be determined.
|
||||||
|
*/
|
||||||
|
virtual std::string getUserDirectory() = 0;
|
||||||
|
|
||||||
|
//! Get system directory
|
||||||
|
/*!
|
||||||
|
Returns the ussystem configuration file directory.
|
||||||
|
*/
|
||||||
|
virtual std::string getSystemDirectory() = 0;
|
||||||
|
|
||||||
|
//! Concatenate path components
|
||||||
|
/*!
|
||||||
|
Concatenate pathname components with a directory separator
|
||||||
|
between them. This should not check if the resulting path
|
||||||
|
is longer than allowed by the system; we'll rely on the
|
||||||
|
system calls to tell us that.
|
||||||
|
*/
|
||||||
|
virtual std::string concatPath(
|
||||||
|
const std::string& prefix,
|
||||||
|
const std::string& suffix) = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IARCHLOG_H
|
||||||
|
#define IARCHLOG_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
|
||||||
|
class IArchLog : public IInterface {
|
||||||
|
public:
|
||||||
|
enum ELevel { kERROR, kWARNING, kNOTE, kINFO, kDEBUG };
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Open the log
|
||||||
|
/*!
|
||||||
|
Opens the log for writing. The log must be opened before being
|
||||||
|
written to.
|
||||||
|
*/
|
||||||
|
virtual void openLog(const char* name) = 0;
|
||||||
|
|
||||||
|
//! Close the log
|
||||||
|
/*!
|
||||||
|
Close the log.
|
||||||
|
*/
|
||||||
|
virtual void closeLog() = 0;
|
||||||
|
|
||||||
|
//! Write to the log
|
||||||
|
/*!
|
||||||
|
Writes the given string to the log with the given level.
|
||||||
|
*/
|
||||||
|
virtual void writeLog(ELevel, const char*) = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IARCHMULTITHREAD_H
|
||||||
|
#define IARCHMULTITHREAD_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
|
||||||
|
class CArchCondImpl;
|
||||||
|
class CArchMutexImpl;
|
||||||
|
class CArchThreadImpl;
|
||||||
|
typedef CArchCondImpl* CArchCond;
|
||||||
|
typedef CArchMutexImpl* CArchMutex;
|
||||||
|
typedef CArchThreadImpl* CArchThread;
|
||||||
|
|
||||||
|
//! Interface for architecture dependent multithreading
|
||||||
|
/*!
|
||||||
|
This interface defines the multithreading operations required by
|
||||||
|
synergy. Each architecture must implement this interface.
|
||||||
|
*/
|
||||||
|
class IArchMultithread : public IInterface {
|
||||||
|
public:
|
||||||
|
typedef void* (*ThreadFunc)(void*);
|
||||||
|
typedef unsigned int ThreadID;
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//
|
||||||
|
// condition variable methods
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual CArchCond newCondVar() = 0;
|
||||||
|
virtual void closeCondVar(CArchCond) = 0;
|
||||||
|
virtual void signalCondVar(CArchCond) = 0;
|
||||||
|
virtual void broadcastCondVar(CArchCond) = 0;
|
||||||
|
virtual bool waitCondVar(CArchCond, CArchMutex, double timeout) = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// mutex methods
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual CArchMutex newMutex() = 0;
|
||||||
|
virtual void closeMutex(CArchMutex) = 0;
|
||||||
|
virtual void lockMutex(CArchMutex) = 0;
|
||||||
|
virtual void unlockMutex(CArchMutex) = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// thread methods
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual CArchThread newThread(ThreadFunc, void*) = 0;
|
||||||
|
virtual CArchThread newCurrentThread() = 0;
|
||||||
|
virtual CArchThread copyThread(CArchThread) = 0;
|
||||||
|
virtual void closeThread(CArchThread) = 0;
|
||||||
|
virtual void cancelThread(CArchThread) = 0;
|
||||||
|
virtual void setPriorityOfThread(CArchThread, int n) = 0;
|
||||||
|
virtual void testCancelThread() = 0;
|
||||||
|
virtual bool wait(CArchThread, double timeout) = 0;
|
||||||
|
virtual bool waitForEvent(double timeout) = 0;
|
||||||
|
virtual bool isSameThread(CArchThread, CArchThread) = 0;
|
||||||
|
virtual bool isExitedThread(CArchThread) = 0;
|
||||||
|
virtual void* getResultOfThread(CArchThread) = 0;
|
||||||
|
virtual ThreadID getIDOfThread(CArchThread) = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IARCHNETWORK_H
|
||||||
|
#define IARCHNETWORK_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
#include "stdstring.h"
|
||||||
|
|
||||||
|
class CArchSocketImpl;
|
||||||
|
class CArchNetAddressImpl;
|
||||||
|
typedef CArchSocketImpl* CArchSocket;
|
||||||
|
typedef CArchNetAddressImpl* CArchNetAddress;
|
||||||
|
|
||||||
|
//! Interface for architecture dependent networking
|
||||||
|
/*!
|
||||||
|
This interface defines the networking operations required by
|
||||||
|
synergy. Each architecture must implement this interface.
|
||||||
|
*/
|
||||||
|
class IArchNetwork : public IInterface {
|
||||||
|
public:
|
||||||
|
enum EAddressFamily {
|
||||||
|
kUNKNOWN,
|
||||||
|
kINET,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ESocketType {
|
||||||
|
kDGRAM,
|
||||||
|
kSTREAM
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kPOLLIN = 1,
|
||||||
|
kPOLLOUT = 2,
|
||||||
|
kPOLLERR = 4,
|
||||||
|
kPOLLNVAL = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
class CPollEntry {
|
||||||
|
public:
|
||||||
|
CArchSocket m_socket;
|
||||||
|
unsigned short m_events;
|
||||||
|
unsigned short m_revents;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
virtual CArchSocket newSocket(EAddressFamily, ESocketType) = 0;
|
||||||
|
virtual CArchSocket copySocket(CArchSocket s) = 0;
|
||||||
|
virtual void closeSocket(CArchSocket s) = 0;
|
||||||
|
virtual void closeSocketForRead(CArchSocket s) = 0;
|
||||||
|
virtual void closeSocketForWrite(CArchSocket s) = 0;
|
||||||
|
virtual void bindSocket(CArchSocket s, CArchNetAddress addr) = 0;
|
||||||
|
virtual void listenOnSocket(CArchSocket s) = 0;
|
||||||
|
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr) = 0;
|
||||||
|
virtual void connectSocket(CArchSocket s, CArchNetAddress name) = 0;
|
||||||
|
virtual int pollSocket(CPollEntry[], int num, double timeout) = 0;
|
||||||
|
virtual size_t readSocket(CArchSocket s, void* buf, size_t len) = 0;
|
||||||
|
virtual size_t writeSocket(CArchSocket s,
|
||||||
|
const void* buf, size_t len) = 0;
|
||||||
|
virtual void throwErrorOnSocket(CArchSocket) = 0;
|
||||||
|
|
||||||
|
//! Set socket to (non-)blocking operation
|
||||||
|
/*!
|
||||||
|
Set socket to block or not block on accept, connect, poll, read and
|
||||||
|
write (i.e. calls that may take an arbitrary amount of time).
|
||||||
|
Returns the previous state.
|
||||||
|
*/
|
||||||
|
virtual bool setBlockingOnSocket(CArchSocket, bool blocking) = 0;
|
||||||
|
|
||||||
|
//! Turn Nagle algorithm on or off on socket
|
||||||
|
/*!
|
||||||
|
Set socket to send messages immediately (true) or to collect small
|
||||||
|
messages into one packet (false). Returns the previous state.
|
||||||
|
*/
|
||||||
|
virtual bool setNoDelayOnSocket(CArchSocket, bool noDelay) = 0;
|
||||||
|
|
||||||
|
virtual std::string getHostName() = 0;
|
||||||
|
virtual CArchNetAddress newAnyAddr(EAddressFamily) = 0;
|
||||||
|
virtual CArchNetAddress copyAddr(CArchNetAddress) = 0;
|
||||||
|
virtual CArchNetAddress nameToAddr(const std::string&) = 0;
|
||||||
|
virtual void closeAddr(CArchNetAddress) = 0;
|
||||||
|
virtual std::string addrToName(CArchNetAddress) = 0;
|
||||||
|
virtual std::string addrToString(CArchNetAddress) = 0;
|
||||||
|
virtual EAddressFamily getAddrFamily(CArchNetAddress) = 0;
|
||||||
|
virtual void setAddrPort(CArchNetAddress, int port) = 0;
|
||||||
|
virtual int getAddrPort(CArchNetAddress) = 0;
|
||||||
|
virtual bool isAnyAddr(CArchNetAddress) = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IARCHSLEEP_H
|
||||||
|
#define IARCHSLEEP_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
|
||||||
|
class IArchSleep : public IInterface {
|
||||||
|
public:
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Sleep
|
||||||
|
/*!
|
||||||
|
Blocks the calling thread for \c timeout seconds. If
|
||||||
|
\c timeout < 0.0 then the call returns immediately. If \c timeout
|
||||||
|
== 0.0 then the calling thread yields the CPU.
|
||||||
|
|
||||||
|
(cancellation point)
|
||||||
|
*/
|
||||||
|
virtual void sleep(double timeout) = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IARCHSTRING_H
|
||||||
|
#define IARCHSTRING_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
class CArchMBStateImpl;
|
||||||
|
typedef CArchMBStateImpl* CArchMBState;
|
||||||
|
|
||||||
|
class IArchString : public IInterface {
|
||||||
|
public:
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! printf() to limited size buffer with va_list
|
||||||
|
/*!
|
||||||
|
This method is equivalent to vsprintf() except it will not write
|
||||||
|
more than \c n bytes to the buffer, returning -1 if the output
|
||||||
|
was truncated and the number of bytes written not including the
|
||||||
|
trailing NUL otherwise.
|
||||||
|
*/
|
||||||
|
virtual int vsnprintf(char* str,
|
||||||
|
int size, const char* fmt, va_list ap) = 0;
|
||||||
|
|
||||||
|
//! Create a new multibyte conversion state
|
||||||
|
virtual CArchMBState newMBState() = 0;
|
||||||
|
|
||||||
|
//! Destroy a multibyte conversion state
|
||||||
|
virtual void closeMBState(CArchMBState) = 0;
|
||||||
|
|
||||||
|
//! Initialize a multibyte conversion state
|
||||||
|
virtual void initMBState(CArchMBState) = 0;
|
||||||
|
|
||||||
|
//! Test a multibyte conversion state
|
||||||
|
virtual bool isInitMBState(CArchMBState) = 0;
|
||||||
|
|
||||||
|
//! Convert multibyte to wide character
|
||||||
|
virtual int convMBToWC(wchar_t*,
|
||||||
|
const char*, int, CArchMBState) = 0;
|
||||||
|
|
||||||
|
//! Convert wide character to multibyte
|
||||||
|
virtual int convWCToMB(char*, wchar_t, CArchMBState) = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IARCHTIME_H
|
||||||
|
#define IARCHTIME_H
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
|
||||||
|
class IArchTime : public IInterface {
|
||||||
|
public:
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Get the current time
|
||||||
|
/*!
|
||||||
|
Returns the number of seconds since some arbitrary starting time.
|
||||||
|
This should return as high a precision as reasonable.
|
||||||
|
*/
|
||||||
|
virtual double time() = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,96 @@
|
||||||
|
# synergy -- mouse and keyboard sharing utility
|
||||||
|
# Copyright (C) 2002 Chris Schoeneman
|
||||||
|
#
|
||||||
|
# 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 COPYING 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.
|
||||||
|
|
||||||
|
## Process this file with automake to produce Makefile.in
|
||||||
|
NULL =
|
||||||
|
DEPTH = ../..
|
||||||
|
VDEPTH = ./$(VPATH)/$(DEPTH)
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
arch.dsp \
|
||||||
|
CArchConsoleWindows.cpp \
|
||||||
|
CArchDaemonWindows.cpp \
|
||||||
|
CArchFileWindows.cpp \
|
||||||
|
CArchLogWindows.cpp \
|
||||||
|
CArchMiscWindows.cpp \
|
||||||
|
CArchMultithreadWindows.cpp \
|
||||||
|
CArchNetworkWinsock.cpp \
|
||||||
|
CArchSleepWindows.cpp \
|
||||||
|
CArchStringWindows.cpp \
|
||||||
|
CArchTimeWindows.cpp \
|
||||||
|
XArchWindows.cpp \
|
||||||
|
CArchConsoleWindows.h \
|
||||||
|
CArchDaemonWindows.h \
|
||||||
|
CArchFileWindows.h \
|
||||||
|
CArchLogWindows.h \
|
||||||
|
CArchMiscWindows.h \
|
||||||
|
CArchMultithreadWindows.h \
|
||||||
|
CArchNetworkWinsock.h \
|
||||||
|
CArchSleepWindows.h \
|
||||||
|
CArchStringWindows.h \
|
||||||
|
CArchTimeWindows.h \
|
||||||
|
XArchWindows.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
MAINTAINERCLEANFILES = \
|
||||||
|
Makefile.in \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
noinst_LIBRARIES = libarch.a
|
||||||
|
libarch_a_SOURCES = \
|
||||||
|
CArch.cpp \
|
||||||
|
CArchImpl.cpp \
|
||||||
|
XArch.cpp \
|
||||||
|
CArch.h \
|
||||||
|
IArchConsole.h \
|
||||||
|
IArchDaemon.h \
|
||||||
|
IArchFile.h \
|
||||||
|
IArchLog.h \
|
||||||
|
IArchMultithread.h \
|
||||||
|
IArchNetwork.h \
|
||||||
|
IArchSleep.h \
|
||||||
|
IArchString.h \
|
||||||
|
IArchTime.h \
|
||||||
|
XArch.h \
|
||||||
|
XArchImpl.h \
|
||||||
|
$(NULL)
|
||||||
|
EXTRA_libarch_a_SOURCES = \
|
||||||
|
CArchConsoleUnix.cpp \
|
||||||
|
CArchDaemonNone.cpp \
|
||||||
|
CArchDaemonUnix.cpp \
|
||||||
|
CArchFileUnix.cpp \
|
||||||
|
CArchLogUnix.cpp \
|
||||||
|
CArchMultithreadPosix.cpp \
|
||||||
|
CArchNetworkBSD.cpp \
|
||||||
|
CArchSleepUnix.cpp \
|
||||||
|
CArchStringUnix.cpp \
|
||||||
|
CArchTimeUnix.cpp \
|
||||||
|
CMultibyte.cpp \
|
||||||
|
CMultibyteOS.cpp \
|
||||||
|
CMultibyteEmu.cpp \
|
||||||
|
XArchUnix.cpp \
|
||||||
|
vsnprintf.cpp \
|
||||||
|
CArchConsoleUnix.h \
|
||||||
|
CArchDaemonNone.h \
|
||||||
|
CArchDaemonUnix.h \
|
||||||
|
CArchFileUnix.h \
|
||||||
|
CArchLogUnix.h \
|
||||||
|
CArchMultithreadPosix.h \
|
||||||
|
CArchNetworkBSD.h \
|
||||||
|
CArchSleepUnix.h \
|
||||||
|
CArchStringUnix.h \
|
||||||
|
CArchTimeUnix.h \
|
||||||
|
XArchUnix.h \
|
||||||
|
$(NULL)
|
||||||
|
INCLUDES = \
|
||||||
|
-I$(VDEPTH)/lib/common \
|
||||||
|
$(NULL)
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "XArch.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// XArch
|
||||||
|
//
|
||||||
|
|
||||||
|
std::string
|
||||||
|
XArch::what() const throw()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (m_what.empty() && m_eval != NULL) {
|
||||||
|
m_what = m_eval->eval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return m_what;
|
||||||
|
}
|
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XARCH_H
|
||||||
|
#define XARCH_H
|
||||||
|
|
||||||
|
#include "stdstring.h"
|
||||||
|
|
||||||
|
//! Generic thread exception
|
||||||
|
/*!
|
||||||
|
Exceptions derived from this class are used by the multithreading
|
||||||
|
library to perform stack unwinding when a thread terminates. These
|
||||||
|
exceptions must always be rethrown by clients when caught.
|
||||||
|
*/
|
||||||
|
class XThread { };
|
||||||
|
|
||||||
|
//! Thread exception to cancel
|
||||||
|
/*!
|
||||||
|
Thrown to cancel a thread. Clients must not throw this type, but
|
||||||
|
must rethrow it if caught (by XThreadCancel, XThread, or ...).
|
||||||
|
*/
|
||||||
|
class XThreadCancel : public XThread { };
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\def RETHROW_XTHREAD
|
||||||
|
Convenience macro to rethrow an XThread exception but ignore other
|
||||||
|
exceptions. Put this in your catch (...) handler after necessary
|
||||||
|
cleanup but before leaving or returning from the handler.
|
||||||
|
*/
|
||||||
|
#define RETHROW_XTHREAD \
|
||||||
|
try { throw; } catch (XThread&) { throw; } catch (...) { }
|
||||||
|
|
||||||
|
//! Lazy error message string evaluation
|
||||||
|
/*!
|
||||||
|
This class encapsulates platform dependent error string lookup.
|
||||||
|
Platforms subclass this type, taking an appropriate error code
|
||||||
|
type in the c'tor and overriding eval() to return the error
|
||||||
|
string for that error code.
|
||||||
|
*/
|
||||||
|
class XArchEval {
|
||||||
|
public:
|
||||||
|
XArchEval() { }
|
||||||
|
virtual ~XArchEval() { }
|
||||||
|
|
||||||
|
virtual XArchEval* clone() const throw() = 0;
|
||||||
|
|
||||||
|
virtual std::string eval() const throw() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Generic exception architecture dependent library
|
||||||
|
class XArch {
|
||||||
|
public:
|
||||||
|
XArch(XArchEval* adoptedEvaluator) : m_eval(adoptedEvaluator) { }
|
||||||
|
XArch(const std::string& msg) : m_eval(NULL), m_what(msg) { }
|
||||||
|
XArch(const XArch& e) : m_eval(e.m_eval->clone()), m_what(e.m_what) { }
|
||||||
|
~XArch() { delete m_eval; }
|
||||||
|
|
||||||
|
std::string what() const throw();
|
||||||
|
|
||||||
|
private:
|
||||||
|
XArchEval* m_eval;
|
||||||
|
mutable std::string m_what;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Macro to declare XArch derived types
|
||||||
|
#define XARCH_SUBCLASS(name_, super_) \
|
||||||
|
class name_ : public super_ { \
|
||||||
|
public: \
|
||||||
|
name_(XArchEval* adoptedEvaluator) : super_(adoptedEvaluator) { } \
|
||||||
|
name_(const std::string& msg) : super_(msg) { } \
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Generic network exception
|
||||||
|
/*!
|
||||||
|
Exceptions derived from this class are used by the networking
|
||||||
|
library to indicate various errors.
|
||||||
|
*/
|
||||||
|
XARCH_SUBCLASS(XArchNetwork, XArch);
|
||||||
|
|
||||||
|
//! Network insufficient permission
|
||||||
|
XARCH_SUBCLASS(XArchNetworkWouldBlock, XArchNetwork);
|
||||||
|
|
||||||
|
//! Network insufficient permission
|
||||||
|
XARCH_SUBCLASS(XArchNetworkAccess, XArchNetwork);
|
||||||
|
|
||||||
|
//! Network insufficient resources
|
||||||
|
XARCH_SUBCLASS(XArchNetworkResource, XArchNetwork);
|
||||||
|
|
||||||
|
//! No support for requested network resource/service
|
||||||
|
XARCH_SUBCLASS(XArchNetworkSupport, XArchNetwork);
|
||||||
|
|
||||||
|
//! Network I/O error
|
||||||
|
XARCH_SUBCLASS(XArchNetworkIO, XArchNetwork);
|
||||||
|
|
||||||
|
//! Network address is unavailable or not local
|
||||||
|
XARCH_SUBCLASS(XArchNetworkNoAddress, XArchNetwork);
|
||||||
|
|
||||||
|
//! Network address in use
|
||||||
|
XARCH_SUBCLASS(XArchNetworkAddressInUse, XArchNetwork);
|
||||||
|
|
||||||
|
//! No route to address
|
||||||
|
XARCH_SUBCLASS(XArchNetworkNoRoute, XArchNetwork);
|
||||||
|
|
||||||
|
//! Socket not connected
|
||||||
|
XARCH_SUBCLASS(XArchNetworkNotConnected, XArchNetwork);
|
||||||
|
|
||||||
|
//! Remote end of socket has disconnected
|
||||||
|
XARCH_SUBCLASS(XArchNetworkDisconnected, XArchNetwork);
|
||||||
|
|
||||||
|
//! Remote end of socket refused connection
|
||||||
|
XARCH_SUBCLASS(XArchNetworkConnectionRefused, XArchNetwork);
|
||||||
|
|
||||||
|
//! Connection is in progress
|
||||||
|
XARCH_SUBCLASS(XArchNetworkConnecting, XArchNetwork);
|
||||||
|
|
||||||
|
//! Remote end of socket is not responding
|
||||||
|
XARCH_SUBCLASS(XArchNetworkTimedOut, XArchNetwork);
|
||||||
|
|
||||||
|
//! Generic network name lookup erros
|
||||||
|
XARCH_SUBCLASS(XArchNetworkName, XArchNetwork);
|
||||||
|
|
||||||
|
//! The named host is unknown
|
||||||
|
XARCH_SUBCLASS(XArchNetworkNameUnknown, XArchNetworkName);
|
||||||
|
|
||||||
|
//! The named host is known but has to address
|
||||||
|
XARCH_SUBCLASS(XArchNetworkNameNoAddress, XArchNetworkName);
|
||||||
|
|
||||||
|
//! Non-recoverable name server error
|
||||||
|
XARCH_SUBCLASS(XArchNetworkNameFailure, XArchNetworkName);
|
||||||
|
|
||||||
|
//! Temporary name server error
|
||||||
|
XARCH_SUBCLASS(XArchNetworkNameUnavailable, XArchNetworkName);
|
||||||
|
|
||||||
|
//! Generic daemon exception
|
||||||
|
/*!
|
||||||
|
Exceptions derived from this class are used by the daemon
|
||||||
|
library to indicate various errors.
|
||||||
|
*/
|
||||||
|
XARCH_SUBCLASS(XArchDaemon, XArch);
|
||||||
|
|
||||||
|
//! Could not daemonize
|
||||||
|
XARCH_SUBCLASS(XArchDaemonFailed, XArchDaemon);
|
||||||
|
|
||||||
|
//! Could not install daemon
|
||||||
|
XARCH_SUBCLASS(XArchDaemonInstallFailed, XArchDaemon);
|
||||||
|
|
||||||
|
//! Could not uninstall daemon
|
||||||
|
XARCH_SUBCLASS(XArchDaemonUninstallFailed, XArchDaemon);
|
||||||
|
|
||||||
|
//! Attempted to uninstall a daemon that was not installed
|
||||||
|
XARCH_SUBCLASS(XArchDaemonUninstallNotInstalled, XArchDaemonUninstallFailed);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -12,18 +12,14 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
#ifndef XARCHIMPL_H
|
||||||
|
#define XARCHIMPL_H
|
||||||
|
|
||||||
|
// include appropriate architecture implementation
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
|
# include "XArchWindows.h"
|
||||||
#include "CWin32Platform.cpp"
|
|
||||||
|
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
|
# include "XArchUnix.h"
|
||||||
#include "CUnixPlatform.cpp"
|
#endif
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#error Unsupported platform
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "XArchUnix.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// XArchEvalUnix
|
||||||
|
//
|
||||||
|
|
||||||
|
XArchEval*
|
||||||
|
XArchEvalUnix::clone() const throw()
|
||||||
|
{
|
||||||
|
return new XArchEvalUnix(m_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
XArchEvalUnix::eval() const throw()
|
||||||
|
{
|
||||||
|
// FIXME -- not thread safe
|
||||||
|
return strerror(m_errno);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XARCHUNIX_H
|
||||||
|
#define XARCHUNIX_H
|
||||||
|
|
||||||
|
#include "XArch.h"
|
||||||
|
|
||||||
|
//! Lazy error message string evaluation for unix
|
||||||
|
class XArchEvalUnix : public XArchEval {
|
||||||
|
public:
|
||||||
|
XArchEvalUnix(int err) : m_errno(err) { }
|
||||||
|
virtual ~XArchEvalUnix() { }
|
||||||
|
|
||||||
|
// XArchEval overrides
|
||||||
|
virtual XArchEval* clone() const throw();
|
||||||
|
virtual std::string eval() const throw();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_errno;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "XArchWindows.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// XArchEvalWindows
|
||||||
|
//
|
||||||
|
|
||||||
|
XArchEval*
|
||||||
|
XArchEvalWindows::clone() const throw()
|
||||||
|
{
|
||||||
|
return new XArchEvalWindows(m_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
XArchEvalWindows::eval() const throw()
|
||||||
|
{
|
||||||
|
char* cmsg;
|
||||||
|
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||||
|
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||||
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||||
|
0,
|
||||||
|
m_errno,
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(LPTSTR)&cmsg,
|
||||||
|
0,
|
||||||
|
NULL) == 0) {
|
||||||
|
cmsg = NULL;
|
||||||
|
return "Unknown error";
|
||||||
|
}
|
||||||
|
std::string smsg(cmsg);
|
||||||
|
LocalFree(cmsg);
|
||||||
|
return smsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// XArchEvalWinsock
|
||||||
|
//
|
||||||
|
|
||||||
|
XArchEval*
|
||||||
|
XArchEvalWinsock::clone() const throw()
|
||||||
|
{
|
||||||
|
return new XArchEvalWinsock(m_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
XArchEvalWinsock::eval() const throw()
|
||||||
|
{
|
||||||
|
// built-in windows function for looking up error message strings
|
||||||
|
// may not look up network error messages correctly. we'll have
|
||||||
|
// to do it ourself.
|
||||||
|
static const struct { int m_code; const char* m_msg; } s_netErrorCodes[] = {
|
||||||
|
/* 10004 */{WSAEINTR, "The (blocking) call was canceled via WSACancelBlockingCall"},
|
||||||
|
/* 10009 */{WSAEBADF, "Bad file handle"},
|
||||||
|
/* 10013 */{WSAEACCES, "The requested address is a broadcast address, but the appropriate flag was not set"},
|
||||||
|
/* 10014 */{WSAEFAULT, "WSAEFAULT"},
|
||||||
|
/* 10022 */{WSAEINVAL, "WSAEINVAL"},
|
||||||
|
/* 10024 */{WSAEMFILE, "No more file descriptors available"},
|
||||||
|
/* 10035 */{WSAEWOULDBLOCK, "Socket is marked as non-blocking and no connections are present or the receive operation would block"},
|
||||||
|
/* 10036 */{WSAEINPROGRESS, "A blocking Windows Sockets operation is in progress"},
|
||||||
|
/* 10037 */{WSAEALREADY, "The asynchronous routine being canceled has already completed"},
|
||||||
|
/* 10038 */{WSAENOTSOCK, "At least on descriptor is not a socket"},
|
||||||
|
/* 10039 */{WSAEDESTADDRREQ, "A destination address is required"},
|
||||||
|
/* 10040 */{WSAEMSGSIZE, "The datagram was too large to fit into the specified buffer and was truncated"},
|
||||||
|
/* 10041 */{WSAEPROTOTYPE, "The specified protocol is the wrong type for this socket"},
|
||||||
|
/* 10042 */{WSAENOPROTOOPT, "The option is unknown or unsupported"},
|
||||||
|
/* 10043 */{WSAEPROTONOSUPPORT,"The specified protocol is not supported"},
|
||||||
|
/* 10044 */{WSAESOCKTNOSUPPORT,"The specified socket type is not supported by this address family"},
|
||||||
|
/* 10045 */{WSAEOPNOTSUPP, "The referenced socket is not a type that supports that operation"},
|
||||||
|
/* 10046 */{WSAEPFNOSUPPORT, "BSD: Protocol family not supported"},
|
||||||
|
/* 10047 */{WSAEAFNOSUPPORT, "The specified address family is not supported"},
|
||||||
|
/* 10048 */{WSAEADDRINUSE, "The specified address is already in use"},
|
||||||
|
/* 10049 */{WSAEADDRNOTAVAIL, "The specified address is not available from the local machine"},
|
||||||
|
/* 10050 */{WSAENETDOWN, "The Windows Sockets implementation has detected that the network subsystem has failed"},
|
||||||
|
/* 10051 */{WSAENETUNREACH, "The network can't be reached from this hos at this time"},
|
||||||
|
/* 10052 */{WSAENETRESET, "The connection must be reset because the Windows Sockets implementation dropped it"},
|
||||||
|
/* 10053 */{WSAECONNABORTED, "The virtual circuit was aborted due to timeout or other failure"},
|
||||||
|
/* 10054 */{WSAECONNRESET, "The virtual circuit was reset by the remote side"},
|
||||||
|
/* 10055 */{WSAENOBUFS, "No buffer space is available or a buffer deadlock has occured. The socket cannot be created"},
|
||||||
|
/* 10056 */{WSAEISCONN, "The socket is already connected"},
|
||||||
|
/* 10057 */{WSAENOTCONN, "The socket is not connected"},
|
||||||
|
/* 10058 */{WSAESHUTDOWN, "The socket has been shutdown"},
|
||||||
|
/* 10059 */{WSAETOOMANYREFS, "BSD: Too many references"},
|
||||||
|
/* 10060 */{WSAETIMEDOUT, "Attempt to connect timed out without establishing a connection"},
|
||||||
|
/* 10061 */{WSAECONNREFUSED, "The attempt to connect was forcefully rejected"},
|
||||||
|
/* 10062 */{WSAELOOP, "Undocumented WinSock error code used in BSD"},
|
||||||
|
/* 10063 */{WSAENAMETOOLONG, "Undocumented WinSock error code used in BSD"},
|
||||||
|
/* 10064 */{WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"},
|
||||||
|
/* 10065 */{WSAEHOSTUNREACH, "No route to host"},
|
||||||
|
/* 10066 */{WSAENOTEMPTY, "Undocumented WinSock error code"},
|
||||||
|
/* 10067 */{WSAEPROCLIM, "Undocumented WinSock error code"},
|
||||||
|
/* 10068 */{WSAEUSERS, "Undocumented WinSock error code"},
|
||||||
|
/* 10069 */{WSAEDQUOT, "Undocumented WinSock error code"},
|
||||||
|
/* 10070 */{WSAESTALE, "Undocumented WinSock error code"},
|
||||||
|
/* 10071 */{WSAEREMOTE, "Undocumented WinSock error code"},
|
||||||
|
/* 10091 */{WSASYSNOTREADY, "Underlying network subsytem is not ready for network communication"},
|
||||||
|
/* 10092 */{WSAVERNOTSUPPORTED, "The version of WinSock API support requested is not provided in this implementation"},
|
||||||
|
/* 10093 */{WSANOTINITIALISED, "WinSock subsystem not properly initialized"},
|
||||||
|
/* 10101 */{WSAEDISCON, "Virtual circuit has gracefully terminated connection"},
|
||||||
|
/* 11001 */{WSAHOST_NOT_FOUND, "The specified host is unknown"},
|
||||||
|
/* 11002 */{WSATRY_AGAIN, "A temporary error occurred on an authoritative name server"},
|
||||||
|
/* 11003 */{WSANO_RECOVERY, "A non-recoverable name server error occurred"},
|
||||||
|
/* 11004 */{WSANO_DATA, "The requested name is valid but does not have an IP address"},
|
||||||
|
/* end */{0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (unsigned int i = 0; s_netErrorCodes[i].m_code != 0; ++i) {
|
||||||
|
if (s_netErrorCodes[i].m_code == m_errno) {
|
||||||
|
return s_netErrorCodes[i].m_msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "Unknown error";
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XARCHWINDOWS_H
|
||||||
|
#define XARCHWINDOWS_H
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include "XArch.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
//! Lazy error message string evaluation for windows
|
||||||
|
class XArchEvalWindows : public XArchEval {
|
||||||
|
public:
|
||||||
|
XArchEvalWindows() : m_errno(GetLastError()) { }
|
||||||
|
XArchEvalWindows(DWORD err) : m_errno(err) { }
|
||||||
|
virtual ~XArchEvalWindows() { }
|
||||||
|
|
||||||
|
// XArchEval overrides
|
||||||
|
virtual XArchEval* clone() const throw();
|
||||||
|
virtual std::string eval() const throw();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DWORD m_errno;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Lazy error message string evaluation for winsock
|
||||||
|
class XArchEvalWinsock : public XArchEval {
|
||||||
|
public:
|
||||||
|
XArchEvalWinsock(int err) : m_errno(err) { }
|
||||||
|
virtual ~XArchEvalWinsock() { }
|
||||||
|
|
||||||
|
// XArchEval overrides
|
||||||
|
virtual XArchEval* clone() const throw();
|
||||||
|
virtual std::string eval() const throw();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_errno;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,269 @@
|
||||||
|
# Microsoft Developer Studio Project File - Name="arch" - Package Owner=<4>
|
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||||
|
# ** DO NOT EDIT **
|
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||||
|
|
||||||
|
CFG=arch - Win32 Debug
|
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||||
|
!MESSAGE use the Export Makefile command and run
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "arch.mak".
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE You can specify a configuration when running NMAKE
|
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "arch.mak" CFG="arch - Win32 Debug"
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE Possible choices for configuration are:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE "arch - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||||
|
!MESSAGE "arch - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||||
|
!MESSAGE
|
||||||
|
|
||||||
|
# Begin Project
|
||||||
|
# PROP AllowPerConfigDependencies 0
|
||||||
|
# PROP Scc_ProjName ""
|
||||||
|
# PROP Scc_LocalPath ""
|
||||||
|
CPP=cl.exe
|
||||||
|
RSC=rc.exe
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "arch - Win32 Release"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 0
|
||||||
|
# PROP BASE Output_Dir "Release"
|
||||||
|
# PROP BASE Intermediate_Dir "Release"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 0
|
||||||
|
# PROP Output_Dir "Release"
|
||||||
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||||
|
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
|
||||||
|
# SUBTRACT CPP /YX
|
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LIB32=link.exe -lib
|
||||||
|
# ADD BASE LIB32 /nologo
|
||||||
|
# ADD LIB32 /nologo
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "arch - Win32 Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "Debug"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "Debug"
|
||||||
|
# PROP Intermediate_Dir "Debug"
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\base" /I "..\mt" /I "..\common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
|
||||||
|
# SUBTRACT CPP /YX
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LIB32=link.exe -lib
|
||||||
|
# ADD BASE LIB32 /nologo
|
||||||
|
# ADD LIB32 /nologo
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# Begin Target
|
||||||
|
|
||||||
|
# Name "arch - Win32 Release"
|
||||||
|
# Name "arch - Win32 Debug"
|
||||||
|
# Begin Group "Source Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArch.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchImpl.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\XArch.cpp
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArch.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchConsoleWindows.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchDaemonWindows.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchImpl.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchLogWindows.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchMiscWindows.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchMultithreadWindows.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchNetworkWinsock.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchSleepWindows.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchStringWindows.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchTimeWindows.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\IArchConsole.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\IArchLog.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\IArchMultithread.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\IArchNetwork.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\IArchSleep.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\IArchString.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\IArchTime.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\XArch.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\XArchImpl.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\XArchWindows.h
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Included Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "inc"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchConsoleWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchDaemonWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchFileWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchLogWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchMiscWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchMultithreadWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchNetworkWinsock.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchSleepWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchStringWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchTimeWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMultibyte.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMultibyteEmu.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMultibyteOS.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\vsnprintf.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\XArchWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# End Target
|
||||||
|
# End Project
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if HAVE_VSNPRINTF
|
||||||
|
|
||||||
|
#if !defined(ARCH_VSNPRINTF)
|
||||||
|
# define ARCH_VSNPRINTF vsnprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
ARCH_STRING::vsnprintf(char* str, int size, const char* fmt, va_list ap)
|
||||||
|
{
|
||||||
|
int n = ::ARCH_VSNPRINTF(str, size, fmt, ap);
|
||||||
|
if (n > size) {
|
||||||
|
n = -1;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !HAVE_VSNPRINTF
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
#error vsnprintf not implemented
|
||||||
|
|
||||||
|
#endif // !HAVE_VSNPRINTF
|
|
@ -14,15 +14,13 @@
|
||||||
|
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
|
#include "CStringUtil.h"
|
||||||
|
#include "LogOutputters.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "Version.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// names of priorities
|
// names of priorities
|
||||||
static const char* g_priority[] = {
|
static const char* g_priority[] = {
|
||||||
"FATAL",
|
"FATAL",
|
||||||
|
@ -56,26 +54,64 @@ static const int g_prioritySuffixLength = 2;
|
||||||
static const int g_priorityPad = g_maxPriorityLength +
|
static const int g_priorityPad = g_maxPriorityLength +
|
||||||
g_prioritySuffixLength;
|
g_prioritySuffixLength;
|
||||||
|
|
||||||
// platform newline sequence
|
//
|
||||||
#if WINDOWS_LIKE
|
// CLogLock
|
||||||
static const char* g_newline = "\r\n";
|
//
|
||||||
#else
|
// Convenience object to lock/unlock a mutex.
|
||||||
static const char* g_newline = "\n";
|
//
|
||||||
#endif
|
|
||||||
|
class CLogLock {
|
||||||
|
public:
|
||||||
|
CLogLock(CArchMutex mutex) : m_mutex(mutex) { ARCH->lockMutex(m_mutex); }
|
||||||
|
~CLogLock() { ARCH->unlockMutex(m_mutex); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
CArchMutex m_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
// minimum length of a newline sequence
|
|
||||||
static const int g_newlineLength = 2;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CLog
|
// CLog
|
||||||
//
|
//
|
||||||
|
|
||||||
CLog::Outputter CLog::s_outputter = NULL;
|
CLog* CLog::s_log = NULL;
|
||||||
CLog::Lock CLog::s_lock = &CLog::dummyLock;
|
|
||||||
int CLog::s_maxPriority = -1;
|
CLog::CLog()
|
||||||
|
{
|
||||||
|
assert(s_log == NULL);
|
||||||
|
|
||||||
|
// create mutex for multithread safe operation
|
||||||
|
m_mutex = ARCH->newMutex();
|
||||||
|
|
||||||
|
// other initalization
|
||||||
|
m_maxPriority = g_defaultMaxPriority;
|
||||||
|
m_maxNewlineLength = 0;
|
||||||
|
insert(new CConsoleLogOutputter);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLog::~CLog()
|
||||||
|
{
|
||||||
|
// clean up
|
||||||
|
for (COutputterList::iterator index = m_outputters.begin();
|
||||||
|
index != m_outputters.end(); ++index) {
|
||||||
|
delete *index;
|
||||||
|
}
|
||||||
|
ARCH->closeMutex(m_mutex);
|
||||||
|
s_log = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLog*
|
||||||
|
CLog::getInstance()
|
||||||
|
{
|
||||||
|
// note -- not thread safe; client must initialize log safely
|
||||||
|
if (s_log == NULL) {
|
||||||
|
s_log = new CLog;
|
||||||
|
}
|
||||||
|
return s_log;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CLog::print(const char* fmt, ...)
|
CLog::print(const char* fmt, ...) const
|
||||||
{
|
{
|
||||||
// check if fmt begins with a priority argument
|
// check if fmt begins with a priority argument
|
||||||
int priority = 4;
|
int priority = 4;
|
||||||
|
@ -85,7 +121,7 @@ CLog::print(const char* fmt, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// done if below priority threshold
|
// done if below priority threshold
|
||||||
if (priority > getMaxPriority()) {
|
if (priority > getFilter()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +134,7 @@ CLog::print(const char* fmt, ...)
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
char* buffer = CStringUtil::vsprint(stack,
|
char* buffer = CStringUtil::vsprint(stack,
|
||||||
sizeof(stack) / sizeof(stack[0]),
|
sizeof(stack) / sizeof(stack[0]),
|
||||||
pad, g_newlineLength, fmt, args);
|
pad, m_maxNewlineLength, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
// output buffer
|
// output buffer
|
||||||
|
@ -110,7 +146,7 @@ CLog::print(const char* fmt, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CLog::printt(const char* file, int line, const char* fmt, ...)
|
CLog::printt(const char* file, int line, const char* fmt, ...) const
|
||||||
{
|
{
|
||||||
// check if fmt begins with a priority argument
|
// check if fmt begins with a priority argument
|
||||||
int priority = 4;
|
int priority = 4;
|
||||||
|
@ -120,7 +156,7 @@ CLog::printt(const char* file, int line, const char* fmt, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// done if below priority threshold
|
// done if below priority threshold
|
||||||
if (priority > getMaxPriority()) {
|
if (priority > getFilter()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +172,7 @@ CLog::printt(const char* file, int line, const char* fmt, ...)
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
char* buffer = CStringUtil::vsprint(stack,
|
char* buffer = CStringUtil::vsprint(stack,
|
||||||
sizeof(stack) / sizeof(stack[0]),
|
sizeof(stack) / sizeof(stack[0]),
|
||||||
pad, g_newlineLength, fmt, args);
|
pad, m_maxNewlineLength, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
// print the prefix to the buffer. leave space for priority label.
|
// print the prefix to the buffer. leave space for priority label.
|
||||||
|
@ -158,31 +194,34 @@ CLog::printt(const char* file, int line, const char* fmt, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CLog::setOutputter(Outputter outputter)
|
CLog::insert(ILogOutputter* outputter)
|
||||||
{
|
{
|
||||||
CHoldLock lock(s_lock);
|
assert(outputter != NULL);
|
||||||
s_outputter = outputter;
|
assert(outputter->getNewline() != NULL);
|
||||||
}
|
|
||||||
|
|
||||||
CLog::Outputter
|
CLogLock lock(m_mutex);
|
||||||
CLog::getOutputter()
|
m_outputters.push_front(outputter);
|
||||||
{
|
int newlineLength = strlen(outputter->getNewline());
|
||||||
CHoldLock lock(s_lock);
|
if (newlineLength > m_maxNewlineLength) {
|
||||||
return s_outputter;
|
m_maxNewlineLength = newlineLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CLog::setLock(Lock newLock)
|
CLog::remove(ILogOutputter* outputter)
|
||||||
{
|
{
|
||||||
CHoldLock lock(s_lock);
|
CLogLock lock(m_mutex);
|
||||||
s_lock = (newLock == NULL) ? dummyLock : newLock;
|
m_outputters.remove(outputter);
|
||||||
}
|
}
|
||||||
|
|
||||||
CLog::Lock
|
void
|
||||||
CLog::getLock()
|
CLog::pop_front()
|
||||||
{
|
{
|
||||||
CHoldLock lock(s_lock);
|
CLogLock lock(m_mutex);
|
||||||
return (s_lock == dummyLock) ? NULL : s_lock;
|
if (!m_outputters.empty()) {
|
||||||
|
delete m_outputters.front();
|
||||||
|
m_outputters.pop_front();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -203,38 +242,19 @@ CLog::setFilter(const char* maxPriority)
|
||||||
void
|
void
|
||||||
CLog::setFilter(int maxPriority)
|
CLog::setFilter(int maxPriority)
|
||||||
{
|
{
|
||||||
CHoldLock lock(s_lock);
|
CLogLock lock(m_mutex);
|
||||||
s_maxPriority = maxPriority;
|
m_maxPriority = maxPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
CLog::getFilter()
|
CLog::getFilter() const
|
||||||
{
|
{
|
||||||
CHoldLock lock(s_lock);
|
CLogLock lock(m_mutex);
|
||||||
return getMaxPriority();
|
return m_maxPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CLog::dummyLock(bool)
|
CLog::output(int priority, char* msg) const
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
CLog::getMaxPriority()
|
|
||||||
{
|
|
||||||
CHoldLock lock(s_lock);
|
|
||||||
|
|
||||||
if (s_maxPriority == -1) {
|
|
||||||
s_maxPriority = g_defaultMaxPriority;
|
|
||||||
setFilter(getenv("SYN_LOG_PRI"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return s_maxPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CLog::output(int priority, char* msg)
|
|
||||||
{
|
{
|
||||||
assert(priority >= -1 && priority < g_numPriority);
|
assert(priority >= -1 && priority < g_numPriority);
|
||||||
assert(msg != NULL);
|
assert(msg != NULL);
|
||||||
|
@ -249,79 +269,23 @@ CLog::output(int priority, char* msg)
|
||||||
msg[g_maxPriorityLength + 1] = ' ';
|
msg[g_maxPriorityLength + 1] = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
// put a newline at the end
|
// write to each outputter
|
||||||
strcat(msg + g_priorityPad, g_newline);
|
CLogLock lock(m_mutex);
|
||||||
|
for (COutputterList::const_iterator index = m_outputters.begin();
|
||||||
|
index != m_outputters.end(); ++index) {
|
||||||
|
// get outputter
|
||||||
|
ILogOutputter* outputter = *index;
|
||||||
|
|
||||||
// print it
|
// put an appropriate newline at the end
|
||||||
CHoldLock lock(s_lock);
|
strcat(msg + g_priorityPad, outputter->getNewline());
|
||||||
if (s_outputter == NULL ||
|
|
||||||
!s_outputter(priority, msg + g_maxPriorityLength - n)) {
|
// open the outputter
|
||||||
#if WINDOWS_LIKE
|
outputter->open(kApplication);
|
||||||
openConsole();
|
|
||||||
#endif
|
// write message and break out of loop if it returns false
|
||||||
fprintf(stderr, "%s", msg + g_maxPriorityLength - n);
|
if (!outputter->write(static_cast<ILogOutputter::ELevel>(priority),
|
||||||
|
msg + g_maxPriorityLength - n)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
|
||||||
|
|
||||||
static DWORD s_thread = 0;
|
|
||||||
|
|
||||||
static
|
|
||||||
BOOL WINAPI
|
|
||||||
CLogSignalHandler(DWORD)
|
|
||||||
{
|
|
||||||
// terminate cleanly and skip remaining handlers
|
|
||||||
PostThreadMessage(s_thread, WM_QUIT, 0, 0);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CLog::openConsole()
|
|
||||||
{
|
|
||||||
static bool s_hasConsole = false;
|
|
||||||
|
|
||||||
// ignore if already created
|
|
||||||
if (s_hasConsole)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// remember the current thread. when we get a ctrl+break or the
|
|
||||||
// console is closed we'll post WM_QUIT to this thread to shutdown
|
|
||||||
// cleanly.
|
|
||||||
// note -- win95/98/me are broken and will not receive a signal
|
|
||||||
// when the console is closed nor during logoff or shutdown,
|
|
||||||
// see microsoft articles Q130717 and Q134284. we could work
|
|
||||||
// around this in a painful way using hooks and hidden windows
|
|
||||||
// (as apache does) but it's not worth it. the app will still
|
|
||||||
// quit, just not cleanly. users in-the-know can use ctrl+c.
|
|
||||||
s_thread = GetCurrentThreadId();
|
|
||||||
|
|
||||||
// open a console
|
|
||||||
if (!AllocConsole())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// get the handle for error output
|
|
||||||
HANDLE herr = GetStdHandle(STD_ERROR_HANDLE);
|
|
||||||
|
|
||||||
// prep console. windows 95 and its ilk have braindead
|
|
||||||
// consoles that can't even resize independently of the
|
|
||||||
// buffer size. use a 25 line buffer for those systems.
|
|
||||||
OSVERSIONINFO osInfo;
|
|
||||||
COORD size = { 80, 1000 };
|
|
||||||
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
|
|
||||||
if (GetVersionEx(&osInfo) &&
|
|
||||||
osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
|
||||||
size.Y = 25;
|
|
||||||
SetConsoleScreenBufferSize(herr, size);
|
|
||||||
SetConsoleTextAttribute(herr,
|
|
||||||
FOREGROUND_RED |
|
|
||||||
FOREGROUND_GREEN |
|
|
||||||
FOREGROUND_BLUE);
|
|
||||||
SetConsoleCtrlHandler(CLogSignalHandler, TRUE);
|
|
||||||
|
|
||||||
// reopen stderr to point at console
|
|
||||||
freopen("con", "w", stderr);
|
|
||||||
s_hasConsole = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
132
lib/base/CLog.h
132
lib/base/CLog.h
|
@ -16,8 +16,15 @@
|
||||||
#define CLOG_H
|
#define CLOG_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
#include "IInterface.h"
|
||||||
|
#include "stdlist.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define CLOG (CLog::getInstance())
|
||||||
|
|
||||||
|
class ILogOutputter;
|
||||||
|
|
||||||
//! Logging facility
|
//! Logging facility
|
||||||
/*!
|
/*!
|
||||||
The logging class; all console output should go through this class.
|
The logging class; all console output should go through this class.
|
||||||
|
@ -42,56 +49,51 @@ public:
|
||||||
kDEBUG2 //!< For even more detailed debugging messages
|
kDEBUG2 //!< For even more detailed debugging messages
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Outputter function.
|
~CLog();
|
||||||
/*!
|
|
||||||
Type of outputter function. The outputter should write \c message,
|
|
||||||
which has the given \c priority, to a log and return true. Or it can
|
|
||||||
return false to let CLog use the default outputter.
|
|
||||||
*/
|
|
||||||
typedef bool (*Outputter)(int priority, const char* message);
|
|
||||||
|
|
||||||
//! Locking function
|
|
||||||
/*!
|
|
||||||
Type of lock/unlock function. If \c lock is true then block other
|
|
||||||
threads that try to lock until this thread unlocks. If \c lock is
|
|
||||||
false then unlock and allow another (waiting) thread to lock.
|
|
||||||
*/
|
|
||||||
typedef void (*Lock)(bool lock);
|
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Set the function used to write the log
|
//! Add an outputter to the head of the list
|
||||||
/*!
|
/*!
|
||||||
Sets the function used to write to the log. The outputter function
|
Inserts an outputter to the head of the outputter list. When the
|
||||||
is called with the formatted string to write and the priority level.
|
logger writes a message, it goes to the outputter at the head of
|
||||||
CLog will have already filtered messages below the current filter
|
the outputter list. If that outputter's \c write() method returns
|
||||||
priority. A NULL outputter means to use the default which is to print
|
true then it also goes to the next outputter, as so on until an
|
||||||
to stderr. Note that the outputter should not call CLog methods but,
|
outputter returns false or there are no more outputters. Outputters
|
||||||
if it does, the current lock function must permit recursive locks.
|
still in the outputter list when the log is destroyed will be
|
||||||
*/
|
deleted.
|
||||||
static void setOutputter(Outputter);
|
|
||||||
|
|
||||||
//! Set the lock/unlock function
|
By default, the logger has one outputter installed which writes to
|
||||||
/*!
|
the console.
|
||||||
Set the lock/unlock function. Use setLock(NULL) to remove the
|
|
||||||
locking function. There is no default lock function; do not call
|
|
||||||
CLog from multiple threads unless a working lock function has been
|
|
||||||
installed.
|
|
||||||
*/
|
*/
|
||||||
static void setLock(Lock);
|
void insert(ILogOutputter* adopted);
|
||||||
|
|
||||||
|
//! Remove an outputter from the list
|
||||||
|
/*!
|
||||||
|
Removes the first occurrence of the given outputter from the
|
||||||
|
outputter list. It does nothing if the outputter is not in the
|
||||||
|
list. The outputter is not deleted.
|
||||||
|
*/
|
||||||
|
void remove(ILogOutputter* orphaned);
|
||||||
|
|
||||||
|
//! Remove the outputter from the head of the list
|
||||||
|
/*!
|
||||||
|
Removes and deletes the outputter at the head of the outputter list.
|
||||||
|
This does nothing if the outputter list is empty.
|
||||||
|
*/
|
||||||
|
void pop_front();
|
||||||
|
|
||||||
//! Set the minimum priority filter.
|
//! Set the minimum priority filter.
|
||||||
/*!
|
/*!
|
||||||
Set the filter. Messages below this priority are discarded.
|
Set the filter. Messages below this priority are discarded.
|
||||||
The default priority is 4 (INFO) (unless built without NDEBUG
|
The default priority is 4 (INFO) (unless built without NDEBUG
|
||||||
in which case it's 5 (DEBUG)). The default can be overridden
|
in which case it's 5 (DEBUG)). setFilter(const char*) returns
|
||||||
by setting the SYN_LOG_PRI env var to "FATAL", "ERROR", etc.
|
true if the priority \c name was recognized; if \c name is NULL
|
||||||
setFilter(const char*) returns true if the priority \c name was
|
then it simply returns true.
|
||||||
recognized; if \c name is NULL then it simply returns true.
|
|
||||||
*/
|
*/
|
||||||
static bool setFilter(const char* name);
|
bool setFilter(const char* name);
|
||||||
static void setFilter(int);
|
void setFilter(int);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
|
@ -101,52 +103,38 @@ public:
|
||||||
/*!
|
/*!
|
||||||
Print a log message using the printf-like \c format and arguments.
|
Print a log message using the printf-like \c format and arguments.
|
||||||
*/
|
*/
|
||||||
static void print(const char* format, ...);
|
void print(const char* format, ...) const;
|
||||||
|
|
||||||
//! Print a log message
|
//! Print a log message
|
||||||
/*!
|
/*!
|
||||||
Print a log message using the printf-like \c format and arguments
|
Print a log message using the printf-like \c format and arguments
|
||||||
preceded by the filename and line number.
|
preceded by the filename and line number.
|
||||||
*/
|
*/
|
||||||
static void printt(const char* file, int line,
|
void printt(const char* file, int line,
|
||||||
const char* format, ...);
|
const char* format, ...) const;
|
||||||
|
|
||||||
//! Get the function used to write the log
|
|
||||||
static Outputter getOutputter();
|
|
||||||
|
|
||||||
//! Get the lock/unlock function
|
|
||||||
/*!
|
|
||||||
Get the lock/unlock function. Note that the lock function is
|
|
||||||
used when retrieving the lock function.
|
|
||||||
*/
|
|
||||||
static Lock getLock();
|
|
||||||
|
|
||||||
//! Get the minimum priority level.
|
//! Get the minimum priority level.
|
||||||
static int getFilter();
|
int getFilter() const;
|
||||||
|
|
||||||
|
//! Get the singleton instance of the log
|
||||||
|
static CLog* getInstance();
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class CHoldLock {
|
CLog();
|
||||||
public:
|
|
||||||
CHoldLock(Lock lock) : m_lock(lock) { m_lock(true); }
|
|
||||||
~CHoldLock() { m_lock(false); }
|
|
||||||
|
|
||||||
private:
|
void output(int priority, char* msg) const;
|
||||||
Lock m_lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void dummyLock(bool);
|
|
||||||
static int getMaxPriority();
|
|
||||||
static void output(int priority, char* msg);
|
|
||||||
#if WINDOWS_LIKE
|
|
||||||
static void openConsole();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Outputter s_outputter;
|
typedef std::list<ILogOutputter*> COutputterList;
|
||||||
static Lock s_lock;
|
|
||||||
static int s_maxPriority;
|
static CLog* s_log;
|
||||||
|
|
||||||
|
CArchMutex m_mutex;
|
||||||
|
COutputterList m_outputters;
|
||||||
|
int m_maxNewlineLength;
|
||||||
|
int m_maxPriority;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -193,12 +181,12 @@ which includes the filename and line number.
|
||||||
#define LOGC(_a1, _a2)
|
#define LOGC(_a1, _a2)
|
||||||
#define CLOG_TRACE
|
#define CLOG_TRACE
|
||||||
#elif defined(NDEBUG)
|
#elif defined(NDEBUG)
|
||||||
#define LOG(_a1) CLog::print _a1
|
#define LOG(_a1) CLOG->print _a1
|
||||||
#define LOGC(_a1, _a2) if (_a1) CLog::print _a2
|
#define LOGC(_a1, _a2) if (_a1) CLOG->print _a2
|
||||||
#define CLOG_TRACE
|
#define CLOG_TRACE
|
||||||
#else
|
#else
|
||||||
#define LOG(_a1) CLog::printt _a1
|
#define LOG(_a1) CLOG->printt _a1
|
||||||
#define LOGC(_a1, _a2) if (_a1) CLog::printt _a2
|
#define LOGC(_a1, _a2) if (_a1) CLOG->printt _a2
|
||||||
#define CLOG_TRACE __FILE__, __LINE__,
|
#define CLOG_TRACE __FILE__, __LINE__,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CStopwatch.h"
|
#include "CStopwatch.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// CStopwatch
|
// CStopwatch
|
||||||
|
@ -24,7 +25,7 @@ CStopwatch::CStopwatch(bool triggered) :
|
||||||
m_stopped(triggered)
|
m_stopped(triggered)
|
||||||
{
|
{
|
||||||
if (!triggered) {
|
if (!triggered) {
|
||||||
m_mark = getClock();
|
m_mark = ARCH->time();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ CStopwatch::reset()
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const double t = getClock();
|
const double t = ARCH->time();
|
||||||
const double dt = t - m_mark;
|
const double dt = t - m_mark;
|
||||||
m_mark = t;
|
m_mark = t;
|
||||||
return dt;
|
return dt;
|
||||||
|
@ -57,7 +58,7 @@ CStopwatch::stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the elapsed time
|
// save the elapsed time
|
||||||
m_mark = getClock() - m_mark;
|
m_mark = ARCH->time() - m_mark;
|
||||||
m_stopped = true;
|
m_stopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ CStopwatch::start()
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the mark such that it reports the time elapsed at stop()
|
// set the mark such that it reports the time elapsed at stop()
|
||||||
m_mark = getClock() - m_mark;
|
m_mark = ARCH->time() - m_mark;
|
||||||
m_stopped = false;
|
m_stopped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +94,7 @@ CStopwatch::getTime()
|
||||||
return m_mark;
|
return m_mark;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return getClock() - m_mark;
|
return ARCH->time() - m_mark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +116,7 @@ CStopwatch::getTime() const
|
||||||
return m_mark;
|
return m_mark;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return getClock() - m_mark;
|
return ARCH->time() - m_mark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,100 +124,3 @@ CStopwatch::operator double() const
|
||||||
{
|
{
|
||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
|
||||||
|
|
||||||
// avoid getting a lot a crap from mmsystem.h that we don't need
|
|
||||||
#define MMNODRV // Installable driver support
|
|
||||||
#define MMNOSOUND // Sound support
|
|
||||||
#define MMNOWAVE // Waveform support
|
|
||||||
#define MMNOMIDI // MIDI support
|
|
||||||
#define MMNOAUX // Auxiliary audio support
|
|
||||||
#define MMNOMIXER // Mixer support
|
|
||||||
#define MMNOJOY // Joystick support
|
|
||||||
#define MMNOMCI // MCI support
|
|
||||||
#define MMNOMMIO // Multimedia file I/O support
|
|
||||||
#define MMNOMMSYSTEM // General MMSYSTEM functions
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
#include <mmsystem.h>
|
|
||||||
|
|
||||||
typedef WINMMAPI DWORD (WINAPI *PTimeGetTime)(void);
|
|
||||||
|
|
||||||
static double s_freq = 0.0;
|
|
||||||
static HINSTANCE s_mmInstance = NULL;
|
|
||||||
static PTimeGetTime s_tgt = NULL;
|
|
||||||
|
|
||||||
//
|
|
||||||
// initialize local variables
|
|
||||||
//
|
|
||||||
|
|
||||||
class CStopwatchInit {
|
|
||||||
public:
|
|
||||||
CStopwatchInit();
|
|
||||||
~CStopwatchInit();
|
|
||||||
};
|
|
||||||
static CStopwatchInit s_init;
|
|
||||||
|
|
||||||
CStopwatchInit::CStopwatchInit()
|
|
||||||
{
|
|
||||||
LARGE_INTEGER freq;
|
|
||||||
if (QueryPerformanceFrequency(&freq) && freq.QuadPart != 0) {
|
|
||||||
s_freq = 1.0 / static_cast<double>(freq.QuadPart);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// load winmm.dll and get timeGetTime
|
|
||||||
s_mmInstance = LoadLibrary("winmm");
|
|
||||||
if (s_mmInstance) {
|
|
||||||
s_tgt = (PTimeGetTime)GetProcAddress(s_mmInstance, "timeGetTime");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CStopwatchInit::~CStopwatchInit()
|
|
||||||
{
|
|
||||||
if (s_mmInstance) {
|
|
||||||
FreeLibrary(reinterpret_cast<HMODULE>(s_mmInstance));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
CStopwatch::getClock() const
|
|
||||||
{
|
|
||||||
// get time. we try three ways, in order of descending precision
|
|
||||||
if (s_freq != 0.0) {
|
|
||||||
LARGE_INTEGER c;
|
|
||||||
QueryPerformanceCounter(&c);
|
|
||||||
return s_freq * static_cast<double>(c.QuadPart);
|
|
||||||
}
|
|
||||||
else if (s_tgt) {
|
|
||||||
return 0.001 * static_cast<double>(s_tgt());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 0.001 * static_cast<double>(GetTickCount());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif UNIX_LIKE
|
|
||||||
|
|
||||||
#if TIME_WITH_SYS_TIME
|
|
||||||
# include <sys/time.h>
|
|
||||||
# include <time.h>
|
|
||||||
#else
|
|
||||||
# if HAVE_SYS_TIME_H
|
|
||||||
# include <sys/time.h>
|
|
||||||
# else
|
|
||||||
# include <time.h>
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
double
|
|
||||||
CStopwatch::getClock() const
|
|
||||||
{
|
|
||||||
struct timeval t;
|
|
||||||
gettimeofday(&t, NULL);
|
|
||||||
return (double)t.tv_sec + 1.0e-6 * (double)t.tv_usec;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // UNIX_LIKE
|
|
||||||
|
|
|
@ -15,90 +15,10 @@
|
||||||
#ifndef CSTRING_H
|
#ifndef CSTRING_H
|
||||||
#define CSTRING_H
|
#define CSTRING_H
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include "stdstring.h"
|
||||||
#include "stdpre.h"
|
|
||||||
#include <string>
|
|
||||||
#include "stdpost.h"
|
|
||||||
|
|
||||||
// use standard C++ string class for our string class
|
// use standard C++ string class for our string class
|
||||||
typedef std::string CString;
|
typedef std::string CString;
|
||||||
|
|
||||||
//! String utilities
|
|
||||||
/*!
|
|
||||||
This class provides various functions for string manipulation.
|
|
||||||
*/
|
|
||||||
class CStringUtil {
|
|
||||||
public:
|
|
||||||
//! Format positional arguments
|
|
||||||
/*!
|
|
||||||
Format a string using positional arguments. fmt has literal
|
|
||||||
characters and conversion specifications introduced by `\%':
|
|
||||||
- \c\%\% -- literal `\%'
|
|
||||||
- \c\%{n} -- positional element n, n a positive integer, {} are literal
|
|
||||||
|
|
||||||
All arguments in the variable list are const char*. Positional
|
|
||||||
elements are indexed from 1.
|
|
||||||
*/
|
|
||||||
static CString format(const char* fmt, ...);
|
|
||||||
|
|
||||||
//! Format positional arguments
|
|
||||||
/*!
|
|
||||||
Same as format() except takes va_list.
|
|
||||||
*/
|
|
||||||
static CString vformat(const char* fmt, va_list);
|
|
||||||
|
|
||||||
//! Print a string using printf-style formatting
|
|
||||||
/*!
|
|
||||||
Equivalent to printf() except the result is returned as a CString.
|
|
||||||
*/
|
|
||||||
static CString print(const char* fmt, ...);
|
|
||||||
|
|
||||||
//! Print a string using printf-style formatting
|
|
||||||
/*!
|
|
||||||
Same as print() except takes va_list.
|
|
||||||
*/
|
|
||||||
static CString vprint(const char* fmt, va_list);
|
|
||||||
|
|
||||||
//! Print a string using printf-style formatting into a buffer
|
|
||||||
/*!
|
|
||||||
This is like print but print into a given buffer. If the resulting
|
|
||||||
string will not fit into \c buffer then a new buffer is allocated and
|
|
||||||
returned, otherwise \c buffer is returned. the caller must delete[]
|
|
||||||
the returned memory if is not \c buffer.
|
|
||||||
|
|
||||||
\c prefix and \c suffix must be >= 0. Exactly \c prefix characters and
|
|
||||||
at least \c suffix characters are available in the buffer before
|
|
||||||
and after the printed string, respectively. \c bufferLength is the
|
|
||||||
length of buffer and should not be adjusted by the caller to
|
|
||||||
account for \c prefix or \c suffix.
|
|
||||||
*/
|
|
||||||
static char* vsprint(char* buffer, int bufferLength,
|
|
||||||
int prefix, int suffix, const char* fmt, va_list);
|
|
||||||
|
|
||||||
//! Case-insensitive comparisons
|
|
||||||
/*!
|
|
||||||
This class provides case-insensitve comparison functions.
|
|
||||||
*/
|
|
||||||
class CaselessCmp {
|
|
||||||
public:
|
|
||||||
//! Same as less()
|
|
||||||
bool operator()(const CString& a, const CString& b) const;
|
|
||||||
|
|
||||||
//! Returns true iff \c a is lexicographically less than \c b
|
|
||||||
static bool less(const CString& a, const CString& b);
|
|
||||||
|
|
||||||
//! Returns true iff \c a is lexicographically equal to \c b
|
|
||||||
static bool equal(const CString& a, const CString& b);
|
|
||||||
|
|
||||||
//! Returns true iff \c a is lexicographically less than \c b
|
|
||||||
static bool cmpLess(const CString::value_type& a,
|
|
||||||
const CString::value_type& b);
|
|
||||||
|
|
||||||
//! Returns true iff \c a is lexicographically equal to \c b
|
|
||||||
static bool cmpEqual(const CString::value_type& a,
|
|
||||||
const CString::value_type& b);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CString.h"
|
#include "CStringUtil.h"
|
||||||
|
#include "CArch.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "stdvector.h"
|
#include "stdvector.h"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
@ -20,12 +21,6 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
#define vsnprintf _vsnprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CStringUtil
|
// CStringUtil
|
||||||
//
|
//
|
||||||
|
@ -152,7 +147,8 @@ CStringUtil::vsprint(char* buffer, int len,
|
||||||
// try writing to input buffer
|
// try writing to input buffer
|
||||||
int n;
|
int n;
|
||||||
if (buffer != NULL && len >= prefix + suffix) {
|
if (buffer != NULL && len >= prefix + suffix) {
|
||||||
n = vsnprintf(buffer + prefix, len - (prefix + suffix), fmt, args);
|
n = ARCH->vsnprintf(buffer + prefix,
|
||||||
|
len - (prefix + suffix), fmt, args);
|
||||||
if (n >= 0 && n <= len - (prefix + suffix))
|
if (n >= 0 && n <= len - (prefix + suffix))
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
@ -163,7 +159,8 @@ CStringUtil::vsprint(char* buffer, int len,
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
len *= 2;
|
len *= 2;
|
||||||
buffer = new char[len + (prefix + suffix)];
|
buffer = new char[len + (prefix + suffix)];
|
||||||
n = vsnprintf(buffer + prefix, len - (prefix + suffix), fmt, args);
|
n = ARCH->vsnprintf(buffer + prefix,
|
||||||
|
len - (prefix + suffix), fmt, args);
|
||||||
} while (n < 0 || n > len - (prefix + suffix));
|
} while (n < 0 || n > len - (prefix + suffix));
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CSTRINGUTIL_H
|
||||||
|
#define CSTRINGUTIL_H
|
||||||
|
|
||||||
|
#include "CString.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
//! String utilities
|
||||||
|
/*!
|
||||||
|
This class provides various functions for string manipulation.
|
||||||
|
*/
|
||||||
|
class CStringUtil {
|
||||||
|
public:
|
||||||
|
//! Format positional arguments
|
||||||
|
/*!
|
||||||
|
Format a string using positional arguments. fmt has literal
|
||||||
|
characters and conversion specifications introduced by `\%':
|
||||||
|
- \c\%\% -- literal `\%'
|
||||||
|
- \c\%{n} -- positional element n, n a positive integer, {} are literal
|
||||||
|
|
||||||
|
All arguments in the variable list are const char*. Positional
|
||||||
|
elements are indexed from 1.
|
||||||
|
*/
|
||||||
|
static CString format(const char* fmt, ...);
|
||||||
|
|
||||||
|
//! Format positional arguments
|
||||||
|
/*!
|
||||||
|
Same as format() except takes va_list.
|
||||||
|
*/
|
||||||
|
static CString vformat(const char* fmt, va_list);
|
||||||
|
|
||||||
|
//! Print a string using printf-style formatting
|
||||||
|
/*!
|
||||||
|
Equivalent to printf() except the result is returned as a CString.
|
||||||
|
*/
|
||||||
|
static CString print(const char* fmt, ...);
|
||||||
|
|
||||||
|
//! Print a string using printf-style formatting
|
||||||
|
/*!
|
||||||
|
Same as print() except takes va_list.
|
||||||
|
*/
|
||||||
|
static CString vprint(const char* fmt, va_list);
|
||||||
|
|
||||||
|
//! Print a string using printf-style formatting into a buffer
|
||||||
|
/*!
|
||||||
|
This is like print but print into a given buffer. If the resulting
|
||||||
|
string will not fit into \c buffer then a new buffer is allocated and
|
||||||
|
returned, otherwise \c buffer is returned. the caller must delete[]
|
||||||
|
the returned memory if is not \c buffer.
|
||||||
|
|
||||||
|
\c prefix and \c suffix must be >= 0. Exactly \c prefix characters and
|
||||||
|
at least \c suffix characters are available in the buffer before
|
||||||
|
and after the printed string, respectively. \c bufferLength is the
|
||||||
|
length of buffer and should not be adjusted by the caller to
|
||||||
|
account for \c prefix or \c suffix.
|
||||||
|
*/
|
||||||
|
static char* vsprint(char* buffer, int bufferLength,
|
||||||
|
int prefix, int suffix, const char* fmt, va_list);
|
||||||
|
|
||||||
|
//! Case-insensitive comparisons
|
||||||
|
/*!
|
||||||
|
This class provides case-insensitve comparison functions.
|
||||||
|
*/
|
||||||
|
class CaselessCmp {
|
||||||
|
public:
|
||||||
|
//! Same as less()
|
||||||
|
bool operator()(const CString& a, const CString& b) const;
|
||||||
|
|
||||||
|
//! Returns true iff \c a is lexicographically less than \c b
|
||||||
|
static bool less(const CString& a, const CString& b);
|
||||||
|
|
||||||
|
//! Returns true iff \c a is lexicographically equal to \c b
|
||||||
|
static bool equal(const CString& a, const CString& b);
|
||||||
|
|
||||||
|
//! Returns true iff \c a is lexicographically less than \c b
|
||||||
|
static bool cmpLess(const CString::value_type& a,
|
||||||
|
const CString::value_type& b);
|
||||||
|
|
||||||
|
//! Returns true iff \c a is lexicographically equal to \c b
|
||||||
|
static bool cmpEqual(const CString::value_type& a,
|
||||||
|
const CString::value_type& b);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CUnicode.h"
|
#include "CUnicode.h"
|
||||||
#include <limits.h>
|
#include "CArch.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -70,59 +70,6 @@ setError(bool* errors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// multibyte conversion stuff when reentrant versions not available
|
|
||||||
//
|
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
|
||||||
#define HAVE_MBSINIT 1
|
|
||||||
#define HAVE_MBRTOWC 1
|
|
||||||
#define HAVE_WCRTOMB 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !HAVE_MBSINIT
|
|
||||||
static
|
|
||||||
int
|
|
||||||
mbsinit(const mbstate_t*)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !HAVE_MBRTOWC
|
|
||||||
#include "CLock.h"
|
|
||||||
#include "CMutex.h"
|
|
||||||
|
|
||||||
static CMutex s_mbrtowcMutex;
|
|
||||||
|
|
||||||
static
|
|
||||||
size_t
|
|
||||||
mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t*)
|
|
||||||
{
|
|
||||||
CLock lock(&s_mbrtowcMutex);
|
|
||||||
int result = mbtowc(pwc, s, n);
|
|
||||||
if (result < 0)
|
|
||||||
return (size_t)-1;
|
|
||||||
else
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !HAVE_WCRTOMB
|
|
||||||
#include "CLock.h"
|
|
||||||
#include "CMutex.h"
|
|
||||||
|
|
||||||
static CMutex s_wcrtombMutex;
|
|
||||||
|
|
||||||
static
|
|
||||||
size_t
|
|
||||||
wcrtomb(char* s, wchar_t wc, mbstate_t*)
|
|
||||||
{
|
|
||||||
CLock lock(&s_wcrtombMutex);
|
|
||||||
return (size_t)wctomb(s, wc);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CUnicode
|
// CUnicode
|
||||||
|
@ -274,14 +221,12 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||||
wchar_t* tmp = UTF8ToWideChar(src, size, errors);
|
wchar_t* tmp = UTF8ToWideChar(src, size, errors);
|
||||||
|
|
||||||
// get length of multibyte string
|
// get length of multibyte string
|
||||||
char mbc[MB_LEN_MAX];
|
int mblen;
|
||||||
size_t mblen;
|
CArchMBState state = ARCH->newMBState();
|
||||||
mbstate_t state;
|
|
||||||
memset(&state, 0, sizeof(state));
|
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
UInt32 n = size;
|
UInt32 n = size;
|
||||||
for (const wchar_t* scan = tmp; n > 0; ++scan, --n) {
|
for (const wchar_t* scan = tmp; n > 0; ++scan, --n) {
|
||||||
mblen = wcrtomb(mbc, *scan, &state);
|
mblen = ARCH->convWCToMB(NULL, *scan, state);
|
||||||
if (mblen == -1) {
|
if (mblen == -1) {
|
||||||
// unconvertable character
|
// unconvertable character
|
||||||
setError(errors);
|
setError(errors);
|
||||||
|
@ -293,11 +238,11 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle nul terminator
|
// handle nul terminator
|
||||||
mblen = wcrtomb(mbc, L'\0', &state);
|
mblen = ARCH->convWCToMB(NULL, L'\0', state);
|
||||||
if (mblen != -1) {
|
if (mblen != -1) {
|
||||||
len += mblen;
|
len += mblen;
|
||||||
}
|
}
|
||||||
assert(mbsinit(&state) != 0);
|
assert(ARCH->isInitMBState(state) != 0);
|
||||||
|
|
||||||
// allocate multibyte string
|
// allocate multibyte string
|
||||||
char* mbs = new char[len];
|
char* mbs = new char[len];
|
||||||
|
@ -306,7 +251,7 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||||
char* dst = mbs;
|
char* dst = mbs;
|
||||||
n = size;
|
n = size;
|
||||||
for (const wchar_t* scan = tmp; n > 0; ++scan, --n) {
|
for (const wchar_t* scan = tmp; n > 0; ++scan, --n) {
|
||||||
mblen = wcrtomb(dst, *scan, &state);
|
mblen = ARCH->convWCToMB(dst, *scan, state);
|
||||||
if (mblen == -1) {
|
if (mblen == -1) {
|
||||||
// unconvertable character
|
// unconvertable character
|
||||||
*dst++ = '?';
|
*dst++ = '?';
|
||||||
|
@ -315,7 +260,7 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||||
dst += mblen;
|
dst += mblen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mblen = wcrtomb(dst, L'\0', &state);
|
mblen = ARCH->convWCToMB(dst, L'\0', state);
|
||||||
if (mblen != -1) {
|
if (mblen != -1) {
|
||||||
// don't include nul terminator
|
// don't include nul terminator
|
||||||
dst += mblen - 1;
|
dst += mblen - 1;
|
||||||
|
@ -325,6 +270,7 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||||
// clean up
|
// clean up
|
||||||
delete[] mbs;
|
delete[] mbs;
|
||||||
delete[] tmp;
|
delete[] tmp;
|
||||||
|
ARCH->closeMBState(state);
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
@ -382,19 +328,18 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||||
// get length of multibyte string
|
// get length of multibyte string
|
||||||
UInt32 n = src.size();
|
UInt32 n = src.size();
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
mbstate_t state;
|
CArchMBState state = ARCH->newMBState();
|
||||||
memset(&state, 0, sizeof(state));
|
|
||||||
for (const char* scan = src.c_str(); n > 0; ) {
|
for (const char* scan = src.c_str(); n > 0; ) {
|
||||||
size_t mblen = mbrtowc(NULL, scan, n, &state);
|
int mblen = ARCH->convMBToWC(NULL, scan, n, state);
|
||||||
switch (mblen) {
|
switch (mblen) {
|
||||||
case (size_t)-2:
|
case -2:
|
||||||
// incomplete last character. convert to unknown character.
|
// incomplete last character. convert to unknown character.
|
||||||
setError(errors);
|
setError(errors);
|
||||||
len += 1;
|
len += 1;
|
||||||
n = 0;
|
n = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (size_t)-1:
|
case -1:
|
||||||
// invalid character. count one unknown character and
|
// invalid character. count one unknown character and
|
||||||
// start at the next byte.
|
// start at the next byte.
|
||||||
setError(errors);
|
setError(errors);
|
||||||
|
@ -417,7 +362,7 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memset(&state, 0, sizeof(state));
|
ARCH->initMBState(state);
|
||||||
|
|
||||||
// allocate wide character string
|
// allocate wide character string
|
||||||
wchar_t* wcs = new wchar_t[len];
|
wchar_t* wcs = new wchar_t[len];
|
||||||
|
@ -426,15 +371,15 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||||
n = src.size();
|
n = src.size();
|
||||||
wchar_t* dst = wcs;
|
wchar_t* dst = wcs;
|
||||||
for (const char* scan = src.c_str(); n > 0; ++dst) {
|
for (const char* scan = src.c_str(); n > 0; ++dst) {
|
||||||
size_t mblen = mbrtowc(dst, scan, n, &state);
|
int mblen = ARCH->convMBToWC(dst, scan, n, state);
|
||||||
switch (mblen) {
|
switch (mblen) {
|
||||||
case (size_t)-2:
|
case -2:
|
||||||
// incomplete character. convert to unknown character.
|
// incomplete character. convert to unknown character.
|
||||||
*dst = (wchar_t)0xfffd;
|
*dst = (wchar_t)0xfffd;
|
||||||
n = 0;
|
n = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (size_t)-1:
|
case -1:
|
||||||
// invalid character. count one unknown character and
|
// invalid character. count one unknown character and
|
||||||
// start at the next byte.
|
// start at the next byte.
|
||||||
*dst = (wchar_t)0xfffd;
|
*dst = (wchar_t)0xfffd;
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
#include "BasicTypes.h"
|
#include "BasicTypes.h"
|
||||||
#include <cwchar>
|
|
||||||
|
|
||||||
//! Unicode utility functions
|
//! Unicode utility functions
|
||||||
/*!
|
/*!
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* 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 COPYING 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ILOGOUTPUTTER_H
|
||||||
|
#define ILOGOUTPUTTER_H
|
||||||
|
|
||||||
|
#include "CLog.h"
|
||||||
|
|
||||||
|
//! Outputter interface
|
||||||
|
/*!
|
||||||
|
Type of outputter interface. The logger performs all output through
|
||||||
|
outputters. ILogOutputter overrides must not call any log functions
|
||||||
|
directly or indirectly.
|
||||||
|
*/
|
||||||
|
class ILogOutputter : public IInterface {
|
||||||
|
public:
|
||||||
|
typedef CLog::ELevel ELevel;
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Open the outputter
|
||||||
|
/*!
|
||||||
|
Opens the outputter for writing. Calling this method on an
|
||||||
|
already open outputter must have no effect.
|
||||||
|
*/
|
||||||
|
virtual void open(const char* title) = 0;
|
||||||
|
|
||||||
|
//! Close the outputter
|
||||||
|
/*!
|
||||||
|
Close the outputter. Calling this method on an already closed
|
||||||
|
outputter must have no effect.
|
||||||
|
*/
|
||||||
|
virtual void close() = 0;
|
||||||
|
|
||||||
|
//! Write a message with level
|
||||||
|
/*!
|
||||||
|
Writes \c message, which has the given \c level, to a log.
|
||||||
|
If this method returns true then CLog will stop passing the
|
||||||
|
message to all outputters in the outputter chain, otherwise
|
||||||
|
it continues. Most implementations should return true.
|
||||||
|
*/
|
||||||
|
virtual bool write(ELevel level, const char* message) = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Returns the newline sequence for the outputter
|
||||||
|
/*!
|
||||||
|
Different outputters use different character sequences for newlines.
|
||||||
|
This method returns the appropriate newline sequence for this
|
||||||
|
outputter.
|
||||||
|
*/
|
||||||
|
virtual const char* getNewline() const = 0;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -28,29 +28,23 @@ libbase_a_SOURCES = \
|
||||||
CFunctionJob.cpp \
|
CFunctionJob.cpp \
|
||||||
CLog.cpp \
|
CLog.cpp \
|
||||||
CStopwatch.cpp \
|
CStopwatch.cpp \
|
||||||
CString.cpp \
|
CStringUtil.cpp \
|
||||||
|
CUnicode.cpp \
|
||||||
|
LogOutputters.cpp \
|
||||||
XBase.cpp \
|
XBase.cpp \
|
||||||
BasicTypes.h \
|
|
||||||
CFunctionJob.h \
|
CFunctionJob.h \
|
||||||
CLog.h \
|
CLog.h \
|
||||||
CStopwatch.h \
|
CStopwatch.h \
|
||||||
CString.h \
|
CString.h \
|
||||||
IInterface.h \
|
CStringUtil.h \
|
||||||
|
CUnicode.h \
|
||||||
IJob.h \
|
IJob.h \
|
||||||
|
ILogOutputter.h \
|
||||||
|
LogOutputters.h \
|
||||||
TMethodJob.h \
|
TMethodJob.h \
|
||||||
Version.h \
|
|
||||||
XBase.h \
|
XBase.h \
|
||||||
common.h \
|
|
||||||
stdfstream.h \
|
|
||||||
stdistream.h \
|
|
||||||
stdlist.h \
|
|
||||||
stdmap.h \
|
|
||||||
stdostream.h \
|
|
||||||
stdpost.h \
|
|
||||||
stdpre.h \
|
|
||||||
stdset.h \
|
|
||||||
stdsstream.h \
|
|
||||||
stdvector.h \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
|
-I$(VDEPTH)/lib/common \
|
||||||
|
-I$(VDEPTH)/lib/arch \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "XBase.h"
|
#include "XBase.h"
|
||||||
|
#include "CStringUtil.h"
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
|
||||||
|
@ -79,65 +80,3 @@ XBase::format(const char* /*id*/, const char* fmt, ...) const throw()
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// MXErrno
|
|
||||||
//
|
|
||||||
|
|
||||||
MXErrno::MXErrno() :
|
|
||||||
#if WINDOWS_LIKE
|
|
||||||
m_errno(GetLastError()),
|
|
||||||
#else
|
|
||||||
m_errno(errno),
|
|
||||||
#endif
|
|
||||||
m_string(NULL)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
MXErrno::MXErrno(int err) :
|
|
||||||
m_errno(err),
|
|
||||||
m_string(NULL)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
MXErrno::~MXErrno()
|
|
||||||
{
|
|
||||||
if (m_string != NULL) {
|
|
||||||
#if WINDOWS_LIKE
|
|
||||||
LocalFree(m_string);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
MXErrno::getErrno() const
|
|
||||||
{
|
|
||||||
return m_errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
MXErrno::getErrstr() const
|
|
||||||
{
|
|
||||||
#if WINDOWS_LIKE
|
|
||||||
if (m_string != NULL) {
|
|
||||||
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
||||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
|
||||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
||||||
0,
|
|
||||||
error,
|
|
||||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
||||||
(LPTSTR)&m_string,
|
|
||||||
0,
|
|
||||||
NULL) == 0) {
|
|
||||||
m_string = NULL;
|
|
||||||
return "unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m_string;
|
|
||||||
#else
|
|
||||||
return strerror(m_errno);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,9 +16,11 @@
|
||||||
#define XBASE_H
|
#define XBASE_H
|
||||||
|
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
|
/*
|
||||||
#include "stdpre.h"
|
#include "stdpre.h"
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include "stdpost.h"
|
#include "stdpost.h"
|
||||||
|
*/
|
||||||
|
|
||||||
//! Exception base class
|
//! Exception base class
|
||||||
/*!
|
/*!
|
||||||
|
@ -52,33 +54,73 @@ private:
|
||||||
mutable CString m_what;
|
mutable CString m_what;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Mix-in for handling \c errno
|
|
||||||
/*!
|
/*!
|
||||||
This mix-in class for exception classes provides storage and query of
|
\def XBASE_SUBCLASS
|
||||||
\c errno. On Windows, it uses GetLastError() instead of errno.
|
Convenience macro to subclass from XBase (or a subclass of it),
|
||||||
|
providing the c'tor taking a const CString&. getWhat() is not
|
||||||
|
declared.
|
||||||
*/
|
*/
|
||||||
class MXErrno {
|
#define XBASE_SUBCLASS(name_, super_) \
|
||||||
public:
|
class name_ : public super_ { \
|
||||||
//! Save \c errno as the error code
|
public: \
|
||||||
MXErrno();
|
name_() : super_() { } \
|
||||||
//! Save \c err as the error code
|
name_(const CString& msg) : super_(msg) { } \
|
||||||
MXErrno(int err);
|
}
|
||||||
virtual ~MXErrno();
|
|
||||||
|
|
||||||
//! @name accessors
|
/*!
|
||||||
//@{
|
\def XBASE_SUBCLASS
|
||||||
|
Convenience macro to subclass from XBase (or a subclass of it),
|
||||||
|
providing the c'tor taking a const CString&. getWhat() must be
|
||||||
|
implemented.
|
||||||
|
*/
|
||||||
|
#define XBASE_SUBCLASS_WHAT(name_, super_) \
|
||||||
|
class name_ : public super_ { \
|
||||||
|
public: \
|
||||||
|
name_() : super_() { } \
|
||||||
|
name_(const CString& msg) : super_(msg) { } \
|
||||||
|
\
|
||||||
|
protected: \
|
||||||
|
virtual CString getWhat() const throw(); \
|
||||||
|
}
|
||||||
|
|
||||||
//! Get the error code
|
/*!
|
||||||
int getErrno() const;
|
\def XBASE_SUBCLASS_FORMAT
|
||||||
|
Convenience macro to subclass from XBase (or a subclass of it),
|
||||||
//! Get the human readable string for the error code
|
providing the c'tor taking a const CString&. what() is overridden
|
||||||
virtual const char* getErrstr() const;
|
to call getWhat() when first called; getWhat() can format the
|
||||||
|
error message and can call what() to get the message passed to the
|
||||||
//@}
|
c'tor.
|
||||||
|
*/
|
||||||
private:
|
#define XBASE_SUBCLASS_FORMAT(name_, super_) \
|
||||||
int m_errno;
|
class name_ : public super_ { \
|
||||||
mutable char* m_string;
|
private: \
|
||||||
};
|
enum EState { kFirst, kFormat, kDone }; \
|
||||||
|
\
|
||||||
|
public: \
|
||||||
|
name_() : super_(), m_state(kDone) { } \
|
||||||
|
name_(const CString& msg) : super_(msg), m_state(kFirst) { } \
|
||||||
|
\
|
||||||
|
virtual const char* what() const \
|
||||||
|
{ \
|
||||||
|
if (m_state == kFirst) { \
|
||||||
|
m_state = kFormat; \
|
||||||
|
m_formatted = getWhat(); \
|
||||||
|
m_state = kDone; \
|
||||||
|
} \
|
||||||
|
if (m_state == kDone) { \
|
||||||
|
return m_formatted.c_str(); \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
return super_::what(); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
protected: \
|
||||||
|
virtual CString getWhat() const throw(); \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
mutable EState m_state; \
|
||||||
|
mutable std::string m_formatted; \
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -41,7 +41,7 @@ RSC=rc.exe
|
||||||
# PROP Intermediate_Dir "Release"
|
# PROP Intermediate_Dir "Release"
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||||
# ADD CPP /nologo /MT /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
|
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\common" /I "..\arch" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
@ -65,7 +65,7 @@ LIB32=link.exe -lib
|
||||||
# PROP Intermediate_Dir "Debug"
|
# PROP Intermediate_Dir "Debug"
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||||
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
|
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\common" /I "..\arch" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
@ -99,7 +99,15 @@ SOURCE=.\CStopwatch.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CString.cpp
|
SOURCE=.\CStringUtil.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CUnicode.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\LogOutputters.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
@ -111,10 +119,6 @@ SOURCE=.\XBase.cpp
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\BasicTypes.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\CFunctionJob.h
|
SOURCE=.\CFunctionJob.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -123,10 +127,6 @@ SOURCE=.\CLog.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\common.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\CStopwatch.h
|
SOURCE=.\CStopwatch.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -135,7 +135,11 @@ SOURCE=.\CString.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\IInterface.h
|
SOURCE=.\CStringUtil.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CUnicode.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
@ -143,43 +147,11 @@ SOURCE=.\IJob.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\stdfstream.h
|
SOURCE=.\ILogOutputter.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\stdistream.h
|
SOURCE=.\LogOutputters.h
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\stdlist.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\stdmap.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\stdostream.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\stdpost.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\stdpre.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\stdset.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\stdsstream.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\stdvector.h
|
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
@ -187,10 +159,6 @@ SOURCE=.\TMethodJob.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\Version.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\XBase.h
|
SOURCE=.\XBase.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# End Group
|
# End Group
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "CStopwatch.h"
|
#include "CStopwatch.h"
|
||||||
#include "TMethodJob.h"
|
#include "TMethodJob.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// CClient
|
// CClient
|
||||||
|
@ -545,7 +546,7 @@ CClient::runServer()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (XSocketConnect& e) {
|
catch (XSocketConnect& e) {
|
||||||
LOG((CLOG_DEBUG1 "failed to connect to server: %s", e.getErrstr()));
|
LOG((CLOG_DEBUG1 "failed to connect to server: %s", e.what()));
|
||||||
|
|
||||||
// failed to connect. if not camping then rethrow.
|
// failed to connect. if not camping then rethrow.
|
||||||
if (!m_camp) {
|
if (!m_camp) {
|
||||||
|
@ -553,7 +554,7 @@ CClient::runServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
// we're camping. wait a bit before retrying
|
// we're camping. wait a bit before retrying
|
||||||
CThread::sleep(15.0);
|
ARCH->sleep(15.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
|
|
||||||
#include "CMSWindowsSecondaryScreen.h"
|
#include "CMSWindowsSecondaryScreen.h"
|
||||||
#include "CMSWindowsScreen.h"
|
#include "CMSWindowsScreen.h"
|
||||||
#include "CPlatform.h"
|
|
||||||
#include "XScreen.h"
|
#include "XScreen.h"
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
|
||||||
// these are only defined when WINVER >= 0x0500
|
// these are only defined when WINVER >= 0x0500
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen(
|
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen(
|
||||||
IScreenReceiver* receiver) :
|
IScreenReceiver* receiver) :
|
||||||
m_is95Family(CPlatform::isWindows95Family()),
|
m_is95Family(CArchMiscWindows::isWindows95Family()),
|
||||||
m_window(NULL),
|
m_window(NULL),
|
||||||
m_mask(0)
|
m_mask(0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,8 @@ libclient_a_SOURCES = \
|
||||||
ISecondaryScreenFactory.h \
|
ISecondaryScreenFactory.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
|
-I$(VDEPTH)/lib/common \
|
||||||
|
-I$(VDEPTH)/lib/arch \
|
||||||
-I$(VDEPTH)/lib/base \
|
-I$(VDEPTH)/lib/base \
|
||||||
-I$(VDEPTH)/lib/mt \
|
-I$(VDEPTH)/lib/mt \
|
||||||
-I$(VDEPTH)/lib/io \
|
-I$(VDEPTH)/lib/io \
|
||||||
|
|
|
@ -41,7 +41,7 @@ RSC=rc.exe
|
||||||
# PROP Intermediate_Dir "Release"
|
# PROP Intermediate_Dir "Release"
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||||
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
|
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\common" /I "..\arch" /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
@ -65,7 +65,7 @@ LIB32=link.exe -lib
|
||||||
# PROP Intermediate_Dir "Debug"
|
# PROP Intermediate_Dir "Debug"
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||||
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
|
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\common" /I "..\arch" /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# synergy -- mouse and keyboard sharing utility
|
||||||
|
# Copyright (C) 2002 Chris Schoeneman
|
||||||
|
#
|
||||||
|
# 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 COPYING 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.
|
||||||
|
|
||||||
|
## Process this file with automake to produce Makefile.in
|
||||||
|
NULL =
|
||||||
|
DEPTH = ../..
|
||||||
|
VDEPTH = ./$(VPATH)/$(DEPTH)
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
common.dsp \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
MAINTAINERCLEANFILES = \
|
||||||
|
Makefile.in \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
noinst_LIBRARIES = libcommon.a
|
||||||
|
libcommon_a_SOURCES = \
|
||||||
|
BasicTypes.h \
|
||||||
|
IInterface.h \
|
||||||
|
Version.h \
|
||||||
|
common.h \
|
||||||
|
stdfstream.h \
|
||||||
|
stdistream.h \
|
||||||
|
stdlist.h \
|
||||||
|
stdmap.h \
|
||||||
|
stdostream.h \
|
||||||
|
stdpost.h \
|
||||||
|
stdpre.h \
|
||||||
|
stdset.h \
|
||||||
|
stdsstream.h \
|
||||||
|
stdstring.h \
|
||||||
|
stdvector.h \
|
||||||
|
$(NULL)
|
||||||
|
INCLUDES = \
|
||||||
|
$(NULL)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue