| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 | 
							- /*
 
-  * Connection.cpp, part of VCMI engine
 
-  *
 
-  * Authors: listed in file AUTHORS in main folder
 
-  *
 
-  * License: GNU General Public License v2.0 or later
 
-  * Full text of license available in license.txt file, in main folder
 
-  *
 
-  */
 
- #include "StdInc.h"
 
- #include "Connection.h"
 
- #include "../registerTypes/RegisterTypes.h"
 
- #include "../mapping/CMapHeader.h"
 
- #include "../CGameState.h"
 
- #include <boost/asio.hpp>
 
- VCMI_LIB_NAMESPACE_BEGIN
 
- using namespace boost;
 
- using namespace boost::asio::ip;
 
- struct ConnectionBuffers
 
- {
 
- 	boost::asio::streambuf readBuffer;
 
- 	boost::asio::streambuf writeBuffer;
 
- };
 
- void CConnection::init()
 
- {
 
- 	enableBufferedWrite = false;
 
- 	enableBufferedRead = false;
 
- 	connectionBuffers = std::make_unique<ConnectionBuffers>();
 
- 	socket->set_option(boost::asio::ip::tcp::no_delay(true));
 
-     try
 
-     {
 
-         socket->set_option(boost::asio::socket_base::send_buffer_size(4194304));
 
-         socket->set_option(boost::asio::socket_base::receive_buffer_size(4194304));
 
-     }
 
-     catch (const boost::system::system_error & e)
 
-     {
 
-         logNetwork->error("error setting socket option: %s", e.what());
 
-     }
 
- 	enableSmartPointerSerialization();
 
- 	disableStackSendingByID();
 
- 	registerTypes(iser);
 
- 	registerTypes(oser);
 
- #ifndef VCMI_ENDIAN_BIG
 
- 	myEndianess = true;
 
- #else
 
- 	myEndianess = false;
 
- #endif
 
- 	connected = true;
 
- 	std::string pom;
 
- 	//we got connection
 
- 	oser & std::string("Aiya!\n") & name & uuid & myEndianess; //identify ourselves
 
- 	iser & pom & pom & contactUuid & contactEndianess;
 
- 	logNetwork->info("Established connection with %s. UUID: %s", pom, contactUuid);
 
- 	mutexRead = std::make_shared<boost::mutex>();
 
- 	mutexWrite = std::make_shared<boost::mutex>();
 
- 	iser.fileVersion = SERIALIZATION_VERSION;
 
- }
 
- CConnection::CConnection(const std::string & host, ui16 port, std::string Name, std::string UUID):
 
- 	io_service(std::make_shared<asio::io_service>()),
 
- 	iser(this),
 
- 	oser(this),
 
- 	name(std::move(Name)),
 
- 	uuid(std::move(UUID))
 
- {
 
- 	int i = 0;
 
- 	boost::system::error_code error = asio::error::host_not_found;
 
- 	socket = std::make_shared<tcp::socket>(*io_service);
 
- 	tcp::resolver resolver(*io_service);
 
- 	tcp::resolver::iterator end;
 
- 	tcp::resolver::iterator pom;
 
- 	tcp::resolver::iterator endpoint_iterator = resolver.resolve(tcp::resolver::query(host, std::to_string(port)), error);
 
- 	if(error)
 
- 	{
 
- 		logNetwork->error("Problem with resolving: \n%s", error.message());
 
- 		throw std::runtime_error("Can't establish connection: Problem with resolving");
 
- 	}
 
- 	pom = endpoint_iterator;
 
- 	if(pom != end)
 
- 		logNetwork->info("Found endpoints:");
 
- 	else
 
- 	{
 
- 		logNetwork->error("Critical problem: No endpoints found!");
 
- 		throw std::runtime_error("Can't establish connection: No endpoints found!");
 
- 	}
 
- 	while(pom != end)
 
- 	{
 
- 		logNetwork->info("\t%d:%s", i, (boost::asio::ip::tcp::endpoint&)*pom);
 
- 		pom++;
 
- 	}
 
- 	i=0;
 
- 	while(endpoint_iterator != end)
 
- 	{
 
- 		logNetwork->info("Trying connection to %s(%d)", (boost::asio::ip::tcp::endpoint&)*endpoint_iterator, i++);
 
- 		socket->connect(*endpoint_iterator, error);
 
- 		if(!error)
 
- 		{
 
- 			init();
 
- 			return;
 
- 		}
 
- 		else
 
- 		{
 
- 			throw std::runtime_error("Can't establish connection: Failed to connect!");
 
- 		}
 
- 		endpoint_iterator++;
 
- 	}
 
- }
 
