1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
#ifndef SOCKET_HANDLER_INCLUDED
# define SOCKET_HANDLER_INCLUDED
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <utility>
#include <memory>
#include <string>
#include <list>
typedef int socket_t;
class Poller;
/**
* An interface, with a series of callbacks that should be implemented in
* subclasses that deal with a socket. These callbacks are called on various events
* (read/write/timeout, etc) when they are notified to a poller
* (select/poll/epoll etc)
*/
class SocketHandler
{
public:
explicit SocketHandler(std::shared_ptr<Poller> poller);
virtual ~SocketHandler() {}
/**
* (re-)Initialize the socket
*/
void init_socket();
/**
* Connect to the remote server, and call on_connected() if this succeeds
*/
void connect(const std::string& address, const std::string& port);
void connect();
/**
* Reads data in our in_buf and the call parse_in_buf, for the implementor
* to handle the data received so far.
*/
void on_recv();
/**
* Write as much data from out_buf as possible, in the socket.
*/
void on_send();
/**
* Add the given data to out_buf and tell our poller that we want to be
* notified when a send event is ready.
*/
void send_data(std::string&& data);
/**
* Watch the socket for send events, if our out buffer is not empty.
*/
void send_pending_data();
/**
* Returns the socket that should be handled by the poller.
*/
socket_t get_socket() const;
/**
* Close the connection, remove us from the poller
*/
void close();
/**
* Called when the connection is successful.
*/
virtual void on_connected() = 0;
/**
* Called when the connection fails. Not when it is closed later, just at
* the connect() call.
*/
virtual void on_connection_failed(const std::string& reason) = 0;
/**
* Called when we detect a disconnection from the remote host.
*/
virtual void on_connection_close() = 0;
/**
* Handle/consume (some of) the data received so far. The data to handle
* may be in the in_buf buffer, or somewhere else, depending on what
* get_receive_buffer() returned. If some data is used from in_buf, it
* should be truncated, only the unused data should be left untouched.
*
* The size argument is the size of the last chunk of data that was added to the buffer.
*/
virtual void parse_in_buffer(const size_t size) = 0;
bool is_connected() const;
bool is_connecting() const;
protected:
/**
* Provide a buffer in which data can be directly received. This can be
* used to avoid copying data into in_buf before using it. If no buffer
* can provided, nullptr is returned (the default implementation does
* that).
*/
virtual void* get_receive_buffer(const size_t size) const;
/**
* The handled socket.
*/
socket_t socket;
/**
* Where data read from the socket is added until we can extract a full
* and meaningful “message” from it.
*
* TODO: something more efficient than a string.
*/
std::string in_buf;
/**
* Where data is added, when we want to send something to the client.
*/
std::list<std::string> out_buf;
/**
* A pointer to the poller that manages us, because we need to communicate
* with it, sometimes (for example to tell it that he now needs to watch
* write events for us). Do not ever try to delete it.
*
* And a raw pointer because we are not owning it, it is owning us
* (actually it is sharing our ownership with a Bridge).
*/
std::shared_ptr<Poller> poller;
/**
* Hostname we are connected/connecting to
*/
std::string address;
/**
* Port we are connected/connecting to
*/
std::string port;
/**
* Keep the details of the addrinfo the triggered a EINPROGRESS error when
* connect()ing to it, to reuse it directly when connect() is called
* again.
*/
struct sockaddr ai_addr;
socklen_t ai_addrlen;
bool connected;
bool connecting;
private:
SocketHandler(const SocketHandler&) = delete;
SocketHandler(SocketHandler&&) = delete;
SocketHandler& operator=(const SocketHandler&) = delete;
SocketHandler& operator=(SocketHandler&&) = delete;
};
#endif // SOCKET_HANDLER_INCLUDED
|