OpenFusion/src/CNProtocol.cpp

358 lines
11 KiB
C++
Raw Normal View History

2020-08-18 20:42:30 +00:00
#include "CNProtocol.hpp"
2020-08-19 01:34:39 +00:00
#include "CNStructs.hpp"
2020-08-18 20:42:30 +00:00
2020-08-22 19:02:58 +00:00
#ifdef _MSC_VER
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#endif
2020-08-18 20:42:30 +00:00
// ========================================================[[ CNSocketEncryption ]]========================================================
// literally C/P from the client and converted to C++ (does some byte swapping /shrug)
int CNSocketEncryption::Encrypt_byte_change_A(int ERSize, uint8_t* data, int size) {
int num = 0;
int num2 = 0;
int num3 = 0;
while (num + ERSize <= size)
{
int num4 = num + num3;
int num5 = num + (ERSize - 1 - num3);
uint8_t b = data[num4];
data[num4] = data[num5];
data[num5] = b;
num += ERSize;
num3++;
if (num3 > ERSize / 2)
{
num3 = 0;
}
}
num2 = ERSize - (num + ERSize - size);
return num + num2;
}
int CNSocketEncryption::xorData(uint8_t* buffer, uint8_t* key, int size) {
// xor every 8 bytes with 8 byte key
for (int i = 0; i < size; i++) {
buffer[i] ^= key[i % keyLength];
}
return size;
}
uint64_t CNSocketEncryption::createNewKey(uint64_t uTime, int32_t iv1, int32_t iv2) {
uint64_t num = (uint64_t)(iv1 + 1);
uint64_t num2 = (uint64_t)(iv2 + 1);
uint64_t dEKey = (uint64_t)(*(uint64_t*)&defaultKey[0]);
return dEKey * (uTime * num * num2);
}
int CNSocketEncryption::encryptData(uint8_t* buffer, uint8_t* key, int size) {
int eRSize = size % (keyLength / 2 + 1) * 2 + keyLength; // C/P from client
int size2 = xorData(buffer, key, size);
return Encrypt_byte_change_A(eRSize, buffer, size2);
}
int CNSocketEncryption::decryptData(uint8_t* buffer, uint8_t* key, int size) {
int eRSize = size % (keyLength / 2 + 1) * 2 + keyLength; // size % of 18????
int size2 = Encrypt_byte_change_A(eRSize, buffer, size);
return xorData(buffer, key, size2);
}
// ========================================================[[ CNPacketData ]]========================================================
2020-08-23 17:19:12 +00:00
CNPacketData::CNPacketData(void* b, uint32_t t, int l): buf(b), size(l), type(t) {}
2020-08-18 20:42:30 +00:00
// ========================================================[[ CNSocket ]]========================================================
CNSocket::CNSocket(SOCKET s, PacketHandler ph): sock(s), pHandler(ph) {
EKey = (uint64_t)(*(uint64_t*)&CNSocketEncryption::defaultKey[0]);
}
bool CNSocket::sendData(uint8_t* data, int size) {
int sentBytes = 0;
2020-08-22 02:32:22 +00:00
int maxTries = 10;
2020-08-18 20:42:30 +00:00
while (sentBytes < size) {
int sent = send(sock, (buffer_t*)(data + sentBytes), size - sentBytes, 0); // no flags defined
2020-08-22 00:33:42 +00:00
if (SOCKETERROR(sent)) {
2020-08-22 02:32:22 +00:00
if (errno == 11 && maxTries > 0) {
maxTries--;
2020-08-22 00:33:42 +00:00
continue; // try again
2020-08-22 02:32:22 +00:00
}
2020-08-22 00:33:42 +00:00
std::cout << "[FATAL] SOCKET ERROR: " << errno << std::endl;
2020-08-18 20:42:30 +00:00
return false; // error occured while sending bytes
2020-08-22 00:33:42 +00:00
}
2020-08-18 20:42:30 +00:00
sentBytes += sent;
}
return true; // it worked!
}
void CNSocket::setEKey(uint64_t k) {
EKey = k;
}
void CNSocket::setFEKey(uint64_t k) {
FEKey = k;
}
uint64_t CNSocket::getEKey() {
return EKey;
}
uint64_t CNSocket::getFEKey() {
return FEKey;
}
bool CNSocket::isAlive() {
return alive;
}
void CNSocket::kill() {
alive = false;
#ifdef _WIN32
shutdown(sock, SD_BOTH);
closesocket(sock);
#else
shutdown(sock, SHUT_RDWR);
close(sock);
#endif
}
2020-08-22 23:31:09 +00:00
// we don't own buf
void CNSocket::sendPacket(void* buf, uint32_t type, size_t size) {
if (!alive)
2020-08-22 00:33:42 +00:00
return;
2020-08-22 23:31:09 +00:00
int tmpSize = size + sizeof(uint32_t);
2020-08-18 20:42:30 +00:00
uint8_t* tmpBuf = (uint8_t*)xmalloc(tmpSize);
// copy packet type to the front of the buffer & then the actual buffer
2020-08-22 23:31:09 +00:00
memcpy(tmpBuf, (void*)&type, sizeof(uint32_t));
memcpy(tmpBuf+sizeof(uint32_t), buf, size);
2020-08-18 20:42:30 +00:00
// encrypt the packet
2020-08-22 23:31:09 +00:00
switch (activeKey) {
case SOCKETKEY_E:
CNSocketEncryption::encryptData((uint8_t*)tmpBuf, (uint8_t*)(&EKey), tmpSize);
break;
case SOCKETKEY_FE:
CNSocketEncryption::encryptData((uint8_t*)tmpBuf, (uint8_t*)(&FEKey), tmpSize);
break;
default: {
free(tmpBuf);
DEBUGLOG(
std::cout << "[WARN]: UNSET KEYTYPE FOR SOCKET!! ABORTING SEND" << std::endl;
)
return;
}
}
2020-08-18 20:42:30 +00:00
// send packet size
2020-08-22 00:33:42 +00:00
if (!sendData((uint8_t*)&tmpSize, sizeof(uint32_t)))
kill();
2020-08-18 20:42:30 +00:00
// send packet data!
2020-08-22 00:33:42 +00:00
if (alive && !sendData(tmpBuf, tmpSize))
kill();
2020-08-18 20:42:30 +00:00
free(tmpBuf); // free tmp buffer
}
2020-08-22 23:31:09 +00:00
void CNSocket::setActiveKey(ACTIVEKEY key) {
activeKey = key;
}
2020-08-18 20:42:30 +00:00
void CNSocket::step() {
if (readSize <= 0) {
// we aren't reading a packet yet, try to start looking for one
int recved = recv(sock, (buffer_t*)readBuffer, sizeof(int32_t), 0);
if (!SOCKETERROR(recved)) {
// we got out packet size!!!!
readSize = *((int32_t*)readBuffer);
// sanity check
if (readSize > MAX_PACKETSIZE) {
kill();
return;
}
// we'll just leave bufferIndex at 0 since we already have the packet size, it's safe to overwrite those bytes
activelyReading = true;
}
}
if (readSize > 0 && readBufferIndex < readSize) {
// read until the end of the packet! (or at least try too)
int recved = recv(sock, (buffer_t*)(readBuffer + readBufferIndex), readSize - readBufferIndex, 0);
if (!SOCKETERROR(recved))
readBufferIndex += recved;
}
if (activelyReading && readBufferIndex - readSize <= 0) {
// decrypt readBuffer and copy to CNPacketData
CNSocketEncryption::decryptData(readBuffer, (uint8_t*)(&EKey), readSize);
void* tmpBuf = xmalloc(readSize-sizeof(int32_t));
memcpy(tmpBuf, readBuffer+sizeof(uint32_t), readSize-sizeof(int32_t));
2020-08-22 23:31:09 +00:00
CNPacketData tmp(tmpBuf, *((uint32_t*)readBuffer), readSize-sizeof(int32_t));
// call packet handler!!
pHandler(this, &tmp);
2020-08-18 20:42:30 +00:00
2020-08-22 23:31:09 +00:00
// clean up the buffer :)
free(tmpBuf);
2020-08-18 20:42:30 +00:00
// reset vars :)
readSize = 0;
readBufferIndex = 0;
activelyReading = false;
}
}
// ========================================================[[ CNServer ]]========================================================
void CNServer::init() {
// create socket file descriptor
sock = socket(AF_INET, SOCK_STREAM, 0);
if (SOCKETINVALID(sock)) {
std::cerr << "[FATAL] OpenFusion: socket failed" << std::endl;
exit(EXIT_FAILURE);
}
// attach socket to the port
int opt = 1;
#ifdef _WIN32
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt)) != 0) {
#else
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) != 0) {
#endif
std::cerr << "[FATAL] OpenFusion: setsockopt failed" << std::endl;
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
addressSize = sizeof(address);
// Bind to the port
if (SOCKETERROR(bind(sock, (struct sockaddr *)&address, addressSize))) {
std::cerr << "[FATAL] OpenFusion: bind failed" << std::endl;
exit(EXIT_FAILURE);
}
if (SOCKETERROR(listen(sock, SOMAXCONN))) {
std::cerr << "[FATAL] OpenFusion: listen failed" << std::endl;
exit(EXIT_FAILURE);
}
// set server listener to non-blocking
#ifdef _WIN32
unsigned long mode = 1;
if (ioctlsocket(sock, FIONBIO, &mode) != 0) {
#else
if (fcntl(sock, F_SETFL, (fcntl(sock, F_GETFL, 0) | O_NONBLOCK)) != 0) {
#endif
std::cerr << "[FATAL] OpenFusion: fcntl failed" << std::endl;
exit(EXIT_FAILURE);
}
}
2020-08-19 01:34:39 +00:00
CNServer::CNServer() {
lastTimer = getTime();
};
CNServer::CNServer(uint16_t p): port(p) {
lastTimer = getTime();
}
2020-08-18 20:42:30 +00:00
void CNServer::start() {
std::cout << "Starting server at *:" << port << std::endl;
// listen to new connections, add to connection list
2020-08-19 00:52:02 +00:00
while (active) {
std::lock_guard<std::mutex> lock(activeCrit);
2020-08-18 20:42:30 +00:00
// listen for a new connection
2020-08-22 23:31:09 +00:00
SOCKET newConnectionSocket = accept(sock, (struct sockaddr *)&(address), (socklen_t*)&(addressSize));
if (!SOCKETINVALID(newConnectionSocket)) {
2020-08-18 20:42:30 +00:00
// new connection! make sure to set non-blocking!
#ifdef _WIN32
unsigned long mode = 1;
2020-08-22 23:31:09 +00:00
if (ioctlsocket(newConnectionSocket, FIONBIO, &mode) != 0) {
2020-08-18 20:42:30 +00:00
#else
2020-08-22 23:31:09 +00:00
if (fcntl(newConnectionSocket, F_SETFL, (fcntl(sock, F_GETFL, 0) | O_NONBLOCK)) != 0) {
2020-08-18 20:42:30 +00:00
#endif
std::cerr << "[WARN] OpenFusion: fcntl failed on new connection" << std::endl;
#ifdef _WIN32
2020-08-22 23:31:09 +00:00
shutdown(newConnectionSocket, SD_BOTH);
closesocket(newConnectionSocket);
#else
2020-08-22 23:31:09 +00:00
shutdown(newConnectionSocket, SHUT_RDWR);
close(newConnectionSocket);
#endif
continue;
2020-08-18 20:42:30 +00:00
}
std::cout << "New connection! " << inet_ntoa(address.sin_addr) << std::endl;
// add connection to list!
2020-08-22 23:31:09 +00:00
CNSocket* tmp = new CNSocket(newConnectionSocket, pHandler);
2020-08-18 20:42:30 +00:00
connections.push_back(tmp);
2020-08-22 23:31:09 +00:00
newConnection(tmp);
2020-08-18 20:42:30 +00:00
}
// for each connection, check if it's alive, if not kill it!
std::list<CNSocket*>::iterator i = connections.begin();
while (i != connections.end()) {
CNSocket* cSock = *i;
if (cSock->isAlive()) {
cSock->step();
++i; // go to the next element
} else {
killConnection(cSock);
connections.erase(i++);
delete cSock;
}
}
2020-08-19 01:34:39 +00:00
if (getTime() - lastTimer > 2000) { // every 2 seconds call the onTimer method
onTimer();
lastTimer = getTime();
}
2020-08-18 20:42:30 +00:00
#ifdef _WIN32
Sleep(0);
#else
sleep(0); // so your cpu isn't at 100% all the time, we don't need all of that! im not hacky! you're hacky!
#endif
}
}
2020-08-19 00:52:02 +00:00
void CNServer::kill() {
std::lock_guard<std::mutex> lock(activeCrit); // the lock will be removed when the function ends
active = false;
// kill all connections
std::list<CNSocket*>::iterator i = connections.begin();
while (i != connections.end()) {
CNSocket* cSock = *i;
if (cSock->isAlive()) {
cSock->kill();
}
++i; // go to the next element
delete cSock;
}
connections.clear();
}
2020-08-22 23:31:09 +00:00
void CNServer::newConnection(CNSocket* cns) {} // stubbed
void CNServer::killConnection(CNSocket* cns) {} // stubbed
void CNServer::onTimer() {} // stubbed