- CConnection::CConnection(std::shared_ptr<TSocket> Socket, std::string Name, std::string UUID):
 
- 	iser(this),
 
- 	oser(this),
 
- 	socket(std::move(Socket)),
 
- 	name(std::move(Name)),
 
- 	uuid(std::move(UUID))
 
- {
 
- 	init();
 
- }
 
- CConnection::CConnection(const std::shared_ptr<TAcceptor> & acceptor,
 
- 						 const std::shared_ptr<boost::asio::io_service> & io_service,
 
- 						 std::string Name,
 
- 						 std::string UUID):
 
- 	io_service(io_service),
 
- 	iser(this),
 
- 	oser(this),
 
- 	name(std::move(Name)),
 
- 	uuid(std::move(UUID))
 
- {
 
- 	boost::system::error_code error = asio::error::host_not_found;
 
- 	socket = std::make_shared<tcp::socket>(*io_service);
 
- 	acceptor->accept(*socket,error);
 
- 	if (error)
 
- 	{
 
- 		logNetwork->error("Error on accepting: %s", error.message());
 
- 		socket.reset();
 
- 		throw std::runtime_error("Can't establish connection :(");
 
- 	}
 
- 	init();
 
- }
 
- void CConnection::flushBuffers()
 
- {
 
- 	if(!enableBufferedWrite)
 
- 		return;
 
- 	try
 
- 	{
 
- 		asio::write(*socket, connectionBuffers->writeBuffer);
 
- 	}
 
- 	catch(...)
 
- 	{
 
- 		//connection has been lost
 
- 		connected = false;
 
- 		throw;
 
- 	}
 
- 	enableBufferedWrite = false;
 
- }
 
- int CConnection::write(const void * data, unsigned size)
 
- {
 
- 	try
 
- 	{
 
- 		if(enableBufferedWrite)
 
- 		{
 
- 			std::ostream ostream(&connectionBuffers->writeBuffer);
 
- 		
 
- 			ostream.write(static_cast<const char *>(data), size);
 
- 			return size;
 
- 		}
 
- 		int ret = static_cast<int>(asio::write(*socket, asio::const_buffers_1(asio::const_buffer(data, size))));
 
- 		return ret;
 
- 	}
 
- 	catch(...)
 
- 	{
 
- 		//connection has been lost
 
- 		connected = false;
 
- 		throw;
 
- 	}
 
- }
 
- int CConnection::read(void * data, unsigned size)
 
- {
 
- 	try
 
- 	{
 
- 		if(enableBufferedRead)
 
- 		{
 
- 			auto available = connectionBuffers->readBuffer.size();
 
- 			while(available < size)
 
- 			{
 
- 				auto bytesRead = socket->read_some(connectionBuffers->readBuffer.prepare(1024));
 
- 				connectionBuffers->readBuffer.commit(bytesRead);
 
- 				available = connectionBuffers->readBuffer.size();
 
- 			}
 
- 			std::istream istream(&connectionBuffers->readBuffer);
 
- 			istream.read(static_cast<char *>(data), size);
 
- 			return size;
 
- 		}
 
- 		int ret = static_cast<int>(asio::read(*socket,asio::mutable_buffers_1(asio::mutable_buffer(data,size))));
 
- 		return ret;
 
- 	}
 
- 	catch(...)
 
- 	{
 
- 		//connection has been lost
 
- 		connected = false;
 
- 		throw;
 
- 	}
 
- }
 
