Socket/Protocols/INet: Allow socket address string representation to omit the address...
g0dil [Thu, 3 Apr 2008 09:18:18 +0000 (09:18 +0000)]
Utils: Add WrapException template
Utils/Daemon: BUGFIX: Only remove pidfile if we have created one ourselves

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@775 270642c3-0616-0410-b53a-bc976706d245

12 files changed:
Console/Node.cci
Packets/Packet.cti
Socket/Protocols/INet/INetAddressing.cc
Socket/SocketHandle.cti
Socket/SocketPolicy.ct
Utils/Daemon/Daemon.cc
Utils/Daemon/Daemon.hh
Utils/Exception.cc
Utils/Exception.cci
Utils/Exception.cti
Utils/Exception.hh
Utils/Exception.test.cc

index 5f824bd..c5adaf3 100644 (file)
@@ -96,14 +96,20 @@ prefix_ senf::console::DirectoryNode &
 senf::console::DirectoryNode::operator[](std::string const & name)
     const
 {
-    return dynamic_cast<DirectoryNode&>(get(name));
+    try {
+        return dynamic_cast<DirectoryNode&>(get(name));
+    }
+    SENF_WRAP_EXC(std::bad_cast)
 }
 
 prefix_ senf::console::CommandNode &
 senf::console::DirectoryNode::operator()(std::string const & name)
     const
 {
-    return dynamic_cast<CommandNode&>(get(name));
+    try {
+        return dynamic_cast<CommandNode&>(get(name));
+    }
+    SENF_WRAP_EXC(std::bad_cast)
 }
 
 prefix_ senf::console::DirectoryNode &
index b58b783..e16f88e 100644 (file)
@@ -26,6 +26,7 @@
 //#include "Packet.ih"
 
 // Custom includes
+#include "../Utils/Exception.hh"
 
 #define prefix_ inline
 ///////////////////////////////cti.p///////////////////////////////////////
@@ -61,7 +62,7 @@ prefix_ OtherPacket senf::Packet::as()
     const
 {
     if (!is<OtherPacket>())
-        throw std::bad_cast();
+        throw WrapException<std::bad_cast>(std::bad_cast());
     return OtherPacket(ptr()->as<typename OtherPacket::type>());
 }
 
index d53ad07..6bc79e5 100644 (file)
 prefix_ senf::INet4SocketAddress::INet4SocketAddress(std::string const & addr)
 {
     clear();
-    unsigned i = addr.find(':');
-    if (i == std::string::npos)
-        throw AddressSyntaxException();
+    unsigned portIx = addr.find(':');
     try {
-        port(boost::lexical_cast< ::u_int16_t >(std::string(addr,i+1)));
+        port( boost::lexical_cast< ::u_int16_t >(portIx == std::string::npos 
+                                                 ? addr : std::string(addr,portIx+1)) );
     }
     catch (boost::bad_lexical_cast const &) {
-        throw AddressSyntaxException();
+        throw AddressSyntaxException() << "invalid port number";
     }
-    address(INet4Address::from_string(std::string(addr,0,i)));
+    if (portIx != std::string::npos)
+        address( INet4Address::from_string(std::string(addr,0,portIx)) );
 }
 
 prefix_ senf::INet4SocketAddress::INet4SocketAddress(INet4Address const & addr, unsigned p)
