Initial commit.
This commit is contained in:
commit
ccb7edff55
7
Doxyfile
Normal file
7
Doxyfile
Normal file
@ -0,0 +1,7 @@
|
||||
GENERATE_HTML=yes
|
||||
EXTRACT_ALL=yes
|
||||
RECURSIVE=yes
|
||||
INPUT=../include
|
||||
DISABLE_INDEX = YES
|
||||
GENERATE_TREEVIEW = YES
|
||||
PROJECT_NAME=msgba
|
30
include/msgba/client_connection_data.h
Normal file
30
include/msgba/client_connection_data.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef MS_CLIENT_CONNECTION_DATA
|
||||
#define MS_CLIENT_CONNECTION_DATA
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct msCoreController;
|
||||
|
||||
/**
|
||||
* Struct representing everything needed while a connection is established.
|
||||
*/
|
||||
struct msClientConnectionData {
|
||||
size_t numberOfThread;
|
||||
int clientFd;
|
||||
struct msCoreController *coreController;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new msClientConnectionData.
|
||||
*
|
||||
* @param numberOfThread The unique identifier for this connection.
|
||||
* @param clientFd The client fd from which receive/send messages.
|
||||
*/
|
||||
struct msClientConnectionData *
|
||||
msClientConnectionDataNew(size_t numberOfThread, int clientFd);
|
||||
|
||||
void
|
||||
msClientConnectionDataDestroy(struct msClientConnectionData **data);
|
||||
#endif
|
31
include/msgba/core_controller.h
Normal file
31
include/msgba/core_controller.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef MS_CORE_CONTROLLER
|
||||
#define MS_CORE_CONTROLLER
|
||||
#include <unistd.h>
|
||||
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/thread.h>
|
||||
|
||||
#include <msgba/client_connection_data.h>
|
||||
|
||||
struct msMultiplayerController;
|
||||
|
||||
struct msCoreController {
|
||||
struct msMultiplayerController *multiplayer;
|
||||
struct mCoreThread threadContext;
|
||||
color_t *outputBuffer;
|
||||
unsigned int stride;
|
||||
};
|
||||
|
||||
struct msCoreController *
|
||||
msCoreControllerLoadGame (const unsigned char *rom, size_t rom_len,
|
||||
const unsigned char *state, size_t state_len,
|
||||
struct msClientConnectionData *const data);
|
||||
|
||||
void
|
||||
msCoreControllerDestroy(struct msCoreController **controller_ptr);
|
||||
|
||||
struct msCoreController *
|
||||
msCoreControllerNew (struct mCore *core, struct msClientConnectionData *const data);
|
||||
void
|
||||
msCoreControllerThreadStart (struct msCoreController *const core_controller);
|
||||
#endif
|
8
include/msgba/global.h
Normal file
8
include/msgba/global.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef MS_GLOBAL
|
||||
#define MS_GLOBAL
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern char *ms_last_error;
|
||||
#endif
|
30
include/msgba/multiplayer_controller.h
Normal file
30
include/msgba/multiplayer_controller.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef MS_MULTIPLAYER_CONTROLLER
|
||||
#define MS_MULTIPLAYER_CONTROLLER
|
||||
#include <mgba/flags.h>
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/thread.h>
|
||||
#include <mgba/core/interface.h>
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/internal/gba/sio/lockstep.h>
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
#include <mgba/internal/gb/sio/lockstep.h>
|
||||
#endif
|
||||
#include <mgba/core/serialize.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
#include <pthread.h>
|
||||
struct msMultiplayerController {
|
||||
struct msPlayer *players;
|
||||
pthread_mutex_t lock;
|
||||
union {
|
||||
struct mLockstep m_lockstep;
|
||||
#ifdef M_CORE_GB
|
||||
struct GBSIOLockstep m_gbLockstep;
|
||||
#endif
|
||||
#ifdef M_CORE_GBA
|
||||
struct GBASIOLockstep m_gbaLockstep;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
#endif
|
46
include/msgba/packet.h
Normal file
46
include/msgba/packet.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <msgba/client_connection_data.h>
|
||||
|
||||
/**
|
||||
* The possible values for a packet id.
|
||||
*/
|
||||
extern enum {
|
||||
PACKET_GET_HELLO, //! Packet id for get hello.
|
||||
PACKET_SEND_FRAME, //! Packet id for send frame.
|
||||
PACKETS_NUMBER //! The number of recognized packets.
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct representing a generic packet.
|
||||
*/
|
||||
struct msPacket {
|
||||
//! The id of the packet.
|
||||
size_t id;
|
||||
//! The size of the data contained in the packet.
|
||||
size_t size;
|
||||
//! The data as a byte array. (Not null terminated.)
|
||||
char *raw_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Asks the code to handle a concrete packet comming from a client.
|
||||
*/
|
||||
bool
|
||||
msPacketHandle(struct msPacket *packet, int client_fd, struct msClientConnectionData *const data);
|
||||
|
||||
/**
|
||||
* When done with a packet it must be destroyed using this method.
|
||||
*/
|
||||
void
|
||||
msPacketDestroy(struct msPacket **packet);
|
||||
|
||||
/**
|
||||
* Tries to retrieve a packet from the client, returns NULL in case of error.
|
||||
* Blocks the current thread.
|
||||
*/
|
||||
struct msPacket *
|
||||
msPacketRead(int client_fd);
|
30
include/msgba/packet/hello.h
Normal file
30
include/msgba/packet/hello.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef MS_PACKET_HELLO
|
||||
#define MS_PACKET_HELLO
|
||||
#include <stdio.h>
|
||||
#include <sys/un.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <msgba/client_connection_data.h>
|
||||
|
||||
struct msPacket;
|
||||
|
||||
struct msPacketHello {
|
||||
size_t size_rom;
|
||||
unsigned char *rom;
|
||||
size_t size_savestate;
|
||||
unsigned char *savestate;
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
msPacketHelloDestroy(struct msPacketHello **hello);
|
||||
bool
|
||||
msPacketHelloHandle(const struct msPacket *packet, struct msPacketHello *hello,
|
||||
struct msClientConnectionData *const data);
|
||||
bool
|
||||
msPacketHelloGet(const struct msPacket *packet, int client_fd,
|
||||
struct msClientConnectionData *const data);
|
||||
#endif
|
26
include/msgba/player.h
Normal file
26
include/msgba/player.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef MS_PLAYER
|
||||
#define MS_PLAYER
|
||||
#include <mgba/flags.h>
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/thread.h>
|
||||
#include <mgba/core/interface.h>
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/internal/gba/sio/lockstep.h>
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
#include <mgba/internal/gb/sio/lockstep.h>
|
||||
#endif
|
||||
|
||||
union Node {
|
||||
struct GBSIOLockstepNode* gb;
|
||||
struct GBASIOLockstepNode* gba;
|
||||
};
|
||||
|
||||
struct msPlayer {
|
||||
struct msCoreController* controller;
|
||||
union Node node;
|
||||
int awake;
|
||||
int32_t cyclesPosted;
|
||||
unsigned waitMask;
|
||||
};
|
||||
#endif
|
35
meson.build
Normal file
35
meson.build
Normal file
@ -0,0 +1,35 @@
|
||||
project('tech.owlcode.msgba', 'c')
|
||||
|
||||
inc = include_directories('include')
|
||||
|
||||
sources = [
|
||||
'src/main.c',
|
||||
'src/player.c',
|
||||
'src/core_controller.c',
|
||||
'src/multiplayer_controller.c',
|
||||
'src/packet.c',
|
||||
'src/packet/hello.c',
|
||||
'src/client_connection_data.c',
|
||||
]
|
||||
|
||||
inc = [
|
||||
'include'
|
||||
]
|
||||
|
||||
link_arguments = [
|
||||
'-lmgba'
|
||||
]
|
||||
|
||||
executable('msgba',
|
||||
sources,
|
||||
include_directories : inc,
|
||||
install : true,
|
||||
link_args : link_arguments,
|
||||
)
|
||||
doxygen = find_program('doxygen', required : false)
|
||||
if doxygen.found()
|
||||
message('Doxygen found')
|
||||
run_target('docs', command : [doxygen, meson.source_root() + '/Doxyfile'])
|
||||
else
|
||||
warning('Documentation disabled without doxygen')
|
||||
endif
|
19
src/client_connection_data.c
Normal file
19
src/client_connection_data.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <msgba/core_controller.h>
|
||||
#include <msgba/client_connection_data.h>
|
||||
struct msClientConnectionData *
|
||||
msClientConnectionDataNew(size_t numberOfThread, int clientFd) {
|
||||
struct msClientConnectionData *data = malloc (sizeof *data);
|
||||
data->numberOfThread = numberOfThread;
|
||||
data->clientFd = clientFd;
|
||||
data->coreController = NULL;
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
msClientConnectionDataDestroy(struct msClientConnectionData **data) {
|
||||
if ((*data)->coreController) {
|
||||
msCoreControllerDestroy(&(*data)->coreController);
|
||||
}
|
||||
free(*data);
|
||||
*data = NULL;
|
||||
}
|
93
src/core_controller.c
Normal file
93
src/core_controller.c
Normal file
@ -0,0 +1,93 @@
|
||||
#include <mgba/flags.h>
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/thread.h>
|
||||
#include <mgba/core/interface.h>
|
||||
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/internal/gba/sio/lockstep.h>
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
#include <mgba/internal/gb/sio/lockstep.h>
|
||||
#endif
|
||||
#include <mgba/core/serialize.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
#include <msgba/global.h>
|
||||
#include <msgba/core_controller.h>
|
||||
|
||||
|
||||
struct msCoreController *
|
||||
msCoreControllerLoadGame (const unsigned char *rom, size_t rom_len,
|
||||
const unsigned char *state, size_t state_len,
|
||||
struct msClientConnectionData *const data) {
|
||||
struct VFile* file_rom = VFileMemChunk (NULL, rom_len);
|
||||
struct VFile* file_state = VFileMemChunk (NULL, state_len);
|
||||
file_rom->seek (file_rom, 0, SEEK_SET);
|
||||
file_state->seek (file_state, 0, SEEK_SET);
|
||||
file_rom->write (file_rom, rom, rom_len);
|
||||
file_state->write (file_state, state, state_len);
|
||||
struct mCore *core = mCoreFindVF (file_rom);
|
||||
struct msCoreController *controller = NULL;
|
||||
if (!core) {
|
||||
ms_last_error = "This rom does not appear to be a GBA or GB/C one";
|
||||
file_rom->close(file_rom);
|
||||
file_state->close(file_rom);
|
||||
goto loadGameReturn;
|
||||
}
|
||||
core->init(core);
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
mCoreInitConfig(core, NULL);
|
||||
mCoreConfigSetIntValue(&core->config, "logLevel", mLOG_FATAL & mLOG_ERROR & mLOG_WARN);
|
||||
|
||||
core->desiredVideoDimensions(core, &width, &height);
|
||||
color_t *outputBuffer = malloc((sizeof *outputBuffer) * width * height);
|
||||
printf("controller->outputBuffer width: %u\n", width);
|
||||
core->setVideoBuffer(core, outputBuffer, width);
|
||||
core->loadROM (core, file_rom);
|
||||
mCoreLoadStateNamed (core, file_state, SAVESTATE_SAVEDATA & SAVESTATE_RTC);
|
||||
|
||||
controller = msCoreControllerNew (core, data);
|
||||
controller->outputBuffer = outputBuffer;
|
||||
controller->stride = width;
|
||||
loadGameReturn:
|
||||
return controller;
|
||||
}
|
||||
|
||||
void
|
||||
msCoreControllerSetFrameCallback(struct msCoreController *const self, void(*callback)(struct mCoreThread *)) {
|
||||
self->threadContext.frameCallback = callback;
|
||||
}
|
||||
|
||||
void
|
||||
msCoreControllerThreadStart (struct msCoreController *const core_controller) {
|
||||
struct mCoreThread *thread = &core_controller->threadContext;
|
||||
mCoreThreadStart(thread);
|
||||
}
|
||||
|
||||
void
|
||||
msCoreControllerDestroy(struct msCoreController **controller_ptr) {
|
||||
if (controller_ptr && *controller_ptr) {
|
||||
struct msCoreController *controller = *controller_ptr;
|
||||
|
||||
if (mCoreThreadHasStarted(&controller->threadContext)
|
||||
&& !mCoreThreadHasExited(&controller->threadContext)) {
|
||||
mCoreThreadEnd(&controller->threadContext);
|
||||
}
|
||||
if (controller->threadContext.core) {
|
||||
struct mCore *core = controller->threadContext.core;
|
||||
core->deinit(core);
|
||||
}
|
||||
free(controller->outputBuffer);
|
||||
free(controller);
|
||||
*controller_ptr = NULL;
|
||||
}
|
||||
}
|
||||
struct msCoreController *
|
||||
msCoreControllerNew (struct mCore *core, struct msClientConnectionData *const data) {
|
||||
struct msCoreController *controller = malloc (sizeof *controller);
|
||||
controller->multiplayer = NULL;
|
||||
controller->threadContext.core = core;
|
||||
controller->threadContext.userData = data;
|
||||
return controller;
|
||||
}
|
105
src/main.c
Normal file
105
src/main.c
Normal file
@ -0,0 +1,105 @@
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <mgba/flags.h>
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/thread.h>
|
||||
#include <mgba/core/interface.h>
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/internal/gba/sio/lockstep.h>
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
#include <mgba/internal/gb/sio/lockstep.h>
|
||||
#endif
|
||||
#include <mgba/core/serialize.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
#include <msgba/core_controller.h>
|
||||
#include <msgba/client_connection_data.h>
|
||||
#include <msgba/global.h>
|
||||
#include <msgba/packet.h>
|
||||
|
||||
char *ms_last_error = "";
|
||||
|
||||
#define MAX_NUMBER_OF_THREADS 100
|
||||
pthread_t pthread_client_connections[MAX_NUMBER_OF_THREADS];
|
||||
pthread_cond_t cond_client_number_decreased;
|
||||
pthread_mutex_t mutex_number_connections;
|
||||
size_t connected_clients = 0;
|
||||
size_t number_of_threads = 0;
|
||||
|
||||
void *handleClientConnection(void *user_data) {
|
||||
struct msClientConnectionData *data = (struct msClientConnectionData *) user_data;
|
||||
int client_fd = data->clientFd;
|
||||
size_t number_of_thread = data->numberOfThread;
|
||||
struct msPacket *packet = NULL;
|
||||
printf("Connection from client with id %lu and fd %d\n", number_of_thread, client_fd);
|
||||
while ((packet = msPacketRead(client_fd)) != NULL) {
|
||||
bool success = msPacketHandle(packet, client_fd, data);
|
||||
msPacketDestroy(&packet);
|
||||
if (!success) {
|
||||
fprintf(stderr, "Failed handling packet for client_fd %d, closing connection\n", client_fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
msClientConnectionDataDestroy(&data);
|
||||
if (close (client_fd) == 1) {
|
||||
fprintf(stderr, "Error closing socket %d\n", client_fd);
|
||||
}
|
||||
printf("Closing connection with id %lu and fd %d\n", number_of_thread, client_fd);
|
||||
pthread_mutex_lock(&mutex_number_connections);
|
||||
connected_clients--;
|
||||
pthread_mutex_unlock(&mutex_number_connections);
|
||||
pthread_cond_signal(&cond_client_number_decreased);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define SOCKET_ADDRESS "msgba.sock"
|
||||
#define BACKLOG 5
|
||||
int main(int argc, char **argv) {
|
||||
struct sockaddr_un address;
|
||||
memset (&address, 0, sizeof address);
|
||||
|
||||
address.sun_family = AF_UNIX;
|
||||
unlink(SOCKET_ADDRESS);
|
||||
size_t max_size_sun_path = sizeof address.sun_path - 1;
|
||||
if (strlen(SOCKET_ADDRESS) > max_size_sun_path) {
|
||||
fprintf(stderr, "Too big socket address");
|
||||
exit (2);
|
||||
}
|
||||
strncpy(address.sun_path, SOCKET_ADDRESS, max_size_sun_path);
|
||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
fprintf (stderr, "Unable to create socket\n");
|
||||
exit (1);
|
||||
}
|
||||
if (bind (fd, (struct sockaddr *)&address,
|
||||
strlen (SOCKET_ADDRESS) + sizeof (address.sun_family)) == -1) {
|
||||
fprintf(stderr, "Unable to bind socket\n");
|
||||
exit (1);
|
||||
}
|
||||
if (listen (fd, BACKLOG) == -1) {
|
||||
fprintf(stderr, "Unable to listen in socket\n");
|
||||
exit (1);
|
||||
}
|
||||
pthread_cond_init(&cond_client_number_decreased, NULL);
|
||||
pthread_mutex_init(&mutex_number_connections, NULL);
|
||||
while (1) {
|
||||
int client_fd = accept(fd, NULL, NULL);
|
||||
pthread_attr_t attributes;
|
||||
pthread_attr_init(&attributes);
|
||||
pthread_attr_setdetachstate(&attributes, 1);
|
||||
pthread_mutex_lock(&mutex_number_connections);
|
||||
while (connected_clients == MAX_NUMBER_OF_THREADS) {
|
||||
pthread_cond_wait(&cond_client_number_decreased, &mutex_number_connections);
|
||||
}
|
||||
struct msClientConnectionData *data = msClientConnectionDataNew(number_of_threads, client_fd);
|
||||
|
||||
pthread_create(&pthread_client_connections[connected_clients++], &attributes,
|
||||
&handleClientConnection, (void *)data);
|
||||
pthread_mutex_unlock(&mutex_number_connections);
|
||||
}
|
||||
}
|
23
src/multiplayer_controller.c
Normal file
23
src/multiplayer_controller.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <mgba/flags.h>
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/thread.h>
|
||||
#include <mgba/core/interface.h>
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/internal/gba/sio/lockstep.h>
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
#include <mgba/internal/gb/sio/lockstep.h>
|
||||
#endif
|
||||
#include <mgba/core/serialize.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
#include <msgba/multiplayer_controller.h>
|
||||
|
||||
struct msMultiplayerController *
|
||||
msMultiplayerControllerNew (void) {
|
||||
struct msMultiplayerController *multiplayer = malloc (sizeof *multiplayer);
|
||||
pthread_mutex_init(&(multiplayer->lock), NULL);
|
||||
multiplayer->players = NULL;
|
||||
return multiplayer;
|
||||
}
|
||||
|
89
src/packet.c
Normal file
89
src/packet.c
Normal file
@ -0,0 +1,89 @@
|
||||
#include <endian.h>
|
||||
|
||||
#include <msgba/packet.h>
|
||||
#include <msgba/packet/hello.h>
|
||||
|
||||
#define PRINT_DEBUG(NAME, CLIENT_FD) \
|
||||
printf ("Received packet %s from client fd %d\n", #NAME, CLIENT_FD);
|
||||
bool
|
||||
msPacketHandle(struct msPacket *packet, int client_fd,
|
||||
struct msClientConnectionData *const data) {
|
||||
bool result = false;
|
||||
switch (packet->id) {
|
||||
case PACKET_GET_HELLO:
|
||||
PRINT_DEBUG(PACKET_HELLO, client_fd);
|
||||
result = msPacketHelloGet(packet, client_fd, data);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
msPacketSend(const struct msPacket *const packet, int fd) {
|
||||
write(fd, (const void *)packet->id, sizeof packet->id);
|
||||
write(fd, (const void *)packet->size, sizeof packet->size);
|
||||
write(fd, (const void *)packet->raw_data, sizeof *packet->raw_data * packet->size);
|
||||
}
|
||||
|
||||
struct msPacket *
|
||||
msPacketNew(const size_t id, const size_t size, char *raw_data) {
|
||||
struct msPacket *packet = malloc(sizeof *packet);
|
||||
packet->id = id;
|
||||
packet->size = size;
|
||||
packet->raw_data = raw_data;
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
msPacketDestroy(struct msPacket **packet) {
|
||||
if ((*packet)->raw_data) {
|
||||
free((*packet)->raw_data);
|
||||
}
|
||||
free(*packet);
|
||||
*packet=NULL;
|
||||
}
|
||||
|
||||
struct msPacket *
|
||||
msPacketRead(int client_fd) {
|
||||
struct msPacket *packet = NULL;
|
||||
size_t id = 0;
|
||||
size_t size = 0;
|
||||
ssize_t result;
|
||||
char *raw_data = NULL;
|
||||
|
||||
result = read(client_fd, &id, sizeof id);
|
||||
if (result < sizeof id) {
|
||||
printf("Unable to read id\n");
|
||||
goto return_read_packet;
|
||||
}
|
||||
result = read(client_fd, &size, sizeof size);
|
||||
if (result < sizeof size) {
|
||||
printf("Unable to read packet\n");
|
||||
goto return_read_packet;
|
||||
}
|
||||
size = be64toh(size);
|
||||
|
||||
raw_data = malloc(size);
|
||||
|
||||
size_t to_read_size = size;
|
||||
while (to_read_size > 0) {
|
||||
result = read(client_fd, &raw_data[size - to_read_size], to_read_size);
|
||||
if (result == -1) {
|
||||
printf("Unable to read raw_data\n");
|
||||
goto return_read_packet;
|
||||
}
|
||||
to_read_size -= result;
|
||||
}
|
||||
if (result < size) {
|
||||
}
|
||||
packet = calloc (1, sizeof *packet);
|
||||
packet->id = id;
|
||||
packet->size = size;
|
||||
packet->raw_data = raw_data;
|
||||
return_read_packet:
|
||||
if (!packet && raw_data) {
|
||||
free(raw_data);
|
||||
}
|
||||
return packet;
|
||||
}
|
103
src/packet/hello.c
Normal file
103
src/packet/hello.c
Normal file
@ -0,0 +1,103 @@
|
||||
#include <msgba/packet.h>
|
||||
#include <msgba/packet/hello.h>
|
||||
void
|
||||
msPacketHelloDestroy(struct msPacketHello **hello) {
|
||||
if ((*hello)->rom) {
|
||||
free((*hello)->rom);
|
||||
(*hello)->rom = NULL;
|
||||
}
|
||||
if ((*hello)->savestate) {
|
||||
free((*hello)->savestate);
|
||||
(*hello)->savestate = NULL;
|
||||
}
|
||||
free(*hello);
|
||||
*hello = NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
msPacketHelloHandle(const struct msPacket *packet, struct msPacketHello *hello,
|
||||
struct msClientConnectionData *const data) {
|
||||
bool result = false;
|
||||
if (data->coreController) {
|
||||
fprintf(stderr, "Attempt to send a second hello, aborting connection.\n");
|
||||
goto return_ms_packet_hello_handle;
|
||||
}
|
||||
printf("Loading game and save for client_fd %d\n", data->clientFd);
|
||||
data->coreController = msCoreControllerLoadGame(hello->rom, hello->size_rom, hello->savestate, hello->size_savestate);
|
||||
msCoreControllerThreadStart(data->coreController);
|
||||
result = true;
|
||||
return_ms_packet_hello_handle:
|
||||
msPacketHelloDestroy(&hello);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
msPacketHelloGet(const struct msPacket *packet, int client_fd,
|
||||
struct msClientConnectionData *const data) {
|
||||
bool result = false;
|
||||
struct msPacketHello *hello = NULL;
|
||||
unsigned char *rom = NULL;
|
||||
unsigned char *savestate = NULL;
|
||||
FILE *fp = fmemopen(packet->raw_data, packet->size, "r");
|
||||
if (!fp) {
|
||||
printf("Unable to fmemopen\n");
|
||||
goto return_get_packet_hello;
|
||||
}
|
||||
size_t size_rom = 0;
|
||||
size_t size_savestate = 0;
|
||||
size_t reads[4] = { 0,0,0,0 };
|
||||
size_t total_read = 0;
|
||||
size_t to_read_size;
|
||||
|
||||
#define FREAD(target, size, count, fp, n, goto_to) \
|
||||
to_read_size = size; \
|
||||
reads[n] = fread(target, to_read_size, count, fp); \
|
||||
reads[n] *= size; \
|
||||
if (reads[n] == -1) { \
|
||||
printf("Unable to read %s\n", #target); \
|
||||
goto goto_to; \
|
||||
}
|
||||
|
||||
|
||||
FREAD(&size_rom, sizeof size_rom, 1, fp, 0, return_get_packet_hello);
|
||||
size_rom = be64toh(size_rom);
|
||||
rom = malloc(sizeof *rom * size_rom);
|
||||
|
||||
FREAD(rom, sizeof *rom, size_rom, fp, 1, return_get_packet_hello);
|
||||
|
||||
FREAD(&size_savestate, sizeof size_savestate, 1, fp, 2, return_get_packet_hello);
|
||||
size_savestate = be64toh(size_savestate);
|
||||
savestate = malloc(sizeof *savestate * size_savestate);
|
||||
|
||||
FREAD(savestate, sizeof *savestate, size_savestate, fp, 3, return_get_packet_hello);
|
||||
fclose(fp);
|
||||
|
||||
for (int i = 0; i<4; i++) {
|
||||
total_read += reads[i];
|
||||
}
|
||||
if (total_read != packet->size) {
|
||||
fprintf (stderr, "Total read (%lu) != packet->size (%lu)\n", total_read, packet->size);
|
||||
goto return_get_packet_hello;
|
||||
}
|
||||
hello = calloc(1, sizeof *hello);
|
||||
hello->size_rom = size_rom;
|
||||
hello->rom = rom;
|
||||
hello->size_savestate = size_savestate;
|
||||
hello->savestate = savestate;
|
||||
result = true;
|
||||
return_get_packet_hello:
|
||||
if (!result) {
|
||||
fprintf(stderr, "Unable to read the packet hello\n");
|
||||
if (rom) {
|
||||
free (rom);
|
||||
rom = NULL;
|
||||
}
|
||||
if (savestate) {
|
||||
free (savestate);
|
||||
savestate = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return msPacketHelloHandle(packet, hello, data);
|
||||
}
|
||||
|
30
src/player.c
Normal file
30
src/player.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <msgba/player.h>
|
||||
#ifdef M_CORE_GBA
|
||||
struct msPlayer *
|
||||
msPlayerNewGBA (struct msCoreController *controller,
|
||||
struct GBASIOLockstepNode *node) {
|
||||
struct msPlayer *player = malloc (sizeof *player);
|
||||
player->controller = controller;
|
||||
player->node.gba = node;
|
||||
player->awake = 1;
|
||||
player->cyclesPosted = 0;
|
||||
player->waitMask = 0;
|
||||
return player;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef M_CORE_GB
|
||||
struct msPlayer *
|
||||
msPlayerNewGB (struct msCoreController *controller,
|
||||
struct GBSIOLockstepNode *node) {
|
||||
struct msPlayer *player = malloc (sizeof *player);
|
||||
player->controller = controller;
|
||||
player->node.gb = node;
|
||||
player->awake = 1;
|
||||
player->cyclesPosted = 0;
|
||||
player->waitMask = 0;
|
||||
return player;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
40
src/try_mem.c
Normal file
40
src/try_mem.c
Normal file
@ -0,0 +1,40 @@
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <mgba/flags.h>
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/thread.h>
|
||||
#include <mgba/core/interface.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/internal/gba/sio/lockstep.h>
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
#include <mgba/internal/gb/sio/lockstep.h>
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
struct mCoreThread *threadContext = malloc(sizeof *threadContext);
|
||||
char *file = "/home/sergio/ruby.gba";
|
||||
struct mCore *core = mCoreFind(file);
|
||||
core->init(core);
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
core->desiredVideoDimensions(core, &width, &height);
|
||||
color_t *outputBuffer = malloc((sizeof *outputBuffer) * width * height);
|
||||
core->setVideoBuffer(core, outputBuffer, 240);
|
||||
mCoreInitConfig(core, NULL);
|
||||
if (!core) {
|
||||
fprintf(stderr, "Unable to load core");
|
||||
return 1;
|
||||
}
|
||||
mCoreLoadFile(core, file);
|
||||
threadContext->core = core;
|
||||
threadContext->userData = NULL;
|
||||
mCoreThreadStart(threadContext);
|
||||
mCoreThreadJoin(threadContext);
|
||||
free(threadContext);
|
||||
}
|
73
tester.pl
Normal file
73
tester.pl
Normal file
@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use v5.34.1;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use IO::Socket::UNIX;
|
||||
|
||||
use Path::Tiny qw/path/;
|
||||
|
||||
my $HOME = $ENV{HOME};
|
||||
my $PACKET_HELLO = 0;
|
||||
|
||||
my $fh = IO::Socket::UNIX->new(
|
||||
Type => SOCK_STREAM(),
|
||||
Peer => 'msgba.sock',
|
||||
) || die "Can't open socket: $IO::Socket::errstr";
|
||||
|
||||
my $rom = path($HOME)->child('ruby.gba')->slurp;
|
||||
my $sav = path($HOME)->child('ruby.ss1')->slurp;
|
||||
|
||||
my $packet_hello = "";
|
||||
open my $fh_packet_hello, '>', \$packet_hello;
|
||||
write_packet_hello($fh_packet_hello, \$rom, \$sav);
|
||||
close $fh_packet_hello;
|
||||
my $packet = "";
|
||||
open my $fh_packet, '>', \$packet;
|
||||
write_packet($fh_packet, $PACKET_HELLO, \$packet_hello);
|
||||
close $fh_packet;
|
||||
print $fh $packet;
|
||||
sleep 1 while 1;
|
||||
|
||||
sub write_packet {
|
||||
my $fh = shift;
|
||||
my $id = shift;
|
||||
my $raw_data = ret_scalar(shift);
|
||||
print $fh pack('Q>', $id);
|
||||
print $fh pack('Q>', length $raw_data);
|
||||
print $fh $raw_data;
|
||||
}
|
||||
|
||||
sub write_packet_hello {
|
||||
my $fh = shift or die "No file handle";
|
||||
my $rom = ret_scalar(shift);
|
||||
my $save = ret_scalar(shift);
|
||||
my $rom_length = length $rom;
|
||||
my $save_length = length $save;
|
||||
say "Packet size = @{[16 + $rom_length + $save_length]}";
|
||||
|
||||
|
||||
print $fh pack 'Q>', $rom_length;
|
||||
print $fh $rom;
|
||||
print $fh pack 'Q>', $save_length;
|
||||
print $fh $save;
|
||||
}
|
||||
|
||||
sub ret_scalar {
|
||||
my $arg = shift;
|
||||
if (check_scalar_ref($arg)) {
|
||||
return ${$arg};
|
||||
}
|
||||
die "No scalar ref";
|
||||
}
|
||||
|
||||
sub check_scalar_ref {
|
||||
my $arg = shift or die "Undefined scalar ref";
|
||||
|
||||
if ((ref $arg) eq 'SCALAR') {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user