New version

This commit is contained in:
TheDoctor
2019-10-12 18:04:36 +01:00
parent b88bed3bd0
commit 6db271bd7e
64 changed files with 2972 additions and 2222 deletions

View File

@ -1,29 +0,0 @@
#include "Config.hpp"
#include <fstream>
void Config::Initialize()
{
Configuration.ReadConfig("config.dat");
Configuration.ReadNodes();
}
inline void Config::SetUsingConsole(bool value)
{
using_console = value;
}
inline bool Config::GetUsingConsole()
{
return using_console;
}
inline void Config::SetLogToFile(bool value)
{
log_to_file = value;
}
inline bool Config::GetLogToFile()
{
return log_to_file;
}

84
src/Cookies.cpp Normal file
View File

@ -0,0 +1,84 @@
// https://github.com/mfichman/http
#include "Cookies.hpp"
#include "Parse.hpp"
#include <cassert>
namespace std::net
{
ParseResult<std::string> ParseName(const char* str)
{
return ParseUntil(str, [](char ch)
{
return isspace(ch) || ch == '=';
});
}
ParseResult<std::string> ParseValue(const char* str)
{
return ParseUntil(str, [](char ch)
{
return ch == ';' || ch == '=';
});
}
ParseResult<std::string> ParseSeparator(const char* str)
{
if (*str)
{
assert(*str == ';' || *str == '=');
return ParseWhitespace(str + 1);
}
else
{
auto result = ParseResult<std::string>{};
result.ch = str;
return result;
}
}
Cookie ParseCookie(const char* str)
{
auto name = ParseName(str);
auto ch = ParseSeparator(name.ch).ch;
auto value = ParseValue(ch);
ch = ParseSeparator(value.ch).ch;
auto cookie = Cookie();
cookie.SetName(name.value);
cookie.SetValue(value.value);
while (*ch)
{
auto flag = ParseValue(ch);
if (flag.value == "Path")
{
ch = ParseSeparator(flag.ch).ch;
flag = ParseValue(ch);
cookie.SetPath(flag.value);
}
else if (flag.value == "HttpOnly")
cookie.SetHttpOnly(true);
else if (flag.value == "Secure")
cookie.SetSecure(true);
ch = ParseSeparator(flag.ch).ch;
}
return cookie;
}
Cookie::Cookie(const std::string& text)
{
*this = ParseCookie(text.c_str());
}
const Cookie Cookies::operator[](const std::string & name) const
{
auto i = m_cookie.find(name);
return (i == m_cookie.end()) ? Cookie() : i->second;
}
void Cookies::SetCookie(const Cookie& cookie)
{
m_cookie[cookie.GetName()] = cookie;
}
}

View File

@ -1,60 +0,0 @@
#include "Handshake.hpp"
#include "Utility.hpp"
Handshake::Handshake()
{
id = -2;
}
Handshake::Handshake(uint16 id, byte con_code, byte distribution_mode)
{
this->id = id;
this->con_code = con_code;
this->distribution_mode = distribution_mode;
}
Handshake::~Handshake()
{
}
const std::vector<byte>& Handshake::EncodeHandshake(const Handshake & handshake)
{
std::vector<byte> handshake_bytes;
std::vector<byte> id = Utility::BitConverter::ToBytes(handshake.id);
std::vector<byte> con_mode = Utility::BitConverter::ToBytes(handshake.con_code);
std::vector<byte> type = Utility::BitConverter::ToBytes(static_cast<uint8>(1));
handshake_bytes.insert(handshake_bytes.begin(), type.begin(), type.end());
handshake_bytes.insert(handshake_bytes.begin(), id.begin(), id.end());
handshake_bytes.insert(handshake_bytes.begin(), con_mode.begin(), con_mode.end());
return handshake_bytes;
}
Handshake & Handshake::DecodeHandshake(const std::vector<byte>& bytes)
{
Handshake handshake;
handshake.id = Utility::BitConverter::ToUint16(bytes, 1);
handshake.con_code = Utility::BitConverter::ToUint8(bytes, 3);
return handshake;
}
const NetworkMessage & Handshake::HandshakeToNetworkMessage(const Handshake & handshake)
{
NetworkMessage message;
message.sender = handshake.id;
message.tag = handshake.con_code;
message.subject = 1;
return message;
}
const Handshake & Handshake::NetworkMessageToHandshake(const NetworkMessage & message)
{
Handshake handshake;
handshake.id = message.sender;
handshake.con_code = message.tag;
return handshake;
}

22
src/Headers.cpp Normal file
View File

@ -0,0 +1,22 @@
// https://github.com/mfichman/http
#include "Headers.hpp"
namespace std::net
{
std::string const Headers::HOST("Host");
std::string const Headers::CONTENT_LENGTH("Content-Length");
std::string const Headers::ACCEPT_ENCODING("Accept-Encoding");
std::string const Headers::CONNECTION("Connection");
const std::string Headers::operator[](const std::string & name) const
{
auto i = m_header.find(name);
return (i == m_header.end()) ? "" : i->second;
}
void Headers::AddHeader(std::string const& name, std::string const& value)
{
m_header.emplace(name, value);
}
}

120
src/Http.cpp Normal file
View File

@ -0,0 +1,120 @@
// https://github.com/mfichman/http
#include "Http.hpp"
#include <cassert>
#include <vector>
#include <sstream>
#include "Socket.hpp"
#include "SecureSocket.hpp"
#undef DELETE
namespace std::net
{
Response Http::Send(Request const& request)
{
// Send an HTTP request. Auto-fill the content-length headers.
std::string string = Str(request);
uint16_t port = 0;
std::unique_ptr<Socket> socket;
std::unique_ptr<SecureSocket> secure_socket;
bool secure = false;
if (request.GetUri().GetScheme() == "https")
{
secure_socket.reset(new SecureSocket());
port = 443;
secure = true;
}
else if (request.GetUri().GetScheme() == "http")
{
socket.reset(new Socket(SocketType::Streaming));
port = 80;
}
else
assert(!"unknown http scheme");
if (request.GetUri().GetPort())
port = request.GetUri().GetPort();
secure ? secure_socket->Connect(IPAddress(request.GetUri().GetHost(), port)) : socket->Connect(IPAddress(request.GetUri().GetHost(), port));
int32_t sent;
secure ? secure_socket->Recv((uint8_t*)string.c_str(), string.size(), sent) : socket->Send((uint8_t*)string.c_str(), string.size(), sent);
std::vector<char> buffer(16384); // 16 KiB
std::stringstream ss;
int32_t read;
do
{
secure ? secure_socket->Recv((uint8_t*)&buffer[0], buffer.size(), read) : socket->Recv((uint8_t*)&buffer[0], buffer.size(), read);
ss.write(&buffer[0], read);
}
while (read > 0);
secure ? secure_socket->Close() : socket->Close();
return Response(ss.str());
}
Response Http::Get(std::string const& path, std::string const& data)
{
// Shortcut for simple GET requests
Request request;
request.SetMethod(Method::GET);
request.SetUri(Uri(path));
request.SetData(data);
return Send(request);
}
Response Http::Post(std::string const& path, std::string const& data)
{
// Shortcut for simple POST requests
Request request;
request.SetMethod(Method::POST);
request.SetUri(Uri(path));
request.SetData(data);
return Send(request);
}
static std::string str_impl(Method method) {
switch (method)
{
case Method::GET:
return "GET";
case Method::HEAD:
return "HEAD";
case Method::POST:
return "POST";
case Method::PUT:
return "PUT";
case Method::DELETE:
return "DELETE";
case Method::TRACE:
return "TRACE";
case Method::CONNECT:
return "CONNECT";
default:
assert(!"unknown request method");
}
return "";
}
std::string Http::Str(Request const& request)
{
// Serialize a request to a string
std::stringstream ss;
auto path = request.GetPath().empty() ? "/" : request.GetPath();
ss << str_impl(request.GetMethod()) << ' ' << path << " HTTP/1.1\n";
ss << Headers::HOST << ": " << request.GetUri().GetHost() << "\n";
ss << Headers::CONTENT_LENGTH << ": " << request.GetData().size() << "\n";
ss << Headers::CONNECTION << ": close\n";
ss << Headers::ACCEPT_ENCODING << ": identity\n";
for (auto header : request.GetHeaders())
ss << header.first << ": " << header.second << "\n";
ss << "\n";
ss << request.GetData();
return ss.str();
}
}

62
src/IPAddress.cpp Normal file
View File

@ -0,0 +1,62 @@
#include "IPAddress.hpp"
namespace std::net
{
const IPAddress IPAddress::None;
const IPAddress IPAddress::Any(0, 0, 0, 0);
const IPAddress IPAddress::LocalHost(127, 0, 0, 1);
const IPAddress IPAddress::Broadcast(255, 255, 255, 255);
std::string IPAddress::ToString() const
{
in_addr address;
address.s_addr = m_address;
return inet_ntoa(address);
}
void IPAddress::Resolve(const std::string& address)
{
m_address = 0;
m_valid = false;
if (address == "255.255.255.255")
{
// The broadcast address needs to be handled explicitly,
// because it is also the value returned by inet_addr on error
m_address = INADDR_BROADCAST;
m_valid = true;
}
else if (address == "0.0.0.0")
{
m_address = INADDR_ANY;
m_valid = true;
}
else
{
uint32_t ip = inet_addr(address.c_str());
if (ip != INADDR_NONE)
{
m_address = ip;
m_valid = true;
}
else
{
addrinfo hints;
std::memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
addrinfo* result = NULL;
if (getaddrinfo(address.c_str(), NULL, &hints, &result) == 0)
{
if (result)
{
ip = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr.s_addr;
freeaddrinfo(result);
m_address = ip;
m_valid = true;
}
}
}
}
}
}

