#include #include #include #include #include #include #include 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; } void msThreadCallbackStart(struct mCoreThread *threadContext) { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGPIPE); pthread_sigmask(SIG_BLOCK, &set, NULL); } void msThreadCallbackSetFrame(struct mCoreThread *threadContext) { #define SEC_TO_NANO(sec) \ (((uint64_t)sec) * 1000 * 1000 * 1000) struct msClientConnectionData *data = (struct msClientConnectionData *)threadContext->userData; unsigned int stride; color_t *outputBuffer; unsigned width, height; unsigned char *raw_data = NULL; size_t raw_data_len = 0; struct msPacketSendFrame *send_frame = NULL; struct msPacket *packet = NULL; 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; data->coreController->threadContext.core->desiredVideoDimensions(data->coreController->threadContext.core, &width, &height); send_frame = msPacketSendFrameNew(stride, width * height, outputBuffer); raw_data = msPacketSendFrameSerialize(send_frame, &raw_data_len); if (!raw_data) { goto return_ms_thread_callback_set_frame; } packet = msPacketNew(PACKET_SEND_FRAME, raw_data_len, raw_data); msPacketSend(packet, data); return_ms_thread_callback_set_frame: if (send_frame) { msPacketSendFrameDestroy(&send_frame); } if (packet) { msPacketDestroy(&packet); } } 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, data); msCoreControllerSetFrameCallback(data->coreController, &msThreadCallbackSetFrame); msCoreControllerSetStartCallback(data->coreController, &msThreadCallbackStart); 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); }