removed restart function from platform. no longer trying to

restart if the X server connection was lost;  since synergy
is likely to be started by xdm or the user's xsession, it's
better for synergy to simply terminate when the connection
is lost.  synergy will still restart due to other errors.
also fixed numerous other minor bugs and cleaned some stuff
up (like app error codes are now consistent and enumerated
in Version.h, for lack of a better place).  and boosted
version and protocol numbers.
This commit is contained in:
crs 2002-07-24 13:01:18 +00:00
parent d9ec880291
commit c6ecc79c0d
16 changed files with 301 additions and 347 deletions

View File

@ -127,7 +127,6 @@ CClient::open()
} }
catch (XScreenOpenFailure&) { catch (XScreenOpenFailure&) {
// can't open screen yet. wait a few seconds to retry. // can't open screen yet. wait a few seconds to retry.
CThread::sleep(3.0);
log((CLOG_INFO "failed to open screen")); log((CLOG_INFO "failed to open screen"));
return false; return false;
} }
@ -360,7 +359,15 @@ CClient::openSecondaryScreen()
m_screen = new CXWindowsSecondaryScreen(this); m_screen = new CXWindowsSecondaryScreen(this);
#endif #endif
log((CLOG_DEBUG1 "opening secondary screen")); log((CLOG_DEBUG1 "opening secondary screen"));
m_screen->open(); try {
m_screen->open();
}
catch (...) {
log((CLOG_DEBUG1 "destroying secondary screen"));
delete m_screen;
m_screen = NULL;
throw;
}
} }
void void
@ -472,7 +479,9 @@ CClient::runServer()
log((CLOG_INFO "connected to server")); log((CLOG_INFO "connected to server"));
break; break;
} }
catch (XSocketConnect&) { catch (XSocketConnect& e) {
log((CLOG_DEBUG1 "failed to connect to server: %s", e.getErrstr()));
// failed to connect. if not camping then rethrow. // failed to connect. if not camping then rethrow.
if (!m_camp) { if (!m_camp) {
throw; throw;

View File

@ -67,95 +67,99 @@ static
int int
realMain(CMutex* mutex) realMain(CMutex* mutex)
{ {
try { // caller should have mutex locked on entry
// initialize threading library
CThread::init();
// make logging thread safe int result = kExitSuccess;
CMutex logMutex; do {
s_logMutex = &logMutex;
CLog::setLock(&logLock);
bool locked = true;
try { try {
// create client // initialize threading library
s_client = new CClient(s_name); CThread::init();
s_client->camp(s_camp);
s_client->setAddress(s_serverAddress); // make logging thread safe
if (!s_client->open()) { CMutex logMutex;
s_logMutex = &logMutex;
CLog::setLock(&logLock);
bool opened = false;
bool locked = true;
try {
// create client
s_client = new CClient(s_name);
s_client->camp(s_camp);
s_client->setAddress(s_serverAddress);
if (s_client->open()) {
opened = true;
// run client
if (mutex != NULL) {
mutex->unlock();
}
locked = false;
s_client->run();
locked = true;
if (mutex != NULL) {
mutex->lock();
}
// get client status
if (s_client->wasRejected()) {
// wait a while before retrying. we don't want
// to bother the server very often if it doesn't
// want us.
if (s_restartable) {
CThread::sleep(60.0);
}
else {
result = kExitFailed;
}
}
// clean up
s_client->close();
}
else {
// wait a few seconds before retrying
if (s_restartable) {
CThread::sleep(3.0);
}
else {
result = kExitFailed;
}
}
// clean up
delete s_client; delete s_client;
s_client = NULL; s_client = NULL;
return 16; CLog::setLock(NULL);
s_logMutex = NULL;
} }
catch (...) {
// run client // clean up
if (mutex != NULL) { if (!locked && mutex != NULL) {
mutex->unlock(); mutex->lock();
}
if (s_client != NULL) {
if (opened) {
s_client->close();
}
delete s_client;
s_client = NULL;
}
CLog::setLock(NULL);
s_logMutex = NULL;
throw;
} }
locked = false;
s_client->run();
locked = true;
if (mutex != NULL) {
mutex->lock();
}
// get client status
bool success = !s_client->wasRejected();
// clean up
s_client->close();
delete s_client;
s_client = NULL;
CLog::setLock(NULL);
s_logMutex = NULL;
return success ? 16 : 0;
} }
catch (...) { catch (XBase& e) {
// clean up log((CLOG_CRIT "failed: %s", e.what()));
if (!locked && mutex != NULL) {
mutex->lock();
}
if (s_client != NULL) {
s_client->close();
delete s_client;
s_client = NULL;
}
CLog::setLock(NULL);
s_logMutex = NULL;
throw;
} }
} catch (XThread&) {
catch (XBase& e) { // terminated
log((CLOG_CRIT "failed: %s", e.what())); return kExitTerminated;
return 16; }
} } while (s_restartable);
catch (XThread&) {
// terminated
return 1;
}
}
static return result;
int
restartMain()
{
return realMain(NULL);
}
// invoke realMain and wait for it. if s_restartable then keep
// restarting realMain until it returns a terminate code.
static
int
restartableMain()
{
if (s_restartable) {
CPlatform platform;
return platform.restart(restartMain, 16);
}
else {
return realMain(NULL);
}
} }
@ -229,10 +233,7 @@ PLATFORM_ARGS
" ourself to the server.\n" " ourself to the server.\n"
" -1, --no-restart do not try to restart the client if it fails for\n" " -1, --no-restart do not try to restart the client if it fails for\n"
" some reason.\n" " some reason.\n"
"* --restart restart the client automatically if it fails for\n" "* --restart restart the client automatically if it fails.\n"
" some unexpected reason, including the server\n"
" disconnecting but not including failing to\n"
" connect to the server.\n"
PLATFORM_DESC PLATFORM_DESC
" -h, --help display this help and exit.\n" " -h, --help display this help and exit.\n"
" --version display version information and exit.\n" " --version display version information and exit.\n"
@ -261,7 +262,7 @@ isArg(int argi, int argc, const char** argv,
if (argi + minRequiredParameters >= argc) { if (argi + minRequiredParameters >= argc) {
log((CLOG_PRINT "%s: missing arguments for `%s'" BYE, log((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
pname, argv[argi], pname)); pname, argv[argi], pname));
bye(2); bye(kExitArgs);
} }
return true; return true;
} }
@ -329,12 +330,12 @@ parse(int argc, const char** argv)
else if (isArg(i, argc, argv, "-h", "--help")) { else if (isArg(i, argc, argv, "-h", "--help")) {
help(); help();
bye(0); bye(kExitSuccess);
} }
else if (isArg(i, argc, argv, NULL, "--version")) { else if (isArg(i, argc, argv, NULL, "--version")) {
version(); version();
bye(0); bye(kExitSuccess);
} }
#if WINDOWS_LIKE #if WINDOWS_LIKE
@ -344,7 +345,7 @@ parse(int argc, const char** argv)
log((CLOG_PRINT "%s: `--install' and `--uninstall'" log((CLOG_PRINT "%s: `--install' and `--uninstall'"
" are mutually exclusive" BYE, " are mutually exclusive" BYE,
pname, argv[i], pname)); pname, argv[i], pname));
bye(2); bye(kExitArgs);
} }
} }
#endif #endif
@ -356,7 +357,7 @@ parse(int argc, const char** argv)
log((CLOG_PRINT "%s: `--install' and `--uninstall'" log((CLOG_PRINT "%s: `--install' and `--uninstall'"
" are mutually exclusive" BYE, " are mutually exclusive" BYE,
pname, argv[i], pname)); pname, argv[i], pname));
bye(2); bye(kExitArgs);
} }
} }
#endif #endif
@ -370,7 +371,7 @@ parse(int argc, const char** argv)
else if (argv[i][0] == '-') { else if (argv[i][0] == '-') {
log((CLOG_PRINT "%s: unrecognized option `%s'" BYE, log((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
pname, argv[i], pname)); pname, argv[i], pname));
bye(2); bye(kExitArgs);
} }
else { else {
@ -386,19 +387,19 @@ parse(int argc, const char** argv)
log((CLOG_PRINT "%s: unrecognized option `%s' to `%s'" BYE, log((CLOG_PRINT "%s: unrecognized option `%s' to `%s'" BYE,
pname, argv[i], pname, pname, argv[i], pname,
s_install ? "--install" : "--uninstall")); s_install ? "--install" : "--uninstall"));
bye(2); bye(kExitArgs);
} }
} }
else { else {
if (i == argc) { if (i == argc) {
log((CLOG_PRINT "%s: a server address or name is required" BYE, log((CLOG_PRINT "%s: a server address or name is required" BYE,
pname, pname)); pname, pname));
bye(1); bye(kExitArgs);
} }
if (i + 1 != argc) { if (i + 1 != argc) {
log((CLOG_PRINT "%s: unrecognized option `%s'" BYE, log((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
pname, argv[i], pname)); pname, argv[i], pname));
bye(2); bye(kExitArgs);
} }
// save server address // save server address
@ -408,7 +409,7 @@ parse(int argc, const char** argv)
catch (XSocketAddress&) { catch (XSocketAddress&) {
log((CLOG_PRINT "%s: invalid server address" BYE, log((CLOG_PRINT "%s: invalid server address" BYE,
pname, pname)); pname, pname));
bye(2); bye(kExitArgs);
} }
} }
@ -432,7 +433,7 @@ parse(int argc, const char** argv)
if (!CLog::setFilter(s_logFilter)) { if (!CLog::setFilter(s_logFilter)) {
log((CLOG_PRINT "%s: unrecognized log level `%s'" BYE, log((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
pname, s_logFilter, pname)); pname, s_logFilter, pname));
bye(2); bye(kExitArgs);
} }
} }
@ -488,7 +489,7 @@ daemonStartup(IPlatform* iplatform, int argc, const char** argv)
parse(argc, argv); parse(argc, argv);
if (s_install || s_uninstall) { if (s_install || s_uninstall) {
// not allowed to install/uninstall from service // not allowed to install/uninstall from service
throw CWin32Platform::CDaemonFailed(1); throw CWin32Platform::CDaemonFailed(kExitArgs);
} }
// run as a service // run as a service
@ -499,7 +500,7 @@ static
int int
daemonStartup95(IPlatform*, int, const char**) daemonStartup95(IPlatform*, int, const char**)
{ {
return restartableMain(); return realMain(NULL);
} }
int WINAPI int WINAPI
@ -529,7 +530,7 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
int result = platform.daemonize(DAEMON_NAME, &daemonStartup); int result = platform.daemonize(DAEMON_NAME, &daemonStartup);
if (result == -1) { if (result == -1) {
log((CLOG_CRIT "failed to start as a service" BYE, pname)); log((CLOG_CRIT "failed to start as a service" BYE, pname));
return 16; return kExitFailed;
} }
return result; return result;
} }
@ -544,7 +545,7 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
if (GetModuleFileName(NULL, path, if (GetModuleFileName(NULL, path,
sizeof(path) / sizeof(path[0])) == 0) { sizeof(path) / sizeof(path[0])) == 0) {
log((CLOG_CRIT "cannot determine absolute path to program")); log((CLOG_CRIT "cannot determine absolute path to program"));
return 16; return kExitFailed;
} }
// construct the command line to start the service with // construct the command line to start the service with
@ -567,24 +568,24 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
"Shares this system's mouse and keyboard with others.", "Shares this system's mouse and keyboard with others.",
path, commandLine.c_str())) { path, commandLine.c_str())) {
log((CLOG_CRIT "failed to install service")); log((CLOG_CRIT "failed to install service"));
return 16; return kExitFailed;
} }
log((CLOG_PRINT "installed successfully")); log((CLOG_PRINT "installed successfully"));
return 0; return kExitSuccess;
} }
else if (s_uninstall) { else if (s_uninstall) {
switch (platform.uninstallDaemon(DAEMON_NAME)) { switch (platform.uninstallDaemon(DAEMON_NAME)) {
case IPlatform::kSuccess: case IPlatform::kSuccess:
log((CLOG_PRINT "uninstalled successfully")); log((CLOG_PRINT "uninstalled successfully"));
return 0; return kExitSuccess;
case IPlatform::kFailed: case IPlatform::kFailed:
log((CLOG_CRIT "failed to uninstall service")); log((CLOG_CRIT "failed to uninstall service"));
return 16; return kExitFailed;
case IPlatform::kAlready: case IPlatform::kAlready:
log((CLOG_CRIT "service isn't installed")); log((CLOG_CRIT "service isn't installed"));
return 16; return kExitFailed;
} }
} }
@ -599,18 +600,18 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
result = platform.daemonize(DAEMON_NAME, &daemonStartup95); result = platform.daemonize(DAEMON_NAME, &daemonStartup95);
if (result == -1) { if (result == -1) {
log((CLOG_CRIT "failed to start as a service" BYE, pname)); log((CLOG_CRIT "failed to start as a service" BYE, pname));
return 16; return kExitFailed;
} }
} }
else { else {
// cannot start a service from the command line so just // cannot start a service from the command line so just
// run normally (except with log messages redirected). // run normally (except with log messages redirected).
result = restartableMain(); result = realMain(NULL);
} }
} }
else { else {
// run // run
result = restartableMain(); result = realMain(NULL);
} }
CNetwork::cleanup(); CNetwork::cleanup();
@ -624,7 +625,7 @@ static
int int
daemonStartup(IPlatform*, int, const char**) daemonStartup(IPlatform*, int, const char**)
{ {
return restartableMain(); return realMain(NULL);
} }
int int
@ -647,11 +648,11 @@ main(int argc, char** argv)
result = platform.daemonize(DAEMON_NAME, &daemonStartup); result = platform.daemonize(DAEMON_NAME, &daemonStartup);
if (result == -1) { if (result == -1) {
log((CLOG_CRIT "failed to daemonize")); log((CLOG_CRIT "failed to daemonize"));
return 16; return kExitFailed;
} }
} }
else { else {
result = restartableMain(); result = realMain(NULL);
} }
CNetwork::cleanup(); CNetwork::cleanup();

