summaryrefslogtreecommitdiff
path: root/csgo-loader/csgo-server/Networking
diff options
context:
space:
mode:
Diffstat (limited to 'csgo-loader/csgo-server/Networking')
-rw-r--r--csgo-loader/csgo-server/Networking/TCPServer.cpp124
-rw-r--r--csgo-loader/csgo-server/Networking/TCPServer.hpp87
-rw-r--r--csgo-loader/csgo-server/Networking/WebSocket.cpp44
-rw-r--r--csgo-loader/csgo-server/Networking/WebSocket.hpp37
4 files changed, 292 insertions, 0 deletions
diff --git a/csgo-loader/csgo-server/Networking/TCPServer.cpp b/csgo-loader/csgo-server/Networking/TCPServer.cpp
new file mode 100644
index 0000000..725bf1a
--- /dev/null
+++ b/csgo-loader/csgo-server/Networking/TCPServer.cpp
@@ -0,0 +1,124 @@
+#include <Networking/TCPServer.hpp>
+
+namespace Networking {
+ void TCPConnection::Close() {
+ printf("[<=] %s disconnected!\n", m_IpAddress);
+
+ if(m_Socket)
+ closesocket(m_Socket);
+ }
+
+ // We will only receive up to 256 bytes per cycle.
+ constexpr int BufferSize = 256;
+
+ void TCPConnection::SendRawBytes(ByteArray &Bytes) {
+ // Send data.
+ int32_t Result = send(m_Socket, (char *)Bytes.data(), (int)Bytes.size(), 0);
+
+ printf("[=>] Sending %zd bytes to %s.\n", Bytes.size(), m_IpAddress);
+
+ if(Result == -1)
+ printf("[=>] Failed to send %zd bytes to %s. (Socket %04Ix)\n", Bytes.size(), m_IpAddress, m_Socket);
+ }
+
+ ByteArray TCPConnection::ReceiveRawBytes() {
+ ByteArray ReceivedBytes;
+ uint8_t RecvBuffer[BufferSize];
+
+ // Attempt to receive a packet.
+ while(true) {
+ int32_t Received = recv(m_Socket, (char*)RecvBuffer, BufferSize, 0);
+
+ // No more bytes left to receive.
+ if(Received < 0)
+ break;
+
+ // Emplace all received bytes.
+ for(int n = 0; n < Received; ++n) {
+ ReceivedBytes.push_back(RecvBuffer[n]);
+ }
+
+ // No more bytes left to receive.
+ if(Received < BufferSize)
+ break;
+ }
+
+ printf("[<=] Received %zd bytes from %s.\n", ReceivedBytes.size(), m_IpAddress);
+
+ return ReceivedBytes;
+ }
+
+ void TCPConnection::SendBytes(ByteArray &Bytes) {
+ // Encrypt outgoing data.
+ ByteArray Encrypted = m_Encryption.Encrypt(Bytes);
+
+ SendRawBytes(Encrypted);
+ }
+
+ ByteArray TCPConnection::ReceiveBytes() {
+ ByteArray ReceivedBytes = ReceiveRawBytes();
+
+ // Decrypt incoming data.
+ ByteArray Decrypted = m_Encryption.Decrypt(ReceivedBytes);
+
+ return Decrypted;
+ }
+
+ bool TCPServer::Start(uint16_t ServerPort) {
+ const int32_t version = 0x101;
+
+ // Initialise WinSocks.
+ if(WSAStartup(version, &m_WinSocks))
+ return false;
+
+ // Create an IPv4 socket.
+ m_Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if(m_Socket == INVALID_SOCKET)
+ return false;
+
+ // Set up server context.
+ m_Context.sin_addr.s_addr = INADDR_ANY;
+ m_Context.sin_family = AF_INET;
+ m_Context.sin_port = htons(ServerPort);
+
+ int32_t Bind = bind(m_Socket, (sockaddr *)&m_Context, sizeof sockaddr_in);
+
+ if(Bind == INVALID_SOCKET)
+ return false;
+
+ // Start listening.
+ printf("[INFO] Server listening on port %d.\n", ServerPort);
+ listen(m_Socket, 1);
+
+ return true;
+ }
+
+ void TCPServer::AcceptConnection() {
+ sockaddr_in IncomingConnection;
+ int32_t AddressLength = sizeof IncomingConnection;
+
+ // Accept the incoming connection.
+ SOCKET IncomingSocket = accept(m_Socket, (sockaddr *)&IncomingConnection, &AddressLength);
+
+ if(IncomingSocket != INVALID_SOCKET) {
+ Wrapper::Encryption Encryption;
+
+ // Initialise encryption context.
+ Encryption.Start();
+
+ // Attempt handshake with client.
+ TCPConnection Connection(IncomingSocket, inet_ntoa(IncomingConnection.sin_addr), Encryption);
+
+ ByteArray EncryptionKey = Connection.GetEncryptionKey();
+ Connection.SendRawBytes(EncryptionKey);
+
+ // Detach a thread to handle the connection.
+ std::thread thread([&] {
+ m_ConnectionHandler(Connection);
+ Connection.Close();
+ });
+ thread.detach();
+ }
+ }
+} \ No newline at end of file
diff --git a/csgo-loader/csgo-server/Networking/TCPServer.hpp b/csgo-loader/csgo-server/Networking/TCPServer.hpp
new file mode 100644
index 0000000..adb6e7c
--- /dev/null
+++ b/csgo-loader/csgo-server/Networking/TCPServer.hpp
@@ -0,0 +1,87 @@
+#pragma once
+
+// For encryption wrappers.
+#include <Security/Encryption.hpp>
+
+// WinSocks
+#include <winsock2.h>
+#pragma comment(lib, "ws2_32.lib")
+
+// std::function
+#include <functional>
+
+// std::min
+#include <algorithm>
+
+// std::thread
+#include <thread>
+
+namespace Networking {
+ // Base connection class, used to handle multiple connections in a thread-based model.
+ class TCPConnection {
+ SOCKET m_Socket;
+ Wrapper::Encryption m_Encryption;
+ const char *m_IpAddress;
+ public:
+ // Initialiser for TCPConnection class.
+ TCPConnection(SOCKET Connection, const char *IpAddress, Wrapper::Encryption &RSA) :
+ m_Encryption(RSA), m_Socket(Connection), m_IpAddress(IpAddress) {
+ printf("[=>] %s connected!\n", IpAddress);
+ }
+
+ // Release the connection once it goes out of scope.
+ void Close();
+
+ // Wrappers for sending/receiving data.
+ void SendRawBytes(ByteArray &Bytes);
+ ByteArray ReceiveRawBytes();
+
+ void SendBytes(ByteArray &Bytes);
+ ByteArray ReceiveBytes();
+
+ // Overload for getting the socket, in case we need to expose it.
+ SOCKET operator()() {
+ return m_Socket;
+ }
+
+ // Expose the encryption key for the connection.
+ ByteArray GetEncryptionKey() {
+ return m_Encryption.GetKey();
+ }
+ };
+
+ // Basic TCP server. Supports custom connection handling (pass a lambda to the handler list).
+ using ConnectionHandler = std::function<void(TCPConnection &)>;
+
+ class TCPServer {
+ WSADATA m_WinSocks;
+ SOCKET m_Socket;
+ sockaddr_in m_Context;
+
+ // Connection handlers, will be called sequentially upon connection.
+ ConnectionHandler m_ConnectionHandler;
+
+ public:
+ // Default constructor, nothing needed for now.
+ TCPServer() = default;
+
+ // Handle destruction of server once it goes out of scope.
+ ~TCPServer() {
+ // If we have a socket, close it.
+ if(m_Socket)
+ closesocket(m_Socket);
+
+ // Close WSA context.
+ WSACleanup();
+ }
+
+ // Handle the creation and handling of TCPServer connections.
+ bool Start(uint16_t ServerPort);
+ void AcceptConnection();
+
+ // Overload for adding connection handlers, C# style support for events.
+ void operator+=(std::function<void(TCPConnection &)> Function) {
+ m_ConnectionHandler = Function;
+ }
+ };
+} \ No newline at end of file
diff --git a/csgo-loader/csgo-server/Networking/WebSocket.cpp b/csgo-loader/csgo-server/Networking/WebSocket.cpp
new file mode 100644
index 0000000..755e89b
--- /dev/null
+++ b/csgo-loader/csgo-server/Networking/WebSocket.cpp
@@ -0,0 +1,44 @@
+#include <Networking/WebSocket.hpp>
+
+namespace Networking {
+ // Initialises a basic HTTP socket.
+ bool WebSocket::Start(const char *Address, const char *Username, const char *Password) {
+ m_Internet = InternetOpenA("none", INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
+
+ if(!m_Internet)
+ return false;
+
+ m_Address = InternetConnectA(m_Internet, Address, INTERNET_DEFAULT_HTTPS_PORT, Username, Password, INTERNET_SERVICE_HTTP, 0, 0);
+
+ if(!m_Address)
+ return false;
+
+ return true;
+ }
+
+ // Receives a response from a request.
+ ByteArray WebSocket::Request(const char *File, const char *Header, ByteArray &Data) {
+ ByteArray Response;
+ InternetHandle WebRequest = HttpOpenRequestA(m_Address, "POST", File, 0, 0, 0, INTERNET_FLAG_SECURE | INTERNET_FLAG_KEEP_CONNECTION, 0);
+
+ // Make connection request.
+ bool Sent = HttpSendRequestA(WebRequest, Header, (DWORD)strlen(Header), Data.data(), (DWORD)Data.size());
+
+ if(Sent) {
+ DWORD ReceivedSize{};
+
+ uint8_t *Block = (uint8_t *)malloc(4096);
+
+ // Read response.
+ while(InternetReadFile(WebRequest, Block, 4096, &ReceivedSize)) {
+ for(size_t n{}; n < std::min< int >(4096, ReceivedSize); ++n) {
+ Response.push_back(Block[n]);
+ }
+ }
+
+ free(Block);
+ }
+
+ return Response;
+ }
+} \ No newline at end of file
diff --git a/csgo-loader/csgo-server/Networking/WebSocket.hpp b/csgo-loader/csgo-server/Networking/WebSocket.hpp
new file mode 100644
index 0000000..f503913
--- /dev/null
+++ b/csgo-loader/csgo-server/Networking/WebSocket.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <windows.h>
+#include <wininet.h>
+#include <vector>
+#include <algorithm>
+#include <cstdint>
+
+#pragma comment(lib, "wininet.lib")
+
+using ByteArray = std::vector<uint8_t>;
+
+namespace Networking {
+ // Whenever the handle goes out of scope, it will automatically be released.
+ class InternetHandle {
+ HINTERNET m_Internet;
+ public:
+ InternetHandle() = default;
+ InternetHandle(HINTERNET Internet) :
+ m_Internet(Internet) { }
+
+ ~InternetHandle() {
+ InternetCloseHandle(m_Internet);
+ }
+
+ operator HINTERNET() { return m_Internet; };
+ };
+
+ class WebSocket {
+ InternetHandle m_Internet;
+ InternetHandle m_Address;
+
+ public:
+ bool Start(const char *Address, const char *Username, const char *Password);
+ ByteArray Request(const char *File, const char *Header, ByteArray &Data);
+ };
+} \ No newline at end of file