Click here to Skip to main content
15,884,629 members
Articles / Programming Languages / C++

RCF - Interprocess Communication for C++

Rate me:
Please Sign up or sign in to vote.
4.94/5 (147 votes)
25 Oct 2011CPOL20 min read 4.6M   8.4K   331  
A server/client IPC framework, using the C++ preprocessor as an IDL compiler.
//******************************************************************************
// RCF - Remote Call Framework
// Copyright (c) 2005 - 2007. All rights reserved.
// Consult your license for conditions of use.
// Developed by Jarl Lindrud.
// Contact: jlindrud@hotmail.com .
//******************************************************************************

#ifndef INCLUDE_RCF_EXCEPTION_HPP
#define INCLUDE_RCF_EXCEPTION_HPP

#include <sstream>
#include <stdexcept>
#include <string>

#include <RCF/util/DefaultInit.hpp>
#include <RCF/TypeTraits.hpp>

namespace RCF {

    // RCF error codes
    // range 0-1000 reserved for RCF, remaining range can be used independently of RCF

    static const int RcfError_Ok                                =  0;
    static const int RcfError_Unspecified                       =  1;
    static const int RcfError_ServerMessageLength               =  2;
    static const int RcfError_ClientMessageLength               =  3;
    static const int RcfError_Serialization                     =  4;
    static const int RcfError_Deserialization                   =  5;
    static const int RcfError_UserModeException                 =  6;
    static const int RcfError_UnknownEndpoint                   =  8;
    static const int RcfError_EndpointPassword                  =  9;
    static const int RcfError_EndpointDown                      = 10;
    static const int RcfError_EndpointRetry                     = 11;
    static const int RcfError_ClientConnectTimeout              = 16;
    static const int RcfError_PeerDisconnect                    = 17;
    static const int RcfError_ClientCancel                      = 18;
    static const int RcfError_StubAssignment                    = 19;
    static const int RcfError_PayloadFilterMismatch             = 20;
    static const int RcfError_OpenSslFilterInit                 = 21;
    static const int RcfError_OpenSslLoadCert                   = 22;
    static const int RcfError_UnknownPublisher                  = 23;
    static const int RcfError_UnknownFilter                     = 24;
    static const int RcfError_NoServerStub                      = 25;
    static const int RcfError_Sspi                              = 26;
    static const int RcfError_SspiAuthFail                      = 27;
    static const int RcfError_SspiInit                          = 28;
    static const int RcfError_UnknownSubscriber                 = 29;
    static const int RcfError_ClientReadTimeout                 = 30;
    static const int RcfError_ClientReadFail                    = 31;
    static const int RcfError_ClientWriteTimeout                = 32;
    static const int RcfError_ClientWriteFail                   = 33;
    static const int RcfError_ClientConnectFail                 = 34;
    static const int RcfError_Filter                            = 35;
    static const int RcfError_Socket                            = 36;
    static const int RcfError_FnId                              = 37;
    static const int RcfError_UnknownInterface                  = 38;
    static const int RcfError_NoEndpoint                        = 39;
    static const int RcfError_TransportCreation                 = 40;
    static const int RcfError_FilterCount                       = 41;
    static const int RcfError_FilterMessage                     = 42;
    static const int RcfError_UnfilterMessage                   = 43;
    static const int RcfError_SspiCredentials                   = 44;
    static const int RcfError_SspiEncrypt                       = 45;
    static const int RcfError_SspiDecrypt                       = 46;
    static const int RcfError_SspiImpersonation                 = 47;
    static const int RcfError_NotConnected                      = 48;
    static const int RcfError_SocketClose                       = 49;
    static const int RcfError_ZlibDeflate                       = 50;
    static const int RcfError_ZlibInflate                       = 51;
    static const int RcfError_Zlib                              = 52;
    static const int RcfError_UnknownSerializationProtocol      = 53;
    static const int RcfError_InvalidErrorMessage               = 54;
    static const int SfError_NoCtor                             = 55;
    static const int SfError_RefMismatch                        = 56;
    static const int SfError_DataFormat                         = 57;
    static const int SfError_ReadFailure                        = 58;
    static const int SfError_WriteFailure                       = 59;
    static const int SfError_BaseDerivedRegistration            = 60;
    static const int SfError_TypeRegistration                   = 61;
    static const int RcfError_BadException                      = 62;
    static const int RcfError_SocketBind                        = 63;
    static const int RcfError_Decoding                          = 64;
    static const int RcfError_Encoding                          = 65;
    static const int RcfError_TokenRequestFailed                = 66;
    static const int RcfError_ObjectFactoryNotFound             = 67;
    static const int RcfError_PortInUse                         = 68;
    static const int RcfError_DynamicObjectNotFound             = 69;
    static const int RcfError_VersionMismatch                   = 70;
    static const int RcfError_RepeatedRetries                   = 71;
    static const int RcfError_SslCertVerification               = 72;
    static const int RcfError_OutOfBoundsLength                 = 73;
    static const int RcfError_User                              = 1001;

