mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
Moving the global on/off onto the LLDP page Building a table of LLDP status from the S ports. Later on, if we wish to implement an lldp receiver we can display the remote details here Adding support to the cmd parser for the lldp commands
936 lines
28 KiB
C
936 lines
28 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
|
|
|
|
#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 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 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();
|
|
|
|
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 *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));
|
|
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)
|
|
{
|
|
char *header = "HTTP/1.1 200 OK\r\n"
|
|
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
|
|
|
char *body = "{\"on\": true, \"port_status\":[true,true,false,true,true,true,true,false,false]}";
|
|
|
|
write(s, header, strlen(header));
|
|
write(s, body, strlen(body));
|
|
}
|
|
|
|
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 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], "/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);
|
|
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;
|
|
}
|