1er commit

This commit is contained in:
2021-08-21 10:14:47 +02:00
commit a99ecf7c2d
99 changed files with 66605 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
#include "network/DataBuffer.h"
#include <iomanip>
#include <fstream>
#include <iostream>
namespace td {
DataBuffer::DataBuffer() { }
DataBuffer::DataBuffer(const DataBuffer& other) : m_Buffer(other.m_Buffer), m_ReadOffset(other.m_ReadOffset) { }
DataBuffer::DataBuffer(DataBuffer&& other) : m_Buffer(std::move(other.m_Buffer)), m_ReadOffset(std::move(other.m_ReadOffset)) { }
DataBuffer::DataBuffer(const std::string& str) : m_Buffer(str.begin(), str.end()) { }
DataBuffer::DataBuffer(const DataBuffer& other, std::size_t offset) {
m_Buffer.reserve(other.GetSize() - offset);
std::copy(other.m_Buffer.begin() + offset, other.m_Buffer.end(), std::back_inserter(m_Buffer));
}
DataBuffer& DataBuffer::operator=(const DataBuffer& other) {
m_Buffer = other.m_Buffer;
m_ReadOffset = other.m_ReadOffset;
return *this;
}
DataBuffer& DataBuffer::operator=(DataBuffer&& other) {
m_Buffer = std::move(other.m_Buffer);
m_ReadOffset = std::move(other.m_ReadOffset);
return *this;
}
void DataBuffer::SetReadOffset(std::size_t pos) {
assert(pos <= GetSize());
m_ReadOffset = pos;
}
std::string DataBuffer::ToString() const {
return std::string(m_Buffer.begin(), m_Buffer.end());
}
std::size_t DataBuffer::GetSize() const { return m_Buffer.size(); }
bool DataBuffer::IsEmpty() const { return m_Buffer.empty(); }
std::size_t DataBuffer::GetRemaining() const {
return m_Buffer.size() - m_ReadOffset;
}
DataBuffer::iterator DataBuffer::begin() {
return m_Buffer.begin();
}
DataBuffer::iterator DataBuffer::end() {
return m_Buffer.end();
}
DataBuffer::const_iterator DataBuffer::begin() const {
return m_Buffer.begin();
}
DataBuffer::const_iterator DataBuffer::end() const {
return m_Buffer.end();
}
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer) {
for (unsigned char u : buffer)
os << std::hex << std::setfill('0') << std::setw(2) << (int)u << " ";
os << std::dec;
return os;
}
bool DataBuffer::ReadFile(const std::string& fileName){
try{
std::ifstream file(fileName);
std::ostringstream ss;
ss << file.rdbuf();
const std::string& s = ss.str();
m_Buffer = DataBuffer::Data(s.begin(), s.end());
m_ReadOffset = 0;
}catch(std::exception& e){
std::cerr << "Failed to read file \"" << fileName << "\" reason : " << e.what() << std::endl;
return false;
}
return m_Buffer.size() > 0;
}
bool DataBuffer::WriteFile(const std::string& fileName){
try{
std::ofstream file(fileName);
file.write((const char*) m_Buffer.data(), m_Buffer.size());
file.flush();
}catch(std::exception& e){
std::cerr << "Failed to write file \"" << fileName << "\" reason : " << e.what() << std::endl;
return false;
}
return true;
}
} // td

127
src/network/IPAddress.cpp Normal file
View File

