diff --git a/src/c90/metric_client.c b/src/c90/metric_client.c new file mode 100644 index 0000000..7f1a929 --- /dev/null +++ b/src/c90/metric_client.c @@ -0,0 +1,110 @@ +/* metric_client.c - C89/C90 custom binary metric client */ +#include +#include +#include +#include +#include +#include +#include + +#define PORT 9999 +#define BUF_SIZE 1024 + +/* same constants */ +#define MSG_PING 0x01 +#define MSG_PONG 0x02 +#define MSG_METRIC_REQ 0x03 +#define MSG_METRIC_RESP 0x04 +#define MSG_ERROR 0xFF + +#define HEADER_SIZE 3 + +static void send_message(int sock, unsigned char type, const void *payload, unsigned short len) { + unsigned char header[HEADER_SIZE]; + header[0] = type; + header[1] = (len >> 8) & 0xFF; + header[2] = len & 0xFF; + write(sock, header, HEADER_SIZE); + if (len > 0) write(sock, payload, len); +} + +static int recv_exact(int sock, void *buf, int n) { + int total = 0; + while (total < n) { + int r = read(sock, (char*)buf + total, n - total); + if (r <= 0) return -1; + total += r; + } + return total; +} + +static void print_wire_comparison(void) { + printf("\n--- Wire overhead comparison ---\n"); + printf("Our protocol (METRIC_REQ 'cpu'): %d bytes\n", HEADER_SIZE + 3); + printf("Equivalent HTTP GET: 77 bytes\n"); + printf("HTTP is ~13x larger\n\n"); +} + +int main(void) { + int sock; + struct sockaddr_in addr; + unsigned char header[HEADER_SIZE]; + unsigned char payload[BUF_SIZE]; + double val; + char line[256]; + + sock = socket(AF_INET, SOCK_STREAM, 0); + addr.sin_family = AF_INET; + addr.sin_port = htons(PORT); + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); + + if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + perror("connect"); + exit(1); + } + + printf("Connected to 127.0.0.1:%d\n", PORT); + print_wire_comparison(); + + printf("Commands: ping | get | quit\nMetrics: cpu, memory, disk, loadavg, uptime\n\n"); + + while (1) { + printf("> "); + if (fgets(line, sizeof(line), stdin) == NULL) break; + line[strcspn(line, "\n")] = '\0'; + + if (strcmp(line, "quit") == 0) break; + if (strcmp(line, "ping") == 0) { + send_message(sock, MSG_PING, NULL, 0); + } else if (strncmp(line, "get ", 4) == 0) { + const char *metric = line + 4; + send_message(sock, MSG_METRIC_REQ, metric, strlen(metric)); + } else { + printf(" Unknown command.\n"); + continue; + } + + /* blocking receive */ + if (recv_exact(sock, header, HEADER_SIZE) != HEADER_SIZE) break; + unsigned char type = header[0]; + unsigned short len = (header[1] << 8) | header[2]; + + if (len > 0) { + if (recv_exact(sock, payload, len) != len) break; + } + + if (type == MSG_PONG) { + printf(" [PONG] server alive\n"); + } else if (type == MSG_METRIC_RESP) { + memcpy(&val, payload, sizeof(double)); + printf(" [METRIC] %.2f\n", val); + } else if (type == MSG_ERROR) { + payload[len] = '\0'; + printf(" [ERROR] %s\n", payload); + } + } + + close(sock); + printf("Disconnected.\n"); + return 0; +} \ No newline at end of file diff --git a/src/c90/metric_server.c b/src/c90/metric_server.c new file mode 100644 index 0000000..0cbb457 --- /dev/null +++ b/src/c90/metric_server.c @@ -0,0 +1,112 @@ +/* metric_server.c - C89/C90 custom binary metric server */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 9999 +#define BACKLOG 5 +#define BUF_SIZE 1024 + +/* Protocol constants (same as Python) */ +#define MSG_PING 0x01 +#define MSG_PONG 0x02 +#define MSG_METRIC_REQ 0x03 +#define MSG_METRIC_RESP 0x04 +#define MSG_ERROR 0xFF + +/* Header: 1 byte type + 2 bytes length (big-endian) */ +#define HEADER_SIZE 3 + +static double get_metric(const char *name) { + if (strcmp(name, "cpu") == 0) return 5.0 + (rand() % 9000)/100.0; + if (strcmp(name, "memory") == 0) return 30.0 + (rand() % 5000)/100.0; + if (strcmp(name, "disk") == 0) return 40.0 + (rand() % 5000)/100.0; + if (strcmp(name, "loadavg") == 0) return 0.5 + (rand() % 350)/100.0; + if (strcmp(name, "uptime") == 0) return (double)(time(NULL) % 100000); + return -1.0; /* error */ +} + +static void send_message(int sock, unsigned char type, const void *payload, unsigned short len) { + unsigned char header[HEADER_SIZE]; + header[0] = type; + header[1] = (len >> 8) & 0xFF; /* big-endian */ + header[2] = len & 0xFF; + write(sock, header, HEADER_SIZE); + if (len > 0) write(sock, payload, len); +} + +static int recv_exact(int sock, void *buf, int n) { + int total = 0; + while (total < n) { + int r = read(sock, (char*)buf + total, n - total); + if (r <= 0) return -1; + total += r; + } + return total; +} + +static void handle_client(int client_sock) { + unsigned char header[HEADER_SIZE]; + unsigned char payload[BUF_SIZE]; + + while (1) { + if (recv_exact(client_sock, header, HEADER_SIZE) != HEADER_SIZE) break; + + unsigned char type = header[0]; + unsigned short len = (header[1] << 8) | header[2]; + + if (len > 0) { + if (recv_exact(client_sock, payload, len) != len) break; + } + + if (type == MSG_PING) { + send_message(client_sock, MSG_PONG, NULL, 0); + } else if (type == MSG_METRIC_REQ) { + payload[len] = '\0'; /* null-terminate */ + double val = get_metric((char*)payload); + if (val < 0) { + const char *err = "Unknown metric"; + send_message(client_sock, MSG_ERROR, err, strlen(err)); + } else { + send_message(client_sock, MSG_METRIC_RESP, &val, sizeof(double)); + } + } else { + const char *err = "Unknown message type"; + send_message(client_sock, MSG_ERROR, err, strlen(err)); + } + } + close(client_sock); +} + +int main(void) { + int srv, client; + struct sockaddr_in addr; + + srand(time(NULL)); + + srv = socket(AF_INET, SOCK_STREAM, 0); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(PORT); + + bind(srv, (struct sockaddr*)&addr, sizeof(addr)); + listen(srv, BACKLOG); + + printf("Metric server listening on port %d (C89 version)\n", PORT); + printf("Metrics: cpu, memory, disk, loadavg, uptime\n\n"); + + while (1) { + client = accept(srv, NULL, NULL); + printf("[+] Client connected\n"); + handle_client(client); + printf("[-] Client disconnected\n"); + } + + close(srv); + return 0; +} \ No newline at end of file diff --git a/src/c90/metric_server_fork.c b/src/c90/metric_server_fork.c new file mode 100644 index 0000000..b125dbe --- /dev/null +++ b/src/c90/metric_server_fork.c @@ -0,0 +1,166 @@ +/* metric_server_fork.c - C89/C90 multi-client metric server using fork() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 9999 +#define BACKLOG 10 +#define BUF_SIZE 1024 + +/* Protocol constants (identical to Python version) */ +#define MSG_PING 0x01 +#define MSG_PONG 0x02 +#define MSG_METRIC_REQ 0x03 +#define MSG_METRIC_RESP 0x04 +#define MSG_ERROR 0xFF + +#define HEADER_SIZE 3 + +static double get_metric(const char *name) +{ + if (strcmp(name, "cpu") == 0) return 5.0 + (rand() % 9000)/100.0; + if (strcmp(name, "memory") == 0) return 30.0 + (rand() % 5000)/100.0; + if (strcmp(name, "disk") == 0) return 40.0 + (rand() % 5000)/100.0; + if (strcmp(name, "loadavg") == 0) return 0.5 + (rand() % 350)/100.0; + if (strcmp(name, "uptime") == 0) return (double)(time(NULL) % 100000); + return -1.0; /* unknown metric */ +} + +static void send_message(int sock, unsigned char type, + const void *payload, unsigned short len) +{ + unsigned char header[HEADER_SIZE]; + header[0] = type; + header[1] = (len >> 8) & 0xFF; /* big-endian */ + header[2] = len & 0xFF; + write(sock, header, HEADER_SIZE); + if (len > 0) + write(sock, payload, len); +} + +static int recv_exact(int sock, void *buf, int n) +{ + int total = 0; + while (total < n) { + int r = read(sock, (char *)buf + total, n - total); + if (r <= 0) return -1; + total += r; + } + return total; +} + +static void handle_client(int client_sock, struct sockaddr_in *addr) +{ + unsigned char header[HEADER_SIZE]; + unsigned char payload[BUF_SIZE]; + char client_ip[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, &addr->sin_addr, client_ip, sizeof(client_ip)); + printf("[+] Connected from %s:%d\n", client_ip, ntohs(addr->sin_port)); + + while (1) { + if (recv_exact(client_sock, header, HEADER_SIZE) != HEADER_SIZE) + break; + + unsigned char type = header[0]; + unsigned short len = (header[1] << 8) | header[2]; + + if (len > 0) { + if (recv_exact(client_sock, payload, len) != len) + break; + } + + if (type == MSG_PING) { + printf(" <- PING from %s\n", client_ip); + send_message(client_sock, MSG_PONG, NULL, 0); + } + else if (type == MSG_METRIC_REQ) { + payload[len] = '\0'; + double val = get_metric((char *)payload); + printf(" <- METRIC_REQ '%s' from %s\n", (char *)payload, client_ip); + if (val < 0.0) { + const char *err = "Unknown metric"; + send_message(client_sock, MSG_ERROR, err, strlen(err)); + } else { + send_message(client_sock, MSG_METRIC_RESP, &val, sizeof(double)); + } + } + else { + const char *err = "Unknown message type"; + send_message(client_sock, MSG_ERROR, err, strlen(err)); + } + } + + close(client_sock); + printf("[-] Disconnected from %s\n", client_ip); +} + +int main(void) +{ + int srv_sock, client_sock; + struct sockaddr_in server_addr, client_addr; + socklen_t client_len = sizeof(client_addr); + pid_t pid; + + srand(time(NULL)); + + /* Classic Unix trick to reap children automatically (no zombies) */ + signal(SIGCHLD, SIG_IGN); + + srv_sock = socket(AF_INET, SOCK_STREAM, 0); + if (srv_sock < 0) { + perror("socket"); + exit(1); + } + + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(PORT); + + if (bind(srv_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("bind"); + exit(1); + } + + if (listen(srv_sock, BACKLOG) < 0) { + perror("listen"); + exit(1); + } + + printf("Metric server (fork() model) listening on port %d\n", PORT); + printf("Available metrics: cpu, memory, disk, loadavg, uptime\n"); + printf("(You can now run multiple clients at the same time!)\n\n"); + + while (1) { + client_sock = accept(srv_sock, (struct sockaddr *)&client_addr, &client_len); + if (client_sock < 0) { + if (errno == EINTR) continue; + perror("accept"); + continue; + } + + pid = fork(); + if (pid < 0) { /* fork failed */ + perror("fork"); + close(client_sock); + } + else if (pid == 0) { /* CHILD process */ + close(srv_sock); /* child does not need the listening socket */ + handle_client(client_sock, &client_addr); + exit(0); + } + else { /* PARENT process */ + close(client_sock); /* parent does not need the client socket */ + } + } + + close(srv_sock); + return 0; +} \ No newline at end of file diff --git a/src/python/__init__.py b/src/python/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/echo_client.py b/src/python/echo_client.py similarity index 100% rename from src/echo_client.py rename to src/python/echo_client.py diff --git a/src/echo_server.py b/src/python/echo_server.py similarity index 100% rename from src/echo_server.py rename to src/python/echo_server.py diff --git a/src/metric_client.py b/src/python/metric_client.py similarity index 100% rename from src/metric_client.py rename to src/python/metric_client.py diff --git a/src/metric_server.py b/src/python/metric_server.py similarity index 100% rename from src/metric_server.py rename to src/python/metric_server.py diff --git a/src/mon_client.py b/src/python/mon_client.py similarity index 100% rename from src/mon_client.py rename to src/python/mon_client.py diff --git a/src/mon_server.py b/src/python/mon_server.py similarity index 100% rename from src/mon_server.py rename to src/python/mon_server.py