AgentXcpp  Revision:0.1.1
Internals Documentation
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Friends Pages
agentxcpp::connector Class Reference

This class provides connection to another agentXcpp entity via a unix domain socket. More...

#include <connector.hpp>

Collaboration diagram for agentxcpp::connector:

List of all members.

Classes

class  pdu_handler
 Interface for classes which can handle incoming PDU's. More...

Public Member Functions

 connector (boost::asio::io_service *io_service, const std::string &unix_domain_socket, unsigned timeout)
 The constructor.
boost::shared_ptr< ResponsePDUwait_for_response (uint32_t packetID)
 Wait with timeout for a reponse.
void register_handler (pdu_handler *handler)
 Register a handler object for received PDU's.
void connect ()
 Connect to the remote entity.
void disconnect ()
 Disconnect the remote entity.
bool is_connected ()
 Find out whether the object is currently connected.
void send (const PDU &pdu)
 send a PDU to the remote entity.
 ~connector ()
 Destructor.

Private Member Functions

void receive_callback (const boost::system::error_code &result)
 Callback function to receive a PDU.
 connector ()
 Hide standard constructor.

Private Attributes

unsigned timeout
 The timeout in milliseconds, used in various contexts.
boost::asio::io_service * io_service
 The mandatory io_service object.
boost::asio::local::stream_protocol::socket * socket
 The socket.
boost::asio::local::stream_protocol::endpoint endpoint
 The endpoint used for unix domain sockets.
std::map< uint32_t,
boost::shared_ptr< ResponsePDU > > 
responses
 The received, yet unprocessed ReponsePDU's.
uint8_t header_buf [20]
 Buffer to receive a PDU header.
pdu_handlerhandler
 The handler object for incoming PDU's.

Detailed Description

This class provides connection to another agentXcpp entity via a unix domain socket.

A connector object is always in one of the following states:

  1. connected
  2. disconnected

When created, a connector object starts in disconnected state. The current state can be obtained using the is_connected() method. Some operations may throw a disconnected exception if the object is in disconnected state. Further, the connection may fail at any point in time, therefore a disconnected exception may also be thrown during a network operation.

The socket needed for networking is created upon connect and destroyed upon disconnect. The reason is that closing the socket may throw a system_error exception, leaving the socket in an unknown state. Destroying it and creating a new one should be safe.

Sending works as follows:

  • The user invokes the send() method.
  • The send() method sends the PDU synchronously (but with a timeout).

Note: The send() function invokes io_service->run_one() one or several times.

Receiving PDU's
  • Upon connecting to the remote entity, an asynchronous read operation is started to receive the PDU header (fixed size). On disconnect, the asynchronous read operation is stopped again.
  • The boost::asio library writes a fixed amount of data (which is the PDU header) into the header_buf member and invokes the receive_callback() function.
  • The receive_callback() method reads the payload length from header_buf and reveives the payload synchronously (but with a timeout).
  • The receive_callback() method then constructs a PDU object and delivers it to a user-provided handler object (which implements the connector::pdu_handler interface) by calling its handle_pdu() method.
  • The handler object processes the PDU as needed. As soon as processing finishes, the receive_callback() method starts the next asynchronous read operation, so that it invoked again when the next header arrives.
Note:
As a special case, ResponsePDU's are not delivered to the registered handler object, but are handled differently. see below for details.
If no handler object is registered, the PDU is received nevertheless and is silently discarded.
The receive_callback() function, and thus the registered handler object's handle_pdu() method are executed in the io_service's run() context.
Receiving ResponsePDU's

The function wait_for_response() supports the request-response communication model. After sending a request to the remote entity (using send()), wait_for_response() is used to wait for the response. It blocks while waiting for a responsePDU from the remote entity, which is then returned to the caller. The wait_for_response() function may seem to do synchronous operations only, but this is not true. In fact, it uses an asynchronous receive mechanism, because there may be other PDU's in the queue before the given response is actually received. wait_for_response() therefore invokes io_service->run_one() one ore more times, until the response is received. This may also cause other asynchronous operations to finish. For example, the registered handler object may receive other PDU types, or another asynchronous operation on the io_service object (outside this class or even outside the agentXcpp library) may be served. Here are the steps performed to receive a ResponsePDU:

  • The wait_for_response() function puts an empty boost::shared_ptr<> into the responses map, using the PacketID of the awaited ResponsePDU as key.
  • The wait_for_response() function invokes io_service->run_one() one or several times, which triggers receive_callback() if data becomes available.
  • When the receive_callback() function is invoked, it receives a single PDU and processes it as described above.
  • If a ResponsePDU is received, the registered handler object is not informed by receive_callback(). Instead, the responses map is searched for an entry with the same PacketID as the received ResponsePDU. If found, the received ResponsePDU is stored in the map. Otherwise the ResponsePDU is silently discarded (as nobody waits for it).
  • The wait_for_response() checks its map entry after each run_one() call for a received ResponsePDU. If it finds one, the entry is erased from the map and returned to the caller.