@@ -81,8 +81,9 @@ prefix_ senf::INet6SocketAddress::INet6SocketAddress(std::string const & addr,
 
     // Format of addr: "[" address [ "%" interface ] "]" ":" port
     //             or: host ":" port
+    //             or: port
 
-    static boost::regex const addressRx ("(?:\\[([a-f0-9A-F:]+)(?:%(.+))?\\]|(.+)):([0-9]+)");
+    static boost::regex const addressRx ("(?:(?:\\[([a-f0-9A-F:]+)(?:%(.+))?\\]|(.+)):)?([0-9]+)");
     // Subexpression numbers:
     enum { NumericAddr = 1,
            ZoneId      = 2,
@@ -98,10 +99,12 @@ prefix_ senf::INet6SocketAddress::INet6SocketAddress(std::string const & addr,
 
     sockaddr_.sin6_port = htons(boost::lexical_cast<boost::uint16_t>(match[Port]));
 
-    INet6Address a (INet6Address::from_string(
-                        match[NumericAddr].matched ? match[NumericAddr] : match[Hostname],
-                        resolve));
-    std::copy(a.begin(), a.end(), &sockaddr_.sin6_addr.s6_addr[0]);
+    if (match[NumericAddr].matched || match[Hostname].matched) {
+        INet6Address a (INet6Address::from_string(
+                            match[NumericAddr].matched ? match[NumericAddr] : match[Hostname],
+                            resolve));
+        std::copy(a.begin(), a.end(), &sockaddr_.sin6_addr.s6_addr[0]);
+    }
 }
 
 prefix_ bool senf::INet6SocketAddress::operator==(INet6SocketAddress const & other)
index 456a7b1..39b3273 100644 (file)
@@ -113,7 +113,7 @@ senf::SocketHandle<SPolicy>::cast_dynamic(FileHandle handle)
 {
     // throws bad_cast if the body is not a SocketBody
     SocketBody & body (dynamic_cast<SocketBody&>(FileHandle::body(handle)));
-    // throws bad_cast if the policy is not compatible
+    // throws bad_cast if the policy is not compatible (already wrapped ...)
     SPolicy::checkBaseOf(body.protocol().policy());
     return cast_static(handle);
 }
@@ -138,7 +138,10 @@ prefix_ Target senf::dynamic_socket_cast(Source handle)
         boost::is_convertible<Target*,FileHandle*>::value &&
         ( boost::is_convertible<Source,Target>::value ||
           boost::is_convertible<Target,Source>::value ) ));
-    return Target::cast_dynamic(handle);
+    try {
+        return Target::cast_dynamic(handle);
+    }
+    SENF_WRAP_EXC(std::bad_cast)
 }
 
 template <class Target, class Source>
index de3f111..fa9ca77 100644 (file)
@@ -27,6 +27,7 @@
 #include "SocketPolicy.ih"
 
 // Custom includes
+#include "../Utils/Exception.hh"
 
 #define prefix_
 ///////////////////////////////ct.p////////////////////////////////////////
@@ -46,7 +47,10 @@ checkBaseOf(SocketPolicyBase const & other)
         (void) dynamic_cast<BOOST_PP_CAT(SomePolicy,_) const &>(                                  \
             other.BOOST_PP_CAT(the,SomePolicy)());
 
-    BOOST_PP_SEQ_FOR_EACH( SP_CheckPolicy, , SENF_SOCKET_POLICIES )
+    try {
+        BOOST_PP_SEQ_FOR_EACH( SP_CheckPolicy, , SENF_SOCKET_POLICIES )
+    }
+    SENF_WRAP_EXC(std::bad_cast)
 
 #   undef SP_CheckPolicy
 }