View File

@ -115,8 +115,9 @@ CTCPSocket::connect(const CNetworkAddress& addr)
addr.getAddressLength()) == CNetwork::Error) { addr.getAddressLength()) == CNetwork::Error) {
// check for failure // check for failure
if (CNetwork::getsockerror() != CNetwork::kECONNECTING) { if (CNetwork::getsockerror() != CNetwork::kECONNECTING) {
XSocketConnect e;
CNetwork::setblocking(m_fd, true); CNetwork::setblocking(m_fd, true);
throw XSocketConnect(); throw e;
} }
// wait for connection or failure // wait for connection or failure
@ -130,8 +131,12 @@ CTCPSocket::connect(const CNetworkAddress& addr)
if ((pfds[0].revents & (CNetwork::kPOLLERR | if ((pfds[0].revents & (CNetwork::kPOLLERR |
CNetwork::kPOLLNVAL)) != 0) { CNetwork::kPOLLNVAL)) != 0) {
// connection failed // connection failed
int error = 0;
CNetwork::AddressLength size = sizeof(error);
CNetwork::setblocking(m_fd, true); CNetwork::setblocking(m_fd, true);
throw XSocketConnect(); CNetwork::getsockopt(m_fd, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char*>(&error), &size);
throw XSocketConnect(error);
} }
if ((pfds[0].revents & CNetwork::kPOLLOUT) != 0) { if ((pfds[0].revents & CNetwork::kPOLLOUT) != 0) {
int error; int error;
@ -142,7 +147,7 @@ CTCPSocket::connect(const CNetworkAddress& addr)
error != 0) { error != 0) {
// connection failed // connection failed
CNetwork::setblocking(m_fd, true); CNetwork::setblocking(m_fd, true);
throw XSocketConnect(); throw XSocketConnect(error);
} }
// connected! // connected!

View File

@ -36,20 +36,36 @@ public:
}; };
class XSocketBind : public XSocketErrno { class XSocketBind : public XSocketErrno {
public:
XSocketBind() { }
XSocketBind(int e) : XSocketErrno(e) { }
protected: protected:
// XBase overrides // XBase overrides
virtual CString getWhat() const throw(); virtual CString getWhat() const throw();
}; };
class XSocketAddressInUse : public XSocketBind { }; class XSocketAddressInUse : public XSocketBind {
public:
XSocketAddressInUse() { }
XSocketAddressInUse(int e) : XSocketBind(e) { }
};
class XSocketConnect : public XSocketErrno { class XSocketConnect : public XSocketErrno {
public:
XSocketConnect() { }
XSocketConnect(int e) : XSocketErrno(e) { }
protected: protected:
// XBase overrides // XBase overrides
virtual CString getWhat() const throw(); virtual CString getWhat() const throw();
}; };
class XSocketCreate : public XSocketErrno { class XSocketCreate : public XSocketErrno {
public:
XSocketCreate() { }
XSocketCreate(int e) : XSocketErrno(e) { }
protected: protected:
// XBase overrides // XBase overrides
virtual CString getWhat() const throw(); virtual CString getWhat() const throw();

View File

@ -7,22 +7,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <syslog.h> #include <syslog.h>
#include <signal.h>
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#if !defined(WIFSIGNALED)
# define WIFSIGNALED(w) (((w) & 0xff) != 0x7f && ((w) & 0xff) != 0)
#endif
#if !defined(WIFEXITED)
# define WIFEXITED(w) (((w) & 0xff) == 0)
#endif
#if !defined(WTERMSIG)
# define WTERMSIG(w) ((w) & 0x7f)
#endif
#if !defined(WEXITSTATUS)
# define WEXITSTATUS(w) (((w) >> 8) & 0xff)
#endif
// //
@ -106,64 +90,6 @@ CUnixPlatform::installDaemonLogger(const char* name)
CLog::setOutputter(&CUnixPlatform::deamonLogger); CLog::setOutputter(&CUnixPlatform::deamonLogger);
} }
int
CUnixPlatform::restart(RestartFunc func, int minErrorCode)
{
// rely on child to catch these signals
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGTERM);
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
for (;;) {
switch (fork()) {
default:
{
// parent process. wait for child to exit.
int status;
if (wait(&status) == -1) {
// wait failed. this is unexpected so bail.
log((CLOG_CRIT "wait() failed"));
return minErrorCode;
}
// what happened? if the child exited normally with a
// status less than 16 then the child was deliberately
// terminated so we also terminate.
if (WIFEXITED(status) && WEXITSTATUS(status) < minErrorCode) {
return WEXITSTATUS(status);
}
// did child die horribly?
if (WIFSIGNALED(status)) {
switch (WTERMSIG(status)) {
case SIGHUP:
case SIGINT:
case SIGQUIT:
case SIGTERM:
break;
default:
// uh oh. bail out.
return 16;
}
}
}
break;
case -1:
// fork() failed. log the error and proceed as a child
log((CLOG_WARN "fork() failed; cannot automatically restart on error"));
// fall through
case 0:
// child process
return func();
}
}
}
const char* const char*
CUnixPlatform::getBasename(const char* pathname) const CUnixPlatform::getBasename(const char* pathname) const
{ {

View File

@ -16,7 +16,6 @@ public:
virtual EResult uninstallDaemon(const char* name); virtual EResult uninstallDaemon(const char* name);
virtual int daemonize(const char* name, DaemonFunc); virtual int daemonize(const char* name, DaemonFunc);
virtual void installDaemonLogger(const char* name); virtual void installDaemonLogger(const char* name);
virtual int restart(RestartFunc, int minErrorCode);
virtual const char* getBasename(const char* pathname) const; virtual const char* getBasename(const char* pathname) const;
virtual CString getUserDirectory() const; virtual CString getUserDirectory() const;
virtual CString getSystemDirectory() const; virtual CString getSystemDirectory() const;

View File

@ -319,15 +319,6 @@ CWin32Platform::installDaemonLogger(const char* name)
} }
} }
int
CWin32Platform::restart(RestartFunc func, int /*minErrorCode*/)
{
// FIXME -- start in separate process or thread. note that this
// isn't too critical as win32 doesn't force us to terminate for
// any reason so we should never have to restart.
return func();
}
const char* const char*
CWin32Platform::getBasename(const char* pathname) const CWin32Platform::getBasename(const char* pathname) const
{ {

View File

@ -49,7 +49,6 @@ public:
virtual EResult uninstallDaemon(const char* name); virtual EResult uninstallDaemon(const char* name);
virtual int daemonize(const char* name, DaemonFunc); virtual int daemonize(const char* name, DaemonFunc);
virtual void installDaemonLogger(const char* name); virtual void installDaemonLogger(const char* name);
virtual int restart(RestartFunc, int minErrorCode);
virtual const char* getBasename(const char* pathname) const; virtual const char* getBasename(const char* pathname) const;
virtual CString getUserDirectory() const; virtual CString getUserDirectory() const;
virtual CString getSystemDirectory() const; virtual CString getSystemDirectory() const;

View File

@ -93,6 +93,11 @@ CXWindowsScreen::CXWindowsScreen(IScreenReceiver* receiver,
assert(m_eventHandler != NULL); assert(m_eventHandler != NULL);
s_screen = this; s_screen = this;
// no clipboards to start with
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
m_clipboard[id] = NULL;
}
} }
CXWindowsScreen::~CXWindowsScreen() CXWindowsScreen::~CXWindowsScreen()
@ -670,7 +675,10 @@ CDisplayLock::CDisplayLock(const CXWindowsScreen* screen) :
m_mutex(&screen->m_mutex), m_mutex(&screen->m_mutex),
m_display(screen->m_display) m_display(screen->m_display)
{ {
assert(m_display != NULL); // note -- it's permitted for m_display to be NULL. that might
// happen if we couldn't connect to the display or if the
// display unexpectedly disconnected. the caller is expected
// to check for NULL as necessary.
m_mutex->lock(); m_mutex->lock();
} }

