175 lines
5.5 KiB
C
175 lines
5.5 KiB
C
#include <pthread.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#include <mgba/core/serialize.h>
|
|
#include <mgba/core/core.h>
|
|
#include <mgba-util/vfs.h>
|
|
|
|
#include <msgba/packet.h>
|
|
#include <msgba/packet/save_request.h>
|
|
#include <msgba/packet/save_response.h>
|
|
#include <msgba/core_controller.h>
|
|
|
|
bool
|
|
msPacketSaveRequestGet(const struct msPacket *packet, int clientFd, struct msClientConnectionData *const data) {
|
|
bool result = false;
|
|
struct msPacketSaveRequest *self = NULL;
|
|
uint64_t identifier = 0;
|
|
FILE *fp = fmemopen(packet->rawData, packet->size, "r");
|
|
if (1 != fread(&identifier, sizeof identifier, 1, fp)) {
|
|
goto return_ms_packet_save_request_get;
|
|
}
|
|
identifier = be64toh(identifier);
|
|
self = malloc(sizeof *self);
|
|
self->identifier = identifier;
|
|
result = true;
|
|
return_ms_packet_save_request_get:
|
|
fclose(fp);
|
|
if (!result) {
|
|
return false;
|
|
}
|
|
return msPacketSaveRequestHandle(packet, self, data);
|
|
}
|
|
|
|
struct msPacketSaveRequestData {
|
|
uint64_t identifier;
|
|
};
|
|
|
|
static struct msPacketSaveRequestData *
|
|
msPacketSaveRequestDataNew(uint64_t identifier) {
|
|
struct msPacketSaveRequestData *self = malloc(sizeof *self);
|
|
self->identifier = identifier;
|
|
return self;
|
|
}
|
|
|
|
void
|
|
msPacketSaveRequestDestroy(struct msPacketSaveRequest **self) {
|
|
free(*self);
|
|
*self = NULL;
|
|
}
|
|
|
|
void
|
|
msPacketSaveRequestDataDestroy(struct msPacketSaveRequestData **self) {
|
|
free(*self);
|
|
*self = NULL;
|
|
}
|
|
|
|
static void
|
|
shrinkOrNullSaveRequestsDataArray(struct msClientConnectionData *data) {
|
|
size_t requestsLen = data->saveRequestsLen;
|
|
struct msPacketSaveRequestData **requests = data->saveRequests;
|
|
for (size_t i = 1; i < requestsLen; i++) {
|
|
requests[i-1] = requests[i];
|
|
}
|
|
requestsLen--;
|
|
data->saveRequestsLen = requestsLen;
|
|
if (!requestsLen) {
|
|
free(data->saveRequests);
|
|
data->saveRequests = NULL;
|
|
return;
|
|
}
|
|
data->saveRequests = realloc(requests, sizeof *requests * requestsLen);
|
|
}
|
|
|
|
static unsigned char *
|
|
vFileToBytes(struct VFile *file, size_t *len) {
|
|
unsigned char *result = NULL;
|
|
const ssize_t bufferLen = 120;
|
|
ssize_t readLen = 0;
|
|
unsigned char buffer[bufferLen];
|
|
if (!len) {
|
|
goto return_vfile_to_bytes;
|
|
}
|
|
*len = 0;
|
|
file->seek(file, 0, SEEK_SET);
|
|
while ((readLen = file->read(file, buffer, bufferLen)) && readLen) {
|
|
*len += readLen;
|
|
size_t size = sizeof *result * *len;
|
|
result = realloc(result, size);
|
|
// memcpy_s not available in linux.
|
|
memcpy(&result[*len - readLen], buffer, readLen); // NOLINT
|
|
}
|
|
return_vfile_to_bytes:
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
msPacketSaveRequestSendResponse(struct mCoreThread *threadContext) {
|
|
struct msClientConnectionData *data = (struct msClientConnectionData *) threadContext->userData;
|
|
struct msPacketSaveRequestData **requests = data->saveRequests;
|
|
size_t requestsLen;
|
|
struct msPacketSaveRequestData *request = NULL;
|
|
struct VFile *saveState = NULL;
|
|
size_t saveLen = 0;
|
|
unsigned char *save = NULL;
|
|
struct msPacketSaveResponse *response = NULL;
|
|
size_t rawDataLen = 0;
|
|
unsigned char *rawData = NULL;
|
|
struct msPacket *packet = NULL;
|
|
pthread_mutex_lock(data->mutexSaveRequests);
|
|
requestsLen = data->saveRequestsLen;
|
|
if (!requestsLen) {
|
|
printf("Somehow the queue of saveRequests got exhausted, this should not happen.\n");
|
|
goto unlock_ms_packet_save_request_send_response;
|
|
}
|
|
struct msCoreController *coreController = data->coreController;
|
|
struct mCore *core = coreController->threadContext.core;
|
|
request = requests[0];
|
|
shrinkOrNullSaveRequestsDataArray(data);
|
|
unlock_ms_packet_save_request_send_response:
|
|
pthread_mutex_unlock(data->mutexSaveRequests);
|
|
if (!requestsLen) {
|
|
return;
|
|
}
|
|
saveState = VFileMemChunk (NULL, 0);
|
|
mCoreSaveStateNamed(core, saveState, SAVESTATE_ALL);
|
|
save = vFileToBytes(saveState, &saveLen);
|
|
response = msPacketSaveResponseNew(request->identifier, saveLen, save);
|
|
rawData = msPacketSaveResponseSerialize(response, &rawDataLen);
|
|
if (!rawData) {
|
|
goto return_ms_packet_save_request_send_response;
|
|
}
|
|
packet = msPacketNew(PACKET_SEND_SAVE_RESPONSE, rawDataLen, rawData);
|
|
msPacketSend(packet, data);
|
|
|
|
return_ms_packet_save_request_send_response:
|
|
if (!packet && rawData) {
|
|
free(rawData);
|
|
}
|
|
if (response) {
|
|
msPacketSaveResponseDestroy(&response);
|
|
}
|
|
if (request) {
|
|
msPacketSaveRequestDataDestroy(&request);
|
|
}
|
|
if (packet) {
|
|
msPacketDestroy(&packet);
|
|
}
|
|
}
|
|
|
|
bool
|
|
msPacketSaveRequestHandle(const struct msPacket *packet, struct msPacketSaveRequest *self, struct msClientConnectionData *const data) {
|
|
bool result = false;
|
|
struct msCoreController *coreController = data->coreController;
|
|
size_t saveRequestsLen = 0;
|
|
if (!coreController) {
|
|
goto return_ms_packet_save_request_handle;
|
|
}
|
|
|
|
pthread_mutex_lock(data->mutexSaveRequests);
|
|
data->saveRequestsLen++;
|
|
saveRequestsLen = data->saveRequestsLen;
|
|
|
|
// W: Suspicious usage of 'sizeof(A*)'; pointer to aggregate by clang-tidy.
|
|
data->saveRequests = realloc(data->saveRequests, sizeof *data->saveRequests * saveRequestsLen);
|
|
data->saveRequests[data->saveRequestsLen - 1] = msPacketSaveRequestDataNew(self->identifier);
|
|
pthread_mutex_unlock(data->mutexSaveRequests);
|
|
|
|
mCoreThreadRunFunction(&coreController->threadContext, &msPacketSaveRequestSendResponse);
|
|
result = true;
|
|
return_ms_packet_save_request_handle:
|
|
msPacketSaveRequestDestroy(&self);
|
|
return result;
|
|
}
|