/**
* @file
* @author Jan Olszak (j.olszak@samsung.com)
+ * @defgroup libIpc libIpc
* @brief Handling client connections
*/
namespace ipc {
/**
- * This class wraps communication via UX sockets for client applications.
+ * @brief This class wraps communication via UX sockets for client applications.
* It uses serialization mechanism from Config.
*
- * For message format @see ipc::Processor
+ * @code
+ * // eventPoll - epoll wrapper class
+ * // address - server socket address
+ * ipc::epoll::EventPoll examplePoll;
+ * ipc::Client myClient(examplePoll, address);
+ * myClient.start(); // connect to the service
+ * // call method synchronously
+ * const auto result = mClient.callSync<api::Void, api::ZoneIds>(
+ * api::ipc::METHOD_GET_ZONE_ID_LIST,
+ * std::make_shared<api::Void>());
+ * // call method asynchronously
+ * // first: declare lambda function to call on completion
+ * auto asyncResult = [result](ipc::Result<api::Void>&& out) {
+ * if (out.isValid()) {
+ * // got successful response!
+ * }
+ * };
+ * std::string id = "example_zone_id";
+ * mClient.callAsync<api::ZoneId, api::Void>(api::ipc::METHOD_DESTROY_ZONE,
+ * std::make_shared<api::ZoneId>(api::ZoneId{id}),
+ * asyncResult);
+ * @endcode
+ *
+ * @see libConfig
+ * @see ipc::Processor
+ * @see ipc::epoll::EventPoll
+ *
+ * @ingroup libIpc
*/
class Client {
public:
/**
- * @param eventPoll event poll
- * @param serverPath path to the server's socket
+ * Constructs the Client, but doesn't start it.
+ * Once set-up, call start() to connect client to the server.
+ *
+ * @param eventPoll event poll
+ * @param serverPath path to the server's socket
*/
Client(epoll::EventPoll& eventPoll, const std::string& serverPath);
~Client();
+ /**
+ * Copying Client class is prohibited.
+ */
Client(const Client&) = delete;
+ /**
+ * Copying Client class is prohibited.
+ */
Client& operator=(const Client&) = delete;
/**
* Starts processing
+ * @note if the Client is already running, it quits immediately (no exception thrown)
*/
void start();
/**
+ * Is the communication thread running?
+ *
* @return is the communication thread running
*/
bool isStarted();
/**
* Stops processing
*
- * @param wait does it block waiting for all internals to stop
+ * @param wait should the call block while waiting for all internals to stop? By default true - do block.
*/
void stop(bool wait = true);
/**
* Set the callback called for each new connection to a peer
*
- * @param newPeerCallback the callback
+ * @param newPeerCallback the callback to call on new connection event
+ * @note if callback is already set, it will be overridden
*/
void setNewPeerCallback(const PeerCallback& newPeerCallback);
/**
* Set the callback called when connection to a peer is lost
*
- * @param removedPeerCallback the callback
+ * @param removedPeerCallback the callback to call on peer disconnected event
+ * @note if callback is already set, it will be overridden
*/
void setRemovedPeerCallback(const PeerCallback& removedPeerCallback);
* When a message with the given method id is received
* the data will be parsed and passed to this callback.
*
- * @param methodID API dependent id of the method
- * @param method method handling implementation
+ * @param methodID API dependent id of the method
+ * @param method method handling implementation
+ * @tparam SentDataType data type to send
+ * @tparam ReceivedDataType data type to receive
*/
template<typename SentDataType, typename ReceivedDataType>
void setMethodHandler(const MethodID methodID,
* When a message with the given method id is received
* the data will be parsed and passed to this callback.
*
- * @param methodID API dependent id of the method
- * @param signal signal handling implementation
- * @tparam ReceivedDataType data type to serialize
+ * @param methodID API dependent id of the method
+ * @param signal data processing callback
+ * @tparam ReceivedDataType data type to receive
*/
template<typename ReceivedDataType>
void setSignalHandler(const MethodID methodID,
const typename SignalHandler<ReceivedDataType>::type& signal);
/**
- * Removes the callback
+ * Removes the callback associated with specific method id.
*
- * @param methodID API dependent id of the method
+ * @param methodID API dependent id of the method
+ * @see setMethodHandler()
+ * @see setSignalHandler()
*/
void removeMethod(const MethodID methodID);
/**
* Synchronous method call.
*
- * @param methodID API dependent id of the method
- * @param data data to send
- * @param timeoutMS how long to wait for the return value before throw
- * @return result data
+ * @param methodID API dependent id of the method
+ * @param data data to send
+ * @param timeoutMS optional, how long to wait for the return value before throw (milliseconds, default: 5000)
+ * @tparam SentDataType data type to send
+ * @tparam ReceivedDataType data type to receive
+ * @return pointer to the call result data
*/
template<typename SentDataType, typename ReceivedDataType>
std::shared_ptr<ReceivedDataType> callSync(const MethodID methodID,
* Asynchronous method call. The return callback will be called on
* return data arrival. It will be run in the PROCESSOR thread.
*
- *
- * @param methodID API dependent id of the method
- * @param data data to send
- * @param resultCallback callback for result serialization and handling
+ * @param methodID API dependent id of the method
+ * @param data data to send
+ * @param resultCallback callback processing the return data
+ * @tparam SentDataType data type to send
+ * @tparam ReceivedDataType data type to receive
*/
template<typename SentDataType, typename ReceivedDataType>
void callAsync(const MethodID methodID,
* There is no return value from the peer
* Sends any data only if a peer registered this a signal
*
- * @param methodID API dependent id of the method
- * @param data data to sent
- * @tparam SentDataType data type to send
+ * @param methodID API dependent id of the method
+ * @param data data to send
+ * @tparam SentDataType data type to send
*/
template<typename SentDataType>
void signal(const MethodID methodID,
namespace ipc {
namespace epoll {
+/**
+ * @brief This class waits on registered file descriptor for events.
+ * It uses epoll mechanism.
+ *
+ * @see ipc::epoll::Events
+ *
+ * @ingroup Types
+ */
class EventPoll {
public:
+ /**
+ * Generic function type used as callback for epoll events.
+ *
+ * @param fd descriptor that triggered the event
+ * @param events event mask that occured
+ * @see ipc::epoll::Events
+ */
typedef std::function<void(int fd, Events events)> Callback;
+ /**
+ * Constructs the EventPoll and initializes the underlaying epoll mechanism.
+ * @throw UtilsException thrown if epoll initialization failed
+ */
EventPoll();
~EventPoll();
+ /**
+ * Returns epoll handle.
+ * @return handle or -1 if not initialized
+ */
int getPollFD() const;
+ /**
+ * Add descriptor and it's watched events.
+ *
+ * @param fd descriptor to watch
+ * @param events events to associate with the descriptor
+ * @param callback callback to call once the event occurs
+ * @throw UtilsException thrown if descriptor already registered or add fail
+ * @see ipc::epoll::Events
+ */
void addFD(const int fd, const Events events, Callback&& callback);
+
+ /**
+ * Modify watched events for descriptor.
+ * @param fd watched descriptor, already registered
+ * @param events events to associate with the descriptor
+ * @throw UtilsException if descriptor not found or epoll modify fail
+ * @see ipc::epoll::Events
+ */
void modifyFD(const int fd, const Events events);
+
+ /**
+ * Remove descriptor from the watch list.
+ * @param fd watched descriptor
+ */
void removeFD(const int fd);
/**
- * Dispatch at most one signaled FD
- * @param timeoutMs how long should wait in case of no pending events
- * (0 - return immediately, -1 - wait forever)
+ * Wait for events on descriptor on the watch list.
+ * Dispatch at most one signaled FD.
+ *
+ * @param timeoutMs how long should wait in case of no pending events
+ * (0 - return immediately, -1 - wait forever)
+ * @throw UtilsException if epoll_wait fails
* @return false on timeout
*/
bool dispatchIteration(const int timeoutMs);
namespace ipc {
namespace epoll {
-typedef unsigned int Events; ///< bitmask of EPOLL* constants
+/**
+ * @brief bitmask of EPOLL* constants
+ * @ingroup Types
+ */
+typedef unsigned int Events;
+/**
+ * Convert event mask into readable string.
+ * Values will be comma separated.
+ * @param events event type mask to convert
+ * @return string describing the mask
+ */
std::string eventsToString(Events events);
} // namespace epoll
namespace ipc {
/**
- * Base class for exceptions in IPC
+ * @brief Base class for all exceptions in libIpc.
+ * @ingroup Types
+ * @defgroup IPCException IPCException
*/
struct IPCException: public std::runtime_error {
IPCException(const std::string& message)
: std::runtime_error(message) {}
};
+/**
+ * Exception to indicate error while reading/parsing data from the socket.
+ * @ingroup IPCException
+ */
struct IPCParsingException: public IPCException {
IPCParsingException(const std::string& message = "Exception during reading/parsing data from the socket")
: IPCException(message) {}
};
+/**
+ * Exception to indicate error while writing/serializing data to the socket.
+ * @ingroup IPCException
+ */
struct IPCSerializationException: public IPCException {
IPCSerializationException(const std::string& message = "Exception during writing/serializing data to the socket")
: IPCException(message) {}
};
+/**
+ * Exception to indicate that requested peer is not available, i.e. might got disconnected.
+ * @ingroup IPCException
+ */
struct IPCPeerDisconnectedException: public IPCException {
IPCPeerDisconnectedException(const std::string& message = "No such peer. Might got disconnected.")
: IPCException(message) {}
};
+/**
+ * Exception to indicate that peer performed a forbidden action.
+ * @ingroup IPCException
+ */
struct IPCNaughtyPeerException: public IPCException {
IPCNaughtyPeerException(const std::string& message = "Peer performed a forbidden action.")
: IPCException(message) {}
};
+/**
+ * Exception to indicate error while removing peer
+ * @ingroup IPCException
+ */
struct IPCRemovedPeerException: public IPCException {
IPCRemovedPeerException(const std::string& message = "Removing peer")
: IPCException(message) {}
};
+/**
+ * Exception to indicate error while closing IPC channel
+ * @ingroup IPCException
+ */
struct IPCClosingException: public IPCException {
IPCClosingException(const std::string& message = "Closing IPC")
: IPCException(message) {}
};
+/**
+ * Exception to indicate timeout event error
+ * @ingroup IPCException
+ */
struct IPCTimeoutException: public IPCException {
IPCTimeoutException(const std::string& message)
: IPCException(message) {}
};
+/**
+ * Exception to indicate user error
+ * @ingroup IPCException
+ */
struct IPCUserException: public IPCException {
IPCUserException(const int code, const std::string& message)
: IPCException(message),
const MessageID messageID);
/**
- * Removes the callback
+ * Removes the callback associated with specific method id.
*
- * @param methodID API dependent id of the method
+ * @param methodID API dependent id of the method
+ * @see setMethodHandler()
+ * @see setSignalHandler()
*/
void removeMethod(const MethodID methodID);
/**
* Synchronous method call.
*
- * @param methodID API dependent id of the method
- * @param peerID id of the peer
- * @param data data to send
- * @param timeoutMS how long to wait for the return value before throw
- * @tparam SentDataType data type to send
+ * @param methodID API dependent id of the method
+ * @param peerID id of the peer
+ * @param data data to send
+ * @param timeoutMS optional, how long to wait for the return value before throw (milliseconds, default: 5000)
+ * @tparam SentDataType data type to send
* @tparam ReceivedDataType data type to receive
+ * @return call result data
*/
template<typename SentDataType, typename ReceivedDataType>
std::shared_ptr<ReceivedDataType> callSync(const MethodID methodID,
class Processor;
+/**
+ * @brief Class used to obtain method call result code.
+ * @ingroup Types
+ */
class MethodResult {
public:
typedef std::shared_ptr<MethodResult> Pointer;
/**
- * This class wraps communication via UX sockets.
+ * @brief This class wraps communication via UX sockets.
* It uses serialization mechanism from Config.
*
- * For message format @see ipc::Processor
+ * @code
+ * // eventPoll - epoll wrapper class
+ * // address - server socket address
+ * ipc::epoll::EventPoll examplePoll;
+ * // create callbacks for connected / disconnected events
+ * ipc::PeerCallback connectedCallback = [this](const ipc::PeerID peerID,
+ * const ipc::FileDescriptor) {
+ * // new connection came!
+ * };
+ * ipc::PeerCallback disconnectedCallback = [this](const ipc::PeerID peerID,
+ * const ipc::FileDescriptor) {
+ * // connection disconnected!
+ * };
+ * // create the service
+ * ipc::Service myService(eventPoll, "/tmp/example_service.socket",
+ * connectedCallback, disconnectedCallback));
+ * // add example method handler
+ * auto exampleMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>& data, MethodResult::Pointer methodResult) {
+ * // got example method call! Incoming data in "data" argument
+ * // respond with some data
+ * auto returnData = std::make_shared<SendData>(data->intVal);
+ * methodResult->set(returnData);
+ * };
+ * const MethodID exampleMethodID = 1234;
+ * myService.setMethodHandler<SendData, RecvData>(exampleMethodID, exampleMethodHandler);
+ * myService.start(); // start the service, clients may connect via /tmp/example_service.socket
+ * @endcode
+ *
+ * @see libConfig
+ * @see ipc::Processor
+ *
+ * @ingroup libIpc
*/
class Service {
public:
/**
- * @param eventPoll event poll
- * @param path path to the socket
+ * Constructs the Service, but doesn't start it.
+ * The object is ready to add methods.
+ * Once set-up, call start() to start the service.
+ *
+ * @param eventPoll event poll
+ * @param path path to the socket
+ * @param addPeerCallback optional on new peer connection callback
+ * @param removePeerCallback optional on peer removal callback
*/
Service(epoll::EventPoll& eventPoll,
const std::string& path,
const PeerCallback& addPeerCallback = nullptr,
const PeerCallback& removePeerCallback = nullptr);
- ~Service();
+ virtual ~Service();
+ /**
+ * Copying Service class is prohibited.
+ */
Service(const Service&) = delete;
+ /**
+ * Copying Service class is prohibited.
+ */
Service& operator=(const Service&) = delete;
/**
* Starts processing
+ * @note if the service is already running, it quits immediately (no exception thrown)
*/
void start();
/**
* Stops all working threads
*
- * @param wait does it block waiting for all internals to stop
+ * @param wait should the call block while waiting for all internals to stop? By default true - do block.
*/
void stop(bool wait = true);
/**
* Set the callback called for each new connection to a peer
*
- * @param newPeerCallback the callback
+ * @param newPeerCallback the callback to call on new connection event
+ * @note if callback is already set, it will be overridden
*/
void setNewPeerCallback(const PeerCallback& newPeerCallback);
/**
* Set the callback called when connection to a peer is lost
*
- * @param removedPeerCallback the callback
+ * @param removedPeerCallback the callback to call on peer disconnected event
+ * @note if callback is already set, it will be overridden
*/
void setRemovedPeerCallback(const PeerCallback& removedPeerCallback);
/**
- * Saves the callback connected to the method id.
- * When a message with the given method id is received
- * the data will be parsed and passed to this callback.
+ * Saves the callbacks connected to the method id.
+ * When a message with the given method id is received,
+ * the data will be passed to the serialization callback through file descriptor.
+ *
+ * Then the process callback will be called with the parsed data.
*
- * @param methodID API dependent id of the method
- * @param method method handling implementation
+ * @param methodID API dependent id of the method
+ * @param method data processing callback
+ * @tparam SentDataType data type to send
+ * @tparam ReceivedDataType data type to receive
*/
template<typename SentDataType, typename ReceivedDataType>
void setMethodHandler(const MethodID methodID,
const typename MethodHandler<SentDataType, ReceivedDataType>::type& method);
/**
- * Saves the callback connected to the method id.
- * When a message with the given method id is received
- * the data will be parsed and passed to this callback.
+ * Saves the callbacks connected to the method id.
+ * When a message with the given method id is received,
+ * the data will be passed to the serialization callback through file descriptor.
+ *
+ * Then the process callback will be called with the parsed data.
+ * There is no return data to send back.
*
- * @param methodID API dependent id of the method
- * @param handler handling implementation
- * @tparam ReceivedDataType data type to serialize
+ * Adding signal sends a registering message to all peers
+ *
+ * @param methodID API dependent id of the method
+ * @param handler data processing callback
+ * @tparam ReceivedDataType data type to receive
*/
template<typename ReceivedDataType>
void setSignalHandler(const MethodID methodID,
const typename SignalHandler<ReceivedDataType>::type& handler);
/**
- * Removes the callback
+ * Removes the callback associated with specific method id.
*
- * @param methodID API dependent id of the method
+ * @param methodID API dependent id of the method
+ * @see setMethodHandler()
+ * @see setSignalHandler()
*/
void removeMethod(const MethodID methodID);
/**
* Synchronous method call.
*
- * @param methodID API dependent id of the method
- * @param data data to send
- * @return result data
+ * @param methodID API dependent id of the method
+ * @param peerID id of the peer
+ * @param data data to send
+ * @param timeoutMS optional, how long to wait for the return value before throw (milliseconds, default: 5000)
+ * @tparam SentDataType data type to send
+ * @tparam ReceivedDataType data type to receive
+ * @return pointer to the call result data
*/
template<typename SentDataType, typename ReceivedDataType>
std::shared_ptr<ReceivedDataType> callSync(const MethodID methodID,
* Asynchronous method call. The return callback will be called on
* return data arrival. It will be run in the PROCESSOR thread.
*
- *
- * @param methodID API dependent id of the method
- * @param data data to send
- * @param resultCallback callback for result serialization and handling
+ * @param methodID API dependent id of the method
+ * @param peerID id of the peer
+ * @param data data to send
+ * @param resultCallback callback processing the return data
+ * @tparam SentDataType data type to send
+ * @tparam ReceivedDataType data type to receive
*/
template<typename SentDataType, typename ReceivedDataType>
void callAsync(const MethodID methodID,
* There is no return value from the peer
* Sends any data only if a peer registered this a signal
*
- * @param methodID API dependent id of the method
- * @param data data to sent
- * @tparam SentDataType data type to send
+ * @param methodID API dependent id of the method
+ * @param data data to send
+ * @tparam SentDataType data type to send
*/
template<typename SentDataType>
void signal(const MethodID methodID,
namespace ipc {
+/**
+ * @brief Generic types used in libIpc.
+ *
+ * @ingroup libIpc
+ * @defgroup Types libIpc tools
+ */
+
typedef int FileDescriptor;
typedef unsigned int MethodID;
typedef std::string MessageID;
typedef std::string PeerID;
-typedef std::function<void(const PeerID, const FileDescriptor)> PeerCallback;
-typedef std::function<void(int fd, std::shared_ptr<void>& data)> SerializeCallback;
-typedef std::function<std::shared_ptr<void>(int fd)> ParseCallback;
+/**
+ * Generic function type used as callback for peer events.
+ *
+ * @param peerID peer identifier that event relates to
+ * @param fd event origin
+ * @ingroup Types
+ */
+typedef std::function<void(const ipc::PeerID peerID, const ipc::FileDescriptor fd)> PeerCallback;
+
+/**
+ * Generic function type used as callback for serializing and
+ * saving serialized data to the descriptor.
+ *
+ * @param fd descriptor to save the serialized data to
+ * @param data data to serialize
+ * @ingroup Types
+ */
+typedef std::function<void(ipc::FileDescriptor fd, std::shared_ptr<void>& data)> SerializeCallback;
+
+/**
+ * Generic function type used as callback for reading and parsing data.
+ *
+ * @param fd descriptor to read the data from
+ * @ingroup Types
+ */
+typedef std::function<std::shared_ptr<void>(ipc::FileDescriptor fd)> ParseCallback;
+/**
+ * Generate an unique message id.
+ *
+ * @return new, unique MessageID
+ * @ingroup Types
+ */
MessageID getNextMessageID();
+
+/**
+ * Generate an unique peer id.
+ *
+ * @return new, unique PeerID
+ * @ingroup Types
+ */
PeerID getNextPeerID();
+/**
+ * Generic type used as a callback function for handling signals.
+ * @tparam ReceivedDataType type of received data
+ * @ingroup Types
+ */
template<typename ReceivedDataType>
struct SignalHandler {
typedef std::function<void(PeerID peerID,