First commit.

This commit is contained in:
2023-12-17 03:29:08 -08:00
commit 09ced8e899
255 changed files with 45001 additions and 0 deletions

336
src/IO/Socket/BaseTCP.cpp Normal file
View File

@@ -0,0 +1,336 @@
#include "../../../include/IO/Socket/BaseTCP.h"
#include "../../../include/Log.h"
namespace lwe
{
BaseTCP::BaseTCP()
: addrType(AddrType::IPV6), localPort(0), remotePort(0), connection(false), bound(false), listening(false),
connected(false)
{
}
BaseTCP::BaseTCP(const AddrType addrType)
: addrType(addrType), localPort(0), remotePort(0), connection(false), bound(false), listening(false),
connected(false)
{
}
BaseTCP::BaseTCP(BaseTCP&& tcp) noexcept
: addrType(tcp.addrType), localAddr(std::move(tcp.localAddr)), localPort(tcp.localPort),
remoteHostName(std::move(tcp.remoteHostName)), remoteAddr(std::move(tcp.remoteAddr)), remotePort(tcp.remotePort),
connection(tcp.connection), bound(tcp.bound), listening(tcp.listening), connected(tcp.connected)
{
}
BaseTCP::BaseTCP(const BaseTCP& tcp)
: addrType(tcp.addrType), localPort(0), remotePort(0), connection(false), bound(false), listening(false),
connected(false)
{
}
BaseTCP& BaseTCP::operator=(BaseTCP&& tcp) noexcept
{
if (this == &tcp)
return *this;
addrType = tcp.addrType;
localAddr = std::move(tcp.localAddr);
localPort = tcp.localPort;
remoteHostName = std::move(tcp.remoteHostName);
remoteAddr = std::move(tcp.remoteAddr);
remotePort = tcp.remotePort;
connection = tcp.connection;
bound = tcp.bound;
listening = tcp.listening;
connected = tcp.connected;
tcp.addrType = AddrType::IPV6;
tcp.localPort = 0;
tcp.remotePort = 0;
tcp.connection = false;
tcp.bound = false;
tcp.listening = false;
tcp.connected = false;
return *this;
}
BaseTCP& BaseTCP::operator=(const BaseTCP& tcp)
{
if (this == &tcp)
return *this;
addrType = tcp.addrType;
localAddr = Str_8();
localPort = 0;
remoteHostName = Str_8();
remoteAddr = Str_8();
remotePort = 0;
connection = false;
bound = false;
listening = false;
connected = false;
return *this;
}
void BaseTCP::SendStr(const Str_8& str)
{
if (!IsValid())
return;
UInt_64 offset = 0;
UInt_64 size = str.Size(true);
while (offset < size)
{
UInt_64 sent = Send((Byte*)&str[offset], size - offset);
if (!sent)
{
LWE_LOG_INT("Error", 0, "Failed to send data.");
return;
}
offset += sent;
}
}
void BaseTCP::SendRes(const Response& res)
{
if (!IsValid())
return;
SendStr(res.FormResult());
}
void BaseTCP::SendReq(Request& req)
{
if (!IsValid())
return;
req.AddToHeader("Host", remoteHostName);
SendStr(req.FormResult());
}
Response BaseTCP::RecvRes()
{
if (!IsValid())
return {};
Str_8 header = RecvHeader();
if (!header.Size())
return {};
Response response(header);
Str_8 encoding = response.GetHeader("Transfer-Encoding");
if (!encoding.Size())
{
int bodySize = response.GetHeader("content-length").ToDecimal<int>();
if (!bodySize)
return response;
response.SetBody(RecvBody(bodySize));
}
else if (encoding == "chunked")
{
Str_8 body;
UInt_64 chunkSize = RecvChunkSize();
while (chunkSize)
{
body += RecvChunk(chunkSize);
chunkSize = RecvChunkSize();
}
response.SetBody(body);
}
return response;
}
Request BaseTCP::RecvReq()
{
if (!IsValid())
return {};
Str_8 header = RecvHeader();
if (!header.Size())
return {};
Request request(header);
if (request.GetVerb() == Verb::GET)
return request;
Str_8 encoding = request.GetHeader("Transfer-Encoding");
if (!encoding.Size())
{
int bodySize = request.GetHeader("Content-Length").ToDecimal<int>();
if (!bodySize)
return request;
request.SetBody(RecvBody(bodySize));
}
else if (encoding == "chunked")
{
Str_8 body;
UInt_64 chunkSize = RecvChunkSize();
while (chunkSize)
{
body += RecvChunk(chunkSize);
chunkSize = RecvChunkSize();
}
request.SetBody(body);
}
return request;
}
AddrType BaseTCP::GetAddressType() const
{
return addrType;
}
Str_8 BaseTCP::GetLocalAddress() const
{
return localAddr;
}
unsigned short BaseTCP::GetLocalPort() const
{
return localPort;
}
Str_8 BaseTCP::GetRemoteAddress() const
{
return remoteAddr;
}
unsigned short BaseTCP::GetRemotePort() const
{
return remotePort;
}
bool BaseTCP::IsConnection() const
{
return connection;
}
bool BaseTCP::IsBound() const
{
return bound;
}
bool BaseTCP::IsListening() const
{
return listening;
}
bool BaseTCP::IsConnected() const
{
return connected;
}
Str_8 BaseTCP::RecvHeader()
{
Byte buffer[MaxHeaderSize];
UInt_64 offset = 0;
while (true)
{
UInt_64 received = Receive(&buffer[offset], 1);
if (!received)
{
return {};
}
else if (buffer[offset] == '\n' && offset - 3 && buffer[offset - 1] == '\r' && buffer[offset - 2] == '\n' && buffer[offset - 3] == '\r')
{
offset -= 3;
break;
}
offset += received;
}
return {(Char_8*)buffer, (UInt_64)offset};
}
Str_8 BaseTCP::RecvBody(const UInt_64 contentLength)
{
Str_8 buffer(contentLength);
UInt_64 offset = 0;
while (offset < contentLength)
{
UInt_64 received = Receive((Byte*)&buffer[offset], contentLength - offset);
if (!received)
{
LWE_LOG_INT("Error", 0, "Failed to receive data.");
return {};
}
offset += received;
}
return buffer;
}
UInt_64 BaseTCP::RecvChunkSize()
{
Str_8 hexSize(10);
UInt_64 offset = 0;
bool cr = false;
while (true)
{
UInt_64 received = Receive((Byte*)&hexSize[offset], 1);
if (!received)
{
LWE_LOG_INT("Error", 0, "Failed to receive data.");
return 0;
}
else if (hexSize[offset] == '\r')
cr = true;
else if (cr && hexSize[offset] == '\n')
break;
++offset;
}
if (hexSize[0] == '0')
Receive((Byte*)&hexSize[offset + 1], 2);
hexSize.Resize(offset - 1);
return hexSize.HexToNum<UInt_64>();
}
Str_8 BaseTCP::RecvChunk(const UInt_64 chunkSize)
{
Str_8 buffer(chunkSize + 2);
UInt_64 offset = 0;
while (offset < chunkSize + 2)
{
UInt_64 received = Receive((Byte*)&buffer[offset], chunkSize + 2 - offset);
if (!received)
{
LWE_LOG_INT("Error", 0, "Failed to receive data.");
return {};
}
offset += received;
}
buffer.Resize(offset - 2);
return buffer;
}
}

77
src/IO/Socket/BaseUDP.cpp Normal file
View File

@@ -0,0 +1,77 @@
#include "../../../include/IO/Socket/BaseUDP.h"
namespace lwe
{
BaseUDP::BaseUDP()
: addrType(AddrType::IPV6), port(0), bound(false)
{
}
BaseUDP::BaseUDP(const AddrType addrType)
: addrType(addrType), port(0), bound(false)
{
}
BaseUDP::BaseUDP(BaseUDP&& udp) noexcept
: addrType(udp.addrType), address(std::move(udp.address)), port(udp.port), bound(true)
{
udp.addrType = AddrType::IPV6;
udp.port = 0;
udp.bound = false;
}
BaseUDP::BaseUDP(const BaseUDP& udp)
: addrType(udp.addrType), address(udp.address), port(udp.port), bound(false)
{
}
BaseUDP& BaseUDP::operator=(BaseUDP&& udp) noexcept
{
if (this == &udp)
return *this;
addrType = udp.addrType;
address = std::move(udp.address);
port = udp.port;
bound = udp.bound;
udp.addrType = AddrType::IPV6;
udp.port = 0;
udp.bound = false;
return *this;
}
BaseUDP& BaseUDP::operator=(const BaseUDP& udp)
{
if (this == &udp)
return *this;
addrType = udp.addrType;
address = udp.address;
port = udp.port;
bound = false;
return *this;
}
bool BaseUDP::IsBound() const
{
return bound;
}
AddrType BaseUDP::GetAddressType() const
{
return addrType;
}
Str_8 BaseUDP::GetLocalAddress() const
{
return address;
}
UInt_16 BaseUDP::GetLocalPort() const
{
return port;
}
}

1316
src/IO/Socket/Comms.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
#include "../../../include/IO/Socket/CommsSystem.h"
#include "../../../include/IO/Socket/Comms.h"
#include "../../../include/IO/Socket/Endpoint.h"
#include "../../../include/IO/Socket/Operation.h"
namespace lwe
{
CommsSystem::~CommsSystem()
{
for (UInt_64 i = 0; i < ops.Size(); ++i)
delete ops[i];
ops.Clear();
}
CommsSystem::CommsSystem()
: hashId(0)
{
}
CommsSystem::CommsSystem(const Str_8& id)
: id(id), hashId(id.Hash_64())
{
}
CommsSystem::CommsSystem(const CommsSystem& sys)
: id(sys.id), hashId(sys.hashId)
{
}
CommsSystem& CommsSystem::operator=(const CommsSystem& sys)
{
if (this == &sys)
return *this;
id = sys.id;
hashId = sys.hashId;
ops = Array<Operation*>();
return *this;
}
Str_8 CommsSystem::GetId() const
{
return id;
}
UInt_64 CommsSystem::GetHashId() const
{
return hashId;
}
bool CommsSystem::HasOperation(const UInt_64 hashId)
{
for (UInt_64 i = 0; i < ops.Size(); ++i)
if (ops[i]->GetHashId() == hashId)
return true;
return false;
}
bool CommsSystem::AddOperation(Operation* op)
{
if (HasOperation(op->GetHashId()))
return false;
ops.Push(op);
return true;
}
void CommsSystem::Execute(Comms* comms, Endpoint* endpoint, const UInt_64 hashId, Serializer<>& payload)
{
for (UInt_64 i = 0; i < ops.Size(); ++i)
{
if (ops[i]->GetHashId() == hashId)
{
ops[i]->Process(comms, endpoint, this, payload);
return;
}
}
LWE_LOG_INT("Info", 0, "System not found.");
}
}

75
src/IO/Socket/DNS.cpp Normal file
View File

@@ -0,0 +1,75 @@
#include "../../../include/IO/Socket/DNS.h"
#include "../../../include/Log.h"
#if defined(LWE_OS_WINDOWS)
#include <WinSock2.h>
#include <WS2tcpip.h>
#elif defined(LWE_OS_LINUX)
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
namespace lwe
{
Str_8 DNS::Resolve(const AddrType addrType, const Str_8& hostName)
{
#if defined(LWE_OS_WINDOWS)
WSADATA data = {};
Int_32 wsaCode = WSAStartup(MAKEWORD(2, 2), &data);
if (wsaCode)
{
LWE_LOG_INT("Error", 0, "Failed to start WSA with error #" + Str_8::FromNum(wsaCode) + ".");
return {};
}
#endif
addrinfo hints = {};
if (addrType == AddrType::IPV6)
hints.ai_family = AF_INET6;
else if (addrType == AddrType::IPV4)
hints.ai_family = AF_INET;
addrinfo* result = nullptr;
Int_32 code = getaddrinfo(hostName, nullptr, &hints, &result);
if (code)
{
LWE_LOG_INT("Error", 1, "Failed to resolve host with error #" + Str_8::FromNum(code) + ".");
return {};
}
#if defined(LWE_OS_WINDOWS)
if (WSACleanup() == SOCKET_ERROR)
{
LWE_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return {};
}
#endif
if (addrType == AddrType::IPV6)
{
Char_8 ipResult[INET6_ADDRSTRLEN];
inet_ntop(result->ai_family, &((sockaddr_in6*)result->ai_addr)->sin6_addr, ipResult, INET6_ADDRSTRLEN);
freeaddrinfo(result);
return ipResult;
}
else if (addrType == AddrType::IPV4)
{
Char_8 ipResult[INET_ADDRSTRLEN];
inet_ntop(result->ai_family, &((sockaddr_in*)result->ai_addr)->sin_addr, ipResult, INET_ADDRSTRLEN);
freeaddrinfo(result);
return ipResult;
}
return {};
}
}

650
src/IO/Socket/Endpoint.cpp Normal file
View File

