7
7
#define O_RDONLY 0
8
8
9
9
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 ;
10
14
11
15
/* must be padded to at least 16 bytes */
12
16
typedef struct {
13
17
uint16_t sin_family ; /* 2 */
14
18
uint16_t sin_port ; /* 4 -> this is in big endian */
15
- int sin_addr ; /* 8 */
19
+ uint32_t sin_addr ; /* 8 */
16
20
char sin_zero [8 ]; /* 16 */
17
21
} sockaddr_in_t ;
18
22
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 );
21
27
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 );
23
32
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 );
26
35
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 );
32
37
33
38
/* this is fine because forked processes are copy on write */
34
39
/* so there shouldn't be any data races */
35
- char http_buf [8192 ];
40
+ static char http_buf [8192 ];
36
41
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 ;
40
46
return p - s ;
41
47
}
42
48
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 ));
48
51
}
49
52
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)
52
62
53
- #define fprintln (fd , s ) \
54
- fprint(fd, s "\n")
63
+ #define printn (s , n ) fprintn(1, s, n)
55
64
56
- #define print (s ) \
57
- fprint(1, s)
65
+ #define printl (s ) fprintl(1, s)
58
66
59
- #define println (s ) \
60
- fprintln(1, s)
67
+ #define println (s ) fprintln(1, s)
61
68
62
69
#ifdef DEBUG
63
- #define die (s ) \
64
- println("FATAL: " s); \
70
+ #define die (s ) \
71
+ println("FATAL: " s); \
65
72
exit(1)
66
73
67
- #define perror (s ) \
68
- println("ERROR: " s)
74
+ #define perror (s ) println("ERROR: " s)
69
75
#else
70
76
#define die (s ) exit(1)
77
+
71
78
#define perror (s )
72
79
#endif
73
80
74
- int tcp_listen (int port ) {
81
+ static int tcp_listen (int port ) {
75
82
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 };
84
84
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 )) {
89
89
die ("listen" );
90
90
}
91
91
return sock ;
92
92
}
93
93
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 ) {
111
95
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 ;
140
101
}
141
102
}
103
+ if (n < 0 ) {
104
+ perror ("read" );
105
+ }
142
106
}
143
107
144
- void http_drop (int clientfd ) {
108
+ static void http_drop (int clientfd ) {
145
109
shutdown (clientfd , SHUT_RDWR );
146
110
close (clientfd );
147
111
}
@@ -159,40 +123,32 @@ void http_drop(int clientfd) {
159
123
* binaries it also makes sense to keep the mem usage low
160
124
*/
161
125
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);
164
127
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 ;
168
130
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 ) {
172
132
perror ("open" );
173
133
http_code (clientfd , "404 Not Found" );
174
134
return 1 ;
175
135
}
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 ;
188
141
}
189
142
}
143
+ if (n < 0 ) {
144
+ perror ("read" );
145
+ }
190
146
http_drop (clientfd );
191
147
return 0 ;
192
148
}
193
149
194
- int atoi ( char * s ) {
195
- int res = 0 ;
150
+ static uint16_t string2port ( const char * s ) {
151
+ uint16_t res = 0 ;
196
152
for (; * s ; ++ s ) {
197
153
if (* s > '9' || * s < '0' ) {
198
154
return 0 ;
@@ -202,38 +158,28 @@ int atoi(char* s) {
202
158
return res ;
203
159
}
204
160
205
- void usage (char * self ) {
206
- print ("usage: " );
161
+ static void usage (const char * self ) {
162
+ printl ("usage: " );
207
163
print (self );
208
164
println (" port file" );
209
165
exit (1 );
210
166
}
211
167
212
- int main (int argc , char * argv []) {
168
+ int main (int argc , char * argv []) {
213
169
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 ) {
220
172
usage (argv [0 ]);
221
173
}
222
174
sock = tcp_listen (port );
223
175
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 ) {
227
178
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 ) {
235
180
perror ("fork" );
236
- continue ;
181
+ } else if (pid == 0 ) {
182
+ return http_serve (clientfd , argv [2 ]);
237
183
}
238
184
}
239
185
return 0 ;
0 commit comments