2024-10-06 22:47:44 +00:00
|
|
|
#include <cmdbuf.h>
|
2024-10-10 03:13:34 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <netinet/in.h>
|
2024-10-07 04:55:44 +00:00
|
|
|
#include <request.h>
|
2024-10-08 02:18:42 +00:00
|
|
|
#include <response.h>
|
2024-10-08 02:00:01 +00:00
|
|
|
#include <server.h>
|
2024-10-01 22:48:28 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2024-10-10 03:13:34 +00:00
|
|
|
#include <time.h>
|
2024-10-01 22:48:28 +00:00
|
|
|
#include <unistd.h>
|
2024-10-02 01:24:48 +00:00
|
|
|
#include <vb.h>
|
2024-10-01 22:48:28 +00:00
|
|
|
|
2024-10-08 02:42:28 +00:00
|
|
|
#define BUFLEN 8096
|
2024-10-10 03:13:34 +00:00
|
|
|
#define MAX_STEP_CYCLES 20000
|
|
|
|
|
2024-10-10 22:38:40 +00:00
|
|
|
int sleepNanos(long int ns) {
|
2024-10-10 03:13:34 +00:00
|
|
|
struct timespec time;
|
|
|
|
time.tv_sec = ns / 1000000000;
|
|
|
|
time.tv_nsec = ns % 1000000000;
|
|
|
|
return nanosleep(&time, NULL);
|
|
|
|
}
|
2024-10-01 22:48:28 +00:00
|
|
|
|
2024-10-02 01:24:48 +00:00
|
|
|
int server(int connfd, VB *sim) {
|
2024-10-07 04:55:44 +00:00
|
|
|
RdbRequest req;
|
2024-10-08 02:18:42 +00:00
|
|
|
RdbResponse res;
|
2024-10-10 22:20:16 +00:00
|
|
|
RdbServer srv;
|
2024-10-08 02:18:42 +00:00
|
|
|
char reqbuf[BUFLEN];
|
|
|
|
char resbuf[BUFLEN];
|
2024-10-08 02:42:28 +00:00
|
|
|
rdb_read_result_t read_result;
|
|
|
|
int result;
|
2024-10-07 04:55:44 +00:00
|
|
|
|
2024-10-10 22:38:40 +00:00
|
|
|
rdbRequestInit(&req, connfd, reqbuf, BUFLEN);
|
|
|
|
rdbResponseInit(&res, connfd, resbuf, BUFLEN);
|
|
|
|
rdbServerInit(&srv, sim);
|
2024-10-08 01:20:01 +00:00
|
|
|
|
2024-10-01 22:48:28 +00:00
|
|
|
while (1) {
|
2024-10-08 02:00:01 +00:00
|
|
|
CommandBuf cmd;
|
2024-10-10 03:13:34 +00:00
|
|
|
int brk;
|
|
|
|
uint32_t cycles;
|
2024-10-10 22:38:40 +00:00
|
|
|
read_result = rdbRequestRead(&req, &cmd);
|
2024-10-08 02:42:28 +00:00
|
|
|
if (read_result == read_result_error) {
|
2024-10-07 04:55:44 +00:00
|
|
|
return -1;
|
2024-10-08 02:42:28 +00:00
|
|
|
} else if (read_result == read_result_disconnected) {
|
2024-10-01 22:48:28 +00:00
|
|
|
printf("client has disconnected\n");
|
|
|
|
return 0;
|
2024-10-08 02:42:28 +00:00
|
|
|
} else if (read_result == read_result_pending) {
|
2024-10-10 22:20:16 +00:00
|
|
|
if (srv.running) {
|
2024-10-10 03:13:34 +00:00
|
|
|
cycles = MAX_STEP_CYCLES;
|
|
|
|
brk = vbEmulate(sim, &cycles);
|
|
|
|
if (brk) {
|
|
|
|
/* We hit a breakpoint */
|
2024-10-10 22:05:25 +00:00
|
|
|
if (brk == -1) {
|
|
|
|
/* actually, not implemented */
|
2024-10-10 22:38:40 +00:00
|
|
|
rdbServerBreak(&srv, &res);
|
2024-10-10 22:05:25 +00:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "surprising response %d from vbEmulate\n", brk);
|
|
|
|
return -1;
|
|
|
|
}
|
2024-10-10 03:13:34 +00:00
|
|
|
} else {
|
2024-10-10 22:38:40 +00:00
|
|
|
sleepNanos((MAX_STEP_CYCLES - cycles) * 50);
|
2024-10-10 03:13:34 +00:00
|
|
|
}
|
2024-10-08 01:20:01 +00:00
|
|
|
}
|
2024-10-07 04:55:44 +00:00
|
|
|
continue;
|
2024-10-01 22:48:28 +00:00
|
|
|
} else {
|
2024-10-08 02:00:01 +00:00
|
|
|
printf("received command \"%.*s\"\n", (int) cmd.len, cmd.buf);
|
2024-10-01 22:48:28 +00:00
|
|
|
fflush(stdout);
|
2024-10-10 22:38:40 +00:00
|
|
|
result = rdbServerHandleCommand(&srv, &cmd, &res);
|
2024-10-08 02:18:42 +00:00
|
|
|
if (result != 0) {
|
|
|
|
return result;
|
2024-10-01 22:48:28 +00:00
|
|
|
}
|
2024-10-10 22:38:40 +00:00
|
|
|
rdbRequestSetBlocking(&req, !srv.running);
|
|
|
|
rdbRequestReset(&req);
|
2024-10-01 22:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2024-10-02 01:24:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int readROM(VB *sim, char *filename) {
|
|
|
|
FILE *file = fopen(filename, "rb");
|
2024-10-08 02:42:28 +00:00
|
|
|
uint8_t *rom;
|
2024-10-02 01:24:48 +00:00
|
|
|
long size;
|
|
|
|
|
|
|
|
if (!file) {
|
|
|
|
perror("could not open file");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fseek(file, 0, SEEK_END)) {
|
|
|
|
perror("could not seek file end");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
size = ftell(file);
|
|
|
|
if (size == -1) {
|
|
|
|
perror("could not read file size");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (fseek(file, 0, SEEK_SET)) {
|
|
|
|
perror("could not seek file start");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-10-08 02:42:28 +00:00
|
|
|
rom = malloc(size);
|
2024-10-06 21:19:14 +00:00
|
|
|
if (!rom) {
|
|
|
|
perror("could not allocate ROM");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
fread(rom, 1, size, file);
|
2024-10-02 01:24:48 +00:00
|
|
|
if (ferror(file)) {
|
|
|
|
perror("could not read file");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (fclose(file)) {
|
|
|
|
perror("could not close file");
|
|
|
|
return 1;
|
|
|
|
}
|
2024-10-06 21:19:14 +00:00
|
|
|
vbSetCartROM(sim, rom, size);
|
2024-10-01 22:48:28 +00:00
|
|
|
|
2024-10-02 01:24:48 +00:00
|
|
|
return 0;
|
2024-10-01 22:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
2024-10-08 02:42:28 +00:00
|
|
|
VB *sim;
|
|
|
|
short port;
|
|
|
|
int fd, connfd;
|
|
|
|
struct sockaddr_in addr, cliaddr;
|
|
|
|
socklen_t cliaddrlen;
|
|
|
|
int response;
|
|
|
|
|
2024-10-02 01:24:48 +00:00
|
|
|
if (argc < 2) {
|
|
|
|
fprintf(stderr, "Please pass a ROM file\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2024-10-08 02:42:28 +00:00
|
|
|
sim = malloc(vbSizeOf());
|
2024-10-06 21:19:14 +00:00
|
|
|
if (!sim) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
vbInit(sim);
|
|
|
|
if (readROM(sim, argv[1])) {
|
2024-10-02 01:24:48 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2024-10-10 03:13:34 +00:00
|
|
|
/* relevant state at the start of the physics sim's main */
|
2024-10-10 22:05:25 +00:00
|
|
|
/*
|
2024-10-10 03:13:34 +00:00
|
|
|
vbSetProgramCounter(sim, 0x070002ba);
|
|
|
|
vbSetProgramRegister(sim, 3, 0x0500ffc0);
|
|
|
|
vbSetProgramRegister(sim, 4, 0x05008000);
|
2024-10-10 22:05:25 +00:00
|
|
|
*/
|
2024-10-02 01:24:48 +00:00
|
|
|
|
|
|
|
if (argc > 2) {
|
2024-10-01 22:48:28 +00:00
|
|
|
char *end;
|
2024-10-02 01:24:48 +00:00
|
|
|
port = (short) strtol(argv[2], &end, 10);
|
|
|
|
if (argv[2] == end) {
|
2024-10-01 22:48:28 +00:00
|
|
|
perror("could not parse port");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
port = 8080;
|
|
|
|
}
|
|
|
|
|
2024-10-08 02:42:28 +00:00
|
|
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
2024-10-01 22:48:28 +00:00
|
|
|
if (fd == -1) {
|
|
|
|
perror("could not open socket");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
addr.sin_port = htons(port);
|
|
|
|
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
|
|
|
|
perror("could not bind socket");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (listen(fd, 1) == -1) {
|
|
|
|
perror("could not listen on socket");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("connecting\n");
|
2024-10-08 02:42:28 +00:00
|
|
|
cliaddrlen = sizeof(cliaddr);
|
2024-10-01 22:48:28 +00:00
|
|
|
connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
|
|
|
|
if (connfd == -1) {
|
|
|
|
perror("could not accept connection");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
printf("connected\n");
|
|
|
|
|
2024-10-08 02:42:28 +00:00
|
|
|
response = server(connfd, sim);
|
2024-10-01 22:48:28 +00:00
|
|
|
return close(connfd)
|
|
|
|
|| close(fd)
|
|
|
|
|| response;
|
|
|
|
}
|