@@ -0,0 +1,127 @@
#include "network/IPAddress.h"
#include <regex>
#include <stdexcept>
#include <sstream>
namespace {
const std::regex IPRegex(R":(^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$):");
const std::wregex IPRegexW(LR":(^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$):");
} // ns
namespace td {
namespace network {
/* Create an invalid address */
IPAddress::IPAddress() noexcept
: m_Valid(false), m_Address(0)
{
}
/* Initialize by string IP */
IPAddress::IPAddress(const std::string& ip)
: m_Valid(false), m_Address(0)
{
std::sregex_iterator begin(ip.begin(), ip.end(), IPRegex);
std::sregex_iterator end;
if (begin == end) return; // m_Valid = false
std::smatch match = *begin;
int octet1 = atoi(std::string(match[1]).c_str());
int octet2 = atoi(std::string(match[2]).c_str());
int octet3 = atoi(std::string(match[3]).c_str());
int octet4 = atoi(std::string(match[4]).c_str());
m_Address = (octet1 << 24) | (octet2 << 16) | (octet3 << 8) | octet4;
m_Valid = true;
}
IPAddress::IPAddress(const std::wstring& ip)
: m_Address(0), m_Valid(false)
{
std::wsregex_iterator begin(ip.begin(), ip.end(), IPRegexW);
std::wsregex_iterator end;
if (begin == end) return; // m_Valid = false
std::wsmatch match = *begin;
int octet1 = std::stoi(match[1]);
int octet2 = std::stoi(match[2]);
int octet3 = std::stoi(match[3]);
int octet4 = std::stoi(match[4]);
m_Address = (octet1 << 24) | (octet2 << 16) | (octet3 << 8) | octet4;
m_Valid = true;
}
/* Initialize by octets */
IPAddress::IPAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4) noexcept
: m_Valid(true)
{
m_Address = (octet1 << 24) | (octet2 << 16) | (octet3 << 8) | octet4;
}
/* Get the specific octet */
uint8_t IPAddress::GetOctet(uint8_t num) const {
if (num == 0 || num > 4) throw std::invalid_argument("Invalid argument in IPAddress:GetOctet.");
return (m_Address >> (8 * (4 - num))) & 0xFF;
}
/* Set the specific octet. 1-4 */
void IPAddress::SetOctet(uint8_t num, uint8_t value) {
if (num == 0 || num > 4) throw std::invalid_argument("Invalid argument in IPAddress:GetOctet.");
uint8_t octets[4];
for (int i = 0; i < 4; ++i)
octets[i] = (m_Address >> ((3 - i) * 8)) & 0xFF;
octets[num - 1] = value;
m_Address = (octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3];
}
IPAddress IPAddress::LocalAddress() {
return IPAddress(127, 0, 0, 1);
}
std::string IPAddress::ToString() const {
std::stringstream ss;
for (int i = 0; i < 4; ++i) {
if (i != 0) ss << ".";
ss << static_cast<unsigned int>(GetOctet(i + 1));
}
return ss.str();
}
bool IPAddress::operator==(const IPAddress& right) {
return m_Address == right.m_Address;
}
bool IPAddress::operator!=(const IPAddress& right) {
return !(*this == right);
}
bool IPAddress::operator==(bool b) {
return IsValid() == b;
}
std::ostream& operator<<(std::ostream& os, const IPAddress& addr) {
return os << addr.ToString();
}
std::wostream& operator<<(std::wostream& os, const IPAddress& addr) {
std::string str = addr.ToString();
return os << std::wstring(str.begin(), str.end());
}
} // ns network
} // ns mc

67
src/network/Network.cpp Normal file
View File

@@ -0,0 +1,67 @@
#include "network/Network.h"
namespace td {
namespace network {
class NetworkInitializer {
public:
NetworkInitializer();
~NetworkInitializer();
NetworkInitializer(const NetworkInitializer& rhs) = delete;
NetworkInitializer& operator=(const NetworkInitializer& rhs) = delete;
};
#ifdef _WIN32
NetworkInitializer::NetworkInitializer() {
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
}
NetworkInitializer::~NetworkInitializer() {
WSACleanup();
}
#else
NetworkInitializer::NetworkInitializer() {
}
NetworkInitializer::~NetworkInitializer() {
}
#endif
NetworkInitializer initializer;
IPAddresses Dns::Resolve(const std::string& host) {
IPAddresses list;
addrinfo hints = { 0 }, *addresses;
//hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
getaddrinfo(host.c_str(), NULL, &hints, &addresses);
for (addrinfo *p = addresses; p != NULL; p = p->ai_next) {
#ifdef _WIN32
//wchar_t straddr[35];
//char straddr[512];
//DWORD len;
//WSAAddressToStringA(p->ai_addr, p->ai_addrlen, NULL, straddr, &len);
char* straddr = inet_ntoa(((sockaddr_in*)p->ai_addr)->sin_addr);
#else
char straddr[512];
inet_ntop(p->ai_family, &((sockaddr_in*)p->ai_addr)->sin_addr, straddr, sizeof(straddr));
#endif
list.push_back(IPAddress(straddr));
}
return list;
}
} // ns network
} // ns mc

79
src/network/Socket.cpp Normal file
View File

