Files
RTLPlayground/tools/httpd_sim.c
T
Rob Emery 48087d3520 Decoupling the load from the spinner so we can get rid of it
Also making the first VLAN in the table load when we load the UI

Removing the tickbox for the PVID, I'll swap this out to ticks
or something later on, but the PVID will be automatically set
based on the untagged membership, otherwise it will be 1

Send the vlan with name command when attempting to add a new VLAN
Because of the structure of the vlan command, we need to send the name as well if its set

Set the PVID based on the untagged membership and reload the
table when applied. We need to block setting the PVID to the tagged by proxy

Blue button

Need to provide array of pvid commands not concat
Storing state of each vlan so we can refer later

Blue button
2026-10-25 09:06:30 +00:00

1081 lines
32 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include "httpd_sim.h"
#include <json.h>
#include <signal.h>
#include "../version.h"
#define SESSION_ID "1234567890ab"
#define PASSWORD "1234"
#define SESSION_TIMEOUT 2000
#define PORTS 6
#define NSFP 1
#define N_COUNTERS 52
#define VLAN_MAX_ID 4094
int currentVLANCount = 1;
#if PORTS == 9
const uint8_t physToLogPort[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
#else
const uint8_t physToLogPort[] = { 4, 5, 6, 7, 3, 8};
#endif
struct mem_vlan {
bool active;
char name[20];
bool untagged[PORTS];
bool tagged[PORTS];
};
struct mem_vlan mem_vlans[VLAN_MAX_ID+1];
//mem_vlans[1] = {.active=true, .name="", .untagged={}, .tagged={}};
struct l2_entry {
char mac[18];
char vlan[4];
char type;
uint8_t port;
uint16_t idx;
};
#define L2_ENTRY_NUM 12
#define L2_MAX_TRANSFER 5
const struct l2_entry l2_entries[12] = {
{ "00:01:2f:00:00:01", "001", 'l', 7, 0x10 },
{ "00:06:78:00:00:02", "001", 'l', 7, 0x20 },
{ "00:01:2e:00:00:03", "001", 's', 7, 0x30 },
{ "60:7d:09:00:00:04", "001", 'l', 7, 0x40 },
{ "1c:2a:a3:00:00:05", "001", 'l', 7, 0x50 },
{ "1c:2a:a3:00:00:06", "001", 's', 7, 0x60 },
{ "02:e0:4c:00:00:07", "001", 'l', 7, 0x70 },
{ "00:e0:4c:00:00:08", "001", 'l', 4, 0x80 },
{ "1c:2a:a3:00:00:09", "001", 'l', 9, 0x90 }, // CPU-Port
{ "3c:8c:f8:00:00:0a", "001", 'l', 7, 0xa0 },
{ "00:01:2e:00:00:0b", "001", 'l', 7, 0xb0 },
{ "00:01:2f:00:01:01", "001", 'l', 7, 0xc0 }
};
time_t last_called;
time_t last_session_use;
uint64_t txG[PORTS], txB[PORTS], rxG[PORTS], rxB[PORTS];
char txG_buff[20], txB_buff[20], rxG_buff[20], rxB_buff[20], counter_buf[20], counter_name[20];
char macs_buff[8];
char sfp_temp[8], sfp_vcc[8], sfp_txbias[8], sfp_txpower[8], sfp_rxpower[8], sfp_laser[8], sfp_options[6];
char num_buff[20];
char l2_idx_buff[20];
char upload_buffer[4194304]; // 4MB
char *content_type = NULL;
char boundary[72];
char cmd_history[1024][256];
uint16_t cmd_ptr = 0;
char *uploaded_config = NULL;
int uploaded_config_len;
const char *session = NULL;
bool authenticated = false;
char is_word(char *c, char *d)
{
uint8_t i = 0;
while (d[i] && (d[i] == c[i]))
i++;
if (d[i])
return 0;
if (c[i] != ' ' && c[i] != '\t' && c[i] != ':' && c[i] != '?' && c[i] != '=' && c[i] != '\n' && c[i] != '\r' && c[i])
return 0;
return 1;
}
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_basic_info(int socket)
{
char *response = "HTTP/1.1 200 OK\r\n"
"Content-Type: application/json; charset=UTF-8\r\n\r\n"
"{\"ip_address\":\"192.168.10.247\",\"ip_gateway\":\"192.168.2.22\",\"ip_netmask\":\"255.255.255.0\",\"mac_address\":\"1c:2a:a3:23:00:02\",\"sw_ver\":\"" VERSION_SW "\",\"hw_ver\":\"SWGT024-V2.0\"}";
write(socket, response, strlen(response));
}
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();
if(vlan == 1) {
sprintf(num_buff, "0x%08x", 0x207ffff);
json_object_object_add(v, "members", json_object_new_string(num_buff));
json_object_object_add(v, "name", json_object_new_string("native"));
json_object_object_add(v, "pvid", json_object_new_string("0x01ff"));
} else {
if(mem_vlans[vlan].active) {
json_object_object_add(v, "name", json_object_new_string(mem_vlans[vlan].name));
json_object_object_add(v, "members", json_object_new_string("0x0000"));
json_object_object_add(v, "pvid", json_object_new_string("0x0000"));
}
}
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_vlanlist(int s)
{
struct json_object *v, *vlans, *vlan;
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();
json_object_object_add(v, "mgmt", json_object_new_int(1));
vlans = json_object_new_array_ext(currentVLANCount);
//foreach VLAN
for (int x=1;x<=VLAN_MAX_ID;++x) {
vlan = json_object_new_object();
if(x ==1 || mem_vlans[x].active) {
json_object_object_add(vlan, "id", json_object_new_int(x));
json_object_object_add(vlan, "name", json_object_new_string(mem_vlans[x].name));
json_object_array_add(vlans, vlan);
}
}
json_object_object_add(v, "vlan", vlans);
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 *ports, *v;
const char *jstring;
char *header = "HTTP/1.1 200 OK\r\n"
"Cache-Control: no-cache\r\n"
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
printf("Sending status.\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, "logPort", json_object_new_int(physToLogPort[i-1]));
json_object_object_add(v, "isSFP", json_object_new_int(i <= PORTS - NSFP ? 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%016lx", txG[i-1]);
sprintf(txB_buff, "0x%016lx", txB[i-1]);
sprintf(rxG_buff, "0x%016lx", rxG[i-1]);
sprintf(rxB_buff, "0x%016lx", 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));
uint16_t macs = 0;
for (int e = 0; e < L2_ENTRY_NUM; e++)
if (l2_entries[e].port == physToLogPort[i-1] && l2_entries[e].type != 's')
macs++;
sprintf(macs_buff, "0x%04x", macs);
json_object_object_add(v, "macs", json_object_new_string(macs_buff));
if (i >= PORTS - NSFP) {
uint16_t temp = 0x28fb + rand() / (RAND_MAX / 100);
uint16_t vcc = 0x7eda + rand() / (RAND_MAX / 100);
uint16_t txbias = 0x0d24 +rand() / (RAND_MAX / 100);
uint16_t txpower = 0x14bd + rand() / (RAND_MAX / 100);
uint16_t rxpower = 0;
uint16_t laser = 0;
uint16_t options = 0x68;
sprintf(sfp_options, "0x%02x", options);
sprintf(sfp_temp, "0x%04x", temp);
sprintf(sfp_vcc, "0x%04x", vcc);
sprintf(sfp_txbias, "0x%04x", txbias);
sprintf(sfp_txpower, "0x%04x", txpower);
sprintf(sfp_rxpower, "0x%04x", rxpower);
sprintf(sfp_laser, "0x%04x", laser);
json_object_object_add(v, "sfp_vendor", json_object_new_string("OEM"));
json_object_object_add(v, "sfp_model", json_object_new_string("10G-SFP+"));
json_object_object_add(v, "sfp_serial", json_object_new_string("12345678"));
json_object_object_add(v, "sfp_options", json_object_new_string(sfp_options));
json_object_object_add(v, "sfp_temp", json_object_new_string(sfp_temp));
json_object_object_add(v, "sfp_vcc", json_object_new_string(sfp_vcc));
json_object_object_add(v, "sfp_txbias", json_object_new_string(sfp_txbias));
json_object_object_add(v, "sfp_txpower", json_object_new_string(sfp_txpower));
json_object_object_add(v, "sfp_rxpower", json_object_new_string(sfp_rxpower));
json_object_object_add(v, "sfp_laser", json_object_new_string(sfp_laser));
} else {
if (i == 1)
json_object_object_add(v, "adv", json_object_new_string("100000"));
else if (i==2)
json_object_object_add(v, "adv", json_object_new_string("000011"));
else
json_object_object_add(v, "adv", json_object_new_string("000100"));
}
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);
}
void send_counters(int s, int port)
{
struct json_object *counters;
const char *jstring;
char *header = "HTTP/1.1 200 OK\r\n"
"Cache-Control: no-cache\r\n"
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
printf("Sending counters\n");
counters = json_object_new_array_ext(N_COUNTERS);
for (int i = 0; i < N_COUNTERS; i++) {
sprintf(counter_buf, "0x%016lx", 0x1234UL + i);
json_object_array_add(counters, json_object_new_string(counter_buf));
}
write(s, header, strlen(header));
jstring = json_object_to_json_string_ext(counters, JSON_C_TO_STRING_PLAIN);
write(s, jstring, strlen(jstring));
json_object_put(counters);
}
void send_eee(int s)
{
struct json_object *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";
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));
uint8_t eee = 0;
eee |= 0x02;
char eee_buf[20];
sprintf(eee_buf, "%08b", eee);
json_object_object_add(v, "eee", json_object_new_string(eee_buf));
uint8_t eee_lp = 0;
eee_lp |= 0x04;
sprintf(eee_buf, "%08b", eee_lp);
json_object_object_add(v, "eee_lp", json_object_new_string(eee_buf));
json_object_object_add(v, "active", json_object_new_int((i % 2) ? 1 : 0));
json_object_array_add(ports, v);
}
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(ports);
}
void send_bandwidth(int s)
{
struct json_object *ports, *v;
const char *jstring;
uint32_t bw;
int limited, fcEnabled;
char *header = "HTTP/1.1 200 OK\r\n"
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
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));
if (i % 2) {
limited = 1;
fcEnabled = i % 4 ? 1 : 0;
bw = 0x100;
} else {
limited = 0;
fcEnabled = 0;
bw = 0xfffff;
}
char bw_buf[20];
sprintf(bw_buf, "%08x", bw);
json_object_object_add(v, "iLimited", json_object_new_int(limited));
json_object_object_add(v, "iFC", json_object_new_int(fcEnabled));
json_object_object_add(v, "iBW", json_object_new_string(bw_buf));
if (i % 4) {
limited = 1;
bw = 0x1000;
} else {
limited = 0;
bw = 0xfffff;
}
sprintf(bw_buf, "%08x", bw);
json_object_object_add(v, "eLimited", json_object_new_int(limited));
json_object_object_add(v, "eBW", json_object_new_string(bw_buf));
json_object_array_add(ports, v);
}
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(ports);
}
void send_mirror(int s)
{
uint16_t mirror_tx, mirror_rx = 0;
char mirror_tx_buf[20];
char mirror_rx_buf[20];
struct json_object *mirror;
const char *jstring;
char *header = "HTTP/1.1 200 OK\r\n"
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
mirror = json_object_new_object();
json_object_object_add(mirror, "mPort", json_object_new_int(1));
json_object_object_add(mirror, "enabled", json_object_new_int(1));
mirror_tx = 0b000110;
mirror_rx = 0b000010;
sprintf(mirror_tx_buf, "%016b", mirror_tx);
sprintf(mirror_rx_buf, "%016b", mirror_rx);
json_object_object_add(mirror, "mirror_tx", json_object_new_string(mirror_tx_buf));
json_object_object_add(mirror, "mirror_rx", json_object_new_string(mirror_rx_buf));
write(s, header, strlen(header));
jstring = json_object_to_json_string_ext(mirror, JSON_C_TO_STRING_PLAIN);
write(s, jstring, strlen(jstring));
json_object_put(mirror);
}
void send_l2(int s, int idx)
{
struct json_object *entries, *v;
const char *jstring;
char *header = "HTTP/1.1 200 OK\r\n"
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
entries = json_object_new_array();
// We find the next entry to transfer based on the index
printf("Starting with idx %04x\n", idx);
int j = 0;
while (j < L2_ENTRY_NUM && l2_entries[j].idx < idx)
j++;
printf("First entry %d, idx: %04x\n", j, l2_entries[j].idx);
int transferred = 0;
while ((j < L2_ENTRY_NUM + 1) && (transferred < L2_MAX_TRANSFER)) {
// if (rand() / (RAND_MAX / 2) >= 1)
// continue;
int i = j % L2_ENTRY_NUM;
printf("Entry %d, idx: %04x, transferred %d\n", i, l2_entries[i].idx, transferred);
v = json_object_new_object();
json_object_object_add(v, "mac", json_object_new_string(l2_entries[i].mac));
json_object_object_add(v, "vlan", json_object_new_string(l2_entries[i].vlan));
if (l2_entries[i].type == 'l')
json_object_object_add(v, "type", json_object_new_string("l"));
else
json_object_object_add(v, "type", json_object_new_string("s"));
json_object_object_add(v, "port", json_object_new_int(l2_entries[i].port));
sprintf(l2_idx_buff, "%04x", l2_entries[i].idx);
json_object_object_add(v, "idx", json_object_new_string(l2_idx_buff));
json_object_array_add(entries, v);
j++;
transferred++;
printf("j %d, transferred %d\n", j, transferred);
}
write(s, header, strlen(header));
jstring = json_object_to_json_string_ext(entries, JSON_C_TO_STRING_PLAIN);
write(s, jstring, strlen(jstring));
json_object_put(entries);
}
void send_lag(int s)
{
char lag_buf[20];
struct json_object *lags = json_object_new_array_ext(4);
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";
for (int i = 0; i < 4; i++) {
v = json_object_new_object();
json_object_object_add(v, "lagNum", json_object_new_int(i));
sprintf(lag_buf, "%016b", 0x30 << (i * 2) & 0x1f8);
json_object_object_add(v, "members", json_object_new_string(lag_buf));
json_object_object_add(v, "hash", json_object_new_string("0x7e"));
json_object_array_add(lags, v);
}
write(s, header, strlen(header));
jstring = json_object_to_json_string_ext(lags, JSON_C_TO_STRING_PLAIN);
write(s, jstring, strlen(jstring));
json_object_put(lags);
}
void send_mtu(int s)
{
struct json_object *mtus, *v;
const char *jstring;
char *header = "HTTP/1.1 200 OK\r\n"
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
mtus = json_object_new_array_ext(PORTS);
char mtu[8];
for (int i = 1; i <= PORTS; i++) {
v = json_object_new_object();
json_object_object_add(v, "portNum", json_object_new_int(i));
sprintf(mtu, "0x%04x", i % 2 ? 16383 : 1522);
json_object_object_add(v, "mtu", json_object_new_string(mtu));
json_object_array_add(mtus, v);
}
write(s, header, strlen(header));
jstring = json_object_to_json_string_ext(mtus, JSON_C_TO_STRING_PLAIN);
write(s, jstring, strlen(jstring));
json_object_put(mtus);
}
void send_lldp(int s)
{
struct json_object *c, *portStatuses, *p;
const char *jstring;
char *header = "HTTP/1.1 200 OK\r\n"
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
c = json_object_new_object();
json_object_object_add(c, "on", json_object_new_int(1));
portStatuses = json_object_new_array_ext(PORTS);
for (int i = 1; i <= PORTS; i++) {
p = json_object_new_object();
json_object_object_add(p, "portNum", json_object_new_int(i));
json_object_object_add(p, "logPort", json_object_new_int(i-1));
json_object_object_add(p, "name", json_object_new_string(""));
json_object_object_add(p, "permitted", json_object_new_int(1));
json_object_array_add(portStatuses, p);
}
json_object_object_add(c, "portStatus", portStatuses);
write(s, header, strlen(header));
jstring = json_object_to_json_string_ext(c, JSON_C_TO_STRING_PLAIN);
write(s, jstring, strlen(jstring));
json_object_put(c);
}
void send_cmd_log(int s)
{
char *header = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain; charset=UTF-8\r\n\r\n";
write(s, header, strlen(header));
for (int i = 0; i < cmd_ptr; i++) {
write(s, cmd_history[i], strlen(cmd_history[i]));
write(s, "\n", 1);
printf("%d: %s\n", i, cmd_history[i]);
}
}
void send_config(int s)
{
char *header = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain; charset=UTF-8\r\n\r\n";
printf("Sending uploaded config\n");
write(s, header, strlen(header));
printf("Uploaded config len: %d\n", uploaded_config_len);
printf(">%s<", uploaded_config);
write(s, uploaded_config, uploaded_config_len);
}
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);
}
int reuse = 1;
if (setsockopt(server.socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
perror("setsockopt(SO_REUSEADDR) failed");
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 send_not_found(int socket) {
char *response = "HTTP/1.1 404 Not found\r\n"
"Content-Type: text/html\r\n\r\n"
"<!DOCTYPE html> <html><head><title>Not Found</title></head>"
"<body><h1>Not found!</h1></html>";
write(socket, response, strlen(response));
}
void send_bad_request(int socket) {
char *response = "HTTP/1.1 400 Bad Request\r\n"
"Content-Type: text/html\r\n\r\n"
"<!DOCTYPE html> <html><head><title>Bad Request</title></head>"
"<body><h1>Bad Request!</h1></html>";
write(socket, response, strlen(response));
}
void send_to_login(int socket) {
char *response = "HTTP/1.1 302 Found\r\n"
"Location: login.html\r\n\r\n";
write(socket, response, strlen(response));
}
void send_unauthorized(int socket) {
char *response = "HTTP/1.1 401 Unauthorized\r\n\r\n";
write(socket, response, strlen(response));
}
char *scan_header(char *p)
{
session = 0;
authenticated = false;
while (*p != '\r' || *(p + 1) != '\n' || *(p + 2) != '\r' || *(p + 3) != '\n') {
if (!*p++)
break;
if (is_word(p, "\nContent-Type:"))
content_type = p + 15;
else if (is_word(p, "\nCookie:")) {
session = p + 9;
while (*session == ' ') session++;
const char *s = strstr(session, "session=");
if (s) session = s + 8;
}
}
if (content_type && is_word(content_type, "multipart/form-data; boundary")) {
printf("Found multiplart\n");
content_type += 30;
uint8_t i = 0;
while (content_type[i] != '\r' && content_type[i] != '\n') {
boundary[i + 2] = content_type[i];
i++;
}
// The boundary between parts is "--" + the boundary given in the header
boundary[0] = '-';
boundary[1] = '-';
boundary[i + 2] = 0;
}
time_t now = time(NULL);
if (session) {
printf("Session: >%s<. time now: %ld last %ld\n", session, now, last_session_use);
if (now - last_session_use > SESSION_TIMEOUT) {
printf("Session expired\n");
} else {
if (!strncmp(session, SESSION_ID, 12))
authenticated = true;
else
printf("Invalid session cookie!\n");
}
}
printf("Time now: %ld last %ld\n", now, last_session_use);
return p;
}
char *skip_boundary(char *p)
{
while (*p) {
if (is_word(p, boundary))
return p + strlen(boundary);
p++;
}
return p;
}
void print_cmd_history(void)
{
for (int i = 0; i < cmd_ptr; i++)
printf("%d: %s\n", i, cmd_history[i]);
}
void delete_vlan(int vid) {
mem_vlans[vid] = (struct mem_vlan){};
currentVLANCount--;
}
void parse_cmd(char* cmd)
{
char *token = strtok(cmd, " ");
char *name;
printf("\t OK FIRST TOKEN: '%s'\n",token);
if (!strncmp(token, "vlan", 4)) {
printf("\t OK IT IS VLAN\n");
token = strtok(NULL, " ");
int vid = atoi(token);
if (vid<1 || vid > VLAN_MAX_ID) {
printf("\t REJECT BECAUSE OF VID:%d\n",vid);
return;
}
token = strtok(NULL, " ");
if(!strncmp(token,"mgmt",4)) {
printf("\t MGMT LEAVE:\n");
return; //TODO
} else if (!strncmp(token,"d",1)) {
printf("\t DELETE VID %d:\n",vid);
delete_vlan(vid);
} else {
if (token[0] >= 'A' && token[0] <= 'z' ){
name = token;
token = strtok(NULL, " ");
printf("\tIS NAME %s:\n", name);
}
struct mem_vlan newvlan = {.active=true};
strcpy(newvlan.name, name);
// a string of [0-9][t]?
printf("\t TOKEN: %s:\n", token);
while(token != NULL) {
int portNum = atoi(token);
bool isTagged = token[strlen(token)] == 't';
printf("\tVLAN: %d Name: %s Port: %d tagged:%d\n", vid, name, portNum, isTagged);
token = strtok(NULL, " ");
if(isTagged) {
newvlan.tagged[portNum] = true;
} else {
newvlan.untagged[portNum] = true;
}
}
mem_vlans[vid] = newvlan;
currentVLANCount++;
}
} else {
}
}
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);
printf("bytesRead: %ld\n", bytesRead);
int filesize = 0;
char *mime;
if (bytesRead > 0) {
buffer[bytesRead] = '\0'; // Null terminate the string
puts(buffer);
if (is_word(buffer, "GET")) {
scan_header(buffer);
if (!strncmp(&buffer[4], "/status.json", 12)) {
printf("Status request\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_status(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/eee.json", 9)) {
printf("EEE request\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_eee(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/bandwidth.json", 15)) {
printf("Bandwidth request\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_bandwidth(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/information.json", 17)) {
printf("Status request\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_basic_info(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/mirror.json", 12)) {
printf("Mirror request\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_mirror(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/lag.json", 9)) {
printf("LAG request\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_lag(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/l2.json?idx=", 13)) {
int idx = atoi(&buffer[17]);
printf("L2 request\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_l2(new_socket, idx);
goto done;
} else if (!strncmp(&buffer[4], "/mtu.json", 9)) {
printf("MTU request\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_mtu(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/vlan.json?vid=", 15)) {
int vlan = atoi(&buffer[19]);
printf("VLAN request for %d\n", vlan);
if (!authenticated)
send_unauthorized(new_socket);
else
send_vlan(new_socket, vlan);
goto done;
} else if (!strncmp(&buffer[4], "/vlanlist", 9)) {
printf("request for vlan list");
if (!authenticated)
send_unauthorized(new_socket);
else
send_vlanlist(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/lldp.json", 10)) {
printf("LLDP request");
if (!authenticated)
send_unauthorized(new_socket);
else
send_lldp(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/cmd_log", 8)) {
printf("Request cmd_log\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_cmd_log(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/config ", 8) && uploaded_config) {
printf("Request current config.\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_config(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/counters.json?port=", 20)) {
int port = atoi(&buffer[24]);
printf("Counters request for %d\n", port);
if (!authenticated)
send_unauthorized(new_socket);
else
send_counters(new_socket, port);
goto done;
}
if (!authenticated && !(!strncmp(&buffer[4], "/login.html", 11) || !strncmp(&buffer[4], "/favicon.ico", 12))) {
send_to_login(new_socket);
goto done;
}
// A web-page is actively accessed, we can reset session time-out
last_session_use = time(NULL);
int i = 0;
while (!isspace(buffer[4 + i]))
i++;
buffer[4+i] = '\0';
printf("Serving file: >%s<, name length %d\n", &buffer[5], i);
if (i > 1)
inptr = fopen(&buffer[5], "rb");
else
inptr = fopen("/index.html", "rb");
if (inptr == NULL) {
printf("Cannot open input file %s\n", &buffer[5]);
send_not_found(new_socket);
goto done;
}
mime = getMime(&buffer[5]);
printf("MIME type: %s\n", mime);
fseek(inptr, 0L, SEEK_END);
filesize = ftell(inptr);
printf("Filesize: %d\n", filesize);
rewind(inptr);
printf("Input file size: %d\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);
} else if (is_word(buffer, "POST")) {
printf("POST request\n");
// Find end of request header
char *p = buffer;
boundary[0] ='\0';
p = scan_header(p);
printf("Boundary: >%s<\n", boundary);
if (!*p || !content_type) {
printf("Bad request, no content type!\n");
send_bad_request(new_socket);
goto done;
}
if (!authenticated && !is_word(&buffer[5], "/login")) {
send_unauthorized(new_socket);
goto done;
}
printf("Bytes read %ld\n", bytesRead);
if (is_word(&buffer[5], "/cmd")) {
printf("POST cmd\n");
printf("CMD: %s\n", p + 4);
strcpy(cmd_history[cmd_ptr], p + 4);
printf("\t GOING TO PARSE THIS: %s\n", p+4);
parse_cmd(p+4);
cmd_ptr++;
print_cmd_history();
char *response = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n\r\n"
"<!DOCTYPE html> <html><head><title>Upload OK</title></head>"
"<body><h1>Command executed successully</h1></html>";
write(new_socket, response, strlen(response));
goto done;
} else if (is_word(&buffer[5], "/login")) {
printf("POST login\n");
p += 4;
p += 4; // Read also over "pwd="
char *response;
if (is_word(p, PASSWORD)) {
printf("Password accepted!\n");
response = "HTTP/1.1 302 Found\r\n"
"Location: index.html\r\n"
"Set-Cookie: session=" SESSION_ID "; Path=/; SameSite=Strict\r\n"
"\r\n";
} else {
response = "HTTP/1.1 302 Found\r\n"
"Location: login.html\r\n\r\n";
}
write(new_socket, response, strlen(response));
goto done;
} else if (is_word(&buffer[5], "/upload") || is_word(&buffer[5], "/config")) {
printf("POST upload/config request\n");
bool config_upload = false;
if (is_word(&buffer[5], "/config"))
config_upload = true;
if (!boundary[0]) {
printf("Bad request, no boundary!\n");
send_bad_request(new_socket);
goto done;
}
// We skip the intial parts as part of the header
do {
p = skip_boundary(p);
if (!*p)
goto bad_request;
p = scan_header(p);
if (!*p || !content_type)
goto bad_request;
} while (!is_word(content_type, "application/octet-stream"));
printf("Have content: >%s<\n", content_type);
p += 4; // Skip \r\n\r\n after content type
char *uptr = upload_buffer;
int bindex = 0;
int bptr = p - buffer;
do {
if (bptr >= bytesRead) {
bptr = 0;
bytesRead = read(new_socket, buffer, BUFFER_SIZE - 1);
printf("bytesRead: %ld\n", bytesRead);
if (!bytesRead)
break;
}
if (!boundary[bindex])
break;
if (buffer[bptr] == boundary[bindex]) {
bptr++;
bindex++;
} else {
for (int i = 0; i < bindex; i++)
*uptr++ = boundary[i];
*uptr++ = buffer[bptr++];
bindex = 0;
}
} while(1);
printf("Done reading\n");
printf("%s", upload_buffer);
if (!bindex || boundary[bindex])
goto bad_request;
char *response = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n\r\n"
"<!DOCTYPE html> <html><head><title>Upload OK</title></head>"
"<body><h1>File uploaded successully</h1></html>";
write(new_socket, response, strlen(response));
if (config_upload) {
uploaded_config_len = (uptr - upload_buffer);
if (uploaded_config)
free (uploaded_config);
uploaded_config = malloc(uploaded_config_len + 1);
memcpy(uploaded_config, upload_buffer, uploaded_config_len);
}
goto done;
}
}
char *response = "HTTP/1.1 200 OK\r\n"
"Cache-Control: max-age=60, must-revalidate\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));
if (filesize)
write(new_socket, buffer, filesize);
} else if (bytesRead == 0) {
printf("EOF\n");
continue;
} else {
perror("Error reading buffer, nothing read...\n");
}
done:
close(new_socket);
continue;
bad_request:
printf("Bad request!\n");
send_bad_request(new_socket);
close(new_socket);
}
}
int main()
{
// Make sure we can handle writes to a dead client without a signal handler
signal(SIGPIPE, SIG_IGN);
struct Server server = serverConstructor(8080, launch);
server.launch(&server);
return 0;
}