Timeout detection

The same timeout value is used by all operations which deal with timeouts. The value is stored in the timeout member.

For timeout detection, a boost deadline timer is used together with the timeout_status member. While the timer is not in use, it's expiry time is set to "infinite" and timeout_status is set to "unused". When starting operations which need timeout detection, the deadline timer's expiry is set to the according time, and timeout_status is set to "in_progress". If the timer expires, the callback function check_deadline() is invoked, which sets the expiry back to "infinite" and timeout_status to "expired". If the operation completes before the timer expires, the expiry is set back to "infinite" and timeout_status is reset to "unused".

Note that the callback check_deadline() may be invoked errornously, e.g. in this situation:

  1. The network operation completes
  2. The timer expires in the backround and check_deadline() is scheduled for invokation at the next call to io_service::run()
  3. The network operation set the timer's expiry to "infinite" The operation thus completed without a timeout condition, but check_deadline() will nevertheless be invoked later. Therefore, it compares the expiry date of the timer with the current timestamp to determine whether the timer really expired.

The check_deadline() callback also restarts the timer on each call to keep it running.

Definition at line 160 of file connector.hpp.


Constructor & Destructor Documentation

agentxcpp::connector::connector ( )
private

Hide standard constructor.

We need an io_service object to function properly.

connector::connector ( boost::asio::io_service *  io_service,
const std::string &  unix_domain_socket,
unsigned  timeout 
)

The constructor.

This constructor initializes the connector object to be in disconnected state.

Parameters:
io_serviceThe io_service object needed for boost::asio operations. It may also be used by other parts of the program.
unix_domain_socketThe path to the unix_domain_socket.
timeoutThe timeout, in milliseconds, for sending and receiving PDU's. See the documentation of the respective methods for details.
Exceptions:
None.

Definition at line 304 of file connector.cpp.

agentxcpp::connector::~connector ( )
inline

Destructor.

Exceptions:
None.

Definition at line 455 of file connector.hpp.

References disconnect().


Member Function Documentation

void connector::connect ( )

Connect to the remote entity.

This function connects to the remote entity and starts receiving PDU's. If the object is already connected, the function does nothing.

Note:
While no handler is registered, received PDU's are silently discarded.
Exceptions:
disconnectedIf connecting fails.

Definition at line 315 of file connector.cpp.

References endpoint, header_buf, io_service, receive_callback(), and socket.

Referenced by agentxcpp::master_proxy::connect(), and agentxcpp::master_proxy::reconnect().

void connector::disconnect ( )

Disconnect the remote entity.

Stops receiving PDU's and disconnects the remote entity.

Exceptions:
None.

Definition at line 348 of file connector.cpp.

References socket.

Referenced by agentxcpp::master_proxy::connect(), agentxcpp::master_proxy::disconnect(), receive_callback(), agentxcpp::master_proxy::reconnect(), send(), wait_for_response(), and ~connector().

bool agentxcpp::connector::is_connected ( )
inline

Find out whether the object is currently connected.

Returns:
Whether the object is in state connected.
Exceptions:
None.

Definition at line 420 of file connector.hpp.

References socket.

Referenced by agentxcpp::master_proxy::connect(), agentxcpp::master_proxy::disconnect(), and agentxcpp::master_proxy::is_connected().

void connector::receive_callback ( const boost::system::error_code &  result)
private

Callback function to receive a PDU.

See the class documentation to learn about the receive mechanism.

Note:
Exceptions thrown by the user-provided handler (if any) are catched and discarded.

The synchronous read operation (to read the payload) may time out, using the class' timeout value. If the read times out, the socket is destroyed and the connector object becomes disconnected.

Parameters:
resultThe result of the asynchronous read operation (provided by boost::asio).
Exceptions:
None.

Definition at line 396 of file connector.cpp.

References disconnect(), agentxcpp::connector::pdu_handler::handle_pdu(), handler, header_buf, agentxcpp::PDU::parse_pdu(), agentxcpp::read32(), responses, and socket.

Referenced by connect().

void connector::register_handler ( pdu_handler handler)

Register a handler object for received PDU's.

Every time a PDU is received, the handler object's handle_pdu() method will be invoked with the PDU as argument. This method is executed in the context of the io_service object's run() or run_one() method. Care should be taken to not block the call, e.g. by doing networking.

After registering a handler it can be unregistered again by calling this function with a null pointer. While no handler object is registered, received PDU's are silently discarded.