@@ -0,0 +1,650 @@
#include "../../../include/IO/Socket/Endpoint.h"
#include "../../../include/IO/Socket/Comms.h"
#include "../../../include/Encryption.h"
#include "../../../include/System/CPU.h"
#if defined(LWE_OS_WINDOWS)
#include <WinSock2.h>
#include <WS2tcpip.h>
#elif defined(LWE_OS_LINUX)
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <cerrno>
#endif
namespace lwe
{
Endpoint::Endpoint()
: hdl(LWE_INVALID_SOCKET), disposition(EndDisp::UNKNOWN), status(Status::PENDING), arch(Architecture::UNKNOWN),
hashId(0), nextSendId(0), nextRecvId(0), port(0), deltaDuration(0.0f), deltaRate(1.0f / 60.0f),
timeout(0.0f), lastPing(0.0f), oldLatency(0.0f), latency(0.0f), queueSlot(0)
{
AddType("Endpoint");
}
Endpoint::Endpoint(Socket hdl, const EndDisp disposition, const Architecture arch, const Str_8& id,
const AddrType& type, const Str_8& address, const UInt_16 port)
: hdl(hdl), disposition(disposition), status(Status::ACTIVE), arch(arch), id(id), hashId(id.Hash_32()), nextSendId(0),
nextRecvId(0), address(address), port(port), deltaDuration(0.0f), deltaRate(1.0f / 60.0f), timeout(0.0f),
lastPing(0.0f), oldLatency(0.0f), latency(0.0f), queueSlot(0)
{
AddType("Endpoint");
}
Endpoint::Endpoint(Socket hdl, const AddrType& type, const Str_8& address, const UInt_16 port)
: hdl(hdl), disposition(EndDisp::UNKNOWN), status(Status::PENDING), arch(Architecture::UNKNOWN), hashId(0),
nextSendId(0), nextRecvId(0), address(address), port(port), deltaDuration(0.0f), deltaRate(1.0f / 60.0f),
timeout(0.0f), lastPing(0.0f), oldLatency(0.0f), latency(0.0f), queueSlot(0)
{
AddType("Endpoint");
}
Endpoint::Endpoint(const Endpoint& end)
: BaseObj(end), hdl(LWE_INVALID_SOCKET), disposition(end.disposition), status(Status::PENDING), arch(end.arch),
id(end.id), hashId(end.hashId), nextSendId(0), nextRecvId(0), address(end.address), port(end.port),
deltaDuration(0.0f), deltaRate(1.0f / 60.0f), timeout(0.0f), lastPing(0.0f),
oldLatency(0.0f), latency(0.0f), queueSlot(0)
{
}
Endpoint& Endpoint::operator=(const Endpoint& end)
{
if (this == &end)
return *this;
BaseObj::operator=(end);
if (status == Status::PENDING)
{
disposition = end.disposition;
status = end.status;
arch = end.arch;
id = end.id;
hashId = end.hashId;
nextSendId = end.nextSendId;
sent = end.sent;
nextRecvId = end.nextRecvId;
received = end.received;
address = end.address;
port = end.port;
deltaDuration = end.deltaDuration;
deltaRate = end.deltaRate;
timeout = end.timeout;
lastPing = end.lastPing;
oldLatency = end.oldLatency;
latency = end.latency;
queueSlot = end.queueSlot;
}
else
{
hdl = LWE_INVALID_SOCKET;
disposition = end.disposition;
status = Status::PENDING;
arch = end.arch;
id = end.id;
hashId = end.hashId;
nextSendId = 0;
sent = Vector<Insurance>();
nextRecvId = 0;
received = Vector<Fragments>();
address = end.address;
port = end.port;
deltaDuration = 0.0f;
deltaRate = 1.0f / 60.0f;
timeout = 0.0f;
lastPing = 0.0f;
oldLatency = 0.0f;
latency = 0.0f;
queueSlot = 0;
}
return *this;
}
void Endpoint::Poll(const float delta)
{
Comms* comms = (Comms*)GetParent();
if (!comms)
{
LWE_LOG_INT("Error", 0, "Endpoint must be a child of a Socket object.");
return;
}
SortReceived();
if (deltaDuration >= deltaRate)
deltaDuration = Math::Mod(deltaDuration, deltaRate);
deltaDuration += delta;
timeout += delta;
latency += delta;
if (sent.Size())
{
for (UInt_64 i = 0; i < sent.Size(); ++i)
{
sent[i].lastResend += delta;
if (sent[i].lastResend >= comms->GetResendRate())
{
Serializer result(Endianness::LE);
result.Write(sent[i].header);
result.WriteSer(sent[i].payload);
if (sent[i].header.encrypted)
Encryption::Encrypt_64(result.Size() - sizeof(bool), &result[sizeof(bool)]);
if (comms->GetAddressType() == AddrType::IPV6)
Send_v6(result);
else if (comms->GetAddressType() == AddrType::IPV4)
Send_v4(result);
sent[i].lastResend = Math::Mod(sent[i].lastResend, comms->GetResendRate());
}
}
}
if (comms->GetDisposition() == EndDisp::SERVICE)
{
lastPing += delta;
if (lastPing >= 1.0f)
Ping(delta);
}
}
EndDisp Endpoint::GetDisposition() const
{
return disposition;
}
void Endpoint::SetStatus(const Status newStatus)
{
status = newStatus;
}
Status Endpoint::GetStatus() const
{
return status;
}
Architecture Endpoint::GetArchitecture() const
{
return arch;
}
Str_8 Endpoint::GetId() const
{
return id;
}
UInt_64 Endpoint::GetHashId() const
{
return hashId;
}
UInt_64 Endpoint::GetNextSendId() const
{
return nextSendId;
}
void Endpoint::Send(const bool deltaLocked, const bool encrypted, const bool ensure, const UInt_64 sys,
const UInt_64 op, const Serializer<>& payload)
{
Comms* comms = (Comms*)GetParent();
if (!comms)
{
LWE_LOG_INT("Error", 0, "Endpoint must be a child of a Socket object.");
return;
}
if (deltaLocked && deltaDuration < deltaRate)
return;
Header header = {
encrypted,
nextSendId++,
1,
0,
ensure,
comms->GetDisposition(),
comms->GetHashId(),
sys,
op
};
if ((comms->GetAddressType() == AddrType::IPV6 && payload.Size() > COMMS_IPV6_PAYLOAD) || (comms->GetAddressType() == AddrType::IPV4 && payload.Size() > COMMS_IPV4_PAYLOAD))
{
Fragments frags = FragmentData(header, payload);
for (UInt_64 i = 0; i < frags.Size(); ++i)
{
Header newHeader = frags.GetHeader();
newHeader.fragment = i;
Send(newHeader, frags[i]);
}
}
else
{
Send(header, payload);
}
}
void Endpoint::Send(const bool deltaLocked, const bool encrypted, const bool ensure, const Str_8& sys,
const Str_8& op, const Serializer<>& payload)
{
Send(deltaLocked, encrypted, ensure, sys.Hash_64(), op.Hash_64(), payload);
}
void Endpoint::RemoveInsurance(const UInt_64 msgId, const UInt_64 fragment)
{
for (UInt_64 i = 0; i < sent.Size(); ++i)
{
if (sent[i].header.id == msgId && sent[i].header.fragment == fragment)
{
sent.Remove(i);
break;
}
}
timeout = 0.0f;
}
UInt_64 Endpoint::GetNextRecvId() const
{
return nextRecvId;
}
void Endpoint::AddReceived(const Header& header, const Serializer<>& payload)
{
Fragments* frags = nullptr;
for (UInt_64 i = 0; i < received.Size(); ++i)
{
if (received[i].GetHeader().id == header.id)
{
if (received[i][header.fragment].Size())
return;
frags = &received[i];
break;
}
}
if (header.id > nextRecvId)
nextRecvId = header.id + 1;
if (frags)
(*frags)[header.fragment] = payload;
else
received.Push({header, payload});
timeout = 0.0f;
}
Vector<Fragments> Endpoint::GetReceived() const
{
return received;
}
Vector<Fragments>* Endpoint::GetReceived()
{
return &received;
}
Str_8 Endpoint::GetAddress() const
{
return address;
}
UInt_16 Endpoint::GetPort() const
{
return port;
}
void Endpoint::SetDeltaRate(const float newDeltaRate)
{
deltaRate = newDeltaRate;
}
float Endpoint::GetDeltaRate() const
{
return deltaRate;
}
float Endpoint::GetTimeout() const
{
return timeout;
}
float Endpoint::GetLastPing() const
{
return lastPing;
}
void Endpoint::Ping(const float delta)
{
Serializer payload(Endianness::LE);
payload.Write(delta);
Send(false, true, false, "Internal", "Ping", payload);
lastPing = 0.0f;
latency = 0.0f;
}
void Endpoint::Pong(const float delta)
{
Serializer payload(Endianness::LE);
payload.Write(delta);
Send(false, true, false, "Internal", "Pong", payload);
timeout = 0.0f;
}
void Endpoint::SendLatency()
{
oldLatency = latency * 1000;
Serializer sPayload(Endianness::LE);
sPayload.Write(oldLatency);
Send(false, true, false, "Internal", "Latency", sPayload);
latency = 0.0f;
timeout = 0.0f;
}
void Endpoint::SetLatency(const float newLatency)
{
oldLatency = newLatency;
}
float Endpoint::GetLatency() const
{
return oldLatency;
}
void Endpoint::SetQueueSlot(const UInt_64 slot)
{
queueSlot = slot;
}
UInt_64 Endpoint::GetQueueSlot() const
{
return queueSlot;
}
Fragments Endpoint::FragmentData(const Header& header, const Serializer<>& data)
{
Comms* comms = (Comms*)GetParent();
if (!comms)
{
LWE_LOG_INT("Error", 0, "Endpoint must be a child of a Socket object.");
return {};
}
Fragments result;
if (comms->GetAddressType() == AddrType::IPV6)
{
UInt_64 frags = data.Size() / COMMS_IPV6_PAYLOAD;
if (data.Size() % COMMS_IPV6_PAYLOAD)
++frags;
result = Fragments(header, frags);
UInt_64 size = COMMS_IPV6_PAYLOAD;
for (UInt_64 i = 0; i < result.Size(); ++i)
{
size = COMMS_IPV6_PAYLOAD;
if (i == result.Size() - 1)
size = data.Size() % COMMS_IPV6_PAYLOAD;
result[i] = {data.GetEndianness(), &data[i * COMMS_IPV6_PAYLOAD], size};
}
}
else if (comms->GetAddressType() == AddrType::IPV4)
{
UInt_64 frags = data.Size() / COMMS_IPV4_PAYLOAD;
if (data.Size() % COMMS_IPV4_PAYLOAD)
++frags;
result = Fragments(header, frags);
UInt_64 size = COMMS_IPV4_PAYLOAD;
for (UInt_64 i = 0; i < result.Size(); ++i)
{
size = COMMS_IPV4_PAYLOAD;
if (i == result.Size() - 1)
size = data.Size() % COMMS_IPV4_PAYLOAD;
result[i] = {data.GetEndianness(), &data[i * COMMS_IPV4_PAYLOAD], size};
}
}
return result;
}
void Endpoint::Send(const Header& header, const Serializer<>& payload)
{
Comms* comms = (Comms*)GetParent();
if (!comms)
{
LWE_LOG_INT("Error", 0, "Endpoint must be a child of a Socket object.");
return;
}
Serializer result(Endianness::LE);
result.Write(header);
result.WriteSer(payload);
if (header.encrypted)
Encryption::Encrypt_64(result.Size() - sizeof(bool), &result[sizeof(bool)]);
if (header.ensure)
sent.Push({header, payload});
if (comms->GetAddressType() == AddrType::IPV6)
Send_v6(result);
else if (comms->GetAddressType() == AddrType::IPV4)
Send_v4(result);
}
bool Endpoint::SortingNeeded() const
{
UInt_64 lastPacket = 0;
for (UInt_64 i = 0; i < received.Size(); ++i)
{
if (received[i].GetHeader().id < lastPacket)
return true;
else
lastPacket = received[i].GetHeader().id;
}
return false;
}
void Endpoint::SortReceived()
{
if (!SortingNeeded())
return;
Vector<Fragments> sorted(0, received.Stride());
for (UInt_64 a = 0; a < received.Size(); ++a)
{
if (sorted.Size())
{
for (UInt_64 b = sorted.Size(); b; --b)
{
if (received[a].GetHeader().id > sorted[b - 1].GetHeader().id)
{
if (b == sorted.Size())
sorted.Push(received[a]);
else
sorted.Insert(b, received[a]);
break;
}
else
{
sorted.Insert(b - 1, received[a]);
break;
}
}
}
else
{
sorted.Push(received[a]);
}
}
received = sorted;
}
UInt_16 Endpoint::Send_v6(const Serializer<>& payload)
{
if (hdl == LWE_INVALID_SOCKET)
{
LWE_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
if (payload.Size() > LWE_IPV6_UDP_PAYLOAD)
{
LWE_LOG_INT("Info", 1, "Attempted to send a packet with the size, \"" + Str_8::FromNum(payload.Size())
+ "\", that exceeds the max payload of, \"" + Str_8::FromNum(LWE_IPV6_UDP_PAYLOAD) + "\".");
return 0;
}
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
Int_32 code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
LWE_LOG_INT("Error", 2, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = 0;
#if defined(LWE_OS_WINDOWS)
dCode = WSAGetLastError();
#elif defined(LWE_OS_LINUX)
dCode = errno;
#endif
LWE_LOG_INT("Error", 3, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
Int_32 sent = sendto(hdl, (char*)&payload[0], (int)payload.Size(), 0, (sockaddr*)&result, sizeof(sockaddr_in6));
#if defined(LWE_OS_WINDOWS)
if (sent == SOCKET_ERROR)
#elif defined(LWE_OS_LINUX)
if (sent == -1)
#endif
{
Int_32 dCode = 0;
#if defined(LWE_OS_WINDOWS)
code = WSAGetLastError();
#elif defined(LWE_OS_LINUX)
code = errno;
#endif
LWE_LOG_INT("Error", 4, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
((Comms*)GetParent())->UnInitialize();
return 0;
}
return (UInt_16)sent;
}
UInt_16 Endpoint::Send_v4(const Serializer<>& payload)
{
if (hdl == LWE_INVALID_SOCKET)
{
LWE_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
if (payload.Size() > LWE_IPV4_UDP_PAYLOAD)
{
LWE_LOG_INT("Info", 1, "Attempted to send a packet with the size, \"" + Str_8::FromNum(payload.Size())
+ "\", that exceeds the max payload of, \"" + Str_8::FromNum(LWE_IPV4_UDP_PAYLOAD) + "\".");
return 0;
}
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
LWE_LOG_INT("Error", 2, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
#if defined(LWE_OS_WINDOWS)
Int_32 dCode = WSAGetLastError();
#elif defined(LWE_OS_LINUX)
Int_32 dCode = errno;
#else
Int_32 dCode = 0;
#endif
LWE_LOG_INT("Error", 2, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
SInt_64 sent = sendto(hdl, (char*)&payload[0], (int)payload.Size(), 0, (sockaddr*)&result, sizeof(sockaddr_in));
#if defined(LWE_OS_WINDOWS)
if (sent == SOCKET_ERROR)
#elif defined(LWE_OS_LINUX)
if (sent == -1)
#endif
{
#if defined(LWE_OS_WINDOWS)
Int_32 dCode = WSAGetLastError();
if (dCode != WSAEWOULDBLOCK)
{
LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
((Comms*)GetParent())->UnInitialize();
}
#elif defined(LWE_OS_LINUX)
Int_32 dCode = errno;
if (dCode != EWOULDBLOCK)
{
LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
((Comms*)GetParent())->UnInitialize();
}
#else
Int_32 dCode = 0;
#endif
return 0;
}
return (UInt_16)sent;
}
}

100
src/IO/Socket/Fragments.cpp Normal file
View File

@@ -0,0 +1,100 @@
#include "../../../include/IO/Socket/Fragments.h"
namespace lwe
{
Fragments::~Fragments()
{
delete[] data;
}
Fragments::Fragments()
: header{}, data(nullptr), size(0)
{
}
Fragments::Fragments(const Header& header, const Serializer<>& payload)
: header(header), data(new Serializer<>[header.fragments]), size(header.fragments)
{
this->header.fragment = 0;
data[header.fragment] = payload;
}
Fragments::Fragments(const Header& header, const UInt_64 size)
: header(header), data(new Serializer<>[size]), size(size)
{
this->header.fragments = size;
this->header.fragment = 0;
}
Fragments::Fragments(const Fragments& frags)
: header(frags.header), data(new Serializer<>[frags.size]), size(frags.size)
{
for (UInt_64 i = 0; i < size; ++i)
data[i] = frags.data[i];
}
Fragments& Fragments::operator=(const Fragments& frags)
{
if (this == &frags)
return *this;
header = frags.header;
delete[] data;
data = new Serializer<>[frags.size];
for (UInt_64 i = 0; i < frags.size; ++i)
data[i] = frags.data[i];
size = frags.size;
return *this;
}
Fragments::operator const Serializer<>* () const
{
return data;
}
Fragments::operator Serializer<>* ()
{
return data;
}
Header Fragments::GetHeader() const
{
return header;
}
UInt_64 Fragments::Size() const
{
return size;
}
bool Fragments::IsComplete() const
{
for (UInt_64 i = 0; i < size; ++i)
if (!data[i].Size())
return false;
return true;
}
Packet Fragments::Combine() const
{
UInt_64 rSize = 0;
for (UInt_64 i = 0; i < size; ++i)
rSize += data[i].Size();
Packet result =
{
header,
{Endianness::LE, rSize}
};
result.header.fragments = 0;
for (UInt_64 i = 0; i < size; ++i)
result.payload.WriteSer(data[i]);
result.payload.SetOffset(0);
return result;
}
}

View File

@@ -0,0 +1,47 @@
#include "../../../include/IO/Socket/Operation.h"
#include "../../../include/IO/Socket/CommsSystem.h"
#include "../../../include/IO/Socket/Comms.h"
#include "../../../include/IO/Socket/Endpoint.h"
namespace lwe
{
Operation::Operation()
: hashId(0)
{
}
Operation::Operation(const Str_8& id)
: id(id), hashId(id.Hash_64())
{
}
Operation::Operation(const Operation& cmd)
: id(cmd.id), hashId(cmd.hashId)
{
}
Operation& Operation::operator=(const Operation& cmd)
{
if (this == &cmd)
return *this;
id = cmd.id;
hashId = cmd.hashId;
return *this;
}
void Operation::Process(Comms* comms, Endpoint* endpoint, CommsSystem* sys, Serializer<>& payload)
{
}
Str_8 Operation::GetId() const
{
return id;
}
UInt_64 Operation::GetHashId() const
{
return hashId;
}
}

337
src/IO/Socket/Request.cpp Normal file
View File

@@ -0,0 +1,337 @@
#include "../../../include/IO/Socket/Request.h"
#include "../../../include/Base64.h"
namespace lwe
{
Request::Request()
: verb(Verb::GET), cType(ContentType::NONE)
{
}
Request::Request(const Verb verb, const Str_8& rsrc)
: verb(verb), rsrc(rsrc), cType(ContentType::NONE)
{
}
Request::Request(const char* data, const UInt_64 size)
: verb(Verb::POST), cType(ContentType::NONE)
{
ReadData(Str_8(data, size));
}
Request::Request(const Str_8& data)
: verb(Verb::POST), cType(ContentType::NONE)
{
ReadData(data);
}
Request& Request::operator=(const Request &req)
{
if (this == &req)
return *this;
verb = req.verb;
rsrc = req.rsrc;
queries = req.queries;
header = req.header;
cType = req.cType;
body = req.body;
return* this;
}
Verb Request::GetVerb() const
{
return verb;
}
void Request::SetContentType(const ContentType cType)
{
if (body.Size())
body.Resize(0);
this->cType = cType;
}
ContentType Request::GetContentType() const
{
return cType;
}
void Request::SetResource(const Str_8& rsrc)
{
this->rsrc = rsrc;
}
Str_8 Request::GetResource() const
{
return rsrc;
}
void Request::AddQuery(const Str_8& var, const Str_8& value)
{
queries.Push(var + "=" + value);
}
Str_8 Request::GetQuery(const Str_8& var)
{
for (UInt_64 i = 0; i < queries.Size(); ++i)
{
Vector<Str_8> data = queries[i].Split("=");
if (data[0] == var)
return data[1];
}
return "";
}
Vector<Str_8> Request::GetQueries() const
{
return queries;
}
void Request::BasicAuth(const Str_8& id, const Str_8& secret)
{
AddToHeader("Authorization", Str_8("Basic ") + Base64::Encode(id + ":" + secret));
}
void Request::BearerAuth(const Str_8& token)
{
AddToHeader("Authorization", "Bearer " + token);
}
void Request::BearerAuth(const Str_8& token, const Str_8& clientId)
{
AddToHeader("Authorization", "Bearer " + token);
AddToHeader("Client-Id", clientId);
}
void Request::BotAuth(const Str_8& token)
{
AddToHeader("Authorization", "Bot " + token);
}
void Request::AddToHeader(const Str_8& var, const Str_8& value)
{
header.Push(var + ": " + value);
}
Str_8 Request::GetHeader(const Str_8& var) const
{
for (UInt_64 i = 0; i < header.Size(); ++i)
{
Vector<Str_8> data = header[i].Split(": ");
if (data[0] == var)
return data[1];
}
return "";
}
Vector<Str_8> Request::GetHeader() const
{
return header;
}
void Request::AddToBody(const Str_8& var, const Str_8& value)
{
if (body.Size())
{
if (cType == ContentType::APP_FORMURLENCODED)
body.Push('&');
}
body += var;
if (cType == ContentType::APP_FORMURLENCODED)
body += "=";
body += value;
}
void Request::AddToBody(const Str_8& data)
{
if (body.Size())
{
if (cType == ContentType::APP_FORMURLENCODED)
body.Push('&');
}
body += data;
}
void Request::SetBody(const Str_8& body)
{
this->body = body;
}
Str_8 Request::GetVar(const Str_8& var) const
{
Vector<Str_8> vars;
if (cType == ContentType::APP_FORMURLENCODED)
vars = body.Split("&");
for (UInt_64 i = 0; i < vars.Size(); ++i)
{
Vector<Str_8> data = vars[i].Split("=");
if (data[0] == var)
return data[1];
}
return "";
}
Str_8 Request::GetBody() const
{
return body;
}
Json Request::GetJson() const
{
return {body, 5};
}
Str_8 Request::FormResult() const
{
Str_8 result = VerbToStr(verb) + " " + rsrc;
if (queries.Size())
result += "?" + queries[0];
for (UInt_64 i = 1; i < queries.Size(); ++i)
result += "&" + queries[i];
result += " HTTP/1.1\r\n";
for (UInt_64 i = 0; i < header.Size(); ++i)
{
result += header[i] + "\r\n";
}
result += "Content-Type: " + ContentTypeToStr(cType) + "\r\n";
if (verb == Verb::GET)
result += "\r\n";
else
result += "Content-Length: " + Str_8::FromNum(body.Size()) + "\r\n\r\n" + body;
return result;
}
bool Request::IsValid() const
{
return rsrc.Size() || queries.Size() || header.Size() || body.Size();
}
Str_8 Request::VerbToStr(const Verb verb)
{
switch (verb)
{
case Verb::POST:
return "POST";
case Verb::GET:
return "GET";
case Verb::PUT:
return "PUT";
case Verb::DEL:
return "DELETE";
default:
return "";
}
}
Str_8 Request::ContentTypeToStr(const ContentType cType)
{
switch (cType)
{
case ContentType::APP_MULTIPART_FORMDATA:
return "multipart/form-data";
case ContentType::APP_FORMURLENCODED:
return "application/x-www-form-urlencoded";
case ContentType::APP_JAVASCRIPT:
return "application/javascript";
case ContentType::APP_JSON:
return "application/json";
case ContentType::APP_XML:
return "application/xml";
case ContentType::TEXT_PLAIN:
return "text/plain";
case ContentType::TEXT_HTML:
return "text/html";
case ContentType::TEXT_XML:
return "text/xml";
default:
return "";
}
}
ContentType Request::StrToContentType(const Str_8& value)
{
if (value == "multipart/form-data")
return ContentType::APP_MULTIPART_FORMDATA;
else if (value == "application/x-www-form-urlencoded")
return ContentType::APP_FORMURLENCODED;
else if (value == "application/javascript")
return ContentType::APP_JAVASCRIPT;
else if (value == "application/json")
return ContentType::APP_JSON;
else if (value == "application/xml")
return ContentType::APP_XML;
else if (value == "text/plain")
return ContentType::TEXT_PLAIN;
else if (value == "text/html")
return ContentType::TEXT_HTML;
else if (value == "text/xml")
return ContentType::TEXT_XML;
else
return ContentType::NONE;
}
void Request::ReadData(const Str_8& data)
{
Vector<Str_8> lines = data.Split("\r\n");
Vector<Str_8> meta = lines[0].Split(" ");
if (meta[0] == "POST")
verb = Verb::POST;
else if (meta[0] == "GET")
verb = Verb::GET;
else if (meta[0] == "PUT")
verb = Verb::PUT;
UInt_64 queryIndex = 0;
if (meta[1].Find("?", &queryIndex))
{
rsrc = meta[1].Sub(0, queryIndex);
cType = ContentType::APP_FORMURLENCODED;
queries = meta[1].Sub(queryIndex + 1).Split("&");
}
else
{
rsrc = meta[1];
}
for (UInt_64 i = 1; i < lines.Size(); ++i)
{
if (!lines[i].Size())
break;
Vector<Str_8> var = lines[i].Split(": ");
if (var[0] == "Content-Type")
{
cType = StrToContentType(var[1]);
continue;
}
if (var[0] == "Content-Length")
continue;
header.Push(lines[i]);
}
}
}

403
src/IO/Socket/Response.cpp Normal file
View File

@@ -0,0 +1,403 @@
#include "../../../include/IO/Socket/Response.h"
namespace lwe
{
Response::Response(const UInt_32 code, const Str_8& server)
: code(code), server(server), cType(ContentType::NONE)
{
}
Response::Response(const char* data, const UInt_64 size)
: code(0), cType(ContentType::NONE)
{
ReadData(Str_8(data, size));
}
Response::Response(const Str_8& data)
: code(0), cType(ContentType::NONE)
{
ReadData(data);
}
Response::Response()
: code(0), cType(ContentType::NONE)
{
}
Response& Response::operator=(const Response& res)
{
if (this == &res)
return *this;
code = res.code;
server = res.server;
cType = res.cType;
header = res.header;
body = res.body;
return *this;
}
void Response::SetCode(const UInt_32 code)
{
this->code = code;
}
UInt_32 Response::GetCode() const
{
return code;
}
void Response::SetServer(const Str_8& server)
{
this->server = server;
}
Str_8 Response::GetServer() const
{
return server;
}
void Response::SetContentType(const ContentType cType)
{
this->cType = cType;
}
ContentType Response::GetContentType() const
{
return cType;
}
void Response::AddToHeader(const Str_8& var, const Str_8& value)
{
header.Push(var + ": " + value);
}
Str_8 Response::GetHeader(const Str_8& var) const
{
Str_8 lIdentity = var.GetLower();
for (UInt_64 i = 0; i < header.Size(); ++i)
{
Vector<Str_8> data = header[i].Split(": ");
if (data[0].GetLower() == lIdentity)
return data[1];
}
return "";
}
Vector<Str_8> Response::GetHeader() const
{
return header;
}
void Response::AddToBody(const Str_8& var, const Str_8& value)
{
if (body.Size())
{
if (cType == ContentType::APP_FORMURLENCODED)
body.Push('&');
}
body += var;
if (cType == ContentType::APP_FORMURLENCODED)
body += "=";
body += value;
}
void Response::AddToBody(const Str_8& data)
{
if (body.Size())
{
if (cType == ContentType::APP_FORMURLENCODED)
body.Push('&');
}
body += data;
}
void Response::SetBody(const Str_8& body)
{
this->body = body;
}
Str_8 Response::GetVar(const Str_8& var) const
{
Vector<Str_8> vars;
if (cType == ContentType::APP_FORMURLENCODED)
vars = body.Split("&");
for (UInt_64 i = 0; i < vars.Size(); ++i)
{
Vector<Str_8> data = vars[i].Split("=");
if (data[0] == var)
return data[1];
}
return "";
}
Str_8 Response::GetBody() const
{
return body;
}
Json Response::GetJson() const
{
return {body, 5};
}
Str_8 Response::FormResult() const
{
Str_8 result = "HTTP/1.1 " + Str_8::FromNum(code) + " " + CodeToStr(code) + "\r\nServer: " + server + "\r\n";
for (UInt_64 i = 0; i < header.Size(); ++i)
{
if (header[i].Find("Content-Length", nullptr, SearchPattern::LEFT_RIGHT, IndexResult::ENDING))
continue;
else if (header[i].Find("Server", nullptr, SearchPattern::LEFT_RIGHT, IndexResult::ENDING))
continue;
else if (header[i].Find("Content-Type", nullptr, SearchPattern::LEFT_RIGHT, IndexResult::ENDING))
continue;
result += header[i] + "\r\n";
}
result += "Content-Type: " + ContentTypeToStr(cType) + "\r\nContent-Length: " + Str_8::FromNum(body.Size()) + "\r\n\r\n" + body;
return result;
}
bool Response::IsValid() const
{
return server.Size() || header.Size() || body.Size();
}
Str_8 Response::CodeToStr(const UInt_32 code)
{
if (code == 100)
return "Continue";
else if (code == 101)
return "Switching Protocols";
else if (code == 102)
return "Processing (WebDAV)";
else if (code == 200)
return "OK";
else if (code == 201)
return "Created";
else if (code == 202)
return "Accepted";
else if (code == 203)
return "Non-Authoritative Information";
else if (code == 204)
return "No Content";
else if (code == 205)
return "Reset Content";
else if (code == 206)
return "Partial Content";
else if (code == 207)
return "Multi-Status (WebDAV)";
else if (code == 208)
return "Already Reported (WebDAV)";
else if (code == 226)
return "IM Used";
else if (code == 300)
return "Multiple Choices";
else if (code == 301)
return "Moved Permanently";
else if (code == 302)
return "Found";
else if (code == 303)
return "See Others";
else if (code == 304)
return "Not Modified";
else if (code == 305)
return "Use Proxy";
else if (code == 306)
return "(Unused)";
else if (code == 307)
return "Temporary Redirect";
else if (code == 308)
return "Permanent Redirect (experimental)";
else if (code == 400)
return "Bad Request";
else if (code == 401)
return "Unauthorized";
else if (code == 402)
return "Payment Required";
else if (code == 403)
return "Forbidden";
else if (code == 404)
return "Not Found";
else if (code == 405)
return "Method Not Allowed";
else if (code == 406)
return "Not Acceptable";
else if (code == 407)
return "Proxy Authentication Required";
else if (code == 408)
return "Request Timeout";
else if (code == 409)
return "Conflict";
else if (code == 410)
return "Gone";
else if (code == 411)
return "Length Required";
else if (code == 412)
return "Precondition Failed";
else if (code == 413)
return "Request Entity Too Large";
else if (code == 414)
return "Request-URI Too Long";
else if (code == 415)
return "Unsupported Media Type";
else if (code == 416)
return "Requested Range Not Satisfiable";
else if (code == 417)
return "Expectation Failed";
else if (code == 418)
return "I'm a teapot (RFC 2324)";
else if (code == 420)
return "Enhance Your Calm (Twitter)";
else if (code == 422)
return "Unprocessable Entity (WebDAV)";
else if (code == 423)
return "Locked (WebDAV)";
else if (code == 424)
return "Failed Dependency (Nginx)";
else if (code == 425)
return "Reserved for WebDAV";
else if (code == 426)
return "Upgrade Required";
else if (code == 428)
return "Precondition Required";
else if (code == 429)
return "Too Many Requests";
else if (code == 431)
return "Request Header Fields Too Large";
else if (code == 444)
return "No Response (Nginx)";
else if (code == 449)
return "Retry With (Microsoft)";
else if (code == 450)
return "Blocked by Windows Parental Controls (Microsoft)";
else if (code == 451)
return "Unavailable For Legal Reasons";
else if (code == 499)
return "Client Closed Request (Nginx)";
else if (code == 500)
return "Internal Server Error";
else if (code == 501)
return "Not Implemented";
else if (code == 502)
return "Bad Gateway";
else if (code == 503)
return "Service Unavailable";
else if (code == 504)
return "Gateway Timeout";
else if (code == 505)
return "HTTP Version Not Supported";
else if (code == 506)
return "Variant Also Negotiates (Experimental)";
else if (code == 507)
return "Insufficient Storage (WebDAV)";
else if (code == 508)
return "Loop Detected (WebDAV)";
else if (code == 509)
return "Bandwidth Limit Exceeded (Apache)";
else if (code == 510)
return "Not Extended";
else if (code == 511)
return "Network Authentication Required";
else if (code == 598)
return "Network read timeout error";
else if (code == 599)
return "Network connect timeout error";
else
return "Unused Status Code";
}
Str_8 Response::ContentTypeToStr(const ContentType cType)
{
switch (cType)
{
case ContentType::APP_MULTIPART_FORMDATA:
return "multipart/form-data";
case ContentType::APP_FORMURLENCODED:
return "application/x-www-form-urlencoded";
case ContentType::APP_JAVASCRIPT:
return "application/javascript";
case ContentType::APP_JSON:
return "application/json";
case ContentType::APP_XML:
return "application/xml";
case ContentType::TEXT_PLAIN:
return "text/plain";
case ContentType::TEXT_HTML:
return "text/html";
case ContentType::TEXT_XML:
return "text/xml";
default:
return "";
}
}
ContentType Response::StrToContentType(const Str_8& value)
{
if (value == "multipart/form-data")
return ContentType::APP_MULTIPART_FORMDATA;
else if (value == "application/x-www-form-urlencoded")
return ContentType::APP_FORMURLENCODED;
else if (value == "application/javascript")
return ContentType::APP_JAVASCRIPT;
else if (value == "application/json")
return ContentType::APP_JSON;
else if (value == "application/xml")
return ContentType::APP_XML;
else if (value == "text/plain")
return ContentType::TEXT_PLAIN;
else if (value == "text/html")
return ContentType::TEXT_HTML;
else if (value == "text/xml")
return ContentType::TEXT_XML;
else
return ContentType::NONE;
}
void Response::ReadData(const Str_8& data)
{
Vector<Str_8> lines = data.Split("\r\n");
Vector<Str_8> meta = lines[0].Split(" ");
code = meta[1].ToDecimal<UInt_32>();
for (UInt_64 i = 1; i < lines.Size(); ++i)
{
if (!lines[i].Size())
break;
Vector<Str_8> var = lines[i].Split(": ");
if (var[0].GetLower() == "server")
{
server = var[1];
continue;
}
else if (var[0].GetLower() == "content-type")
{
Vector<Str_8> ctData = var[1].Split(";");
cType = StrToContentType(ctData[0].GetLower());
continue;
}
header.Push(lines[i]);
}
}
}

View File

@@ -0,0 +1,653 @@
#include "../../../../include/IO/Socket/RestAPIs/Spotify.h"
#include "../../../../include/IO/Socket/DNS.h"
#include "../../../../include/System/System.h"
#include "../../../../include/URI.h"
namespace lwe
{
const Str_8 Spotify::trackUriPrefix = "https://open.spotify.com/track/";
Spotify::~Spotify()
{
client.Release();
}
Spotify::Spotify()
: forceVerify(false)
{
}
Spotify::Spotify(const Str_8& clientId, const Str_8& secret, const Str_8& redURI, const Array<Str_8>& scopes, const bool forceVerify)
: client(AddrType::IPV4), clientId(clientId), secret(secret), redURI(redURI), scopes(scopes), forceVerify(forceVerify)
{
}
bool Spotify::Authorize()
{
Str_8 scopesFinal;
for (UInt_64 i = 0; i < scopes.Size(); ++i)
{
scopesFinal += scopes[i];
if (i < scopes.Size() - 1)
scopesFinal += "%20";
}
Str_8 rURI = URI::Encode(redURI);
Str_8 uri = "https://accounts.spotify.com/authorize?client_id=" + clientId + "&redirect_uri=" + rURI +
"&response_type=code&show_dialog=" + (forceVerify ? "true" : "false") + "&scope=" +
scopesFinal;
TCP server(AddrType::IPV4);
server.Initialize();
server.Bind(DNS::Resolve(server.GetAddressType(), "localhost"), 65534);
server.Listen();
System::OpenURI(uri);
TCP* cbClient = server.Accept();
Request cbReq = cbClient->RecvReq();
if (cbReq.GetResource() != "/callback")
{
Response resp(423, "Event Horizon");
resp.SetContentType(ContentType::TEXT_HTML);
resp.SetBody("<!DOCTYPE html><html><head><title>LWE Response</title><link rel=\"icon\" type=\"image/png\" href=\"https://cdn3.iconfinder.com/data/icons/contour-animals-2/512/wolf-512.png\" /></head><body>Hostile Information Received</body></html>");
cbClient->SendRes(resp);
cbClient->Release();
return false;
}
Response resp(200, "Event Horizon");
resp.SetContentType(ContentType::TEXT_HTML);
resp.SetBody("<!DOCTYPE html><html><head><title>LWE Response</title><link rel=\"icon\" type=\"image/png\" href=\"https://cdn3.iconfinder.com/data/icons/contour-animals-2/512/wolf-512.png\" /></head><body>Authentication Successful</body></html>");
cbClient->SendRes(resp);
cbClient->Release();
server.Release();
SSL accounts(AddrType::IPV4);
accounts.Initialize();
accounts.Connect("accounts.spotify.com", SSL::HTTPS_Port);
Request authReq(Verb::POST, "/api/token");
authReq.SetContentType(ContentType::APP_FORMURLENCODED);
authReq.BasicAuth(clientId, secret);
authReq.AddToBody("grant_type", "authorization_code");
authReq.AddToBody("code", cbReq.GetQuery("code"));
authReq.AddToBody("redirect_uri", rURI);
accounts.SendReq(authReq);
Response authRes = accounts.RecvRes();
accounts.Release();
if (authRes.GetCode() == 400)
{
LWE_LOG_INT("Error", 0, "Could not authorize with Spotify because the client id was invalid.");
return false;
}
else if (authRes.GetCode() == 403)
{
LWE_LOG_INT("Error", 1, "Could not authorize with Spotify because the secret was invalid.");
return false;
}
else if (authRes.GetCode() != 200)
{
LWE_LOG_INT("Error", 2, "Could not authorize with Spotify with code " + Str_8::FromNum(authRes.GetCode()) + ".");
return false;
}
Json authResJson = authRes.GetJson();
JsonObj* value = (JsonObj*)authResJson.GetValue();
if (!value)
return false;
JsonVar* tokenVar = value->GetVar("access_token");
if (!tokenVar)
return false;
JsonVar* rTokenVar = value->GetVar("refresh_token");
if (!rTokenVar)
return false;
token = ((JsonStr*)tokenVar->GetValue())->value;
rToken = ((JsonStr*)rTokenVar->GetValue())->value;
return true;
}
UInt_32 Spotify::SetVolume(const UInt_8 level)
{
StartConnection();
Request req(Verb::PUT, "/v1/me/player/volume");
req.AddQuery("volume_percent", Str_8::FromNum(level));
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::Play()
{
StartConnection();
Request req(Verb::PUT, "/v1/me/player/play");
req.BearerAuth(token);
client.Release();
client.Initialize();
client.Connect("", SSL::HTTPS_Port);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::Pause()
{
StartConnection();
Request req(Verb::PUT, "/v1/me/player/pause");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::SetRepeat(const SpotifyState state)
{
StartConnection();
Str_8 result;
switch (state)
{
case SpotifyState::TRACK:
result = "track";
break;
case SpotifyState::CONTEXT:
result = "context";
break;
case SpotifyState::OFF:
result = "off";
break;
}
Request req(Verb::PUT, "/v1/me/player/repeat");
req.AddQuery("state", result);
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::SetShuffle(const bool state)
{
StartConnection();
Request req(Verb::PUT, "/v1/me/player/repeat");
req.AddQuery("state", state ? "true" : "false");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::SearchTrack(Vector<Str_8>& artists, Str_8& id, Str_8& name)
{
StartConnection();
Request req(Verb::GET, "/v1/search");
Str_8 q = "artist%3A";
for (UInt_64 i = 0; i < artists.Size(); ++i)
{
q += artists[i].ReplaceAll(" ", "+");
if (i != artists.Size() - 1)
q += "%2C+";
}
q += "+track%3A" + name.ReplaceAll(" ", "+");
req.AddQuery("q", q);
req.AddQuery("type", "track");
req.AddQuery("limit", "1");
req.AddQuery("offset", "0");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return SearchTrack(artists, name, id);
}
Json body = res.GetJson();
JsonNum* total = (JsonNum*)body.RetrieveValue("tracks.total");
if (!total || total->value == 0.0f)
return 0;
JsonObj* item = (JsonObj*)body.RetrieveValue("tracks.items[0]");
if (!item)
return 0;
JsonVar* artistsVar = item->GetVar("artists");
if (!artistsVar)
return 0;
JsonArray* artistsArray = (JsonArray*)artistsVar->GetValue();
if (!artistsArray)
return 0;
JsonVar* trackIdVar = item->GetVar("id");
if (!trackIdVar)
return 0;
JsonStr* trackIdValue = (JsonStr*)trackIdVar->GetValue();
if (!trackIdValue)
return 0;
JsonVar* trackNameVar = item->GetVar("name");
if (!trackNameVar)
return 0;
JsonStr* trackNameValue = (JsonStr*)trackNameVar->GetValue();
if (!trackNameValue)
return 0;
artists.Resize(artistsArray->Size());
for (UInt_64 i = 0; i < artistsArray->Size(); ++i)
{
JsonObj* artistObj = (JsonObj*)(*artistsArray)[i];
JsonVar* artistNameVar = artistObj->GetVar("name");
JsonStr* artistNameValue = (JsonStr*)artistNameVar->GetValue();
artists[i] = artistNameValue->value;
}
id = trackIdValue->value;
name = trackNameValue->value;
return res.GetCode();
}
UInt_32 Spotify::GetPlayingTrack(Vector<Str_8>& artists, Str_8& id, Str_8& name)
{
StartConnection();
Request req(Verb::GET, "/v1/me/player/currently-playing");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return GetPlayingTrack(artists, id, name);
}
Json result = res.GetJson();
JsonObj* itemObj = (JsonObj*)result.RetrieveValue("item");
if (!itemObj)
return {};
JsonVar* artistsVar = itemObj->GetVar("artists");
if (!artistsVar)
return 0;
JsonArray* artistsArray = (JsonArray*)artistsVar->GetValue();
if (!artistsArray)
return 0;
JsonVar* trackIdVar = itemObj->GetVar("id");
if (!trackIdVar)
return 0;
JsonStr* trackIdValue = (JsonStr*)trackIdVar->GetValue();
if (!trackIdValue)
return 0;
JsonVar* trackNameVar = itemObj->GetVar("name");
if (!trackNameVar)
return 0;
JsonStr* trackNameValue = (JsonStr*)trackNameVar->GetValue();
if (!trackNameValue)
return 0;
artists.Resize(artistsArray->Size());
for (UInt_64 i = 0; i < artists.Size(); ++i)
{
JsonObj* artistObj = (JsonObj*)(*artistsArray)[i];
JsonVar* artistNameVar = artistObj->GetVar("name");
JsonStr* artistNameValue = (JsonStr*)artistNameVar->GetValue();
artists[i] = artistNameValue->value;
}
id = trackIdValue->value;
name = trackNameValue->value;
return res.GetCode();
}
UInt_32 Spotify::GetQueue(Array<Track>& tracks)
{
StartConnection();
Request req(Verb::GET, "/v1/me/player/queue");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return GetQueue(tracks);
}
Json json = res.GetJson();
JsonObj* root = (JsonObj*)json.GetValue();
JsonVar* currentVar = root->GetVar("currently_playing");
if (!currentVar->GetValue())
return res.GetCode();
JsonObj* currentObj = (JsonObj*)currentVar->GetValue();
JsonArray* cArtists = (JsonArray*)currentObj->GetVar("artists")->GetValue();
JsonArray* queue = (JsonArray*)root->GetVar("queue")->GetValue();
tracks.Resize(queue->Size() + 1);
tracks[0].artists.Resize(cArtists->Size());
for (UInt_64 i = 0; i < cArtists->Size(); ++i)
tracks[0].artists[i] = ((JsonStr*)((JsonObj*)(*cArtists)[i])->GetVar("name")->GetValue())->value;
tracks[0].id = ((JsonStr*)currentObj->GetVar("id")->GetValue())->value;
tracks[0].name = ((JsonStr*)currentObj->GetVar("name")->GetValue())->value;
for (UInt_64 i = 1; i < queue->Size(); ++i)
{
JsonObj* trackObj = (JsonObj*)(*queue)[i - 1];
JsonArray* artists = (JsonArray*)trackObj->GetVar("artists")->GetValue();
tracks[i].artists.Resize(artists->Size());
for (UInt_64 a = 0; a < artists->Size(); ++a)
tracks[i].artists[a] = ((JsonStr*)((JsonObj*)(*artists)[a])->GetVar("name")->GetValue())->value;
tracks[i].id = ((JsonStr*)trackObj->GetVar("id")->GetValue())->value;
tracks[i].name = ((JsonStr*)trackObj->GetVar("name")->GetValue())->value;
}
return res.GetCode();
}
UInt_32 Spotify::QueueTrack(const Str_8& id)
{
StartConnection();
Request req(Verb::POST, "/v1/me/player/queue");
req.AddQuery("uri", "spotify:track:" + id);
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return QueueTrack(id);
}
return res.GetCode();
}
UInt_32 Spotify::AddTracks(const Str_8& playlistId, const Array<Str_8>& trackIds, const UInt_32 pos)
{
StartConnection();
JsonObj obj(0);
JsonArray tracks(trackIds.Size(), 0);
for (UInt_64 i = 0; i < trackIds.Size(); ++i)
tracks[i] = (JsonBase*)new JsonStr("spotify:track:" + trackIds[i]);
obj.AddVar({"uris", tracks});
obj.AddVar({"position", (float)pos});
Json json(obj);
Request req(Verb::POST, "/v1/playlists/" + playlistId + "/tracks");
req.BearerAuth(token);
req.SetContentType(ContentType::APP_JSON);
req.SetBody(json.ToStr(true));
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return AddTracks(playlistId, trackIds, pos);
}
return res.GetCode();
}
UInt_32 Spotify::AddTrack(const Str_8& playlistId, const Str_8& trackId, const UInt_32 pos)
{
StartConnection();
Request req(Verb::POST, "/v1/playlists/" + playlistId + "/tracks");
req.AddQuery("position", Str_8::FromNum(pos));
req.AddQuery("uris", "spotify:track:" + trackId);
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return AddTrack(playlistId, trackId, pos);
}
return res.GetCode();
}
UInt_32 Spotify::Skip()
{
StartConnection();
Request req(Verb::POST, "/v1/me/player/next");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Skip();
}
return res.GetCode();
}
UInt_32 Spotify::Previous()
{
StartConnection();
Request req(Verb::POST, "/v1/me/player/previous");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::Seek(const UInt_32 pos)
{
StartConnection();
Request req(Verb::PUT, "/v1/me/player/seek");
req.AddQuery("position_ms", Str_8::FromNum(pos));
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Seek(pos);
}
return res.GetCode();
}
void Spotify::StartConnection()
{
client.Release();
client.Initialize();
client.Connect("api.spotify.com", SSL::HTTPS_Port);
}
bool Spotify::ReAuthorize()
{
SSL accounts;
accounts.Initialize();
accounts.Connect("accounts.spotify.com", SSL::HTTPS_Port);
Request reAuth(Verb::POST, "/api/token");
reAuth.SetContentType(ContentType::APP_FORMURLENCODED);
reAuth.BasicAuth(clientId, secret);
reAuth.AddToBody("grant_type", "refresh_token");
reAuth.AddToBody("refresh_token", rToken);
accounts.SendReq(reAuth);
Response res = accounts.RecvRes();
accounts.Release();
if (res.GetCode() != 200)
{
LWE_LOG_INT("Error", 0, "Failed to reauthorize with Spotify with code #" + Str_8::FromNum(res.GetCode()) + ".");
client.Release();
return false;
}
Json json = res.GetJson();
JsonObj* obj = (JsonObj*)json.GetValue();
JsonVar* tokenVar = obj->GetVar("access_token");
if (!tokenVar)
return false;
token = ((JsonStr*)tokenVar->GetValue())->value;
return true;
}
bool Spotify::IsActive() const
{
return client.IsConnected();
}
Str_8 Spotify::GetClientId() const
{
return clientId;
}
Str_8 Spotify::GetSecret() const
{
return secret;
}
Str_8 Spotify::GetRedURI() const
{
return redURI;
}
bool Spotify::IsVerificationForced() const
{
return forceVerify;
}
}

View File

@@ -0,0 +1,150 @@
#include "../../../../include/IO/Socket/RestAPIs/Twitch.h"
#include "../../../../include/IO/Socket/DNS.h"
#include "../../../../include/System/System.h"
#include "../../../../include/URI.h"
namespace lwe
{
Twitch::~Twitch()
{
client.Release();
}
Twitch::Twitch()
: forceVerify(false)
{
}
Twitch::Twitch(const Str_8& clientId, const Str_8& secret, const Str_8& redURI, const Array<Str_8>& scopes, const bool forceVerify)
: client(AddrType::IPV4), clientId(clientId), secret(secret), redURI(redURI), scopes(scopes), forceVerify(forceVerify)
{
}
bool Twitch::Authorize()
{
Str_8 scopesFinal;
for (UInt_64 i = 0; i < scopes.Size(); ++i)
{
scopesFinal += scopes[i];
if (i < scopes.Size() - 1)
scopesFinal += "%20";
}
Str_8 rURI = URI::Encode(redURI);
Str_8 uri = "https://id.twitch.tv/oauth2/authorize?client_id=" + clientId + "&redirect_uri=" + rURI +
"&response_type=code&force_verify=" + (forceVerify ? "true" : "false") + "&scope=" +
scopesFinal;
TCP server(AddrType::IPV4);
server.Bind(DNS::Resolve(client.GetAddressType(), "localhost"), 65535);
server.Listen();
System::OpenURI(uri);
TCP* cbClient = server.Accept();
Request cbReq = cbClient->RecvReq();
if (cbReq.GetResource() != "/callback")
{
Response resp(423, "Event Horizon");
resp.SetContentType(ContentType::TEXT_HTML);
resp.SetBody(
"<!DOCTYPE html><html><head><title>LWE Response</title><link rel=\"icon\" type=\"image/png\" href=\"https://cdn3.iconfinder.com/data/icons/contour-animals-2/512/wolf-512.png\" /></head><body>Hostile Information Received</body></html>");
cbClient->SendRes(resp);
cbClient->Release();
return false;
}
Response resp(200, "Event Horizon");
resp.SetContentType(ContentType::TEXT_HTML);
resp.SetBody(
"<!DOCTYPE html><html><head><title>LWE Response</title><link rel=\"icon\" type=\"image/png\" href=\"https://cdn3.iconfinder.com/data/icons/contour-animals-2/512/wolf-512.png\" /></head><body>Authentication Successful</body></html>");
cbClient->SendRes(resp);
cbClient->Release();
server.Release();
client.Initialize();
client.Connect("id.twitch.tv", SSL::HTTPS_Port);
Request authReq(Verb::POST, "/oauth2/token");
authReq.SetContentType(ContentType::APP_FORMURLENCODED);
authReq.AddToBody("client_id", clientId);
authReq.AddToBody("client_secret", secret);
authReq.AddToBody("code", cbReq.GetQuery("code"));
authReq.AddToBody("grant_type", "authorization_code");
authReq.AddToBody("redirect_uri", redURI);
client.SendReq(authReq);
Response authRes = client.RecvRes();
if (authRes.GetCode() == 400)
{
client.Release();
LWE_LOG_INT("Error", 0, "Could not authorize with Twitch because the client id was invalid.");
return false;
} else if (authRes.GetCode() == 403)
{
client.Release();
LWE_LOG_INT("Error", 1, "Could not authorize with Twitch because the secret was invalid.");
return false;
} else if (authRes.GetCode() != 200)
{
client.Release();
LWE_LOG_INT("Error", 2, "Could not authorize with Twitch.");
return false;
}
Json authResJson = authRes.GetJson();
JsonObj* value = (JsonObj*) authResJson.GetValue();
if (!value)
return false;
JsonVar* var = value->GetVar("access_token");
if (!var)
return false;
token = ((JsonStr*) var->GetValue())->value;
return true;
}
Str_8 Twitch::GetClientId() const
{
return clientId;
}
Str_8 Twitch::GetSecret() const
{
return secret;
}
Str_8 Twitch::GetRedURI() const
{
return redURI;
}
bool Twitch::IsVerificationForced() const
{
return forceVerify;
}
Str_8 Twitch::GetToken() const
{
return token;
}
}

View File

@@ -0,0 +1,177 @@
#include "../../../../include/IO/Socket/RestAPIs/TwitchChat.h"
#include "../../../../include/IO/Socket/DNS.h"
#include "../../../../include/IO/Console.h"
namespace lwe
{
TwitchChat::~TwitchChat()
{
UnInitialize();
}
TwitchChat::TwitchChat()
: initialized(false)
{
}
TwitchChat::TwitchChat(const Str_8& username)
: username(username), initialized(false)
{
}
TwitchChat::TwitchChat(const Str_8& username, const Str_8& token)
: username(username), token(token), initialized(false)
{
}
TwitchChat::TwitchChat(const TwitchChat& chat)
: username(chat.username), token(chat.token), initialized(false)
{
}
TwitchChat& TwitchChat::operator=(const TwitchChat& chat)
{
if (this == &chat)
return *this;
client = TCP();
username = chat.username;
token = chat.token;
channel = Str_8();
initialized = false;
return *this;
}
void TwitchChat::SetToken(const Str_8& newToken)
{
token = newToken;
}
void TwitchChat::Initialize()
{
if (initialized)
return;
client = TCP(lwe::AddrType::IPV4);
client.Connect(DNS::Resolve(AddrType::IPV4, "irc.chat.twitch.tv"), 6667);
client.SetBlocking(false);
Str_8 r("PASS oauth:" + token + "\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
r = "NICK " + username + "\r\n";
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
initialized = true;
}
void TwitchChat::UnInitialize()
{
if (!initialized)
return;
client.Release();
initialized = false;
}
void TwitchChat::JoinChannel(const Str_8& newChannel)
{
if (!initialized || channel == newChannel)
return;
channel = newChannel;
Str_8 r("Join #" + newChannel + "\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
}
void TwitchChat::LeaveChannel()
{
if (!initialized)
return;
Str_8 r("PART #" + channel + "\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
}
void TwitchChat::SendPong()
{
if (!initialized)
return;
Str_8 r("PONG :tmi.twitch.tv\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
}
void TwitchChat::SendMsg(const Str_8& msg)
{
if (!initialized)
return;
Str_8 r("PRIVMSG #" + channel + " :" + msg + "\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
//irc.SendStr(":" + username + "!" + username + "@" + username + ".tmi.twitch.tv PRIVMSG #" + username + " :" + msg + "\r\n");
}
void TwitchChat::WhisperMsg(const Str_8& user, const Str_8& msg)
{
if (!initialized)
return;
Str_8 r("PRIVMSG #jtv :/w " + user + " " + msg + "\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
}
Str_8 TwitchChat::RecvMsg()
{
Str_8 result;
Byte received[1024];
UInt_64 recvSize = 0;
do
{
recvSize = client.Receive(received, 1024);
if (recvSize)
result.Push((Char_8*) received, recvSize);
else
break;
} while (!result.Find("\r\n", nullptr, SearchPattern::RIGHT_LEFT));
return result;
}
Str_8 TwitchChat::GetUsername() const
{
return username;
}
Str_8 TwitchChat::GetChannel() const
{
return channel;
}
}

236
src/IO/Socket/SSL.cpp Normal file
View File

@@ -0,0 +1,236 @@
#include "../../../include/IO/Socket/SSL.h"
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
namespace lwe
{
SSL::~SSL()
{
if (!IsValid())
return;
if (sslHdl)
{
if (connection)
SSL_shutdown(sslHdl);
SSL_free(sslHdl);
}
if (ctx)
SSL_CTX_free(ctx);
}
SSL::SSL()
: ctx(nullptr), sslHdl(nullptr)
{
}
SSL::SSL(const AddrType type)
: TCP(type), ctx(nullptr), sslHdl(nullptr)
{
SSL::Initialize();
}
SSL::SSL(TCP&& tcp) noexcept
: TCP(std::move(tcp)), ctx(nullptr), sslHdl(nullptr)
{
}
SSL::SSL(const TCP& tcp)
: TCP(tcp), ctx(nullptr), sslHdl(nullptr)
{
}
SSL::SSL(const SSL& ssl)
: TCP(ssl), ctx(nullptr), sslHdl(nullptr)
{
}
SSL& SSL::operator=(const SSL& ssl)
{
if (this == &ssl)
return *this;
TCP::operator=(ssl);
ctx = nullptr;
sslHdl = nullptr;
return *this;
}
void SSL::Initialize()
{
TCP::Initialize();
if (IsValid())
return;
SSL_library_init();
}
void SSL::Release()
{
TCP::Release();
if (!IsValid())
return;
if (sslHdl)
{
if (connection)
SSL_shutdown(sslHdl);
SSL_free(sslHdl);
sslHdl = nullptr;
}
if (ctx)
{
SSL_CTX_free(ctx);
ctx = nullptr;
}
}
void SSL::Bind(const Str_8& address, unsigned short port)
{
if (bound)
return;
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_server_method());
sslHdl = SSL_new(ctx);
SSL_set_fd(sslHdl, hdl);
TCP::Bind(address, port);
}
SSL* SSL::Accept()
{
if (!bound)
return nullptr;
TCP* tcp = TCP::Accept();
SSL* client = new SSL(std::move(*tcp));
delete tcp;
client->ctx = nullptr;
client->sslHdl = SSL_new(ctx);
SSL_set_fd(client->sslHdl, client->hdl);
int err = SSL_accept(client->sslHdl);
if (!err)
{
LWE_LOG_INT("Error", 0, "Failed SSL handshake with error #" + Str_8::FromNum(SSL_get_error(client->sslHdl, err)) + ".");
return {};
}
return client;
}
void SSL::Connect(const Str_8& address, const UInt_16 port)
{
if (bound)
return;
TCP::Connect(address, port);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_client_method());
sslHdl = SSL_new(ctx);
SSL_set_fd(sslHdl, hdl);
SSL_connect(sslHdl);
}
UInt_64 SSL::Send(const Byte* const buffer, const UInt_32 size)
{
int written = SSL_write(sslHdl, buffer, (int)size);
if (written <= 0)
{
int code = SSL_get_error(sslHdl, written);
ERR_print_errors_fp(stderr);
LWE_LOG_INT("Error", 0, "Failed to send data with error #" + Str_8::FromNum(code) + ".");
return 0;
}
return written;
}
UInt_64 SSL::Receive(Byte* const buffer, const UInt_32 size)
{
int received = SSL_read(sslHdl, buffer, (int)size);
if (received <= 0)
{
int code = SSL_get_error(sslHdl, received);
ERR_print_errors_fp(stderr);
LWE_LOG_INT("Error", 0, "Failed to receive data with error #" + Str_8::FromNum(code) + ".");
return 0;
}
return received;
}
void SSL::UseCertificate(const Byte* data, const UInt_64 size)
{
X509 *cert = d2i_X509(nullptr, &data, (long)size);
if (!cert)
{
LWE_LOG_INT("Error", 0, "Invalid certificate.");
return;
}
if (SSL_CTX_use_certificate(ctx, cert) != 1)
{
LWE_LOG_INT("Error", 1, "Failed to use certificate.");
return;
}
X509_free(cert);
}
void SSL::UsePrivateKey(const Byte* data, const UInt_64 size)
{
EVP_PKEY *key = d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &data, (long)size);
if (!key)
{
LWE_LOG_INT("Error", 0, "Invalid private key.");
return;
}
if (SSL_CTX_use_PrivateKey(ctx, key) != 1)
{
LWE_LOG_INT("Error", 1, "Failed to use private key.");
return;
}
EVP_PKEY_free(key);
}
bool SSL::IsValid()
{
return TCP::IsValid() && sslHdl;
}
}

1316
src/IO/Socket/Socket.cpp Normal file

File diff suppressed because it is too large Load Diff

478
src/IO/Socket/TCP_BSD.cpp Normal file
View File

@@ -0,0 +1,478 @@
#include "../../../include/IO/Socket/TCP_BSD.h"
#include "../../../include/IO/Socket/DNS.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <cerrno>
namespace lwe
{
TCP::~TCP()
{
if (hdl == LWE_INVALID_SOCKET)
return;
if (connection)
{
if (shutdown(hdl, SHUT_RDWR) == -1)
LWE_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(errno) + ".");
}
if (close(hdl) == -1)
LWE_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
}
TCP::TCP()
: hdl(LWE_INVALID_SOCKET)
{
}
TCP::TCP(const AddrType addrType)
: BaseTCP(addrType), hdl(LWE_INVALID_SOCKET)
{
TCP::Initialize();
}
TCP::TCP(TCP&& tcp) noexcept
: BaseTCP(std::move(tcp)), hdl(tcp.hdl)
{
tcp.hdl = LWE_INVALID_SOCKET;
}
TCP::TCP(const TCP& tcp)
: BaseTCP(tcp), hdl(LWE_INVALID_SOCKET)
{
}
TCP& TCP::operator=(TCP&& tcp) noexcept
{
if (this == &tcp)
return *this;
BaseTCP::operator=(std::move(tcp));
hdl = tcp.hdl;
tcp.hdl = LWE_INVALID_SOCKET;
return *this;
}
TCP& TCP::operator=(const TCP& tcp)
{
if (this == &tcp)
return *this;
BaseTCP::operator=(tcp);
hdl = LWE_INVALID_SOCKET;
return *this;
}
void TCP::Initialize()
{
if (IsValid())
return;
if (addrType == AddrType::IPV6)
hdl = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
else if (addrType == AddrType::IPV4)
hdl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
else
return;
if (hdl == LWE_INVALID_SOCKET)
{
UInt_32 code = errno;
LWE_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + ".");
}
}
void TCP::Release()
{
if (!IsValid())
return;
if (connection)
{
if (shutdown(hdl, SHUT_RDWR) == -1)
LWE_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(errno) + ".");
}
if (close(hdl) == -1)
LWE_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
connection = false;
bound = false;
listening = false;
connected = false;
hdl = LWE_INVALID_SOCKET;
}
void TCP::Bind(const Str_8& address, unsigned short port)
{
if (!IsValid() || bound || connection)
return;
if (addrType == AddrType::IPV6)
Bind_v6(address, port);
else if (addrType == AddrType::IPV4)
Bind_v4(address, port);
this->localAddr = address;
this->localPort = port;
bound = true;
}
void TCP::Listen()
{
if (connection || !IsValid() || !bound || listening)
return;
int code = listen(hdl, SOMAXCONN);
if (code == -1)
{
LWE_LOG_INT("Error", 0, "Failed to listen with error #" + Str_8::FromNum(errno) + ".");
return;
}
listening = true;
}
TCP* TCP::Accept()
{
if (connection || !IsValid() || !bound || !listening)
return nullptr;
sockaddr_in6 remote = {};
UInt_32 addrLen = sizeof(sockaddr_in6);
TCP* client = new TCP();
client->addrType = addrType;
client->localAddr = localAddr;
client->localPort = localPort;
client->connection = true;
client->hdl = accept(hdl, (sockaddr*)&remote, &addrLen);
if (client->hdl == LWE_INVALID_SOCKET)
{
if (errno != EWOULDBLOCK)
LWE_LOG_INT("Error", 0, "Failed to accept client with error #" + Str_8::FromNum(errno) + ".");
delete client;
return nullptr;
}
if (addrLen == sizeof(sockaddr_in6))
{
char tmpAddr[INET6_ADDRSTRLEN];
if (!inet_ntop(remote.sin6_family, &remote.sin6_addr, tmpAddr, INET6_ADDRSTRLEN))
{
LWE_LOG_INT("Error", 1, "Failed to convert IPv6 address with error #" + Str_8::FromNum(errno) + ".");
delete client;
return nullptr;
}
client->remoteAddr = tmpAddr;
client->remotePort = ntohs(remote.sin6_port);
}
else if (addrLen == sizeof(sockaddr_in))
{
char tmpAddr[INET_ADDRSTRLEN];
if (!inet_ntop(((sockaddr_in*)&remote)->sin_family, &((sockaddr_in*)&remote)->sin_addr, tmpAddr, INET_ADDRSTRLEN))
{
LWE_LOG_INT("Error", 1, "Failed to convert IPv4 address with error #" + Str_8::FromNum(errno) + ".");
delete client;
return nullptr;
}
client->remoteAddr = tmpAddr;
client->remotePort = ntohs(((sockaddr_in*)&remote)->sin_port);
}
return client;
}
void TCP::Connect(const Str_8& address, const unsigned short port)
{
if (connection || !IsValid() || listening)
return;
remoteHostName = address;
remoteAddr = DNS::Resolve(addrType, address);
remotePort = port;
if (addrType == AddrType::IPV6)
Connect_v6(remoteAddr, port);
else if (addrType == AddrType::IPV4)
Connect_v4(remoteAddr, port);
connected = true;
}
UInt_64 TCP::Send(const Byte *const buffer, const UInt_32 size)
{
if (!IsValid())
{
LWE_LOG_INT("Error", 0, "Attempted to send while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
LWE_LOG_INT("Error", 1, "Attempted to send while socket is not connected or a connection.");
return 0;
}
SInt_64 sent = send(hdl, (char*)buffer, size, 0);
if (sent == -1)
{
int err = errno;
if (err == ECONNRESET)
{
Release();
LWE_LOG_INT("Information", 0, "Connection dropped.");
}
else
LWE_LOG_INT("Error", 1, "Failed to send with error #" + Str_8::FromNum(err) + ".");
return 0;
}
return (UInt_64)sent;
}
UInt_64 TCP::Receive(Byte* const buffer, const UInt_32 size)
{
if (!IsValid())
{
LWE_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
LWE_LOG_INT("Error", 1, "Attempted to receive while socket is not connected or a connection.");
return 0;
}
SInt_64 received = recv(hdl, (char*)buffer, size, 0);
if (received == -1)
{
int err = errno;
if (err == ECONNRESET)
{
Release();
LWE_LOG_INT("Information", 0, "Connection dropped.");
}
else if (err != EWOULDBLOCK)
{
LWE_LOG_INT("Error", 2, "Failed to receive with error #" + Str_8::FromNum(err) + ".");
}
return 0;
}
return (UInt_64)received;
}
void TCP::SetBlocking(const bool blocking)
{
if (!IsValid())
{
LWE_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized.");
return;
}
int flags = fcntl(hdl, F_GETFL, 0);
if (flags == -1)
{
LWE_LOG_INT("Error", 0, "Failed to retrieve flags.");
return;
}
if (blocking)
flags ^= O_NONBLOCK;
else
flags |= O_NONBLOCK;
if (fcntl(hdl, F_SETFL, flags) == -1)
LWE_LOG_INT("Error", 1, "Failed to toggle non-blocking mode with error #" + Str_8::FromNum(errno) + ".");
}
bool TCP::IsBlocking() const
{
int flags = fcntl(hdl, F_GETFL, 0);
if (flags == -1)
{
LWE_LOG_INT("Error", 0, "Failed to retrieve flags.");
return true;
}
return !(flags & O_NONBLOCK);
}
bool TCP::IsValid() const
{
return hdl != LWE_INVALID_SOCKET;
}
void TCP::Bind_v6(const Str_8& address, unsigned short port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin6_addr = in6addr_any;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == -1)
{
LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + ".");
return;
}
}
void TCP::Bind_v4(const Str_8& address, unsigned short port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
{
result.sin_addr.s_addr = INADDR_ANY;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == -1)
{
LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + ".");
return;
}
}
void TCP::Connect_v6(const Str_8& address, unsigned short port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
int code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
code = connect(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == -1)
{
int err = errno;
if (err == ETIMEDOUT)
{
LWE_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
LWE_LOG_INT("Error", 3, "Failed to connect with error #" + Str_8::FromNum(err) + ".");
}
return;
}
}
void TCP::Connect_v4(const Str_8& address, unsigned short port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
code = connect(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == -1)
{
int err = errno;
if (err == ETIMEDOUT)
{
LWE_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
LWE_LOG_INT("Error", 3, "Failed to connect with error #" + Str_8::FromNum(err) + ".");
}
return;
}
}
};

500
src/IO/Socket/TCP_W32.cpp Normal file
View File

@@ -0,0 +1,500 @@
#include "../../../include/IO/Socket/TCP_W32.h"
#include "../../../include/IO/Socket/DNS.h"
#include <WinSock2.h>
#include <WS2tcpip.h>
namespace lwe
{
TCP::~TCP()
{
if (hdl == LWE_INVALID_SOCKET)
return;
Int_32 code;
if (connection)
{
code = shutdown(hdl, SD_SEND);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(GetLastError()) + ".");
}
code = closesocket(hdl);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
if (!connection && WSACleanup() == SOCKET_ERROR)
LWE_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
}
TCP::TCP()
: hdl(LWE_INVALID_SOCKET)
{
}
TCP::TCP(const AddrType addrType)
: BaseTCP(addrType), hdl(LWE_INVALID_SOCKET)
{
TCP::Initialize();
}
TCP::TCP(TCP&& tcp) noexcept
: BaseTCP(std::move(tcp)), hdl(tcp.hdl)
{
tcp.hdl = LWE_INVALID_SOCKET;
}
TCP::TCP(const TCP& tcp)
: BaseTCP(tcp), hdl(LWE_INVALID_SOCKET)
{
TCP::Initialize();
}
TCP& TCP::operator=(TCP&& tcp) noexcept
{
if (this == &tcp)
return *this;
BaseTCP::operator=(tcp);
hdl = tcp.hdl;
tcp.hdl = LWE_INVALID_SOCKET;
return *this;
}
TCP& TCP::operator=(const TCP& tcp)
{
if (this == &tcp)
return *this;
BaseTCP::operator=(tcp);
hdl = LWE_INVALID_SOCKET;
TCP::Initialize();
return *this;
}
void TCP::Initialize()
{
WSADATA data = {};
int code = WSAStartup(MAKEWORD(2, 2), &data);
if (code)
{
LWE_LOG_INT("Error", 0, "WSAStartup failed with the error #" + Str_8::FromNum(code) + ".");
return;
}
if (addrType == AddrType::IPV6)
hdl = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
else if (addrType == AddrType::IPV4)
hdl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
else
return;
if (hdl == LWE_INVALID_SOCKET)
{
UInt_32 code = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + ".");
if (WSACleanup() == SOCKET_ERROR)
LWE_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
}
}
void TCP::Release()
{
if (!IsValid())
return;
Int_32 code;
if (connection)
{
code = shutdown(hdl, SD_SEND);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(GetLastError()) + ".");
}
code = closesocket(hdl);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
hdl = LWE_INVALID_SOCKET;
if (!connection && WSACleanup() == SOCKET_ERROR)
LWE_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
connection = false;
bound = false;
listening = false;
connected = false;
}
void TCP::Bind(const Str_8& address, unsigned short port)
{
if (!IsValid() || bound || connection)
return;
if (addrType == AddrType::IPV6)
Bind_v6(address, port);
else if (addrType == AddrType::IPV4)
Bind_v4(address, port);
this->localAddr = address;
this->localPort = port;
bound = true;
}
void TCP::Listen()
{
if (connection || !IsValid() || !bound || listening)
return;
int code = listen(hdl, SOMAXCONN);
if (code == -1)
{
LWE_LOG_INT("Error", 0, "Failed to listen with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
listening = true;
}
TCP* TCP::Accept()
{
if (connection || !IsValid() || !bound || !listening)
return nullptr;
sockaddr_in6 remote = {};
UInt_32 addrLen = sizeof(sockaddr_in6);
TCP* client = new TCP();
client->addrType = addrType;
client->localAddr = localAddr;
client->localPort = localPort;
client->connection = true;
client->hdl = accept(hdl, (sockaddr*)&remote, (int*)&addrLen);
if (client->hdl == LWE_INVALID_SOCKET)
{
Int_32 code = WSAGetLastError();
if (code != WSAEWOULDBLOCK)
LWE_LOG_INT("Error", 0, "Failed to accept client with error #" + Str_8::FromNum(code) + ".");
delete client;
return nullptr;
}
if (addrLen == sizeof(sockaddr_in6))
{
char tmpAddr[INET6_ADDRSTRLEN];
if (!inet_ntop(remote.sin6_family, &remote.sin6_addr, tmpAddr, INET6_ADDRSTRLEN))
{
Int_32 code = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to convert IPv6 address with error #" + Str_8::FromNum(code) + ".");
delete client;
return nullptr;
}
client->remoteAddr = tmpAddr;
client->remotePort = ntohs(remote.sin6_port);
}
else if (addrLen == sizeof(sockaddr_in))
{
char tmpAddr[INET_ADDRSTRLEN];
if (!inet_ntop(((sockaddr_in*)&remote)->sin_family, &((sockaddr_in*)&remote)->sin_addr, tmpAddr, INET_ADDRSTRLEN))
{
Int_32 code = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to convert IPv4 address with error #" + Str_8::FromNum(code) + ".");
delete client;
return nullptr;
}
client->remoteAddr = tmpAddr;
client->remotePort = ntohs(((sockaddr_in*)&remote)->sin_port);
}
return client;
}
void TCP::Connect(const Str_8& address, const unsigned short port)
{
if (connection || !IsValid() || listening)
return;
remoteHostName = address;
remoteAddr = DNS::Resolve(addrType, address);
remotePort = port;
if (addrType == AddrType::IPV6)
Connect_v6(remoteAddr, port);
else if (addrType == AddrType::IPV4)
Connect_v4(remoteAddr, port);
connected = true;
}
UInt_64 TCP::Send(const Byte *const buffer, const UInt_32 size)
{
if (!IsValid())
{
LWE_LOG_INT("Error", 0, "Attempted to send while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
LWE_LOG_INT("Error", 1, "Attempted to send while socket is not connected or a connection.");
return 0;
}
SInt_64 sent = (SInt_64)send(hdl, (char*)buffer, (int)size, 0);
if (sent == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAECONNRESET)
{
Release();
LWE_LOG_INT("Information", 0, "Connection dropped.");
}
else
LWE_LOG_INT("Error", 1, "Failed to send with error #" + Str_8::FromNum(err) + ".");
return 0;
}
return (UInt_64)sent;
}
UInt_64 TCP::Receive(Byte* const buffer, const UInt_32 size)
{
if (!IsValid())
{
LWE_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
LWE_LOG_INT("Error", 1, "Attempted to receive while socket is not connected or a connection.");
return 0;
}
SInt_64 received = (SInt_64)recv(hdl, (char*)buffer, (int)size, 0);
if (received == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAECONNRESET)
{
Release();
LWE_LOG_INT("Information", 0, "Connection dropped.");
}
else if (err == WSAECONNABORTED)
{
LWE_LOG_INT("Information", 1, "Receiving timed-out.");
}
else if (err != WSAEWOULDBLOCK)
{
LWE_LOG_INT("Error", 2, "Failed to receive with error #" + Str_8::FromNum(err) + ".");
}
return 0;
}
return (UInt_64)received;
}
void TCP::SetBlocking(const bool blocking)
{
if (!IsValid())
{
LWE_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized.");
return;
}
u_long r = (u_long)!blocking;
int result = ioctlsocket(hdl, FIONBIO, &r);
if (result != NO_ERROR)
LWE_LOG_INT("Error", 1, "Failed to toggle non-blocking mode with error #" + Str_8::FromNum(result) + ".");
}
bool TCP::IsBlocking() const
{
u_long r = 0;
if (ioctlsocket(hdl, FIONREAD, &r) == SOCKET_ERROR)
LWE_LOG_INT("Error", 0, "Failed to retrieve socket info.");
return (bool)r;
}
bool TCP::IsValid() const
{
return hdl != LWE_INVALID_SOCKET;
}
void TCP::Bind_v6(const Str_8& address, unsigned short port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin6_addr = in6addr_any;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == -1)
{
LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
}
void TCP::Bind_v4(const Str_8& address, unsigned short port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin_addr.S_un.S_addr = INADDR_ANY;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == -1)
{
LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
}
void TCP::Connect_v6(const Str_8& address, unsigned short port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
int code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
code = connect(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAETIMEDOUT)
{
LWE_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
LWE_LOG_INT("Error", 3, "Failed to connect with error #" + Str_8::FromNum(err) + ".");
}
return;
}
}
void TCP::Connect_v4(const Str_8& address, unsigned short port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
code = connect(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAETIMEDOUT)
{
LWE_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
LWE_LOG_INT("Error", 3, "Failed to connect with error #" + Str_8::FromNum(err) + ".");
}
return;
}
}
}

