synergy hook DLL will now restart itself if a client tries to
init() it while it's already running. fixed an uninitialized pointer bug in CServer and some cleanup-on-error code in CMSWindowsPrimaryScreen. also added timeout to read() on IInputStream and a heartbeat sent by clients so the server can disconnect clients that are dead but never reset the TCP connection. previously the server would keep these dead clients around forever and if the user was locked on the client screen for some reason then the server would have to be rebooted (or the server would have to be killed via a remote login).
This commit is contained in:
parent
d9b2c59d02
commit
ed8ed72f26
|
@ -13,6 +13,7 @@
|
||||||
#include "CTimerThread.h"
|
#include "CTimerThread.h"
|
||||||
#include "XThread.h"
|
#include "XThread.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "CStopwatch.h"
|
||||||
#include "TMethodJob.h"
|
#include "TMethodJob.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -301,23 +302,36 @@ CClient::runSession(void*)
|
||||||
m_compressMouse = false;
|
m_compressMouse = false;
|
||||||
|
|
||||||
// handle messages from server
|
// handle messages from server
|
||||||
|
CStopwatch heartbeat;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// if no input is pending then flush compressed mouse motion
|
// if no input is pending then flush compressed mouse motion
|
||||||
if (input->getSize() == 0) {
|
if (input->getSize() == 0) {
|
||||||
flushCompressedMouse();
|
flushCompressedMouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for reply
|
// wait for a message
|
||||||
log((CLOG_DEBUG2 "waiting for message"));
|
log((CLOG_DEBUG2 "waiting for message"));
|
||||||
UInt8 code[4];
|
UInt8 code[4];
|
||||||
UInt32 n = input->read(code, 4);
|
UInt32 n = input->read(code, 4, kHeartRate);
|
||||||
|
|
||||||
// verify we got an entire code
|
// check if server hungup
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
log((CLOG_NOTE "server disconnected"));
|
log((CLOG_NOTE "server disconnected"));
|
||||||
// server hungup
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for time out
|
||||||
|
if (n == (UInt32)-1 || heartbeat.getTime() > kHeartRate) {
|
||||||
|
// send heartbeat
|
||||||
|
CProtocolUtil::writef(m_output, kMsgCNoop);
|
||||||
|
heartbeat.reset();
|
||||||
|
if (n == (UInt32)-1) {
|
||||||
|
// no message to process
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify we got an entire code
|
||||||
if (n != 4) {
|
if (n != 4) {
|
||||||
// client sent an incomplete message
|
// client sent an incomplete message
|
||||||
log((CLOG_ERR "incomplete message from server"));
|
log((CLOG_ERR "incomplete message from server"));
|
||||||
|
@ -347,6 +361,10 @@ CClient::runSession(void*)
|
||||||
else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) {
|
else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) {
|
||||||
onKeyRepeat();
|
onKeyRepeat();
|
||||||
}
|
}
|
||||||
|
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||||
|
// accept and discard no-op
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else if (memcmp(code, kMsgCEnter, 4) == 0) {
|
else if (memcmp(code, kMsgCEnter, 4) == 0) {
|
||||||
onEnter();
|
onEnter();
|
||||||
}
|
}
|
||||||
|
|
|
@ -468,7 +468,7 @@ CHTTPProtocol::readLine(IInputStream* stream, CString& tmpBuffer)
|
||||||
|
|
||||||
// read more from stream
|
// read more from stream
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
UInt32 n = stream->read(buffer, sizeof(buffer));
|
UInt32 n = stream->read(buffer, sizeof(buffer), -1.0);
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
// stream is empty. return what's leftover.
|
// stream is empty. return what's leftover.
|
||||||
CString line = tmpBuffer;
|
CString line = tmpBuffer;
|
||||||
|
@ -514,7 +514,7 @@ CHTTPProtocol::readBlock(IInputStream* stream,
|
||||||
if (n > numBytes) {
|
if (n > numBytes) {
|
||||||
n = numBytes;
|
n = numBytes;
|
||||||
}
|
}
|
||||||
n = stream->read(buffer, n);
|
n = stream->read(buffer, n, -1.0);
|
||||||
|
|
||||||
// if stream is empty then return what we've got so far
|
// if stream is empty then return what we've got so far
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
|
#include "CStopwatch.h"
|
||||||
#include "IJob.h"
|
#include "IJob.h"
|
||||||
#include "XIO.h"
|
#include "XIO.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -43,15 +44,19 @@ CBufferedInputStream::hangup()
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32
|
UInt32
|
||||||
CBufferedInputStream::readNoLock(void* dst, UInt32 n)
|
CBufferedInputStream::readNoLock(void* dst, UInt32 n, double timeout)
|
||||||
{
|
{
|
||||||
if (m_closed) {
|
if (m_closed) {
|
||||||
throw XIOClosed();
|
throw XIOClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for data (or hangup)
|
// wait for data, hangup, or timeout
|
||||||
|
CStopwatch timer(true);
|
||||||
while (!m_hungup && m_empty == true) {
|
while (!m_hungup && m_empty == true) {
|
||||||
m_empty.wait();
|
if (!m_empty.wait(timer, timeout)) {
|
||||||
|
// timed out
|
||||||
|
return (UInt32)-1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read data
|
// read data
|
||||||
|
@ -98,10 +103,10 @@ CBufferedInputStream::close()
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32
|
UInt32
|
||||||
CBufferedInputStream::read(void* dst, UInt32 n)
|
CBufferedInputStream::read(void* dst, UInt32 n, double timeout)
|
||||||
{
|
{
|
||||||
CLock lock(m_mutex);
|
CLock lock(m_mutex);
|
||||||
return readNoLock(dst, n);
|
return readNoLock(dst, n, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32
|
UInt32
|
||||||
|
|
|
@ -26,7 +26,7 @@ public:
|
||||||
void hangup();
|
void hangup();
|
||||||
|
|
||||||
// same as read() but caller must lock the mutex
|
// same as read() but caller must lock the mutex
|
||||||
UInt32 readNoLock(void*, UInt32 count);
|
UInt32 readNoLock(void*, UInt32 count, double timeout);
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ public:
|
||||||
// IInputStream overrides
|
// IInputStream overrides
|
||||||
// these all lock the mutex for their duration
|
// these all lock the mutex for their duration
|
||||||
virtual void close();
|
virtual void close();
|
||||||
virtual UInt32 read(void*, UInt32 count);
|
virtual UInt32 read(void*, UInt32 count, double timeout);
|
||||||
virtual UInt32 getSize() const;
|
virtual UInt32 getSize() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -14,7 +14,7 @@ public:
|
||||||
|
|
||||||
// IInputStream overrides
|
// IInputStream overrides
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
virtual UInt32 read(void*, UInt32 maxCount) = 0;
|
virtual UInt32 read(void*, UInt32 maxCount, double timeout) = 0;
|
||||||
virtual UInt32 getSize() const = 0;
|
virtual UInt32 getSize() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -13,8 +13,11 @@ public:
|
||||||
|
|
||||||
// read up to maxCount bytes into buffer, return number read.
|
// read up to maxCount bytes into buffer, return number read.
|
||||||
// blocks if no data is currently available. if buffer is NULL
|
// blocks if no data is currently available. if buffer is NULL
|
||||||
// then the data is discarded.
|
// then the data is discarded. returns (UInt32)-1 if there's
|
||||||
virtual UInt32 read(void* buffer, UInt32 maxCount) = 0;
|
// no data for timeout seconds; if timeout < 0 then it blocks
|
||||||
|
// until data is available.
|
||||||
|
// (cancellation point)
|
||||||
|
virtual UInt32 read(void* buffer, UInt32 maxCount, double timeout) = 0;
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
|
|
||||||
|
|
|
@ -386,21 +386,27 @@ CMSWindowsPrimaryScreen::onOpenDisplay()
|
||||||
// initialize hook library
|
// initialize hook library
|
||||||
m_init(m_threadID);
|
m_init(m_threadID);
|
||||||
|
|
||||||
// install the screen saver hook
|
try {
|
||||||
if (m_installScreenSaver != NULL) {
|
// install the screen saver hook
|
||||||
m_installScreenSaver();
|
if (m_installScreenSaver != NULL) {
|
||||||
}
|
m_installScreenSaver();
|
||||||
|
}
|
||||||
|
|
||||||
// get the input desktop and switch to it
|
// get the input desktop and switch to it
|
||||||
if (m_is95Family) {
|
if (m_is95Family) {
|
||||||
if (!openDesktop()) {
|
if (!openDesktop()) {
|
||||||
throw XScreenOpenFailure();
|
throw XScreenOpenFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!switchDesktop(openInputDesktop())) {
|
||||||
|
throw XScreenOpenFailure();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
catch (...) {
|
||||||
if (!switchDesktop(openInputDesktop())) {
|
m_cleanup();
|
||||||
throw XScreenOpenFailure();
|
throw;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ CServer::CServer(const CString& serverName) :
|
||||||
m_active(NULL),
|
m_active(NULL),
|
||||||
m_primaryInfo(NULL),
|
m_primaryInfo(NULL),
|
||||||
m_seqNum(0),
|
m_seqNum(0),
|
||||||
|
m_activeSaver(NULL),
|
||||||
m_httpServer(NULL),
|
m_httpServer(NULL),
|
||||||
m_httpAvailable(&m_mutex, s_httpMaxSimultaneousRequests)
|
m_httpAvailable(&m_mutex, s_httpMaxSimultaneousRequests)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "IOutputStream.h"
|
#include "IOutputStream.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "CStopwatch.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -29,22 +30,35 @@ CServerProtocol1_0::~CServerProtocol1_0()
|
||||||
void
|
void
|
||||||
CServerProtocol1_0::run()
|
CServerProtocol1_0::run()
|
||||||
{
|
{
|
||||||
// handle messages until the client hangs up
|
// handle messages until the client hangs up or stops sending heartbeats
|
||||||
|
CStopwatch heartTimer;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
CThread::testCancel();
|
CThread::testCancel();
|
||||||
|
|
||||||
// wait for a message
|
// wait for a message
|
||||||
UInt8 code[4];
|
UInt8 code[4];
|
||||||
UInt32 n = getInputStream()->read(code, 4);
|
UInt32 n = getInputStream()->read(code, 4, kHeartRate);
|
||||||
CThread::testCancel();
|
CThread::testCancel();
|
||||||
|
|
||||||
// verify we got an entire code
|
// check if client hungup
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
log((CLOG_NOTE "client \"%s\" disconnected", getClient().c_str()));
|
log((CLOG_NOTE "client \"%s\" disconnected", getClient().c_str()));
|
||||||
|
|
||||||
// client hungup
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if client has stopped sending heartbeats
|
||||||
|
if (n == (UInt32)-1) {
|
||||||
|
if (heartTimer.getTime() > kHeartDeath) {
|
||||||
|
log((CLOG_NOTE "client \"%s\" is dead", getClient().c_str()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// got a message so reset heartbeat monitor
|
||||||
|
heartTimer.reset();
|
||||||
|
|
||||||
|
// verify we got an entire code
|
||||||
if (n != 4) {
|
if (n != 4) {
|
||||||
log((CLOG_ERR "incomplete message from \"%s\": %d bytes", getClient().c_str(), n));
|
log((CLOG_ERR "incomplete message from \"%s\": %d bytes", getClient().c_str(), n));
|
||||||
|
|
||||||
|
@ -57,6 +71,10 @@ CServerProtocol1_0::run()
|
||||||
if (memcmp(code, kMsgDInfo, 4) == 0) {
|
if (memcmp(code, kMsgDInfo, 4) == 0) {
|
||||||
recvInfo();
|
recvInfo();
|
||||||
}
|
}
|
||||||
|
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||||
|
// discard no-ops
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
|
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
|
||||||
recvGrabClipboard();
|
recvGrabClipboard();
|
||||||
}
|
}
|
||||||
|
@ -83,8 +101,17 @@ CServerProtocol1_0::queryInfo()
|
||||||
|
|
||||||
// wait for and verify reply
|
// wait for and verify reply
|
||||||
UInt8 code[4];
|
UInt8 code[4];
|
||||||
UInt32 n = getInputStream()->read(code, 4);
|
for (;;) {
|
||||||
if (n != 4 && memcmp(code, kMsgDInfo, 4) != 0) {
|
UInt32 n = getInputStream()->read(code, 4, -1.0);
|
||||||
|
if (n == 4) {
|
||||||
|
if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||||
|
// discard heartbeats
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (memcmp(code, kMsgDInfo, 4) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
throw XBadClient();
|
throw XBadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -468,9 +468,13 @@ init(DWORD threadID)
|
||||||
{
|
{
|
||||||
assert(g_hinstance != NULL);
|
assert(g_hinstance != NULL);
|
||||||
|
|
||||||
// see if already initialized
|
// see if already initialized. if it is we'll shut down and
|
||||||
|
// reinitialize. this allows the hook DLL to be reclaimed by
|
||||||
|
// a new synergyd if the previous one died unexpectedly.
|
||||||
if (g_threadID != 0) {
|
if (g_threadID != 0) {
|
||||||
return 0;
|
uninstallScreenSaver();
|
||||||
|
uninstall();
|
||||||
|
cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
// save thread id. we'll post messages to this thread's
|
// save thread id. we'll post messages to this thread's
|
||||||
|
@ -624,9 +628,10 @@ uninstall(void)
|
||||||
UnhookWindowsHookEx(g_getMessage);
|
UnhookWindowsHookEx(g_getMessage);
|
||||||
g_getMessage = NULL;
|
g_getMessage = NULL;
|
||||||
}
|
}
|
||||||
g_keyboard = NULL;
|
g_keyboard = NULL;
|
||||||
g_mouse = NULL;
|
g_mouse = NULL;
|
||||||
g_cbt = NULL;
|
g_cbt = NULL;
|
||||||
|
g_wheelSupport = kWheelNone;
|
||||||
|
|
||||||
// show the cursor
|
// show the cursor
|
||||||
restoreCursor();
|
restoreCursor();
|
||||||
|
@ -664,7 +669,7 @@ uninstallScreenSaver(void)
|
||||||
assert(g_hinstance != NULL);
|
assert(g_hinstance != NULL);
|
||||||
|
|
||||||
// uninstall hook unless the mouse wheel hook is installed
|
// uninstall hook unless the mouse wheel hook is installed
|
||||||
if (g_getMessage != NULL && g_threadID == 0) {
|
if (g_getMessage != NULL && g_wheelSupport == kWheelNone) {
|
||||||
UnhookWindowsHookEx(g_getMessage);
|
UnhookWindowsHookEx(g_getMessage);
|
||||||
g_getMessage = NULL;
|
g_getMessage = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "CInputPacketStream.h"
|
#include "CInputPacketStream.h"
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
|
#include "CStopwatch.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// CInputPacketStream
|
// CInputPacketStream
|
||||||
|
@ -26,14 +27,21 @@ CInputPacketStream::close()
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32
|
UInt32
|
||||||
CInputPacketStream::read(void* buffer, UInt32 n)
|
CInputPacketStream::read(void* buffer, UInt32 n, double timeout)
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
// wait for entire message to be read. return immediately if
|
// wait for entire message to be read. return if stream
|
||||||
// stream hungup.
|
// hungup or timeout.
|
||||||
if (!waitForFullMessage()) {
|
switch (waitForFullMessage(timeout)) {
|
||||||
|
case kData:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHungup:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case kTimedout:
|
||||||
|
return (UInt32)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// limit number of bytes to read to the number of bytes left in the
|
// limit number of bytes to read to the number of bytes left in the
|
||||||
|
@ -43,7 +51,7 @@ CInputPacketStream::read(void* buffer, UInt32 n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// now read from our buffer
|
// now read from our buffer
|
||||||
n = m_buffer.readNoLock(buffer, n);
|
n = m_buffer.readNoLock(buffer, n, -1.0);
|
||||||
assert(n <= m_size);
|
assert(n <= m_size);
|
||||||
m_size -= n;
|
m_size -= n;
|
||||||
|
|
||||||
|
@ -60,48 +68,70 @@ CInputPacketStream::getSize() const
|
||||||
UInt32
|
UInt32
|
||||||
CInputPacketStream::getSizeNoLock() const
|
CInputPacketStream::getSizeNoLock() const
|
||||||
{
|
{
|
||||||
|
CStopwatch timer(true);
|
||||||
while (!hasFullMessage() && getStream()->getSize() > 0) {
|
while (!hasFullMessage() && getStream()->getSize() > 0) {
|
||||||
// read more data
|
// read more data
|
||||||
if (!getMoreMessage()) {
|
if (getMoreMessage(-1.0) != kData) {
|
||||||
// stream hungup
|
// stream hungup
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
CInputPacketStream::EResult
|
||||||
CInputPacketStream::waitForFullMessage() const
|
CInputPacketStream::waitForFullMessage(double timeout) const
|
||||||
{
|
{
|
||||||
|
CStopwatch timer(true);
|
||||||
while (!hasFullMessage()) {
|
while (!hasFullMessage()) {
|
||||||
|
// compute remaining timeout
|
||||||
|
double t = timeout - timer.getTime();
|
||||||
|
if (timeout >= 0.0 && t <= 0.0) {
|
||||||
|
// timeout
|
||||||
|
return kTimedout;
|
||||||
|
}
|
||||||
|
|
||||||
// read more data
|
// read more data
|
||||||
if (!getMoreMessage()) {
|
switch (getMoreMessage(t)) {
|
||||||
|
case kData:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHungup:
|
||||||
// stream hungup
|
// stream hungup
|
||||||
return false;
|
return kHungup;
|
||||||
|
|
||||||
|
case kTimedout:
|
||||||
|
// stream timed out
|
||||||
|
return kTimedout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return kData;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
CInputPacketStream::EResult
|
||||||
CInputPacketStream::getMoreMessage() const
|
CInputPacketStream::getMoreMessage(double timeout) const
|
||||||
{
|
{
|
||||||
// read more data
|
// read more data
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
UInt32 n = getStream()->read(buffer, sizeof(buffer));
|
UInt32 n = getStream()->read(buffer, sizeof(buffer), timeout);
|
||||||
|
|
||||||
|
// return if stream timed out
|
||||||
|
if (n == (UInt32)-1) {
|
||||||
|
return kTimedout;
|
||||||
|
}
|
||||||
|
|
||||||
// return if stream hungup
|
// return if stream hungup
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
m_buffer.hangup();
|
m_buffer.hangup();
|
||||||
return false;
|
return kHungup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// append to our buffer
|
// append to our buffer
|
||||||
m_buffer.write(buffer, n);
|
m_buffer.write(buffer, n);
|
||||||
|
|
||||||
return true;
|
return kData;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -117,7 +147,7 @@ CInputPacketStream::hasFullMessage() const
|
||||||
|
|
||||||
// save payload length
|
// save payload length
|
||||||
UInt8 buffer[4];
|
UInt8 buffer[4];
|
||||||
UInt32 n = m_buffer.readNoLock(buffer, sizeof(buffer));
|
UInt32 n = m_buffer.readNoLock(buffer, sizeof(buffer), -1.0);
|
||||||
assert(n == 4);
|
assert(n == 4);
|
||||||
m_size = ((UInt32)buffer[0] << 24) |
|
m_size = ((UInt32)buffer[0] << 24) |
|
||||||
((UInt32)buffer[1] << 16) |
|
((UInt32)buffer[1] << 16) |
|
||||||
|
|
|
@ -16,13 +16,15 @@ public:
|
||||||
|
|
||||||
// IInputStream overrides
|
// IInputStream overrides
|
||||||
virtual void close();
|
virtual void close();
|
||||||
virtual UInt32 read(void*, UInt32 maxCount);
|
virtual UInt32 read(void*, UInt32 maxCount, double timeout);
|
||||||
virtual UInt32 getSize() const;
|
virtual UInt32 getSize() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum EResult { kData, kHungup, kTimedout };
|
||||||
|
|
||||||
UInt32 getSizeNoLock() const;
|
UInt32 getSizeNoLock() const;
|
||||||
bool waitForFullMessage() const;
|
EResult waitForFullMessage(double timeout) const;
|
||||||
bool getMoreMessage() const;
|
EResult getMoreMessage(double timeout) const;
|
||||||
bool hasFullMessage() const;
|
bool hasFullMessage() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -348,7 +348,7 @@ CProtocolUtil::read(IInputStream* stream, void* vbuffer, UInt32 count)
|
||||||
UInt8* buffer = reinterpret_cast<UInt8*>(vbuffer);
|
UInt8* buffer = reinterpret_cast<UInt8*>(vbuffer);
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
// read more
|
// read more
|
||||||
UInt32 n = stream->read(buffer, count);
|
UInt32 n = stream->read(buffer, count, -1.0);
|
||||||
|
|
||||||
// bail if stream has hungup
|
// bail if stream has hungup
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
|
|
@ -10,6 +10,12 @@ static const SInt16 kProtocolMinorVersion = 1;
|
||||||
// contact port number
|
// contact port number
|
||||||
static const UInt16 kDefaultPort = 24800;
|
static const UInt16 kDefaultPort = 24800;
|
||||||
|
|
||||||
|
// time between heartbeats (in seconds)
|
||||||
|
static const double kHeartRate = 2.0;
|
||||||
|
|
||||||
|
// time without a heartbeat that we call death
|
||||||
|
static const double kHeartDeath = 3.0 * kHeartRate;
|
||||||
|
|
||||||
//
|
//
|
||||||
// message codes (trailing NUL is not part of code). in comments, $n
|
// message codes (trailing NUL is not part of code). in comments, $n
|
||||||
// refers to the n'th argument (counting from one). message codes are
|
// refers to the n'th argument (counting from one). message codes are
|
||||||
|
@ -24,6 +30,9 @@ static const UInt16 kDefaultPort = 24800;
|
||||||
// command codes
|
// command codes
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// no operation; secondary -> primary
|
||||||
|
static const char kMsgCNoop[] = "CNOP";
|
||||||
|
|
||||||
// close connection; primary -> secondary
|
// close connection; primary -> secondary
|
||||||
static const char kMsgCClose[] = "CBYE";
|
static const char kMsgCClose[] = "CBYE";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue