diff --git a/tools/Makefile b/tools/Makefile index ce2573f..60a80b2 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,6 +1,6 @@ CC = gcc -all: injector fileadder +all: injector fileadder httpd_sim clean: rm *.o @@ -10,3 +10,6 @@ injector: injector.c fileadder: fileadder.c gcc $^ -o $@ + +httpd_sim: httpd_sim.c httpd_sim.h + gcc $< -o $@ -I/usr/include/json-c -ljson-c diff --git a/tools/httpd_sim.c b/tools/httpd_sim.c new file mode 100644 index 0000000..cb7792f --- /dev/null +++ b/tools/httpd_sim.c @@ -0,0 +1,240 @@ +#include +#include +#include +#include +#include +#include +#include +#include "httpd_sim.h" +#include + +#define PORTS 6 +time_t last_called; + +uint64_t txG[PORTS], txB[PORTS], rxG[PORTS], rxB[PORTS]; +char txG_buff[20], txB_buff[20], rxG_buff[20], rxB_buff[20]; +char num_buff[20]; + +int hasSuffix(const char *str, const char *suffix) +{ + if (!str || !suffix) + return 0; + + size_t lenstr = strlen(str); + size_t lensuffix = strlen(suffix); + + if (lensuffix > lenstr) + return 0; + + return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0; +} + + +char *getMime(const char *name) +{ + if (hasSuffix(name, ".html")) + return "text/html"; + else if (hasSuffix(name, ".svg")) + return "image/svg+xml"; + else if (hasSuffix(name, ".ico")) + return "image/svg+xml"; + else if (hasSuffix(name, ".png")) + return "image/png"; + else if (hasSuffix(name, ".js")) + return "text/javascript"; + else if (hasSuffix(name, ".css")) + return "text/css"; + return "text/plain"; +} + + +void send_vlan(int s, int vlan) +{ + struct json_object *v; + const char *jstring; + char *header = "HTTP/1.1 200 OK\r\n" + "Content-Type: application/json; charset=UTF-8\r\n\r\n"; + + v = json_object_new_object(); + + sprintf(num_buff, "0x%08x", 0x00060011); + json_object_object_add(v, "members", json_object_new_string(num_buff)); + + write(s, header, strlen(header)); + + jstring = json_object_to_json_string_ext(v, JSON_C_TO_STRING_PLAIN); + write(s, jstring, strlen(jstring)); + json_object_put(v); +} + + +void send_status(int s) +{ + struct json_object *jobj, *ports, *v; + const char *jstring; + char *header = "HTTP/1.1 200 OK\r\n" + "Content-Type: application/json; charset=UTF-8\r\n\r\n"; + + time_t now = time(NULL); + now == last_called ? last_called + 1 : now; // Make sure we don't divide by 0 for rates + + ports = json_object_new_array_ext(PORTS); + for (int i = 1; i <= PORTS; i++) { + v = json_object_new_object(); + json_object_object_add(v, "portNum", json_object_new_int(i)); + json_object_object_add(v, "isSFP", json_object_new_int(i < 5 ? 0 : 1)); + json_object_object_add(v, "enabled", json_object_new_int((i % 4) ? 1 : 0)); + json_object_object_add(v, "link", json_object_new_int(i % 2 ? ((i == 1)? 5 : 2) : 0)); + if (i % 2) { + uint64_t rate = (i == 1) ? 2400000000 : 950000000; + txG[i-1] += rate * (now - last_called); + rxG[i-1] += rate * (now - last_called); + txB[i-1] += rate * (now - last_called) / 10000000; + rxB[i-1] += rate * (now - last_called) / 10000000; + } + sprintf(txG_buff, "0x%016x", txG[i-1]); + sprintf(txB_buff, "0x%016x", txB[i-1]); + sprintf(rxG_buff, "0x%016x", rxG[i-1]); + sprintf(rxB_buff, "0x%016x", rxB[i-1]); + json_object_object_add(v, "txG", json_object_new_string(txG_buff)); + json_object_object_add(v, "txB", json_object_new_string(txB_buff)); + json_object_object_add(v, "rxG", json_object_new_string(rxG_buff)); + json_object_object_add(v, "rxB", json_object_new_string(rxB_buff)); + json_object_array_add(ports, v); + } + last_called = now; + + write(s, header, strlen(header)); + + jstring = json_object_to_json_string_ext(ports, JSON_C_TO_STRING_PLAIN); + write(s, jstring, strlen(jstring)); + json_object_put(v); +} + + +struct Server serverConstructor(int port, void (*launch)(struct Server *server)) { + struct Server server; + + server.domain = AF_INET; + server.service = SOCK_STREAM; + server.port = port; + server.protocol = 0; + server.backlog = 10; + + server.address.sin_family = server.domain; + server.address.sin_port = htons(port); + server.address.sin_addr.s_addr = htonl(INADDR_ANY); + + server.socket = socket(server.domain, server.service, server.protocol); + if (server.socket < 0) { + perror("Failed to initialize/connect to socket...\n"); + exit(EXIT_FAILURE); + } + + if (bind(server.socket, (struct sockaddr*)&server.address, sizeof(server.address)) < 0) { + perror("Failed to bind socket...\n"); + exit(EXIT_FAILURE); + } + + if (listen(server.socket, server.backlog) < 0) { + perror("Failed to start listening...\n"); + exit(EXIT_FAILURE); + } + + server.launch = launch; + return server; +} + +void launch(struct Server *server) { + char buffer[BUFFER_SIZE]; + FILE *inptr; + + last_called = time(NULL); + for (int i=0; i < PORTS; i++) + txG[i] = txB[i] = rxG[i] = rxB[i] = 0; + + while (1) { + printf("=== Waiting for connection on port %d === \n", server->port); + int addrlen = sizeof(server->address); + int new_socket = accept(server->socket, (struct sockaddr*)&server->address, (socklen_t*)&addrlen); + ssize_t bytesRead = read(new_socket, buffer, BUFFER_SIZE - 1); + if (bytesRead >= 0) { + buffer[bytesRead] = '\0'; // Null terminate the string + puts(buffer); + + if (buffer[0] == 'G' && buffer[1] == 'E' && buffer[2] == 'T' && buffer[3] == ' ') { + printf("GET request\n"); + if (!strncmp(&buffer[4], "/status.json", 12)) { + printf("Status request\n"); + send_status(new_socket); + goto done; + } + if (!strncmp(&buffer[4], "/vlan.json?vid=", 15)) { + int vlan = atoi(&buffer[19]); + printf("VLAN request for %d\n", vlan); + send_vlan(new_socket, vlan); + goto done; + } + int i = 0; + while (!isspace(buffer[4 + i])) + i++; + buffer[4+i] = '\0'; + + printf("Serving file: >%s<\n", &buffer[5]); + inptr = fopen(&buffer[5], "rb"); + if (inptr == NULL) { + printf("Cannot open input file %s\n", &buffer[5]); + char *response = "HTTP/1.1 404 Not found\r\n" + "Content-Type: text/html\r\n\r\n" + " Not found" + "