View File

@ -1,23 +0,0 @@
#include "Init.hpp"
#include "Config.hpp"
#include <iostream>
#ifdef _MSC_VER
bool Initialization::Initialize()
{
uint16 code = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (code != 0)
{
if (Config::GetUsingConsole())
std::cerr << code << std::endl; // display some more information too
return false;
}
return true;
}
const WSADATA &Initialization::GetData()
{
return wsa_data;
}
#endif

View File

@ -1,9 +0,0 @@
#include "NetworkBuffer.hpp"
NetworkBuffer::NetworkBuffer()
{
}
NetworkBuffer::~NetworkBuffer()
{
}

View File

@ -1,110 +0,0 @@
#include "NetworkMessage.hpp"
#include "Utility.hpp"
#include "Serializer.hpp"
#include "Handshake.hpp"
#include <vector>
NetworkMessage::NetworkMessage()
{
}
NetworkMessage::NetworkMessage(uint16 sender, byte distribution_mode, uint16 destination_id, byte tag, byte subject) :
sender(sender), distribution_mode(distribution_mode), destination_id(destination_id), tag(tag), subject(subject)
{
}
NetworkMessage::NetworkMessage(const NetworkBuffer &buffer)
{
*this = DecodeMessage(buffer);
}
NetworkMessage::~NetworkMessage()
{
}
const NetworkBuffer &NetworkMessage::EncodeMessage(const NetworkMessage &message)
{
if (message.valid)
{
NetworkBuffer net_buffer;
if (!IS_HANDSHAKE(message))
{
std::vector<byte> sender = Utility::BitConverter::ToBytes(message.sender);
std::vector<byte> distribution_mode = Utility::BitConverter::ToBytes(message.distribution_mode);
std::vector<byte> destination_id = Utility::BitConverter::ToBytes(message.destination_id);
std::vector<byte> tag = Utility::BitConverter::ToBytes(message.tag);
std::vector<byte> subject = Utility::BitConverter::ToBytes(message.subject);
std::vector<byte> data;
if (message.data != nullptr)
data = Serializer::to_bytes(message.data);
std::vector<byte> type = Utility::BitConverter::ToBytes(0);
net_buffer.body.insert(net_buffer.body.begin(), type.begin(), type.end());
net_buffer.body.insert(net_buffer.body.begin(), sender.begin(), sender.end());
net_buffer.body.insert(net_buffer.body.begin(), distribution_mode.begin(), distribution_mode.end());
net_buffer.body.insert(net_buffer.body.begin(), destination_id.begin(), destination_id.end());
net_buffer.body.insert(net_buffer.body.begin(), tag.begin(), tag.end());
net_buffer.body.insert(net_buffer.body.begin(), subject.begin(), subject.end());
if (message.data != nullptr && data.size() > 0)
net_buffer.body.insert(net_buffer.body.begin(), data.begin(), data.end());
net_buffer.header = Utility::BitConverter::ToBytes(sender.size() + distribution_mode.size() + destination_id.size() +
tag.size() + subject.size() + data.size());
net_buffer.valid = true;
}
else
{
std::vector<byte> handshake_bytes = Handshake::EncodeHandshake(Handshake::NetworkMessageToHandshake(message));
std::vector<byte> type = Utility::BitConverter::ToBytes(static_cast<uint8>(1));
handshake_bytes.insert(handshake_bytes.begin(), type.begin(), type.end());
net_buffer.header = Utility::BitConverter::ToBytes(handshake_bytes.size());
net_buffer.body = handshake_bytes;
}
return net_buffer;
}
return NetworkBuffer();
}
const NetworkMessage &NetworkMessage::DecodeMessage(const NetworkBuffer &buffer)
{
if (buffer.valid)
{
byte type = buffer.body[0];
switch (type)
{
case 0:
{
NetworkMessage message;
message.sender = Utility::BitConverter::ToUint16(buffer.body, 1);
message.distribution_mode = buffer.body[3];
message.destination_id = Utility::BitConverter::ToUint16(buffer.body, 4);
message.tag = buffer.body[6];
message.subject = Utility::BitConverter::ToUint8(buffer.body, 7);
message.valid = message.sender != -2 && message.tag != ConnectTag && message.tag != DisconnectTag;
if (Utility::BitConverter::ToInt32(buffer.header) < 9)
return message;
void *object;
object = Serializer::from_bytes(buffer.body, object);
return message;
}
case 1:
{
NetworkMessage message;
message.sender = Utility::BitConverter::ToUint16(buffer.body, 1);
message.tag = Utility::BitConverter::ToUint8(buffer.body, 3);
message.subject = 1;
message.valid = message.sender != -2 && IS_HANDSHAKE(message);
return message;
break;
}
default:
{
//type not supported
throw std::runtime_error("NetworkMessage - Decoding version not supported");
}
}
}
return NetworkMessage();
}

0
src/Parse.cpp Normal file
View File

31
src/Request.cpp Normal file
View File

@ -0,0 +1,31 @@
// https://github.com/mfichman/http
#include "Request.hpp"
namespace std::net
{
const std::string Request::GetHeaderElement(const std::string& name) const
{
return m_headers[name];
}
void Request::SetMethod(Method method)
{
m_method = method;
}
void Request::SetUri(const Uri& uri)
{
m_uri = uri;
}
void Request::SetData(const std::string& data)
{
m_data = data;
}
void Request::AddHeader(const std::string& name, const std::string& value)
{
m_headers.AddHeader(name, value);
}
}

97
src/Response.cpp Normal file
View File

@ -0,0 +1,97 @@
// https://github.com/mfichman/http
#include "Response.hpp"
#include "Parse.hpp"
namespace std::net
{
static ParseResult<HttpStatus> ParseStatus(const char* str)
{
ParseResult<HttpStatus> result
{
};
auto code = ParseToken(str);
result.value = (HttpStatus)std::atoi(code.value.c_str());
result.ch = code.ch;
return result;
}
Response ParseResponse(const char* str)
{
// Parse an HTTP response
auto version = ParseToken(str);
auto code = ParseStatus(version.ch);
auto message = ParseUntil(code.ch, [](char ch)
{
return ch == '\r';
});
auto response = Response();
if (version.value != "HTTP/1.1")
throw std::runtime_error("bad HTTP version");
auto ch = parseCrLf(message.ch).ch;
while (*ch != '\0' && *ch != '\r')
{
auto name = ParseUntil(ch, [](char ch)
{
return ch == ':';
});
if (*name.ch)
name.ch++; // For ":"
auto ws = ParseWhile(name.ch, isspace);
auto value = ParseUntil(ws.ch, [](char ch)
{
return ch == '\r';
});
response.SetHeader(name.value, value.value);
if (name.value == "Set-Cookie")
response.SetCookie(Cookie(value.value));
ch = parseCrLf(value.ch).ch;
}
ch = parseCrLf(ch).ch;
response.SetStatus(code.value);
response.SetData(ch);
return response;
}
Response::Response(const std::string& response)
{
*this = ParseResponse(response.c_str());
}
const std::string Response::GetHeader(const std::string& name) const
{
return m_headers[name];
}
const Cookie Response::GetCookie(const std::string& name) const
{
return m_cookies[name];
}
void Response::SetStatus(HttpStatus status)
{
m_status = status;
}
void Response::SetData(const std::string& data)
{
m_data = data;
}
void Response::SetHeader(const std::string& name, const std::string& value)
{
m_headers.AddHeader(name, value);
}
void Response::SetCookie(const Cookie& cookie)
{
m_cookies.SetCookie(cookie);
}
}

163
src/SecureSocket.cpp Normal file
View File

