-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.s
322 lines (233 loc) · 6.39 KB
/
server.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
.include "out/const.s"
// The above includes many constants needed to talk to the OS
// out/const.s is automatically generated by make_const.c
.data
my_addr: .ds sizeof_sockaddr_in
.equ req_buf_size, 1024
req_buf: .ds req_buf_size
current_timeval: .ds sizeof_timeval
.equ current_time_str_size, 16
current_time_str: .ds current_time_str_size
stat_buf: .ds sizeof_stat
.text
.align 2
.global _start
// Gets the address of (writable) memory in the data section
.macro dadr Xn, name
adrp \Xn, \name@page
add \Xn, \Xn, \name@pageoff
.endm
// Performs a syscall by name
.macro sys name
mov x16, SYS_\name
svc 0
.endm
// Socket setup
_start:
// Get listener sock fd
mov x0, PF_INET
mov x1, SOCK_STREAM
mov x2, xzr
sys socket
// Save returned sockfd
mov x10, x0
// Allow reusing address
mov x0, x10
mov x1, SOL_SOCKET
mov x2, SO_REUSEADDR
adr x3, true
mov x4, sizeof_int
sys setsockopt
// Allow reusing port
mov x0, x10
mov x1, SOL_SOCKET
mov x2, SO_REUSEPORT
adr x3, true
mov x4, sizeof_int
sys setsockopt
// Construct sockaddr_in struct for bind
dadr x1, my_addr
mov w9, AF_INET
strb w9, [x1, offsetof_sin_family]
mov w9, htons_PORT
strh w9, [x1, offsetof_sin_port]
mov w9, INADDR_ANY
strb w9, [x1, offsetof_sin_addr]
// Bind port
mov x0, x10
mov x2, sizeof_sockaddr_in
sys bind
// Listen
mov x0, x10
mov x1, 10
sys listen
// Print listening message
mov x0, 1
adr x1, listening_msg
mov x2, listening_msg_len
sys write
// Accept loop
accept_connection:
mov x0, x10
mov x1, xzr
mov x2, xzr
sys accept
// Store fd for this specific connection
mov x11, x0
// Read request
dadr x12, req_buf
mov x0, x11
mov x1, x12
mov x2, req_buf_size
sys read
// Print request to stdout
mov x0, 1
mov x1, x12
mov x2, req_buf_size
sys write
// Match routes and jump to their handlers
adr x0, index_route
adr x1, handle_index
bl match_route
adr x0, time_route
adr x1, handle_time
bl match_route
adr x0, cat_gif_route
adr x1, handle_cat_gif
bl match_route
// If we get here, nothing was matched. Return 404.
adr x1, not_found_response
mov x2, not_found_response_len
bl write_response
b end_response
match_route:
mov x14, 0
match_route_char:
// Load the next request char and expected route char
ldrb w15, [x12, x14]
ldrb w16, [x0, x14]
cmp w16, wzr // check for NUL terminator
b.eq end_of_route
// Compare request and route chars
cmp w15, w16
b.ne route_not_matched
// Char matched
add x14, x14, 1
// Keep looping if we haven't reached the end of the buffer
cmp x14, req_buf_size
b.lt match_route_char
b route_not_matched
end_of_route:
cmp w15, ' '
b.ne route_not_matched
// Route matched, jump to handler
br x1
route_not_matched:
ret
write_response:
mov x0, x11
sys write
ret
end_response:
mov x0, x11
adr x1, newline
mov x2, 1
sys write
// Close connection fd
mov x0, x11
sys close
// Accept another connection
b accept_connection
// Route handlers
handle_index:
adr x1, ok_html_response
mov x2, ok_html_response_len
bl write_response
adr x1, index_response
mov x2, index_response_len
bl write_response
b end_response
handle_time:
dadr x13, current_timeval
mov x0, x13
mov x1, xzr
sys gettimeofday
adr x1, ok_html_response
mov x2, ok_html_response_len
bl write_response
ldr w0, [x13]
dadr x1, current_time_str
mov x4, current_time_str_size
mov x6, 10
digit_to_ascii:
// Extract the last digit
mov x3, x0
udiv x0, x0, x6 // x0 = x0 / 10
msub x5, x0, x6, x3 // x5 = x3 - x0 * 10 (remainder)
// Get the ascii code by adding 0x30
add x5, x5, 0x30
strb w5, [x1, x4]
// Write the response if we've reached the first digit
cmp x0, 1
b.lt write_time_response
// Move pointer to the left
sub x4, x4, 1
b digit_to_ascii
write_time_response:
add x1, x1, x4
mov x3, current_time_str_size + 1
sub x2, x3, x4
bl write_response
b end_response
handle_cat_gif:
adr x1, ok_gif_response
mov x2, ok_gif_response_len
bl write_response
// Open cat.gif
adr x0, cat_gif_path
mov x1, O_RDONLY
sys open
// Get its size using stat
mov x13, x0
dadr x14, stat_buf
mov x1, x14
sys fstat64 // not just fstat! took me a while to figure out
// Let the OS blast the file out the socket
mov x0, x13
mov x1, x11
mov x2, xzr
add x3, x14, offsetof_st_size
mov x4, xzr
mov x5, xzr
sys sendfile // such a cool syscall
mov x0, x13
sys close
b end_response
true: .word 1
zero_offset: .byte 0
.align 4
newline: .ascii "\n"
.align 4
index_route: .asciz "GET /"
.align 4
time_route: .asciz "GET /time"
.align 4
cat_gif_route: .asciz "GET /cat.gif"
.align 4
cat_gif_path: .asciz "cat.gif"
.align 4
not_found_response:
.ascii "HTTP/1.1 404 Not Found\n\r\nNot Found"
not_found_response_len = . - not_found_response
.align 4
ok_html_response:
.ascii "HTTP/1.1 200 OK\nContent-Type: text/html\n\r\n"
ok_html_response_len = . - ok_html_response
.align 4
ok_gif_response:
.ascii "HTTP/1.1 200 OK\nContent-Type: image/gif\n\r\n"
ok_gif_response_len = . - ok_gif_response
.align 4
index_response:
.ascii "<img src=\"cat.gif\"><p>This wonderful cat gif is brought to you by ARM64 assembly.</p><p>Also, check out this dynamic <a href=\"/time\">time page</a>.</p>"
index_response_len = . - index_response