@@ -0,0 +1,79 @@
#include "network/Socket.h"
#include "network/IPAddress.h"
#include "network/Network.h"
#ifdef _WIN32
#define ioctl ioctlsocket
#endif
#include <iostream>
namespace td {
namespace network {
Socket::Socket(Type type)
: m_Handle(INVALID_SOCKET),
m_Type(type),
m_Blocking(false),
m_Status(Disconnected)
{
}
Socket::~Socket() {
Disconnect();
}
bool Socket::SetBlocking(bool block) {
unsigned long mode = block ? 0 : 1;
if(ioctl(m_Handle, FIONBIO, &mode) < 0){
return false;
}
m_Blocking = block;
}
bool Socket::IsBlocking() const noexcept {
return m_Blocking;
}
Socket::Type Socket::GetType() const noexcept {
return m_Type;
}
SocketHandle Socket::GetHandle() const noexcept {
return m_Handle;
}
void Socket::SetStatus(Socket::Status status) {
m_Status = status;
}
Socket::Status Socket::GetStatus() const noexcept {
return m_Status;
}
bool Socket::Connect(const std::string& ip, uint16_t port) {
IPAddress addr(ip);
return Connect(addr, port);
}
std::size_t Socket::Send(const std::string& data) {
return this->Send(reinterpret_cast<const unsigned char*>(data.c_str()), data.length());
}
std::size_t Socket::Send(DataBuffer& buffer) {
std::string data = buffer.ToString();
return this->Send(reinterpret_cast<const unsigned char*>(data.c_str()), data.length());
}
void Socket::Disconnect() {
if (m_Handle != INVALID_SOCKET)
closesocket(m_Handle);
m_Status = Disconnected;
}
} // ns network
} // ns mc

View File