@ -0,0 +1,163 @@
#include "SecureSocket.hpp"
#include <cassert>
namespace inl::net::sockets
{
/*SecureSocket::SecureSocket()
: m_context(0), m_conn(0), m_eof(false)
{
m_socket = std::make_unique<Socket>(SocketType::Streaming);
// Intitialize the SSL client-side socket
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
}
bool SecureSocket::Connect(const IPAddress & addrStr)
{
if (!m_context)
{
m_context = SSL_CTX_new(SSLv23_client_method());
assert(m_context);
}
if (!m_conn)
{
m_conn = SSL_new(m_context);
assert(m_conn);
m_in = BIO_new(BIO_s_mem());
m_out = BIO_new(BIO_s_mem());
SSL_set_bio(m_conn, m_in, m_out);
SSL_set_connect_state(m_conn);
}
return m_socket->Connect(addrStr);
}
bool SecureSocket::Close() const
{
return m_socket->Close();
}
bool SecureSocket::HasPendingData(uint32_t & pendingDataSize) const
{
return m_socket->HasPendingData(pendingDataSize);
}
bool SecureSocket::Send(uint8_t* data, int32_t count, int32_t &sent, int flags)
{
sent = SSL_write(m_conn, data, count);
SendFromBio(); // Write data if available
if (sent < 0)
{
HandleReturn(sent);
return true;
}
return sent > 0;
}
bool SecureSocket::SendRaw(uint8_t * buf, size_t len, int flags)
{
int32_t sent;
return m_socket->Send(buf, len, sent) && sent == len;
}
bool SecureSocket::SendFromBio(int flags)
{
uint8_t buf[4096];
size_t pending = BIO_ctrl_pending(m_out);
if (!pending)
return true;
size_t bytes = BIO_read(m_out, buf, sizeof(buf));
if (bytes > 0)
return SendRaw(buf, bytes, flags);
else if (bytes == -1 || bytes == 0)
return true;
return false;
}
bool SecureSocket::RecvToBio(int flags)
{
uint8_t buf[4096];
size_t bytes = m_socket->Recv(buf, sizeof(buf), flags);
if (bytes > 0)
{
size_t written = BIO_write(m_in, buf, int(bytes));
assert(bytes == written);
return true;
}
else if (bytes == 0)
{
// No data
m_eof = true;
return true;
}
return false;
}
void SecureSocket::HandleReturn(size_t ret)
{
int32_t err = SSL_get_error(m_conn, ret);
if (SSL_ERROR_WANT_WRITE == err)
SendFromBio();
else if (SSL_ERROR_WANT_READ == err)
RecvToBio();
else if (SSL_ERROR_SSL == err)
throw inl::RuntimeException();
else
assert(!"unexpected error");
}
bool SecureSocket::Recv(uint8_t* data, int32_t count, int32_t &read, int flags)
{
read = SSL_read(m_conn, data, count);
if (read < 0)
{
HandleReturn(read);
if (m_eof)
return false;
}
return read > 0;
}
bool SecureSocket::Wait(SocketWaitConditions cond, std::chrono::milliseconds t) const
{
return m_socket->Wait(cond, t);
}
SocketConnectionState SecureSocket::GetConnectionState() const
{
return m_socket->GetConnectionState();
}
void SecureSocket::GetAddress(IPAddress & outAddr) const
{
m_socket->GetAddress(outAddr);
}
int32_t SecureSocket::GetPort() const
{
return m_socket->GetPort();
}
void SecureSocket::UseCertificateFile(std::string const & path)
{
if (!m_context)
assert(!"not initialized yet");
if (SSL_CTX_use_certificate_file(m_context, path.c_str(), SSL_FILETYPE_PEM) <= 0)
throw inl::RuntimeException();
}
void SecureSocket::UsePrivateKeyFile(std::string const & path)
{
if (!m_context)
assert(!"not initialized yet");
if (SSL_CTX_use_PrivateKey_file(m_context, path.c_str(), SSL_FILETYPE_PEM) <= 0)
throw inl::RuntimeException();
if (!SSL_CTX_check_private_key(m_context))
throw inl::RuntimeException();
}*/
}

View File

@ -1,20 +0,0 @@
#include "Serializer.hpp"
template<typename T> const std::vector<byte> &Serializer::to_bytes(const T& object)
{
std::vector<byte> bytes;
const byte *begin = reinterpret_cast<const byte*>(std::addressof(object));
const byte *end = begin + sizeof(T);
std::copy(begin, end, bytes.begin());
return bytes;
}
template<typename T> const T& Serializer::from_bytes(const std::vector<byte> &bytes, T& object)
{
static_assert(std::is_trivially_copyable<T>::value, "not a TriviallyCopyable type");
std::copy(bytes.begin(), bytes.end(), reinterpret_cast<const byte*>(std::addressof(object)));
return object;
}

511
src/Socket.cpp Normal file
View File

