Socket.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #include <sys/socket.h>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <netinet/in.h>
  5. #include <unistd.h>
  6. #include <poll.h>
  7. #include "server/network/Socket.h"
  8. Socket::Socket() : socketId(-1) {
  9. // domain - AF_INET - IPv4 Internet protocols
  10. // type - SOCK_STREAM - two-way, connection-based byte streams
  11. // protocol - 0 - use standard protocol for the given socket type
  12. socketId = socket(AF_INET, SOCK_STREAM, 0);
  13. if(socketId == -1) {
  14. std::cout << "cannot create socket: " << strerror(errno) << "\n";
  15. }
  16. }
  17. Socket::~Socket() {
  18. if(socketId == -1) {
  19. return;
  20. }
  21. if(close(socketId) == -1) {
  22. std::cout << "cannot close socket: " << strerror(errno) << "\n";
  23. }
  24. }
  25. bool Socket::hasError() const {
  26. return socketId == -1;
  27. }
  28. bool Socket::setNonLinger() {
  29. // prevents clients from blocking the port if the server exits
  30. // this is useful if server and client run on the same system
  31. struct linger sl;
  32. sl.l_onoff = 1; // nonzero to linger on close
  33. sl.l_linger = 0; // time to linger
  34. // sockfd - listenerSocket - modified socket
  35. // level - SOL_SOCKET - manipulate options at the sockets API level
  36. // optname - SO_LINGER - identifier of the option
  37. if(setsockopt(socketId, SOL_SOCKET, SO_LINGER, &sl, sizeof (struct linger)) == -1) {
  38. std::cout << "cannot set non lingering: " << strerror(errno) << "\n";
  39. return true;
  40. }
  41. return false;
  42. }
  43. bool Socket::listenOnPort(u16 port, uint queueLength) const {
  44. // specify binding data
  45. struct sockaddr_in connectSocketData;
  46. // clear padding
  47. memset(&connectSocketData, 0, sizeof (struct sockaddr_in));
  48. // IPv4 Internet protocols
  49. connectSocketData.sin_family = AF_INET;
  50. // port in network byte order
  51. connectSocketData.sin_port = htons(port);
  52. // address in network byte order, accept any incoming messages
  53. connectSocketData.sin_addr.s_addr = htons(INADDR_ANY);
  54. // bind the socket
  55. if(bind(socketId, (struct sockaddr*) &connectSocketData, sizeof (struct sockaddr_in)) == -1) {
  56. std::cout << "cannot bind socket: " << strerror(errno) << "\n";
  57. return true;
  58. }
  59. // mark the socket as handler for connection requests
  60. // backlog - queueLength - max queue length of pending connections
  61. if(listen(socketId, queueLength) == -1) {
  62. std::cout << "cannot start listening on socket: " << strerror(errno) << "\n";
  63. return true;
  64. }
  65. return false;
  66. }
  67. WaitResult Socket::waitForConnection(uint timeoutMillis) const {
  68. // wait until a connection arrives with timeout, this prevents being stuck in accept
  69. struct pollfd fds;
  70. fds.fd = socketId; // file descriptor for polling
  71. fds.events = POLLIN; // wait until data is ready to read
  72. fds.revents = 0; // return events - none
  73. // nfds_t - 1 - amount of passed in structs
  74. // timeout - timeoutMillis - milliseconds to wait until an event occurs
  75. int result = poll(&fds, 1, timeoutMillis);
  76. if(result > 0) {
  77. return WaitResult::SUCCESS;
  78. } else if(result == 0) {
  79. return WaitResult::TIMEOUT;
  80. }
  81. std::cout << "poll error: " << strerror(errno) << "\n";
  82. return WaitResult::ERROR;
  83. }
  84. int Socket::acceptConnection() const {
  85. struct sockaddr_in clientSocketData;
  86. // accepts an incoming client connection and stores the data in the given struct
  87. socklen_t addrlen = sizeof (struct sockaddr_in);
  88. int clientSocket = accept(socketId, (struct sockaddr*) &clientSocketData, &addrlen);
  89. if(clientSocket >= 0) {
  90. return clientSocket;
  91. }
  92. std::cout << "accept error: " << strerror(errno) << "\n";
  93. return -1;
  94. }