@@ -0,0 +1,71 @@
#include "network/TCPListener.h"
#include <fcntl.h>
#ifndef _WIN32
#define closesocket close
#define SD_BOTH SHUT_RDWR
#define ioctlsocket ioctl
#endif
namespace td{
namespace network{
TCPListener::TCPListener(){}
TCPListener::~TCPListener(){
destroy();
}
bool TCPListener::listen(uint16_t port, int maxConnections){
if ((m_Handle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
return false;
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (::bind(m_Handle, reinterpret_cast<sockaddr*>(&address), sizeof(address)) < 0)
return false;
if (::listen(m_Handle, maxConnections) < 0)
return false;
m_Port = port;
m_MaxConnections = maxConnections;
return true;
}
bool TCPListener::accept(TCPSocket& newSocket){
int addrlen = sizeof(newSocket.m_RemoteAddr);
if ((newSocket.m_Handle = ::accept(m_Handle, reinterpret_cast<sockaddr*>(&newSocket.m_RemoteAddr),
reinterpret_cast<socklen_t*>(&addrlen))) < 0)
return false;
newSocket.SetStatus(Socket::Status::Connected);
newSocket.SetBlocking(false);
return true;
}
void TCPListener::destroy(){
if(m_Handle != INVALID_SOCKET)
::closesocket(m_Handle);
}
bool TCPListener::close(){
if (::shutdown(m_Handle, SD_BOTH) == 0)
return true;
return false;
}
bool TCPListener::setBlocking(bool blocking){
unsigned long mode = blocking ? 0 : 1;
if(ioctlsocket(m_Handle, FIONBIO, &mode) < 0){
return false;
}
return true;
}
} // namespace network
} // namespace td

141
src/network/TCPSocket.cpp Normal file
View File

@@ -0,0 +1,141 @@
#include "network/TCPSocket.h"
#include "misc/Compression.h"
#include <iostream>
#ifdef _WIN32
#define WOULDBLOCK WSAEWOULDBLOCK
#define MSG_DONTWAIT 0
#else
#define WOULDBLOCK EWOULDBLOCK
#endif
namespace td {
namespace network {
TCPSocket::TCPSocket()
: Socket(Socket::TCP), m_Port(0)
{
m_Handle = INVALID_SOCKET;
}
bool TCPSocket::Connect(const IPAddress& address, unsigned short port) {
if (this->GetStatus() == Connected)
return true;
struct addrinfo hints = { 0 }, *result = nullptr;
if ((m_Handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
return false;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if (getaddrinfo(address.ToString().c_str(), std::to_string(port).c_str(), &hints, &result) != 0)
return false;
struct addrinfo* ptr = nullptr;
for (ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
struct sockaddr_in* sockaddr = (struct sockaddr_in*)ptr->ai_addr;
if (::connect(m_Handle, (struct sockaddr*)sockaddr, sizeof(struct sockaddr_in)) != 0)
continue;
m_RemoteAddr = *sockaddr;
break;
}
freeaddrinfo(result);
if (!ptr)
return false;
this->SetStatus(Connected);
m_RemoteIP = address;
m_Port = port;
return true;
}
size_t TCPSocket::Send(const unsigned char* data, size_t size){
if (this->GetStatus() != Connected)
return 0;
size_t sent = 0;
while (sent < size) {
int cur = ::send(m_Handle, reinterpret_cast<const char*>(data + sent), size - sent, 0);
if (cur <= 0) {
Disconnect();
return 0;
}
sent += cur;
}
return sent;
}
std::size_t TCPSocket::Receive(DataBuffer& buffer, std::size_t amount) {
buffer.Resize(amount);
buffer.SetReadOffset(0);
int recvAmount = ::recv(m_Handle, (char*)&buffer[0], amount, 0);
if (recvAmount <= 0) {
#if defined(_WIN32) || defined(WIN32)
int err = WSAGetLastError();
#else
int err = errno;
#endif
if (err == WOULDBLOCK) {
buffer.Clear();
return 0;
}
Disconnect();
buffer.Clear();
return 0;
}
buffer.Resize(recvAmount);
return recvAmount;
}
DataBuffer TCPSocket::Receive(std::size_t amount) {
std::unique_ptr<char[]> buf(new char[amount]);
int received = ::recv(m_Handle, buf.get(), amount, 0);
if (received <= 0) {
#if defined(_WIN32) || defined(WIN32)
int err = WSAGetLastError();
#else
int err = errno;
#endif
if (err == WOULDBLOCK)
return DataBuffer();
Disconnect();
return DataBuffer();
}
return DataBuffer(std::string(buf.get(), received));
}
TCPSocket::TCPSocket(TCPSocket&& other) : Socket(TCP){
m_Handle = other.m_Handle;
m_Port = other.m_Port;
m_RemoteAddr = other.m_RemoteAddr;
m_RemoteIP = other.m_RemoteIP;
SetStatus(other.GetStatus());
SetBlocking(other.IsBlocking());
other.m_Handle = INVALID_SOCKET;
}
void SendPacket(const DataBuffer& data, network::TCPSocket& socket){
DataBuffer compressed = utils::Compress(data);
/*DataBuffer buffer;
buffer.Reserve(sizeof(std::size_t) + data.GetSize());
buffer << data.GetSize() << data;*/
socket.Send((const std::uint8_t*) compressed.ToString().data(), compressed.GetSize());
}
} // ns network
} // ns mc

77
src/network/UDPSocket.cpp Normal file
View File

@@ -0,0 +1,77 @@
#include "network/UDPSocket.h"
#include <iostream>
#ifdef _WIN32
#define WOULDBLOCK WSAEWOULDBLOCK
#else
#define WOULDBLOCK EWOULDBLOCK
#endif
namespace td {
namespace network {
UDPSocket::UDPSocket()
: Socket(Socket::UDP), m_Port(0)
{
m_Handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
bool UDPSocket::Connect(const IPAddress& address, unsigned short port) {
if (this->GetStatus() == Connected)
return true;
m_RemoteAddr.sin_port = htons(port);
m_RemoteAddr.sin_family = AF_INET;
m_RemoteAddr.sin_addr.s_addr = inet_addr(address.ToString().c_str());
this->SetStatus(Connected);
m_RemoteIP = IPAddress(address);
m_Port = port;
return true;
}
size_t UDPSocket::Send(const unsigned char* data, size_t size) {
size_t sent = 0;
if (this->GetStatus() != Connected)
return 0;
while (sent < size) {
int cur = sendto(m_Handle, reinterpret_cast<const char*>(data + sent), size - sent, 0,
reinterpret_cast<sockaddr*>(&m_RemoteAddr), sizeof(sockaddr_in));
if (cur <= 0) {
Disconnect();
return 0;
}
sent += cur;
}
return sent;
}
DataBuffer UDPSocket::Receive(std::size_t amount) {
std::unique_ptr<char[]> buf(new char[amount]);
socklen_t slen = sizeof(sockaddr_in);
int received = recvfrom(m_Handle, buf.get(), amount, 0,
reinterpret_cast<sockaddr*>(&m_RemoteAddr), &slen);
if (received <= 0) {
#if defined(_WIN32) || defined(WIN32)
int err = WSAGetLastError();
#else
int err = errno;
#endif
if (err == WOULDBLOCK)
return DataBuffer(std::string(buf.get(), received));
Disconnect();
return DataBuffer();
}
return DataBuffer(std::string(buf.get(), received));
}
} // ns network
} // ns mc