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:
crs 2003-01-04 22:01:32 +00:00
parent 62303391a8
commit f65921bc3f
169 changed files with 9676 additions and 5601 deletions

74
PORTING
View File

@ -10,16 +10,19 @@ The synergy source code organization is:
. -- root makefiles, some standard documentation . -- root makefiles, some standard documentation
cmd -- program source code cmd -- program source code
synergy -- synergy client launcher -- synergy launcher for Windows
synergyd -- synergy server synergyc -- synergy client
synergys -- synergy server
config -- stuff for autoconf/automake config -- stuff for autoconf/automake
dist -- files for creating distributions dist -- files for creating distributions
rpm -- files for creating RPMs rpm -- files for creating RPMs
doc -- placeholder for documentation doc -- placeholder for documentation
examples -- example files examples -- example files
lib -- library source code lib -- library source code
arch -- platform dependent utility library
base -- simple utilities base -- simple utilities
client -- synergy client library client -- synergy client library
common -- commonly needed header files
http -- simple http tools http -- simple http tools
io -- I/O io -- I/O
mt -- multithreading mt -- multithreading
@ -130,7 +133,7 @@ following these guidelines.
* Other headers in directory, sorted alphabetically * Other headers in directory, sorted alphabetically
* Headers for each library, sorted alphabetically per library * Headers for each library, sorted alphabetically per library
Include headers from the library closest in the dependency graph Include headers from the library closest in the dependency graph
first, then the next farthest, etc. sort alphabetically within first, then the next farthest, etc. Sort alphabetically within
each library. each library.
* System headers * System headers
@ -181,12 +184,8 @@ following these guidelines.
Inheriting implementation from multiple classes can have unpleasant Inheriting implementation from multiple classes can have unpleasant
consequences in C++ due to it's limited capabilities. Classes can consequences in C++ due to it's limited capabilities. Classes can
inherit from any number of interface classes. An interface class inherit from any number of interface classes. An interface class
provides only pure virtual methods. provides only pure virtual methods. Synergy breaks this rule in
IInterface which implements the virtual destructor for convenience.
Synergy breaks this rule in two places. First is that IInterface
implements the virtual destructor. However, it's just an empty
method so it doesn't really count. Second is MXErrno which provides
implementation for exceptions that use the global errno variable.
* No globals * No globals
Avoid global variables. All global variables must be static, making Avoid global variables. All global variables must be static, making
@ -272,18 +271,20 @@ following these guidelines.
* Open brace for function is on a line by itself in first column * Open brace for function is on a line by itself in first column
* Close brace for function lines up with open brace * Close brace for function lines up with open brace
* Always use braces on: if, else, for, while, do, switch * Always use braces on: if, else, for, while, do, switch
* `else {' goes on it's own line * `else {' goes on its own line
* Always explicitly test pointers against NULL * Always explicitly test pointers against NULL
e.g. `if (ptr == NULL)' not `if (ptr)' e.g. `if (ptr == NULL)' not `if (ptr)'
* Always explicitly test integral values against 0
e.g. `if (i == 0)' not `if (i)'
* Put spaces around binary operators and after statements * Put spaces around binary operators and after statements
e.g. `if (a == b) {' not `if(a==b){' e.g. `if (a == b) {' not `if(a==b){'
* C'tor initializers are one per line, indented one tab stop * C'tor initializers are one per line, indented one tab stop
* Other indentation should follow existing practice * Other indentation should follow existing practice
* Use Qt style comments for extraction by doxygen * Use Qt style comments for extraction by doxygen (i.e. //! and /*!)
* Mark incomplete or buggy code with `FIXME' * Mark incomplete or buggy code with `FIXME'
- Other - Other
* calls to log() should always be all on one line (even past column 80) * calls to LOG() should always be all on one line (even past column 80)
Class Relationships Class Relationships
@ -300,4 +301,51 @@ FIXME -- high level overview of class relationships
Portability Portability
----------- -----------
FIXME -- information about porting to new platforms Porting synergy to a new platform requires the following steps:
- Setting up the build
- Adjusting lib/common/common.h
- Implementing lib/arch
- Implementing lib/platform
- Implementing primary and secondary screens for the platform
- Tweaking synergyc and synergys
Setting up the build:
The first phase is simply to create the files necessary to build the
other files. On Unix, synergy uses autoconf/automake which produces
a `configure' script that generates makefiles. On Windows, synergy
uses Visual C++ workspace and project files. If you're porting to
another Unix variant, you may need to adjust `configure.in',
`acinclude.m4', and Unix flavor dependent code in lib/arch.
Adjusting lib/common/common.h:
The lib/common/common.h header file is included directly or indirectly
by every other file. It prepares some platform dependent macros for
integer sizes and defines a macro for conveniently testing which
platform we're building on. That macro is named *_LIKE (e.g. UNIX_LIKE)
and has the value `1'. Exactly one *_LIKE macro must be defined by
common.h.
Implementing lib/arch:
Most platform dependent code lives in lib/arch. There are several
interface classes there and they must all be implemented for each
platform. See the interface header files for more information.
Implementing lib/platform:
Most of the remaining platform dependent code lives in lib/platform.
The code there implements platform dependent window, clipboard, and
screen saver handling. The following interfaces must be implemented:
FIXME
Implementing primary and secondary screens for the platform:
FIXME
Tweaking synergyc and synergys:
FIXME

View File

@ -12,8 +12,11 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include "CPlatform.h"
#include "CLog.h" #include "CLog.h"
#include "ILogOutputter.h"
#include "CArch.h"
#include "CStringUtil.h"
#include "XArch.h"
#include "CAutoStart.h" #include "CAutoStart.h"
#include "LaunchUtil.h" #include "LaunchUtil.h"
#include "resource.h" #include "resource.h"
@ -23,6 +26,37 @@
#define CLIENT_DAEMON_INFO "Shares this system's mouse and keyboard with others." #define CLIENT_DAEMON_INFO "Shares this system's mouse and keyboard with others."
#define SERVER_DAEMON_INFO "Shares this system's mouse and keyboard with others." #define SERVER_DAEMON_INFO "Shares this system's mouse and keyboard with others."
//
// CAutoStartOutputter
//
// This class detects a message above a certain level and saves it
//
class CAutoStartOutputter : public ILogOutputter {
public:
CAutoStartOutputter(CString* msg) : m_msg(msg) { }
virtual ~CAutoStartOutputter() { }
// ILogOutputter overrides
virtual void open(const char*) { }
virtual void close() { }
virtual bool write(ELevel level, const char* message);
virtual const char* getNewline() const { return ""; }
private:
CString* m_msg;
};
bool
CAutoStartOutputter::write(ELevel level, const char* message)
{
if (level <= CLog::kERROR) {
*m_msg = message;
}
return false;
}
// //
// CAutoStart // CAutoStart
// //
@ -51,8 +85,7 @@ void
CAutoStart::doModal() CAutoStart::doModal()
{ {
// install our log outputter // install our log outputter
CLog::Outputter oldOutputter = CLog::getOutputter(); CLOG->insert(new CAutoStartOutputter(&m_errorMessage));
CLog::setOutputter(&CAutoStart::onLog);
// reset saved flag // reset saved flag
m_userConfigSaved = false; m_userConfigSaved = false;
@ -61,8 +94,8 @@ CAutoStart::doModal()
DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_AUTOSTART), DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_AUTOSTART),
m_parent, dlgProc, (LPARAM)this); m_parent, dlgProc, (LPARAM)this);
// restore log outputter // remove log outputter
CLog::setOutputter(oldOutputter); CLOG->pop_front();
} }
bool bool
@ -74,19 +107,16 @@ CAutoStart::wasUserConfigSaved() const
void void
CAutoStart::update() CAutoStart::update()
{ {
// need a platform object
CPlatform platform;
// get installation state // get installation state
const bool installedSystem = platform.isDaemonInstalled( const bool installedSystem = ARCH->isDaemonInstalled(
m_name.c_str(), true); m_name.c_str(), true);
const bool installedUser = platform.isDaemonInstalled( const bool installedUser = ARCH->isDaemonInstalled(
m_name.c_str(), false); m_name.c_str(), false);
// get user's permissions // get user's permissions
const bool canInstallSystem = platform.canInstallDaemon( const bool canInstallSystem = ARCH->canInstallDaemon(
m_name.c_str(), true); m_name.c_str(), true);
const bool canInstallUser = platform.canInstallDaemon( const bool canInstallUser = ARCH->canInstallDaemon(
m_name.c_str(), false); m_name.c_str(), false);
// update messages // update messages
@ -165,22 +195,25 @@ CAutoStart::onInstall(bool allUsers)
m_errorMessage = ""; m_errorMessage = "";
// install // install
CPlatform platform; try {
if (!platform.installDaemon(m_name.c_str(), ARCH->installDaemon(m_name.c_str(),
m_isServer ? SERVER_DAEMON_INFO : CLIENT_DAEMON_INFO, m_isServer ? SERVER_DAEMON_INFO : CLIENT_DAEMON_INFO,
appPath.c_str(), m_cmdLine.c_str(), allUsers)) { appPath.c_str(), m_cmdLine.c_str(), allUsers);
if (m_errorMessage.empty()) {
m_errorMessage = getString(IDS_INSTALL_GENERIC_ERROR);
}
showError(m_hwnd, m_errorMessage);
return false;
}
askOkay(m_hwnd, getString(IDS_INSTALL_TITLE), askOkay(m_hwnd, getString(IDS_INSTALL_TITLE),
getString(allUsers ? getString(allUsers ?
IDS_INSTALLED_SYSTEM : IDS_INSTALLED_SYSTEM :
IDS_INSTALLED_USER)); IDS_INSTALLED_USER));
return true; return true;
}
catch (XArchDaemon& e) {
if (m_errorMessage.empty()) {
m_errorMessage = CStringUtil::format(
getString(IDS_INSTALL_GENERIC_ERROR).c_str(),
e.what().c_str());
}
showError(m_hwnd, m_errorMessage);
return false;
}
} }
bool bool
@ -190,30 +223,23 @@ CAutoStart::onUninstall(bool allUsers)
m_errorMessage = ""; m_errorMessage = "";
// uninstall // uninstall
CPlatform platform; try {
if (platform.uninstallDaemon(m_name.c_str(), allUsers) != ARCH->uninstallDaemon(m_name.c_str(), allUsers);
IPlatform::kSuccess) {
if (m_errorMessage.empty()) {
m_errorMessage = getString(IDS_UNINSTALL_GENERIC_ERROR);
}
showError(m_hwnd, m_errorMessage);
return false;
}
askOkay(m_hwnd, getString(IDS_UNINSTALL_TITLE), askOkay(m_hwnd, getString(IDS_UNINSTALL_TITLE),
getString(allUsers ? getString(allUsers ?
IDS_UNINSTALLED_SYSTEM : IDS_UNINSTALLED_SYSTEM :
IDS_UNINSTALLED_USER)); IDS_UNINSTALLED_USER));
return true; return true;
}
bool
CAutoStart::onLog(int priority, const char* message)
{
if (priority <= CLog::kERROR) {
s_singleton->m_errorMessage = message;
} }
return true; catch (XArchDaemon& e) {
if (m_errorMessage.empty()) {
m_errorMessage = CStringUtil::format(
getString(IDS_UNINSTALL_GENERIC_ERROR).c_str(),
e.what().c_str());
}
showError(m_hwnd, m_errorMessage);
return false;
}
} }
BOOL BOOL

View File

@ -57,9 +57,6 @@ private:
bool onInstall(bool allUsers); bool onInstall(bool allUsers);
bool onUninstall(bool allUsers); bool onUninstall(bool allUsers);
// log handling
static bool onLog(int priority, const char* message);
// message handling // message handling
BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM); BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM); static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);

View File

