nanomsgxx-design
- Nanomsgxx Design
This chapter exposes the main design decisions that were made when developping nanomsgxx.
nanomsg uses many constants to represent protocols, socket domains, options,
flags... Since C++ syntax is mostly compatible with C, standard nanomsg constants
(NN) can be simply used wherever constants are expected in the C++ API.
However nanomsgxx ports all constants within the nnxx namespace, removing the
leading NN_
. For example the NN_MSG
constant in the C API is ported by the
nnxx::MSG
symbol. This applies to almost all constants, except in a few cases
where it conflicts with some existing symbols (more on that later).
nanomsgxx functions accept string arguments in some cases, to bind or connect to a node for example. Everywhere a string is expected the functions are designed to receive any object that can be converted to a C-string (null-terminted char sequence), this includes:
const char *
type, or implicitly converted to this pointer typestd::string
type, or any other specialization of std::basic_string
const char *
This feature can be extended by providing a c_str function for new types, for example:
namespace X {
const char *c_str(const other_string_type &s) {
return s.c_string();
}
}
The nanomsgxx API provides a few object types that abstracts concepts of the C API, while trying to stay as close as possible it adds a few extra types to integrate with the C++ standard library and take advantages of the rich features of the language.
All types in the nanomsgxx API provide a move constructor and a move assignment operator, these are powerful features of C++11 and the library makes heavy use of it to provide an easy resource management model, as well as protecting the user from mis-using the library in some places.
Member functions are used of nanomsgxx objects to provide operations that are
part of the object's identity, providing the low-level pieces on which extensions
can be built.
For example the nnxx::socket
type will have the recv and send member functions
because receiving and sending messages are the core features of the this type,
but protocol extensions such as turning on or off Nagle's algorithm for TCP
connections will be provided as a non-member function because it's not an
operation that can be performed on any socket type.
The nanomsg library uses the POSIX mechanism to report errors, setting errno
to some error number and returning a nagative number from the function.
C++ exceptions are used to report these conditions and almost all exceptions
thrown by the nanomsgxx functions are sub-classes of std::system_error
, so the
original error number that was generated by the underlying nanomsg routine can
be accessed through the caught exception.
When a program receives a signal it may cause any ongoing system call to be
cancelled to execute a signal handler instead, in that case the systeam call
terminates with the EINTR error code. While nanomsg mirrors this behavior,
nanomsgxx reports these conditions with the nnxx::signal_error
exception.
This can be deactivated on a per-call basis by passing nnxx::NO_SIGNAL_ERROR
in the flags argument on any blocking call, you should then refer to the
documentation of each function to understand how to handle this case.
nanomsg's API lets the user define a timeout for any blocking operation
(typically receiving or sending messages), and reports any timeout in the
operation with a nnxx::timeout_error
exception.
This can be deactivated on a per-call basis by passing nnxx::NO_TIMEOUT_ERROR
in the flags argument on any blocking call, you should then refer to the
documentation of each function to understand how to handle this case.
When the program is about to exit it is supposed to inform the nanomsg library
by calling nn_term, making any future or pending calls to nanomsg routines
failing and setting errno to ETERM. While this is still reported with an
exception in nanomsgxx it's on case where the exception thrown isn't a sub-class
of std::system_error
. The nnxx::term_error
exception is instead a sub-class of
std::logic_error
. That allows the program to handle this condition away from
local error handling logic.
The nanomsg library uses dynamic memory allocations in some places, if these
fail for whatever reasons the functions report the error with the ENOMEM errno
code.
This is another case where nanomsgxx will report an error through an exception
that is not a subclass of std::system_error
. The C++ standard library provides
the std::bad_alloc
exception for this purpose, in order to easily integrate with
programs that are written for standard C++ nanomsgxx also reports memory
allocation failures by throwing an instance of std::bad_alloc
.
nanomsgxx(7)
nanomsgxx-messages(7)
nanomsg(7)
Achille Roussel