summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/Network.cpp108
-rw-r--r--src/network/Network.hpp26
-rw-r--r--src/network/NetworkClient.cpp107
-rw-r--r--src/network/NetworkClient.hpp42
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;
+};
+