    // RCF subsystem identifiers
    static const int RcfSubsystem_None                          = 0;
    static const int RcfSubsystem_Os                            = 1;
    static const int RcfSubsystem_Zlib                          = 2;
    static const int RcfSubsystem_OpenSsl                       = 3;
    static const int RcfSubsystem_Asio                          = 4;

    std::string getErrorString(int rcfError);
    std::string getSubSystemName(int subSystem);
    std::string getOsErrorString(int osError);

    /// Base class of all exceptions thrown by RCF.
    class Exception : public std::runtime_error
    {
    public:
        Exception() :
            std::runtime_error(""),
            mWhat(),
            mError(RCF_DEFAULT_INIT),
            mSubSystemError(RCF_DEFAULT_INIT),
            mSubSystem(RCF_DEFAULT_INIT)
        {}

        Exception(const std::string &what, const std::string &context = "") :
            std::runtime_error(""),
            mWhat(what),
            mContext(context),
            mError(RcfError_Unspecified),
            mSubSystemError(RCF_DEFAULT_INIT),
            mSubSystem(RCF_DEFAULT_INIT)
        {}

        Exception(
            int error,
            const std::string &what = "",
            const std::string &context = "") :
                std::runtime_error(""),
                mWhat(what),
                mContext(context),
                mError(error),
                mSubSystemError(RCF_DEFAULT_INIT),
                mSubSystem(RCF_DEFAULT_INIT)
        {}

        Exception(
            int error,
            int subSystemError,
            int subSystem,
            const std::string &what = "",
            const std::string &context = "") :
                std::runtime_error(""),
                mWhat(what),
                mContext(context),
                mError(error),
                mSubSystemError(subSystemError),
                mSubSystem(subSystem)
        {}

        ~Exception() throw()
        {}

        const char *what() const throw()
        {
            mTranslatedWhat = translate();
            return mTranslatedWhat.c_str();
        }

        int getError() const
        {
            return mError;
        }

        int getSubSystemError() const
        {
            return mSubSystemError;
        }

        int getSubSystem() const
        {
            return mSubSystem;
        }

        void setContext(const std::string &context)
        {
            mContext = context;
        }

        std::string getContext() const
        {
            return mContext;
        }

        void setWhat(const std::string &what)
        {
            mWhat = what;
        }

        std::string getWhat() const
        {
            return mWhat;
        }

    protected:

        std::string translate() const
        {
            //return getErrorString(mError) + " (" + mWhat + ")";

            std::string osErr;
            // TODO: retrieve error messages from other subsystems as well
            if (mSubSystem == RcfSubsystem_Os)
            {
                osErr = getOsErrorString(mSubSystemError);
            }

            std::ostringstream os;
            os
                << "[" << mError << ": " << getErrorString(mError) << "]"
                << "[" << mSubSystem << ": " << getSubSystemName(mSubSystem) << "]"
                << "[" << mSubSystemError << ": " << osErr << "]"
                << "[What: " << mWhat << "]"
                << "[Context: " << mContext << "]";
            return os.str();
        }