@ -0,0 +1,511 @@
#include "Socket.hpp"
#include "IPAddress.hpp"
namespace std::net
{
void Socket::init()
{
if (GetSocketType() == SocketType::Unknown)
throw std::invalid_argument("Unknown socket type");
if (m_socket == INVALID_SOCKET)
{
m_socket = socket(AF_INET, (int)GetSocketType(), 0);
if (m_socket == INVALID_SOCKET)
throw std::runtime_error("Couldnt create socket");
}
if (GetSocketType() == SocketType::Streaming)
{
int yes = 1;
// Disable the Nagle algorithm (i.e. removes buffering of TCP packets)
setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&yes), sizeof(yes));
// On Mac OS X, disable the SIGPIPE signal on disconnection
#if defined(__APPLE__) && defined(__MACH__)
setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char*>(&yes), sizeof(yes));
#endif
}
else
{
// Enable broadcast by default for UDP sockets
int yes = 1;
setsockopt(m_socket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&yes), sizeof(yes));
}
}
bool Socket::Close()
{
if (m_socket != INVALID_SOCKET)
{
int32_t error = closesocket(m_socket);
m_socket = INVALID_SOCKET;
return error == 0;
}
return false;
}
bool Socket::Bind(const IPAddress &addr)
{
sockaddr_in addr_in = addr.ToCAddr();
return bind(m_socket, (sockaddr*)&addr_in, sizeof(sockaddr_in)) == 0;
}
bool Socket::Connect(const IPAddress& addr)
{
sockaddr_in addr_in = addr.ToCAddr();
int32_t Return = connect(m_socket, (sockaddr*)&addr_in, sizeof(sockaddr_in));
SocketErrors Error = TranslateErrorCode(Return);
// "would block" is not an error
return ((Error == SocketErrors::SE_NO_ERROR) || (Error == SocketErrors::SE_EWOULDBLOCK));
}
bool Socket::WaitForPendingConnection(bool& hasPendingConnection, std::chrono::milliseconds t)
{
bool hasSucceeded = false;
hasPendingConnection = false;
if (HasState(SocketParam::HasError) == SocketReturn::No)
{
SocketReturn state = HasState(SocketParam::CanRead, t);
hasSucceeded = state != SocketReturn::EncounteredError;
hasPendingConnection = state == SocketReturn::Yes;
}
return hasSucceeded;
}
bool Socket::HasPendingData(uint32_t& pendingDataSize)
{
pendingDataSize = 0;
if (HasState(SocketParam::CanRead) == SocketReturn::Yes)
{
if (ioctl(m_socket, FIONREAD,
#if defined(_WIN32)
(u_long*)
#endif
&pendingDataSize) == 0)
return (pendingDataSize > 0);
}
return false;
}
std::unique_ptr<Socket> Socket::Accept()
{
SOCKET newSocket = accept(m_socket, nullptr, nullptr);
if (newSocket != INVALID_SOCKET)
{
return std::make_unique<Socket>(newSocket, GetSocketType());
}
return nullptr;
}
bool Socket::SendTo(const uint8_t* data, int32_t count, int32_t& sent, const IPAddress& addrDest)
{
sockaddr_in addr = addrDest.ToCAddr();
sent = sendto(m_socket, (const char*)data, count, 0, (sockaddr*)&addr, sizeof(sockaddr_in));
bool result = sent >= 0;
if (result)
m_lastActivityTime = std::chrono::system_clock::now().time_since_epoch().count();
return result;
}
bool Socket::Send(const uint8_t* data, int32_t count, int32_t& sent)
{
sent = send(m_socket, (const char*)data, count, 0);
bool result = sent != SOCKET_ERROR;
if (result)
m_lastActivityTime = std::chrono::system_clock::now().time_since_epoch().count();
return result;
}
bool Socket::RecvFrom(uint8_t* data, int32_t size, int32_t& read, IPAddress& srcAddr, SocketReceiveFlags flags)
{
socklen_t len = sizeof(sockaddr_in);
sockaddr_in addr = srcAddr.ToCAddr();
const int translatedFlags = TranslateFlags(flags);
read = recvfrom(m_socket, (char*)data, size, translatedFlags, (sockaddr*)&addr, &len);
if (read < 0 && TranslateErrorCode(read) == SocketErrors::SE_EWOULDBLOCK)
read = 0;
else if (read <= 0) // 0 means gracefully closed
{
read = 0;
return false;
}
m_lastActivityTime = std::chrono::system_clock::now().time_since_epoch().count();
return true;
}
bool Socket::Recv(uint8_t* data, int32_t size, int32_t& read, SocketReceiveFlags flags)
{
const int translatedFlags = TranslateFlags(flags);
read = recv(m_socket, (char*)data, size, translatedFlags);
if (read < 0 && TranslateErrorCode(read) == SocketErrors::SE_EWOULDBLOCK)
read = 0;
else if (read <= 0) // 0 means gracefully closed
{
read = 0;
return false;
}
m_lastActivityTime = std::chrono::system_clock::now().time_since_epoch().count();
return true;
}
bool Socket::Wait(SocketWaitConditions cond, std::chrono::milliseconds t)
{
if ((cond == SocketWaitConditions::WaitForRead) || (cond == SocketWaitConditions::WaitForReadOrWrite))
{
if (HasState(SocketParam::CanRead, t) == SocketReturn::Yes)
return true;
}
if ((cond == SocketWaitConditions::WaitForWrite) || (cond == SocketWaitConditions::WaitForReadOrWrite))
{
if (HasState(SocketParam::CanWrite, t) == SocketReturn::Yes)
return true;
}
return false;
}
SocketConnectionState Socket::GetConnectionState()
{
SocketConnectionState currentState = SocketConnectionState::ConnectionError;
if (HasState(SocketParam::HasError) == SocketReturn::No)
{
if (std::chrono::system_clock::now().time_since_epoch().count() - m_lastActivityTime > std::chrono::milliseconds(5).count())
{
SocketReturn writeState = HasState(SocketParam::CanWrite, std::chrono::milliseconds(1));
SocketReturn readState = HasState(SocketParam::CanRead, std::chrono::milliseconds(1));
if (writeState == SocketReturn::Yes || readState == SocketReturn::Yes)
{
currentState = SocketConnectionState::Connected;
m_lastActivityTime = std::chrono::system_clock::now().time_since_epoch().count();
}
else if (writeState == SocketReturn::No && readState == SocketReturn::No)
currentState = SocketConnectionState::NotConnected;
}
else
currentState = SocketConnectionState::Connected;
}
return currentState;
}
void Socket::GetAddress(IPAddress& outAddr)
{
struct sockaddr_in addr;
socklen_t Size = sizeof(sockaddr_in);
if (getsockname(m_socket, (sockaddr*)&addr, &Size) != 0)
return;
outAddr = IPAddress(inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
}
bool Socket::GetPeerAddress(IPAddress& outAddr)
{
struct sockaddr_in addr;
socklen_t size = sizeof(sockaddr_in);
int result = getpeername(m_socket, (sockaddr*)&addr, &size);
if (result != 0)
return false;
outAddr = IPAddress(inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
return result == 0;
}
bool Socket::SetNonBlocking(bool isNonBlocking)
{
#if PLATFORM_HTML5 // if we have more platforms later (html5, android, ios) later we need to do some changes to networking
throw std::exception("Can't have blocking sockets on HTML5");
return false;
#else
#if _WIN32
return ioctl(m_socket, FIONBIO, (u_long*)&isNonBlocking) == 0;
#else
int flags = fcntl(m_socket, F_GETFL, 0);
flags = isNonBlocking ? flags | O_NONBLOCK : flags ^ (flags & O_NONBLOCK);
int err = fcntl(m_socket, F_SETFL, flags);
return (err == 0 ? true : false);
#endif
#endif
}
bool Socket::JoinMulticastGroup(const IPAddress& addrStr)
{
sockaddr_in addr = addrStr.ToCAddr();
ip_mreq imr;
imr.imr_interface.s_addr = INADDR_ANY;
imr.imr_multiaddr = addr.sin_addr;
return (setsockopt(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&imr, sizeof(imr)) == 0);
}
bool Socket::LeaveMulticastGroup(const IPAddress& addrStr)
{
sockaddr_in addr = addrStr.ToCAddr();
ip_mreq imr;
imr.imr_interface.s_addr = INADDR_ANY;
imr.imr_multiaddr = addr.sin_addr;
return (setsockopt(m_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&imr, sizeof(imr)) == 0);
}
bool Socket::SetLinger(bool shouldLinger, int32_t t)
{
linger ling;
ling.l_onoff = shouldLinger;
ling.l_linger = t;
return setsockopt(m_socket, SOL_SOCKET, SO_LINGER, (char*)&ling, sizeof(ling)) == 0;
}
bool Socket::SetSendBufferSize(int32_t size, int32_t& newSize)
{
socklen_t len = sizeof(int32_t);
bool success = setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&size, sizeof(int32_t)) == 0;
getsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&newSize, &len);
return success;
}
bool Socket::SetReceiveBufferSize(int32_t size, int32_t& newSize)
{
socklen_t len = sizeof(int32_t);
bool success = setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char*)&size, sizeof(int32_t)) == 0;
getsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char*)&newSize, &len);
return success;
}
uint32_t Socket::GetPort()
{
sockaddr_in addr;
socklen_t size = sizeof(sockaddr_in);
if (getsockname(m_socket, (sockaddr*)&addr, &size) != 0)
return 0; // invalid port
return ntohs(addr.sin_port);
}
SocketReturn Socket::HasState(SocketParam state, std::chrono::milliseconds t)
{
timeval time;
time.tv_sec = t.count();
time.tv_usec = t.count() * 1000 + t.count();
fd_set socketSet;
FD_ZERO(&socketSet);
FD_SET(m_socket, &socketSet);
int32_t SelectStatus = 0;
switch (state)
{
case SocketParam::CanRead:
SelectStatus = select(m_socket + 1, &socketSet, nullptr, nullptr, &time);
break;
case SocketParam::CanWrite:
SelectStatus = select(m_socket + 1, nullptr, &socketSet, nullptr, &time);
break;
case SocketParam::HasError:
SelectStatus = select(m_socket + 1, nullptr, nullptr, &socketSet, &time);
break;
}
return SelectStatus > 0 ? SocketReturn::Yes :
SelectStatus == 0 ? SocketReturn::No :
SocketReturn::EncounteredError;
}
SocketErrors Socket::TranslateErrorCode(int32_t code)
{
#if !_WIN32
if (code == SOCKET_ERROR)
{
return SE_SOCKET_ERROR;
}
switch (code)
{
case 0: return SocketErrors::SE_NO_ERROR;
case EINTR: return SocketErrors::SE_EINTR;
case EBADF: return SocketErrors::SE_EBADF;
case EACCES: return SocketErrors::SE_EACCES;
case EFAULT: return SocketErrors::SE_EFAULT;
case EINVAL: return SocketErrors::SE_EINVAL;
case EMFILE: return SocketErrors::SE_EMFILE;
case EWOULDBLOCK: return SocketErrors::SE_EWOULDBLOCK;
case EINPROGRESS: return SocketErrors::SE_EINPROGRESS;
case EALREADY: return SocketErrors::SE_EALREADY;
case ENOTSOCK: return SocketErrors::SE_ENOTSOCK;
case EDESTADDRREQ: return SocketErrors::SE_EDESTADDRREQ;
case EMSGSIZE: return SocketErrors::SE_EMSGSIZE;
case EPROTOTYPE: return SocketErrors::SE_EPROTOTYPE;
case ENOPROTOOPT: return SocketErrors::SE_ENOPROTOOPT;
case EPROTONOSUPPORT: return SocketErrors::SE_EPROTONOSUPPORT;
case ESOCKTNOSUPPORT: return SocketErrors::SE_ESOCKTNOSUPPORT;
case EOPNOTSUPP: return SocketErrors::SE_EOPNOTSUPP;
case EPFNOSUPPORT: return SocketErrors::SE_EPFNOSUPPORT;
case EAFNOSUPPORT: return SocketErrors::SE_EAFNOSUPPORT;
case EADDRINUSE: return SocketErrors::SE_EADDRINUSE;
case EADDRNOTAVAIL: return SocketErrors::SE_EADDRNOTAVAIL;
case ENETDOWN: return SocketErrors::SE_ENETDOWN;
case ENETUNREACH: return SocketErrors::SE_ENETUNREACH;
case ENETRESET: return SocketErrors::SE_ENETRESET;
case ECONNABORTED: return SocketErrors::SE_ECONNABORTED;
case ECONNRESET: return SocketErrors::SE_ECONNRESET;
case ENOBUFS: return SocketErrors::SE_ENOBUFS;
case EISCONN: return SocketErrors::SE_EISCONN;
case ENOTCONN: return SocketErrors::SE_ENOTCONN;
case ESHUTDOWN: return SocketErrors::SE_ESHUTDOWN;
case ETOOMANYREFS: return SocketErrors::SE_ETOOMANYREFS;
case ETIMEDOUT: return SocketErrors::SE_ETIMEDOUT;
case ECONNREFUSED: return SocketErrors::SE_ECONNREFUSED;
case ELOOP: return SocketErrors::SE_ELOOP;
case ENAMETOOLONG: return SocketErrors::SE_ENAMETOOLONG;
case EHOSTDOWN: return SocketErrors::SE_EHOSTDOWN;
case EHOSTUNREACH: return SocketErrors::SE_EHOSTUNREACH;
case ENOTEMPTY: return SocketErrors::SE_ENOTEMPTY;
case EUSERS: return SocketErrors::SE_EUSERS;
case EDQUOT: return SocketErrors::SE_EDQUOT;
case ESTALE: return SocketErrors::SE_ESTALE;
case EREMOTE: return SocketErrors::SE_EREMOTE;
case ENODEV: return SocketErrors::SE_NODEV;
#if !PLATFORM_HAS_NO_EPROCLIM
case EPROCLIM: return SocketErrors::SE_EPROCLIM;
#endif
// case EDISCON: return SE_EDISCON;
// case SYSNOTREADY: return SE_SYSNOTREADY;
// case VERNOTSUPPORTED: return SE_VERNOTSUPPORTED;
// case NOTINITIALISED: return SE_NOTINITIALISED;
#if PLATFORM_HAS_BSD_SOCKET_FEATURE_GETHOSTNAME
case HOST_NOT_FOUND: return SocketErrors::SE_HOST_NOT_FOUND;
case TRY_AGAIN: return SocketErrors::SE_TRY_AGAIN;
case NO_RECOVERY: return SocketErrors::SE_NO_RECOVERY;
#endif
// case NO_DATA: return SE_NO_DATA;
// case : return SE_UDP_ERR_PORT_UNREACH; //@TODO Find it's replacement
}
return SocketErrors::SE_EINVAL;
#else
// handle the generic -1 error
if (code == SOCKET_ERROR)
{
return SocketErrors::SE_SOCKET_ERROR;
}
switch (code)
{
case 0: return SocketErrors::SE_NO_ERROR;
case ERROR_INVALID_HANDLE: return SocketErrors::SE_ECONNRESET; // invalid socket handle catch
case WSAEINTR: return SocketErrors::SE_EINTR;
case WSAEBADF: return SocketErrors::SE_EBADF;
case WSAEACCES: return SocketErrors::SE_EACCES;
case WSAEFAULT: return SocketErrors::SE_EFAULT;
case WSAEINVAL: return SocketErrors::SE_EINVAL;
case WSAEMFILE: return SocketErrors::SE_EMFILE;
case WSAEWOULDBLOCK: return SocketErrors::SE_EWOULDBLOCK;
case WSAEINPROGRESS: return SocketErrors::SE_EINPROGRESS;
case WSAEALREADY: return SocketErrors::SE_EALREADY;
case WSAENOTSOCK: return SocketErrors::SE_ENOTSOCK;
case WSAEDESTADDRREQ: return SocketErrors::SE_EDESTADDRREQ;
case WSAEMSGSIZE: return SocketErrors::SE_EMSGSIZE;
case WSAEPROTOTYPE: return SocketErrors::SE_EPROTOTYPE;
case WSAENOPROTOOPT: return SocketErrors::SE_ENOPROTOOPT;
case WSAEPROTONOSUPPORT: return SocketErrors::SE_EPROTONOSUPPORT;
case WSAESOCKTNOSUPPORT: return SocketErrors::SE_ESOCKTNOSUPPORT;
case WSAEOPNOTSUPP: return SocketErrors::SE_EOPNOTSUPP;
case WSAEPFNOSUPPORT: return SocketErrors::SE_EPFNOSUPPORT;
case WSAEAFNOSUPPORT: return SocketErrors::SE_EAFNOSUPPORT;
case WSAEADDRINUSE: return SocketErrors::SE_EADDRINUSE;
case WSAEADDRNOTAVAIL: return SocketErrors::SE_EADDRNOTAVAIL;
case WSAENETDOWN: return SocketErrors::SE_ENETDOWN;
case WSAENETUNREACH: return SocketErrors::SE_ENETUNREACH;
case WSAENETRESET: return SocketErrors::SE_ENETRESET;
case WSAECONNABORTED: return SocketErrors::SE_ECONNABORTED;
case WSAECONNRESET: return SocketErrors::SE_ECONNRESET;
case WSAENOBUFS: return SocketErrors::SE_ENOBUFS;
case WSAEISCONN: return SocketErrors::SE_EISCONN;
case WSAENOTCONN: return SocketErrors::SE_ENOTCONN;
case WSAESHUTDOWN: return SocketErrors::SE_ESHUTDOWN;
case WSAETOOMANYREFS: return SocketErrors::SE_ETOOMANYREFS;
case WSAETIMEDOUT: return SocketErrors::SE_ETIMEDOUT;
case WSAECONNREFUSED: return SocketErrors::SE_ECONNREFUSED;
case WSAELOOP: return SocketErrors::SE_ELOOP;
case WSAENAMETOOLONG: return SocketErrors::SE_ENAMETOOLONG;
case WSAEHOSTDOWN: return SocketErrors::SE_EHOSTDOWN;
case WSAEHOSTUNREACH: return SocketErrors::SE_EHOSTUNREACH;
case WSAENOTEMPTY: return SocketErrors::SE_ENOTEMPTY;
case WSAEPROCLIM: return SocketErrors::SE_EPROCLIM;
case WSAEUSERS: return SocketErrors::SE_EUSERS;
case WSAEDQUOT: return SocketErrors::SE_EDQUOT;
case WSAESTALE: return SocketErrors::SE_ESTALE;
case WSAEREMOTE: return SocketErrors::SE_EREMOTE;
case WSAEDISCON: return SocketErrors::SE_EDISCON;
case WSASYSNOTREADY: return SocketErrors::SE_SYSNOTREADY;
case WSAVERNOTSUPPORTED: return SocketErrors::SE_VERNOTSUPPORTED;
case WSANOTINITIALISED: return SocketErrors::SE_NOTINITIALISED;
case WSAHOST_NOT_FOUND: return SocketErrors::SE_HOST_NOT_FOUND;
case WSATRY_AGAIN: return SocketErrors::SE_TRY_AGAIN;
case WSANO_RECOVERY: return SocketErrors::SE_NO_RECOVERY;
case WSANO_DATA: return SocketErrors::SE_NO_DATA;
// case : return SE_UDP_ERR_PORT_UNREACH;
}
return SocketErrors::SE_NO_ERROR;
#endif
}
int Socket::TranslateFlags(SocketReceiveFlags flags)
{
int translatedFlags = 0;
if ((int)flags & (int)SocketReceiveFlags::Peek)
{
translatedFlags |= MSG_PEEK;
#if !_WIN32
translatedFlags |= MSG_DONTWAIT;
#endif
}
if ((int)flags & (int)SocketReceiveFlags::WaitAll)
{
translatedFlags |= MSG_WAITALL;
}
return translatedFlags;
}
}

