commit 2b570ac
uint
·
2026-01-25 18:24:30 +0000 UTC
parent f45ea23
refactor + improve saftey on http server, create config.h
5 files changed,
+169,
-25
M
LICENCE
+1,
-1
1@@ -1,6 +1,6 @@
2 ISC License
3
4-Copyright 2025 uint
5+Copyright 2026 uint
6
7 Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
8
M
Makefile
+9,
-7
1@@ -1,15 +1,17 @@
2-CC=cc
3+CC ?= cc
4
5-CPPFLAGS=
6-CFLAGS= -std=c99 -Wall -Wextra -O2 -Iserver/include
7-
8-DAE=paradosd
9+CPPFLAGS =
10+CFLAGS = -std=c99 -Wall -Wextra -O2 -Iserver/include
11+OUT = parados
12
13 all: parados
14
15 parados:
16- $(CC) server/*.c -o $(DAE)
17+ $(CC) server/*.c -o $(OUT)
18+
19+clean:
20+ rm -f $(OUT)
21
22-clangd:
23+compile_flags:
24 rm -f compile_flags.txt
25 for f in ${CPPFLAGS} ${CFLAGS}; do echo $$f >> compile_flags.txt; done
D
paradosd
+0,
-0
+13,
-0
1@@ -0,0 +1,13 @@
2+#include <stdbool.h>
3+
4+static const char* media_dir = "/path/to/media";
5+static const char* server_addr = "127.0.0.1";
6+static const int server_port = 3579;
7+static const bool verbose_log = false;
8+
9+enum {
10+ HTTP_REQ_MAX = 2048,
11+ HTTP_RESP_MAX = 512,
12+ LISTEN_BACKLOG = 64,
13+};
14+
+146,
-17
1@@ -1,3 +1,5 @@
2+#include <errno.h>
3+#include <stddef.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7@@ -7,9 +9,16 @@
8 #include <arpa/inet.h>
9 #include <netinet/in.h>
10
11-#define PORT 6767
12+#include "config.h"
13
14 void die(const char* s, int e);
15+int read_reqline(int c, char* method, size_t msz, char* path, size_t psz);
16+void reply_text(int c, const char* status, const char* body);
17+void run(void);
18+void setup(void);
19+int write_all(int fd, const void* buf, size_t n);
20+
21+int sock;
22
23 void die(const char* s, int e)
24 {
25@@ -17,43 +26,163 @@ void die(const char* s, int e)
26 exit(e);
27 }
28
29-int main(void)
30+int read_reqline(int c, char* method, size_t msz, char* path, size_t psz)
31+{
32+ char buf[HTTP_REQ_MAX];
33+ size_t used = 0;
34+
35+ for (;;) {
36+ if (used + 1 >= sizeof(buf))
37+ return -1;
38+
39+ ssize_t r = read(c, buf + used, sizeof(buf) - 1 - used);
40+ if (r <= 0)
41+ return -1;
42+
43+ used += (size_t)r;
44+ buf[used] = '\0';
45+
46+ char* eol = strstr(buf, "\r\n");
47+ if (eol) {
48+ *eol = '\0';
49+ break;
50+ }
51+ }
52+
53+ if (sscanf(buf, "%15s %1023s", method, path) != 2)
54+ return -1;
55+
56+ method[msz-1] = '\0';
57+ path[psz-1] = '\0';
58+
59+ return 0;
60+}
61+
62+void reply_text(int c, const char* status, const char* body)
63+{
64+ char resp[HTTP_RESP_MAX];
65+ int n = snprintf(
66+ resp, sizeof(resp),
67+
68+ "%s"
69+ "Content-Type: text/plain\r\n"
70+ "Content-Length: %zu\r\n"
71+ "Connection: close\r\n"
72+ "\r\n"
73+ "%s",
74+
75+ status,
76+ strlen(body), body
77+ );
78+
79+ if (n < 0)
80+ return;
81+
82+ if ((size_t)n >= sizeof(resp))
83+ n = (int)(sizeof(resp) - 1);
84+
85+ (void)write_all(c, resp, (size_t)n);
86+}
87+
88+void run(void)
89+{
90+ for (;;) {
91+ int c = accept(sock, NULL, NULL);
92+ if (c < 0) {
93+ if (errno == EINTR)
94+ continue;
95+ continue;
96+ }
97+
98+ char method[16];
99+ char path[1024];
100+
101+ if (read_reqline(c, method, sizeof(method), path, sizeof(path)) < 0) {
102+ reply_text(c, "HTTP/1.1 400 Bad Request\r\n", "bad request\n");
103+ shutdown(c, SHUT_WR);
104+ close(c);
105+ continue;
106+ }
107+
108+ if (strcmp(method, "GET") != 0) {
109+ reply_text(c, "HTTP/1.1 405 Method Not Allowed\r\n", "method not allowed\n");
110+ shutdown(c, SHUT_WR);
111+ close(c);
112+ continue;
113+ }
114+
115+ if (strcmp(path, "/ping") == 0) {
116+ reply_text(c, "HTTP/1.1 200 OK\r\n", "ok\n");
117+ shutdown(c, SHUT_WR);
118+ close(c);
119+ continue;
120+ }
121+
122+ reply_text(c, "HTTP/1.1 404 Not Found\r\n", "not found\n");
123+ shutdown(c, SHUT_WR);
124+ close(c);
125+ }
126+}
127+
128+void setup(void)
129 {
130 int ret = 1;
131- int s = socket(AF_INET, SOCK_STREAM, 0);
132- if (s < 0)
133+ sock = socket(AF_INET, SOCK_STREAM, 0);
134+ if (sock < 0)
135 die("socket", EXIT_FAILURE);
136
137 int yes = 1;
138- ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
139+ ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
140 if (ret < 0)
141 die("setsockopt", EXIT_FAILURE);
142
143 struct sockaddr_in a;
144 memset(&a, 0, sizeof(a));
145 a.sin_family = AF_INET;
146- a.sin_port = htons(PORT);
147- a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
148+ a.sin_port = htons(server_port);
149+ ret = inet_pton(AF_INET, server_addr, &a.sin_addr);
150+ if (ret != 1)
151+ die("inet_pton", EXIT_FAILURE);
152
153- ret = bind(s, (struct sockaddr*)&a, sizeof(a));
154+ ret = bind(sock, (struct sockaddr*)&a, sizeof(a));
155 if (ret < 0)
156 die("bind", EXIT_FAILURE);
157
158- ret = listen(s, 64);
159+ ret = listen(sock, LISTEN_BACKLOG);
160 if (ret < 0)
161 die("listen", EXIT_FAILURE);
162
163- printf("listening on 127.0.0.1:%d\n", PORT);
164+ if (verbose_log)
165+ printf("listening on %s:%d\n", server_addr, server_port);
166+}
167
168- for (;;) {
169- int c = accept(s, NULL, NULL);
170- if (c < 0)
171- continue;
172+int write_all(int fd, const void* buf, size_t n)
173+{
174+ const char* p = buf;
175
176- (void)write(c, "hello\n", 6);
177- shutdown(c, SHUT_WR);
178- close(c);
179+ while (n > 0) {
180+ ssize_t w = write(fd, p, n);
181+ if (w < 0) {
182+ if (errno == EINTR)
183+ continue;
184+ return -1;
185+ }
186+
187+ p += (size_t)w;
188+ n -= (size_t)w;
189 }
190
191+ return 0;
192+}
193+
194+int main(void)
195+{
196+ setup();
197+#ifdef __OpenBSD__
198+ if (pledge("stdio inet", NULL) < 0)
199+ die("pledge", EXIT_FAILURE);
200+#endif
201+ run();
202 return EXIT_SUCCESS;
203 }
204+