diff --git a/CPPTools/CPPTools.vcxproj b/CPPTools/CPPTools.vcxproj
index 7629231..dbeee4e 100644
--- a/CPPTools/CPPTools.vcxproj
+++ b/CPPTools/CPPTools.vcxproj
@@ -139,13 +139,14 @@
+
+
-
diff --git a/CPPTools/CPPTools.vcxproj.filters b/CPPTools/CPPTools.vcxproj.filters
index e414768..f69797c 100644
--- a/CPPTools/CPPTools.vcxproj.filters
+++ b/CPPTools/CPPTools.vcxproj.filters
@@ -27,6 +27,9 @@
Header Files
+
+ Header Files
+
@@ -35,7 +38,7 @@
Source Files
-
+
Source Files
diff --git a/CPPTools/Net.cpp b/CPPTools/Net.cpp
new file mode 100644
index 0000000..bab19a3
--- /dev/null
+++ b/CPPTools/Net.cpp
@@ -0,0 +1,398 @@
+#include "Net.h"
+
+#include
+#include
+#include
+#include
+#include
+
+namespace IO {
+
+ bool connected(SOCKET sock)
+ {
+ char buf;
+ int err = recv(sock, &buf, 1, MSG_PEEK);
+ if (err == SOCKET_ERROR)
+ {
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool cryptoLevelsAreCompatible(CryptoLevel l1, CryptoLevel l2) {
+ return !(((l1 == CryptoLevel::None) && (l2 == CryptoLevel::Force)) || ((l2 == CryptoLevel::None) && (l1 == CryptoLevel::Force)));
+ }
+
+ char* __cdecl readSparse(std::vector* sparse, ulong_64b rSize, bool pop = true) {
+ if (sparse->size() < rSize) throw new _exception(); // This should never happen if function is used correctly
+ char* c = new char[rSize];
+ for (ulong_64b b = 0; b < rSize; ++b) c[b] = sparse->at(b);
+ if (pop) sparse->erase(sparse->begin(), sparse->begin() + rSize);
+ return c;
+ }
+
+ bool hasFullMessage(std::vector *sparse) {
+ if (sparse->size() < sizeof(ulong_64b)) return false;
+ ulong_64b size = 0;
+ char* c = readSparse(sparse, sizeof(ulong_64b), false);
+ memcpy(&size, c, sizeof(ulong_64b));
+ delete[] c;
+ return sparse->size() >= (size + sizeof(ulong_64b));
+ }
+
+
+
+ void NetClient::sharedSetup() {
+ if (preferEncrypted != CryptoLevel::None) keys = Crypto::RSA::rsa_gen_keys();
+ packets = new std::vector();
+ sparse = new std::vector();
+ outPacketBuf = new std::vector();
+ _open = true;
+ canWrite = true;
+ evt = nullptr;
+ char cryptoPref = static_cast(preferEncrypted);
+ if (send(_socket, &cryptoPref, 1, 0) == SOCKET_ERROR) throw new _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
+ }
+ NetClient::NetClient(char* ipAddr, char* port, CryptoLevel preferEncrypted) :
+ commTime(time(nullptr)), preferEncrypted(preferEncrypted), startNegotiate(false)
+ {
+ _socket = INVALID_SOCKET;
+ this->noThread = false;
+
+ WSADATA wsaData;
+ int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
+ if (iResult != 0) throw new _exception();
+
+
+ struct addrinfo *result = NULL, *ptr = NULL, hints;
+
+ ZeroMemory(&hints, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ iResult = getaddrinfo(ipAddr, port, &hints, &result);
+
+ if (iResult) throw new _exception();
+
+ for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
+
+ // Create a SOCKET for connecting to server
+ _socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
+ if (_socket == INVALID_SOCKET) {
+ throw new _exception();
+ }
+
+ // Connect to server.
+ iResult = connect(_socket, ptr->ai_addr, (int)ptr->ai_addrlen);
+ if (iResult == SOCKET_ERROR) {
+ closesocket(_socket);
+ _socket = INVALID_SOCKET;
+ continue;
+ }
+ break;
+ }
+
+ freeaddrinfo(result);
+
+ if (_socket == INVALID_SOCKET) throw new _exception();
+
+ sharedSetup();
+ }
+
+ NetClient::NetClient(SOCKET wrap, bool noThread, Crypto::RSA::KeyData& keys, CryptoLevel preferEncrypted, bool startNegotiate) :
+ commTime(time(nullptr)), preferEncrypted(preferEncrypted), startNegotiate(startNegotiate)
+ {
+ _socket = wrap;
+ this->noThread = noThread;
+ sharedSetup();
+ }
+
+ NetClient::~NetClient() {
+ packets->clear();
+ delete packets;
+ sparse->clear();
+ delete sparse;
+ if (isOpen()) close();
+ }
+ bool NetClient::close() {
+ bool result = !_open;
+ _open = false;
+ result &= (SOCKET_ERROR == shutdown(_socket, SD_BOTH));
+ closesocket(_socket);
+ return result;
+ }
+ void NetClient::closeWrite() {
+ shutdown(_socket, SD_SEND);
+ canWrite = false;
+ }
+ bool NetClient::_write(char* message, ulong_64b size) {
+ 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) return false;
+ else if (i == 0) --wIdx;
+ }
+ for (ulong_64b wIdx = 0; wIdx < size; ++wIdx) {
+ if ((i = send(_socket, message + wIdx, 1, 0)) == SOCKET_ERROR) return false;
+ else if (i == 0) --wIdx;
+ }
+ return true;
+ }
+ bool NetClient::write(void* message, ulong_64b size) {
+ if (firstMessage) {
+ Packet p;
+ p.message = (char*)message;
+ p.size = size;
+ outPacketBuf->push_back(p);
+ return true;
+ }
+ if (!canWrite) return false;
+ char* msg = encrypted ? Crypto::full_auto_encrypt(message, size, pK, &size) : (char*)message;
+ _write(msg, size);
+ if (encrypted) delete[] msg;
+ return true;
+ }
+ bool NetClient::write(char* message) { return write(message, strlen(message)); }
+ bool NetClient::writeBufferedPackets() {
+ for (size_t t = 0; t < outPacketBuf->size(); ++t) if (!write(outPacketBuf->at(t).message, outPacketBuf->at(t).size)) { delete outPacketBuf; return false; };
+ delete outPacketBuf;
+ return true;
+ }
+ Packet NetClient::read() {
+ if (packets->size() != 0) {
+ Packet p = packets->at(0);
+ packets->erase(packets->begin(), packets->begin() + 1); // Delete first buffered packet
+ return p;
+ }
+ throw new _exception(); // No packets available!
+ }
+ void NetClient::setEventHandler(std::function _ev) {
+ evt = _ev;
+
+ // Process unhandled packets
+ if (evt != nullptr)
+ for (size_t t = packets->size(); t > 0; --t) {
+ Packet p = packets->at(t - 1);
+ packets->pop_back();
+ evt(this, p);
+ }
+ }
+ bool NetClient::isEncrypted() { return encrypted; }
+ void NetClient::update() {
+ if (!connected(_socket)) {
+ _open = false;
+ close();
+ return;
+ }
+ int iResult = 0, rdErr;
+ unsigned long rCount;
+ rdErr = ioctlsocket(_socket, FIONREAD, &rCount);
+ if (rdErr == SOCKET_ERROR) throw new _exception(); // Error using socket :(
+ if (rCount > 0) {
+ iResult = recv(_socket, rBuf, BUFSIZE, 0);
+ if (iResult > 0)
+ for (int i = 0; i < iResult; ++i)
+ if (sparse->size() < BUF_2_MAX)
+ sparse->push_back(rBuf[i]); // Drop anything over the absolute max
+ }
+ while (!firstMessage && hasFullMessage(sparse)) {
+ Packet p;
+ char* size = readSparse(sparse, sizeof(ulong_64b));
+ memcpy(&p.size, size, sizeof(ulong_64b));
+ delete[] size;
+ p.message = readSparse(sparse, p.size);
+ if (encrypted) p.message = Crypto::full_auto_decrypt(p.message, keys.privKey, &p.size);
+ if (evt == nullptr) packets->push_back(p);
+ else evt(this, p); // Notify event handler of a new packet
+ }
+ if (iResult > 0) {
+ if (firstMessage) {
+ if (!fm_neg_hasLevel && sparse->size() >= 1) {
+ fm_neg_hasLevel = true;
+ char* readCrypt = readSparse(sparse, 1);
+ CryptoLevel lvl = static_cast(*readCrypt);
+ free(readCrypt);
+ if (cryptoLevelsAreCompatible(lvl, preferEncrypted)) {
+ // Determine whether or not to use encryption
+ encrypted = (preferEncrypted == CryptoLevel::Force) || (lvl == CryptoLevel::Force) || ((preferEncrypted == CryptoLevel::Prefer) && (lvl == CryptoLevel::Prefer));
+
+ if (!encrypted) {
+ firstMessage = false; // We're done here. No need to try to get a public key for an unencrypted channel
+ writeBufferedPackets();
+ }
+ else {
+ ulong_64b size;
+ char* c = Crypto::RSA::serializeKey(keys.publKey, &size);
+ _write(c, size); // This shouldn't be encrypted
+ delete[] c;
+ }
+ }
+ else throw new _exception(); // Incompatible cryptographic requirements!
+ }
+ if (fm_neg_hasLevel && !fm_neg_hasSize && encrypted && sparse->size() >= sizeof(ulong_64b)) {
+ fm_neg_hasSize = true;
+ char* readSize = readSparse(sparse, sizeof(ulong_64b));
+
+ fm_neg_size = 0;
+ memcpy(&fm_neg_size, readSize, sizeof(ulong_64b));
+ free(readSize);
+ }
+ if (fm_neg_hasSize && sparse->size() >= fm_neg_size) {
+ char* msg = readSparse(sparse, fm_neg_size);
+
+ CryptoPP::StringSource src((const byte*)msg, fm_neg_size, true);
+ pK.Load(src);
+
+ firstMessage = false;
+ writeBufferedPackets();
+ }
+ }
+ }
+ else if (iResult < 0 && _open) {
+ _open = false;
+ close();
+ }
+ }
+ bool NetClient::isOpen() { return _open; }
+
+ void NetClient::setOnDestroy(std::function call) { onDestroy = call; }
+
+ 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 f = nullptr, CryptoLevel pref = CryptoLevel::None) : pref(pref) {
+ if (pref != CryptoLevel::None) keys = Crypto::RSA::rsa_gen_keys();
+ _open = true;
+ timeoutHandler = NULL;
+ onDestroy = NULL;
+ handlers = new std::vector >();
+ if (f != NULL) handlers->push_back(f);
+ clients = new std::vector();
+ clientListener = std::thread([this, port]() {
+ SOCKET _server;
+ WSADATA wsaData;
+ int iResult;
+
+ struct addrinfo *result = NULL;
+ struct addrinfo hints;
+
+ // Initialize Winsock
+ iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
+ if (iResult != 0) throw new _exception();
+
+
+ ZeroMemory(&hints, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_flags = AI_PASSIVE;
+
+ // Resolve the server address and port
+ iResult = getaddrinfo(NULL, port, &hints, &result);
+ if (iResult) {
+ throw new _exception();
+ }
+
+ // Create a SOCKET for connecting to server
+ _server = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
+ if (_server == INVALID_SOCKET) {
+ freeaddrinfo(result);
+ throw new _exception();
+ }
+
+ // Setup the TCP listening socket
+ iResult = bind(_server, result->ai_addr, (int)result->ai_addrlen);
+ if (iResult == SOCKET_ERROR) {
+ freeaddrinfo(result);
+ closesocket(_server);
+ throw new _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.
+ closesocket(_server);
+ throw new _exception();
+ }
+ timeval t;
+ t.tv_sec = 0;
+ t.tv_usec = 5000;
+ do {
+ fd_set connecting;
+ connecting.fd_count = 1;
+ connecting.fd_array[0] = _server;
+ int i = select(NULL, &connecting, NULL, NULL, &t); // Check for new clients
+ if (i == SOCKET_ERROR) {
+ 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
+ SOCKET client = accept(_server, NULL, NULL);
+ if (client == INVALID_SOCKET) {
+ closesocket(_server);
+ if (_open) throw new _exception();
+ else break;
+ }
+ NetClient* cli = new NetClient(client, true, keys, this->pref, false);
+ clients->push_back(cli);
+ for (ulong_64b t = 0; t < handlers->size(); ++t)
+ if (handlers->at(t)(cli))
+ break;
+
+ }
+ updateClients();
+ } while (_open);
+ closesocket(_server);
+ close();
+ });
+
+ }
+
+ NetServer::~NetServer() {
+ if (_open) close();
+ handlers->clear();
+ delete handlers;
+ clients->clear();
+ delete clients;
+ onDestroy();
+ }
+
+ void NetServer::addHandler(std::function evtH) {
+ handlers->push_back(evtH);
+ }
+
+ void NetServer::clearHandlers() {
+ handlers->clear();
+ }
+
+ void NetServer::updateClients() {
+ for (ulong_64b t = clients->size(); t > 0; --t) {
+ NetClient* c = clients->at(t - 1);
+ if (!c->isOpen() || (timeoutHandler != NULL && !timeoutHandler(c))) {
+ clients->erase(clients->begin() + t - 1, clients->begin() + t);
+ c->close();
+ }
+ else c->update();
+ }
+ }
+ CryptoLevel NetServer::getCryptoPreference() { return pref; }
+
+ bool NetServer::isOpen() { return _open; }
+
+ void NetServer::setOnDestroy(std::function call) { onDestroy = call; }
+}
\ No newline at end of file
diff --git a/CPPTools/Net.h b/CPPTools/Net.h
new file mode 100644
index 0000000..223744b
--- /dev/null
+++ b/CPPTools/Net.h
@@ -0,0 +1,112 @@
+#pragma once
+
+
+#ifndef _NET_H
+#define _NET_H
+
+#ifdef _NET_SMALL_BUF
+#define BUFSIZE 512
+#define BUF_2_MAX 2048
+#else
+#define BUFSIZE 16384
+#define BUF_2_MAX 16384
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "Crypto.h"
+#include "ArchAbstract.h"
+
+#include
+#include
+#include
+#include
+
+
+namespace IO {
+
+ enum CryptoLevel { None, Prefer, Force };
+
+ struct Packet {
+ ulong_64b size;
+ char* message;
+ };
+
+ class NetServer;
+ class NetClient {
+ friend class NetServer; // Allow NetServer to access all members of NetClient
+
+ private:
+ volatile bool _open; // Whether or not connection is open
+ 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
+ char rBuf[BUFSIZE]; // Recieve buffer
+ 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 firstMessage = true; // Whether or not negotiation has yet ocurred
+ ulong_64b fm_neg_size;
+ bool fm_neg_hasLevel = false;
+ bool fm_neg_hasSize = false;
+ bool startNegotiate = false;
+ std::vector* sparse;
+ std::vector* outPacketBuf;
+ Crypto::RSA::KeyData keys; // Client's keysets (if using encryption)
+ CryptoPP::RSAFunction pK; // Remote host's public key (if using encryption)
+
+ NetClient(SOCKET, bool, CryptoLevel, bool);// Special setup constructor
+ NetClient(SOCKET, bool, Crypto::RSA::KeyData&, CryptoLevel = CryptoLevel::None, bool = false);// Create wrapper for existing socket
+ void sharedSetup(); // 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 writeBufferedPackets(); // Flushes and deletes buffer
+ void update(); // Read incoming data and store in buffers
+ protected:
+ std::thread listener; // Incoming data listener (optional)
+ SOCKET _socket; // Underlying socket used for communication
+ std::vector* packets; // Basically a set containing a backlog of unprocessed data. Will oly be used if event handler doesn't exist
+ std::function evt; // New data event handler
+ std::function onDestroy; // Event handler called when NetClient object is destroyed
+ public:
+ time_t commTime; // Latest time a transaction occurred
+ std::vector associatedData;
+ NetClient(char* ipAddr, char* port, CryptoLevel = CryptoLevel::None);// Standard constructor for creating connection
+ ~NetClient();
+ bool close();
+ void closeWrite();
+ bool isEncrypted();
+ size_t getBOPCount(); // Should return the amount of buffered packets to be sent to server
+ bool write(void* message, ulong_64b size);
+ bool write(char* message);
+ Packet read();
+ void setEventHandler(std::function); // Register a callback that is guaranteed to be called when the socket has at least one unprocessed packet
+ void setOnDestroy(std::function);
+ bool isOpen();
+ ulong_64b available();
+ };
+
+ class NetServer {
+ friend class NetClient;
+ private:
+ CryptoLevel pref;
+ Crypto::RSA::KeyData keys; // Server's keysets (if using encryption)
+
+ std::function onDestroy;
+ volatile bool _open;
+ void updateClients();
+ protected:
+ std::thread clientListener;
+ std::vector>* handlers;
+ std::vector* clients;
+ public:
+ std::function timeoutHandler;
+ NetServer(char* port, std::function, CryptoLevel);
+ ~NetServer();
+ bool isOpen();
+ CryptoLevel getCryptoPreference();
+ void addHandler(std::function);
+ void clearHandlers();
+ void setOnDestroy(std::function);
+ bool close();
+ };
+}
+
+#endif
\ No newline at end of file
diff --git a/CPPTools/Support.cpp b/CPPTools/Support.cpp
index aa3104e..75de7ba 100644
--- a/CPPTools/Support.cpp
+++ b/CPPTools/Support.cpp
@@ -118,376 +118,4 @@ namespace Tools {
for (size_t t = strlen(c); t > 0; --t) if (!isDigit(c[t - 1])) return false;
return true;
}
-}
-
-namespace IO {
-
- bool cryptoLevelsAreCompatible(CryptoLevel l1, CryptoLevel l2) {
- return !(((l1 == CryptoLevel::None) && (l2 == CryptoLevel::Force)) || ((l2 == CryptoLevel::None) && (l1 == CryptoLevel::Force)));
- }
-
- char* __cdecl readSparse(std::vector* sparse, ulong_64b rSize, bool pop = true) {
- if (sparse->size() < rSize) throw new _exception(); // This should never happen if function is used correctly
- char* c = new char[rSize];
- for (ulong_64b b = 0; b < rSize; ++b) c[b] = sparse->at(b);
- if(pop) sparse->erase(sparse->begin(), sparse->begin() + rSize);
- return c;
- }
-
- bool hasFullMessage(std::vector *sparse) {
- if (sparse->size() < sizeof(ulong_64b)) return false;
- ulong_64b size = 0;
- char* c = readSparse(sparse, sizeof(ulong_64b), false);
- memcpy(&size, c, sizeof(ulong_64b));
- delete[] c;
- return sparse->size() >= (size + sizeof(ulong_64b));
- }
-
-
-
- void NetClient::sharedSetup() {
- if (preferEncrypted != CryptoLevel::None) keys = Crypto::RSA::rsa_gen_keys();
- packets = new std::vector();
- sparse = new std::vector();
- outPacketBuf = new std::vector();
- _open = true;
- canWrite = true;
- evt = nullptr;
- char cryptoPref = static_cast(preferEncrypted);
- if(send(_socket, &cryptoPref, 1, 0)==SOCKET_ERROR) throw new _exception(); // Cannot establish connection :(
- //_write(&cryptoPref, 1);
- if (!noThread) listener = std::thread([this]() { while(_open) { update(); Sleep(25); } }); // Setup separate thread for reading new data
- }
- NetClient::NetClient(char* ipAddr, char* port, CryptoLevel preferEncrypted) :
- commTime(time(nullptr)), preferEncrypted(preferEncrypted), startNegotiate(false)
- {
- _socket = INVALID_SOCKET;
- this->noThread = false;
-
- WSADATA wsaData;
- int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (iResult != 0) throw new _exception();
-
-
- struct addrinfo *result = NULL, *ptr = NULL, hints;
-
- ZeroMemory(&hints, sizeof(hints));
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
-
- iResult = getaddrinfo(ipAddr, port, &hints, &result);
-
- if (iResult) throw new _exception();
-
- for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
-
- // Create a SOCKET for connecting to server
- _socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
- if (_socket == INVALID_SOCKET) {
- throw new _exception();
- }
-
- // Connect to server.
- iResult = connect(_socket, ptr->ai_addr, (int)ptr->ai_addrlen);
- if (iResult == SOCKET_ERROR) {
- closesocket(_socket);
- _socket = INVALID_SOCKET;
- continue;
- }
- break;
- }
-
- freeaddrinfo(result);
-
- if (_socket == INVALID_SOCKET) throw new _exception();
-
- sharedSetup();
- }
-
- NetClient::NetClient(SOCKET wrap, bool noThread, Crypto::RSA::KeyData& keys, CryptoLevel preferEncrypted, bool startNegotiate) :
- commTime(time(nullptr)), preferEncrypted(preferEncrypted), startNegotiate(startNegotiate)
- {
- _socket = wrap;
- this->noThread = noThread;
- sharedSetup();
- }
-
- NetClient::~NetClient() {
- packets->clear();
- delete packets;
- sparse->clear();
- delete sparse;
- if (isOpen()) close();
- }
- bool NetClient::close() {
- bool result = !_open;
- _open = false;
- result &= (SOCKET_ERROR==shutdown(_socket, SD_BOTH));
- closesocket(_socket);
- return result;
- }
- void NetClient::closeWrite() {
- shutdown(_socket, SD_SEND);
- canWrite = false;
- }
- bool NetClient::_write(char* message, ulong_64b size) {
- 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) return false;
- else if (i == 0) --wIdx;
- }
- for (ulong_64b wIdx = 0; wIdx < size; ++wIdx) {
- if ((i = send(_socket, message + wIdx, 1, 0)) == SOCKET_ERROR) return false;
- else if (i == 0) --wIdx;
- }
- return true;
- }
- bool NetClient::write(void* message, ulong_64b size) {
- if (firstMessage) {
- Packet p;
- p.message = (char*)message;
- p.size = size;
- outPacketBuf->push_back(p);
- return true;
- }
- if (!canWrite) return false;
- char* msg = encrypted?Crypto::full_auto_encrypt(message, size, pK, &size):(char*)message;
- _write(msg, size);
- if (encrypted) delete[] msg;
- return true;
- }
- bool NetClient::write(char* message) { return write(message, strlen(message)); }
- bool NetClient::writeBufferedPackets() {
- for (size_t t = 0; t < outPacketBuf->size(); ++t) if (!write(outPacketBuf->at(t).message, outPacketBuf->at(t).size)) { delete outPacketBuf; return false; };
- delete outPacketBuf;
- return true;
- }
- Packet NetClient::read() {
- if (packets->size() != 0) {
- Packet p = packets->at(0);
- packets->erase(packets->begin(), packets->begin()+1); // Delete first buffered packet
- return p;
- }
- throw new _exception(); // No packets available!
- }
- void NetClient::setEventHandler(std::function _ev) {
- evt = _ev;
-
- // Process unhandled packets
- if (evt != nullptr)
- for (size_t t = packets->size(); t > 0; --t) {
- Packet p = packets->at(t - 1);
- packets->pop_back();
- evt(this, p);
- }
- }
- bool NetClient::isEncrypted() { return encrypted; }
- void NetClient::update() {
- int iResult = 0;
- unsigned long rCount;
- int rdErr = ioctlsocket(_socket, FIONREAD, &rCount);
- if (rdErr == SOCKET_ERROR) throw new _exception(); // Error using socket :(
- if (rCount > 0) {
- iResult = recv(_socket, rBuf, BUFSIZE, 0);
- if (iResult > 0)
- for (int i = 0; i < iResult; ++i)
- if (sparse->size() < BUF_2_MAX)
- sparse->push_back(rBuf[i]); // Drop anything over the absolute max
- }
- while (!firstMessage && hasFullMessage(sparse)) {
- Packet p;
- char* size = readSparse(sparse, sizeof(ulong_64b));
- memcpy(&p.size, size, sizeof(ulong_64b));
- delete[] size;
- p.message = readSparse(sparse, p.size);
- if (encrypted) p.message = Crypto::full_auto_decrypt(p.message, keys.privKey, &p.size);
- if(evt==nullptr) packets->push_back(p);
- else evt(this, p); // Notify event handler of a new packet
- }
- if (iResult > 0) {
- if (firstMessage) {
- if (!fm_neg_hasLevel && sparse->size() >= 1) {
- fm_neg_hasLevel = true;
- char* readCrypt = readSparse(sparse, 1);
- CryptoLevel lvl = static_cast(*readCrypt);
- free(readCrypt);
- if (cryptoLevelsAreCompatible(lvl, preferEncrypted)) {
- // Determine whether or not to use encryption
- encrypted = (preferEncrypted == CryptoLevel::Force) || (lvl == CryptoLevel::Force) || ((preferEncrypted == CryptoLevel::Prefer) && (lvl == CryptoLevel::Prefer));
-
- if (!encrypted) {
- firstMessage = false; // We're done here. No need to try to get a public key for an unencrypted channel
- writeBufferedPackets();
- }
- else {
- ulong_64b size;
- char* c = Crypto::RSA::serializeKey(keys.publKey, &size);
- _write(c, size); // This shouldn't be encrypted
- delete[] c;
- }
- }
- else throw new _exception(); // Incompatible cryptographic requirements!
- }
- if (fm_neg_hasLevel && !fm_neg_hasSize && encrypted && sparse->size() >= sizeof(ulong_64b)) {
- fm_neg_hasSize = true;
- char* readSize = readSparse(sparse, sizeof(ulong_64b));
-
- fm_neg_size = 0;
- memcpy(&fm_neg_size, readSize, sizeof(ulong_64b));
- free(readSize);
- }
- if (fm_neg_hasSize && sparse->size() >= fm_neg_size) {
- char* msg = readSparse(sparse, fm_neg_size);
-
- CryptoPP::StringSource src((const byte*)msg, fm_neg_size, true);
- pK.Load(src);
-
- firstMessage = false;
- writeBufferedPackets();
- }
- }
- }else if (iResult < 0 && _open) {
- _open = false;
- close();
- }
- }
- bool NetClient::isOpen() { return _open; }
-
- void NetClient::setOnDestroy(std::function call) { onDestroy = call; }
-
- 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 f=nullptr, CryptoLevel pref=CryptoLevel::None) : pref(pref) {
- if (pref != CryptoLevel::None) keys = Crypto::RSA::rsa_gen_keys();
- _open = true;
- timeoutHandler = NULL;
- onDestroy = NULL;
- handlers = new std::vector >();
- if (f != NULL) handlers->push_back(f);
- clients = new std::vector();
- clientListener = std::thread([this, port]() {
- SOCKET _server;
- WSADATA wsaData;
- int iResult;
-
- struct addrinfo *result = NULL;
- struct addrinfo hints;
-
- // Initialize Winsock
- iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (iResult != 0) throw new _exception();
-
-
- ZeroMemory(&hints, sizeof(hints));
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_flags = AI_PASSIVE;
-
- // Resolve the server address and port
- iResult = getaddrinfo(NULL, port, &hints, &result);
- if (iResult) {
- throw new _exception();
- }
-
- // Create a SOCKET for connecting to server
- _server = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
- if (_server == INVALID_SOCKET) {
- freeaddrinfo(result);
- throw new _exception();
- }
-
- // Setup the TCP listening socket
- iResult = bind(_server, result->ai_addr, (int)result->ai_addrlen);
- if (iResult == SOCKET_ERROR) {
- freeaddrinfo(result);
- closesocket(_server);
- throw new _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.
- closesocket(_server);
- throw new _exception();
- }
- timeval t;
- t.tv_sec = 0;
- t.tv_usec = 5000;
- do {
- fd_set connecting;
- connecting.fd_count = 1;
- connecting.fd_array[0] = _server;
- int i = select(NULL, &connecting, NULL, NULL, &t); // Check for new clients
- if (i == SOCKET_ERROR) {
- 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
- SOCKET client = accept(_server, NULL, NULL);
- if (client == INVALID_SOCKET) {
- closesocket(_server);
- if (_open) throw new _exception();
- else break;
- }
- NetClient* cli = new NetClient(client, true, keys, this->pref, false);
- clients->push_back(cli);
- for (ulong_64b t = 0; t < handlers->size(); ++t)
- if (handlers->at(t)(cli))
- break;
-
- }
- updateClients();
- } while (_open);
- closesocket(_server);
- close();
- });
-
- }
-
- NetServer::~NetServer() {
- if (_open) close();
- handlers->clear();
- delete handlers;
- clients->clear();
- delete clients;
- onDestroy();
- }
-
- void NetServer::addHandler(std::function evtH) {
- handlers->push_back(evtH);
- }
-
- void NetServer::clearHandlers() {
- handlers->clear();
- }
-
- void NetServer::updateClients() {
- for (ulong_64b t = clients->size(); t > 0; --t) {
- NetClient* c = clients->at(t-1);
- if (!c->isOpen() || (timeoutHandler != NULL && !timeoutHandler(c))) {
- clients->erase(clients->begin() + t - 1, clients->begin() + t);
- c->close();
- }
- else c->update();
- }
- }
- CryptoLevel NetServer::getCryptoPreference() { return pref; }
-
- bool NetServer::isOpen() { return _open; }
-
- void NetServer::setOnDestroy(std::function call) { onDestroy = call; }
}
\ No newline at end of file
diff --git a/CPPTools/Support.h b/CPPTools/Support.h
index 1aae9d1..63b24ca 100644
--- a/CPPTools/Support.h
+++ b/CPPTools/Support.h
@@ -3,27 +3,8 @@
#ifndef _SUPPORT_H
#define _SUPPORT_H
-#ifdef _SUPPORT_SMALL_BUF
-#define BUFSIZE 512
-#define BUF_2_MAX 2048
-#else
-#define BUFSIZE 16384
-#define BUF_2_MAX 16384
-#endif
-
-#define WIN32_LEAN_AND_MEAN
-
#include "ArchAbstract.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
#include "Crypto.h"
@@ -46,89 +27,4 @@ namespace Tools {
bool isIP(char* c);
}
-namespace IO {
-
- enum CryptoLevel { None, Prefer, Force };
-
- struct Packet {
- ulong_64b size;
- char* message;
- };
-
- class NetServer;
- class NetClient {
- friend class NetServer; // Allow NetServer to access all members of NetClient
-
- private:
- volatile bool _open; // Whether or not connection is open
- 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
- char rBuf[BUFSIZE]; // Recieve buffer
- 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 firstMessage = true; // Whether or not negotiation has yet ocurred
- ulong_64b fm_neg_size;
- bool fm_neg_hasLevel = false;
- bool fm_neg_hasSize = false;
- bool startNegotiate = false;
- std::vector* sparse;
- std::vector* outPacketBuf;
- Crypto::RSA::KeyData keys; // Client's keysets (if using encryption)
- CryptoPP::RSAFunction pK; // Remote host's public key (if using encryption)
-
- NetClient(SOCKET, bool, CryptoLevel, bool);// Special setup constructor
- NetClient(SOCKET, bool, Crypto::RSA::KeyData&, CryptoLevel = CryptoLevel::None, bool = false);// Create wrapper for existing socket
- void sharedSetup(); // 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 writeBufferedPackets(); // Flushes and deletes buffer
- void update(); // Read incoming data and store in buffers
- protected:
- std::thread listener; // Incoming data listener (optional)
- SOCKET _socket; // Underlying socket used for communication
- std::vector* packets; // Basically a set containing a backlog of unprocessed data. Will oly be used if event handler doesn't exist
- std::function evt; // New data event handler
- std::function onDestroy; // Event handler called when NetClient object is destroyed
- public:
- time_t commTime; // Latest time a transaction occurred
- std::vector associatedData;
- NetClient(char* ipAddr, char* port, CryptoLevel = CryptoLevel::None);// Standard constructor for creating connection
- ~NetClient();
- bool close();
- void closeWrite();
- bool isEncrypted();
- size_t getBOPCount(); // Should return the amount of buffered packets to be sent to server
- bool write(void* message, ulong_64b size);
- bool write(char* message);
- Packet read();
- void setEventHandler(std::function); // Register a callback that is guaranteed to be called when the socket has at least one unprocessed packet
- void setOnDestroy(std::function);
- bool isOpen();
- ulong_64b available();
- };
-
- class NetServer {
- friend class NetClient;
- private:
- CryptoLevel pref;
- Crypto::RSA::KeyData keys; // Server's keysets (if using encryption)
-
- std::function onDestroy;
- volatile bool _open;
- void updateClients();
- protected:
- std::thread clientListener;
- std::vector>* handlers;
- std::vector* clients;
- public:
- std::function timeoutHandler;
- NetServer(char* port, std::function, CryptoLevel);
- ~NetServer();
- bool isOpen();
- CryptoLevel getCryptoPreference();
- void addHandler(std::function);
- void clearHandlers();
- void setOnDestroy(std::function);
- bool close();
- };
-}
#endif
\ No newline at end of file
diff --git a/CPPTools/Test.cpp b/CPPTools/Test.cpp
deleted file mode 100644
index 3c37c46..0000000
--- a/CPPTools/Test.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "Support.h"
-#include
-
-int main() {
- std::vector* sparse = new std::vector();
-
- sparse->push_back(1);
- sparse->push_back(2);
- sparse->push_back(3);
-
- std::cout << sparse->size() << std::endl;
-
- sparse->erase(sparse->begin(), sparse->begin()+sparse->size());
-
- std::cout << sparse->size() << std::endl;
- std::cin.ignore();
-}
\ No newline at end of file
diff --git a/CPPTools/Tools.h b/CPPTools/Tools.h
index eaf0a9e..a3ae697 100644
--- a/CPPTools/Tools.h
+++ b/CPPTools/Tools.h
@@ -2,4 +2,5 @@
#include "Crypto.h"
#include "Support.h"
-#include "ArchAbstract.h"
\ No newline at end of file
+#include "ArchAbstract.h"
+#include "Net.h"
\ No newline at end of file