View File

@ -1,255 +1,60 @@
#include "TcpClient.hpp"
#include "NetworkBuffer.hpp"
#include "Utility.hpp"
#include "Config.hpp"
#include "Handshake.hpp"
#include "TcpSocketBuilder.hpp"
#include <string>
#include <future>
#include <iostream>
TcpClient::TcpClient(const std::string &ip) : port(default_client_port)
namespace std::net
{
initialize(ip);
}
TcpClient::TcpClient(const std::string &ip, uint16 port) :
ip(ip), port(port)
{
initialize(ip, port);
}
const std::string &TcpClient::GetIP()
{
return ip;
}
uint16 TcpClient::GetPort()
{
return port;
}
void TcpClient::SetIP(const std::string & ip)
{
this->ip = ip;
}
void TcpClient::SetPort(uint16 port)
{
this->port = port;
}
uint16 TcpClient::GetID()
{
return id;
}
void TcpClient::SetID(uint16 id)
{
this->id = id;
}
void TcpClient::receive_data(TcpClient *client)
{
while (client->receive)
TcpClient::TcpClient(Socket *soc)
{
NetworkMessage message(client->ReceiveMessage());
if (message.valid)
{
if (IS_HANDSHAKE(message))
{
if (message.tag == ConnectTag) // some user has connected - not us, never
std::async(std::launch::async, client->OnConnect, message.sender);
else if (message.tag == DisconnectTag) // some user has disconnected, it can be us
std::async(std::launch::async, client->OnDisconnect, message.sender);
else if (message.tag == Close)
{
std::async(std::launch::async, client->OnDisconnect, message.sender);
close_connection(client);
}
}
else
std::async(std::launch::async, client->OnMessage, message.sender, message.tag, message.subject, message.data); // we received data
}
}
}
void TcpClient::ReceiveMessages()
{
std::async(std::launch::async, &receive_data, this);
}
const NetworkMessage & TcpClient::ReceiveMessage()
{
return receive_data_array();
}
std::future<bool> TcpClient::SendMessage(const NetworkMessage &message)
{
return std::async(std::launch::async, &send_network_message, message, this);
}
void TcpClient::SetOnDisconnectCallback(std::function<void(uint16)> func)
{
OnDisconnect = func;
}
void TcpClient::SetOnConnectCallback(std::function<void(uint16)> func)
{
OnConnect = func;
}
void TcpClient::SetOnMessageCallback(std::function<void(uint16, byte, byte, void*)> func)
{
OnMessage = func;
}
const TcpClient & TcpClient::DefaultTcpClient()
{
return TcpClient();
}
TcpClient::TcpClient(const SOCKET & socket)
{
tcp_socket = socket;
}
bool TcpClient::initialize(const std::string &ip, uint16 port)
{
if (Utility::IPUtil::ValidIPV4(ip) || port == 0)
return false;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
uint16 code = getaddrinfo(ip.c_str(), std::to_string(port).c_str(), &hints, &result);
if (code != 0)
{
if (Config::GetUsingConsole())
std::cerr << code << std::endl; // display more info
WSACleanup();
return false;
m_socket = std::unique_ptr<Socket>(soc); // will this work
}
tcp_socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (tcp_socket == INVALID_SOCKET)
TcpClient::TcpClient(SocketProtocol protocol)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl; // display more info
freeaddrinfo(result);
WSACleanup();
return false;
m_socket = TcpSocketBuilder().AsNonBlocking().AsReusable().Protocol(protocol).Build();
}
return initialized = true;
}
TcpClient::~TcpClient()
{
freeaddrinfo(result);
WSACleanup();
Utility::Delete(result);
}
void TcpClient::Shutdown()
{
Handshake handshake(id, Close, Server);
SendMessage(Handshake::HandshakeToNetworkMessage(handshake));
uint16 code = closesocket(tcp_socket);
if (code == SOCKET_ERROR)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl; // display more info
bool TcpClient::Connect(const IPAddress& addrStr)
{
return m_socket->Connect(addrStr);
}
WSACleanup();
}
bool TcpClient::Connect()
{
if (!initialized)
{
if (ip.size() == 0 || std::count(ip.begin(), ip.end(), '.') != 4 && port == 0 && !initialize(ip, port))
return false;
bool TcpClient::Close() const
{
return m_socket->Close();
}
else return false;
uint16 connect_code = connect(tcp_socket, result->ai_addr, result->ai_addrlen);
if (connect_code == SOCKET_ERROR)
return false;
NetworkMessage message(receive_data_array());
if (IS_HANDSHAKE(message))
{
if (message.tag == Accept)
{
receive = true;
OnConnect(message.sender);
return true;
}
bool TcpClient::HasPendingData(uint32_t& pendingDataSize) const
{
return m_socket->HasPendingData(pendingDataSize);
}
return false;
}
bool TcpClient::DataAvailable(int32 &size)
{
return ioctlsocket(tcp_socket, FIONREAD, reinterpret_cast<u_long*>(size)) != NO_ERROR && size > 0;
}
const NetworkBuffer &TcpClient::receive_data_array()
{
NetworkBuffer buffer;
int32 temp;
if (DataAvailable(temp) && temp > sizeof(int32))
{
byte *header = new byte[sizeof(int32)]();
if (recv(tcp_socket, reinterpret_cast<char*>(header), sizeof(int32), 0) != sizeof(int32))
return NetworkBuffer();
buffer.header = std::vector<byte>(header, header + sizeof(int32));
bool TcpClient::Send(const uint8_t* data, int32_t count, int32_t& sent) const
{
return m_socket->Send(data, count, sent);
}
else
return NetworkBuffer();
int32 body_size = Utility::BitConverter::ToInt32(buffer.header);
byte *body = new byte[body_size]();
int16 received_bytes = recv(tcp_socket, reinterpret_cast<char*>(body), body_size, 0);
if (received_bytes == SOCKET_ERROR || received_bytes != body_size || WSAGetLastError() != 0)
return NetworkBuffer();
buffer.body = std::vector<byte>(body, body + body_size);
buffer.valid = true;
return buffer;
}
bool TcpClient::send_network_message(const NetworkMessage &message, TcpClient *client)
{
NetworkBuffer buffer = NetworkMessage::EncodeMessage(message);
int32 lenght = Utility::BitConverter::ToInt32(buffer.header);
int32 bytes_sent = send(client->tcp_socket, reinterpret_cast<char*>(buffer.body.data()), lenght, 0);
return bytes_sent == SOCKET_ERROR || bytes_sent != lenght || WSAGetLastError() != 0;
}
void TcpClient::close_connection(TcpClient * client)
{
shutdown(client->tcp_socket, SD_BOTH);
closesocket(client->tcp_socket);
}
bool TcpClient::SendBytes(const std::vector<byte>& bytes)
{
int32 bytes_sent = send(tcp_socket, reinterpret_cast<const char*>(bytes.data()), bytes.size(), 0);
if (bytes_sent == SOCKET_ERROR || bytes_sent != bytes.size() || WSAGetLastError() != 0)
{
//something went wrong couldnt send anything/some data
bool TcpClient::Recv(uint8_t* data, int32_t size, int32_t& read, SocketReceiveFlags flags) const
{
return m_socket->Recv(data, size, read, flags);
}
}
bool TcpClient::SendBytes(byte * bytes, uint32 size)
{
int32 bytes_sent = send(tcp_socket, reinterpret_cast<const char*>(bytes), size, 0);
return bytes_sent == SOCKET_ERROR || bytes_sent != size || WSAGetLastError() != 0;
bool TcpClient::Wait(SocketWaitConditions cond, std::chrono::milliseconds t) const
{
return m_socket->Wait(cond, t);
}
SocketConnectionState TcpClient::GetConnectionState() const
{
return m_socket->GetConnectionState();
}
void TcpClient::GetAddress(IPAddress& outAddr) const
{
return m_socket->GetAddress(outAddr);
}
int32_t TcpClient::GetPort() const
{
return m_socket->GetPort();
}
}

54
src/TcpListener.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "TcpListener.hpp"
#include "TcpSocketBuilder.hpp"
#include "Socket.hpp"
#include "TcpClient.hpp"
namespace std::net
{
TcpListener::TcpListener(uint16_t port, std::chrono::milliseconds inSleepTime)
: m_port(port)
, m_sleepTime(inSleepTime)
{
m_socket = TcpSocketBuilder().AsNonBlocking().AsReusable().Bind(IPAddress(0, 0, 0, 0, port)).Listening().Build();
}
TcpListener::TcpListener(Socket *InSocket, std::chrono::milliseconds inSleepTime)
: m_sleepTime(inSleepTime)
{
m_socket = std::unique_ptr<Socket>(InSocket);
}
TcpClient *TcpListener::AcceptClient()
{
if (m_socket == nullptr)
m_socket = TcpSocketBuilder().AsReusable().Bind(IPAddress(0, 0, 0, 0, m_port)).Listening().Build();
if (m_socket == nullptr)
return nullptr;
std::string remoteAddress;
const bool hasZeroSleepTime = (m_sleepTime == std::chrono::milliseconds(0));
bool pending = false;
if (m_socket->WaitForPendingConnection(pending, m_sleepTime))
{
if (pending)
{
std::unique_ptr<Socket> connectionSocket = m_socket->Accept();
if (connectionSocket != nullptr)
{
return new TcpClient(connectionSocket.release());
}
}
else if (hasZeroSleepTime)
std::this_thread::sleep_for(std::chrono::milliseconds(0));
}
else
std::this_thread::sleep_for(std::chrono::milliseconds(m_sleepTime));
return nullptr;
}
}

View File

@ -1,290 +0,0 @@
#include "TcpServer.hpp"
#include "Config.hpp"
#include "Handshake.hpp"
#include "Utility.hpp"
#include <string>
#include <future>
#include <iostream>
TcpServer::TcpServer()
{
initialize(); // initialize with the default port
clients.reserve(max_connections);
}
TcpServer::TcpServer(uint16 port)
{
initialize(port);
clients.reserve(max_connections);
}
TcpServer::~TcpServer()
{
}
void TcpServer::Shutdown()
{
running = false;
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
(*it).Shutdown();
clients.erase(it);
}
shutdown_internal();
}
void TcpServer::AcceptConnections()
{
if (!running)
{
running = true;
std::async(std::launch::async, &accept_connections, this);
}
}
void TcpServer::process_client_messages(TcpServer *server, TcpClient & client)
{
while (server->running)
{
NetworkMessage message(client.ReceiveMessage());
if (message.valid)
server->SendMessage(message);
}
}
bool TcpServer::SendMessage(const NetworkMessage & message)
{
switch (message.distribution_mode)
{
case All: // this will send the message to all except the user that sent it
{
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient client = *it;
if (message.sender != client.GetID())
client.SendMessage(message);
}
for (uint16 i = 0; i < OnMessageFunctions.size(); i++)
OnMessageFunctions[i](message);
}
case AllAndMe: // this will send the message to EVERYONE including the user that sent it
{
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient client = *it;
client.SendMessage(message);
}
for (uint16 i = 0; i < OnMessageFunctions.size(); i++)
OnMessageFunctions[i](message);
}
case Server: // this will only send the message to the server
{
if (message.tag == DisconnectTag)
CloseSocket(message.sender);
for (uint16 i = 0; i < OnMessageFunctions.size(); i++)
OnMessageFunctions[i](message);
}
case Others: // this will send the message to others, excluding server and the user that sent it
{
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient client = *it;
if (message.sender != client.GetID())
client.SendMessage(message);
}
}
case ID: // this will send the message to a specific id
{
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient client = *it;
if (message.sender == client.GetID())
client.SendMessage(message);
}
return false;
}
}
}
uint16 TcpServer::allocate_id() // this function is only used in the AddToClientsList function
{
for (uint16 i = 1; i < max_connections; ++i)
{
bool flag = true;
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient client = *it;
if (client.GetID() == i)
{
flag = false;
break;
}
}
if (flag)
return i;
}
return 0;
}
void TcpServer::add_to_clients_list(TcpClient & client_socket)
{
uint16 id = allocate_id();
if (id > 0)
{
client_socket.SetID(id);
clients.emplace_back(client_socket);
AcceptConnection(client_socket.GetID());
}
else
{
if (Config::GetUsingConsole())
std::cout << "No available ID's" << std::endl;
RejectConnection(client_socket);
}
}
void TcpServer::RejectConnection(TcpClient &client)
{
Handshake handshake(client.GetID(), Reject, ID);
SendMessage(Handshake::HandshakeToNetworkMessage(handshake));
}
void TcpServer::AcceptConnection(uint16 id)
{
Handshake handshake(id, Accept, AllAndMe);
SendMessage(Handshake::HandshakeToNetworkMessage(handshake));
}
void TcpServer::CloseSocket(TcpClient & client)
{
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient it_client = *it;
if (client.GetID() == it_client.GetID())
{
it_client.Shutdown();
clients.erase(it);
}
}
}
void TcpServer::CloseSocket(uint16 id)
{
TcpClient client = GetClientByID(id);
if (client.GetID() != -2)
CloseSocket(client);
}
const TcpClient & TcpServer::GetClientByID(uint16 id)
{
for (std::vector<TcpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
TcpClient client = *it;
if (client.GetID() == id)
return client;
}
return TcpClient::DefaultTcpClient();
}
void TcpServer::SetMaxConnections(uint16 value)
{
max_connections = value;
}
uint16 TcpServer::GetMaxConnections()
{
return max_connections;
}
bool TcpServer::initialize(uint16 port)
{
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
uint16 code = getaddrinfo(0, std::to_string(port).c_str(), &hints, &result);
if (code != 0)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl; // display more info
WSACleanup();
return false;
}
server_tcp_socket = ::socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (server_tcp_socket == INVALID_SOCKET)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl; // display more info
freeaddrinfo(result);
WSACleanup();
return false;
}
code = bind(server_tcp_socket, result->ai_addr, result->ai_addrlen);
if (code == SOCKET_ERROR)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl; // display more info
freeaddrinfo(result);
closesocket(server_tcp_socket);
WSACleanup();
return false;
}
freeaddrinfo(result);
return initialized = true;
}
bool TcpServer::StartServer(bool accept_connections)
{
if (listen(server_tcp_socket, SOMAXCONN) == SOCKET_ERROR)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_tcp_socket);
WSACleanup();
return false;
}
if (accept_connections)
AcceptConnections();
return true;
}
void TcpServer::accept_connections(TcpServer *server)
{
while (server->running)
{
SOCKET client_socket = accept(server->server_tcp_socket, 0, 0);
if (client_socket == INVALID_SOCKET)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl;
closesocket(server->server_tcp_socket);
WSACleanup();
server->running = false; // if we cant accept a connection idk if we should stop the server or not mh
break;
}
TcpClient client(client_socket);
server->add_to_clients_list(client);
std::async(std::launch::async, &process_client_messages, server, client);
}
}
void TcpServer::shutdown_internal()
{
freeaddrinfo(result);
WSACleanup();
Utility::Delete(result);
}

