Skip to content

Commit f816fa1

Browse files
tleydxdyFrancesco149
tleydxdy
authored andcommitted
strip more, simplify code, assembly hack, 5328 bytes
1 parent e80f6b4 commit f816fa1

File tree

3 files changed

+104
-155
lines changed

3 files changed

+104
-155
lines changed

build.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
#!/bin/sh
22

33
gcc \
4-
-std=c89 -pedantic \
4+
-pedantic \
55
-Wall -Werror \
66
-s -Os -no-pie \
77
-nostdlib \
88
-ffreestanding \
99
-fno-stack-protector \
1010
-fdata-sections \
11+
-ffunction-sections \
1112
-fno-unwind-tables \
1213
-fno-asynchronous-unwind-tables \
13-
-ffunction-sections \
1414
-Wl,-n \
1515
-Wl,--gc-sections \
1616
-Wl,--build-id=none \
1717
start.S httpd.c \
1818
-o httpd &&
19-
strip -R .comment httpd
19+
strip -R .comment -R .bss httpd

httpd.c

Lines changed: 79 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -7,141 +7,105 @@
77
#define O_RDONLY 0
88

99
typedef unsigned short uint16_t;
10+
typedef unsigned int uint32_t;
11+
typedef unsigned int size_t;
12+
typedef unsigned int socklen_t;
13+
typedef int ssize_t;
1014

1115
/* must be padded to at least 16 bytes */
1216
typedef struct {
1317
uint16_t sin_family; /* 2 */
1418
uint16_t sin_port; /* 4 -> this is in big endian */
15-
int sin_addr; /* 8 */
19+
uint32_t sin_addr; /* 8 */
1620
char sin_zero[8]; /* 16 */
1721
} sockaddr_in_t;
1822

19-
int write(int fd, void* buf, int buf_len);
20-
int read(int fd, void* buf, int buf_len);
23+
ssize_t read(int fd, void *buf, size_t nbyte);
24+
ssize_t write(int fd, const void *buf, size_t nbyte);
25+
int open(const char *path, int flags);
26+
int close(int fd);
2127
int socket(int domain, int type, int protocol);
22-
int bind(int socket, void* address, int address_len);
28+
int accept(int socket, sockaddr_in_t *restrict address,
29+
socklen_t *restrict address_len);
30+
int shutdown(int socket, int how);
31+
int bind(int socket, const sockaddr_in_t *address, socklen_t address_len);
2332
int listen(int socket, int backlog);
24-
int accept(int socket, void* address, int address_len);
25-
int close(int fd);
33+
int setsockopt(int socket, int level, int option_name, const void *option_value,
34+
socklen_t option_len);
2635
int fork();
27-
int setsockopt(int socket, int level, int option_name,
28-
void* val, int val_len);
29-
void exit(int code);
30-
int shutdown(int socket, int how);
31-
int open(char* path, int flags);
36+
void exit(int status);
3237

3338
/* this is fine because forked processes are copy on write */
3439
/* so there shouldn't be any data races */
35-
char http_buf[8192];
40+
static char http_buf[8192];
3641

