prog
This commit is contained in:
13
backup/client/CMakeLists.txt
Normal file
13
backup/client/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
client.c
|
||||
clientremote.c
|
||||
)
|
||||
|
||||
# Subdirs
|
71
backup/client/client.c
Normal file
71
backup/client/client.c
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
void clientInit(
|
||||
client_t *client,
|
||||
const clientinit_t init
|
||||
) {
|
||||
assertNotNull(client, "Client cannot be NULL.");
|
||||
memset(client, 0, sizeof(client_t));
|
||||
|
||||
client->type = init.type;
|
||||
client->state = CLIENT_STATE_CONNECTING;
|
||||
|
||||
// Perform connection
|
||||
switch(init.type) {
|
||||
case CLIENT_TYPE_REMOTE:
|
||||
clientRemoteInit(client, init.remote);
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Invalid client type.");
|
||||
}
|
||||
|
||||
// Begin exchanging.
|
||||
// clientSend(client, (packet_t){
|
||||
// .type = PACKET_TYPE_HELLO
|
||||
// });
|
||||
}
|
||||
|
||||
void clientSend(
|
||||
client_t *client,
|
||||
const packet_t packet
|
||||
) {
|
||||
assertNotNull(client, "Client cannot be NULL.");
|
||||
assertTrue(
|
||||
client->state == CLIENT_STATE_CONNECTED,
|
||||
"Client must be connected to send packets."
|
||||
);
|
||||
|
||||
switch(client->type) {
|
||||
case CLIENT_TYPE_REMOTE:
|
||||
clientRemoteSend(client, packet);
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Invalid client type.");
|
||||
}
|
||||
}
|
||||
|
||||
void clientDispose(client_t *client) {
|
||||
assertNotNull(client, "Client cannot be NULL.");
|
||||
client->state = CLIENT_STATE_DISCONNECTING;
|
||||
|
||||
switch(client->type) {
|
||||
case CLIENT_TYPE_REMOTE:
|
||||
clientRemoteDispose(client);
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Invalid client type.");
|
||||
}
|
||||
|
||||
client->state = CLIENT_STATE_DISCONNECTED;
|
||||
}
|
51
backup/client/client.h
Normal file
51
backup/client/client.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "clientremote.h"
|
||||
|
||||
typedef enum {
|
||||
CLIENT_TYPE_SINGLE_PLAYER,
|
||||
CLIENT_TYPE_LOCAL,
|
||||
CLIENT_TYPE_REMOTE
|
||||
} clienttype_t;
|
||||
|
||||
typedef enum {
|
||||
CLIENT_STATE_DISCONNECTED,
|
||||
CLIENT_STATE_DISCONNECTING,
|
||||
CLIENT_STATE_CONNECTING,
|
||||
CLIENT_STATE_CONNECTED
|
||||
} clientstate_t;
|
||||
|
||||
typedef struct _client_t {
|
||||
clienttype_t type;
|
||||
clientstate_t state;
|
||||
|
||||
union {
|
||||
clientremote_t remote;
|
||||
};
|
||||
} client_t;
|
||||
|
||||
typedef struct {
|
||||
clienttype_t type;
|
||||
|
||||
union {
|
||||
clientremoteinit_t remote;
|
||||
};
|
||||
} clientinit_t;
|
||||
|
||||
void clientInit(
|
||||
client_t *client,
|
||||
const clientinit_t init
|
||||
);
|
||||
|
||||
void clientSend(
|
||||
client_t *client,
|
||||
const packet_t packet
|
||||
);
|
||||
|
||||
void clientDispose(client_t *client);
|
61
backup/client/clientremote.c
Normal file
61
backup/client/clientremote.c
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "assert/assert.h"
|
||||
#include "console/console.h"
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void* clientRemoteThreadFunc(void* arg) {
|
||||
client_t *client = (client_t*)arg;
|
||||
assertNotNull(client, "Client is NULL");
|
||||
|
||||
client->state = CLIENT_STATE_CONNECTED;
|
||||
|
||||
// Set socket to non-blocking
|
||||
int flags = fcntl(client->remote.clientSockDesc, F_GETFL, 0);
|
||||
fcntl(client->remote.clientSockDesc, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
char buffer[1024];
|
||||
while (client->state == CLIENT_STATE_CONNECTED) {
|
||||
ssize_t bytesRead = read(client->remote.clientSockDesc, buffer, sizeof(buffer));
|
||||
if (bytesRead > 0) {
|
||||
// Process the received data
|
||||
printf("Received data: %.*s\n", (int)bytesRead, buffer);
|
||||
} else if (bytesRead == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
// An error occurred
|
||||
perror("Read error");
|
||||
break;
|
||||
}
|
||||
// Sleep for a short duration to prevent busy-waiting
|
||||
usleep(10000); // 10ms
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void clientRemoteInit(
|
||||
client_t *client,
|
||||
const clientremoteinit_t init
|
||||
) {
|
||||
client->remote.clientSockDesc = init.clientSockDesc;
|
||||
consolePrint("Accepted a new connection.");
|
||||
|
||||
pthread_create(&client->remote.thread, NULL, clientRemoteThreadFunc, client);
|
||||
}
|
||||
|
||||
void clientRemoteSend(client_t *client, const packet_t packet) {
|
||||
printf("send pack\n");
|
||||
}
|
||||
|
||||
void clientRemoteDispose(client_t *client) {
|
||||
pthread_join(client->remote.thread, NULL);
|
||||
|
||||
close(client->remote.clientSockDesc);
|
||||
consolePrint("Client disconnected.");
|
||||
}
|
26
backup/client/clientremote.h
Normal file
26
backup/client/clientremote.h
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "net/packet.h"
|
||||
|
||||
typedef struct _client_t client_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t clientSockDesc;
|
||||
} clientremoteinit_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t clientSockDesc;
|
||||
pthread_t thread;
|
||||
} clientremote_t;
|
||||
|
||||
void clientRemoteInit(client_t *client, const clientremoteinit_t init);
|
||||
void clientRemoteSend(client_t *client, const packet_t packet);
|
||||
void * clientRemoteThread(void *arg);
|
||||
void clientRemoteDispose(client_t *client);
|
14
backup/server/CMakeLists.txt
Normal file
14
backup/server/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
server.c
|
||||
serverlocal.c
|
||||
serversingleplayer.c
|
||||
)
|
||||
|
||||
# Subdirs
|
77
backup/server/server.c
Normal file
77
backup/server/server.c
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "server.h"
|
||||
#include "console/console.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
server_t SERVER;
|
||||
|
||||
void serverInit() {
|
||||
memset(&SERVER, 0, sizeof(server_t));
|
||||
}
|
||||
|
||||
void serverStart(const serverstart_t start) {
|
||||
assertTrue(SERVER.state==SERVER_STATE_STOPPED, "Server is already running.");
|
||||
|
||||
SERVER.type = start.type;
|
||||
SERVER.clientCount = 0;
|
||||
|
||||
switch(start.type) {
|
||||
case SERVER_TYPE_SINGLE_PLAYER:
|
||||
serverSinglePlayerStart(start.singlePlayer);
|
||||
break;
|
||||
|
||||
case SERVER_TYPE_LOCAL:
|
||||
serverLocalStart(start.local);
|
||||
break;
|
||||
|
||||
case SERVER_TYPE_REMOTE:
|
||||
assertUnreachable("Remote server not implemented.");
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Unknown server type.");
|
||||
}
|
||||
|
||||
SERVER.state = SERVER_STATE_RUNNING;
|
||||
}
|
||||
|
||||
void serverStop() {
|
||||
assertTrue(SERVER.state == SERVER_STATE_RUNNING,"Server is already stopped.");
|
||||
|
||||
for(uint8_t i = 0; i < SERVER.clientCount; i++) {
|
||||
clientDispose(&SERVER.clients[i]);
|
||||
}
|
||||
|
||||
switch(SERVER.type) {
|
||||
case SERVER_TYPE_SINGLE_PLAYER:
|
||||
assertUnreachable("Single player server not implemented.");
|
||||
break;
|
||||
|
||||
case SERVER_TYPE_LOCAL:
|
||||
serverLocalStop();
|
||||
break;
|
||||
|
||||
case SERVER_TYPE_REMOTE:
|
||||
assertUnreachable("Remote server not implemented.");
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Unknown server type.");
|
||||
}
|
||||
|
||||
SERVER.state = SERVER_STATE_STOPPED;
|
||||
}
|
||||
|
||||
void serverUpdate() {
|
||||
if(SERVER.state == SERVER_STATE_STOPPED) return;
|
||||
}
|
||||
|
||||
void serverDispose() {
|
||||
if(SERVER.state == SERVER_STATE_RUNNING) serverStop();
|
||||
}
|
53
backup/server/server.h
Normal file
53
backup/server/server.h
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "client/client.h"
|
||||
#include "serversingleplayer.h"
|
||||
#include "serverlocal.h"
|
||||
|
||||
#define SERVER_CLIENT_COUNT_MAX 4
|
||||
|
||||
typedef enum {
|
||||
SERVER_TYPE_SINGLE_PLAYER = 0,
|
||||
SERVER_TYPE_LOCAL = 1,
|
||||
SERVER_TYPE_REMOTE = 2
|
||||
} servertype_t;
|
||||
|
||||
typedef enum {
|
||||
SERVER_STATE_STOPPED = 0,
|
||||
SERVER_STATE_RUNNING = 1
|
||||
} serverstate_t;
|
||||
|
||||
typedef struct {
|
||||
servertype_t type;
|
||||
|
||||
union {
|
||||
serversingleplayerstart_t singlePlayer;
|
||||
serverlocalstart_t local;
|
||||
};
|
||||
} serverstart_t;
|
||||
|
||||
typedef struct {
|
||||
serverstate_t state;
|
||||
servertype_t type;
|
||||
|
||||
client_t clients[SERVER_CLIENT_COUNT_MAX];
|
||||
uint8_t clientCount;
|
||||
|
||||
union {
|
||||
serverlocal_t local;
|
||||
};
|
||||
} server_t;
|
||||
|
||||
extern server_t SERVER;
|
||||
|
||||
void serverInit();
|
||||
void serverStart(const serverstart_t start);
|
||||
void serverStop();
|
||||
void serverUpdate();
|
||||
void serverDispose();
|
127
backup/server/serverlocal.c
Normal file
127
backup/server/serverlocal.c
Normal file
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "server.h"
|
||||
#include "assert/assert.h"
|
||||
#include "console/console.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
void serverLocalStart(const serverlocalstart_t start) {
|
||||
//Create the socket
|
||||
SERVER.local.sockDesc = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(SERVER.local.sockDesc < 0) {
|
||||
assertUnreachable("Failed to create socket");
|
||||
}
|
||||
|
||||
//Bind the socket
|
||||
SERVER.local.sockAddr.sin_family = AF_INET;
|
||||
SERVER.local.sockAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
SERVER.local.sockAddr.sin_port = htons(start.port);
|
||||
|
||||
if(bind(
|
||||
SERVER.local.sockDesc,
|
||||
(struct sockaddr*)&SERVER.local.sockAddr,
|
||||
sizeof(SERVER.local.sockAddr)
|
||||
) < 0) {
|
||||
assertUnreachable("Failed to bind socket");
|
||||
}
|
||||
|
||||
//Listen on the socket
|
||||
if(listen(SERVER.local.sockDesc, 5) < 0) {
|
||||
assertUnreachable("Failed to listen on socket");
|
||||
}
|
||||
|
||||
// Begin the server thread.
|
||||
consolePrint("Server started.");
|
||||
|
||||
// Start the server thread
|
||||
SERVER.local.threadState = SERVER_LOCAL_THREAD_STATE_STARTING;
|
||||
pthread_create(&SERVER.local.thread, NULL, serverLocalThread, NULL);
|
||||
|
||||
while(SERVER.local.threadState == SERVER_LOCAL_THREAD_STATE_STARTING) {
|
||||
usleep(SERVER_LOCAL_THREAD_SLEEP_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
void serverLocalStop() {
|
||||
SERVER.local.threadState = SERVER_LOCAL_THREAD_STATE_STOPPING;
|
||||
while(SERVER.local.threadState == SERVER_LOCAL_THREAD_STATE_STOPPING) {
|
||||
usleep(SERVER_LOCAL_THREAD_SLEEP_TIME);
|
||||
}
|
||||
|
||||
// Stop the server thread.
|
||||
pthread_cancel(SERVER.local.thread);
|
||||
|
||||
//Close the socket
|
||||
close(SERVER.local.sockDesc);
|
||||
|
||||
// End the server thread.
|
||||
consolePrint("Server stopped.");
|
||||
}
|
||||
|
||||
void * serverLocalThread(void *arg) {
|
||||
SERVER.local.threadState = SERVER_LOCAL_THREAD_STATE_RUNNING;
|
||||
|
||||
fd_set readfds;
|
||||
int32_t activity;
|
||||
int32_t error;
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = SERVER_LOCAL_THREAD_ACCEPT_SLEEP_TIME;
|
||||
|
||||
// Set the socket to non-blocking mode
|
||||
int flags = fcntl(SERVER.local.sockDesc, F_GETFL, 0);
|
||||
fcntl(SERVER.local.sockDesc, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
while(SERVER.local.threadState == SERVER_LOCAL_THREAD_STATE_RUNNING) {
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(SERVER.local.sockDesc, &readfds);
|
||||
|
||||
activity = select(
|
||||
SERVER.local.sockDesc + 1,
|
||||
&readfds,
|
||||
NULL,
|
||||
NULL,
|
||||
&timeout
|
||||
);
|
||||
|
||||
if(activity < 0) assertUnreachable("Select error");
|
||||
|
||||
if(!FD_ISSET(SERVER.local.sockDesc, &readfds)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Accept incoming connections
|
||||
int32_t clientSockDesc = accept(SERVER.local.sockDesc, NULL, NULL);
|
||||
if(clientSockDesc < 0) {
|
||||
printf("Failed to accept connection\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now, is the server full?
|
||||
if(SERVER.clientCount >= SERVER_CLIENT_COUNT_MAX) {
|
||||
consolePrint("Server is full, rejecting connection.");
|
||||
// TODO: Write a reason to client.
|
||||
close(clientSockDesc);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create client.
|
||||
client_t *client = &SERVER.clients[SERVER.clientCount];
|
||||
clientInit(client, (clientinit_t){
|
||||
.type = CLIENT_TYPE_REMOTE,
|
||||
.remote = {
|
||||
.clientSockDesc = clientSockDesc
|
||||
}
|
||||
});
|
||||
SERVER.clientCount++;
|
||||
}
|
||||
|
||||
SERVER.local.threadState = SERVER_LOCAL_THREAD_STATE_STOPPED;
|
||||
return NULL;
|
||||
}
|
36
backup/server/serverlocal.h
Normal file
36
backup/server/serverlocal.h
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define SERVER_LOCAL_PORT_DEFAULT 8080
|
||||
#define SERVER_LOCAL_THREAD_SLEEP_TIME 1000
|
||||
#define SERVER_LOCAL_THREAD_ACCEPT_SLEEP_TIME 60000
|
||||
|
||||
typedef enum {
|
||||
SERVER_LOCAL_THREAD_STATE_STOPPED = 0,
|
||||
SERVER_LOCAL_THREAD_STATE_STARTING = 1,
|
||||
SERVER_LOCAL_THREAD_STATE_RUNNING = 2,
|
||||
SERVER_LOCAL_THREAD_STATE_STOPPING = 3
|
||||
} serverlocalthreadstate_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t port;
|
||||
} serverlocalstart_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t sockDesc;
|
||||
struct sockaddr_in sockAddr;
|
||||
pthread_t thread;
|
||||
uint8_t threadState;
|
||||
} serverlocal_t;
|
||||
|
||||
void serverLocalStart(const serverlocalstart_t start);
|
||||
void serverLocalStop();
|
||||
void * serverLocalThread(void *arg);
|
12
backup/server/serversingleplayer.c
Normal file
12
backup/server/serversingleplayer.c
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "server.h"
|
||||
|
||||
void serverSinglePlayerStart(const serversingleplayerstart_t start) {
|
||||
|
||||
}
|
15
backup/server/serversingleplayer.h
Normal file
15
backup/server/serversingleplayer.h
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct {
|
||||
int32_t nothing;
|
||||
} serversingleplayerstart_t;
|
||||
|
||||
void serverSinglePlayerStart(const serversingleplayerstart_t start);
|
Reference in New Issue
Block a user