52
src/TcpSocketBuilder.cpp Normal file
View File

@ -0,0 +1,52 @@
#include "TcpSocketBuilder.hpp"
#include "Socket.hpp"
#include "TcpClient.hpp"
#include "TcpListener.hpp"
namespace std::net
{
std::unique_ptr<Socket> TcpSocketBuilder::Build() const
{
std::unique_ptr<Socket> socket = std::make_unique<Socket>(SocketType::Streaming, m_socketProtocol);
if (socket != nullptr)
{
bool Error = !socket->SetReuseAddr(m_reusable) ||
!socket->SetLinger(m_linger, m_lingerTimeout);
if (!Error)
Error = m_bound && !socket->Bind(m_boundAddr);
if (!Error)
Error = m_listen && !socket->Listen();
if (!Error)
Error = !socket->SetNonBlocking(!m_blocking);
if (!Error)
{
int32_t out_new_size;
if (m_receiveBufferSize > 0)
socket->SetReceiveBufferSize(m_receiveBufferSize, out_new_size);
if (m_sendBufferSize > 0)
socket->SetSendBufferSize(m_sendBufferSize, out_new_size);
}
if (Error)
throw std::runtime_error("Couldnt create socket"); // make parameter a string depending on the error
}
return socket;
}
std::unique_ptr<TcpClient> TcpSocketBuilder::BuildClient() const
{
std::unique_ptr<Socket> socket = Build();
return std::make_unique<TcpClient>(socket.release());
}
std::unique_ptr<TcpListener> TcpSocketBuilder::BuildListener() const
{
std::unique_ptr<Socket> socket = Build();
return std::make_unique<TcpListener>(socket.release());
}
}

