Connection.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. * Connection.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "Connection.h"
  12. #include "../registerTypes/RegisterTypes.h"
  13. #include "../mapping/CMap.h"
  14. #include "../CGameState.h"
  15. #if BOOST_VERSION >= 106600
  16. #define BOOST_ASIO_ENABLE_OLD_SERVICES
  17. #endif
  18. #include <boost/asio.hpp>
  19. using namespace boost;
  20. using namespace boost::asio::ip;
  21. #if defined(__hppa__) || \
  22. defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
  23. (defined(__MIPS__) && defined(__MISPEB__)) || \
  24. defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \
  25. defined(__sparc__)
  26. #define BIG_ENDIAN
  27. #else
  28. #define LIL_ENDIAN
  29. #endif
  30. void CConnection::init()
  31. {
  32. boost::asio::ip::tcp::no_delay option(true);
  33. socket->set_option(option);
  34. enableSmartPointerSerialization();
  35. disableStackSendingByID();
  36. registerTypes(iser);
  37. registerTypes(oser);
  38. #ifdef LIL_ENDIAN
  39. myEndianess = true;
  40. #else
  41. myEndianess = false;
  42. #endif
  43. connected = true;
  44. std::string pom;
  45. //we got connection
  46. oser & std::string("Aiya!\n") & name & myEndianess; //identify ourselves
  47. iser & pom & pom & contactEndianess;
  48. logNetwork->info("Established connection with %s", pom);
  49. wmx = new boost::mutex();
  50. rmx = new boost::mutex();
  51. handler = nullptr;
  52. receivedStop = sendStop = false;
  53. static int cid = 1;
  54. connectionID = cid++;
  55. iser.fileVersion = SERIALIZATION_VERSION;
  56. }
  57. CConnection::CConnection(std::string host, ui16 port, std::string Name)
  58. :iser(this), oser(this), io_service(new asio::io_service), name(Name)
  59. {
  60. int i;
  61. boost::system::error_code error = asio::error::host_not_found;
  62. socket = new tcp::socket(*io_service);
  63. tcp::resolver resolver(*io_service);
  64. tcp::resolver::iterator end, pom, endpoint_iterator = resolver.resolve(tcp::resolver::query(host, std::to_string(port)),error);
  65. if(error)
  66. {
  67. logNetwork->error("Problem with resolving: \n%s", error.message());
  68. goto connerror1;
  69. }
  70. pom = endpoint_iterator;
  71. if(pom != end)
  72. logNetwork->info("Found endpoints:");
  73. else
  74. {
  75. logNetwork->error("Critical problem: No endpoints found!");
  76. goto connerror1;
  77. }
  78. i=0;
  79. while(pom != end)
  80. {
  81. logNetwork->info("\t%d:%s", i, (boost::asio::ip::tcp::endpoint&)*pom);
  82. pom++;
  83. }
  84. i=0;
  85. while(endpoint_iterator != end)
  86. {
  87. logNetwork->info("Trying connection to %s(%d)", (boost::asio::ip::tcp::endpoint&)*endpoint_iterator, i++);
  88. socket->connect(*endpoint_iterator, error);
  89. if(!error)
  90. {
  91. init();
  92. return;
  93. }
  94. else
  95. {
  96. logNetwork->error("Problem with connecting: %s", error.message());
  97. }
  98. endpoint_iterator++;
  99. }
  100. //we shouldn't be here - error handling
  101. connerror1:
  102. logNetwork->error("Something went wrong... checking for error info");
  103. if(error)
  104. logNetwork->error(error.message());
  105. else
  106. logNetwork->error("No error info. ");
  107. delete io_service;
  108. //delete socket;
  109. throw std::runtime_error("Can't establish connection :(");
  110. }
  111. CConnection::CConnection(TSocket * Socket, std::string Name )
  112. :iser(this), oser(this), socket(Socket),io_service(&Socket->get_io_service()), name(Name)//, send(this), rec(this)
  113. {
  114. init();
  115. }
  116. CConnection::CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_service, std::string Name)
  117. : iser(this), oser(this), name(Name)//, send(this), rec(this)
  118. {
  119. boost::system::error_code error = asio::error::host_not_found;
  120. socket = new tcp::socket(*io_service);
  121. acceptor->accept(*socket,error);
  122. if (error)
  123. {
  124. logNetwork->error("Error on accepting: %s", error.message());
  125. delete socket;
  126. throw std::runtime_error("Can't establish connection :(");
  127. }
  128. init();
  129. }
  130. int CConnection::write(const void * data, unsigned size)
  131. {
  132. try
  133. {
  134. int ret;
  135. ret = asio::write(*socket,asio::const_buffers_1(asio::const_buffer(data,size)));
  136. return ret;
  137. }
  138. catch(...)
  139. {
  140. //connection has been lost
  141. connected = false;
  142. throw;
  143. }
  144. }
  145. int CConnection::read(void * data, unsigned size)
  146. {
  147. try
  148. {
  149. int ret = asio::read(*socket,asio::mutable_buffers_1(asio::mutable_buffer(data,size)));
  150. return ret;
  151. }
  152. catch(...)
  153. {
  154. //connection has been lost
  155. connected = false;
  156. throw;
  157. }
  158. }
  159. CConnection::~CConnection()
  160. {
  161. if(handler)
  162. handler->join();
  163. delete handler;
  164. close();
  165. delete io_service;
  166. delete wmx;
  167. delete rmx;
  168. }
  169. template<class T>
  170. CConnection & CConnection::operator&(const T &t) {
  171. // throw std::exception();
  172. //XXX this is temporaly ? solution to fix gcc (4.3.3, other?) compilation
  173. // problem for more details contact [email protected] or [email protected]
  174. // do not remove this exception it shoudnt be called
  175. return *this;
  176. }
  177. void CConnection::close()
  178. {
  179. if(socket)
  180. {
  181. socket->close();
  182. vstd::clear_pointer(socket);
  183. }
  184. }
  185. bool CConnection::isOpen() const
  186. {
  187. return socket && connected;
  188. }
  189. bool CConnection::isHost() const
  190. {
  191. return connectionID == 1;
  192. }
  193. void CConnection::reportState(vstd::CLoggerBase * out)
  194. {
  195. out->debug("CConnection");
  196. if(socket && socket->is_open())
  197. {
  198. out->debug("\tWe have an open and valid socket");
  199. out->debug("\t %d bytes awaiting", socket->available());
  200. }
  201. }
  202. CPack * CConnection::retrievePack()
  203. {
  204. CPack *ret = nullptr;
  205. boost::unique_lock<boost::mutex> lock(*rmx);
  206. logNetwork->trace("Listening... ");
  207. iser & ret;
  208. logNetwork->trace("\treceived server message of type %s", (ret? typeid(*ret).name() : "nullptr"));
  209. return ret;
  210. }
  211. void CConnection::sendPackToServer(const CPack &pack, PlayerColor player, ui32 requestID)
  212. {
  213. boost::unique_lock<boost::mutex> lock(*wmx);
  214. logNetwork->trace("Sending to server a pack of type %s", typeid(pack).name());
  215. oser & player & requestID & &pack; //packs has to be sent as polymorphic pointers!
  216. }
  217. void CConnection::disableStackSendingByID()
  218. {
  219. CSerializer::sendStackInstanceByIds = false;
  220. }
  221. void CConnection::enableStackSendingByID()
  222. {
  223. CSerializer::sendStackInstanceByIds = true;
  224. }
  225. void CConnection::disableSmartPointerSerialization()
  226. {
  227. iser.smartPointerSerialization = oser.smartPointerSerialization = false;
  228. }
  229. void CConnection::enableSmartPointerSerialization()
  230. {
  231. iser.smartPointerSerialization = oser.smartPointerSerialization = true;
  232. }
  233. void CConnection::prepareForSendingHeroes()
  234. {
  235. iser.loadedPointers.clear();
  236. oser.savedPointers.clear();
  237. disableSmartVectorMemberSerialization();
  238. enableSmartPointerSerialization();
  239. disableStackSendingByID();
  240. }
  241. void CConnection::enterPregameConnectionMode()
  242. {
  243. iser.loadedPointers.clear();
  244. oser.savedPointers.clear();
  245. disableSmartVectorMemberSerialization();
  246. disableSmartPointerSerialization();
  247. }
  248. void CConnection::disableSmartVectorMemberSerialization()
  249. {
  250. CSerializer::smartVectorMembersSerialization = false;
  251. }
  252. void CConnection::enableSmartVectorMemberSerializatoin()
  253. {
  254. CSerializer::smartVectorMembersSerialization = true;
  255. }
  256. std::string CConnection::toString() const
  257. {
  258. boost::format fmt("Connection with %s (ID: %d)");
  259. fmt % name % connectionID;
  260. return fmt.str();
  261. }