[Box Backup-commit] COMMIT r3296 - box/trunk/lib/server

subversion at boxbackup.org subversion at boxbackup.org
Sun Mar 2 08:58:41 GMT 2014


Author: chris
Date: 2014-03-02 08:58:41 +0000 (Sun, 02 Mar 2014)
New Revision: 3296

Modified:
   box/trunk/lib/server/ConnectionException.txt
   box/trunk/lib/server/Message.h
   box/trunk/lib/server/Protocol.h
   box/trunk/lib/server/makeprotocol.pl.in
Log:
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.

Modified: box/trunk/lib/server/ConnectionException.txt
===================================================================
--- box/trunk/lib/server/ConnectionException.txt	2014-03-02 08:58:29 UTC (rev 3295)
+++ box/trunk/lib/server/ConnectionException.txt	2014-03-02 08:58:41 UTC (rev 3296)
@@ -25,3 +25,4 @@
 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.

Modified: box/trunk/lib/server/Message.h
===================================================================
--- box/trunk/lib/server/Message.h	2014-03-02 08:58:29 UTC (rev 3295)
+++ box/trunk/lib/server/Message.h	2014-03-02 08:58:41 UTC (rev 3296)
@@ -41,6 +41,7 @@
 
 	virtual void LogSysLog(const char *Action) const { }
 	virtual void LogFile(const char *Action, FILE *file) const { }
+	virtual std::string ToString() const = 0;
 };
 
 /*

Modified: box/trunk/lib/server/Protocol.h
===================================================================
--- box/trunk/lib/server/Protocol.h	2014-03-02 08:58:29 UTC (rev 3295)
+++ box/trunk/lib/server/Protocol.h	2014-03-02 08:58:41 UTC (rev 3296)
@@ -211,4 +211,3 @@
 };
 
 #endif // PROTOCOL__H
-

Modified: box/trunk/lib/server/makeprotocol.pl.in
===================================================================
--- box/trunk/lib/server/makeprotocol.pl.in	2014-03-02 08:58:29 UTC (rev 3295)
+++ box/trunk/lib/server/makeprotocol.pl.in	2014-03-02 08:58:41 UTC (rev 3296)
@@ -211,13 +211,16 @@
 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 $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 @@
 
 # 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();
+	$client_server_base_class();
+	virtual ~$client_server_base_class();
+	virtual std::auto_ptr<IOStream> ReceiveStream() = 0;
 	bool GetLastError(int &rTypeOut, int &rSubTypeOut);
-	virtual std::auto_ptr<IOStream> ReceiveStream() = 0;
 
 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,22 +568,41 @@
 __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 @@
 	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 @@
 			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 @@
 			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 @@
 //		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 @@
 
 # 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 @@
 	}
 	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 @@
 	{
 		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 @@
 __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,30 +852,35 @@
 	else
 	{
 		print H <<__E;
-	virtual void InformStreamReceiving(u_int32_t Size)
+public:
+	virtual std::auto_ptr<IOStream> ReceiveStream();
+__E
+
+		print CPP <<__E;
+std::auto_ptr<IOStream> $server_or_client_class\::ReceiveStream()
+{
+	try
 	{
-		this->Protocol::InformStreamReceiving(Size);
+		return $custom_protocol_subclass\::ReceiveStream();
 	}
-	virtual void InformStreamSending(u_int32_t Size)
+	catch(ConnectionException &e)
 	{
-		this->Protocol::InformStreamSending(Size);
+		if(e.GetSubType() == ConnectionException::Protocol_ObjWhenStreamExpected)
+		{
+			THROW_EXCEPTION_MESSAGE(ConnectionException,
+				Protocol_ObjWhenStreamExpected,
+				"Last exchange was " << mPreviousCommand <<
+				" => " << mPreviousReply);
+		}
+		else
+		{
+			throw;
+		}
 	}
-
-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;
@@ -849,23 +895,13 @@
 		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 @@
 	{
 		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 @@
 __E
 
 	# write receive and send functions
-	print CPP <<__E;
-std::auto_ptr<Message> $server_or_client_class\::MakeMessage(int ObjType)
+	if(not $writing_local)
+	{
+		print CPP <<__E;
+std::auto_ptr<$message_base_class> $server_or_client_class\::Receive()
 {
-	switch(ObjType)
-	{
-__E
+	std::auto_ptr<$message_base_class> apReply;
 
-	# do objects within this
-	for my $cmd (@cmd_list)
+	try
 	{
-		print CPP <<__E;
-	case $cmd_id{$cmd}:
-		return std::auto_ptr<Message>(new $cmd_classes{$cmd}());
-		break;
-__E
+		apReply = std::auto_ptr<$message_base_class>(
+			($message_base_class *)
+			$custom_protocol_subclass\::ReceiveInternal().release());
 	}
-
-	print CPP <<__E;
-	default:
-		THROW_EXCEPTION(ConnectionException, Conn_Protocol_UnknownCommandRecieved)
+	catch(ConnectionException &e)
+	{
+		if(e.GetSubType() == ConnectionException::Protocol_StreamWhenObjExpected)
+		{
+			THROW_EXCEPTION_MESSAGE(ConnectionException,
+				Protocol_StreamWhenObjExpected,
+				"Last exchange was " << mPreviousCommand <<
+				" => " << mPreviousReply);
+		}
+		else
+		{
+			throw;
+		}
 	}
-}
-__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");
+		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 @@
 			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 @@
 				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,8 +1080,6 @@
 					}
 					
 					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
@@ -1042,12 +1086,6 @@
 	
 	// 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 @@
 					}
 
 					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
-				}
 			}
 		}
 	}




More information about the Boxbackup-commit mailing list