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 &
//#include "Packet.ih"
// Custom includes
+#include "../Utils/Exception.hh"
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
const
{
if (!is<OtherPacket>())
- throw std::bad_cast();
+ throw WrapException<std::bad_cast>(std::bad_cast());
return OtherPacket(ptr()->as<typename OtherPacket::type>());
}
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)
// 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,
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)
{
// 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);
}
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>
#include "SocketPolicy.ih"
// Custom includes
+#include "../Utils/Exception.hh"
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
(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
}
prefix_ senf::Daemon::~Daemon()
{
- if (! pidfile_.empty()) {
+ if (pidfileCreated_) {
try {
LIBC_CALL( ::unlink, (pidfile_.c_str()) );
} catch (Exception e) {
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_;
}
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();
#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;
}
prefix_ senf::Daemon::Daemon()
: argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
- detached_(false)
+ pidfileCreated_(false), detached_(false)
{}
////////////////////////////////////////
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
int stdout_;
int stderr_;
std::string pidfile_;
+ bool pidfileCreated_;
bool detached_;
};
///////////////////////////////////////////////////////////////////////////
// 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) );
}
#endif
+///////////////////////////////////////////////////////////////////////////
+// senf::Exception
+
+prefix_ senf::Exception::~Exception()
+ throw()
+{}
+
+prefix_ char const * senf::Exception::what()
+ const throw()
+{
+ return message().c_str();
+}
+
///////////////////////////////////////////////////////////////////////////
// senf::SystemException
///////////////////////////////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
#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)
///////////////////////////////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_
/** \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 {
// Some code which might raise an arbitrary senf exception
}
- catch (senf::Exception & e) {
+ catch (senf::ExceptionMixin & e) {
e << "\handling user " << user;
throw;
}
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
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
#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 {