Server.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. #include <iostream>
  2. #include <cstring>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <unistd.h>
  6. #include <poll.h>
  7. #include "server/network/Server.h"
  8. // the empty function ensures the thread is joinable
  9. Server::ConnectedClient::ConnectedClient() : th([]() {}), socket(-1)
  10. {
  11. }
  12. Server::Server(uint16_t port, uint16_t maxClients, const IServerListener& listener) :
  13. shouldRun(false), port(port), maxClients(maxClients), serverListener(listener),
  14. listenerSocket(-1), clientAmount(0), clients(nullptr)
  15. {
  16. // create socket for incoming connections
  17. // domain - AF_INET - IPv4 Internet protocols
  18. // type - SOCK_STREAM - two-way, connection-based byte streams
  19. // protocol - 0 - use standard protocol for the given socket type
  20. listenerSocket = socket(AF_INET, SOCK_STREAM, 0);
  21. if(listenerSocket == -1)
  22. {
  23. printError("cannot create listener socket");
  24. return;
  25. }
  26. // prevents clients from blocking the port if the server exits
  27. // this is useful if server and client run on the same system
  28. struct linger sl;
  29. sl.l_onoff = 1; // nonzero to linger on close
  30. sl.l_linger = 0; // time to linger
  31. // sockfd - listenerSocket - modified socket
  32. // level - SOL_SOCKET - manipulate options at the sockets API level
  33. // optname - SO_LINGER - identifier of the option
  34. if(setsockopt(listenerSocket, SOL_SOCKET, SO_LINGER, &sl, sizeof(struct linger)) == -1)
  35. {
  36. printError("cannot set non lingering");
  37. return;
  38. }
  39. // specify binding data
  40. struct sockaddr_in connectSocketData;
  41. // clear padding
  42. memset(&connectSocketData, 0, sizeof(struct sockaddr_in));
  43. // IPv4 Internet protocols
  44. connectSocketData.sin_family = AF_INET;
  45. // port in network byte order
  46. connectSocketData.sin_port = htons(port);
  47. // address in network byte order, accept any incoming messages
  48. connectSocketData.sin_addr.s_addr = htons(INADDR_ANY);
  49. // bind the socket
  50. if(bind(listenerSocket, (struct sockaddr*) &connectSocketData, sizeof(struct sockaddr_in)) == -1)
  51. {
  52. printError("cannot bind listener socket");
  53. return;
  54. }
  55. // mark the socket as handler for connection requests
  56. // backlog - 5 - max queue length of pending connections
  57. if(listen(listenerSocket, 5) == -1)
  58. {
  59. printError("cannot start listening on socket");
  60. return;
  61. }
  62. shouldRun = true;
  63. listenerThread = std::thread(&Server::listenForClients, this);
  64. clients = new ConnectedClient[maxClients];
  65. }
  66. Server::~Server()
  67. {
  68. shouldRun = false;
  69. listenerThread.join();
  70. if(listenerSocket != -1)
  71. {
  72. if(close(listenerSocket) == -1)
  73. {
  74. printError("cannot close listener socket");
  75. }
  76. }
  77. if(clients != nullptr)
  78. {
  79. for(uint16_t i = 0; i < maxClients; i++)
  80. {
  81. if(clients[i].socket != -1)
  82. {
  83. if(shutdown(clients[i].socket, SHUT_RDWR))
  84. {
  85. printError("cannot shutdown client socket");
  86. }
  87. if(close(clients[i].socket) == -1)
  88. {
  89. printError("cannot close client socket");
  90. }
  91. }
  92. if(clients[i].th.joinable())
  93. {
  94. clients[i].th.join();
  95. }
  96. else
  97. {
  98. std::cout << "cannot join client connection thread " << std::endl;
  99. }
  100. }
  101. delete[] clients;
  102. }
  103. }
  104. bool Server::isRunning() const
  105. {
  106. return shouldRun;
  107. }
  108. void Server::printError(const char* message) const
  109. {
  110. std::cout << message << ": " << strerror(errno) << std::endl;
  111. }
  112. void Server::listenForClients()
  113. {
  114. while(shouldRun)
  115. {
  116. // wait until a connection arrives with timeout, this prevents being
  117. // stuck in accept
  118. struct pollfd fds;
  119. fds.fd = listenerSocket; // file descriptor for polling
  120. fds.events = POLLIN; // wait until data is ready to read
  121. fds.revents = 0; // return events - none
  122. // nfds_t - 1 - amount of passed in structs
  123. // timeout - 100 - milliseconds to wait until an event occurs
  124. // returns 0 on timeout, -1 on error, and >0 on success
  125. int pollData = poll(&fds, 1, 100);
  126. if(pollData > 0)
  127. {
  128. struct sockaddr_in clientSocketData;
  129. // accepts an incoming client connection and stores the data in the
  130. // given struct, returns a nonnegative file descriptor on success
  131. socklen_t addrlen = sizeof(struct sockaddr_in);
  132. int clientSocket = accept(listenerSocket, (struct sockaddr*) &clientSocketData, &addrlen);
  133. if(clientSocket >= 0)
  134. {
  135. //std::cout << inet_ntoa(clientSocketData.sin_addr) << ":" << (int) ntohs(clientSocketData.sin_port) << std::endl;
  136. if(addClient(clientSocket))
  137. {
  138. if(close(clientSocket) == -1)
  139. {
  140. printError("cannot close client socket");
  141. }
  142. }
  143. }
  144. else
  145. {
  146. printError("accept error");
  147. break;
  148. }
  149. }
  150. else if(pollData == -1)
  151. {
  152. printError("poll error");
  153. break;
  154. }
  155. }
  156. }
  157. bool Server::addClient(int clientSocket)
  158. {
  159. std::lock_guard<std::mutex> lg(clientMutex);
  160. if(clientAmount >= maxClients)
  161. {
  162. serverListener.onFullServerClientConnect(clientSocket);
  163. return true;
  164. }
  165. else
  166. {
  167. // search for free slot
  168. uint16_t index = 0;
  169. while(index < maxClients)
  170. {
  171. if(clients[index].socket == -1)
  172. {
  173. break;
  174. }
  175. index++;
  176. }
  177. if(index >= maxClients)
  178. {
  179. std::cout << "cannot find free slot - even if there should be one" << std::endl;
  180. return true;
  181. }
  182. //ensure old thread has ended
  183. if(!clients[index].th.joinable())
  184. {
  185. std::cout << "cannot join thread of non used client connection" << std::endl;
  186. return true;
  187. }
  188. clients[index].th.join();
  189. clients[index].socket = clientSocket;
  190. clients[index].th = std::thread(&Server::listenOnClient, this, std::ref(clients[index]));
  191. clientAmount++;
  192. return false;
  193. }
  194. }
  195. void Server::listenOnClient(ConnectedClient& cc)
  196. {
  197. // poll data
  198. struct pollfd fds;
  199. fds.fd = cc.socket; // file descriptor for polling
  200. fds.events = POLLIN; // wait until data is ready to read
  201. fds.revents = 0; // return events - none
  202. serverListener.onClientConnect(cc.socket);
  203. Stream st;
  204. while(shouldRun)
  205. {
  206. // nfds_t - 1 - amount of passed in structs
  207. // timeout - 100 - milliseconds to wait until an event occurs
  208. // returns 0 on timeout, -1 on error, and >0 on success
  209. int pollData = poll(&fds, 1, 100);
  210. if(pollData > 0)
  211. {
  212. st.readSocket(cc.socket);
  213. if(st.hasData())
  214. {
  215. serverListener.onClientPackage(cc.socket, st);
  216. }
  217. else
  218. {
  219. // client closed connection
  220. break;
  221. }
  222. }
  223. else if(pollData == -1)
  224. {
  225. printError("cannot poll from client");
  226. break;
  227. }
  228. }
  229. serverListener.onClientDisconnect(cc.socket);
  230. // reset slot for another client
  231. if(shouldRun)
  232. {
  233. std::lock_guard<std::mutex> lg(clientMutex);
  234. if(close(cc.socket) == -1)
  235. {
  236. printError("cannot close socket of client");
  237. }
  238. cc.socket = -1;
  239. clientAmount--;
  240. }
  241. }