summaryrefslogtreecommitdiff
path: root/lib/server
diff options
context:
space:
mode:
Diffstat (limited to 'lib/server')
-rw-r--r--lib/server/Daemon.cpp169
-rw-r--r--lib/server/Daemon.h12
-rw-r--r--lib/server/Message.cpp125
-rw-r--r--lib/server/Message.h69
-rw-r--r--lib/server/Protocol.cpp99
-rw-r--r--lib/server/Protocol.h52
-rw-r--r--lib/server/SSLLib.cpp13
-rw-r--r--lib/server/SSLLib.h3
-rw-r--r--lib/server/ServerException.txt4
-rw-r--r--lib/server/ServerStream.h35
-rw-r--r--lib/server/Socket.cpp25
-rw-r--r--lib/server/SocketListen.h63
-rw-r--r--lib/server/SocketStream.cpp18
-rw-r--r--lib/server/SocketStream.h11
-rw-r--r--lib/server/SocketStreamTLS.cpp37
-rw-r--r--lib/server/TLSContext.cpp20
-rw-r--r--lib/server/TcpNice.cpp235
-rw-r--r--lib/server/TcpNice.h174
-rwxr-xr-xlib/server/makeprotocol.pl.in897
19 files changed, 2061 insertions, 0 deletions
diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp
index 8b4f1d0c..9b96647b 100644
--- a/lib/server/Daemon.cpp
+++ b/lib/server/Daemon.cpp
@@ -25,6 +25,7 @@
#ifdef WIN32
#include <ws2tcpip.h>
+<<<<<<< HEAD
#endif
#include <iostream>
@@ -36,6 +37,26 @@
#include "UnixUser.h"
#include "FileModificationTime.h"
#include "Logging.h"
+=======
+ #include <process.h>
+#endif
+
+#include "depot.h"
+
+#include <iostream>
+
+#ifdef NEED_BOX_VERSION_H
+# include "BoxVersion.h"
+#endif
+
+#include "Configuration.h"
+#include "Daemon.h"
+#include "FileModificationTime.h"
+#include "Guards.h"
+#include "Logging.h"
+#include "ServerException.h"
+#include "UnixUser.h"
+>>>>>>> 0.12
#include "Utils.h"
#include "MemLeakFindOn.h"
@@ -64,6 +85,10 @@ Daemon::Daemon()
mKeepConsoleOpenAfterFork(false),
#endif
mHaveConfigFile(false),
+<<<<<<< HEAD
+=======
+ mLogFileLevel(Log::INVALID),
+>>>>>>> 0.12
mAppName(DaemonName())
{
// In debug builds, switch on assert failure logging to syslog
@@ -100,15 +125,25 @@ std::string Daemon::GetOptionString()
{
return "c:"
#ifndef WIN32
+<<<<<<< HEAD
"DFK"
#endif
"hkPqQt:TUvVW:";
+=======
+ "DF"
+ #endif
+ "hkKo:O:PqQt:TUvVW:";
+>>>>>>> 0.12
}
void Daemon::Usage()
{
std::cout <<
DaemonBanner() << "\n"
+<<<<<<< HEAD
+=======
+ "(built with QDBM " << dpversion << ")\n"
+>>>>>>> 0.12
"\n"
"Usage: " << mAppName << " [options] [config file]\n"
"\n"
@@ -121,6 +156,7 @@ void Daemon::Usage()
" -F Do not fork into background, but fork to serve multiple clients\n"
#endif
" -k Keep console open after fork, keep writing log messages to it\n"
+<<<<<<< HEAD
#ifndef WIN32
" -K Stop writing log messages to console while daemon is running\n"
" -P Show process ID (PID) in console output\n"
@@ -133,6 +169,21 @@ void Daemon::Usage()
" -t <tag> Tag console output with specified marker\n"
" -T Timestamp console output\n"
" -U Timestamp console output with microseconds\n";
+=======
+ " -K Stop writing log messages to console while daemon is running\n"
+ " -o <file> Log to a file, defaults to maximum verbosity\n"
+ " -O <level> Set file log verbosity to error/warning/notice/info/trace/everything\n"
+ " -P Show process ID (PID) in console output\n"
+ " -q Run more quietly, reduce verbosity level by one, can repeat\n"
+ " -Q Run at minimum verbosity, log nothing to console and system\n"
+ " -t <tag> Tag console output with specified marker\n"
+ " -T Timestamp console output\n"
+ " -U Timestamp console output with microseconds\n"
+ " -v Run more verbosely, increase verbosity level by one, can repeat\n"
+ " -V Run at maximum verbosity, log everything to console and system\n"
+ " -W <level> Set verbosity to error/warning/notice/info/trace/everything\n"
+ ;
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -171,6 +222,16 @@ int Daemon::ProcessOption(signed int option)
break;
#endif // !WIN32
+<<<<<<< HEAD
+=======
+ case 'h':
+ {
+ Usage();
+ return 2;
+ }
+ break;
+
+>>>>>>> 0.12
case 'k':
{
mKeepConsoleOpenAfterFork = true;
@@ -183,10 +244,28 @@ int Daemon::ProcessOption(signed int option)
}
break;
+<<<<<<< HEAD
case 'h':
{
Usage();
return 2;
+=======
+ case 'o':
+ {
+ mLogFile = optarg;
+ mLogFileLevel = Log::EVERYTHING;
+ }
+ break;
+
+ case 'O':
+ {
+ mLogFileLevel = Logging::GetNamedLevel(optarg);
+ if (mLogFileLevel == Log::INVALID)
+ {
+ BOX_FATAL("Invalid logging level: " << optarg);
+ return 2;
+ }
+>>>>>>> 0.12
}
break;
@@ -215,6 +294,28 @@ int Daemon::ProcessOption(signed int option)
}
break;
+<<<<<<< HEAD
+=======
+ case 't':
+ {
+ Logging::SetProgramName(optarg);
+ Console::SetShowTag(true);
+ }
+ break;
+
+ case 'T':
+ {
+ Console::SetShowTime(true);
+ }
+ break;
+
+ case 'U':
+ {
+ Console::SetShowTime(true);
+ Console::SetShowTimeMicros(true);
+ }
+ break;
+>>>>>>> 0.12
case 'v':
{
@@ -240,12 +341,17 @@ int Daemon::ProcessOption(signed int option)
mLogLevel = Logging::GetNamedLevel(optarg);
if (mLogLevel == Log::INVALID)
{
+<<<<<<< HEAD
BOX_FATAL("Invalid logging level");
+=======
+ BOX_FATAL("Invalid logging level: " << optarg);
+>>>>>>> 0.12
return 2;
}
}
break;
+<<<<<<< HEAD
case 't':
{
Logging::SetProgramName(optarg);
@@ -266,6 +372,8 @@ int Daemon::ProcessOption(signed int option)
}
break;
+=======
+>>>>>>> 0.12
case '?':
{
BOX_FATAL("Unknown option on command line: "
@@ -295,6 +403,7 @@ int Daemon::ProcessOption(signed int option)
// Created: 2003/07/29
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
{
// Find filename of config file
@@ -305,6 +414,41 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
mLogLevel = Log::NOTICE; // need an int to do math with
#else
mLogLevel = Log::INFO; // need an int to do math with
+=======
+int Daemon::Main(const std::string& rDefaultConfigFile, int argc,
+ const char *argv[])
+{
+ // Find filename of config file
+ mConfigFileName = rDefaultConfigFile;
+ mAppName = argv[0];
+
+ int ret = ProcessOptions(argc, argv);
+ if (ret != 0)
+ {
+ return ret;
+ }
+
+ return Main(mConfigFileName);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Daemon::ProcessOptions(int argc, const char *argv[])
+// Purpose: Parses command-line options. Useful when you have
+// a local Daemon object and don't intend to fork()
+// or call Main().
+// Created: 2008/11/04
+//
+// --------------------------------------------------------------------------
+
+int Daemon::ProcessOptions(int argc, const char *argv[])
+{
+ #ifdef BOX_RELEASE_BUILD
+ mLogLevel = Log::NOTICE;
+ #else
+ mLogLevel = Log::INFO;
+>>>>>>> 0.12
#endif
if (argc == 2 && strcmp(argv[1], "/?") == 0)
@@ -359,7 +503,17 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
Logging::FilterConsole((Log::Level)mLogLevel);
Logging::FilterSyslog ((Log::Level)mLogLevel);
+<<<<<<< HEAD
return Main(mConfigFileName);
+=======
+ if (mLogFileLevel != Log::INVALID)
+ {
+ mapLogFileLogger.reset(
+ new FileLogger(mLogFile, mLogFileLevel));
+ }
+
+ return 0;
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -381,7 +535,11 @@ bool Daemon::Configure(const std::string& rConfigFileName)
try
{
+<<<<<<< HEAD
if (!FileExists(rConfigFileName.c_str()))
+=======
+ if (!FileExists(rConfigFileName))
+>>>>>>> 0.12
{
BOX_FATAL("The main configuration file for " <<
DaemonName() << " was not found: " <<
@@ -969,9 +1127,20 @@ void Daemon::SetProcessTitle(const char *format, ...)
char title[256];
::vsnprintf(title, sizeof(title), format, args);
+<<<<<<< HEAD
// Set process title
::setproctitle("%s", title);
+=======
+#ifdef WIN32
+ StringCchCatA(title, sizeof(title)," - " PACKAGE_NAME);
+ SetConsoleTitleA(title);
+#else // !WIN32
+ // Set process title
+ ::setproctitle("%s", title);
+#endif
+
+>>>>>>> 0.12
#endif // HAVE_SETPROCTITLE
}
diff --git a/lib/server/Daemon.h b/lib/server/Daemon.h
index a3212a00..f2fa98c3 100644
--- a/lib/server/Daemon.h
+++ b/lib/server/Daemon.h
@@ -40,8 +40,14 @@ private:
Daemon(const Daemon &rToCopy);
public:
+<<<<<<< HEAD
virtual int Main(const char *DefaultConfigFile, int argc,
const char *argv[]);
+=======
+ virtual int Main(const std::string& rDefaultConfigFile, int argc,
+ const char *argv[]);
+ virtual int ProcessOptions(int argc, const char *argv[]);
+>>>>>>> 0.12
/* override this Main() if you want custom option processing: */
virtual int Main(const std::string &rConfigFile);
@@ -99,6 +105,12 @@ private:
bool mKeepConsoleOpenAfterFork;
bool mHaveConfigFile;
int mLogLevel; // need an int to do math with
+<<<<<<< HEAD
+=======
+ std::string mLogFile;
+ Log::Level mLogFileLevel;
+ std::auto_ptr<FileLogger> mapLogFileLogger;
+>>>>>>> 0.12
static Daemon *spDaemon;
std::string mAppName;
};
diff --git a/lib/server/Message.cpp b/lib/server/Message.cpp
new file mode 100644
index 00000000..2ff9e6ae
--- /dev/null
+++ b/lib/server/Message.cpp
@@ -0,0 +1,125 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Message.h
+// Purpose: Protocol object base class
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "Message.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Message::Message()
+// Purpose: Default constructor
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+Message::Message()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Message::Message()
+// Purpose: Destructor
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+Message::~Message()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Message::Message()
+// Purpose: Copy constructor
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+Message::Message(const Message &rToCopy)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Message::IsError(int &, int &)
+// Purpose: Does this represent an error, and if so, what is the type and subtype?
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+bool Message::IsError(int &rTypeOut, int &rSubTypeOut) const
+{
+ return false;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Message::IsConversationEnd()
+// Purpose: Does this command end the conversation?
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+bool Message::IsConversationEnd() const
+{
+ return false;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Message::GetType()
+// Purpose: Return type of the object
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+int Message::GetType() const
+{
+ // This isn't implemented in the base class!
+ THROW_EXCEPTION(CommonException, Internal)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Message::SetPropertiesFromStreamData(Protocol &)
+// Purpose: Set the properties of the object from the stream data ready in the Protocol object
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+void Message::SetPropertiesFromStreamData(Protocol &rProtocol)
+{
+ // This isn't implemented in the base class!
+ THROW_EXCEPTION(CommonException, Internal)
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Message::WritePropertiesToStreamData(Protocol &)
+// Purpose: Write the properties of the object into the stream data in the Protocol object
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+void Message::WritePropertiesToStreamData(Protocol &rProtocol) const
+{
+ // This isn't implemented in the base class!
+ THROW_EXCEPTION(CommonException, Internal)
+}
+
+
+
diff --git a/lib/server/Message.h b/lib/server/Message.h
new file mode 100644
index 00000000..0d073d49
--- /dev/null
+++ b/lib/server/Message.h
@@ -0,0 +1,69 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Message.h
+// Purpose: Protocol object base class
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+
+#ifndef PROTOCOLOBJECT__H
+#define PROTOCOLOBJECT__H
+
+#include <memory>
+
+class Protocol;
+class ProtocolContext;
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: Message
+// Purpose: Basic object representation of objects to pass through a Protocol session
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+class Message
+{
+public:
+ Message();
+ virtual ~Message();
+ Message(const Message &rToCopy);
+
+ // Info about this object
+ virtual int GetType() const;
+ virtual bool IsError(int &rTypeOut, int &rSubTypeOut) const;
+ virtual bool IsConversationEnd() const;
+
+ // reading and writing with Protocol objects
+ virtual void SetPropertiesFromStreamData(Protocol &rProtocol);
+ virtual void WritePropertiesToStreamData(Protocol &rProtocol) const;
+
+ virtual void LogSysLog(const char *Action) const { }
+ virtual void LogFile(const char *Action, FILE *file) const { }
+};
+
+/*
+class Reply;
+
+class Request : public Message
+{
+public:
+ Request() { }
+ virtual ~Request() { }
+ Request(const Request &rToCopy) { }
+ virtual std::auto_ptr<Reply> DoCommand(Protocol &rProtocol,
+ ProtocolContext &rContext) = 0;
+};
+
+class Reply : public Message
+{
+public:
+ Reply() { }
+ virtual ~Reply() { }
+ Reply(const Reply &rToCopy) { }
+};
+*/
+
+#endif // PROTOCOLOBJECT__H
+
diff --git a/lib/server/Protocol.cpp b/lib/server/Protocol.cpp
index 5dc5d0b1..6333b1db 100644
--- a/lib/server/Protocol.cpp
+++ b/lib/server/Protocol.cpp
@@ -11,8 +11,14 @@
#include <sys/types.h>
+<<<<<<< HEAD
#include <stdlib.h>
#include <string.h>
+=======
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
+>>>>>>> 0.12
#include <new>
@@ -44,6 +50,7 @@
//
// --------------------------------------------------------------------------
Protocol::Protocol(IOStream &rStream)
+<<<<<<< HEAD
: mrStream(rStream),
mHandshakeDone(false),
mMaxObjectSize(PROTOCOL_DEFAULT_MAXOBJSIZE),
@@ -55,6 +62,19 @@ Protocol::Protocol(IOStream &rStream)
mValidDataSize(-1),
mLastErrorType(NoError),
mLastErrorSubType(NoError)
+=======
+: mrStream(rStream),
+ mHandshakeDone(false),
+ mMaxObjectSize(PROTOCOL_DEFAULT_MAXOBJSIZE),
+ mTimeout(PROTOCOL_DEFAULT_TIMEOUT),
+ mpBuffer(0),
+ mBufferSize(0),
+ mReadOffset(-1),
+ mWriteOffset(-1),
+ mValidDataSize(-1),
+ mLogToSysLog(false),
+ mLogToFile(NULL)
+>>>>>>> 0.12
{
BOX_TRACE("Send block allocation size is " <<
PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK);
@@ -82,6 +102,7 @@ Protocol::~Protocol()
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
// Name: Protocol::GetLastError(int &, int &)
// Purpose: Returns true if there was an error, and type and subtype if there was.
// Created: 2003/08/19
@@ -110,6 +131,8 @@ bool Protocol::GetLastError(int &rTypeOut, int &rSubTypeOut)
// --------------------------------------------------------------------------
//
// Function
+=======
+>>>>>>> 0.12
// Name: Protocol::Handshake()
// Purpose: Handshake with peer (exchange ident strings)
// Created: 2003/08/20
@@ -127,7 +150,11 @@ void Protocol::Handshake()
PW_Handshake hsSend;
::memset(&hsSend, 0, sizeof(hsSend));
// Copy in ident string
+<<<<<<< HEAD
::strncpy(hsSend.mIdent, GetIdentString(), sizeof(hsSend.mIdent));
+=======
+ ::strncpy(hsSend.mIdent, GetProtocolIdentString(), sizeof(hsSend.mIdent));
+>>>>>>> 0.12
// Send it
mrStream.Write(&hsSend, sizeof(hsSend));
@@ -200,7 +227,11 @@ void Protocol::CheckAndReadHdr(void *hdr)
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
std::auto_ptr<ProtocolObject> Protocol::Receive()
+=======
+std::auto_ptr<Message> Protocol::ReceiveInternal()
+>>>>>>> 0.12
{
// Get object header
PW_ObjectHeader objHeader;
@@ -220,7 +251,11 @@ std::auto_ptr<ProtocolObject> Protocol::Receive()
}
// Create a blank object
+<<<<<<< HEAD
std::auto_ptr<ProtocolObject> obj(MakeProtocolObject(ntohl(objHeader.mObjType)));
+=======
+ std::auto_ptr<Message> obj(MakeMessage(ntohl(objHeader.mObjType)));
+>>>>>>> 0.12
// Make sure memory is allocated to read it into
EnsureBufferAllocated(objSize);
@@ -272,7 +307,11 @@ std::auto_ptr<ProtocolObject> Protocol::Receive()
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
void Protocol::Send(const ProtocolObject &rObject)
+=======
+void Protocol::SendInternal(const Message &rObject)
+>>>>>>> 0.12
{
// Check usage
if(mValidDataSize != -1 || mWriteOffset != -1 || mReadOffset != -1)
@@ -715,6 +754,20 @@ void Protocol::SendStream(IOStream &rStream)
// Can't send this using the fixed size header
uncertainSize = true;
}
+<<<<<<< HEAD
+=======
+
+ if(streamSize == 0)
+ {
+ // Server protocol will throw an assertion failure if we
+ // try to send a stream whose size is definitely zero:
+ // ASSERT FAILED: [BytesToRead > 0] at PartialReadStream.cpp:31
+ // so catch this on the client side to help debugging
+ THROW_EXCEPTION_MESSAGE(ServerException, Protocol_BadUsage,
+ "Sending a stream with a definite size of zero "
+ "is not allowed in the protocol");
+ }
+>>>>>>> 0.12
// Inform sub class
InformStreamSending(streamSize);
@@ -854,7 +907,30 @@ int Protocol::SendStreamSendBlock(uint8_t *Block, int BytesInBlock)
// --------------------------------------------------------------------------
void Protocol::InformStreamReceiving(u_int32_t Size)
{
+<<<<<<< HEAD
// Do nothing
+=======
+ if(GetLogToSysLog())
+ {
+ if(Size == Protocol::ProtocolStream_SizeUncertain)
+ {
+ BOX_TRACE("Receiving stream, size uncertain");
+ }
+ else
+ {
+ BOX_TRACE("Receiving stream, size " << Size);
+ }
+ }
+
+ if(GetLogToFile())
+ {
+ ::fprintf(GetLogToFile(),
+ (Size == Protocol::ProtocolStream_SizeUncertain)
+ ? "Receiving stream, size uncertain\n"
+ : "Receiving stream, size %d\n", Size);
+ ::fflush(GetLogToFile());
+ }
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -867,7 +943,30 @@ void Protocol::InformStreamReceiving(u_int32_t Size)
// --------------------------------------------------------------------------
void Protocol::InformStreamSending(u_int32_t Size)
{
+<<<<<<< HEAD
// Do nothing
+=======
+ if(GetLogToSysLog())
+ {
+ if(Size == Protocol::ProtocolStream_SizeUncertain)
+ {
+ BOX_TRACE("Sending stream, size uncertain");
+ }
+ else
+ {
+ BOX_TRACE("Sending stream, size " << Size);
+ }
+ }
+
+ if(GetLogToFile())
+ {
+ ::fprintf(GetLogToFile(),
+ (Size == Protocol::ProtocolStream_SizeUncertain)
+ ? "Sending stream, size uncertain\n"
+ : "Sending stream, size %d\n", Size);
+ ::fflush(GetLogToFile());
+ }
+>>>>>>> 0.12
}
diff --git a/lib/server/Protocol.h b/lib/server/Protocol.h
index e037e33c..dc660ad5 100644
--- a/lib/server/Protocol.h
+++ b/lib/server/Protocol.h
@@ -12,12 +12,22 @@
#include <sys/types.h>
+<<<<<<< HEAD
class IOStream;
#include "ProtocolObject.h"
+=======
+>>>>>>> 0.12
#include <memory>
#include <vector>
#include <string>
+<<<<<<< HEAD
+=======
+#include "Message.h"
+
+class IOStream;
+
+>>>>>>> 0.12
// default timeout is 15 minutes
#define PROTOCOL_DEFAULT_TIMEOUT (15*60*1000)
// 16 default maximum object size -- should be enough
@@ -40,11 +50,22 @@ public:
private:
Protocol(const Protocol &rToCopy);
+<<<<<<< HEAD
public:
void Handshake();
std::auto_ptr<ProtocolObject> Receive();
void Send(const ProtocolObject &rObject);
+=======
+protected:
+ // Unsafe to make public, as they may allow sending objects
+ // from a different protocol. The derived class prevents this.
+ std::auto_ptr<Message> ReceiveInternal();
+ void SendInternal(const Message &rObject);
+
+public:
+ void Handshake();
+>>>>>>> 0.12
std::auto_ptr<IOStream> ReceiveStream();
void SendStream(IOStream &rStream);
@@ -54,8 +75,11 @@ public:
UnknownError = 0
};
+<<<<<<< HEAD
bool GetLastError(int &rTypeOut, int &rSubTypeOut);
+=======
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Function
@@ -87,7 +111,11 @@ public:
// --------------------------------------------------------------------------
void SetMaxObjectSize(unsigned int NewMaxObjSize) {mMaxObjectSize = NewMaxObjSize;}
+<<<<<<< HEAD
// For ProtocolObject derived classes
+=======
+ // For Message derived classes
+>>>>>>> 0.12
void Read(void *Buffer, int Size);
void Read(std::string &rOut, int Size);
void Read(int64_t &rOut);
@@ -168,11 +196,23 @@ public:
{
ProtocolStream_SizeUncertain = 0xffffffff
};
+<<<<<<< HEAD
protected:
virtual std::auto_ptr<ProtocolObject> MakeProtocolObject(int ObjType) = 0;
virtual const char *GetIdentString() = 0;
void SetError(int Type, int SubType) {mLastErrorType = Type; mLastErrorSubType = SubType;}
+=======
+ bool GetLogToSysLog() { return mLogToSysLog; }
+ FILE *GetLogToFile() { return mLogToFile; }
+ void SetLogToSysLog(bool Log = false) {mLogToSysLog = Log;}
+ void SetLogToFile(FILE *File = 0) {mLogToFile = File;}
+
+protected:
+ virtual std::auto_ptr<Message> MakeMessage(int ObjType) = 0;
+ virtual const char *GetProtocolIdentString() = 0;
+
+>>>>>>> 0.12
void CheckAndReadHdr(void *hdr); // don't use type here to avoid dependency
// Will be used for logging
@@ -183,7 +223,10 @@ private:
void EnsureBufferAllocated(int Size);
int SendStreamSendBlock(uint8_t *Block, int BytesInBlock);
+<<<<<<< HEAD
private:
+=======
+>>>>>>> 0.12
IOStream &mrStream;
bool mHandshakeDone;
unsigned int mMaxObjectSize;
@@ -193,8 +236,17 @@ private:
int mReadOffset;
int mWriteOffset;
int mValidDataSize;
+<<<<<<< HEAD
int mLastErrorType;
int mLastErrorSubType;
+=======
+ bool mLogToSysLog;
+ FILE *mLogToFile;
+};
+
+class ProtocolContext
+{
+>>>>>>> 0.12
};
#endif // PROTOCOL__H
diff --git a/lib/server/SSLLib.cpp b/lib/server/SSLLib.cpp
index de7a941b..6feaae4a 100644
--- a/lib/server/SSLLib.cpp
+++ b/lib/server/SSLLib.cpp
@@ -18,6 +18,10 @@
#include <wincrypt.h>
#endif
+<<<<<<< HEAD
+=======
+#include "CryptoUtils.h"
+>>>>>>> 0.12
#include "SSLLib.h"
#include "ServerException.h"
@@ -39,8 +43,14 @@ void SSLLib::Initialise()
{
if(!::SSL_library_init())
{
+<<<<<<< HEAD
LogError("initialising OpenSSL");
THROW_EXCEPTION(ServerException, SSLLibraryInitialisationError)
+=======
+ THROW_EXCEPTION_MESSAGE(ServerException,
+ SSLLibraryInitialisationError,
+ CryptoUtils::LogError("initialising OpenSSL"));
+>>>>>>> 0.12
}
// More helpful error messages
@@ -89,6 +99,7 @@ void SSLLib::Initialise()
}
+<<<<<<< HEAD
// --------------------------------------------------------------------------
//
// Function
@@ -109,3 +120,5 @@ void SSLLib::LogError(const std::string& rErrorDuringAction)
}
}
+=======
+>>>>>>> 0.12
diff --git a/lib/server/SSLLib.h b/lib/server/SSLLib.h
index ff4aab19..b679d623 100644
--- a/lib/server/SSLLib.h
+++ b/lib/server/SSLLib.h
@@ -29,7 +29,10 @@
namespace SSLLib
{
void Initialise();
+<<<<<<< HEAD
void LogError(const std::string& rErrorDuringAction);
+=======
+>>>>>>> 0.12
};
#endif // SSLLIB__H
diff --git a/lib/server/ServerException.txt b/lib/server/ServerException.txt
index ed591b73..f8c558c6 100644
--- a/lib/server/ServerException.txt
+++ b/lib/server/ServerException.txt
@@ -13,7 +13,11 @@ SocketOpenError 10
SocketPollError 11
SocketCloseError 13
SocketNameUNIXPathTooLong 14
+<<<<<<< HEAD
SocketBindError 16 Check the ListenAddresses directive in your config file -- must refer to local IP addresses only
+=======
+SocketBindError 16 Check the ListenAddresses directive (bbstored) or CommandSocket (bbackupd) in your config file -- must refer to local IP addresses (or existing writable path) only
+>>>>>>> 0.12
SocketAcceptError 17
ServerStreamBadListenAddrs 18
ServerForkError 19
diff --git a/lib/server/ServerStream.h b/lib/server/ServerStream.h
index e49dbcbe..8625832d 100644
--- a/lib/server/ServerStream.h
+++ b/lib/server/ServerStream.h
@@ -48,6 +48,18 @@ private:
ServerStream(const ServerStream &rToCopy)
{
}
+<<<<<<< HEAD
+=======
+
+ std::string mConnectionDetails;
+
+protected:
+ const std::string& GetConnectionDetails()
+ {
+ return mConnectionDetails;
+ }
+
+>>>>>>> 0.12
public:
virtual const char *DaemonName() const
@@ -122,6 +134,13 @@ public:
protected:
virtual void NotifyListenerIsReady() { }
+<<<<<<< HEAD
+=======
+ virtual void LogConnectionDetails(std::string details)
+ {
+ BOX_NOTICE("Handling incoming connection from " << details);
+ }
+>>>>>>> 0.12
public:
virtual void Run2(bool &rChildExit)
@@ -237,8 +256,14 @@ public:
{
// Get the incoming connection
// (with zero wait time)
+<<<<<<< HEAD
std::string logMessage;
std::auto_ptr<StreamType> connection(psocket->Accept(0, &logMessage));
+=======
+ std::auto_ptr<StreamType> connection(
+ psocket->Accept(0,
+ &mConnectionDetails));
+>>>>>>> 0.12
// Was there one (there should be...)
if(connection.get())
@@ -264,6 +289,10 @@ public:
// Set up daemon
EnterChild();
SetProcessTitle("transaction");
+<<<<<<< HEAD
+=======
+ LogConnectionDetails(mConnectionDetails);
+>>>>>>> 0.12
// Memory leak test the forked process
#ifdef BOX_MEMORY_LEAK_TESTING
@@ -281,7 +310,13 @@ public:
}
// Log it
+<<<<<<< HEAD
BOX_NOTICE("Message from child process " << pid << ": " << logMessage);
+=======
+ BOX_TRACE("Forked child process " << pid <<
+ " to handle connection from " <<
+ mConnectionDetails);
+>>>>>>> 0.12
}
else
{
diff --git a/lib/server/Socket.cpp b/lib/server/Socket.cpp
index 4a83bdb0..69a11330 100644
--- a/lib/server/Socket.cpp
+++ b/lib/server/Socket.cpp
@@ -123,6 +123,7 @@ void Socket::NameLookupToSockAddr(SocketAllAddr &addr, int &sockDomain,
// --------------------------------------------------------------------------
void Socket::LogIncomingConnection(const struct sockaddr *addr, socklen_t addrlen)
{
+<<<<<<< HEAD
if(addr == NULL) {THROW_EXCEPTION(CommonException, BadArguments)}
switch(addr->sa_family)
@@ -144,6 +145,10 @@ void Socket::LogIncomingConnection(const struct sockaddr *addr, socklen_t addrle
BOX_WARNING("Incoming connection of unknown type");
break;
}
+=======
+ BOX_INFO("Incoming connection from " <<
+ IncomingConnectionLogMessage(addr, addrlen));
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -161,20 +166,40 @@ std::string Socket::IncomingConnectionLogMessage(const struct sockaddr *addr, so
switch(addr->sa_family)
{
case AF_UNIX:
+<<<<<<< HEAD
return std::string("Incoming connection from local (UNIX socket)");
+=======
+ return std::string("local (UNIX socket)");
+>>>>>>> 0.12
break;
case AF_INET:
{
+<<<<<<< HEAD
char msg[256]; // more than enough
sockaddr_in *a = (sockaddr_in*)addr;
sprintf(msg, "Incoming connection from %s port %d", inet_ntoa(a->sin_addr), ntohs(a->sin_port));
return std::string(msg);
+=======
+ sockaddr_in *a = (sockaddr_in*)addr;
+ std::ostringstream oss;
+ oss << inet_ntoa(a->sin_addr) << " port " <<
+ ntohs(a->sin_port);
+ return oss.str();
+>>>>>>> 0.12
}
break;
default:
+<<<<<<< HEAD
return std::string("Incoming connection of unknown type");
+=======
+ {
+ std::ostringstream oss;
+ oss << "unknown socket type " << addr->sa_family;
+ return oss.str();
+ }
+>>>>>>> 0.12
break;
}
diff --git a/lib/server/SocketListen.h b/lib/server/SocketListen.h
index 586adf22..635b15e8 100644
--- a/lib/server/SocketListen.h
+++ b/lib/server/SocketListen.h
@@ -87,12 +87,24 @@ public:
{
Close();
}
+<<<<<<< HEAD
+=======
+
+>>>>>>> 0.12
private:
SocketListen(const SocketListen &rToCopy)
{
}
+<<<<<<< HEAD
public:
+=======
+
+ int mType, mPort;
+ std::string mName;
+
+public:
+>>>>>>> 0.12
enum
{
MaxMultipleListenSockets = MaxMultiListenSockets
@@ -108,8 +120,13 @@ public:
if(::close(mSocketHandle) == -1)
#endif
{
+<<<<<<< HEAD
BOX_LOG_SYS_ERROR("Failed to close network "
"socket");
+=======
+ BOX_LOG_SOCKET_ERROR(mType, mName, mPort,
+ "Failed to close network socket");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException,
SocketCloseError)
}
@@ -127,6 +144,13 @@ public:
// ------------------------------------------------------------------
void Listen(Socket::Type Type, const char *Name, int Port = 0)
{
+<<<<<<< HEAD
+=======
+ mType = Type;
+ mName = Name;
+ mPort = Port;
+
+>>>>>>> 0.12
if(mSocketHandle != -1)
{
THROW_EXCEPTION(ServerException, SocketAlreadyOpen);
@@ -144,7 +168,12 @@ public:
0 /* let OS choose protocol */);
if(mSocketHandle == -1)
{
+<<<<<<< HEAD
BOX_LOG_SYS_ERROR("Failed to create a network socket");
+=======
+ BOX_LOG_SOCKET_ERROR(Type, Name, Port,
+ "Failed to create a network socket");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, SocketOpenError)
}
@@ -158,7 +187,12 @@ public:
&option, sizeof(option)) == -1)
#endif
{
+<<<<<<< HEAD
BOX_LOG_SYS_ERROR("Failed to set socket options");
+=======
+ BOX_LOG_SOCKET_ERROR(Type, Name, Port,
+ "Failed to set socket options");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, SocketOpenError)
}
@@ -166,10 +200,25 @@ public:
if(::bind(mSocketHandle, &addr.sa_generic, addrLen) == -1
|| ::listen(mSocketHandle, ListenBacklog) == -1)
{
+<<<<<<< HEAD
// Dispose of the socket
::close(mSocketHandle);
mSocketHandle = -1;
THROW_EXCEPTION(ServerException, SocketBindError)
+=======
+ int err_number = errno;
+
+ BOX_LOG_SOCKET_ERROR(Type, Name, Port,
+ "Failed to bind socket");
+
+ // Dispose of the socket
+ ::close(mSocketHandle);
+ mSocketHandle = -1;
+
+ THROW_SYS_FILE_ERRNO("Failed to bind or listen "
+ "on socket", Name, err_number,
+ ServerException, SocketBindError);
+>>>>>>> 0.12
}
}
@@ -222,7 +271,11 @@ public:
// signal?
if(errno == EINTR)
{
+<<<<<<< HEAD
BOX_ERROR("Failed to accept "
+=======
+ BOX_INFO("Failed to accept "
+>>>>>>> 0.12
"connection: interrupted by "
"signal");
// return nothing
@@ -230,8 +283,13 @@ public:
}
else
{
+<<<<<<< HEAD
BOX_LOG_SYS_ERROR("Failed to poll "
"connection");
+=======
+ BOX_LOG_SOCKET_ERROR(mType, mName, mPort,
+ "Failed to poll connection");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException,
SocketPollError)
}
@@ -250,7 +308,12 @@ public:
// Got socket (or error), unlock (implicit in destruction)
if(sock == -1)
{
+<<<<<<< HEAD
BOX_LOG_SYS_ERROR("Failed to accept connection");
+=======
+ BOX_LOG_SOCKET_ERROR(mType, mName, mPort,
+ "Failed to accept connection");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, SocketAcceptError)
}
diff --git a/lib/server/SocketStream.cpp b/lib/server/SocketStream.cpp
index 95b4b4f4..7c92ebba 100644
--- a/lib/server/SocketStream.cpp
+++ b/lib/server/SocketStream.cpp
@@ -154,14 +154,24 @@ void SocketStream::Open(Socket::Type Type, const std::string& rName, int Port)
int sockDomain = 0;
SocketAllAddr addr;
int addrLen = 0;
+<<<<<<< HEAD
Socket::NameLookupToSockAddr(addr, sockDomain, Type, rName, Port, addrLen);
+=======
+ Socket::NameLookupToSockAddr(addr, sockDomain, Type, rName, Port,
+ addrLen);
+>>>>>>> 0.12
// Create the socket
mSocketHandle = ::socket(sockDomain, SOCK_STREAM,
0 /* let OS choose protocol */);
if(mSocketHandle == INVALID_SOCKET_VALUE)
{
+<<<<<<< HEAD
BOX_LOG_SYS_ERROR("Failed to create a network socket");
+=======
+ BOX_LOG_SOCKET_ERROR(Type, rName, Port,
+ "Failed to create a network socket");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, SocketOpenError)
}
@@ -169,6 +179,7 @@ void SocketStream::Open(Socket::Type Type, const std::string& rName, int Port)
if(::connect(mSocketHandle, &addr.sa_generic, addrLen) == -1)
{
// Dispose of the socket
+<<<<<<< HEAD
#ifdef WIN32
DWORD err = WSAGetLastError();
::closesocket(mSocketHandle);
@@ -179,6 +190,13 @@ void SocketStream::Open(Socket::Type Type, const std::string& rName, int Port)
BOX_LOG_SYS_ERROR("Failed to connect to socket (type " <<
Type << ", name " << rName << ", port " << Port <<
")");
+=======
+ BOX_LOG_SOCKET_ERROR(Type, rName, Port,
+ "Failed to connect to socket");
+#ifdef WIN32
+ ::closesocket(mSocketHandle);
+#else // !WIN32
+>>>>>>> 0.12
::close(mSocketHandle);
#endif // WIN32
diff --git a/lib/server/SocketStream.h b/lib/server/SocketStream.h
index 2b582f21..aa62e4e9 100644
--- a/lib/server/SocketStream.h
+++ b/lib/server/SocketStream.h
@@ -51,7 +51,10 @@ public:
virtual bool GetPeerCredentials(uid_t &rUidOut, gid_t &rGidOut);
protected:
+<<<<<<< HEAD
tOSSocketHandle GetSocketHandle();
+=======
+>>>>>>> 0.12
void MarkAsReadClosed() {mReadClosed = true;}
void MarkAsWriteClosed() {mWriteClosed = true;}
@@ -69,6 +72,14 @@ public:
off_t GetBytesWritten() const {return mBytesWritten;}
void ResetCounters() {mBytesRead = mBytesWritten = 0;}
bool IsOpened() { return mSocketHandle != INVALID_SOCKET_VALUE; }
+<<<<<<< HEAD
+=======
+
+ /**
+ * Only for use by NiceSocketStream!
+ */
+ tOSSocketHandle GetSocketHandle();
+>>>>>>> 0.12
};
#endif // SOCKETSTREAM__H
diff --git a/lib/server/SocketStreamTLS.cpp b/lib/server/SocketStreamTLS.cpp
index 19fdadd4..6f1cc46a 100644
--- a/lib/server/SocketStreamTLS.cpp
+++ b/lib/server/SocketStreamTLS.cpp
@@ -19,11 +19,20 @@
#include <poll.h>
#endif
+<<<<<<< HEAD
#include "SocketStreamTLS.h"
#include "SSLLib.h"
#include "ServerException.h"
#include "TLSContext.h"
#include "BoxTime.h"
+=======
+#include "BoxTime.h"
+#include "CryptoUtils.h"
+#include "ServerException.h"
+#include "SocketStreamTLS.h"
+#include "SSLLib.h"
+#include "TLSContext.h"
+>>>>>>> 0.12
#include "MemLeakFindOn.h"
@@ -124,7 +133,11 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer)
mpBIO = ::BIO_new(::BIO_s_socket());
if(mpBIO == 0)
{
+<<<<<<< HEAD
SSLLib::LogError("creating socket bio");
+=======
+ CryptoUtils::LogError("creating socket bio");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSAllocationFailed)
}
@@ -135,7 +148,11 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer)
mpSSL = ::SSL_new(rContext.GetRawContext());
if(mpSSL == 0)
{
+<<<<<<< HEAD
SSLLib::LogError("creating SSL object");
+=======
+ CryptoUtils::LogError("creating SSL object");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSAllocationFailed)
}
@@ -203,12 +220,20 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer)
// Error occured
if(IsServer)
{
+<<<<<<< HEAD
SSLLib::LogError("accepting connection");
+=======
+ CryptoUtils::LogError("accepting connection");
+>>>>>>> 0.12
THROW_EXCEPTION(ConnectionException, Conn_TLSHandshakeFailed)
}
else
{
+<<<<<<< HEAD
SSLLib::LogError("connecting");
+=======
+ CryptoUtils::LogError("connecting");
+>>>>>>> 0.12
THROW_EXCEPTION(ConnectionException, Conn_TLSHandshakeFailed)
}
}
@@ -335,7 +360,11 @@ int SocketStreamTLS::Read(void *pBuffer, int NBytes, int Timeout)
break;
default:
+<<<<<<< HEAD
SSLLib::LogError("reading");
+=======
+ CryptoUtils::LogError("reading");
+>>>>>>> 0.12
THROW_EXCEPTION(ConnectionException, Conn_TLSReadFailed)
break;
}
@@ -400,7 +429,11 @@ void SocketStreamTLS::Write(const void *pBuffer, int NBytes)
break;
default:
+<<<<<<< HEAD
SSLLib::LogError("writing");
+=======
+ CryptoUtils::LogError("writing");
+>>>>>>> 0.12
THROW_EXCEPTION(ConnectionException, Conn_TLSWriteFailed)
break;
}
@@ -442,7 +475,11 @@ void SocketStreamTLS::Shutdown(bool Read, bool Write)
if(::SSL_shutdown(mpSSL) < 0)
{
+<<<<<<< HEAD
SSLLib::LogError("shutting down");
+=======
+ CryptoUtils::LogError("shutting down");
+>>>>>>> 0.12
THROW_EXCEPTION(ConnectionException, Conn_TLSShutdownFailed)
}
diff --git a/lib/server/TLSContext.cpp b/lib/server/TLSContext.cpp
index ebc7384a..1f06d602 100644
--- a/lib/server/TLSContext.cpp
+++ b/lib/server/TLSContext.cpp
@@ -12,7 +12,11 @@
#define TLS_CLASS_IMPLEMENTATION_CPP
#include <openssl/ssl.h>
+<<<<<<< HEAD
#include "TLSContext.h"
+=======
+#include "CryptoUtils.h"
+>>>>>>> 0.12
#include "ServerException.h"
#include "SSLLib.h"
#include "TLSContext.h"
@@ -77,14 +81,22 @@ void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const c
{
std::string msg = "loading certificates from ";
msg += CertificatesFile;
+<<<<<<< HEAD
SSLLib::LogError(msg);
+=======
+ CryptoUtils::LogError(msg);
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSLoadCertificatesFailed)
}
if(::SSL_CTX_use_PrivateKey_file(mpContext, PrivateKeyFile, SSL_FILETYPE_PEM) != 1)
{
std::string msg = "loading private key from ";
msg += PrivateKeyFile;
+<<<<<<< HEAD
SSLLib::LogError(msg);
+=======
+ CryptoUtils::LogError(msg);
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSLoadPrivateKeyFailed)
}
@@ -93,7 +105,11 @@ void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const c
{
std::string msg = "loading CA cert from ";
msg += TrustedCAsFile;
+<<<<<<< HEAD
SSLLib::LogError(msg);
+=======
+ CryptoUtils::LogError(msg);
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSLoadTrustedCAsFailed)
}
@@ -105,7 +121,11 @@ void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const c
// Setup allowed ciphers
if(::SSL_CTX_set_cipher_list(mpContext, CIPHER_LIST) != 1)
{
+<<<<<<< HEAD
SSLLib::LogError("setting cipher list to " CIPHER_LIST);
+=======
+ CryptoUtils::LogError("setting cipher list to " CIPHER_LIST);
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSSetCiphersFailed)
}
}
diff --git a/lib/server/TcpNice.cpp b/lib/server/TcpNice.cpp
new file mode 100644
index 00000000..20619e49
--- /dev/null
+++ b/lib/server/TcpNice.cpp
@@ -0,0 +1,235 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: TcpNice.cpp
+// Purpose: Calculator for adaptive TCP window sizing to support
+// low-priority background flows using the stochastic
+// algorithm, as described in
+// http://www.thlab.net/~lmassoul/p18-key.pdf
+// Created: 11/02/2012
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include "TcpNice.h"
+#include "Logging.h"
+#include "BoxTime.h"
+
+#ifdef HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: TcpNice::TcpNice()
+// Purpose: Initialise state of the calculator
+// Created: 11/02/2012
+//
+// --------------------------------------------------------------------------
+TcpNice::TcpNice()
+: mLastWindowSize(1),
+ mGammaPercent(100),
+ mAlphaStar(100),
+ mDeltaPercent(10)
+{
+ mRateEstimateMovingAverage[0] = 0;
+ mRateEstimateMovingAverage[1] = 0;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: int GetNextWindowSize(int bytesChange,
+// box_time_t timeElapsed, int rttEstimateMillis)
+// Purpose: Calculate the next recommended window size, given the
+// number of bytes sent since the previous recommendation,
+// and the time elapsed.
+// Created: 11/02/2012
+//
+// --------------------------------------------------------------------------
+int TcpNice::GetNextWindowSize(int bytesChange, box_time_t timeElapsed,
+ int rttEstimateMicros)
+{
+ int epsilon = (mAlphaStar * 1000000) / rttEstimateMicros;
+
+ // timeElapsed is in microseconds, so this will fail for T > 2000 seconds
+ int rateLastPeriod = ((uint64_t)bytesChange * 1000000 / timeElapsed);
+
+ int rawAdjustment = epsilon + rateLastPeriod -
+ mRateEstimateMovingAverage[0];
+
+ int gammaAdjustment = (rawAdjustment * mGammaPercent) / 100;
+
+ int newWindowSize = mLastWindowSize + gammaAdjustment;
+
+ int newRateEstimateMovingAverage =
+ (((100 - mDeltaPercent) * mRateEstimateMovingAverage[1]) / 100) +
+ ((mDeltaPercent * rateLastPeriod) / 100);
+
+ /*
+ * b is the number of bytes sent during the previous control period
+ * T is the length (in us) of the previous control period
+ * rtt is the round trip time (in us) reported by the kernel on the socket
+ * e is epsilon, a parameter of the formula, calculated as alpha/rtt
+ * rb is the actual rate (goodput) over the previous period
+ * rbhat is the previous (last-but-one) EWMA rate estimate
+ * raw is the unscaled adjustment to the window size
+ * gamma is the scaled adjustment to the window size
+ * wb is the final window size
+ */
+
+ BOX_TRACE("TcpNice: "
+ "b=" << bytesChange << ", "
+ "T=" << timeElapsed << ", "
+ "rtt=" << rttEstimateMicros << ", "
+ "e=" << epsilon << ", "
+ "rb=" << rateLastPeriod << ", "
+ "rbhat=" << newRateEstimateMovingAverage << ", "
+ "raw=" << rawAdjustment << ", "
+ "gamma=" << gammaAdjustment << ", "
+ "wb=" << newWindowSize);
+
+ mRateEstimateMovingAverage[0] = mRateEstimateMovingAverage[1];
+ mRateEstimateMovingAverage[1] = newRateEstimateMovingAverage;
+ mLastWindowSize = newWindowSize;
+
+ return newWindowSize;
+}
+
+// --------------------------------------------------------------------------
+//
+// Constructor
+// Name: NiceSocketStream::NiceSocketStream(
+// std::auto_ptr<SocketStream> apSocket)
+// Purpose: Initialise state of the socket wrapper
+// Created: 11/02/2012
+//
+// --------------------------------------------------------------------------
+
+NiceSocketStream::NiceSocketStream(std::auto_ptr<SocketStream> apSocket)
+: mapSocket(apSocket),
+ mTcpNice(),
+ mBytesWrittenThisPeriod(0),
+ mPeriodStartTime(GetCurrentBoxTime()),
+ mTimeIntervalMillis(1000),
+ mEnabled(false)
+{ }
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: NiceSocketStream::Write(const void *pBuffer, int NBytes)
+// Purpose: Writes bytes to the underlying stream, adjusting window size
+// using a TcpNice calculator.
+// Created: 2012/02/11
+//
+// --------------------------------------------------------------------------
+void NiceSocketStream::Write(const void *pBuffer, int NBytes)
+{
+#if HAVE_DECL_SO_SNDBUF && HAVE_DECL_TCP_INFO
+ if(mEnabled && mapTimer.get() && mapTimer->HasExpired())
+ {
+ box_time_t newPeriodStart = GetCurrentBoxTime();
+ box_time_t elapsed = newPeriodStart - mPeriodStartTime;
+ int socket = mapSocket->GetSocketHandle();
+ int rtt = 50; // WAG
+
+# if HAVE_DECL_SOL_TCP && HAVE_DECL_TCP_INFO && HAVE_STRUCT_TCP_INFO_TCPI_RTT
+ struct tcp_info info;
+ socklen_t optlen = sizeof(info);
+ if(getsockopt(socket, SOL_TCP, TCP_INFO, &info, &optlen) == -1)
+ {
+ BOX_LOG_SYS_WARNING("getsockopt(" << socket << ", SOL_TCP, "
+ "TCP_INFO) failed");
+ }
+ else if(optlen != sizeof(info))
+ {
+ BOX_WARNING("getsockopt(" << socket << ", SOL_TCP, "
+ "TCP_INFO) return structure size " << optlen << ", "
+ "expected " << sizeof(info));
+ }
+ else
+ {
+ rtt = info.tcpi_rtt;
+ }
+# endif
+
+ int newWindow = mTcpNice.GetNextWindowSize(mBytesWrittenThisPeriod,
+ elapsed, rtt);
+
+ if(setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &newWindow,
+ sizeof(newWindow)) == -1)
+ {
+ BOX_LOG_SYS_WARNING("getsockopt(" << socket << ", SOL_SOCKET, "
+ "SO_SNDBUF, " << newWindow << ") failed");
+ }
+
+ StopTimer();
+ }
+
+ if(mEnabled && !mapTimer.get())
+ {
+ // Don't start the timer until we receive the first data to write,
+ // as diffing might take a long time and we don't want to bias
+ // the TcpNice algorithm by running while we don't have bulk data
+ // to send.
+ StartTimer();
+ mPeriodStartTime = GetCurrentBoxTime();
+ mBytesWrittenThisPeriod = 0;
+ }
+
+ mBytesWrittenThisPeriod += NBytes;
+#endif // HAVE_DECL_SO_SNDBUF
+
+ mapSocket->Write(pBuffer, NBytes);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: NiceSocketStream::SetEnabled(bool enabled)
+// Purpose: Update the enabled status, and if disabling, cancel the
+// timer and set a sensible window size.
+// Created: 2012/02/12
+//
+// --------------------------------------------------------------------------
+
+void NiceSocketStream::SetEnabled(bool enabled)
+{
+ mEnabled = enabled;
+
+ if(!enabled)
+ {
+ StopTimer();
+#if HAVE_DECL_SO_SNDBUF
+ int socket = mapSocket->GetSocketHandle();
+ int newWindow = 1<<17;
+ if(setsockopt(socket, SOL_SOCKET, SO_SNDBUF,
+# ifdef WIN32
+ // optval is a const char * on Windows, even
+ // though the argument is a boolean or integer,
+ // for reasons best known to Microsoft!
+ (const char *)&newWindow,
+# else
+ &newWindow,
+# endif
+ sizeof(newWindow)) == -1)
+ {
+ BOX_LOG_SYS_WARNING("getsockopt(" << socket << ", SOL_SOCKET, "
+ "SO_SNDBUF, " << newWindow << ") failed");
+ }
+#endif
+ }
+}
diff --git a/lib/server/TcpNice.h b/lib/server/TcpNice.h
new file mode 100644
index 00000000..e2027749
--- /dev/null
+++ b/lib/server/TcpNice.h
@@ -0,0 +1,174 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: TcpNice.h
+// Purpose: Calculator for adaptive TCP window sizing to support
+// low-priority background flows using the stochastic
+// algorithm, as described in
+// http://www.thlab.net/~lmassoul/p18-key.pdf
+// Created: 11/02/2012
+//
+// --------------------------------------------------------------------------
+
+#ifndef TCPNICE__H
+#define TCPNICE__H
+
+#include <memory>
+
+#include "SocketStream.h"
+#include "Timer.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: TcpNice
+// Purpose: Calculator for adaptive TCP window sizing.
+// Created: 11/02/2012
+//
+// --------------------------------------------------------------------------
+
+class TcpNice
+{
+public:
+ TcpNice();
+ int GetNextWindowSize(int bytesChange, box_time_t timeElapsed,
+ int rttEstimateMicros);
+
+private:
+ /**
+ * The previous (last recommended) window size is one of the parameters
+ * used to calculate the next window size.
+ */
+ int mLastWindowSize;
+
+ /**
+ * Controls the speed of adaptation and the variance (random variation)
+ * of the stable state in response to noise. The paper suggests using
+ * 1.0 (100%).
+ */
+ int mGammaPercent;
+
+ /**
+ * Controls the extent to which background flows are allowed to affect
+ * foreground flows. Its detailed meaning is not explained in the paper,
+ * but its units are bytes, and I think it controls how aggressive we
+ * are at increasing window size, potentially at the expense of other
+ * competing flows.
+ */
+ int mAlphaStar;
+
+ /**
+ * Controls the speed of adaptation of the exponential weighted moving
+ * average (EWMA) estimate of the bandwidth available to this flow.
+ * The paper uses 10%.
+ */
+ int mDeltaPercent;
+
+ /**
+ * The stochastic algorithm in the paper uses the rate estimate for the
+ * last-but-one period (rbHat[n-2]) to calculate the next window size.
+ * So we keep both the last (in rateEstimateMovingAverage[1]) and the
+ * last-but-one (in rateEstimateMovingAverage[0]) values.
+ */
+ int mRateEstimateMovingAverage[2];
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: NiceSocketStream
+// Purpose: Wrapper around a SocketStream to limit sending rate to
+// avoid interference with higher-priority flows.
+// Created: 11/02/2012
+//
+// --------------------------------------------------------------------------
+
+class NiceSocketStream : public IOStream
+{
+private:
+ std::auto_ptr<SocketStream> mapSocket;
+ TcpNice mTcpNice;
+ std::auto_ptr<Timer> mapTimer;
+ int mBytesWrittenThisPeriod;
+ box_time_t mPeriodStartTime;
+
+ /**
+ * The control interval T from the paper, in milliseconds. The available
+ * bandwidth is estimated over this period, and the window size is
+ * recalculated at the end of each period. It should be long enough for
+ * TCP to adapt to a change in window size; perhaps 10-100 RTTs. One
+ * second (1000) is probably a good first approximation in many cases.
+ */
+ int mTimeIntervalMillis;
+
+ /**
+ * Because our data use is bursty, and tcp nice works on the assumption
+ * that we've always got data to send, we should only enable nice mode
+ * when we're doing a bulk upload, and disable it afterwards.
+ */
+ bool mEnabled;
+
+ void StartTimer()
+ {
+ mapTimer.reset(new Timer(mTimeIntervalMillis, "NiceSocketStream"));
+ }
+
+ void StopTimer()
+ {
+ mapTimer.reset();
+ }
+
+public:
+ NiceSocketStream(std::auto_ptr<SocketStream> apSocket);
+ virtual ~NiceSocketStream()
+ {
+ // Be nice about closing the socket
+ mapSocket->Shutdown();
+ mapSocket->Close();
+ }
+
+ // This is the only magic
+ virtual void Write(const void *pBuffer, int NBytes);
+
+ // Everything else is delegated to the sink
+ virtual int Read(void *pBuffer, int NBytes,
+ int Timeout = IOStream::TimeOutInfinite)
+ {
+ return mapSocket->Read(pBuffer, NBytes, Timeout);
+ }
+ virtual pos_type BytesLeftToRead()
+ {
+ return mapSocket->BytesLeftToRead();
+ }
+ virtual pos_type GetPosition() const
+ {
+ return mapSocket->GetPosition();
+ }
+ virtual void Seek(IOStream::pos_type Offset, int SeekType)
+ {
+ mapSocket->Seek(Offset, SeekType);
+ }
+ virtual void Flush(int Timeout = IOStream::TimeOutInfinite)
+ {
+ mapSocket->Flush(Timeout);
+ }
+ virtual void Close()
+ {
+ mapSocket->Close();
+ }
+ virtual bool StreamDataLeft()
+ {
+ return mapSocket->StreamDataLeft();
+ }
+ virtual bool StreamClosed()
+ {
+ return mapSocket->StreamClosed();
+ }
+ virtual void SetEnabled(bool enabled);
+
+private:
+ NiceSocketStream(const NiceSocketStream &rToCopy)
+ { /* do not call */ }
+};
+
+#endif // TCPNICE__H
diff --git a/lib/server/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in
index 91ba55b0..9caa970d 100755
--- a/lib/server/makeprotocol.pl.in
+++ b/lib/server/makeprotocol.pl.in
@@ -30,6 +30,7 @@ my %log_display_types =
'string' => ['%s', 'VAR.c_str()']
);
+<<<<<<< HEAD
my ($type, $file) = @ARGV;
@@ -48,6 +49,21 @@ my @extra_header_files;
my $implement_syslog = 0;
my $implement_filelog = 0;
+=======
+if (@ARGV != 1)
+{
+ die "Usage: $0 <protocol-txt-file>\n";
+}
+
+my ($file) = @ARGV;
+
+open IN, $file or die "Can't open input file $file\n";
+
+print "Making protocol classes from $file...\n";
+
+my @extra_header_files;
+
+>>>>>>> 0.12
# read attributes
my %attr;
while(<IN>)
@@ -59,6 +75,7 @@ while(<IN>)
my ($k,$v) = split /\s+/,$l,2;
+<<<<<<< HEAD
if($k eq 'ClientType')
{
add_type($v) if $type eq 'Client';
@@ -94,6 +111,20 @@ while(<IN>)
{
$log_display_types{$type_name} = [$printf_format,$arg_template]
}
+=======
+ if($k eq 'AddType')
+ {
+ add_type($v);
+ }
+ elsif($k eq 'ImplementLog')
+ {
+ # Always implement logging
+ }
+ elsif($k eq 'LogTypeToText')
+ {
+ my ($type_name,$printf_format,$arg_template) = split /\s+/,$v;
+ $log_display_types{$type_name} = [$printf_format,$arg_template]
+>>>>>>> 0.12
}
else
{
@@ -169,9 +200,19 @@ close IN;
# open files
+<<<<<<< HEAD
my $h_filename = 'autogen_'.$protocol_name.'Protocol'.$type.'.h';
open CPP,'>autogen_'.$protocol_name.'Protocol'.$type.'.cpp';
open H,">$h_filename";
+=======
+my $filename_base = 'autogen_'.$protocol_name.'Protocol';
+print "Writing $filename_base.cpp\n";
+print "Writing $filename_base.h\n";
+open CPP, "> $filename_base.cpp";
+open H, "> $filename_base.h";
+
+my $guardname = uc 'AUTOGEN_'.$protocol_name.'Protocol_H';
+>>>>>>> 0.12
print CPP <<__E;
@@ -181,6 +222,7 @@ print CPP <<__E;
#include <sstream>
+<<<<<<< HEAD
#include "$h_filename"
#include "IOStream.h"
@@ -199,27 +241,52 @@ EOF
my $guardname = uc 'AUTOGEN_'.$protocol_name.'Protocol'.$type.'_H';
print H <<__E;
+=======
+#include "$filename_base.h"
+#include "IOStream.h"
+__E
+
+print H <<__E;
+>>>>>>> 0.12
// Auto-generated file -- do not edit
#ifndef $guardname
#define $guardname
+<<<<<<< HEAD
#include "Protocol.h"
#include "ProtocolObject.h"
+=======
+#include <cstdio>
+#include <list>
+
+#ifndef WIN32
+#include <syslog.h>
+#endif
+
+#include "Protocol.h"
+#include "Message.h"
+>>>>>>> 0.12
#include "ServerException.h"
class IOStream;
+<<<<<<< HEAD
__E
if($implement_filelog)
{
print H qq~#include <stdio.h>\n~;
}
+=======
+
+__E
+>>>>>>> 0.12
# extra headers
for(@extra_header_files)
{
+<<<<<<< HEAD
print H qq~#include "$_"\n~
}
print H "\n";
@@ -320,12 +387,103 @@ public:
$classname_base$cmd();
$classname_base$cmd(const $classname_base$cmd &rToCopy);
~$classname_base$cmd();
+=======
+ print H qq@#include "$_"\n@;
+}
+
+print H <<__E;
+
+// need utils file for the server
+#include "Utils.h"
+
+__E
+
+my $message_base_class = "${protocol_name}ProtocolMessage";
+my $objects_extra_h = '';
+my $objects_extra_cpp = '';
+
+# define the context
+print H "class $context_class;\n\n";
+print CPP <<__E;
+#include "$context_class_inc"
+#include "MemLeakFindOn.h"
+__E
+
+my $request_base_class = "${protocol_name}ProtocolRequest";
+my $reply_base_class = "${protocol_name}ProtocolReply";
+# the abstract protocol interface
+my $protocol_base_class = $protocol_name."ProtocolBase";
+my $replyable_base_class = $protocol_name."ProtocolReplyable";
+
+print H <<__E;
+class $protocol_base_class;
+class $replyable_base_class;
+class $reply_base_class;
+
+class $message_base_class : public Message
+{
+public:
+ virtual std::auto_ptr<$message_base_class> DoCommand($replyable_base_class &rProtocol,
+ $context_class &rContext) const;
+};
+
+class $reply_base_class
+{
+};
+
+class $request_base_class
+{
+};
+
+__E
+
+print CPP <<__E;
+std::auto_ptr<$message_base_class> $message_base_class\::DoCommand($replyable_base_class &rProtocol,
+ $context_class &rContext) const
+{
+ THROW_EXCEPTION(ConnectionException, Conn_Protocol_TriedToExecuteReplyCommand)
+}
+__E
+
+my %cmd_class;
+
+# output the classes
+foreach my $cmd (@cmd_list)
+{
+ my @cmd_base_classes = ($message_base_class);
+
+ if(obj_is_type($cmd, 'Command'))
+ {
+ push @cmd_base_classes, $request_base_class;
+ }
+
+ if(obj_is_type($cmd, 'Reply'))
+ {
+ push @cmd_base_classes, $reply_base_class;
+ }
+
+ my $cmd_base_class = join(", ", map {"public $_"} @cmd_base_classes);
+ my $cmd_class = $protocol_name."Protocol".$cmd;
+ $cmd_class{$cmd} = $cmd_class;
+
+ print H <<__E;
+class $cmd_class : $cmd_base_class
+{
+public:
+ $cmd_class();
+ $cmd_class(const $cmd_class &rToCopy);
+ ~$cmd_class();
+>>>>>>> 0.12
int GetType() const;
enum
{
TypeID = $cmd_id{$cmd}
};
__E
+<<<<<<< HEAD
+=======
+
+>>>>>>> 0.12
# constants
if(exists $cmd_constants{$cmd})
{
@@ -333,16 +491,25 @@ __E
print H join(",\n\t\t",@{$cmd_constants{$cmd}});
print H "\n\t};\n";
}
+<<<<<<< HEAD
+=======
+
+>>>>>>> 0.12
# flags
if(obj_is_type($cmd,'EndsConversation'))
{
print H "\tbool IsConversationEnd() const;\n";
}
+<<<<<<< HEAD
+=======
+
+>>>>>>> 0.12
if(obj_is_type($cmd,'IsError'))
{
print H "\tbool IsError(int &rTypeOut, int &rSubTypeOut) const;\n";
print H "\tstd::string GetMessage() const;\n";
}
+<<<<<<< HEAD
if($type eq 'Server' && obj_is_type($cmd, 'Command'))
{
print H "\tstd::auto_ptr<ProtocolObject> DoCommand(${protocol_name}ProtocolServer &rProtocol, $context_class &rContext); // IMPLEMENT THIS\n"
@@ -399,6 +566,54 @@ __E
print H "\tvirtual void LogFile(const char *Action, FILE *file) const;\n";
}
+=======
+
+ if(obj_is_type($cmd, 'Command'))
+ {
+ print H <<__E;
+ std::auto_ptr<$message_base_class> DoCommand($replyable_base_class &rProtocol,
+ $context_class &rContext) const; // IMPLEMENT THIS\n
+__E
+ }
+
+ # want to be able to read from streams?
+ print H "\tvoid SetPropertiesFromStreamData(Protocol &rProtocol);\n";
+
+ # write Get functions
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ print H "\t".translate_type_to_arg_type($ty)." Get$nm() {return m$nm;}\n";
+ }
+
+ my $param_con_args = '';
+ # extra constructor?
+ if($#{$cmd_contents{$cmd}} >= 0)
+ {
+ my @a;
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ push @a,translate_type_to_arg_type($ty)." $nm";
+ }
+ $param_con_args = join(', ',@a);
+ print H "\t$cmd_class(".$param_con_args.");\n";
+ }
+ print H "\tvoid WritePropertiesToStreamData(Protocol &rProtocol) const;\n";
+ # set functions
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ print H "\tvoid Set$nm(".translate_type_to_arg_type($ty)." $nm) {m$nm = $nm;}\n";
+ }
+
+ print H "\tvirtual void LogSysLog(const char *Action) const;\n";
+ print H "\tvirtual void LogFile(const char *Action, FILE *file) const;\n";
+ print H "\tvirtual std::string ToString() const;\n";
+>>>>>>> 0.12
# write member variables and setup for cpp file
my @def_constructor_list;
@@ -432,6 +647,7 @@ __E
my $param_con_vars = join(",\n\t ",@param_constructor_list);
$param_con_vars = "\n\t: ".$param_con_vars if $param_con_vars ne '';
+<<<<<<< HEAD
my $class = "$classname_base$cmd".'::';
print CPP <<__E;
$class$classname_base$cmd()$def_con_vars
@@ -444,10 +660,24 @@ $class~$classname_base$cmd()
{
}
int ${class}GetType() const
+=======
+ print CPP <<__E;
+$cmd_class\::$cmd_class()$def_con_vars
+{
+}
+$cmd_class\::$cmd_class(const $cmd_class &rToCopy)$copy_con_vars
+{
+}
+$cmd_class\::~$cmd_class()
+{
+}
+int $cmd_class\::GetType() const
+>>>>>>> 0.12
{
return $cmd_id{$cmd};
}
__E
+<<<<<<< HEAD
if($read_from_streams)
{
print CPP "void ${class}SetPropertiesFromStreamData(Protocol &rProtocol)\n{\n";
@@ -491,18 +721,68 @@ __E
{
print CPP "bool ${class}IsConversationEnd() const\n{\n\treturn true;\n}\n";
}
+=======
+ print CPP "void $cmd_class\::SetPropertiesFromStreamData(Protocol &rProtocol)\n{\n";
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+ if($ty =~ m/\Avector/)
+ {
+ print CPP "\trProtocol.ReadVector(m$nm);\n";
+ }
+ else
+ {
+ print CPP "\trProtocol.Read(m$nm);\n";
+ }
+ }
+ print CPP "}\n";
+
+ # implement extra constructor?
+ if($param_con_vars ne '')
+ {
+ print CPP "$cmd_class\::$cmd_class($param_con_args)$param_con_vars\n{\n}\n";
+ }
+ print CPP "void $cmd_class\::WritePropertiesToStreamData(Protocol &rProtocol) const\n{\n";
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+ if($ty =~ m/\Avector/)
+ {
+ print CPP "\trProtocol.WriteVector(m$nm);\n";
+ }
+ else
+ {
+ print CPP "\trProtocol.Write(m$nm);\n";
+ }
+ }
+ print CPP "}\n";
+
+ if(obj_is_type($cmd,'EndsConversation'))
+ {
+ print CPP "bool $cmd_class\::IsConversationEnd() const\n{\n\treturn true;\n}\n";
+ }
+
+>>>>>>> 0.12
if(obj_is_type($cmd,'IsError'))
{
# get parameters
my ($mem_type,$mem_subtype) = split /,/,obj_get_type_params($cmd,'IsError');
print CPP <<__E;
+<<<<<<< HEAD
bool ${class}IsError(int &rTypeOut, int &rSubTypeOut) const
+=======
+bool $cmd_class\::IsError(int &rTypeOut, int &rSubTypeOut) const
+>>>>>>> 0.12
{
rTypeOut = m$mem_type;
rSubTypeOut = m$mem_subtype;
return true;
}
+<<<<<<< HEAD
std::string ${class}GetMessage() const
+=======
+std::string $cmd_class\::GetMessage() const
+>>>>>>> 0.12
{
switch(m$mem_subtype)
{
@@ -526,6 +806,7 @@ __E
__E
}
+<<<<<<< HEAD
if($implement_syslog)
{
my ($log) = make_log_strings_framework($cmd);
@@ -667,11 +948,453 @@ const char *${prefix}GetIdentString()
return "$ident_string";
}
std::auto_ptr<ProtocolObject> ${prefix}MakeProtocolObject(int ObjType)
+=======
+ my ($log) = make_log_strings_framework($cmd);
+ print CPP <<__E;
+std::string $cmd_class\::ToString() const
+{
+ std::ostringstream oss;
+ try
+ {
+ oss << $log;
+ }
+ catch(std::exception &e)
+ {
+ oss << "Failed to log command: " << e.what();
+ }
+ return oss.str();
+}
+void $cmd_class\::LogSysLog(const char *Action) const
+{
+ try
+ {
+ BOX_TRACE(Action << " " << $log);
+ }
+ catch(std::exception &e)
+ {
+ BOX_WARNING("Failed to log command: " << Action << ": " <<
+ e.what());
+ }
+}
+void $cmd_class\::LogFile(const char *Action, FILE *File) const
+{
+ ::fprintf(File, "%s %s\\n", Action, ToString().c_str());
+ ::fflush(File);
+}
+__E
+}
+
+my $error_class = $protocol_name."ProtocolError";
+
+# the abstract protocol interface
+print H <<__E;
+class $protocol_base_class
+{
+public:
+ $protocol_base_class();
+ virtual ~$protocol_base_class();
+ virtual const char *GetIdentString();
+ bool GetLastError(int &rTypeOut, int &rSubTypeOut);
+
+protected:
+ void CheckReply(const std::string& requestCommand,
+ const $message_base_class &rReply, int expectedType);
+ void SetLastError(int Type, int SubType)
+ {
+ mLastErrorType = Type;
+ mLastErrorSubType = SubType;
+ }
+
+private:
+ $protocol_base_class(const $protocol_base_class &rToCopy); /* do not call */
+ int mLastErrorType;
+ int mLastErrorSubType;
+};
+
+class $replyable_base_class : public virtual $protocol_base_class
+{
+public:
+ $replyable_base_class();
+ virtual ~$replyable_base_class();
+
+ /*
+ virtual std::auto_ptr<$message_base_class> Receive() = 0;
+ virtual void Send(const ${message_base_class} &rObject) = 0;
+ */
+
+ virtual std::auto_ptr<IOStream> ReceiveStream() = 0;
+ virtual int GetTimeout() = 0;
+ void SendStreamAfterCommand(std::auto_ptr<IOStream> apStream);
+
+protected:
+ std::list<IOStream*> mStreamsToSend;
+ void DeleteStreamsToSend();
+
+private:
+ $replyable_base_class(const $replyable_base_class &rToCopy); /* do not call */
+};
+
+__E
+
+print CPP <<__E;
+$protocol_base_class\::$protocol_base_class()
+: mLastErrorType(Protocol::NoError),
+ mLastErrorSubType(Protocol::NoError)
+{ }
+
+$protocol_base_class\::~$protocol_base_class()
+{ }
+
+const char *$protocol_base_class\::GetIdentString()
+{
+ return "$ident_string";
+}
+
+$replyable_base_class\::$replyable_base_class()
+{ }
+
+$replyable_base_class\::~$replyable_base_class()
+{ }
+
+void $replyable_base_class\::SendStreamAfterCommand(std::auto_ptr<IOStream> apStream)
+{
+ ASSERT(apStream.get() != NULL);
+ mStreamsToSend.push_back(apStream.release());
+}
+
+void $replyable_base_class\::DeleteStreamsToSend()
+{
+ for(std::list<IOStream*>::iterator i(mStreamsToSend.begin()); i != mStreamsToSend.end(); ++i)
+ {
+ delete (*i);
+ }
+
+ mStreamsToSend.clear();
+}
+
+void $protocol_base_class\::CheckReply(const std::string& requestCommand,
+ const $message_base_class &rReply, int expectedType)
+{
+ if(rReply.GetType() == expectedType)
+ {
+ // Correct response, do nothing
+ }
+ else
+ {
+ // Set protocol error
+ int type, subType;
+
+ if(rReply.IsError(type, subType))
+ {
+ SetLastError(type, subType);
+ THROW_EXCEPTION_MESSAGE(ConnectionException,
+ Conn_Protocol_UnexpectedReply,
+ requestCommand << " command failed: "
+ "received error " <<
+ (($error_class&)rReply).GetMessage());
+ }
+ else
+ {
+ SetLastError(Protocol::UnknownError, Protocol::UnknownError);
+ THROW_EXCEPTION_MESSAGE(ConnectionException,
+ Conn_Protocol_UnexpectedReply,
+ requestCommand << " command failed: "
+ "received unexpected response type " <<
+ rReply.GetType());
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Protocol::GetLastError(int &, int &)
+// Purpose: Returns true if there was an error, and type and subtype if there was.
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+bool $protocol_base_class\::GetLastError(int &rTypeOut, int &rSubTypeOut)
+{
+ if(mLastErrorType == Protocol::NoError)
+ {
+ // no error.
+ return false;
+ }
+
+ // Return type and subtype in args
+ rTypeOut = mLastErrorType;
+ rSubTypeOut = mLastErrorSubType;
+
+ // and unset them
+ mLastErrorType = Protocol::NoError;
+ mLastErrorSubType = Protocol::NoError;
+
+ return true;
+}
+
+__E
+
+# the callable protocol interface (implemented by Client and Local classes)
+# with Query methods that don't take a context parameter
+my $callable_base_class = $protocol_name."ProtocolCallable";
+print H <<__E;
+class $callable_base_class : public virtual $protocol_base_class
+{
+public:
+ virtual std::auto_ptr<IOStream> ReceiveStream() = 0;
+ virtual int GetTimeout() = 0;
+__E
+
+# add plain object taking query functions
+my $with_params;
+for my $cmd (@cmd_list)
+{
+ if(obj_is_type($cmd,'Command'))
+ {
+ my $has_stream = obj_is_type($cmd,'StreamWithCommand');
+ my $argextra = $has_stream?', std::auto_ptr<IOStream> apStream':'';
+ my $queryextra = $has_stream?', apStream':'';
+ my $request_class = $cmd_class{$cmd};
+ my $reply_class = $cmd_class{obj_get_type_params($cmd,'Command')};
+
+ print H "\tvirtual std::auto_ptr<$reply_class> Query(const $request_class &rQuery$argextra) = 0;\n";
+ my @a;
+ my @na;
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+ push @a,translate_type_to_arg_type($ty)." $nm";
+ push @na,"$nm";
+ }
+ my $ar = join(', ',@a);
+ my $nar = join(', ',@na);
+ $nar = "($nar)" if $nar ne '';
+
+ $with_params .= <<__E;
+ inline std::auto_ptr<$reply_class> Query$cmd($ar$argextra)
+ {
+ $request_class send$nar;
+ return Query(send$queryextra);
+ }
+__E
+ }
+}
+
+# quick hack to correct bad argument lists for commands with zero parameters but with streams
+$with_params =~ s/\(, /(/g;
+
+print H <<__E;
+
+$with_params
+};
+__E
+
+# standard remote protocol objects
+foreach my $type ('Client', 'Server', 'Local')
+{
+ my $writing_client = ($type eq 'Client');
+ my $writing_server = ($type eq 'Server');
+ my $writing_local = ($type eq 'Local');
+
+ my $server_or_client_class = $protocol_name."Protocol".$type;
+ my @base_classes;
+
+ if (not $writing_client)
+ {
+ push @base_classes, $replyable_base_class;
+ }
+ if (not $writing_server)
+ {
+ push @base_classes, $callable_base_class;
+ }
+ if (not $writing_local)
+ {
+ push @base_classes, "Protocol";
+ }
+
+ my $base_classes_str = join(", ", map {"public $_"} @base_classes);
+
+ print H <<__E;
+class $server_or_client_class : $base_classes_str
+{
+public:
+__E
+
+ if($writing_local)
+ {
+ print H <<__E;
+ $server_or_client_class($context_class &rContext);
+__E
+ }
+ else
+ {
+ print H <<__E;
+ $server_or_client_class(IOStream &rStream);
+ std::auto_ptr<$message_base_class> Receive();
+ void Send(const $message_base_class &rObject);
+__E
+ }
+
+ print H <<__E;
+ virtual ~$server_or_client_class();
+__E
+
+ if($writing_server)
+ {
+ # need to put in the conversation function
+ print H <<__E;
+ void DoServer($context_class &rContext);
+
+__E
+ }
+
+ if($writing_client or $writing_local)
+ {
+ # add plain object taking query functions
+ for my $cmd (@cmd_list)
+ {
+ if(obj_is_type($cmd,'Command'))
+ {
+ my $has_stream = obj_is_type($cmd,'StreamWithCommand');
+ my $argextra = $has_stream?', std::auto_ptr<IOStream> apStream':'';
+ my $queryextra = $has_stream?', apStream':'';
+ my $request_class = $cmd_class{$cmd};
+ my $reply_class = $cmd_class{obj_get_type_params($cmd,'Command')};
+ print H "\tstd::auto_ptr<$reply_class> Query(const $request_class &rQuery$argextra);\n";
+ }
+ }
+ }
+
+ if($writing_local)
+ {
+ print H <<__E;
+private:
+ $context_class &mrContext;
+__E
+ }
+
+ print H <<__E;
+
+protected:
+ virtual std::auto_ptr<Message> MakeMessage(int ObjType);
+
+__E
+
+ if($writing_local)
+ {
+ print H <<__E;
+ virtual void InformStreamReceiving(u_int32_t Size) { }
+ virtual void InformStreamSending(u_int32_t Size) { }
+
+public:
+ virtual std::auto_ptr<IOStream> ReceiveStream()
+ {
+ std::auto_ptr<IOStream> apStream(mStreamsToSend.front());
+ mStreamsToSend.pop_front();
+ return apStream;
+ }
+__E
+ }
+ else
+ {
+ print H <<__E;
+ virtual void InformStreamReceiving(u_int32_t Size)
+ {
+ this->Protocol::InformStreamReceiving(Size);
+ }
+ virtual void InformStreamSending(u_int32_t Size)
+ {
+ this->Protocol::InformStreamSending(Size);
+ }
+
+public:
+ virtual std::auto_ptr<IOStream> ReceiveStream()
+ {
+ return this->Protocol::ReceiveStream();
+ }
+__E
+ }
+
+ print H <<__E;
+ virtual const char *GetProtocolIdentString()
+ {
+ return GetIdentString();
+ }
+__E
+
+ if($writing_local)
+ {
+ print H <<__E;
+ virtual int GetTimeout()
+ {
+ return IOStream::TimeOutInfinite;
+ }
+__E
+ }
+ else
+ {
+ print H <<__E;
+ virtual int GetTimeout()
+ {
+ return this->Protocol::GetTimeout();
+ }
+__E
+ }
+
+ print H <<__E;
+ /*
+ virtual void Handshake()
+ {
+ this->Protocol::Handshake();
+ }
+ virtual bool GetLastError(int &rTypeOut, int &rSubTypeOut)
+ {
+ return this->Protocol::GetLastError(rTypeOut, rSubTypeOut);
+ }
+ */
+
+private:
+ $server_or_client_class(const $server_or_client_class &rToCopy); /* no copies */
+};
+
+__E
+
+ my $destructor_extra = ($writing_server) ? "\n\tDeleteStreamsToSend();"
+ : '';
+
+ if($writing_local)
+ {
+ print CPP <<__E;
+$server_or_client_class\::$server_or_client_class($context_class &rContext)
+: mrContext(rContext)
+{ }
+__E
+ }
+ else
+ {
+ print CPP <<__E;
+$server_or_client_class\::$server_or_client_class(IOStream &rStream)
+: Protocol(rStream)
+{ }
+__E
+ }
+
+ print CPP <<__E;
+$server_or_client_class\::~$server_or_client_class()
+{$destructor_extra
+}
+__E
+
+ # write receive and send functions
+ print CPP <<__E;
+std::auto_ptr<Message> $server_or_client_class\::MakeMessage(int ObjType)
+>>>>>>> 0.12
{
switch(ObjType)
{
__E
+<<<<<<< HEAD
# do objects within this
for my $cmd (@cmd_list)
{
@@ -683,11 +1406,25 @@ __E
}
print CPP <<__E;
+=======
+ # do objects within this
+ for my $cmd (@cmd_list)
+ {
+ print CPP <<__E;
+ case $cmd_id{$cmd}:
+ return std::auto_ptr<Message>(new $cmd_class{$cmd}());
+ break;
+__E
+ }
+
+ print CPP <<__E;
+>>>>>>> 0.12
default:
THROW_EXCEPTION(ConnectionException, Conn_Protocol_UnknownCommandRecieved)
}
}
__E
+<<<<<<< HEAD
# write receive and send functions
print CPP <<__E;
std::auto_ptr<$derive_objects_from> ${prefix}Receive()
@@ -714,10 +1451,31 @@ __E
__E
}
print CPP <<__E;
+=======
+
+ if(not $writing_local)
+ {
+ print CPP <<__E;
+std::auto_ptr<$message_base_class> $server_or_client_class\::Receive()
+{
+ std::auto_ptr<$message_base_class> preply(($message_base_class *)
+ Protocol::ReceiveInternal().release());
+
+ if(GetLogToSysLog())
+ {
+ preply->LogSysLog("Receive");
+ }
+
+ if(GetLogToFile() != 0)
+ {
+ preply->LogFile("Receive", GetLogToFile());
+ }
+>>>>>>> 0.12
return preply;
}
+<<<<<<< HEAD
void ${prefix}Send(const ${derive_objects_from} &rObject)
{
__E
@@ -750,6 +1508,31 @@ if($type eq 'Server')
{
print CPP <<__E;
void ${prefix}DoServer($context_class &rContext)
+=======
+void $server_or_client_class\::Send(const $message_base_class &rObject)
+{
+ if(GetLogToSysLog())
+ {
+ rObject.LogSysLog("Send");
+ }
+
+ if(GetLogToFile() != 0)
+ {
+ rObject.LogFile("Send", GetLogToFile());
+ }
+
+ Protocol::SendInternal(rObject);
+}
+
+__E
+ }
+
+ # write server function?
+ if($writing_server)
+ {
+ print CPP <<__E;
+void $server_or_client_class\::DoServer($context_class &rContext)
+>>>>>>> 0.12
{
// Handshake with client
Handshake();
@@ -759,6 +1542,7 @@ void ${prefix}DoServer($context_class &rContext)
while(inProgress)
{
// Get an object from the conversation
+<<<<<<< HEAD
std::auto_ptr<${derive_objects_from}> pobj(Receive());
// Run the command
@@ -773,6 +1557,24 @@ void ${prefix}DoServer($context_class &rContext)
// Send the streams
SendStream(*mStreamsToSend[s]);
}
+=======
+ std::auto_ptr<$message_base_class> pobj = Receive();
+
+ // Run the command
+ std::auto_ptr<$message_base_class> preply = pobj->DoCommand(*this, rContext);
+
+ // Send the reply
+ Send(*preply);
+
+ // Send any streams
+ for(std::list<IOStream*>::iterator
+ i = mStreamsToSend.begin();
+ i != mStreamsToSend.end(); ++i)
+ {
+ SendStream(**i);
+ }
+
+>>>>>>> 0.12
// Delete these streams
DeleteStreamsToSend();
@@ -784,6 +1586,7 @@ void ${prefix}DoServer($context_class &rContext)
}
}
+<<<<<<< HEAD
void ${prefix}SendStreamAfterCommand(IOStream *pStream)
{
ASSERT(pStream != NULL);
@@ -898,10 +1701,45 @@ __E
}
print CPP <<__E;
std::auto_ptr<$classname_base$reply> ${classname_base}::Query(const $classname_base$cmd &rQuery$argextra)
+=======
+__E
+ }
+
+ # write client Query functions?
+ if($writing_client or $writing_local)
+ {
+ for my $cmd (@cmd_list)
+ {
+ if(obj_is_type($cmd,'Command'))
+ {
+ my $request_class = $cmd_class{$cmd};
+ my $reply_msg = obj_get_type_params($cmd,'Command');
+ my $reply_class = $cmd_class{$reply_msg};
+ my $reply_id = $cmd_id{$reply_msg};
+ my $has_stream = obj_is_type($cmd,'StreamWithCommand');
+ my $argextra = $has_stream?', std::auto_ptr<IOStream> apStream':'';
+ my $send_stream_extra = '';
+ my $send_stream_method = $writing_client ? "SendStream"
+ : "SendStreamAfterCommand";
+
+ if($writing_client)
+ {
+ if($has_stream)
+ {
+ $send_stream_extra = <<__E;
+ // Send stream after the command
+ SendStream(*apStream);
+__E
+ }
+
+ print CPP <<__E;
+std::auto_ptr<$reply_class> $server_or_client_class\::Query(const $request_class &rQuery$argextra)
+>>>>>>> 0.12
{
// Send query
Send(rQuery);
$send_stream_extra
+<<<<<<< HEAD
// Wait for the reply
std::auto_ptr<${derive_objects_from}> preply(Receive().release());
@@ -933,12 +1771,53 @@ std::auto_ptr<$classname_base$reply> ${classname_base}::Query(const $classname_b
}
}
__E
+=======
+
+ // Wait for the reply
+ std::auto_ptr<$message_base_class> preply = Receive();
+
+ CheckReply("$cmd", *preply, $reply_id);
+
+ // Correct response, if no exception thrown by CheckReply
+ return std::auto_ptr<$reply_class>(($reply_class *)preply.release());
+}
+__E
+ }
+ elsif($writing_local)
+ {
+ if($has_stream)
+ {
+ $send_stream_extra = <<__E;
+ // Send stream after the command
+ SendStreamAfterCommand(apStream);
+__E
+ }
+
+ print CPP <<__E;
+std::auto_ptr<$reply_class> $server_or_client_class\::Query(const $request_class &rQuery$argextra)
+{
+ // Send query
+ $send_stream_extra
+ std::auto_ptr<$message_base_class> preply = rQuery.DoCommand(*this, mrContext);
+
+ CheckReply("$cmd", *preply, $reply_id);
+
+ // Correct response, if no exception thrown by CheckReply
+ return std::auto_ptr<$reply_class>(($reply_class *)preply.release());
+}
+__E
+ }
+ }
+>>>>>>> 0.12
}
}
}
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
print H <<__E;
#endif // $guardname
@@ -948,8 +1827,12 @@ __E
close H;
close CPP;
+<<<<<<< HEAD
sub obj_is_type
+=======
+sub obj_is_type ($$)
+>>>>>>> 0.12
{
my ($c,$ty) = @_;
for(@{$cmd_attributes{$c}})
@@ -1003,6 +1886,7 @@ sub translate_type_to_member_type
return $typename
}
+<<<<<<< HEAD
sub make_log_strings
{
my ($cmd) = @_;
@@ -1037,6 +1921,8 @@ sub make_log_strings
return ($cmd.'('.join(',',@str).')', join(',','',@arg));
}
+=======
+>>>>>>> 0.12
sub make_log_strings_framework
{
my ($cmd) = @_;
@@ -1053,7 +1939,11 @@ sub make_log_strings_framework
my ($format,$arg) = @{$log_display_types{$ty}};
$arg =~ s/VAR/m$nm/g;
+<<<<<<< HEAD
if ($format eq '\\"%s\\"')
+=======
+ if ($format eq '"%s"')
+>>>>>>> 0.12
{
$arg = "\"\\\"\" << $arg << \"\\\"\"";
}
@@ -1080,7 +1970,11 @@ sub make_log_strings_framework
}
}
+<<<<<<< HEAD
my $log_cmd = "Action << \" $cmd(\" ";
+=======
+ my $log_cmd = '"'.$cmd.'(" ';
+>>>>>>> 0.12
foreach my $arg (@args)
{
$arg = "<< $arg ";
@@ -1090,4 +1984,7 @@ sub make_log_strings_framework
return $log_cmd;
}
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12