AltCraft-tools/TransperentProxy/replaymod.c

116 lines
3.8 KiB
C

#include "replaymod.h"
#include "proxy.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <endian.h>
static const char json_format[]="{\"singleplayer\":false,\"fileFormat\":\"MCPR\",\"fileFormatVersion\":9,\"generator\":\"ACTools proxy\",\"selfId\":-1,"
"\"serverName\":\"%s\","
"\"date\":%lu,"
"\"duration\":%u,"
"\"mcversion\":\"%s\",\"players\":[",
json_format_end[]="]}\n";
void replay_init_context(struct context *ctx, const char *restrict version/*, const uint8_t *restrict buffer, uint32_t len*/) {
replay_free_context(ctx);
char buf[32];
time_t t = time(NULL);
struct tm *tm = localtime(&t);
sprintf(buf, "%d_%02d_%02d_%02d_%02d_%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
mkdir(buf, S_IRWXU);
int dirfd=open(buf, O_DIRECTORY);
ctx->replay.replayfileFD=openat(dirfd, "recording.tmcpr", O_CREAT|O_CLOEXEC|O_WRONLY|O_NONBLOCK, S_IREAD|S_IWRITE);
ctx->replay.replayinfoFD=openat(dirfd, "metaData.json", O_CREAT|O_CLOEXEC|O_WRONLY, S_IREAD|S_IWRITE);
if(ctx->replay.replayfileFD == -1 || ctx->replay.replayinfoFD == -1) {
perror("openat() failed: ");
if(ctx->replay.replayfileFD != -1)
close(ctx->replay.replayfileFD);
else if (ctx->replay.replayinfoFD != -1)
close(ctx->replay.replayinfoFD);
ctx->replay.replayfileFD = -1;
return;
}
// fcntl(ctx->replay.replayfileFD, F_SETFL, fcntl(ctx->replay.replayfileFD, F_GETFL) | O_NONBLOCK);
gettimeofday(&ctx->replay.startTime, NULL);//Can fail on linux with EFAULT
ctx->replay.startTime.tv_usec/=1000;
ctx->replay.startTime.tv_usec+=ctx->replay.startTime.tv_sec*1000;
ctx->replay.versionName = version;
ctx->replay.UUIDs = malloc(4*sizeof(uint8_t*));
void *ptr = malloc(4*37);
ctx->replay.UUIDs[0] = ptr;
ctx->replay.UUIDs[1] = ptr+37;
ctx->replay.UUIDs[2] = ptr+(2*37);
ctx->replay.UUIDs[3] = ptr+(3*37);
ctx->replay.uuidcount = 4;
ctx->replay.uuidused = 0;
}
void replay_free_context(struct context *ctx) {
if(ctx->replay.replayfileFD == -1)
return;
close(ctx->replay.replayfileFD);
ctx->replay.replayfileFD = -1;
if(ctx->replay.replayinfoFD != -1) {
struct timeval now;
gettimeofday(&now, NULL);
uint32_t diff = (uint32_t)(now.tv_usec/1000 + now.tv_sec*1000 - ctx->replay.startTime.tv_usec);//msecs in tv_usec
dprintf(ctx->replay.replayinfoFD, json_format, "127.0.0.1", ctx->replay.startTime.tv_usec, diff, ctx->replay.versionName);
for(uint8_t i = 0; i < ctx->replay.uuidcount; i++) {
if(i)
dprintf(ctx->replay.replayinfoFD, ",");
dprintf(ctx->replay.replayinfoFD, "\"%s\"", ctx->replay.UUIDs[i]);
}
dprintf(ctx->replay.replayinfoFD, json_format_end);
close(ctx->replay.replayinfoFD);
ctx->replay.replayinfoFD = -1;
}
}
void replay_write_packet(struct context *ctx, const uint8_t *restrict buffer, uint32_t len) {
if(ctx->replay.replayfileFD == -1)
return;
struct timeval now;
gettimeofday(&now, NULL);
uint32_t diff = (uint32_t)(now.tv_usec/1000 + now.tv_sec*1000 - ctx->replay.startTime.tv_usec);//msecs in tv_usec
uint32_t buf[2] = {htobe32(diff), htobe32(len)};
struct iovec iv[2]={{buf, 2*4}, {(void*)buffer, len}};
if(writev(ctx->replay.replayfileFD, iv, 2) == -1)
perror("writev() failed");
}
void replay_add_uuid(struct context *ctx, const uint8_t *restrict buffer) {
for(uint32_t i=0; i<ctx->replay.uuidused; i++) {
if(memcmp(buffer, ctx->replay.UUIDs[i], 36) == 0)
return;//Already added
}
if(ctx->replay.uuidused == ctx->replay.uuidcount) {
ctx->replay.UUIDs=realloc(ctx->replay.UUIDs, (++ctx->replay.uuidcount)*sizeof(uint8_t*));
ctx->replay.UUIDs[ctx->replay.uuidused] = malloc(37);
}
memcpy(ctx->replay.UUIDs[ctx->replay.uuidused], buffer, 36);
(ctx->replay.UUIDs[ctx->replay.uuidused])[36]=0;
ctx->replay.uuidused++;
}