362
src/IO/Socket/UDP_BSD.cpp Normal file
View File

@@ -0,0 +1,362 @@
#include "../../../include/IO/Socket/UDP_BSD.h"
#include "../../../include/Log.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <cerrno>
namespace lwe
{
UDP::~UDP()
{
if (hdl == LWE_INVALID_SOCKET)
return;
Int_32 code = close(hdl);
if (code == -1)
LWE_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
}
UDP::UDP()
: hdl(LWE_INVALID_SOCKET)
{
}
UDP::UDP(const AddrType addrType)
: BaseUDP(addrType), hdl(LWE_INVALID_SOCKET)
{
if (addrType == AddrType::IPV6)
hdl = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
else if (addrType == AddrType::IPV4)
hdl = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
else
return;
if (hdl == LWE_INVALID_SOCKET)
{
UInt_32 code = errno;
LWE_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + ".");
return;
}
}
UDP::UDP(UDP&& udp) noexcept
: BaseUDP(std::move(udp)), hdl(udp.hdl)
{
udp.hdl = LWE_INVALID_SOCKET;
}
UDP::UDP(const UDP& udp)
: BaseUDP(udp), hdl(LWE_INVALID_SOCKET)
{
}
UDP& UDP::operator=(UDP&& udp) noexcept
{
if (this == &udp)
return *this;
BaseUDP::operator=(std::move(udp));
hdl = udp.hdl;
udp.hdl = LWE_INVALID_SOCKET;
return *this;
}
UDP& UDP::operator=(const UDP& udp)
{
if (this == &udp)
return *this;
BaseUDP::operator=(udp);
hdl = LWE_INVALID_SOCKET;
return *this;
}
void UDP::Release()
{
if (!IsValid())
return;
Int_32 code = close(hdl);
if (code == -1)
LWE_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
hdl = LWE_INVALID_SOCKET;
bound = false;
}
void UDP::Bind(const Str_8& address, const UInt_16 port)
{
if (!IsValid() || bound)
return;
if (addrType == AddrType::IPV6)
Bind_v6(address, port);
else if (addrType == AddrType::IPV4)
Bind_v4(address, port);
this->address = address;
this->port = port;
bound = true;
}
UInt_64 UDP::Send(const Str_8& address, const UInt_16 port, const Byte *const data, const UInt_64 size)
{
if (addrType == AddrType::IPV6)
return Send_v6(address, port, data, size);
else if (addrType == AddrType::IPV4)
return Send_v4(address, port, data, size);
return 0;
}
UInt_64 UDP::Receive(Str_8* const address, UInt_16* const port, Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
LWE_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized.");
return 0;
}
sockaddr_in6 remote = {};
UInt_32 addrLen = sizeof(sockaddr_in);
SInt_64 received = 0;
received = recvfrom(hdl, data, size, 0, (sockaddr*)&remote, &addrLen);
if (received == -1)
{
int code = errno;
if (code != ECONNRESET && code != EWOULDBLOCK)
{
Release();
LWE_LOG_INT("Error", 1, "Failed to receive with error #" + Str_8::FromNum(code) + ".");
}
return 0;
}
if (addrLen == sizeof(sockaddr_in6))
{
char tmpAddr[INET6_ADDRSTRLEN];
if (!inet_ntop(remote.sin6_family, &remote.sin6_addr, tmpAddr, INET6_ADDRSTRLEN))
{
Int_32 code = errno;
LWE_LOG_INT("Error", 2, "Failed to convert IPv6 address with error #" + Str_8::FromNum(code) + ".");
return received;
}
*address = tmpAddr;
*port = ntohs(remote.sin6_port);
}
else if (addrLen == sizeof(sockaddr_in))
{
char tmpAddr[INET_ADDRSTRLEN];
if (!inet_ntop(((sockaddr_in*)&remote)->sin_family, &((sockaddr_in*)&remote)->sin_addr, tmpAddr, INET_ADDRSTRLEN))
{
Int_32 code = errno;
LWE_LOG_INT("Error", 2, "Failed to convert IPv4 address with error #" + Str_8::FromNum(code) + ".");
return received;
}
*address = tmpAddr;
*port = ntohs(((sockaddr_in*)&remote)->sin_port);
}
return received;
}
void UDP::SetBlocking(const bool blocking)
{
if (!IsValid())
{
LWE_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized.");
return;
}
if (fcntl(hdl, F_SETFL, O_NONBLOCK, blocking) == -1)
LWE_LOG_INT("Error", 1, "Failed to toggle non-blocking mode with error #" + Str_8::FromNum(errno) + ".");
}
bool UDP::IsBlocking() const
{
return (bool)fcntl(hdl, F_GETFL, O_NONBLOCK);
}
bool UDP::IsValid() const
{
return hdl != LWE_INVALID_SOCKET;
}
void UDP::Bind_v6(const Str_8& address, const UInt_16 port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
if (address.Size())
{
Int_32 code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin6_addr = in6addr_any;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == -1)
{
LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + ".");
return;
}
}
void UDP::Bind_v4(const Str_8& address, const UInt_16 port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin_addr.s_addr = INADDR_ANY;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == -1)
{
LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + ".");
return;
}
}
UInt_64 UDP::Send_v6(const Str_8& addr, const UInt_16 port, const Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
LWE_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
Int_32 code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
LWE_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
Int_32 sent = sendto(hdl, (char*)&data[0], (int)size, 0, (sockaddr*)&result, sizeof(sockaddr_in6));
if (sent == -1)
{
Int_32 dCode = errno;
LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
Release();
return 0;
}
return sent;
}
UInt_64 UDP::Send_v4(const Str_8& addr, const UInt_16 port, const Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
LWE_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
LWE_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
int sent = sendto(hdl, (char*)&data[0], (int)size, 0, (sockaddr*)&result, sizeof(sockaddr_in));
if (sent == -1)
{
Int_32 dCode = errno;
LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
Release();
return 0;
}
return sent;
}
};