View File

@ -1,123 +0,0 @@
#include "UdpClient.hpp"
#include "Handshake.hpp"
#include "Config.hpp"
#include <iostream>
#include <future>
UdpClient::UdpClient(const std::string & ip)
{
initialize(ip);
}
UdpClient::UdpClient(const std::string & ip, uint16)
{
initialize(ip, port);
}
uint16 UdpClient::GetPort()
{
return port;
}
void UdpClient::SetPort(uint16 port)
{
this->port = port;
}
uint16 UdpClient::GetID()
{
return id;
}
void UdpClient::SetID(uint16 id)
{
this->id = id;
}
void UdpClient::ReceiveMessages()
{
}
const NetworkMessage & UdpClient::ReceiveMessage()
{
// TODO: insert return statement here
}
std::future<bool> UdpClient::SendMessage(const NetworkMessage & message)
{
return std::async(std::launch::async, &send_network_message, message, this);
}
const std::string &UdpClient::GetIP()
{
return ip;
}
void UdpClient::SetIP(const std::string & ip)
{
this->ip = ip;
}
UdpClient::UdpClient(const SOCKET & socket)
{
udp_socket = socket;
}
const NetworkBuffer & UdpClient::receive_data_array()
{
// TODO: insert return statement here
}
void UdpClient::receive_data(UdpClient * client)
{
}
bool UdpClient::initialize(const std::string &ip, uint16 port)
{
if (Utility::IPUtil::ValidIPV4(ip) || port == 0)
return false;
udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udp_socket == INVALID_SOCKET)
{
WSACleanup();
return false;
}
}
UdpClient::~UdpClient()
{
WSACleanup();
}
void UdpClient::Shutdown()
{
Handshake handshake(id, Close, Server);
SendMessage(Handshake::HandshakeToNetworkMessage(handshake));
uint16 code = closesocket(udp_socket);
if (code == SOCKET_ERROR)
{
if (Config::GetUsingConsole())
std::cerr << WSAGetLastError() << std::endl; // display more info
}
WSACleanup();
}
bool UdpClient::SendBytes(const std::vector<byte> &bytes)
{
}
bool UdpClient::SendBytes(byte *bytes, uint32 lenght)
{
}
bool UdpClient::send_network_message(const NetworkMessage &message, UdpClient *client)
{
}

View File