View File

@ -206,7 +206,9 @@ CXWindowsUtil::CErrorLock::CErrorLock(Display* display,
CXWindowsUtil::CErrorLock::~CErrorLock() CXWindowsUtil::CErrorLock::~CErrorLock()
{ {
// make sure everything finishes before uninstalling handler // make sure everything finishes before uninstalling handler
XSync(m_display, False); if (m_display != NULL) {
XSync(m_display, False);
}
// restore old handler // restore old handler
XSetErrorHandler(m_oldXHandler); XSetErrorHandler(m_oldXHandler);
@ -217,7 +219,9 @@ void
CXWindowsUtil::CErrorLock::install(ErrorHandler handler, void* data) CXWindowsUtil::CErrorLock::install(ErrorHandler handler, void* data)
{ {
// make sure everything finishes before installing handler // make sure everything finishes before installing handler
XSync(m_display, False); if (m_display != NULL) {
XSync(m_display, False);
}
// install handler // install handler
m_handler = handler; m_handler = handler;

View File

@ -7,7 +7,6 @@
class IPlatform : public IInterface { class IPlatform : public IInterface {
public: public:
typedef int (*DaemonFunc)(IPlatform*, int argc, const char** argv); typedef int (*DaemonFunc)(IPlatform*, int argc, const char** argv);
typedef int (*RestartFunc)();
enum EResult { enum EResult {
kSuccess, kSuccess,
@ -53,11 +52,6 @@ public:
// in the log to identify this process. // in the log to identify this process.
virtual void installDaemonLogger(const char* name) = 0; virtual void installDaemonLogger(const char* name) = 0;
// continually restart the given function in a separate process
// or thread until it exits normally with a code less than the
// given code then return the code.
virtual int restart(RestartFunc, int minErrorCode) = 0;
// accessors // accessors
// find the basename in the given pathname // find the basename in the given pathname

View File

@ -34,6 +34,7 @@ CPrimaryClient::CPrimaryClient(IServer* server,
CPrimaryClient::~CPrimaryClient() CPrimaryClient::~CPrimaryClient()
{ {
log((CLOG_DEBUG1 "destroying primary screen"));
delete m_screen; delete m_screen;
} }

View File

@ -59,13 +59,11 @@ CServer::open()
} }
catch (XScreenOpenFailure&) { catch (XScreenOpenFailure&) {
// can't open screen yet. wait a few seconds to retry. // can't open screen yet. wait a few seconds to retry.
CThread::sleep(3.0);
log((CLOG_INFO "failed to open screen")); log((CLOG_INFO "failed to open screen"));
return false; return false;
} }
catch (XUnknownClient& e) { catch (XUnknownClient& e) {
// can't open screen yet. wait a few seconds to retry. // can't open screen yet. wait a few seconds to retry.
CThread::sleep(3.0);
log((CLOG_CRIT "unknown screen name `%s'", e.getName().c_str())); log((CLOG_CRIT "unknown screen name `%s'", e.getName().c_str()));
return false; return false;
} }
@ -1135,7 +1133,9 @@ CServer::acceptClients(void*)
listen->bind(m_config.getSynergyAddress()); listen->bind(m_config.getSynergyAddress());
break; break;
} }
catch (XSocketAddressInUse&) { catch (XSocketBind& e) {
log((CLOG_DEBUG1 "bind failed: %s", e.getErrstr()));
// give up if we've waited too long // give up if we've waited too long
if (timer.getTime() >= m_bindTimeout) { if (timer.getTime() >= m_bindTimeout) {
log((CLOG_DEBUG1 "waited too long to bind, giving up")); log((CLOG_DEBUG1 "waited too long to bind, giving up"));
@ -1143,7 +1143,6 @@ CServer::acceptClients(void*)
} }
// wait a bit before retrying // wait a bit before retrying
log((CLOG_DEBUG1 "bind failed; waiting to retry"));
CThread::sleep(5.0); CThread::sleep(5.0);
} }
} }
@ -1419,7 +1418,9 @@ CServer::acceptHTTPClients(void*)
listen->bind(m_config.getHTTPAddress()); listen->bind(m_config.getHTTPAddress());
break; break;
} }
catch (XSocketAddressInUse&) { catch (XSocketBind& e) {
log((CLOG_DEBUG1 "bind HTTP failed: %s", e.getErrstr()));
// give up if we've waited too long // give up if we've waited too long
if (timer.getTime() >= m_bindTimeout) { if (timer.getTime() >= m_bindTimeout) {
log((CLOG_DEBUG1 "waited too long to bind HTTP, giving up")); log((CLOG_DEBUG1 "waited too long to bind HTTP, giving up"));
@ -1427,7 +1428,6 @@ CServer::acceptHTTPClients(void*)
} }
// wait a bit before retrying // wait a bit before retrying
log((CLOG_DEBUG1 "bind HTTP failed; waiting to retry"));
CThread::sleep(5.0); CThread::sleep(5.0);
} }
} }

