Server.cpp 8.9 KB

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