Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
afeda2281d | ||
![]() |
21372a9eb3 | ||
![]() |
88928ba722 | ||
![]() |
04ef028372 | ||
79d518f97e | |||
![]() |
76e0c6b31d | ||
![]() |
d13e86fc75 | ||
be17d51c3f | |||
43cea7b40b | |||
![]() |
f3c5bdebbb | ||
d8ee17c011 | |||
e399fcb5cb | |||
![]() |
506b4257a3 | ||
e14794529e |
@ -72,9 +72,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<TargetExt>64.lib</TargetExt>
|
<TargetExt>64.lib</TargetExt>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||||
<TargetExt>.lib</TargetExt>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
@ -130,6 +128,8 @@
|
|||||||
<Link>
|
<Link>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<AdditionalLibraryDirectories>$(SolutionDir)libs\win_crypto++\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<AdditionalDependencies>cryptlib.lib;winsqlite3.lib;shlwapi.lib;Crypt32.lib;Ws2_32.lib;Mswsock.lib;AdvApi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
<Lib>
|
<Lib>
|
||||||
<AdditionalLibraryDirectories>$(SolutionDir)libs\win_crypto++\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>$(SolutionDir)libs\win_crypto++\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
@ -7,6 +7,21 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace Crypto {
|
namespace Crypto {
|
||||||
|
static unsigned long x = 123456789, y = 362436069, z = 521288629;
|
||||||
|
|
||||||
|
unsigned long xorshf96(void) { //period 2^96-1
|
||||||
|
unsigned long t;
|
||||||
|
x ^= x << 16;
|
||||||
|
x ^= x >> 5;
|
||||||
|
x ^= x << 1;
|
||||||
|
|
||||||
|
t = x;
|
||||||
|
x = y;
|
||||||
|
y = z;
|
||||||
|
z = t ^ x ^ y;
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
namespace AES {
|
namespace AES {
|
||||||
// -------- AES START --------
|
// -------- AES START --------
|
||||||
@ -38,7 +53,7 @@ namespace Crypto {
|
|||||||
|
|
||||||
(*resultingSize) = t;
|
(*resultingSize) = t;
|
||||||
|
|
||||||
char* cipher = (char*)malloc(t);
|
char* cipher = (char*)new char[t];
|
||||||
memcpy(cipher, ciphertext.c_str(), t);
|
memcpy(cipher, ciphertext.c_str(), t);
|
||||||
|
|
||||||
return cipher;
|
return cipher;
|
||||||
@ -61,11 +76,11 @@ namespace Crypto {
|
|||||||
|
|
||||||
*resultSize = decryptedtext.size();
|
*resultSize = decryptedtext.size();
|
||||||
|
|
||||||
char* c = (char*)malloc(*resultSize);
|
char* c = (char*)new char[*resultSize];
|
||||||
//memset(c, 0, decryptedtext.size());
|
//memset(c, 0, decryptedtext.size());
|
||||||
memcpy(c, decryptedtext.c_str(), decryptedtext.size());
|
memcpy(c, decryptedtext.c_str(), decryptedtext.size());
|
||||||
|
|
||||||
decryptedtext.~basic_string();
|
//decryptedtext.~basic_string();
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -74,9 +89,15 @@ namespace Crypto {
|
|||||||
Payload aes_auto_encrypt(void* msg, ulong_64b size) {
|
Payload aes_auto_encrypt(void* msg, ulong_64b size) {
|
||||||
char* message = (char*)msg;
|
char* message = (char*)msg;
|
||||||
Payload p;
|
Payload p;
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
p.key = (char*)malloc(sizeof(AES_KEY));
|
// Generate random number 'n stuff
|
||||||
|
for (volatile unsigned int i = ((unsigned int)rand())%4096; i > 0; --i) xorshf96();
|
||||||
|
time_t t = (time_t) xorshf96();
|
||||||
|
if (sizeof(long) < sizeof(time_t)) t ^= xorshf96() << ((sizeof(time_t) / 2) + (sizeof(time_t)%2)); // Fill ALL the bits!
|
||||||
|
srand(time(NULL)+(signed long long)t);
|
||||||
|
|
||||||
|
|
||||||
|
p.key = (char*)new char[sizeof(AES_KEY)];
|
||||||
AES_KEY k = (AES_KEY)rand();
|
AES_KEY k = (AES_KEY)rand();
|
||||||
|
|
||||||
p.keySize = sizeof(AES_KEY);
|
p.keySize = sizeof(AES_KEY);
|
||||||
@ -142,9 +163,15 @@ namespace Crypto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace RSA {
|
namespace RSA {
|
||||||
|
|
||||||
|
KeyData::KeyData(CryptoPP::RSA::PrivateKey *priv, CryptoPP::RSA::PublicKey *pub) : privKey(priv), publKey(pub) { }
|
||||||
|
KeyData::~KeyData() {
|
||||||
|
delete privKey;
|
||||||
|
delete publKey;
|
||||||
|
}
|
||||||
|
|
||||||
// -------- RSA START --------
|
// -------- RSA START --------
|
||||||
KeyData rsa_gen_keys() {
|
KeyData* rsa_gen_keys() {
|
||||||
KeyData k;
|
|
||||||
|
|
||||||
CryptoPP::InvertibleRSAFunction params;
|
CryptoPP::InvertibleRSAFunction params;
|
||||||
CryptoPP::RandomPool rng;
|
CryptoPP::RandomPool rng;
|
||||||
@ -153,8 +180,8 @@ namespace Crypto {
|
|||||||
rng.IncorporateEntropy((const byte*)&t, sizeof(t) * 8);
|
rng.IncorporateEntropy((const byte*)&t, sizeof(t) * 8);
|
||||||
|
|
||||||
params.GenerateRandomWithKeySize(rng, 3072);
|
params.GenerateRandomWithKeySize(rng, 3072);
|
||||||
k.privKey = CryptoPP::RSA::PrivateKey(params);
|
|
||||||
k.publKey = CryptoPP::RSA::PublicKey(params);
|
KeyData *k = new KeyData(new CryptoPP::RSA::PrivateKey(params), new CryptoPP::RSA::PublicKey(params));
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +191,7 @@ namespace Crypto {
|
|||||||
//func.DEREncodePublicKey(queue);
|
//func.DEREncodePublicKey(queue);
|
||||||
|
|
||||||
|
|
||||||
byte* shortened = (byte*)malloc(*rSize=queue.TotalBytesRetrievable());
|
byte* shortened = (byte*)new byte[*rSize=queue.TotalBytesRetrievable()];
|
||||||
memset(shortened, 0, *rSize);
|
memset(shortened, 0, *rSize);
|
||||||
|
|
||||||
std::vector<byte> spk;
|
std::vector<byte> spk;
|
||||||
@ -178,6 +205,44 @@ namespace Crypto {
|
|||||||
return (char*)shortened;
|
return (char*)shortened;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* serializePrivKey(CryptoPP::RSA::PrivateKey& func, ulong_64b* rSize) {
|
||||||
|
CryptoPP::ByteQueue queue;
|
||||||
|
func.Save(queue);
|
||||||
|
//func.DEREncodePublicKey(queue);
|
||||||
|
|
||||||
|
|
||||||
|
byte* shortened = (byte*)new byte[*rSize = queue.TotalBytesRetrievable()];
|
||||||
|
memset(shortened, 0, *rSize);
|
||||||
|
|
||||||
|
std::vector<byte> spk;
|
||||||
|
spk.resize(queue.TotalBytesRetrievable());
|
||||||
|
|
||||||
|
CryptoPP::ArraySink snk(&spk[0], spk.size());
|
||||||
|
queue.CopyTo(snk);
|
||||||
|
|
||||||
|
for (ulong_64b t = 0; t < spk.size(); ++t) shortened[t] = spk.at(t);
|
||||||
|
|
||||||
|
return (char*)shortened;
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptoPP::RSA::PublicKey* deserializePublicKey(char* c, ulong_64b size) {
|
||||||
|
CryptoPP::RSA::PublicKey *pK = new CryptoPP::RSA::PublicKey();
|
||||||
|
|
||||||
|
CryptoPP::StringSource src((const byte*)c, size, true);
|
||||||
|
pK->Load(src);
|
||||||
|
|
||||||
|
return pK;
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptoPP::RSA::PrivateKey* deserializePrivateKey(char* c, ulong_64b size) {
|
||||||
|
CryptoPP::RSA::PrivateKey *pK = new CryptoPP::RSA::PrivateKey();
|
||||||
|
|
||||||
|
CryptoPP::StringSource src((const byte*)c, size, true);
|
||||||
|
pK->Load(src);
|
||||||
|
|
||||||
|
return pK;
|
||||||
|
}
|
||||||
|
|
||||||
char* rsa_encrypt(void* msg, ulong_64b size, CryptoPP::RSA::PublicKey& pubKey, ulong_64b* resultingSize) {
|
char* rsa_encrypt(void* msg, ulong_64b size, CryptoPP::RSA::PublicKey& pubKey, ulong_64b* resultingSize) {
|
||||||
char* message = (char*)msg;
|
char* message = (char*)msg;
|
||||||
CryptoPP::RandomPool rng;
|
CryptoPP::RandomPool rng;
|
||||||
@ -191,9 +256,10 @@ namespace Crypto {
|
|||||||
|
|
||||||
*resultingSize = cipher.size();
|
*resultingSize = cipher.size();
|
||||||
|
|
||||||
char* c = (char*)malloc(cipher.size());
|
char* c = (char*)new char[cipher.size()];
|
||||||
memset(c, 0, cipher.size());
|
//memset(c, 0, cipher.size());
|
||||||
memcpy(c, cipher.c_str(), cipher.size());
|
memcpy(c, cipher.c_str(), cipher.size());
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,9 +276,11 @@ namespace Crypto {
|
|||||||
|
|
||||||
*resultingSize = clear.size();
|
*resultingSize = clear.size();
|
||||||
|
|
||||||
char* c = (char*)malloc(clear.size());
|
char* c = (char*)new char[clear.size()];
|
||||||
memset(c, 0, clear.size());
|
//memset(c, 0, clear.size());
|
||||||
memcpy(c, clear.c_str(), clear.size());
|
memcpy(c, clear.c_str(), clear.size());
|
||||||
|
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
// -------- RSA END --------
|
// -------- RSA END --------
|
||||||
@ -220,14 +288,21 @@ namespace Crypto {
|
|||||||
|
|
||||||
char* full_auto_encrypt(void* msg, ulong_64b mSize, CryptoPP::RSA::PublicKey& pk, ulong_64b* rSize) {
|
char* full_auto_encrypt(void* msg, ulong_64b mSize, CryptoPP::RSA::PublicKey& pk, ulong_64b* rSize) {
|
||||||
AES::Payload p = AES::aes_auto_encrypt(msg, mSize);
|
AES::Payload p = AES::aes_auto_encrypt(msg, mSize);
|
||||||
p.key = RSA::rsa_encrypt(p.key, p.keySize, pk, &p.keySize);
|
char *c = RSA::rsa_encrypt(p.key, p.keySize, pk, &p.keySize);
|
||||||
|
delete[] p.key;
|
||||||
|
p.key = c;
|
||||||
return p.serialize(rSize);
|
return p.serialize(rSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* full_auto_decrypt(void* msg, CryptoPP::RSA::PrivateKey& pk, ulong_64b* rSize) {
|
char* full_auto_decrypt(void* msg, CryptoPP::RSA::PrivateKey& pk, ulong_64b* rSize) {
|
||||||
ulong_64b size;
|
ulong_64b size;
|
||||||
AES::Payload p = AES::deserializePayload(msg, &size);
|
AES::Payload p = AES::deserializePayload(msg, &size);
|
||||||
p.key = RSA::rsa_decrypt(p.key, p.keySize, pk, &p.keySize);
|
char *c = RSA::rsa_decrypt(p.key, p.keySize, pk, &p.keySize);
|
||||||
return AES::aes_auto_decrypt(p, rSize);
|
delete[] p.key;
|
||||||
|
p.key = c;
|
||||||
|
c = AES::aes_auto_decrypt(p, rSize);
|
||||||
|
delete[] p.key;
|
||||||
|
delete[] p.ldPayload;
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -50,13 +50,18 @@ namespace Crypto {
|
|||||||
|
|
||||||
namespace RSA {
|
namespace RSA {
|
||||||
struct KeyData {
|
struct KeyData {
|
||||||
CryptoPP::RSA::PrivateKey privKey;
|
const CryptoPP::RSA::PrivateKey *privKey;
|
||||||
CryptoPP::RSA::PublicKey publKey;
|
const CryptoPP::RSA::PublicKey *publKey;
|
||||||
|
KeyData(CryptoPP::RSA::PrivateKey*, CryptoPP::RSA::PublicKey*);
|
||||||
|
~KeyData();
|
||||||
};
|
};
|
||||||
|
|
||||||
char* serializeKey(CryptoPP::RSA::PublicKey&, ulong_64b* rSize);
|
char* serializeKey(CryptoPP::RSA::PublicKey&, ulong_64b* rSize);
|
||||||
|
char* serializePrivKey(CryptoPP::RSA::PrivateKey&, ulong_64b* rSize);
|
||||||
|
CryptoPP::RSA::PublicKey* deserializePublicKey(char* c, ulong_64b size);
|
||||||
|
CryptoPP::RSA::PrivateKey* deserializePrivateKey(char* c, ulong_64b size);
|
||||||
|
|
||||||
KeyData rsa_gen_keys();
|
KeyData* rsa_gen_keys();
|
||||||
char* rsa_encrypt(void* message, ulong_64b size, CryptoPP::RSA::PublicKey& pubKey, ulong_64b* resultingSize);
|
char* rsa_encrypt(void* message, ulong_64b size, CryptoPP::RSA::PublicKey& pubKey, ulong_64b* resultingSize);
|
||||||
char* rsa_decrypt(void* message, ulong_64b size, CryptoPP::RSA::PrivateKey& privKey, ulong_64b* resultingSize);
|
char* rsa_decrypt(void* message, ulong_64b size, CryptoPP::RSA::PrivateKey& privKey, ulong_64b* resultingSize);
|
||||||
}
|
}
|
||||||
|
451
CPPTools/Net.cpp
451
CPPTools/Net.cpp
@ -1,41 +1,73 @@
|
|||||||
#include "Net.h"
|
#include "Net.h"
|
||||||
|
#include "Support.h"
|
||||||
|
|
||||||
|
#include <future>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
namespace IO {
|
namespace IO {
|
||||||
|
|
||||||
bool connected(SOCKET sock)
|
AsyncKeys::AsyncKeys() {
|
||||||
{
|
gen = std::async(std::launch::async, [this]() {
|
||||||
char buf;
|
Crypto::RSA::KeyData *data = Crypto::RSA::rsa_gen_keys();
|
||||||
int err = recv(sock, &buf, 1, MSG_PEEK);
|
done = true;
|
||||||
if (err == SOCKET_ERROR)
|
return data;
|
||||||
{
|
});
|
||||||
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
done = suppressDelete = false;
|
||||||
{
|
chain = false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
AsyncKeys::AsyncKeys(Crypto::RSA::KeyData* predef) {
|
||||||
|
done = suppressDelete = true;
|
||||||
|
keys = predef;
|
||||||
|
chain = false;
|
||||||
|
}
|
||||||
|
AsyncKeys::AsyncKeys(AsyncKeys* chainKeys) {
|
||||||
|
this->chainKeys = chainKeys;
|
||||||
|
chain = true;
|
||||||
|
}
|
||||||
|
AsyncKeys::~AsyncKeys() {
|
||||||
|
if (!chain && !suppressDelete) delete keys;
|
||||||
|
}
|
||||||
|
Crypto::RSA::KeyData* AsyncKeys::get() {
|
||||||
|
if (chain) return chainKeys->get();
|
||||||
|
if (!done) {
|
||||||
|
keys = gen.get();
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool cryptoLevelsAreCompatible(CryptoLevel l1, CryptoLevel l2) {
|
bool cryptoLevelsAreCompatible(CryptoLevel l1, CryptoLevel l2) {
|
||||||
return !(((l1 == CryptoLevel::None) && (l2 == CryptoLevel::Force)) || ((l2 == CryptoLevel::None) && (l1 == CryptoLevel::Force)));
|
return !(((l1 == CryptoLevel::None) && (l2 == CryptoLevel::Force)) || ((l2 == CryptoLevel::None) && (l1 == CryptoLevel::Force)));
|
||||||
}
|
}
|
||||||
|
|
||||||
char* __cdecl readSparse(std::vector<char>* sparse, ulong_64b rSize, bool pop = true) {
|
char* __cdecl readSparse(std::vector<char>* sparse, ulong_64b rSize, bool pop = true) {
|
||||||
if (sparse->size() < rSize) throw new _exception(); // This should never happen if function is used correctly
|
if (sparse->size() < rSize) throw new std::exception(); // This should never happen if function is used correctly
|
||||||
char* c = new char[rSize];
|
char* c = new char[rSize];
|
||||||
for (ulong_64b b = 0; b < rSize; ++b) c[b] = sparse->at(b);
|
for (ulong_64b b = 0; b < rSize; ++b) c[b] = sparse->at(b);
|
||||||
if (pop) sparse->erase(sparse->begin(), sparse->begin() + rSize);
|
if (pop) sparse->erase(sparse->begin(), sparse->begin() + rSize);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void flushPrecedingPings(std::vector<char>* sparse) {
|
||||||
|
while (sparse->size() >= sizeof(ulong_64b)) {
|
||||||
|
ulong_64b size = 0;
|
||||||
|
char* c = readSparse(sparse, sizeof(ulong_64b), false);
|
||||||
|
memcpy(&size, c, sizeof(ulong_64b));
|
||||||
|
delete[] c;
|
||||||
|
if (size != FLAG_PING) return;
|
||||||
|
else delete[] readSparse(sparse, sizeof(ulong_64b)); // If this block is a ping packet, remove it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool hasFullMessage(std::vector<char> *sparse) {
|
bool hasFullMessage(std::vector<char> *sparse) {
|
||||||
if (sparse->size() < sizeof(ulong_64b)) return false;
|
if (sparse->size() < sizeof(ulong_64b)) return false;
|
||||||
|
flushPrecedingPings(sparse);
|
||||||
ulong_64b size = 0;
|
ulong_64b size = 0;
|
||||||
char* c = readSparse(sparse, sizeof(ulong_64b), false);
|
char* c = readSparse(sparse, sizeof(ulong_64b), false);
|
||||||
memcpy(&size, c, sizeof(ulong_64b));
|
memcpy(&size, c, sizeof(ulong_64b));
|
||||||
@ -45,27 +77,30 @@ namespace IO {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void NetClient::sharedSetup() {
|
void NetClient::sharedSetup(bool setupKeys) {
|
||||||
if (preferEncrypted != CryptoLevel::None) keys = Crypto::RSA::rsa_gen_keys();
|
if (setupKeys && (preferEncrypted != CryptoLevel::None)) keyData = new AsyncKeys();
|
||||||
packets = new std::vector<Packet>();
|
packets = new std::vector<Packet>();
|
||||||
sparse = new std::vector<char>();
|
sparse = new std::vector<char>();
|
||||||
outPacketBuf = new std::vector<Packet>();
|
outPacketBuf = new std::vector<Packet>();
|
||||||
|
rBuf.resize(1);
|
||||||
_open = true;
|
_open = true;
|
||||||
canWrite = true;
|
canWrite = true;
|
||||||
evt = nullptr;
|
evt = nullptr;
|
||||||
char cryptoPref = static_cast<char>(preferEncrypted);
|
char cryptoPref = static_cast<char>(preferEncrypted);
|
||||||
if (send(_socket, &cryptoPref, 1, 0) == SOCKET_ERROR) throw new _exception(); // Cannot establish connection :(
|
commTime = time(nullptr);
|
||||||
|
if (send(_socket, &cryptoPref, 1, 0) == SOCKET_ERROR) throw new std::exception(); // Cannot establish connection :(
|
||||||
if (!noThread) listener = std::thread([](NetClient& cli) { while (cli._open) { cli.update(); Sleep(25); } }, std::ref(*this)); // Setup separate thread for reading new data
|
if (!noThread) listener = std::thread([](NetClient& cli) { while (cli._open) { cli.update(); Sleep(25); } }, std::ref(*this)); // Setup separate thread for reading new data
|
||||||
}
|
}
|
||||||
NetClient::NetClient(char* ipAddr, char* port, CryptoLevel preferEncrypted) :
|
NetClient::NetClient(char* ipAddr, char* port, CryptoLevel preferEncrypted) : NetClient(ipAddr, port, preferEncrypted, true) {}
|
||||||
commTime(time(nullptr)), preferEncrypted(preferEncrypted), startNegotiate(false)
|
NetClient::NetClient(char* ipAddr, char* port, CryptoLevel preferEncrypted, bool setupKeys) :
|
||||||
|
preferEncrypted(preferEncrypted), startNegotiate(false)
|
||||||
{
|
{
|
||||||
_socket = INVALID_SOCKET;
|
_socket = INVALID_SOCKET;
|
||||||
this->noThread = false;
|
this->noThread = false;
|
||||||
|
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
if (iResult != 0) throw new _exception();
|
if (iResult != 0) throw new std::exception();
|
||||||
|
|
||||||
|
|
||||||
struct addrinfo *result = NULL, *ptr = NULL, hints;
|
struct addrinfo *result = NULL, *ptr = NULL, hints;
|
||||||
@ -77,14 +112,14 @@ namespace IO {
|
|||||||
|
|
||||||
iResult = getaddrinfo(ipAddr, port, &hints, &result);
|
iResult = getaddrinfo(ipAddr, port, &hints, &result);
|
||||||
|
|
||||||
if (iResult) throw new _exception();
|
if (iResult) throw new std::exception();
|
||||||
|
|
||||||
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
|
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
|
||||||
|
|
||||||
// Create a SOCKET for connecting to server
|
// Create a SOCKET for connecting to server
|
||||||
_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
|
_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
|
||||||
if (_socket == INVALID_SOCKET) {
|
if (_socket == INVALID_SOCKET) {
|
||||||
throw new _exception();
|
throw new std::exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect to server.
|
// Connect to server.
|
||||||
@ -99,20 +134,31 @@ namespace IO {
|
|||||||
|
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
|
|
||||||
if (_socket == INVALID_SOCKET) throw new _exception();
|
if (_socket == INVALID_SOCKET) throw new std::exception();
|
||||||
|
|
||||||
sharedSetup();
|
sharedSetup(setupKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
NetClient::NetClient(SOCKET wrap, bool noThread, Crypto::RSA::KeyData& keys, CryptoLevel preferEncrypted, bool startNegotiate) :
|
NetClient::NetClient(char* ipAddr, char* port, AsyncKeys *keyData, CryptoLevel level) : NetClient(ipAddr, port, level, false) { this->keyData = keyData; }
|
||||||
commTime(time(nullptr)), preferEncrypted(preferEncrypted), startNegotiate(startNegotiate)
|
|
||||||
|
NetClient::NetClient(SOCKET wrap, bool noThread, AsyncKeys *keyData, CryptoLevel preferEncrypted, bool startNegotiate) :
|
||||||
|
preferEncrypted(preferEncrypted), startNegotiate(startNegotiate)
|
||||||
{
|
{
|
||||||
_socket = wrap;
|
_socket = wrap;
|
||||||
this->noThread = noThread;
|
this->noThread = noThread;
|
||||||
sharedSetup();
|
this->keyData = new AsyncKeys(keyData);
|
||||||
|
sharedSetup(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
NetClient::~NetClient() {
|
NetClient::~NetClient() {
|
||||||
|
delete keyData;
|
||||||
|
for (std::pair<char*, std::pair<ulong_64b, char*>*> *p : associatedData) {
|
||||||
|
delete[] p->first;
|
||||||
|
delete[] p->second->second;
|
||||||
|
delete p->second;
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
associatedData.clear();
|
||||||
packets->clear();
|
packets->clear();
|
||||||
delete packets;
|
delete packets;
|
||||||
sparse->clear();
|
sparse->clear();
|
||||||
@ -120,6 +166,10 @@ namespace IO {
|
|||||||
if (isOpen()) close();
|
if (isOpen()) close();
|
||||||
}
|
}
|
||||||
bool NetClient::close() {
|
bool NetClient::close() {
|
||||||
|
if (getBOPCount()) {
|
||||||
|
scheduleTerminate = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
bool result = !_open;
|
bool result = !_open;
|
||||||
_open = false;
|
_open = false;
|
||||||
result &= (SOCKET_ERROR == shutdown(_socket, SD_BOTH));
|
result &= (SOCKET_ERROR == shutdown(_socket, SD_BOTH));
|
||||||
@ -130,18 +180,46 @@ namespace IO {
|
|||||||
shutdown(_socket, SD_SEND);
|
shutdown(_socket, SD_SEND);
|
||||||
canWrite = false;
|
canWrite = false;
|
||||||
}
|
}
|
||||||
bool NetClient::_write(char* message, ulong_64b size) {
|
bool NetClient::ping() {
|
||||||
int i;
|
int i;
|
||||||
char* c = new char[sizeof(ulong_64b)];
|
char* c = new char[sizeof(ulong_64b)];
|
||||||
memcpy(c, &size, sizeof(ulong_64b));
|
ulong_64b pingValue = FLAG_PING;
|
||||||
|
memcpy(c, (const char*)&pingValue, sizeof(ulong_64b));
|
||||||
for (ulong_64b wIdx = 0; wIdx < sizeof(ulong_64b); ++wIdx) {
|
for (ulong_64b wIdx = 0; wIdx < sizeof(ulong_64b); ++wIdx) {
|
||||||
if ((i = send(_socket, c + wIdx, 1, 0)) == SOCKET_ERROR) return false;
|
if ((i = send(_socket, c + wIdx, 1, 0)) == SOCKET_ERROR) return false;
|
||||||
else if (i == 0) --wIdx;
|
else if (i == 0) --wIdx;
|
||||||
}
|
}
|
||||||
for (ulong_64b wIdx = 0; wIdx < size; ++wIdx) {
|
commTime = time(nullptr);
|
||||||
if ((i = send(_socket, message + wIdx, 1, 0)) == SOCKET_ERROR) return false;
|
delete[] c;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NetClient::getBOPCount() { return firstMessage ? outPacketBuf->size() : 0; }
|
||||||
|
|
||||||
|
bool NetClient::_write(char* message, ulong_64b size) {
|
||||||
|
if (size==FLAG_PING) throw new std::exception(); // Max value is reserved for ping packet
|
||||||
|
int i;
|
||||||
|
char* c = new char[sizeof(ulong_64b)];
|
||||||
|
memcpy(c, &size, sizeof(ulong_64b));
|
||||||
|
for (ulong_64b wIdx = 0; wIdx < sizeof(ulong_64b); ++wIdx) {
|
||||||
|
if ((i = send(_socket, c + wIdx, 1, 0)) == SOCKET_ERROR) {
|
||||||
|
delete[] message;
|
||||||
|
delete[] c;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
else if (i == 0) --wIdx;
|
else if (i == 0) --wIdx;
|
||||||
}
|
}
|
||||||
|
for (ulong_64b wIdx = 0; wIdx < size; ++wIdx) {
|
||||||
|
if ((i = send(_socket, message + wIdx, 1, 0)) == SOCKET_ERROR) {
|
||||||
|
delete[] message;
|
||||||
|
delete[] c;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (i == 0) --wIdx;
|
||||||
|
}
|
||||||
|
commTime = time(nullptr);
|
||||||
|
if(autoDelete) delete[] message;
|
||||||
|
delete[] c;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool NetClient::write(void* message, ulong_64b size) {
|
bool NetClient::write(void* message, ulong_64b size) {
|
||||||
@ -153,9 +231,16 @@ namespace IO {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!canWrite) return false;
|
if (!canWrite) return false;
|
||||||
char* msg = encrypted ? Crypto::full_auto_encrypt(message, size, pK, &size) : (char*)message;
|
char* bMsg = new char[size+1];
|
||||||
_write(msg, size + encrypted);
|
bMsg[0] = remotePUID;
|
||||||
if (encrypted) delete[] msg;
|
++remotePUID;
|
||||||
|
memcpy(bMsg + 1, message, size);
|
||||||
|
++size;
|
||||||
|
char* msg = encrypted ? Crypto::full_auto_encrypt(bMsg, size, pK, &size) : (char*)bMsg;
|
||||||
|
_write(msg, size);
|
||||||
|
if (!autoDelete && encrypted) delete[] msg;
|
||||||
|
delete[] bMsg;
|
||||||
|
if (autoDelete) delete[] message;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool NetClient::write(char* message) { return write(message, strlen(message)+1); } // Send together with the null-terminator
|
bool NetClient::write(char* message) { return write(message, strlen(message)+1); } // Send together with the null-terminator
|
||||||
@ -170,7 +255,7 @@ namespace IO {
|
|||||||
packets->erase(packets->begin(), packets->begin() + 1); // Delete first buffered packet
|
packets->erase(packets->begin(), packets->begin() + 1); // Delete first buffered packet
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
throw new _exception(); // No packets available!
|
throw new std::exception(); // No packets available!
|
||||||
}
|
}
|
||||||
void NetClient::setEventHandler(std::function<void(NetClient*, Packet)> _ev) {
|
void NetClient::setEventHandler(std::function<void(NetClient*, Packet)> _ev) {
|
||||||
evt = _ev;
|
evt = _ev;
|
||||||
@ -185,29 +270,41 @@ namespace IO {
|
|||||||
}
|
}
|
||||||
bool NetClient::isEncrypted() { return encrypted; }
|
bool NetClient::isEncrypted() { return encrypted; }
|
||||||
void NetClient::update() {
|
void NetClient::update() {
|
||||||
/*if (!connected(_socket)) { // Check this later...
|
|
||||||
_open = false;
|
|
||||||
close();
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
int iResult = 0, rdErr;
|
int iResult = 0, rdErr;
|
||||||
unsigned long rCount;
|
unsigned long rCount;
|
||||||
rdErr = ioctlsocket(_socket, FIONREAD, &rCount);
|
rdErr = ioctlsocket(_socket, FIONREAD, &rCount);
|
||||||
if (rdErr == SOCKET_ERROR) throw new _exception(); // Error using socket :(
|
if (rdErr == SOCKET_ERROR) throw new _exception(); // Error using socket :(
|
||||||
if (rCount > 0) {
|
if (rCount > 0) {
|
||||||
iResult = recv(_socket, rBuf, BUFSIZE, 0);
|
rBuf.resize(rCount);
|
||||||
|
iResult = recv(_socket, &rBuf[0], rCount, 0);
|
||||||
if (iResult > 0)
|
if (iResult > 0)
|
||||||
for (int i = 0; i < iResult; ++i)
|
for (int i = 0; i < iResult; ++i)
|
||||||
if (sparse->size() < BUF_2_MAX)
|
if (sparse->size() < BUF_2_MAX)
|
||||||
sparse->push_back(rBuf[i]); // Drop anything over the absolute max
|
sparse->push_back(rBuf[i]); // Drop anything over the absolute max
|
||||||
|
commTime = time(nullptr);
|
||||||
|
if(!firstMessage) flushPrecedingPings(sparse);
|
||||||
}
|
}
|
||||||
while (!firstMessage && hasFullMessage(sparse)) {
|
while (!firstMessage && hasFullMessage(sparse)) {
|
||||||
Packet p;
|
Packet p;
|
||||||
|
|
||||||
char* size = readSparse(sparse, sizeof(ulong_64b));
|
char* size = readSparse(sparse, sizeof(ulong_64b));
|
||||||
memcpy(&p.size, size, sizeof(ulong_64b));
|
memcpy(&p.size, size, sizeof(ulong_64b));
|
||||||
delete[] size;
|
delete[] size;
|
||||||
|
|
||||||
p.message = readSparse(sparse, p.size);
|
p.message = readSparse(sparse, p.size);
|
||||||
if (encrypted) p.message = Crypto::full_auto_decrypt(p.message, keys.privKey, &p.size);
|
if (encrypted) p.message = Crypto::full_auto_decrypt(p.message, (CryptoPP::RSA::PrivateKey&)*keyData->get()->privKey, &p.size);
|
||||||
|
|
||||||
|
p.packetUID = p.message[0];
|
||||||
|
if (p.packetUID != expectedNextPUID) continue; // Detect packet replay/mismatch
|
||||||
|
else ++expectedNextPUID;
|
||||||
|
|
||||||
|
--p.size;
|
||||||
|
|
||||||
|
char* c = new char[p.size];
|
||||||
|
memcpy(c, p.message + 1, p.size);
|
||||||
|
delete[] p.message;
|
||||||
|
p.message = c;
|
||||||
|
|
||||||
if (evt == nullptr) packets->push_back(p);
|
if (evt == nullptr) packets->push_back(p);
|
||||||
else evt(this, p); // Notify event handler of a new packet
|
else evt(this, p); // Notify event handler of a new packet
|
||||||
}
|
}
|
||||||
@ -228,12 +325,12 @@ namespace IO {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ulong_64b size;
|
ulong_64b size;
|
||||||
char* c = Crypto::RSA::serializeKey(keys.publKey, &size);
|
char* c = Crypto::RSA::serializeKey((CryptoPP::RSA::PublicKey&)*keyData->get()->publKey, &size);
|
||||||
_write(c, size); // This shouldn't be encrypted
|
_write(c, size); // This shouldn't be encrypted
|
||||||
delete[] c;
|
if(!autoDelete) delete[] c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else throw new _exception(); // Incompatible cryptographic requirements!
|
else throw new std::exception(); // Incompatible cryptographic requirements!
|
||||||
}
|
}
|
||||||
if (fm_neg_hasLevel && !fm_neg_hasSize && encrypted && sparse->size() >= sizeof(ulong_64b)) {
|
if (fm_neg_hasLevel && !fm_neg_hasSize && encrypted && sparse->size() >= sizeof(ulong_64b)) {
|
||||||
fm_neg_hasSize = true;
|
fm_neg_hasSize = true;
|
||||||
@ -258,29 +355,73 @@ namespace IO {
|
|||||||
_open = false;
|
_open = false;
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
if (autoPing && ((time(nullptr) - commTime) > 1)) if (!ping()) { _open = false; close(); }
|
||||||
|
if (scheduleTerminate && !getBOPCount()) close();
|
||||||
}
|
}
|
||||||
bool NetClient::isOpen() { return _open; }
|
bool NetClient::isOpen() { return _open; }
|
||||||
|
|
||||||
void NetClient::setOnDestroy(std::function<void()> call) { onDestroy = call; }
|
void NetClient::setOnDestroy(std::function<void()> call) { onDestroy = call; }
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<ulong_64b, char*> NetClient::getValue(const char* name, bool copy) {
|
||||||
|
for(std::pair<char*, std::pair<ulong_64b, char*>*>* p : associatedData)
|
||||||
|
if (!strcmp(p->first, name)) {
|
||||||
|
char* c = copy ? new char[p->second->first] : p->second->second;
|
||||||
|
if (copy) memcpy(c, p->second->second, p->second->first);
|
||||||
|
return std::pair<ulong_64b, char*>(p->second->first, c);
|
||||||
|
}
|
||||||
|
return std::pair<ulong_64b, char*>(0, nullptr);
|
||||||
|
}
|
||||||
|
char* NetClient::getStrValue(const char* name, bool copy) {
|
||||||
|
return getValue(name, copy).second;
|
||||||
|
}
|
||||||
|
void NetClient::setValue(const char* name, std::pair<ulong_64b, char*> value, bool copy, bool del) {
|
||||||
|
for (std::pair<char*, std::pair<ulong_64b, char*>*>* p : associatedData)
|
||||||
|
if (!strcmp(p->first, name)) {
|
||||||
|
p->second->first = value.first;
|
||||||
|
if (del) delete[] p->second->second;
|
||||||
|
char* c = copy ? new char[value.first] : value.second;
|
||||||
|
if (copy) memcpy(c, value.second, value.first);
|
||||||
|
p->second->second = c;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::pair<char*, std::pair<ulong_64b, char*>*>* p = new std::pair<char*, std::pair<ulong_64b, char*>*>();
|
||||||
|
p->first = (char*)name;
|
||||||
|
p->second = new std::pair<ulong_64b, char*>();
|
||||||
|
p->second->first = value.first;
|
||||||
|
if (del) delete[] p->second->second;
|
||||||
|
char* c = copy ? new char[value.first] : value.second;
|
||||||
|
if (copy) memcpy(c, value.second, value.first);
|
||||||
|
p->second->second = c;
|
||||||
|
|
||||||
|
associatedData.push_back(p);
|
||||||
|
}
|
||||||
|
void NetClient::setValue(const char* name, char* value, bool copy, bool del) {
|
||||||
|
setValue(name, std::pair<ulong_64b, char*>(strlen(value), value), copy, del);
|
||||||
|
}
|
||||||
|
bool NetClient::removeValue(const char* name, bool del) {
|
||||||
|
for (size_t t = associatedData.size(); t>0; --t)
|
||||||
|
if (!strcmp(associatedData.at(t-1)->first, name)) {
|
||||||
|
if (del) delete[] associatedData.at(t-1)->second->second;
|
||||||
|
associatedData.erase(associatedData.begin()+t-1, associatedData.begin()+t);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool NetClient::containsKey(const char* name) {
|
||||||
|
for (size_t t = associatedData.size(); t>0; --t)
|
||||||
|
if (!strcmp(associatedData.at(t - 1)->first, name))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ulong_64b NetClient::available() { return packets->size(); }
|
ulong_64b NetClient::available() { return packets->size(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool NetServer::close() {
|
|
||||||
if (!_open) return false;
|
|
||||||
_open = false;
|
|
||||||
for (ulong_64b t = clients->size(); t > 0; --t) {
|
|
||||||
NetClient* s = clients->at(t - 1);
|
|
||||||
s->close();
|
|
||||||
clients->pop_back();
|
|
||||||
delete s;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetServer::NetServer(char* port, std::function<bool(NetClient*)> f = nullptr, CryptoLevel pref = CryptoLevel::None) : pref(pref) {
|
|
||||||
if (pref != CryptoLevel::None) keys = Crypto::RSA::rsa_gen_keys();
|
void NetServer::sharedSetup(char* port, std::function<bool(NetClient*)> f) {
|
||||||
_open = true;
|
_open = true;
|
||||||
timeoutHandler = NULL;
|
timeoutHandler = NULL;
|
||||||
onDestroy = NULL;
|
onDestroy = NULL;
|
||||||
@ -297,7 +438,7 @@ namespace IO {
|
|||||||
|
|
||||||
// Initialize Winsock
|
// Initialize Winsock
|
||||||
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
if (iResult != 0) throw new _exception();
|
if (iResult != 0) throw new std::exception();
|
||||||
|
|
||||||
|
|
||||||
ZeroMemory(&hints, sizeof(hints));
|
ZeroMemory(&hints, sizeof(hints));
|
||||||
@ -309,14 +450,14 @@ namespace IO {
|
|||||||
// Resolve the server address and port
|
// Resolve the server address and port
|
||||||
iResult = getaddrinfo(NULL, port, &hints, &result);
|
iResult = getaddrinfo(NULL, port, &hints, &result);
|
||||||
if (iResult) {
|
if (iResult) {
|
||||||
throw new _exception();
|
throw new std::exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a SOCKET for connecting to server
|
// Create a SOCKET for connecting to server
|
||||||
_server = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
_server = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
||||||
if (_server == INVALID_SOCKET) {
|
if (_server == INVALID_SOCKET) {
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
throw new _exception();
|
throw new std::exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the TCP listening socket
|
// Setup the TCP listening socket
|
||||||
@ -324,31 +465,31 @@ namespace IO {
|
|||||||
if (iResult == SOCKET_ERROR) {
|
if (iResult == SOCKET_ERROR) {
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
closesocket(_server);
|
closesocket(_server);
|
||||||
throw new _exception(); // Can't be fucked to deal with errors
|
throw new std::exception(); // Can't be fucked to deal with errors
|
||||||
}
|
}
|
||||||
if (listen(_server, 20) == SOCKET_ERROR) { // 20 is the backlog amount, i.e. amount of connections Windows will accept if program is busy and can't accept atm.
|
if (listen(_server, 20) == SOCKET_ERROR) { // 20 is the backlog amount, i.e. amount of connections Windows will accept if program is busy and can't accept atm.
|
||||||
closesocket(_server);
|
closesocket(_server);
|
||||||
throw new _exception();
|
throw new std::exception();
|
||||||
}
|
}
|
||||||
timeval t;
|
timeval t;
|
||||||
t.tv_sec = 0;
|
t.tv_sec = 0;
|
||||||
t.tv_usec = 5000;
|
t.tv_usec = 5000;
|
||||||
do {
|
do {
|
||||||
|
Next:
|
||||||
|
if (!_open) break;
|
||||||
fd_set connecting;
|
fd_set connecting;
|
||||||
connecting.fd_count = 1;
|
connecting.fd_count = 1;
|
||||||
connecting.fd_array[0] = _server;
|
connecting.fd_array[0] = _server;
|
||||||
int i = select(NULL, &connecting, NULL, NULL, &t); // Check for new clients
|
int i = select(NULL, &connecting, NULL, NULL, &t); // Check for new clients
|
||||||
if (i == SOCKET_ERROR) {
|
if (i == SOCKET_ERROR) throw new std::exception();
|
||||||
throw new _exception();
|
|
||||||
}
|
|
||||||
if (connecting.fd_count > 0) { // This checks if any new clients are tryig to connect. If not, don't block to await one; just continue to update clients
|
if (connecting.fd_count > 0) { // This checks if any new clients are tryig to connect. If not, don't block to await one; just continue to update clients
|
||||||
SOCKET client = accept(_server, NULL, NULL);
|
SOCKET client = accept(_server, NULL, NULL);
|
||||||
if (client == INVALID_SOCKET) {
|
if (client == INVALID_SOCKET) {
|
||||||
closesocket(_server);
|
closesocket(_server);
|
||||||
if (_open) throw new _exception();
|
if (_open) throw new std::exception();
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
NetClient* cli = new NetClient(client, true, keys, this->pref, false);
|
NetClient* cli = new NetClient(client, true, keyData, this->pref, false);
|
||||||
clients->push_back(cli);
|
clients->push_back(cli);
|
||||||
for (ulong_64b t = 0; t < handlers->size(); ++t)
|
for (ulong_64b t = 0; t < handlers->size(); ++t)
|
||||||
if (handlers->at(t)(cli))
|
if (handlers->at(t)(cli))
|
||||||
@ -356,18 +497,54 @@ namespace IO {
|
|||||||
|
|
||||||
}
|
}
|
||||||
updateClients();
|
updateClients();
|
||||||
|
if (scheduleTerminate) {
|
||||||
|
for (NetClient* cli : *clients)
|
||||||
|
if (cli->getBOPCount() > 0)
|
||||||
|
goto Next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
} while (_open);
|
} while (_open);
|
||||||
closesocket(_server);
|
closesocket(_server);
|
||||||
close();
|
close();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetServer::close() {
|
||||||
|
for (NetClient* cli : *clients) {
|
||||||
|
if (cli->getBOPCount() > 0) {
|
||||||
|
scheduleTerminate = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_open) return false;
|
||||||
|
_open = false;
|
||||||
|
for (ulong_64b t = clients->size(); t > 0; --t) {
|
||||||
|
NetClient* s = clients->at(t - 1);
|
||||||
|
s->close();
|
||||||
|
clients->pop_back();
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetServer::NetServer(char* port, std::function<bool(NetClient*)> f, CryptoLevel pref) : pref(pref) {
|
||||||
|
if (pref != CryptoLevel::None) keyData = new AsyncKeys();
|
||||||
|
sharedSetup(port, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NetServer::NetServer(char* port, std::function<bool(NetClient*)> f, AsyncKeys &keyData, CryptoLevel level) : pref(level) {
|
||||||
|
this->keyData = new AsyncKeys(keyData.get());
|
||||||
|
sharedSetup(port, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
NetServer::~NetServer() {
|
NetServer::~NetServer() {
|
||||||
|
delete keyData;
|
||||||
if (_open) close();
|
if (_open) close();
|
||||||
handlers->clear();
|
handlers->clear();
|
||||||
delete handlers;
|
delete handlers;
|
||||||
clients->clear();
|
for (NetClient *cli : *clients) delete cli;
|
||||||
|
clients->clear();
|
||||||
delete clients;
|
delete clients;
|
||||||
onDestroy();
|
onDestroy();
|
||||||
}
|
}
|
||||||
@ -395,4 +572,142 @@ namespace IO {
|
|||||||
bool NetServer::isOpen() { return _open; }
|
bool NetServer::isOpen() { return _open; }
|
||||||
|
|
||||||
void NetServer::setOnDestroy(std::function<void()> call) { onDestroy = call; }
|
void NetServer::setOnDestroy(std::function<void()> call) { onDestroy = call; }
|
||||||
|
|
||||||
|
void NetServer::setAutoPing(bool b) { for (NetClient* cli : *clients) cli->autoPing = b; }
|
||||||
|
|
||||||
|
ulong_64b NetServer::getClientCount() { return clients->size(); }
|
||||||
|
|
||||||
|
NetClient* NetServer::at(ulong_64b idx) { return clients->at(idx); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void writeState(NetClient& cli, const char* stateName, char state) {
|
||||||
|
char* c = cli.getStrValue(stateName, false);
|
||||||
|
if (c == nullptr) c = new char[0];
|
||||||
|
c[0] = state;
|
||||||
|
cli.setValue(stateName, c, false, false); // Write/overwrite
|
||||||
|
}
|
||||||
|
|
||||||
|
char readState(NetClient& cli, const char* stateName) {
|
||||||
|
char* c = cli.getStrValue(stateName, false);
|
||||||
|
if (c == nullptr) return 0;
|
||||||
|
else return *c;
|
||||||
|
}
|
||||||
|
|
||||||
|
PartialNetworkStream::PartialNetworkStream(NetClient& client, bool noBuffer, bool permissive) :
|
||||||
|
std::ostream(std::_Uninitialized::_Noinit),
|
||||||
|
client(client),
|
||||||
|
buffer(noBuffer?nullptr:new std::vector<char>()),
|
||||||
|
permissive(permissive)
|
||||||
|
{ /* NOP */}
|
||||||
|
|
||||||
|
PartialNetworkStream::~PartialNetworkStream() {
|
||||||
|
if (client.isOpen() && !stateIs(client, PartialCommState::COMM_FULL)) {
|
||||||
|
sendState(PartialCommState::COMM_FULL);
|
||||||
|
writeState(client, STREAM_ATTRIB, PartialCommState::COMM_FULL);
|
||||||
|
}
|
||||||
|
client.removeValue(STREAM_ATTRIB); // Cleanup
|
||||||
|
}
|
||||||
|
void PartialNetworkStream::write(char* message, std::streamsize size, bool autoFlush) {
|
||||||
|
bool isPartial = stateIs(client, PartialCommState::COMM_PARTIAL);
|
||||||
|
if (!isPartial || autoFlush || (size > STREAM_BUFMIN)) {
|
||||||
|
if(isPartial) flush();
|
||||||
|
client.write(message, size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (std::streamsize t = 0; t < size; ++t) buffer->push_back(message[t]);
|
||||||
|
if (buffer->size() > STREAM_BUFMIN) flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void PartialNetworkStream::writeNonPartial(char* message, std::streamsize size) {
|
||||||
|
bool b = stateIs(client, PartialCommState::COMM_PARTIAL);
|
||||||
|
if (b) client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE));
|
||||||
|
client.write(message, size);
|
||||||
|
if (b) client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE));
|
||||||
|
}
|
||||||
|
void PartialNetworkStream::flush() {
|
||||||
|
if(!check(PartialCommState::COMM_FULL)) return; // Check failed in a permissive state
|
||||||
|
if (buffer->size() == 0) return;
|
||||||
|
bool b = stateIs(client, PartialCommState::COMM_PAUSE);
|
||||||
|
if (b) client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE)); // Temporarily set the remote read state to PARTIAL
|
||||||
|
client.write(&buffer->at(0), buffer->size());
|
||||||
|
if (b) client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE)); // Set the remote read state back to PAUSE
|
||||||
|
buffer->clear();
|
||||||
|
}
|
||||||
|
bool PartialNetworkStream::check(PartialCommState state) {
|
||||||
|
if (readState(client, STREAM_ATTRIB) == state) {
|
||||||
|
if (permissive) return false;
|
||||||
|
throw new std::exception("Stream is not open!");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void PartialNetworkStream::sendState(PartialCommState state) {
|
||||||
|
switch (getCommState()) {
|
||||||
|
case PartialCommState::COMM_PAUSE:
|
||||||
|
if (state == PartialCommState::COMM_FULL) {
|
||||||
|
client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE));
|
||||||
|
client.write((char*)&STREAM_DELIMIT, sizeof(STREAM_DELIMIT));
|
||||||
|
}
|
||||||
|
else if (state == PartialCommState::COMM_PARTIAL) client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE));
|
||||||
|
break;
|
||||||
|
case PartialCommState::COMM_PARTIAL:
|
||||||
|
if (state == PartialCommState::COMM_FULL) client.write((char*)&STREAM_DELIMIT, sizeof(STREAM_DELIMIT));
|
||||||
|
else if (state == PartialCommState::COMM_PAUSE) client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE));
|
||||||
|
break;
|
||||||
|
case PartialCommState::COMM_FULL:
|
||||||
|
if (state == PartialCommState::COMM_PARTIAL) client.write((char*)&STREAM_DELIMIT, sizeof(STREAM_DELIMIT));
|
||||||
|
else if (state == PartialCommState::COMM_PAUSE) {
|
||||||
|
client.write((char*)&STREAM_DELIMIT, sizeof(STREAM_PAUSE));
|
||||||
|
client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PartialNetworkStream::endPartial() {
|
||||||
|
flush();
|
||||||
|
sendState(PartialCommState::COMM_FULL);
|
||||||
|
writeState(client, STREAM_ATTRIB, PartialCommState::COMM_FULL);
|
||||||
|
}
|
||||||
|
void PartialNetworkStream::startPartial() {
|
||||||
|
sendState(PartialCommState::COMM_PARTIAL);
|
||||||
|
writeState(client, STREAM_ATTRIB, PartialCommState::COMM_PARTIAL);
|
||||||
|
}
|
||||||
|
PartialCommState PartialNetworkStream::getCommState() {
|
||||||
|
return static_cast<PartialCommState>(readState(client, STREAM_ATTRIB));
|
||||||
|
}
|
||||||
|
bool PartialNetworkStream::stateIs(NetClient& cli, PartialCommState state) { return readState(cli, STREAM_ATTRIB) == state; }
|
||||||
|
PartialDataState PartialNetworkStream::accept(NetClient& cli, Packet& pkt) {
|
||||||
|
bool toggle_partial = (pkt.size-1) == sizeof(STREAM_DELIMIT) && ((*(ulong_64b*)pkt.message) == STREAM_DELIMIT);
|
||||||
|
bool toggle_pause = !toggle_partial && ((pkt.size-1) == sizeof(STREAM_PAUSE) && ((*(ulong_64b*)pkt.message) == STREAM_PAUSE));
|
||||||
|
if (!toggle_partial && !toggle_pause) return PartialDataState::DATA;
|
||||||
|
else if (toggle_partial) {
|
||||||
|
if (stateIs(cli, PartialCommState::COMM_FULL)) {
|
||||||
|
writeState(cli, STREAM_ATTRIB, PartialCommState::COMM_PARTIAL);
|
||||||
|
return PartialDataState::START;
|
||||||
|
}
|
||||||
|
else if (stateIs(cli, PartialCommState::COMM_PAUSE)) {
|
||||||
|
writeState(cli, STREAM_ATTRIB, PartialCommState::COMM_PARTIAL);
|
||||||
|
return PartialDataState::RESUME;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
writeState(cli, STREAM_ATTRIB, PartialCommState::COMM_FULL);
|
||||||
|
return PartialDataState::END;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* if(toggle_pause) */{
|
||||||
|
if (stateIs(cli, PartialCommState::COMM_FULL)) {
|
||||||
|
writeState(cli, STREAM_ATTRIB, PartialCommState::COMM_PAUSE);
|
||||||
|
return PartialDataState::PAUSE;
|
||||||
|
}
|
||||||
|
else if (stateIs(cli, PartialCommState::COMM_PAUSE)) {
|
||||||
|
writeState(cli, STREAM_ATTRIB, PartialCommState::COMM_PARTIAL);
|
||||||
|
return PartialDataState::RESUME;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
writeState(cli, STREAM_ATTRIB, PartialCommState::COMM_PAUSE);
|
||||||
|
return PartialDataState::PAUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
131
CPPTools/Net.h
131
CPPTools/Net.h
@ -8,12 +8,17 @@
|
|||||||
#define BUFSIZE 512
|
#define BUFSIZE 512
|
||||||
#define BUF_2_MAX 2048
|
#define BUF_2_MAX 2048
|
||||||
#else
|
#else
|
||||||
#define BUFSIZE 16384
|
#define BUFSIZE 1073741824 // 1 GiB
|
||||||
#define BUF_2_MAX 16384
|
#define BUF_2_MAX 1073741824 // 1 GiB
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
// Ping flag tells the recieving host to drop the current ulong_64b, as it is sent to check if the connection is still alive
|
||||||
|
#define FLAG_PING (ulong_64b)-1
|
||||||
|
#define FLAG_PART (ulong_64b)-2
|
||||||
|
#define FLAG_NPRT (ulong_64b)-3
|
||||||
|
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "ArchAbstract.h"
|
#include "ArchAbstract.h"
|
||||||
|
|
||||||
@ -21,13 +26,36 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
|
||||||
namespace IO {
|
namespace IO {
|
||||||
|
|
||||||
|
class AsyncKeys {
|
||||||
|
private:
|
||||||
|
std::future<Crypto::RSA::KeyData*> gen;
|
||||||
|
Crypto::RSA::KeyData* keys;
|
||||||
|
AsyncKeys* chainKeys;
|
||||||
|
volatile bool done;
|
||||||
|
bool suppressDelete;
|
||||||
|
bool chain;
|
||||||
|
public:
|
||||||
|
AsyncKeys();
|
||||||
|
AsyncKeys(Crypto::RSA::KeyData* predef);
|
||||||
|
AsyncKeys(AsyncKeys*);
|
||||||
|
~AsyncKeys();
|
||||||
|
Crypto::RSA::KeyData* get();
|
||||||
|
};
|
||||||
|
|
||||||
enum CryptoLevel { None, Prefer, Force };
|
enum CryptoLevel { None, Prefer, Force };
|
||||||
|
|
||||||
struct Packet {
|
struct Packet {
|
||||||
|
ulong_64b size;
|
||||||
|
char packetUID;
|
||||||
|
char* message;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PartialPacket {
|
||||||
ulong_64b size;
|
ulong_64b size;
|
||||||
char* message;
|
char* message;
|
||||||
};
|
};
|
||||||
@ -40,35 +68,44 @@ namespace IO {
|
|||||||
volatile bool _open; // Whether or not connection is open
|
volatile bool _open; // Whether or not connection is open
|
||||||
bool canWrite; // Whether or not writing to peer is possible
|
bool canWrite; // Whether or not writing to peer is possible
|
||||||
bool noThread; // Whether or not reading incoming data should be / is being done in a separate thread
|
bool noThread; // Whether or not reading incoming data should be / is being done in a separate thread
|
||||||
char rBuf[BUFSIZE]; // Recieve buffer
|
bool scheduleTerminate = false;
|
||||||
|
std::vector<char> rBuf;
|
||||||
CryptoLevel preferEncrypted = CryptoLevel::None;// Whether or not the socket should attempt to request an encrypted channel
|
CryptoLevel preferEncrypted = CryptoLevel::None;// Whether or not the socket should attempt to request an encrypted channel
|
||||||
bool encrypted = false; // Whether or not negotiation determined the use of an encrypted channel
|
bool encrypted = false; // Whether or not negotiation determined the use of an encrypted channel
|
||||||
bool firstMessage = true; // Whether or not negotiation has yet ocurred
|
bool firstMessage = true; // Whether or not negotiation has yet ocurred
|
||||||
ulong_64b fm_neg_size;
|
ulong_64b fm_neg_size; // First message negotiation size
|
||||||
bool fm_neg_hasLevel = false;
|
bool fm_neg_hasLevel = false; // First message has crypto level
|
||||||
bool fm_neg_hasSize = false;
|
bool fm_neg_hasSize = false; // Got negotiation size from first message
|
||||||
bool startNegotiate = false;
|
bool startNegotiate = false; // Whether or not to initiate negotiation
|
||||||
|
char expectedNextPUID = 0;
|
||||||
|
char remotePUID = 0;
|
||||||
std::vector<char>* sparse;
|
std::vector<char>* sparse;
|
||||||
std::vector<Packet>* outPacketBuf;
|
std::vector<Packet>* outPacketBuf;
|
||||||
Crypto::RSA::KeyData keys; // Client's keysets (if using encryption)
|
AsyncKeys *keyData; // Client's keysets (if using encryption)
|
||||||
CryptoPP::RSAFunction pK; // Remote host's public key (if using encryption)
|
CryptoPP::RSAFunction pK; // Remote host's public key (if using encryption)
|
||||||
|
|
||||||
|
NetClient(char*, char*, CryptoLevel, bool); // Underlying setup for regular constructors
|
||||||
NetClient(SOCKET, bool, CryptoLevel, bool);// Special setup constructor
|
NetClient(SOCKET, bool, CryptoLevel, bool);// Special setup constructor
|
||||||
NetClient(SOCKET, bool, Crypto::RSA::KeyData&, CryptoLevel = CryptoLevel::None, bool = false);// Create wrapper for existing socket
|
NetClient(SOCKET, bool, AsyncKeys*, CryptoLevel = CryptoLevel::None, bool = false);// Create wrapper for existing socket
|
||||||
void sharedSetup(); // Setup function for all constructor
|
void sharedSetup(bool); // Setup function for all constructor
|
||||||
bool _write(char*, ulong_64b); // Internal write function. Doesn't do any of the fancy auto encryption: just raw write...
|
bool _write(char*, ulong_64b); // Internal write function. Doesn't do any of the fancy auto encryption: just raw write...
|
||||||
bool writeBufferedPackets(); // Flushes and deletes buffer
|
bool writeBufferedPackets(); // Flushes and deletes buffer
|
||||||
void update(); // Read incoming data and store in buffers
|
void update(); // Read incoming data and store in buffers
|
||||||
protected:
|
protected:
|
||||||
|
std::vector<std::pair<char*, std::pair<ulong_64b, char*>*>*> associatedData;
|
||||||
std::thread listener; // Incoming data listener (optional)
|
std::thread listener; // Incoming data listener (optional)
|
||||||
SOCKET _socket; // Underlying socket used for communication
|
SOCKET _socket; // Underlying socket used for communication
|
||||||
std::vector<Packet>* packets; // Basically a set containing a backlog of unprocessed data. Will oly be used if event handler doesn't exist
|
std::vector<Packet>* packets; // Basically a set containing a backlog of unprocessed data. Will oly be used if event handler doesn't exist
|
||||||
|
|
||||||
|
|
||||||
std::function<void(NetClient*, Packet)> evt; // New data event handler
|
std::function<void(NetClient*, Packet)> evt; // New data event handler
|
||||||
std::function<void()> onDestroy; // Event handler called when NetClient object is destroyed
|
std::function<void()> onDestroy; // Event handler called when NetClient object is destroyed
|
||||||
public:
|
public:
|
||||||
|
bool autoPing = true; // Whether or not client should actively check connection state
|
||||||
|
bool autoDelete = false;
|
||||||
time_t commTime; // Latest time a transaction occurred
|
time_t commTime; // Latest time a transaction occurred
|
||||||
std::vector<char*> associatedData;
|
|
||||||
NetClient(char* ipAddr, char* port, CryptoLevel = CryptoLevel::None);// Standard constructor for creating connection
|
NetClient(char* ipAddr, char* port, CryptoLevel = CryptoLevel::None);// Standard constructor for creating connection
|
||||||
|
NetClient(char* ipAddr, char* port, AsyncKeys*, CryptoLevel);// Standard constructor for creating connection with predefined keys
|
||||||
~NetClient();
|
~NetClient();
|
||||||
bool close();
|
bool close();
|
||||||
void closeWrite();
|
void closeWrite();
|
||||||
@ -77,20 +114,29 @@ namespace IO {
|
|||||||
bool write(void* message, ulong_64b size);
|
bool write(void* message, ulong_64b size);
|
||||||
bool write(char* message);
|
bool write(char* message);
|
||||||
Packet read();
|
Packet read();
|
||||||
void setEventHandler(std::function<void(NetClient*, Packet)>); // Register a callback that is guaranteed to be called when the socket has at least one unprocessed packet
|
void setEventHandler(std::function<void(NetClient*, Packet)>);// Register a callback that is guaranteed to be called when the socket has at least one unprocessed packet
|
||||||
void setOnDestroy(std::function<void()>);
|
void setOnDestroy(std::function<void()>);
|
||||||
|
std::pair<ulong_64b, char*> getValue(const char* name, bool copy = true);
|
||||||
|
char* getStrValue(const char* name, bool copy = true);
|
||||||
|
void setValue(const char* name, std::pair<ulong_64b, char*> value, bool copy = true, bool del = true);
|
||||||
|
void setValue(const char* name, char* data, bool copy = true, bool del = true);
|
||||||
|
bool removeValue(const char* name, bool del = true);
|
||||||
|
bool containsKey(const char* name);
|
||||||
bool isOpen();
|
bool isOpen();
|
||||||
ulong_64b available();
|
ulong_64b available();
|
||||||
|
bool ping(); // Check if connection is alive by pinging remote host
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetServer {
|
class NetServer {
|
||||||
friend class NetClient;
|
friend class NetClient;
|
||||||
private:
|
private:
|
||||||
CryptoLevel pref;
|
CryptoLevel pref;
|
||||||
Crypto::RSA::KeyData keys; // Server's keysets (if using encryption)
|
AsyncKeys *keyData; // Server's keysets (if using encryption)
|
||||||
|
|
||||||
std::function<void()> onDestroy;
|
std::function<void()> onDestroy;
|
||||||
volatile bool _open;
|
volatile bool _open;
|
||||||
|
bool scheduleTerminate = false;
|
||||||
|
|
||||||
|
void sharedSetup(char* port, std::function<bool(NetClient*)> f);
|
||||||
void updateClients();
|
void updateClients();
|
||||||
protected:
|
protected:
|
||||||
std::thread clientListener;
|
std::thread clientListener;
|
||||||
@ -98,7 +144,8 @@ namespace IO {
|
|||||||
std::vector<NetClient*>* clients;
|
std::vector<NetClient*>* clients;
|
||||||
public:
|
public:
|
||||||
std::function<bool(NetClient*)> timeoutHandler;
|
std::function<bool(NetClient*)> timeoutHandler;
|
||||||
NetServer(char* port, std::function<bool(NetClient*)>, CryptoLevel);
|
NetServer(char* port, std::function<bool(NetClient*)> = nullptr, CryptoLevel = CryptoLevel::None);
|
||||||
|
NetServer(char* port, std::function<bool(NetClient*)>, AsyncKeys&, CryptoLevel);
|
||||||
~NetServer();
|
~NetServer();
|
||||||
bool isOpen();
|
bool isOpen();
|
||||||
CryptoLevel getCryptoPreference();
|
CryptoLevel getCryptoPreference();
|
||||||
@ -106,6 +153,60 @@ namespace IO {
|
|||||||
void clearHandlers();
|
void clearHandlers();
|
||||||
void setOnDestroy(std::function<void()>);
|
void setOnDestroy(std::function<void()>);
|
||||||
bool close();
|
bool close();
|
||||||
|
void setAutoPing(bool);
|
||||||
|
ulong_64b getClientCount();
|
||||||
|
NetClient* at(ulong_64b);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Partial data stream management
|
||||||
|
static const auto STREAM_DELIMIT = FLAG_PART;
|
||||||
|
static const auto STREAM_PAUSE = FLAG_NPRT;
|
||||||
|
static const auto STREAM_ATTRIB = (const char*) "$PartialNetworkStream$ACTIVE";
|
||||||
|
static const auto STREAM_BUFMIN = 32;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
START represents the beginning of a partial message
|
||||||
|
PAUSE represents a pause in the partial stream in which a full (unrelated) message is being sent
|
||||||
|
RESUME tells dev that the partial stream is being resumed (from a full-write state)
|
||||||
|
END represebts the end of a partial message
|
||||||
|
DATA represents the the supplied data isn't metadata
|
||||||
|
*/
|
||||||
|
enum PartialDataState { START, PAUSE, RESUME, END, DATA };
|
||||||
|
|
||||||
|
/*
|
||||||
|
PARTIAL tells you that the stream is currently accepting partial data packets
|
||||||
|
PAUSE means that the client is set to accept a partial stream, but has been specifically paused to accept a full message
|
||||||
|
FULL means that the client is interpreting messages as full message blocks
|
||||||
|
*/
|
||||||
|
enum PartialCommState { COMM_FULL, COMM_PARTIAL, COMM_PAUSE };
|
||||||
|
|
||||||
|
|
||||||
|
class PartialNetworkStream : public std::ostream{
|
||||||
|
protected:
|
||||||
|
const bool permissive;
|
||||||
|
bool open;
|
||||||
|
std::vector<char>* buffer;
|
||||||
|
NetClient& client;
|
||||||
|
|
||||||
|
bool check(PartialCommState state);
|
||||||
|
void sendState(PartialCommState state);
|
||||||
|
public:
|
||||||
|
PartialNetworkStream(NetClient&, bool = false, bool = true);
|
||||||
|
~PartialNetworkStream();
|
||||||
|
|
||||||
|
void endPartial();
|
||||||
|
void startPartial();
|
||||||
|
PartialCommState getCommState();
|
||||||
|
void write(char*, std::streamsize, bool = false);
|
||||||
|
void writeNonPartial(char*, std::streamsize);
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
static PartialDataState accept(NetClient& cli, Packet& pkt);
|
||||||
|
static bool stateIs(NetClient& cli, PartialCommState state);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,27 +76,54 @@ namespace Tools {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* toHexString(const void* data, ulong_64b size) {
|
char* toHexString(const void* data, ulong_64b size, bool ignorePreZero) {
|
||||||
char* c = (char*)data;
|
char* c = (char*)data;
|
||||||
|
|
||||||
ulong_64b lastNonZero = 0;
|
ulong_64b lastNonZero = ignorePreZero?0:size-1;
|
||||||
for (ulong_64b t = 0; t < size; ++t) if (c[t] != 0) lastNonZero = t;
|
if (ignorePreZero) {
|
||||||
if (lastNonZero == 0) return (char*)memset(malloc(1), '0', 1);
|
for (ulong_64b t = size; t > 0; --t)
|
||||||
|
if (c[t - 1] != 0) {
|
||||||
|
lastNonZero = t - 1;
|
||||||
|
goto Ayy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else goto Ayy;
|
||||||
|
return new char[2]{ '0', 0 };
|
||||||
|
|
||||||
char* c1 = (char*)malloc(lastNonZero * 2);
|
Ayy:
|
||||||
for (ulong_64b t = 0; t < lastNonZero; ++t) {
|
char* c1 = (char*)new char[1 + ((lastNonZero + 1) * 2)];
|
||||||
c1[2 * t] = (c[t]) & 15;
|
c1[lastNonZero * 2] = 0;
|
||||||
if (c1[(2 * t)] < 9) c1[(2 * t)] += 48;
|
for (ulong_64b j = lastNonZero + 1; j > 0; --j) {
|
||||||
|
ulong_64b t = 1 + lastNonZero - j;
|
||||||
|
c1[2 * t] = (c[j - 1] >> 4) & 15;
|
||||||
|
if (c1[(2 * t)] < 10) c1[(2 * t)] += 48;
|
||||||
else c1[(2 * t)] += 55;
|
else c1[(2 * t)] += 55;
|
||||||
|
|
||||||
c1[(2 * t) + 1] = (c[t] >> 4) & 15;
|
c1[(2 * t) + 1] = (c[j - 1]) & 15;
|
||||||
if (c1[(2 * t) + 1] < 9) c1[(2 * t) + 1] += 48;
|
if (c1[(2 * t) + 1] < 10) c1[(2 * t) + 1] += 48;
|
||||||
else c1[(2 * t) + 1] += 55;
|
else c1[(2 * t) + 1] += 55;
|
||||||
}
|
}
|
||||||
return c1;
|
return c1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* toHexString(ulong_64b value) { return toHexString(&value, sizeof(value)); }
|
char* toHexString(const void* data, ulong_64b size) { return toHexString(data, size, true); }
|
||||||
|
|
||||||
|
char* toHexString(ulong_64b value) { return toHexString(&value, sizeof(value), false); }
|
||||||
|
|
||||||
|
void* parseHex(char* c, size_t *rSize) {
|
||||||
|
size_t len = strlen(c);
|
||||||
|
size_t rem = (len % 2);
|
||||||
|
size_t target = (len + rem) / 2;
|
||||||
|
if (rSize != nullptr) *rSize = target;
|
||||||
|
char* out = new char[target];
|
||||||
|
if (rem) out[target - 1] = c[0] - (c[0]>64 ? 55 : 48);
|
||||||
|
for (size_t t = rem; t < len; ++t) {
|
||||||
|
out[target - 1 - ((t + rem) / 2)] |= (c[t] - (c[t] > 64 ? 55 : 48)) << (((t + 1) % 2) * 4);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong_64b parseHexLong(char* c) { return *(ulong_64b*)parseHex(c, nullptr); }
|
||||||
|
|
||||||
bool isDigit(char c) { return (c > 47) && (c < 58); }
|
bool isDigit(char c) { return (c > 47) && (c < 58); }
|
||||||
|
|
||||||
|
@ -20,8 +20,11 @@ namespace Tools {
|
|||||||
ulong_64b indexOf(char*, char);
|
ulong_64b indexOf(char*, char);
|
||||||
ulong_64b lastIndexOf(char*, char);
|
ulong_64b lastIndexOf(char*, char);
|
||||||
char* copydata(const char*, ulong_64b);
|
char* copydata(const char*, ulong_64b);
|
||||||
|
char* toHexString(const void* data, ulong_64b size, bool);
|
||||||
char* toHexString(const void* data, ulong_64b size);
|
char* toHexString(const void* data, ulong_64b size);
|
||||||
char* toHexString(ulong_64b value);
|
char* toHexString(ulong_64b);
|
||||||
|
void* parseHex(char*, size_t *rSize);
|
||||||
|
ulong_64b parseHexLong(char*);
|
||||||
bool isDigit(char c);
|
bool isDigit(char c);
|
||||||
bool isNumber(char* c);
|
bool isNumber(char* c);
|
||||||
bool isIP(char* c);
|
bool isIP(char* c);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user