View File

@ -77,114 +77,106 @@ static
int int
realMain(CMutex* mutex) realMain(CMutex* mutex)
{ {
// s_serverLock should have mutex locked on entry // caller should have mutex locked on entry
try { int result = kExitSuccess;
// initialize threading library do {
CThread::init();
// make logging thread safe
CMutex logMutex;
s_logMutex = &logMutex;
CLog::setLock(&logLock);
bool locked = true;
try { try {
// if configuration has no screens then add this system // initialize threading library
// as the default CThread::init();
if (s_config.begin() == s_config.end()) {
s_config.addScreen(s_name);
}
// set the contact address, if provided, in the config. // make logging thread safe
// otherwise, if the config doesn't have an address, use CMutex logMutex;
// the default. s_logMutex = &logMutex;
if (s_synergyAddress.isValid()) { CLog::setLock(&logLock);
s_config.setSynergyAddress(s_synergyAddress);
}
else if (!s_config.getSynergyAddress().isValid()) {
s_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
}
// set HTTP address is provided bool opened = false;
if (s_httpAddress.isValid()) { bool locked = true;
s_config.setHTTPAddress(s_httpAddress); try {
} // if configuration has no screens then add this system
// as the default
if (s_config.begin() == s_config.end()) {
s_config.addScreen(s_name);
}
// create server // set the contact address, if provided, in the config.
s_server = new CServer(s_name); // otherwise, if the config doesn't have an address, use
s_server->setConfig(s_config); // the default.
if (!s_server->open()) { if (s_synergyAddress.isValid()) {
s_config.setSynergyAddress(s_synergyAddress);
}
else if (!s_config.getSynergyAddress().isValid()) {
s_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
}
// set HTTP address if provided
if (s_httpAddress.isValid()) {
s_config.setHTTPAddress(s_httpAddress);
}
// create server
s_server = new CServer(s_name);
s_server->setConfig(s_config);
if (s_server->open()) {
opened = true;
// run server (unlocked)
if (mutex != NULL) {
mutex->unlock();
}
locked = false;
s_server->run();
locked = true;
if (mutex != NULL) {
mutex->lock();
}
// clean up
s_server->close();
}
else {
// wait a few seconds before retrying
if (s_restartable) {
CThread::sleep(3.0);
}
else {
result = kExitFailed;
}
}
// clean up
delete s_server; delete s_server;
s_server = NULL; s_server = NULL;
return 16; CLog::setLock(NULL);
s_logMutex = NULL;
} }
catch (...) {
// run server (unlocked) // clean up
if (mutex != NULL) { if (!locked && mutex != NULL) {
mutex->unlock(); mutex->lock();
}
if (s_server != NULL) {
if (opened) {
s_server->close();
}
delete s_server;
s_server = NULL;
}
CLog::setLock(NULL);
s_logMutex = NULL;
throw;
} }
locked = false;
s_server->run();
locked = true;
if (mutex != NULL) {
mutex->lock();
}
// clean up
s_server->close();
delete s_server;
s_server = NULL;
CLog::setLock(NULL);
s_logMutex = NULL;
} }
catch (...) { catch (XBase& e) {
// clean up log((CLOG_CRIT "failed: %s", e.what()));
if (!locked && mutex != NULL) {
mutex->lock();
}
if (s_server != NULL) {
s_server->close();
delete s_server;
s_server = NULL;
}
CLog::setLock(NULL);
s_logMutex = NULL;
throw;
} }
} catch (XThread&) {
catch (XBase& e) { // terminated
log((CLOG_CRIT "failed: %s", e.what())); return kExitTerminated;
return 16; }
} } while (s_restartable);
catch (XThread&) {
// terminated
return 1;
}
return 0; return result;
}
static
int
restartMain()
{
return realMain(NULL);
}
// invoke realMain and wait for it. if s_restartable then keep
// restarting realMain until it returns a terminate code.
static
int
restartableMain()
{
if (s_restartable) {
CPlatform platform;
return platform.restart(restartMain, 16);
}
else {
return realMain(NULL);
}
} }
@ -308,7 +300,7 @@ isArg(int argi, int argc, const char** argv,
if (argi + minRequiredParameters >= argc) { if (argi + minRequiredParameters >= argc) {
log((CLOG_PRINT "%s: missing arguments for `%s'" BYE, log((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
pname, argv[argi], pname)); pname, argv[argi], pname));
bye(2); bye(kExitArgs);
} }
return true; return true;
} }
@ -347,7 +339,7 @@ parse(int argc, const char** argv)
catch (XSocketAddress&) { catch (XSocketAddress&) {
log((CLOG_PRINT "%s: invalid address for `%s'" BYE, log((CLOG_PRINT "%s: invalid address for `%s'" BYE,
pname, argv[i], pname)); pname, argv[i], pname));
bye(2); bye(kExitArgs);
} }
++i; ++i;
} }
@ -360,7 +352,7 @@ parse(int argc, const char** argv)
catch (XSocketAddress&) { catch (XSocketAddress&) {
log((CLOG_PRINT "%s: invalid address for `%s'" BYE, log((CLOG_PRINT "%s: invalid address for `%s'" BYE,
pname, argv[i], pname)); pname, argv[i], pname));
bye(2); bye(kExitArgs);
} }
++i; ++i;
} }
@ -397,12 +389,12 @@ parse(int argc, const char** argv)
else if (isArg(i, argc, argv, "-h", "--help")) { else if (isArg(i, argc, argv, "-h", "--help")) {
help(); help();
bye(0); bye(kExitSuccess);
} }
else if (isArg(i, argc, argv, NULL, "--version")) { else if (isArg(i, argc, argv, NULL, "--version")) {
version(); version();
bye(0); bye(kExitSuccess);
} }
#if WINDOWS_LIKE #if WINDOWS_LIKE
@ -412,7 +404,7 @@ parse(int argc, const char** argv)
log((CLOG_PRINT "%s: `--install' and `--uninstall'" log((CLOG_PRINT "%s: `--install' and `--uninstall'"
" are mutually exclusive" BYE, " are mutually exclusive" BYE,
pname, argv[i], pname)); pname, argv[i], pname));
bye(2); bye(kExitArgs);
} }
} }
#endif #endif
@ -424,7 +416,7 @@ parse(int argc, const char** argv)
log((CLOG_PRINT "%s: `--install' and `--uninstall'" log((CLOG_PRINT "%s: `--install' and `--uninstall'"
" are mutually exclusive" BYE, " are mutually exclusive" BYE,
pname, argv[i], pname)); pname, argv[i], pname));
bye(2); bye(kExitArgs);
} }
} }
#endif #endif
@ -438,7 +430,7 @@ parse(int argc, const char** argv)
else if (argv[i][0] == '-') { else if (argv[i][0] == '-') {
log((CLOG_PRINT "%s: unrecognized option `%s'" BYE, log((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
pname, argv[i], pname)); pname, argv[i], pname));
bye(2); bye(kExitArgs);
} }
else { else {
@ -451,7 +443,7 @@ parse(int argc, const char** argv)
if (i != argc) { if (i != argc) {
log((CLOG_PRINT "%s: unrecognized option `%s'" BYE, log((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
pname, argv[i], pname)); pname, argv[i], pname));
bye(2); bye(kExitArgs);
} }
// increase default filter level for daemon. the user must // increase default filter level for daemon. the user must
@ -474,7 +466,7 @@ parse(int argc, const char** argv)
if (!CLog::setFilter(s_logFilter)) { if (!CLog::setFilter(s_logFilter)) {
log((CLOG_PRINT "%s: unrecognized log level `%s'" BYE, log((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
pname, s_logFilter, pname)); pname, s_logFilter, pname));
bye(2); bye(kExitArgs);
} }
} }
@ -499,7 +491,7 @@ loadConfig(const char* pathname, bool require)
if (require) { if (require) {
log((CLOG_PRINT "%s: cannot read configuration '%s': %s", log((CLOG_PRINT "%s: cannot read configuration '%s': %s",
pname, pathname, e.what())); pname, pathname, e.what()));
bye(3); bye(kExitConfig);
} }
else { else {
log((CLOG_DEBUG "cannot read configuration \"%s\": %s", log((CLOG_DEBUG "cannot read configuration \"%s\": %s",
@ -595,7 +587,7 @@ daemonStartup(IPlatform* iplatform, int argc, const char** argv)
parse(argc, argv); parse(argc, argv);
if (s_install || s_uninstall) { if (s_install || s_uninstall) {
// not allowed to install/uninstall from service // not allowed to install/uninstall from service
throw CWin32Platform::CDaemonFailed(1); throw CWin32Platform::CDaemonFailed(kExitArgs);
} }
// load configuration // load configuration
@ -609,7 +601,7 @@ static
int int
daemonStartup95(IPlatform*, int, const char**) daemonStartup95(IPlatform*, int, const char**)
{ {
return restartableMain(); return realMain(NULL);
} }
int WINAPI int WINAPI
@ -639,7 +631,7 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
int result = platform.daemonize(DAEMON_NAME, &daemonStartup); int result = platform.daemonize(DAEMON_NAME, &daemonStartup);
if (result == -1) { if (result == -1) {
log((CLOG_CRIT "failed to start as a service" BYE, pname)); log((CLOG_CRIT "failed to start as a service" BYE, pname));
return 16; return kExitFailed;
} }
return result; return result;
} }
@ -654,7 +646,7 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
if (GetModuleFileName(NULL, path, if (GetModuleFileName(NULL, path,
sizeof(path) / sizeof(path[0])) == 0) { sizeof(path) / sizeof(path[0])) == 0) {
log((CLOG_CRIT "cannot determine absolute path to program")); log((CLOG_CRIT "cannot determine absolute path to program"));
return 16; return kExitFailed;
} }
// construct the command line to start the service with // construct the command line to start the service with
@ -681,24 +673,24 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
"Shares this system's mouse and keyboard with others.", "Shares this system's mouse and keyboard with others.",
path, commandLine.c_str())) { path, commandLine.c_str())) {
log((CLOG_CRIT "failed to install service")); log((CLOG_CRIT "failed to install service"));
return 16; return kExitFailed;
} }
log((CLOG_PRINT "installed successfully")); log((CLOG_PRINT "installed successfully"));
return 0; return kExitSuccess;
} }
else if (s_uninstall) { else if (s_uninstall) {
switch (platform.uninstallDaemon(DAEMON_NAME)) { switch (platform.uninstallDaemon(DAEMON_NAME)) {
case IPlatform::kSuccess: case IPlatform::kSuccess:
log((CLOG_PRINT "uninstalled successfully")); log((CLOG_PRINT "uninstalled successfully"));
return 0; return kExitSuccess;
case IPlatform::kFailed: case IPlatform::kFailed:
log((CLOG_CRIT "failed to uninstall service")); log((CLOG_CRIT "failed to uninstall service"));
return 16; return kExitFailed;
case IPlatform::kAlready: case IPlatform::kAlready:
log((CLOG_CRIT "service isn't installed")); log((CLOG_CRIT "service isn't installed"));
return 16; return kExitFailed;
} }
} }
@ -716,18 +708,18 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
result = platform.daemonize(DAEMON_NAME, &daemonStartup95); result = platform.daemonize(DAEMON_NAME, &daemonStartup95);
if (result == -1) { if (result == -1) {
log((CLOG_CRIT "failed to start as a service" BYE, pname)); log((CLOG_CRIT "failed to start as a service" BYE, pname));
return 16; return kExitFailed;
} }
} }
else { else {
// cannot start a service from the command line so just // cannot start a service from the command line so just
// run normally (except with log messages redirected). // run normally (except with log messages redirected).
result = restartableMain(); result = realMain(NULL);
} }
} }
else { else {
// run // run
result = restartableMain(); result = realMain(NULL);
} }
CNetwork::cleanup(); CNetwork::cleanup();
@ -741,7 +733,7 @@ static
int int
daemonStartup(IPlatform*, int, const char**) daemonStartup(IPlatform*, int, const char**)
{ {
return restartableMain(); return realMain(NULL);
} }
int int
@ -767,11 +759,11 @@ main(int argc, char** argv)
result = platform.daemonize(DAEMON_NAME, &daemonStartup); result = platform.daemonize(DAEMON_NAME, &daemonStartup);
if (result == -1) { if (result == -1) {
log((CLOG_CRIT "failed to daemonize")); log((CLOG_CRIT "failed to daemonize"));
return 16; return kExitFailed;
} }
} }
else { else {
result = restartableMain(); result = realMain(NULL);
} }
CNetwork::cleanup(); CNetwork::cleanup();