@ -13,8 +13,8 @@
*/ */
#include "CConfig.h" #include "CConfig.h"
#include "CPlatform.h"
#include "LaunchUtil.h" #include "LaunchUtil.h"
#include "CArch.h"
#include "resource.h" #include "resource.h"
#include "stdfstream.h" #include "stdfstream.h"
@ -107,10 +107,9 @@ CString
getAppPath(const CString& appName) getAppPath(const CString& appName)
{ {
// prepare path to app // prepare path to app
CPlatform platform;
char myPathname[MAX_PATH]; char myPathname[MAX_PATH];
GetModuleFileName(s_instance, myPathname, MAX_PATH); GetModuleFileName(s_instance, myPathname, MAX_PATH);
const char* myBasename = platform.getBasename(myPathname); const char* myBasename = ARCH->getBasename(myPathname);
CString appPath = CString(myPathname, myBasename - myPathname); CString appPath = CString(myPathname, myBasename - myPathname);
appPath += appName; appPath += appName;
return appPath; return appPath;
@ -136,24 +135,20 @@ loadConfig(const CString& pathname, CConfig& config)
bool bool
loadConfig(CConfig& config) loadConfig(CConfig& config)
{ {
CPlatform platform;
// load configuration // load configuration
bool configLoaded = false; bool configLoaded = false;
CString path = platform.getUserDirectory(); CString path = ARCH->getUserDirectory();
if (!path.empty()) { if (!path.empty()) {
CPlatform platform;
// try loading the user's configuration // try loading the user's configuration
path = platform.addPathComponent(path, CONFIG_NAME); path = ARCH->concatPath(path, CONFIG_NAME);
if (loadConfig(path, config)) { if (loadConfig(path, config)) {
configLoaded = true; configLoaded = true;
} }
else { else {
// try the system-wide config file // try the system-wide config file
path = platform.getSystemDirectory(); path = ARCH->getSystemDirectory();
if (!path.empty()) { if (!path.empty()) {
path = platform.addPathComponent(path, CONFIG_NAME); path = ARCH->concatPath(path, CONFIG_NAME);
if (loadConfig(path, config)) { if (loadConfig(path, config)) {
configLoaded = true; configLoaded = true;
} }
@ -183,13 +178,11 @@ saveConfig(const CString& pathname, const CConfig& config)
bool bool
saveConfig(const CConfig& config, bool sysOnly) saveConfig(const CConfig& config, bool sysOnly)
{ {
CPlatform platform;
// try saving the user's configuration // try saving the user's configuration
if (!sysOnly) { if (!sysOnly) {
CString path = platform.getUserDirectory(); CString path = ARCH->getUserDirectory();
if (!path.empty()) { if (!path.empty()) {
path = platform.addPathComponent(path, CONFIG_NAME); path = ARCH->concatPath(path, CONFIG_NAME);
if (saveConfig(path, config)) { if (saveConfig(path, config)) {
return true; return true;
} }
@ -198,9 +191,9 @@ saveConfig(const CConfig& config, bool sysOnly)
// try the system-wide config file // try the system-wide config file
else { else {
CString path = platform.getSystemDirectory(); CString path = ARCH->getSystemDirectory();
if (!path.empty()) { if (!path.empty()) {
path = platform.addPathComponent(path, CONFIG_NAME); path = ARCH->concatPath(path, CONFIG_NAME);
if (saveConfig(path, config)) { if (saveConfig(path, config)) {
return true; return true;
} }

View File

@ -14,9 +14,9 @@
#include "CConfig.h" #include "CConfig.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
#include "CPlatform.h"
#include "CNetwork.h"
#include "CLog.h" #include "CLog.h"
#include "CStringUtil.h"
#include "CArch.h"
#include "Version.h" #include "Version.h"
#include "stdvector.h" #include "stdvector.h"
#include "resource.h" #include "resource.h"
@ -62,10 +62,26 @@ static const char* s_debugName[][2] = {
}; };
static const int s_defaultDebug = 3; // INFO static const int s_defaultDebug = 3; // INFO
static HWND s_mainWindow; //
static CConfig s_config; // program arguments
static CConfig s_oldConfig; //
static CStringList s_screens;
#define ARG CArgs::s_instance
class CArgs {
public:
CArgs() { s_instance = this; }
~CArgs() { s_instance = NULL; }
public:
static CArgs* s_instance;
CConfig m_config;
CConfig m_oldConfig;
CStringList m_screens;
};
CArgs* CArgs::s_instance = NULL;
static static
BOOL CALLBACK BOOL CALLBACK
@ -117,7 +133,7 @@ static
void void
enableSaveControls(HWND hwnd) enableSaveControls(HWND hwnd)
{ {
enableItem(hwnd, IDC_MAIN_SAVE, s_config != s_oldConfig); enableItem(hwnd, IDC_MAIN_SAVE, ARG->m_config != ARG->m_oldConfig);
} }
static static
@ -171,8 +187,8 @@ updateNeighbor(HWND hwnd, const CString& screen, EDirection direction)
// add all screens to combo box // add all screens to combo box
if (!screen.empty()) { if (!screen.empty()) {
for (CConfig::const_iterator index = s_config.begin(); for (CConfig::const_iterator index = ARG->m_config.begin();
index != s_config.end(); ++index) { index != ARG->m_config.end(); ++index) {
SendMessage(hwnd, CB_INSERTSTRING, SendMessage(hwnd, CB_INSERTSTRING,
(WPARAM)-1, (LPARAM)index->c_str()); (WPARAM)-1, (LPARAM)index->c_str());
} }
@ -184,7 +200,7 @@ updateNeighbor(HWND hwnd, const CString& screen, EDirection direction)
// select neighbor in combo box // select neighbor in combo box
LRESULT index = 0; LRESULT index = 0;
if (!screen.empty()) { if (!screen.empty()) {
const CString& neighbor = s_config.getNeighbor(screen, direction); const CString& neighbor = ARG->m_config.getNeighbor(screen, direction);
if (!neighbor.empty()) { if (!neighbor.empty()) {
index = SendMessage(hwnd, CB_FINDSTRINGEXACT, index = SendMessage(hwnd, CB_FINDSTRINGEXACT,
0, (LPARAM)neighbor.c_str()); 0, (LPARAM)neighbor.c_str());
@ -205,7 +221,7 @@ updateNeighbors(HWND hwnd)
HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST); HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0); LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
if (index != LB_ERR) { if (index != LB_ERR) {
screen = s_screens[index]; screen = ARG->m_screens[index];
} }
// set neighbor combo boxes // set neighbor combo boxes
@ -230,7 +246,7 @@ addScreen(HWND hwnd)
if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD), if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
hwnd, addDlgProc, (LPARAM)&info) != 0) { hwnd, addDlgProc, (LPARAM)&info) != 0) {
// get current number of screens // get current number of screens
UInt32 i = s_screens.size(); UInt32 i = ARG->m_screens.size();
// add screen to list control // add screen to list control
HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST); HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
@ -239,15 +255,15 @@ addScreen(HWND hwnd)
SendMessage(child, LB_ADDSTRING, 0, (LPARAM)item.c_str()); SendMessage(child, LB_ADDSTRING, 0, (LPARAM)item.c_str());
// add screen to screen list // add screen to screen list
s_screens.push_back(info.m_screen); ARG->m_screens.push_back(info.m_screen);
// add screen to config // add screen to config
s_config.addScreen(info.m_screen); ARG->m_config.addScreen(info.m_screen);
// add aliases to config // add aliases to config
for (CStringList::const_iterator index = info.m_aliases.begin(); for (CStringList::const_iterator index = info.m_aliases.begin();
index != info.m_aliases.end(); ++index) { index != info.m_aliases.end(); ++index) {
s_config.addAlias(info.m_screen, *index); ARG->m_config.addAlias(info.m_screen, *index);
} }
// update neighbors // update neighbors
@ -271,9 +287,9 @@ editScreen(HWND hwnd)
// fill in screen info // fill in screen info
CScreenInfo info; CScreenInfo info;
info.m_screen = s_screens[index]; info.m_screen = ARG->m_screens[index];
for (CConfig::all_const_iterator index = s_config.beginAll(); for (CConfig::all_const_iterator index = ARG->m_config.beginAll();
index != s_config.endAll(); ++index) { index != ARG->m_config.endAll(); ++index) {
if (CStringUtil::CaselessCmp::equal(index->second, info.m_screen) && if (CStringUtil::CaselessCmp::equal(index->second, info.m_screen) &&
!CStringUtil::CaselessCmp::equal(index->second, index->first)) { !CStringUtil::CaselessCmp::equal(index->second, index->first)) {
info.m_aliases.push_back(index->first); info.m_aliases.push_back(index->first);
@ -287,21 +303,21 @@ editScreen(HWND hwnd)
if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD), if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
hwnd, addDlgProc, (LPARAM)&info) != 0) { hwnd, addDlgProc, (LPARAM)&info) != 0) {
// replace screen // replace screen
s_screens[index] = info.m_screen; ARG->m_screens[index] = info.m_screen;
// remove old aliases // remove old aliases
for (CStringList::const_iterator index = oldInfo.m_aliases.begin(); for (CStringList::const_iterator index = oldInfo.m_aliases.begin();
index != oldInfo.m_aliases.end(); ++index) { index != oldInfo.m_aliases.end(); ++index) {
s_config.removeAlias(*index); ARG->m_config.removeAlias(*index);
} }
// replace name // replace name
s_config.renameScreen(oldInfo.m_screen, info.m_screen); ARG->m_config.renameScreen(oldInfo.m_screen, info.m_screen);
// add new aliases // add new aliases
for (CStringList::const_iterator index = info.m_aliases.begin(); for (CStringList::const_iterator index = info.m_aliases.begin();
index != info.m_aliases.end(); ++index) { index != info.m_aliases.end(); ++index) {
s_config.addAlias(info.m_screen, *index); ARG->m_config.addAlias(info.m_screen, *index);
} }
// update list // update list
@ -331,16 +347,16 @@ removeScreen(HWND hwnd)
} }
// get screen name // get screen name
CString name = s_screens[index]; CString name = ARG->m_screens[index];
// remove screen from list control // remove screen from list control
SendMessage(child, LB_DELETESTRING, index, 0); SendMessage(child, LB_DELETESTRING, index, 0);
// remove screen from screen list // remove screen from screen list
s_screens.erase(&s_screens[index]); ARG->m_screens.erase(&ARG->m_screens[index]);
// remove screen from config (this also removes aliases) // remove screen from config (this also removes aliases)
s_config.removeScreen(name); ARG->m_config.removeScreen(name);
// update neighbors // update neighbors
updateNeighbors(hwnd); updateNeighbors(hwnd);
@ -361,20 +377,20 @@ changeNeighbor(HWND hwnd, HWND combo, EDirection direction)
} }
// get screen name // get screen name
CString screen = s_screens[index]; CString screen = ARG->m_screens[index];
// get selected neighbor // get selected neighbor
index = SendMessage(combo, CB_GETCURSEL, 0, 0); index = SendMessage(combo, CB_GETCURSEL, 0, 0);
// remove old connection // remove old connection
s_config.disconnect(screen, direction); ARG->m_config.disconnect(screen, direction);
// add new connection // add new connection
if (index != LB_ERR && index != 0) { if (index != LB_ERR && index != 0) {
LRESULT size = SendMessage(combo, CB_GETLBTEXTLEN, index, 0); LRESULT size = SendMessage(combo, CB_GETLBTEXTLEN, index, 0);
char* neighbor = new char[size + 1]; char* neighbor = new char[size + 1];
SendMessage(combo, CB_GETLBTEXT, index, (LPARAM)neighbor); SendMessage(combo, CB_GETLBTEXT, index, (LPARAM)neighbor);
s_config.connect(screen, direction, CString(neighbor)); ARG->m_config.connect(screen, direction, CString(neighbor));
delete[] neighbor; delete[] neighbor;
} }
@ -444,14 +460,14 @@ getCommandLine(HWND hwnd, bool testing)
// get and verify screen name // get and verify screen name
HWND child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT); HWND child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
CString name = getWindowText(child); CString name = getWindowText(child);
if (!s_config.isValidScreenName(name)) { if (!ARG->m_config.isValidScreenName(name)) {
showError(hwnd, CStringUtil::format( showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_SCREEN_NAME).c_str(), getString(IDS_INVALID_SCREEN_NAME).c_str(),
name.c_str())); name.c_str()));
SetFocus(child); SetFocus(child);
return CString(); return CString();
} }
if (!isClient && !s_config.isScreen(name)) { if (!isClient && !ARG->m_config.isScreen(name)) {
showError(hwnd, CStringUtil::format( showError(hwnd, CStringUtil::format(
getString(IDS_UNKNOWN_SCREEN_NAME).c_str(), getString(IDS_UNKNOWN_SCREEN_NAME).c_str(),
name.c_str())); name.c_str()));
@ -490,7 +506,7 @@ getCommandLine(HWND hwnd, bool testing)
// check server name // check server name
child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT); child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
CString server = getWindowText(child); CString server = getWindowText(child);
if (!s_config.isValidScreenName(server)) { if (!ARG->m_config.isValidScreenName(server)) {
showError(hwnd, CStringUtil::format( showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_SERVER_NAME).c_str(), getString(IDS_INVALID_SERVER_NAME).c_str(),
server.c_str())); server.c_str()));
@ -649,15 +665,13 @@ static
void void
initMainWindow(HWND hwnd) initMainWindow(HWND hwnd)
{ {
CPlatform platform;
// append version number to title // append version number to title
CString titleFormat = getString(IDS_TITLE); CString titleFormat = getString(IDS_TITLE);
setWindowText(hwnd, CStringUtil::format(titleFormat.c_str(), VERSION)); setWindowText(hwnd, CStringUtil::format(titleFormat.c_str(), VERSION));
// load configuration // load configuration
bool configLoaded = loadConfig(s_config); bool configLoaded = loadConfig(ARG->m_config);
s_oldConfig = s_config; ARG->m_oldConfig = ARG->m_config;
enableSaveControls(hwnd); enableSaveControls(hwnd);
// choose client/server radio buttons // choose client/server radio buttons
@ -673,9 +687,9 @@ initMainWindow(HWND hwnd)
if (configLoaded) { if (configLoaded) {
int i = 1; int i = 1;
child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST); child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
for (CConfig::const_iterator index = s_config.begin(); for (CConfig::const_iterator index = ARG->m_config.begin();
index != s_config.end(); ++i, ++index) { index != ARG->m_config.end(); ++i, ++index) {
s_screens.push_back(*index); ARG->m_screens.push_back(*index);
CString item = CStringUtil::print("%d. %s", i, index->c_str()); CString item = CStringUtil::print("%d. %s", i, index->c_str());
SendMessage(child, LB_ADDSTRING, 0, (LPARAM)item.c_str()); SendMessage(child, LB_ADDSTRING, 0, (LPARAM)item.c_str());
} }
@ -687,9 +701,9 @@ initMainWindow(HWND hwnd)
child = getItem(hwnd, IDC_MAIN_ADVANCED_PORT_EDIT); child = getItem(hwnd, IDC_MAIN_ADVANCED_PORT_EDIT);
SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer); SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
CNetwork::gethostname(buffer, sizeof(buffer)); CString hostname = ARCH->getHostName();
child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT); child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer); SendMessage(child, WM_SETTEXT, 0, (LPARAM)hostname.c_str());
child = getItem(hwnd, IDC_MAIN_DEBUG); child = getItem(hwnd, IDC_MAIN_DEBUG);
for (unsigned int i = 0; i < sizeof(s_debugName) / for (unsigned int i = 0; i < sizeof(s_debugName) /
@ -746,7 +760,7 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
tokenize(newAliases, getWindowText(child)); tokenize(newAliases, getWindowText(child));
// name must be valid // name must be valid
if (!s_config.isValidScreenName(newName)) { if (!ARG->m_config.isValidScreenName(newName)) {
showError(hwnd, CStringUtil::format( showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_SCREEN_NAME).c_str(), getString(IDS_INVALID_SCREEN_NAME).c_str(),
newName.c_str())); newName.c_str()));
@ -756,7 +770,7 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
// aliases must be valid // aliases must be valid
for (CStringList::const_iterator index = newAliases.begin(); for (CStringList::const_iterator index = newAliases.begin();
index != newAliases.end(); ++index) { index != newAliases.end(); ++index) {
if (!s_config.isValidScreenName(*index)) { if (!ARG->m_config.isValidScreenName(*index)) {
showError(hwnd, CStringUtil::format( showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_SCREEN_NAME).c_str(), getString(IDS_INVALID_SCREEN_NAME).c_str(),
index->c_str())); index->c_str()));
@ -775,7 +789,7 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
// name must not exist in config but allow same name. also // name must not exist in config but allow same name. also
// allow name if it exists in the old alias list but not the // allow name if it exists in the old alias list but not the
// new one. // new one.
if (s_config.isScreen(newName) && if (ARG->m_config.isScreen(newName) &&
!CStringUtil::CaselessCmp::equal(newName, info->m_screen) && !CStringUtil::CaselessCmp::equal(newName, info->m_screen) &&
!isNameInList(info->m_aliases, newName)) { !isNameInList(info->m_aliases, newName)) {
showError(hwnd, CStringUtil::format( showError(hwnd, CStringUtil::format(
@ -788,7 +802,7 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
// allow an alias to be the old name. // allow an alias to be the old name.
for (CStringList::const_iterator index = newAliases.begin(); for (CStringList::const_iterator index = newAliases.begin();
index != newAliases.end(); ++index) { index != newAliases.end(); ++index) {
if (s_config.isScreen(*index) && if (ARG->m_config.isScreen(*index) &&
!CStringUtil::CaselessCmp::equal(*index, info->m_screen) && !CStringUtil::CaselessCmp::equal(*index, info->m_screen) &&
!isNameInList(info->m_aliases, *index)) { !isNameInList(info->m_aliases, *index)) {
showError(hwnd, CStringUtil::format( showError(hwnd, CStringUtil::format(
@ -830,7 +844,7 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
switch (LOWORD(wParam)) { switch (LOWORD(wParam)) {
case IDCANCEL: case IDCANCEL:
// test for unsaved data // test for unsaved data
if (s_config != s_oldConfig) { if (ARG->m_config != ARG->m_oldConfig) {
if (!askVerify(hwnd, getString(IDS_UNSAVED_DATA_REALLY_QUIT))) { if (!askVerify(hwnd, getString(IDS_UNSAVED_DATA_REALLY_QUIT))) {
return 0; return 0;
} }
@ -846,14 +860,14 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
const bool testing = (LOWORD(wParam) == IDC_MAIN_TEST); const bool testing = (LOWORD(wParam) == IDC_MAIN_TEST);
// save data // save data
if (s_config != s_oldConfig) { if (ARG->m_config != ARG->m_oldConfig) {
if (!saveConfig(s_config, false)) { if (!saveConfig(ARG->m_config, false)) {
showError(hwnd, CStringUtil::format( showError(hwnd, CStringUtil::format(
getString(IDS_SAVE_FAILED).c_str(), getString(IDS_SAVE_FAILED).c_str(),
getErrorString(GetLastError()).c_str())); getErrorString(GetLastError()).c_str()));
return 0; return 0;
} }
s_oldConfig = s_config; ARG->m_oldConfig = ARG->m_config;
enableSaveControls(hwnd); enableSaveControls(hwnd);
} }
@ -892,11 +906,11 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
if (!cmdLine.empty()) { if (!cmdLine.empty()) {
// run dialog // run dialog
CAutoStart autoStart(hwnd, CAutoStart autoStart(hwnd,
isClientChecked(hwnd) ? NULL : &s_config, isClientChecked(hwnd) ? NULL : &ARG->m_config,
cmdLine); cmdLine);
autoStart.doModal(); autoStart.doModal();
if (autoStart.wasUserConfigSaved()) { if (autoStart.wasUserConfigSaved()) {
s_oldConfig = s_config; ARG->m_oldConfig = ARG->m_config;
enableSaveControls(hwnd); enableSaveControls(hwnd);
} }
} }
@ -904,13 +918,13 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
case IDC_MAIN_SAVE: case IDC_MAIN_SAVE:
if (!saveConfig(s_config, false)) { if (!saveConfig(ARG->m_config, false)) {
showError(hwnd, CStringUtil::format( showError(hwnd, CStringUtil::format(
getString(IDS_SAVE_FAILED).c_str(), getString(IDS_SAVE_FAILED).c_str(),
getErrorString(GetLastError()).c_str())); getErrorString(GetLastError()).c_str()));
} }
else { else {
s_oldConfig = s_config; ARG->m_oldConfig = ARG->m_config;
enableSaveControls(hwnd); enableSaveControls(hwnd);
} }
return 0; return 0;
@ -981,10 +995,11 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
int WINAPI int WINAPI
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow) WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
{ {
s_instance = instance; CArch arch;
CLOG;
CArgs args;
// initialize network library s_instance = instance;
CNetwork::init();
// register main window (dialog) class // register main window (dialog) class
WNDCLASSEX classInfo; WNDCLASSEX classInfo;
@ -1009,13 +1024,14 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
RegisterClassEx(&classInfo); RegisterClassEx(&classInfo);
// create main window // create main window
s_mainWindow = CreateDialog(s_instance, MAKEINTRESOURCE(IDD_MAIN), 0, NULL); HWND m_mainWindow = CreateDialog(s_instance,
MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
// prep window // prep window
initMainWindow(s_mainWindow); initMainWindow(m_mainWindow);
// show window // show window
ShowWindow(s_mainWindow, nCmdShow); ShowWindow(m_mainWindow, nCmdShow);
// main loop // main loop
MSG msg; MSG msg;
@ -1032,7 +1048,7 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
break; break;
default: default:
if (!IsDialogMessage(s_mainWindow, &msg)) { if (!IsDialogMessage(m_mainWindow, &msg)) {
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
} }

View File

@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c # ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
@ -71,7 +71,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32

View File

@ -241,8 +241,8 @@ BEGIN
"Synergy is not configured to start automatically." "Synergy is not configured to start automatically."
IDS_INSTALL_LABEL "Install" IDS_INSTALL_LABEL "Install"
IDS_UNINSTALL_LABEL "Uninstall" IDS_UNINSTALL_LABEL "Uninstall"
IDS_INSTALL_GENERIC_ERROR "Install failed for an unknown reason." IDS_INSTALL_GENERIC_ERROR "Install failed: %{1}."
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed for an unknown reason." IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed: %{1}."
IDS_INSTALL_TITLE "Installed Auto-Start" IDS_INSTALL_TITLE "Installed Auto-Start"
IDS_INSTALLED_SYSTEM "Installed auto-start. Synergy will now automatically start each time you start your computer." IDS_INSTALLED_SYSTEM "Installed auto-start. Synergy will now automatically start each time you start your computer."
IDS_INSTALLED_USER "Installed auto-start. Synergy will now automatically start each time you log in." IDS_INSTALLED_USER "Installed auto-start. Synergy will now automatically start each time you log in."

View File

@ -38,6 +38,7 @@ synergyc_LDADD = \
$(DEPTH)/lib/io/libio.a \ $(DEPTH)/lib/io/libio.a \
$(DEPTH)/lib/mt/libmt.a \ $(DEPTH)/lib/mt/libmt.a \
$(DEPTH)/lib/base/libbase.a \ $(DEPTH)/lib/base/libbase.a \
$(DEPTH)/lib/arch/libarch.a \
$(X_LIBS) \ $(X_LIBS) \
$(X_PRE_LIBS) \ $(X_PRE_LIBS) \
-lXtst \ -lXtst \
@ -46,6 +47,8 @@ synergyc_LDADD = \
$(X_EXTRA_LIBS) \ $(X_EXTRA_LIBS) \
$(NULL) $(NULL)
INCLUDES = \ INCLUDES = \
-I$(VDEPTH)/lib/common \
-I$(VDEPTH)/lib/arch \
-I$(VDEPTH)/lib/base \ -I$(VDEPTH)/lib/base \
-I$(VDEPTH)/lib/mt \ -I$(VDEPTH)/lib/mt \
-I$(VDEPTH)/lib/io \ -I$(VDEPTH)/lib/io \

View File

@ -14,11 +14,9 @@
#include "CClient.h" #include "CClient.h"
#include "ISecondaryScreenFactory.h" #include "ISecondaryScreenFactory.h"
#include "CPlatform.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
#include "Version.h" #include "Version.h"
#include "XScreen.h" #include "XScreen.h"
#include "CNetwork.h"
#include "CNetworkAddress.h" #include "CNetworkAddress.h"
#include "CTCPSocketFactory.h" #include "CTCPSocketFactory.h"
#include "XSocket.h" #include "XSocket.h"
@ -28,12 +26,18 @@
#include "CThread.h" #include "CThread.h"
#include "XThread.h" #include "XThread.h"
#include "CLog.h" #include "CLog.h"
#include "LogOutputters.h"
#include "CString.h" #include "CString.h"
#include "CArch.h"
#include "CArchMiscWindows.h"
#include <cstring> #include <cstring>
#define DAEMON_RUNNING(running_)
#if WINDOWS_LIKE #if WINDOWS_LIKE
#include "CMSWindowsSecondaryScreen.h" #include "CMSWindowsSecondaryScreen.h"
#include "resource.h" #include "resource.h"
#undef DAEMON_RUNNING
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
#elif UNIX_LIKE #elif UNIX_LIKE
#include "CXWindowsSecondaryScreen.h" #include "CXWindowsSecondaryScreen.h"
#endif #endif
@ -49,35 +53,33 @@
// program arguments // program arguments
// //
static const char* pname = NULL; #define ARG CArgs::s_instance
static bool s_backend = false;
static bool s_restartable = true;
static bool s_daemon = true;
static bool s_camp = true;
static const char* s_logFilter = NULL;
static CString s_name;
static CNetworkAddress s_serverAddress;
class CArgs {
public:
CArgs() :
m_pname(NULL),
m_backend(false),
m_restartable(true),
m_daemon(true),
m_camp(true),
m_logFilter(NULL)
{ s_instance = this; }
~CArgs() { s_instance = NULL; }
// public:
// logging thread safety static CArgs* s_instance;
// const char* m_pname;
bool m_backend;
bool m_restartable;
bool m_daemon;
bool m_camp;
const char* m_logFilter;
CString m_name;
CNetworkAddress m_serverAddress;
};
static CMutex* s_logMutex = NULL; CArgs* CArgs::s_instance = NULL;
static
void
logLock(bool lock)
{
assert(s_logMutex != NULL);
if (lock) {
s_logMutex->lock();
}
else {
s_logMutex->unlock();
}
}
// //
@ -113,27 +115,17 @@ static CClient* s_client = NULL;
static static
int int
realMain(CMutex* mutex) realMain(void)
{ {
// caller should have mutex locked on entry
// initialize threading library
CThread::init();
// make logging thread safe
CMutex logMutex;
s_logMutex = &logMutex;
CLog::setLock(&logLock);
int result = kExitSuccess; int result = kExitSuccess;
do { do {
bool opened = false; bool opened = false;
bool locked = true; bool locked = true;
try { try {
// create client // create client
s_client = new CClient(s_name); s_client = new CClient(ARG->m_name);
s_client->camp(s_camp); s_client->camp(ARG->m_camp);
s_client->setAddress(s_serverAddress); s_client->setAddress(ARG->m_serverAddress);
s_client->setScreenFactory(new CSecondaryScreenFactory); s_client->setScreenFactory(new CSecondaryScreenFactory);
s_client->setSocketFactory(new CTCPSocketFactory); s_client->setSocketFactory(new CTCPSocketFactory);
s_client->setStreamFilterFactory(NULL); s_client->setStreamFilterFactory(NULL);
@ -144,9 +136,7 @@ realMain(CMutex* mutex)
opened = true; opened = true;
// run client // run client
if (mutex != NULL) { DAEMON_RUNNING(true);
mutex->unlock();
}
locked = false; locked = false;
s_client->mainLoop(); s_client->mainLoop();
locked = true; locked = true;
@ -160,8 +150,8 @@ realMain(CMutex* mutex)
// clean up // clean up
#define FINALLY do { \ #define FINALLY do { \
if (!locked && mutex != NULL) { \ if (!locked) { \
mutex->lock(); \ DAEMON_RUNNING(false); \
} \ } \
if (s_client != NULL) { \ if (s_client != NULL) { \
if (opened) { \ if (opened) { \
@ -175,8 +165,8 @@ realMain(CMutex* mutex)
} }
catch (XScreenUnavailable& e) { catch (XScreenUnavailable& e) {
// wait before retrying if we're going to retry // wait before retrying if we're going to retry
if (s_restartable) { if (ARG->m_restartable) {
CThread::sleep(e.getRetryTime()); ARCH->sleep(e.getRetryTime());
} }
else { else {
result = kExitFailed; result = kExitFailed;
@ -189,7 +179,7 @@ realMain(CMutex* mutex)
} }
catch (...) { catch (...) {
// don't try to restart and fail // don't try to restart and fail
s_restartable = false; ARG->m_restartable = false;
result = kExitFailed; result = kExitFailed;
FINALLY; FINALLY;
} }
@ -200,19 +190,10 @@ realMain(CMutex* mutex)
} }
catch (XThread&) { catch (XThread&) {
// terminated // terminated
s_restartable = false; ARG->m_restartable = false;
result = kExitTerminated; result = kExitTerminated;
} }
catch (...) { } while (ARG->m_restartable);
CLog::setLock(NULL);
s_logMutex = NULL;
throw;
}
} while (s_restartable);
// clean up
CLog::setLock(NULL);
s_logMutex = NULL;
return result; return result;
} }
@ -233,7 +214,7 @@ version()
LOG((CLOG_PRINT LOG((CLOG_PRINT
"%s %s, protocol version %d.%d\n" "%s %s, protocol version %d.%d\n"
"%s", "%s",
pname, ARG->m_pname,
kVersion, kVersion,
kProtocolMajorVersion, kProtocolMajorVersion,
kProtocolMinorVersion, kProtocolMinorVersion,
@ -279,7 +260,7 @@ help()
"\n" "\n"
"Where log messages go depends on the platform and whether or not the\n" "Where log messages go depends on the platform and whether or not the\n"
"client is running as a daemon.", "client is running as a daemon.",
pname, kDefaultPort)); ARG->m_pname, kDefaultPort));
} }
@ -294,7 +275,7 @@ isArg(int argi, int argc, const char** argv,
// match. check args left. // match. check args left.
if (argi + minRequiredParameters >= argc) { if (argi + minRequiredParameters >= argc) {
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE, LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
pname, argv[argi], pname)); ARG->m_pname, argv[argi], ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
return true; return true;
@ -308,61 +289,58 @@ static
void void
parse(int argc, const char** argv) parse(int argc, const char** argv)
{ {
assert(pname != NULL); assert(ARG->m_pname != NULL);
assert(argv != NULL); assert(argv != NULL);
assert(argc >= 1); assert(argc >= 1);
// set defaults // set defaults
char hostname[256]; ARG->m_name = ARCH->getHostName();
if (CNetwork::gethostname(hostname, sizeof(hostname)) != CNetwork::Error) {
s_name = hostname;
}
// parse options // parse options
int i; int i;
for (i = 1; i < argc; ++i) { for (i = 1; i < argc; ++i) {
if (isArg(i, argc, argv, "-d", "--debug", 1)) { if (isArg(i, argc, argv, "-d", "--debug", 1)) {
// change logging level // change logging level
s_logFilter = argv[++i]; ARG->m_logFilter = argv[++i];
} }
else if (isArg(i, argc, argv, "-n", "--name", 1)) { else if (isArg(i, argc, argv, "-n", "--name", 1)) {
// save screen name // save screen name
s_name = argv[++i]; ARG->m_name = argv[++i];
} }
else if (isArg(i, argc, argv, NULL, "--camp")) { else if (isArg(i, argc, argv, NULL, "--camp")) {
// enable camping // enable camping
s_camp = true; ARG->m_camp = true;
} }
else if (isArg(i, argc, argv, NULL, "--no-camp")) { else if (isArg(i, argc, argv, NULL, "--no-camp")) {
// disable camping // disable camping
s_camp = false; ARG->m_camp = false;
} }
else if (isArg(i, argc, argv, "-f", "--no-daemon")) { else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
// not a daemon // not a daemon
s_daemon = false; ARG->m_daemon = false;
} }
else if (isArg(i, argc, argv, NULL, "--daemon")) { else if (isArg(i, argc, argv, NULL, "--daemon")) {
// daemonize // daemonize
s_daemon = true; ARG->m_daemon = true;
} }
else if (isArg(i, argc, argv, "-1", "--no-restart")) { else if (isArg(i, argc, argv, "-1", "--no-restart")) {
// don't try to restart // don't try to restart
s_restartable = false; ARG->m_restartable = false;
} }
else if (isArg(i, argc, argv, NULL, "--restart")) { else if (isArg(i, argc, argv, NULL, "--restart")) {
// try to restart // try to restart
s_restartable = true; ARG->m_restartable = true;
} }
else if (isArg(i, argc, argv, "-z", NULL)) { else if (isArg(i, argc, argv, "-z", NULL)) {
s_backend = true; ARG->m_backend = true;
} }
else if (isArg(i, argc, argv, "-h", "--help")) { else if (isArg(i, argc, argv, "-h", "--help")) {
@ -383,7 +361,7 @@ parse(int argc, const char** argv)
else if (argv[i][0] == '-') { else if (argv[i][0] == '-') {
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
pname, argv[i], pname)); ARG->m_pname, argv[i], ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
@ -396,49 +374,60 @@ parse(int argc, const char** argv)
// exactly one non-option argument (server-address) // exactly one non-option argument (server-address)
if (i == argc) { if (i == argc) {
LOG((CLOG_PRINT "%s: a server address or name is required" BYE, LOG((CLOG_PRINT "%s: a server address or name is required" BYE,
pname, pname)); ARG->m_pname, ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
if (i + 1 != argc) { if (i + 1 != argc) {
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
pname, argv[i], pname)); ARG->m_pname, argv[i], ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
// save server address // save server address
try { try {
s_serverAddress = CNetworkAddress(argv[i], kDefaultPort); ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
} }
catch (XSocketAddress& e) { catch (XSocketAddress& e) {
LOG((CLOG_PRINT "%s: %s" BYE, LOG((CLOG_PRINT "%s: %s" BYE,
pname, e.what(), pname)); ARG->m_pname, e.what(), ARG->m_pname));
bye(kExitFailed); bye(kExitFailed);
} }
// increase default filter level for daemon. the user must // increase default filter level for daemon. the user must
// explicitly request another level for a daemon. // explicitly request another level for a daemon.
if (s_daemon && s_logFilter == NULL) { if (ARG->m_daemon && ARG->m_logFilter == NULL) {
#if WINDOWS_LIKE #if WINDOWS_LIKE
if (CPlatform::isWindows95Family()) { if (CArchMiscWindows::isWindows95Family()) {
// windows 95 has no place for logging so avoid showing // windows 95 has no place for logging so avoid showing
// the log console window. // the log console window.
s_logFilter = "FATAL"; ARG->m_logFilter = "FATAL";
} }
else else
#endif #endif
{ {
s_logFilter = "NOTE"; ARG->m_logFilter = "NOTE";
} }
} }
// set log filter // set log filter
if (!CLog::setFilter(s_logFilter)) { if (!CLOG->setFilter(ARG->m_logFilter)) {
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE, LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
pname, s_logFilter, pname)); ARG->m_pname, ARG->m_logFilter, ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
} }
static
void
useSystemLog()
{
// redirect log messages
ILogOutputter* logger = new CSystemLogOutputter;
logger->open(DAEMON_NAME);
CLOG->insert(new CStopLogOutputter);
CLOG->insert(logger);
}
// //
// platform dependent entry points // platform dependent entry points
// //
@ -449,24 +438,41 @@ parse(int argc, const char** argv)
static bool s_hasImportantLogMessages = false; static bool s_hasImportantLogMessages = false;
static //
// CMessageBoxOutputter
//
// This class writes severe log messages to a message box
//
class CMessageBoxOutputter : public ILogOutputter {
public:
CMessageBoxOutputter() { }
virtual ~CMessageBoxOutputter() { }
// ILogOutputter overrides
virtual void open(const char*) { }
virtual void close() { }
virtual bool write(ELevel level, const char* message);
virtual const char* getNewline() const { return ""; }
};
bool bool
logMessageBox(int priority, const char* msg) CMessageBoxOutputter::write(ELevel level, const char* message)
{ {
// note any important messages the user may need to know about // note any important messages the user may need to know about
if (priority <= CLog::kWARNING) { if (level <= CLog::kWARNING) {
s_hasImportantLogMessages = true; s_hasImportantLogMessages = true;
} }
// FATAL and PRINT messages get a dialog box if not running as // FATAL and PRINT messages get a dialog box if not running as
// backend. if we're running as a backend the user will have // backend. if we're running as a backend the user will have
// a chance to see the messages when we exit. // a chance to see the messages when we exit.
if (!s_backend && priority <= CLog::kFATAL) { if (!ARG->m_backend && level <= CLog::kFATAL) {
MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING); MessageBox(NULL, message, ARG->m_pname, MB_OK | MB_ICONWARNING);
return true; return false;
} }
else { else {
return false; return true;
} }
} }
@ -474,7 +480,7 @@ static
void void
byeThrow(int x) byeThrow(int x)
{ {
throw CWin32Platform::CDaemonFailed(x); CArchMiscWindows::daemonFailed(x);
} }
static static
@ -486,10 +492,9 @@ daemonStop(void)
static static
int int
daemonStartup(IPlatform* iplatform, int argc, const char** argv) daemonStartup(int argc, const char** argv)
{ {
// get platform pointer useSystemLog();
CWin32Platform* platform = static_cast<CWin32Platform*>(iplatform);
// catch errors that would normally exit // catch errors that would normally exit
bye = &byeThrow; bye = &byeThrow;
@ -498,35 +503,35 @@ daemonStartup(IPlatform* iplatform, int argc, const char** argv)
parse(argc, argv); parse(argc, argv);
// cannot run as backend if running as a service // cannot run as backend if running as a service
s_backend = false; ARG->m_backend = false;
// run as a service // run as a service
return platform->runDaemon(realMain, daemonStop); return CArchMiscWindows::runDaemon(realMain, daemonStop);
} }
static static
int int
daemonStartup95(IPlatform*, int, const char**) daemonStartup95(int, const char**)
{ {
return realMain(NULL); useSystemLog();
return realMain();
} }
int WINAPI int WINAPI
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
{ {
CPlatform platform; CArch arch;
CLOG;
CArgs args;
// save instance // save instance
CMSWindowsScreen::init(instance); CMSWindowsScreen::init(instance);
// get program name // get program name
pname = platform.getBasename(__argv[0]); ARG->m_pname = ARCH->getBasename(__argv[0]);
// initialize network library
CNetwork::init();
// send PRINT and FATAL output to a message box // send PRINT and FATAL output to a message box
CLog::setOutputter(&logMessageBox); CLOG->insert(new CMessageBoxOutputter);
// windows NT family starts services using no command line options. // windows NT family starts services using no command line options.
// since i'm not sure how to tell the difference between that and // since i'm not sure how to tell the difference between that and
@ -534,10 +539,10 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
// arguments and we're on NT then we're being invoked as a service. // arguments and we're on NT then we're being invoked as a service.
// users on NT can use `--daemon' or `--no-daemon' to force us out // users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path. // of the service code path.
if (__argc <= 1 && !CWin32Platform::isWindows95Family()) { if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
int result = platform.daemonize(DAEMON_NAME, &daemonStartup); int result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
if (result == -1) { if (result == -1) {
LOG((CLOG_CRIT "failed to start as a service" BYE, pname)); LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
return kExitFailed; return kExitFailed;
} }
return result; return result;
@ -548,38 +553,36 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
// daemonize if requested // daemonize if requested
int result; int result;
if (s_daemon) { if (ARG->m_daemon) {
// redirect log messages
platform.installDaemonLogger(DAEMON_NAME);
// start as a daemon // start as a daemon
if (CWin32Platform::isWindows95Family()) { if (CArchMiscWindows::isWindows95Family()) {
result = platform.daemonize(DAEMON_NAME, &daemonStartup95); try {
if (result == -1) { result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
LOG((CLOG_CRIT "failed to start as a service" BYE, pname)); }
catch (XArchDaemon&) {
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
result = kExitFailed; result = kExitFailed;
} }
} }
else { else {
// cannot start a service from the command line so just // cannot start a service from the command line so just
// run normally (except with log messages redirected). // run normally (except with log messages redirected).
result = realMain(NULL); useSystemLog();
result = realMain();
} }
} }
else { else {
// run // run
result = realMain(NULL); result = realMain();
} }
CNetwork::cleanup();
// let user examine any messages if we're running as a backend // let user examine any messages if we're running as a backend
// by putting up a dialog box before exiting. // by putting up a dialog box before exiting.
if (s_backend && s_hasImportantLogMessages) { if (ARG->m_backend && s_hasImportantLogMessages) {
char msg[1024]; char msg[1024];
msg[0] = '\0'; msg[0] = '\0';
LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0])); LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0]));
MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING); MessageBox(NULL, msg, ARG->m_pname, MB_OK | MB_ICONWARNING);
} }
return result; return result;
@ -589,40 +592,40 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
static static
int int
daemonStartup(IPlatform*, int, const char**) daemonStartup(int, const char**)
{ {
return realMain(NULL); useSystemLog();
return realMain();
} }
int int
main(int argc, char** argv) main(int argc, char** argv)
{ {
CPlatform platform; CArch arch;
CLOG;
CArgs args;
// get program name // get program name
pname = platform.getBasename(argv[0]); ARG->m_pname = ARCH->getBasename(argv[0]);
// initialize network library
CNetwork::init();
// parse command line // parse command line
parse(argc, const_cast<const char**>(argv)); parse(argc, const_cast<const char**>(argv));
// daemonize if requested // daemonize if requested
int result; int result;
if (s_daemon) { if (ARG->m_daemon) {
result = platform.daemonize(DAEMON_NAME, &daemonStartup); try {
if (result == -1) { result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon&) {
LOG((CLOG_CRIT "failed to daemonize")); LOG((CLOG_CRIT "failed to daemonize"));
return kExitFailed; result = kExitFailed;
} }
} }
else { else {
result = realMain(NULL); result = realMain();
} }
CNetwork::cleanup();
return result; return result;
} }

View File

@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c # ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
@ -54,7 +54,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo # ADD BSC32 /nologo
LINK32=link.exe LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"../../Release/synergyc.exe" # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "synergyc - Win32 Debug" !ELSEIF "$(CFG)" == "synergyc - Win32 Debug"
@ -70,7 +70,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
@ -81,7 +81,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo # ADD BSC32 /nologo
LINK32=link.exe LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"../../Debug/synergyc.exe" /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
!ENDIF !ENDIF

View File

@ -39,6 +39,7 @@ synergys_LDADD = \
$(DEPTH)/lib/io/libio.a \ $(DEPTH)/lib/io/libio.a \
$(DEPTH)/lib/mt/libmt.a \ $(DEPTH)/lib/mt/libmt.a \
$(DEPTH)/lib/base/libbase.a \ $(DEPTH)/lib/base/libbase.a \
$(DEPTH)/lib/arch/libarch.a \
$(X_LIBS) \ $(X_LIBS) \
$(X_PRE_LIBS) \ $(X_PRE_LIBS) \
-lXtst \ -lXtst \
@ -47,6 +48,8 @@ synergys_LDADD = \
$(X_EXTRA_LIBS) \ $(X_EXTRA_LIBS) \
$(NULL) $(NULL)
INCLUDES = \ INCLUDES = \
-I$(VDEPTH)/lib/common \
-I$(VDEPTH)/lib/arch \
-I$(VDEPTH)/lib/base \ -I$(VDEPTH)/lib/base \
-I$(VDEPTH)/lib/mt \ -I$(VDEPTH)/lib/mt \
-I$(VDEPTH)/lib/io \ -I$(VDEPTH)/lib/io \

View File

@ -15,11 +15,9 @@
#include "CServer.h" #include "CServer.h"
#include "CConfig.h" #include "CConfig.h"
#include "IPrimaryScreenFactory.h" #include "IPrimaryScreenFactory.h"
#include "CPlatform.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
#include "Version.h" #include "Version.h"
#include "XScreen.h" #include "XScreen.h"
#include "CNetwork.h"
#include "CTCPSocketFactory.h" #include "CTCPSocketFactory.h"
#include "XSocket.h" #include "XSocket.h"
#include "CLock.h" #include "CLock.h"
@ -27,12 +25,18 @@
#include "CThread.h" #include "CThread.h"
#include "XThread.h" #include "XThread.h"
#include "CLog.h" #include "CLog.h"
#include "LogOutputters.h"
#include "CArch.h"
#include "CArchMiscWindows.h"
#include "stdfstream.h" #include "stdfstream.h"
#include <cstring> #include <cstring>
#define DAEMON_RUNNING(running_)
#if WINDOWS_LIKE #if WINDOWS_LIKE
#include "CMSWindowsPrimaryScreen.h" #include "CMSWindowsPrimaryScreen.h"
#include "resource.h" #include "resource.h"
#undef DAEMON_RUNNING
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
#elif UNIX_LIKE #elif UNIX_LIKE
#include "CXWindowsPrimaryScreen.h" #include "CXWindowsPrimaryScreen.h"
#endif #endif
@ -57,37 +61,35 @@
// program arguments // program arguments
// //
static const char* pname = NULL; #define ARG CArgs::s_instance
static bool s_backend = false;
static bool s_restartable = true;
static bool s_daemon = true;
static const char* s_configFile = NULL;
static const char* s_logFilter = NULL;
static CString s_name;
static CNetworkAddress s_synergyAddress;
static CNetworkAddress s_httpAddress;
static CConfig s_config;
class CArgs {
public:
CArgs() :
m_pname(NULL),
m_backend(false),
m_restartable(true),
m_daemon(true),
m_configFile(NULL),
m_logFilter(NULL)
{ s_instance = this; }
~CArgs() { s_instance = NULL; }
// public:
// logging thread safety static CArgs* s_instance;
// const char* m_pname;
bool m_backend;
bool m_restartable;
bool m_daemon;
const char* m_configFile;
const char* m_logFilter;
CString m_name;
CNetworkAddress m_synergyAddress;
CNetworkAddress m_httpAddress;
CConfig m_config;
};
static CMutex* s_logMutex = NULL; CArgs* CArgs::s_instance = NULL;
static
void
logLock(bool lock)
{
assert(s_logMutex != NULL);
if (lock) {
s_logMutex->lock();
}
else {
s_logMutex->unlock();
}
}
// //
@ -124,18 +126,8 @@ static CServer* s_server = NULL;
static static
int int
realMain(CMutex* mutex) realMain(void)
{ {
// caller should have mutex locked on entry
// initialize threading library
CThread::init();
// make logging thread safe
CMutex logMutex;
s_logMutex = &logMutex;
CLog::setLock(&logLock);
int result = kExitSuccess; int result = kExitSuccess;
do { do {
bool opened = false; bool opened = false;
@ -143,28 +135,28 @@ realMain(CMutex* mutex)
try { try {
// if configuration has no screens then add this system // if configuration has no screens then add this system
// as the default // as the default
if (s_config.begin() == s_config.end()) { if (ARG->m_config.begin() == ARG->m_config.end()) {
s_config.addScreen(s_name); ARG->m_config.addScreen(ARG->m_name);
} }
// set the contact address, if provided, in the config. // set the contact address, if provided, in the config.
// otherwise, if the config doesn't have an address, use // otherwise, if the config doesn't have an address, use
// the default. // the default.
if (s_synergyAddress.isValid()) { if (ARG->m_synergyAddress.isValid()) {
s_config.setSynergyAddress(s_synergyAddress); ARG->m_config.setSynergyAddress(ARG->m_synergyAddress);
} }
else if (!s_config.getSynergyAddress().isValid()) { else if (!ARG->m_config.getSynergyAddress().isValid()) {
s_config.setSynergyAddress(CNetworkAddress(kDefaultPort)); ARG->m_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
} }
// set HTTP address if provided // set HTTP address if provided
if (s_httpAddress.isValid()) { if (ARG->m_httpAddress.isValid()) {
s_config.setHTTPAddress(s_httpAddress); ARG->m_config.setHTTPAddress(ARG->m_httpAddress);
} }
// create server // create server
s_server = new CServer(s_name); s_server = new CServer(ARG->m_name);
s_server->setConfig(s_config); s_server->setConfig(ARG->m_config);
s_server->setScreenFactory(new CPrimaryScreenFactory); s_server->setScreenFactory(new CPrimaryScreenFactory);
s_server->setSocketFactory(new CTCPSocketFactory); s_server->setSocketFactory(new CTCPSocketFactory);
s_server->setStreamFilterFactory(NULL); s_server->setStreamFilterFactory(NULL);
@ -174,18 +166,16 @@ realMain(CMutex* mutex)
s_server->open(); s_server->open();
opened = true; opened = true;
// run server (unlocked) // run server
if (mutex != NULL) { DAEMON_RUNNING(true);
mutex->unlock();
}
locked = false; locked = false;
s_server->mainLoop(); s_server->mainLoop();
locked = true; locked = true;
// clean up // clean up
#define FINALLY do { \ #define FINALLY do { \
if (!locked && mutex != NULL) { \ if (!locked) { \
mutex->lock(); \ DAEMON_RUNNING(false); \
} \ } \
if (s_server != NULL) { \ if (s_server != NULL) { \
if (opened) { \ if (opened) { \
@ -199,8 +189,8 @@ realMain(CMutex* mutex)
} }
catch (XScreenUnavailable& e) { catch (XScreenUnavailable& e) {
// wait before retrying if we're going to retry // wait before retrying if we're going to retry
if (s_restartable) { if (ARG->m_restartable) {
CThread::sleep(e.getRetryTime()); ARCH->sleep(e.getRetryTime());
} }
else { else {
result = kExitFailed; result = kExitFailed;
@ -213,7 +203,7 @@ realMain(CMutex* mutex)
} }
catch (...) { catch (...) {
// don't try to restart and fail // don't try to restart and fail
s_restartable = false; ARG->m_restartable = false;
result = kExitFailed; result = kExitFailed;
FINALLY; FINALLY;
} }
@ -224,19 +214,10 @@ realMain(CMutex* mutex)
} }
catch (XThread&) { catch (XThread&) {
// terminated // terminated
s_restartable = false; ARG->m_restartable = false;
result = kExitTerminated; result = kExitTerminated;
} }
catch (...) { } while (ARG->m_restartable);
CLog::setLock(NULL);
s_logMutex = NULL;
throw;
}
} while (s_restartable);
// clean up
CLog::setLock(NULL);
s_logMutex = NULL;
return result; return result;
} }
@ -257,7 +238,7 @@ version()
LOG((CLOG_PRINT LOG((CLOG_PRINT
"%s %s, protocol version %d.%d\n" "%s %s, protocol version %d.%d\n"
"%s", "%s",
pname, ARG->m_pname,
kVersion, kVersion,
kProtocolMajorVersion, kProtocolMajorVersion,
kProtocolMinorVersion, kProtocolMinorVersion,
@ -287,8 +268,6 @@ help()
#endif #endif
CPlatform platform;
LOG((CLOG_PRINT LOG((CLOG_PRINT
"Usage: %s" "Usage: %s"
" [--address <address>]" " [--address <address>]"
@ -333,13 +312,13 @@ PLATFORM_EXTRA
"\n" "\n"
"Where log messages go depends on the platform and whether or not the\n" "Where log messages go depends on the platform and whether or not the\n"
"server is running as a daemon.", "server is running as a daemon.",
pname, ARG->m_pname,
kDefaultPort, kDefaultPort,
platform.addPathComponent( ARCH->concatPath(
platform.getUserDirectory(), ARCH->getUserDirectory(),
USR_CONFIG_NAME).c_str(), USR_CONFIG_NAME).c_str(),
platform.addPathComponent( ARCH->concatPath(
platform.getSystemDirectory(), ARCH->getSystemDirectory(),
SYS_CONFIG_NAME).c_str())); SYS_CONFIG_NAME).c_str()));
} }
@ -354,7 +333,7 @@ isArg(int argi, int argc, const char** argv,
// match. check args left. // match. check args left.
if (argi + minRequiredParameters >= argc) { if (argi + minRequiredParameters >= argc) {
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE, LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
pname, argv[argi], pname)); ARG->m_pname, argv[argi], ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
return true; return true;
@ -368,32 +347,30 @@ static
void void
parse(int argc, const char** argv) parse(int argc, const char** argv)
{ {
assert(pname != NULL); assert(ARG->m_pname != NULL);
assert(argv != NULL); assert(argv != NULL);
assert(argc >= 1); assert(argc >= 1);
// set defaults // set defaults
char hostname[256]; ARG->m_name = ARCH->getHostName();
if (CNetwork::gethostname(hostname, sizeof(hostname)) != CNetwork::Error) {
s_name = hostname;
}
// parse options // parse options
int i; int i;
for (i = 1; i < argc; ++i) { for (i = 1; i < argc; ++i) {
if (isArg(i, argc, argv, "-d", "--debug", 1)) { if (isArg(i, argc, argv, "-d", "--debug", 1)) {
// change logging level // change logging level
s_logFilter = argv[++i]; ARG->m_logFilter = argv[++i];
} }
else if (isArg(i, argc, argv, "-a", "--address", 1)) { else if (isArg(i, argc, argv, "-a", "--address", 1)) {
// save listen address // save listen address
try { try {
s_synergyAddress = CNetworkAddress(argv[i + 1], kDefaultPort); ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
kDefaultPort);
} }
catch (XSocketAddress& e) { catch (XSocketAddress& e) {
LOG((CLOG_PRINT "%s: %s" BYE, LOG((CLOG_PRINT "%s: %s" BYE,
pname, e.what(), pname)); ARG->m_pname, e.what(), ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
++i; ++i;
@ -402,11 +379,12 @@ parse(int argc, const char** argv)
else if (isArg(i, argc, argv, NULL, "--http", 1)) { else if (isArg(i, argc, argv, NULL, "--http", 1)) {
// save listen address // save listen address
try { try {
s_httpAddress = CNetworkAddress(argv[i + 1], kDefaultPort + 1); ARG->m_httpAddress = CNetworkAddress(argv[i + 1],
kDefaultPort + 1);
} }
catch (XSocketAddress& e) { catch (XSocketAddress& e) {
LOG((CLOG_PRINT "%s: %s" BYE, LOG((CLOG_PRINT "%s: %s" BYE,
pname, e.what(), pname)); ARG->m_pname, e.what(), ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
++i; ++i;
@ -414,36 +392,36 @@ parse(int argc, const char** argv)
else if (isArg(i, argc, argv, "-n", "--name", 1)) { else if (isArg(i, argc, argv, "-n", "--name", 1)) {
// save screen name // save screen name
s_name = argv[++i]; ARG->m_name = argv[++i];
} }
else if (isArg(i, argc, argv, "-c", "--config", 1)) { else if (isArg(i, argc, argv, "-c", "--config", 1)) {
// save configuration file path // save configuration file path
s_configFile = argv[++i]; ARG->m_configFile = argv[++i];
} }
else if (isArg(i, argc, argv, "-f", "--no-daemon")) { else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
// not a daemon // not a daemon
s_daemon = false; ARG->m_daemon = false;
} }
else if (isArg(i, argc, argv, NULL, "--daemon")) { else if (isArg(i, argc, argv, NULL, "--daemon")) {
// daemonize // daemonize
s_daemon = true; ARG->m_daemon = true;
} }
else if (isArg(i, argc, argv, "-1", "--no-restart")) { else if (isArg(i, argc, argv, "-1", "--no-restart")) {
// don't try to restart // don't try to restart
s_restartable = false; ARG->m_restartable = false;
} }
else if (isArg(i, argc, argv, NULL, "--restart")) { else if (isArg(i, argc, argv, NULL, "--restart")) {
// try to restart // try to restart
s_restartable = true; ARG->m_restartable = true;
} }
else if (isArg(i, argc, argv, "-z", NULL)) { else if (isArg(i, argc, argv, "-z", NULL)) {
s_backend = true; ARG->m_backend = true;
} }
else if (isArg(i, argc, argv, "-h", "--help")) { else if (isArg(i, argc, argv, "-h", "--help")) {
@ -464,7 +442,7 @@ parse(int argc, const char** argv)
else if (argv[i][0] == '-') { else if (argv[i][0] == '-') {
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
pname, argv[i], pname)); ARG->m_pname, argv[i], ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
@ -477,30 +455,30 @@ parse(int argc, const char** argv)
// no non-option arguments are allowed // no non-option arguments are allowed
if (i != argc) { if (i != argc) {
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
pname, argv[i], pname)); ARG->m_pname, argv[i], ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
// increase default filter level for daemon. the user must // increase default filter level for daemon. the user must
// explicitly request another level for a daemon. // explicitly request another level for a daemon.
if (s_daemon && s_logFilter == NULL) { if (ARG->m_daemon && ARG->m_logFilter == NULL) {
#if WINDOWS_LIKE #if WINDOWS_LIKE
if (CPlatform::isWindows95Family()) { if (CArchMiscWindows::isWindows95Family()) {
// windows 95 has no place for logging so avoid showing // windows 95 has no place for logging so avoid showing
// the log console window. // the log console window.
s_logFilter = "FATAL"; ARG->m_logFilter = "FATAL";
} }
else else
#endif #endif
{ {
s_logFilter = "NOTE"; ARG->m_logFilter = "NOTE";
} }
} }
// set log filter // set log filter
if (!CLog::setFilter(s_logFilter)) { if (!CLOG->setFilter(ARG->m_logFilter)) {
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE, LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
pname, s_logFilter, pname)); ARG->m_pname, ARG->m_logFilter, ARG->m_pname));
bye(kExitArgs); bye(kExitArgs);
} }
} }
@ -518,14 +496,14 @@ loadConfig(const char* pathname, bool require)
if (!configStream) { if (!configStream) {
throw XConfigRead("cannot open file"); throw XConfigRead("cannot open file");
} }
configStream >> s_config; configStream >> ARG->m_config;
LOG((CLOG_DEBUG "configuration read successfully")); LOG((CLOG_DEBUG "configuration read successfully"));
return true; return true;
} }
catch (XConfigRead& e) { catch (XConfigRead& e) {
if (require) { if (require) {
LOG((CLOG_PRINT "%s: cannot read configuration '%s': %s", LOG((CLOG_PRINT "%s: cannot read configuration '%s': %s",
pname, pathname, e.what())); ARG->m_pname, pathname, e.what()));
bye(kExitConfig); bye(kExitConfig);
} }
else { else {
@ -541,36 +519,46 @@ void
loadConfig() loadConfig()
{ {
// load the config file, if specified // load the config file, if specified
if (s_configFile != NULL) { if (ARG->m_configFile != NULL) {
// require the user specified file to load correctly // require the user specified file to load correctly
loadConfig(s_configFile, true); loadConfig(ARG->m_configFile, true);
} }
// load the default configuration if no explicit file given // load the default configuration if no explicit file given
else { else {
// get the user's home directory. use the effective user id // get the user's home directory. use the effective user id
// so a user can't get a setuid root program to load his file. // so a user can't get a setuid root program to load his file.
CPlatform platform;
bool loaded = false; bool loaded = false;
CString path = platform.getUserDirectory(); CString path = ARCH->getUserDirectory();
if (!path.empty()) { if (!path.empty()) {
// complete path // complete path
path = platform.addPathComponent(path, USR_CONFIG_NAME); path = ARCH->concatPath(path, USR_CONFIG_NAME);
// now try loading the user's configuration // now try loading the user's configuration
loaded = loadConfig(path.c_str(), false); loaded = loadConfig(path.c_str(), false);
} }
if (!loaded) { if (!loaded) {
// try the system-wide config file // try the system-wide config file
path = platform.getSystemDirectory(); path = ARCH->getSystemDirectory();
if (!path.empty()) { if (!path.empty()) {
path = platform.addPathComponent(path, SYS_CONFIG_NAME); path = ARCH->concatPath(path, SYS_CONFIG_NAME);
loadConfig(path.c_str(), false); loadConfig(path.c_str(), false);
} }
} }
} }
} }
static
void
useSystemLog()
{
// redirect log messages
ILogOutputter* logger = new CSystemLogOutputter;
logger->open(DAEMON_NAME);
CLOG->insert(new CStopLogOutputter);
CLOG->insert(logger);
}
// //
// platform dependent entry points // platform dependent entry points
// //
@ -581,24 +569,41 @@ loadConfig()
static bool s_hasImportantLogMessages = false; static bool s_hasImportantLogMessages = false;
static //
// CMessageBoxOutputter
//
// This class writes severe log messages to a message box
//
class CMessageBoxOutputter : public ILogOutputter {
public:
CMessageBoxOutputter() { }
virtual ~CMessageBoxOutputter() { }
// ILogOutputter overrides
virtual void open(const char*) { }
virtual void close() { }
virtual bool write(ELevel level, const char* message);
virtual const char* getNewline() const { return ""; }
};
bool bool
logMessageBox(int priority, const char* msg) CMessageBoxOutputter::write(ELevel level, const char* message)
{ {
// note any important messages the user may need to know about // note any important messages the user may need to know about
if (priority <= CLog::kWARNING) { if (level <= CLog::kWARNING) {
s_hasImportantLogMessages = true; s_hasImportantLogMessages = true;
} }
// FATAL and PRINT messages get a dialog box if not running as // FATAL and PRINT messages get a dialog box if not running as
// backend. if we're running as a backend the user will have // backend. if we're running as a backend the user will have
// a chance to see the messages when we exit. // a chance to see the messages when we exit.
if (!s_backend && priority <= CLog::kFATAL) { if (!ARG->m_backend && level <= CLog::kFATAL) {
MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING); MessageBox(NULL, message, ARG->m_pname, MB_OK | MB_ICONWARNING);
return true; return false;
} }
else { else {
return false; return true;
} }
} }
@ -606,7 +611,7 @@ static
void void
byeThrow(int x) byeThrow(int x)
{ {
throw CWin32Platform::CDaemonFailed(x); CArchMiscWindows::daemonFailed(x);
} }
static static
@ -618,10 +623,9 @@ daemonStop(void)
static static
int int
daemonStartup(IPlatform* iplatform, int argc, const char** argv) daemonStartup(int argc, const char** argv)
{ {
// get platform pointer useSystemLog();
CWin32Platform* platform = static_cast<CWin32Platform*>(iplatform);
// catch errors that would normally exit // catch errors that would normally exit
bye = &byeThrow; bye = &byeThrow;
@ -630,38 +634,38 @@ daemonStartup(IPlatform* iplatform, int argc, const char** argv)
parse(argc, argv); parse(argc, argv);
// cannot run as backend if running as a service // cannot run as backend if running as a service
s_backend = false; ARG->m_backend = false;
// load configuration // load configuration
loadConfig(); loadConfig();
// run as a service // run as a service
return platform->runDaemon(realMain, daemonStop); return CArchMiscWindows::runDaemon(realMain, daemonStop);
} }
static static
int int
daemonStartup95(IPlatform*, int, const char**) daemonStartup95(int, const char**)
{ {
return realMain(NULL); useSystemLog();
return realMain();
} }
int WINAPI int WINAPI
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
{ {
CPlatform platform; CArch arch;
CLOG;
CArgs args;
// save instance // save instance
CMSWindowsScreen::init(instance); CMSWindowsScreen::init(instance);
// get program name // get program name
pname = platform.getBasename(__argv[0]); ARG->m_pname = ARCH->getBasename(__argv[0]);
// initialize network library
CNetwork::init();
// send PRINT and FATAL output to a message box // send PRINT and FATAL output to a message box
CLog::setOutputter(&logMessageBox); CLOG->insert(new CMessageBoxOutputter);
// windows NT family starts services using no command line options. // windows NT family starts services using no command line options.
// since i'm not sure how to tell the difference between that and // since i'm not sure how to tell the difference between that and
@ -669,13 +673,14 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
// arguments and we're on NT then we're being invoked as a service. // arguments and we're on NT then we're being invoked as a service.
// users on NT can use `--daemon' or `--no-daemon' to force us out // users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path. // of the service code path.
if (__argc <= 1 && !CWin32Platform::isWindows95Family()) { if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
int result = platform.daemonize(DAEMON_NAME, &daemonStartup); try {
if (result == -1) { return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
LOG((CLOG_CRIT "failed to start as a service" BYE, pname)); }
catch (XArchDaemon&) {
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
return kExitFailed; return kExitFailed;
} }
return result;
} }
// parse command line // parse command line
@ -686,38 +691,36 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
// daemonize if requested // daemonize if requested
int result; int result;
if (s_daemon) { if (ARG->m_daemon) {
// redirect log messages
platform.installDaemonLogger(DAEMON_NAME);
// start as a daemon // start as a daemon
if (CWin32Platform::isWindows95Family()) { if (CArchMiscWindows::isWindows95Family()) {
result = platform.daemonize(DAEMON_NAME, &daemonStartup95); try {
if (result == -1) { result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
LOG((CLOG_CRIT "failed to start as a service" BYE, pname)); }
catch (XArchDaemon&) {
LOG((CLOG_CRIT "failed to start as a service" BYE, ARG->m_pname));
result = kExitFailed; result = kExitFailed;
} }
} }
else { else {
// cannot start a service from the command line so just // cannot start a service from the command line so just
// run normally (except with log messages redirected). // run normally (except with log messages redirected).
result = realMain(NULL); useSystemLog();
result = realMain();
} }
} }
else { else {
// run // run
result = realMain(NULL); result = realMain();
} }
CNetwork::cleanup();
// let user examine any messages if we're running as a backend // let user examine any messages if we're running as a backend
// by putting up a dialog box before exiting. // by putting up a dialog box before exiting.
if (s_backend && s_hasImportantLogMessages) { if (ARG->m_backend && s_hasImportantLogMessages) {
char msg[1024]; char msg[1024];
msg[0] = '\0'; msg[0] = '\0';
LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0])); LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0]));
MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING); MessageBox(NULL, msg, ARG->m_pname, MB_OK | MB_ICONWARNING);
} }
return result; return result;
@ -727,21 +730,21 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
static static
int int
daemonStartup(IPlatform*, int, const char**) daemonStartup(int, const char**)
{ {
return realMain(NULL); useSystemLog();
return realMain();
} }
int int
main(int argc, char** argv) main(int argc, char** argv)
{ {
CPlatform platform; CArch arch;
CLOG;
CArgs args;
// get program name // get program name
pname = platform.getBasename(argv[0]); ARG->m_pname = ARCH->getBasename(argv[0]);
// initialize network library
CNetwork::init();
// parse command line // parse command line
parse(argc, const_cast<const char**>(argv)); parse(argc, const_cast<const char**>(argv));
@ -751,19 +754,19 @@ main(int argc, char** argv)
// daemonize if requested // daemonize if requested
int result; int result;
if (s_daemon) { if (ARG->m_daemon) {
result = platform.daemonize(DAEMON_NAME, &daemonStartup); try {
if (result == -1) { result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon&) {
LOG((CLOG_CRIT "failed to daemonize")); LOG((CLOG_CRIT "failed to daemonize"));
return kExitFailed; result = kExitFailed;
} }
} }
else { else {
result = realMain(NULL); result = realMain();
} }
CNetwork::cleanup();
return result; return result;
} }

View File

@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c # ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
@ -70,7 +70,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32

View File

@ -13,7 +13,7 @@ dnl GNU General Public License for more details.
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
dnl initialize dnl initialize
AC_INIT(lib/base/common.h) AC_INIT(lib/common/common.h)
AC_CONFIG_AUX_DIR(config) AC_CONFIG_AUX_DIR(config)
dnl current version dnl current version
@ -99,7 +99,9 @@ LIBS="$NANOSLEEP_LIBS $INET_ATON_LIBS $PTHREAD_LIBS $LIBS"
AC_OUTPUT([ AC_OUTPUT([
Makefile Makefile
lib/Makefile lib/Makefile
lib/arch/Makefile
lib/base/Makefile lib/base/Makefile
lib/common/Makefile
lib/mt/Makefile lib/mt/Makefile
lib/io/Makefile lib/io/Makefile
lib/http/Makefile lib/http/Makefile

View File

@ -16,6 +16,8 @@ DEPTH = ..
VDEPTH = ./$(VPATH)/$(DEPTH) VDEPTH = ./$(VPATH)/$(DEPTH)
SUBDIRS = \ SUBDIRS = \
common \
arch \
base \ base \
mt \ mt \
io \ io \

576
lib/arch/CArch.cpp Normal file
View 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
View 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

View 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";
}

View 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

View 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;
}

View 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

View 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;
}

View 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

View 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);
}

View 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

View 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

View 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
View 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

View 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;
}

View 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
View 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
View 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
View 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

View 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
}
}

View 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

View 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);
}

View 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

View 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);
}
}

View 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

View 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);
}

View 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

View 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]);
}
}

View 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

View 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));
}
}

View 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

View 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
View 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

View 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();
}

View 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

View File

@ -12,25 +12,23 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#ifndef CPLATFORM_H #include "CArchStringUnix.h"
#define CPLATFORM_H #include <stdio.h>
#include "common.h" #include "CMultibyte.cpp"
#if WINDOWS_LIKE //
// CArchStringUnix
//
#include "CWin32Platform.h" CArchStringUnix::CArchStringUnix()
typedef CWin32Platform CPlatform; {
initMB();
}
#elif UNIX_LIKE CArchStringUnix::~CArchStringUnix()
{
cleanMB();
}
#include "CUnixPlatform.h" #include "vsnprintf.cpp"
typedef CUnixPlatform CPlatform;
#else
#error Unsupported platform
#endif
#endif

View 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

View 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"

View 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

View 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
View 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

View 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());
}
}

View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -12,18 +12,14 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include "common.h" #ifndef XARCHIMPL_H
#define XARCHIMPL_H
// include appropriate architecture implementation
#if WINDOWS_LIKE #if WINDOWS_LIKE
# include "XArchWindows.h"
#include "CWin32Platform.cpp"
#elif UNIX_LIKE #elif UNIX_LIKE
# include "XArchUnix.h"
#include "CUnixPlatform.cpp" #endif
#else
#error Unsupported platform
#endif #endif

33
lib/arch/XArchUnix.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -14,15 +14,13 @@
#include "CLog.h" #include "CLog.h"
#include "CString.h" #include "CString.h"
#include "CStringUtil.h"
#include "LogOutputters.h"
#include "CArch.h"
#include "Version.h"
#include <cstdio> #include <cstdio>
#include <cstdlib>
#include <cstring> #include <cstring>
#if WINDOWS_LIKE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
// names of priorities // names of priorities
static const char* g_priority[] = { static const char* g_priority[] = {
"FATAL", "FATAL",
@ -56,26 +54,64 @@ static const int g_prioritySuffixLength = 2;
static const int g_priorityPad = g_maxPriorityLength + static const int g_priorityPad = g_maxPriorityLength +
g_prioritySuffixLength; g_prioritySuffixLength;
// platform newline sequence //
#if WINDOWS_LIKE // CLogLock
static const char* g_newline = "\r\n"; //
#else // Convenience object to lock/unlock a mutex.
static const char* g_newline = "\n"; //
#endif
class CLogLock {
public:
CLogLock(CArchMutex mutex) : m_mutex(mutex) { ARCH->lockMutex(m_mutex); }
~CLogLock() { ARCH->unlockMutex(m_mutex); }
private:
CArchMutex m_mutex;
};
// minimum length of a newline sequence
static const int g_newlineLength = 2;
// //
// CLog // CLog
// //
CLog::Outputter CLog::s_outputter = NULL; CLog* CLog::s_log = NULL;
CLog::Lock CLog::s_lock = &CLog::dummyLock;
int CLog::s_maxPriority = -1; CLog::CLog()
{
assert(s_log == NULL);
// create mutex for multithread safe operation
m_mutex = ARCH->newMutex();
// other initalization
m_maxPriority = g_defaultMaxPriority;
m_maxNewlineLength = 0;
insert(new CConsoleLogOutputter);
}
CLog::~CLog()
{
// clean up
for (COutputterList::iterator index = m_outputters.begin();
index != m_outputters.end(); ++index) {
delete *index;
}
ARCH->closeMutex(m_mutex);
s_log = NULL;
}
CLog*
CLog::getInstance()
{
// note -- not thread safe; client must initialize log safely
if (s_log == NULL) {
s_log = new CLog;
}
return s_log;
}
void void
CLog::print(const char* fmt, ...) CLog::print(const char* fmt, ...) const
{ {
// check if fmt begins with a priority argument // check if fmt begins with a priority argument
int priority = 4; int priority = 4;
@ -85,7 +121,7 @@ CLog::print(const char* fmt, ...)
} }
// done if below priority threshold // done if below priority threshold
if (priority > getMaxPriority()) { if (priority > getFilter()) {
return; return;
} }
@ -98,7 +134,7 @@ CLog::print(const char* fmt, ...)
va_start(args, fmt); va_start(args, fmt);
char* buffer = CStringUtil::vsprint(stack, char* buffer = CStringUtil::vsprint(stack,
sizeof(stack) / sizeof(stack[0]), sizeof(stack) / sizeof(stack[0]),
pad, g_newlineLength, fmt, args); pad, m_maxNewlineLength, fmt, args);
va_end(args); va_end(args);
// output buffer // output buffer
@ -110,7 +146,7 @@ CLog::print(const char* fmt, ...)
} }
void void
CLog::printt(const char* file, int line, const char* fmt, ...) CLog::printt(const char* file, int line, const char* fmt, ...) const
{ {
// check if fmt begins with a priority argument // check if fmt begins with a priority argument
int priority = 4; int priority = 4;
@ -120,7 +156,7 @@ CLog::printt(const char* file, int line, const char* fmt, ...)
} }
// done if below priority threshold // done if below priority threshold
if (priority > getMaxPriority()) { if (priority > getFilter()) {
return; return;
} }
@ -136,7 +172,7 @@ CLog::printt(const char* file, int line, const char* fmt, ...)
va_start(args, fmt); va_start(args, fmt);
char* buffer = CStringUtil::vsprint(stack, char* buffer = CStringUtil::vsprint(stack,
sizeof(stack) / sizeof(stack[0]), sizeof(stack) / sizeof(stack[0]),
pad, g_newlineLength, fmt, args); pad, m_maxNewlineLength, fmt, args);
va_end(args); va_end(args);
// print the prefix to the buffer. leave space for priority label. // print the prefix to the buffer. leave space for priority label.
@ -158,31 +194,34 @@ CLog::printt(const char* file, int line, const char* fmt, ...)
} }
void void
CLog::setOutputter(Outputter outputter) CLog::insert(ILogOutputter* outputter)
{ {
CHoldLock lock(s_lock); assert(outputter != NULL);
s_outputter = outputter; assert(outputter->getNewline() != NULL);
}
CLog::Outputter CLogLock lock(m_mutex);
CLog::getOutputter() m_outputters.push_front(outputter);
{ int newlineLength = strlen(outputter->getNewline());
CHoldLock lock(s_lock); if (newlineLength > m_maxNewlineLength) {
return s_outputter; m_maxNewlineLength = newlineLength;
}
} }
void void
CLog::setLock(Lock newLock) CLog::remove(ILogOutputter* outputter)
{ {
CHoldLock lock(s_lock); CLogLock lock(m_mutex);
s_lock = (newLock == NULL) ? dummyLock : newLock; m_outputters.remove(outputter);
} }
CLog::Lock void
CLog::getLock() CLog::pop_front()
{ {
CHoldLock lock(s_lock); CLogLock lock(m_mutex);
return (s_lock == dummyLock) ? NULL : s_lock; if (!m_outputters.empty()) {
delete m_outputters.front();
m_outputters.pop_front();
}
} }
bool bool
@ -203,38 +242,19 @@ CLog::setFilter(const char* maxPriority)
void void
CLog::setFilter(int maxPriority) CLog::setFilter(int maxPriority)
{ {
CHoldLock lock(s_lock); CLogLock lock(m_mutex);
s_maxPriority = maxPriority; m_maxPriority = maxPriority;
} }
int int
CLog::getFilter() CLog::getFilter() const
{ {
CHoldLock lock(s_lock); CLogLock lock(m_mutex);
return getMaxPriority(); return m_maxPriority;
} }
void void
CLog::dummyLock(bool) CLog::output(int priority, char* msg) const
{
// do nothing
}
int
CLog::getMaxPriority()
{
CHoldLock lock(s_lock);
if (s_maxPriority == -1) {
s_maxPriority = g_defaultMaxPriority;
setFilter(getenv("SYN_LOG_PRI"));
}
return s_maxPriority;
}
void
CLog::output(int priority, char* msg)
{ {
assert(priority >= -1 && priority < g_numPriority); assert(priority >= -1 && priority < g_numPriority);
assert(msg != NULL); assert(msg != NULL);
@ -249,79 +269,23 @@ CLog::output(int priority, char* msg)
msg[g_maxPriorityLength + 1] = ' '; msg[g_maxPriorityLength + 1] = ' ';
} }
// put a newline at the end // write to each outputter
strcat(msg + g_priorityPad, g_newline); CLogLock lock(m_mutex);
for (COutputterList::const_iterator index = m_outputters.begin();
index != m_outputters.end(); ++index) {
// get outputter
ILogOutputter* outputter = *index;
// print it // put an appropriate newline at the end
CHoldLock lock(s_lock); strcat(msg + g_priorityPad, outputter->getNewline());
if (s_outputter == NULL ||
!s_outputter(priority, msg + g_maxPriorityLength - n)) { // open the outputter
#if WINDOWS_LIKE outputter->open(kApplication);
openConsole();
#endif // write message and break out of loop if it returns false
fprintf(stderr, "%s", msg + g_maxPriorityLength - n); if (!outputter->write(static_cast<ILogOutputter::ELevel>(priority),
msg + g_maxPriorityLength - n)) {
break;
}
} }
} }
#if WINDOWS_LIKE
static DWORD s_thread = 0;
static
BOOL WINAPI
CLogSignalHandler(DWORD)
{
// terminate cleanly and skip remaining handlers
PostThreadMessage(s_thread, WM_QUIT, 0, 0);
return TRUE;
}
void
CLog::openConsole()
{
static bool s_hasConsole = false;
// ignore if already created
if (s_hasConsole)
return;
// remember the current thread. when we get a ctrl+break or the
// console is closed we'll post WM_QUIT to this thread to shutdown
// cleanly.
// note -- win95/98/me are broken and will not receive a signal
// when the console is closed nor during logoff or shutdown,
// see microsoft articles Q130717 and Q134284. we could work
// around this in a painful way using hooks and hidden windows
// (as apache does) but it's not worth it. the app will still
// quit, just not cleanly. users in-the-know can use ctrl+c.
s_thread = GetCurrentThreadId();
// open a console
if (!AllocConsole())
return;
// get the handle for error output
HANDLE herr = GetStdHandle(STD_ERROR_HANDLE);
// prep console. windows 95 and its ilk have braindead
// consoles that can't even resize independently of the
// buffer size. use a 25 line buffer for those systems.
OSVERSIONINFO osInfo;
COORD size = { 80, 1000 };
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
if (GetVersionEx(&osInfo) &&
osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
size.Y = 25;
SetConsoleScreenBufferSize(herr, size);
SetConsoleTextAttribute(herr,
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE);
SetConsoleCtrlHandler(CLogSignalHandler, TRUE);
// reopen stderr to point at console
freopen("con", "w", stderr);
s_hasConsole = true;
}
#endif

View File

@ -16,8 +16,15 @@
#define CLOG_H #define CLOG_H
#include "common.h" #include "common.h"
#include "IArchMultithread.h"
#include "IInterface.h"
#include "stdlist.h"
#include <stdarg.h> #include <stdarg.h>
#define CLOG (CLog::getInstance())
class ILogOutputter;
//! Logging facility //! Logging facility
/*! /*!
The logging class; all console output should go through this class. The logging class; all console output should go through this class.
@ -42,56 +49,51 @@ public:
kDEBUG2 //!< For even more detailed debugging messages kDEBUG2 //!< For even more detailed debugging messages
}; };
//! Outputter function. ~CLog();
/*!
Type of outputter function. The outputter should write \c message,
which has the given \c priority, to a log and return true. Or it can
return false to let CLog use the default outputter.
*/
typedef bool (*Outputter)(int priority, const char* message);
//! Locking function
/*!
Type of lock/unlock function. If \c lock is true then block other
threads that try to lock until this thread unlocks. If \c lock is
false then unlock and allow another (waiting) thread to lock.
*/
typedef void (*Lock)(bool lock);
//! @name manipulators //! @name manipulators
//@{ //@{
//! Set the function used to write the log //! Add an outputter to the head of the list
/*! /*!
Sets the function used to write to the log. The outputter function Inserts an outputter to the head of the outputter list. When the
is called with the formatted string to write and the priority level. logger writes a message, it goes to the outputter at the head of
CLog will have already filtered messages below the current filter the outputter list. If that outputter's \c write() method returns
priority. A NULL outputter means to use the default which is to print true then it also goes to the next outputter, as so on until an
to stderr. Note that the outputter should not call CLog methods but, outputter returns false or there are no more outputters. Outputters
if it does, the current lock function must permit recursive locks. still in the outputter list when the log is destroyed will be
*/ deleted.
static void setOutputter(Outputter);
//! Set the lock/unlock function By default, the logger has one outputter installed which writes to
/*! the console.
Set the lock/unlock function. Use setLock(NULL) to remove the
locking function. There is no default lock function; do not call
CLog from multiple threads unless a working lock function has been
installed.
*/ */
static void setLock(Lock); void insert(ILogOutputter* adopted);
//! Remove an outputter from the list
/*!
Removes the first occurrence of the given outputter from the
outputter list. It does nothing if the outputter is not in the
list. The outputter is not deleted.
*/
void remove(ILogOutputter* orphaned);
//! Remove the outputter from the head of the list
/*!
Removes and deletes the outputter at the head of the outputter list.
This does nothing if the outputter list is empty.
*/
void pop_front();
//! Set the minimum priority filter. //! Set the minimum priority filter.
/*! /*!
Set the filter. Messages below this priority are discarded. Set the filter. Messages below this priority are discarded.
The default priority is 4 (INFO) (unless built without NDEBUG The default priority is 4 (INFO) (unless built without NDEBUG
in which case it's 5 (DEBUG)). The default can be overridden in which case it's 5 (DEBUG)). setFilter(const char*) returns
by setting the SYN_LOG_PRI env var to "FATAL", "ERROR", etc. true if the priority \c name was recognized; if \c name is NULL
setFilter(const char*) returns true if the priority \c name was then it simply returns true.
recognized; if \c name is NULL then it simply returns true.
*/ */
static bool setFilter(const char* name); bool setFilter(const char* name);
static void setFilter(int); void setFilter(int);
//@} //@}
//! @name accessors //! @name accessors
@ -101,52 +103,38 @@ public:
/*! /*!
Print a log message using the printf-like \c format and arguments. Print a log message using the printf-like \c format and arguments.
*/ */
static void print(const char* format, ...); void print(const char* format, ...) const;
//! Print a log message //! Print a log message
/*! /*!
Print a log message using the printf-like \c format and arguments Print a log message using the printf-like \c format and arguments
preceded by the filename and line number. preceded by the filename and line number.
*/ */
static void printt(const char* file, int line, void printt(const char* file, int line,
const char* format, ...); const char* format, ...) const;
//! Get the function used to write the log
static Outputter getOutputter();
//! Get the lock/unlock function
/*!
Get the lock/unlock function. Note that the lock function is
used when retrieving the lock function.
*/
static Lock getLock();
//! Get the minimum priority level. //! Get the minimum priority level.
static int getFilter(); int getFilter() const;
//! Get the singleton instance of the log
static CLog* getInstance();
//@} //@}
private: private:
class CHoldLock { CLog();
public:
CHoldLock(Lock lock) : m_lock(lock) { m_lock(true); }
~CHoldLock() { m_lock(false); }
private: void output(int priority, char* msg) const;
Lock m_lock;
};
static void dummyLock(bool);
static int getMaxPriority();
static void output(int priority, char* msg);
#if WINDOWS_LIKE
static void openConsole();
#endif
private: private:
static Outputter s_outputter; typedef std::list<ILogOutputter*> COutputterList;
static Lock s_lock;
static int s_maxPriority; static CLog* s_log;
CArchMutex m_mutex;
COutputterList m_outputters;
int m_maxNewlineLength;
int m_maxPriority;
}; };
/*! /*!
@ -193,12 +181,12 @@ which includes the filename and line number.
#define LOGC(_a1, _a2) #define LOGC(_a1, _a2)
#define CLOG_TRACE #define CLOG_TRACE
#elif defined(NDEBUG) #elif defined(NDEBUG)
#define LOG(_a1) CLog::print _a1 #define LOG(_a1) CLOG->print _a1
#define LOGC(_a1, _a2) if (_a1) CLog::print _a2 #define LOGC(_a1, _a2) if (_a1) CLOG->print _a2
#define CLOG_TRACE #define CLOG_TRACE
#else #else
#define LOG(_a1) CLog::printt _a1 #define LOG(_a1) CLOG->printt _a1
#define LOGC(_a1, _a2) if (_a1) CLog::printt _a2 #define LOGC(_a1, _a2) if (_a1) CLOG->printt _a2
#define CLOG_TRACE __FILE__, __LINE__, #define CLOG_TRACE __FILE__, __LINE__,
#endif #endif

View File

@ -13,6 +13,7 @@
*/ */
#include "CStopwatch.h" #include "CStopwatch.h"
#include "CArch.h"
// //
// CStopwatch // CStopwatch
@ -24,7 +25,7 @@ CStopwatch::CStopwatch(bool triggered) :
m_stopped(triggered) m_stopped(triggered)
{ {
if (!triggered) { if (!triggered) {
m_mark = getClock(); m_mark = ARCH->time();
} }
} }
@ -42,7 +43,7 @@ CStopwatch::reset()
return dt; return dt;
} }
else { else {
const double t = getClock(); const double t = ARCH->time();
const double dt = t - m_mark; const double dt = t - m_mark;
m_mark = t; m_mark = t;
return dt; return dt;
@ -57,7 +58,7 @@ CStopwatch::stop()
} }
// save the elapsed time // save the elapsed time
m_mark = getClock() - m_mark; m_mark = ARCH->time() - m_mark;
m_stopped = true; m_stopped = true;
} }
@ -70,7 +71,7 @@ CStopwatch::start()
} }
// set the mark such that it reports the time elapsed at stop() // set the mark such that it reports the time elapsed at stop()
m_mark = getClock() - m_mark; m_mark = ARCH->time() - m_mark;
m_stopped = false; m_stopped = false;
} }
@ -93,7 +94,7 @@ CStopwatch::getTime()
return m_mark; return m_mark;
} }
else { else {
return getClock() - m_mark; return ARCH->time() - m_mark;
} }
} }
@ -115,7 +116,7 @@ CStopwatch::getTime() const
return m_mark; return m_mark;
} }
else { else {
return getClock() - m_mark; return ARCH->time() - m_mark;
} }
} }
@ -123,100 +124,3 @@ CStopwatch::operator double() const
{ {
return getTime(); return getTime();
} }
#if WINDOWS_LIKE
// avoid getting a lot a crap from mmsystem.h that we don't need
#define MMNODRV // Installable driver support
#define MMNOSOUND // Sound support
#define MMNOWAVE // Waveform support
#define MMNOMIDI // MIDI support
#define MMNOAUX // Auxiliary audio support
#define MMNOMIXER // Mixer support
#define MMNOJOY // Joystick support
#define MMNOMCI // MCI support
#define MMNOMMIO // Multimedia file I/O support
#define MMNOMMSYSTEM // General MMSYSTEM functions
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
typedef WINMMAPI DWORD (WINAPI *PTimeGetTime)(void);
static double s_freq = 0.0;
static HINSTANCE s_mmInstance = NULL;
static PTimeGetTime s_tgt = NULL;
//
// initialize local variables
//
class CStopwatchInit {
public:
CStopwatchInit();
~CStopwatchInit();
};
static CStopwatchInit s_init;
CStopwatchInit::CStopwatchInit()
{
LARGE_INTEGER freq;
if (QueryPerformanceFrequency(&freq) && freq.QuadPart != 0) {
s_freq = 1.0 / static_cast<double>(freq.QuadPart);
}
else {
// load winmm.dll and get timeGetTime
s_mmInstance = LoadLibrary("winmm");
if (s_mmInstance) {
s_tgt = (PTimeGetTime)GetProcAddress(s_mmInstance, "timeGetTime");
}
}
}
CStopwatchInit::~CStopwatchInit()
{
if (s_mmInstance) {
FreeLibrary(reinterpret_cast<HMODULE>(s_mmInstance));
}
}
double
CStopwatch::getClock() const
{
// get time. we try three ways, in order of descending precision
if (s_freq != 0.0) {
LARGE_INTEGER c;
QueryPerformanceCounter(&c);
return s_freq * static_cast<double>(c.QuadPart);
}
else if (s_tgt) {
return 0.001 * static_cast<double>(s_tgt());
}
else {
return 0.001 * static_cast<double>(GetTickCount());
}
}
#elif UNIX_LIKE
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
double
CStopwatch::getClock() const
{
struct timeval t;
gettimeofday(&t, NULL);
return (double)t.tv_sec + 1.0e-6 * (double)t.tv_usec;
}
#endif // UNIX_LIKE

View File

@ -15,90 +15,10 @@
#ifndef CSTRING_H #ifndef CSTRING_H
#define CSTRING_H #define CSTRING_H
#include <stdarg.h> #include "stdstring.h"
#include "stdpre.h"
#include <string>
#include "stdpost.h"
// use standard C++ string class for our string class // use standard C++ string class for our string class
typedef std::string CString; typedef std::string CString;
//! String utilities
/*!
This class provides various functions for string manipulation.
*/
class CStringUtil {
public:
//! Format positional arguments
/*!
Format a string using positional arguments. fmt has literal
characters and conversion specifications introduced by `\%':
- \c\%\% -- literal `\%'
- \c\%{n} -- positional element n, n a positive integer, {} are literal
All arguments in the variable list are const char*. Positional
elements are indexed from 1.
*/
static CString format(const char* fmt, ...);
//! Format positional arguments
/*!
Same as format() except takes va_list.
*/
static CString vformat(const char* fmt, va_list);
//! Print a string using printf-style formatting
/*!
Equivalent to printf() except the result is returned as a CString.
*/
static CString print(const char* fmt, ...);
//! Print a string using printf-style formatting
/*!
Same as print() except takes va_list.
*/
static CString vprint(const char* fmt, va_list);
//! Print a string using printf-style formatting into a buffer
/*!
This is like print but print into a given buffer. If the resulting
string will not fit into \c buffer then a new buffer is allocated and
returned, otherwise \c buffer is returned. the caller must delete[]
the returned memory if is not \c buffer.
\c prefix and \c suffix must be >= 0. Exactly \c prefix characters and
at least \c suffix characters are available in the buffer before
and after the printed string, respectively. \c bufferLength is the
length of buffer and should not be adjusted by the caller to
account for \c prefix or \c suffix.
*/
static char* vsprint(char* buffer, int bufferLength,
int prefix, int suffix, const char* fmt, va_list);
//! Case-insensitive comparisons
/*!
This class provides case-insensitve comparison functions.
*/
class CaselessCmp {
public:
//! Same as less()
bool operator()(const CString& a, const CString& b) const;
//! Returns true iff \c a is lexicographically less than \c b
static bool less(const CString& a, const CString& b);
//! Returns true iff \c a is lexicographically equal to \c b
static bool equal(const CString& a, const CString& b);
//! Returns true iff \c a is lexicographically less than \c b
static bool cmpLess(const CString::value_type& a,
const CString::value_type& b);
//! Returns true iff \c a is lexicographically equal to \c b
static bool cmpEqual(const CString::value_type& a,
const CString::value_type& b);
};
};
#endif #endif

View File

@ -12,7 +12,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include "CString.h" #include "CStringUtil.h"
#include "CArch.h"
#include "common.h" #include "common.h"
#include "stdvector.h" #include "stdvector.h"
#include <cctype> #include <cctype>
@ -20,12 +21,6 @@
#include <cstdlib> #include <cstdlib>
#include <algorithm> #include <algorithm>
#if WINDOWS_LIKE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define vsnprintf _vsnprintf
#endif
// //
// CStringUtil // CStringUtil
// //
@ -152,7 +147,8 @@ CStringUtil::vsprint(char* buffer, int len,
// try writing to input buffer // try writing to input buffer
int n; int n;
if (buffer != NULL && len >= prefix + suffix) { if (buffer != NULL && len >= prefix + suffix) {
n = vsnprintf(buffer + prefix, len - (prefix + suffix), fmt, args); n = ARCH->vsnprintf(buffer + prefix,
len - (prefix + suffix), fmt, args);
if (n >= 0 && n <= len - (prefix + suffix)) if (n >= 0 && n <= len - (prefix + suffix))
return buffer; return buffer;
} }
@ -163,7 +159,8 @@ CStringUtil::vsprint(char* buffer, int len,
delete[] buffer; delete[] buffer;
len *= 2; len *= 2;
buffer = new char[len + (prefix + suffix)]; buffer = new char[len + (prefix + suffix)];
n = vsnprintf(buffer + prefix, len - (prefix + suffix), fmt, args); n = ARCH->vsnprintf(buffer + prefix,
len - (prefix + suffix), fmt, args);
} while (n < 0 || n > len - (prefix + suffix)); } while (n < 0 || n > len - (prefix + suffix));
return buffer; return buffer;

99
lib/base/CStringUtil.h Normal file
View 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

View File

@ -13,7 +13,7 @@
*/ */
#include "CUnicode.h" #include "CUnicode.h"
#include <limits.h> #include "CArch.h"
#include <string.h> #include <string.h>
// //
@ -70,59 +70,6 @@ setError(bool* errors)
} }
} }
//
// multibyte conversion stuff when reentrant versions not available
//
#if WINDOWS_LIKE
#define HAVE_MBSINIT 1
#define HAVE_MBRTOWC 1
#define HAVE_WCRTOMB 1
#endif
#if !HAVE_MBSINIT
static
int
mbsinit(const mbstate_t*)
{
return 1;
}
#endif
#if !HAVE_MBRTOWC
#include "CLock.h"
#include "CMutex.h"
static CMutex s_mbrtowcMutex;
static
size_t
mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t*)
{
CLock lock(&s_mbrtowcMutex);
int result = mbtowc(pwc, s, n);
if (result < 0)
return (size_t)-1;
else
return result;
}
#endif
#if !HAVE_WCRTOMB
#include "CLock.h"
#include "CMutex.h"
static CMutex s_wcrtombMutex;
static
size_t
wcrtomb(char* s, wchar_t wc, mbstate_t*)
{
CLock lock(&s_wcrtombMutex);
return (size_t)wctomb(s, wc);
}
#endif
// //
// CUnicode // CUnicode
@ -274,14 +221,12 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
wchar_t* tmp = UTF8ToWideChar(src, size, errors); wchar_t* tmp = UTF8ToWideChar(src, size, errors);
// get length of multibyte string // get length of multibyte string
char mbc[MB_LEN_MAX]; int mblen;
size_t mblen; CArchMBState state = ARCH->newMBState();
mbstate_t state;
memset(&state, 0, sizeof(state));
size_t len = 0; size_t len = 0;
UInt32 n = size; UInt32 n = size;
for (const wchar_t* scan = tmp; n > 0; ++scan, --n) { for (const wchar_t* scan = tmp; n > 0; ++scan, --n) {
mblen = wcrtomb(mbc, *scan, &state); mblen = ARCH->convWCToMB(NULL, *scan, state);
if (mblen == -1) { if (mblen == -1) {
// unconvertable character // unconvertable character
setError(errors); setError(errors);
@ -293,11 +238,11 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
} }
// handle nul terminator // handle nul terminator
mblen = wcrtomb(mbc, L'\0', &state); mblen = ARCH->convWCToMB(NULL, L'\0', state);
if (mblen != -1) { if (mblen != -1) {
len += mblen; len += mblen;
} }
assert(mbsinit(&state) != 0); assert(ARCH->isInitMBState(state) != 0);
// allocate multibyte string // allocate multibyte string
char* mbs = new char[len]; char* mbs = new char[len];
@ -306,7 +251,7 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
char* dst = mbs; char* dst = mbs;
n = size; n = size;
for (const wchar_t* scan = tmp; n > 0; ++scan, --n) { for (const wchar_t* scan = tmp; n > 0; ++scan, --n) {
mblen = wcrtomb(dst, *scan, &state); mblen = ARCH->convWCToMB(dst, *scan, state);
if (mblen == -1) { if (mblen == -1) {
// unconvertable character // unconvertable character
*dst++ = '?'; *dst++ = '?';
@ -315,7 +260,7 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
dst += mblen; dst += mblen;
} }
} }
mblen = wcrtomb(dst, L'\0', &state); mblen = ARCH->convWCToMB(dst, L'\0', state);
if (mblen != -1) { if (mblen != -1) {
// don't include nul terminator // don't include nul terminator
dst += mblen - 1; dst += mblen - 1;
@ -325,6 +270,7 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
// clean up // clean up
delete[] mbs; delete[] mbs;
delete[] tmp; delete[] tmp;
ARCH->closeMBState(state);
return text; return text;
} }
@ -382,19 +328,18 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
// get length of multibyte string // get length of multibyte string
UInt32 n = src.size(); UInt32 n = src.size();
size_t len = 0; size_t len = 0;
mbstate_t state; CArchMBState state = ARCH->newMBState();
memset(&state, 0, sizeof(state));
for (const char* scan = src.c_str(); n > 0; ) { for (const char* scan = src.c_str(); n > 0; ) {
size_t mblen = mbrtowc(NULL, scan, n, &state); int mblen = ARCH->convMBToWC(NULL, scan, n, state);
switch (mblen) { switch (mblen) {
case (size_t)-2: case -2:
// incomplete last character. convert to unknown character. // incomplete last character. convert to unknown character.
setError(errors); setError(errors);
len += 1; len += 1;
n = 0; n = 0;
break; break;
case (size_t)-1: case -1:
// invalid character. count one unknown character and // invalid character. count one unknown character and
// start at the next byte. // start at the next byte.
setError(errors); setError(errors);
@ -417,7 +362,7 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
break; break;
} }
} }
memset(&state, 0, sizeof(state)); ARCH->initMBState(state);
// allocate wide character string // allocate wide character string
wchar_t* wcs = new wchar_t[len]; wchar_t* wcs = new wchar_t[len];
@ -426,15 +371,15 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
n = src.size(); n = src.size();
wchar_t* dst = wcs; wchar_t* dst = wcs;
for (const char* scan = src.c_str(); n > 0; ++dst) { for (const char* scan = src.c_str(); n > 0; ++dst) {
size_t mblen = mbrtowc(dst, scan, n, &state); int mblen = ARCH->convMBToWC(dst, scan, n, state);
switch (mblen) { switch (mblen) {
case (size_t)-2: case -2:
// incomplete character. convert to unknown character. // incomplete character. convert to unknown character.
*dst = (wchar_t)0xfffd; *dst = (wchar_t)0xfffd;
n = 0; n = 0;
break; break;
case (size_t)-1: case -1:
// invalid character. count one unknown character and // invalid character. count one unknown character and
// start at the next byte. // start at the next byte.
*dst = (wchar_t)0xfffd; *dst = (wchar_t)0xfffd;

View File

@ -17,7 +17,6 @@
#include "CString.h" #include "CString.h"
#include "BasicTypes.h" #include "BasicTypes.h"
#include <cwchar>
//! Unicode utility functions //! Unicode utility functions
/*! /*!

71
lib/base/ILogOutputter.h Normal file
View 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

View File

@ -28,29 +28,23 @@ libbase_a_SOURCES = \
CFunctionJob.cpp \ CFunctionJob.cpp \
CLog.cpp \ CLog.cpp \
CStopwatch.cpp \ CStopwatch.cpp \
CString.cpp \ CStringUtil.cpp \
CUnicode.cpp \
LogOutputters.cpp \
XBase.cpp \ XBase.cpp \
BasicTypes.h \
CFunctionJob.h \ CFunctionJob.h \
CLog.h \ CLog.h \
CStopwatch.h \ CStopwatch.h \
CString.h \ CString.h \
IInterface.h \ CStringUtil.h \
CUnicode.h \
IJob.h \ IJob.h \
ILogOutputter.h \
LogOutputters.h \
TMethodJob.h \ TMethodJob.h \
Version.h \
XBase.h \ XBase.h \
common.h \
stdfstream.h \
stdistream.h \
stdlist.h \
stdmap.h \
stdostream.h \
stdpost.h \
stdpre.h \
stdset.h \
stdsstream.h \
stdvector.h \
$(NULL) $(NULL)
INCLUDES = \ INCLUDES = \
-I$(VDEPTH)/lib/common \
-I$(VDEPTH)/lib/arch \
$(NULL) $(NULL)

View File

@ -13,6 +13,7 @@
*/ */
#include "XBase.h" #include "XBase.h"
#include "CStringUtil.h"
#include <cerrno> #include <cerrno>
#include <cstdarg> #include <cstdarg>
@ -79,65 +80,3 @@ XBase::format(const char* /*id*/, const char* fmt, ...) const throw()
return result; return result;
} }
//
// MXErrno
//
MXErrno::MXErrno() :
#if WINDOWS_LIKE
m_errno(GetLastError()),
#else
m_errno(errno),
#endif
m_string(NULL)
{
// do nothing
}
MXErrno::MXErrno(int err) :
m_errno(err),
m_string(NULL)
{
// do nothing
}
MXErrno::~MXErrno()
{
if (m_string != NULL) {
#if WINDOWS_LIKE
LocalFree(m_string);
#endif
}
}
int
MXErrno::getErrno() const
{
return m_errno;
}
const char*
MXErrno::getErrstr() const
{
#if WINDOWS_LIKE
if (m_string != NULL) {
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&m_string,
0,
NULL) == 0) {
m_string = NULL;
return "unknown error";
}
}
return m_string;
#else
return strerror(m_errno);
#endif
}

View File

@ -16,9 +16,11 @@
#define XBASE_H #define XBASE_H
#include "CString.h" #include "CString.h"
/*
#include "stdpre.h" #include "stdpre.h"
#include <exception> #include <exception>
#include "stdpost.h" #include "stdpost.h"
*/
//! Exception base class //! Exception base class
/*! /*!
@ -52,33 +54,73 @@ private:
mutable CString m_what; mutable CString m_what;
}; };
//! Mix-in for handling \c errno
/*! /*!
This mix-in class for exception classes provides storage and query of \def XBASE_SUBCLASS
\c errno. On Windows, it uses GetLastError() instead of errno. Convenience macro to subclass from XBase (or a subclass of it),
providing the c'tor taking a const CString&. getWhat() is not
declared.
*/ */
class MXErrno { #define XBASE_SUBCLASS(name_, super_) \
public: class name_ : public super_ { \
//! Save \c errno as the error code public: \
MXErrno(); name_() : super_() { } \
//! Save \c err as the error code name_(const CString& msg) : super_(msg) { } \
MXErrno(int err); }
virtual ~MXErrno();
//! @name accessors /*!
//@{ \def XBASE_SUBCLASS
Convenience macro to subclass from XBase (or a subclass of it),
providing the c'tor taking a const CString&. getWhat() must be
implemented.
*/
#define XBASE_SUBCLASS_WHAT(name_, super_) \
class name_ : public super_ { \
public: \
name_() : super_() { } \
name_(const CString& msg) : super_(msg) { } \
\
protected: \
virtual CString getWhat() const throw(); \
}
//! Get the error code /*!
int getErrno() const; \def XBASE_SUBCLASS_FORMAT
Convenience macro to subclass from XBase (or a subclass of it),
//! Get the human readable string for the error code providing the c'tor taking a const CString&. what() is overridden
virtual const char* getErrstr() const; to call getWhat() when first called; getWhat() can format the
error message and can call what() to get the message passed to the
//@} c'tor.
*/
private: #define XBASE_SUBCLASS_FORMAT(name_, super_) \
int m_errno; class name_ : public super_ { \
mutable char* m_string; private: \
}; enum EState { kFirst, kFormat, kDone }; \
\
public: \
name_() : super_(), m_state(kDone) { } \
name_(const CString& msg) : super_(msg), m_state(kFirst) { } \
\
virtual const char* what() const \
{ \
if (m_state == kFirst) { \
m_state = kFormat; \
m_formatted = getWhat(); \
m_state = kDone; \
} \
if (m_state == kDone) { \
return m_formatted.c_str(); \
} \
else { \
return super_::what(); \
} \
} \
\
protected: \
virtual CString getWhat() const throw(); \
\
private: \
mutable EState m_state; \
mutable std::string m_formatted; \
}
#endif #endif

View File

@ -41,7 +41,7 @@ RSC=rc.exe
# PROP Intermediate_Dir "Release" # PROP Intermediate_Dir "Release"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c # ADD CPP /nologo /MT /W4 /GX /O2 /I "..\common" /I "..\arch" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG"
@ -65,7 +65,7 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "Debug" # PROP Intermediate_Dir "Debug"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\common" /I "..\arch" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG"
@ -99,7 +99,15 @@ SOURCE=.\CStopwatch.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CString.cpp SOURCE=.\CStringUtil.cpp
# End Source File
# Begin Source File
SOURCE=.\CUnicode.cpp
# End Source File
# Begin Source File
SOURCE=.\LogOutputters.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -111,10 +119,6 @@ SOURCE=.\XBase.cpp
# PROP Default_Filter "h;hpp;hxx;hm;inl" # PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File # Begin Source File
SOURCE=.\BasicTypes.h
# End Source File
# Begin Source File
SOURCE=.\CFunctionJob.h SOURCE=.\CFunctionJob.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -123,10 +127,6 @@ SOURCE=.\CLog.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\common.h
# End Source File
# Begin Source File
SOURCE=.\CStopwatch.h SOURCE=.\CStopwatch.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -135,7 +135,11 @@ SOURCE=.\CString.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\IInterface.h SOURCE=.\CStringUtil.h
# End Source File
# Begin Source File
SOURCE=.\CUnicode.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -143,43 +147,11 @@ SOURCE=.\IJob.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\stdfstream.h SOURCE=.\ILogOutputter.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\stdistream.h SOURCE=.\LogOutputters.h
# End Source File
# Begin Source File
SOURCE=.\stdlist.h
# End Source File
# Begin Source File
SOURCE=.\stdmap.h
# End Source File
# Begin Source File
SOURCE=.\stdostream.h
# End Source File
# Begin Source File
SOURCE=.\stdpost.h
# End Source File
# Begin Source File
SOURCE=.\stdpre.h
# End Source File
# Begin Source File
SOURCE=.\stdset.h
# End Source File
# Begin Source File
SOURCE=.\stdsstream.h
# End Source File
# Begin Source File
SOURCE=.\stdvector.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -187,10 +159,6 @@ SOURCE=.\TMethodJob.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\Version.h
# End Source File
# Begin Source File
SOURCE=.\XBase.h SOURCE=.\XBase.h
# End Source File # End Source File
# End Group # End Group

View File

@ -36,6 +36,7 @@
#include "CLog.h" #include "CLog.h"
#include "CStopwatch.h" #include "CStopwatch.h"
#include "TMethodJob.h" #include "TMethodJob.h"
#include "CArch.h"
// //
// CClient // CClient
@ -545,7 +546,7 @@ CClient::runServer()
break; break;
} }
catch (XSocketConnect& e) { catch (XSocketConnect& e) {
LOG((CLOG_DEBUG1 "failed to connect to server: %s", e.getErrstr())); LOG((CLOG_DEBUG1 "failed to connect to server: %s", e.what()));
// failed to connect. if not camping then rethrow. // failed to connect. if not camping then rethrow.
if (!m_camp) { if (!m_camp) {
@ -553,7 +554,7 @@ CClient::runServer()
} }
// we're camping. wait a bit before retrying // we're camping. wait a bit before retrying
CThread::sleep(15.0); ARCH->sleep(15.0);
} }
} }