@ -1,57 +0,0 @@
#include "UdpServer.hpp"
#include "Utility.hpp"
uint16 UdpServer::allocate_id()
{
for (uint16 i = 1; i < max_connections; ++i)
{
bool flag = true;
for (std::vector<UdpClient>::iterator it = clients.begin(); it != clients.end(); ++it)
{
UdpClient client = *it;
if (client.GetID() == i)
{
flag = false;
break;
}
}
if (flag)
return i;
}
return 0;
}
bool UdpServer::initialize(uint16 port)
{
server_udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (server_udp_socket == INVALID_SOCKET)
{
WSACleanup();
return false;
}
memset(&server, '\0', sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.S_un.S_un_b.s_b1 = 0;
server.sin_addr.S_un.S_un_b.s_b2 = 0;
server.sin_addr.S_un.S_un_b.s_b3 = 0;
server.sin_addr.S_un.S_un_b.s_b4 = 0;
if (bind(server_udp_socket, reinterpret_cast<struct sockaddr*>(&server), sizeof(struct sockaddr_in)) == -1)
{
closesocket(server_udp_socket);
WSACleanup();
return false;
}
return initialized = true;
}
void UdpServer::shutdown_internal()
{
WSACleanup();
}

64
src/UdpSocket.cpp Normal file
View File

@ -0,0 +1,64 @@
#include "UdpSocket.hpp"
namespace std::net
{
UdpSocket::UdpSocket(Socket * soc)
{
m_socket = std::unique_ptr<Socket>(soc); // will this work
}
UdpSocket::UdpSocket(SocketProtocol protocol)
{
m_socket = std::make_unique<Socket>(SocketType::Datagram, protocol);
}
bool UdpSocket::Bind(const IPAddress & addr)
{
return m_socket->Bind(addr);
}
bool UdpSocket::SendTo(const uint8_t * data, int32_t count, int32_t & sent, const IPAddress & addrDest)
{
return m_socket->SendTo(data, count, sent, addrDest);
}
bool UdpSocket::RecvFrom(uint8_t * data, int32_t size, int32_t & read, IPAddress & srcAddr, SocketReceiveFlags flags)
{
return m_socket->RecvFrom(data, size, read, srcAddr, flags);
}
bool UdpSocket::GetPeerAddress(IPAddress & outAddr)
{
return m_socket->GetPeerAddress(outAddr);
}
bool UdpSocket::JoinMulticastGroup(const IPAddress & addrStr)
{
return m_socket->JoinMulticastGroup(addrStr);
}
bool UdpSocket::LeaveMulticastGroup(const IPAddress & addrStr)
{
return m_socket->LeaveMulticastGroup(addrStr);
}
bool UdpSocket::SetMulticastLoopback(bool loopback)
{
return m_socket->SetMulticastLoopback(loopback);
}
bool UdpSocket::SetMulticastTtl(uint8_t timeToLive)
{
return m_socket->SetMulticastTtl(timeToLive);
}
uint32_t UdpSocket::GetPort()
{
return m_socket->GetPort();
}
bool UdpSocket::SetReuseAddr(bool allowReuse)
{
return m_socket->SetReuseAddr(allowReuse);
}
}

188
src/Uri.cpp Normal file
View File

@ -0,0 +1,188 @@
// https://github.com/mfichman/http
#include "Uri.hpp"
#include "Parse.hpp"
namespace std::net
{
static bool IsReserved(char ch)
{
switch (ch)
{
case '/':
return true;
case '#':
return true;
case '?':
return true;
default:
return false;
}
}
static ParseResult<std::string> ParseScheme(char const* str)
{
auto result = ParseWhile(str, [](char ch)
{
return ch != ':' && !IsReserved(ch);
});
result.ch = (result.ch[0] == ':') ? (result.ch + 1) : (result.ch);
return result;
}
static ParseResult<std::string> ParseUser(char const* str)
{
auto result = ParseWhile(str, [](char ch)
{
return ch != '@' && !IsReserved(ch);
});
if (result.ch[0] == '@')
result.ch = result.ch + 1;
else {
result.ch = str;
result.value = "";
}
return result;
}
static ParseResult<std::string> ParseHost(char const* str)
{
return ParseWhile(str, [](char ch)
{
return ch != ':' && !IsReserved(ch);
});
}
static ParseResult<uint16_t> ParsePort(char const* str)
{
ParseResult<uint16_t> result;
if (str[0] != ':')
{
result.value = 0;
result.ch = str;
return result;
}
auto tmp = ParseWhile(str + 1, [](char ch)
{
return !IsReserved(ch);
});
result.value = uint16_t(strtol(tmp.value.c_str(), 0, 10));
result.ch = tmp.ch;
return result;
}
static ParseResult<Authority> parseAuthority(char const* str)
{
ParseResult<Authority> result
{
};
if (str[0] == '\0' || str[0] != '/' || str[1] != '/')
{
result.ch = str;
return result;
}
auto user = ParseUser(str + 2); // For "//"
auto host = ParseHost(user.ch);
auto port = ParsePort(host.ch);
result.value.SetUser(user.value);
result.value.SetHost(host.value);
result.value.SetPort(port.value);
result.ch = port.ch;
return result;
}
static ParseResult<std::string> parsePath(char const* str)
{
// Return query/frag as part of path for now
ParseResult<std::string> result = ParseWhile(str, [](char ch)
{
return true;
});
/*
ParseResult<std::string> result = parseWhile(str, [](char ch) {
return ch != '/' && !isReserved(ch);
});
result.ch = (result.ch[0] == '?') ? (result.ch+1) : (result.ch);
*/
return result;
}
static Uri parseUri(char const* str)
{
Uri uri;
auto scheme = ParseScheme(str);
auto authority = parseAuthority(scheme.ch);
auto path = parsePath(authority.ch);
uri.SetScheme(scheme.value);
uri.SetAuthority(authority.value);
uri.SetPath(path.value);
return uri;
}
Authority::Authority(std::string const& user, std::string const& host, uint16_t port)
{
m_user = user;
m_host = host;
m_port = port;
}
Authority::Authority()
{
m_port = 0;
}
void Authority::SetUser(std::string const& user)
{
m_user = user;
}
void Authority::SetHost(std::string const& host)
{
m_host = host;
}
void Authority::SetPort(uint16_t port)
{
m_port = port;
}
Uri::Uri(const char* value)
{
*this = parseUri(value);
}
Uri::Uri(const std::string& value)
{
*this = parseUri(value.c_str());
}
Uri::Uri() {
}
void Uri::SetScheme(const std::string& scheme)
{
m_scheme = scheme;
}
void Uri::SetAuthority(const Authority& authority)
{
m_authority = authority;
}
void Uri::SetPath(const std::string& path)
{
m_path = path;
}
}

View File

@ -1,280 +0,0 @@
#include "Utility.hpp"
#include <fstream>
#include <sstream>
#include <algorithm>
void Utility::Delete(void *pointer)
{
if (pointer == nullptr)
return;
delete pointer;
pointer = nullptr;
}
void Utility::DeleteArray(void *pointer)
{
if (pointer == nullptr)
return;
delete[] pointer;
pointer = nullptr;
}
std::vector<std::string> Utility::StringConverter::Split(const std::string & str, const std::string & delimiter)
{
std::vector<std::string> splited;
if (str.empty() && delimiter.empty())
return std::vector<std::string>();
std::stringstream ss(str);
std::string token;
while (std::getline(ss, token, delimiter[0]))
splited.push_back(token);
return splited;
}
const std::vector<byte> &Utility::BitConverter::ToBytes(uint8 number)
{
return std::vector<byte>();
}
uint8 Utility::BitConverter::ToUint8(const std::vector<byte> &bytes, uint16 start_index)
{
return uint8();
}
const std::vector<byte> &Utility::BitConverter::ToBytes(uint16 number)
{
return std::vector<byte>();
}
uint16 Utility::BitConverter::ToUint16(const std::vector<byte> &bytes, uint16 start_index)
{
return uint16();
}
const std::vector<byte> & Utility::BitConverter::ToBytes(uint32 number)
{
return std::vector<byte>();
}
uint32 Utility::BitConverter::ToUint32(const std::vector<byte> & bytes, uint16 start_index)
{
return uint32();
}
const std::vector<byte> & Utility::BitConverter::ToBytes(uint64 number)
{
return std::vector<byte>();
}
uint64 Utility::BitConverter::ToUint64(const std::vector<byte> & bytes, uint16 start_index)
{
return uint64();
}
const std::vector<byte> & Utility::BitConverter::ToBytes(int8 number)
{
return std::vector<byte>();
}
int8 Utility::BitConverter::ToInt8(const std::vector<byte> & bytes, uint16 start_index)
{
return int8();
}
const std::vector<byte> & Utility::BitConverter::ToBytes(int16 number)
{
return std::vector<byte>();
}
int16 Utility::BitConverter::ToInt16(const std::vector<byte> & bytes, uint16 start_index)
{
return int16();
}
const std::vector<byte> & Utility::BitConverter::ToBytes(int32 number)
{
return std::vector<byte>();
}
int32 Utility::BitConverter::ToInt32(const std::vector<byte> & bytes, uint16 start_index)
{
return int32();
}
const std::vector<byte> & Utility::BitConverter::ToBytes(int64 number)
{
return std::vector<byte>();
}
int64 Utility::BitConverter::ToInt64(const std::vector<byte> & bytes, uint16 start_index)
{
return int64();
}
const std::string & Utility::StringConverter::ToString(bool value)
{
return std::string();
}
const std::string & Utility::StringConverter::ToString(uint8 value)
{
return std::string();
}
const std::string & Utility::StringConverter::ToString(uint16 value)
{
return std::string();
}
const std::string & Utility::StringConverter::ToString(uint32 value)
{
return std::string();
}
const std::string & Utility::StringConverter::ToString(uint64 value)
{
return std::string();
}
const std::string & Utility::StringConverter::ToString(int8 value)
{
return std::string();
}
const std::string & Utility::StringConverter::ToString(int16 value)
{
return std::string();
}
const std::string & Utility::StringConverter::ToString(int32 value)
{
return std::string();
}
const std::string & Utility::StringConverter::ToString(int64 value)
{
return std::string();
}
const std::string & Utility::StringConverter::ToString(const std::vector<byte>& bytes)
{
return std::string();
}
uint8 Utility::StringConverter::ToUint8(const std::string & str)
{
return uint8();
}
uint16 Utility::StringConverter::ToUint16(const std::string & str)
{
return uint16();
}
uint32 Utility::StringConverter::ToUint32(const std::string & str)
{
return uint32();
}
uint64 Utility::StringConverter::ToUint64(const std::string & str)
{
return uint64();
}
int8 Utility::StringConverter::ToInt8(const std::string & str)
{
return int8();
}
int16 Utility::StringConverter::ToInt16(const std::string & str)
{
return int16();
}
int32 Utility::StringConverter::ToInt32(const std::string & str)
{
return int32();
}
int64 Utility::StringConverter::ToInt64(const std::string & str)
{
return int64();
}
const std::vector<byte>& Utility::StringConverter::ToBytes(const std::string & str)
{
return std::vector<byte>();
}
const std::string & Utility::StringConverter::ToString(const std::vector<byte> & bytes, uint16 start_index, uint16 lenght)
{
return std::string();
}
const std::string & Utility::StringConverter::Trim(std::string & str, char ch)
{
if (str.empty() && ch == 0)
return std::string();
for (std::string::iterator it = str.begin(); it != str.end(); ++it)
{
if (*it == ch)
str.erase(it);
}
return str;
}
void Utility::ConfigReader::ReadConfig(const std::string & file_name)
{
if (file_name.empty())
return;
std::fstream file;
file.open(file_name);
if (file.is_open())
{
longlong file_lenght = file.gcount();
char *content = new char[static_cast<uint32>(file_lenght)]();
file.read(content, file_lenght);
file_content = std::string(content);
}
}
void Utility::ConfigReader::ReadNodes()
{
if (file_content.empty())
return;
std::stringstream ss(file_content);
std::string temp;
std::vector<std::string> nodes_lines;
while (std::getline(ss, temp, '\n'))
{
if (temp.substr(0, 2) != "//")
nodes_lines.emplace_back(temp);
}
for (std::vector<std::string>::iterator it = nodes_lines.begin(); it != nodes_lines.end(); ++it)
{
std::string node_str = Utility::StringConverter::Trim(*it, ' ');
std::vector<std::string> node = Utility::StringConverter::Split(node_str, "=");
nodes.insert(std::pair<std::string, std::string>(node.at(0), node.at(1)));
}
}
const std::string & Utility::ConfigReader::operator[](const std::string &key)
{
return nodes.at(key);
}
bool Utility::IPUtil::ValidIPV4(const std::string & ip)
{
std::vector<std::string> splitted_address = Utility::StringConverter::Split(ip, ".");
if (splitted_address.size() != 4)
return false;
uint8 a1 = Utility::StringConverter::ToUint8(splitted_address[0]);
uint8 a2 = Utility::StringConverter::ToUint8(splitted_address[1]);
uint8 a3 = Utility::StringConverter::ToUint8(splitted_address[2]);
uint8 a4 = Utility::StringConverter::ToUint8(splitted_address[3]);
return a1 != 0 && a2 != 0 && a3 != 0 && a4 != 0 &&
a1 != 255 && a2 != 255 && a3 != 255 && a4 != 255;
}

View File

@ -1,64 +0,0 @@
#include "VoidNetClient.hpp"
#include "Utility.hpp"
#include <future>
bool VoidNetClientAPI::Connect(const std::string &ip, uint16 port)
{
tcp_client.SetIP(ip);
tcp_client.SetPort(port);
return tcp_client.Connect();
}
void VoidNetClientAPI::SendMessageToServer(byte tag, byte subject, void *data)
{
SendMessage(Server, 0, tag, subject, data);
}
void VoidNetClientAPI::SendMessageToID(uint16 destination_id, byte tag, byte subject, void *data)
{
SendMessage(ID, destination_id, tag, subject, data);
}
void VoidNetClientAPI::SendMessageToOthers(byte tag, byte subject, void *data)
{
SendMessage(Others, 0, tag, subject, data);
}
void VoidNetClientAPI::SendMessageToAll(byte tag, byte subject, void *data)
{
SendMessage(All, 0, tag, subject, data);
}
void VoidNetClientAPI::SendMessageToAllAndMe(byte tag, byte subject, void *data)
{
SendMessage(AllAndMe, 0, tag, subject, data);
}
void VoidNetClientAPI::SendMessage(byte distribution_mode, uint16 destination_id, byte tag, byte subject, void *data)
{
NetworkMessage message;
message.tag = tag;
message.subject = subject;
message.data = data;
message.distribution_mode = distribution_mode;
message.sender = id;
message.destination_id = destination_id;
if (!IS_HANDSHAKE(message))
tcp_client.SendMessage(message);
}
void VoidNetClientAPI::Receive()
{
std::async(std::launch::async, &receive_data);
}
void VoidNetClientAPI::receive_data()
{
tcp_client.ReceiveMessages();
}
void VoidNetClientAPI::Disconnect()
{
tcp_client.Shutdown();
}