mirror of
https://github.com/debauchee/barrier.git
synced 2024-12-24 03:23:15 +03:00
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
|
||||
cmd -- program source code
|
||||
synergy -- synergy client
|
||||
synergyd -- synergy server
|
||||
launcher -- synergy launcher for Windows
|
||||
synergyc -- synergy client
|
||||
synergys -- synergy server
|
||||
config -- stuff for autoconf/automake
|
||||
dist -- files for creating distributions
|
||||
rpm -- files for creating RPMs
|
||||
doc -- placeholder for documentation
|
||||
examples -- example files
|
||||
lib -- library source code
|
||||
arch -- platform dependent utility library
|
||||
base -- simple utilities
|
||||
client -- synergy client library
|
||||
common -- commonly needed header files
|
||||
http -- simple http tools
|
||||
io -- I/O
|
||||
mt -- multithreading
|
||||
@ -130,7 +133,7 @@ following these guidelines.
|
||||
* Other headers in directory, sorted alphabetically
|
||||
* Headers for each library, sorted alphabetically per library
|
||||
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.
|
||||
* System headers
|
||||
|
||||
@ -181,12 +184,8 @@ following these guidelines.
|
||||
Inheriting implementation from multiple classes can have unpleasant
|
||||
consequences in C++ due to it's limited capabilities. Classes can
|
||||
inherit from any number of interface classes. An interface class
|
||||
provides only pure virtual methods.
|
||||
|
||||
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.
|
||||
provides only pure virtual methods. Synergy breaks this rule in
|
||||
IInterface which implements the virtual destructor for convenience.
|
||||
|
||||
* No globals
|
||||
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
|
||||
* Close brace for function lines up with open brace
|
||||
* 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
|
||||
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
|
||||
e.g. `if (a == b) {' not `if(a==b){'
|
||||
* C'tor initializers are one per line, indented one tab stop
|
||||
* 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'
|
||||
|
||||
- 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
|
||||
@ -300,4 +301,51 @@ FIXME -- high level overview of class relationships
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "CPlatform.h"
|
||||
#include "CLog.h"
|
||||
#include "ILogOutputter.h"
|
||||
#include "CArch.h"
|
||||
#include "CStringUtil.h"
|
||||
#include "XArch.h"
|
||||
#include "CAutoStart.h"
|
||||
#include "LaunchUtil.h"
|
||||
#include "resource.h"
|
||||
@ -23,6 +26,37 @@
|
||||
#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."
|
||||
|
||||
//
|
||||
// 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
|
||||
//
|
||||
@ -51,8 +85,7 @@ void
|
||||
CAutoStart::doModal()
|
||||
{
|
||||
// install our log outputter
|
||||
CLog::Outputter oldOutputter = CLog::getOutputter();
|
||||
CLog::setOutputter(&CAutoStart::onLog);
|
||||
CLOG->insert(new CAutoStartOutputter(&m_errorMessage));
|
||||
|
||||
// reset saved flag
|
||||
m_userConfigSaved = false;
|
||||
@ -61,8 +94,8 @@ CAutoStart::doModal()
|
||||
DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_AUTOSTART),
|
||||
m_parent, dlgProc, (LPARAM)this);
|
||||
|
||||
// restore log outputter
|
||||
CLog::setOutputter(oldOutputter);
|
||||
// remove log outputter
|
||||
CLOG->pop_front();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -74,19 +107,16 @@ CAutoStart::wasUserConfigSaved() const
|
||||
void
|
||||
CAutoStart::update()
|
||||
{
|
||||
// need a platform object
|
||||
CPlatform platform;
|
||||
|
||||
// get installation state
|
||||
const bool installedSystem = platform.isDaemonInstalled(
|
||||
const bool installedSystem = ARCH->isDaemonInstalled(
|
||||
m_name.c_str(), true);
|
||||
const bool installedUser = platform.isDaemonInstalled(
|
||||
const bool installedUser = ARCH->isDaemonInstalled(
|
||||
m_name.c_str(), false);
|
||||
|
||||
// get user's permissions
|
||||
const bool canInstallSystem = platform.canInstallDaemon(
|
||||
const bool canInstallSystem = ARCH->canInstallDaemon(
|
||||
m_name.c_str(), true);
|
||||
const bool canInstallUser = platform.canInstallDaemon(
|
||||
const bool canInstallUser = ARCH->canInstallDaemon(
|
||||
m_name.c_str(), false);
|
||||
|
||||
// update messages
|
||||
@ -165,22 +195,25 @@ CAutoStart::onInstall(bool allUsers)
|
||||
m_errorMessage = "";
|
||||
|
||||
// install
|
||||
CPlatform platform;
|
||||
if (!platform.installDaemon(m_name.c_str(),
|
||||
try {
|
||||
ARCH->installDaemon(m_name.c_str(),
|
||||
m_isServer ? SERVER_DAEMON_INFO : CLIENT_DAEMON_INFO,
|
||||
appPath.c_str(), m_cmdLine.c_str(), allUsers)) {
|
||||
appPath.c_str(), m_cmdLine.c_str(), allUsers);
|
||||
askOkay(m_hwnd, getString(IDS_INSTALL_TITLE),
|
||||
getString(allUsers ?
|
||||
IDS_INSTALLED_SYSTEM :
|
||||
IDS_INSTALLED_USER));
|
||||
return true;
|
||||
}
|
||||
catch (XArchDaemon& e) {
|
||||
if (m_errorMessage.empty()) {
|
||||
m_errorMessage = getString(IDS_INSTALL_GENERIC_ERROR);
|
||||
m_errorMessage = CStringUtil::format(
|
||||
getString(IDS_INSTALL_GENERIC_ERROR).c_str(),
|
||||
e.what().c_str());
|
||||
}
|
||||
showError(m_hwnd, m_errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
askOkay(m_hwnd, getString(IDS_INSTALL_TITLE),
|
||||
getString(allUsers ?
|
||||
IDS_INSTALLED_SYSTEM :
|
||||
IDS_INSTALLED_USER));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -190,30 +223,23 @@ CAutoStart::onUninstall(bool allUsers)
|
||||
m_errorMessage = "";
|
||||
|
||||
// uninstall
|
||||
CPlatform platform;
|
||||
if (platform.uninstallDaemon(m_name.c_str(), allUsers) !=
|
||||
IPlatform::kSuccess) {
|
||||
try {
|
||||
ARCH->uninstallDaemon(m_name.c_str(), allUsers);
|
||||
askOkay(m_hwnd, getString(IDS_UNINSTALL_TITLE),
|
||||
getString(allUsers ?
|
||||
IDS_UNINSTALLED_SYSTEM :
|
||||
IDS_UNINSTALLED_USER));
|
||||
return true;
|
||||
}
|
||||
catch (XArchDaemon& e) {
|
||||
if (m_errorMessage.empty()) {
|
||||
m_errorMessage = getString(IDS_UNINSTALL_GENERIC_ERROR);
|
||||
m_errorMessage = CStringUtil::format(
|
||||
getString(IDS_UNINSTALL_GENERIC_ERROR).c_str(),
|
||||
e.what().c_str());
|
||||
}
|
||||
showError(m_hwnd, m_errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
askOkay(m_hwnd, getString(IDS_UNINSTALL_TITLE),
|
||||
getString(allUsers ?
|
||||
IDS_UNINSTALLED_SYSTEM :
|
||||
IDS_UNINSTALLED_USER));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CAutoStart::onLog(int priority, const char* message)
|
||||
{
|
||||
if (priority <= CLog::kERROR) {
|
||||
s_singleton->m_errorMessage = message;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL
|
||||
|
@ -57,9 +57,6 @@ private:
|
||||
bool onInstall(bool allUsers);
|
||||
bool onUninstall(bool allUsers);
|
||||
|
||||
// log handling
|
||||
static bool onLog(int priority, const char* message);
|
||||
|
||||
// message handling
|
||||
BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
|
||||
static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
@ -13,8 +13,8 @@
|
||||
*/
|
||||
|
||||
#include "CConfig.h"
|
||||
#include "CPlatform.h"
|
||||
#include "LaunchUtil.h"
|
||||
#include "CArch.h"
|
||||
#include "resource.h"
|
||||
#include "stdfstream.h"
|
||||
|
||||
@ -107,10 +107,9 @@ CString
|
||||
getAppPath(const CString& appName)
|
||||
{
|
||||
// prepare path to app
|
||||
CPlatform platform;
|
||||
char 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);
|
||||
appPath += appName;
|
||||
return appPath;
|
||||
@ -136,24 +135,20 @@ loadConfig(const CString& pathname, CConfig& config)
|
||||
bool
|
||||
loadConfig(CConfig& config)
|
||||
{
|
||||
CPlatform platform;
|
||||
|
||||
// load configuration
|
||||
bool configLoaded = false;
|
||||
CString path = platform.getUserDirectory();
|
||||
CString path = ARCH->getUserDirectory();
|
||||
if (!path.empty()) {
|
||||
CPlatform platform;
|
||||
|
||||
// try loading the user's configuration
|
||||
path = platform.addPathComponent(path, CONFIG_NAME);
|
||||
path = ARCH->concatPath(path, CONFIG_NAME);
|
||||
if (loadConfig(path, config)) {
|
||||
configLoaded = true;
|
||||
}
|
||||
else {
|
||||
// try the system-wide config file
|
||||
path = platform.getSystemDirectory();
|
||||
path = ARCH->getSystemDirectory();
|
||||
if (!path.empty()) {
|
||||
path = platform.addPathComponent(path, CONFIG_NAME);
|
||||
path = ARCH->concatPath(path, CONFIG_NAME);
|
||||
if (loadConfig(path, config)) {
|
||||
configLoaded = true;
|
||||
}
|
||||
@ -183,13 +178,11 @@ saveConfig(const CString& pathname, const CConfig& config)
|
||||
bool
|
||||
saveConfig(const CConfig& config, bool sysOnly)
|
||||
{
|
||||
CPlatform platform;
|
||||
|
||||
// try saving the user's configuration
|
||||
if (!sysOnly) {
|
||||
CString path = platform.getUserDirectory();
|
||||
CString path = ARCH->getUserDirectory();
|
||||
if (!path.empty()) {
|
||||
path = platform.addPathComponent(path, CONFIG_NAME);
|
||||
path = ARCH->concatPath(path, CONFIG_NAME);
|
||||
if (saveConfig(path, config)) {
|
||||
return true;
|
||||
}
|
||||
@ -198,9 +191,9 @@ saveConfig(const CConfig& config, bool sysOnly)
|
||||
|
||||
// try the system-wide config file
|
||||
else {
|
||||
CString path = platform.getSystemDirectory();
|
||||
CString path = ARCH->getSystemDirectory();
|
||||
if (!path.empty()) {
|
||||
path = platform.addPathComponent(path, CONFIG_NAME);
|
||||
path = ARCH->concatPath(path, CONFIG_NAME);
|
||||
if (saveConfig(path, config)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -14,9 +14,9 @@
|
||||
|
||||
#include "CConfig.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "CPlatform.h"
|
||||
#include "CNetwork.h"
|
||||
#include "CLog.h"
|
||||
#include "CStringUtil.h"
|
||||
#include "CArch.h"
|
||||
#include "Version.h"
|
||||
#include "stdvector.h"
|
||||
#include "resource.h"
|
||||
@ -62,10 +62,26 @@ static const char* s_debugName[][2] = {
|
||||
};
|
||||
static const int s_defaultDebug = 3; // INFO
|
||||
|
||||
static HWND s_mainWindow;
|
||||
static CConfig s_config;
|
||||
static CConfig s_oldConfig;
|
||||
static CStringList s_screens;
|
||||
//
|
||||
// program arguments
|
||||
//
|
||||
|
||||
#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
|
||||
BOOL CALLBACK
|
||||
@ -117,7 +133,7 @@ static
|
||||
void
|
||||
enableSaveControls(HWND hwnd)
|
||||
{
|
||||
enableItem(hwnd, IDC_MAIN_SAVE, s_config != s_oldConfig);
|
||||
enableItem(hwnd, IDC_MAIN_SAVE, ARG->m_config != ARG->m_oldConfig);
|
||||
}
|
||||
|
||||
static
|
||||
@ -171,8 +187,8 @@ updateNeighbor(HWND hwnd, const CString& screen, EDirection direction)
|
||||
|
||||
// add all screens to combo box
|
||||
if (!screen.empty()) {
|
||||
for (CConfig::const_iterator index = s_config.begin();
|
||||
index != s_config.end(); ++index) {
|
||||
for (CConfig::const_iterator index = ARG->m_config.begin();
|
||||
index != ARG->m_config.end(); ++index) {
|
||||
SendMessage(hwnd, CB_INSERTSTRING,
|
||||
(WPARAM)-1, (LPARAM)index->c_str());
|
||||
}
|
||||
@ -184,7 +200,7 @@ updateNeighbor(HWND hwnd, const CString& screen, EDirection direction)
|
||||
// select neighbor in combo box
|
||||
LRESULT index = 0;
|
||||
if (!screen.empty()) {
|
||||
const CString& neighbor = s_config.getNeighbor(screen, direction);
|
||||
const CString& neighbor = ARG->m_config.getNeighbor(screen, direction);
|
||||
if (!neighbor.empty()) {
|
||||
index = SendMessage(hwnd, CB_FINDSTRINGEXACT,
|
||||
0, (LPARAM)neighbor.c_str());
|
||||
@ -205,7 +221,7 @@ updateNeighbors(HWND hwnd)
|
||||
HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
|
||||
LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
|
||||
if (index != LB_ERR) {
|
||||
screen = s_screens[index];
|
||||
screen = ARG->m_screens[index];
|
||||
}
|
||||
|
||||
// set neighbor combo boxes
|
||||
@ -230,7 +246,7 @@ addScreen(HWND hwnd)
|
||||
if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
|
||||
hwnd, addDlgProc, (LPARAM)&info) != 0) {
|
||||
// get current number of screens
|
||||
UInt32 i = s_screens.size();
|
||||
UInt32 i = ARG->m_screens.size();
|
||||
|
||||
// add screen to list control
|
||||
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());
|
||||
|
||||
// add screen to screen list
|
||||
s_screens.push_back(info.m_screen);
|
||||
ARG->m_screens.push_back(info.m_screen);
|
||||
|
||||
// add screen to config
|
||||
s_config.addScreen(info.m_screen);
|
||||
ARG->m_config.addScreen(info.m_screen);
|
||||
|
||||
// add aliases to config
|
||||
for (CStringList::const_iterator index = info.m_aliases.begin();
|
||||
index != info.m_aliases.end(); ++index) {
|
||||
s_config.addAlias(info.m_screen, *index);
|
||||
ARG->m_config.addAlias(info.m_screen, *index);
|
||||
}
|
||||
|
||||
// update neighbors
|
||||
@ -271,9 +287,9 @@ editScreen(HWND hwnd)
|
||||
|
||||
// fill in screen info
|
||||
CScreenInfo info;
|
||||
info.m_screen = s_screens[index];
|
||||
for (CConfig::all_const_iterator index = s_config.beginAll();
|
||||
index != s_config.endAll(); ++index) {
|
||||
info.m_screen = ARG->m_screens[index];
|
||||
for (CConfig::all_const_iterator index = ARG->m_config.beginAll();
|
||||
index != ARG->m_config.endAll(); ++index) {
|
||||
if (CStringUtil::CaselessCmp::equal(index->second, info.m_screen) &&
|
||||
!CStringUtil::CaselessCmp::equal(index->second, index->first)) {
|
||||
info.m_aliases.push_back(index->first);
|
||||
@ -287,21 +303,21 @@ editScreen(HWND hwnd)
|
||||
if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
|
||||
hwnd, addDlgProc, (LPARAM)&info) != 0) {
|
||||
// replace screen
|
||||
s_screens[index] = info.m_screen;
|
||||
ARG->m_screens[index] = info.m_screen;
|
||||
|
||||
// remove old aliases
|
||||
for (CStringList::const_iterator index = oldInfo.m_aliases.begin();
|
||||
index != oldInfo.m_aliases.end(); ++index) {
|
||||
s_config.removeAlias(*index);
|
||||
ARG->m_config.removeAlias(*index);
|
||||
}
|
||||
|
||||
// replace name
|
||||
s_config.renameScreen(oldInfo.m_screen, info.m_screen);
|
||||
ARG->m_config.renameScreen(oldInfo.m_screen, info.m_screen);
|
||||
|
||||
// add new aliases
|
||||
for (CStringList::const_iterator index = info.m_aliases.begin();
|
||||
index != info.m_aliases.end(); ++index) {
|
||||
s_config.addAlias(info.m_screen, *index);
|
||||
ARG->m_config.addAlias(info.m_screen, *index);
|
||||
}
|
||||
|
||||
// update list
|
||||
@ -331,16 +347,16 @@ removeScreen(HWND hwnd)
|
||||
}
|
||||
|
||||
// get screen name
|
||||
CString name = s_screens[index];
|
||||
CString name = ARG->m_screens[index];
|
||||
|
||||
// remove screen from list control
|
||||
SendMessage(child, LB_DELETESTRING, index, 0);
|
||||
|
||||
// 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)
|
||||
s_config.removeScreen(name);
|
||||
ARG->m_config.removeScreen(name);
|
||||
|
||||
// update neighbors
|
||||
updateNeighbors(hwnd);
|
||||
@ -361,20 +377,20 @@ changeNeighbor(HWND hwnd, HWND combo, EDirection direction)
|
||||
}
|
||||
|
||||
// get screen name
|
||||
CString screen = s_screens[index];
|
||||
CString screen = ARG->m_screens[index];
|
||||
|
||||
// get selected neighbor
|
||||
index = SendMessage(combo, CB_GETCURSEL, 0, 0);
|
||||
|
||||
// remove old connection
|
||||
s_config.disconnect(screen, direction);
|
||||
ARG->m_config.disconnect(screen, direction);
|
||||
|
||||
// add new connection
|
||||
if (index != LB_ERR && index != 0) {
|
||||
LRESULT size = SendMessage(combo, CB_GETLBTEXTLEN, index, 0);
|
||||
char* neighbor = new char[size + 1];
|
||||
SendMessage(combo, CB_GETLBTEXT, index, (LPARAM)neighbor);
|
||||
s_config.connect(screen, direction, CString(neighbor));
|
||||
ARG->m_config.connect(screen, direction, CString(neighbor));
|
||||
delete[] neighbor;
|
||||
}
|
||||
|
||||
@ -444,14 +460,14 @@ getCommandLine(HWND hwnd, bool testing)
|
||||
// get and verify screen name
|
||||
HWND child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
|
||||
CString name = getWindowText(child);
|
||||
if (!s_config.isValidScreenName(name)) {
|
||||
if (!ARG->m_config.isValidScreenName(name)) {
|
||||
showError(hwnd, CStringUtil::format(
|
||||
getString(IDS_INVALID_SCREEN_NAME).c_str(),
|
||||
name.c_str()));
|
||||
SetFocus(child);
|
||||
return CString();
|
||||
}
|
||||
if (!isClient && !s_config.isScreen(name)) {
|
||||
if (!isClient && !ARG->m_config.isScreen(name)) {
|
||||
showError(hwnd, CStringUtil::format(
|
||||
getString(IDS_UNKNOWN_SCREEN_NAME).c_str(),
|
||||
name.c_str()));
|
||||
@ -490,7 +506,7 @@ getCommandLine(HWND hwnd, bool testing)
|
||||
// check server name
|
||||
child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
|
||||
CString server = getWindowText(child);
|
||||
if (!s_config.isValidScreenName(server)) {
|
||||
if (!ARG->m_config.isValidScreenName(server)) {
|
||||
showError(hwnd, CStringUtil::format(
|
||||
getString(IDS_INVALID_SERVER_NAME).c_str(),
|
||||
server.c_str()));
|
||||
@ -649,15 +665,13 @@ static
|
||||
void
|
||||
initMainWindow(HWND hwnd)
|
||||
{
|
||||
CPlatform platform;
|
||||
|
||||
// append version number to title
|
||||
CString titleFormat = getString(IDS_TITLE);
|
||||
setWindowText(hwnd, CStringUtil::format(titleFormat.c_str(), VERSION));
|
||||
|
||||
// load configuration
|
||||
bool configLoaded = loadConfig(s_config);
|
||||
s_oldConfig = s_config;
|
||||
bool configLoaded = loadConfig(ARG->m_config);
|
||||
ARG->m_oldConfig = ARG->m_config;
|
||||
enableSaveControls(hwnd);
|
||||
|
||||
// choose client/server radio buttons
|
||||
@ -673,9 +687,9 @@ initMainWindow(HWND hwnd)
|
||||
if (configLoaded) {
|
||||
int i = 1;
|
||||
child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
|
||||
for (CConfig::const_iterator index = s_config.begin();
|
||||
index != s_config.end(); ++i, ++index) {
|
||||
s_screens.push_back(*index);
|
||||
for (CConfig::const_iterator index = ARG->m_config.begin();
|
||||
index != ARG->m_config.end(); ++i, ++index) {
|
||||
ARG->m_screens.push_back(*index);
|
||||
CString item = CStringUtil::print("%d. %s", i, index->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);
|
||||
SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
|
||||
|
||||
CNetwork::gethostname(buffer, sizeof(buffer));
|
||||
CString hostname = ARCH->getHostName();
|
||||
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);
|
||||
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));
|
||||
|
||||
// name must be valid
|
||||
if (!s_config.isValidScreenName(newName)) {
|
||||
if (!ARG->m_config.isValidScreenName(newName)) {
|
||||
showError(hwnd, CStringUtil::format(
|
||||
getString(IDS_INVALID_SCREEN_NAME).c_str(),
|
||||
newName.c_str()));
|
||||
@ -756,7 +770,7 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
// aliases must be valid
|
||||
for (CStringList::const_iterator index = newAliases.begin();
|
||||
index != newAliases.end(); ++index) {
|
||||
if (!s_config.isValidScreenName(*index)) {
|
||||
if (!ARG->m_config.isValidScreenName(*index)) {
|
||||
showError(hwnd, CStringUtil::format(
|
||||
getString(IDS_INVALID_SCREEN_NAME).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
|
||||
// allow name if it exists in the old alias list but not the
|
||||
// new one.
|
||||
if (s_config.isScreen(newName) &&
|
||||
if (ARG->m_config.isScreen(newName) &&
|
||||
!CStringUtil::CaselessCmp::equal(newName, info->m_screen) &&
|
||||
!isNameInList(info->m_aliases, newName)) {
|
||||
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.
|
||||
for (CStringList::const_iterator index = newAliases.begin();
|
||||
index != newAliases.end(); ++index) {
|
||||
if (s_config.isScreen(*index) &&
|
||||
if (ARG->m_config.isScreen(*index) &&
|
||||
!CStringUtil::CaselessCmp::equal(*index, info->m_screen) &&
|
||||
!isNameInList(info->m_aliases, *index)) {
|
||||
showError(hwnd, CStringUtil::format(
|
||||
@ -830,7 +844,7 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
switch (LOWORD(wParam)) {
|
||||
case IDCANCEL:
|
||||
// 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))) {
|
||||
return 0;
|
||||
}
|
||||
@ -846,14 +860,14 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
const bool testing = (LOWORD(wParam) == IDC_MAIN_TEST);
|
||||
|
||||
// save data
|
||||
if (s_config != s_oldConfig) {
|
||||
if (!saveConfig(s_config, false)) {
|
||||
if (ARG->m_config != ARG->m_oldConfig) {
|
||||
if (!saveConfig(ARG->m_config, false)) {
|
||||
showError(hwnd, CStringUtil::format(
|
||||
getString(IDS_SAVE_FAILED).c_str(),
|
||||
getErrorString(GetLastError()).c_str()));
|
||||
return 0;
|
||||
}
|
||||
s_oldConfig = s_config;
|
||||
ARG->m_oldConfig = ARG->m_config;
|
||||
enableSaveControls(hwnd);
|
||||
}
|
||||
|
||||
@ -892,11 +906,11 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
if (!cmdLine.empty()) {
|
||||
// run dialog
|
||||
CAutoStart autoStart(hwnd,
|
||||
isClientChecked(hwnd) ? NULL : &s_config,
|
||||
isClientChecked(hwnd) ? NULL : &ARG->m_config,
|
||||
cmdLine);
|
||||
autoStart.doModal();
|
||||
if (autoStart.wasUserConfigSaved()) {
|
||||
s_oldConfig = s_config;
|
||||
ARG->m_oldConfig = ARG->m_config;
|
||||
enableSaveControls(hwnd);
|
||||
}
|
||||
}
|
||||
@ -904,13 +918,13 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
|
||||
case IDC_MAIN_SAVE:
|
||||
if (!saveConfig(s_config, false)) {
|
||||
if (!saveConfig(ARG->m_config, false)) {
|
||||
showError(hwnd, CStringUtil::format(
|
||||
getString(IDS_SAVE_FAILED).c_str(),
|
||||
getErrorString(GetLastError()).c_str()));
|
||||
}
|
||||
else {
|
||||
s_oldConfig = s_config;
|
||||
ARG->m_oldConfig = ARG->m_config;
|
||||
enableSaveControls(hwnd);
|
||||
}
|
||||
return 0;
|
||||
@ -981,10 +995,11 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
int WINAPI
|
||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
||||
{
|
||||
s_instance = instance;
|
||||
CArch arch;
|
||||
CLOG;
|
||||
CArgs args;
|
||||
|
||||
// initialize network library
|
||||
CNetwork::init();
|
||||
s_instance = instance;
|
||||
|
||||
// register main window (dialog) class
|
||||
WNDCLASSEX classInfo;
|
||||
@ -1009,13 +1024,14 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
||||
RegisterClassEx(&classInfo);
|
||||
|
||||
// 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
|
||||
initMainWindow(s_mainWindow);
|
||||
initMainWindow(m_mainWindow);
|
||||
|
||||
// show window
|
||||
ShowWindow(s_mainWindow, nCmdShow);
|
||||
ShowWindow(m_mainWindow, nCmdShow);
|
||||
|
||||
// main loop
|
||||
MSG msg;
|
||||
@ -1032,7 +1048,7 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!IsDialogMessage(s_mainWindow, &msg)) {
|
||||
if (!IsDialogMessage(m_mainWindow, &msg)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ RSC=rc.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# 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
|
||||
# ADD BASE 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 Target_Dir ""
|
||||
# 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
|
||||
# ADD BASE 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."
|
||||
IDS_INSTALL_LABEL "Install"
|
||||
IDS_UNINSTALL_LABEL "Uninstall"
|
||||
IDS_INSTALL_GENERIC_ERROR "Install failed for an unknown reason."
|
||||
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed for an unknown reason."
|
||||
IDS_INSTALL_GENERIC_ERROR "Install failed: %{1}."
|
||||
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed: %{1}."
|
||||
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_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/mt/libmt.a \
|
||||
$(DEPTH)/lib/base/libbase.a \
|
||||
$(DEPTH)/lib/arch/libarch.a \
|
||||
$(X_LIBS) \
|
||||
$(X_PRE_LIBS) \
|
||||
-lXtst \
|
||||
@ -46,6 +47,8 @@ synergyc_LDADD = \
|
||||
$(X_EXTRA_LIBS) \
|
||||
$(NULL)
|
||||
INCLUDES = \
|
||||
-I$(VDEPTH)/lib/common \
|
||||
-I$(VDEPTH)/lib/arch \
|
||||
-I$(VDEPTH)/lib/base \
|
||||
-I$(VDEPTH)/lib/mt \
|
||||
-I$(VDEPTH)/lib/io \
|
||||
|
@ -14,11 +14,9 @@
|
||||
|
||||
#include "CClient.h"
|
||||
#include "ISecondaryScreenFactory.h"
|
||||
#include "CPlatform.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "Version.h"
|
||||
#include "XScreen.h"
|
||||
#include "CNetwork.h"
|
||||
#include "CNetworkAddress.h"
|
||||
#include "CTCPSocketFactory.h"
|
||||
#include "XSocket.h"
|
||||
@ -28,12 +26,18 @@
|
||||
#include "CThread.h"
|
||||
#include "XThread.h"
|
||||
#include "CLog.h"
|
||||
#include "LogOutputters.h"
|
||||
#include "CString.h"
|
||||
#include "CArch.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include <cstring>
|
||||
|
||||
#define DAEMON_RUNNING(running_)
|
||||
#if WINDOWS_LIKE
|
||||
#include "CMSWindowsSecondaryScreen.h"
|
||||
#include "resource.h"
|
||||
#undef DAEMON_RUNNING
|
||||
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||
#elif UNIX_LIKE
|
||||
#include "CXWindowsSecondaryScreen.h"
|
||||
#endif
|
||||
@ -49,35 +53,33 @@
|
||||
// program arguments
|
||||
//
|
||||
|
||||
static const char* pname = NULL;
|
||||
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;
|
||||
#define ARG CArgs::s_instance
|
||||
|
||||
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; }
|
||||
|
||||
//
|
||||
// logging thread safety
|
||||
//
|
||||
public:
|
||||
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;
|
||||
|
||||
static
|
||||
void
|
||||
logLock(bool lock)
|
||||
{
|
||||
assert(s_logMutex != NULL);
|
||||
|
||||
if (lock) {
|
||||
s_logMutex->lock();
|
||||
}
|
||||
else {
|
||||
s_logMutex->unlock();
|
||||
}
|
||||
}
|
||||
CArgs* CArgs::s_instance = NULL;
|
||||
|
||||
|
||||
//
|
||||
@ -113,27 +115,17 @@ static CClient* s_client = NULL;
|
||||
|
||||
static
|
||||
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;
|
||||
do {
|
||||
bool opened = false;
|
||||
bool locked = true;
|
||||
try {
|
||||
// create client
|
||||
s_client = new CClient(s_name);
|
||||
s_client->camp(s_camp);
|
||||
s_client->setAddress(s_serverAddress);
|
||||
s_client = new CClient(ARG->m_name);
|
||||
s_client->camp(ARG->m_camp);
|
||||
s_client->setAddress(ARG->m_serverAddress);
|
||||
s_client->setScreenFactory(new CSecondaryScreenFactory);
|
||||
s_client->setSocketFactory(new CTCPSocketFactory);
|
||||
s_client->setStreamFilterFactory(NULL);
|
||||
@ -144,9 +136,7 @@ realMain(CMutex* mutex)
|
||||
opened = true;
|
||||
|
||||
// run client
|
||||
if (mutex != NULL) {
|
||||
mutex->unlock();
|
||||
}
|
||||
DAEMON_RUNNING(true);
|
||||
locked = false;
|
||||
s_client->mainLoop();
|
||||
locked = true;
|
||||
@ -160,8 +150,8 @@ realMain(CMutex* mutex)
|
||||
|
||||
// clean up
|
||||
#define FINALLY do { \
|
||||
if (!locked && mutex != NULL) { \
|
||||
mutex->lock(); \
|
||||
if (!locked) { \
|
||||
DAEMON_RUNNING(false); \
|
||||
} \
|
||||
if (s_client != NULL) { \
|
||||
if (opened) { \
|
||||
@ -175,8 +165,8 @@ realMain(CMutex* mutex)
|
||||
}
|
||||
catch (XScreenUnavailable& e) {
|
||||
// wait before retrying if we're going to retry
|
||||
if (s_restartable) {
|
||||
CThread::sleep(e.getRetryTime());
|
||||
if (ARG->m_restartable) {
|
||||
ARCH->sleep(e.getRetryTime());
|
||||
}
|
||||
else {
|
||||
result = kExitFailed;
|
||||
@ -189,8 +179,8 @@ realMain(CMutex* mutex)
|
||||
}
|
||||
catch (...) {
|
||||
// don't try to restart and fail
|
||||
s_restartable = false;
|
||||
result = kExitFailed;
|
||||
ARG->m_restartable = false;
|
||||
result = kExitFailed;
|
||||
FINALLY;
|
||||
}
|
||||
#undef FINALLY
|
||||
@ -200,19 +190,10 @@ realMain(CMutex* mutex)
|
||||
}
|
||||
catch (XThread&) {
|
||||
// terminated
|
||||
s_restartable = false;
|
||||
result = kExitTerminated;
|
||||
ARG->m_restartable = false;
|
||||
result = kExitTerminated;
|
||||
}
|
||||
catch (...) {
|
||||
CLog::setLock(NULL);
|
||||
s_logMutex = NULL;
|
||||
throw;
|
||||
}
|
||||
} while (s_restartable);
|
||||
|
||||
// clean up
|
||||
CLog::setLock(NULL);
|
||||
s_logMutex = NULL;
|
||||
} while (ARG->m_restartable);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -233,7 +214,7 @@ version()
|
||||
LOG((CLOG_PRINT
|
||||
"%s %s, protocol version %d.%d\n"
|
||||
"%s",
|
||||
pname,
|
||||
ARG->m_pname,
|
||||
kVersion,
|
||||
kProtocolMajorVersion,
|
||||
kProtocolMinorVersion,
|
||||
@ -279,7 +260,7 @@ help()
|
||||
"\n"
|
||||
"Where log messages go depends on the platform and whether or not the\n"
|
||||
"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.
|
||||
if (argi + minRequiredParameters >= argc) {
|
||||
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
||||
pname, argv[argi], pname));
|
||||
ARG->m_pname, argv[argi], ARG->m_pname));
|
||||
bye(kExitArgs);
|
||||
}
|
||||
return true;
|
||||
@ -308,61 +289,58 @@ static
|
||||
void
|
||||
parse(int argc, const char** argv)
|
||||
{
|
||||
assert(pname != NULL);
|
||||
assert(argv != NULL);
|
||||
assert(argc >= 1);
|
||||
assert(ARG->m_pname != NULL);
|
||||
assert(argv != NULL);
|
||||
assert(argc >= 1);
|
||||
|
||||
// set defaults
|
||||
char hostname[256];
|
||||
if (CNetwork::gethostname(hostname, sizeof(hostname)) != CNetwork::Error) {
|
||||
s_name = hostname;
|
||||
}
|
||||
ARG->m_name = ARCH->getHostName();
|
||||
|
||||
// parse options
|
||||
int i;
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
||||
// change logging level
|
||||
s_logFilter = argv[++i];
|
||||
ARG->m_logFilter = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
||||
// save screen name
|
||||
s_name = argv[++i];
|
||||
ARG->m_name = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--camp")) {
|
||||
// enable camping
|
||||
s_camp = true;
|
||||
ARG->m_camp = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--no-camp")) {
|
||||
// disable camping
|
||||
s_camp = false;
|
||||
ARG->m_camp = false;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
||||
// not a daemon
|
||||
s_daemon = false;
|
||||
ARG->m_daemon = false;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
||||
// daemonize
|
||||
s_daemon = true;
|
||||
ARG->m_daemon = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
||||
// don't try to restart
|
||||
s_restartable = false;
|
||||
ARG->m_restartable = false;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
||||
// try to restart
|
||||
s_restartable = true;
|
||||
ARG->m_restartable = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-z", NULL)) {
|
||||
s_backend = true;
|
||||
ARG->m_backend = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-h", "--help")) {
|
||||
@ -383,7 +361,7 @@ parse(int argc, const char** argv)
|
||||
|
||||
else if (argv[i][0] == '-') {
|
||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||
pname, argv[i], pname));
|
||||
ARG->m_pname, argv[i], ARG->m_pname));
|
||||
bye(kExitArgs);
|
||||
}
|
||||
|
||||
@ -396,49 +374,60 @@ parse(int argc, const char** argv)
|
||||
// exactly one non-option argument (server-address)
|
||||
if (i == argc) {
|
||||
LOG((CLOG_PRINT "%s: a server address or name is required" BYE,
|
||||
pname, pname));
|
||||
ARG->m_pname, ARG->m_pname));
|
||||
bye(kExitArgs);
|
||||
}
|
||||
if (i + 1 != argc) {
|
||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||
pname, argv[i], pname));
|
||||
ARG->m_pname, argv[i], ARG->m_pname));
|
||||
bye(kExitArgs);
|
||||
}
|
||||
|
||||
// save server address
|
||||
try {
|
||||
s_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
|
||||
ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
|
||||
}
|
||||
catch (XSocketAddress& e) {
|
||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||
pname, e.what(), pname));
|
||||
ARG->m_pname, e.what(), ARG->m_pname));
|
||||
bye(kExitFailed);
|
||||
}
|
||||
|
||||
// increase default filter level for daemon. the user must
|
||||
// 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 (CPlatform::isWindows95Family()) {
|
||||
if (CArchMiscWindows::isWindows95Family()) {
|
||||
// windows 95 has no place for logging so avoid showing
|
||||
// the log console window.
|
||||
s_logFilter = "FATAL";
|
||||
ARG->m_logFilter = "FATAL";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
s_logFilter = "NOTE";
|
||||
ARG->m_logFilter = "NOTE";
|
||||
}
|
||||
}
|
||||
|
||||
// set log filter
|
||||
if (!CLog::setFilter(s_logFilter)) {
|
||||
if (!CLOG->setFilter(ARG->m_logFilter)) {
|
||||
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
||||
pname, s_logFilter, pname));
|
||||
ARG->m_pname, ARG->m_logFilter, ARG->m_pname));
|
||||
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
|
||||
//
|
||||
@ -449,24 +438,41 @@ parse(int argc, const char** argv)
|
||||
|
||||
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
|
||||
logMessageBox(int priority, const char* msg)
|
||||
CMessageBoxOutputter::write(ELevel level, const char* message)
|
||||
{
|
||||
// note any important messages the user may need to know about
|
||||
if (priority <= CLog::kWARNING) {
|
||||
if (level <= CLog::kWARNING) {
|
||||
s_hasImportantLogMessages = true;
|
||||
}
|
||||
|
||||
// FATAL and PRINT messages get a dialog box if not running as
|
||||
// backend. if we're running as a backend the user will have
|
||||
// a chance to see the messages when we exit.
|
||||
if (!s_backend && priority <= CLog::kFATAL) {
|
||||
MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING);
|
||||
return true;
|
||||
if (!ARG->m_backend && level <= CLog::kFATAL) {
|
||||
MessageBox(NULL, message, ARG->m_pname, MB_OK | MB_ICONWARNING);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,7 +480,7 @@ static
|
||||
void
|
||||
byeThrow(int x)
|
||||
{
|
||||
throw CWin32Platform::CDaemonFailed(x);
|
||||
CArchMiscWindows::daemonFailed(x);
|
||||
}
|
||||
|
||||
static
|
||||
@ -486,10 +492,9 @@ daemonStop(void)
|
||||
|
||||
static
|
||||
int
|
||||
daemonStartup(IPlatform* iplatform, int argc, const char** argv)
|
||||
daemonStartup(int argc, const char** argv)
|
||||
{
|
||||
// get platform pointer
|
||||
CWin32Platform* platform = static_cast<CWin32Platform*>(iplatform);
|
||||
useSystemLog();
|
||||
|
||||
// catch errors that would normally exit
|
||||
bye = &byeThrow;
|
||||
@ -498,35 +503,35 @@ daemonStartup(IPlatform* iplatform, int argc, const char** argv)
|
||||
parse(argc, argv);
|
||||
|
||||
// cannot run as backend if running as a service
|
||||
s_backend = false;
|
||||
ARG->m_backend = false;
|
||||
|
||||
// run as a service
|
||||
return platform->runDaemon(realMain, daemonStop);
|
||||
return CArchMiscWindows::runDaemon(realMain, daemonStop);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
daemonStartup95(IPlatform*, int, const char**)
|
||||
daemonStartup95(int, const char**)
|
||||
{
|
||||
return realMain(NULL);
|
||||
useSystemLog();
|
||||
return realMain();
|
||||
}
|
||||
|
||||
int WINAPI
|
||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
{
|
||||
CPlatform platform;
|
||||
CArch arch;
|
||||
CLOG;
|
||||
CArgs args;
|
||||
|
||||
// save instance
|
||||
CMSWindowsScreen::init(instance);
|
||||
|
||||
// get program name
|
||||
pname = platform.getBasename(__argv[0]);
|
||||
|
||||
// initialize network library
|
||||
CNetwork::init();
|
||||
ARG->m_pname = ARCH->getBasename(__argv[0]);
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||
// of the service code path.
|
||||
if (__argc <= 1 && !CWin32Platform::isWindows95Family()) {
|
||||
int result = platform.daemonize(DAEMON_NAME, &daemonStartup);
|
||||
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||
int result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||
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 result;
|
||||
@ -548,38 +553,36 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
|
||||
// daemonize if requested
|
||||
int result;
|
||||
if (s_daemon) {
|
||||
// redirect log messages
|
||||
platform.installDaemonLogger(DAEMON_NAME);
|
||||
|
||||
if (ARG->m_daemon) {
|
||||
// start as a daemon
|
||||
if (CWin32Platform::isWindows95Family()) {
|
||||
result = platform.daemonize(DAEMON_NAME, &daemonStartup95);
|
||||
if (result == -1) {
|
||||
LOG((CLOG_CRIT "failed to start as a service" BYE, pname));
|
||||
if (CArchMiscWindows::isWindows95Family()) {
|
||||
try {
|
||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
||||
}
|
||||
catch (XArchDaemon&) {
|
||||
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
||||
result = kExitFailed;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// cannot start a service from the command line so just
|
||||
// run normally (except with log messages redirected).
|
||||
result = realMain(NULL);
|
||||
useSystemLog();
|
||||
result = realMain();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// run
|
||||
result = realMain(NULL);
|
||||
result = realMain();
|
||||
}
|
||||
|
||||
CNetwork::cleanup();
|
||||
|
||||
// let user examine any messages if we're running as a backend
|
||||
// by putting up a dialog box before exiting.
|
||||
if (s_backend && s_hasImportantLogMessages) {
|
||||
if (ARG->m_backend && s_hasImportantLogMessages) {
|
||||
char msg[1024];
|
||||
msg[0] = '\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;
|
||||
@ -589,40 +592,40 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
|
||||
static
|
||||
int
|
||||
daemonStartup(IPlatform*, int, const char**)
|
||||
daemonStartup(int, const char**)
|
||||
{
|
||||
return realMain(NULL);
|
||||
useSystemLog();
|
||||
return realMain();
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
CPlatform platform;
|
||||
CArch arch;
|
||||
CLOG;
|
||||
CArgs args;
|
||||
|
||||
// get program name
|
||||
pname = platform.getBasename(argv[0]);
|
||||
|
||||
// initialize network library
|
||||
CNetwork::init();
|
||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||
|
||||
// parse command line
|
||||
parse(argc, const_cast<const char**>(argv));
|
||||
|
||||
// daemonize if requested
|
||||
int result;
|
||||
if (s_daemon) {
|
||||
result = platform.daemonize(DAEMON_NAME, &daemonStartup);
|
||||
if (result == -1) {
|
||||
if (ARG->m_daemon) {
|
||||
try {
|
||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||
}
|
||||
catch (XArchDaemon&) {
|
||||
LOG((CLOG_CRIT "failed to daemonize"));
|
||||
return kExitFailed;
|
||||
result = kExitFailed;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = realMain(NULL);
|
||||
result = realMain();
|
||||
}
|
||||
|
||||
CNetwork::cleanup();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ RSC=rc.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# 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
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
@ -54,7 +54,7 @@ BSC32=bscmake.exe
|
||||
# ADD BSC32 /nologo
|
||||
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 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"
|
||||
|
||||
@ -70,7 +70,7 @@ LINK32=link.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# 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 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
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
@ -81,7 +81,7 @@ BSC32=bscmake.exe
|
||||
# ADD BSC32 /nologo
|
||||
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 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
|
||||
|
||||
|
@ -39,6 +39,7 @@ synergys_LDADD = \
|
||||
$(DEPTH)/lib/io/libio.a \
|
||||
$(DEPTH)/lib/mt/libmt.a \
|
||||
$(DEPTH)/lib/base/libbase.a \
|
||||
$(DEPTH)/lib/arch/libarch.a \
|
||||
$(X_LIBS) \
|
||||
$(X_PRE_LIBS) \
|
||||
-lXtst \
|
||||
@ -47,6 +48,8 @@ synergys_LDADD = \
|
||||
$(X_EXTRA_LIBS) \
|
||||
$(NULL)
|
||||
INCLUDES = \
|
||||
-I$(VDEPTH)/lib/common \
|
||||
-I$(VDEPTH)/lib/arch \
|
||||
-I$(VDEPTH)/lib/base \
|
||||
-I$(VDEPTH)/lib/mt \
|
||||
-I$(VDEPTH)/lib/io \
|
||||
|
@ -15,11 +15,9 @@
|
||||
#include "CServer.h"
|
||||
#include "CConfig.h"
|
||||
#include "IPrimaryScreenFactory.h"
|
||||
#include "CPlatform.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "Version.h"
|
||||
#include "XScreen.h"
|
||||
#include "CNetwork.h"
|
||||
#include "CTCPSocketFactory.h"
|
||||
#include "XSocket.h"
|
||||
#include "CLock.h"
|
||||
@ -27,12 +25,18 @@
|
||||
#include "CThread.h"
|
||||
#include "XThread.h"
|
||||
#include "CLog.h"
|
||||
#include "LogOutputters.h"
|
||||
#include "CArch.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include "stdfstream.h"
|
||||
#include <cstring>
|
||||
|
||||
#define DAEMON_RUNNING(running_)
|
||||
#if WINDOWS_LIKE
|
||||
#include "CMSWindowsPrimaryScreen.h"
|
||||
#include "resource.h"
|
||||
#undef DAEMON_RUNNING
|
||||
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||
#elif UNIX_LIKE
|
||||
#include "CXWindowsPrimaryScreen.h"
|
||||
#endif
|
||||
@ -57,37 +61,35 @@
|
||||
// program arguments
|
||||
//
|
||||
|
||||
static const char* pname = NULL;
|
||||
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;
|
||||
#define ARG CArgs::s_instance
|
||||
|
||||
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; }
|
||||
|
||||
//
|
||||
// logging thread safety
|
||||
//
|
||||
public:
|
||||
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;
|
||||
|
||||
static
|
||||
void
|
||||
logLock(bool lock)
|
||||
{
|
||||
assert(s_logMutex != NULL);
|
||||
|
||||
if (lock) {
|
||||
s_logMutex->lock();
|
||||
}
|
||||
else {
|
||||
s_logMutex->unlock();
|
||||
}
|
||||
}
|
||||
CArgs* CArgs::s_instance = NULL;
|
||||
|
||||
|
||||
//
|
||||
@ -124,18 +126,8 @@ static CServer* s_server = NULL;
|
||||
|
||||
static
|
||||
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;
|
||||
do {
|
||||
bool opened = false;
|
||||
@ -143,28 +135,28 @@ realMain(CMutex* mutex)
|
||||
try {
|
||||
// if configuration has no screens then add this system
|
||||
// as the default
|
||||
if (s_config.begin() == s_config.end()) {
|
||||
s_config.addScreen(s_name);
|
||||
if (ARG->m_config.begin() == ARG->m_config.end()) {
|
||||
ARG->m_config.addScreen(ARG->m_name);
|
||||
}
|
||||
|
||||
// set the contact address, if provided, in the config.
|
||||
// otherwise, if the config doesn't have an address, use
|
||||
// the default.
|
||||
if (s_synergyAddress.isValid()) {
|
||||
s_config.setSynergyAddress(s_synergyAddress);
|
||||
if (ARG->m_synergyAddress.isValid()) {
|
||||
ARG->m_config.setSynergyAddress(ARG->m_synergyAddress);
|
||||
}
|
||||
else if (!s_config.getSynergyAddress().isValid()) {
|
||||
s_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
|
||||
else if (!ARG->m_config.getSynergyAddress().isValid()) {
|
||||
ARG->m_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
|
||||
}
|
||||
|
||||
// set HTTP address if provided
|
||||
if (s_httpAddress.isValid()) {
|
||||
s_config.setHTTPAddress(s_httpAddress);
|
||||
if (ARG->m_httpAddress.isValid()) {
|
||||
ARG->m_config.setHTTPAddress(ARG->m_httpAddress);
|
||||
}
|
||||
|
||||
// create server
|
||||
s_server = new CServer(s_name);
|
||||
s_server->setConfig(s_config);
|
||||
s_server = new CServer(ARG->m_name);
|
||||
s_server->setConfig(ARG->m_config);
|
||||
s_server->setScreenFactory(new CPrimaryScreenFactory);
|
||||
s_server->setSocketFactory(new CTCPSocketFactory);
|
||||
s_server->setStreamFilterFactory(NULL);
|
||||
@ -174,18 +166,16 @@ realMain(CMutex* mutex)
|
||||
s_server->open();
|
||||
opened = true;
|
||||
|
||||
// run server (unlocked)
|
||||
if (mutex != NULL) {
|
||||
mutex->unlock();
|
||||
}
|
||||
// run server
|
||||
DAEMON_RUNNING(true);
|
||||
locked = false;
|
||||
s_server->mainLoop();
|
||||
locked = true;
|
||||
|
||||
// clean up
|
||||
#define FINALLY do { \
|
||||
if (!locked && mutex != NULL) { \
|
||||
mutex->lock(); \
|
||||
if (!locked) { \
|
||||
DAEMON_RUNNING(false); \
|
||||
} \
|
||||
if (s_server != NULL) { \
|
||||
if (opened) { \
|
||||
@ -199,8 +189,8 @@ realMain(CMutex* mutex)
|
||||
}
|
||||
catch (XScreenUnavailable& e) {
|
||||
// wait before retrying if we're going to retry
|
||||
if (s_restartable) {
|
||||
CThread::sleep(e.getRetryTime());
|
||||
if (ARG->m_restartable) {
|
||||
ARCH->sleep(e.getRetryTime());
|
||||
}
|
||||
else {
|
||||
result = kExitFailed;
|
||||
@ -213,8 +203,8 @@ realMain(CMutex* mutex)
|
||||
}
|
||||
catch (...) {
|
||||
// don't try to restart and fail
|
||||
s_restartable = false;
|
||||
result = kExitFailed;
|
||||
ARG->m_restartable = false;
|
||||
result = kExitFailed;
|
||||
FINALLY;
|
||||
}
|
||||
#undef FINALLY
|
||||
@ -224,19 +214,10 @@ realMain(CMutex* mutex)
|
||||
}
|
||||
catch (XThread&) {
|
||||
// terminated
|
||||
s_restartable = false;
|
||||
result = kExitTerminated;
|
||||
ARG->m_restartable = false;
|
||||
result = kExitTerminated;
|
||||
}
|
||||
catch (...) {
|
||||
CLog::setLock(NULL);
|
||||
s_logMutex = NULL;
|
||||
throw;
|
||||
}
|
||||
} while (s_restartable);
|
||||
|
||||
// clean up
|
||||
CLog::setLock(NULL);
|
||||
s_logMutex = NULL;
|
||||
} while (ARG->m_restartable);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -257,7 +238,7 @@ version()
|
||||
LOG((CLOG_PRINT
|
||||
"%s %s, protocol version %d.%d\n"
|
||||
"%s",
|
||||
pname,
|
||||
ARG->m_pname,
|
||||
kVersion,
|
||||
kProtocolMajorVersion,
|
||||
kProtocolMinorVersion,
|
||||
@ -287,8 +268,6 @@ help()
|
||||
|
||||
#endif
|
||||
|
||||
CPlatform platform;
|
||||
|
||||
LOG((CLOG_PRINT
|
||||
"Usage: %s"
|
||||
" [--address <address>]"
|
||||
@ -333,13 +312,13 @@ PLATFORM_EXTRA
|
||||
"\n"
|
||||
"Where log messages go depends on the platform and whether or not the\n"
|
||||
"server is running as a daemon.",
|
||||
pname,
|
||||
ARG->m_pname,
|
||||
kDefaultPort,
|
||||
platform.addPathComponent(
|
||||
platform.getUserDirectory(),
|
||||
ARCH->concatPath(
|
||||
ARCH->getUserDirectory(),
|
||||
USR_CONFIG_NAME).c_str(),
|
||||
platform.addPathComponent(
|
||||
platform.getSystemDirectory(),
|
||||
ARCH->concatPath(
|
||||
ARCH->getSystemDirectory(),
|
||||
SYS_CONFIG_NAME).c_str()));
|
||||
}
|
||||
|
||||
@ -354,7 +333,7 @@ isArg(int argi, int argc, const char** argv,
|
||||
// match. check args left.
|
||||
if (argi + minRequiredParameters >= argc) {
|
||||
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
||||
pname, argv[argi], pname));
|
||||
ARG->m_pname, argv[argi], ARG->m_pname));
|
||||
bye(kExitArgs);
|
||||
}
|
||||
return true;
|
||||
@ -368,32 +347,30 @@ static
|
||||
void
|
||||
parse(int argc, const char** argv)
|
||||
{
|
||||
assert(pname != NULL);
|
||||
assert(argv != NULL);
|
||||
assert(argc >= 1);
|
||||
assert(ARG->m_pname != NULL);
|
||||
assert(argv != NULL);
|
||||
assert(argc >= 1);
|
||||
|
||||
// set defaults
|
||||
char hostname[256];
|
||||
if (CNetwork::gethostname(hostname, sizeof(hostname)) != CNetwork::Error) {
|
||||
s_name = hostname;
|
||||
}
|
||||
ARG->m_name = ARCH->getHostName();
|
||||
|
||||
// parse options
|
||||
int i;
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
||||
// change logging level
|
||||
s_logFilter = argv[++i];
|
||||
ARG->m_logFilter = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
|
||||
// save listen address
|
||||
try {
|
||||
s_synergyAddress = CNetworkAddress(argv[i + 1], kDefaultPort);
|
||||
ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
|
||||
kDefaultPort);
|
||||
}
|
||||
catch (XSocketAddress& e) {
|
||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||
pname, e.what(), pname));
|
||||
ARG->m_pname, e.what(), ARG->m_pname));
|
||||
bye(kExitArgs);
|
||||
}
|
||||
++i;
|
||||
@ -402,11 +379,12 @@ parse(int argc, const char** argv)
|
||||
else if (isArg(i, argc, argv, NULL, "--http", 1)) {
|
||||
// save listen address
|
||||
try {
|
||||
s_httpAddress = CNetworkAddress(argv[i + 1], kDefaultPort + 1);
|
||||
ARG->m_httpAddress = CNetworkAddress(argv[i + 1],
|
||||
kDefaultPort + 1);
|
||||
}
|
||||
catch (XSocketAddress& e) {
|
||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||
pname, e.what(), pname));
|
||||
ARG->m_pname, e.what(), ARG->m_pname));
|
||||
bye(kExitArgs);
|
||||
}
|
||||
++i;
|
||||
@ -414,36 +392,36 @@ parse(int argc, const char** argv)
|
||||
|
||||
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
||||
// save screen name
|
||||
s_name = argv[++i];
|
||||
ARG->m_name = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-c", "--config", 1)) {
|
||||
// save configuration file path
|
||||
s_configFile = argv[++i];
|
||||
ARG->m_configFile = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
||||
// not a daemon
|
||||
s_daemon = false;
|
||||
ARG->m_daemon = false;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
||||
// daemonize
|
||||
s_daemon = true;
|
||||
ARG->m_daemon = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
||||
// don't try to restart
|
||||
s_restartable = false;
|
||||
ARG->m_restartable = false;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
||||
// try to restart
|
||||
s_restartable = true;
|
||||
ARG->m_restartable = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-z", NULL)) {
|
||||
s_backend = true;
|
||||
ARG->m_backend = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-h", "--help")) {
|
||||
@ -464,7 +442,7 @@ parse(int argc, const char** argv)
|
||||
|
||||
else if (argv[i][0] == '-') {
|
||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||
pname, argv[i], pname));
|
||||
ARG->m_pname, argv[i], ARG->m_pname));
|
||||
bye(kExitArgs);
|
||||
}
|
||||
|
||||
@ -477,30 +455,30 @@ parse(int argc, const char** argv)
|
||||
// no non-option arguments are allowed
|
||||
if (i != argc) {
|
||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||
pname, argv[i], pname));
|
||||
ARG->m_pname, argv[i], ARG->m_pname));
|
||||
bye(kExitArgs);
|
||||
}
|
||||
|
||||
// increase default filter level for daemon. the user must
|
||||
// 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 (CPlatform::isWindows95Family()) {
|
||||
if (CArchMiscWindows::isWindows95Family()) {
|
||||
// windows 95 has no place for logging so avoid showing
|
||||
// the log console window.
|
||||
s_logFilter = "FATAL";
|
||||
ARG->m_logFilter = "FATAL";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
s_logFilter = "NOTE";
|
||||
ARG->m_logFilter = "NOTE";
|
||||
}
|
||||
}
|
||||
|
||||
// set log filter
|
||||
if (!CLog::setFilter(s_logFilter)) {
|
||||
if (!CLOG->setFilter(ARG->m_logFilter)) {
|
||||
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
||||
pname, s_logFilter, pname));
|
||||
ARG->m_pname, ARG->m_logFilter, ARG->m_pname));
|
||||
bye(kExitArgs);
|
||||
}
|
||||
}
|
||||
@ -518,14 +496,14 @@ loadConfig(const char* pathname, bool require)
|
||||
if (!configStream) {
|
||||
throw XConfigRead("cannot open file");
|
||||
}
|
||||
configStream >> s_config;
|
||||
configStream >> ARG->m_config;
|
||||
LOG((CLOG_DEBUG "configuration read successfully"));
|
||||
return true;
|
||||
}
|
||||
catch (XConfigRead& e) {
|
||||
if (require) {
|
||||
LOG((CLOG_PRINT "%s: cannot read configuration '%s': %s",
|
||||
pname, pathname, e.what()));
|
||||
ARG->m_pname, pathname, e.what()));
|
||||
bye(kExitConfig);
|
||||
}
|
||||
else {
|
||||
@ -541,36 +519,46 @@ void
|
||||
loadConfig()
|
||||
{
|
||||
// load the config file, if specified
|
||||
if (s_configFile != NULL) {
|
||||
if (ARG->m_configFile != NULL) {
|
||||
// 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
|
||||
else {
|
||||
// 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.
|
||||
CPlatform platform;
|
||||
bool loaded = false;
|
||||
CString path = platform.getUserDirectory();
|
||||
CString path = ARCH->getUserDirectory();
|
||||
if (!path.empty()) {
|
||||
// complete path
|
||||
path = platform.addPathComponent(path, USR_CONFIG_NAME);
|
||||
path = ARCH->concatPath(path, USR_CONFIG_NAME);
|
||||
|
||||
// now try loading the user's configuration
|
||||
loaded = loadConfig(path.c_str(), false);
|
||||
}
|
||||
if (!loaded) {
|
||||
// try the system-wide config file
|
||||
path = platform.getSystemDirectory();
|
||||
path = ARCH->getSystemDirectory();
|
||||
if (!path.empty()) {
|
||||
path = platform.addPathComponent(path, SYS_CONFIG_NAME);
|
||||
path = ARCH->concatPath(path, SYS_CONFIG_NAME);
|
||||
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
|
||||
//
|
||||
@ -581,24 +569,41 @@ loadConfig()
|
||||
|
||||
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
|
||||
logMessageBox(int priority, const char* msg)
|
||||
CMessageBoxOutputter::write(ELevel level, const char* message)
|
||||
{
|
||||
// note any important messages the user may need to know about
|
||||
if (priority <= CLog::kWARNING) {
|
||||
if (level <= CLog::kWARNING) {
|
||||
s_hasImportantLogMessages = true;
|
||||
}
|
||||
|
||||
// FATAL and PRINT messages get a dialog box if not running as
|
||||
// backend. if we're running as a backend the user will have
|
||||
// a chance to see the messages when we exit.
|
||||
if (!s_backend && priority <= CLog::kFATAL) {
|
||||
MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING);
|
||||
return true;
|
||||
if (!ARG->m_backend && level <= CLog::kFATAL) {
|
||||
MessageBox(NULL, message, ARG->m_pname, MB_OK | MB_ICONWARNING);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -606,7 +611,7 @@ static
|
||||
void
|
||||
byeThrow(int x)
|
||||
{
|
||||
throw CWin32Platform::CDaemonFailed(x);
|
||||
CArchMiscWindows::daemonFailed(x);
|
||||
}
|
||||
|
||||
static
|
||||
@ -618,10 +623,9 @@ daemonStop(void)
|
||||
|
||||
static
|
||||
int
|
||||
daemonStartup(IPlatform* iplatform, int argc, const char** argv)
|
||||
daemonStartup(int argc, const char** argv)
|
||||
{
|
||||
// get platform pointer
|
||||
CWin32Platform* platform = static_cast<CWin32Platform*>(iplatform);
|
||||
useSystemLog();
|
||||
|
||||
// catch errors that would normally exit
|
||||
bye = &byeThrow;
|
||||
@ -630,38 +634,38 @@ daemonStartup(IPlatform* iplatform, int argc, const char** argv)
|
||||
parse(argc, argv);
|
||||
|
||||
// cannot run as backend if running as a service
|
||||
s_backend = false;
|
||||
ARG->m_backend = false;
|
||||
|
||||
// load configuration
|
||||
loadConfig();
|
||||
|
||||
// run as a service
|
||||
return platform->runDaemon(realMain, daemonStop);
|
||||
return CArchMiscWindows::runDaemon(realMain, daemonStop);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
daemonStartup95(IPlatform*, int, const char**)
|
||||
daemonStartup95(int, const char**)
|
||||
{
|
||||
return realMain(NULL);
|
||||
useSystemLog();
|
||||
return realMain();
|
||||
}
|
||||
|
||||
int WINAPI
|
||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
{
|
||||
CPlatform platform;
|
||||
CArch arch;
|
||||
CLOG;
|
||||
CArgs args;
|
||||
|
||||
// save instance
|
||||
CMSWindowsScreen::init(instance);
|
||||
|
||||
// get program name
|
||||
pname = platform.getBasename(__argv[0]);
|
||||
|
||||
// initialize network library
|
||||
CNetwork::init();
|
||||
ARG->m_pname = ARCH->getBasename(__argv[0]);
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||
// of the service code path.
|
||||
if (__argc <= 1 && !CWin32Platform::isWindows95Family()) {
|
||||
int result = platform.daemonize(DAEMON_NAME, &daemonStartup);
|
||||
if (result == -1) {
|
||||
LOG((CLOG_CRIT "failed to start as a service" BYE, pname));
|
||||
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||
try {
|
||||
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||
}
|
||||
catch (XArchDaemon&) {
|
||||
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
||||
return kExitFailed;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// parse command line
|
||||
@ -686,38 +691,36 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
|
||||
// daemonize if requested
|
||||
int result;
|
||||
if (s_daemon) {
|
||||
// redirect log messages
|
||||
platform.installDaemonLogger(DAEMON_NAME);
|
||||
|
||||
if (ARG->m_daemon) {
|
||||
// start as a daemon
|
||||
if (CWin32Platform::isWindows95Family()) {
|
||||
result = platform.daemonize(DAEMON_NAME, &daemonStartup95);
|
||||
if (result == -1) {
|
||||
LOG((CLOG_CRIT "failed to start as a service" BYE, pname));
|
||||
if (CArchMiscWindows::isWindows95Family()) {
|
||||
try {
|
||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
||||
}
|
||||
catch (XArchDaemon&) {
|
||||
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
|
||||
result = kExitFailed;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// cannot start a service from the command line so just
|
||||
// run normally (except with log messages redirected).
|
||||
result = realMain(NULL);
|
||||
useSystemLog();
|
||||
result = realMain();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// run
|
||||
result = realMain(NULL);
|
||||
result = realMain();
|
||||
}
|
||||
|
||||
CNetwork::cleanup();
|
||||
|
||||
// let user examine any messages if we're running as a backend
|
||||
// by putting up a dialog box before exiting.
|
||||
if (s_backend && s_hasImportantLogMessages) {
|
||||
if (ARG->m_backend && s_hasImportantLogMessages) {
|
||||
char msg[1024];
|
||||
msg[0] = '\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;
|
||||
@ -727,21 +730,21 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
|
||||
static
|
||||
int
|
||||
daemonStartup(IPlatform*, int, const char**)
|
||||
daemonStartup(int, const char**)
|
||||
{
|
||||
return realMain(NULL);
|
||||
useSystemLog();
|
||||
return realMain();
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
CPlatform platform;
|
||||
CArch arch;
|
||||
CLOG;
|
||||
CArgs args;
|
||||
|
||||
// get program name
|
||||
pname = platform.getBasename(argv[0]);
|
||||
|
||||
// initialize network library
|
||||
CNetwork::init();
|
||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||
|
||||
// parse command line
|
||||
parse(argc, const_cast<const char**>(argv));
|
||||
@ -751,19 +754,19 @@ main(int argc, char** argv)
|
||||
|
||||
// daemonize if requested
|
||||
int result;
|
||||
if (s_daemon) {
|
||||
result = platform.daemonize(DAEMON_NAME, &daemonStartup);
|
||||
if (result == -1) {
|
||||
if (ARG->m_daemon) {
|
||||
try {
|
||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||
}
|
||||
catch (XArchDaemon&) {
|
||||
LOG((CLOG_CRIT "failed to daemonize"));
|
||||
return kExitFailed;
|
||||
result = kExitFailed;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = realMain(NULL);
|
||||
result = realMain();
|
||||
}
|
||||
|
||||
CNetwork::cleanup();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ RSC=rc.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# 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
|
||||
# ADD BASE 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 Target_Dir ""
|
||||
# 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
|
||||
# ADD BASE 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 initialize
|
||||
AC_INIT(lib/base/common.h)
|
||||
AC_INIT(lib/common/common.h)
|
||||
AC_CONFIG_AUX_DIR(config)
|
||||
|
||||
dnl current version
|
||||
@ -99,7 +99,9 @@ LIBS="$NANOSLEEP_LIBS $INET_ATON_LIBS $PTHREAD_LIBS $LIBS"
|
||||
AC_OUTPUT([
|
||||
Makefile
|
||||
lib/Makefile
|
||||
lib/arch/Makefile
|
||||
lib/base/Makefile
|
||||
lib/common/Makefile
|
||||
lib/mt/Makefile
|
||||
lib/io/Makefile
|
||||
lib/http/Makefile
|
||||
|
@ -16,6 +16,8 @@ DEPTH = ..
|
||||
VDEPTH = ./$(VPATH)/$(DEPTH)
|
||||
|
||||
SUBDIRS = \
|
||||
common \
|
||||
arch \
|
||||
base \
|
||||
mt \
|
||||
io \
|
||||
|
576
lib/arch/CArch.cpp
Normal file
576
lib/arch/CArch.cpp
Normal file
@ -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();
|
||||
}
|
163
lib/arch/CArch.h
Normal file
163
lib/arch/CArch.h
Normal file
@ -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
|
54
lib/arch/CArchConsoleUnix.cpp
Normal file
54
lib/arch/CArchConsoleUnix.cpp
Normal file
@ -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";
|
||||
}
|
34
lib/arch/CArchConsoleUnix.h
Normal file
34
lib/arch/CArchConsoleUnix.h
Normal file
@ -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
|
107
lib/arch/CArchConsoleWindows.cpp
Normal file
107
lib/arch/CArchConsoleWindows.cpp
Normal file
@ -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;
|
||||
}
|
47
lib/arch/CArchConsoleWindows.h
Normal file
47
lib/arch/CArchConsoleWindows.h
Normal file
@ -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
|
65
lib/arch/CArchDaemonNone.cpp
Normal file
65
lib/arch/CArchDaemonNone.cpp
Normal file
@ -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;
|
||||
}
|
39
lib/arch/CArchDaemonNone.h
Normal file
39
lib/arch/CArchDaemonNone.h
Normal file
@ -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
|
81
lib/arch/CArchDaemonUnix.cpp
Normal file
81
lib/arch/CArchDaemonUnix.cpp
Normal file
@ -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);
|
||||
}
|
32
lib/arch/CArchDaemonUnix.h
Normal file
32
lib/arch/CArchDaemonUnix.h
Normal file
@ -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
130
lib/arch/CArchDaemonWindows.h
Normal file
130
lib/arch/CArchDaemonWindows.h
Normal file
@ -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
|
94
lib/arch/CArchFileUnix.cpp
Normal file
94
lib/arch/CArchFileUnix.cpp
Normal file
@ -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;
|
||||
}
|
35
lib/arch/CArchFileUnix.h
Normal file
35
lib/arch/CArchFileUnix.h
Normal file
@ -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
|
132
lib/arch/CArchFileWindows.cpp
Normal file
132
lib/arch/CArchFileWindows.cpp
Normal file
@ -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;
|
||||
}
|
35
lib/arch/CArchFileWindows.h
Normal file
35
lib/arch/CArchFileWindows.h
Normal file
@ -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
|
43
lib/arch/CArchImpl.cpp
Normal file
43
lib/arch/CArchImpl.cpp
Normal file
@ -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
|
73
lib/arch/CArchLogUnix.cpp
Normal file
73
lib/arch/CArchLogUnix.cpp
Normal file
@ -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);
|
||||
}
|
33
lib/arch/CArchLogUnix.h
Normal file
33
lib/arch/CArchLogUnix.h
Normal file
@ -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
|
84
lib/arch/CArchLogWindows.cpp
Normal file
84
lib/arch/CArchLogWindows.cpp
Normal file
@ -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
|
||||
}
|
||||
}
|
39
lib/arch/CArchLogWindows.h
Normal file
39
lib/arch/CArchLogWindows.h
Normal file
@ -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
|
53
lib/arch/CArchMiscWindows.cpp
Normal file
53
lib/arch/CArchMiscWindows.cpp
Normal file
@ -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);
|
||||
}
|
48
lib/arch/CArchMiscWindows.h
Normal file
48
lib/arch/CArchMiscWindows.h
Normal file
@ -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
|
748
lib/arch/CArchMultithreadPosix.cpp
Normal file
748
lib/arch/CArchMultithreadPosix.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
93
lib/arch/CArchMultithreadPosix.h
Normal file
93
lib/arch/CArchMultithreadPosix.h
Normal file
@ -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
|
648
lib/arch/CArchMultithreadWindows.cpp
Normal file
648
lib/arch/CArchMultithreadWindows.cpp
Normal file
@ -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);
|
||||
}
|
99
lib/arch/CArchMultithreadWindows.h
Normal file
99
lib/arch/CArchMultithreadWindows.h
Normal file
@ -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
|
847
lib/arch/CArchNetworkBSD.cpp
Normal file
847
lib/arch/CArchNetworkBSD.cpp
Normal file
@ -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]);
|
||||
}
|
||||
}
|
95
lib/arch/CArchNetworkBSD.h
Normal file
95
lib/arch/CArchNetworkBSD.h
Normal file
@ -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
|
838
lib/arch/CArchNetworkWinsock.cpp
Normal file
838
lib/arch/CArchNetworkWinsock.cpp
Normal file
@ -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));
|
||||
}
|
||||
}
|
91
lib/arch/CArchNetworkWinsock.h
Normal file
91
lib/arch/CArchNetworkWinsock.h
Normal file
@ -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
|
88
lib/arch/CArchSleepUnix.cpp
Normal file
88
lib/arch/CArchSleepUnix.cpp
Normal file
@ -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
|
||||
}
|
31
lib/arch/CArchSleepUnix.h
Normal file
31
lib/arch/CArchSleepUnix.h
Normal file
@ -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
|
54
lib/arch/CArchSleepWindows.cpp
Normal file
54
lib/arch/CArchSleepWindows.cpp
Normal file
@ -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();
|
||||
}
|
31
lib/arch/CArchSleepWindows.h
Normal file
31
lib/arch/CArchSleepWindows.h
Normal file
@ -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.
|
||||
*/
|
||||
|
||||
#ifndef CPLATFORM_H
|
||||
#define CPLATFORM_H
|
||||
#include "CArchStringUnix.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "CMultibyte.cpp"
|
||||
|
||||
#if WINDOWS_LIKE
|
||||
//
|
||||
// CArchStringUnix
|
||||
//
|
||||
|
||||
#include "CWin32Platform.h"
|
||||
typedef CWin32Platform CPlatform;
|
||||
CArchStringUnix::CArchStringUnix()
|
||||
{
|
||||
initMB();
|
||||
}
|
||||
|
||||
#elif UNIX_LIKE
|
||||
CArchStringUnix::~CArchStringUnix()
|
||||
{
|
||||
cleanMB();
|
||||
}
|
||||
|
||||
#include "CUnixPlatform.h"
|
||||
typedef CUnixPlatform CPlatform;
|
||||
|
||||
#else
|
||||
|
||||
#error Unsupported platform
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#include "vsnprintf.cpp"
|
38
lib/arch/CArchStringUnix.h
Normal file
38
lib/arch/CArchStringUnix.h
Normal file
@ -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
|
38
lib/arch/CArchStringWindows.cpp
Normal file
38
lib/arch/CArchStringWindows.cpp
Normal file
@ -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"
|
38
lib/arch/CArchStringWindows.h
Normal file
38
lib/arch/CArchStringWindows.h
Normal file
@ -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
|
47
lib/arch/CArchTimeUnix.cpp
Normal file
47
lib/arch/CArchTimeUnix.cpp
Normal file
@ -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;
|
||||
}
|
31
lib/arch/CArchTimeUnix.h
Normal file
31
lib/arch/CArchTimeUnix.h
Normal file
@ -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
|
86
lib/arch/CArchTimeWindows.cpp
Normal file
86
lib/arch/CArchTimeWindows.cpp
Normal file
@ -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());
|
||||
}
|
||||
}
|
31
lib/arch/CArchTimeWindows.h
Normal file
31
lib/arch/CArchTimeWindows.h
Normal file
@ -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
|
40
lib/arch/CMultibyte.cpp
Normal file
40
lib/arch/CMultibyte.cpp
Normal file
@ -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
|
81
lib/arch/CMultibyteEmu.cpp
Normal file
81
lib/arch/CMultibyteEmu.cpp
Normal file
@ -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;
|
||||
}
|
68
lib/arch/CMultibyteOS.cpp
Normal file
68
lib/arch/CMultibyteOS.cpp
Normal file
@ -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));
|
||||
}
|
57
lib/arch/IArchConsole.h
Normal file
57
lib/arch/IArchConsole.h
Normal file
@ -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
|
104
lib/arch/IArchDaemon.h
Normal file
104
lib/arch/IArchDaemon.h
Normal file
@ -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
|
59
lib/arch/IArchFile.h
Normal file
59
lib/arch/IArchFile.h
Normal file
@ -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
|
49
lib/arch/IArchLog.h
Normal file
49
lib/arch/IArchLog.h
Normal file
@ -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
|
80
lib/arch/IArchMultithread.h
Normal file
80
lib/arch/IArchMultithread.h
Normal file
@ -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
|
105
lib/arch/IArchNetwork.h
Normal file
105
lib/arch/IArchNetwork.h
Normal file
@ -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
|
38
lib/arch/IArchSleep.h
Normal file
38
lib/arch/IArchSleep.h
Normal file
@ -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
|
61
lib/arch/IArchString.h
Normal file
61
lib/arch/IArchString.h
Normal file
@ -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
|
35
lib/arch/IArchTime.h
Normal file
35
lib/arch/IArchTime.h
Normal file
@ -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
|
96
lib/arch/Makefile.am
Normal file
96
lib/arch/Makefile.am
Normal file
@ -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)
|
33
lib/arch/XArch.cpp
Normal file
33
lib/arch/XArch.cpp
Normal file
@ -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;
|
||||
}
|
165
lib/arch/XArch.h
Normal file
165
lib/arch/XArch.h
Normal file
@ -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.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#ifndef XARCHIMPL_H
|
||||
#define XARCHIMPL_H
|
||||
|
||||
// include appropriate architecture implementation
|
||||
#if WINDOWS_LIKE
|
||||
|
||||
#include "CWin32Platform.cpp"
|
||||
|
||||
# include "XArchWindows.h"
|
||||
#elif UNIX_LIKE
|
||||
|
||||
#include "CUnixPlatform.cpp"
|
||||
|
||||
#else
|
||||
|
||||
#error Unsupported platform
|
||||
# include "XArchUnix.h"
|
||||
#endif
|
||||
|
||||
#endif
|
33
lib/arch/XArchUnix.cpp
Normal file
33
lib/arch/XArchUnix.cpp
Normal file
@ -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);
|
||||
}
|
34
lib/arch/XArchUnix.h
Normal file
34
lib/arch/XArchUnix.h
Normal file
@ -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
|
126
lib/arch/XArchWindows.cpp
Normal file
126
lib/arch/XArchWindows.cpp
Normal file
@ -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";
|
||||
}
|
52
lib/arch/XArchWindows.h
Normal file
52
lib/arch/XArchWindows.h
Normal file
@ -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
|
269
lib/arch/arch.dsp
Normal file
269
lib/arch/arch.dsp
Normal file
@ -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
|
36
lib/arch/vsnprintf.cpp
Normal file
36
lib/arch/vsnprintf.cpp
Normal file
@ -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 "CString.h"
|
||||
#include "CStringUtil.h"
|
||||
#include "LogOutputters.h"
|
||||
#include "CArch.h"
|
||||
#include "Version.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#if WINDOWS_LIKE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// names of priorities
|
||||
static const char* g_priority[] = {
|
||||
"FATAL",
|
||||
@ -56,26 +54,64 @@ static const int g_prioritySuffixLength = 2;
|
||||
static const int g_priorityPad = g_maxPriorityLength +
|
||||
g_prioritySuffixLength;
|
||||
|
||||
// platform newline sequence
|
||||
#if WINDOWS_LIKE
|
||||
static const char* g_newline = "\r\n";
|
||||
#else
|
||||
static const char* g_newline = "\n";
|
||||
#endif
|
||||
//
|
||||
// CLogLock
|
||||
//
|
||||
// Convenience object to lock/unlock a mutex.
|
||||
//
|
||||
|
||||
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::Outputter CLog::s_outputter = NULL;
|
||||
CLog::Lock CLog::s_lock = &CLog::dummyLock;
|
||||
int CLog::s_maxPriority = -1;
|
||||
CLog* CLog::s_log = NULL;
|
||||
|
||||
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
|
||||
CLog::print(const char* fmt, ...)
|
||||
CLog::print(const char* fmt, ...) const
|
||||
{
|
||||
// check if fmt begins with a priority argument
|
||||
int priority = 4;
|
||||
@ -85,7 +121,7 @@ CLog::print(const char* fmt, ...)
|
||||
}
|
||||
|
||||
// done if below priority threshold
|
||||
if (priority > getMaxPriority()) {
|
||||
if (priority > getFilter()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -98,7 +134,7 @@ CLog::print(const char* fmt, ...)
|
||||
va_start(args, fmt);
|
||||
char* buffer = CStringUtil::vsprint(stack,
|
||||
sizeof(stack) / sizeof(stack[0]),
|
||||
pad, g_newlineLength, fmt, args);
|
||||
pad, m_maxNewlineLength, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// output buffer
|
||||
@ -110,7 +146,7 @@ CLog::print(const char* fmt, ...)
|
||||
}
|
||||
|
||||
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
|
||||
int priority = 4;
|
||||
@ -120,7 +156,7 @@ CLog::printt(const char* file, int line, const char* fmt, ...)
|
||||
}
|
||||
|
||||
// done if below priority threshold
|
||||
if (priority > getMaxPriority()) {
|
||||
if (priority > getFilter()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -136,7 +172,7 @@ CLog::printt(const char* file, int line, const char* fmt, ...)
|
||||
va_start(args, fmt);
|
||||
char* buffer = CStringUtil::vsprint(stack,
|
||||
sizeof(stack) / sizeof(stack[0]),
|
||||
pad, g_newlineLength, fmt, args);
|
||||
pad, m_maxNewlineLength, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// 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
|
||||
CLog::setOutputter(Outputter outputter)
|
||||
CLog::insert(ILogOutputter* outputter)
|
||||
{
|
||||
CHoldLock lock(s_lock);
|
||||
s_outputter = outputter;
|
||||
}
|
||||
assert(outputter != NULL);
|
||||
assert(outputter->getNewline() != NULL);
|
||||
|
||||
CLog::Outputter
|
||||
CLog::getOutputter()
|
||||
{
|
||||
CHoldLock lock(s_lock);
|
||||
return s_outputter;
|
||||
CLogLock lock(m_mutex);
|
||||
m_outputters.push_front(outputter);
|
||||
int newlineLength = strlen(outputter->getNewline());
|
||||
if (newlineLength > m_maxNewlineLength) {
|
||||
m_maxNewlineLength = newlineLength;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CLog::setLock(Lock newLock)
|
||||
CLog::remove(ILogOutputter* outputter)
|
||||
{
|
||||
CHoldLock lock(s_lock);
|
||||
s_lock = (newLock == NULL) ? dummyLock : newLock;
|
||||
CLogLock lock(m_mutex);
|
||||
m_outputters.remove(outputter);
|
||||
}
|
||||
|
||||
CLog::Lock
|
||||
CLog::getLock()
|
||||
void
|
||||
CLog::pop_front()
|
||||
{
|
||||
CHoldLock lock(s_lock);
|
||||
return (s_lock == dummyLock) ? NULL : s_lock;
|
||||
CLogLock lock(m_mutex);
|
||||
if (!m_outputters.empty()) {
|
||||
delete m_outputters.front();
|
||||
m_outputters.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -203,38 +242,19 @@ CLog::setFilter(const char* maxPriority)
|
||||
void
|
||||
CLog::setFilter(int maxPriority)
|
||||
{
|
||||
CHoldLock lock(s_lock);
|
||||
s_maxPriority = maxPriority;
|
||||
CLogLock lock(m_mutex);
|
||||
m_maxPriority = maxPriority;
|
||||
}
|
||||
|
||||
int
|
||||
CLog::getFilter()
|
||||
CLog::getFilter() const
|
||||
{
|
||||
CHoldLock lock(s_lock);
|
||||
return getMaxPriority();
|
||||
CLogLock lock(m_mutex);
|
||||
return m_maxPriority;
|
||||
}
|
||||
|
||||
void
|
||||
CLog::dummyLock(bool)
|
||||
{
|
||||
// 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)
|
||||
CLog::output(int priority, char* msg) const
|
||||
{
|
||||
assert(priority >= -1 && priority < g_numPriority);
|
||||
assert(msg != NULL);
|
||||
@ -249,79 +269,23 @@ CLog::output(int priority, char* msg)
|
||||
msg[g_maxPriorityLength + 1] = ' ';
|
||||
}
|
||||
|
||||
// put a newline at the end
|
||||
strcat(msg + g_priorityPad, g_newline);
|
||||
// write to each outputter
|
||||
CLogLock lock(m_mutex);
|
||||
for (COutputterList::const_iterator index = m_outputters.begin();
|
||||
index != m_outputters.end(); ++index) {
|
||||
// get outputter
|
||||
ILogOutputter* outputter = *index;
|
||||
|
||||
// put an appropriate newline at the end
|
||||
strcat(msg + g_priorityPad, outputter->getNewline());
|
||||
|
||||
// print it
|
||||
CHoldLock lock(s_lock);
|
||||
if (s_outputter == NULL ||
|
||||
!s_outputter(priority, msg + g_maxPriorityLength - n)) {
|
||||
#if WINDOWS_LIKE
|
||||
openConsole();
|
||||
#endif
|
||||
fprintf(stderr, "%s", msg + g_maxPriorityLength - n);
|
||||
// open the outputter
|
||||
outputter->open(kApplication);
|
||||
|
||||
// write message and break out of loop if it returns false
|
||||
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
|
||||
|
||||
#include "common.h"
|
||||
#include "IArchMultithread.h"
|
||||
#include "IInterface.h"
|
||||
#include "stdlist.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#define CLOG (CLog::getInstance())
|
||||
|
||||
class ILogOutputter;
|
||||
|
||||
//! Logging facility
|
||||
/*!
|
||||
The logging class; all console output should go through this class.
|
||||
@ -42,56 +49,51 @@ public:
|
||||
kDEBUG2 //!< For even more detailed debugging messages
|
||||
};
|
||||
|
||||
//! Outputter function.
|
||||
/*!
|
||||
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);
|
||||
~CLog();
|
||||
|
||||
//! @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
|
||||
is called with the formatted string to write and the priority level.
|
||||
CLog will have already filtered messages below the current filter
|
||||
priority. A NULL outputter means to use the default which is to print
|
||||
to stderr. Note that the outputter should not call CLog methods but,
|
||||
if it does, the current lock function must permit recursive locks.
|
||||
*/
|
||||
static void setOutputter(Outputter);
|
||||
Inserts an outputter to the head of the outputter list. When the
|
||||
logger writes a message, it goes to the outputter at the head of
|
||||
the outputter list. If that outputter's \c write() method returns
|
||||
true then it also goes to the next outputter, as so on until an
|
||||
outputter returns false or there are no more outputters. Outputters
|
||||
still in the outputter list when the log is destroyed will be
|
||||
deleted.
|
||||
|
||||
//! Set the lock/unlock function
|
||||
/*!
|
||||
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.
|
||||
By default, the logger has one outputter installed which writes to
|
||||
the console.
|
||||
*/
|
||||
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 filter. Messages below this priority are discarded.
|
||||
The default priority is 4 (INFO) (unless built without NDEBUG
|
||||
in which case it's 5 (DEBUG)). The default can be overridden
|
||||
by setting the SYN_LOG_PRI env var to "FATAL", "ERROR", etc.
|
||||
setFilter(const char*) returns true if the priority \c name was
|
||||
recognized; if \c name is NULL then it simply returns true.
|
||||
in which case it's 5 (DEBUG)). setFilter(const char*) returns
|
||||
true if the priority \c name was recognized; if \c name is NULL
|
||||
then it simply returns true.
|
||||
*/
|
||||
static bool setFilter(const char* name);
|
||||
static void setFilter(int);
|
||||
bool setFilter(const char* name);
|
||||
void setFilter(int);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
@ -101,52 +103,38 @@ public:
|
||||
/*!
|
||||
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 using the printf-like \c format and arguments
|
||||
preceded by the filename and line number.
|
||||
*/
|
||||
static void printt(const char* file, int line,
|
||||
const char* format, ...);
|
||||
|
||||
//! 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();
|
||||
void printt(const char* file, int line,
|
||||
const char* format, ...) const;
|
||||
|
||||
//! Get the minimum priority level.
|
||||
static int getFilter();
|
||||
int getFilter() const;
|
||||
|
||||
//! Get the singleton instance of the log
|
||||
static CLog* getInstance();
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
class CHoldLock {
|
||||
public:
|
||||
CHoldLock(Lock lock) : m_lock(lock) { m_lock(true); }
|
||||
~CHoldLock() { m_lock(false); }
|
||||
CLog();
|
||||
|
||||
private:
|
||||
Lock m_lock;
|
||||
};
|
||||
|
||||
static void dummyLock(bool);
|
||||
static int getMaxPriority();
|
||||
static void output(int priority, char* msg);
|
||||
#if WINDOWS_LIKE
|
||||
static void openConsole();
|
||||
#endif
|
||||
void output(int priority, char* msg) const;
|
||||
|
||||
private:
|
||||
static Outputter s_outputter;
|
||||
static Lock s_lock;
|
||||
static int s_maxPriority;
|
||||
typedef std::list<ILogOutputter*> COutputterList;
|
||||
|
||||
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 CLOG_TRACE
|
||||
#elif defined(NDEBUG)
|
||||
#define LOG(_a1) CLog::print _a1
|
||||
#define LOGC(_a1, _a2) if (_a1) CLog::print _a2
|
||||
#define LOG(_a1) CLOG->print _a1
|
||||
#define LOGC(_a1, _a2) if (_a1) CLOG->print _a2
|
||||
#define CLOG_TRACE
|
||||
#else
|
||||
#define LOG(_a1) CLog::printt _a1
|
||||
#define LOGC(_a1, _a2) if (_a1) CLog::printt _a2
|
||||
#define LOG(_a1) CLOG->printt _a1
|
||||
#define LOGC(_a1, _a2) if (_a1) CLOG->printt _a2
|
||||
#define CLOG_TRACE __FILE__, __LINE__,
|
||||
#endif
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "CStopwatch.h"
|
||||
#include "CArch.h"
|
||||
|
||||
//
|
||||
// CStopwatch
|
||||
@ -24,7 +25,7 @@ CStopwatch::CStopwatch(bool triggered) :
|
||||
m_stopped(triggered)
|
||||
{
|
||||
if (!triggered) {
|
||||
m_mark = getClock();
|
||||
m_mark = ARCH->time();
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +43,7 @@ CStopwatch::reset()
|
||||
return dt;
|
||||
}
|
||||
else {
|
||||
const double t = getClock();
|
||||
const double t = ARCH->time();
|
||||
const double dt = t - m_mark;
|
||||
m_mark = t;
|
||||
return dt;
|
||||
@ -57,7 +58,7 @@ CStopwatch::stop()
|
||||
}
|
||||
|
||||
// save the elapsed time
|
||||
m_mark = getClock() - m_mark;
|
||||
m_mark = ARCH->time() - m_mark;
|
||||
m_stopped = true;
|
||||
}
|
||||
|
||||
@ -70,7 +71,7 @@ CStopwatch::start()
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -93,7 +94,7 @@ CStopwatch::getTime()
|
||||
return m_mark;
|
||||
}
|
||||
else {
|
||||
return getClock() - m_mark;
|
||||
return ARCH->time() - m_mark;
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,7 +116,7 @@ CStopwatch::getTime() const
|
||||
return m_mark;
|
||||
}
|
||||
else {
|
||||
return getClock() - m_mark;
|
||||
return ARCH->time() - m_mark;
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,100 +124,3 @@ CStopwatch::operator double() const
|
||||
{
|
||||
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
|
||||
#define CSTRING_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "stdpre.h"
|
||||
#include <string>
|
||||
#include "stdpost.h"
|
||||
#include "stdstring.h"
|
||||
|
||||
// use standard C++ string class for our string class
|
||||
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
|
||||
|
||||
|
@ -12,7 +12,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "CString.h"
|
||||
#include "CStringUtil.h"
|
||||
#include "CArch.h"
|
||||
#include "common.h"
|
||||
#include "stdvector.h"
|
||||
#include <cctype>
|
||||
@ -20,12 +21,6 @@
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
#if WINDOWS_LIKE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
//
|
||||
// CStringUtil
|
||||
//
|
||||
@ -152,7 +147,8 @@ CStringUtil::vsprint(char* buffer, int len,
|
||||
// try writing to input buffer
|
||||
int n;
|
||||
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))
|
||||
return buffer;
|
||||
}
|
||||
@ -163,7 +159,8 @@ CStringUtil::vsprint(char* buffer, int len,
|
||||
delete[] buffer;
|
||||
len *= 2;
|
||||
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));
|
||||
|
||||
return buffer;
|
99
lib/base/CStringUtil.h
Normal file
99
lib/base/CStringUtil.h
Normal file
@ -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 <limits.h>
|
||||
#include "CArch.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
|
||||
@ -274,14 +221,12 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||
wchar_t* tmp = UTF8ToWideChar(src, size, errors);
|
||||
|
||||
// get length of multibyte string
|
||||
char mbc[MB_LEN_MAX];
|
||||
size_t mblen;
|
||||
mbstate_t state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
int mblen;
|
||||
CArchMBState state = ARCH->newMBState();
|
||||
size_t len = 0;
|
||||
UInt32 n = size;
|
||||
for (const wchar_t* scan = tmp; n > 0; ++scan, --n) {
|
||||
mblen = wcrtomb(mbc, *scan, &state);
|
||||
mblen = ARCH->convWCToMB(NULL, *scan, state);
|
||||
if (mblen == -1) {
|
||||
// unconvertable character
|
||||
setError(errors);
|
||||
@ -293,11 +238,11 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||
}
|
||||
|
||||
// handle nul terminator
|
||||
mblen = wcrtomb(mbc, L'\0', &state);
|
||||
mblen = ARCH->convWCToMB(NULL, L'\0', state);
|
||||
if (mblen != -1) {
|
||||
len += mblen;
|
||||
}
|
||||
assert(mbsinit(&state) != 0);
|
||||
assert(ARCH->isInitMBState(state) != 0);
|
||||
|
||||
// allocate multibyte string
|
||||
char* mbs = new char[len];
|
||||
@ -306,7 +251,7 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||
char* dst = mbs;
|
||||
n = size;
|
||||
for (const wchar_t* scan = tmp; n > 0; ++scan, --n) {
|
||||
mblen = wcrtomb(dst, *scan, &state);
|
||||
mblen = ARCH->convWCToMB(dst, *scan, state);
|
||||
if (mblen == -1) {
|
||||
// unconvertable character
|
||||
*dst++ = '?';
|
||||
@ -315,7 +260,7 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||
dst += mblen;
|
||||
}
|
||||
}
|
||||
mblen = wcrtomb(dst, L'\0', &state);
|
||||
mblen = ARCH->convWCToMB(dst, L'\0', state);
|
||||
if (mblen != -1) {
|
||||
// don't include nul terminator
|
||||
dst += mblen - 1;
|
||||
@ -325,6 +270,7 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||
// clean up
|
||||
delete[] mbs;
|
||||
delete[] tmp;
|
||||
ARCH->closeMBState(state);
|
||||
|
||||
return text;
|
||||
}
|
||||
@ -382,19 +328,18 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||
// get length of multibyte string
|
||||
UInt32 n = src.size();
|
||||
size_t len = 0;
|
||||
mbstate_t state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
CArchMBState state = ARCH->newMBState();
|
||||
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) {
|
||||
case (size_t)-2:
|
||||
case -2:
|
||||
// incomplete last character. convert to unknown character.
|
||||
setError(errors);
|
||||
len += 1;
|
||||
n = 0;
|
||||
break;
|
||||
|
||||
case (size_t)-1:
|
||||
case -1:
|
||||
// invalid character. count one unknown character and
|
||||
// start at the next byte.
|
||||
setError(errors);
|
||||
@ -417,7 +362,7 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||
break;
|
||||
}
|
||||
}
|
||||
memset(&state, 0, sizeof(state));
|
||||
ARCH->initMBState(state);
|
||||
|
||||
// allocate wide character string
|
||||
wchar_t* wcs = new wchar_t[len];
|
||||
@ -426,15 +371,15 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||
n = src.size();
|
||||
wchar_t* dst = wcs;
|
||||
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) {
|
||||
case (size_t)-2:
|
||||
case -2:
|
||||
// incomplete character. convert to unknown character.
|
||||
*dst = (wchar_t)0xfffd;
|
||||
n = 0;
|
||||
break;
|
||||
|
||||
case (size_t)-1:
|
||||
case -1:
|
||||
// invalid character. count one unknown character and
|
||||
// start at the next byte.
|
||||
*dst = (wchar_t)0xfffd;
|
@ -17,7 +17,6 @@
|
||||
|
||||
#include "CString.h"
|
||||
#include "BasicTypes.h"
|
||||
#include <cwchar>
|
||||
|
||||
//! Unicode utility functions
|
||||
/*!
|
71
lib/base/ILogOutputter.h
Normal file
71
lib/base/ILogOutputter.h
Normal file
@ -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 \
|
||||
CLog.cpp \
|
||||
CStopwatch.cpp \
|
||||
CString.cpp \
|
||||
CStringUtil.cpp \
|
||||
CUnicode.cpp \
|
||||
LogOutputters.cpp \
|
||||
XBase.cpp \
|
||||
BasicTypes.h \
|
||||
CFunctionJob.h \
|
||||
CLog.h \
|
||||
CStopwatch.h \
|
||||
CString.h \
|
||||
IInterface.h \
|
||||
CStringUtil.h \
|
||||
CUnicode.h \
|
||||
IJob.h \
|
||||
ILogOutputter.h \
|
||||
LogOutputters.h \
|
||||
TMethodJob.h \
|
||||
Version.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)
|
||||
INCLUDES = \
|
||||
-I$(VDEPTH)/lib/common \
|
||||
-I$(VDEPTH)/lib/arch \
|
||||
$(NULL)
|
||||
|
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "XBase.h"
|
||||
#include "CStringUtil.h"
|
||||
#include <cerrno>
|
||||
#include <cstdarg>
|
||||
|
||||
@ -79,65 +80,3 @@ XBase::format(const char* /*id*/, const char* fmt, ...) const throw()
|
||||
|
||||
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
|
||||
|
||||
#include "CString.h"
|
||||
/*
|
||||
#include "stdpre.h"
|
||||
#include <exception>
|
||||
#include "stdpost.h"
|
||||
*/
|
||||
|
||||
//! Exception base class
|
||||
/*!
|
||||
@ -52,33 +54,73 @@ private:
|
||||
mutable CString m_what;
|
||||
};
|
||||
|
||||
//! Mix-in for handling \c errno
|
||||
/*!
|
||||
This mix-in class for exception classes provides storage and query of
|
||||
\c errno. On Windows, it uses GetLastError() instead of errno.
|
||||
\def XBASE_SUBCLASS
|
||||
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 {
|
||||
public:
|
||||
//! Save \c errno as the error code
|
||||
MXErrno();
|
||||
//! Save \c err as the error code
|
||||
MXErrno(int err);
|
||||
virtual ~MXErrno();
|
||||
#define XBASE_SUBCLASS(name_, super_) \
|
||||
class name_ : public super_ { \
|
||||
public: \
|
||||
name_() : super_() { } \
|
||||
name_(const CString& msg) : super_(msg) { } \
|
||||
}
|
||||
|
||||
//! @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;
|
||||
|
||||
//! Get the human readable string for the error code
|
||||
virtual const char* getErrstr() const;
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
int m_errno;
|
||||
mutable char* m_string;
|
||||
};
|
||||
/*!
|
||||
\def XBASE_SUBCLASS_FORMAT
|
||||
Convenience macro to subclass from XBase (or a subclass of it),
|
||||
providing the c'tor taking a const CString&. what() is overridden
|
||||
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.
|
||||
*/
|
||||
#define XBASE_SUBCLASS_FORMAT(name_, super_) \
|
||||
class name_ : public super_ { \
|
||||
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
|
||||
|
@ -41,7 +41,7 @@ RSC=rc.exe
|
||||
# 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 /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
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
@ -65,7 +65,7 @@ LIB32=link.exe -lib
|
||||
# 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 /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
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
@ -99,7 +99,15 @@ SOURCE=.\CStopwatch.cpp
|
||||
# End 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
|
||||
# Begin Source File
|
||||
|
||||
@ -111,10 +119,6 @@ SOURCE=.\XBase.cpp
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\BasicTypes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CFunctionJob.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -123,10 +127,6 @@ SOURCE=.\CLog.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\common.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CStopwatch.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -135,7 +135,11 @@ SOURCE=.\CString.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IInterface.h
|
||||
SOURCE=.\CStringUtil.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CUnicode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
@ -143,43 +147,11 @@ SOURCE=.\IJob.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stdfstream.h
|
||||
SOURCE=.\ILogOutputter.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stdistream.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
|
||||
SOURCE=.\LogOutputters.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
@ -187,10 +159,6 @@ SOURCE=.\TMethodJob.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Version.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\XBase.h
|
||||
# End Source File
|
||||
# End Group
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "CLog.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CArch.h"
|
||||
|
||||
//
|
||||
// CClient
|
||||
@ -545,7 +546,7 @@ CClient::runServer()
|
||||
break;
|
||||
}
|
||||
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.
|
||||
if (!m_camp) {
|
||||
@ -553,7 +554,7 @@ CClient::runServer()
|
||||
}
|
||||
|
||||
// we're camping. wait a bit before retrying
|
||||
CThread::sleep(15.0);
|
||||
ARCH->sleep(15.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,10 @@
|
||||
|
||||
#include "CMSWindowsSecondaryScreen.h"
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "CPlatform.h"
|
||||
#include "XScreen.h"
|
||||
#include "CLock.h"
|
||||
#include "CLog.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include <cctype>
|
||||
|
||||
// these are only defined when WINVER >= 0x0500
|
||||
@ -34,7 +34,7 @@
|
||||
|
||||
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen(
|
||||
IScreenReceiver* receiver) :
|
||||
m_is95Family(CPlatform::isWindows95Family()),
|
||||
m_is95Family(CArchMiscWindows::isWindows95Family()),
|
||||
m_window(NULL),
|
||||
m_mask(0)
|
||||
{
|
||||
|
@ -38,6 +38,8 @@ libclient_a_SOURCES = \
|
||||
ISecondaryScreenFactory.h \
|
||||
$(NULL)
|
||||
INCLUDES = \
|
||||
-I$(VDEPTH)/lib/common \
|
||||
-I$(VDEPTH)/lib/arch \
|
||||
-I$(VDEPTH)/lib/base \
|
||||
-I$(VDEPTH)/lib/mt \
|
||||
-I$(VDEPTH)/lib/io \
|
||||
|
@ -41,7 +41,7 @@ RSC=rc.exe
|
||||
# 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 "..\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
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
@ -65,7 +65,7 @@ LIB32=link.exe -lib
|
||||
# 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 "..\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
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
|
45
lib/common/Makefile.am
Normal file
45
lib/common/Makefile.am
Normal file
@ -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
Block a user