        // protected to make serialization of RemoteException simpler
    protected:

        std::string mWhat;
        std::string mContext;
        int mError;
        int mSubSystemError;
        int mSubSystem;

        mutable std::string mTranslatedWhat;
    };

    class RemoteException : public Exception
    {
    public:
        RemoteException()
        {}

        RemoteException(
            int remoteError,
            const std::string &remoteWhat = "",
            const std::string &remoteContext = "",
            const std::string &remoteExceptionType = "") :
                Exception(
                    remoteError,
                    remoteWhat,
                    remoteContext),
                    mRemoteExceptionType(remoteExceptionType)
        {}

        RemoteException(
            int remoteError,
            int remoteSubSystemError,
            int remoteSubSystem,
            const std::string &remoteWhat = "",
            const std::string &remoteContext = "",
            const std::string &remoteExceptionType = "") :
                Exception(
                    remoteError,
                    remoteSubSystemError,
                    remoteSubSystem,
                    remoteWhat,
                    remoteContext),
                    mRemoteExceptionType(remoteExceptionType)
        {}

        ~RemoteException() throw()
        {}

        const char *what() const throw()
        {
            mTranslatedWhat = "[Remote]" + translate();
            return mTranslatedWhat.c_str();
        }

        std::string getRemoteExceptionType() const
        {
            return mRemoteExceptionType;
        }

        template<typename Archive>
        void serialize(Archive &ar, const unsigned int)
        {
            ar
                & mWhat
                & mContext
                & mError
                & mSubSystemError
                & mSubSystem
                & mRemoteExceptionType;
        }

        virtual void throwCopy() const;

    private:
        std::string mRemoteExceptionType;
    };

#define RCF_DEFINE_EXCEPTION(E, PE)                             \
    class E : public PE                                         \
    {                                                           \
    public:                                                     \
        E(                                                      \
            const std::string &what = "") :                     \
                PE(RcfError_Unspecified, what)                  \
        {}                                                      \
        E(                                                      \
            int error,                                          \
            const std::string &what = "") :                     \
                PE(error, what)                                 \
        {}                                                      \
        E(                                                      \
            int error,                                          \
            int subSystemError,                                 \
            int subSystem,                                      \
            const std::string &what = "") :                     \
                PE(error, subSystemError, subSystem, what)      \
        {}                                                      \
        ~E() throw()                                            \
        {}                                                      \
    };

    RCF_DEFINE_EXCEPTION(SerializationException,        Exception)
    RCF_DEFINE_EXCEPTION(AssertionFailureException,     Exception)
    RCF_DEFINE_EXCEPTION(FilterException,               Exception)

    class VersioningException : public RemoteException
    {
    public:
        VersioningException(int version) :
            RemoteException(RcfError_VersionMismatch),
            mVersion(version)
        {}

        ~VersioningException() throw()
        {}

        int getVersion() const
        {
            return mVersion;
        }

    private:
        int mVersion;
    };

#undef RCF_DEFINE_EXCEPTION

} // namespace RCF

// TODO: this should be in RcfServer.cpp, I think
#include <memory>
#include <boost/type_traits.hpp>
RCF_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION( RCF::RemoteException )
RCF_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION( std::auto_ptr<RCF::RemoteException> )

#endif // ! INCLUDE_RCF_EXCEPTION_HPP

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Australia Australia
Software developer, from Sweden and now living in Canberra, Australia, working on distributed C++ applications. When he is not programming, Jarl enjoys skiing and playing table tennis. He derives immense satisfaction from referring to himself in third person.

Comments and Discussions