2023-03-19 20:03:24 +01:00
|
|
|
#include <pthread.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2023-03-13 00:06:19 +01:00
|
|
|
#include <sys/signal.h>
|
|
|
|
|
2023-03-24 22:28:30 +01:00
|
|
|
#include <mgba/core/serialize.h>
|
|
|
|
|
2023-03-13 00:06:19 +01:00
|
|
|
#include <msgba/packet/send_frame.h>
|
2023-03-10 23:37:11 +01:00
|
|
|
#include <msgba/packet.h>
|
|
|
|
#include <msgba/packet/hello.h>
|
2023-03-11 08:17:25 +01:00
|
|
|
#include <msgba/core_controller.h>
|
2023-03-13 00:06:19 +01:00
|
|
|
|
2023-03-10 23:37:11 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-03-13 00:06:19 +01:00
|
|
|
void
|
|
|
|
msThreadCallbackStart(struct mCoreThread *threadContext) {
|
|
|
|
sigset_t set;
|
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, SIGPIPE);
|
|
|
|
pthread_sigmask(SIG_BLOCK, &set, NULL);
|
2023-03-24 22:28:30 +01:00
|
|
|
struct msClientConnectionData *data = (struct msClientConnectionData *)threadContext->userData;
|
|
|
|
struct msCoreController *coreController = data->coreController;
|
|
|
|
struct mCore *core = coreController->threadContext.core;
|
|
|
|
if (!mCoreLoadStateNamed (core, coreController->saveState, 0)) { // SAVESTATE_SAVEDATA & SAVESTATE_RTC)) {
|
|
|
|
fprintf(stderr, "Unable to load save state\n");
|
|
|
|
}
|
2023-03-13 00:06:19 +01:00
|
|
|
}
|
2023-03-12 20:24:14 +01:00
|
|
|
void
|
|
|
|
msThreadCallbackSetFrame(struct mCoreThread *threadContext) {
|
2023-03-19 20:03:24 +01:00
|
|
|
#define SEC_TO_NANO(sec) \
|
|
|
|
(((uint64_t)sec) * 1000 * 1000 * 1000)
|
2023-03-12 20:24:14 +01:00
|
|
|
struct msClientConnectionData *data = (struct msClientConnectionData *)threadContext->userData;
|
2023-03-19 20:03:24 +01:00
|
|
|
unsigned int stride;
|
|
|
|
color_t *outputBuffer;
|
2023-03-12 20:24:14 +01:00
|
|
|
unsigned width, height;
|
2023-03-13 01:37:13 +01:00
|
|
|
unsigned char *raw_data = NULL;
|
2023-03-13 00:06:19 +01:00
|
|
|
size_t raw_data_len = 0;
|
2023-03-13 01:37:13 +01:00
|
|
|
struct msPacketSendFrame *send_frame = NULL;
|
|
|
|
struct msPacket *packet = NULL;
|
2023-03-19 20:03:24 +01:00
|
|
|
struct timespec current_date;
|
|
|
|
timespec_get(¤t_date, TIME_UTC);
|
|
|
|
uint64_t nano_current = SEC_TO_NANO(current_date.tv_sec % 1000) + current_date.tv_nsec;
|
|
|
|
uint64_t nano_last = SEC_TO_NANO(data->lastFrameDate->tv_sec % 1000) + data->lastFrameDate->tv_nsec + (SEC_TO_NANO(1) / 60);
|
|
|
|
|
|
|
|
if (!data || !data->coreController) {
|
|
|
|
goto return_ms_thread_callback_set_frame;
|
|
|
|
}
|
|
|
|
stride = data->coreController->stride;
|
|
|
|
outputBuffer = data->coreController->outputBuffer;
|
|
|
|
|
|
|
|
while (nano_current < nano_last && nano_last != 0 && nano_last - nano_current < SEC_TO_NANO(10)) {
|
|
|
|
usleep(500);
|
|
|
|
timespec_get(¤t_date, TIME_UTC);
|
|
|
|
nano_current = SEC_TO_NANO(current_date.tv_sec % 1000) + current_date.tv_nsec;
|
|
|
|
}
|
|
|
|
*data->lastFrameDate = current_date;
|
2023-03-13 00:06:19 +01:00
|
|
|
|
2023-03-12 20:24:14 +01:00
|
|
|
data->coreController->threadContext.core->desiredVideoDimensions(data->coreController->threadContext.core, &width, &height);
|
2023-03-13 00:06:19 +01:00
|
|
|
|
|
|
|
send_frame = msPacketSendFrameNew(stride, width * height, outputBuffer);
|
|
|
|
raw_data = msPacketSendFrameSerialize(send_frame, &raw_data_len);
|
2023-03-13 01:37:13 +01:00
|
|
|
if (!raw_data) {
|
|
|
|
goto return_ms_thread_callback_set_frame;
|
|
|
|
}
|
2023-03-13 00:06:19 +01:00
|
|
|
|
|
|
|
packet = msPacketNew(PACKET_SEND_FRAME, raw_data_len, raw_data);
|
|
|
|
msPacketSend(packet, data);
|
|
|
|
|
2023-03-13 01:37:13 +01:00
|
|
|
return_ms_thread_callback_set_frame:
|
|
|
|
if (send_frame) {
|
|
|
|
msPacketSendFrameDestroy(&send_frame);
|
|
|
|
}
|
|
|
|
if (packet) {
|
|
|
|
msPacketDestroy(&packet);
|
|
|
|
}
|
2023-03-12 20:24:14 +01:00
|
|
|
}
|
|
|
|
|
2023-03-10 23:37:11 +01:00
|
|
|
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);
|
2023-03-11 08:17:25 +01:00
|
|
|
data->coreController = msCoreControllerLoadGame(hello->rom, hello->size_rom, hello->savestate, hello->size_savestate, data);
|
2023-03-12 20:24:14 +01:00
|
|
|
msCoreControllerSetFrameCallback(data->coreController, &msThreadCallbackSetFrame);
|
2023-03-13 00:06:19 +01:00
|
|
|
msCoreControllerSetStartCallback(data->coreController, &msThreadCallbackStart);
|
2023-03-10 23:37:11 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|