Libftpp
A modern C++ library
client.cpp
Go to the documentation of this file.
1 #include "client.hpp"
2 
3 Client::Client() : _tmpMsg(), _fd(-1) {}
4 
5 Client::Client(const std::string& address, const size_t& port) : _tmpMsg(), _fd(-1)
6 {
7  connect(address, port);
8 }
9 
10 void Client::_networkError(std::string&& errorMsg)
11 {
12  disconnect();
13  errorMsg += strerror(errno);
14  errorMsg += " (errno: " + std::to_string(errno) + ")";
15  throw std::runtime_error(errorMsg);
16 }
17 
18 void Client::connect(const std::string& address, const size_t& port)
19 {
20  disconnect();
21 
22  _fd = ::socket(AF_INET, SOCK_STREAM, 0);
23  if (_fd < 0)
24  return _networkError("Cannot create socket");
25 
26  sockaddr_in sockaddr;
27  sockaddr.sin_family = AF_INET;
28  sockaddr.sin_port = htons(port);
29 
30  if (inet_pton(AF_INET, address.c_str(), &sockaddr.sin_addr) <= 0)
31  {
32  hostent* host = gethostbyname(address.c_str());
33  if (!host)
34  return _networkError("Cannot resolve hostname: " + address);
35 
36  memcpy(&sockaddr.sin_addr, host->h_addr, host->h_length);
37  }
38 
39  if (::connect(_fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0)
40  return _networkError("Cannot connect to socket: ");
41 }
42 
44 {
45  if (_fd > 0)
46  {
47  // shutdown(_fd, SHUT_RDWR);
48  close(_fd);
49  }
50  _fd = -1;
51 }
52 
53 void Client::defineAction(const Message::Type& messageType,
54  const std::function<void(const Message& msg)>& action)
55 {
56  _triggers[messageType].push_back(action);
57 }
58 
59 void Client::send(const Message& message)
60 {
61  auto data = message.getSerializedData();
62  ::send(_fd, data.data(), data.size(), 0);
63 }
64 
65 bool Client::_isConnected() const
66 {
67  if (_fd <= 0)
68  return false;
69 
70  int error = 0;
71  socklen_t len = sizeof(error);
72 
73  // Si la socket est fermée, getsockopt va échouer ou renvoyer une erreur
74  return (getsockopt(_fd, SOL_SOCKET, SO_ERROR, &error, &len) == 0 && error == 0);
75 }
76 
77 void Client::_receiveMessage()
78 {
79 
80  char buffRead[MAX_READ_BUFFER];
81  int bytes;
82  while ((bytes = recv(_fd, buffRead, sizeof(buffRead), MSG_DONTWAIT)) > 0)
83  {
84  _tmpMsg.appendBytes(reinterpret_cast<unsigned char*>(buffRead), bytes);
85  }
86 
87  if (bytes == 0)
88  {
89  // Connexion fermée par le serveur
90  disconnect();
91  return;
92  }
93 
94  if (bytes == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
95  {
96  // Déconnexions réseau (ne pas lever d'exception)
97  if (errno == ENOTCONN || // Transport endpoint is not connected
98  errno == ECONNRESET || // Connection reset by peer
99  errno == EPIPE || // Broken pipe
100  errno == EBADF) // Bad file descriptor
101  {
102  disconnect();
103  return;
104  }
105 
106  _networkError("Cannot receive message: ");
107  }
108 
109  while (_tmpMsg.isComplet())
110  {
111  Message::Type msgType;
112  _tmpMsg >> msgType;
113 
114  Message newMsg(msgType);
115 
116  size_t dataSize;
117  _tmpMsg >> dataSize;
118 
119  newMsg.appendBytes(_tmpMsg.getBuffer()->data().data(), dataSize);
120 
121  _tmpMsg.incr_cursor(dataSize);
122 
123  _msgs.push_back(newMsg);
124  }
125 }
126 
128 {
129  if (!_isConnected())
130  return;
131  while (_fd > 0)
132  {
133  FD_ZERO(&_readyRead);
134  FD_SET(_fd, &_readyRead);
135 
136  timeval timeout = {0, 10000}; // Pour que le select soit non bloquant
137 
138  int ready = select(_fd + 1, &_readyRead, NULL, NULL, &timeout);
139  if (ready <= 0 || !FD_ISSET(_fd, &_readyRead))
140  break;
141 
142  _receiveMessage();
143  }
144 
145  for (auto& msg : _msgs)
146  {
147  auto it = _triggers.find(msg.type());
148  if (it == _triggers.end())
149  continue;
150 
151  for (auto& funct : it->second)
152  funct(msg);
153  }
154  _msgs.clear();
155 }
void connect(const std::string &address, const size_t &port)
Definition: client.cpp:18
void send(const Message &message)
Definition: client.cpp:59
void update()
Definition: client.cpp:127
void disconnect()
Definition: client.cpp:43
void defineAction(const Message::Type &messageType, const std::function< void(const Message &msg)> &action)
Definition: client.cpp:53
Client()
Definition: client.cpp:3
const std::vector< unsigned char > data() const
Definition: data_buffer.cpp:57
Class representing a structured message for network communication.
Definition: message.hpp:47
std::vector< unsigned char > getSerializedData() const
Definition: message.cpp:26
bool isComplet()
Definition: message.cpp:10
void appendBytes(const unsigned char *data, size_t len)
Definition: message.cpp:5
void incr_cursor(size_t len) const
Definition: message.cpp:69
int Type
Definition: message.hpp:49
DataBuffer * getBuffer()
Definition: message.cpp:84
#define MAX_READ_BUFFER
Definition: client.hpp:17