diff options
author | Chris Wilson <chris+github@qwirx.com> | 2014-03-02 08:58:41 +0000 |
---|---|---|
committer | Chris Wilson <chris+github@qwirx.com> | 2014-03-02 08:58:41 +0000 |
commit | 772ecab2a053fefbf7b65e66e05babfb21920aea (patch) | |
tree | 25e538a40637b2bc9ae2eb0b48be2cef6388272e /lib | |
parent | 7f8353d71c272415d09531c46888560b7ea7de8f (diff) |
Add information about last exchange when wrong type of object received.
Helps with debugging ConnectionException::Protocol_StreamWhenObjExpected and
ConnectionException::Protocol_ObjWhenStreamExpected errors, which may be caused
by a command returning an error message and failing to consume any uploaded
streams first.
Add extra debugging in ProtocolLocal objects to detect when this happens
during the command itself, which helps with debugging.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/server/ConnectionException.txt | 1 | ||||
-rw-r--r-- | lib/server/Message.h | 1 | ||||
-rw-r--r-- | lib/server/Protocol.h | 1 | ||||
-rwxr-xr-x | lib/server/makeprotocol.pl.in | 265 |
4 files changed, 158 insertions, 110 deletions
diff --git a/lib/server/ConnectionException.txt b/lib/server/ConnectionException.txt index c3429116..7dcaadeb 100644 --- a/lib/server/ConnectionException.txt +++ b/lib/server/ConnectionException.txt @@ -25,3 +25,4 @@ Protocol_HandshakeFailed 48 Protocol_StreamWhenObjExpected 49 Protocol_ObjWhenStreamExpected 50 Protocol_TimeOutWhenSendingStream 52 Probably a network issue between client and server. +Protocol_StreamsNotConsumed 53 The server command handler did not consume all streams that were sent. diff --git a/lib/server/Message.h b/lib/server/Message.h index 0d073d49..c6fa3cc1 100644 --- a/lib/server/Message.h +++ b/lib/server/Message.h @@ -41,6 +41,7 @@ public: virtual void LogSysLog(const char *Action) const { } virtual void LogFile(const char *Action, FILE *file) const { } + virtual std::string ToString() const = 0; }; /* diff --git a/lib/server/Protocol.h b/lib/server/Protocol.h index 0995393d..6a63d3b2 100644 --- a/lib/server/Protocol.h +++ b/lib/server/Protocol.h @@ -211,4 +211,3 @@ class ProtocolContext }; #endif // PROTOCOL__H - diff --git a/lib/server/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in index 00dc58d4..97b0b3d9 100755 --- a/lib/server/makeprotocol.pl.in +++ b/lib/server/makeprotocol.pl.in @@ -211,13 +211,16 @@ __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 $custom_protocol_subclass = $protocol_name."Protocol"; +my $client_server_base_class = $protocol_name."ProtocolClientServer"; my $replyable_base_class = $protocol_name."ProtocolReplyable"; +my $callable_base_class = $protocol_name."ProtocolCallable"; print H <<__E; -class $protocol_base_class; +class $custom_protocol_subclass; +class $client_server_base_class; +class $callable_base_class; class $replyable_base_class; -class $reply_base_class; class $message_base_class : public Message { @@ -234,6 +237,20 @@ class $request_base_class { }; +class $custom_protocol_subclass : public Protocol +{ +public: + $custom_protocol_subclass(std::auto_ptr<SocketStream> apConn) + : Protocol(apConn) + { } + virtual ~$custom_protocol_subclass() { } + virtual std::auto_ptr<Message> MakeMessage(int ObjType); + virtual const char *GetProtocolIdentString(); + +private: + $custom_protocol_subclass(const $custom_protocol_subclass &rToCopy); +}; + __E print CPP <<__E; @@ -507,34 +524,34 @@ my $error_class = $protocol_name."ProtocolError"; # the abstract protocol interface print H <<__E; -class $protocol_base_class + +class $client_server_base_class { public: - $protocol_base_class(); - virtual ~$protocol_base_class(); - virtual const char *GetIdentString(); - bool GetLastError(int &rTypeOut, int &rSubTypeOut); + $client_server_base_class(); + virtual ~$client_server_base_class(); virtual std::auto_ptr<IOStream> ReceiveStream() = 0; + 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; } + std::string mPreviousCommand; + std::string mPreviousReply; private: - $protocol_base_class(const $protocol_base_class &rToCopy); /* do not call */ + $client_server_base_class(const $client_server_base_class &rToCopy); /* do not call */ int mLastErrorType; int mLastErrorSubType; }; -class $replyable_base_class : public virtual $protocol_base_class +class $replyable_base_class : public virtual $client_server_base_class { public: - $replyable_base_class(); + $replyable_base_class() { } virtual ~$replyable_base_class(); virtual int GetTimeout() = 0; @@ -551,21 +568,40 @@ private: __E print CPP <<__E; -$protocol_base_class\::$protocol_base_class() +$client_server_base_class\::$client_server_base_class() : mLastErrorType(Protocol::NoError), mLastErrorSubType(Protocol::NoError) { } -$protocol_base_class\::~$protocol_base_class() +$client_server_base_class\::~$client_server_base_class() { } -const char *$protocol_base_class\::GetIdentString() +const char *$custom_protocol_subclass\::GetProtocolIdentString() { return "$ident_string"; } -$replyable_base_class\::$replyable_base_class() -{ } +std::auto_ptr<Message> $custom_protocol_subclass\::MakeMessage(int ObjType) +{ + switch(ObjType) + { +__E + +# do objects within this +for my $cmd (@cmd_list) +{ + print CPP <<__E; + case $cmd_id{$cmd}: + return std::auto_ptr<Message>(new $cmd_classes{$cmd}()); + break; +__E +} + +print CPP <<__E; + default: + THROW_EXCEPTION(ConnectionException, Conn_Protocol_UnknownCommandRecieved) + } +} $replyable_base_class\::~$replyable_base_class() { } @@ -586,8 +622,9 @@ void $replyable_base_class\::DeleteStreamsToSend() mStreamsToSend.clear(); } -void $protocol_base_class\::CheckReply(const std::string& requestCommand, - const $message_base_class &rReply, int expectedType) +void $callable_base_class\::CheckReply(const std::string& requestCommandName, + const $message_base_class &rCommand, const $message_base_class &rReply, + int expectedType) { if(rReply.GetType() == expectedType) { @@ -603,7 +640,7 @@ void $protocol_base_class\::CheckReply(const std::string& requestCommand, SetLastError(type, subType); THROW_EXCEPTION_MESSAGE(ConnectionException, Conn_Protocol_UnexpectedReply, - requestCommand << " command failed: " + requestCommandName << " command failed: " "received error " << (($error_class&)rReply).GetMessage()); } @@ -612,11 +649,17 @@ void $protocol_base_class\::CheckReply(const std::string& requestCommand, SetLastError(Protocol::UnknownError, Protocol::UnknownError); THROW_EXCEPTION_MESSAGE(ConnectionException, Conn_Protocol_UnexpectedReply, - requestCommand << " command failed: " + requestCommandName << " command failed: " "received unexpected response type " << rReply.GetType()); } } + + // As a client, if we get an unexpected reply later, we'll want to know + // the last command that we executed, and the reply, to help debug the + // server. + mPreviousCommand = rCommand.ToString(); + mPreviousReply = rReply.ToString(); } // -------------------------------------------------------------------------- @@ -627,7 +670,7 @@ void $protocol_base_class\::CheckReply(const std::string& requestCommand, // Created: 2003/08/19 // // -------------------------------------------------------------------------- -bool $protocol_base_class\::GetLastError(int &rTypeOut, int &rSubTypeOut) +bool $client_server_base_class\::GetLastError(int &rTypeOut, int &rSubTypeOut) { if(mLastErrorType == Protocol::NoError) { @@ -650,12 +693,18 @@ __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 +class $callable_base_class : public virtual $client_server_base_class { public: virtual int GetTimeout() = 0; + +protected: + void CheckReply(const std::string& requestCommandName, + const $message_base_class &rCommand, + const $message_base_class &rReply, int expectedType); + +public: __E # add plain object taking query functions @@ -722,7 +771,7 @@ foreach my $type ('Client', 'Server', 'Local') } if (not $writing_local) { - push @base_classes, "Protocol"; + push @base_classes, $custom_protocol_subclass; } my $base_classes_str = join(", ", map {"public $_"} @base_classes); @@ -743,8 +792,10 @@ __E { print H <<__E; $server_or_client_class(std::auto_ptr<SocketStream> apConn); +private: std::auto_ptr<$message_base_class> Receive(); void Send(const $message_base_class &rObject); +public: __E } @@ -786,19 +837,9 @@ private: __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() { @@ -811,29 +852,34 @@ __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(); - } + virtual std::auto_ptr<IOStream> ReceiveStream(); __E - } - print H <<__E; - virtual const char *GetProtocolIdentString() + print CPP <<__E; +std::auto_ptr<IOStream> $server_or_client_class\::ReceiveStream() +{ + try + { + return $custom_protocol_subclass\::ReceiveStream(); + } + catch(ConnectionException &e) { - return GetIdentString(); + if(e.GetSubType() == ConnectionException::Protocol_ObjWhenStreamExpected) + { + THROW_EXCEPTION_MESSAGE(ConnectionException, + Protocol_ObjWhenStreamExpected, + "Last exchange was " << mPreviousCommand << + " => " << mPreviousReply); + } + else + { + throw; + } } +} __E + } if($writing_local) { @@ -849,23 +895,13 @@ __E print H <<__E; virtual int GetTimeout() { - return this->Protocol::GetTimeout(); + return $custom_protocol_subclass\::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 */ }; @@ -887,7 +923,7 @@ __E { print CPP <<__E; $server_or_client_class\::$server_or_client_class(std::auto_ptr<SocketStream> apConn) -: Protocol(apConn) +: $custom_protocol_subclass(apConn) { } __E } @@ -899,49 +935,45 @@ $server_or_client_class\::~$server_or_client_class() __E # write receive and send functions - print CPP <<__E; -std::auto_ptr<Message> $server_or_client_class\::MakeMessage(int ObjType) -{ - switch(ObjType) - { -__E - - # do objects within this - for my $cmd (@cmd_list) - { - print CPP <<__E; - case $cmd_id{$cmd}: - return std::auto_ptr<Message>(new $cmd_classes{$cmd}()); - break; -__E - } - - print CPP <<__E; - default: - THROW_EXCEPTION(ConnectionException, Conn_Protocol_UnknownCommandRecieved) - } -} -__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()); + std::auto_ptr<$message_base_class> apReply; + + try + { + apReply = std::auto_ptr<$message_base_class>( + ($message_base_class *) + $custom_protocol_subclass\::ReceiveInternal().release()); + } + catch(ConnectionException &e) + { + if(e.GetSubType() == ConnectionException::Protocol_StreamWhenObjExpected) + { + THROW_EXCEPTION_MESSAGE(ConnectionException, + Protocol_StreamWhenObjExpected, + "Last exchange was " << mPreviousCommand << + " => " << mPreviousReply); + } + else + { + throw; + } + } if(GetLogToSysLog()) { - preply->LogSysLog("Receive"); + apReply->LogSysLog("Receive"); } if(GetLogToFile() != 0) { - preply->LogFile("Receive", GetLogToFile()); + apReply->LogFile("Receive", GetLogToFile()); } - return preply; + return apReply; } void $server_or_client_class\::Send(const $message_base_class &rObject) @@ -992,6 +1024,15 @@ void $server_or_client_class\::DoServer($context_class &rContext) SendStream(**i); } + // As a server, if we get an unexpected message later, we'll + // want to know/ the last command that we received, and the + // reply, to help debug our response to it. + mPreviousCommand = pobj->ToString(); + std::ostringstream reply; + reply << preply->ToString() << " and " << + mStreamsToSend.size() << " streams"; + mPreviousReply = reply.str(); + // Delete these streams DeleteStreamsToSend(); @@ -1022,7 +1063,12 @@ __E my $send_stream_extra = ''; my $send_stream_method = $writing_client ? "SendStream" : "SendStreamAfterCommand"; - + + print CPP <<__E; +std::auto_ptr<$reply_class> $server_or_client_class\::Query(const $request_class &rQuery$argextra) +{ +__E + if($writing_client) { if($has_stream) @@ -1034,20 +1080,12 @@ __E } print CPP <<__E; -std::auto_ptr<$reply_class> $server_or_client_class\::Query(const $request_class &rQuery$argextra) -{ // Send query Send(rQuery); $send_stream_extra // 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) @@ -1061,19 +1099,28 @@ __E } print CPP <<__E; -std::auto_ptr<$reply_class> $server_or_client_class\::Query(const $request_class &rQuery$argextra) -{ - // Send query + // Push streams to send, if any, into queue for retrieval by DoCommand. $send_stream_extra + + // Execute the command and get the reply message std::auto_ptr<$message_base_class> preply = rQuery.DoCommand(*this, mrContext); - CheckReply("$cmd", *preply, $reply_id); + if(!mStreamsToSend.empty()) + { + THROW_EXCEPTION_MESSAGE(ConnectionException, + Protocol_StreamsNotConsumed, rQuery.ToString()); + } +__E + } + + # Common to both client and local + print CPP <<__E; + CheckReply("$cmd", rQuery, *preply, $reply_id); // Correct response, if no exception thrown by CheckReply return std::auto_ptr<$reply_class>(($reply_class *)preply.release()); } __E - } } } } |