Server.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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(close(clients[i].socket) == -1)
  84. {
  85. printError("cannot close client socket");
  86. }
  87. }
  88. if(clients[i].th.joinable())
  89. {
  90. clients[i].th.join();
  91. }
  92. else
  93. {
  94. std::cout << "cannot join client connection thread " << std::endl;
  95. }
  96. }
  97. delete[] clients;
  98. }
  99. }
  100. bool Server::isRunning() const
  101. {
  102. return shouldRun;
  103. }
  104. void Server::printError(const char* message) const
  105. {
  106. std::cout << message << ": " << strerror(errno) << std::endl;
  107. }
  108. void Server::listenForClients()
  109. {
  110. while(shouldRun)
  111. {
  112. // wait until a connection arrives with timeout, this prevents being
  113. // stuck in accept
  114. struct pollfd fds;
  115. fds.fd = listenerSocket; // file descriptor for polling
  116. fds.events = POLLIN; // wait until data is ready to read
  117. fds.revents = 0; // return events - none
  118. // nfds_t - 1 - amount of passed in structs
  119. // timeout - 100 - milliseconds to wait until an event occurs
  120. // returns 0 on timeout, -1 on error, and >0 on success
  121. int pollData = poll(&fds, 1, 100);
  122. if(pollData > 0)
  123. {
  124. struct sockaddr_in clientSocketData;
  125. // accepts an incoming client connection and stores the data in the
  126. // given struct, returns a nonnegative file descriptor on success
  127. socklen_t addrlen = sizeof(struct sockaddr_in);
  128. int clientSocket = accept(listenerSocket, (struct sockaddr*) &clientSocketData, &addrlen);
  129. if(clientSocket >= 0)
  130. {
  131. //std::cout << inet_ntoa(clientSocketData.sin_addr) << ":" << (int) ntohs(clientSocketData.sin_port) << std::endl;
  132. if(addClientThreadsafe(clientSocket))
  133. {
  134. if(close(clientSocket) == -1)
  135. {
  136. printError("cannot close client socket");
  137. }
  138. }
  139. }
  140. else
  141. {
  142. printError("accept error");
  143. break;
  144. }
  145. }
  146. else if(pollData == -1)
  147. {
  148. printError("poll error");
  149. break;
  150. }
  151. }
  152. }
  153. bool Server::addClientThreadsafe(int clientSocket)
  154. {
  155. clientMutex.lock();
  156. bool b = addClient(clientSocket);
  157. clientMutex.unlock();
  158. return b;
  159. }
  160. bool Server::addClient(int clientSocket)
  161. {
  162. if(clientAmount >= maxClients)
  163. {
  164. serverListener.onFullServerClientConnect(clientSocket);
  165. return true;
  166. }
  167. else
  168. {
  169. // search for free slot
  170. uint16_t index = 0;
  171. while(index < maxClients)
  172. {
  173. if(clients[index].socket == -1)
  174. {
  175. break;
  176. }
  177. index++;
  178. }
  179. if(index >= maxClients)
  180. {
  181. std::cout << "cannot find free slot - even if there should be one" << std::endl;
  182. return true;
  183. }
  184. //ensure old thread has ended
  185. if(!clients[index].th.joinable())
  186. {
  187. std::cout << "cannot join thread of non used client connection" << std::endl;
  188. return true;
  189. }
  190. clients[index].th.join();
  191. clients[index].socket = clientSocket;
  192. clients[index].th = std::thread(&Server::listenOnClient, this, std::ref(clients[index]));
  193. clientAmount++;
  194. return false;
  195. }
  196. }
  197. void Server::listenOnClient(ConnectedClient& cc)
  198. {
  199. // poll data
  200. struct pollfd fds;
  201. fds.fd = cc.socket; // file descriptor for polling
  202. fds.events = POLLIN; // wait until data is ready to read
  203. fds.revents = 0; // return events - none
  204. serverListener.onClientConnect(cc.socket);
  205. Stream st;
  206. while(shouldRun)
  207. {
  208. // nfds_t - 1 - amount of passed in structs
  209. // timeout - 100 - milliseconds to wait until an event occurs
  210. // returns 0 on timeout, -1 on error, and >0 on success
  211. int pollData = poll(&fds, 1, 100);
  212. if(pollData > 0)
  213. {
  214. st.readSocket(cc.socket);
  215. if(st.hasData())
  216. {
  217. serverListener.onClientPackage(cc.socket, st);
  218. }
  219. else
  220. {
  221. // client closed connection
  222. break;
  223. }
  224. }
  225. else if(pollData == -1)
  226. {
  227. printError("cannot poll from client");
  228. break;
  229. }
  230. }
  231. serverListener.onClientDisconnect(cc.socket);
  232. // reset slot for another client
  233. clientMutex.lock();
  234. if(close(cc.socket) == -1)
  235. {
  236. perror("cannot close socket of client");
  237. }
  238. cc.socket = -1;
  239. clientAmount--;
  240. clientMutex.unlock();
  241. }