View File

@ -5,7 +5,7 @@
// version number // version number
static const SInt16 kProtocolMajorVersion = 0; static const SInt16 kProtocolMajorVersion = 0;
static const SInt16 kProtocolMinorVersion = 1; static const SInt16 kProtocolMinorVersion = 7;
// contact port number // contact port number
static const UInt16 kDefaultPort = 24800; static const UInt16 kDefaultPort = 24800;
@ -87,7 +87,7 @@ static const char kMsgCScreenSaver[] = "CSEC%1i";
// sent by primary in response to a secondary screen's kMsgDInfo. // sent by primary in response to a secondary screen's kMsgDInfo.
// this is sent for every kMsgDInfo, whether or not the primary // this is sent for every kMsgDInfo, whether or not the primary
// had sent a kMsgQInfo. // had sent a kMsgQInfo.
static const char kMsgCInfoAck[] = "CIAK"; static const char kMsgCInfoAck[] = "CIAK";
// //
@ -165,16 +165,16 @@ static const char kMsgQInfo[] = "QINF";
static const char kMsgEIncompatible[] = "EICV%2i%2i"; static const char kMsgEIncompatible[] = "EICV%2i%2i";
// name provided when connecting is already in use: primary -> secondary // name provided when connecting is already in use: primary -> secondary
static const char kMsgEBusy[] = "EBSY"; static const char kMsgEBusy[] = "EBSY";
// unknown client: primary -> secondary // unknown client: primary -> secondary
// name provided when connecting is not in primary's screen // name provided when connecting is not in primary's screen
// configuration map. // configuration map.
static const char kMsgEUnknown[] = "EUNK"; static const char kMsgEUnknown[] = "EUNK";
// protocol violation: primary -> secondary // protocol violation: primary -> secondary
// primary should disconnect after sending this message. // primary should disconnect after sending this message.
static const char kMsgEBad[] = "EBAD"; static const char kMsgEBad[] = "EBAD";
// //

View File

@ -4,10 +4,19 @@
#include "BasicTypes.h" #include "BasicTypes.h"
static const char* kCopyright = "Copyright (C) 2002 Chris Schoeneman"; static const char* kCopyright = "Copyright (C) 2002 Chris Schoeneman";
static const char* kContact = "Chris Schoeneman crs23@bigfoot.com";
// build version // build version. follows linux kernel style: minor number even implies
// a release version, odd implies development version.
static const SInt16 kMajorVersion = 0; static const SInt16 kMajorVersion = 0;
static const SInt16 kMinorVersion = 5; static const SInt16 kMinorVersion = 9;
static const SInt16 kReleaseVersion = 0; static const SInt16 kReleaseVersion = 7;
// exit codes
static const int kExitSuccess = 0; // successful completion
static const int kExitFailed = 1; // general failure
static const int kExitTerminated = 2; // killed by signal
static const int kExitArgs = 3; // bad arguments
static const int kExitConfig = 4; // cannot read configuration
#endif #endif