msgba/src/packet/save_request.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;
}