1 /* 2 * Copyright (C) 2011-2016 OpenDungeons Team 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "ODSocketServer.h" 19 #include "network/ODPacket.h" 20 #include "game/Player.h" 21 22 #include "utils/Helper.h" 23 #include "utils/LogManager.h" 24 25 #include <SFML/System.hpp> 26 ODSocketServer()27ODSocketServer::ODSocketServer(): 28 mThread(nullptr), 29 mIsConnected(false) 30 { 31 } 32 ~ODSocketServer()33ODSocketServer::~ODSocketServer() 34 { 35 if(mIsConnected) 36 stopServer(); 37 } 38 createServer(int listeningPort)39bool ODSocketServer::createServer(int listeningPort) 40 { 41 mIsConnected = false; 42 43 // As we use selector, there is no need to set the socket as not-blocking 44 sf::Socket::Status status = mSockListener.listen(listeningPort); 45 if (status != sf::Socket::Done) 46 { 47 OD_LOG_ERR("Could not listen to server port status=" 48 + Helper::toString(status)); 49 return false; 50 } 51 52 mSockSelector.add(mSockListener); 53 mIsConnected = true; 54 OD_LOG_INF("Server connected and listening"); 55 mThread = new sf::Thread(&ODSocketServer::serverThread, this); 56 mThread->launch(); 57 58 return true; 59 } 60 isConnected()61bool ODSocketServer::isConnected() 62 { 63 return mIsConnected; 64 } 65 doTask(int timeoutMs)66void ODSocketServer::doTask(int timeoutMs) 67 { 68 mClockMainTask.restart(); 69 while((timeoutMs == 0) || 70 (timeoutMs > mClockMainTask.getElapsedTime().asMilliseconds())) 71 { 72 bool isSockReady; 73 if(timeoutMs != 0) 74 { 75 // We adapt the timeout so that the function returns after timeoutMs 76 // even if events occurred 77 int timeoutMsAdjusted = std::max(1, timeoutMs - mClockMainTask.getElapsedTime().asMilliseconds()); 78 isSockReady = mSockSelector.wait(sf::milliseconds(timeoutMsAdjusted)); 79 } 80 else 81 { 82 isSockReady = mSockSelector.wait(sf::Time::Zero); 83 } 84 85 // Check if a client tries to connect or to communicate 86 if(!isSockReady) 87 continue; 88 89 if(mSockSelector.isReady(mSockListener)) 90 { 91 // New connection 92 ODSocketClient* newClient = notifyNewConnection(mSockListener); 93 if (newClient != nullptr) 94 { 95 // New connection 96 OD_LOG_INF("New client connected."); 97 // The server wants to keep the client 98 newClient->setSource(ODSocketClient::ODSource::network); 99 mSockSelector.add(newClient->getSockClient()); 100 mSockClients.push_back(newClient); 101 } 102 } 103 else 104 { 105 106 for(std::vector<ODSocketClient*>::iterator it = mSockClients.begin(); it != mSockClients.end();) 107 { 108 ODSocketClient* client = *it; 109 if((mSockSelector.isReady(client->getSockClient())) && 110 (!notifyClientMessage(client))) 111 { 112 // The server wants to remove the client 113 it = mSockClients.erase(it); 114 mSockSelector.remove(client->getSockClient()); 115 client->disconnect(); 116 delete client; 117 } 118 else 119 { 120 ++it; 121 } 122 } 123 } 124 } 125 } 126 stopServer()127void ODSocketServer::stopServer() 128 { 129 mIsConnected = false; 130 if(mThread != nullptr) 131 delete mThread; // Delete waits for the thread to finish 132 mThread = nullptr; 133 mSockSelector.clear(); 134 mSockListener.close(); 135 for (std::vector<ODSocketClient*>::iterator it = mSockClients.begin(); it != mSockClients.end(); ++it) 136 { 137 ODSocketClient* client = *it; 138 client->disconnect(); 139 delete client; 140 } 141 142 mSockClients.clear(); 143 } 144