- CConnection::~CConnection()
 
- {
 
- 	if(handler)
 
- 		handler->join();
 
- 	close();
 
- }
 
- template<class T>
 
- CConnection & CConnection::operator&(const T &t) {
 
- //	throw std::exception();
 
- //XXX this is temporaly ? solution to fix gcc (4.3.3, other?) compilation
 
- //    problem for more details contact [email protected] or [email protected]
 
- //    do not remove this exception it shoudnt be called
 
- 	return *this;
 
- }
 
- void CConnection::close()
 
- {
 
- 	if(socket)
 
- 	{
 
- 		socket->close();
 
- 		socket.reset();
 
- 	}
 
- }
 
- bool CConnection::isOpen() const
 
- {
 
- 	return socket && connected;
 
- }
 
- void CConnection::reportState(vstd::CLoggerBase * out)
 
- {
 
- 	out->debug("CConnection");
 
- 	if(socket && socket->is_open())
 
- 	{
 
- 		out->debug("\tWe have an open and valid socket");
 
- 		out->debug("\t %d bytes awaiting", socket->available());
 
- 	}
 
- }
 
- CPack * CConnection::retrievePack()
 
- {
 
- 	enableBufferedRead = true;
 
- 	CPack * pack = nullptr;
 
- 	boost::unique_lock<boost::mutex> lock(*mutexRead);
 
- 	iser & pack;
 
- 	logNetwork->trace("Received CPack of type %s", (pack ? typeid(*pack).name() : "nullptr"));
 
- 	if(pack == nullptr)
 
- 	{
 
- 		logNetwork->error("Received a nullptr CPack! You should check whether client and server ABI matches.");
 
- 	}
 
- 	else
 
- 	{
 
- 		pack->c = this->shared_from_this();
 
- 	}
 
- 	enableBufferedRead = false;
 
- 	return pack;
 
- }
 
- void CConnection::sendPack(const CPack * pack)
 
- {
 
- 	boost::unique_lock<boost::mutex> lock(*mutexWrite);
 
- 	logNetwork->trace("Sending a pack of type %s", typeid(*pack).name());
 
- 	enableBufferedWrite = true;
 
- 	oser & pack;
 
- 	flushBuffers();
 
- }
 
- void CConnection::disableStackSendingByID()
 
- {
 
- 	CSerializer::sendStackInstanceByIds = false;
 
- }
 
- void CConnection::enableStackSendingByID()
 
- {
 
- 	CSerializer::sendStackInstanceByIds = true;
 
- }
 
- void CConnection::disableSmartPointerSerialization()
 
- {
 
- 	iser.smartPointerSerialization = oser.smartPointerSerialization = false;
 
- }
 
- void CConnection::enableSmartPointerSerialization()
 
- {
 
- 	iser.smartPointerSerialization = oser.smartPointerSerialization = true;
 
- }
 
- void CConnection::enterLobbyConnectionMode()
 
- {
 
- 	iser.loadedPointers.clear();
 
- 	oser.savedPointers.clear();
 
- 	disableSmartVectorMemberSerialization();
 
- 	disableSmartPointerSerialization();
 
- }
 
- void CConnection::enterGameplayConnectionMode(CGameState * gs)
 
- {
 
- 	enableStackSendingByID();
 
- 	disableSmartPointerSerialization();
 
- 	addStdVecItems(gs);
 
- }
 
- void CConnection::disableSmartVectorMemberSerialization()
 
- {
 
- 	CSerializer::smartVectorMembersSerialization = false;
 
- }
 
- void CConnection::enableSmartVectorMemberSerializatoin()
 
- {
 
- 	CSerializer::smartVectorMembersSerialization = true;
 
- }
 
- std::string CConnection::toString() const
 
- {
 
- 	boost::format fmt("Connection with %s (ID: %d UUID: %s)");
 
- 	fmt % name % connectionID % uuid;
 
- 	return fmt.str();
 
- }
 
- VCMI_LIB_NAMESPACE_END
 
 
  |