quest/src2/server.c

671 lines
14 KiB
C
Raw Normal View History

2023-04-04 01:57:29 +10:00
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#define NS_PER_S 1000000000
struct timespec finish, delta;
int pausedTime = 0;
bool timerActive = false;
bool paused = false;
bool alive = true;
bool hasUndoneAtLeastOnce = false;
2023-07-20 20:10:23 +10:00
bool runUnsaved = false;
2023-04-04 01:57:29 +10:00
int timerOffset = 0;
enum event_type {
START,
SPLIT,
SKIP,
PAUSE,
RESUME,
STOP
};
struct run_event {
enum event_type type;
struct timespec time;
};
2023-07-20 22:25:09 +10:00
struct segment {
char *shortname;
char *longname;
char *description;
};
struct route {
char *name;
struct segment *segments;
int segment_count;
};
2023-04-04 01:57:29 +10:00
struct run_event *run;
//Enough to hold a sm64 16 star, can realloc later
int runMaxLength = 12;
int runMarker = 0;
int runMarker2 = 0;
//save file stuff
char *default_file_name = "untitled.quest";
2023-07-20 20:38:06 +10:00
int run_count = 0;
2023-04-04 01:57:29 +10:00
int files = 0;
char **filePaths = NULL;
char **names, **values;
int valuecount;
2023-07-20 22:25:09 +10:00
struct segment *segments;
int segment_count = 0;
struct route *routes;
int route_count = 0;
struct route current_route;
2023-04-04 01:57:29 +10:00
//functions
void sub_timespec(struct timespec t1, struct timespec t2, struct timespec* td);
void offset_timespec(int milliseconds, struct timespec* t);
int timespecToMS(struct timespec t);
void extend_run();
void add_event(enum event_type t);
void appendRunToFile();
void timespecToRFC3339(struct timespec t, char buf[]);
void loadFiles();
2023-07-20 22:25:09 +10:00
void add_segment(char *sname, char *lname, char *desc);
void addFile(char *path);
2023-07-20 22:25:09 +10:00
void sendInt(int sock, int value);
void sendValue(int sock, char* name);
void sendString(int sock, char* str);
void doprocessing (int sock);
void addPauseTime();
void subtractPauseTime();
int current_ms();
//basic timer commands
void start();
void split();
void stop();
void skip();
void undo();
void redo();
void pause_timer();
void resume();
//convenient combination commands
void start_split_stop();
void start_split();
void split_stop();
void start_stop();
void pause_resume();
void undo_redo();
2023-04-04 01:57:29 +10:00
void sub_timespec(struct timespec t1, struct timespec t2, struct timespec* td)
{
td->tv_nsec = t2.tv_nsec - t1.tv_nsec;
td->tv_sec = t2.tv_sec - t1.tv_sec;
if (td->tv_sec > 0 && td->tv_nsec < 0) {
td->tv_nsec += NS_PER_S;
td->tv_sec--;
} else if (td->tv_sec < 0 && td->tv_nsec > 0) {
td->tv_nsec -= NS_PER_S;
td->tv_sec++;
}
}
void offset_timespec(int milliseconds, struct timespec* t)
{
//this should leave milliseconds with just the remainder
int second_offset = milliseconds / 1000;
milliseconds -= second_offset * 1000;
int nanosecond_offset = milliseconds * 1000000;
t->tv_nsec -= nanosecond_offset;
if (t->tv_nsec < 0) {
second_offset++;
t->tv_nsec += 1000000000;
}
t->tv_sec -= second_offset;
}
int timespecToMS(struct timespec t)
{
return (t.tv_nsec / 1000000) + (t.tv_sec * 1000);
}
void extend_run()
{
runMaxLength *= 2;
run = realloc(run, sizeof(struct run_event) * runMaxLength);
}
void add_event(enum event_type t)
{
if (runMarker == runMaxLength)
extend_run();
run[runMarker].type = t;
clock_gettime(CLOCK_REALTIME, &run[runMarker].time);
if (t == START)
offset_timespec(timerOffset, &run[runMarker].time);
runMarker++;
runMarker2 = runMarker;
}
2023-07-24 18:44:01 +10:00
void reset_timer()
{
runMarker = 0;
runMarker2 = 0;
}
2023-04-04 01:57:29 +10:00
void start()
{
if (timerActive) return;
2023-07-24 18:44:01 +10:00
//Save the old run to the file before the new one starts,
2023-04-04 01:57:29 +10:00
//the reason to do this here is it gives the runner a chance to undo
//if they accidentally hit the stop button
2023-07-20 20:10:23 +10:00
appendRunToFile();
2023-07-24 18:44:01 +10:00
reset_timer();
2023-04-04 01:57:29 +10:00
timerActive = true;
add_event(START);
}
void stop()
{
if (!timerActive) return;
2023-04-04 01:57:29 +10:00
timerActive = false;
add_event(STOP);
//this makes sure the time clients recieve from time
//requests match the time on the stop event
finish = run[runMarker - 1].time;
2023-07-20 20:10:23 +10:00
runUnsaved = true;
2023-04-04 01:57:29 +10:00
}
void start_split_stop()
{
if (!timerActive) {
start();
} else {
if (runMarker < current_route.segment_count) {
split();
} else {
stop();
}
}
}
void start_split()
{
if (!timerActive) start();
else split();
}
void split_stop()
{
if (runMarker < current_route.segment_count) split();
else stop();
}
void start_stop()
{
if (!timerActive) start();
else stop();
}
2023-04-04 01:57:29 +10:00
void split()
{
if (!timerActive) return;
2023-04-04 01:57:29 +10:00
add_event(SPLIT);
}
void skip()
{
if (!timerActive) return;
2023-04-04 01:57:29 +10:00
add_event(SKIP);
}
void addPauseTime()
{
int pauseEvent = 0;
for (int i = runMarker - 2; i >= 1; i--) {
if (run[i].type == PAUSE) {
pauseEvent = i;
break;
}
}
sub_timespec(run[pauseEvent].time, run[runMarker - 1].time, &delta);
pausedTime += timespecToMS(delta);
}
void subtractPauseTime()
{
int pauseEvent = 0;
for (int i = runMarker - 1; i >= i; i--) {
if (run[i].type == PAUSE) {
pauseEvent = i;
break;
}
}
sub_timespec(run[pauseEvent].time, run[runMarker].time, &delta);
pausedTime -= timespecToMS(delta);
}
void undo()
{
if (!timerActive) return;
2023-04-04 01:57:29 +10:00
if (runMarker > 0) {
runMarker--;
if (run[runMarker].type == STOP)
timerActive = true;
if (run[runMarker].type == START)
timerActive = false;
if (run[runMarker].type == PAUSE)
paused = false;
if (run[runMarker].type == RESUME) {
paused = true;
subtractPauseTime();
}
hasUndoneAtLeastOnce = true;
2023-04-04 01:57:29 +10:00
}
}
void redo()
{
if (!timerActive) return;
2023-04-04 01:57:29 +10:00
if (runMarker < runMarker2) {
runMarker++;
if (run[runMarker - 1].type == STOP)
timerActive = false;
if (run[runMarker - 1].type == START)
timerActive = true;
if (run[runMarker - 1].type == PAUSE)
paused = true;
if (run[runMarker - 1].type == RESUME) {
paused = false;
addPauseTime();
}
} else {
hasUndoneAtLeastOnce = false;
2023-04-04 01:57:29 +10:00
}
}
void undo_redo()
{
if (hasUndoneAtLeastOnce) redo();
else undo();
}
2023-04-04 01:57:29 +10:00
//this isnt just called pause() because that would overlap with <unistd.h>
void pause_timer()
{
if (!timerActive) return;
2023-04-04 01:57:29 +10:00
if (!paused) {
add_event(PAUSE);
paused = true;
}
}
void resume()
{
if (!timerActive) return;
2023-04-04 01:57:29 +10:00
if (paused) {
add_event(RESUME);
paused = false;
addPauseTime();
}
}
void pause_resume()
{
if (paused) resume();
else pause_timer();
}
void appendRunToFile()
{
2023-07-20 20:10:23 +10:00
if (!runUnsaved)
return;
char* save_path = NULL;
if (files <= 0)
save_path = default_file_name;
else
save_path = filePaths[0];
FILE* fp;
fp = fopen(save_path, "a+");
fprintf(fp, "%s\n", "Run");
if (current_route.name != NULL) {
fprintf(fp, "\t%s\n", "Route");
fprintf(fp, "\t\t%s\n", current_route.name);
}
int i = 0;
bool done = false;
while (!done) {
if (run[i].type == STOP) {
done = true;
}
switch (run[i].type) {
case START:
fprintf(fp, "\t%s\n", "Start");
break;
case SPLIT:
fprintf(fp, "\t%s\n", "Split");
break;
case SKIP:
fprintf(fp, "\t%s\n", "Skip");
break;
case PAUSE:
fprintf(fp, "\t%s\n", "Pause");
break;
case RESUME:
fprintf(fp, "\t%s\n", "Resume");
break;
case STOP:
fprintf(fp, "\t%s\n", "Stop");
break;
}
if (i == 0) {
char buf[25];
timespecToRFC3339(run[i].time, buf);
fprintf(fp, "\t\t%s\n", buf);
}
else {
sub_timespec(run[i - 1].time, run[i].time, &delta);
fprintf(fp, "\t\t%d\n", timespecToMS(delta));
}
i++;
}
fprintf(fp, "\n");
fclose(fp);
2023-07-20 20:38:06 +10:00
run_count++;
2023-07-20 20:10:23 +10:00
runUnsaved = false;
}
void timespecToRFC3339(struct timespec t, char buf[])
{
const int tmpsize = 21;
struct tm tm;
gmtime_r(&t.tv_sec, &tm);
strftime(buf, tmpsize, "%Y-%m-%d %H:%M:%S.", &tm);
sprintf(buf + tmpsize - 1, "%03luZ", (t.tv_nsec / 1000000));
}
2023-04-04 01:57:29 +10:00
void loadFiles()
{
FILE* fp;
char buff[255];
char buff2[255];
for (int i = 0; i < files; i++) {
fp = fopen(filePaths[i], "r+");
2023-04-04 01:57:29 +10:00
while(1) {
2023-07-20 20:10:23 +10:00
if (!fgets(buff, 255, fp))
break;
2023-07-20 20:38:06 +10:00
if (buff[0] == '/' && buff[1] == '/' || buff[0] == '\n' || buff[0] == '\t')
2023-04-04 01:57:29 +10:00
continue;
2023-07-20 22:25:09 +10:00
if (!strcmp(buff, "Segment\n")) {
char *s = NULL;
char *l = NULL;
char *d = NULL;
for (int x = 0; x < 3; x++) {
if (!fgets(buff2, 255, fp))
break;
if (!strcmp(buff2, "\tShortname\n")) {
if (!fgets(buff2, 255, fp))
break;
s = malloc(strlen(buff2) - 2);
s = strncpy(s, buff2 + 2, strlen(buff2) - 2);
s[strlen(s) - 1] = '\0';
} else if (!strcmp(buff2, "\tLongname\n")) {
if (!fgets(buff2, 255, fp))
break;
l = malloc(strlen(buff2) - 2);
l = strncpy(l, buff2 + 2, strlen(buff2) - 2);
l[strlen(l) - 1] = '\0';
} else if (!strcmp(buff2, "\tDescription\n")) {
if (!fgets(buff2, 255, fp))
break;
d = malloc(strlen(buff2) - 2);
d = strncpy(d, buff2 + 2, strlen(buff2) - 2);
d[strlen(d) - 1] = '\0';
}
}
add_segment(s, l, d);
continue;
}
if (!strcmp(buff, "Route\n"))
2023-07-20 20:38:06 +10:00
continue;
if (!strcmp(buff, "Run\n")) {
run_count++;
continue;
}
2023-07-20 20:10:23 +10:00
if (!fgets(buff2, 255, fp))
2023-04-04 01:57:29 +10:00
break;
if (buff2[0] == '\t') {
valuecount++;
2023-07-18 23:53:22 +10:00
2023-04-04 01:57:29 +10:00
names = realloc(names, sizeof(char*) * valuecount);
2023-07-19 01:45:26 +10:00
names[valuecount - 1] = malloc(strlen(buff));
2023-04-04 01:57:29 +10:00
strncpy(names[valuecount - 1], buff, strlen(buff) - 1);
names[valuecount - 1][strlen(buff)] = '\0';
2023-07-18 23:53:22 +10:00
2023-04-04 01:57:29 +10:00
values = realloc(values, sizeof(char*) * valuecount);
2023-07-19 01:45:26 +10:00
values[valuecount - 1] = malloc(strlen(buff2) - 1);
2023-04-04 01:57:29 +10:00
strncpy(values[valuecount - 1], buff2 + 1, strlen(buff2) - 1);
values[valuecount - 1][strlen(buff2)] = '\0';
}
}
fclose(fp);
}
}
2023-07-20 22:25:09 +10:00
void add_segment(char *sname, char *lname, char *desc)
{
segment_count++;
segments = realloc(segments, sizeof(struct segment) * segment_count);
segments[segment_count - 1].shortname = sname;
segments[segment_count - 1].longname = lname;
segments[segment_count - 1].description = desc;
}
2023-04-04 01:57:29 +10:00
//TODO: eventually file loading should support loading multiple files
void addFile(char *path)
{
files++;
filePaths = realloc(filePaths, sizeof(char*) * files);
filePaths[files - 1] = path;
loadFiles();
}
int current_ms()
2023-04-04 01:57:29 +10:00
{
if (timerActive)
clock_gettime(CLOCK_REALTIME, &finish);
if (paused) {
sub_timespec(run[0].time, run[runMarker - 1].time, &delta);
} else {
sub_timespec(run[0].time, finish, &delta);
}
return timespecToMS(delta) - pausedTime;
}
2023-04-04 01:57:29 +10:00
void sendInt(int sock, int value)
{
char buffer[256];
sprintf(buffer, "%d", value);
int n = write(sock, &buffer, 256);
2023-04-04 01:57:29 +10:00
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
}
void sendValue(int sock, char* name)
{
char buffer[256];
2023-04-04 01:57:29 +10:00
int n, x;
bool namefound = false;
for(int i = 0; i < valuecount; i++) {
if (!strcmp(names[i], name)) {
x = i;
namefound = true;
}
}
if (namefound)
strcpy(buffer, values[x]);
2023-04-04 01:57:29 +10:00
else
strcpy(buffer, "DATA NOT PRESENT");
n = write(sock, &buffer, 256);
2023-07-20 22:25:09 +10:00
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
}
void sendString(int sock, char* str)
{
char buffer[256];
strcpy(buffer, str);
int n = write(sock, &buffer, 256);
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
}
2023-04-04 01:57:29 +10:00
void doprocessing (int sock)
{
int n;
char buffer[256];
n = read(sock, &buffer, 256);
char *token = strtok(buffer, " ");
2023-04-04 01:57:29 +10:00
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
if (!strcmp(token, "current_time")) {
2023-04-04 01:57:29 +10:00
//printf("Recieved time command\n");
sendInt(sock, current_ms());
} else if (!strcmp(token, "start")) {
2023-04-04 01:57:29 +10:00
printf("Recieved start command\n");
start();
} else if (!strcmp(token, "stop")) {
2023-04-04 01:57:29 +10:00
printf("Recieved stop command\n");
stop();
} else if (!strcmp(token, "kill")) {
2023-04-04 01:57:29 +10:00
printf("Recieved kill command\n");
alive = false;
} else if (!strcmp(token, "split")) {
2023-04-04 01:57:29 +10:00
printf("Recieved split command\n");
split();
} else if (!strcmp(token, "skip")) {
2023-04-04 01:57:29 +10:00
printf("Recieved skip command\n");
skip();
} else if (!strcmp(token, "pause")) {
2023-04-04 01:57:29 +10:00
printf("Recieved pause command\n");
pause_timer();
} else if (!strcmp(token, "resume")) {
2023-04-04 01:57:29 +10:00
printf("Recieved resume command\n");
resume();
} else if (!strcmp(token, "undo")) {
2023-04-04 01:57:29 +10:00
printf("Recieved undo command\n");
undo();
} else if (!strcmp(token, "redo")) {
2023-04-04 01:57:29 +10:00
printf("Recieved redo command\n");
redo();
} else if (!strcmp(token, "Foreground-Color")) {
2023-04-04 01:57:29 +10:00
printf("Recieved request for foreground color\n");
sendValue(sock, "Foreground-Color");
} else if (!strcmp(token, "Background-Color")) {
2023-04-04 01:57:29 +10:00
printf("Recieved request for background color\n");
sendValue(sock, "Background-Color");
} else if (!strcmp(token, "save")) {
2023-07-20 20:10:23 +10:00
printf("Recieved save command\n");
appendRunToFile();
} else if (!strcmp(token, "run_count")) {
2023-07-20 22:25:09 +10:00
printf("Recieved request for run count\n");
sendInt(sock, run_count);
} else if (!strcmp(token, "segment_count")) {
printf("Recieved request for segment count\n");
sendInt(sock, segment_count);
} else if (!strcmp(token, "start_split_stop")) {
printf("Recieved start_split_stop command\n");
start_split_stop();
} else if (!strcmp(token, "pause_resume")) {
printf("Recieved pause_resume command\n");
pause_resume();
} else if (!strcmp(token, "start-stop")) {
printf("Recieved start-stop command\n");
start_stop();
} else if (!strcmp(token, "start-split")) {
printf("Recieved start-split command\n");
start_split();
} else if (!strcmp(token, "split-stop")) {
printf("Recieved split-stop command\n");
split_stop();
} else if (!strcmp(token, "undo-redo")) {
printf("Recieved undo-redo command\n");
undo_redo();
} else if (!strcmp(token, "segment_name")) {
token = strtok(NULL, " ");
int x = atoi(token);
printf("Recieved request for segment %s's name: %s\n", token, segments[x].shortname);
sendString(sock, segments[x].shortname);
2023-04-04 01:57:29 +10:00
} else {
printf("Recieved invalid command, ignoring...\n");
2023-04-04 01:57:29 +10:00
}
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n, pid;
run = malloc(sizeof(struct run_event) * runMaxLength);
//TODO: remove this file testing boilerplate
2023-04-11 14:06:42 +10:00
if (argc > 1)
addFile(argv[1]);
2023-04-04 01:57:29 +10:00
/* First call to socket() function */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 8101;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
/* Now bind the host address using bind() call.*/
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
exit(1);
}
listen(sockfd,5);
clilen = sizeof(cli_addr);
2023-07-20 20:10:23 +10:00
printf("Ready!\n");
2023-04-04 01:57:29 +10:00
while (alive) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
perror("ERROR on accept");
exit(1);
}
2023-07-18 23:53:22 +10:00
doprocessing(newsockfd);
close(newsockfd);
}
2023-04-04 01:57:29 +10:00
free(run);
close(sockfd);
}