380
src/IO/Socket/UDP_W32.cpp Normal file
View File

@@ -0,0 +1,380 @@
#include "../../../include/IO/Socket/UDP_W32.h"
#include "../../../include/Log.h"
#include <WinSock2.h>
#include <WS2tcpip.h>
namespace lwe
{
UDP::~UDP()
{
if (hdl == LWE_INVALID_SOCKET)
return;
Int_32 code = closesocket(hdl);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
if (WSACleanup() == SOCKET_ERROR)
LWE_LOG_INT("Error", 1, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
}
UDP::UDP()
: hdl(LWE_INVALID_SOCKET)
{
}
UDP::UDP(const AddrType addrType)
: BaseUDP(addrType), hdl(LWE_INVALID_SOCKET)
{
WSADATA data = {};
int code = WSAStartup(MAKEWORD(2, 2), &data);
if (code)
{
LWE_LOG_INT("Error", 0, "WSAStartup failed with the error #" + Str_8::FromNum(code) + ".");
return;
}
if (addrType == AddrType::IPV6)
hdl = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
else if (addrType == AddrType::IPV4)
hdl = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
else
return;
if (hdl == LWE_INVALID_SOCKET)
{
UInt_32 code = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + ".");
if (WSACleanup() == SOCKET_ERROR)
LWE_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
}
UDP::UDP(UDP&& udp) noexcept
: BaseUDP(std::move(udp)), hdl(udp.hdl)
{
udp.hdl = LWE_INVALID_SOCKET;
}
UDP::UDP(const UDP& udp)
: BaseUDP(udp), hdl(LWE_INVALID_SOCKET)
{
}
UDP& UDP::operator=(UDP&& udp) noexcept
{
if (this == &udp)
return *this;
BaseUDP::operator=(std::move(udp));
hdl = udp.hdl;
udp.hdl = LWE_INVALID_SOCKET;
return *this;
}
UDP& UDP::operator=(const UDP& udp)
{
if (this == &udp)
return *this;
BaseUDP::operator=(udp);
hdl = LWE_INVALID_SOCKET;
return *this;
}
void UDP::Release()
{
if (!IsValid())
return;
Int_32 code = closesocket(hdl);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
hdl = LWE_INVALID_SOCKET;
if (WSACleanup() == SOCKET_ERROR)
LWE_LOG_INT("Error", 1, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
bound = false;
}
void UDP::Bind(const Str_8& address, const UInt_16 port)
{
if (!IsValid() || bound)
return;
if (addrType == AddrType::IPV6)
Bind_v6(address, port);
else if (addrType == AddrType::IPV4)
Bind_v4(address, port);
this->address = address;
this->port = port;
bound = true;
}
UInt_64 UDP::Send(const Str_8& address, const UInt_16 port, const Byte *const data, const UInt_64 size)
{
if (addrType == AddrType::IPV6)
return Send_v6(address, port, data, size);
else if (addrType == AddrType::IPV4)
return Send_v4(address, port, data, size);
return 0;
}
UInt_64 UDP::Receive(Str_8* const address, UInt_16* const port, Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
LWE_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized.");
return 0;
}
sockaddr_in6 remote = {};
UInt_32 addrLen = sizeof(sockaddr_in);
SInt_64 received = recvfrom(hdl, (char*)data, (int)size, 0, (sockaddr*)&remote, (int*)&addrLen);
if (received == SOCKET_ERROR)
{
int code = WSAGetLastError();
if (code != WSAECONNRESET && code != WSAEWOULDBLOCK)
{
Release();
LWE_LOG_INT("Error", 1, "Failed to receive with error #" + Str_8::FromNum(code) + ".");
}
return 0;
}
if (addrLen == sizeof(sockaddr_in6))
{
char tmpAddr[INET6_ADDRSTRLEN];
if (!inet_ntop(remote.sin6_family, &remote.sin6_addr, tmpAddr, INET6_ADDRSTRLEN))
{
Int_32 code = WSAGetLastError();
LWE_LOG_INT("Error", 2, "Failed to convert IPv6 address with error #" + Str_8::FromNum(code) + ".");
return received;
}
*address = tmpAddr;
*port = ntohs(remote.sin6_port);
}
else if (addrLen == sizeof(sockaddr_in))
{
char tmpAddr[INET_ADDRSTRLEN];
if (!inet_ntop(((sockaddr_in*)&remote)->sin_family, &((sockaddr_in*)&remote)->sin_addr, tmpAddr, INET_ADDRSTRLEN))
{
Int_32 code = WSAGetLastError();
LWE_LOG_INT("Error", 2, "Failed to convert IPv4 address with error #" + Str_8::FromNum(code) + ".");
return received;
}
*address = tmpAddr;
*port = ntohs(((sockaddr_in*)&remote)->sin_port);
}
return received;
}
void UDP::SetBlocking(const bool blocking)
{
if (!IsValid())
{
LWE_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized.");
return;
}
u_long r = (u_long)!blocking;
int result = ioctlsocket(hdl, FIONBIO, &r);
if (result != NO_ERROR)
LWE_LOG_INT("Error", 1, "Failed to toggle non-blocking mode with error #" + Str_8::FromNum(result) + ".");
}
bool UDP::IsBlocking() const
{
u_long r = 0;
if (ioctlsocket(hdl, FIONREAD, &r) == SOCKET_ERROR)
LWE_LOG_INT("Error", 0, "Failed to retrieve socket info.");
return (bool)r;
}
bool UDP::IsValid() const
{
return hdl != LWE_INVALID_SOCKET;
}
void UDP::Bind_v6(const Str_8& address, const UInt_16 port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
if (address.Size())
{
Int_32 code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin6_addr = in6addr_any;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == SOCKET_ERROR)
{
LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
}
void UDP::Bind_v4(const Str_8& address, const UInt_16 port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin_addr.S_un.S_addr = INADDR_ANY;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == SOCKET_ERROR)
{
LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
}
UInt_64 UDP::Send_v6(const Str_8& addr, const UInt_16 port, const Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
LWE_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
Int_32 code = inet_pton(AF_INET6, addr, &result.sin6_addr);
if (!code)
{
LWE_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
Int_32 sent = sendto(hdl, (char*)&data[0], (int)size, 0, (sockaddr*)&result, sizeof(sockaddr_in6));
if (sent == SOCKET_ERROR)
{
Int_32 dCode = WSAGetLastError();
LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
Release();
return 0;
}
return sent;
}
UInt_64 UDP::Send_v4(const Str_8& addr, const UInt_16 port, const Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
LWE_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
int code = inet_pton(AF_INET, addr, &result.sin_addr);
if (!code)
{
LWE_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
int sent = sendto(hdl, (char*)&data[0], (int)size, 0, (sockaddr*)&result, sizeof(sockaddr_in));
if (sent == SOCKET_ERROR)
{
Int_32 dCode = WSAGetLastError();
LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
Release();
return 0;
}
return sent;
}
}