37-
int strlen(char* s) {
38-
char* p;
39-
for (p = s; *p; ++p);
42+
static size_t strlen(const char *s) {
43+
const char *p = s;
44+
while (*p)
45+
++p;
4046
return p - s;
4147
}
4248

43-
uint16_t swap_uint16(uint16_t x) {
44-
return (
45-
((x << 8) & 0xFF00) |
46-
((x >> 8) & 0x00FF)
47-
);
49+
static uint16_t swap_uint16(uint16_t x) {
50+
return (((x << 8) & 0xFF00) | ((x >> 8) & 0x00FF));
4851
}
4952

50-
#define fprint(fd, s) \
51-
write(fd, s, strlen(s))
53+
#define fprint(fd, s) write(fd, s, strlen(s))
54+
55+
#define fprintn(fd, s, n) write(fd, s, n)
56+
57+
#define fprintl(fd, s) fprintn(fd, s, sizeof(s) - 1)
58+
59+
#define fprintln(fd, s) fprintl(fd, s "\n")
60+
61+
#define print(s) fprint(1, s)
5262

53-
#define fprintln(fd, s) \
54-
fprint(fd, s "\n")
63+
#define printn(s, n) fprintn(1, s, n)
5564

56-
#define print(s) \
57-
fprint(1, s)
65+
#define printl(s) fprintl(1, s)
5866

59-
#define println(s) \
60-
fprintln(1, s)
67+
#define println(s) fprintln(1, s)
6168

6269
#ifdef DEBUG
63-
#define die(s) \
64-
println("FATAL: " s); \
70+
#define die(s) \
71+
println("FATAL: " s); \
6572
exit(1)
6673

67-
#define perror(s) \
68-
println("ERROR: " s)
74+
#define perror(s) println("ERROR: " s)
6975
#else
7076
#define die(s) exit(1)
77+
7178
#define perror(s)
7279
#endif
7380

74-
int tcp_listen(int port) {
81+
static int tcp_listen(int port) {
7582
static int yes = 1;
76-
static sockaddr_in_t addr;
77-
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
78-
if (sock < 0) {
79-
die("socket");
80-
}
81-
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
82-
/* address is zero = any address */
83-
addr.sin_family = AF_INET;
83+
static sockaddr_in_t addr = {AF_INET};
8484
addr.sin_port = swap_uint16(port);
85-
if (bind(sock, &addr, sizeof(addr)) < 0) {
86-
die("bind");
87-
}
88-
if (listen(sock, 10) < 0) {
85+
int sock;
86+
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ||
87+
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) ||
88+
bind(sock, &addr, sizeof(addr)) || listen(sock, 10)) {
8989
die("listen");
9090
}
9191
return sock;
9292
}
9393

94-
/*
95-
* must read the entire request otherwise some clients misbehave
96-
* http request ends with an empty line
97-
* line separator is \r\n but might as well handle \n aswell
98-
*/
99-
100-
int isspace(char c) {
101-
switch (c) {
102-
case '\r':
103-
case ' ':
104-
case '\t':
105-
return 1;
106-
}
107-
return 0;
108-
}
109-
110-
void http_consume(int clientfd) {
94+
static void http_consume(int clientfd) {
11195
int n;
112-
int total = 0;
113-
char* p;
114-
char* buf = http_buf;
115-
char* last_line = buf;
116-
while (1) {
117-
n = read(clientfd, buf, sizeof(http_buf) - (buf - http_buf) - 1);
118-
if (n > 0) {
119-
buf[n] = 0;
120-
buf += n;
121-
total += n;
122-
} else {
123-
if (n < 0) {
124-
perror("read");
125-
}
126-
break;
127-
}
128-
/* iterate lines, look for empty line */
129-
for (p = last_line; p < http_buf + total; ++p) {
130-
for (; *p && isspace(*p); ++p);
131-
if (*p == '\n') {
132-
/* all whitespace line */
133-
write(1, http_buf, total);
134-
return;
135-
}
136-
/* skip rest of the line */
137-
for (; *p && *p != '\n'; ++p);
138-
/* micro optimization: save last line start */
139-
last_line = p;
96+
while ((n = read(clientfd, http_buf, sizeof(http_buf))) > 0) {
97+
printn(http_buf, n);
98+
const char *p = http_buf + (n - 3);
99+
if (n < 3 || (*p == '\n' && *(p + 1) == '\r' && *(p + 2) == '\n')) {
100+
return;
140101
}
141102
}
103+
if (n < 0) {
104+
perror("read");
105+
}
142106
}
143107

144-
void http_drop(int clientfd) {
108+
static void http_drop(int clientfd) {
145109
shutdown(clientfd, SHUT_RDWR);
146110
close(clientfd);
147111
}
@@ -159,40 +123,32 @@ void http_drop(int clientfd) {
159123
* binaries it also makes sense to keep the mem usage low
160124
*/
161125

162-
#define http_code(fd, x) \
163-
fprint(fd, "HTTP/1.1 " x "\r\n\r\n" x);
126+
#define http_code(fd, x) fprintl(fd, "HTTP/1.1 " x "\r\n\r\n" x);
164127

165-
int http_serve(int clientfd, char* file_path) {
166-
int f;
167-
char* buf = http_buf;
128+
static int http_serve(int clientfd, const char *file_path) {
129+
int f, n;
168130
http_consume(clientfd);
169-
fprint(clientfd, "HTTP/1.1 200 OK\r\n\r\n");
170-
f = open(file_path, O_RDONLY);
171-
if (f < 0) {
131+
if ((f = open(file_path, O_RDONLY)) < 0) {
172132
perror("open");
173133
http_code(clientfd, "404 Not Found");
174134
return 1;
175135
}
176-
while (1) {
177-
int n = read(f, buf, sizeof(http_buf));
178-
if (n > 0) {
179-
if (write(clientfd, buf, n) < 0) {
180-
perror("write");
181-
return 1;
182-
}
183-
} else {
184-
if (n < 0) {
185-
perror("read");
186-
}
187-
break;
136+
fprintl(clientfd, "HTTP/1.1 200 OK\r\n\r\n");
137+
while ((n = read(f, http_buf, sizeof(http_buf))) > 0) {
138+
if (write(clientfd, http_buf, n) < 0) {
139+
perror("write");
140+
return 1;
188141
}
189142
}
143+
if (n < 0) {
144+
perror("read");
145+
}
190146
http_drop(clientfd);
191147
return 0;
192148
}
193149

194-
int atoi(char* s) {
195-
int res = 0;
150+
static uint16_t string2port(const char *s) {
151+
uint16_t res = 0;
196152
for (; *s; ++s) {
197153
if (*s > '9' || *s < '0') {
198154
return 0;
@@ -202,38 +158,28 @@ int atoi(char* s) {
202158
return res;
203159
}
204160

205-
void usage(char* self) {
206-
print("usage: ");
161+
static void usage(const char *self) {
162+
printl("usage: ");
207163
print(self);
208164
println(" port file");
209165
exit(1);
210166
}
211167

212-
int main(int argc, char* argv[]) {
168+
int main(int argc, char *argv[]) {
213169
int sock;
214-
int port;
215-
if (argc != 3) {
216-
usage(argv[0]);
217-
}
218-
port = atoi(argv[1]);
219-
if (!port) {
170+
uint16_t port;
171+
if (argc != 3 || (port = string2port(argv[1])) == 0) {
220172
usage(argv[0]);
221173
}
222174
sock = tcp_listen(port);
223175
while (1) {
224-
int pid;
225-
int clientfd = accept(sock, 0, 0);
226-
if (clientfd < 0) {
176+
int pid, clientfd;
177+
if ((clientfd = accept(sock, 0, 0)) < 0) {
227178
perror("accept");
228-
continue;
229-
}
230-
pid = fork();
231-
if (!pid) {
232-
return http_serve(clientfd, argv[2]);
233-
}
234-
if (pid < 0) {
179+
} else if ((pid = fork()) < 0) {
235180
perror("fork");
236-
continue;
181+
} else if (pid == 0) {
182+
return http_serve(clientfd, argv[2]);
237183
}
238184
}
239185
return 0;

start.S

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,37 @@
55
/* ^^^ */
66
/* stack grows from a high address to a low address */
77

8+
#define c(x, n) \
9+
.global x; \
10+
x:; \
11+
add r9,n
12+
13+
c(exit, 3) /* 60 */
14+
c(fork, 3) /* 57 */
15+
c(setsockopt, 4) /* 54 */
16+
c(listen, 1) /* 50 */
17+
c(bind, 1) /* 49 */
18+
c(shutdown, 5) /* 48 */
19+
c(accept, 2) /* 43 */
20+
c(socket, 38) /* 41 */
21+
c(close, 1) /* 03 */
22+
c(open, 1) /* 02 */
23+
c(write, 1) /* 01 */
24+
.global read /* 00 */
25+
read:
26+
827
.global _syscall
928
_syscall:
1029
mov r10,rcx
30+
mov rax,r9
31+
xor r9,r9
1132
syscall
1233
ret
1334

14-
#define c(x, n) \
15-
.global x; \
16-
x:; \
17-
mov eax,n; \
18-
jmp _syscall
19-
20-
c(read, 0)
21-
c(write, 1)
22-
c(open, 2)
23-
c(close, 3)
24-
c(socket, 41)
25-
c(accept, 43)
26-
c(shutdown, 48)
27-
c(bind, 49)
28-
c(listen, 50)
29-
c(setsockopt, 54)
30-
c(fork, 57)
31-
c(exit, 60)
32-
3335
.global _start
3436
_start:
3537
xor rbp,rbp
38+
xor r9,r9
3639
pop rdi /* argc */
3740
mov rsi,rsp /* argv */
3841
call main

0 commit comments

Comments
 (0)