RType
ServerSocket.cpp
Go to the documentation of this file.
1 /*
2 ** EPITECH PROJECT, 2023
3 ** R-type
4 ** File description:
5 ** R-type
6 */
7 
8 #include "ServerSocket.hpp"
9 #include <arpa/inet.h>
10 #include <iostream>
11 #include <stdexcept>
12 #include <unistd.h>
13 
14 /*
15  * @brief Construct a new Server Socket:: Server Socket object
16  */
18 {
19  std::cout << "ServerSocket constructor" << std::endl;
20 
21 #ifdef _WIN32
22  WSADATA wsaData;
23  if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
24  std::cout << "WSAStartup failed: " << WSAGetLastError() << std::endl;
25  throw std::runtime_error("Failed to initialize Winsock");
26  }
27  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
28  if (sockfd == INVALID_SOCKET) {
29  std::cout << "Error at socket(): " << WSAGetLastError() << std::endl;
30  WSACleanup();
31  throw std::runtime_error("Failed to create socket");
32  }
33 #elif defined(__unix__) || defined(__unix__) || defined(__APPLE__) || defined(__MACH__)
34  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
35  std::cout << "coucou " << std::endl;
36  if (sockfd < 0) {
37  std::cout << "Error sockfd < 0 sockfd : " << sockfd << std::endl;
38  throw std::runtime_error("Failed to create socket");
39  }
40 #endif
41  timeout = std::make_unique<struct timeval>();
42  timeout->tv_sec = 0;
43  timeout->tv_usec = 1;
44  std::cout << "Socket created successfully (fd: " << sockfd << ")" << std::endl;
45 }
46 
47 /*
48  * @brief Destroy the Server Socket:: Server Socket object
49  */
51 {
52 #ifdef _WIN32
53  closesocket(sockfd);
54 #elif defined(__unix__) || defined(__unix__) || defined(__APPLE__) || defined(__MACH__)
55  close(sockfd);
56 #endif
57 }
58 
59 /*
60  * @brief Initialize the server socket with the given port
61  * @param port The port to listen on
62  */
63 void ServerSocket::init_server(int port)
64 {
65  memset(&serv_addr, 0, sizeof(serv_addr));
66  serv_addr.sin_family = AF_INET;
67  serv_addr.sin_port = htons(port);
68  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
69  if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
70  throw std::runtime_error("Failed to bind socket");
71  }
72 }
73 
74 /*
75  * @brief Send a packet to the given client
76  * @param packet The packet to send
77  * @param client The client to send the packet to
78  */
79 void ServerSocket::send(Packet *packet, struct sockaddr_in client)
80 {
81  splitAndSend(packet, client);
82 }
83 
84 /*
85  * @brief Send a packet to the given client
86  * @param packet The packet to send
87  * @param client The client to send the packet to
88  */
89 void ServerSocket::sendPacket(SplitPacket *packet, struct sockaddr_in dest)
90 {
91  char *buffer = static_cast<char *>(malloc(sizeof(SplitPacket)));
92  memset(buffer, 0, sizeof(SplitPacket));
93  memcpy(buffer, packet, sizeof(SplitPacket));
94  if (sendto(sockfd, reinterpret_cast<const char *>(buffer), sizeof(SplitPacket), 0, (struct sockaddr *)&dest,
95  sizeof(dest)) < 0) {
96  throw std::runtime_error("Failed to send packet");
97  }
98  free(buffer);
99 }
100 
101 /*
102  * @brief Add a client to the clients list
103  * @param client The client to add
104  */
105 void ServerSocket::addClient(struct sockaddr_in client)
106 {
107  int id = 1;
108  for (auto &[i, cli, splitPackets, lastReceived] : clients) {
109  if (i == id) {
110  id++;
111  } else {
112  break;
113  }
114  }
115  clients.emplace_back(id, client, std::vector<std::tuple<std::shared_ptr<SplitPacket>, timeval>>(), timeval());
116 }
117 
118 /*
119  * @brief Get the client id from the given client
120  * @param client The client to get the id from
121  * @return The client id
122  */
123 int ServerSocket::getClientId(struct sockaddr_in client)
124 {
125  if (clients.empty()) {
126  return -1;
127  }
128  for (auto &[id, cli, splitPackets, lastReceived] : clients) {
129  if (cli.sin_addr.s_addr == client.sin_addr.s_addr && cli.sin_port == client.sin_port) {
130  return id;
131  }
132  }
133  return -1;
134 }
135 
136 /*
137  * @brief Receive a packet from a client
138  * @return The received packet and the client id
139  */
141 {
143  return manageClientsBuffer();
144 }
145 
146 /*std::tuple<std::unique_ptr<Packet>, int> ServerSocket::receive() {
147  packet_last.code = UNDEFINED;
148 
149 
150  struct sockaddr_in cli_addr_code{};
151  socklen_t len_code = sizeof(cli_addr_code);
152  if (select(sockfd + 1, &_readfds, nullptr, nullptr, timeout.get()) < 0) {
153  throw std::runtime_error("Failed to read from socket");
154  } else if (FD_ISSET(sockfd, &_readfds)) {
155  if (recvfrom(sockfd, reinterpret_cast<char *>(&packet_last.code), sizeof(int), 0, (struct
156 sockaddr*)&cli_addr_code, &len_code) < 0) { throw std::runtime_error("Failed to read from socket");
157  }
158  if (packet_last.code == UNDEFINED) {
159  throw std::runtime_error("Failed to read from socket");
160  }
161  } else {
162  return std::tuple<std::unique_ptr<Packet>, int>(nullptr, 0);
163  }
164 
165  std::cout << "packet.code: " << packet_last.code << std::endl;
166  struct sockaddr_in cli_addr_size{};
167  socklen_t len_size = sizeof(cli_addr_size);
168  if (select(sockfd + 1, &_readfds, nullptr, nullptr, timeout.get()) < 0) {
169  throw std::runtime_error("Failed to read from socket");
170  } else if (FD_ISSET(sockfd, &_readfds)) {
171  if (recvfrom(sockfd, reinterpret_cast<char *>(&packet_last.data_size), sizeof(int), 0, (struct
172 sockaddr*)&cli_addr_size, &len_size) < 0) { throw std::runtime_error("Failed to read from socket");
173  }
174  if (cli_addr_size.sin_addr.s_addr != cli_addr_code.sin_addr.s_addr || cli_addr_size.sin_port !=
175 cli_addr_code.sin_port) { throw std::runtime_error("Failed to read from socket");
176  }
177  } else {
178  return std::tuple<std::unique_ptr<Packet>, int>(nullptr, 0);
179  }
180  std::cout << "packet.data_size: " << packet_last.data_size << std::endl;
181 
182 
183  packet_last.data = malloc(packet_last.data_size + 1);
184  memset(packet_last.data, 0, packet_last.data_size + 1);
185  struct sockaddr_in cli_addr_data{};
186  socklen_t len_data = sizeof(cli_addr_data);
187  char *buffer = static_cast<char *>(malloc(packet_last.data_size + 1));
188  memset(buffer, 0, packet_last.data_size + 1);
189  if (select(sockfd + 1, &_readfds, nullptr, nullptr, timeout.get()) < 0) {
190  throw std::runtime_error("Failed to read from socket");
191  } else if (FD_ISSET(sockfd, &_readfds)) {
192  if (recvfrom(sockfd, buffer, packet_last.data_size, 0, (struct sockaddr*)&cli_addr_data, &len_data) < 0) {
193  throw std::runtime_error("Failed to read from socket");
194  }
195  } else {
196  free(buffer);
197  free(packet_last.data);
198  return std::tuple<std::unique_ptr<Packet>, int>(nullptr, 0);
199  }
200  memcpy(packet_last.data, buffer, packet_last.data_size);
201 
202  std::string message = reinterpret_cast<char *>(packet_last.data);
203  std::cout << "message: " << message << std::endl;
204 
205  int id = getClientId(cli_addr_data);
206  if (id == -1) {
207  addClient(cli_addr_data);
208  id = getClientId(cli_addr_data);
209  }
210 
211 
212  lastClientAddress = cli_addr_data;
213  std::unique_ptr<Packet> cli_addr_packet = std::make_unique<Packet>();
214  if (message == "connection") {
215  cli_addr_packet->code = MESSAGE;
216  cli_addr_packet->data_size = 19;
217  cli_addr_packet->data = malloc(19);
218  memcpy(cli_addr_packet->data, "connection accepted", 19);
219  } else {
220  cli_addr_packet->code = MESSAGE;
221  cli_addr_packet->data_size = 8;
222  cli_addr_packet->data = malloc(8);
223  memcpy(cli_addr_packet->data, "received", 8);
224  }
225  send(cli_addr_packet.get(), cli_addr_data);
226  return std::make_tuple(std::move(std::make_unique<Packet>(packet_last)), id);
227 }*/
228 
229 /*
230  * @brief Initialize the fd_set
231  */
233 {
234  FD_ZERO(&_readfds);
235  FD_SET(sockfd, &_readfds);
236 }
237 
238 /*
239  * @brief Run the server
240  */
242 {
243  while (true) {
245  receive();
246  if (lastMessage == "ping") {
247  std::unique_ptr<Packet> packet = std::make_unique<Packet>();
248  packet->code = MESSAGE;
249  packet->data_size = 4;
250  packet->data = malloc(4);
251  memcpy(packet->data, "pong", 4);
252  send(packet.get(), lastClientAddress);
253  }
254  if (lastMessage == "exit")
255  break;
256  }
257 }
258 
259 /*
260  * @brief Get the clients list
261  * @return The clients list
262  */
263 std::vector<
266 {
267  return clients;
268 }
269 
270 /*
271  * @brief Get the client address from the given id
272  * @param id The client id
273  * @return The client address
274  */
275 struct sockaddr_in ServerSocket::getClientAddress(int id)
276 {
277  for (auto &[i, cli, splitPackets, lastReceived] : clients) {
278  if (i == id) {
279  return cli;
280  }
281  }
282  throw std::runtime_error("Client not found");
283 }
284 
285 /*
286  * @brief Broadcast a packet to all clients
287  * @param packet The packet to broadcast
288  */
289 void ServerSocket::broadcast(Packet *packet)
290 {
291  for (auto &[id, cli, splitPackets, lastReceived] : clients) {
292  send(packet, cli);
293  }
294 }
295 
296 /*
297  * @brief Broadcast a packet to all clients except the given id
298  * @param packet The packet to broadcast
299  * @param id The id to exclude
300  */
301 void ServerSocket::splitAndSend(Packet *packet, struct sockaddr_in dest)
302 {
303  std::unique_ptr<SplitPacket> splitPacket = std::make_unique<SplitPacket>();
304  splitPacket->code = packet->code;
305  int i;
306 
307  if (packet->data_size < 1024) {
308  splitPacket->data[0] = '\0';
309  splitPacket->packet_id = 0;
310  splitPacket->max_packet_id = 0;
311  memset(splitPacket->data, 0, 1024);
312  memcpy(splitPacket->data, packet->data, packet->data_size);
313  sendPacket(splitPacket.get(), dest);
314  } else {
315  splitPacket->max_packet_id = packet->data_size / 1024 + 1;
316  for (i = 0; i < packet->data_size / 1024; i++) {
317  splitPacket->packet_id = i;
318  memset(splitPacket->data, 0, 1024);
319  memcpy(splitPacket->data, (char *)packet->data + i * 1024, 1024);
320  sendPacket(splitPacket.get(), dest);
321  }
322  int rest = packet->data_size % 1024;
323  if (rest > 0) {
324  splitPacket->packet_id = i + 1;
325  memset(splitPacket->data, 0, 1024);
326  memcpy(splitPacket->data, (char *)packet->data + i * 1024 + 1, rest);
327  sendPacket(splitPacket.get(), dest);
328  }
329  }
330 }
331 
332 /*
333  * @brief Receive a packet from a client and add it to the buffer
334  */
336 {
337  struct sockaddr_in cli_addr {
338  };
339 
340  std::shared_ptr<SplitPacket> packet = std::make_shared<SplitPacket>();
341  timeval recvTime{};
342  socklen_t len = sizeof(cli_addr);
343  char *buffer = static_cast<char *>(malloc(sizeof(SplitPacket)));
344  memset(buffer, 0, sizeof(SplitPacket));
345  if (select(sockfd + 1, &_readfds, nullptr, nullptr, timeout.get()) < 0) {
346  free(buffer);
347  throw std::runtime_error("Failed to read from socket");
348  } else if (FD_ISSET(sockfd, &_readfds)) {
349  if (recvfrom(sockfd, buffer, sizeof(SplitPacket), 0, (struct sockaddr *)&cli_addr, &len) < 0) {
350  throw std::runtime_error("Failed to read from socket");
351  }
352  } else {
353  free(buffer);
354  return;
355  }
356 
357  memcpy(packet.get(), buffer, sizeof(SplitPacket));
358 
359  int id = getClientId(cli_addr);
360  if (id == -1) {
361  addClient(cli_addr);
362  id = getClientId(cli_addr);
364  }
365  for (auto &[i, cli, splitPackets, lastReceived] : clients) {
366  if (i == id) {
367  gettimeofday(&recvTime, nullptr);
368  gettimeofday(&lastReceived, nullptr);
369  splitPackets.emplace_back(packet, recvTime);
370  }
371  }
372  free(buffer);
373 }
374 
375 /*
376  * @brief Manage the clients buffer
377  * @return The received packet and the client id
378  */
380 {
381  std::unique_ptr<Packet> packet = std::make_unique<Packet>();
382  int counter = 0;
383  long long int size = 0;
384  std::unique_ptr<struct timeval> now = std::make_unique<struct timeval>();
385  std::unique_ptr<struct timeval> diff = std::make_unique<struct timeval>();
386 
387  for (auto &[id, cli, splitPackets, lastReceived] : getClients()) {
388  auto it = splitPackets.begin();
389  while (it != splitPackets.end()) {
390  auto &[splitPacket, recvTime] = *it;
391  if (splitPacket->packet_id == 0 && splitPacket->max_packet_id == 0) {
392  packet->code = splitPacket->code;
393  packet->data_size = splitPacket->max_packet_id * 1024;
394  if (packet->data_size == 0) {
395  packet->data_size = 1024;
396  }
397  packet->data = malloc(packet->data_size);
398  memcpy(packet->data, splitPacket->data, packet->data_size);
399  it = splitPackets.erase(it);
400  return std::make_tuple(std::move(packet), id);
401  } else {
402  if (splitPacket->packet_id == counter) {
403  counter++;
404  size += strlen(splitPacket->data);
405  if (splitPacket->packet_id == splitPacket->max_packet_id) {
406  packet->code = splitPacket->code;
407  packet->data_size = size;
408  packet->data = malloc(packet->data_size + 1);
409  memset(packet->data, 0, packet->data_size + 1);
410  int counterAssign = 0;
411  auto itAssign = splitPackets.begin();
412  while (itAssign != splitPackets.end()) {
413  auto &[splitPacketAssign, recvTimeAssign] = *itAssign;
414  memcpy((char *)packet->data + counterAssign * 1024, splitPacketAssign->data,
415  strlen(splitPacketAssign->data));
416  counterAssign++;
417  itAssign = splitPackets.erase(itAssign);
418  }
419  return std::make_tuple(std::move(packet), id);
420  }
421  } else {
422  counter = 0;
423  size = 0;
424  }
425  }
426  ++it;
427  }
428  }
429 
430  free(packet->data);
431  for (auto &[idtimeout, clitimeout, splitPacketstimeout, lastReceivedtimeout] : getClients()) {
432  auto ittimeout = splitPacketstimeout.begin();
433  while (ittimeout != splitPacketstimeout.end()) {
434  auto &[splitPackettimeout, recvTimetimeout] = *ittimeout;
435  gettimeofday(now.get(), nullptr);
436  timersub(now.get(), &recvTimetimeout, diff.get());
437  if (diff->tv_sec > 1) {
438  ittimeout = splitPacketstimeout.erase(ittimeout);
439  } else {
440  ++ittimeout;
441  }
442  }
443  }
444  return std::make_tuple(nullptr, 0);
445 }
446 
447 /*
448  * @brief Check if a client has disconnected
449  * @return The disconnected client id
450  */
452 {
453  timeval now{};
454  timeval diff{};
455  int idClient = -1;
456 
457  gettimeofday(&now, nullptr);
458  for (auto &[id, cli, splitPackets, lastReceived] : getClients()) {
459  timersub(&now, &lastReceived, &diff);
460  if (diff.tv_sec > 1) {
461  std::shared_ptr<Packet> packet = std::make_shared<Packet>();
462  packet->code = EVENT;
463  packet->data_size = strlen("player left");
464  packet->data = malloc(packet->data_size);
465  memcpy(packet->data, "player left", packet->data_size);
466  broadcast(packet.get());
467  auto it = getClients().begin();
468  while (it != getClients().end()) {
469  auto &[iddel, clidel, splitPacketsdel, lastReceiveddel] = *it;
470  if (id == iddel) {
471  idClient = id;
472  it = getClients().erase(it);
473  break;
474  } else {
475  ++it;
476  }
477  }
478  }
479  }
480  return idClient;
481 }
482 
483 /*
484  * @brief Check if a new client has connected
485  * @return The new client id
486  */
488 {
489  newClientConnected = true;
490  newClientId = id;
491 }
492 
493 /*
494  * @brief Get the new client id
495  * @return The new client id
496  */
498 {
499  if (!newClientConnected) {
500  return -1;
501  }
502  newClientConnected = false;
503  return newClientId;
504 }
505 
506 /*
507  * @brief Dump the clients list
508  */
510 {
511  std::cout << "Clients dump:" << std::endl;
512  for (auto &[id, cli, splitPackets, lastReceived] : getClients()) {
513  std::cout << "id: " << id;
514  std::cout << " cli.sin_family: " << cli.sin_family;
515  std::cout << " cli.sin_port: " << cli.sin_port;
516  std::cout << " cli.sin_addr.s_addr: " << cli.sin_addr.s_addr;
517  std::cout << " splitPackets.size(): " << splitPackets.size();
518  std::cout << " lastReceived.tv_sec: " << lastReceived.tv_sec;
519  std::cout << " lastReceived.tv_usec: " << lastReceived.tv_usec << std::endl;
520  }
521 }