Not found!

"; + write(new_socket, response, strlen(response)); + goto done; + } + + char *mime =getMime(&buffer[5]); + printf("MIME type: %s\n", mime); + + fseek(inptr, 0L, SEEK_END); + int filesize = ftell(inptr); + printf("Filesize: %d\n", filesize); + rewind(inptr); + printf("Input file size: %ld\n", filesize); + if (filesize > BUFFER_SIZE) { + printf("File too large.\n"); + goto done; + } + size_t bytes_read = fread(buffer, 1, sizeof(buffer), inptr); + + printf("Bytes read: %ld\n", bytes_read); + + if (bytes_read != filesize) { + printf("Error reading input file.\n"); + goto done; + } + fclose(inptr); + char *response = "HTTP/1.1 200 OK\r\n" + "Content-Type: "; + write(new_socket, response, strlen(response)); + + write(new_socket, mime, strlen(mime)); + response = "; charset=UTF-8\r\n\r\n"; + write(new_socket, response, strlen(response)); + + write(new_socket, buffer, filesize); + } + } else { + perror("Error reading buffer...\n"); + } + +done: + close(new_socket); + } +} + + +int main() { + struct Server server = serverConstructor(8080, launch); + server.launch(&server); + return 0; +} diff --git a/tools/httpd_sim.h b/tools/httpd_sim.h new file mode 100644 index 0000000..1e4ccdb --- /dev/null +++ b/tools/httpd_sim.h @@ -0,0 +1,26 @@ +#ifndef server_h +#define server_h + +#include + +#define BUFFER_SIZE 16000 + +struct Server { + int domain; + int port; + int service; + int protocol; + int backlog; + u_long interface; + + int socket; + struct sockaddr_in address; + + void (*launch)(struct Server *server); +}; + +struct Server server_Constructor(int port, void (*launch)(struct Server *server)); +void launch(struct Server *server); + +#endif +