View File

@ -14,10 +14,10 @@
#include "CMSWindowsSecondaryScreen.h" #include "CMSWindowsSecondaryScreen.h"
#include "CMSWindowsScreen.h" #include "CMSWindowsScreen.h"
#include "CPlatform.h"
#include "XScreen.h" #include "XScreen.h"
#include "CLock.h" #include "CLock.h"
#include "CLog.h" #include "CLog.h"
#include "CArchMiscWindows.h"
#include <cctype> #include <cctype>
// these are only defined when WINVER >= 0x0500 // these are only defined when WINVER >= 0x0500
@ -34,7 +34,7 @@
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen( CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen(
IScreenReceiver* receiver) : IScreenReceiver* receiver) :
m_is95Family(CPlatform::isWindows95Family()), m_is95Family(CArchMiscWindows::isWindows95Family()),
m_window(NULL), m_window(NULL),
m_mask(0) m_mask(0)
{ {

View File

@ -38,6 +38,8 @@ libclient_a_SOURCES = \
ISecondaryScreenFactory.h \ ISecondaryScreenFactory.h \
$(NULL) $(NULL)
INCLUDES = \ INCLUDES = \
-I$(VDEPTH)/lib/common \
-I$(VDEPTH)/lib/arch \
-I$(VDEPTH)/lib/base \ -I$(VDEPTH)/lib/base \
-I$(VDEPTH)/lib/mt \ -I$(VDEPTH)/lib/mt \
-I$(VDEPTH)/lib/io \ -I$(VDEPTH)/lib/io \

View File

@ -41,7 +41,7 @@ RSC=rc.exe
# PROP Intermediate_Dir "Release" # PROP Intermediate_Dir "Release"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c # ADD CPP /nologo /MT /W4 /GX /O2 /I "..\common" /I "..\arch" /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG"
@ -65,7 +65,7 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "Debug" # PROP Intermediate_Dir "Debug"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\common" /I "..\arch" /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG"

45
lib/common/Makefile.am Normal file
View 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