summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorChris Wilson <chris+github@qwirx.com>2014-10-31 22:09:42 +0000
committerChris Wilson <chris+github@qwirx.com>2014-10-31 22:09:42 +0000
commite8efeb785c158581be729aa1dee122f50789ac86 (patch)
treedd1fda26285a9255411c607b6910b79a89877242 /lib
parent9236e14007c068d7d9294d90aeb976eb9cecab84 (diff)
Refactor handling of exceptions in protocol server command executors.
Add a standard method to Replyable that will be called if a recoverable exception (a BoxException) occurs, and can return a protocol Message to be sent to the client, such as an error code for various standard errors, or rethrow the exception. If you want something different, catch exceptions and return the desired reply yourself, or you'll get the default handling.
Diffstat (limited to 'lib')
-rw-r--r--lib/backupstore/BackupCommands.cpp161
-rw-r--r--lib/backupstore/BackupProtocol.h2
-rwxr-xr-xlib/server/makeprotocol.pl.in51
3 files changed, 103 insertions, 111 deletions
diff --git a/lib/backupstore/BackupCommands.cpp b/lib/backupstore/BackupCommands.cpp
index c32987fe..ab0dc4b8 100644
--- a/lib/backupstore/BackupCommands.cpp
+++ b/lib/backupstore/BackupCommands.cpp
@@ -52,11 +52,58 @@
return PROTOCOL_ERROR(Err_SessionReadOnly); \
}
+
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupProtocolVersion::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Return the current version, or an error if the requested version isn't allowed
+// Name: BackupProtocolMessage::HandleException(BoxException& e)
+// Purpose: Return an error message appropriate to the passed-in
+// exception, or rethrow it.
+// Created: 2014/09/14
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<BackupProtocolMessage> BackupProtocolReplyable::HandleException(BoxException& e) const
+{
+ if(e.GetType() == RaidFileException::ExceptionType &&
+ e.GetSubType() == RaidFileException::RaidFileDoesntExist)
+ {
+ return PROTOCOL_ERROR(Err_DoesNotExist);
+ }
+ else if (e.GetType() == BackupStoreException::ExceptionType)
+ {
+ if(e.GetSubType() == BackupStoreException::AddedFileDoesNotVerify)
+ {
+ return PROTOCOL_ERROR(Err_FileDoesNotVerify);
+ }
+ else if(e.GetSubType() == BackupStoreException::AddedFileExceedsStorageLimit)
+ {
+ return PROTOCOL_ERROR(Err_StorageLimitExceeded);
+ }
+ else if(e.GetSubType() == BackupStoreException::MultiplyReferencedObject)
+ {
+ return PROTOCOL_ERROR(Err_MultiplyReferencedObject);
+ }
+ else if(e.GetSubType() == BackupStoreException::CouldNotFindEntryInDirectory)
+ {
+ return PROTOCOL_ERROR(Err_DoesNotExist);
+ }
+ else if(e.GetSubType() == BackupStoreException::NameAlreadyExistsInDirectory)
+ {
+ return PROTOCOL_ERROR(Err_TargetNameExists);
+ }
+ }
+
+ throw;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolVersion::DoCommand(Protocol &,
+// BackupStoreContext &)
+// Purpose: Return the current version, or an error if the
+// requested version isn't allowed
// Created: 2003/08/20
//
// --------------------------------------------------------------------------
@@ -192,23 +239,12 @@ std::auto_ptr<BackupProtocolMessage> BackupProtocolListDirectory::DoCommand(Back
// Store the listing to a stream
std::auto_ptr<CollectInBufferStream> stream(new CollectInBufferStream);
- try
- {
- // Ask the context for a directory
- const BackupStoreDirectory &rdir(
- rContext.GetDirectory(mObjectID));
- rdir.WriteToStream(*stream, mFlagsMustBeSet,
- mFlagsNotToBeSet, mSendAttributes,
- false /* never send dependency info to the client */);
- }
- catch(RaidFileException &e)
- {
- if (e.GetSubType() == RaidFileException::RaidFileDoesntExist)
- {
- return PROTOCOL_ERROR(Err_DoesNotExist);
- }
- throw;
- }
+ // Ask the context for a directory
+ const BackupStoreDirectory &rdir(
+ rContext.GetDirectory(mObjectID));
+ rdir.WriteToStream(*stream, mFlagsMustBeSet,
+ mFlagsNotToBeSet, mSendAttributes,
+ false /* never send dependency info to the client */);
stream->SetForReading();
@@ -252,29 +288,10 @@ std::auto_ptr<BackupProtocolMessage> BackupProtocolStoreFile::DoCommand(
}
// Ask the context to store it
- int64_t id = 0;
- try
- {
- id = rContext.AddFile(rDataStream, mDirectoryObjectID,
- mModificationTime, mAttributesHash, mDiffFromFileID,
- mFilename,
- true /* mark files with same name as old versions */);
- }
- catch(BackupStoreException &e)
- {
- if(e.GetSubType() == BackupStoreException::AddedFileDoesNotVerify)
- {
- return PROTOCOL_ERROR(Err_FileDoesNotVerify);
- }
- else if(e.GetSubType() == BackupStoreException::AddedFileExceedsStorageLimit)
- {
- return PROTOCOL_ERROR(Err_StorageLimitExceeded);
- }
- else
- {
- throw;
- }
- }
+ int64_t id = rContext.AddFile(rDataStream, mDirectoryObjectID,
+ mModificationTime, mAttributesHash, mDiffFromFileID,
+ mFilename,
+ true /* mark files with same name as old versions */);
// Tell the caller what the file ID was
return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(id));
@@ -507,25 +524,9 @@ std::auto_ptr<BackupProtocolMessage> BackupProtocolCreateDirectory2::DoCommand(
}
bool alreadyExists = false;
- int64_t id;
-
- try
- {
- id = rContext.AddDirectory(mContainingDirectoryID,
- mDirectoryName, attr, mAttributesModTime, mModificationTime,
- alreadyExists);
- }
- catch(BackupStoreException &e)
- {
- if(e.GetSubType() == BackupStoreException::AddedFileExceedsStorageLimit)
- {
- return PROTOCOL_ERROR(Err_StorageLimitExceeded);
- }
- else
- {
- throw;
- }
- }
+ int64_t id = rContext.AddDirectory(mContainingDirectoryID,
+ mDirectoryName, attr, mAttributesModTime, mModificationTime,
+ alreadyExists);
if(alreadyExists)
{
@@ -666,19 +667,7 @@ std::auto_ptr<BackupProtocolMessage> BackupProtocolDeleteDirectory::DoCommand(Ba
}
// Context handles this
- try
- {
- rContext.DeleteDirectory(mObjectID);
- }
- catch(BackupStoreException &e)
- {
- if(e.GetSubType() == BackupStoreException::MultiplyReferencedObject)
- {
- return PROTOCOL_ERROR(Err_MultiplyReferencedObject);
- }
-
- throw;
- }
+ rContext.DeleteDirectory(mObjectID);
// return the object ID
return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(mObjectID));
@@ -746,27 +735,9 @@ std::auto_ptr<BackupProtocolMessage> BackupProtocolMoveObject::DoCommand(BackupP
CHECK_WRITEABLE_SESSION
// Let context do this, but modify error reporting on exceptions...
- try
- {
- rContext.MoveObject(mObjectID, mMoveFromDirectory, mMoveToDirectory,
- mNewFilename, (mFlags & Flags_MoveAllWithSameName) == Flags_MoveAllWithSameName,
- (mFlags & Flags_AllowMoveOverDeletedObject) == Flags_AllowMoveOverDeletedObject);
- }
- catch(BackupStoreException &e)
- {
- if(e.GetSubType() == BackupStoreException::CouldNotFindEntryInDirectory)
- {
- return PROTOCOL_ERROR(Err_DoesNotExist);
- }
- else if(e.GetSubType() == BackupStoreException::NameAlreadyExistsInDirectory)
- {
- return PROTOCOL_ERROR(Err_TargetNameExists);
- }
- else
- {
- throw;
- }
- }
+ rContext.MoveObject(mObjectID, mMoveFromDirectory, mMoveToDirectory,
+ mNewFilename, (mFlags & Flags_MoveAllWithSameName) == Flags_MoveAllWithSameName,
+ (mFlags & Flags_AllowMoveOverDeletedObject) == Flags_AllowMoveOverDeletedObject);
// Return the object ID
return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(mObjectID));
diff --git a/lib/backupstore/BackupProtocol.h b/lib/backupstore/BackupProtocol.h
index 0e0988f7..d9070c73 100644
--- a/lib/backupstore/BackupProtocol.h
+++ b/lib/backupstore/BackupProtocol.h
@@ -19,7 +19,7 @@
// Class
// Name: BackupProtocolLocal2
// Purpose: BackupProtocolLocal with a few more IQ points
-// Created: 2003/08/21
+// Created: 2014/09/20
//
// --------------------------------------------------------------------------
class BackupProtocolLocal2 : public BackupProtocolLocal
diff --git a/lib/server/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in
index 65d1f3a9..d61a14d0 100755
--- a/lib/server/makeprotocol.pl.in
+++ b/lib/server/makeprotocol.pl.in
@@ -604,10 +604,11 @@ public:
virtual int GetTimeout() = 0;
void SendStreamAfterCommand(std::auto_ptr<IOStream> apStream);
-
+
protected:
std::list<IOStream*> mStreamsToSend;
void DeleteStreamsToSend();
+ virtual std::auto_ptr<$message_base_class> HandleException(BoxException& e) const;
private:
$replyable_base_class(const $replyable_base_class &rToCopy); /* do not call */
@@ -1077,24 +1078,31 @@ void $server_or_client_class\::DoServer($context_class &rContext)
// Run the command
try
{
- if(pobj->HasStreamWithCommand())
+ try
{
- std::auto_ptr<IOStream> apDataStream = ReceiveStream();
- SelfFlushingStream autoflush(*apDataStream);
- preply = pobj->DoCommand(*this, rContext, *apDataStream);
+ if(pobj->HasStreamWithCommand())
+ {
+ std::auto_ptr<IOStream> apDataStream = ReceiveStream();
+ SelfFlushingStream autoflush(*apDataStream);
+ preply = pobj->DoCommand(*this, rContext, *apDataStream);
+ }
+ else
+ {
+ preply = pobj->DoCommand(*this, rContext);
+ }
}
- else
+ catch(BoxException &e)
{
- preply = pobj->DoCommand(*this, rContext);
+ // First try a the built-in exception handler
+ preply = HandleException(e);
}
}
- catch (std::exception &e)
- {
- Send($cmd_classes{$error_message}());
- throw;
- }
catch (...)
{
+ // Fallback in case the exception isn't a BoxException
+ // or the exception handler fails as well. This path
+ // throws the exception upwards, killing the process
+ // that handles the current client.
Send($cmd_classes{$error_message}());
throw;
}
@@ -1183,19 +1191,32 @@ __E
}
elsif($writing_local)
{
+ print CPP <<__E;
+ std::auto_ptr<$message_base_class> apReply;
+ try
+ {
+__E
if($has_stream)
{
print CPP <<__E;
- std::auto_ptr<$message_base_class> apReply = rQuery.DoCommand(*this,
- mrContext, *apDataStream);
+ apReply = rQuery.DoCommand(*this, mrContext, *apDataStream);
__E
}
else
{
print CPP <<__E;
- std::auto_ptr<$message_base_class> apReply = rQuery.DoCommand(*this, mrContext);
+ apReply = rQuery.DoCommand(*this, mrContext);
__E
}
+
+ print CPP <<__E;
+ }
+ catch(BoxException &e)
+ {
+ // First try a the built-in exception handler
+ apReply = HandleException(e);
+ }
+__E
}
# Common to both client and local