diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/Network.cpp | 108 | ||||
-rw-r--r-- | src/network/Network.hpp | 26 | ||||
-rw-r--r-- | src/network/NetworkClient.cpp | 107 | ||||
-rw-r--r-- | src/network/NetworkClient.hpp | 42 |
4 files changed, 283 insertions, 0 deletions
diff --git a/src/network/Network.cpp b/src/network/Network.cpp new file mode 100644 index 0000000..a3023ff --- /dev/null +++ b/src/network/Network.cpp @@ -0,0 +1,108 @@ +#include <iostream> +#include "Network.hpp" +#include "../packet/PacketBuilder.hpp" + +Network::Network(std::string address, unsigned short port) : m_address(address), m_port(port) { + std::cout << "Connecting to server " << m_address << ":" << m_port << std::endl; + sf::Socket::Status status = m_socket.connect(sf::IpAddress(m_address), m_port); + m_socket.setBlocking(true); + if (status != sf::Socket::Done) { + if (status == sf::Socket::Error) { + std::cerr << "Can't connect to remote server" << std::endl; + throw 14; + } else { + std::cerr << "Connection failed with unknown reason" << std::endl; + throw 13; + } + } + std::cout << "Connected." << std::endl; +} + +Network::~Network() { + std::cout << "Disconnecting..." << std::endl; + m_socket.disconnect(); +} + +void Network::SendHandshake(std::string username) { + //Handshake packet + Packet handshakePacket = PacketBuilder::CHandshaking0x00(316, m_address, m_port, 2); + SendPacket(handshakePacket); + + //LoginStart packet + Field fName; + fName.SetString(username); + Packet loginPacket(0); + loginPacket.AddField(fName); + SendPacket(loginPacket); +} + +void Network::SendPacket(Packet &packet) { + m_socket.setBlocking(true); + byte *packetData = new byte[packet.GetLength()]; + packet.CopyToBuff(packetData); + m_socket.send(packetData, packet.GetLength()); + delete[] packetData; +} + +Packet Network::ReceivePacket() { + byte bufLen[5] = {0}; + size_t rec = 0; + for (int i = 0; i < 5; i++) { + byte buff = 0; + size_t r = 0; + m_socket.receive(&buff, 1, r); + rec += r; + bufLen[i] = buff; + if ((buff & 0b10000000) == 0) { + break; + } + } + Field fLen = FieldParser::Parse(VarInt, bufLen); + size_t packetLen = fLen.GetVarInt() + fLen.GetLength(); + if (packetLen > 1024 * 1024 * 30) + std::cout << "OMG! SIZEOF PACKET IS " << packetLen << std::endl; + if (packetLen < rec) { + return Packet(bufLen); + } + byte *bufPack = new byte[packetLen]; + std::copy(bufLen, bufLen + rec, bufPack); + size_t dataLen = rec; + while (m_socket.receive(bufPack + dataLen, packetLen - dataLen, rec) == sf::Socket::Done && dataLen < packetLen) { + dataLen += rec; + } + if (dataLen < packetLen) + throw 93; + else { + Packet p(bufPack); + delete[] bufPack; + return p; + } + + /*if (m_socket.receive(bufPack + rec, packetLen - rec, rec) != sf::Socket::Done) { + delete[] bufPack; + throw 93; + } + rec++; + //Check for losted data + int losted = 0; + for (int i = packetLen - 2; i > 0; i--) + if (bufPack[i] == 'N') + losted++; + if (losted > 100) { + if (m_socket.receive(bufPack + rec, packetLen - rec, rec) != sf::Socket::Done) { + throw 93; + } + std::cout << "Keep receiving!" << std::endl; + } + //One more time + losted = 0; + for (int i = packetLen - 2; i > 0; i--) + if (bufPack[i] == 'N') + losted++; + if (losted > 100) { + std::cout << "\x1b[31m" << "Losted " << losted << " bytes of " << packetLen << "\x1b[0m" << std::endl; + delete[] bufPack; + throw 93; + }*/ + throw 94; +} diff --git a/src/network/Network.hpp b/src/network/Network.hpp new file mode 100644 index 0000000..ea9042c --- /dev/null +++ b/src/network/Network.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include <string> +#include <SFML/Network.hpp> +#include "../packet/Packet.hpp" + + +class Network { +public: + Network(std::string address, unsigned short port); + + ~Network(); + + void SendHandshake(std::string username); + + void SendPacket(Packet &packet); + + Packet ReceivePacket(); + +private: + std::string m_address; + unsigned short m_port; + sf::TcpSocket m_socket; + bool m_isCommpress=false; +}; + diff --git a/src/network/NetworkClient.cpp b/src/network/NetworkClient.cpp new file mode 100644 index 0000000..cbe705b --- /dev/null +++ b/src/network/NetworkClient.cpp @@ -0,0 +1,107 @@ +#include "NetworkClient.hpp" +#include "../packet/PacketParser.hpp" +#include "../packet/PacketBuilder.hpp" +#include <nlohmann/json.hpp> + +ServerInfo NetworkClient::ServerPing(std::string address, unsigned short port) { + ServerInfo info; + Network network(address, port); + Packet packet_handshake = PacketBuilder::CHandshaking0x00(316, address, port, 1); + network.SendPacket(packet_handshake); + Packet packet_request(0); + network.SendPacket(packet_request); + Packet packet_response = network.ReceivePacket(); + PacketParser::Parse(packet_response, Login); + //std::string json = static_cast<FieldString *>(packet_response_parsed.GetFieldById(0))->GetValue(); + std::string json = packet_response.GetField(0).GetString(); + try { + nlohmann::json j = nlohmann::json::parse(json); + info.protocol = j["version"]["protocol"].get<int>(); + info.version = j["version"]["name"].get<std::string>(); + info.players_max = j["players"]["max"].get<int>(); + info.players_online = j["players"]["online"].get<int>(); + info.description = j["description"]["text"].get<std::string>(); + for (auto t:j["description"]["extra"]) { + info.description += t["text"].get<std::string>(); + } + if (!j["favicon"].is_null()) + info.favicon = j["favicon"].get<std::string>(); + info.json = json; + for (auto t:j["players"]["sample"]) { + std::pair<std::string, std::string> player; + player.first = t["id"].get<std::string>(); + player.second = t["name"].get<std::string>(); + info.players.push_back(player); + } + } catch (const nlohmann::detail::exception e) { + std::cerr << "Parsed json is not valid (" << e.id << "): " << e.what() << std::endl; + } + //Ping + Packet packet_ping(0x01); + Field payload; + payload.SetLong(771235); + packet_ping.AddField(payload); + std::chrono::high_resolution_clock clock; + auto t1 = clock.now(); + network.SendPacket(packet_ping); + Packet pong = network.ReceivePacket(); + auto t2 = clock.now(); + pong.ParseField(Long); + if (pong.GetField(0).GetLong() == 771235) { + std::chrono::duration<double, std::milli> pingTime = t2 - t1; + info.ping = pingTime.count(); + } + return info; +} + +NetworkClient::NetworkClient(std::string address, unsigned short port, std::string username) : m_network(address, + port) { + m_network.SendHandshake(username); + Update(); + m_networkThread = std::thread(&NetworkClient::MainLoop, this); +} + +NetworkClient::~NetworkClient() { + isContinue=false; + m_networkThread.join(); +} + +Packet * NetworkClient::GetPacket() { + if (m_received.size() < 1) + return nullptr; + Packet packet = m_received.front(); + m_received.pop(); + return new Packet(packet); +} + +void NetworkClient::AddPacketToQueue(Packet packet) { + m_toSend.push(packet); +} + +void NetworkClient::Update() { + if (m_toSend.size() > 0) { + m_network.SendPacket(m_toSend.front()); + m_toSend.pop(); + } + Packet received = m_network.ReceivePacket(); + if (received.GetId() == 0x1F) { + PacketParser::Parse(received); + Packet response = PacketBuilder::CPlay0x0B(received.GetField(0).GetVarInt()); + m_network.SendPacket(response); + return; + } + m_updateMutex.lock(); + m_received.push(received); + m_updateMutex.unlock(); +} + +void NetworkClient::MainLoop() { + try { + while (isContinue) { + Update(); + } + } catch (int e){ + std::cerr<<"NetworkClient exception: "<<e<<std::endl; + } + +} diff --git a/src/network/NetworkClient.hpp b/src/network/NetworkClient.hpp new file mode 100644 index 0000000..a41b5f4 --- /dev/null +++ b/src/network/NetworkClient.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include <queue> +#include <thread> +#include <mutex> +#include "Network.hpp" + +struct ServerInfo{ + std::string version; + int protocol = 0; + int players_max = 0; + int players_online = 0; + std::vector<std::pair<std::string, std::string>> players; + std::string description; + double ping = 0; + std::string favicon; + std::string json; +}; +class NetworkClient { +public: + NetworkClient(std::string address, unsigned short port, std::string username); + ~NetworkClient(); + + void Update(); + + void MainLoop(); + + Packet * GetPacket(); + void AddPacketToQueue(Packet packet); + + static ServerInfo ServerPing(std::string address,unsigned short port); +private: + std::mutex m_updateMutex; + std::thread m_networkThread; + bool isContinue=true; + NetworkClient (const NetworkClient&); + NetworkClient&operator=(const NetworkClient&); + Network m_network; + std::queue <Packet> m_received; + std::queue <Packet> m_toSend; +}; + |