141 lines
3.9 KiB
C
141 lines
3.9 KiB
C
//
|
|
// Created by rov on 12/27/25.
|
|
//
|
|
|
|
#include "network.h"
|
|
|
|
#include <SDL3/SDL.h>
|
|
#include <SDL3_net/SDL_net.h>
|
|
|
|
#define NET_TIMEOUT 30000
|
|
|
|
typedef enum ConnectionResult {
|
|
CONN_SUCCESS = 0,
|
|
CONN_ERR_BAD_HOSTNAME = 1,
|
|
CONN_ERR_NO_SERVER = 2
|
|
} CONNECTION_RESULT;
|
|
|
|
void Gui_UpdateStatusBar(const Gui_t* gui, const char *message);
|
|
|
|
bool Network_Init(Network_t *network) {
|
|
if (!NET_Init()) {
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Failed to initialize SDL_net.", NULL);
|
|
return false;
|
|
}
|
|
|
|
network->socket = NULL;
|
|
|
|
return true;
|
|
}
|
|
|
|
void Network_Shutdown(const Network_t *network) {
|
|
NET_DestroyStreamSocket(network->socket);
|
|
NET_Quit();
|
|
}
|
|
|
|
CONNECTION_RESULT ConnectToServer(Network_t *network, const ConfigParams_t *configParams, const Gui_t *gui) {
|
|
Gui_UpdateStatusBar(gui, "Searching for hostname...");
|
|
|
|
NET_Address *netAddress = NET_ResolveHostname(configParams->serverAddress);
|
|
const NET_Status resolveHostnameStatus = NET_WaitUntilResolved(netAddress, NET_TIMEOUT);
|
|
if (resolveHostnameStatus != NET_SUCCESS) {
|
|
NET_UnrefAddress(netAddress);
|
|
return CONN_ERR_BAD_HOSTNAME;
|
|
}
|
|
|
|
Gui_UpdateStatusBar(gui, "Trying to connect...");
|
|
|
|
network->socket = NET_CreateClient(netAddress, configParams->serverPort);
|
|
const NET_Status createClientStatus = NET_WaitUntilConnected(network->socket, NET_TIMEOUT);
|
|
if (createClientStatus != NET_SUCCESS) {
|
|
NET_DestroyStreamSocket(network->socket);
|
|
network->socket = NULL;
|
|
|
|
NET_UnrefAddress(netAddress);
|
|
return CONN_ERR_NO_SERVER;
|
|
}
|
|
|
|
// TODO: is this okay?
|
|
NET_UnrefAddress(netAddress);
|
|
|
|
return CONN_SUCCESS;
|
|
}
|
|
|
|
void Network_ConnectAndReportStatus(Network_t *network, const ConfigParams_t *configParams, const Gui_t *gui) {
|
|
if (network->socket != NULL) {
|
|
return;
|
|
}
|
|
|
|
const CONNECTION_RESULT result = ConnectToServer(network, configParams, gui);
|
|
const char *message = NULL;
|
|
|
|
switch (result) {
|
|
case CONN_SUCCESS:
|
|
message = "Connection established.";
|
|
break;
|
|
case CONN_ERR_BAD_HOSTNAME:
|
|
message = "Error: IP address or host not found.";
|
|
break;
|
|
case CONN_ERR_NO_SERVER:
|
|
message = "Error: No server running on host.";
|
|
break;
|
|
}
|
|
|
|
Gui_UpdateStatusBar(gui, message);
|
|
}
|
|
|
|
void Network_Send(NET_StreamSocket* socket, uint8_t* packetBuf, const uint16_t packetLen) {
|
|
const uint16_t payloadLength = packetLen - 2;
|
|
|
|
*(uint16_t*) packetBuf = payloadLength;
|
|
|
|
if (!NET_WriteToStreamSocket(socket, packetBuf, packetLen)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Network_Send: Failed to send packet.");
|
|
}
|
|
}
|
|
|
|
void Network_HandleLoginOrCreateChar(const uint16_t opcode, uint8_t* packetBuf, uint16_t* packetLen, const void* data, const int dataLength) {
|
|
// Copy the opcode
|
|
packetBuf[*packetLen] = (uint8_t) opcode;
|
|
*packetLen += 1;
|
|
|
|
// Write unk0
|
|
const uint16_t unk0 = 1;
|
|
memcpy(&packetBuf[*packetLen], &unk0, 2);
|
|
*packetLen += 2;
|
|
|
|
// Write unk1
|
|
const uint16_t unk1 = 'g';
|
|
memcpy(&packetBuf[*packetLen], &unk1, 2);
|
|
*packetLen += 2;
|
|
|
|
memcpy(&packetBuf[*packetLen], data, dataLength);
|
|
*packetLen += dataLength;
|
|
}
|
|
|
|
void Network_SendPacket(const Network_t* network, const PACKET_HANDLER handler, const uint16_t opcode, void* data, const int dataLength) {
|
|
if (network->socket == NULL) {
|
|
return;
|
|
}
|
|
|
|
uint8_t packetBuf[1050];
|
|
uint16_t packetLen = 2;
|
|
|
|
// TODO: need this?
|
|
memset(packetBuf, 0, 1049);
|
|
|
|
// Write handler to buffer at offset 2
|
|
memcpy(&packetBuf[packetLen], &handler, 2);
|
|
packetLen += 2;
|
|
|
|
switch (handler) {
|
|
case HANDLER_LOGIN_OR_CREATE_CHAR:
|
|
Network_HandleLoginOrCreateChar(opcode, packetBuf, &packetLen, data, dataLength);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Network_Send(network->socket, packetBuf, packetLen);
|
|
}
|