mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-06 09:09:40 +02:00
Fix connection to game lobby & map load
This commit is contained in:
@@ -13,397 +13,150 @@
|
||||
#include "BinaryDeserializer.h"
|
||||
#include "BinarySerializer.h"
|
||||
|
||||
//#include "../networkPacks/NetPacksBase.h"
|
||||
#include "../networkPacks/NetPacksBase.h"
|
||||
#include "../network/NetworkConnection.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class DLL_LINKAGE ConnectionPackWriter final : public IBinaryWriter
|
||||
{
|
||||
public:
|
||||
std::vector<uint8_t> buffer;
|
||||
|
||||
int write(const void * data, unsigned size) final;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ConnectionPackReader final : public IBinaryReader
|
||||
{
|
||||
public:
|
||||
const std::vector<uint8_t> * buffer;
|
||||
size_t position;
|
||||
|
||||
int read(void * data, unsigned size) final;
|
||||
};
|
||||
|
||||
int ConnectionPackWriter::write(const void * data, unsigned size)
|
||||
{
|
||||
const uint8_t * begin_ptr = static_cast<const uint8_t *>(data);
|
||||
const uint8_t * end_ptr = begin_ptr + size;
|
||||
buffer.insert(buffer.end(), begin_ptr, end_ptr);
|
||||
return size;
|
||||
}
|
||||
|
||||
int ConnectionPackReader::read(void * data, unsigned size)
|
||||
{
|
||||
if (position + size > buffer->size())
|
||||
throw std::runtime_error("End of file reached when reading received network pack!");
|
||||
|
||||
uint8_t * begin_ptr = static_cast<uint8_t *>(data);
|
||||
|
||||
std::copy_n(buffer->begin() + position, size, begin_ptr);
|
||||
position += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
CConnection::CConnection(std::weak_ptr<NetworkConnection> networkConnection)
|
||||
: networkConnection(networkConnection)
|
||||
, packReader(std::make_unique<ConnectionPackReader>())
|
||||
, packWriter(std::make_unique<ConnectionPackWriter>())
|
||||
, deserializer(std::make_unique<BinaryDeserializer>(packReader.get()))
|
||||
, serializer(std::make_unique<BinarySerializer>(packWriter.get()))
|
||||
, connectionID(-1)
|
||||
{
|
||||
assert(networkConnection.lock() != nullptr);
|
||||
|
||||
enableSmartPointerSerialization();
|
||||
disableStackSendingByID();
|
||||
deserializer->fileVersion = SERIALIZATION_VERSION;
|
||||
}
|
||||
|
||||
CConnection::~CConnection() = default;
|
||||
|
||||
void CConnection::sendPack(const CPack * pack)
|
||||
{
|
||||
auto connectionPtr = networkConnection.lock();
|
||||
|
||||
if (!connectionPtr)
|
||||
throw std::runtime_error("Attempt to send packet on a closed connection!");
|
||||
|
||||
*serializer & pack;
|
||||
|
||||
logNetwork->trace("Sending a pack of type %s", typeid(*pack).name());
|
||||
|
||||
connectionPtr->sendPacket(packWriter->buffer);
|
||||
packWriter->buffer.clear();
|
||||
}
|
||||
|
||||
CPack * CConnection::retrievePack(const std::vector<uint8_t> & data)
|
||||
{
|
||||
return nullptr;
|
||||
CPack * result;
|
||||
|
||||
packReader->buffer = &data;
|
||||
packReader->position = 0;
|
||||
|
||||
*deserializer & result;
|
||||
|
||||
logNetwork->trace("Received CPack of type %s", (result ? typeid(*result).name() : "nullptr"));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CConnection::isMyConnection(const std::shared_ptr<NetworkConnection> & otherConnection) const
|
||||
{
|
||||
return otherConnection != nullptr && networkConnection.lock() == otherConnection;
|
||||
}
|
||||
|
||||
void CConnection::disableStackSendingByID()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CConnection::enterLobbyConnectionMode()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CConnection::enterGameplayConnectionMode(CGameState * gs)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CConnection::write(const void * data, unsigned size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CConnection::read(void * data, unsigned size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
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();
|
||||
#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("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("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("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;
|
||||
|
||||
if (!socket)
|
||||
throw std::runtime_error("Can't write to closed socket!");
|
||||
|
||||
try
|
||||
{
|
||||
asio::write(*socket, connectionBuffers->writeBuffer);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
//connection has been lost
|
||||
connected = false;
|
||||
throw;
|
||||
}
|
||||
|
||||
enableBufferedWrite = false;
|
||||
}
|
||||
|
||||
int CConnection::write(const void * data, unsigned size)
|
||||
{
|
||||
if (!socket)
|
||||
throw std::runtime_error("Can't write to closed socket!");
|
||||
|
||||
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()
|
||||
{
|
||||
close();
|
||||
|
||||
if(handler)
|
||||
{
|
||||
// ugly workaround to avoid self-join if last strong reference to shared_ptr that owns this class has been released in this very thread, e.g. on netpack processing
|
||||
if (boost::this_thread::get_id() != handler->get_id())
|
||||
handler->join();
|
||||
else
|
||||
handler->detach();
|
||||
}
|
||||
}
|
||||
|
||||
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 t0@czlug.icis.pcz.pl or impono@gmail.com
|
||||
// do not remove this exception it shoudnt be called
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CConnection::close()
|
||||
{
|
||||
if(socket)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket->shutdown(boost::asio::ip::tcp::socket::shutdown_receive);
|
||||
}
|
||||
catch (const boost::system::system_error & e)
|
||||
{
|
||||
logNetwork->error("error closing socket: %s", e.what());
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
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;
|
||||
packReader->sendStackInstanceByIds = false;
|
||||
packWriter->sendStackInstanceByIds = false;
|
||||
}
|
||||
|
||||
void CConnection::enableStackSendingByID()
|
||||
{
|
||||
CSerializer::sendStackInstanceByIds = true;
|
||||
}
|
||||
|
||||
void CConnection::disableSmartPointerSerialization()
|
||||
{
|
||||
iser.smartPointerSerialization = oser.smartPointerSerialization = false;
|
||||
}
|
||||
|
||||
void CConnection::enableSmartPointerSerialization()
|
||||
{
|
||||
iser.smartPointerSerialization = oser.smartPointerSerialization = true;
|
||||
packReader->sendStackInstanceByIds = true;
|
||||
packWriter->sendStackInstanceByIds = true;
|
||||
}
|
||||
|
||||
void CConnection::enterLobbyConnectionMode()
|
||||
{
|
||||
iser.loadedPointers.clear();
|
||||
oser.savedPointers.clear();
|
||||
deserializer->loadedPointers.clear();
|
||||
serializer->savedPointers.clear();
|
||||
disableSmartVectorMemberSerialization();
|
||||
disableSmartPointerSerialization();
|
||||
disableStackSendingByID();
|
||||
}
|
||||
|
||||
void CConnection::enterGameplayConnectionMode(CGameState * gs)
|
||||
{
|
||||
enableStackSendingByID();
|
||||
disableSmartPointerSerialization();
|
||||
addStdVecItems(gs);
|
||||
|
||||
packReader->addStdVecItems(gs);
|
||||
packWriter->addStdVecItems(gs);
|
||||
}
|
||||
|
||||
void CConnection::disableSmartPointerSerialization()
|
||||
{
|
||||
deserializer->smartPointerSerialization = false;
|
||||
serializer->smartPointerSerialization = false;
|
||||
}
|
||||
|
||||
void CConnection::enableSmartPointerSerialization()
|
||||
{
|
||||
deserializer->smartPointerSerialization = true;
|
||||
serializer->smartPointerSerialization = true;
|
||||
}
|
||||
|
||||
void CConnection::disableSmartVectorMemberSerialization()
|
||||
{
|
||||
CSerializer::smartVectorMembersSerialization = false;
|
||||
packReader->smartVectorMembersSerialization = false;
|
||||
packWriter->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();
|
||||
packReader->smartVectorMembersSerialization = true;
|
||||
packWriter->smartVectorMembersSerialization = true;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,84 +9,49 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "CSerializer.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class BinaryDeserializer;
|
||||
class BinarySerializer;
|
||||
struct CPack;
|
||||
struct ConnectionBuffers;
|
||||
class NetworkConnection;
|
||||
class ConnectionPackReader;
|
||||
class ConnectionPackWriter;
|
||||
class CGameState;
|
||||
|
||||
/// Main class for network communication
|
||||
/// Allows establishing connection and bidirectional read-write
|
||||
class DLL_LINKAGE CConnection : public IBinaryReader, public IBinaryWriter, public std::enable_shared_from_this<CConnection>
|
||||
/// Wrapper class for game connection
|
||||
/// Handles serialization and deserialization of data received from network
|
||||
class DLL_LINKAGE CConnection : boost::noncopyable
|
||||
{
|
||||
/// Non-owning pointer to underlying connection
|
||||
std::weak_ptr<NetworkConnection> networkConnection;
|
||||
|
||||
// void init();
|
||||
// void reportState(vstd::CLoggerBase * out) override;
|
||||
//
|
||||
int write(const void * data, unsigned size) override;
|
||||
int read(void * data, unsigned size) override;
|
||||
// void flushBuffers();
|
||||
//
|
||||
// bool enableBufferedWrite;
|
||||
// bool enableBufferedRead;
|
||||
// std::unique_ptr<ConnectionBuffers> connectionBuffers;
|
||||
//
|
||||
std::unique_ptr<BinaryDeserializer> iser;
|
||||
std::unique_ptr<BinarySerializer> oser;
|
||||
//
|
||||
// std::string contactUuid;
|
||||
// std::string name; //who uses this connection
|
||||
std::unique_ptr<ConnectionPackReader> packReader;
|
||||
std::unique_ptr<ConnectionPackWriter> packWriter;
|
||||
std::unique_ptr<BinaryDeserializer> deserializer;
|
||||
std::unique_ptr<BinarySerializer> serializer;
|
||||
|
||||
void disableStackSendingByID();
|
||||
void enableStackSendingByID();
|
||||
void disableSmartPointerSerialization();
|
||||
void enableSmartPointerSerialization();
|
||||
void disableSmartVectorMemberSerialization();
|
||||
void enableSmartVectorMemberSerializatoin();
|
||||
|
||||
public:
|
||||
bool isMyConnection(const std::shared_ptr<NetworkConnection> & otherConnection) const;
|
||||
|
||||
std::string uuid;
|
||||
int connectionID;
|
||||
|
||||
CConnection(std::weak_ptr<NetworkConnection> networkConnection);
|
||||
// CConnection(const std::string & host, ui16 port, std::string Name, std::string UUID);
|
||||
// CConnection(const std::shared_ptr<TAcceptor> & acceptor, const std::shared_ptr<boost::asio::io_service> & Io_service, std::string Name, std::string UUID);
|
||||
// CConnection(std::shared_ptr<TSocket> Socket, std::string Name, std::string UUID); //use immediately after accepting connection into socket
|
||||
// virtual ~CConnection();
|
||||
~CConnection();
|
||||
|
||||
// void close();
|
||||
// bool isOpen() const;
|
||||
//
|
||||
// CPack * retrievePack();
|
||||
void sendPack(const CPack * pack);
|
||||
|
||||
CPack * retrievePack(const std::vector<uint8_t> & data);
|
||||
// std::vector<uint8_t> serializePack(const CPack * pack);
|
||||
//
|
||||
void disableStackSendingByID();
|
||||
// void enableStackSendingByID();
|
||||
// void disableSmartPointerSerialization();
|
||||
// void enableSmartPointerSerialization();
|
||||
// void disableSmartVectorMemberSerialization();
|
||||
// void enableSmartVectorMemberSerializatoin();
|
||||
//
|
||||
|
||||
void enterLobbyConnectionMode();
|
||||
void enterGameplayConnectionMode(CGameState * gs);
|
||||
//
|
||||
// std::string toString() const;
|
||||
//
|
||||
// template<class T>
|
||||
// CConnection & operator>>(T &t)
|
||||
// {
|
||||
// iser & t;
|
||||
// return * this;
|
||||
// }
|
||||
//
|
||||
// template<class T>
|
||||
// CConnection & operator<<(const T &t)
|
||||
// {
|
||||
// oser & t;
|
||||
// return * this;
|
||||
// }
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
Reference in New Issue
Block a user