index 13668ee..f1ac715 100644 (file)
@@ -57,7 +57,7 @@
 
 prefix_ senf::Daemon::~Daemon()
 {
-    if (! pidfile_.empty()) {
+    if (pidfileCreated_) {
         try {
             LIBC_CALL( ::unlink, (pidfile_.c_str()) );
         } catch (Exception e) {
@@ -77,11 +77,13 @@ prefix_ bool senf::Daemon::daemon()
     return daemonize_;
 }
 
-prefix_ int senf::Daemon::argc() {
+prefix_ int senf::Daemon::argc() 
+{
     return argc_;
 }
 
-prefix_ char const ** senf::Daemon::argv() {
+prefix_ char const ** senf::Daemon::argv() 
+{
     return argv_;
 }
 
@@ -194,10 +196,14 @@ prefix_ int senf::Daemon::start(int argc, char const ** argv)
             openLog();
             fork();
         }
-        if (! pidfile_.empty() && ! pidfileCreate()) {
-            std::cerr << "\n*** PID file '" << pidfile_ << "' creation failed. Daemon running ?" 
-                      << std::endl;
-            return 1;
+        if (! pidfile_.empty()) {
+            if (pidfileCreate())
+                pidfileCreated_ = true;
+            else {
+                std::cerr << "PID file '" << pidfile_ 
+                          << "' creation failed. Daemon running ?" << std::endl;
+                return 1;
+            }
         }
 
         main();
@@ -209,11 +215,11 @@ prefix_ int senf::Daemon::start(int argc, char const ** argv)
 #ifndef SENF_DEBUG
 
     catch (std::exception & e) {
-        std::cerr << "\n*** Fatal exception: " << e.what() << std::endl;
+        std::cerr << "\n*** Fatal exception: " << e.what() << "\n" << std::endl;
         return 1;
     }
     catch (...) {
-        std::cerr << "\n*** Fatal exception: (unknown)" << std::endl;
+        std::cerr << "\n*** Fatal exception: (unknown)" << "\n" << std::endl;
         return 1;
     }
 
@@ -227,7 +233,7 @@ prefix_ int senf::Daemon::start(int argc, char const ** argv)
 
 prefix_ senf::Daemon::Daemon()
     : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
-      detached_(false)
+      pidfileCreated_(false), detached_(false)
 {}
 
 ////////////////////////////////////////
@@ -369,8 +375,10 @@ prefix_ bool senf::Daemon::pidfileCreate()
             if ( ! (pidf >> old_pid)
                  || old_pid < 0 
                  || ::kill(old_pid, 0) >= 0 
-                 || errno == EPERM )
+                 || errno == EPERM ) {
+                LIBC_CALL( ::unlink, (tempname.c_str()) );
                 return false;
+            }
         }
 
         // If we reach this point, the pid file exists but the process mentioned within the
index 30d6b24..2a0ee69 100644 (file)
@@ -209,6 +209,7 @@ namespace senf {
         int stdout_;
         int stderr_;
         std::string pidfile_;
+        bool pidfileCreated_;
 
         bool detached_;
     };
index c86dade..4c74f6c 100644 (file)
 ///////////////////////////////////////////////////////////////////////////
 // senf::Exception
 
-prefix_ senf::Exception::~Exception()
-    throw()
-{}
-
-prefix_ char const * senf::Exception::what()
-    const throw()
-{
-    return message_.c_str();
-}
-
 #ifdef SENF_DEBUG
-prefix_ void senf::Exception::addBacktrace()
+prefix_ void senf::ExceptionMixin::addBacktrace()
 {
     void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
     unsigned nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
@@ -80,6 +70,19 @@ prefix_ void senf::Exception::addBacktrace()
 }
 #endif
 
+/////////////////////////////////////////////////////////////////////////// 
+// senf::Exception
+
+prefix_ senf::Exception::~Exception()
+    throw()
+{}
+
+prefix_ char const * senf::Exception::what()
+    const throw()
+{
+    return message().c_str();
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::SystemException
 
index 1b611a2..189c2f1 100644 (file)
@@ -28,9 +28,9 @@
 ///////////////////////////////cci.p///////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////
-// senf::Exception
+// senf::ExceptionMixin
 
-prefix_ senf::Exception::Exception(std::string const & description)
+prefix_ senf::ExceptionMixin::ExceptionMixin(std::string const & description)
     : message_(description)
 {
 #ifdef SENF_DEBUG
@@ -38,18 +38,25 @@ prefix_ senf::Exception::Exception(std::string const & description)
 #endif
 }
 
-prefix_ std::string const & senf::Exception::message()
+prefix_ std::string const & senf::ExceptionMixin::message()
     const
 {
     return message_;
 }
 
-prefix_ void senf::Exception::append(std::string text)
+prefix_ void senf::ExceptionMixin::append(std::string text)
 {
     message_ += text;
 }
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::Exception
+
+prefix_ senf::Exception::Exception(std::string const & description)
+    : ExceptionMixin(description)
+{}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::SystemException
 
 prefix_ senf::SystemException::SystemException(std::string const & descr _SENF_EXC_DEBUG_ARGS_ND)
index a398908..ea12370 100644 (file)
 ///////////////////////////////cti.p///////////////////////////////////////
 
 template <class Exc, class Arg>
-prefix_ typename boost::enable_if< boost::is_convertible<Exc*,senf::Exception*>, Exc & >::type
+prefix_ typename boost::enable_if< boost::is_convertible<Exc*,senf::ExceptionMixin*>, Exc & >::type
 senf::operator<<(Exc const & exc, Arg const & arg)
 {
     const_cast<Exc &>(exc).append( boost::lexical_cast<std::string>(arg) );
     return const_cast<Exc &>(exc);
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::WrapExcecption<BaseException>
+
+template <class BaseException>
+prefix_ senf::WrapException<BaseException>::WrapException(BaseException const & base)
+    : ExceptionMixin(base.what()), BaseException(base)
+{}
+
+template <class BaseException>
+prefix_ senf::WrapException<BaseException>::~WrapException()
+    throw()
+{}
+
+template <class BaseException>
+prefix_ char const * senf::WrapException<BaseException>::what()
+    const throw()
+{
+    return message().c_str();
+}
+
 /////////////////////////////cti.e///////////////////////////////////////
 #undef prefix_
 
index fefe136..840379e 100644 (file)
@@ -42,7 +42,8 @@
 /** \defgroup exception Exception classes
 
     All exceptions in %senf are derived from senf::Exception. This class adds the possibility to
-    extend the exception description while it is processed:
+    extend the exception description while it is processed. The functionality is provided by a mixin
+    class senf::ExceptionMixin:
 
     \code
     try {
@@ -50,7 +51,7 @@
         // Some code which might raise an arbitrary senf exception
 
     }
-    catch (senf::Exception & e) {
+    catch (senf::ExceptionMixin & e) {
         e << "\handling user " << user;
         throw;
     }
@@ -64,7 +65,7 @@
     try { 
         // ...
     }
-    catch (senf::Exception & e) {
+    catch (senf::ExceptionMixin & e) {
         e << boost::format("\ncall id 0x%04x@%s") % id % address;
     }
     \endcode
     automatically include a stack backtrace. For this to work, you need to add the
     <tt>-rdynamic</tt> option to all link commands. This feature depends on <tt>gcc</tt> and
     the GNU-libc.
+
+    To apply these features (extensibility, backtrace) to a non-senf exception, the non-senf
+    exception can be wrapped and rethrown.
+    \code
+    void foo() {
+        try {
+            // ... code that might throw std::bad_cast or somelib::FooException
+        }
+        SENF_WRAP_EXC(std::bad_cast)
+        SENF_WRAP_EXC(somelib::FooException)
+    }
+    \endcode The re-thrown exception can then be caught as <tt>std::bad_cast</tt> or as
+    senf::ExceptionMixin as needed. It is safe, to wrap an exception twice (the macro will detect
+    this case).
+    \code
+    bar() {
+    try {
+        try {
+            foo();
+        }
+        catch (senf::ExceptionMixin & ex) {
+            ex << "\nadd this info";
+        }
+    }
+    catch (std::bad_cast const & ex) {
+        std::cerr << ex.what() << std::endl;
+    }
+    \endcode
+    The final error output will include
+    \li a backtrace if compiled in debug mode
+    \li the original error message from the <tt>std::bad_cast</tt> exception
+    \li the additional error message "add this info"
+
+    \todo Link against libcwd to add file-name/line-number information to the backtrace and remove
+        the dependency on -rdynamic
  */
 
 namespace senf {
 
-    /** \brief Generic exception base-class
+    /** \brief Generic extensible exception mixin
 
-        Exception is a generic exception base-class which allows the exception to be later extended
+        ExceptionMixin is a generic exception mixin which allows the exception to be later extended
         by catching and re-throwing it (See example in \ref exception).
 
         \ingroup exception
       */
-    class Exception
-        : public std::exception
+    class ExceptionMixin
     {
     public:
-        ///////////////////////////////////////////////////////////////////////////
-        ///\name Structors and default members
-        ///@{
-
-        virtual ~Exception() throw();
-
-        ///@}
-        ///////////////////////////////////////////////////////////////////////////
-
-        virtual char const * what() const throw();
         std::string const & message() const;
 
         void append(std::string text); ///< Extend exception description
                                         /**< Adds \a text to the description text. */
 
     protected:
-        Exception(std::string const & description = ""); ///< Initialize exception with string
+        explicit ExceptionMixin(std::string const & description = ""); 
+                                        ///< Initialize exception with string
                                         /**< \a description is the initial error description
                                              string. This should probably be a string constant
                                              describing the exception for most derived
@@ -128,8 +154,65 @@ namespace senf {
         std::string message_;
     };
 
+    /** \brief Extensible exception base-class
+
+        This base-class is an exception which already includes the ExceptionMixin. All SENF
+        exceptions are derived from this class. Other user-exception may be defined by deriving from
+        this class too.
+
+        \see \ref exception
+
+        \ingroup exception
+     */
+    class Exception
+        : public ExceptionMixin, public std::exception
+    {
+    public:
+        virtual ~Exception() throw();
+
+        virtual char const * what() const throw();
+
+    protected:
+        explicit Exception(std::string const & description = "");
+    };
+    
+    /** \brief Wrapper for standard non-senf exceptions
+
+        This class wraps an exception of type \a BaseException and adds functionality from
+        senf::ExceptionMixin.
+
+        \ingroup exception
+     */
+    template <class BaseException>
+    class WrapException
+        : public ExceptionMixin, public BaseException
+    {
+    public:
+        typedef BaseException Base;
+
+        WrapException(BaseException const & base);
+        virtual ~WrapException() throw();
+
+        virtual char const * what() const throw();
+    };
+
+    /** \brief Wrap a non-senf exception
+
+        This macro allows to wrap a non-senf exception adding functionality from ExceptionMixin
+        using the WrapException template. For an example, see \ref exception.
+
+        \ingroup exception
+     */
+#   define SENF_WRAP_EXC(Ex)                                                                      \
+        catch (Ex const & base) {                                                                 \
+            if (dynamic_cast<senf::ExceptionMixin const *>(&base))                                \
+                throw;                                                                            \
+            else                                                                                  \
+                throw senf::WrapException<Ex>(base);                                              \
+        }
+
     template <class Exc, class Arg>
-    typename boost::enable_if< boost::is_convertible<Exc*,Exception*>, Exc & >::type
+    typename boost::enable_if< boost::is_convertible<Exc*,ExceptionMixin*>, Exc & >::type
     operator<<(Exc const & exc, Arg const & arg); ///< Extend exception description
                                         /**< Adds \a arg converted to string to the end of the
                                              exception description string. This operator allows to
index 9a29f71..7706bcd 100644 (file)
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
+BOOST_AUTO_UNIT_TEST(wrapException)
+{
+    bool bad_cast (false);
+
+    try {
+        try {
+            try {
+                try {
+                    try {
+                        throw std::bad_cast();
+                    }
+                    SENF_WRAP_EXC(std::bad_cast)
+                }
+                SENF_WRAP_EXC(std::bad_cast)
+            }
+            catch (senf::ExceptionMixin & ex) {
+                ex << "\nspecial exception";
+                throw;
+            }
+        }
+        catch (std::exception const & ex) {
+            BOOST_CHECK( std::string(ex.what()).find("-- \n") != std::string::npos );
+            BOOST_CHECK( std::string(ex.what()).find("special exception") != std::string::npos );
+            throw;
+        }
+    }
+    catch (std::bad_cast &) {
+        bad_cast = true;
+    }
+    BOOST_CHECK( bad_cast );
+}
+
 BOOST_AUTO_UNIT_TEST(errnoException)
 {
     try {