mirror of
https://github.com/debauchee/barrier.git
synced 2026-05-10 08:21:40 +08:00
moving 1.4 to trunk
This commit is contained in:
25
src/lib/CMakeLists.txt
Normal file
25
src/lib/CMakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
# synergy -- mouse and keyboard sharing utility
|
||||
# Copyright (C) 2009 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
add_subdirectory(arch)
|
||||
add_subdirectory(base)
|
||||
add_subdirectory(client)
|
||||
add_subdirectory(common)
|
||||
add_subdirectory(io)
|
||||
add_subdirectory(mt)
|
||||
add_subdirectory(net)
|
||||
add_subdirectory(platform)
|
||||
add_subdirectory(server)
|
||||
add_subdirectory(synergy)
|
||||
54
src/lib/arch/CArch.cpp
Normal file
54
src/lib/arch/CArch.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArch.h"
|
||||
|
||||
//
|
||||
// CArch
|
||||
//
|
||||
|
||||
CArch* CArch::s_instance = NULL;
|
||||
|
||||
CArch::CArch()
|
||||
{
|
||||
}
|
||||
|
||||
CArch::~CArch()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CArch::init()
|
||||
{
|
||||
// initialization that requires ARCH is done here.
|
||||
ARCH_NETWORK::init();
|
||||
#if SYSAPI_WIN32
|
||||
ARCH_TASKBAR::init();
|
||||
CArchMiscWindows::init();
|
||||
#endif
|
||||
}
|
||||
|
||||
CArch*
|
||||
CArch::getInstance()
|
||||
{
|
||||
if (s_instance == NULL) {
|
||||
s_instance = new CArch();
|
||||
s_instance->init();
|
||||
}
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
143
src/lib/arch/CArch.h
Normal file
143
src/lib/arch/CArch.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// TODO: consider whether or not to use either encapsulation (as below)
|
||||
// or inheritance (as it is now) for the ARCH stuff.
|
||||
//
|
||||
// case for encapsulation:
|
||||
// pros:
|
||||
// - compiler errors for missing pv implementations are not absolutely bonkers.
|
||||
// - function names don't have to be so verbose.
|
||||
// - easier to understand and debug.
|
||||
// - ctors in IArch implementations can call other implementations.
|
||||
// cons:
|
||||
// - slightly more code for calls to ARCH.
|
||||
// - you'll have to modify each ARCH call.
|
||||
//
|
||||
// also, we may want to consider making each encapsulated
|
||||
// class lazy-loaded so that apps like the daemon don't load
|
||||
// stuff when they don't need it.
|
||||
|
||||
#ifndef CARCH_H
|
||||
#define CARCH_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
# include "CArchConsoleWindows.h"
|
||||
# include "CArchDaemonWindows.h"
|
||||
# include "CArchFileWindows.h"
|
||||
# include "CArchLogWindows.h"
|
||||
# include "CArchIpcLogWindows.h"
|
||||
# include "CArchMiscWindows.h"
|
||||
# include "CArchMultithreadWindows.h"
|
||||
# include "CArchNetworkWinsock.h"
|
||||
# include "CArchSleepWindows.h"
|
||||
# include "CArchStringWindows.h"
|
||||
# include "CArchSystemWindows.h"
|
||||
# include "CArchTaskBarWindows.h"
|
||||
# include "CArchTimeWindows.h"
|
||||
# include "CArchPluginWindows.h"
|
||||
#elif SYSAPI_UNIX
|
||||
# include "CArchConsoleUnix.h"
|
||||
# include "CArchDaemonUnix.h"
|
||||
# include "CArchFileUnix.h"
|
||||
# include "CArchLogUnix.h"
|
||||
# include "CArchIpcLogUnix.h"
|
||||
# if HAVE_PTHREAD
|
||||
# include "CArchMultithreadPosix.h"
|
||||
# endif
|
||||
# include "CArchNetworkBSD.h"
|
||||
# include "CArchSleepUnix.h"
|
||||
# include "CArchStringUnix.h"
|
||||
# include "CArchSystemUnix.h"
|
||||
# include "CArchTaskBarXWindows.h"
|
||||
# include "CArchTimeUnix.h"
|
||||
# include "CArchPluginUnix.h"
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\def ARCH
|
||||
This macro evaluates to the singleton CArch object.
|
||||
*/
|
||||
#define ARCH (CArch::getInstance())
|
||||
|
||||
//! Delegating implementation of architecture dependent interfaces
|
||||
/*!
|
||||
This class is a centralized interface to all architecture dependent
|
||||
interface implementations (except miscellaneous functions). It
|
||||
instantiates an implementation of each interface and delegates calls
|
||||
to each method to those implementations. Clients should use the
|
||||
\c ARCH macro to access this object. Clients must also instantiate
|
||||
exactly one of these objects before attempting to call any method,
|
||||
typically at the beginning of \c main().
|
||||
*/
|
||||
class CArch : public ARCH_CONSOLE,
|
||||
public ARCH_DAEMON,
|
||||
public ARCH_FILE,
|
||||
public ARCH_LOG,
|
||||
public ARCH_MULTITHREAD,
|
||||
public ARCH_NETWORK,
|
||||
public ARCH_SLEEP,
|
||||
public ARCH_STRING,
|
||||
public ARCH_SYSTEM,
|
||||
public ARCH_TASKBAR,
|
||||
public ARCH_TIME {
|
||||
public:
|
||||
~CArch();
|
||||
|
||||
//
|
||||
// accessors
|
||||
//
|
||||
|
||||
//! Return the singleton instance
|
||||
/*!
|
||||
The client must have instantiated exactly once CArch object before
|
||||
calling this function.
|
||||
*/
|
||||
static CArch* getInstance();
|
||||
|
||||
ARCH_IPC_LOG& ipcLog() const { return (ARCH_IPC_LOG&)m_ipcLog; }
|
||||
ARCH_PLUGIN& plugin() const { return (ARCH_PLUGIN&)m_plugin; }
|
||||
|
||||
private:
|
||||
CArch();
|
||||
void init();
|
||||
|
||||
private:
|
||||
static CArch* s_instance;
|
||||
ARCH_IPC_LOG m_ipcLog;
|
||||
ARCH_PLUGIN m_plugin;
|
||||
};
|
||||
|
||||
//! Convenience object to lock/unlock an arch mutex
|
||||
class CArchMutexLock {
|
||||
public:
|
||||
CArchMutexLock(CArchMutex mutex) : m_mutex(mutex)
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
}
|
||||
~CArchMutexLock()
|
||||
{
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
private:
|
||||
CArchMutex m_mutex;
|
||||
};
|
||||
|
||||
#endif
|
||||
31
src/lib/arch/CArchConsoleStd.cpp
Normal file
31
src/lib/arch/CArchConsoleStd.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchConsoleStd.h"
|
||||
#include "CLog.h"
|
||||
#include <iostream>
|
||||
|
||||
void
|
||||
CArchConsoleStd::writeConsole(ELevel level, const char* str)
|
||||
{
|
||||
if ((level >= kFATAL) && (level <= kWARNING))
|
||||
std::cerr << str << std::endl;
|
||||
else
|
||||
std::cout << str << std::endl;
|
||||
|
||||
std::cout.flush();
|
||||
}
|
||||
33
src/lib/arch/CArchConsoleStd.h
Normal file
33
src/lib/arch/CArchConsoleStd.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IArchConsole.h"
|
||||
|
||||
//! Cross platform implementation of IArchConsole
|
||||
class CArchConsoleStd : public IArchConsole {
|
||||
public:
|
||||
CArchConsoleStd() { }
|
||||
virtual ~CArchConsoleStd() { }
|
||||
|
||||
// IArchConsole overrides
|
||||
virtual void openConsole(const char* title) { }
|
||||
virtual void closeConsole() { }
|
||||
virtual void showConsole(bool) { }
|
||||
virtual void writeConsole(ELevel level, const char*);
|
||||
};
|
||||
22
src/lib/arch/CArchConsoleUnix.cpp
Normal file
22
src/lib/arch/CArchConsoleUnix.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchConsoleUnix.h"
|
||||
|
||||
CArchConsoleUnix::CArchConsoleUnix() { }
|
||||
|
||||
CArchConsoleUnix::~CArchConsoleUnix() { }
|
||||
28
src/lib/arch/CArchConsoleUnix.h
Normal file
28
src/lib/arch/CArchConsoleUnix.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CArchConsoleStd.h"
|
||||
|
||||
#define ARCH_CONSOLE CArchConsoleUnix
|
||||
|
||||
class CArchConsoleUnix : public CArchConsoleStd {
|
||||
public:
|
||||
CArchConsoleUnix();
|
||||
virtual ~CArchConsoleUnix();
|
||||
};
|
||||
22
src/lib/arch/CArchConsoleWindows.cpp
Normal file
22
src/lib/arch/CArchConsoleWindows.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchConsoleWindows.h"
|
||||
|
||||
CArchConsoleWindows::CArchConsoleWindows() { }
|
||||
|
||||
CArchConsoleWindows::~CArchConsoleWindows() { }
|
||||
28
src/lib/arch/CArchConsoleWindows.h
Normal file
28
src/lib/arch/CArchConsoleWindows.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CArchConsoleStd.h"
|
||||
|
||||
#define ARCH_CONSOLE CArchConsoleWindows
|
||||
|
||||
class CArchConsoleWindows : public CArchConsoleStd {
|
||||
public:
|
||||
CArchConsoleWindows();
|
||||
virtual ~CArchConsoleWindows();
|
||||
};
|
||||
85
src/lib/arch/CArchDaemonNone.cpp
Normal file
85
src/lib/arch/CArchDaemonNone.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchDaemonNone.h"
|
||||
|
||||
//
|
||||
// CArchDaemonNone
|
||||
//
|
||||
|
||||
CArchDaemonNone::CArchDaemonNone()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CArchDaemonNone::~CArchDaemonNone()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonNone::installDaemon(const char*,
|
||||
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*, bool)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonNone::installDaemon()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonNone::uninstallDaemon()
|
||||
{
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchDaemonNone::commandLine() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
53
src/lib/arch/CArchDaemonNone.h
Normal file
53
src/lib/arch/CArchDaemonNone.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHDAEMONNONE_H
|
||||
#define CARCHDAEMONNONE_H
|
||||
|
||||
#include "IArchDaemon.h"
|
||||
|
||||
#define ARCH_DAEMON CArchDaemonNone
|
||||
|
||||
//! Dummy implementation of IArchDaemon
|
||||
/*!
|
||||
This class implements IArchDaemon for a platform that does not have
|
||||
daemons. The install and uninstall functions do nothing, the query
|
||||
functions return false, and \c daemonize() simply calls the passed
|
||||
function and returns its result.
|
||||
*/
|
||||
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,
|
||||
const char* dependencies,
|
||||
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);
|
||||
virtual void installDaemon();
|
||||
virtual void uninstallDaemon();
|
||||
virtual std::string commandLine() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
127
src/lib/arch/CArchDaemonUnix.cpp
Normal file
127
src/lib/arch/CArchDaemonUnix.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchDaemonUnix.h"
|
||||
#include "XArchUnix.h"
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <cstdlib>
|
||||
#include "CLog.h"
|
||||
|
||||
//
|
||||
// CArchDaemonUnix
|
||||
//
|
||||
|
||||
CArchDaemonUnix::CArchDaemonUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CArchDaemonUnix::~CArchDaemonUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
// In Mac OS X, fork()'d child processes can't use most APIs (the frameworks
|
||||
// that Synergy uses in fact prevent it and make the process just up and die),
|
||||
// so need to exec a copy of the program that doesn't fork so isn't limited.
|
||||
int
|
||||
execSelfNonDaemonized()
|
||||
{
|
||||
extern char** NXArgv;
|
||||
char** selfArgv = NXArgv;
|
||||
|
||||
setenv("_SYNERGY_DAEMONIZED", "", 1);
|
||||
|
||||
execvp(selfArgv[0], selfArgv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool alreadyDaemonized() {
|
||||
return getenv("_SYNERGY_DAEMONIZED") != NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
CArchDaemonUnix::daemonize(const char* name, DaemonFunc func)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
if (alreadyDaemonized())
|
||||
return func(1, &name);
|
||||
#endif
|
||||
|
||||
// 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();
|
||||
|
||||
#ifndef __APPLE__
|
||||
// NB: don't run chdir on apple; causes strange behaviour.
|
||||
// chdir to root so we don't keep mounted filesystems points busy
|
||||
// TODO: this is a bit of a hack - can we find a better solution?
|
||||
int chdirErr = chdir("/");
|
||||
if (chdirErr)
|
||||
// NB: file logging actually isn't working at this point!
|
||||
LOG((CLOG_ERR "chdir error: %i", chdirErr));
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
|
||||
int dupErr = dup(1);
|
||||
if (dupErr)
|
||||
// NB: file logging actually isn't working at this point!
|
||||
LOG((CLOG_ERR "dup error: %i", dupErr));
|
||||
|
||||
#ifdef __APPLE__
|
||||
return execSelfNonDaemonized();
|
||||
#endif
|
||||
|
||||
// invoke function
|
||||
return func(1, &name);
|
||||
}
|
||||
38
src/lib/arch/CArchDaemonUnix.h
Normal file
38
src/lib/arch/CArchDaemonUnix.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHDAEMONUNIX_H
|
||||
#define CARCHDAEMONUNIX_H
|
||||
|
||||
#include "CArchDaemonNone.h"
|
||||
|
||||
#undef ARCH_DAEMON
|
||||
#define ARCH_DAEMON CArchDaemonUnix
|
||||
|
||||
//! Unix implementation of IArchDaemon
|
||||
class CArchDaemonUnix : public CArchDaemonNone {
|
||||
public:
|
||||
CArchDaemonUnix();
|
||||
virtual ~CArchDaemonUnix();
|
||||
|
||||
// IArchDaemon overrides
|
||||
virtual int daemonize(const char* name, DaemonFunc func);
|
||||
};
|
||||
|
||||
#define CONFIG_FILE "/etc/synergy/synergyd.conf"
|
||||
|
||||
#endif
|
||||
841
src/lib/arch/CArchDaemonWindows.cpp
Normal file
841
src/lib/arch/CArchDaemonWindows.cpp
Normal file
@@ -0,0 +1,841 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchDaemonWindows.h"
|
||||
#include "CArch.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include "XArchWindows.h"
|
||||
#include "stdvector.h"
|
||||
|
||||
//
|
||||
// CArchDaemonWindows
|
||||
//
|
||||
|
||||
CArchDaemonWindows* CArchDaemonWindows::s_daemon = NULL;
|
||||
|
||||
CArchDaemonWindows::CArchDaemonWindows() :
|
||||
m_daemonThreadID(0)
|
||||
{
|
||||
m_quitMessage = RegisterWindowMessage("SynergyDaemonExit");
|
||||
}
|
||||
|
||||
CArchDaemonWindows::~CArchDaemonWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
int
|
||||
CArchDaemonWindows::runDaemon(RunFunc runFunc)
|
||||
{
|
||||
assert(s_daemon != NULL);
|
||||
|
||||
return s_daemon->doRunDaemon(runFunc);
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::daemonRunning(bool running)
|
||||
{
|
||||
// if s_daemon is NULL we assume we're running on the windows
|
||||
// 95 family and we just ignore this call so the caller doesn't
|
||||
// have to go through the trouble of not calling it on the
|
||||
// windows 95 family.
|
||||
if (s_daemon != NULL) {
|
||||
s_daemon->doDaemonRunning(running);
|
||||
}
|
||||
}
|
||||
|
||||
UINT
|
||||
CArchDaemonWindows::getDaemonQuitMessage()
|
||||
{
|
||||
if (s_daemon != NULL) {
|
||||
return s_daemon->doGetDaemonQuitMessage();
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::daemonFailed(int result)
|
||||
{
|
||||
// if s_daemon is NULL we assume we're running on the windows
|
||||
// 95 family and we just ignore this call so the caller doesn't
|
||||
// have to go through the trouble of not calling it on the
|
||||
// windows 95 family.
|
||||
if (s_daemon != NULL) {
|
||||
throw XArchDaemonRunFailed(result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::installDaemon(const char* name,
|
||||
const char* description,
|
||||
const char* pathname,
|
||||
const char* commandLine,
|
||||
const char* dependencies,
|
||||
bool allUsers)
|
||||
{
|
||||
// if not for all users then use the user's autostart registry.
|
||||
// key. if windows 95 family then use windows 95 services key.
|
||||
if (!allUsers || CArchMiscWindows::isWindows95Family()) {
|
||||
// open registry
|
||||
HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ?
|
||||
open95ServicesKey() : openUserStartupKey();
|
||||
if (key == NULL) {
|
||||
// can't open key
|
||||
throw XArchDaemonInstallFailed(new XArchEvalWindows);
|
||||
}
|
||||
|
||||
// construct entry
|
||||
std::string value;
|
||||
value += "\"";
|
||||
value += pathname;
|
||||
value += "\" ";
|
||||
value += commandLine;
|
||||
|
||||
// install entry
|
||||
CArchMiscWindows::setValue(key, name, value);
|
||||
|
||||
// clean up
|
||||
CArchMiscWindows::closeKey(key);
|
||||
}
|
||||
|
||||
// windows NT family services
|
||||
else {
|
||||
// open service manager
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
|
||||
if (mgr == NULL) {
|
||||
// can't open service manager
|
||||
throw XArchDaemonInstallFailed(new XArchEvalWindows);
|
||||
}
|
||||
|
||||
// create the service
|
||||
SC_HANDLE service = CreateService(mgr,
|
||||
name,
|
||||
name,
|
||||
0,
|
||||
SERVICE_WIN32_OWN_PROCESS |
|
||||
SERVICE_INTERACTIVE_PROCESS,
|
||||
SERVICE_AUTO_START,
|
||||
SERVICE_ERROR_NORMAL,
|
||||
pathname,
|
||||
NULL,
|
||||
NULL,
|
||||
dependencies,
|
||||
NULL,
|
||||
NULL);
|
||||
if (service == NULL) {
|
||||
// can't create service
|
||||
DWORD err = GetLastError();
|
||||
if (err != ERROR_SERVICE_EXISTS) {
|
||||
CloseServiceHandle(mgr);
|
||||
throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// done with service (but only try to close if not null)
|
||||
CloseServiceHandle(service);
|
||||
}
|
||||
|
||||
// done with manager
|
||||
CloseServiceHandle(mgr);
|
||||
|
||||
// open the registry key for this service
|
||||
HKEY key = openNTServicesKey();
|
||||
key = CArchMiscWindows::addKey(key, name);
|
||||
if (key == NULL) {
|
||||
// can't open key
|
||||
DWORD err = GetLastError();
|
||||
try {
|
||||
uninstallDaemon(name, allUsers);
|
||||
}
|
||||
catch (...) {
|
||||
// ignore
|
||||
}
|
||||
throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
|
||||
}
|
||||
|
||||
// set the description
|
||||
CArchMiscWindows::setValue(key, _T("Description"), description);
|
||||
|
||||
// set command line
|
||||
key = CArchMiscWindows::addKey(key, _T("Parameters"));
|
||||
if (key == NULL) {
|
||||
// can't open key
|
||||
DWORD err = GetLastError();
|
||||
CArchMiscWindows::closeKey(key);
|
||||
try {
|
||||
uninstallDaemon(name, allUsers);
|
||||
}
|
||||
catch (...) {
|
||||
// ignore
|
||||
}
|
||||
throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
|
||||
}
|
||||
CArchMiscWindows::setValue(key, _T("CommandLine"), commandLine);
|
||||
|
||||
// done with registry
|
||||
CArchMiscWindows::closeKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::uninstallDaemon(const char* name, bool allUsers)
|
||||
{
|
||||
// if not for all users then use the user's autostart registry.
|
||||
// key. if windows 95 family then use windows 95 services key.
|
||||
if (!allUsers || CArchMiscWindows::isWindows95Family()) {
|
||||
// open registry
|
||||
HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ?
|
||||
open95ServicesKey() : openUserStartupKey();
|
||||
if (key == NULL) {
|
||||
// can't open key. daemon is probably not installed.
|
||||
throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows);
|
||||
}
|
||||
|
||||
// remove entry
|
||||
CArchMiscWindows::deleteValue(key, name);
|
||||
|
||||
// clean up
|
||||
CArchMiscWindows::closeKey(key);
|
||||
}
|
||||
|
||||
// windows NT family services
|
||||
else {
|
||||
// remove parameters for this service. ignore failures.
|
||||
HKEY key = openNTServicesKey();
|
||||
key = CArchMiscWindows::openKey(key, name);
|
||||
if (key != NULL) {
|
||||
CArchMiscWindows::deleteKey(key, _T("Parameters"));
|
||||
CArchMiscWindows::closeKey(key);
|
||||
}
|
||||
|
||||
// open service manager
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
|
||||
if (mgr == NULL) {
|
||||
// can't open service manager
|
||||
throw XArchDaemonUninstallFailed(new XArchEvalWindows);
|
||||
}
|
||||
|
||||
// open the service. oddly, you must open a service to delete it.
|
||||
SC_HANDLE service = OpenService(mgr, name, DELETE | SERVICE_STOP);
|
||||
if (service == NULL) {
|
||||
DWORD err = GetLastError();
|
||||
CloseServiceHandle(mgr);
|
||||
if (err != ERROR_SERVICE_DOES_NOT_EXIST) {
|
||||
throw XArchDaemonUninstallFailed(new XArchEvalWindows(err));
|
||||
}
|
||||
throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err));
|
||||
}
|
||||
|
||||
// stop the service. we don't care if we fail.
|
||||
SERVICE_STATUS status;
|
||||
ControlService(service, SERVICE_CONTROL_STOP, &status);
|
||||
|
||||
// delete the service
|
||||
const bool okay = (DeleteService(service) == 0);
|
||||
const DWORD err = GetLastError();
|
||||
|
||||
// clean up
|
||||
CloseServiceHandle(service);
|
||||
CloseServiceHandle(mgr);
|
||||
|
||||
// give windows a chance to remove the service before
|
||||
// we check if it still exists.
|
||||
ARCH->sleep(1);
|
||||
|
||||
// handle failure. ignore error if service isn't installed anymore.
|
||||
if (!okay && isDaemonInstalled(name, allUsers)) {
|
||||
if (err == ERROR_SUCCESS) {
|
||||
// this seems to occur even though the uninstall was successful.
|
||||
// it could be a timing issue, i.e., isDaemonInstalled is
|
||||
// called too soon. i've added a sleep to try and stop this.
|
||||
return;
|
||||
}
|
||||
if (err == ERROR_IO_PENDING) {
|
||||
// this seems to be a spurious error
|
||||
return;
|
||||
}
|
||||
if (err != ERROR_SERVICE_MARKED_FOR_DELETE) {
|
||||
throw XArchDaemonUninstallFailed(new XArchEvalWindows(err));
|
||||
}
|
||||
throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
CArchDaemonWindows::daemonize(const char* name, DaemonFunc func)
|
||||
{
|
||||
assert(name != NULL);
|
||||
assert(func != NULL);
|
||||
|
||||
// windows 95 family services
|
||||
if (CArchMiscWindows::isWindows95Family()) {
|
||||
typedef DWORD (WINAPI *RegisterServiceProcessT)(DWORD, DWORD);
|
||||
|
||||
// mark this process as a service so it's not killed when the
|
||||
// user logs off.
|
||||
HINSTANCE kernel = LoadLibrary("kernel32.dll");
|
||||
if (kernel == NULL) {
|
||||
throw XArchDaemonFailed(new XArchEvalWindows);
|
||||
}
|
||||
RegisterServiceProcessT RegisterServiceProcess =
|
||||
reinterpret_cast<RegisterServiceProcessT>(
|
||||
GetProcAddress(kernel,
|
||||
"RegisterServiceProcess"));
|
||||
if (RegisterServiceProcess == NULL) {
|
||||
// missing RegisterServiceProcess function
|
||||
DWORD err = GetLastError();
|
||||
FreeLibrary(kernel);
|
||||
throw XArchDaemonFailed(new XArchEvalWindows(err));
|
||||
}
|
||||
if (RegisterServiceProcess(0, 1) == 0) {
|
||||
// RegisterServiceProcess failed
|
||||
DWORD err = GetLastError();
|
||||
FreeLibrary(kernel);
|
||||
throw XArchDaemonFailed(new XArchEvalWindows(err));
|
||||
}
|
||||
FreeLibrary(kernel);
|
||||
|
||||
// now simply call the daemon function
|
||||
return func(1, &name);
|
||||
}
|
||||
|
||||
// windows NT family services
|
||||
else {
|
||||
// save daemon function
|
||||
m_daemonFunc = func;
|
||||
|
||||
// construct the service entry
|
||||
SERVICE_TABLE_ENTRY entry[2];
|
||||
entry[0].lpServiceName = const_cast<char*>(name);
|
||||
entry[0].lpServiceProc = &CArchDaemonWindows::serviceMainEntry;
|
||||
entry[1].lpServiceName = NULL;
|
||||
entry[1].lpServiceProc = NULL;
|
||||
|
||||
// hook us up to the service control manager. this won't return
|
||||
// (if successful) until the processes have terminated.
|
||||
s_daemon = this;
|
||||
if (StartServiceCtrlDispatcher(entry) == 0) {
|
||||
// StartServiceCtrlDispatcher failed
|
||||
s_daemon = NULL;
|
||||
throw XArchDaemonFailed(new XArchEvalWindows);
|
||||
}
|
||||
|
||||
s_daemon = NULL;
|
||||
return m_daemonResult;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CArchDaemonWindows::canInstallDaemon(const char* /*name*/, bool allUsers)
|
||||
{
|
||||
// if not for all users then use the user's autostart registry.
|
||||
// key. if windows 95 family then use windows 95 services key.
|
||||
if (!allUsers || CArchMiscWindows::isWindows95Family()) {
|
||||
// check if we can open the registry key
|
||||
HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ?
|
||||
open95ServicesKey() : openUserStartupKey();
|
||||
CArchMiscWindows::closeKey(key);
|
||||
return (key != NULL);
|
||||
}
|
||||
|
||||
// windows NT family services
|
||||
else {
|
||||
// check if we can open service manager for write
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
|
||||
if (mgr == NULL) {
|
||||
return false;
|
||||
}
|
||||
CloseServiceHandle(mgr);
|
||||
|
||||
// check if we can open the registry key
|
||||
HKEY key = openNTServicesKey();
|
||||
// key = CArchMiscWindows::addKey(key, name);
|
||||
// key = CArchMiscWindows::addKey(key, _T("Parameters"));
|
||||
CArchMiscWindows::closeKey(key);
|
||||
|
||||
return (key != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CArchDaemonWindows::isDaemonInstalled(const char* name, bool allUsers)
|
||||
{
|
||||
// open service manager
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
|
||||
if (mgr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// open the service
|
||||
SC_HANDLE service = OpenService(mgr, name, GENERIC_READ);
|
||||
|
||||
// clean up
|
||||
if (service != NULL) {
|
||||
CloseServiceHandle(service);
|
||||
}
|
||||
CloseServiceHandle(mgr);
|
||||
|
||||
return (service != NULL);
|
||||
}
|
||||
|
||||
HKEY
|
||||
CArchDaemonWindows::openNTServicesKey()
|
||||
{
|
||||
static const char* s_keyNames[] = {
|
||||
_T("SYSTEM"),
|
||||
_T("CurrentControlSet"),
|
||||
_T("Services"),
|
||||
NULL
|
||||
};
|
||||
|
||||
return CArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames);
|
||||
}
|
||||
|
||||
HKEY
|
||||
CArchDaemonWindows::open95ServicesKey()
|
||||
{
|
||||
static const char* s_keyNames[] = {
|
||||
_T("Software"),
|
||||
_T("Microsoft"),
|
||||
_T("Windows"),
|
||||
_T("CurrentVersion"),
|
||||
_T("RunServices"),
|
||||
NULL
|
||||
};
|
||||
|
||||
return CArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames);
|
||||
}
|
||||
|
||||
HKEY
|
||||
CArchDaemonWindows::openUserStartupKey()
|
||||
{
|
||||
static const char* s_keyNames[] = {
|
||||
_T("Software"),
|
||||
_T("Microsoft"),
|
||||
_T("Windows"),
|
||||
_T("CurrentVersion"),
|
||||
_T("Run"),
|
||||
NULL
|
||||
};
|
||||
|
||||
return CArchMiscWindows::addKey(HKEY_CURRENT_USER, s_keyNames);
|
||||
}
|
||||
|
||||
bool
|
||||
CArchDaemonWindows::isRunState(DWORD state)
|
||||
{
|
||||
switch (state) {
|
||||
case SERVICE_START_PENDING:
|
||||
case SERVICE_CONTINUE_PENDING:
|
||||
case SERVICE_RUNNING:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
CArchDaemonWindows::doRunDaemon(RunFunc run)
|
||||
{
|
||||
// should only be called from DaemonFunc
|
||||
assert(m_serviceMutex != NULL);
|
||||
assert(run != NULL);
|
||||
|
||||
// create message queue for this thread
|
||||
MSG dummy;
|
||||
PeekMessage(&dummy, NULL, 0, 0, PM_NOREMOVE);
|
||||
|
||||
int result = 0;
|
||||
ARCH->lockMutex(m_serviceMutex);
|
||||
m_daemonThreadID = GetCurrentThreadId();
|
||||
while (m_serviceState != SERVICE_STOPPED) {
|
||||
// wait until we're told to start
|
||||
while (!isRunState(m_serviceState) &&
|
||||
m_serviceState != SERVICE_STOP_PENDING) {
|
||||
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
||||
}
|
||||
|
||||
// run unless told to stop
|
||||
if (m_serviceState != SERVICE_STOP_PENDING) {
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
try {
|
||||
result = run();
|
||||
}
|
||||
catch (...) {
|
||||
ARCH->lockMutex(m_serviceMutex);
|
||||
setStatusError(0);
|
||||
m_serviceState = SERVICE_STOPPED;
|
||||
setStatus(m_serviceState);
|
||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
throw;
|
||||
}
|
||||
ARCH->lockMutex(m_serviceMutex);
|
||||
}
|
||||
|
||||
// notify of new state
|
||||
if (m_serviceState == SERVICE_PAUSE_PENDING) {
|
||||
m_serviceState = SERVICE_PAUSED;
|
||||
}
|
||||
else {
|
||||
m_serviceState = SERVICE_STOPPED;
|
||||
}
|
||||
setStatus(m_serviceState);
|
||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||
}
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::doDaemonRunning(bool running)
|
||||
{
|
||||
ARCH->lockMutex(m_serviceMutex);
|
||||
if (running) {
|
||||
m_serviceState = SERVICE_RUNNING;
|
||||
setStatus(m_serviceState);
|
||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||
}
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
}
|
||||
|
||||
UINT
|
||||
CArchDaemonWindows::doGetDaemonQuitMessage()
|
||||
{
|
||||
return m_quitMessage;
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::setStatus(DWORD state)
|
||||
{
|
||||
setStatus(state, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint)
|
||||
{
|
||||
assert(s_daemon != NULL);
|
||||
|
||||
SERVICE_STATUS status;
|
||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS |
|
||||
SERVICE_INTERACTIVE_PROCESS;
|
||||
status.dwCurrentState = state;
|
||||
status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
|
||||
SERVICE_ACCEPT_PAUSE_CONTINUE |
|
||||
SERVICE_ACCEPT_SHUTDOWN;
|
||||
status.dwWin32ExitCode = NO_ERROR;
|
||||
status.dwServiceSpecificExitCode = 0;
|
||||
status.dwCheckPoint = step;
|
||||
status.dwWaitHint = waitHint;
|
||||
SetServiceStatus(s_daemon->m_statusHandle, &status);
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::setStatusError(DWORD error)
|
||||
{
|
||||
assert(s_daemon != NULL);
|
||||
|
||||
SERVICE_STATUS status;
|
||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS |
|
||||
SERVICE_INTERACTIVE_PROCESS;
|
||||
status.dwCurrentState = SERVICE_STOPPED;
|
||||
status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
|
||||
SERVICE_ACCEPT_PAUSE_CONTINUE |
|
||||
SERVICE_ACCEPT_SHUTDOWN;
|
||||
status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
|
||||
status.dwServiceSpecificExitCode = error;
|
||||
status.dwCheckPoint = 0;
|
||||
status.dwWaitHint = 0;
|
||||
SetServiceStatus(s_daemon->m_statusHandle, &status);
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
|
||||
{
|
||||
typedef std::vector<LPCTSTR> ArgList;
|
||||
typedef std::vector<std::string> Arguments;
|
||||
const char** argv = const_cast<const char**>(argvIn);
|
||||
|
||||
// create synchronization objects
|
||||
m_serviceMutex = ARCH->newMutex();
|
||||
m_serviceCondVar = ARCH->newCondVar();
|
||||
|
||||
// register our service handler function
|
||||
m_statusHandle = RegisterServiceCtrlHandler(argv[0],
|
||||
&CArchDaemonWindows::serviceHandlerEntry);
|
||||
if (m_statusHandle == 0) {
|
||||
// cannot start as service
|
||||
m_daemonResult = -1;
|
||||
ARCH->closeCondVar(m_serviceCondVar);
|
||||
ARCH->closeMutex(m_serviceMutex);
|
||||
return;
|
||||
}
|
||||
|
||||
// tell service control manager that we're starting
|
||||
m_serviceState = SERVICE_START_PENDING;
|
||||
setStatus(m_serviceState, 0, 10000);
|
||||
|
||||
std::string commandLine;
|
||||
|
||||
// if no arguments supplied then try getting them from the registry.
|
||||
// the first argument doesn't count because it's the service name.
|
||||
Arguments args;
|
||||
ArgList myArgv;
|
||||
if (argc <= 1) {
|
||||
// read command line
|
||||
HKEY key = openNTServicesKey();
|
||||
key = CArchMiscWindows::openKey(key, argvIn[0]);
|
||||
key = CArchMiscWindows::openKey(key, _T("Parameters"));
|
||||
if (key != NULL) {
|
||||
commandLine = CArchMiscWindows::readValueString(key,
|
||||
_T("CommandLine"));
|
||||
}
|
||||
|
||||
// if the command line isn't empty then parse and use it
|
||||
if (!commandLine.empty()) {
|
||||
// parse, honoring double quoted substrings
|
||||
std::string::size_type i = commandLine.find_first_not_of(" \t");
|
||||
while (i != std::string::npos && i != commandLine.size()) {
|
||||
// find end of string
|
||||
std::string::size_type e;
|
||||
if (commandLine[i] == '\"') {
|
||||
// quoted. find closing quote.
|
||||
++i;
|
||||
e = commandLine.find("\"", i);
|
||||
|
||||
// whitespace must follow closing quote
|
||||
if (e == std::string::npos ||
|
||||
(e + 1 != commandLine.size() &&
|
||||
commandLine[e + 1] != ' ' &&
|
||||
commandLine[e + 1] != '\t')) {
|
||||
args.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
// extract
|
||||
args.push_back(commandLine.substr(i, e - i));
|
||||
i = e + 1;
|
||||
}
|
||||
else {
|
||||
// unquoted. find next whitespace.
|
||||
e = commandLine.find_first_of(" \t", i);
|
||||
if (e == std::string::npos) {
|
||||
e = commandLine.size();
|
||||
}
|
||||
|
||||
// extract
|
||||
args.push_back(commandLine.substr(i, e - i));
|
||||
i = e + 1;
|
||||
}
|
||||
|
||||
// next argument
|
||||
i = commandLine.find_first_not_of(" \t", i);
|
||||
}
|
||||
|
||||
// service name goes first
|
||||
myArgv.push_back(argv[0]);
|
||||
|
||||
// get pointers
|
||||
for (size_t j = 0; j < args.size(); ++j) {
|
||||
myArgv.push_back(args[j].c_str());
|
||||
}
|
||||
|
||||
// adjust argc/argv
|
||||
argc = (DWORD)myArgv.size();
|
||||
argv = &myArgv[0];
|
||||
}
|
||||
}
|
||||
|
||||
m_commandLine = commandLine;
|
||||
|
||||
try {
|
||||
// invoke daemon function
|
||||
m_daemonResult = m_daemonFunc(static_cast<int>(argc), argv);
|
||||
}
|
||||
catch (XArchDaemonRunFailed& e) {
|
||||
setStatusError(e.m_result);
|
||||
m_daemonResult = -1;
|
||||
}
|
||||
catch (...) {
|
||||
setStatusError(1);
|
||||
m_daemonResult = -1;
|
||||
}
|
||||
|
||||
// clean up
|
||||
ARCH->closeCondVar(m_serviceCondVar);
|
||||
ARCH->closeMutex(m_serviceMutex);
|
||||
|
||||
// we're going to exit now, so set status to stopped
|
||||
m_serviceState = SERVICE_STOPPED;
|
||||
setStatus(m_serviceState, 0, 10000);
|
||||
}
|
||||
|
||||
void WINAPI
|
||||
CArchDaemonWindows::serviceMainEntry(DWORD argc, LPTSTR* argv)
|
||||
{
|
||||
s_daemon->serviceMain(argc, argv);
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::serviceHandler(DWORD ctrl)
|
||||
{
|
||||
assert(m_serviceMutex != NULL);
|
||||
assert(m_serviceCondVar != NULL);
|
||||
|
||||
ARCH->lockMutex(m_serviceMutex);
|
||||
|
||||
// ignore request if service is already stopped
|
||||
if (s_daemon == NULL || m_serviceState == SERVICE_STOPPED) {
|
||||
if (s_daemon != NULL) {
|
||||
setStatus(m_serviceState);
|
||||
}
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ctrl) {
|
||||
case SERVICE_CONTROL_PAUSE:
|
||||
m_serviceState = SERVICE_PAUSE_PENDING;
|
||||
setStatus(m_serviceState, 0, 5000);
|
||||
PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0);
|
||||
while (isRunState(m_serviceState)) {
|
||||
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
||||
}
|
||||
break;
|
||||
|
||||
case SERVICE_CONTROL_CONTINUE:
|
||||
// FIXME -- maybe should flush quit messages from queue
|
||||
m_serviceState = SERVICE_CONTINUE_PENDING;
|
||||
setStatus(m_serviceState, 0, 5000);
|
||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||
break;
|
||||
|
||||
case SERVICE_CONTROL_STOP:
|
||||
case SERVICE_CONTROL_SHUTDOWN:
|
||||
m_serviceState = SERVICE_STOP_PENDING;
|
||||
setStatus(m_serviceState, 0, 5000);
|
||||
PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0);
|
||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||
while (isRunState(m_serviceState)) {
|
||||
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown service command
|
||||
// fall through
|
||||
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
setStatus(m_serviceState);
|
||||
break;
|
||||
}
|
||||
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
}
|
||||
|
||||
void WINAPI
|
||||
CArchDaemonWindows::serviceHandlerEntry(DWORD ctrl)
|
||||
{
|
||||
s_daemon->serviceHandler(ctrl);
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::start(const char* name)
|
||||
{
|
||||
// open service manager
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
|
||||
if (mgr == NULL) {
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
}
|
||||
|
||||
// open the service
|
||||
SC_HANDLE service = OpenService(
|
||||
mgr, name, SERVICE_START);
|
||||
|
||||
if (service == NULL) {
|
||||
CloseServiceHandle(mgr);
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
}
|
||||
|
||||
// start the service
|
||||
if (!StartService(service, 0, NULL)) {
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::stop(const char* name)
|
||||
{
|
||||
// open service manager
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
|
||||
if (mgr == NULL) {
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
}
|
||||
|
||||
// open the service
|
||||
SC_HANDLE service = OpenService(
|
||||
mgr, name,
|
||||
SERVICE_STOP | SERVICE_QUERY_STATUS);
|
||||
|
||||
if (service == NULL) {
|
||||
CloseServiceHandle(mgr);
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
}
|
||||
|
||||
// ask the service to stop, asynchronously
|
||||
SERVICE_STATUS ss;
|
||||
if (!ControlService(service, SERVICE_CONTROL_STOP, &ss)) {
|
||||
DWORD dwErrCode = GetLastError();
|
||||
if (dwErrCode != ERROR_SERVICE_NOT_ACTIVE) {
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::installDaemon()
|
||||
{
|
||||
// install default daemon if not already installed.
|
||||
if (!isDaemonInstalled(DEFAULT_DAEMON_NAME, true)) {
|
||||
char path[MAX_PATH];
|
||||
GetModuleFileName(CArchMiscWindows::instanceWin32(), path, MAX_PATH);
|
||||
installDaemon(DEFAULT_DAEMON_NAME, DEFAULT_DAEMON_INFO, path, "", "", true);
|
||||
}
|
||||
|
||||
start(DEFAULT_DAEMON_NAME);
|
||||
}
|
||||
|
||||
void
|
||||
CArchDaemonWindows::uninstallDaemon()
|
||||
{
|
||||
// remove legacy services if installed.
|
||||
if (isDaemonInstalled(LEGACY_SERVER_DAEMON_NAME, true)) {
|
||||
uninstallDaemon(LEGACY_SERVER_DAEMON_NAME, true);
|
||||
}
|
||||
if (isDaemonInstalled(LEGACY_CLIENT_DAEMON_NAME, true)) {
|
||||
uninstallDaemon(LEGACY_CLIENT_DAEMON_NAME, true);
|
||||
}
|
||||
|
||||
// remove new service if installed.
|
||||
if (isDaemonInstalled(DEFAULT_DAEMON_NAME, true)) {
|
||||
uninstallDaemon(DEFAULT_DAEMON_NAME, true);
|
||||
}
|
||||
}
|
||||
159
src/lib/arch/CArchDaemonWindows.h
Normal file
159
src/lib/arch/CArchDaemonWindows.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
//! Win32 implementation of IArchDaemon
|
||||
class CArchDaemonWindows : public IArchDaemon {
|
||||
public:
|
||||
typedef int (*RunFunc)(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 runFunc is called in a new thread and when the
|
||||
daemon must exit the main loop due to some external control the
|
||||
getDaemonQuitMessage() is posted to the thread. This function returns
|
||||
what \c runFunc returns. \c runFunc should call \c daemonFailed() if
|
||||
the daemon fails.
|
||||
*/
|
||||
static int runDaemon(RunFunc runFunc);
|
||||
|
||||
//! 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);
|
||||
|
||||
//! Get daemon quit message
|
||||
/*!
|
||||
The windows NT daemon tells daemon thread to exit by posting this
|
||||
message to it. The thread must, of course, have a message queue
|
||||
for this to work.
|
||||
*/
|
||||
static UINT getDaemonQuitMessage();
|
||||
|
||||
// IArchDaemon overrides
|
||||
virtual void installDaemon(const char* name,
|
||||
const char* description,
|
||||
const char* pathname,
|
||||
const char* commandLine,
|
||||
const char* dependencies,
|
||||
bool allUsers);
|
||||
virtual void uninstallDaemon(const char* name, bool allUsers);
|
||||
virtual void installDaemon();
|
||||
virtual void uninstallDaemon();
|
||||
virtual int daemonize(const char* name, DaemonFunc func);
|
||||
virtual bool canInstallDaemon(const char* name, bool allUsers);
|
||||
virtual bool isDaemonInstalled(const char* name, bool allUsers);
|
||||
std::string commandLine() const { return m_commandLine; }
|
||||
|
||||
private:
|
||||
static HKEY openNTServicesKey();
|
||||
static HKEY open95ServicesKey();
|
||||
static HKEY openUserStartupKey();
|
||||
|
||||
int doRunDaemon(RunFunc runFunc);
|
||||
void doDaemonRunning(bool running);
|
||||
UINT doGetDaemonQuitMessage();
|
||||
|
||||
static void setStatus(DWORD state);
|
||||
static void setStatus(DWORD state, DWORD step, DWORD waitHint);
|
||||
static void setStatusError(DWORD error);
|
||||
|
||||
static bool isRunState(DWORD state);
|
||||
|
||||
void serviceMain(DWORD, LPTSTR*);
|
||||
static void WINAPI serviceMainEntry(DWORD, LPTSTR*);
|
||||
|
||||
void serviceHandler(DWORD ctrl);
|
||||
static void WINAPI serviceHandlerEntry(DWORD ctrl);
|
||||
|
||||
void start(const char* name);
|
||||
void stop(const char* name);
|
||||
|
||||
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;
|
||||
|
||||
DWORD m_daemonThreadID;
|
||||
DaemonFunc m_daemonFunc;
|
||||
int m_daemonResult;
|
||||
|
||||
SERVICE_STATUS_HANDLE m_statusHandle;
|
||||
|
||||
UINT m_quitMessage;
|
||||
|
||||
std::string m_commandLine;
|
||||
};
|
||||
|
||||
#define DEFAULT_DAEMON_NAME _T("Synergy")
|
||||
#define DEFAULT_DAEMON_INFO _T("Manages the Synergy foreground processes.")
|
||||
|
||||
#define LEGACY_SERVER_DAEMON_NAME _T("Synergy Server")
|
||||
#define LEGACY_CLIENT_DAEMON_NAME _T("Synergy Client")
|
||||
|
||||
static const TCHAR* const g_daemonKeyPath[] = {
|
||||
_T("SOFTWARE"),
|
||||
_T("The Synergy Project"),
|
||||
_T("Synergy"),
|
||||
_T("Service"),
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif
|
||||
101
src/lib/arch/CArchFileUnix.cpp
Normal file
101
src/lib/arch/CArchFileUnix.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchFileUnix.h"
|
||||
#include <stdio.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()
|
||||
{
|
||||
char* buffer = NULL;
|
||||
std::string dir;
|
||||
#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);
|
||||
if (size == -1) {
|
||||
size = BUFSIZ;
|
||||
}
|
||||
#else
|
||||
long size = BUFSIZ;
|
||||
#endif
|
||||
buffer = new char[size];
|
||||
getpwuid_r(getuid(), &pwent, buffer, size, &pwentp);
|
||||
#else
|
||||
struct passwd* pwentp = getpwuid(getuid());
|
||||
#endif
|
||||
if (pwentp != NULL && pwentp->pw_dir != NULL) {
|
||||
dir = pwentp->pw_dir;
|
||||
}
|
||||
delete[] buffer;
|
||||
return dir;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
39
src/lib/arch/CArchFileUnix.h
Normal file
39
src/lib/arch/CArchFileUnix.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHFILEUNIX_H
|
||||
#define CARCHFILEUNIX_H
|
||||
|
||||
#include "IArchFile.h"
|
||||
|
||||
#define ARCH_FILE CArchFileUnix
|
||||
|
||||
//! Unix implementation of IArchFile
|
||||
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
|
||||
135
src/lib/arch/CArchFileWindows.cpp
Normal file
135
src/lib/arch/CArchFileWindows.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchFileWindows.h"
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <tchar.h>
|
||||
#include <string.h>
|
||||
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
39
src/lib/arch/CArchFileWindows.h
Normal file
39
src/lib/arch/CArchFileWindows.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHFILEWINDOWS_H
|
||||
#define CARCHFILEWINDOWS_H
|
||||
|
||||
#include "IArchFile.h"
|
||||
|
||||
#define ARCH_FILE CArchFileWindows
|
||||
|
||||
//! Win32 implementation of IArchFile
|
||||
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
|
||||
46
src/lib/arch/CArchIpcLogUnix.cpp
Normal file
46
src/lib/arch/CArchIpcLogUnix.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchIpcLogUnix.h"
|
||||
|
||||
CArchIpcLogUnix::CArchIpcLogUnix()
|
||||
{
|
||||
}
|
||||
|
||||
CArchIpcLogUnix::~CArchIpcLogUnix()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CArchIpcLogUnix::openLog(const char* name)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CArchIpcLogUnix::closeLog()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CArchIpcLogUnix::showLog(bool showIfEmpty)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CArchIpcLogUnix::writeLog(ELevel, const char*)
|
||||
{
|
||||
}
|
||||
34
src/lib/arch/CArchIpcLogUnix.h
Normal file
34
src/lib/arch/CArchIpcLogUnix.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IArchLog.h"
|
||||
|
||||
#define ARCH_IPC_LOG CArchIpcLogUnix
|
||||
|
||||
class CArchIpcLogUnix : public IArchLog {
|
||||
public:
|
||||
CArchIpcLogUnix();
|
||||
virtual ~CArchIpcLogUnix();
|
||||
|
||||
// IArchLog overrides
|
||||
virtual void openLog(const char* name);
|
||||
virtual void closeLog();
|
||||
virtual void showLog(bool showIfEmpty);
|
||||
virtual void writeLog(ELevel, const char*);
|
||||
};
|
||||
111
src/lib/arch/CArchIpcLogWindows.cpp
Normal file
111
src/lib/arch/CArchIpcLogWindows.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchIpcLogWindows.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include "XArch.h"
|
||||
#include "CThread.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CArch.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
//
|
||||
// CArchIpcLogWindows
|
||||
//
|
||||
|
||||
CArchIpcLogWindows::CArchIpcLogWindows() :
|
||||
m_pipe(NULL),
|
||||
m_listenThread(NULL),
|
||||
m_connected(false)
|
||||
{
|
||||
}
|
||||
|
||||
CArchIpcLogWindows::~CArchIpcLogWindows()
|
||||
{
|
||||
if (m_listenThread != NULL)
|
||||
delete m_listenThread;
|
||||
}
|
||||
|
||||
void
|
||||
CArchIpcLogWindows::openLog(const char* name)
|
||||
{
|
||||
// grant access to everyone.
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
|
||||
SetSecurityDescriptorDacl(&sd, TRUE, static_cast<PACL>(0), FALSE);
|
||||
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
|
||||
HANDLE pipe = CreateNamedPipe(
|
||||
TEXT("\\\\.\\pipe\\SynergyLog"),
|
||||
PIPE_ACCESS_DUPLEX,
|
||||
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
1024, 1024, 0, &sa);
|
||||
|
||||
if (pipe == INVALID_HANDLE_VALUE)
|
||||
XArch("could not create named pipe.");
|
||||
|
||||
m_pipe = pipe;
|
||||
|
||||
m_listenThread = new CThread(new TMethodJob<CArchIpcLogWindows>(
|
||||
this, &CArchIpcLogWindows::connectThread, nullptr));
|
||||
}
|
||||
|
||||
void
|
||||
CArchIpcLogWindows::connectThread(void*)
|
||||
{
|
||||
// HACK: this seems like a hacky pile of bollocks. it will continuously call
|
||||
// ConnectNamedPipe every second. if there is no client, it will block,
|
||||
// but if there is a client it will return FALSE and GetLastError() will
|
||||
// be ERROR_PIPE_CONNECTED. in any other case, the client has gone away
|
||||
// and ConnectNamedPipe will go back to blocking (waiting for the client
|
||||
// to reconnect).
|
||||
while (true) {
|
||||
BOOL result = ConnectNamedPipe(m_pipe, NULL);
|
||||
if ((result == TRUE) || (GetLastError() == ERROR_PIPE_CONNECTED)) {
|
||||
m_connected = true;
|
||||
ARCH->sleep(1);
|
||||
} else {
|
||||
DisconnectNamedPipe(m_pipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchIpcLogWindows::closeLog()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CArchIpcLogWindows::showLog(bool)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CArchIpcLogWindows::writeLog(ELevel level, const char* data)
|
||||
{
|
||||
if (!m_connected)
|
||||
return;
|
||||
|
||||
DWORD bytesWritten;
|
||||
WriteFile(m_pipe, data, (DWORD)strlen(data), &bytesWritten, NULL);
|
||||
}
|
||||
48
src/lib/arch/CArchIpcLogWindows.h
Normal file
48
src/lib/arch/CArchIpcLogWindows.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include "IArchLog.h"
|
||||
#include <windows.h>
|
||||
|
||||
#define ARCH_IPC_LOG CArchIpcLogWindows
|
||||
|
||||
class CThread;
|
||||
|
||||
//! Win32 implementation of IArchLog (IPC version)
|
||||
class CArchIpcLogWindows : public IArchLog {
|
||||
public:
|
||||
CArchIpcLogWindows();
|
||||
virtual ~CArchIpcLogWindows();
|
||||
|
||||
// IArchLog overrides
|
||||
virtual void openLog(const char* name);
|
||||
virtual void closeLog();
|
||||
virtual void showLog(bool showIfEmpty);
|
||||
virtual void writeLog(ELevel, const char*);
|
||||
|
||||
private:
|
||||
void connectThread(void*);
|
||||
|
||||
private:
|
||||
HANDLE m_pipe;
|
||||
CThread* m_listenThread;
|
||||
bool m_connected;
|
||||
};
|
||||
82
src/lib/arch/CArchLogUnix.cpp
Normal file
82
src/lib/arch/CArchLogUnix.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "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::showLog(bool)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
38
src/lib/arch/CArchLogUnix.h
Normal file
38
src/lib/arch/CArchLogUnix.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHLOGUNIX_H
|
||||
#define CARCHLOGUNIX_H
|
||||
|
||||
#include "IArchLog.h"
|
||||
|
||||
#define ARCH_LOG CArchLogUnix
|
||||
|
||||
//! Unix implementation of IArchLog
|
||||
class CArchLogUnix : public IArchLog {
|
||||
public:
|
||||
CArchLogUnix();
|
||||
virtual ~CArchLogUnix();
|
||||
|
||||
// IArchLog overrides
|
||||
virtual void openLog(const char* name);
|
||||
virtual void closeLog();
|
||||
virtual void showLog(bool);
|
||||
virtual void writeLog(ELevel, const char*);
|
||||
};
|
||||
|
||||
#endif
|
||||
93
src/lib/arch/CArchLogWindows.cpp
Normal file
93
src/lib/arch/CArchLogWindows.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchLogWindows.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include <string.h>
|
||||
|
||||
//
|
||||
// CArchLogWindows
|
||||
//
|
||||
|
||||
CArchLogWindows::CArchLogWindows() : m_eventLog(NULL)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CArchLogWindows::~CArchLogWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CArchLogWindows::openLog(const char* name)
|
||||
{
|
||||
if (m_eventLog == NULL && !CArchMiscWindows::isWindows95Family()) {
|
||||
m_eventLog = RegisterEventSource(NULL, name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchLogWindows::closeLog()
|
||||
{
|
||||
if (m_eventLog != NULL) {
|
||||
DeregisterEventSource(m_eventLog);
|
||||
m_eventLog = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchLogWindows::showLog(bool)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
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,
|
||||
(DWORD)strlen(msg) + 1, // raw data size
|
||||
NULL,
|
||||
const_cast<char*>(msg));// raw data
|
||||
}
|
||||
}
|
||||
44
src/lib/arch/CArchLogWindows.h
Normal file
44
src/lib/arch/CArchLogWindows.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHLOGWINDOWS_H
|
||||
#define CARCHLOGWINDOWS_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include "IArchLog.h"
|
||||
#include <windows.h>
|
||||
|
||||
#define ARCH_LOG CArchLogWindows
|
||||
|
||||
//! Win32 implementation of IArchLog
|
||||
class CArchLogWindows : public IArchLog {
|
||||
public:
|
||||
CArchLogWindows();
|
||||
virtual ~CArchLogWindows();
|
||||
|
||||
// IArchLog overrides
|
||||
virtual void openLog(const char* name);
|
||||
virtual void closeLog();
|
||||
virtual void showLog(bool showIfEmpty);
|
||||
virtual void writeLog(ELevel, const char*);
|
||||
|
||||
private:
|
||||
HANDLE m_eventLog;
|
||||
};
|
||||
|
||||
#endif
|
||||
554
src/lib/arch/CArchMiscWindows.cpp
Normal file
554
src/lib/arch/CArchMiscWindows.cpp
Normal file
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchMiscWindows.h"
|
||||
#include "CArchDaemonWindows.h"
|
||||
#include "CLog.h"
|
||||
|
||||
#include <Wtsapi32.h>
|
||||
#pragma warning(disable: 4099)
|
||||
#include <Userenv.h>
|
||||
#pragma warning(default: 4099)
|
||||
#include "Version.h"
|
||||
|
||||
// parent process name for services in Vista
|
||||
#define SERVICE_LAUNCHER "services.exe"
|
||||
|
||||
#ifndef ES_SYSTEM_REQUIRED
|
||||
#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001)
|
||||
#endif
|
||||
#ifndef ES_DISPLAY_REQUIRED
|
||||
#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002)
|
||||
#endif
|
||||
#ifndef ES_CONTINUOUS
|
||||
#define ES_CONTINUOUS ((DWORD)0x80000000)
|
||||
#endif
|
||||
typedef DWORD EXECUTION_STATE;
|
||||
|
||||
//
|
||||
// CArchMiscWindows
|
||||
//
|
||||
|
||||
CArchMiscWindows::CDialogs* CArchMiscWindows::s_dialogs = NULL;
|
||||
DWORD CArchMiscWindows::s_busyState = 0;
|
||||
CArchMiscWindows::STES_t CArchMiscWindows::s_stes = NULL;
|
||||
HICON CArchMiscWindows::s_largeIcon = NULL;
|
||||
HICON CArchMiscWindows::s_smallIcon = NULL;
|
||||
HINSTANCE CArchMiscWindows::s_instanceWin32 = NULL;
|
||||
|
||||
void
|
||||
CArchMiscWindows::init()
|
||||
{
|
||||
s_dialogs = new CDialogs;
|
||||
isWindows95Family();
|
||||
}
|
||||
|
||||
bool
|
||||
CArchMiscWindows::isWindows95Family()
|
||||
{
|
||||
static bool init = false;
|
||||
static bool result = false;
|
||||
|
||||
if (!init) {
|
||||
OSVERSIONINFO version;
|
||||
version.dwOSVersionInfoSize = sizeof(version);
|
||||
if (GetVersionEx(&version) == 0) {
|
||||
// cannot determine OS; assume windows 95 family
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
result = (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
CArchMiscWindows::isWindowsModern()
|
||||
{
|
||||
static bool init = false;
|
||||
static bool result = false;
|
||||
|
||||
if (!init) {
|
||||
OSVERSIONINFO version;
|
||||
version.dwOSVersionInfoSize = sizeof(version);
|
||||
if (GetVersionEx(&version) == 0) {
|
||||
// cannot determine OS; assume not modern
|
||||
result = false;
|
||||
}
|
||||
else {
|
||||
result = ((version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
|
||||
version.dwMajorVersion == 4 &&
|
||||
version.dwMinorVersion > 0) ||
|
||||
(version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
||||
version.dwMajorVersion > 4));
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::setIcons(HICON largeIcon, HICON smallIcon)
|
||||
{
|
||||
s_largeIcon = largeIcon;
|
||||
s_smallIcon = smallIcon;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::getIcons(HICON& largeIcon, HICON& smallIcon)
|
||||
{
|
||||
largeIcon = s_largeIcon;
|
||||
smallIcon = s_smallIcon;
|
||||
}
|
||||
|
||||
int
|
||||
CArchMiscWindows::runDaemon(RunFunc runFunc)
|
||||
{
|
||||
return CArchDaemonWindows::runDaemon(runFunc);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::daemonRunning(bool running)
|
||||
{
|
||||
CArchDaemonWindows::daemonRunning(running);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::daemonFailed(int result)
|
||||
{
|
||||
CArchDaemonWindows::daemonFailed(result);
|
||||
}
|
||||
|
||||
UINT
|
||||
CArchMiscWindows::getDaemonQuitMessage()
|
||||
{
|
||||
return CArchDaemonWindows::getDaemonQuitMessage();
|
||||
}
|
||||
|
||||
HKEY
|
||||
CArchMiscWindows::openKey(HKEY key, const TCHAR* keyName)
|
||||
{
|
||||
return openKey(key, keyName, false);
|
||||
}
|
||||
|
||||
HKEY
|
||||
CArchMiscWindows::openKey(HKEY key, const TCHAR* const* keyNames)
|
||||
{
|
||||
return openKey(key, keyNames, false);
|
||||
}
|
||||
|
||||
HKEY
|
||||
CArchMiscWindows::addKey(HKEY key, const TCHAR* keyName)
|
||||
{
|
||||
return openKey(key, keyName, true);
|
||||
}
|
||||
|
||||
HKEY
|
||||
CArchMiscWindows::addKey(HKEY key, const TCHAR* const* keyNames)
|
||||
{
|
||||
return openKey(key, keyNames, true);
|
||||
}
|
||||
|
||||
HKEY
|
||||
CArchMiscWindows::openKey(HKEY key, const TCHAR* keyName, bool create)
|
||||
{
|
||||
// ignore if parent is NULL
|
||||
if (key == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// open next key
|
||||
HKEY newKey;
|
||||
LONG result = RegOpenKeyEx(key, keyName, 0,
|
||||
KEY_WRITE | KEY_QUERY_VALUE, &newKey);
|
||||
if (result != ERROR_SUCCESS && create) {
|
||||
DWORD disp;
|
||||
result = RegCreateKeyEx(key, keyName, 0, TEXT(""),
|
||||
0, KEY_WRITE | KEY_QUERY_VALUE,
|
||||
NULL, &newKey, &disp);
|
||||
}
|
||||
if (result != ERROR_SUCCESS) {
|
||||
RegCloseKey(key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// switch to new key
|
||||
RegCloseKey(key);
|
||||
return newKey;
|
||||
}
|
||||
|
||||
HKEY
|
||||
CArchMiscWindows::openKey(HKEY key, const TCHAR* const* keyNames, bool create)
|
||||
{
|
||||
for (size_t i = 0; key != NULL && keyNames[i] != NULL; ++i) {
|
||||
// open next key
|
||||
key = openKey(key, keyNames[i], create);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::closeKey(HKEY key)
|
||||
{
|
||||
assert(key != NULL);
|
||||
if (key==NULL) return;
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::deleteKey(HKEY key, const TCHAR* name)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if (key==NULL || name==NULL) return;
|
||||
RegDeleteKey(key, name);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::deleteValue(HKEY key, const TCHAR* name)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if (key==NULL || name==NULL) return;
|
||||
RegDeleteValue(key, name);
|
||||
}
|
||||
|
||||
bool
|
||||
CArchMiscWindows::hasValue(HKEY key, const TCHAR* name)
|
||||
{
|
||||
DWORD type;
|
||||
LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL);
|
||||
return (result == ERROR_SUCCESS &&
|
||||
(type == REG_DWORD || type == REG_SZ));
|
||||
}
|
||||
|
||||
CArchMiscWindows::EValueType
|
||||
CArchMiscWindows::typeOfValue(HKEY key, const TCHAR* name)
|
||||
{
|
||||
DWORD type;
|
||||
LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
return kNO_VALUE;
|
||||
}
|
||||
switch (type) {
|
||||
case REG_DWORD:
|
||||
return kUINT;
|
||||
|
||||
case REG_SZ:
|
||||
return kSTRING;
|
||||
|
||||
case REG_BINARY:
|
||||
return kBINARY;
|
||||
|
||||
default:
|
||||
return kUNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::setValue(HKEY key,
|
||||
const TCHAR* name, const std::string& value)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if(key ==NULL || name==NULL) return; // TODO: throw exception
|
||||
RegSetValueEx(key, name, 0, REG_SZ,
|
||||
reinterpret_cast<const BYTE*>(value.c_str()),
|
||||
(DWORD)value.size() + 1);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::setValue(HKEY key, const TCHAR* name, DWORD value)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if(key ==NULL || name==NULL) return; // TODO: throw exception
|
||||
RegSetValueEx(key, name, 0, REG_DWORD,
|
||||
reinterpret_cast<CONST BYTE*>(&value),
|
||||
sizeof(DWORD));
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::setValueBinary(HKEY key,
|
||||
const TCHAR* name, const std::string& value)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if(key ==NULL || name==NULL) return; // TODO: throw exception
|
||||
RegSetValueEx(key, name, 0, REG_BINARY,
|
||||
reinterpret_cast<const BYTE*>(value.data()),
|
||||
(DWORD)value.size());
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR* name, DWORD type)
|
||||
{
|
||||
// get the size of the string
|
||||
DWORD actualType;
|
||||
DWORD size = 0;
|
||||
LONG result = RegQueryValueEx(key, name, 0, &actualType, NULL, &size);
|
||||
if (result != ERROR_SUCCESS || actualType != type) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// if zero size then return empty string
|
||||
if (size == 0) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// allocate space
|
||||
char* buffer = new char[size];
|
||||
|
||||
// read it
|
||||
result = RegQueryValueEx(key, name, 0, &actualType,
|
||||
reinterpret_cast<BYTE*>(buffer), &size);
|
||||
if (result != ERROR_SUCCESS || actualType != type) {
|
||||
delete[] buffer;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// clean up and return value
|
||||
if (type == REG_SZ && buffer[size - 1] == '\0') {
|
||||
// don't include terminating nul; std::string will add one.
|
||||
--size;
|
||||
}
|
||||
std::string value(buffer, size);
|
||||
delete[] buffer;
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchMiscWindows::readValueString(HKEY key, const TCHAR* name)
|
||||
{
|
||||
return readBinaryOrString(key, name, REG_SZ);
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchMiscWindows::readValueBinary(HKEY key, const TCHAR* name)
|
||||
{
|
||||
return readBinaryOrString(key, name, REG_BINARY);
|
||||
}
|
||||
|
||||
DWORD
|
||||
CArchMiscWindows::readValueInt(HKEY key, const TCHAR* name)
|
||||
{
|
||||
DWORD type;
|
||||
DWORD value;
|
||||
DWORD size = sizeof(value);
|
||||
LONG result = RegQueryValueEx(key, name, 0, &type,
|
||||
reinterpret_cast<BYTE*>(&value), &size);
|
||||
if (result != ERROR_SUCCESS || type != REG_DWORD) {
|
||||
return 0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::addDialog(HWND hwnd)
|
||||
{
|
||||
s_dialogs->insert(hwnd);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::removeDialog(HWND hwnd)
|
||||
{
|
||||
s_dialogs->erase(hwnd);
|
||||
}
|
||||
|
||||
bool
|
||||
CArchMiscWindows::processDialog(MSG* msg)
|
||||
{
|
||||
for (CDialogs::const_iterator index = s_dialogs->begin();
|
||||
index != s_dialogs->end(); ++index) {
|
||||
if (IsDialogMessage(*index, msg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::addBusyState(DWORD busyModes)
|
||||
{
|
||||
s_busyState |= busyModes;
|
||||
setThreadExecutionState(s_busyState);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::removeBusyState(DWORD busyModes)
|
||||
{
|
||||
s_busyState &= ~busyModes;
|
||||
setThreadExecutionState(s_busyState);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::setThreadExecutionState(DWORD busyModes)
|
||||
{
|
||||
// look up function dynamically so we work on older systems
|
||||
if (s_stes == NULL) {
|
||||
HINSTANCE kernel = LoadLibrary("kernel32.dll");
|
||||
if (kernel != NULL) {
|
||||
s_stes = reinterpret_cast<STES_t>(GetProcAddress(kernel,
|
||||
"SetThreadExecutionState"));
|
||||
}
|
||||
if (s_stes == NULL) {
|
||||
s_stes = &CArchMiscWindows::dummySetThreadExecutionState;
|
||||
}
|
||||
}
|
||||
|
||||
// convert to STES form
|
||||
EXECUTION_STATE state = 0;
|
||||
if ((busyModes & kSYSTEM) != 0) {
|
||||
state |= ES_SYSTEM_REQUIRED;
|
||||
}
|
||||
if ((busyModes & kDISPLAY) != 0) {
|
||||
state |= ES_DISPLAY_REQUIRED;
|
||||
}
|
||||
if (state != 0) {
|
||||
state |= ES_CONTINUOUS;
|
||||
}
|
||||
|
||||
// do it
|
||||
s_stes(state);
|
||||
}
|
||||
|
||||
DWORD
|
||||
CArchMiscWindows::dummySetThreadExecutionState(DWORD)
|
||||
{
|
||||
// do nothing
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::wakeupDisplay()
|
||||
{
|
||||
// We can't use ::setThreadExecutionState here because it sets
|
||||
// ES_CONTINUOUS, which we don't want.
|
||||
|
||||
if (s_stes == NULL) {
|
||||
HINSTANCE kernel = LoadLibrary("kernel32.dll");
|
||||
if (kernel != NULL) {
|
||||
s_stes = reinterpret_cast<STES_t>(GetProcAddress(kernel,
|
||||
"SetThreadExecutionState"));
|
||||
}
|
||||
if (s_stes == NULL) {
|
||||
s_stes = &CArchMiscWindows::dummySetThreadExecutionState;
|
||||
}
|
||||
}
|
||||
|
||||
s_stes(ES_DISPLAY_REQUIRED);
|
||||
|
||||
// restore the original execution states
|
||||
setThreadExecutionState(s_busyState);
|
||||
}
|
||||
|
||||
bool
|
||||
CArchMiscWindows::wasLaunchedAsService()
|
||||
{
|
||||
CString name;
|
||||
if (!getParentProcessName(name)) {
|
||||
LOG((CLOG_ERR "cannot determine if process was launched as service"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return (name == SERVICE_LAUNCHER);
|
||||
}
|
||||
|
||||
bool
|
||||
CArchMiscWindows::getParentProcessName(CString &name)
|
||||
{
|
||||
PROCESSENTRY32 parentEntry;
|
||||
if (!getParentProcessEntry(parentEntry)){
|
||||
LOG((CLOG_ERR "could not get entry for parent process"));
|
||||
return false;
|
||||
}
|
||||
|
||||
name = parentEntry.szExeFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
CArchMiscWindows::getSelfProcessEntry(PROCESSENTRY32& entry)
|
||||
{
|
||||
// get entry from current PID
|
||||
return getProcessEntry(entry, GetCurrentProcessId());
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
CArchMiscWindows::getParentProcessEntry(PROCESSENTRY32& entry)
|
||||
{
|
||||
// get the current process, so we can get parent PID
|
||||
PROCESSENTRY32 selfEntry;
|
||||
if (!getSelfProcessEntry(selfEntry)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get entry from parent PID
|
||||
return getProcessEntry(entry, selfEntry.th32ParentProcessID);
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
CArchMiscWindows::getProcessEntry(PROCESSENTRY32& entry, DWORD processID)
|
||||
{
|
||||
// first we need to take a snapshot of the running processes
|
||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (snapshot == INVALID_HANDLE_VALUE) {
|
||||
LOG((CLOG_ERR "could not get process snapshot (error: %i)",
|
||||
GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
entry.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
// get the first process, and if we can't do that then it's
|
||||
// unlikely we can go any further
|
||||
BOOL gotEntry = Process32First(snapshot, &entry);
|
||||
if (!gotEntry) {
|
||||
LOG((CLOG_ERR "could not get first process entry (error: %i)",
|
||||
GetLastError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while(gotEntry) {
|
||||
|
||||
if (entry.th32ProcessID == processID) {
|
||||
// found current process
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// now move on to the next entry (when we reach end, loop will stop)
|
||||
gotEntry = Process32Next(snapshot, &entry);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HINSTANCE
|
||||
CArchMiscWindows::instanceWin32()
|
||||
{
|
||||
assert(s_instanceWin32 != NULL);
|
||||
return s_instanceWin32;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMiscWindows::setInstanceWin32(HINSTANCE instance)
|
||||
{
|
||||
assert(instance != NULL);
|
||||
s_instanceWin32 = instance;
|
||||
}
|
||||
214
src/lib/arch/CArchMiscWindows.h
Normal file
214
src/lib/arch/CArchMiscWindows.h
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHMISCWINDOWS_H
|
||||
#define CARCHMISCWINDOWS_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include "common.h"
|
||||
#include "stdstring.h"
|
||||
#include "stdset.h"
|
||||
#include <windows.h>
|
||||
#include <Tlhelp32.h>
|
||||
#include "CString.h"
|
||||
|
||||
//! Miscellaneous win32 functions.
|
||||
class CArchMiscWindows {
|
||||
public:
|
||||
enum EValueType {
|
||||
kUNKNOWN,
|
||||
kNO_VALUE,
|
||||
kUINT,
|
||||
kSTRING,
|
||||
kBINARY
|
||||
};
|
||||
enum EBusyModes {
|
||||
kIDLE = 0x0000,
|
||||
kSYSTEM = 0x0001,
|
||||
kDISPLAY = 0x0002
|
||||
};
|
||||
|
||||
typedef int (*RunFunc)(void);
|
||||
|
||||
//! Initialize
|
||||
static void init();
|
||||
|
||||
//! Test if windows 95, et al.
|
||||
/*!
|
||||
Returns true iff the platform is win95/98/me.
|
||||
*/
|
||||
static bool isWindows95Family();
|
||||
|
||||
//! Test if windows 95, et al.
|
||||
/*!
|
||||
Returns true iff the platform is win98 or win2k or higher (i.e.
|
||||
not windows 95 or windows NT).
|
||||
*/
|
||||
static bool isWindowsModern();
|
||||
|
||||
//! Set the application icons
|
||||
/*!
|
||||
Set the application icons.
|
||||
*/
|
||||
static void setIcons(HICON largeIcon, HICON smallIcon);
|
||||
|
||||
//! Get the application icons
|
||||
/*!
|
||||
Get the application icons.
|
||||
*/
|
||||
static void getIcons(HICON& largeIcon, HICON& smallIcon);
|
||||
|
||||
//! Run the daemon
|
||||
/*!
|
||||
Delegates to CArchDaemonWindows.
|
||||
*/
|
||||
static int runDaemon(RunFunc runFunc);
|
||||
|
||||
//! 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);
|
||||
|
||||
//! Get daemon quit message
|
||||
/*!
|
||||
Delegates to CArchDaemonWindows.
|
||||
*/
|
||||
static UINT getDaemonQuitMessage();
|
||||
|
||||
//! Open and return a registry key, closing the parent key
|
||||
static HKEY openKey(HKEY parent, const TCHAR* child);
|
||||
|
||||
//! Open and return a registry key, closing the parent key
|
||||
static HKEY openKey(HKEY parent, const TCHAR* const* keyPath);
|
||||
|
||||
//! Open/create and return a registry key, closing the parent key
|
||||
static HKEY addKey(HKEY parent, const TCHAR* child);
|
||||
|
||||
//! Open/create and return a registry key, closing the parent key
|
||||
static HKEY addKey(HKEY parent, const TCHAR* const* keyPath);
|
||||
|
||||
//! Close a key
|
||||
static void closeKey(HKEY);
|
||||
|
||||
//! Delete a key (which should have no subkeys)
|
||||
static void deleteKey(HKEY parent, const TCHAR* name);
|
||||
|
||||
//! Delete a value
|
||||
static void deleteValue(HKEY parent, const TCHAR* name);
|
||||
|
||||
//! Test if a value exists
|
||||
static bool hasValue(HKEY key, const TCHAR* name);
|
||||
|
||||
//! Get type of value
|
||||
static EValueType typeOfValue(HKEY key, const TCHAR* name);
|
||||
|
||||
//! Set a string value in the registry
|
||||
static void setValue(HKEY key, const TCHAR* name,
|
||||
const std::string& value);
|
||||
|
||||
//! Set a DWORD value in the registry
|
||||
static void setValue(HKEY key, const TCHAR* name, DWORD value);
|
||||
|
||||
//! Set a BINARY value in the registry
|
||||
/*!
|
||||
Sets the \p name value of \p key to \p value.data().
|
||||
*/
|
||||
static void setValueBinary(HKEY key, const TCHAR* name,
|
||||
const std::string& value);
|
||||
|
||||
//! Read a string value from the registry
|
||||
static std::string readValueString(HKEY, const TCHAR* name);
|
||||
|
||||
//! Read a DWORD value from the registry
|
||||
static DWORD readValueInt(HKEY, const TCHAR* name);
|
||||
|
||||
//! Read a BINARY value from the registry
|
||||
static std::string readValueBinary(HKEY, const TCHAR* name);
|
||||
|
||||
//! Add a dialog
|
||||
static void addDialog(HWND);
|
||||
|
||||
//! Remove a dialog
|
||||
static void removeDialog(HWND);
|
||||
|
||||
//! Process dialog message
|
||||
/*!
|
||||
Checks if the message is destined for a dialog. If so the message
|
||||
is passed to the dialog and returns true, otherwise returns false.
|
||||
*/
|
||||
static bool processDialog(MSG*);
|
||||
|
||||
//! Disable power saving
|
||||
static void addBusyState(DWORD busyModes);
|
||||
|
||||
//! Enable power saving
|
||||
static void removeBusyState(DWORD busyModes);
|
||||
|
||||
//! Briefly interrupt power saving
|
||||
static void wakeupDisplay();
|
||||
|
||||
//! Returns true if this process was launched via NT service host.
|
||||
static bool wasLaunchedAsService();
|
||||
|
||||
//! Returns true if we got the parent process name.
|
||||
static bool getParentProcessName(CString &name);
|
||||
|
||||
static HINSTANCE instanceWin32();
|
||||
|
||||
static void setInstanceWin32(HINSTANCE instance);
|
||||
|
||||
static BOOL WINAPI getProcessEntry(PROCESSENTRY32& entry, DWORD processID);
|
||||
static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32& entry);
|
||||
static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32& entry);
|
||||
|
||||
private:
|
||||
//! Open and return a registry key, closing the parent key
|
||||
static HKEY openKey(HKEY parent, const TCHAR* child, bool create);
|
||||
|
||||
//! Open and return a registry key, closing the parent key
|
||||
static HKEY openKey(HKEY parent, const TCHAR* const* keyPath,
|
||||
bool create);
|
||||
|
||||
//! Read a string value from the registry
|
||||
static std::string readBinaryOrString(HKEY, const TCHAR* name, DWORD type);
|
||||
|
||||
//! Set thread busy state
|
||||
static void setThreadExecutionState(DWORD);
|
||||
|
||||
static DWORD WINAPI dummySetThreadExecutionState(DWORD);
|
||||
|
||||
private:
|
||||
typedef std::set<HWND> CDialogs;
|
||||
typedef DWORD (WINAPI *STES_t)(DWORD);
|
||||
|
||||
static CDialogs* s_dialogs;
|
||||
static DWORD s_busyState;
|
||||
static STES_t s_stes;
|
||||
static HICON s_largeIcon;
|
||||
static HICON s_smallIcon;
|
||||
static HINSTANCE s_instanceWin32;
|
||||
};
|
||||
|
||||
#endif
|
||||
809
src/lib/arch/CArchMultithreadPosix.cpp
Normal file
809
src/lib/arch/CArchMultithreadPosix.cpp
Normal file
@@ -0,0 +1,809 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "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
|
||||
|
||||
#if !HAVE_PTHREAD_SIGNAL
|
||||
// boy, is this platform broken. forget about pthread signal
|
||||
// handling and let signals through to every process. synergy
|
||||
// will not terminate cleanly when it gets SIGTERM or SIGINT.
|
||||
# define pthread_sigmask sigprocmask
|
||||
# define pthread_kill(tid_, sig_) kill(0, (sig_))
|
||||
# define sigwait(set_, sig_)
|
||||
# undef HAVE_POSIX_SIGWAIT
|
||||
# define HAVE_POSIX_SIGWAIT 1
|
||||
#endif
|
||||
|
||||
static
|
||||
void
|
||||
setSignalSet(sigset_t* sigset)
|
||||
{
|
||||
sigemptyset(sigset);
|
||||
sigaddset(sigset, SIGHUP);
|
||||
sigaddset(sigset, SIGINT);
|
||||
sigaddset(sigset, SIGTERM);
|
||||
sigaddset(sigset, SIGUSR2);
|
||||
}
|
||||
|
||||
//
|
||||
// CArchThreadImpl
|
||||
//
|
||||
|
||||
class CArchThreadImpl {
|
||||
public:
|
||||
CArchThreadImpl();
|
||||
|
||||
public:
|
||||
int m_refCount;
|
||||
IArchMultithread::ThreadID m_id;
|
||||
pthread_t m_thread;
|
||||
IArchMultithread::ThreadFunc m_func;
|
||||
void* m_userData;
|
||||
bool m_cancel;
|
||||
bool m_cancelling;
|
||||
bool m_exited;
|
||||
void* m_result;
|
||||
void* m_networkData;
|
||||
};
|
||||
|
||||
CArchThreadImpl::CArchThreadImpl() :
|
||||
m_refCount(1),
|
||||
m_id(0),
|
||||
m_func(NULL),
|
||||
m_userData(NULL),
|
||||
m_cancel(false),
|
||||
m_cancelling(false),
|
||||
m_exited(false),
|
||||
m_result(NULL),
|
||||
m_networkData(NULL)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CArchMultithreadPosix
|
||||
//
|
||||
|
||||
CArchMultithreadPosix* CArchMultithreadPosix::s_instance = NULL;
|
||||
|
||||
CArchMultithreadPosix::CArchMultithreadPosix() :
|
||||
m_newThreadCalled(false),
|
||||
m_nextID(0)
|
||||
{
|
||||
assert(s_instance == NULL);
|
||||
|
||||
s_instance = this;
|
||||
|
||||
// no signal handlers
|
||||
for (size_t i = 0; i < kNUM_SIGNALS; ++i) {
|
||||
m_signalFunc[i] = NULL;
|
||||
m_signalUserData[i] = NULL;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadPosix::setNetworkDataForCurrentThread(void* data)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
CArchThreadImpl* thread = find(pthread_self());
|
||||
thread->m_networkData = data;
|
||||
unlockMutex(m_threadMutex);
|
||||
}
|
||||
|
||||
void*
|
||||
CArchMultithreadPosix::getNetworkDataForThread(CArchThread thread)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
void* data = thread->m_networkData;
|
||||
unlockMutex(m_threadMutex);
|
||||
return data;
|
||||
}
|
||||
|
||||
CArchMultithreadPosix*
|
||||
CArchMultithreadPosix::getInstance()
|
||||
{
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
CArchCond
|
||||
CArchMultithreadPosix::newCondVar()
|
||||
{
|
||||
CArchCondImpl* cond = new CArchCondImpl;
|
||||
int status = pthread_cond_init(&cond->m_cond, NULL);
|
||||
(void)status;
|
||||
assert(status == 0);
|
||||
return cond;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadPosix::closeCondVar(CArchCond cond)
|
||||
{
|
||||
int status = pthread_cond_destroy(&cond->m_cond);
|
||||
(void)status;
|
||||
assert(status == 0);
|
||||
delete cond;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadPosix::signalCondVar(CArchCond cond)
|
||||
{
|
||||
int status = pthread_cond_signal(&cond->m_cond);
|
||||
(void)status;
|
||||
assert(status == 0);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadPosix::broadcastCondVar(CArchCond cond)
|
||||
{
|
||||
int status = pthread_cond_broadcast(&cond->m_cond);
|
||||
(void)status;
|
||||
assert(status == 0);
|
||||
}
|
||||
|
||||
bool
|
||||
CArchMultithreadPosix::waitCondVar(CArchCond cond,
|
||||
CArchMutex mutex, double timeout)
|
||||
{
|
||||
// we can't wait on a condition variable and also wake it up for
|
||||
// cancellation since we don't use posix cancellation. so we
|
||||
// must wake up periodically to check for cancellation. we
|
||||
// can't simply go back to waiting after the check since the
|
||||
// condition may have changed and we'll have lost the signal.
|
||||
// so we have to return to the caller. since the caller will
|
||||
// always check for spurious wakeups the only drawback here is
|
||||
// performance: we're waking up a lot more than desired.
|
||||
static const double maxCancellationLatency = 0.1;
|
||||
if (timeout < 0.0 || timeout > maxCancellationLatency) {
|
||||
timeout = maxCancellationLatency;
|
||||
}
|
||||
|
||||
// see if we should cancel this thread
|
||||
testCancelThread();
|
||||
|
||||
// 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;
|
||||
long timeout_sec = (long)timeout;
|
||||
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;
|
||||
}
|
||||
|
||||
// wait
|
||||
int status = pthread_cond_timedwait(&cond->m_cond,
|
||||
&mutex->m_mutex, &finalTime);
|
||||
|
||||
// check for cancel again
|
||||
testCancelThread();
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
// success
|
||||
return true;
|
||||
|
||||
case ETIMEDOUT:
|
||||
return false;
|
||||
|
||||
default:
|
||||
assert(0 && "condition variable wait error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CArchMutex
|
||||
CArchMultithreadPosix::newMutex()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int status = pthread_mutexattr_init(&attr);
|
||||
assert(status == 0);
|
||||
CArchMutexImpl* mutex = new CArchMutexImpl;
|
||||
status = pthread_mutex_init(&mutex->m_mutex, &attr);
|
||||
assert(status == 0);
|
||||
return mutex;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadPosix::closeMutex(CArchMutex mutex)
|
||||
{
|
||||
int status = pthread_mutex_destroy(&mutex->m_mutex);
|
||||
(void)status;
|
||||
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;
|
||||
#if HAVE_PTHREAD_SIGNAL
|
||||
startSignalHandler();
|
||||
#endif
|
||||
}
|
||||
|
||||
lockMutex(m_threadMutex);
|
||||
|
||||
// create thread impl for new thread
|
||||
CArchThreadImpl* thread = new CArchThreadImpl;
|
||||
thread->m_func = func;
|
||||
thread->m_userData = data;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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::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 thread->m_id;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadPosix::setSignalHandler(
|
||||
ESignal signal, SignalFunc func, void* userData)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
m_signalFunc[signal] = func;
|
||||
m_signalUserData[signal] = userData;
|
||||
unlockMutex(m_threadMutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadPosix::raiseSignal(ESignal signal)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
if (m_signalFunc[signal] != NULL) {
|
||||
m_signalFunc[signal](signal, m_signalUserData[signal]);
|
||||
pthread_kill(m_mainThread->m_thread, SIGWAKEUP);
|
||||
}
|
||||
else if (signal == kINTERRUPT || signal == kTERMINATE) {
|
||||
ARCH->cancelThread(m_mainThread);
|
||||
}
|
||||
unlockMutex(m_threadMutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadPosix::startSignalHandler()
|
||||
{
|
||||
// set signal mask. the main thread blocks these signals and
|
||||
// the signal handler thread will listen for them.
|
||||
sigset_t sigset, oldsigset;
|
||||
setSignalSet(&sigset);
|
||||
pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset);
|
||||
|
||||
// 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,
|
||||
NULL);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
if (status != 0) {
|
||||
// can't create thread to wait for signal so don't block
|
||||
// the signals.
|
||||
pthread_sigmask(SIG_UNBLOCK, &oldsigset, 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);
|
||||
|
||||
// set thread id. note that we don't worry about m_nextID
|
||||
// wrapping back to 0 and duplicating thread ID's since the
|
||||
// likelihood of synergy running that long is vanishingly
|
||||
// small.
|
||||
thread->m_id = ++m_nextID;
|
||||
|
||||
// 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*)
|
||||
{
|
||||
// detach
|
||||
pthread_detach(pthread_self());
|
||||
|
||||
// add signal to mask
|
||||
sigset_t sigset;
|
||||
setSignalSet(&sigset);
|
||||
|
||||
// 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 = 0;
|
||||
sigwait(&sigset, &signal);
|
||||
#else
|
||||
sigwait(&sigset);
|
||||
#endif
|
||||
|
||||
// if we get here then the signal was raised
|
||||
switch (signal) {
|
||||
case SIGINT:
|
||||
ARCH->raiseSignal(kINTERRUPT);
|
||||
break;
|
||||
|
||||
case SIGTERM:
|
||||
ARCH->raiseSignal(kTERMINATE);
|
||||
break;
|
||||
|
||||
case SIGHUP:
|
||||
ARCH->raiseSignal(kHANGUP);
|
||||
break;
|
||||
|
||||
case SIGUSR2:
|
||||
ARCH->raiseSignal(kUSER);
|
||||
break;
|
||||
|
||||
default:
|
||||
// ignore
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
116
src/lib/arch/CArchMultithreadPosix.h
Normal file
116
src/lib/arch/CArchMultithreadPosix.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
//! Posix implementation of IArchMultithread
|
||||
class CArchMultithreadPosix : public IArchMultithread {
|
||||
public:
|
||||
CArchMultithreadPosix();
|
||||
virtual ~CArchMultithreadPosix();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
void setNetworkDataForCurrentThread(void*);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
void* getNetworkDataForThread(CArchThread);
|
||||
|
||||
static CArchMultithreadPosix* 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 isSameThread(CArchThread, CArchThread);
|
||||
virtual bool isExitedThread(CArchThread);
|
||||
virtual void* getResultOfThread(CArchThread);
|
||||
virtual ThreadID getIDOfThread(CArchThread);
|
||||
virtual void setSignalHandler(ESignal, SignalFunc, void*);
|
||||
virtual void raiseSignal(ESignal);
|
||||
|
||||
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;
|
||||
ThreadID m_nextID;
|
||||
|
||||
pthread_t m_signalThread;
|
||||
SignalFunc m_signalFunc[kNUM_SIGNALS];
|
||||
void* m_signalUserData[kNUM_SIGNALS];
|
||||
};
|
||||
|
||||
#endif
|
||||
702
src/lib/arch/CArchMultithreadWindows.cpp
Normal file
702
src/lib/arch/CArchMultithreadWindows.cpp
Normal file
@@ -0,0 +1,702 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && !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;
|
||||
void* m_networkData;
|
||||
};
|
||||
|
||||
CArchThreadImpl::CArchThreadImpl() :
|
||||
m_refCount(1),
|
||||
m_thread(NULL),
|
||||
m_id(0),
|
||||
m_func(NULL),
|
||||
m_userData(NULL),
|
||||
m_cancelling(false),
|
||||
m_result(NULL),
|
||||
m_networkData(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;
|
||||
|
||||
// no signal handlers
|
||||
for (size_t i = 0; i < kNUM_SIGNALS; ++i) {
|
||||
m_signalFunc[i] = NULL;
|
||||
m_signalUserData[i] = NULL;
|
||||
}
|
||||
|
||||
// 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 = NULL;
|
||||
m_mainThread->m_id = GetCurrentThreadId();
|
||||
insert(m_mainThread);
|
||||
}
|
||||
|
||||
CArchMultithreadWindows::~CArchMultithreadWindows()
|
||||
{
|
||||
s_instance = NULL;
|
||||
|
||||
// clean up thread list
|
||||
for (CThreadList::iterator index = m_threadList.begin();
|
||||
index != m_threadList.end(); ++index) {
|
||||
delete *index;
|
||||
}
|
||||
|
||||
// done with mutex
|
||||
delete m_threadMutex;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadWindows::setNetworkDataForCurrentThread(void* data)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
CArchThreadImpl* thread = findNoRef(GetCurrentThreadId());
|
||||
thread->m_networkData = data;
|
||||
unlockMutex(m_threadMutex);
|
||||
}
|
||||
|
||||
void*
|
||||
CArchMultithreadWindows::getNetworkDataForThread(CArchThread thread)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
void* data = thread->m_networkData;
|
||||
unlockMutex(m_threadMutex);
|
||||
return data;
|
||||
}
|
||||
|
||||
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[4];
|
||||
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 = 0;
|
||||
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(findNoRefOrCreate(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)
|
||||
{
|
||||
struct CPriorityInfo {
|
||||
public:
|
||||
DWORD m_class;
|
||||
int m_level;
|
||||
};
|
||||
static const CPriorityInfo s_pClass[] = {
|
||||
{ IDLE_PRIORITY_CLASS, THREAD_PRIORITY_IDLE },
|
||||
{ IDLE_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
|
||||
{ IDLE_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
|
||||
{ IDLE_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
|
||||
{ IDLE_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
|
||||
{ IDLE_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
|
||||
{ NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
|
||||
{ NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
|
||||
{ NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
|
||||
{ NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
|
||||
{ NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
|
||||
{ HIGH_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
|
||||
{ HIGH_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
|
||||
{ HIGH_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
|
||||
{ HIGH_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
|
||||
{ HIGH_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
|
||||
{ REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_IDLE },
|
||||
{ REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
|
||||
{ REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
|
||||
{ REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
|
||||
{ REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
|
||||
{ REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
|
||||
{ REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_TIME_CRITICAL}
|
||||
};
|
||||
#if defined(_DEBUG)
|
||||
// don't use really high priorities when debugging
|
||||
static const size_t s_pMax = 13;
|
||||
#else
|
||||
static const size_t s_pMax = sizeof(s_pClass) / sizeof(s_pClass[0]) - 1;
|
||||
#endif
|
||||
static const size_t s_pBase = 8; // index of normal priority
|
||||
|
||||
assert(thread != NULL);
|
||||
|
||||
size_t index;
|
||||
if (n > 0 && s_pBase < (size_t)n) {
|
||||
// lowest priority
|
||||
index = 0;
|
||||
}
|
||||
else {
|
||||
index = (size_t)((int)s_pBase - n);
|
||||
if (index > s_pMax) {
|
||||
// highest priority
|
||||
index = s_pMax;
|
||||
}
|
||||
}
|
||||
SetPriorityClass(GetCurrentProcess(), s_pClass[index].m_class);
|
||||
SetThreadPriority(thread->m_thread, s_pClass[index].m_level);
|
||||
}
|
||||
|
||||
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 woken up 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::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);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadWindows::setSignalHandler(
|
||||
ESignal signal, SignalFunc func, void* userData)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
m_signalFunc[signal] = func;
|
||||
m_signalUserData[signal] = userData;
|
||||
unlockMutex(m_threadMutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadWindows::raiseSignal(ESignal signal)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
if (m_signalFunc[signal] != NULL) {
|
||||
m_signalFunc[signal](signal, m_signalUserData[signal]);
|
||||
ARCH->unblockPollSocket(m_mainThread);
|
||||
}
|
||||
else if (signal == kINTERRUPT || signal == kTERMINATE) {
|
||||
ARCH->cancelThread(m_mainThread);
|
||||
}
|
||||
unlockMutex(m_threadMutex);
|
||||
}
|
||||
|
||||
CArchThreadImpl*
|
||||
CArchMultithreadWindows::find(DWORD id)
|
||||
{
|
||||
CArchThreadImpl* impl = findNoRef(id);
|
||||
if (impl != NULL) {
|
||||
refThread(impl);
|
||||
}
|
||||
return impl;
|
||||
}
|
||||
|
||||
CArchThreadImpl*
|
||||
CArchMultithreadWindows::findNoRef(DWORD id)
|
||||
{
|
||||
CArchThreadImpl* impl = findNoRefOrCreate(id);
|
||||
if (impl == NULL) {
|
||||
// create thread for calling thread which isn't in our list and
|
||||
// add it to the list. this won't normally happen but it can if
|
||||
// the system calls us under a new thread, like it does when we
|
||||
// run as a service.
|
||||
impl = new CArchThreadImpl;
|
||||
impl->m_thread = NULL;
|
||||
impl->m_id = GetCurrentThreadId();
|
||||
insert(impl);
|
||||
}
|
||||
return impl;
|
||||
}
|
||||
|
||||
CArchThreadImpl*
|
||||
CArchMultithreadWindows::findNoRefOrCreate(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(findNoRefOrCreate(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(findNoRefOrCreate(thread->m_id) != NULL);
|
||||
++thread->m_refCount;
|
||||
}
|
||||
|
||||
void
|
||||
CArchMultithreadWindows::testCancelThreadImpl(CArchThreadImpl* 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)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
118
src/lib/arch/CArchMultithreadWindows.h
Normal file
118
src/lib/arch/CArchMultithreadWindows.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
//! Win32 implementation of IArchMultithread
|
||||
class CArchMultithreadWindows : public IArchMultithread {
|
||||
public:
|
||||
CArchMultithreadWindows();
|
||||
virtual ~CArchMultithreadWindows();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
void setNetworkDataForCurrentThread(void*);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
HANDLE getCancelEventForCurrentThread();
|
||||
|
||||
void* getNetworkDataForThread(CArchThread);
|
||||
|
||||
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 isSameThread(CArchThread, CArchThread);
|
||||
virtual bool isExitedThread(CArchThread);
|
||||
virtual void* getResultOfThread(CArchThread);
|
||||
virtual ThreadID getIDOfThread(CArchThread);
|
||||
virtual void setSignalHandler(ESignal, SignalFunc, void*);
|
||||
virtual void raiseSignal(ESignal);
|
||||
|
||||
private:
|
||||
CArchThreadImpl* find(DWORD id);
|
||||
CArchThreadImpl* findNoRef(DWORD id);
|
||||
CArchThreadImpl* findNoRefOrCreate(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;
|
||||
CArchThread m_mainThread;
|
||||
|
||||
SignalFunc m_signalFunc[kNUM_SIGNALS];
|
||||
void* m_signalUserData[kNUM_SIGNALS];
|
||||
};
|
||||
|
||||
#endif
|
||||
986
src/lib/arch/CArchNetworkBSD.cpp
Normal file
986
src/lib/arch/CArchNetworkBSD.cpp
Normal file
@@ -0,0 +1,986 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchNetworkBSD.h"
|
||||
#include "CArch.h"
|
||||
#include "CArchMultithreadPosix.h"
|
||||
#include "XArchUnix.h"
|
||||
#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>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_POLL
|
||||
# include <poll.h>
|
||||
#else
|
||||
# if HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
# endif
|
||||
# if HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !HAVE_INET_ATON
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
static const int s_family[] = {
|
||||
PF_UNSPEC,
|
||||
PF_INET
|
||||
};
|
||||
static const int s_type[] = {
|
||||
SOCK_DGRAM,
|
||||
SOCK_STREAM
|
||||
};
|
||||
|
||||
#if !HAVE_INET_ATON
|
||||
// parse dotted quad addresses. we don't bother with the weird BSD'ism
|
||||
// of handling octal and hex and partial forms.
|
||||
static
|
||||
in_addr_t
|
||||
inet_aton(const char* cp, struct in_addr* inp)
|
||||
{
|
||||
unsigned int a, b, c, d;
|
||||
if (sscanf(cp, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) {
|
||||
return 0;
|
||||
}
|
||||
if (a >= 256 || b >= 256 || c >= 256 || d >= 256) {
|
||||
return 0;
|
||||
}
|
||||
unsigned char* incp = (unsigned char*)inp;
|
||||
incp[0] = (unsigned char)(a & 0xffu);
|
||||
incp[1] = (unsigned char)(b & 0xffu);
|
||||
incp[2] = (unsigned char)(c & 0xffu);
|
||||
incp[3] = (unsigned char)(d & 0xffu);
|
||||
return inp->s_addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// CArchNetworkBSD
|
||||
//
|
||||
|
||||
CArchNetworkBSD::CArchNetworkBSD()
|
||||
{
|
||||
}
|
||||
|
||||
CArchNetworkBSD::~CArchNetworkBSD()
|
||||
{
|
||||
ARCH->closeMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchNetworkBSD::init()
|
||||
{
|
||||
// create mutex to make some calls thread safe
|
||||
m_mutex = ARCH->newMutex();
|
||||
}
|
||||
|
||||
CArchSocket
|
||||
CArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
|
||||
{
|
||||
// create socket
|
||||
int fd = socket(s_family[family], s_type[type], 0);
|
||||
if (fd == -1) {
|
||||
throwError(errno);
|
||||
}
|
||||
try {
|
||||
setBlockingOnSocket(fd, false);
|
||||
}
|
||||
catch (...) {
|
||||
close(fd);
|
||||
throw;
|
||||
}
|
||||
|
||||
// allocate socket object
|
||||
CArchSocketImpl* newSocket = new CArchSocketImpl;
|
||||
newSocket->m_fd = fd;
|
||||
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) {
|
||||
if (close(s->m_fd) == -1) {
|
||||
// close failed. restore the last ref and throw.
|
||||
int err = errno;
|
||||
ARCH->lockMutex(m_mutex);
|
||||
++s->m_refCount;
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
throwError(err);
|
||||
}
|
||||
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
|
||||
ACCEPT_TYPE_ARG3 len = (ACCEPT_TYPE_ARG3)((*addr)->m_len);
|
||||
int fd = accept(s->m_fd, &(*addr)->m_addr, &len);
|
||||
(*addr)->m_len = (socklen_t)len;
|
||||
if (fd == -1) {
|
||||
int err = errno;
|
||||
delete newSocket;
|
||||
delete *addr;
|
||||
*addr = NULL;
|
||||
if (err == EAGAIN) {
|
||||
return NULL;
|
||||
}
|
||||
throwError(err);
|
||||
}
|
||||
|
||||
try {
|
||||
setBlockingOnSocket(fd, false);
|
||||
}
|
||||
catch (...) {
|
||||
close(fd);
|
||||
delete newSocket;
|
||||
delete *addr;
|
||||
*addr = NULL;
|
||||
throw;
|
||||
}
|
||||
|
||||
// initialize socket
|
||||
newSocket->m_fd = fd;
|
||||
newSocket->m_refCount = 1;
|
||||
|
||||
// discard address if not requested
|
||||
if (addr == &dummy) {
|
||||
ARCH->closeAddr(dummy);
|
||||
}
|
||||
|
||||
return newSocket;
|
||||
}
|
||||
|
||||
bool
|
||||
CArchNetworkBSD::connectSocket(CArchSocket s, CArchNetAddress addr)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(addr != NULL);
|
||||
|
||||
if (connect(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
|
||||
if (errno == EISCONN) {
|
||||
return true;
|
||||
}
|
||||
if (errno == EINPROGRESS) {
|
||||
return false;
|
||||
}
|
||||
throwError(errno);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#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[1 + 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;
|
||||
}
|
||||
}
|
||||
int n = num;
|
||||
|
||||
// add the unblock pipe
|
||||
const int* unblockPipe = getUnblockPipe();
|
||||
if (unblockPipe != NULL) {
|
||||
pfd[n].fd = unblockPipe[0];
|
||||
pfd[n].events = POLLIN;
|
||||
++n;
|
||||
}
|
||||
|
||||
// prepare timeout
|
||||
int t = (timeout < 0.0) ? -1 : static_cast<int>(1000.0 * timeout);
|
||||
|
||||
// do the poll
|
||||
n = poll(pfd, n, t);
|
||||
|
||||
// reset the unblock pipe
|
||||
if (n > 0 && unblockPipe != NULL && (pfd[num].revents & POLLIN) != 0) {
|
||||
// the unblock event was signalled. flush the pipe.
|
||||
char dummy[100];
|
||||
int ignore;
|
||||
|
||||
do {
|
||||
ignore = read(unblockPipe[0], dummy, sizeof(dummy));
|
||||
} while (errno != EAGAIN);
|
||||
|
||||
// don't count this unblock pipe in return value
|
||||
--n;
|
||||
}
|
||||
|
||||
// handle results
|
||||
if (n == -1) {
|
||||
if (errno == EINTR) {
|
||||
// interrupted system call
|
||||
ARCH->testCancelThread();
|
||||
delete[] pfd;
|
||||
return 0;
|
||||
}
|
||||
delete[] pfd;
|
||||
throwError(errno);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] pfd;
|
||||
return n;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add the unblock pipe
|
||||
const int* unblockPipe = getUnblockPipe();
|
||||
if (unblockPipe != NULL) {
|
||||
FD_SET(unblockPipe[0], &readSet);
|
||||
readSetP = &readSet;
|
||||
if (unblockPipe[0] > n) {
|
||||
n = unblockPipe[0];
|
||||
}
|
||||
}
|
||||
|
||||
// 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.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);
|
||||
|
||||
// reset the unblock pipe
|
||||
if (n > 0 && unblockPipe != NULL && FD_ISSET(unblockPipe[0], &readSet)) {
|
||||
// the unblock event was signalled. flush the pipe.
|
||||
char dummy[100];
|
||||
do {
|
||||
read(unblockPipe[0], dummy, sizeof(dummy));
|
||||
} while (errno != EAGAIN);
|
||||
}
|
||||
|
||||
// handle results
|
||||
if (n == -1) {
|
||||
if (errno == EINTR) {
|
||||
// interrupted system call
|
||||
ARCH->testCancelThread();
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
CArchNetworkBSD::unblockPollSocket(CArchThread thread)
|
||||
{
|
||||
const int* unblockPipe = getUnblockPipeForThread(thread);
|
||||
if (unblockPipe != NULL) {
|
||||
char dummy = 0;
|
||||
int ignore;
|
||||
|
||||
ignore = write(unblockPipe[1], &dummy, 1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
CArchNetworkBSD::readSocket(CArchSocket s, void* buf, size_t len)
|
||||
{
|
||||
assert(s != NULL);
|
||||
|
||||
ssize_t n = read(s->m_fd, buf, len);
|
||||
if (n == -1) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
return 0;
|
||||
}
|
||||
throwError(errno);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t
|
||||
CArchNetworkBSD::writeSocket(CArchSocket s, const void* buf, size_t len)
|
||||
{
|
||||
assert(s != NULL);
|
||||
|
||||
ssize_t n = write(s->m_fd, buf, len);
|
||||
if (n == -1) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
return 0;
|
||||
}
|
||||
throwError(errno);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
CArchNetworkBSD::throwErrorOnSocket(CArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
|
||||
// get the error from the socket layer
|
||||
int err = 0;
|
||||
socklen_t size = (socklen_t)sizeof(err);
|
||||
if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR,
|
||||
(optval_t*)&err, &size) == -1) {
|
||||
err = errno;
|
||||
}
|
||||
|
||||
// throw if there's an error
|
||||
if (err != 0) {
|
||||
throwError(err);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking)
|
||||
{
|
||||
assert(fd != -1);
|
||||
|
||||
int mode = fcntl(fd, F_GETFL, 0);
|
||||
if (mode == -1) {
|
||||
throwError(errno);
|
||||
}
|
||||
if (blocking) {
|
||||
mode &= ~O_NONBLOCK;
|
||||
}
|
||||
else {
|
||||
mode |= O_NONBLOCK;
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, mode) == -1) {
|
||||
throwError(errno);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CArchNetworkBSD::setNoDelayOnSocket(CArchSocket s, bool noDelay)
|
||||
{
|
||||
assert(s != NULL);
|
||||
|
||||
// get old state
|
||||
int oflag;
|
||||
socklen_t size = (socklen_t)sizeof(oflag);
|
||||
if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY,
|
||||
(optval_t*)&oflag, &size) == -1) {
|
||||
throwError(errno);
|
||||
}
|
||||
|
||||
int flag = noDelay ? 1 : 0;
|
||||
size = (socklen_t)sizeof(flag);
|
||||
if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY,
|
||||
(optval_t*)&flag, size) == -1) {
|
||||
throwError(errno);
|
||||
}
|
||||
|
||||
return (oflag != 0);
|
||||
}
|
||||
|
||||
bool
|
||||
CArchNetworkBSD::setReuseAddrOnSocket(CArchSocket s, bool reuse)
|
||||
{
|
||||
assert(s != NULL);
|
||||
|
||||
// get old state
|
||||
int oflag;
|
||||
socklen_t size = (socklen_t)sizeof(oflag);
|
||||
if (getsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(optval_t*)&oflag, &size) == -1) {
|
||||
throwError(errno);
|
||||
}
|
||||
|
||||
int flag = reuse ? 1 : 0;
|
||||
size = (socklen_t)sizeof(flag);
|
||||
if (setsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(optval_t*)&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 = (socklen_t)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 = (socklen_t)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)
|
||||
if (info->h_addrtype == AF_INET) {
|
||||
addr->m_len = (socklen_t)sizeof(struct sockaddr_in);
|
||||
inaddr.sin_family = info->h_addrtype;
|
||||
inaddr.sin_port = 0;
|
||||
memcpy(&inaddr.sin_addr, info->h_addr_list[0],
|
||||
sizeof(inaddr.sin_addr));
|
||||
memcpy(&addr->m_addr, &inaddr, addr->m_len);
|
||||
}
|
||||
else {
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
delete addr;
|
||||
throw XArchNetworkNameUnsupported(
|
||||
"The requested name is valid but "
|
||||
"does not have a supported address family");
|
||||
}
|
||||
|
||||
// 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(
|
||||
reinterpret_cast<const char*>(&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 == (socklen_t)sizeof(struct sockaddr_in));
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0 && "unknown address family");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CArchNetworkBSD::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
|
||||
{
|
||||
return (a->m_len == b->m_len &&
|
||||
memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0);
|
||||
}
|
||||
|
||||
const int*
|
||||
CArchNetworkBSD::getUnblockPipe()
|
||||
{
|
||||
CArchMultithreadPosix* mt = CArchMultithreadPosix::getInstance();
|
||||
CArchThread thread = mt->newCurrentThread();
|
||||
const int* p = getUnblockPipeForThread(thread);
|
||||
ARCH->closeThread(thread);
|
||||
return p;
|
||||
}
|
||||
|
||||
const int*
|
||||
CArchNetworkBSD::getUnblockPipeForThread(CArchThread thread)
|
||||
{
|
||||
CArchMultithreadPosix* mt = CArchMultithreadPosix::getInstance();
|
||||
int* unblockPipe = (int*)mt->getNetworkDataForThread(thread);
|
||||
if (unblockPipe == NULL) {
|
||||
unblockPipe = new int[2];
|
||||
if (pipe(unblockPipe) != -1) {
|
||||
try {
|
||||
setBlockingOnSocket(unblockPipe[0], false);
|
||||
mt->setNetworkDataForCurrentThread(unblockPipe);
|
||||
}
|
||||
catch (...) {
|
||||
delete[] unblockPipe;
|
||||
unblockPipe = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
delete[] unblockPipe;
|
||||
unblockPipe = NULL;
|
||||
}
|
||||
}
|
||||
return unblockPipe;
|
||||
}
|
||||
|
||||
void
|
||||
CArchNetworkBSD::throwError(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case EINTR:
|
||||
ARCH->testCancelThread();
|
||||
throw XArchNetworkInterrupted(new XArchEvalUnix(err));
|
||||
|
||||
case EACCES:
|
||||
case EPERM:
|
||||
throw XArchNetworkAccess(new XArchEvalUnix(err));
|
||||
|
||||
case ENFILE:
|
||||
case EMFILE:
|
||||
case ENODEV:
|
||||
case ENOBUFS:
|
||||
case ENOMEM:
|
||||
case ENETDOWN:
|
||||
#if defined(ENOSR)
|
||||
case ENOSR:
|
||||
#endif
|
||||
throw XArchNetworkResource(new XArchEvalUnix(err));
|
||||
|
||||
case EPROTOTYPE:
|
||||
case EPROTONOSUPPORT:
|
||||
case EAFNOSUPPORT:
|
||||
case EPFNOSUPPORT:
|
||||
case ESOCKTNOSUPPORT:
|
||||
case EINVAL:
|
||||
case ENOPROTOOPT:
|
||||
case EOPNOTSUPP:
|
||||
case ESHUTDOWN:
|
||||
#if defined(ENOPKG)
|
||||
case ENOPKG:
|
||||
#endif
|
||||
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:
|
||||
throw XArchNetworkShutdown(new XArchEvalUnix(err));
|
||||
|
||||
case ECONNABORTED:
|
||||
case ECONNRESET:
|
||||
throw XArchNetworkDisconnected(new XArchEvalUnix(err));
|
||||
|
||||
case ECONNREFUSED:
|
||||
throw XArchNetworkConnectionRefused(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]);
|
||||
}
|
||||
}
|
||||
105
src/lib/arch/CArchNetworkBSD.h
Normal file
105
src/lib/arch/CArchNetworkBSD.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHNETWORKBSD_H
|
||||
#define CARCHNETWORKBSD_H
|
||||
|
||||
#include "IArchNetwork.h"
|
||||
#include "IArchMultithread.h"
|
||||
#if HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#if !HAVE_SOCKLEN_T
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
// old systems may use char* for [gs]etsockopt()'s optval argument.
|
||||
// this should be void on modern systems but char is forwards
|
||||
// compatible so we always use it.
|
||||
typedef char optval_t;
|
||||
|
||||
#define ARCH_NETWORK CArchNetworkBSD
|
||||
|
||||
class CArchSocketImpl {
|
||||
public:
|
||||
int m_fd;
|
||||
int m_refCount;
|
||||
};
|
||||
|
||||
class CArchNetAddressImpl {
|
||||
public:
|
||||
CArchNetAddressImpl() : m_len(sizeof(m_addr)) { }
|
||||
|
||||
public:
|
||||
struct sockaddr m_addr;
|
||||
socklen_t m_len;
|
||||
};
|
||||
|
||||
//! Berkeley (BSD) sockets implementation of IArchNetwork
|
||||
class CArchNetworkBSD : public IArchNetwork {
|
||||
public:
|
||||
CArchNetworkBSD();
|
||||
virtual ~CArchNetworkBSD();
|
||||
|
||||
virtual void init();
|
||||
|
||||
// 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 bool connectSocket(CArchSocket s, CArchNetAddress name);
|
||||
virtual int pollSocket(CPollEntry[], int num, double timeout);
|
||||
virtual void unblockPollSocket(CArchThread thread);
|
||||
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 setNoDelayOnSocket(CArchSocket, bool noDelay);
|
||||
virtual bool setReuseAddrOnSocket(CArchSocket, bool reuse);
|
||||
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);
|
||||
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
|
||||
|
||||
private:
|
||||
const int* getUnblockPipe();
|
||||
const int* getUnblockPipeForThread(CArchThread);
|
||||
void setBlockingOnSocket(int fd, bool blocking);
|
||||
void throwError(int);
|
||||
void throwNameError(int);
|
||||
|
||||
private:
|
||||
CArchMutex m_mutex;
|
||||
};
|
||||
|
||||
#endif
|
||||
942
src/lib/arch/CArchNetworkWinsock.cpp
Normal file
942
src/lib/arch/CArchNetworkWinsock.cpp
Normal file
@@ -0,0 +1,942 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "CArchNetworkWinsock.h"
|
||||
#include "CArch.h"
|
||||
#include "CArchMultithreadWindows.h"
|
||||
#include "IArchMultithread.h"
|
||||
#include "XArchWindows.h"
|
||||
#include <malloc.h>
|
||||
|
||||
static const int s_family[] = {
|
||||
PF_UNSPEC,
|
||||
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 * data);
|
||||
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 * fdset);
|
||||
static WSAEVENT (PASCAL FAR *WSACreateEvent_winsock)(void);
|
||||
static BOOL (PASCAL FAR *WSACloseEvent_winsock)(WSAEVENT);
|
||||
static BOOL (PASCAL FAR *WSASetEvent_winsock)(WSAEVENT);
|
||||
static BOOL (PASCAL FAR *WSAResetEvent_winsock)(WSAEVENT);
|
||||
static int (PASCAL FAR *WSAEventSelect_winsock)(SOCKET, WSAEVENT, long);
|
||||
static DWORD (PASCAL FAR *WSAWaitForMultipleEvents_winsock)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL);
|
||||
static int (PASCAL FAR *WSAEnumNetworkEvents_winsock)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS);
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
CArchNetAddressImpl*
|
||||
CArchNetAddressImpl::alloc(size_t size)
|
||||
{
|
||||
size_t totalSize = size + ADDR_HDR_SIZE;
|
||||
CArchNetAddressImpl* addr = (CArchNetAddressImpl*)malloc(totalSize);
|
||||
addr->m_len = (int)size;
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CArchNetworkWinsock
|
||||
//
|
||||
|
||||
CArchNetworkWinsock::CArchNetworkWinsock()
|
||||
{
|
||||
}
|
||||
|
||||
CArchNetworkWinsock::~CArchNetworkWinsock()
|
||||
{
|
||||
if (s_networkModule != NULL) {
|
||||
WSACleanup_winsock();
|
||||
::FreeLibrary(s_networkModule);
|
||||
|
||||
WSACleanup_winsock = NULL;
|
||||
s_networkModule = NULL;
|
||||
}
|
||||
ARCH->closeMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchNetworkWinsock::init()
|
||||
{
|
||||
static const char* s_library[] = { "ws2_32.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 {
|
||||
initModule((HMODULE)::LoadLibrary(s_library[i]));
|
||||
m_mutex = ARCH->newMutex();
|
||||
return;
|
||||
}
|
||||
catch (XArchNetwork&) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
// can't initialize any library
|
||||
throw XArchNetworkSupport("Cannot load winsock library");
|
||||
}
|
||||
|
||||
void
|
||||
CArchNetworkWinsock::initModule(HMODULE module)
|
||||
{
|
||||
if (module == NULL) {
|
||||
throw XArchNetworkSupport("");
|
||||
}
|
||||
|
||||
// get startup function address
|
||||
int (PASCAL FAR *startup)(WORD, LPWSADATA);
|
||||
setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA));
|
||||
|
||||
// startup network library
|
||||
WORD version = MAKEWORD(2 /*major*/, 0 /*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 *));
|
||||
setfunc(WSACreateEvent_winsock, WSACreateEvent, WSAEVENT (PASCAL FAR *)(void));
|
||||
setfunc(WSACloseEvent_winsock, WSACloseEvent, BOOL (PASCAL FAR *)(WSAEVENT));
|
||||
setfunc(WSASetEvent_winsock, WSASetEvent, BOOL (PASCAL FAR *)(WSAEVENT));
|
||||
setfunc(WSAResetEvent_winsock, WSAResetEvent, BOOL (PASCAL FAR *)(WSAEVENT));
|
||||
setfunc(WSAEventSelect_winsock, WSAEventSelect, int (PASCAL FAR *)(SOCKET, WSAEVENT, long));
|
||||
setfunc(WSAWaitForMultipleEvents_winsock, WSAWaitForMultipleEvents, DWORD (PASCAL FAR *)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL));
|
||||
setfunc(WSAEnumNetworkEvents_winsock, WSAEnumNetworkEvents, int (PASCAL FAR *)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS));
|
||||
|
||||
s_networkModule = module;
|
||||
}
|
||||
|
||||
CArchSocket
|
||||
CArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type)
|
||||
{
|
||||
// create socket
|
||||
SOCKET fd = socket_winsock(s_family[family], s_type[type], 0);
|
||||
if (fd == INVALID_SOCKET) {
|
||||
throwError(getsockerror_winsock());
|
||||
}
|
||||
try {
|
||||
setBlockingOnSocket(fd, false);
|
||||
}
|
||||
catch (...) {
|
||||
close_winsock(fd);
|
||||
throw;
|
||||
}
|
||||
|
||||
// allocate socket object
|
||||
CArchSocketImpl* socket = new CArchSocketImpl;
|
||||
socket->m_socket = fd;
|
||||
socket->m_refCount = 1;
|
||||
socket->m_event = WSACreateEvent_winsock();
|
||||
socket->m_pollWrite = true;
|
||||
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) {
|
||||
if (close_winsock(s->m_socket) == SOCKET_ERROR) {
|
||||
// close failed. restore the last ref and throw.
|
||||
int err = getsockerror_winsock();
|
||||
ARCH->lockMutex(m_mutex);
|
||||
++s->m_refCount;
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
throwError(err);
|
||||
}
|
||||
WSACloseEvent_winsock(s->m_event);
|
||||
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);
|
||||
|
||||
// create new socket and temporary address
|
||||
CArchSocketImpl* socket = new CArchSocketImpl;
|
||||
CArchNetAddress tmp = CArchNetAddressImpl::alloc(sizeof(struct sockaddr));
|
||||
|
||||
// accept on socket
|
||||
SOCKET fd = accept_winsock(s->m_socket, &tmp->m_addr, &tmp->m_len);
|
||||
if (fd == INVALID_SOCKET) {
|
||||
int err = getsockerror_winsock();
|
||||
delete socket;
|
||||
free(tmp);
|
||||
*addr = NULL;
|
||||
if (err == WSAEWOULDBLOCK) {
|
||||
return NULL;
|
||||
}
|
||||
throwError(err);
|
||||
}
|
||||
|
||||
try {
|
||||
setBlockingOnSocket(fd, false);
|
||||
}
|
||||
catch (...) {
|
||||
close_winsock(fd);
|
||||
delete socket;
|
||||
free(tmp);
|
||||
*addr = NULL;
|
||||
throw;
|
||||
}
|
||||
|
||||
// initialize socket
|
||||
socket->m_socket = fd;
|
||||
socket->m_refCount = 1;
|
||||
socket->m_event = WSACreateEvent_winsock();
|
||||
socket->m_pollWrite = true;
|
||||
|
||||
// copy address if requested
|
||||
if (addr != NULL) {
|
||||
*addr = ARCH->copyAddr(tmp);
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
return socket;
|
||||
}
|
||||
|
||||
bool
|
||||
CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(addr != NULL);
|
||||
|
||||
if (connect_winsock(s->m_socket, &addr->m_addr,
|
||||
addr->m_len) == SOCKET_ERROR) {
|
||||
if (getsockerror_winsock() == WSAEISCONN) {
|
||||
return true;
|
||||
}
|
||||
if (getsockerror_winsock() == WSAEWOULDBLOCK) {
|
||||
return false;
|
||||
}
|
||||
throwError(getsockerror_winsock());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
|
||||
{
|
||||
int i;
|
||||
DWORD n;
|
||||
|
||||
// prepare sockets and wait list
|
||||
bool canWrite = false;
|
||||
WSAEVENT* events = (WSAEVENT*)alloca((num + 1) * sizeof(WSAEVENT));
|
||||
for (i = 0, n = 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;
|
||||
}
|
||||
|
||||
// select desired events
|
||||
long socketEvents = 0;
|
||||
if ((pe[i].m_events & kPOLLIN) != 0) {
|
||||
socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
||||
}
|
||||
if ((pe[i].m_events & kPOLLOUT) != 0) {
|
||||
socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE;
|
||||
|
||||
// if m_pollWrite is false then we assume the socket is
|
||||
// writable. winsock doesn't signal writability except
|
||||
// when the state changes from unwritable.
|
||||
if (!pe[i].m_socket->m_pollWrite) {
|
||||
canWrite = true;
|
||||
pe[i].m_revents |= kPOLLOUT;
|
||||
}
|
||||
}
|
||||
|
||||
// if no events then ignore socket
|
||||
if (socketEvents == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// select socket for desired events
|
||||
WSAEventSelect_winsock(pe[i].m_socket->m_socket,
|
||||
pe[i].m_socket->m_event, socketEvents);
|
||||
|
||||
// add socket event to wait list
|
||||
events[n++] = pe[i].m_socket->m_event;
|
||||
}
|
||||
|
||||
// if no sockets then return immediately
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// add the unblock event
|
||||
CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
|
||||
CArchThread thread = mt->newCurrentThread();
|
||||
WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
|
||||
ARCH->closeThread(thread);
|
||||
if (unblockEvent == NULL) {
|
||||
unblockEvent = new WSAEVENT;
|
||||
*unblockEvent = WSACreateEvent_winsock();
|
||||
mt->setNetworkDataForCurrentThread(unblockEvent);
|
||||
}
|
||||
events[n++] = *unblockEvent;
|
||||
|
||||
// prepare timeout
|
||||
DWORD t = (timeout < 0.0) ? INFINITE : (DWORD)(1000.0 * timeout);
|
||||
if (canWrite) {
|
||||
// if we know we can write then don't block
|
||||
t = 0;
|
||||
}
|
||||
|
||||
// wait
|
||||
DWORD result = WSAWaitForMultipleEvents_winsock(n, events, FALSE, t, FALSE);
|
||||
|
||||
// reset the unblock event
|
||||
WSAResetEvent_winsock(*unblockEvent);
|
||||
|
||||
// handle results
|
||||
if (result == WSA_WAIT_FAILED) {
|
||||
if (getsockerror_winsock() == WSAEINTR) {
|
||||
// interrupted system call
|
||||
ARCH->testCancelThread();
|
||||
return 0;
|
||||
}
|
||||
throwError(getsockerror_winsock());
|
||||
}
|
||||
if (result == WSA_WAIT_TIMEOUT && !canWrite) {
|
||||
return 0;
|
||||
}
|
||||
if (result == WSA_WAIT_EVENT_0 + n - 1) {
|
||||
// the unblock event was signalled
|
||||
return 0;
|
||||
}
|
||||
for (i = 0, n = 0; i < num; ++i) {
|
||||
// skip events we didn't check
|
||||
if (pe[i].m_socket == NULL ||
|
||||
(pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get events
|
||||
WSANETWORKEVENTS info;
|
||||
if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket,
|
||||
pe[i].m_socket->m_event, &info) == SOCKET_ERROR) {
|
||||
continue;
|
||||
}
|
||||
if ((info.lNetworkEvents & FD_READ) != 0) {
|
||||
pe[i].m_revents |= kPOLLIN;
|
||||
}
|
||||
if ((info.lNetworkEvents & FD_ACCEPT) != 0) {
|
||||
pe[i].m_revents |= kPOLLIN;
|
||||
}
|
||||
if ((info.lNetworkEvents & FD_WRITE) != 0) {
|
||||
pe[i].m_revents |= kPOLLOUT;
|
||||
|
||||
// socket is now writable so don't bothing polling for
|
||||
// writable until it becomes unwritable.
|
||||
pe[i].m_socket->m_pollWrite = false;
|
||||
}
|
||||
if ((info.lNetworkEvents & FD_CONNECT) != 0) {
|
||||
if (info.iErrorCode[FD_CONNECT_BIT] != 0) {
|
||||
pe[i].m_revents |= kPOLLERR;
|
||||
}
|
||||
else {
|
||||
pe[i].m_revents |= kPOLLOUT;
|
||||
pe[i].m_socket->m_pollWrite = false;
|
||||
}
|
||||
}
|
||||
if ((info.lNetworkEvents & FD_CLOSE) != 0) {
|
||||
if (info.iErrorCode[FD_CLOSE_BIT] != 0) {
|
||||
pe[i].m_revents |= kPOLLERR;
|
||||
}
|
||||
else {
|
||||
if ((pe[i].m_events & kPOLLIN) != 0) {
|
||||
pe[i].m_revents |= kPOLLIN;
|
||||
}
|
||||
if ((pe[i].m_events & kPOLLOUT) != 0) {
|
||||
pe[i].m_revents |= kPOLLOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pe[i].m_revents != 0) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)n;
|
||||
}
|
||||
|
||||
void
|
||||
CArchNetworkWinsock::unblockPollSocket(CArchThread thread)
|
||||
{
|
||||
// set the unblock event
|
||||
CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
|
||||
WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
|
||||
if (unblockEvent != NULL) {
|
||||
WSASetEvent_winsock(*unblockEvent);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
CArchNetworkWinsock::readSocket(CArchSocket s, void* buf, size_t len)
|
||||
{
|
||||
assert(s != NULL);
|
||||
|
||||
int n = recv_winsock(s->m_socket, buf, (int)len, 0);
|
||||
if (n == SOCKET_ERROR) {
|
||||
int err = getsockerror_winsock();
|
||||
if (err == WSAEINTR || err == WSAEWOULDBLOCK) {
|
||||
return 0;
|
||||
}
|
||||
throwError(err);
|
||||
}
|
||||
return static_cast<size_t>(n);
|
||||
}
|
||||
|
||||
size_t
|
||||
CArchNetworkWinsock::writeSocket(CArchSocket s, const void* buf, size_t len)
|
||||
{
|
||||
assert(s != NULL);
|
||||
|
||||
int n = send_winsock(s->m_socket, buf, (int)len, 0);
|
||||
if (n == SOCKET_ERROR) {
|
||||
int err = getsockerror_winsock();
|
||||
if (err == WSAEINTR) {
|
||||
return 0;
|
||||
}
|
||||
if (err == WSAEWOULDBLOCK) {
|
||||
s->m_pollWrite = true;
|
||||
return 0;
|
||||
}
|
||||
throwError(err);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchNetworkWinsock::setBlockingOnSocket(SOCKET s, bool blocking)
|
||||
{
|
||||
assert(s != 0);
|
||||
|
||||
int flag = blocking ? 0 : 1;
|
||||
if (ioctl_winsock(s, FIONBIO, &flag) == SOCKET_ERROR) {
|
||||
throwError(getsockerror_winsock());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool
|
||||
CArchNetworkWinsock::setReuseAddrOnSocket(CArchSocket s, bool reuse)
|
||||
{
|
||||
assert(s != NULL);
|
||||
|
||||
// get old state
|
||||
BOOL oflag;
|
||||
int size = sizeof(oflag);
|
||||
if (getsockopt_winsock(s->m_socket, SOL_SOCKET,
|
||||
SO_REUSEADDR, &oflag, &size) == SOCKET_ERROR) {
|
||||
throwError(getsockerror_winsock());
|
||||
}
|
||||
|
||||
// set new state
|
||||
BOOL flag = reuse ? 1 : 0;
|
||||
size = sizeof(flag);
|
||||
if (setsockopt_winsock(s->m_socket, SOL_SOCKET,
|
||||
SO_REUSEADDR, &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)
|
||||
{
|
||||
CArchNetAddressImpl* addr = NULL;
|
||||
switch (family) {
|
||||
case kINET: {
|
||||
addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
|
||||
struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
||||
ipAddr->sin_family = AF_INET;
|
||||
ipAddr->sin_port = 0;
|
||||
ipAddr->sin_addr.s_addr = INADDR_ANY;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0 && "invalid family");
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
CArchNetAddress
|
||||
CArchNetworkWinsock::copyAddr(CArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
|
||||
CArchNetAddressImpl* copy = CArchNetAddressImpl::alloc(addr->m_len);
|
||||
memcpy(TYPED_ADDR(void, copy), TYPED_ADDR(void, addr), addr->m_len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
CArchNetAddress
|
||||
CArchNetworkWinsock::nameToAddr(const std::string& name)
|
||||
{
|
||||
// allocate address
|
||||
CArchNetAddressImpl* addr = NULL;
|
||||
|
||||
// try to convert assuming an IPv4 dot notation address
|
||||
struct sockaddr_in inaddr;
|
||||
memset(&inaddr, 0, sizeof(inaddr));
|
||||
inaddr.sin_family = AF_INET;
|
||||
inaddr.sin_port = 0;
|
||||
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 = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
|
||||
memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len);
|
||||
}
|
||||
|
||||
else {
|
||||
// address lookup
|
||||
struct hostent* info = gethostbyname_winsock(name.c_str());
|
||||
if (info == NULL) {
|
||||
throwNameError(getsockerror_winsock());
|
||||
}
|
||||
|
||||
// copy over address (only IPv4 currently supported)
|
||||
if (info->h_addrtype == AF_INET) {
|
||||
addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
|
||||
memcpy(&inaddr.sin_addr, info->h_addr_list[0],
|
||||
sizeof(inaddr.sin_addr));
|
||||
memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len);
|
||||
}
|
||||
else {
|
||||
throw XArchNetworkNameUnsupported(
|
||||
"The requested name is valid but "
|
||||
"does not have a supported address family");
|
||||
}
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void
|
||||
CArchNetworkWinsock::closeAddr(CArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
|
||||
free(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 (addr->m_len == sizeof(struct sockaddr_in) &&
|
||||
ipAddr->sin_addr.s_addr == INADDR_ANY);
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0 && "unknown address family");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CArchNetworkWinsock::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
|
||||
{
|
||||
return (a == b || (a->m_len == b->m_len &&
|
||||
memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0));
|
||||
}
|
||||
|
||||
void
|
||||
CArchNetworkWinsock::throwError(int err)
|
||||
{
|
||||
switch (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 WSAEDISCON:
|
||||
throw XArchNetworkShutdown(new XArchEvalWinsock(err));
|
||||
|
||||
case WSAENETRESET:
|
||||
case WSAECONNABORTED:
|
||||
case WSAECONNRESET:
|
||||
throw XArchNetworkDisconnected(new XArchEvalWinsock(err));
|
||||
|
||||
case WSAECONNREFUSED:
|
||||
throw XArchNetworkConnectionRefused(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));
|
||||
}
|
||||
}
|
||||
104
src/lib/arch/CArchNetworkWinsock.h
Normal file
104
src/lib/arch/CArchNetworkWinsock.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
int m_refCount;
|
||||
WSAEVENT m_event;
|
||||
bool m_pollWrite;
|
||||
};
|
||||
|
||||
class CArchNetAddressImpl {
|
||||
public:
|
||||
static CArchNetAddressImpl* alloc(size_t);
|
||||
|
||||
public:
|
||||
int m_len;
|
||||
struct sockaddr m_addr;
|
||||
};
|
||||
#define ADDR_HDR_SIZE offsetof(CArchNetAddressImpl, m_addr)
|
||||
#define TYPED_ADDR(type_, addr_) (reinterpret_cast<type_*>(&addr_->m_addr))
|
||||
|
||||
//! Win32 implementation of IArchNetwork
|
||||
class CArchNetworkWinsock : public IArchNetwork {
|
||||
public:
|
||||
CArchNetworkWinsock();
|
||||
virtual ~CArchNetworkWinsock();
|
||||
|
||||
virtual void init();
|
||||
|
||||
// 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 bool connectSocket(CArchSocket s, CArchNetAddress name);
|
||||
virtual int pollSocket(CPollEntry[], int num, double timeout);
|
||||
virtual void unblockPollSocket(CArchThread thread);
|
||||
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 setNoDelayOnSocket(CArchSocket, bool noDelay);
|
||||
virtual bool setReuseAddrOnSocket(CArchSocket, bool reuse);
|
||||
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);
|
||||
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
|
||||
|
||||
private:
|
||||
void initModule(HMODULE);
|
||||
|
||||
void setBlockingOnSocket(SOCKET, bool blocking);
|
||||
|
||||
void throwError(int);
|
||||
void throwNameError(int);
|
||||
|
||||
private:
|
||||
CArchMutex m_mutex;
|
||||
};
|
||||
|
||||
#endif
|
||||
31
src/lib/arch/CArchPluginUnix.cpp
Normal file
31
src/lib/arch/CArchPluginUnix.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchPluginUnix.h"
|
||||
|
||||
CArchPluginUnix::CArchPluginUnix()
|
||||
{
|
||||
}
|
||||
|
||||
CArchPluginUnix::~CArchPluginUnix()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CArchPluginUnix::init(void* eventTarget)
|
||||
{
|
||||
}
|
||||
32
src/lib/arch/CArchPluginUnix.h
Normal file
32
src/lib/arch/CArchPluginUnix.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IArchPlugin.h"
|
||||
|
||||
#define ARCH_PLUGIN CArchPluginUnix
|
||||
|
||||
//! Unix implementation of IArchPlugin
|
||||
class CArchPluginUnix : public IArchPlugin {
|
||||
public:
|
||||
CArchPluginUnix();
|
||||
virtual ~CArchPluginUnix();
|
||||
|
||||
// IArchPlugin overrides
|
||||
void init(void* eventTarget);
|
||||
};
|
||||
126
src/lib/arch/CArchPluginWindows.cpp
Normal file
126
src/lib/arch/CArchPluginWindows.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchPluginWindows.h"
|
||||
#include "XArchWindows.h"
|
||||
#include "CLog.h"
|
||||
#include "IEventQueue.h"
|
||||
#include "CEvent.h"
|
||||
#include "CScreen.h"
|
||||
#include "IPlatformScreen.h" // temp
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <iostream>
|
||||
|
||||
typedef int (*initFunc)(void (*sendEvent)(const char*, void*), void (*log)(const char*));
|
||||
|
||||
void* CArchPluginWindows::m_eventTarget = NULL;
|
||||
|
||||
CArchPluginWindows::CArchPluginWindows()
|
||||
{
|
||||
}
|
||||
|
||||
CArchPluginWindows::~CArchPluginWindows()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CArchPluginWindows::init(void* eventTarget)
|
||||
{
|
||||
m_eventTarget = eventTarget;
|
||||
|
||||
CString dir = getPluginsDir();
|
||||
LOG((CLOG_DEBUG "plugins dir: %s", dir.c_str()));
|
||||
|
||||
CString pattern = CString(dir).append("\\*.dll");
|
||||
std::vector<CString> plugins;
|
||||
getFilenames(pattern, plugins);
|
||||
|
||||
std::vector<CString>::iterator it;
|
||||
for (it = plugins.begin(); it != plugins.end(); ++it)
|
||||
load(*it);
|
||||
}
|
||||
|
||||
void
|
||||
CArchPluginWindows::load(const CString& dllFilename)
|
||||
{
|
||||
LOG((CLOG_DEBUG "loading plugin: %s", dllFilename.c_str()));
|
||||
CString path = CString(getPluginsDir()).append("\\").append(dllFilename);
|
||||
HINSTANCE library = LoadLibrary(path.c_str());
|
||||
if (library == NULL)
|
||||
throw XArch(new XArchEvalWindows);
|
||||
|
||||
initFunc initPlugin = (initFunc)GetProcAddress(library, "init");
|
||||
initPlugin(&sendEvent, &log);
|
||||
}
|
||||
|
||||
CString
|
||||
CArchPluginWindows::getModuleDir()
|
||||
{
|
||||
TCHAR c_modulePath[MAX_PATH];
|
||||
GetModuleFileName(NULL, c_modulePath, MAX_PATH);
|
||||
if (GetLastError() != ERROR_SUCCESS) {
|
||||
throw XArch(new XArchEvalWindows);
|
||||
}
|
||||
|
||||
CString modulePath(c_modulePath);
|
||||
size_t lastSlash = modulePath.find_last_of("\\");
|
||||
|
||||
if (lastSlash != CString::npos) {
|
||||
return modulePath.substr(0, lastSlash);
|
||||
}
|
||||
|
||||
throw XArch("could not get module path.");
|
||||
}
|
||||
|
||||
void
|
||||
CArchPluginWindows::getFilenames(const CString& pattern, std::vector<CString>& filenames)
|
||||
{
|
||||
WIN32_FIND_DATA data;
|
||||
HANDLE find = FindFirstFile(pattern.c_str(), &data);
|
||||
if (find == INVALID_HANDLE_VALUE) {
|
||||
FindClose(find);
|
||||
LOG((CLOG_DEBUG "plugins dir is empty: %s", pattern.c_str()));
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
filenames.push_back(data.cFileName);
|
||||
} while (FindNextFile(find, &data));
|
||||
|
||||
FindClose(find);
|
||||
}
|
||||
|
||||
CString CArchPluginWindows::getPluginsDir()
|
||||
{
|
||||
return getModuleDir().append("\\").append(PLUGINS_DIR);
|
||||
}
|
||||
|
||||
void
|
||||
sendEvent(const char* eventName, void* data)
|
||||
{
|
||||
LOG((CLOG_DEBUG5 "plugin sending event"));
|
||||
CEvent::Type type = EVENTQUEUE->getRegisteredType(eventName);
|
||||
EVENTQUEUE->addEvent(CEvent(type, CArchPluginWindows::m_eventTarget, data));
|
||||
}
|
||||
|
||||
void
|
||||
log(const char* text)
|
||||
{
|
||||
LOG((CLOG_DEBUG "plugin: %s", text));
|
||||
}
|
||||
47
src/lib/arch/CArchPluginWindows.h
Normal file
47
src/lib/arch/CArchPluginWindows.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IArchPlugin.h"
|
||||
#include "CString.h"
|
||||
#include <vector>
|
||||
|
||||
#define ARCH_PLUGIN CArchPluginWindows
|
||||
|
||||
class CScreen;
|
||||
|
||||
//! Windows implementation of IArchPlugin
|
||||
class CArchPluginWindows : public IArchPlugin {
|
||||
public:
|
||||
CArchPluginWindows();
|
||||
virtual ~CArchPluginWindows();
|
||||
|
||||
// IArchPlugin overrides
|
||||
void init(void* eventTarget);
|
||||
|
||||
static void* m_eventTarget;
|
||||
|
||||
private:
|
||||
CString getModuleDir();
|
||||
void getFilenames(const CString& pattern, std::vector<CString>& filenames);
|
||||
void load(const CString& dllPath);
|
||||
CString getPluginsDir();
|
||||
};
|
||||
|
||||
void sendEvent(const char* text, void* data);
|
||||
void log(const char* text);
|
||||
91
src/lib/arch/CArchSleepUnix.cpp
Normal file
91
src/lib/arch/CArchSleepUnix.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "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 = ARCH->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 - (ARCH->time() - startTime);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
35
src/lib/arch/CArchSleepUnix.h
Normal file
35
src/lib/arch/CArchSleepUnix.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHSLEEPUNIX_H
|
||||
#define CARCHSLEEPUNIX_H
|
||||
|
||||
#include "IArchSleep.h"
|
||||
|
||||
#define ARCH_SLEEP CArchSleepUnix
|
||||
|
||||
//! Unix implementation of IArchSleep
|
||||
class CArchSleepUnix : public IArchSleep {
|
||||
public:
|
||||
CArchSleepUnix();
|
||||
virtual ~CArchSleepUnix();
|
||||
|
||||
// IArchSleep overrides
|
||||
virtual void sleep(double timeout);
|
||||
};
|
||||
|
||||
#endif
|
||||
60
src/lib/arch/CArchSleepWindows.cpp
Normal file
60
src/lib/arch/CArchSleepWindows.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "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));
|
||||
if (timeout == 0.0) {
|
||||
Sleep(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Sleep((DWORD)(1000.0 * timeout));
|
||||
}
|
||||
ARCH->testCancelThread();
|
||||
}
|
||||
35
src/lib/arch/CArchSleepWindows.h
Normal file
35
src/lib/arch/CArchSleepWindows.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHSLEEPWINDOWS_H
|
||||
#define CARCHSLEEPWINDOWS_H
|
||||
|
||||
#include "IArchSleep.h"
|
||||
|
||||
#define ARCH_SLEEP CArchSleepWindows
|
||||
|
||||
//! Win32 implementation of IArchSleep
|
||||
class CArchSleepWindows : public IArchSleep {
|
||||
public:
|
||||
CArchSleepWindows();
|
||||
virtual ~CArchSleepWindows();
|
||||
|
||||
// IArchSleep overrides
|
||||
virtual void sleep(double timeout);
|
||||
};
|
||||
|
||||
#endif
|
||||
40
src/lib/arch/CArchStringUnix.cpp
Normal file
40
src/lib/arch/CArchStringUnix.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchStringUnix.h"
|
||||
#include <stdio.h>
|
||||
|
||||
//
|
||||
// CArchStringUnix
|
||||
//
|
||||
|
||||
#include "CMultibyte.h"
|
||||
#include "vsnprintf.h"
|
||||
|
||||
CArchStringUnix::CArchStringUnix()
|
||||
{
|
||||
}
|
||||
|
||||
CArchStringUnix::~CArchStringUnix()
|
||||
{
|
||||
}
|
||||
|
||||
IArchString::EWideCharEncoding
|
||||
CArchStringUnix::getWideCharEncoding()
|
||||
{
|
||||
return kUCS4;
|
||||
}
|
||||
36
src/lib/arch/CArchStringUnix.h
Normal file
36
src/lib/arch/CArchStringUnix.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHSTRINGUNIX_H
|
||||
#define CARCHSTRINGUNIX_H
|
||||
|
||||
#include "IArchString.h"
|
||||
|
||||
#define ARCH_STRING CArchStringUnix
|
||||
|
||||
//! Unix implementation of IArchString
|
||||
class CArchStringUnix : public IArchString {
|
||||
public:
|
||||
CArchStringUnix();
|
||||
virtual ~CArchStringUnix();
|
||||
|
||||
// IArchString overrides
|
||||
virtual EWideCharEncoding
|
||||
getWideCharEncoding();
|
||||
};
|
||||
|
||||
#endif
|
||||
45
src/lib/arch/CArchStringWindows.cpp
Normal file
45
src/lib/arch/CArchStringWindows.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include "CArchStringWindows.h"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//
|
||||
// CArchStringWindows
|
||||
//
|
||||
|
||||
#include "CMultibyte.h"
|
||||
#define HAVE_VSNPRINTF 1
|
||||
#define ARCH_VSNPRINTF _vsnprintf
|
||||
#include "vsnprintf.h"
|
||||
|
||||
CArchStringWindows::CArchStringWindows()
|
||||
{
|
||||
}
|
||||
|
||||
CArchStringWindows::~CArchStringWindows()
|
||||
{
|
||||
}
|
||||
|
||||
IArchString::EWideCharEncoding
|
||||
CArchStringWindows::getWideCharEncoding()
|
||||
{
|
||||
return kUTF16;
|
||||
}
|
||||
36
src/lib/arch/CArchStringWindows.h
Normal file
36
src/lib/arch/CArchStringWindows.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHSTRINGWINDOWS_H
|
||||
#define CARCHSTRINGWINDOWS_H
|
||||
|
||||
#include "IArchString.h"
|
||||
|
||||
#define ARCH_STRING CArchStringWindows
|
||||
|
||||
//! Win32 implementation of IArchString
|
||||
class CArchStringWindows : public IArchString {
|
||||
public:
|
||||
CArchStringWindows();
|
||||
virtual ~CArchStringWindows();
|
||||
|
||||
// IArchString overrides
|
||||
virtual EWideCharEncoding
|
||||
getWideCharEncoding();
|
||||
};
|
||||
|
||||
#endif
|
||||
74
src/lib/arch/CArchSystemUnix.cpp
Normal file
74
src/lib/arch/CArchSystemUnix.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchSystemUnix.h"
|
||||
#include <sys/utsname.h>
|
||||
|
||||
//
|
||||
// CArchSystemUnix
|
||||
//
|
||||
|
||||
CArchSystemUnix::CArchSystemUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CArchSystemUnix::~CArchSystemUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchSystemUnix::getOSName() const
|
||||
{
|
||||
#if defined(HAVE_SYS_UTSNAME_H)
|
||||
struct utsname info;
|
||||
if (uname(&info) == 0) {
|
||||
std::string msg;
|
||||
msg += info.sysname;
|
||||
msg += " ";
|
||||
msg += info.release;
|
||||
msg += " ";
|
||||
msg += info.version;
|
||||
return msg;
|
||||
}
|
||||
#endif
|
||||
return "Unix";
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchSystemUnix::getPlatformName() const
|
||||
{
|
||||
#if defined(HAVE_SYS_UTSNAME_H)
|
||||
struct utsname info;
|
||||
if (uname(&info) == 0) {
|
||||
return std::string(info.machine);
|
||||
}
|
||||
#endif
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchSystemUnix::setting(const std::string&) const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
CArchSystemUnix::setting(const std::string&, const std::string&) const
|
||||
{
|
||||
}
|
||||
38
src/lib/arch/CArchSystemUnix.h
Normal file
38
src/lib/arch/CArchSystemUnix.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHSYSTEMUNIX_H
|
||||
#define CARCHSYSTEMUNIX_H
|
||||
|
||||
#include "IArchSystem.h"
|
||||
|
||||
#define ARCH_SYSTEM CArchSystemUnix
|
||||
|
||||
//! Unix implementation of IArchString
|
||||
class CArchSystemUnix : public IArchSystem {
|
||||
public:
|
||||
CArchSystemUnix();
|
||||
virtual ~CArchSystemUnix();
|
||||
|
||||
// IArchSystem overrides
|
||||
virtual std::string getOSName() const;
|
||||
virtual std::string getPlatformName() const;
|
||||
virtual std::string setting(const std::string&) const;
|
||||
virtual void setting(const std::string&, const std::string&) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
178
src/lib/arch/CArchSystemWindows.cpp
Normal file
178
src/lib/arch/CArchSystemWindows.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchSystemWindows.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include "XArchWindows.h"
|
||||
|
||||
#include "tchar.h"
|
||||
#include <string>
|
||||
|
||||
static const char* s_settingsKeyNames[] = {
|
||||
_T("SOFTWARE"),
|
||||
_T("Synergy"),
|
||||
NULL
|
||||
};
|
||||
|
||||
//
|
||||
// CArchSystemWindows
|
||||
//
|
||||
|
||||
CArchSystemWindows::CArchSystemWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CArchSystemWindows::~CArchSystemWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchSystemWindows::getOSName() const
|
||||
{
|
||||
#if WINVER >= _WIN32_WINNT_WIN2K
|
||||
OSVERSIONINFOEX info;
|
||||
#else
|
||||
OSVERSIONINFO info;
|
||||
#endif
|
||||
|
||||
info.dwOSVersionInfoSize = sizeof(info);
|
||||
if (GetVersionEx((OSVERSIONINFO*) &info)) {
|
||||
switch (info.dwPlatformId) {
|
||||
case VER_PLATFORM_WIN32_NT:
|
||||
#if WINVER >= _WIN32_WINNT_WIN2K
|
||||
if (info.dwMajorVersion == 6) {
|
||||
if(info.dwMinorVersion == 0) {
|
||||
if (info.wProductType == VER_NT_WORKSTATION) {
|
||||
return "Microsoft Windows Vista";
|
||||
} else {
|
||||
return "Microsoft Windows Server 2008";
|
||||
}
|
||||
} else if(info.dwMinorVersion == 1) {
|
||||
if (info.wProductType == VER_NT_WORKSTATION) {
|
||||
return "Microsoft Windows 7";
|
||||
} else {
|
||||
return "Microsoft Windows Server 2008 R2";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (info.dwMajorVersion == 5 && info.dwMinorVersion == 2) {
|
||||
return "Microsoft Windows Server 2003";
|
||||
}
|
||||
if (info.dwMajorVersion == 5 && info.dwMinorVersion == 1) {
|
||||
return "Microsoft Windows XP";
|
||||
}
|
||||
if (info.dwMajorVersion == 5 && info.dwMinorVersion == 0) {
|
||||
return "Microsoft Windows Server 2000";
|
||||
}
|
||||
if (info.dwMajorVersion <= 4) {
|
||||
return "Microsoft Windows NT";
|
||||
}
|
||||
char buffer[100];
|
||||
sprintf(buffer, "Microsoft Windows %d.%d",
|
||||
info.dwMajorVersion, info.dwMinorVersion);
|
||||
return buffer;
|
||||
|
||||
case VER_PLATFORM_WIN32_WINDOWS:
|
||||
if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
|
||||
if (info.szCSDVersion[1] == 'C' ||
|
||||
info.szCSDVersion[1] == 'B') {
|
||||
return "Microsoft Windows 95 OSR2";
|
||||
}
|
||||
return "Microsoft Windows 95";
|
||||
}
|
||||
if (info.dwMajorVersion == 4 && info.dwMinorVersion == 10) {
|
||||
if (info.szCSDVersion[1] == 'A') {
|
||||
return "Microsoft Windows 98 SE";
|
||||
}
|
||||
return "Microsoft Windows 98";
|
||||
}
|
||||
if (info.dwMajorVersion == 4 && info.dwMinorVersion == 90) {
|
||||
return "Microsoft Windows ME";
|
||||
}
|
||||
if (info.dwMajorVersion == 4) {
|
||||
return "Microsoft Windows unknown 95 family";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "Microsoft Windows <unknown>";
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchSystemWindows::getPlatformName() const
|
||||
{
|
||||
#ifdef _X86_
|
||||
if(isWOW64())
|
||||
return "x86 (WOW64)";
|
||||
else
|
||||
return "x86";
|
||||
#else
|
||||
#ifdef _AMD64_
|
||||
return "x64";
|
||||
#else
|
||||
return "Unknown";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchSystemWindows::setting(const std::string& valueName) const
|
||||
{
|
||||
HKEY key = CArchMiscWindows::openKey(HKEY_LOCAL_MACHINE, s_settingsKeyNames);
|
||||
if (key == NULL)
|
||||
return "";
|
||||
|
||||
return CArchMiscWindows::readValueString(key, valueName.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
CArchSystemWindows::setting(const std::string& valueName, const std::string& valueString) const
|
||||
{
|
||||
HKEY key = CArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_settingsKeyNames);
|
||||
if (key == NULL)
|
||||
throw XArch(std::string("could not access registry key: ") + valueName);
|
||||
CArchMiscWindows::setValue(key, valueName.c_str(), valueString.c_str());
|
||||
}
|
||||
|
||||
bool
|
||||
CArchSystemWindows::isWOW64() const
|
||||
{
|
||||
#if WINVER >= _WIN32_WINNT_WINXP
|
||||
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
|
||||
HMODULE hModule = GetModuleHandle(TEXT("kernel32"));
|
||||
if (!hModule) return FALSE;
|
||||
|
||||
LPFN_ISWOW64PROCESS fnIsWow64Process =
|
||||
(LPFN_ISWOW64PROCESS) GetProcAddress(hModule, "IsWow64Process");
|
||||
|
||||
BOOL bIsWow64 = FALSE;
|
||||
if(NULL != fnIsWow64Process &&
|
||||
fnIsWow64Process(GetCurrentProcess(), &bIsWow64) &&
|
||||
bIsWow64)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
40
src/lib/arch/CArchSystemWindows.h
Normal file
40
src/lib/arch/CArchSystemWindows.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHSYSTEMWINDOWS_H
|
||||
#define CARCHSYSTEMWINDOWS_H
|
||||
|
||||
#include "IArchSystem.h"
|
||||
|
||||
#define ARCH_SYSTEM CArchSystemWindows
|
||||
|
||||
//! Win32 implementation of IArchString
|
||||
class CArchSystemWindows : public IArchSystem {
|
||||
public:
|
||||
CArchSystemWindows();
|
||||
virtual ~CArchSystemWindows();
|
||||
|
||||
// IArchSystem overrides
|
||||
virtual std::string getOSName() const;
|
||||
virtual std::string getPlatformName() const;
|
||||
virtual std::string setting(const std::string& valueName) const;
|
||||
virtual void setting(const std::string& valueName, const std::string& valueString) const;
|
||||
|
||||
bool isWOW64() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
501
src/lib/arch/CArchTaskBarWindows.cpp
Normal file
501
src/lib/arch/CArchTaskBarWindows.cpp
Normal file
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchTaskBarWindows.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include "IArchTaskBarReceiver.h"
|
||||
#include "CArch.h"
|
||||
#include "XArch.h"
|
||||
#include <string.h>
|
||||
#include <shellapi.h>
|
||||
#include "CAppUtilWindows.h"
|
||||
|
||||
static const UINT kAddReceiver = WM_USER + 10;
|
||||
static const UINT kRemoveReceiver = WM_USER + 11;
|
||||
static const UINT kUpdateReceiver = WM_USER + 12;
|
||||
static const UINT kNotifyReceiver = WM_USER + 13;
|
||||
static const UINT kFirstReceiverID = WM_USER + 14;
|
||||
|
||||
//
|
||||
// CArchTaskBarWindows
|
||||
//
|
||||
|
||||
CArchTaskBarWindows* CArchTaskBarWindows::s_instance = NULL;
|
||||
|
||||
CArchTaskBarWindows::CArchTaskBarWindows() :
|
||||
m_nextID(kFirstReceiverID)
|
||||
{
|
||||
// save the singleton instance
|
||||
s_instance = this;
|
||||
}
|
||||
|
||||
CArchTaskBarWindows::~CArchTaskBarWindows()
|
||||
{
|
||||
if (m_thread != NULL) {
|
||||
PostMessage(m_hwnd, WM_QUIT, 0, 0);
|
||||
ARCH->wait(m_thread, -1.0);
|
||||
ARCH->closeThread(m_thread);
|
||||
}
|
||||
ARCH->closeCondVar(m_condVar);
|
||||
ARCH->closeMutex(m_mutex);
|
||||
s_instance = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::init()
|
||||
{
|
||||
// we need a mutex
|
||||
m_mutex = ARCH->newMutex();
|
||||
|
||||
// and a condition variable which uses the above mutex
|
||||
m_ready = false;
|
||||
m_condVar = ARCH->newCondVar();
|
||||
|
||||
// we're going to want to get a result from the thread we're
|
||||
// about to create to know if it initialized successfully.
|
||||
// so we lock the condition variable.
|
||||
ARCH->lockMutex(m_mutex);
|
||||
|
||||
// open a window and run an event loop in a separate thread.
|
||||
// this has to happen in a separate thread because if we
|
||||
// create a window on the current desktop with the current
|
||||
// thread then the current thread won't be able to switch
|
||||
// desktops if it needs to.
|
||||
m_thread = ARCH->newThread(&CArchTaskBarWindows::threadEntry, this);
|
||||
|
||||
// wait for child thread
|
||||
while (!m_ready) {
|
||||
ARCH->waitCondVar(m_condVar, m_mutex, -1.0);
|
||||
}
|
||||
|
||||
// ready
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::addDialog(HWND hwnd)
|
||||
{
|
||||
CArchMiscWindows::addDialog(hwnd);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::removeDialog(HWND hwnd)
|
||||
{
|
||||
CArchMiscWindows::removeDialog(hwnd);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver)
|
||||
{
|
||||
// ignore bogus receiver
|
||||
if (receiver == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add receiver if necessary
|
||||
CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
|
||||
if (index == m_receivers.end()) {
|
||||
// add it, creating a new message ID for it
|
||||
CReceiverInfo info;
|
||||
info.m_id = getNextID();
|
||||
index = m_receivers.insert(std::make_pair(receiver, info)).first;
|
||||
|
||||
// add ID to receiver mapping
|
||||
m_idTable.insert(std::make_pair(info.m_id, index));
|
||||
}
|
||||
|
||||
// add receiver
|
||||
PostMessage(m_hwnd, kAddReceiver, index->second.m_id, 0);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::removeReceiver(IArchTaskBarReceiver* receiver)
|
||||
{
|
||||
// find receiver
|
||||
CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
|
||||
if (index == m_receivers.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove icon. wait for this to finish before returning.
|
||||
SendMessage(m_hwnd, kRemoveReceiver, index->second.m_id, 0);
|
||||
|
||||
// recycle the ID
|
||||
recycleID(index->second.m_id);
|
||||
|
||||
// discard
|
||||
m_idTable.erase(index->second.m_id);
|
||||
m_receivers.erase(index);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::updateReceiver(IArchTaskBarReceiver* receiver)
|
||||
{
|
||||
// find receiver
|
||||
CReceiverToInfoMap::const_iterator index = m_receivers.find(receiver);
|
||||
if (index == m_receivers.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update icon and tool tip
|
||||
PostMessage(m_hwnd, kUpdateReceiver, index->second.m_id, 0);
|
||||
}
|
||||
|
||||
UINT
|
||||
CArchTaskBarWindows::getNextID()
|
||||
{
|
||||
if (m_oldIDs.empty()) {
|
||||
return m_nextID++;
|
||||
}
|
||||
UINT id = m_oldIDs.back();
|
||||
m_oldIDs.pop_back();
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::recycleID(UINT id)
|
||||
{
|
||||
m_oldIDs.push_back(id);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::addIcon(UINT id)
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
CIDToReceiverMap::const_iterator index = m_idTable.find(id);
|
||||
if (index != m_idTable.end()) {
|
||||
modifyIconNoLock(index->second, NIM_ADD);
|
||||
}
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::removeIcon(UINT id)
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
removeIconNoLock(id);
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::updateIcon(UINT id)
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
CIDToReceiverMap::const_iterator index = m_idTable.find(id);
|
||||
if (index != m_idTable.end()) {
|
||||
modifyIconNoLock(index->second, NIM_MODIFY);
|
||||
}
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::addAllIcons()
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
|
||||
index != m_receivers.end(); ++index) {
|
||||
modifyIconNoLock(index, NIM_ADD);
|
||||
}
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::removeAllIcons()
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
|
||||
index != m_receivers.end(); ++index) {
|
||||
removeIconNoLock(index->second.m_id);
|
||||
}
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::modifyIconNoLock(
|
||||
CReceiverToInfoMap::const_iterator index, DWORD taskBarMessage)
|
||||
{
|
||||
// get receiver
|
||||
UINT id = index->second.m_id;
|
||||
IArchTaskBarReceiver* receiver = index->first;
|
||||
|
||||
// lock receiver so icon and tool tip are guaranteed to be consistent
|
||||
receiver->lock();
|
||||
|
||||
// get icon data
|
||||
HICON icon = reinterpret_cast<HICON>(
|
||||
const_cast<IArchTaskBarReceiver::Icon>(receiver->getIcon()));
|
||||
|
||||
// get tool tip
|
||||
std::string toolTip = receiver->getToolTip();
|
||||
|
||||
// done querying
|
||||
receiver->unlock();
|
||||
|
||||
// prepare to add icon
|
||||
NOTIFYICONDATA data;
|
||||
data.cbSize = sizeof(NOTIFYICONDATA);
|
||||
data.hWnd = m_hwnd;
|
||||
data.uID = id;
|
||||
data.uFlags = NIF_MESSAGE;
|
||||
data.uCallbackMessage = kNotifyReceiver;
|
||||
data.hIcon = icon;
|
||||
if (icon != NULL) {
|
||||
data.uFlags |= NIF_ICON;
|
||||
}
|
||||
if (!toolTip.empty()) {
|
||||
strncpy(data.szTip, toolTip.c_str(), sizeof(data.szTip));
|
||||
data.szTip[sizeof(data.szTip) - 1] = '\0';
|
||||
data.uFlags |= NIF_TIP;
|
||||
}
|
||||
else {
|
||||
data.szTip[0] = '\0';
|
||||
}
|
||||
|
||||
// add icon
|
||||
if (Shell_NotifyIcon(taskBarMessage, &data) == 0) {
|
||||
// failed
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::removeIconNoLock(UINT id)
|
||||
{
|
||||
NOTIFYICONDATA data;
|
||||
data.cbSize = sizeof(NOTIFYICONDATA);
|
||||
data.hWnd = m_hwnd;
|
||||
data.uID = id;
|
||||
if (Shell_NotifyIcon(NIM_DELETE, &data) == 0) {
|
||||
// failed
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::handleIconMessage(
|
||||
IArchTaskBarReceiver* receiver, LPARAM lParam)
|
||||
{
|
||||
// process message
|
||||
switch (lParam) {
|
||||
case WM_LBUTTONDOWN:
|
||||
receiver->showStatus();
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDBLCLK:
|
||||
receiver->primaryAction();
|
||||
break;
|
||||
|
||||
case WM_RBUTTONUP: {
|
||||
POINT p;
|
||||
GetCursorPos(&p);
|
||||
receiver->runMenu(p.x, p.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
// currently unused
|
||||
break;
|
||||
|
||||
default:
|
||||
// unused
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CArchTaskBarWindows::processDialogs(MSG* msg)
|
||||
{
|
||||
// only one thread can be in this method on any particular object
|
||||
// at any given time. that's not a problem since only our event
|
||||
// loop calls this method and there's just one of those.
|
||||
|
||||
ARCH->lockMutex(m_mutex);
|
||||
|
||||
// remove removed dialogs
|
||||
m_dialogs.erase(false);
|
||||
|
||||
// merge added dialogs into the dialog list
|
||||
for (CDialogs::const_iterator index = m_addedDialogs.begin();
|
||||
index != m_addedDialogs.end(); ++index) {
|
||||
m_dialogs.insert(std::make_pair(index->first, index->second));
|
||||
}
|
||||
m_addedDialogs.clear();
|
||||
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
|
||||
// check message against all dialogs until one handles it.
|
||||
// note that we don't hold a lock while checking because
|
||||
// the message is processed and may make calls to this
|
||||
// object. that's okay because addDialog() and
|
||||
// removeDialog() don't change the map itself (just the
|
||||
// values of some elements).
|
||||
ARCH->lockMutex(m_mutex);
|
||||
for (CDialogs::const_iterator index = m_dialogs.begin();
|
||||
index != m_dialogs.end(); ++index) {
|
||||
if (index->second) {
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
if (IsDialogMessage(index->first, msg)) {
|
||||
return true;
|
||||
}
|
||||
ARCH->lockMutex(m_mutex);
|
||||
}
|
||||
}
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LRESULT
|
||||
CArchTaskBarWindows::wndProc(HWND hwnd,
|
||||
UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg) {
|
||||
case kNotifyReceiver: {
|
||||
// lookup receiver
|
||||
CIDToReceiverMap::const_iterator index = m_idTable.find((UINT)wParam);
|
||||
if (index != m_idTable.end()) {
|
||||
IArchTaskBarReceiver* receiver = index->second->first;
|
||||
handleIconMessage(receiver, lParam);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kAddReceiver:
|
||||
addIcon((UINT)wParam);
|
||||
break;
|
||||
|
||||
case kRemoveReceiver:
|
||||
removeIcon((UINT)wParam);
|
||||
break;
|
||||
|
||||
case kUpdateReceiver:
|
||||
updateIcon((UINT)wParam);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (msg == m_taskBarRestart) {
|
||||
// task bar was recreated so re-add our icons
|
||||
addAllIcons();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK
|
||||
CArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// if msg is WM_NCCREATE, extract the CArchTaskBarWindows* and put
|
||||
// it in the extra window data then forward the call.
|
||||
CArchTaskBarWindows* self = NULL;
|
||||
if (msg == WM_NCCREATE) {
|
||||
CREATESTRUCT* createInfo;
|
||||
createInfo = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||
self = reinterpret_cast<CArchTaskBarWindows*>(
|
||||
createInfo->lpCreateParams);
|
||||
SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(self));
|
||||
}
|
||||
else {
|
||||
// get the extra window data and forward the call
|
||||
LONG data = GetWindowLong(hwnd, 0);
|
||||
if (data != 0) {
|
||||
self = reinterpret_cast<CArchTaskBarWindows*>(
|
||||
reinterpret_cast<void*>(data));
|
||||
}
|
||||
}
|
||||
|
||||
// forward the message
|
||||
if (self != NULL) {
|
||||
return self->wndProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
else {
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::threadMainLoop()
|
||||
{
|
||||
// register the task bar restart message
|
||||
m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
||||
|
||||
// register a window class
|
||||
WNDCLASSEX classInfo;
|
||||
classInfo.cbSize = sizeof(classInfo);
|
||||
classInfo.style = CS_NOCLOSE;
|
||||
classInfo.lpfnWndProc = &CArchTaskBarWindows::staticWndProc;
|
||||
classInfo.cbClsExtra = 0;
|
||||
classInfo.cbWndExtra = sizeof(CArchTaskBarWindows*);
|
||||
classInfo.hInstance = instanceWin32();
|
||||
classInfo.hIcon = NULL;
|
||||
classInfo.hCursor = NULL;
|
||||
classInfo.hbrBackground = NULL;
|
||||
classInfo.lpszMenuName = NULL;
|
||||
classInfo.lpszClassName = TEXT("SynergyTaskBar");
|
||||
classInfo.hIconSm = NULL;
|
||||
ATOM windowClass = RegisterClassEx(&classInfo);
|
||||
|
||||
// create window
|
||||
m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW,
|
||||
reinterpret_cast<LPCTSTR>(windowClass),
|
||||
TEXT("Synergy Task Bar"),
|
||||
WS_POPUP,
|
||||
0, 0, 1, 1,
|
||||
NULL,
|
||||
NULL,
|
||||
instanceWin32(),
|
||||
reinterpret_cast<void*>(this));
|
||||
|
||||
// signal ready
|
||||
ARCH->lockMutex(m_mutex);
|
||||
m_ready = true;
|
||||
ARCH->broadcastCondVar(m_condVar);
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
|
||||
// handle failure
|
||||
if (m_hwnd == NULL) {
|
||||
UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), instanceWin32());
|
||||
return;
|
||||
}
|
||||
|
||||
// main loop
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
if (!processDialogs(&msg)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
removeAllIcons();
|
||||
DestroyWindow(m_hwnd);
|
||||
UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), instanceWin32());
|
||||
}
|
||||
|
||||
void*
|
||||
CArchTaskBarWindows::threadEntry(void* self)
|
||||
{
|
||||
reinterpret_cast<CArchTaskBarWindows*>(self)->threadMainLoop();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HINSTANCE CArchTaskBarWindows::instanceWin32()
|
||||
{
|
||||
return CArchMiscWindows::instanceWin32();
|
||||
}
|
||||
116
src/lib/arch/CArchTaskBarWindows.h
Normal file
116
src/lib/arch/CArchTaskBarWindows.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHTASKBARWINDOWS_H
|
||||
#define CARCHTASKBARWINDOWS_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include "IArchTaskBar.h"
|
||||
#include "IArchMultithread.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
#include <windows.h>
|
||||
|
||||
#define ARCH_TASKBAR CArchTaskBarWindows
|
||||
|
||||
//! Win32 implementation of IArchTaskBar
|
||||
class CArchTaskBarWindows : public IArchTaskBar {
|
||||
public:
|
||||
CArchTaskBarWindows();
|
||||
virtual ~CArchTaskBarWindows();
|
||||
|
||||
virtual void init();
|
||||
|
||||
//! Add a dialog window
|
||||
/*!
|
||||
Tell the task bar event loop about a dialog. Win32 annoyingly
|
||||
requires messages destined for modeless dialog boxes to be
|
||||
dispatched differently than other messages.
|
||||
*/
|
||||
static void addDialog(HWND);
|
||||
|
||||
//! Remove a dialog window
|
||||
/*!
|
||||
Remove a dialog window added via \c addDialog().
|
||||
*/
|
||||
static void removeDialog(HWND);
|
||||
|
||||
// IArchTaskBar overrides
|
||||
virtual void addReceiver(IArchTaskBarReceiver*);
|
||||
virtual void removeReceiver(IArchTaskBarReceiver*);
|
||||
virtual void updateReceiver(IArchTaskBarReceiver*);
|
||||
|
||||
private:
|
||||
class CReceiverInfo {
|
||||
public:
|
||||
UINT m_id;
|
||||
};
|
||||
|
||||
typedef std::map<IArchTaskBarReceiver*, CReceiverInfo> CReceiverToInfoMap;
|
||||
typedef std::map<UINT, CReceiverToInfoMap::iterator> CIDToReceiverMap;
|
||||
typedef std::vector<UINT> CIDStack;
|
||||
typedef std::map<HWND, bool> CDialogs;
|
||||
|
||||
UINT getNextID();
|
||||
void recycleID(UINT);
|
||||
|
||||
void addIcon(UINT);
|
||||
void removeIcon(UINT);
|
||||
void updateIcon(UINT);
|
||||
void addAllIcons();
|
||||
void removeAllIcons();
|
||||
void modifyIconNoLock(CReceiverToInfoMap::const_iterator,
|
||||
DWORD taskBarMessage);
|
||||
void removeIconNoLock(UINT id);
|
||||
void handleIconMessage(IArchTaskBarReceiver*, LPARAM);
|
||||
|
||||
bool processDialogs(MSG*);
|
||||
LRESULT wndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
static LRESULT CALLBACK
|
||||
staticWndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
void threadMainLoop();
|
||||
static void* threadEntry(void*);
|
||||
|
||||
HINSTANCE instanceWin32();
|
||||
|
||||
private:
|
||||
static CArchTaskBarWindows* s_instance;
|
||||
|
||||
// multithread data
|
||||
CArchMutex m_mutex;
|
||||
CArchCond m_condVar;
|
||||
bool m_ready;
|
||||
int m_result;
|
||||
CArchThread m_thread;
|
||||
|
||||
// child thread data
|
||||
HWND m_hwnd;
|
||||
UINT m_taskBarRestart;
|
||||
|
||||
// shared data
|
||||
CReceiverToInfoMap m_receivers;
|
||||
CIDToReceiverMap m_idTable;
|
||||
CIDStack m_oldIDs;
|
||||
UINT m_nextID;
|
||||
|
||||
// dialogs
|
||||
CDialogs m_dialogs;
|
||||
CDialogs m_addedDialogs;
|
||||
};
|
||||
|
||||
#endif
|
||||
50
src/lib/arch/CArchTaskBarXWindows.cpp
Normal file
50
src/lib/arch/CArchTaskBarXWindows.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CArchTaskBarXWindows.h"
|
||||
|
||||
//
|
||||
// CArchTaskBarXWindows
|
||||
//
|
||||
|
||||
CArchTaskBarXWindows::CArchTaskBarXWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CArchTaskBarXWindows::~CArchTaskBarXWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarXWindows::addReceiver(IArchTaskBarReceiver* /*receiver*/)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarXWindows::removeReceiver(IArchTaskBarReceiver* /*receiver*/)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarXWindows::updateReceiver(IArchTaskBarReceiver* /*receiver*/)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
37
src/lib/arch/CArchTaskBarXWindows.h
Normal file
37
src/lib/arch/CArchTaskBarXWindows.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHTASKBARXWINDOWS_H
|
||||
#define CARCHTASKBARXWINDOWS_H
|
||||
|
||||
#include "IArchTaskBar.h"
|
||||
|
||||
#define ARCH_TASKBAR CArchTaskBarXWindows
|
||||
|
||||
//! X11 implementation of IArchTaskBar
|
||||
class CArchTaskBarXWindows : public IArchTaskBar {
|
||||
public:
|
||||
CArchTaskBarXWindows();
|
||||
virtual ~CArchTaskBarXWindows();
|
||||
|
||||
// IArchTaskBar overrides
|
||||
virtual void addReceiver(IArchTaskBarReceiver*);
|
||||
virtual void removeReceiver(IArchTaskBarReceiver*);
|
||||
virtual void updateReceiver(IArchTaskBarReceiver*);
|
||||
};
|
||||
|
||||
#endif
|
||||
50
src/lib/arch/CArchTimeUnix.cpp
Normal file
50
src/lib/arch/CArchTimeUnix.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "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;
|
||||
}
|
||||
35
src/lib/arch/CArchTimeUnix.h
Normal file
35
src/lib/arch/CArchTimeUnix.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHTIMEUNIX_H
|
||||
#define CARCHTIMEUNIX_H
|
||||
|
||||
#include "IArchTime.h"
|
||||
|
||||
#define ARCH_TIME CArchTimeUnix
|
||||
|
||||
//! Generic Unix implementation of IArchTime
|
||||
class CArchTimeUnix : public IArchTime {
|
||||
public:
|
||||
CArchTimeUnix();
|
||||
virtual ~CArchTimeUnix();
|
||||
|
||||
// IArchTime overrides
|
||||
virtual double time();
|
||||
};
|
||||
|
||||
#endif
|
||||
89
src/lib/arch/CArchTimeWindows.cpp
Normal file
89
src/lib/arch/CArchTimeWindows.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
35
src/lib/arch/CArchTimeWindows.h
Normal file
35
src/lib/arch/CArchTimeWindows.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CARCHTIMEWINDOWS_H
|
||||
#define CARCHTIMEWINDOWS_H
|
||||
|
||||
#include "IArchTime.h"
|
||||
|
||||
#define ARCH_TIME CArchTimeWindows
|
||||
|
||||
//! Win32 implementation of IArchTime
|
||||
class CArchTimeWindows : public IArchTime {
|
||||
public:
|
||||
CArchTimeWindows();
|
||||
virtual ~CArchTimeWindows();
|
||||
|
||||
// IArchTime overrides
|
||||
virtual double time();
|
||||
};
|
||||
|
||||
#endif
|
||||
111
src/lib/arch/CMakeLists.txt
Normal file
111
src/lib/arch/CMakeLists.txt
Normal file
@@ -0,0 +1,111 @@
|
||||
# synergy -- mouse and keyboard sharing utility
|
||||
# Copyright (C) 2009 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(src
|
||||
CArch.cpp
|
||||
IArchString.cpp
|
||||
XArch.cpp
|
||||
CArchConsoleStd.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
||||
set(inc
|
||||
CArchConsoleWindows.h
|
||||
CArchDaemonWindows.h
|
||||
CArchFileWindows.h
|
||||
CArchLogWindows.h
|
||||
CArchIpcLogWindows.h
|
||||
CArchMiscWindows.h
|
||||
CArchMultithreadWindows.h
|
||||
CArchNetworkWinsock.h
|
||||
CArchSleepWindows.h
|
||||
CArchStringWindows.h
|
||||
CArchSystemWindows.h
|
||||
CArchTaskBarWindows.h
|
||||
CArchTimeWindows.h
|
||||
CArchConsoleStd.h
|
||||
XArchWindows.h
|
||||
CMultibyte.h
|
||||
vsnprintf.h
|
||||
XArch.h
|
||||
IArchPlugin.h
|
||||
CArchPluginWindows.h
|
||||
)
|
||||
|
||||
list(APPEND src
|
||||
${inc}
|
||||
CArchConsoleWindows.cpp
|
||||
CArchDaemonWindows.cpp
|
||||
CArchFileWindows.cpp
|
||||
CArchLogWindows.cpp
|
||||
CArchIpcLogWindows.cpp
|
||||
CArchMiscWindows.cpp
|
||||
CArchMultithreadWindows.cpp
|
||||
CArchNetworkWinsock.cpp
|
||||
CArchSleepWindows.cpp
|
||||
CArchStringWindows.cpp
|
||||
CArchSystemWindows.cpp
|
||||
CArchTaskBarWindows.cpp
|
||||
CArchTimeWindows.cpp
|
||||
XArchWindows.cpp
|
||||
CArchPluginWindows.cpp
|
||||
)
|
||||
|
||||
elseif (UNIX)
|
||||
|
||||
list(APPEND src
|
||||
CArchConsoleUnix.cpp
|
||||
CArchDaemonUnix.cpp
|
||||
CArchFileUnix.cpp
|
||||
CArchLogUnix.cpp
|
||||
CArchIpcLogUnix.cpp
|
||||
CArchMultithreadPosix.cpp
|
||||
CArchNetworkBSD.cpp
|
||||
CArchSleepUnix.cpp
|
||||
CArchStringUnix.cpp
|
||||
CArchSystemUnix.cpp
|
||||
CArchTaskBarXWindows.cpp
|
||||
CArchTimeUnix.cpp
|
||||
XArchUnix.cpp
|
||||
CArchDaemonNone.cpp
|
||||
CArchPluginUnix.cpp
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
set(inc
|
||||
../base
|
||||
../common
|
||||
../mt
|
||||
../platform
|
||||
../synergy
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
list(APPEND inc
|
||||
../../..
|
||||
../arch
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(${inc})
|
||||
add_library(arch STATIC ${src})
|
||||
|
||||
if (WIN32)
|
||||
if (GAME_DEVICE_SUPPORT)
|
||||
target_link_libraries(arch synxinhk)
|
||||
endif()
|
||||
endif()
|
||||
57
src/lib/arch/CMultibyte.h
Normal file
57
src/lib/arch/CMultibyte.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CMULTIBYTE_H
|
||||
#define CMULTIBYTE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "CArch.h"
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#if HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
#endif
|
||||
#if HAVE_WCHAR_H || defined(_MSC_VER)
|
||||
# include <wchar.h>
|
||||
#elif __APPLE__
|
||||
// wtf? Darwin puts mbtowc() et al. in stdlib
|
||||
# include <cstdlib>
|
||||
#else
|
||||
// platform apparently has no wchar_t support. provide dummy
|
||||
// implementations. hopefully at least the C++ compiler has
|
||||
// a built-in wchar_t type.
|
||||
|
||||
static inline
|
||||
int
|
||||
mbtowc(wchar_t* dst, const char* src, int n)
|
||||
{
|
||||
*dst = static_cast<wchar_t>(*src);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline
|
||||
int
|
||||
wctomb(char* dst, wchar_t src)
|
||||
{
|
||||
*dst = static_cast<char>(src);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
68
src/lib/arch/IArchConsole.h
Normal file
68
src/lib/arch/IArchConsole.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHCONSOLE_H
|
||||
#define IARCHCONSOLE_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "ELevel.h"
|
||||
|
||||
//! Interface for architecture dependent console output
|
||||
/*!
|
||||
This interface defines the console operations required by
|
||||
synergy. Each architecture must implement this interface.
|
||||
*/
|
||||
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;
|
||||
|
||||
//! Show the console
|
||||
/*!
|
||||
Causes the console to become visible. This generally only makes sense
|
||||
for a console in a graphical user interface. Other implementations
|
||||
will do nothing. Iff \p showIfEmpty is \c false then the implementation
|
||||
may optionally only show the console if it's not empty.
|
||||
*/
|
||||
virtual void showConsole(bool showIfEmpty) = 0;
|
||||
|
||||
//! Write to the console
|
||||
/*!
|
||||
Writes the given string to the console, opening it if necessary.
|
||||
*/
|
||||
virtual void writeConsole(ELevel, const char*) = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
#endif
|
||||
131
src/lib/arch/IArchDaemon.h
Normal file
131
src/lib/arch/IArchDaemon.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHDAEMON_H
|
||||
#define IARCHDAEMON_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "CString.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. If \p dependencies is not NULL
|
||||
then it's a concatenation of NUL terminated other daemon names
|
||||
followed by a NUL; the daemon will be configured to startup after
|
||||
the listed daemons. Throws an \c XArchDaemon exception on failure.
|
||||
*/
|
||||
virtual void installDaemon(const char* name,
|
||||
const char* description,
|
||||
const char* pathname,
|
||||
const char* commandLine,
|
||||
const char* dependencies,
|
||||
bool allUsers) = 0;
|
||||
|
||||
//! Uninstall daemon
|
||||
/*!
|
||||
Uninstall a daemon. Throws an \c XArchDaemon on failure.
|
||||
*/
|
||||
virtual void uninstallDaemon(const char* name, bool allUsers) = 0;
|
||||
|
||||
//! Install daemon
|
||||
/*!
|
||||
Installs the default daemon.
|
||||
*/
|
||||
virtual void installDaemon() = 0;
|
||||
|
||||
//! Uninstall daemon
|
||||
/*!
|
||||
Uninstalls the default daemon.
|
||||
*/
|
||||
virtual void uninstallDaemon() = 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;
|
||||
|
||||
//@}
|
||||
|
||||
//! Get the command line
|
||||
/*!
|
||||
Gets the command line with which the application was started.
|
||||
*/
|
||||
virtual std::string commandLine() const = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
#endif
|
||||
67
src/lib/arch/IArchFile.h
Normal file
67
src/lib/arch/IArchFile.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHFILE_H
|
||||
#define IARCHFILE_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "stdstring.h"
|
||||
|
||||
//! Interface for architecture dependent file system operations
|
||||
/*!
|
||||
This interface defines the file system operations required by
|
||||
synergy. Each architecture must implement this interface.
|
||||
*/
|
||||
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
|
||||
65
src/lib/arch/IArchLog.h
Normal file
65
src/lib/arch/IArchLog.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHLOG_H
|
||||
#define IARCHLOG_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "ELevel.h"
|
||||
|
||||
//! Interface for architecture dependent logging
|
||||
/*!
|
||||
This interface defines the logging operations required by
|
||||
synergy. Each architecture must implement this interface.
|
||||
*/
|
||||
class IArchLog : public IInterface {
|
||||
public:
|
||||
//! @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;
|
||||
|
||||
//! Show the log
|
||||
/*!
|
||||
Causes the log to become visible. This generally only makes sense
|
||||
for a log in a graphical user interface. Other implementations
|
||||
will do nothing. Iff \p showIfEmpty is \c false then the implementation
|
||||
may optionally only show the log if it's not empty.
|
||||
*/
|
||||
virtual void showLog(bool showIfEmpty) = 0;
|
||||
|
||||
//! Write to the log
|
||||
/*!
|
||||
Writes the given string to the log with the given level.
|
||||
*/
|
||||
virtual void writeLog(ELevel, const char*) = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
#endif
|
||||
275
src/lib/arch/IArchMultithread.h
Normal file
275
src/lib/arch/IArchMultithread.h
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHMULTITHREAD_H
|
||||
#define IARCHMULTITHREAD_H
|
||||
|
||||
#include "IInterface.h"
|
||||
|
||||
/*!
|
||||
\class CArchCondImpl
|
||||
\brief Internal condition variable data.
|
||||
An architecture dependent type holding the necessary data for a
|
||||
condition variable.
|
||||
*/
|
||||
class CArchCondImpl;
|
||||
|
||||
/*!
|
||||
\var CArchCond
|
||||
\brief Opaque condition variable type.
|
||||
An opaque type representing a condition variable.
|
||||
*/
|
||||
typedef CArchCondImpl* CArchCond;
|
||||
|
||||
/*!
|
||||
\class CArchMutexImpl
|
||||
\brief Internal mutex data.
|
||||
An architecture dependent type holding the necessary data for a mutex.
|
||||
*/
|
||||
class CArchMutexImpl;
|
||||
|
||||
/*!
|
||||
\var CArchMutex
|
||||
\brief Opaque mutex type.
|
||||
An opaque type representing a mutex.
|
||||
*/
|
||||
typedef CArchMutexImpl* CArchMutex;
|
||||
|
||||
/*!
|
||||
\class CArchThreadImpl
|
||||
\brief Internal thread data.
|
||||
An architecture dependent type holding the necessary data for a thread.
|
||||
*/
|
||||
class CArchThreadImpl;
|
||||
|
||||
/*!
|
||||
\var CArchThread
|
||||
\brief Opaque thread type.
|
||||
An opaque type representing a thread.
|
||||
*/
|
||||
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:
|
||||
//! Type of thread entry point
|
||||
typedef void* (*ThreadFunc)(void*);
|
||||
//! Type of thread identifier
|
||||
typedef unsigned int ThreadID;
|
||||
//! Types of signals
|
||||
/*!
|
||||
Not all platforms support all signals. Unsupported signals are
|
||||
ignored.
|
||||
*/
|
||||
enum ESignal {
|
||||
kINTERRUPT, //!< Interrupt (e.g. Ctrl+C)
|
||||
kTERMINATE, //!< Terminate (e.g. Ctrl+Break)
|
||||
kHANGUP, //!< Hangup (SIGHUP)
|
||||
kUSER, //!< User (SIGUSR2)
|
||||
kNUM_SIGNALS
|
||||
};
|
||||
//! Type of signal handler function
|
||||
typedef void (*SignalFunc)(ESignal, void* userData);
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//
|
||||
// condition variable methods
|
||||
//
|
||||
|
||||
//! Create a condition variable
|
||||
/*!
|
||||
The condition variable is an opaque data type.
|
||||
*/
|
||||
virtual CArchCond newCondVar() = 0;
|
||||
|
||||
//! Destroy a condition variable
|
||||
virtual void closeCondVar(CArchCond) = 0;
|
||||
|
||||
//! Signal a condition variable
|
||||
/*!
|
||||
Signalling a condition variable releases one waiting thread.
|
||||
*/
|
||||
virtual void signalCondVar(CArchCond) = 0;
|
||||
|
||||
//! Broadcast a condition variable
|
||||
/*!
|
||||
Broadcasting a condition variable releases all waiting threads.
|
||||
*/
|
||||
virtual void broadcastCondVar(CArchCond) = 0;
|
||||
|
||||
//! Wait on a condition variable
|
||||
/*!
|
||||
Wait on a conditation variable for up to \c timeout seconds.
|
||||
If \c timeout is < 0 then there is no timeout. The mutex must
|
||||
be locked when this method is called. The mutex is unlocked
|
||||
during the wait and locked again before returning. Returns
|
||||
true if the condition variable was signalled and false on
|
||||
timeout.
|
||||
|
||||
(Cancellation point)
|
||||
*/
|
||||
virtual bool waitCondVar(CArchCond, CArchMutex, double timeout) = 0;
|
||||
|
||||
//
|
||||
// mutex methods
|
||||
//
|
||||
|
||||
//! Create a recursive mutex
|
||||
/*!
|
||||
Creates a recursive mutex. A thread may lock a recursive mutex
|
||||
when it already holds a lock on that mutex. The mutex is an
|
||||
opaque data type.
|
||||
*/
|
||||
virtual CArchMutex newMutex() = 0;
|
||||
|
||||
//! Destroy a mutex
|
||||
virtual void closeMutex(CArchMutex) = 0;
|
||||
|
||||
//! Lock a mutex
|
||||
virtual void lockMutex(CArchMutex) = 0;
|
||||
|
||||
//! Unlock a mutex
|
||||
virtual void unlockMutex(CArchMutex) = 0;
|
||||
|
||||
//
|
||||
// thread methods
|
||||
//
|
||||
|
||||
//! Start a new thread
|
||||
/*!
|
||||
Creates and starts a new thread, using \c func as the entry point
|
||||
and passing it \c userData. The thread is an opaque data type.
|
||||
*/
|
||||
virtual CArchThread newThread(ThreadFunc func, void* userData) = 0;
|
||||
|
||||
//! Get a reference to the calling thread
|
||||
/*!
|
||||
Returns a thread representing the current (i.e. calling) thread.
|
||||
*/
|
||||
virtual CArchThread newCurrentThread() = 0;
|
||||
|
||||
//! Copy a thread object
|
||||
/*!
|
||||
Returns a reference to to thread referred to by \c thread.
|
||||
*/
|
||||
virtual CArchThread copyThread(CArchThread thread) = 0;
|
||||
|
||||
//! Release a thread reference
|
||||
/*!
|
||||
Deletes the given thread object. This does not destroy the thread
|
||||
the object referred to, even if there are no remaining references.
|
||||
Use cancelThread() and waitThread() to stop a thread and wait for
|
||||
it to exit.
|
||||
*/
|
||||
virtual void closeThread(CArchThread) = 0;
|
||||
|
||||
//! Force a thread to exit
|
||||
/*!
|
||||
Causes \c thread to exit when it next calls a cancellation point.
|
||||
A thread avoids cancellation as long as it nevers calls a
|
||||
cancellation point. Once it begins the cancellation process it
|
||||
must always let cancellation go to completion but may take as
|
||||
long as necessary to clean up.
|
||||
*/
|
||||
virtual void cancelThread(CArchThread thread) = 0;
|
||||
|
||||
//! Change thread priority
|
||||
/*!
|
||||
Changes the priority of \c thread by \c n. If \c n is positive
|
||||
the thread has a lower priority and if negative a higher priority.
|
||||
Some architectures may not support either or both directions.
|
||||
*/
|
||||
virtual void setPriorityOfThread(CArchThread, int n) = 0;
|
||||
|
||||
//! Cancellation point
|
||||
/*!
|
||||
This method does nothing but is a cancellation point. Clients
|
||||
can make their own functions cancellation points by calling this
|
||||
method at appropriate times.
|
||||
|
||||
(Cancellation point)
|
||||
*/
|
||||
virtual void testCancelThread() = 0;
|
||||
|
||||
//! Wait for a thread to exit
|
||||
/*!
|
||||
Waits for up to \c timeout seconds for \c thread to exit (normally
|
||||
or by cancellation). Waits forever if \c timeout < 0. Returns
|
||||
true if the thread exited, false otherwise. Waiting on the current
|
||||
thread returns immediately with false.
|
||||
|
||||
(Cancellation point)
|
||||
*/
|
||||
virtual bool wait(CArchThread thread, double timeout) = 0;
|
||||
|
||||
//! Compare threads
|
||||
/*!
|
||||
Returns true iff two thread objects refer to the same thread.
|
||||
Note that comparing thread objects directly is meaningless.
|
||||
*/
|
||||
virtual bool isSameThread(CArchThread, CArchThread) = 0;
|
||||
|
||||
//! Test if thread exited
|
||||
/*!
|
||||
Returns true iff \c thread has exited.
|
||||
*/
|
||||
virtual bool isExitedThread(CArchThread thread) = 0;
|
||||
|
||||
//! Returns the exit code of a thread
|
||||
/*!
|
||||
Waits indefinitely for \c thread to exit (if it hasn't yet) then
|
||||
returns the thread's exit code.
|
||||
|
||||
(Cancellation point)
|
||||
*/
|
||||
virtual void* getResultOfThread(CArchThread thread) = 0;
|
||||
|
||||
//! Returns an ID for a thread
|
||||
/*!
|
||||
Returns some ID number for \c thread. This is for logging purposes.
|
||||
All thread objects referring to the same thread return the same ID.
|
||||
However, clients should us isSameThread() to compare thread objects
|
||||
instead of comparing IDs.
|
||||
*/
|
||||
virtual ThreadID getIDOfThread(CArchThread thread) = 0;
|
||||
|
||||
//! Set the interrupt handler
|
||||
/*!
|
||||
Sets the function to call on receipt of an external interrupt.
|
||||
By default and when \p func is NULL, the main thread is cancelled.
|
||||
*/
|
||||
virtual void setSignalHandler(ESignal, SignalFunc func,
|
||||
void* userData) = 0;
|
||||
|
||||
//! Invoke the signal handler
|
||||
/*!
|
||||
Invokes the signal handler for \p signal, if any. If no handler
|
||||
cancels the main thread for \c kINTERRUPT and \c kTERMINATE and
|
||||
ignores the call otherwise.
|
||||
*/
|
||||
virtual void raiseSignal(ESignal signal) = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
#endif
|
||||
284
src/lib/arch/IArchNetwork.h
Normal file
284
src/lib/arch/IArchNetwork.h
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHNETWORK_H
|
||||
#define IARCHNETWORK_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "stdstring.h"
|
||||
|
||||
class CArchThreadImpl;
|
||||
typedef CArchThreadImpl* CArchThread;
|
||||
|
||||
/*!
|
||||
\class CArchSocketImpl
|
||||
\brief Internal socket data.
|
||||
An architecture dependent type holding the necessary data for a socket.
|
||||
*/
|
||||
class CArchSocketImpl;
|
||||
|
||||
/*!
|
||||
\var CArchSocket
|
||||
\brief Opaque socket type.
|
||||
An opaque type representing a socket.
|
||||
*/
|
||||
typedef CArchSocketImpl* CArchSocket;
|
||||
|
||||
/*!
|
||||
\class CArchNetAddressImpl
|
||||
\brief Internal network address data.
|
||||
An architecture dependent type holding the necessary data for a network
|
||||
address.
|
||||
*/
|
||||
class CArchNetAddressImpl;
|
||||
|
||||
/*!
|
||||
\var CArchNetAddress
|
||||
\brief Opaque network address type.
|
||||
An opaque type representing a network address.
|
||||
*/
|
||||
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:
|
||||
//! Supported address families
|
||||
enum EAddressFamily {
|
||||
kUNKNOWN,
|
||||
kINET,
|
||||
};
|
||||
|
||||
//! Supported socket types
|
||||
enum ESocketType {
|
||||
kDGRAM,
|
||||
kSTREAM
|
||||
};
|
||||
|
||||
//! Events for \c poll()
|
||||
/*!
|
||||
Events for \c poll() are bitmasks and can be combined using the
|
||||
bitwise operators.
|
||||
*/
|
||||
enum {
|
||||
kPOLLIN = 1, //!< Socket is readable
|
||||
kPOLLOUT = 2, //!< Socket is writable
|
||||
kPOLLERR = 4, //!< The socket is in an error state
|
||||
kPOLLNVAL = 8 //!< The socket is invalid
|
||||
};
|
||||
|
||||
//! A socket query for \c poll()
|
||||
class CPollEntry {
|
||||
public:
|
||||
//! The socket to query
|
||||
CArchSocket m_socket;
|
||||
|
||||
//! The events to query for
|
||||
/*!
|
||||
The events to query for can be any combination of kPOLLIN and
|
||||
kPOLLOUT.
|
||||
*/
|
||||
unsigned short m_events;
|
||||
|
||||
//! The result events
|
||||
unsigned short m_revents;
|
||||
};
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Create a new socket
|
||||
/*!
|
||||
The socket is an opaque data type.
|
||||
*/
|
||||
virtual CArchSocket newSocket(EAddressFamily, ESocketType) = 0;
|
||||
|
||||
//! Copy a socket object
|
||||
/*!
|
||||
Returns a reference to to socket referred to by \c s.
|
||||
*/
|
||||
virtual CArchSocket copySocket(CArchSocket s) = 0;
|
||||
|
||||
//! Release a socket reference
|
||||
/*!
|
||||
Deletes the given socket object. This does not destroy the socket
|
||||
the object referred to until there are no remaining references for
|
||||
the socket.
|
||||
*/
|
||||
virtual void closeSocket(CArchSocket s) = 0;
|
||||
|
||||
//! Close socket for further reads
|
||||
/*!
|
||||
Calling this disallows future reads on socket \c s.
|
||||
*/
|
||||
virtual void closeSocketForRead(CArchSocket s) = 0;
|
||||
|
||||
//! Close socket for further writes
|
||||
/*!
|
||||
Calling this disallows future writes on socket \c s.
|
||||
*/
|
||||
virtual void closeSocketForWrite(CArchSocket s) = 0;
|
||||
|
||||
//! Bind socket to address
|
||||
/*!
|
||||
Binds socket \c s to the address \c addr.
|
||||
*/
|
||||
virtual void bindSocket(CArchSocket s, CArchNetAddress addr) = 0;
|
||||
|
||||
//! Listen for connections on socket
|
||||
/*!
|
||||
Causes the socket \c s to begin listening for incoming connections.
|
||||
*/
|
||||
virtual void listenOnSocket(CArchSocket s) = 0;
|
||||
|
||||
//! Accept connection on socket
|
||||
/*!
|
||||
Accepts a connection on socket \c s, returning a new socket for the
|
||||
connection and filling in \c addr with the address of the remote
|
||||
end. \c addr may be NULL if the remote address isn't required.
|
||||
The original socket \c s is unaffected and remains in the listening
|
||||
state. The new socket shares most of the properties of \c s except
|
||||
it's not in the listening state and it's connected. Returns NULL
|
||||
if there are no pending connection requests.
|
||||
*/
|
||||
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr) = 0;
|
||||
|
||||
//! Connect socket
|
||||
/*!
|
||||
Connects the socket \c s to the remote address \c addr. Returns
|
||||
true if the connection succeed immediately, false if the connection
|
||||
is in progress, and throws if the connection failed immediately.
|
||||
If it returns false, \c pollSocket() can be used to wait on the
|
||||
socket for writing to detect when the connection finally succeeds
|
||||
or fails.
|
||||
*/
|
||||
virtual bool connectSocket(CArchSocket s, CArchNetAddress addr) = 0;
|
||||
|
||||
//! Check socket state
|
||||
/*!
|
||||
Tests the state of \c num sockets for readability and/or writability.
|
||||
Waits up to \c timeout seconds for some socket to become readable
|
||||
and/or writable (or indefinitely if \c timeout < 0). Returns the
|
||||
number of sockets that were readable (if readability was being
|
||||
queried) or writable (if writablility was being queried) and sets
|
||||
the \c m_revents members of the entries. \c kPOLLERR and \c kPOLLNVAL
|
||||
are set in \c m_revents as appropriate. If a socket indicates
|
||||
\c kPOLLERR then \c throwErrorOnSocket() can be used to determine
|
||||
the type of error. Returns 0 immediately regardless of the \c timeout
|
||||
if no valid sockets are selected for testing.
|
||||
|
||||
(Cancellation point)
|
||||
*/
|
||||
virtual int pollSocket(CPollEntry[], int num, double timeout) = 0;
|
||||
|
||||
//! Unblock thread in pollSocket()
|
||||
/*!
|
||||
Cause a thread that's in a pollSocket() call to return. This
|
||||
call may return before the thread is unblocked. If the thread is
|
||||
not in a pollSocket() call this call has no effect.
|
||||
*/
|
||||
virtual void unblockPollSocket(CArchThread thread) = 0;
|
||||
|
||||
//! Read data from socket
|
||||
/*!
|
||||
Read up to \c len bytes from socket \c s in \c buf and return the
|
||||
number of bytes read. The number of bytes can be less than \c len
|
||||
if not enough data is available. Returns 0 if the remote end has
|
||||
disconnected and/or there is no more queued received data.
|
||||
*/
|
||||
virtual size_t readSocket(CArchSocket s, void* buf, size_t len) = 0;
|
||||
|
||||
//! Write data from socket
|
||||
/*!
|
||||
Write up to \c len bytes to socket \c s from \c buf and return the
|
||||
number of bytes written. The number of bytes can be less than
|
||||
\c len if the remote end disconnected or the internal buffers fill
|
||||
up.
|
||||
*/
|
||||
virtual size_t writeSocket(CArchSocket s,
|
||||
const void* buf, size_t len) = 0;
|
||||
|
||||
//! Check error on socket
|
||||
/*!
|
||||
If the socket \c s is in an error state then throws an appropriate
|
||||
XArchNetwork exception.
|
||||
*/
|
||||
virtual void throwErrorOnSocket(CArchSocket s) = 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;
|
||||
|
||||
//! Turn address reuse on or off on socket
|
||||
/*!
|
||||
Allows the address this socket is bound to to be reused while in the
|
||||
TIME_WAIT state. Returns the previous state.
|
||||
*/
|
||||
virtual bool setReuseAddrOnSocket(CArchSocket, bool reuse) = 0;
|
||||
|
||||
//! Return local host's name
|
||||
virtual std::string getHostName() = 0;
|
||||
|
||||
//! Create an "any" network address
|
||||
virtual CArchNetAddress newAnyAddr(EAddressFamily) = 0;
|
||||
|
||||
//! Copy a network address
|
||||
virtual CArchNetAddress copyAddr(CArchNetAddress) = 0;
|
||||
|
||||
//! Convert a name to a network address
|
||||
virtual CArchNetAddress nameToAddr(const std::string&) = 0;
|
||||
|
||||
//! Destroy a network address
|
||||
virtual void closeAddr(CArchNetAddress) = 0;
|
||||
|
||||
//! Convert an address to a host name
|
||||
virtual std::string addrToName(CArchNetAddress) = 0;
|
||||
|
||||
//! Convert an address to a string
|
||||
virtual std::string addrToString(CArchNetAddress) = 0;
|
||||
|
||||
//! Get an address's family
|
||||
virtual EAddressFamily getAddrFamily(CArchNetAddress) = 0;
|
||||
|
||||
//! Set the port of an address
|
||||
virtual void setAddrPort(CArchNetAddress, int port) = 0;
|
||||
|
||||
//! Get the port of an address
|
||||
virtual int getAddrPort(CArchNetAddress) = 0;
|
||||
|
||||
//! Test addresses for equality
|
||||
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress) = 0;
|
||||
|
||||
//! Test for the "any" address
|
||||
/*!
|
||||
Returns true if \c addr is the "any" address. \c newAnyAddr()
|
||||
returns an "any" address.
|
||||
*/
|
||||
virtual bool isAnyAddr(CArchNetAddress addr) = 0;
|
||||
|
||||
//@}
|
||||
|
||||
virtual void init() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
41
src/lib/arch/IArchPlugin.h
Normal file
41
src/lib/arch/IArchPlugin.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define PLUGINS_DIR "plugins"
|
||||
|
||||
#include "IInterface.h"
|
||||
|
||||
//! Interface for plugin manager.
|
||||
/*!
|
||||
A plugin manager should load all 3rd party plugins from the plugins dir,
|
||||
and then look for common function names in the plugins.
|
||||
*/
|
||||
class IArchPlugin : public IInterface {
|
||||
public:
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Load plugins
|
||||
/*!
|
||||
Scan the plugins dir and load plugins.
|
||||
*/
|
||||
virtual void init(void* eventTarget) = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
46
src/lib/arch/IArchSleep.h
Normal file
46
src/lib/arch/IArchSleep.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHSLEEP_H
|
||||
#define IARCHSLEEP_H
|
||||
|
||||
#include "IInterface.h"
|
||||
|
||||
//! Interface for architecture dependent sleeping
|
||||
/*!
|
||||
This interface defines the sleep operations required by
|
||||
synergy. Each architecture must implement this interface.
|
||||
*/
|
||||
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
|
||||
187
src/lib/arch/IArchString.cpp
Normal file
187
src/lib/arch/IArchString.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2011 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "IArchString.h"
|
||||
#include "common.h"
|
||||
#include "CArch.h"
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
static CArchMutex s_mutex = NULL;
|
||||
|
||||
//
|
||||
// use C library non-reentrant multibyte conversion with mutex
|
||||
//
|
||||
|
||||
IArchString::~IArchString()
|
||||
{
|
||||
if (s_mutex != NULL) {
|
||||
ARCH->closeMutex(s_mutex);
|
||||
s_mutex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
IArchString::convStringWCToMB(char* dst,
|
||||
const wchar_t* src, UInt32 n, bool* errors)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
bool dummyErrors;
|
||||
if (errors == NULL) {
|
||||
errors = &dummyErrors;
|
||||
}
|
||||
|
||||
if (s_mutex == NULL) {
|
||||
s_mutex = ARCH->newMutex();
|
||||
}
|
||||
|
||||
ARCH->lockMutex(s_mutex);
|
||||
|
||||
if (dst == NULL) {
|
||||
char dummy[MB_LEN_MAX];
|
||||
for (const wchar_t* scan = src; n > 0; ++scan, --n) {
|
||||
int mblen = wctomb(dummy, *scan);
|
||||
if (mblen == -1) {
|
||||
*errors = true;
|
||||
mblen = 1;
|
||||
}
|
||||
len += mblen;
|
||||
}
|
||||
int mblen = wctomb(dummy, L'\0');
|
||||
if (mblen != -1) {
|
||||
len += mblen - 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
char* dst0 = dst;
|
||||
for (const wchar_t* scan = src; n > 0; ++scan, --n) {
|
||||
int mblen = wctomb(dst, *scan);
|
||||
if (mblen == -1) {
|
||||
*errors = true;
|
||||
*dst++ = '?';
|
||||
}
|
||||
else {
|
||||
dst += mblen;
|
||||
}
|
||||
}
|
||||
int mblen = wctomb(dst, L'\0');
|
||||
if (mblen != -1) {
|
||||
// don't include nul terminator
|
||||
dst += mblen - 1;
|
||||
}
|
||||
len = (int)(dst - dst0);
|
||||
}
|
||||
ARCH->unlockMutex(s_mutex);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
IArchString::convStringMBToWC(wchar_t* dst,
|
||||
const char* src, UInt32 n, bool* errors)
|
||||
{
|
||||
int len = 0;
|
||||
wchar_t dummy;
|
||||
|
||||
bool dummyErrors;
|
||||
if (errors == NULL) {
|
||||
errors = &dummyErrors;
|
||||
}
|
||||
|
||||
if (s_mutex == NULL) {
|
||||
s_mutex = ARCH->newMutex();
|
||||
}
|
||||
|
||||
ARCH->lockMutex(s_mutex);
|
||||
|
||||
if (dst == NULL) {
|
||||
for (const char* scan = src; n > 0; ) {
|
||||
int mblen = mbtowc(&dummy, scan, n);
|
||||
switch (mblen) {
|
||||
case -2:
|
||||
// incomplete last character. convert to unknown character.
|
||||
*errors = true;
|
||||
len += 1;
|
||||
n = 0;
|
||||
break;
|
||||
|
||||
case -1:
|
||||
// invalid character. count one unknown character and
|
||||
// start at the next byte.
|
||||
*errors = true;
|
||||
len += 1;
|
||||
scan += 1;
|
||||
n -= 1;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
len += 1;
|
||||
scan += 1;
|
||||
n -= 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
// normal character
|
||||
len += 1;
|
||||
scan += mblen;
|
||||
n -= mblen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
wchar_t* dst0 = dst;
|
||||
for (const char* scan = src; n > 0; ++dst) {
|
||||
int mblen = mbtowc(dst, scan, n);
|
||||
switch (mblen) {
|
||||
case -2:
|
||||
// incomplete character. convert to unknown character.
|
||||
*errors = true;
|
||||
*dst = (wchar_t)0xfffd;
|
||||
n = 0;
|
||||
break;
|
||||
|
||||
case -1:
|
||||
// invalid character. count one unknown character and
|
||||
// start at the next byte.
|
||||
*errors = true;
|
||||
*dst = (wchar_t)0xfffd;
|
||||
scan += 1;
|
||||
n -= 1;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
*dst = (wchar_t)0x0000;
|
||||
scan += 1;
|
||||
n -= 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
// normal character
|
||||
scan += mblen;
|
||||
n -= mblen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
len = (int)(dst - dst0);
|
||||
}
|
||||
ARCH->unlockMutex(s_mutex);
|
||||
|
||||
return len;
|
||||
}
|
||||
73
src/lib/arch/IArchString.h
Normal file
73
src/lib/arch/IArchString.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHSTRING_H
|
||||
#define IARCHSTRING_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "BasicTypes.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
//! Interface for architecture dependent string operations
|
||||
/*!
|
||||
This interface defines the string operations required by
|
||||
synergy. Each architecture must implement this interface.
|
||||
*/
|
||||
class IArchString : public IInterface {
|
||||
public:
|
||||
virtual ~IArchString();
|
||||
|
||||
//! Wide character encodings
|
||||
/*!
|
||||
The known wide character encodings
|
||||
*/
|
||||
enum EWideCharEncoding {
|
||||
kUCS2, //!< The UCS-2 encoding
|
||||
kUCS4, //!< The UCS-4 encoding
|
||||
kUTF16, //!< The UTF-16 encoding
|
||||
kUTF32 //!< The UTF-32 encoding
|
||||
};
|
||||
|
||||
//! @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);
|
||||
|
||||
//! Convert multibyte string to wide character string
|
||||
virtual int convStringMBToWC(wchar_t*,
|
||||
const char*, UInt32 n, bool* errors);
|
||||
|
||||
//! Convert wide character string to multibyte string
|
||||
virtual int convStringWCToMB(char*,
|
||||
const wchar_t*, UInt32 n, bool* errors);
|
||||
|
||||
//! Return the architecture's native wide character encoding
|
||||
virtual EWideCharEncoding
|
||||
getWideCharEncoding() = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
#endif
|
||||
61
src/lib/arch/IArchSystem.h
Normal file
61
src/lib/arch/IArchSystem.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHSYSTEM_H
|
||||
#define IARCHSYSTEM_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "stdstring.h"
|
||||
|
||||
//! Interface for architecture dependent system queries
|
||||
/*!
|
||||
This interface defines operations for querying system info.
|
||||
*/
|
||||
class IArchSystem : public IInterface {
|
||||
public:
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Identify the OS
|
||||
/*!
|
||||
Returns a string identifying the operating system.
|
||||
*/
|
||||
virtual std::string getOSName() const = 0;
|
||||
|
||||
//! Identify the platform
|
||||
/*!
|
||||
Returns a string identifying the platform this OS is running on.
|
||||
*/
|
||||
virtual std::string getPlatformName() const = 0;
|
||||
//@}
|
||||
|
||||
//! Get a Synergy setting
|
||||
/*!
|
||||
Reads a Synergy setting from the system.
|
||||
*/
|
||||
virtual std::string setting(const std::string& valueName) const = 0;
|
||||
//@}
|
||||
|
||||
//! Set a Synergy setting
|
||||
/*!
|
||||
Writes a Synergy setting from the system.
|
||||
*/
|
||||
virtual void setting(const std::string& valueName, const std::string& valueString) const = 0;
|
||||
//@}
|
||||
};
|
||||
|
||||
#endif
|
||||
65
src/lib/arch/IArchTaskBar.h
Normal file
65
src/lib/arch/IArchTaskBar.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHTASKBAR_H
|
||||
#define IARCHTASKBAR_H
|
||||
|
||||
#include "IInterface.h"
|
||||
|
||||
class IArchTaskBarReceiver;
|
||||
|
||||
//! Interface for architecture dependent task bar control
|
||||
/*!
|
||||
This interface defines the task bar icon operations required
|
||||
by synergy. Each architecture must implement this interface
|
||||
though each operation can be a no-op.
|
||||
*/
|
||||
class IArchTaskBar : public IInterface {
|
||||
public:
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Add a receiver
|
||||
/*!
|
||||
Add a receiver object to be notified of user and application
|
||||
events. This should be called before other methods. When
|
||||
the receiver is added to the task bar, its icon appears on
|
||||
the task bar.
|
||||
*/
|
||||
virtual void addReceiver(IArchTaskBarReceiver*) = 0;
|
||||
|
||||
//! Remove a receiver
|
||||
/*!
|
||||
Remove a receiver object from the task bar. This removes the
|
||||
icon from the task bar.
|
||||
*/
|
||||
virtual void removeReceiver(IArchTaskBarReceiver*) = 0;
|
||||
|
||||
//! Update a receiver
|
||||
/*!
|
||||
Updates the display of the receiver on the task bar. This
|
||||
should be called when the receiver appearance may have changed
|
||||
(e.g. it's icon or tool tip has changed).
|
||||
*/
|
||||
virtual void updateReceiver(IArchTaskBarReceiver*) = 0;
|
||||
|
||||
//@}
|
||||
|
||||
virtual void init() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
100
src/lib/arch/IArchTaskBarReceiver.h
Normal file
100
src/lib/arch/IArchTaskBarReceiver.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHTASKBARRECEIVER_H
|
||||
#define IARCHTASKBARRECEIVER_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "stdstring.h"
|
||||
|
||||
class IScreen;
|
||||
class INode;
|
||||
|
||||
//! Interface for architecture dependent task bar event handling
|
||||
/*!
|
||||
This interface defines the task bar icon event handlers required
|
||||
by synergy. Each architecture must implement this interface
|
||||
though each operation can be a no-op.
|
||||
*/
|
||||
class IArchTaskBarReceiver : public IInterface {
|
||||
public:
|
||||
// Icon data is architecture dependent
|
||||
typedef void* Icon;
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Show status window
|
||||
/*!
|
||||
Open a window displaying current status. This should return
|
||||
immediately without waiting for the window to be closed.
|
||||
*/
|
||||
virtual void showStatus() = 0;
|
||||
|
||||
//! Popup menu
|
||||
/*!
|
||||
Popup a menu of operations at or around \c x,y and perform the
|
||||
chosen operation.
|
||||
*/
|
||||
virtual void runMenu(int x, int y) = 0;
|
||||
|
||||
//! Perform primary action
|
||||
/*!
|
||||
Perform the primary (default) action.
|
||||
*/
|
||||
virtual void primaryAction() = 0;
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Lock receiver
|
||||
/*!
|
||||
Locks the receiver from changing state. The receiver should be
|
||||
locked when querying it's state to ensure consistent results.
|
||||
Each call to \c lock() must have a matching \c unlock() and
|
||||
locks cannot be nested.
|
||||
*/
|
||||
virtual void lock() const = 0;
|
||||
|
||||
//! Unlock receiver
|
||||
virtual void unlock() const = 0;
|
||||
|
||||
//! Get icon
|
||||
/*!
|
||||
Returns the icon to display in the task bar. The interface
|
||||
to set the icon is left to subclasses. Getting and setting
|
||||
the icon must be thread safe.
|
||||
*/
|
||||
virtual const Icon getIcon() const = 0;
|
||||
|
||||
//! Get tooltip
|
||||
/*!
|
||||
Returns the tool tip to display in the task bar. The interface
|
||||
to set the tooltip is left to sublclasses. Getting and setting
|
||||
the icon must be thread safe.
|
||||
*/
|
||||
virtual std::string getToolTip() const = 0;
|
||||
|
||||
virtual void updateStatus(INode*, const CString& errorMsg) = 0;
|
||||
|
||||
virtual void cleanup() {}
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
#endif
|
||||
43
src/lib/arch/IArchTime.h
Normal file
43
src/lib/arch/IArchTime.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IARCHTIME_H
|
||||
#define IARCHTIME_H
|
||||
|
||||
#include "IInterface.h"
|
||||
|
||||
//! Interface for architecture dependent time operations
|
||||
/*!
|
||||
This interface defines the time operations required by
|
||||
synergy. Each architecture must implement this interface.
|
||||
*/
|
||||
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
|
||||
36
src/lib/arch/XArch.cpp
Normal file
36
src/lib/arch/XArch.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "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;
|
||||
}
|
||||
173
src/lib/arch/XArch.h
Normal file
173
src/lib/arch/XArch.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XARCH_H
|
||||
#define XARCH_H
|
||||
|
||||
#include "common.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 != NULL ? e.m_eval->clone() : NULL),
|
||||
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);
|
||||
|
||||
//! Operation was interrupted
|
||||
XARCH_SUBCLASS(XArchNetworkInterrupted, 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 read end of socket has closed
|
||||
XARCH_SUBCLASS(XArchNetworkShutdown, XArchNetwork);
|
||||
|
||||
//! Remote end of socket has disconnected
|
||||
XARCH_SUBCLASS(XArchNetworkDisconnected, XArchNetwork);
|
||||
|
||||
//! Remote end of socket refused connection
|
||||
XARCH_SUBCLASS(XArchNetworkConnectionRefused, 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 no address
|
||||
XARCH_SUBCLASS(XArchNetworkNameNoAddress, XArchNetworkName);
|
||||
|
||||
//! Non-recoverable name server error
|
||||
XARCH_SUBCLASS(XArchNetworkNameFailure, XArchNetworkName);
|
||||
|
||||
//! Temporary name server error
|
||||
XARCH_SUBCLASS(XArchNetworkNameUnavailable, XArchNetworkName);
|
||||
|
||||
//! The named host is known but no supported address
|
||||
XARCH_SUBCLASS(XArchNetworkNameUnsupported, 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
|
||||
36
src/lib/arch/XArchUnix.cpp
Normal file
36
src/lib/arch/XArchUnix.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "XArchUnix.h"
|
||||
#include <cstring>
|
||||
|
||||
//
|
||||
// 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);
|
||||
}
|
||||
37
src/lib/arch/XArchUnix.h
Normal file
37
src/lib/arch/XArchUnix.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
130
src/lib/arch/XArchWindows.cpp
Normal file
130
src/lib/arch/XArchWindows.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "XArchWindows.h"
|
||||
#include "CArchNetworkWinsock.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 host 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, "Connection was refused"},
|
||||
/* 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";
|
||||
}
|
||||
55
src/lib/arch/XArchWindows.h
Normal file
55
src/lib/arch/XArchWindows.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
66
src/lib/arch/vsnprintf.h
Normal file
66
src/lib/arch/vsnprintf.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "IArchString.h"
|
||||
|
||||
#if HAVE_VSNPRINTF
|
||||
|
||||
#if !defined(ARCH_VSNPRINTF)
|
||||
# define ARCH_VSNPRINTF vsnprintf
|
||||
#endif
|
||||
|
||||
int
|
||||
IArchString::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;
|
||||
}
|
||||
|
||||
#elif SYSAPI_UNIX // !HAVE_VSNPRINTF
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
IArchString::vsnprintf(char* str, int size, const char* fmt, va_list ap)
|
||||
{
|
||||
static FILE* bitbucket = fopen("/dev/null", "w");
|
||||
if (bitbucket == NULL) {
|
||||
// uh oh
|
||||
if (size > 0) {
|
||||
str[0] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
// count the characters using the bitbucket
|
||||
int n = vfprintf(bitbucket, fmt, ap);
|
||||
if (n + 1 <= size) {
|
||||
// it'll fit so print it into str
|
||||
vsprintf(str, fmt, ap);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
#else // !HAVE_VSNPRINTF && !SYSAPI_UNIX
|
||||
|
||||
#error vsnprintf not implemented
|
||||
|
||||
#endif // !HAVE_VSNPRINTF
|
||||
83
src/lib/base/CEvent.cpp
Normal file
83
src/lib/base/CEvent.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CEvent.h"
|
||||
#include "CEventQueue.h"
|
||||
|
||||
//
|
||||
// CEvent
|
||||
//
|
||||
|
||||
CEvent::CEvent() :
|
||||
m_type(kUnknown),
|
||||
m_target(NULL),
|
||||
m_data(NULL),
|
||||
m_flags(0)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CEvent::CEvent(Type type, void* target, void* data, Flags flags) :
|
||||
m_type(type),
|
||||
m_target(target),
|
||||
m_data(data),
|
||||
m_flags(flags)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
CEvent::getType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void*
|
||||
CEvent::getTarget() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
void*
|
||||
CEvent::getData() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
CEvent::Flags
|
||||
CEvent::getFlags() const
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
void
|
||||
CEvent::deleteData(const CEvent& event)
|
||||
{
|
||||
switch (event.getType()) {
|
||||
case kUnknown:
|
||||
case kQuit:
|
||||
case kSystem:
|
||||
case kTimer:
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((event.getFlags() & kDontFreeData) == 0) {
|
||||
free(event.getData());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
105
src/lib/base/CEvent.h
Normal file
105
src/lib/base/CEvent.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CEVENT_H
|
||||
#define CEVENT_H
|
||||
|
||||
#include "BasicTypes.h"
|
||||
#include "stdmap.h"
|
||||
|
||||
//! Event
|
||||
/*!
|
||||
A \c CEvent holds an event type and a pointer to event data.
|
||||
*/
|
||||
class CEvent {
|
||||
public:
|
||||
typedef UInt32 Type;
|
||||
enum {
|
||||
kUnknown, //!< The event type is unknown
|
||||
kQuit, //!< The quit event
|
||||
kSystem, //!< The data points to a system event type
|
||||
kTimer, //!< The data points to timer info
|
||||
kLast //!< Must be last
|
||||
};
|
||||
|
||||
typedef UInt32 Flags;
|
||||
enum {
|
||||
kNone = 0x00, //!< No flags
|
||||
kDeliverImmediately = 0x01, //!< Dispatch and free event immediately
|
||||
kDontFreeData = 0x02 //!< Don't free data in deleteData
|
||||
};
|
||||
|
||||
CEvent();
|
||||
|
||||
//! Create \c CEvent with data
|
||||
/*!
|
||||
The \p type must have been registered using \c registerType().
|
||||
The \p data must be POD (plain old data) allocated by malloc(),
|
||||
which means it cannot have a constructor, destructor or be
|
||||
composed of any types that do. \p target is the intended
|
||||
recipient of the event. \p flags is any combination of \c Flags.
|
||||
*/
|
||||
CEvent(Type type, void* target = NULL, void* data = NULL,
|
||||
Flags flags = kNone);
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Release event data
|
||||
/*!
|
||||
Deletes event data for the given event (using free()).
|
||||
*/
|
||||
static void deleteData(const CEvent&);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Get event type
|
||||
/*!
|
||||
Returns the event type.
|
||||
*/
|
||||
Type getType() const;
|
||||
|
||||
//! Get the event target
|
||||
/*!
|
||||
Returns the event target.
|
||||
*/
|
||||
void* getTarget() const;
|
||||
|
||||
//! Get the event data
|
||||
/*!
|
||||
Returns the event data.
|
||||
*/
|
||||
void* getData() const;
|
||||
|
||||
//! Get event flags
|
||||
/*!
|
||||
Returns the event flags.
|
||||
*/
|
||||
Flags getFlags() const;
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
Type m_type;
|
||||
void* m_target;
|
||||
void* m_data;
|
||||
Flags m_flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
541
src/lib/base/CEventQueue.cpp
Normal file
541
src/lib/base/CEventQueue.cpp
Normal file
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CEventQueue.h"
|
||||
#include "CLog.h"
|
||||
#include "CSimpleEventQueueBuffer.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "IEventJob.h"
|
||||
#include "CArch.h"
|
||||
|
||||
// interrupt handler. this just adds a quit event to the queue.
|
||||
static
|
||||
void
|
||||
interrupt(CArch::ESignal, void*)
|
||||
{
|
||||
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CEventQueue
|
||||
//
|
||||
|
||||
CEventQueue::CEventQueue() :
|
||||
m_nextType(CEvent::kLast)
|
||||
{
|
||||
setInstance(this);
|
||||
m_mutex = ARCH->newMutex();
|
||||
ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, NULL);
|
||||
ARCH->setSignalHandler(CArch::kTERMINATE, &interrupt, NULL);
|
||||
m_buffer = new CSimpleEventQueueBuffer;
|
||||
}
|
||||
|
||||
CEventQueue::~CEventQueue()
|
||||
{
|
||||
delete m_buffer;
|
||||
ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL);
|
||||
ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL);
|
||||
ARCH->closeMutex(m_mutex);
|
||||
setInstance(NULL);
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
CEventQueue::registerType(const char* name)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
m_typeMap.insert(std::make_pair(m_nextType, name));
|
||||
m_nameMap.insert(std::make_pair(name, m_nextType));
|
||||
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
|
||||
return m_nextType++;
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
CEventQueue::registerTypeOnce(CEvent::Type& type, const char* name)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
if (type == CEvent::kUnknown) {
|
||||
m_typeMap.insert(std::make_pair(m_nextType, name));
|
||||
m_nameMap.insert(std::make_pair(name, m_nextType));
|
||||
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
|
||||
type = m_nextType++;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
const char*
|
||||
CEventQueue::getTypeName(CEvent::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case CEvent::kUnknown:
|
||||
return "nil";
|
||||
|
||||
case CEvent::kQuit:
|
||||
return "quit";
|
||||
|
||||
case CEvent::kSystem:
|
||||
return "system";
|
||||
|
||||
case CEvent::kTimer:
|
||||
return "timer";
|
||||
|
||||
default:
|
||||
CTypeMap::const_iterator i = m_typeMap.find(type);
|
||||
if (i == m_typeMap.end()) {
|
||||
return "<unknown>";
|
||||
}
|
||||
else {
|
||||
return i->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
|
||||
// discard old buffer and old events
|
||||
delete m_buffer;
|
||||
for (CEventTable::iterator i = m_events.begin(); i != m_events.end(); ++i) {
|
||||
CEvent::deleteData(i->second);
|
||||
}
|
||||
m_events.clear();
|
||||
m_oldEventIDs.clear();
|
||||
|
||||
// use new buffer
|
||||
m_buffer = buffer;
|
||||
if (m_buffer == NULL) {
|
||||
m_buffer = new CSimpleEventQueueBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::getEvent(CEvent& event, double timeout)
|
||||
{
|
||||
CStopwatch timer(true);
|
||||
retry:
|
||||
// if no events are waiting then handle timers and then wait
|
||||
while (m_buffer->isEmpty()) {
|
||||
// handle timers first
|
||||
if (hasTimerExpired(event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// get time remaining in timeout
|
||||
double timeLeft = timeout - timer.getTime();
|
||||
if (timeout >= 0.0 && timeLeft <= 0.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get time until next timer expires. if there is a timer
|
||||
// and it'll expire before the client's timeout then use
|
||||
// that duration for our timeout instead.
|
||||
double timerTimeout = getNextTimerTimeout();
|
||||
if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) {
|
||||
timeLeft = timerTimeout;
|
||||
}
|
||||
|
||||
// wait for an event
|
||||
m_buffer->waitForEvent(timeLeft);
|
||||
}
|
||||
|
||||
// get the event
|
||||
UInt32 dataID;
|
||||
IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID);
|
||||
switch (type) {
|
||||
case IEventQueueBuffer::kNone:
|
||||
if (timeout < 0.0 || timeout <= timer.getTime()) {
|
||||
// don't want to fail if client isn't expecting that
|
||||
// so if getEvent() fails with an infinite timeout
|
||||
// then just try getting another event.
|
||||
goto retry;
|
||||
}
|
||||
return false;
|
||||
|
||||
case IEventQueueBuffer::kSystem:
|
||||
return true;
|
||||
|
||||
case IEventQueueBuffer::kUser:
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
event = removeEvent(dataID);
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0 && "invalid event type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::dispatchEvent(const CEvent& event)
|
||||
{
|
||||
void* target = event.getTarget();
|
||||
IEventJob* job = getHandler(event.getType(), target);
|
||||
if (job == NULL) {
|
||||
job = getHandler(CEvent::kUnknown, target);
|
||||
}
|
||||
if (job != NULL) {
|
||||
job->run(event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::addEvent(const CEvent& event)
|
||||
{
|
||||
// discard bogus event types
|
||||
switch (event.getType()) {
|
||||
case CEvent::kUnknown:
|
||||
case CEvent::kSystem:
|
||||
case CEvent::kTimer:
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((event.getFlags() & CEvent::kDeliverImmediately) != 0) {
|
||||
dispatchEvent(event);
|
||||
CEvent::deleteData(event);
|
||||
}
|
||||
else {
|
||||
CArchMutexLock lock(m_mutex);
|
||||
|
||||
// store the event's data locally
|
||||
UInt32 eventID = saveEvent(event);
|
||||
|
||||
// add it
|
||||
if (!m_buffer->addEvent(eventID)) {
|
||||
// failed to send event
|
||||
removeEvent(eventID);
|
||||
CEvent::deleteData(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
CEventQueue::newTimer(double duration, void* target)
|
||||
{
|
||||
assert(duration > 0.0);
|
||||
|
||||
CEventQueueTimer* timer = m_buffer->newTimer(duration, false);
|
||||
if (target == NULL) {
|
||||
target = timer;
|
||||
}
|
||||
CArchMutexLock lock(m_mutex);
|
||||
m_timers.insert(timer);
|
||||
// initial duration is requested duration plus whatever's on
|
||||
// the clock currently because the latter will be subtracted
|
||||
// the next time we check for timers.
|
||||
m_timerQueue.push(CTimer(timer, duration,
|
||||
duration + m_time.getTime(), target, false));
|
||||
return timer;
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
CEventQueue::newOneShotTimer(double duration, void* target)
|
||||
{
|
||||
assert(duration > 0.0);
|
||||
|
||||
CEventQueueTimer* timer = m_buffer->newTimer(duration, true);
|
||||
if (target == NULL) {
|
||||
target = timer;
|
||||
}
|
||||
CArchMutexLock lock(m_mutex);
|
||||
m_timers.insert(timer);
|
||||
// initial duration is requested duration plus whatever's on
|
||||
// the clock currently because the latter will be subtracted
|
||||
// the next time we check for timers.
|
||||
m_timerQueue.push(CTimer(timer, duration,
|
||||
duration + m_time.getTime(), target, true));
|
||||
return timer;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::deleteTimer(CEventQueueTimer* timer)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
for (CTimerQueue::iterator index = m_timerQueue.begin();
|
||||
index != m_timerQueue.end(); ++index) {
|
||||
if (index->getTimer() == timer) {
|
||||
m_timerQueue.erase(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
CTimers::iterator index = m_timers.find(timer);
|
||||
if (index != m_timers.end()) {
|
||||
m_timers.erase(index);
|
||||
}
|
||||
m_buffer->deleteTimer(timer);
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::adoptHandler(CEvent::Type type, void* target, IEventJob* handler)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
IEventJob*& job = m_handlers[target][type];
|
||||
delete job;
|
||||
job = handler;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::removeHandler(CEvent::Type type, void* target)
|
||||
{
|
||||
IEventJob* handler = NULL;
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
CHandlerTable::iterator index = m_handlers.find(target);
|
||||
if (index != m_handlers.end()) {
|
||||
CTypeHandlerTable& typeHandlers = index->second;
|
||||
CTypeHandlerTable::iterator index2 = typeHandlers.find(type);
|
||||
if (index2 != typeHandlers.end()) {
|
||||
handler = index2->second;
|
||||
typeHandlers.erase(index2);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete handler;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::removeHandlers(void* target)
|
||||
{
|
||||
std::vector<IEventJob*> handlers;
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
CHandlerTable::iterator index = m_handlers.find(target);
|
||||
if (index != m_handlers.end()) {
|
||||
// copy to handlers array and clear table for target
|
||||
CTypeHandlerTable& typeHandlers = index->second;
|
||||
for (CTypeHandlerTable::iterator index2 = typeHandlers.begin();
|
||||
index2 != typeHandlers.end(); ++index2) {
|
||||
handlers.push_back(index2->second);
|
||||
}
|
||||
typeHandlers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// delete handlers
|
||||
for (std::vector<IEventJob*>::iterator index = handlers.begin();
|
||||
index != handlers.end(); ++index) {
|
||||
delete *index;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::isEmpty() const
|
||||
{
|
||||
return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0);
|
||||
}
|
||||
|
||||
IEventJob*
|
||||
CEventQueue::getHandler(CEvent::Type type, void* target) const
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
CHandlerTable::const_iterator index = m_handlers.find(target);
|
||||
if (index != m_handlers.end()) {
|
||||
const CTypeHandlerTable& typeHandlers = index->second;
|
||||
CTypeHandlerTable::const_iterator index2 = typeHandlers.find(type);
|
||||
if (index2 != typeHandlers.end()) {
|
||||
return index2->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UInt32
|
||||
CEventQueue::saveEvent(const CEvent& event)
|
||||
{
|
||||
// choose id
|
||||
UInt32 id;
|
||||
if (!m_oldEventIDs.empty()) {
|
||||
// reuse an id
|
||||
id = m_oldEventIDs.back();
|
||||
m_oldEventIDs.pop_back();
|
||||
}
|
||||
else {
|
||||
// make a new id
|
||||
id = static_cast<UInt32>(m_events.size());
|
||||
}
|
||||
|
||||
// save data
|
||||
m_events[id] = event;
|
||||
return id;
|
||||
}
|
||||
|
||||
CEvent
|
||||
CEventQueue::removeEvent(UInt32 eventID)
|
||||
{
|
||||
// look up id
|
||||
CEventTable::iterator index = m_events.find(eventID);
|
||||
if (index == m_events.end()) {
|
||||
return CEvent();
|
||||
}
|
||||
|
||||
// get data
|
||||
CEvent event = index->second;
|
||||
m_events.erase(index);
|
||||
|
||||
// save old id for reuse
|
||||
m_oldEventIDs.push_back(eventID);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::hasTimerExpired(CEvent& event)
|
||||
{
|
||||
// return true if there's a timer in the timer priority queue that
|
||||
// has expired. if returning true then fill in event appropriately
|
||||
// and reset and reinsert the timer.
|
||||
if (m_timerQueue.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get time elapsed since last check
|
||||
const double time = m_time.getTime();
|
||||
m_time.reset();
|
||||
|
||||
// countdown elapsed time
|
||||
for (CTimerQueue::iterator index = m_timerQueue.begin();
|
||||
index != m_timerQueue.end(); ++index) {
|
||||
(*index) -= time;
|
||||
}
|
||||
|
||||
// done if no timers are expired
|
||||
if (m_timerQueue.top() > 0.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove timer from queue
|
||||
CTimer timer = m_timerQueue.top();
|
||||
m_timerQueue.pop();
|
||||
|
||||
// prepare event and reset the timer's clock
|
||||
timer.fillEvent(m_timerEvent);
|
||||
event = CEvent(CEvent::kTimer, timer.getTarget(), &m_timerEvent);
|
||||
timer.reset();
|
||||
|
||||
// reinsert timer into queue if it's not a one-shot
|
||||
if (!timer.isOneShot()) {
|
||||
m_timerQueue.push(timer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
double
|
||||
CEventQueue::getNextTimerTimeout() const
|
||||
{
|
||||
// return -1 if no timers, 0 if the top timer has expired, otherwise
|
||||
// the time until the top timer in the timer priority queue will
|
||||
// expire.
|
||||
if (m_timerQueue.empty()) {
|
||||
return -1.0;
|
||||
}
|
||||
if (m_timerQueue.top() <= 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
return m_timerQueue.top();
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
CEventQueue::getRegisteredType(const CString& name) const
|
||||
{
|
||||
CNameMap::const_iterator found = m_nameMap.find(name);
|
||||
if (found != m_nameMap.end())
|
||||
return found->second;
|
||||
|
||||
return CEvent::kUnknown;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CEventQueue::CTimer
|
||||
//
|
||||
|
||||
CEventQueue::CTimer::CTimer(CEventQueueTimer* timer, double timeout,
|
||||
double initialTime, void* target, bool oneShot) :
|
||||
m_timer(timer),
|
||||
m_timeout(timeout),
|
||||
m_target(target),
|
||||
m_oneShot(oneShot),
|
||||
m_time(initialTime)
|
||||
{
|
||||
assert(m_timeout > 0.0);
|
||||
}
|
||||
|
||||
CEventQueue::CTimer::~CTimer()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::CTimer::reset()
|
||||
{
|
||||
m_time = m_timeout;
|
||||
}
|
||||
|
||||
CEventQueue::CTimer&
|
||||
CEventQueue::CTimer::operator-=(double dt)
|
||||
{
|
||||
m_time -= dt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CEventQueue::CTimer::operator double() const
|
||||
{
|
||||
return m_time;
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::CTimer::isOneShot() const
|
||||
{
|
||||
return m_oneShot;
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
CEventQueue::CTimer::getTimer() const
|
||||
{
|
||||
return m_timer;
|
||||
}
|
||||
|
||||
void*
|
||||
CEventQueue::CTimer::getTarget() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::CTimer::fillEvent(CTimerEvent& event) const
|
||||
{
|
||||
event.m_timer = m_timer;
|
||||
event.m_count = 0;
|
||||
if (m_time <= 0.0) {
|
||||
event.m_count = static_cast<UInt32>((m_timeout - m_time) / m_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::CTimer::operator<(const CTimer& t) const
|
||||
{
|
||||
return m_time < t.m_time;
|
||||
}
|
||||
130
src/lib/base/CEventQueue.h
Normal file
130
src/lib/base/CEventQueue.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CEVENTQUEUE_H
|
||||
#define CEVENTQUEUE_H
|
||||
|
||||
#include "IEventQueue.h"
|
||||
#include "CEvent.h"
|
||||
#include "CPriorityQueue.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "IArchMultithread.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdset.h"
|
||||
|
||||
//! Event queue
|
||||
/*!
|
||||
An event queue that implements the platform independent parts and
|
||||
delegates the platform dependent parts to a subclass.
|
||||
*/
|
||||
class CEventQueue : public IEventQueue {
|
||||
public:
|
||||
CEventQueue();
|
||||
virtual ~CEventQueue();
|
||||
|
||||
// IEventQueue overrides
|
||||
virtual void adoptBuffer(IEventQueueBuffer*);
|
||||
virtual bool getEvent(CEvent& event, double timeout = -1.0);
|
||||
virtual bool dispatchEvent(const CEvent& event);
|
||||
virtual void addEvent(const CEvent& event);
|
||||
virtual CEventQueueTimer*
|
||||
newTimer(double duration, void* target);
|
||||
virtual CEventQueueTimer*
|
||||
newOneShotTimer(double duration, void* target);
|
||||
virtual void deleteTimer(CEventQueueTimer*);
|
||||
virtual void adoptHandler(CEvent::Type type,
|
||||
void* target, IEventJob* handler);
|
||||
virtual void removeHandler(CEvent::Type type, void* target);
|
||||
virtual void removeHandlers(void* target);
|
||||
virtual CEvent::Type
|
||||
registerType(const char* name);
|
||||
virtual CEvent::Type
|
||||
registerTypeOnce(CEvent::Type& type, const char* name);
|
||||
virtual bool isEmpty() const;
|
||||
virtual IEventJob* getHandler(CEvent::Type type, void* target) const;
|
||||
virtual const char* getTypeName(CEvent::Type type);
|
||||
virtual CEvent::Type
|
||||
getRegisteredType(const CString& name) const;
|
||||
|
||||
private:
|
||||
UInt32 saveEvent(const CEvent& event);
|
||||
CEvent removeEvent(UInt32 eventID);
|
||||
bool hasTimerExpired(CEvent& event);
|
||||
double getNextTimerTimeout() const;
|
||||
|
||||
private:
|
||||
class CTimer {
|
||||
public:
|
||||
CTimer(CEventQueueTimer*, double timeout, double initialTime,
|
||||
void* target, bool oneShot);
|
||||
~CTimer();
|
||||
|
||||
void reset();
|
||||
|
||||
CTimer& operator-=(double);
|
||||
|
||||
operator double() const;
|
||||
|
||||
bool isOneShot() const;
|
||||
CEventQueueTimer*
|
||||
getTimer() const;
|
||||
void* getTarget() const;
|
||||
void fillEvent(CTimerEvent&) const;
|
||||
|
||||
bool operator<(const CTimer&) const;
|
||||
|
||||
private:
|
||||
CEventQueueTimer* m_timer;
|
||||
double m_timeout;
|
||||
void* m_target;
|
||||
bool m_oneShot;
|
||||
double m_time;
|
||||
};
|
||||
typedef std::set<CEventQueueTimer*> CTimers;
|
||||
typedef CPriorityQueue<CTimer> CTimerQueue;
|
||||
typedef std::map<UInt32, CEvent> CEventTable;
|
||||
typedef std::vector<UInt32> CEventIDList;
|
||||
typedef std::map<CEvent::Type, const char*> CTypeMap;
|
||||
typedef std::map<CString, CEvent::Type> CNameMap;
|
||||
typedef std::map<CEvent::Type, IEventJob*> CTypeHandlerTable;
|
||||
typedef std::map<void*, CTypeHandlerTable> CHandlerTable;
|
||||
|
||||
CArchMutex m_mutex;
|
||||
|
||||
// registered events
|
||||
CEvent::Type m_nextType;
|
||||
CTypeMap m_typeMap;
|
||||
CNameMap m_nameMap;
|
||||
|
||||
// buffer of events
|
||||
IEventQueueBuffer* m_buffer;
|
||||
|
||||
// saved events
|
||||
CEventTable m_events;
|
||||
CEventIDList m_oldEventIDs;
|
||||
|
||||
// timers
|
||||
CStopwatch m_time;
|
||||
CTimers m_timers;
|
||||
CTimerQueue m_timerQueue;
|
||||
CTimerEvent m_timerEvent;
|
||||
|
||||
// event handlers
|
||||
CHandlerTable m_handlers;
|
||||
};
|
||||
|
||||
#endif
|
||||
43
src/lib/base/CFunctionEventJob.cpp
Normal file
43
src/lib/base/CFunctionEventJob.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CFunctionEventJob.h"
|
||||
|
||||
//
|
||||
// CFunctionEventJob
|
||||
//
|
||||
|
||||
CFunctionEventJob::CFunctionEventJob(
|
||||
void (*func)(const CEvent&, void*), void* arg) :
|
||||
m_func(func),
|
||||
m_arg(arg)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CFunctionEventJob::~CFunctionEventJob()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CFunctionEventJob::run(const CEvent& event)
|
||||
{
|
||||
if (m_func != NULL) {
|
||||
m_func(event, m_arg);
|
||||
}
|
||||
}
|
||||
41
src/lib/base/CFunctionEventJob.h
Normal file
41
src/lib/base/CFunctionEventJob.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CFUNCTIONEVENTJOB_H
|
||||
#define CFUNCTIONEVENTJOB_H
|
||||
|
||||
#include "IEventJob.h"
|
||||
|
||||
//! Use a function as an event job
|
||||
/*!
|
||||
An event job class that invokes a function.
|
||||
*/
|
||||
class CFunctionEventJob : public IEventJob {
|
||||
public:
|
||||
//! run() invokes \c func(arg)
|
||||
CFunctionEventJob(void (*func)(const CEvent&, void*), void* arg = NULL);
|
||||
virtual ~CFunctionEventJob();
|
||||
|
||||
// IEventJob overrides
|
||||
virtual void run(const CEvent&);
|
||||
|
||||
private:
|
||||
void (*m_func)(const CEvent&, void*);
|
||||
void* m_arg;
|
||||
};
|
||||
|
||||
#endif
|
||||
42
src/lib/base/CFunctionJob.cpp
Normal file
42
src/lib/base/CFunctionJob.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CFunctionJob.h"
|
||||
|
||||
//
|
||||
// CFunctionJob
|
||||
//
|
||||
|
||||
CFunctionJob::CFunctionJob(void (*func)(void*), void* arg) :
|
||||
m_func(func),
|
||||
m_arg(arg)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CFunctionJob::~CFunctionJob()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CFunctionJob::run()
|
||||
{
|
||||
if (m_func != NULL) {
|
||||
m_func(m_arg);
|
||||
}
|
||||
}
|
||||
41
src/lib/base/CFunctionJob.h
Normal file
41
src/lib/base/CFunctionJob.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CFUNCTIONJOB_H
|
||||
#define CFUNCTIONJOB_H
|
||||
|
||||
#include "IJob.h"
|
||||
|
||||
//! Use a function as a job
|
||||
/*!
|
||||
A job class that invokes a function.
|
||||
*/
|
||||
class CFunctionJob : public IJob {
|
||||
public:
|
||||
//! run() invokes \c func(arg)
|
||||
CFunctionJob(void (*func)(void*), void* arg = NULL);
|
||||
virtual ~CFunctionJob();
|
||||
|
||||
// IJob overrides
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
void (*m_func)(void*);
|
||||
void* m_arg;
|
||||
};
|
||||
|
||||
#endif
|
||||
297
src/lib/base/CLog.cpp
Normal file
297
src/lib/base/CLog.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CLog.h"
|
||||
#include "CString.h"
|
||||
#include "CStringUtil.h"
|
||||
#include "LogOutputters.h"
|
||||
#include "CArch.h"
|
||||
#include "Version.h"
|
||||
#include "XArch.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
// names of priorities
|
||||
static const char* g_priority[] = {
|
||||
"FATAL",
|
||||
"ERROR",
|
||||
"WARNING",
|
||||
"NOTE",
|
||||
"INFO",
|
||||
"DEBUG",
|
||||
"DEBUG1",
|
||||
"DEBUG2",
|
||||
"DEBUG3",
|
||||
"DEBUG4",
|
||||
"DEBUG5"
|
||||
};
|
||||
|
||||
// number of priorities
|
||||
static const int g_numPriority = (int)(sizeof(g_priority) / sizeof(g_priority[0]));
|
||||
|
||||
// the default priority
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
static const int g_defaultMaxPriority = kDEBUG;
|
||||
#else
|
||||
static const int g_defaultMaxPriority = kINFO;
|
||||
#endif
|
||||
|
||||
// length of longest string in g_priority
|
||||
static const int g_maxPriorityLength = 7;
|
||||
|
||||
// length of suffix string (": ")
|
||||
static const int g_prioritySuffixLength = 2;
|
||||
|
||||
// amount of padded required to fill in the priority prefix
|
||||
static const int g_priorityPad = g_maxPriorityLength +
|
||||
g_prioritySuffixLength;
|
||||
|
||||
|
||||
//
|
||||
// CLog
|
||||
//
|
||||
|
||||
CLog* CLog::s_log = NULL;
|
||||
|
||||
CLog::CLog()
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
for (COutputterList::iterator index = m_alwaysOutputters.begin();
|
||||
index != m_alwaysOutputters.end(); ++index) {
|
||||
delete *index;
|
||||
}
|
||||
ARCH->closeMutex(m_mutex);
|
||||
}
|
||||
|
||||
CLog*
|
||||
CLog::getInstance()
|
||||
{
|
||||
if (s_log == NULL)
|
||||
s_log = new CLog();
|
||||
|
||||
return s_log;
|
||||
}
|
||||
|
||||
const char*
|
||||
CLog::getFilterName() const
|
||||
{
|
||||
return getFilterName(getFilter());
|
||||
}
|
||||
|
||||
const char*
|
||||
CLog::getFilterName(int level) const
|
||||
{
|
||||
return g_priority[level];
|
||||
}
|
||||
|
||||
void
|
||||
CLog::print(const char* file, int line, const char* fmt, ...)
|
||||
{
|
||||
// check if fmt begins with a priority argument
|
||||
ELevel priority = kINFO;
|
||||
if ((strlen(fmt) > 2) && (fmt[0] == '%' && fmt[1] == 'z')) {
|
||||
|
||||
// 060 in octal is 0 (48 in decimal), so subtracting this converts ascii
|
||||
// number it a true number. we could use atoi instead, but this is how
|
||||
// it was done originally.
|
||||
priority = (ELevel)(fmt[2] - '\060');
|
||||
|
||||
// move the pointer on past the debug priority char
|
||||
fmt += 3;
|
||||
}
|
||||
|
||||
// done if below priority threshold
|
||||
if (priority > getFilter()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// compute prefix padding length
|
||||
char stack[1024];
|
||||
|
||||
// compute suffix padding length
|
||||
int sPad = m_maxNewlineLength;
|
||||
|
||||
// print to buffer, leaving space for a newline at the end and prefix
|
||||
// at the beginning.
|
||||
char* buffer = stack;
|
||||
int len = (int)(sizeof(stack) / sizeof(stack[0]));
|
||||
while (true) {
|
||||
// try printing into the buffer
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int n = ARCH->vsnprintf(buffer, len - sPad, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// if the buffer wasn't big enough then make it bigger and try again
|
||||
if (n < 0 || n > (int)len) {
|
||||
if (buffer != stack) {
|
||||
delete[] buffer;
|
||||
}
|
||||
len *= 2;
|
||||
buffer = new char[len];
|
||||
}
|
||||
|
||||
// if the buffer was big enough then continue
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// print the prefix to the buffer. leave space for priority label.
|
||||
// do not prefix time and file for kPRINT (CLOG_PRINT)
|
||||
if (priority != kPRINT) {
|
||||
|
||||
char message[2048];
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
struct tm *tm;
|
||||
char tmp[220];
|
||||
time_t t;
|
||||
time(&t);
|
||||
tm = localtime(&t);
|
||||
sprintf(tmp, "%04i-%02i-%02iT%02i:%02i:%02i", tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
sprintf(message, "%s %s: %s\n\t%s,%d", tmp, g_priority[priority], buffer, file, line);
|
||||
#else
|
||||
sprintf(message, "%s: %s", g_priority[priority], buffer);
|
||||
#endif
|
||||
|
||||
output(priority, message);
|
||||
} else {
|
||||
output(priority, buffer);
|
||||
}
|
||||
|
||||
// clean up
|
||||
if (buffer != stack) {
|
||||
delete[] buffer;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
|
||||
{
|
||||
assert(outputter != NULL);
|
||||
|
||||
CArchMutexLock lock(m_mutex);
|
||||
if (alwaysAtHead) {
|
||||
m_alwaysOutputters.push_front(outputter);
|
||||
}
|
||||
else {
|
||||
m_outputters.push_front(outputter);
|
||||
}
|
||||
|
||||
outputter->open(kAppVersion);
|
||||
|
||||
// Issue 41
|
||||
// don't show log unless user requests it, as some users find this
|
||||
// feature irritating (i.e. when they lose network connectivity).
|
||||
// in windows the log window can be displayed by selecting "show log"
|
||||
// from the synergy system tray icon.
|
||||
// if this causes problems for other architectures, then a different
|
||||
// work around should be attempted.
|
||||
//outputter->show(false);
|
||||
}
|
||||
|
||||
void
|
||||
CLog::remove(ILogOutputter* outputter)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
m_outputters.remove(outputter);
|
||||
m_alwaysOutputters.remove(outputter);
|
||||
}
|
||||
|
||||
void
|
||||
CLog::pop_front(bool alwaysAtHead)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
COutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters;
|
||||
if (!list->empty()) {
|
||||
delete list->front();
|
||||
list->pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CLog::setFilter(const char* maxPriority)
|
||||
{
|
||||
if (maxPriority != NULL) {
|
||||
for (int i = 0; i < g_numPriority; ++i) {
|
||||
if (strcmp(maxPriority, g_priority[i]) == 0) {
|
||||
setFilter(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CLog::setFilter(int maxPriority)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
m_maxPriority = maxPriority;
|
||||
}
|
||||
|
||||
int
|
||||
CLog::getFilter() const
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
return m_maxPriority;
|
||||
}
|
||||
|
||||
void
|
||||
CLog::output(ELevel priority, char* msg)
|
||||
{
|
||||
assert(priority >= -1 && priority < g_numPriority);
|
||||
assert(msg != NULL);
|
||||
if (!msg) return;
|
||||
|
||||
CArchMutexLock lock(m_mutex);
|
||||
|
||||
COutputterList::const_iterator i;
|
||||
|
||||
for (i = m_alwaysOutputters.begin(); i != m_alwaysOutputters.end(); ++i) {
|
||||
|
||||
// write to outputter
|
||||
(*i)->write(priority, msg);
|
||||
}
|
||||
|
||||
for (i = m_outputters.begin(); i != m_outputters.end(); ++i) {
|
||||
|
||||
// write to outputter and break out of loop if it returns false
|
||||
if (!(*i)->write(priority, msg)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
207
src/lib/base/CLog.h
Normal file
207
src/lib/base/CLog.h
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CLOG_H
|
||||
#define CLOG_H
|
||||
|
||||
#include "common.h"
|
||||
#include "IArchMultithread.h"
|
||||
#include "stdlist.h"
|
||||
#include <stdarg.h>
|
||||
#include "CArch.h"
|
||||
|
||||
#define CLOG (CLog::getInstance())
|
||||
|
||||
class ILogOutputter;
|
||||
class CThread;
|
||||
|
||||
//! Logging facility
|
||||
/*!
|
||||
The logging class; all console output should go through this class.
|
||||
It supports multithread safe operation, several message priority levels,
|
||||
filtering by priority, and output redirection. The macros LOG() and
|
||||
LOGC() provide convenient access.
|
||||
*/
|
||||
class CLog {
|
||||
public:
|
||||
~CLog();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Add an outputter to the head of the list
|
||||
/*!
|
||||
Inserts an outputter to the head of the outputter list. When the
|
||||
logger writes a message, it goes to the outputter at the head of
|
||||
the outputter list. If that outputter's \c write() method returns
|
||||
true then it also goes to the next outputter, as so on until an
|
||||
outputter returns false or there are no more outputters. Outputters
|
||||
still in the outputter list when the log is destroyed will be
|
||||
deleted. If \c alwaysAtHead is true then the outputter is always
|
||||
called before all outputters with \c alwaysAtHead false and the
|
||||
return value of the outputter is ignored.
|
||||
|
||||
By default, the logger has one outputter installed which writes to
|
||||
the console.
|
||||
*/
|
||||
void insert(ILogOutputter* adopted,
|
||||
bool alwaysAtHead = false);
|
||||
|
||||
//! 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. Only removes
|
||||
outputters that were inserted with the matching \c alwaysAtHead.
|
||||
*/
|
||||
void pop_front(bool alwaysAtHead = false);
|
||||
|
||||
//! Set the minimum priority filter.
|
||||
/*!
|
||||
Set the filter. Messages below this priority are discarded.
|
||||
The default priority is 4 (INFO) (unless built without NDEBUG
|
||||
in which case it's 5 (DEBUG)). setFilter(const char*) returns
|
||||
true if the priority \c name was recognized; if \c name is NULL
|
||||
then it simply returns true.
|
||||
*/
|
||||
bool setFilter(const char* name);
|
||||
void setFilter(int);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Print a log message
|
||||
/*!
|
||||
Print a log message using the printf-like \c format and arguments
|
||||
preceded by the filename and line number. If \c file is NULL then
|
||||
neither the file nor the line are printed.
|
||||
*/
|
||||
void print(const char* file, int line,
|
||||
const char* format, ...);
|
||||
|
||||
//! Get the minimum priority level.
|
||||
int getFilter() const;
|
||||
|
||||
//! Get the filter name of the current filter level.
|
||||
const char* getFilterName() const;
|
||||
|
||||
//! Get the filter name of a specified filter level.
|
||||
const char* getFilterName(int level) const;
|
||||
|
||||
//! Get the singleton instance of the log
|
||||
static CLog* getInstance();
|
||||
|
||||
//! Get the console filter level (messages above this are not sent to console).
|
||||
int getConsoleMaxLevel() const { return kDEBUG1; }
|
||||
//@}
|
||||
|
||||
private:
|
||||
CLog();
|
||||
void output(ELevel priority, char* msg);
|
||||
|
||||
private:
|
||||
typedef std::list<ILogOutputter*> COutputterList;
|
||||
|
||||
static CLog* s_log;
|
||||
|
||||
CArchMutex m_mutex;
|
||||
COutputterList m_outputters;
|
||||
COutputterList m_alwaysOutputters;
|
||||
int m_maxNewlineLength;
|
||||
int m_maxPriority;
|
||||
};
|
||||
|
||||
/*!
|
||||
\def LOG(arg)
|
||||
Write to the log. Because macros cannot accept variable arguments, this
|
||||
should be invoked like so:
|
||||
\code
|
||||
LOG((CLOG_XXX "%d and %d are %s", x, y, x == y ? "equal" : "not equal"));
|
||||
\endcode
|
||||
In particular, notice the double open and close parentheses. Also note
|
||||
that there is no comma after the \c CLOG_XXX. The \c XXX should be
|
||||
replaced by one of enumerants in \c CLog::ELevel without the leading
|
||||
\c k. For example, \c CLOG_INFO. The special \c CLOG_PRINT level will
|
||||
not be filtered and is never prefixed by the filename and line number.
|
||||
|
||||
If \c NOLOGGING is defined during the build then this macro expands to
|
||||
nothing. If \c NDEBUG is defined during the build then it expands to a
|
||||
call to CLog::print. Otherwise it expands to a call to CLog::printt,
|
||||
which includes the filename and line number.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\def LOGC(expr, arg)
|
||||
Write to the log if and only if expr is true. Because macros cannot accept
|
||||
variable arguments, this should be invoked like so:
|
||||
\code
|
||||
LOGC(x == y, (CLOG_XXX "%d and %d are equal", x, y));
|
||||
\endcode
|
||||
In particular, notice the parentheses around everything after the boolean
|
||||
expression. Also note that there is no comma after the \c CLOG_XXX.
|
||||
The \c XXX should be replaced by one of enumerants in \c CLog::ELevel
|
||||
without the leading \c k. For example, \c CLOG_INFO. The special
|
||||
\c CLOG_PRINT level will not be filtered and is never prefixed by the
|
||||
filename and line number.
|
||||
|
||||
If \c NOLOGGING is defined during the build then this macro expands to
|
||||
nothing. If \c NDEBUG is not defined during the build then it expands
|
||||
to a call to CLog::print that prints the filename and line number,
|
||||
otherwise it expands to a call that doesn't.
|
||||
*/
|
||||
|
||||
#if defined(NOLOGGING)
|
||||
#define LOG(_a1)
|
||||
#define LOGC(_a1, _a2)
|
||||
#define CLOG_TRACE
|
||||
#elif defined(NDEBUG)
|
||||
#define LOG(_a1) CLOG->print _a1
|
||||
#define LOGC(_a1, _a2) if (_a1) CLOG->print _a2
|
||||
#define CLOG_TRACE NULL, 0,
|
||||
#else
|
||||
#define LOG(_a1) CLOG->print _a1
|
||||
#define LOGC(_a1, _a2) if (_a1) CLOG->print _a2
|
||||
#define CLOG_TRACE __FILE__, __LINE__,
|
||||
#endif
|
||||
|
||||
// the CLOG_* defines are line and file plus %z and an octal number (060=0,
|
||||
// 071=9), but the limitation is that once we run out of numbers at either
|
||||
// end, then we resort to using non-numerical chars. this still works (since
|
||||
// to deduce the number we subtract octal \060, so '/' is -1, and ':' is 10
|
||||
|
||||
#define CLOG_PRINT CLOG_TRACE "%z\057" // char is '/'
|
||||
#define CLOG_CRIT CLOG_TRACE "%z\060" // char is '0'
|
||||
#define CLOG_ERR CLOG_TRACE "%z\061"
|
||||
#define CLOG_WARN CLOG_TRACE "%z\062"
|
||||
#define CLOG_NOTE CLOG_TRACE "%z\063"
|
||||
#define CLOG_INFO CLOG_TRACE "%z\064"
|
||||
#define CLOG_DEBUG CLOG_TRACE "%z\065"
|
||||
#define CLOG_DEBUG1 CLOG_TRACE "%z\066"
|
||||
#define CLOG_DEBUG2 CLOG_TRACE "%z\067"
|
||||
#define CLOG_DEBUG3 CLOG_TRACE "%z\070"
|
||||
#define CLOG_DEBUG4 CLOG_TRACE "%z\071" // char is '9'
|
||||
#define CLOG_DEBUG5 CLOG_TRACE "%z\072" // char is ':'
|
||||
|
||||
#endif
|
||||
78
src/lib/base/CMakeLists.txt
Normal file
78
src/lib/base/CMakeLists.txt
Normal file
@@ -0,0 +1,78 @@
|
||||
# synergy -- mouse and keyboard sharing utility
|
||||
# Copyright (C) 2009 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(inc
|
||||
CEvent.h
|
||||
CEventQueue.h
|
||||
CFunctionEventJob.h
|
||||
CFunctionJob.h
|
||||
CLog.h
|
||||
CPriorityQueue.h
|
||||
CSimpleEventQueueBuffer.h
|
||||
CStopwatch.h
|
||||
CString.h
|
||||
CStringUtil.h
|
||||
CUnicode.h
|
||||
IEventJob.h
|
||||
IEventQueue.h
|
||||
IEventQueueBuffer.h
|
||||
IJob.h
|
||||
ILogOutputter.h
|
||||
LogOutputters.h
|
||||
TMethodEventJob.h
|
||||
TMethodJob.h
|
||||
XBase.h
|
||||
ELevel.h
|
||||
)
|
||||
|
||||
set(src
|
||||
CEvent.cpp
|
||||
CEventQueue.cpp
|
||||
CFunctionEventJob.cpp
|
||||
CFunctionJob.cpp
|
||||
CLog.cpp
|
||||
CSimpleEventQueueBuffer.cpp
|
||||
CStopwatch.cpp
|
||||
CStringUtil.cpp
|
||||
CUnicode.cpp
|
||||
IEventQueue.cpp
|
||||
LogOutputters.cpp
|
||||
XBase.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND src ${inc})
|
||||
endif()
|
||||
|
||||
set(inc
|
||||
../arch
|
||||
../common
|
||||
../mt
|
||||
../synergy
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
list(APPEND inc
|
||||
../../..
|
||||
../base
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(${inc})
|
||||
add_library(base STATIC ${src})
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(base common)
|
||||
endif()
|
||||
139
src/lib/base/CPriorityQueue.h
Normal file
139
src/lib/base/CPriorityQueue.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CPRIORITYQUEUE_H
|
||||
#define CPRIORITYQUEUE_H
|
||||
|
||||
#include "stdvector.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
//! A priority queue with an iterator
|
||||
/*!
|
||||
This priority queue is the same as a standard priority queue except:
|
||||
it sorts by std::greater, it has a forward iterator through the elements
|
||||
(which can appear in any order), and its contents can be swapped.
|
||||
*/
|
||||
template <class T, class Container = std::vector<T>,
|
||||
#if defined(_MSC_VER)
|
||||
class Compare = std::greater<Container::value_type> >
|
||||
#else
|
||||
class Compare = std::greater<typename Container::value_type> >
|
||||
#endif
|
||||
class CPriorityQueue {
|
||||
public:
|
||||
typedef typename Container::value_type value_type;
|
||||
typedef typename Container::size_type size_type;
|
||||
typedef typename Container::iterator iterator;
|
||||
typedef typename Container::const_iterator const_iterator;
|
||||
typedef Container container_type;
|
||||
|
||||
CPriorityQueue() { }
|
||||
CPriorityQueue(Container& swappedIn) { swap(swappedIn); }
|
||||
~CPriorityQueue() { }
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Add element
|
||||
void push(const value_type& v)
|
||||
{
|
||||
c.push_back(v);
|
||||
std::push_heap(c.begin(), c.end(), comp);
|
||||
}
|
||||
|
||||
//! Remove head element
|
||||
void pop()
|
||||
{
|
||||
std::pop_heap(c.begin(), c.end(), comp);
|
||||
c.pop_back();
|
||||
}
|
||||
|
||||
//! Erase element
|
||||
void erase(iterator i)
|
||||
{
|
||||
c.erase(i);
|
||||
std::make_heap(c.begin(), c.end(), comp);
|
||||
}
|
||||
|
||||
//! Get start iterator
|
||||
iterator begin()
|
||||
{
|
||||
return c.begin();
|
||||
}
|
||||
|
||||
//! Get end iterator
|
||||
iterator end()
|
||||
{
|
||||
return c.end();
|
||||
}
|
||||
|
||||
//! Swap contents with another priority queue
|
||||
void swap(CPriorityQueue<T, Container, Compare>& q)
|
||||
{
|
||||
c.swap(q.c);
|
||||
}
|
||||
|
||||
//! Swap contents with another container
|
||||
void swap(Container& c2)
|
||||
{
|
||||
c.swap(c2);
|
||||
std::make_heap(c.begin(), c.end(), comp);
|
||||
}
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Returns true if there are no elements
|
||||
bool empty() const
|
||||
{
|
||||
return c.empty();
|
||||
}
|
||||
|
||||
//! Returns the number of elements
|
||||
size_type size() const
|
||||
{
|
||||
return c.size();
|
||||
}
|
||||
|
||||
//! Returns the head element
|
||||
const value_type& top() const
|
||||
{
|
||||
return c.front();
|
||||
}
|
||||
|
||||
//! Get start iterator
|
||||
const_iterator begin() const
|
||||
{
|
||||
return c.begin();
|
||||
}
|
||||
|
||||
//! Get end iterator
|
||||
const_iterator end() const
|
||||
{
|
||||
return c.end();
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
Container c;
|
||||
Compare comp;
|
||||
};
|
||||
|
||||
#endif
|
||||
100
src/lib/base/CSimpleEventQueueBuffer.cpp
Normal file
100
src/lib/base/CSimpleEventQueueBuffer.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CSimpleEventQueueBuffer.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "CArch.h"
|
||||
|
||||
class CEventQueueTimer { };
|
||||
|
||||
//
|
||||
// CSimpleEventQueueBuffer
|
||||
//
|
||||
|
||||
CSimpleEventQueueBuffer::CSimpleEventQueueBuffer()
|
||||
{
|
||||
m_queueMutex = ARCH->newMutex();
|
||||
m_queueReadyCond = ARCH->newCondVar();
|
||||
m_queueReady = false;
|
||||
}
|
||||
|
||||
CSimpleEventQueueBuffer::~CSimpleEventQueueBuffer()
|
||||
{
|
||||
ARCH->closeCondVar(m_queueReadyCond);
|
||||
ARCH->closeMutex(m_queueMutex);
|
||||
}
|
||||
|
||||
void
|
||||
CSimpleEventQueueBuffer::waitForEvent(double timeout)
|
||||
{
|
||||
CArchMutexLock lock(m_queueMutex);
|
||||
CStopwatch timer(true);
|
||||
while (!m_queueReady) {
|
||||
double timeLeft = timeout;
|
||||
if (timeLeft >= 0.0) {
|
||||
timeLeft -= timer.getTime();
|
||||
if (timeLeft < 0.0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ARCH->waitCondVar(m_queueReadyCond, m_queueMutex, timeLeft);
|
||||
}
|
||||
}
|
||||
|
||||
IEventQueueBuffer::Type
|
||||
CSimpleEventQueueBuffer::getEvent(CEvent&, UInt32& dataID)
|
||||
{
|
||||
CArchMutexLock lock(m_queueMutex);
|
||||
if (!m_queueReady) {
|
||||
return kNone;
|
||||
}
|
||||
dataID = m_queue.back();
|
||||
m_queue.pop_back();
|
||||
m_queueReady = !m_queue.empty();
|
||||
return kUser;
|
||||
}
|
||||
|
||||
bool
|
||||
CSimpleEventQueueBuffer::addEvent(UInt32 dataID)
|
||||
{
|
||||
CArchMutexLock lock(m_queueMutex);
|
||||
m_queue.push_front(dataID);
|
||||
if (!m_queueReady) {
|
||||
m_queueReady = true;
|
||||
ARCH->broadcastCondVar(m_queueReadyCond);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CSimpleEventQueueBuffer::isEmpty() const
|
||||
{
|
||||
CArchMutexLock lock(m_queueMutex);
|
||||
return !m_queueReady;
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
CSimpleEventQueueBuffer::newTimer(double, bool) const
|
||||
{
|
||||
return new CEventQueueTimer;
|
||||
}
|
||||
|
||||
void
|
||||
CSimpleEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
|
||||
{
|
||||
delete timer;
|
||||
}
|
||||
52
src/lib/base/CSimpleEventQueueBuffer.h
Normal file
52
src/lib/base/CSimpleEventQueueBuffer.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CSIMPLEEVENTQUEUEBUFFER_H
|
||||
#define CSIMPLEEVENTQUEUEBUFFER_H
|
||||
|
||||
#include "IEventQueueBuffer.h"
|
||||
#include "IArchMultithread.h"
|
||||
#include "stddeque.h"
|
||||
|
||||
//! In-memory event queue buffer
|
||||
/*!
|
||||
An event queue buffer provides a queue of events for an IEventQueue.
|
||||
*/
|
||||
class CSimpleEventQueueBuffer : public IEventQueueBuffer {
|
||||
public:
|
||||
CSimpleEventQueueBuffer();
|
||||
~CSimpleEventQueueBuffer();
|
||||
|
||||
// IEventQueueBuffer overrides
|
||||
virtual void waitForEvent(double timeout);
|
||||
virtual Type getEvent(CEvent& event, UInt32& dataID);
|
||||
virtual bool addEvent(UInt32 dataID);
|
||||
virtual bool isEmpty() const;
|
||||
virtual CEventQueueTimer*
|
||||
newTimer(double duration, bool oneShot) const;
|
||||
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||
|
||||
private:
|
||||
typedef std::deque<UInt32> CEventDeque;
|
||||
|
||||
CArchMutex m_queueMutex;
|
||||
CArchCond m_queueReadyCond;
|
||||
bool m_queueReady;
|
||||
CEventDeque m_queue;
|
||||
};
|
||||
|
||||
#endif
|
||||
129
src/lib/base/CStopwatch.cpp
Normal file
129
src/lib/base/CStopwatch.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CStopwatch.h"
|
||||
#include "CArch.h"
|
||||
|
||||
//
|
||||
// CStopwatch
|
||||
//
|
||||
|
||||
CStopwatch::CStopwatch(bool triggered) :
|
||||
m_mark(0.0),
|
||||
m_triggered(triggered),
|
||||
m_stopped(triggered)
|
||||
{
|
||||
if (!triggered) {
|
||||
m_mark = ARCH->time();
|
||||
}
|
||||
}
|
||||
|
||||
CStopwatch::~CStopwatch()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
double
|
||||
CStopwatch::reset()
|
||||
{
|
||||
if (m_stopped) {
|
||||
const double dt = m_mark;
|
||||
m_mark = 0.0;
|
||||
return dt;
|
||||
}
|
||||
else {
|
||||
const double t = ARCH->time();
|
||||
const double dt = t - m_mark;
|
||||
m_mark = t;
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CStopwatch::stop()
|
||||
{
|
||||
if (m_stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
// save the elapsed time
|
||||
m_mark = ARCH->time() - m_mark;
|
||||
m_stopped = true;
|
||||
}
|
||||
|
||||
void
|
||||
CStopwatch::start()
|
||||
{
|
||||
m_triggered = false;
|
||||
if (!m_stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set the mark such that it reports the time elapsed at stop()
|
||||
m_mark = ARCH->time() - m_mark;
|
||||
m_stopped = false;
|
||||
}
|
||||
|
||||
void
|
||||
CStopwatch::setTrigger()
|
||||
{
|
||||
stop();
|
||||
m_triggered = true;
|
||||
}
|
||||
|
||||
double
|
||||
CStopwatch::getTime()
|
||||
{
|
||||
if (m_triggered) {
|
||||
const double dt = m_mark;
|
||||
start();
|
||||
return dt;
|
||||
}
|
||||
else if (m_stopped) {
|
||||
return m_mark;
|
||||
}
|
||||
else {
|
||||
return ARCH->time() - m_mark;
|
||||
}
|
||||
}
|
||||
|
||||
CStopwatch::operator double()
|
||||
{
|
||||
return getTime();
|
||||
}
|
||||
|
||||
bool
|
||||
CStopwatch::isStopped() const
|
||||
{
|
||||
return m_stopped;
|
||||
}
|
||||
|
||||
double
|
||||
CStopwatch::getTime() const
|
||||
{
|
||||
if (m_stopped) {
|
||||
return m_mark;
|
||||
}
|
||||
else {
|
||||
return ARCH->time() - m_mark;
|
||||
}
|
||||
}
|
||||
|
||||
CStopwatch::operator double() const
|
||||
{
|
||||
return getTime();
|
||||
}
|
||||
111
src/lib/base/CStopwatch.h
Normal file
111
src/lib/base/CStopwatch.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CSTOPWATCH_H
|
||||
#define CSTOPWATCH_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
//! A timer class
|
||||
/*!
|
||||
This class measures time intervals. All time interval measurement
|
||||
should use this class.
|
||||
*/
|
||||
class CStopwatch {
|
||||
public:
|
||||
/*!
|
||||
The default constructor does an implicit reset() or setTrigger().
|
||||
If triggered == false then the clock starts ticking.
|
||||
*/
|
||||
CStopwatch(bool triggered = false);
|
||||
~CStopwatch();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Reset the timer to zero
|
||||
/*!
|
||||
Set the start time to the current time, returning the time since
|
||||
the last reset. This does not remove the trigger if it's set nor
|
||||
does it start a stopped clock. If the clock is stopped then
|
||||
subsequent reset()'s will return 0.
|
||||
*/
|
||||
double reset();
|
||||
|
||||
//! Stop the timer
|
||||
/*!
|
||||
Stop the stopwatch. The time interval while stopped is not
|
||||
counted by the stopwatch. stop() does not remove the trigger.
|
||||
Has no effect if already stopped.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
//! Start the timer
|
||||
/*!
|
||||
Start the stopwatch. start() removes the trigger, even if the
|
||||
stopwatch was already started.
|
||||
*/
|
||||
void start();
|
||||
|
||||
//! Stop the timer and set the trigger
|
||||
/*!
|
||||
setTrigger() stops the clock like stop() except there's an
|
||||
implicit start() the next time (non-const) getTime() is called.
|
||||
This is useful when you want the clock to start the first time
|
||||
you check it.
|
||||
*/
|
||||
void setTrigger();
|
||||
|
||||
//! Get elapsed time
|
||||
/*!
|
||||
Returns the time since the last reset() (or calls reset() and
|
||||
returns zero if the trigger is set).
|
||||
*/
|
||||
double getTime();
|
||||
//! Same as getTime()
|
||||
operator double();
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Check if timer is stopped
|
||||
/*!
|
||||
Returns true if the stopwatch is stopped.
|
||||
*/
|
||||
bool isStopped() const;
|
||||
|
||||
// return the time since the last reset().
|
||||
//! Get elapsed time
|
||||
/*!
|
||||
Returns the time since the last reset(). This cannot trigger the
|
||||
stopwatch to start and will not clear the trigger.
|
||||
*/
|
||||
double getTime() const;
|
||||
//! Same as getTime() const
|
||||
operator double() const;
|
||||
//@}
|
||||
|
||||
private:
|
||||
double getClock() const;
|
||||
|
||||
private:
|
||||
double m_mark;
|
||||
bool m_triggered;
|
||||
bool m_stopped;
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user