tcp_client.hpp 5.10 KiB
/*
* tcp_client.hpp
*
* Created on: 03.01.2021
* Author: doralitze
*/
#pragma once
#include <ev++.h>
#include <functional>
#include <list>
#include <memory>
#include <string>
#include <unistd.h>
#include "net/async_fd.hpp"
#include "net/connection_client.hpp"
#include "net/ioqueue.hpp"
namespace rmrf::net {
enum class exit_status_t : uint16_t {
NO_ERROR = 0,
TIMEOUT = 1
};
/**
* This class ressembles a TCP client.
* @class tcp_client
* @author doralitze BenBe
* @brief A raw TCP client.
*/
class tcp_client : public connection_client, std::enable_shared_from_this<tcp_client> {
public:
/**
* A callback for the destructor must match this definition.
*/
typedef std::function<void(exit_status_t)> destructor_cb_type;
private:
const destructor_cb_type destructor_cb;
const std::string peer_address;
uint16_t port;
auto_fd net_socket;
::ev::io io;
ioqueue write_queue;
bool data_write_active = false;
public:
/**
* Construct a new TCP client using an already existing socket. This might be particulary useful if you've
* got a server and accept incoming connections.
*
* @brief Connect to a TCP server
* @param destructor_cb_ The callback that should be issued when the client closes or looses it's connection
* @param socket_fd A file descriptor for an already open socket to be wrapped by this client
* @param peer_address_ The address the socket is bound to on the other end of the connection
* @param port_ The bound port
*/
tcp_client(const destructor_cb_type destructor_cb_, auto_fd&& socket_fd, std::string peer_address_, uint16_t port_);
/**
* Construct a new TCP client using an address and port pair.
* @brief Connect to a TCP server
* @param peer_address_ The address to connect to
* @param port_ The remote port to connect to described as uint16
*/
tcp_client(const std::string& peer_address_, const uint16_t port_);
/**
* Construct a new TCP client using an address and a service description.
* @brief Connect to a TCP server
* @param peer_address_ The address to connect to
* @param service_or_port The service or port to connect with.
*/
tcp_client(const std::string& peer_address_, const std::string& service_or_port);
/**
* Construct a new TCP client using an address, a service description and a socket family identifier.
* @brief Connect to a TCP server
* @param peer_address_ The address to connect to
* @param service_or_port The service or port to connect with.
* @param ip_addr_family The IP or service address family as defined in <sys/socket.h>
*/
tcp_client(const std::string& peer_address_, const std::string& service_or_port, int ip_addr_family);
/**
* This descructor will handle the resource deallocation and frees the socket. It also stops the
* event queue and will call the specified destructor_cb_ (if any).
* @brief The descructor
*/
virtual ~tcp_client();
/**
* This method sends data over the socket. Keep in mind that this method only enqueues the
* data and requests it's transmission but does not send the data directly. While this ensures
* asynchronous execution you need to check if your data has been send using the is_write_queue_empty
* method.
* @brief Send data down the socket.
* @param data The data to send
*/
virtual void write_data(const std::string& data);
/**
* Get the connected sockets address. Keep in mind that the lone existance of this address
* does not guaruntee the integrity of the connection.
* @brief Get the connected sockets address
* @return The peers address.
*/
std::string get_peer_address();
/**
* Use this method in order to retrieve the associated port. A port number of 0 encodes an invalid
* port state. This either means that the choosen protocol familiy does not support the concepts
* of ports or the socket is broken.
* @brief Get the bound port
* @return The port or 0
*/
uint16_t get_port();
/**
* Use this method in order to check if all pending write requests have been successfully transmitted.
* This method returns false if the write queue is not empty or the socket is currently transmitting data.
* Note: If the socket connection crashes with an netio exception it might be possible that this
* method returns true even if the last data send has been corrupted.
* @brief Check if all pending data has been send.
* @return true if all pending data has been send.
*/
bool is_write_queue_empty();
private:
/**
* This method implements the io queue callback. It is responsible for the actual data transactions
* @param w The io handle to use
* @param events The event flag container
*/
void cb_ev(::ev::io& w, int events);
/**
* This method pushes the front of the write_queue to the socket. It will automatically advance
* the internal buffers and discard empty ones.
* @param w The io handle to use.
*/
void push_write_queue(::ev::io& w);
};
}