Note:
Any exceptions thrown by the handler object are silently discarded.
There can be only one handler object registered at a time.
Parameters:
handlerA pointer to the handler object, or null.
Exceptions:
None.

Definition at line 390 of file connector.cpp.

References handler.

Referenced by agentxcpp::master_proxy::master_proxy().

void connector::send ( const PDU pdu)

send a PDU to the remote entity.

The PDU is sent to the remote entity. If the timeout expires during the send operation, a timeout_error is thrown and the object gets disconnected.

Note:
The run_one() of the io_service object is called at least one time by this operation.
Parameters:
pduThe PDU to send
Exceptions:
timeout_errorIf a timeout error occurs. The function uses the timeout value given during construction. The objects gets disconnected in this case. Some data might be sent already.
disconnectedIf disconnected. This is also thrown if sending fails and the object gets disconnected for that reason. Some data might be sent already.

Definition at line 559 of file connector.cpp.

References disconnect(), agentxcpp::PDU::serialize(), and socket.

Referenced by agentxcpp::master_proxy::connect(), agentxcpp::master_proxy::disconnect(), agentxcpp::master_proxy::do_registration(), agentxcpp::master_proxy::handle_pdu(), and agentxcpp::master_proxy::undo_registration().

boost::shared_ptr< ResponsePDU > connector::wait_for_response ( uint32_t  packetID)

Wait with timeout for a reponse.

This function blocks until a ResponsePDU with the given packetID is received or until the timeout expires, whichever comes first. The received ResponsePDU (if any) is returned.

This function calls run_one() repeatedly on the io_service object until the desired ResponsePDU arrives or the timeout expires. This may cause other asynchronous operations to be served, as well.

Parameters:
packetIDThe packetID to wait for.
Exceptions:
timeout_exceptionIf the timeout expired before the ResponsePDU was received. The connector object stays in connected state.
disconnectedIf disconnected. This is also thrown if the operation fails and the object gets disconnected for that reason.
Returns:
The received ResponsePDU.

Definition at line 594 of file connector.cpp.

References disconnect(), agentxcpp::timeout_timer::expired, io_service, responses, agentxcpp::timeout_timer::running, and socket.

Referenced by agentxcpp::master_proxy::connect(), agentxcpp::master_proxy::disconnect(), agentxcpp::master_proxy::do_registration(), and agentxcpp::master_proxy::undo_registration().


Member Data Documentation

boost::asio::local::stream_protocol::endpoint agentxcpp::connector::endpoint
private

The endpoint used for unix domain sockets.

Definition at line 234 of file connector.hpp.

Referenced by connect().

pdu_handler* agentxcpp::connector::handler
private

The handler object for incoming PDU's.

This handler object is informed by receive_callback() for each received PDU (except ResponsePDU's).

The pointer may be null, which means that there is no handler object registered.

Definition at line 303 of file connector.hpp.

Referenced by receive_callback(), and register_handler().

uint8_t agentxcpp::connector::header_buf[20]
private

Buffer to receive a PDU header.

See the class documentation to learn about the receive mechanism.

The PDU header is placed here before receive_callback() is called by boost::asio.

Since the AgentX-header is always 20 bytes in length, this buffer is 20 bytes in size.

Definition at line 292 of file connector.hpp.

Referenced by connect(), and receive_callback().

boost::asio::io_service* agentxcpp::connector::io_service
private

The mandatory io_service object.

This object is needed for boost::asio sockets. It is provided by the user of this class.

Definition at line 222 of file connector.hpp.

Referenced by connect(), and wait_for_response().

std::map< uint32_t, boost::shared_ptr<ResponsePDU> > agentxcpp::connector::responses
private

The received, yet unprocessed ReponsePDU's.

See the class documentation to learn about the receive mechanism.

The wait_for_response() function stores a null pointer to this map to indicate that it is waiting for a certain response.

When a response is received, the receive_callback() function stores it into the map, but only if a null pointer is found for the packetID of the received ResponsePDU. Otherwise, the received ResponsePDU is discarded.

After a ResponsePDU was received and stored into the map, the wait_for_response() function processes it and erases it from the map.

The map key is the packetID of the response which is awaited.

Definition at line 277 of file connector.hpp.

Referenced by receive_callback(), and wait_for_response().

boost::asio::local::stream_protocol::socket* agentxcpp::connector::socket
private

The socket.

The null pointer while disconnected.

Definition at line 229 of file connector.hpp.

Referenced by connect(), disconnect(), is_connected(), receive_callback(), send(), and wait_for_response().

unsigned agentxcpp::connector::timeout
private

The timeout in milliseconds, used in various contexts.

Definition at line 214 of file connector.hpp.


The documentation for this class was generated from the following files: