3 | ;
4 | ;This file is part of asmttpd.
5 | ;
6 | ;asmttpd is free software: you can redistribute it and/or modify
7 | ;it under the terms of the GNU General Public License as published by
8 | ;the Free Software Foundation, either version 2 of the License, or
9 | ;(at your option) any later version.
10 | ;
11 | ;asmttpd is distributed in the hope that it will be useful,
12 | ;but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ;GNU General Public License for more details.
15 | ;
16 | ;You should have received a copy of the GNU General Public License
17 | ;along with asmttpd. If not, see .
18 |
19 | struc sockaddr_in
20 | sin_family: resw 1
21 | sin_port: resw 1
22 | sin_addr: resd 1
23 | endstruc
24 |
25 | sa: istruc sockaddr_in
26 | at sin_family, dw AF_INET
27 | at sin_port, dw 0
28 | at sin_addr, dd 0 ;INADDR_ANY
29 | iend
30 |
31 | request_type dq 0
32 | request_offset dq 0
33 |
34 | timeval: ;struct
35 | tv_sec dq 0
36 | tv_usec dq 0
37 | sigaction: ;struct
38 | sa_handler dq 0
39 | sa_flags dq SA_RESTORER ; also dq, because padding
40 | sa_restorer dq 0
41 | sa_mask dq 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
42 |
43 | dir_ent_pointer dq 0
44 | dir_ent_size dq 0
45 |
46 | ;Strings
47 | in_enter db "In Enter:",0x00
48 | in_enter_len equ $ - in_enter
49 | in_exit db "In Exit:", 0x00
50 | in_exit_len equ $ - in_exit
51 | new_line db 0x0a
52 | start_text db "asmttpd - ",ASMTTPD_VERSION,0x0a,0x00
53 | start_text_len equ $ - start_text
54 | msg_bind_error db "Error - Bind() failed. Check if port is in use or you have sufficient privileges.",0x00
55 | msg_bind_error_len equ $ - msg_bind_error
56 | msg_error db "An error has occured, exiting",0x00
57 | msg_error_len equ $ - msg_error
58 | msg_help db "Usage: ./asmttpd /path/to/directory port",0x00
59 | msg_help_len equ $ - msg_help
60 | msg_not_a_directory dd "Error: Specified document root is not a directory",0x00
61 | msg_not_a_directory_len equ $ - msg_not_a_directory
62 | msg_request_log db 0x0a,"Request: ",0x00
63 | msg_request_log_len equ $ - msg_request_log
64 |
65 | header_range_search db "Range: ",0x00
66 | header_range_search_len equ $ - header_range_search
67 |
68 | location db "Location: ",0x00
69 |
70 | find_bytes_range db "bytes=",0x00
71 | find_bytes_range_len equ $ - find_bytes_range
72 |
73 | filter_prev_dir db "../",0x00
74 | filter_prev_dir_len equ $ - filter_prev_dir
75 |
76 | crlfx2 db 0x0d,0x0a,0x0d,0x0a,0x00
77 | crlfx2_len equ $ - crlfx2
78 |
79 | crlf db 0x0d,0x0a,0x00
80 | crlf_len equ $ - crlf
81 |
82 | char_slash db "/",0x00
83 | char_hyphen db "-",0x00
84 |
85 | ;HTTP
86 | http_200 db "HTTP/1.1 200 OK",0x0d,0x0a,0x00
87 | http_200_len equ $ - http_200
88 | http_206 db "HTTP/1.1 206 Partial Content",0x0d,0x0a,0x00
89 | http_206_len equ $ - http_206
90 | http_301 db "HTTP/1.1 301 Moved Permanently",0x0d,0x0a,0x00
91 | http_301_len equ $ - http_301
92 | http_404 db "HTTP/1.1 404 Not Found",0x0d,0x0a,0x00
93 | http_404_len equ $ - http_404
94 | http_404_text db "I'm sorry, Dave. I'm afraid I can't do that. 404 Not Found",0x00
95 | http_404_text_len equ $ - http_404_text
96 | http_400 db "HTTP/1.1 400 Bad Request",0x0d,0x0a,0x00
97 | http_400_len equ $ - http_400
98 | http_413 db "HTTP/1.1 413 Request Entity Too Large",0x0d,0x0a,0x00
99 | http_413_len equ $ - http_413
100 | http_416 db "HTTP/1.1 416 Requested Range Not Satisfiable",0x0d,0x0a,0x00
101 | http_416_len equ $ - http_416
102 |
103 | server_header db "Server: asmttpd/",ASMTTPD_VERSION,0x0d,0x0a,0x00
104 | server_header_len equ $ - server_header
105 |
106 | range_header db "Accept-Ranges: bytes",0x0d,0x0a,0x00
107 | range_header_len equ $ - range_header
108 |
109 | content_range db "Content-Range: bytes ",0x00
110 | content_range_len equ $ - content_range ;Content-Range: bytes 200-1000/3000
111 |
112 | content_length db "Content-Length: ",0x00 ;Content-Length: 800
113 | content_length_len equ $ - content_length
114 |
115 | connection_header db "Connection: close",0x0d,0x0a,0x00
116 | connection_header_len equ $ - connection_header
117 |
118 | content_type db "Content-Type: ",0x00
119 | content_type_len equ $ - content_type
120 |
121 | ;Content-Type
122 | content_type_html db "text/html",0x0d,0x0a,0x00
123 | content_type_html_len equ $ - content_type_html
124 |
125 | content_type_octet_stream db "application/octet-stream",0x0d,0x0a,0x00
126 | content_type_octet_stream_len equ $ - content_type_octet_stream
127 |
128 | content_type_xhtml db "application/xhtml+xml",0x0d,0x0a,0x00
129 | content_type_xhtml_len equ $ - content_type_xhtml
130 |
131 | content_type_xml db "text/xml",0x0d,0x0a,0x00
132 | content_type_xml_len equ $ - content_type_xml
133 |
134 | content_type_javascript db "application/javascript",0x0d,0x0a,0x00
135 | content_type_javascript_len equ $ - content_type_javascript
136 |
137 | content_type_css db "text/css",0x0d,0x0a,0x00
138 | content_type_css_len equ $ - content_type_css
139 |
140 | content_type_jpeg db "image/jpeg",0x0d,0x0a,0x00
141 | content_type_jpeg_len equ $ - content_type_jpeg
142 |
143 | content_type_png db "image/png",0x0d,0x0a,0x00
144 | content_type_png_len equ $ - content_type_png
145 |
146 | content_type_gif db "image/gif",0x0d,0x0a,0x00
147 | content_type_gif_len equ $ - content_type_gif
148 |
149 | content_type_svg db "image/svg+xml",0x0d,0x0a,0x00
150 | content_type_svg_len equ $ - content_type_svg
151 |
152 | content_type_txt db "text/plain",0x0d,0x0a,0x00
153 | content_type_txt_len equ $ - content_type_txt
154 |
155 | default_document db "/index.html",0x00
156 | default_document_len equ $ - default_document
157 |
158 | ;Content extension
159 | extension_html db ".html",0x00
160 | extension_htm db ".htm" ,0x00
161 | extension_javascript db ".js", 0x00
162 | extension_css db ".css", 0x00
163 | extension_xhtml db ".xhtml",0x00
164 | extension_xml db ".xml",0x00
165 | extension_gif db ".gif",0x00
166 | extension_jpg db ".jpg",0x00
167 | extension_jpeg db ".jpeg",0x00
168 | extension_png db ".png",0x00
169 | extension_svg db ".svg",0x00
170 | extension_txt db ".txt",0x00
171 |
172 | ; dir listing
173 | http_200_dir_list_open_h1_tag db "Index of ",0x00
174 | http_200_dir_list_close_h1_tag db "
",0x00
175 | http_dir_entry_open_a_tag_pre db '',0x00
177 | http_dir_entry_close_a_tag db '
',0x00
178 |
--------------------------------------------------------------------------------
/debug.asm:
--------------------------------------------------------------------------------
1 | ;asmttpd - Web server for Linux written in amd64 assembly.
2 | ;Copyright (C) 2014 nemasu
3 | ;
4 | ;This file is part of asmttpd.
5 | ;
6 | ;asmttpd is free software: you can redistribute it and/or modify
7 | ;it under the terms of the GNU General Public License as published by
8 | ;the Free Software Foundation, either version 2 of the License, or
9 | ;(at your option) any later version.
10 | ;
11 | ;asmttpd is distributed in the hope that it will be useful,
12 | ;but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ;GNU General Public License for more details.
15 | ;
16 | ;You should have received a copy of the GNU General Public License
17 | ;along with asmttpd. If not, see .
18 |
19 | ;hint, use these with GDB
20 | ;set follow-fork-mode child
21 |
22 | section .bss
23 | printbuffer: resb 1024;debug
24 |
25 | section .text
26 | print_rdi:
27 |
28 | stackpush
29 | push rax
30 | push rbx
31 | push rcx
32 |
33 |
34 | call get_number_of_digits
35 | mov rcx, rax ;
36 |
37 | inc rax ;include NL char in length
38 | push rax; save length for syscall
39 |
40 | ;add lf
41 | mov rdx, 0xa
42 | mov [printbuffer+rcx], dl
43 | dec rcx
44 |
45 | mov rax, rdi ; value to print
46 | xor rdx, rdx ; zero other half
47 | mov rbx, 10
48 |
49 | print_rdi_start:
50 | xor rdx, rdx ; zero other half
51 | div rbx ; divide by 10
52 |
53 | add rdx, 0x30
54 | mov [printbuffer+rcx], dl
55 | dec rcx
56 | cmp rax, 9
57 | ja print_rdi_start
58 |
59 | add rax, 0x30 ;last digit
60 | mov [printbuffer+rcx], al
61 |
62 | pop rcx ;restore original length
63 |
64 | mov rdi, printbuffer
65 | mov rsi, rcx
66 | call sys_write
67 |
68 | pop rcx
69 | pop rbx
70 | pop rax
71 | stackpop
72 | ret
73 |
74 |
--------------------------------------------------------------------------------
/dirent.asm:
--------------------------------------------------------------------------------
1 | ;asmttpd - Web server for Linux written in amd64 assembly.
2 | ;Copyright (C) 2014 nemasu
3 | ;
4 | ;This file is part of asmttpd.
5 | ;
6 | ;asmttpd is free software: you can redistribute it and/or modify
7 | ;it under the terms of the GNU General Public License as published by
8 | ;the Free Software Foundation, either version 2 of the License, or
9 | ;(at your option) any later version.
10 | ;
11 | ;asmttpd is distributed in the hope that it will be useful,
12 | ;but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ;GNU General Public License for more details.
15 | ;
16 | ;You should have received a copy of the GNU General Public License
17 | ;along with asmttpd. If not, see .
18 |
19 | ; d_inode = off + 0
20 | ; d_offset = off + 8
21 | ; d_reclen = off + 16
22 | ; d_name = off + 18
23 | ; null byte
24 | ; d_type = reclen - 1
25 |
26 | ; Get total number of getdents entries
27 | get_dir_ents_number: ;ret rax entries
28 | stackpush
29 |
30 | xor rax, rax
31 | xor rcx, rcx ; hold offset to current reclen entry
32 | xor rbx, rbx ; hold total number of entries read
33 | xor rdx, rdx ; hold total reclen bytes read
34 | mov rcx, 16 ; point to first reclen offset
35 |
36 | read_dir_ents_reclen:
37 | mov rsi, [dir_ent_pointer] ; points to linux_dirents buffer
38 | add rsi, rcx
39 | lodsw ; ax now contains length of current entry
40 | inc rbx
41 | add rcx, rax
42 | add rdx, rax
43 | cmp rdx, [dir_ent_size]
44 | jne read_dir_ents_reclen
45 |
46 | mov rax, rbx
47 | stackpop
48 | ret
49 |
50 | ; Add a list of HTML formatted entries into a buffer
51 | generate_dir_entries: ;rdi - buffer, ret - rax length of string in buffer
52 | stackpush
53 | ; Add heading
54 | mov rsi, http_200_dir_list_open_h1_tag
55 | call string_concat
56 | ; Add // into heading contents
57 | mov rsi, [rbp-16]
58 | add rsi, r9
59 | call string_concat
60 | mov rsi, [directory_path]
61 | call string_remove
62 | ; Close heading
63 | mov rsi, http_200_dir_list_close_h1_tag
64 | call string_concat
65 |
66 | mov rsi, crlf
67 | call string_concat
68 |
69 | xor rcx, rcx ; hold offset to current reclen entry
70 | xor rbx, rbx ; hold total number of entries read
71 | xor rdx, rdx ; hold total reclen bytes read
72 | mov rcx, 16 ; point to first reclen offset
73 |
74 | read_dir_ents:
75 | mov rsi, [dir_ent_pointer] ; points to linux_dirents buffer
76 | add rsi, rcx
77 | lodsw ; ax now contains length of current entry
78 | inc rbx
79 | add rcx, rax
80 | add rdx, rax
81 |
82 | ; ignore the '.' entry
83 | cmp word[rsi], 0x002e
84 | je read_dir_ents_end
85 |
86 | mov rbx, rsi
87 | push rbx ; save for second time
88 |
89 | push rsi
90 | mov rsi, http_dir_entry_open_a_tag_pre
91 | call string_concat
92 | pop rsi
93 |
94 | call string_concat ; add name, prepend with request dir
95 |
96 | cmp word[rbx], 0x2e2e ; check for '..'
97 | jne finish_link_tag
98 | push rsi
99 | mov rsi, char_slash
100 | call string_concat
101 | pop rsi
102 |
103 | finish_link_tag:
104 | push rsi
105 | mov rsi, http_dir_entry_open_a_tag_post
106 | call string_concat
107 | pop rsi
108 |
109 | pop rbx
110 | mov rsi, rbx
111 | call string_concat ; add name again
112 |
113 | push rsi
114 | mov rsi, http_dir_entry_close_a_tag
115 | call string_concat
116 | pop rsi
117 |
118 | read_dir_ents_end:
119 | cmp rdx, [dir_ent_size]
120 | jne read_dir_ents
121 |
122 | call get_string_length
123 | stackpop
124 | ret
125 |
--------------------------------------------------------------------------------
/http.asm:
--------------------------------------------------------------------------------
1 | ;asmttpd - Web server for Linux written in amd64 assembly.
2 | ;Copyright (C) 2014 nemasu
3 | ;
4 | ;This file is part of asmttpd.
5 | ;
6 | ;asmttpd is free software: you can redistribute it and/or modify
7 | ;it under the terms of the GNU General Public License as published by
8 | ;the Free Software Foundation, either version 2 of the License, or
9 | ;(at your option) any later version.
10 | ;
11 | ;asmttpd is distributed in the hope that it will be useful,
12 | ;but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ;GNU General Public License for more details.
15 | ;
16 | ;You should have received a copy of the GNU General Public License
17 | ;along with asmttpd. If not, see .
18 |
19 | ;This writes the text after "Content-Type: " at rsi
20 | detect_content_type: ;rdi - pointer to buffer that contains request, ret - rax: type flag
21 | stackpush
22 |
23 | mov rsi, extension_htm
24 | call string_ends_with
25 | mov r10, CONTENT_TYPE_HTML
26 | cmp rax, 1
27 | je detect_content_type_ret
28 |
29 | mov rsi, extension_html
30 | call string_ends_with
31 | mov r10, CONTENT_TYPE_HTML
32 | cmp rax, 1
33 | je detect_content_type_ret
34 |
35 | mov rsi, extension_css
36 | call string_ends_with
37 | mov r10, CONTENT_TYPE_CSS
38 | cmp rax, 1
39 | je detect_content_type_ret
40 |
41 | mov rsi, extension_javascript
42 | call string_ends_with
43 | mov r10, CONTENT_TYPE_JAVASCRIPT
44 | cmp rax, 1
45 | je detect_content_type_ret
46 |
47 | mov rsi, extension_xhtml
48 | call string_ends_with
49 | mov r10, CONTENT_TYPE_XHTML
50 | cmp rax, 1
51 | je detect_content_type_ret
52 |
53 | mov rsi, extension_xml
54 | call string_ends_with
55 | mov r10, CONTENT_TYPE_XML
56 | cmp rax, 1
57 | je detect_content_type_ret
58 |
59 | mov rsi, extension_gif
60 | call string_ends_with
61 | mov r10, CONTENT_TYPE_GIF
62 | cmp rax, 1
63 | je detect_content_type_ret
64 |
65 | mov rsi, extension_png
66 | call string_ends_with
67 | mov r10, CONTENT_TYPE_PNG
68 | cmp rax, 1
69 | je detect_content_type_ret
70 |
71 | mov rsi, extension_jpeg
72 | call string_ends_with
73 | mov r10, CONTENT_TYPE_JPEG
74 | cmp rax, 1
75 | je detect_content_type_ret
76 |
77 | mov rsi, extension_jpg
78 | call string_ends_with
79 | mov r10, CONTENT_TYPE_JPEG
80 | cmp rax, 1
81 | je detect_content_type_ret
82 |
83 | mov rsi, extension_svg
84 | call string_ends_with
85 | mov r10, CONTENT_TYPE_SVG
86 | cmp rax, 1
87 | je detect_content_type_ret
88 |
89 | mov rsi, extension_txt
90 | call string_ends_with
91 | mov r10, CONTENT_TYPE_TXT
92 | cmp rax, 1
93 | je detect_content_type_ret
94 |
95 | mov r10, CONTENT_TYPE_OCTET_STREAM ; default to octet-stream
96 | detect_content_type_ret:
97 | mov rax, r10
98 | stackpop
99 | ret
100 |
101 | add_content_type_header: ;rdi - pointer to buffer, rsi - type
102 | stackpush
103 |
104 | mov r10, rsi
105 |
106 | mov rsi, content_type
107 | call string_concat
108 |
109 | cmp r10, CONTENT_TYPE_HTML
110 | je add_response_html
111 | cmp r10, CONTENT_TYPE_OCTET_STREAM
112 | je add_response_octet_stream
113 | cmp r10, CONTENT_TYPE_CSS
114 | je add_response_css
115 | cmp r10, CONTENT_TYPE_JAVASCRIPT
116 | je add_response_javascript
117 | cmp r10, CONTENT_TYPE_XHTML
118 | je add_response_xhtml
119 | cmp r10, CONTENT_TYPE_XML
120 | je add_response_xml
121 | cmp r10, CONTENT_TYPE_GIF
122 | je add_response_gif
123 | cmp r10, CONTENT_TYPE_PNG
124 | je add_response_png
125 | cmp r10, CONTENT_TYPE_JPEG
126 | je add_response_jpeg
127 | cmp r10, CONTENT_TYPE_SVG
128 | je add_response_svg
129 | cmp r10, CONTENT_TYPE_TXT
130 | je add_response_txt
131 |
132 | jmp add_response_octet_stream
133 |
134 | add_response_html:
135 | mov rsi, content_type_html
136 | call string_concat
137 | jmp add_response_cont
138 |
139 | add_response_octet_stream:
140 | mov rsi, content_type_octet_stream
141 | call string_concat
142 | jmp add_response_cont
143 |
144 | add_response_css:
145 | mov rsi, content_type_css
146 | call string_concat
147 | jmp add_response_cont
148 |
149 | add_response_javascript:
150 | mov rsi, content_type_javascript
151 | call string_concat
152 | jmp add_response_cont
153 |
154 | add_response_xhtml:
155 | mov rsi, content_type_xhtml
156 | call string_concat
157 | jmp add_response_cont
158 |
159 | add_response_xml:
160 | mov rsi, content_type_xml
161 | call string_concat
162 | jmp add_response_cont
163 |
164 | add_response_gif:
165 | mov rsi, content_type_gif
166 | call string_concat
167 | jmp add_response_cont
168 |
169 | add_response_png:
170 | mov rsi, content_type_png
171 | call string_concat
172 | jmp add_response_cont
173 |
174 | add_response_jpeg:
175 | mov rsi, content_type_jpeg
176 | call string_concat
177 | jmp add_response_cont
178 |
179 | add_response_svg:
180 | mov rsi, content_type_svg
181 | call string_concat
182 | jmp add_response_cont
183 |
184 | add_response_txt:
185 | mov rsi, content_type_txt
186 | call string_concat
187 | jmp add_response_cont
188 |
189 |
190 | add_response_cont:
191 | stackpop
192 | ret
193 |
194 | create_httpError_response: ;rdi - pointer, rsi - error code: 400, 416, 413
195 | stackpush
196 |
197 | cmp rsi, 416
198 | je create_httpError_response_416
199 | cmp rsi, 413
200 | je create_httpError_response_413
201 |
202 | ;garbage/default is 400
203 | mov rsi, http_400
204 | mov rdx, http_400_len
205 | call string_copy
206 | jmp create_httpError_response_cont
207 |
208 | create_httpError_response_416:
209 | mov rsi, http_416
210 | mov rdx, http_416_len
211 | call string_copy
212 | jmp create_httpError_response_cont
213 |
214 | create_httpError_response_413:
215 | mov rsi, http_413
216 | mov rdx, http_413_len
217 | call string_copy
218 | jmp create_httpError_response_cont
219 |
220 | create_httpError_response_cont:
221 | mov rsi, server_header
222 | call string_concat
223 |
224 | mov rsi, connection_header
225 | call string_concat
226 |
227 | mov rsi, crlfx2
228 | call string_concat
229 |
230 | call get_string_length
231 |
232 | stackpop
233 | ret
234 |
235 |
236 | create_http206_response: ;rdi - pointer, rsi - from, rdx - to, r10 - total r9 - type
237 | ; looks like Content-Length: `rdx subtract rsi add 1`
238 | ; Content-Range: bytes rsi-rdx/r10
239 | stackpush
240 |
241 | push rsi
242 | push rdx
243 |
244 | mov rsi, http_206 ; copy first one
245 | mov rdx, http_206_len
246 | call string_copy
247 |
248 | mov rsi, server_header
249 | call string_concat
250 |
251 | mov rsi, connection_header
252 | call string_concat
253 |
254 | mov rsi, range_header
255 | call string_concat
256 |
257 | mov rsi, r9
258 | call add_content_type_header
259 |
260 | mov rsi, content_length
261 | call string_concat
262 |
263 | pop rdx
264 | pop rsi
265 | push rsi
266 |
267 | mov r8, rdx
268 | sub r8, rsi
269 | inc r8 ; inc cause 'to' is zero based
270 | mov rsi, r8
271 |
272 | call string_concat_int
273 |
274 | mov rsi, crlf
275 | call string_concat
276 |
277 | mov rsi, content_range
278 | call string_concat
279 |
280 | pop rsi
281 | call string_concat_int
282 |
283 | mov rsi, char_hyphen
284 | call string_concat
285 |
286 | mov rsi, rdx
287 | call string_concat_int
288 |
289 | mov rsi, char_slash
290 | call string_concat
291 |
292 | mov rsi, r10 ; val
293 | call string_concat_int
294 |
295 | mov rsi, crlfx2
296 | call string_concat
297 |
298 | call get_string_length
299 | jmp create_http206_response_ret
300 |
301 | create_http206_response_fail:
302 | mov rax, 0
303 | stackpop
304 | ret
305 |
306 | create_http206_response_ret:
307 | stackpop
308 | ret
309 |
310 | create_http200_response: ;rdi - pointer to buffer, rsi - type, rdx - length
311 | stackpush
312 |
313 | push rdx ; save length
314 |
315 | mov r10, rsi ;type
316 |
317 | mov rsi, http_200 ;First one we copy
318 | mov rdx, http_200_len
319 | call string_copy
320 |
321 | mov rsi, server_header
322 | call string_concat
323 |
324 | ;mov rsi, connection_header
325 | ;call string_concat
326 |
327 | mov rsi, range_header
328 | call string_concat
329 |
330 | mov rsi, content_length
331 | call string_concat
332 |
333 | pop rsi ; length
334 | call string_concat_int
335 |
336 | mov rsi, crlf
337 | call string_concat
338 |
339 | mov rsi, r10
340 | call add_content_type_header
341 |
342 | mov rsi, crlf
343 | call string_concat
344 |
345 | call get_string_length
346 |
347 | stackpop
348 | ret
349 |
350 | create_http404_response: ;rdi - pointer to buffer
351 | stackpush
352 |
353 | mov rsi, http_404 ;First one we copy
354 | mov rdx, http_404_len
355 | call string_copy
356 |
357 | mov rsi, server_header
358 | call string_concat
359 |
360 | mov rsi, connection_header
361 | call string_concat
362 |
363 | mov rsi, crlf
364 | call string_concat
365 |
366 | mov rsi, http_404_text
367 | call string_concat
368 |
369 | mov rsi, crlf
370 | call string_concat
371 |
372 | call get_string_length
373 |
374 | stackpop
375 | ret
376 |
377 | create_http301_response: ;rdi - pointer to buffer
378 | stackpush
379 |
380 | mov rsi, http_301 ;First one we copy
381 | mov rdx, http_301_len
382 | call string_copy
383 |
384 | mov rsi, server_header
385 | call string_concat
386 |
387 | mov rsi, r10
388 | call add_content_type_header
389 |
390 | mov rsi, connection_header
391 | call string_concat
392 |
393 | mov rsi, location
394 | call string_concat
395 |
396 | ; Remove directory path (web_root) from buffer
397 | mov rsi, [rbp-16]
398 | add rsi, r9
399 | call string_concat
400 | mov rsi, [directory_path]
401 | call string_remove
402 |
403 | mov rsi, char_slash
404 | call string_concat
405 |
406 | mov rsi, crlf
407 | call string_concat
408 |
409 | call get_string_length
410 |
411 | stackpop
412 | ret
413 |
414 | get_request_type: ;rdi - pointer to buffer, ret = rax: request type
415 | stackpush
416 |
417 | cld
418 | mov r10, -1
419 | mov rsi, rdi
420 | find_request_string:
421 | inc r10
422 | lodsb
423 | cmp al, 0x20
424 | jne find_request_string
425 | mov rax, r10
426 | add rax, 0x03
427 | mov [request_offset], rax
428 |
429 | mov rax, REQ_UNK
430 |
431 | check_get:
432 | cmp byte[rdi+0], 0x47
433 | jne check_head
434 | cmp byte[rdi+1], 0x45
435 | jne check_head
436 | cmp byte[rdi+2], 0x54
437 | jne check_head
438 | mov rax, REQ_GET
439 |
440 | check_head:
441 | cmp byte[rdi+0], 0x48
442 | jne request_type_return
443 | cmp byte[rdi+1], 0x45
444 | jne request_type_return
445 | cmp byte[rdi+2], 0x41
446 | jne request_type_return
447 | cmp byte[rdi+3], 0x44
448 | jne request_type_return
449 | mov rax, REQ_HEAD
450 |
451 | request_type_return:
452 | stackpop
453 | ret
454 |
--------------------------------------------------------------------------------
/macros.asm:
--------------------------------------------------------------------------------
1 | ;asmttpd - Web server for Linux written in amd64 assembly.
2 | ;Copyright (C) 2014 nemasu
3 | ;
4 | ;This file is part of asmttpd.
5 | ;
6 | ;asmttpd is free software: you can redistribute it and/or modify
7 | ;it under the terms of the GNU General Public License as published by
8 | ;the Free Software Foundation, either version 2 of the License, or
9 | ;(at your option) any later version.
10 | ;
11 | ;asmttpd is distributed in the hope that it will be useful,
12 | ;but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ;GNU General Public License for more details.
15 | ;
16 | ;You should have received a copy of the GNU General Public License
17 | ;along with asmttpd. If not, see .
18 |
19 | ; Simple Macros
20 | %macro stackpush 0
21 | push rdi
22 | push rsi
23 | push rdx
24 | push r10
25 | push r8
26 | push r9
27 | push rbx
28 | push rcx
29 | %endmacro
30 |
31 | %macro stackpop 0
32 | pop rcx
33 | pop rbx
34 | pop r9
35 | pop r8
36 | pop r10
37 | pop rdx
38 | pop rsi
39 | pop rdi
40 | %endmacro
41 |
42 |
--------------------------------------------------------------------------------
/main.asm:
--------------------------------------------------------------------------------
1 | ;asmttpd - Web server for Linux written in amd64 assembly.
2 | ;Copyright (C) 2014 nemasu
3 | ;
4 | ;This file is part of asmttpd.
5 | ;
6 | ;asmttpd is free software: you can redistribute it and/or modify
7 | ;it under the terms of the GNU General Public License as published by
8 | ;the Free Software Foundation, either version 2 of the License, or
9 | ;(at your option) any later version.
10 | ;
11 | ;asmttpd is distributed in the hope that it will be useful,
12 | ;but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ;GNU General Public License for more details.
15 | ;
16 | ;You should have received a copy of the GNU General Public License
17 | ;along with asmttpd. If not, see .
18 |
19 | %include "constants.asm"
20 | %include "macros.asm"
21 |
22 | %define ASMTTPD_VERSION "0.4.7"
23 |
24 | %define THREAD_COUNT 10 ; Number of worker threads
25 |
26 | ;Following amd64 syscall standards for internal function calls: rdi rsi rdx r10 r8 r9
27 |
28 | section .data
29 | %include "data.asm"
30 |
31 | section .bss
32 | %include "bss.asm"
33 |
34 | section .text
35 | %include "string.asm"
36 | %include "http.asm"
37 | %include "syscall.asm"
38 | %include "dirent.asm"
39 | ;%include "mutex.asm"
40 | ;%include "debug.asm"
41 |
42 | global _start
43 |
44 | _start:
45 |
46 | mov QWORD [one_constant], 1
47 |
48 | mov rdi, start_text
49 | mov rsi, start_text_len
50 | call print_line
51 |
52 | mov rdi, [rsp] ;Num of args
53 | cmp rdi,3 ;Exit if no argument, should be directory location
54 | jne exit_with_help
55 |
56 | mov rdi, [rsp+16+8]; Port (second) parameter
57 | call string_atoi
58 | xchg al, ah
59 | mov [listen_port], eax
60 |
61 | mov rax, [rsp+16] ;Directory (first) parameter
62 | mov [directory_path], rax
63 |
64 | ; Register signal handlers ( just close all other threads by jumping to SYS_EXIT_GROUP )
65 | mov r10, 8 ; sizeof(sigset_t) displays 128, but strace shows 8 ... so 8 it is! -_-
66 | xor rdx, rdx
67 | mov QWORD [sa_handler], exit
68 | mov rsi, sigaction
69 | mov rdi, SIGINT
70 | mov rax, SYS_RT_SIGACTION
71 | syscall
72 | mov rdi, SIGTERM
73 | mov rax, SYS_RT_SIGACTION
74 | syscall
75 | mov QWORD [sa_handler], SIGIGN
76 | mov rdi, SIGPIPE
77 | mov rax, SYS_RT_SIGACTION
78 | syscall
79 |
80 | ;Try opening directory
81 | mov rdi, [directory_path]
82 | mov rdx, OPEN_DIRECTORY
83 | call sys_open_directory
84 |
85 | cmp rax, 0
86 | jl exit_with_no_directory_error
87 |
88 | ;Create socket
89 | call sys_create_tcp_socket
90 | cmp rax, 0
91 | jl exit_error
92 | mov [listen_socket], rax
93 |
94 | ;reuseaddr
95 | mov rdi, [listen_socket]
96 | call sys_reuse
97 |
98 | ;Bind to port
99 | call sys_bind_server
100 | cmp rax, 0
101 | jl exit_bind_error
102 |
103 | ;Start listening
104 | call sys_listen
105 |
106 | ;Create threads
107 | mov r10, THREAD_COUNT
108 |
109 | thread_pool_setup:
110 | push r10
111 |
112 | mov rdi, worker_thread
113 | xor rsi, rsi
114 | call sys_clone
115 |
116 | pop r10
117 | dec r10
118 | cmp r10, 0
119 |
120 | jne thread_pool_setup
121 |
122 | main_thread:
123 |
124 |
125 | mov rdi, 10
126 | call sys_sleep
127 |
128 | jmp main_thread
129 |
130 | worker_thread:
131 |
132 | mov rbp, rsp
133 | sub rsp, 16
134 | ;Offsets: 8 - socket fd, 16 - buffer
135 |
136 | mov QWORD [rbp-16], 0 ; Used for pointer to recieve buffer
137 |
138 | mov rdi, THREAD_BUFFER_SIZE+2+URL_LENGTH_LIMIT+DIRECTORY_LENGTH_LIMIT+DIRECTORY_LIST_BUFFER+CUSTOM_CONTENT_BUFFER ; Allow room to append null, and to create path
139 | call sys_mmap_mem
140 | mov QWORD [rbp-16], rax
141 |
142 | worker_thread_start:
143 |
144 | call sys_accept
145 |
146 | mov [rbp-8], rax ; save fd
147 |
148 | mov rdi, rax
149 | call sys_cork ; cork it
150 |
151 | worker_thread_continue:
152 |
153 | ;HTTP Stuff starts here
154 | mov rdi, QWORD [rbp-8] ;fd
155 | mov rsi, [rbp-16] ;buffer
156 | mov rdx, THREAD_BUFFER_SIZE ;size
157 | call sys_recv
158 |
159 | cmp rax, 0
160 | jle worker_thread_close
161 |
162 | push rax ; save original received length
163 |
164 | ;stackpush
165 | ;push rax
166 | ;mov rdi, rsi
167 | ;mov rsi, rax
168 | ;call print_line ; debug
169 | ;pop rax
170 | ;stackpop
171 |
172 | ; add null
173 | mov rdi, [rbp-16]
174 | add rdi, rax
175 | mov BYTE [rdi], 0x00
176 |
177 | ;Make sure its a valid request
178 | mov rdi, [rbp-16]
179 | mov rsi, crlfx2
180 | call string_ends_with
181 | cmp rax, 1
182 | jne worker_thread_400_response
183 |
184 | mov rdi, [rbp-16]
185 | call get_request_type
186 | mov [request_type], rax
187 | cmp BYTE [request_type], REQ_UNK
188 | je worker_thread_400_response
189 |
190 | ;Find request
191 | mov rax, 0x2F ; '/' character
192 | mov rdi, [rbp-16] ;scan buffer
193 | mov rcx, -1 ;Start count
194 | cld ;Increment rdi
195 | repne scasb
196 | jne worker_thread_400_response
197 | mov rax, -2
198 | sub rax, rcx ;Get the length
199 |
200 | mov r8, rax ; start offset for requested file
201 | mov rdi, [rbp-16]
202 | add rdi, r8
203 | mov rax, 0x20 ;'space' character
204 | mov rcx, -1
205 | cld
206 | repne scasb
207 | jne worker_thread_400_response
208 | mov rax, -1
209 | sub rax, rcx
210 | mov r9, rax
211 | add r9, r8 ;end offset
212 |
213 | pop r11 ; restore orig recvd length
214 | mov rdi, [rbp-16]
215 | add rdi, r11 ; end of buffer, lets use it!
216 | mov r12, r11 ; keeping count
217 |
218 | mov rsi, [directory_path]
219 | xor r15, r15 ; Make sure directory path does not exceed DIRECTORY_LENGTH_LIMIT
220 |
221 | worker_thread_append_directory_path:
222 | inc r15
223 | cmp r15, DIRECTORY_LENGTH_LIMIT
224 | je worker_thread_400_response
225 | lodsb
226 | stosb
227 | inc r12
228 | cmp al, 0x00
229 | jne worker_thread_append_directory_path
230 |
231 | dec r12 ; get rid of 0x00
232 |
233 | ;Check if default document needed
234 | cmp r9, [request_offset] ; Offset of document requested
235 | jne no_default_document
236 | mov rsi, default_document
237 | mov rdi, [rbp-16]
238 | add rdi, r12
239 | mov rcx, default_document_len
240 | add r12, rcx
241 | rep movsb
242 | mov r9, r11 ; saving offset into a stack saved register
243 | jmp worker_thread_remove_pre_dir
244 |
245 | no_default_document:
246 |
247 | ; Adds the file to the end of buffer ( where we juts put the document prefix )
248 | mov rsi, [rbp-16]
249 | add rsi, r8 ; points to beginning of path
250 | mov rdi, [rbp-16]
251 | add rdi, r12 ;go to end of buffer
252 | mov rcx, r9
253 | sub rcx, r8
254 | cmp rcx, URL_LENGTH_LIMIT ; Make sure this does not exceed URL_PATH_LENGTH
255 | jg worker_thread_400_response
256 | add r12, rcx
257 | rep movsb
258 |
259 | dec r12 ; exclude space character
260 | mov rdi, [rbp-16]
261 | add rdi, r12
262 | mov BYTE [rdi], 0x00 ; add null
263 |
264 | mov r9, r11 ; saving offset into a stack saved register
265 | ; [rbp-16] + r9 now holds string for file opening
266 |
267 | worker_thread_remove_pre_dir:
268 |
269 | ;-----Simple request logging
270 | ;mov rdi, msg_request_log
271 | ;mov rsi, msg_request_log_len
272 | ;call sys_write
273 | ;mov rdi, [rbp-16]
274 | ;add rdi, r9
275 | ;call get_string_length
276 | ;mov rsi, rax
277 | ;call print_line
278 | ;-----End Simple logging
279 | mov rdi, [rbp-16]
280 | add rdi, r9
281 | mov rsi, filter_prev_dir ; remove any '../'
282 | call string_remove
283 | cmp rax, 0
284 | jne worker_thread_remove_pre_dir
285 |
286 |
287 | mov rdi, [rbp-16]
288 | add rdi, r9
289 | call detect_content_type
290 | mov r8, rax ;r8: Content Type
291 |
292 | cmp r8, CONTENT_TYPE_OCTET_STREAM
293 | jne worker_thread_response
294 |
295 | worker_thread_test_dir:
296 | mov rdi, [rbp-16]
297 | add rdi, r9
298 | mov rdx, OPEN_RDONLY | OPEN_DIRECTORY
299 | call sys_open_directory
300 | cmp rax, 0
301 | jl worker_thread_response ; TODO error cannot open dir - 404?
302 |
303 | ; Check if request ends in '/' and if not respond 301, which in turn triggers another request with a trailing '/'
304 | push rax
305 | mov rdi, [rbp-16]
306 | add rdi, r9
307 | call get_string_length
308 | add rdi, rax
309 | dec rdi
310 | cmp byte[rdi], 0x2f
311 | jne worker_thread_301_response
312 | pop rax
313 |
314 | mov rbx, THREAD_BUFFER_SIZE+2+URL_LENGTH_LIMIT+DIRECTORY_LENGTH_LIMIT
315 | mov rsi, [rbp-16]
316 | add rsi, rbx
317 | push r9 ; Save pointer to http buffer
318 | mov r9, rsi ; Pointer to dir list buffer, first entry contains bytes read
319 |
320 | mov rdi, rax ; fd
321 | mov rdx, DIRECTORY_LIST_BUFFER
322 | call sys_get_dir_listing
323 | cmp rax, 0 ; rax = bytes read
324 | jl worker_thread_response ; TODO error no bytes read - 404?
325 |
326 | mov [dir_ent_pointer], r9
327 | mov [dir_ent_size], rax
328 |
329 | pop r9
330 | jmp worker_thread_200_response_dir_list
331 |
332 | worker_thread_response:
333 |
334 | ;Try to open requested file
335 | mov rdi, [rbp-16]
336 | add rdi, r9
337 | call sys_open
338 | cmp rax, 0
339 |
340 | jl worker_thread_404_response ;file not found, so 404
341 | ; Done with buffer offsets, put response and data into it starting at beg
342 | mov r10, rax ; r10: file fd
343 |
344 | ;Determine if request requires a 206 response
345 |
346 | mov rdi, r10 ; fd
347 | xor rsi, rsi
348 | mov rdx, LSEEK_END
349 | call sys_lseek
350 | push rax
351 |
352 | ;Basically if "Range:" is in the header
353 | mov rdi, [rbp-16]
354 | mov rsi, header_range_search
355 | call string_contains
356 |
357 | pop rdi
358 | cmp rax, -1
359 | jne worker_thread_206_response
360 |
361 | jmp worker_thread_200_response ;else, we're good to go
362 |
363 | ;---------404 Response Start-------------
364 | worker_thread_404_response:
365 |
366 | mov rdi, [rbp-16]
367 | call create_http404_response
368 |
369 | ;Send response
370 | mov rdi, [rbp-8]
371 | mov rsi, [rbp-16]
372 | mov rdx, rax
373 | call sys_send
374 |
375 | ;and exit
376 | jmp worker_thread_close
377 | ;---------404 Response End--------------
378 |
379 | ;---------301 Response Start-------------
380 | worker_thread_301_response:
381 |
382 | mov rdi, [rbp-16]
383 | mov r10, CONTENT_TYPE_HTML
384 | call create_http301_response
385 |
386 | ;Send response
387 | mov rdi, [rbp-8]
388 | mov rsi, [rbp-16]
389 | mov rdx, rax
390 | call sys_send
391 |
392 | ;and exit
393 | jmp worker_thread_close
394 | ;---------301 Response End--------------
395 |
396 | ;---------206 Response Start------------
397 | worker_thread_206_response:
398 | ; r8: content type , r10: fd, rax: Range: start
399 |
400 | push r10
401 | push r8
402 |
403 | mov r8, rdi ; r8 now size
404 |
405 | ;Seek to beg of file
406 | mov rdi, r10 ; fd
407 | mov rsi, 0
408 | mov rdx, LSEEK_SET
409 | call sys_lseek
410 |
411 | ; find 'bytes='
412 | mov rdi, [rbp-16]
413 | add rdi, rax
414 | mov rsi, find_bytes_range
415 | call string_contains
416 | cmp rax, -1
417 | je worker_thread_400_response
418 |
419 | add rdi, rax
420 | add rdi, 6 ; go to number
421 |
422 | push rdi ; save beg of first number
423 |
424 | mov rax, 0
425 | create_http206_response_lbeg:
426 | inc rdi
427 | inc rax
428 | cmp rax, 200 ; todo tweak this number
429 | jge worker_thread_close_file
430 | cmp BYTE [rdi], 0x2D ; look for '-'
431 | jne create_http206_response_lbeg
432 |
433 | mov BYTE [rdi], 0x00 ; replace '-' with null
434 | mov rbx, rdi ; save new beg
435 | inc rbx
436 | pop rdi ; restore beg of first number, convert to int
437 | call string_atoi
438 |
439 | mov rdi, rbx ; char after null
440 | mov rbx, rax ; rbx: from byte range
441 |
442 | push rdi ; save beginning of 2nd byte range
443 |
444 | create_http206_response_rbeg:
445 | inc rdi
446 | cmp BYTE [rdi], 0x0a ; look for end of line
447 | jne create_http206_response_rbeg
448 |
449 | dec rdi
450 | mov BYTE [rdi], 0x00; replace end with null
451 | pop rdi ; restore 2nd byte range
452 |
453 | call string_atoi
454 |
455 | mov rcx,rax ; rcx: to byte range, -1 if there is no end
456 | ;byte range: rbx -> rcx(-1 if to end)
457 |
458 |
459 | cmp rcx, -1
460 | jne worker_thread_206_skip_unknown_end
461 | mov rcx, r8
462 | dec rcx ; zero based
463 | worker_thread_206_skip_unknown_end:
464 |
465 | cmp rcx, r8
466 | jge worker_thread_413_response
467 |
468 | cmp rbx, rcx
469 | jg worker_thread_416_response
470 |
471 | pop r9 ; type
472 | mov r10, r8 ;total
473 | mov rdi, [rbp-16]
474 | mov rsi, rbx ;from
475 | mov r13, rsi ; r13: from offset
476 | mov rdx, rcx ;to
477 | mov r12, rcx ; r12: to byte range
478 | call create_http206_response
479 | mov r9, rax ; r9: header size
480 |
481 | sub r12, r13 ; r12: amount to send
482 | inc r12; zero based
483 |
484 | ;Send it
485 | mov rdi, [rbp-8]
486 | mov rsi, [rbp-16]
487 | mov rdx, r9
488 | call sys_send
489 |
490 | pop rdi ; sock fd - stack is empty now
491 | push rdi ; save it so we can close it
492 |
493 | mov rsi, r13 ; file offset ( range 'from' )
494 | mov rdx, LSEEK_SET
495 | call sys_lseek
496 |
497 |
498 | mov rdx, r12 ;file size to send
499 | mov rsi, rdi
500 | mov rdi, [rbp-8]
501 | call sys_sendfile
502 |
503 | ;stackpush
504 | ;push rax
505 | ;mov rdi, rsi
506 | ;mov rsi, r9
507 | ;call print_line ; debug
508 | ;pop rax
509 | ;stackpop
510 |
511 | pop r10; restore fd for close
512 | jmp worker_thread_close_file
513 | ;---------206 Response End--------------
514 |
515 | ;------200 Dir List Response Start------
516 | worker_thread_200_response_dir_list:
517 | mov rdi, [rbp-16]
518 | mov rbx, THREAD_BUFFER_SIZE+2+URL_LENGTH_LIMIT+DIRECTORY_LENGTH_LIMIT+DIRECTORY_LIST_BUFFER
519 | inc rbx ; zero pad start
520 | add rdi, rbx
521 | push rdi ; save start of directory list buffer for later
522 |
523 | call generate_dir_entries ; rax = new length
524 | push rax ; save length of contents for later
525 |
526 | ;Create Response
527 | mov rdi, [rbp-16]
528 | mov rsi, CONTENT_TYPE_HTML ; as we are sending custom HTML, change type
529 | mov rdx, rax ; total file size
530 | call create_http200_response
531 |
532 | mov r8, rax ; header size
533 |
534 | mov rdi, [rbp-8]
535 | mov rsi, [rbp-16]
536 | mov rdx, rax
537 | call sys_send
538 |
539 | ;Send the html formatted directory contents
540 | pop rax ; restore buffer pointer and length
541 | pop rdi
542 | mov rsi, rdi
543 | mov rdi, [rbp-8]
544 | mov rdx, rax
545 | call sys_send
546 | jmp worker_thread_close
547 | ;-------200 Dir List Response End-------
548 |
549 | ;---------200 Response Start------------
550 | worker_thread_200_response:
551 |
552 | ;rdi - total filesize
553 | push rdi
554 |
555 | ;Seek to beg of file
556 | mov rdi, r10 ; fd
557 | mov rsi, 0
558 | mov rdx, LSEEK_SET
559 | call sys_lseek
560 |
561 | ;Create Response
562 | mov rdi, [rbp-16]
563 | mov rsi, r8 ; type, figured out above
564 | pop rdx ; total file size
565 | push rdx ; save for sendfile
566 | call create_http200_response
567 |
568 | mov r8, rax ; header size
569 |
570 | mov rdi, [rbp-8]
571 | mov rsi, [rbp-16]
572 | mov rdx, rax
573 | call sys_send
574 |
575 | cmp rax, 0
576 | jle worker_thread_close_file
577 |
578 | cmp BYTE [request_type], REQ_HEAD
579 | je worker_thread_close_file
580 |
581 | mov rdi, [rbp-8]
582 | mov rsi, r10
583 | pop rdx
584 | call sys_sendfile
585 | jmp worker_thread_close_file
586 | ;---------200 Response End--------------
587 |
588 | ;---------400 Response Start------------
589 | worker_thread_400_response:
590 | mov rdi, [rbp-16]
591 | mov rsi, 400
592 | call create_httpError_response
593 |
594 | mov rdi, [rbp-8]
595 | mov rsi, [rbp-16]
596 | mov rdx, rax
597 | call sys_send
598 |
599 | jmp worker_thread_close
600 | ;---------400 Response End--------------
601 |
602 | ;---------413 Response Start------------
603 | worker_thread_413_response:
604 | mov rdi, [rbp-16]
605 | mov rsi, 413
606 | call create_httpError_response
607 |
608 | mov rdi, [rbp-8]
609 | mov rsi, [rbp-16]
610 | mov rdx, rax
611 | call sys_send
612 |
613 | jmp worker_thread_close
614 | ;---------413 Response End--------------
615 |
616 | ;---------416 Response Start------------
617 | worker_thread_416_response:
618 | mov rdi, [rbp-16]
619 | mov rsi, 416
620 | call create_httpError_response
621 |
622 | mov rdi, [rbp-8]
623 | mov rsi, [rbp-16]
624 | mov rdx, rax
625 | call sys_send
626 |
627 | jmp worker_thread_close
628 | ;---------416 Response End--------------
629 |
630 | worker_thread_close_file:
631 | ;Uncork
632 | mov rdi, [rbp-8]
633 | call sys_uncork
634 |
635 | ;Close File
636 | mov rdi, r10
637 | call sys_close
638 |
639 | ;Close Socket
640 | worker_thread_close:
641 | mov rdi, [rbp-8]
642 | call sys_close
643 |
644 | jmp worker_thread_start
645 |
646 | exit_with_no_directory_error:
647 | mov rdi, msg_not_a_directory
648 | mov rsi, msg_not_a_directory_len
649 | call print_line
650 | jmp exit
651 |
652 | exit_with_help:
653 | mov rdi, msg_help
654 | mov rsi, msg_help_len
655 | call print_line
656 | jmp exit
657 |
658 | exit_error:
659 | mov rdi, msg_error
660 | mov rsi, msg_error_len
661 | call print_line
662 |
663 | mov rdi, -1
664 | mov rax, SYS_EXIT_GROUP
665 | syscall
666 | jmp exit
667 |
668 | exit_bind_error:
669 | mov rdi, msg_bind_error
670 | mov rsi, msg_bind_error_len
671 | call print_line
672 |
673 | mov rdi, -1
674 | mov rax, SYS_EXIT_GROUP
675 | syscall
676 | jmp exit
677 |
678 | exit_thread:
679 |
680 | xor rdi, rdi
681 | mov rax, SYS_EXIT
682 | syscall
683 | jmp exit
684 |
685 | exit:
686 |
687 | mov rdi, [listen_socket]
688 | call sys_close
689 |
690 | xor rdi, rdi
691 | mov rax, SYS_EXIT_GROUP
692 | syscall
693 |
694 |
--------------------------------------------------------------------------------
/mutex.asm:
--------------------------------------------------------------------------------
1 | ;asmttpd - Web server for Linux written in amd64 assembly.
2 | ;Copyright (C) 2014 nemasu
3 | ;
4 | ;This file is part of asmttpd.
5 | ;
6 | ;asmttpd is free software: you can redistribute it and/or modify
7 | ;it under the terms of the GNU General Public License as published by
8 | ;the Free Software Foundation, either version 2 of the License, or
9 | ;(at your option) any later version.
10 | ;
11 | ;asmttpd is distributed in the hope that it will be useful,
12 | ;but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ;GNU General Public License for more details.
15 | ;
16 | ;You should have received a copy of the GNU General Public License
17 | ;along with asmttpd. If not, see .
18 |
19 | mutex_leave:
20 | stackpush
21 |
22 | mov rax, 1
23 | mov rdi, 0
24 | lock cmpxchg [queue_futex], rdi ; 1 -> 0 case
25 | cmp rax, 1
26 | je mutex_leave_end
27 |
28 | mov QWORD [queue_futex], 0
29 | mov rdi, 1
30 | call sys_futex_wake
31 |
32 | mutex_leave_end:
33 | stackpop
34 | ret
35 |
36 | mutex_enter:
37 | stackpush
38 |
39 | mov rax, 0
40 | mov rdi, 1
41 | lock cmpxchg [queue_futex], rdi
42 | cmp rax, 0
43 | je mutex_enter_end
44 |
45 | mutex_enter_begin:
46 | cmp rax, 2
47 | je mutex_enter_wait
48 | mov rax, 1
49 | mov rdi, 2
50 | lock cmpxchg [queue_futex], rdi
51 | cmp rax, 1
52 | je mutex_enter_wait
53 | ;Both tries ( c == 2 || cmpxchg( 1, 2 ) ) failed
54 | mutex_enter_cont:
55 | mov rax, 0
56 | mov rdi, 2
57 | lock cmpxchg [queue_futex], rdi
58 | cmp rax, 0
59 | jne mutex_enter_begin
60 | jmp mutex_enter_end
61 |
62 | mutex_enter_wait:
63 | mov rdi, 2
64 | call sys_futex_wait
65 | jmp mutex_enter_cont
66 |
67 | mutex_enter_end:
68 | stackpop
69 | ret
70 |
--------------------------------------------------------------------------------
/string.asm:
--------------------------------------------------------------------------------
1 | ;asmttpd - Web server for Linux written in amd64 assembly.
2 | ;Copyright (C) 2014 nemasu
3 | ;
4 | ;This file is part of asmttpd.
5 | ;
6 | ;asmttpd is free software: you can redistribute it and/or modify
7 | ;it under the terms of the GNU General Public License as published by
8 | ;the Free Software Foundation, either version 2 of the License, or
9 | ;(at your option) any later version.
10 | ;
11 | ;asmttpd is distributed in the hope that it will be useful,
12 | ;but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ;GNU General Public License for more details.
15 | ;
16 | ;You should have received a copy of the GNU General Public License
17 | ;along with asmttpd. If not, see .
18 | string_itoa:; rdi - buffer, rsi - int
19 | stackpush
20 | push rcx
21 | push rbx
22 |
23 | xchg rdi, rsi
24 | call get_number_of_digits
25 | xchg rdi, rsi
26 | mov rcx, rax ;
27 |
28 | ;add null
29 | mov al, 0x0
30 | mov [rdi+rcx], al
31 | dec rcx
32 |
33 | mov rax, rsi ; value to print
34 | xor rdx, rdx ; zero other half
35 | mov rbx, 10
36 |
37 | string_itoa_start:
38 | xor rdx, rdx ; zero other half
39 | div rbx ; divide by 10
40 |
41 | add rdx, 0x30
42 | mov [rdi+rcx], dl
43 | dec rcx
44 | cmp rax, 9
45 | ja string_itoa_start
46 |
47 | cmp rcx, 0
48 | jl string_itoa_done
49 | add rax, 0x30 ;last digit
50 | mov [rdi+rcx], al
51 |
52 | string_itoa_done:
53 | pop rbx
54 | pop rcx
55 | stackpop
56 | ret
57 |
58 | string_atoi: ; rdi = string, rax = int
59 | stackpush
60 |
61 | mov r8, 0 ; ;return
62 |
63 | call get_string_length
64 | mov r10, rax ; length
65 | cmp rax, 0
66 | je string_atoi_ret_empty
67 |
68 | mov r9, 1 ; multiplier
69 |
70 | dec r10
71 | string_atoi_loop:
72 | xor rbx, rbx
73 | mov bl, BYTE [rdi+r10]
74 | sub bl, 0x30 ;get byte, subtract to get real from ascii value
75 | mov rax, r9
76 | mul rbx ; multiply value by multiplier
77 | add r8, rax ; add result to running total
78 | dec r10 ; next digit
79 | mov rax, 10 ; multiply r9 ( multiplier ) by 10
80 | mul r9
81 | mov r9, rax
82 | cmp r10, -1
83 | jne string_atoi_loop
84 | jmp string_atoi_ret
85 |
86 | string_atoi_ret_empty:
87 | mov rax, -1
88 | stackpop
89 | ret
90 |
91 | string_atoi_ret:
92 | mov rax, r8
93 | stackpop
94 | ret
95 |
96 | string_copy: ; rdi = dest, rsi = source, rdx = bytes to copy
97 | stackpush
98 | mov rcx, rdx
99 | inc rcx ; to get null
100 | cld
101 | rep movsb
102 | stackpop
103 | ret
104 |
105 | string_concat_int: ;rdi = string being added to, rsi = int to add, ret: new length
106 | stackpush
107 |
108 | call get_string_length
109 | add rdi, rax
110 | call string_itoa
111 |
112 | call get_string_length
113 |
114 | stackpop
115 | ret
116 |
117 | string_concat: ;rdi = string being added to, rsi = string to add, ret: new length
118 | stackpush
119 |
120 | call get_string_length
121 | add rdi, rax ; Go to end of string
122 | mov r10, rax
123 |
124 | ;Get length of source ie. bytes to copy
125 | push rdi
126 | mov rdi, rsi
127 | call get_string_length
128 | inc rax ; null
129 | mov rcx, rax
130 | add r10, rax
131 | pop rdi
132 |
133 | rep movsb
134 |
135 | mov rax, r10
136 |
137 | stackpop
138 | ret
139 |
140 | string_contains: ;rdi = haystack, rsi = needle, ret = rax: location of string, else -1
141 | stackpush
142 |
143 | xor r10, r10 ; total length from beginning
144 | xor r8, r8 ; count from offset
145 |
146 | string_contains_start:
147 | mov dl, BYTE [rdi]
148 | cmp dl, 0x00
149 | je string_contains_ret_no
150 | cmp dl, BYTE [rsi]
151 | je string_contains_check
152 | inc rdi
153 | inc r10 ; count from base ( total will be r10 + r8 )
154 | jmp string_contains_start
155 |
156 | string_contains_check:
157 | inc r8 ; already checked at pos 0
158 | cmp BYTE [rsi+r8], 0x00
159 | je string_contains_ret_ok
160 | mov dl, [rdi+r8]
161 | cmp dl ,0x00
162 | je string_contains_ret_no
163 | cmp dl, [rsi+r8]
164 | je string_contains_check
165 |
166 | inc rdi
167 | inc r10
168 | xor r8, r8
169 | jmp string_contains_start
170 |
171 | string_contains_ret_ok:
172 | mov rax, r10
173 | jmp string_contains_ret
174 |
175 | string_contains_ret_no:
176 | mov rax, -1
177 |
178 | string_contains_ret:
179 | stackpop
180 | ret
181 |
182 |
183 | ;Removes first instance of string
184 | string_remove: ;rdi = source, rsi = string to remove, ret = 1 for removed, 0 for not found
185 | stackpush
186 |
187 | mov r9, 0 ; return flag
188 |
189 | call get_string_length
190 | mov r8, rax ; r8: source length
191 | cmp r8, 0
192 | mov rax, 0
193 | jle string_remove_ret ; source string empty?
194 |
195 | push rdi
196 | mov rdi, rsi
197 | call get_string_length
198 | mov r10, rax ; r10: string to remove length
199 | pop rdi
200 | cmp r10, 0
201 | mov rax, 0
202 | jle string_remove_ret ; string to remove is blank?
203 |
204 | string_remove_start:
205 |
206 | call string_contains
207 |
208 | cmp rax,-1
209 | je string_remove_ret
210 |
211 | ;Shift source string over
212 | add rdi, rax
213 | mov rsi, rdi
214 | add rsi, r10 ; copying to itself sans found string
215 |
216 | cld
217 | string_remove_do_copy:
218 | lodsb
219 | stosb
220 | cmp al, 0x00
221 | jne string_remove_do_copy
222 |
223 | mov r9, 1
224 |
225 | string_remove_ret:
226 | mov rax, r9
227 | stackpop
228 | ret
229 |
230 | string_ends_with:;rdi = haystack, rsi = needle, ret = rax: 0 false, 1 true
231 | stackpush
232 |
233 | ;Get length of haystack, store in r8
234 | call get_string_length
235 | mov r8, rax
236 |
237 | ;Get length of needle, store in r10
238 | push rdi
239 | mov rdi, rsi
240 | call get_string_length
241 | mov r10, rax
242 | pop rdi
243 |
244 | add rdi, r8
245 | add rsi, r10
246 |
247 | xor rax, rax
248 | xor rdx, rdx
249 |
250 | string_ends_with_loop:
251 | ;Start from end, dec r10 till 0
252 | mov dl, BYTE [rdi]
253 | cmp dl, BYTE [rsi]
254 | jne string_ends_with_ret
255 | dec rdi
256 | dec rsi
257 | dec r10
258 | cmp r10, 0
259 | jne string_ends_with_loop
260 | mov rax, 1
261 |
262 | string_ends_with_ret:
263 | stackpop
264 | ret
265 |
266 | string_char_at_reverse: ;rdi = haystack, rsi = count from end, rdx = character(not pointer), ret = rax: 0 false, 1 true
267 | stackpush
268 | inc rsi ; include null
269 | call get_string_length
270 | add rdi, rax ; go to end
271 | sub rdi, rsi ; subtract count
272 | mov rax, 0 ; set return to false
273 | cmp dl, BYTE [rdi] ; compare rdx(dl)
274 | jne string_char_at_reverse_ret
275 | mov rax, 1
276 | string_char_at_reverse_ret:
277 | stackpop
278 | ret
279 |
280 | print_line: ; rdi = pointer, rsi = length
281 | stackpush
282 | call sys_write
283 | mov rdi, new_line
284 | mov rsi, 1
285 | call sys_write
286 | stackpop
287 | ret
288 |
289 | get_string_length: ; rdi = pointer, ret rax
290 | stackpush
291 | cld
292 | mov r10, -1
293 | mov rsi, rdi
294 | get_string_length_start:
295 | inc r10
296 | lodsb
297 | cmp al, 0x00
298 | jne get_string_length_start
299 | mov rax, r10
300 | stackpop
301 | ret
302 |
303 | get_number_of_digits: ; of rdi, ret rax
304 | stackpush
305 | push rbx
306 | push rcx
307 |
308 | mov rax, rdi
309 | mov rbx, 10
310 | mov rcx, 1 ;count
311 | gnod_cont:
312 | cmp rax, 10
313 | jb gnod_ret
314 |
315 | xor rdx,rdx
316 | div rbx
317 |
318 | inc rcx
319 | jmp gnod_cont
320 | gnod_ret:
321 | mov rax, rcx
322 |
323 | pop rcx
324 | pop rbx
325 | stackpop
326 | ret
327 |
328 |
--------------------------------------------------------------------------------
/syscall.asm:
--------------------------------------------------------------------------------
1 | ;asmttpd - Web server for Linux written in amd64 assembly.
2 | ;Copyright (C) 2014 nemasu
3 | ;
4 | ;This file is part of asmttpd.
5 | ;
6 | ;asmttpd is free software: you can redistribute it and/or modify
7 | ;it under the terms of the GNU General Public License as published by
8 | ;the Free Software Foundation, either version 2 of the License, or
9 | ;(at your option) any later version.
10 | ;
11 | ;asmttpd is distributed in the hope that it will be useful,
12 | ;but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ;GNU General Public License for more details.
15 | ;
16 | ;You should have received a copy of the GNU General Public License
17 | ;along with asmttpd. If not, see .
18 |
19 | section .text
20 |
21 | sys_cork:;rdi - socket
22 | stackpush
23 | mov r10, one_constant ;pointer to 1
24 | mov r8, 8 ;sizeof int
25 | mov rsi, LEVEL_IPPROTO_TCP
26 | mov rdx, SOCKOPT_TCP_CORK
27 | mov rax, SYS_SETSOCKOPT
28 | syscall
29 | stackpop
30 | ret
31 |
32 | sys_uncork;rdi - socket
33 | stackpush
34 | mov r10, one_constant ;pointer to 1
35 | mov r8, 8 ;sizeof int
36 | mov rsi, LEVEL_IPPROTO_TCP
37 | mov rdx, SOCKOPT_TCP_CORK
38 | mov rax, SYS_SETSOCKOPT
39 | syscall
40 | stackpop
41 | ret
42 |
43 | sys_reuse;rdi - socket
44 | stackpush
45 | mov r8, 8 ;sizeof int
46 | mov r10, one_constant ;pointer to 1
47 | mov rsi, LEVEL_SOL_TCP
48 | mov rdx, SOCKOPT_TCP_REUSEADDR
49 | mov rax, SYS_SETSOCKOPT
50 | syscall
51 | stackpop
52 | ret
53 |
54 | sys_sendfile: ;rdi - outfd, rsi - infd, rdx - file size
55 | stackpush
56 | mov r10, rdx
57 | xor rdx, rdx
58 | mov rax, SYS_SENDFILE
59 | syscall
60 | stackpop
61 | ret
62 |
63 | sys_lseek:; rdi - fd, rsi - offset, rdx - flag
64 | stackpush
65 | mov rax, SYS_LSEEK
66 | syscall
67 | stackpop
68 | ret
69 |
70 | sys_open:
71 | stackpush
72 | mov rsi, OPEN_RDONLY ;flags
73 | mov rax, SYS_OPEN
74 | syscall
75 | stackpop
76 | ret
77 |
78 | sys_close:
79 | stackpush
80 | mov rax, SYS_CLOSE
81 | syscall
82 | stackpop
83 | ret
84 |
85 | sys_send:
86 | stackpush
87 | xor r10, r10
88 | xor r8, r8
89 | xor r9, r9
90 | mov rax, SYS_SENDTO
91 | syscall
92 | stackpop
93 | ret
94 |
95 | sys_recv:
96 | stackpush
97 | xor r10, r10 ; flags
98 | xor r8, r8
99 | xor r9, r9
100 | mov rax, SYS_RECVFROM
101 | syscall
102 | stackpop
103 | ret
104 |
105 | sys_accept:
106 | stackpush
107 | mov rdi, [listen_socket]
108 | xor rsi, rsi
109 | xor rdx, rdx
110 | mov rax, SYS_ACCEPT
111 | syscall
112 | stackpop
113 | ret
114 |
115 | sys_listen:
116 | stackpush
117 | mov rdi, [listen_socket]
118 | mov rsi, 100000000;backlog
119 | mov rax, SYS_LISTEN
120 | syscall
121 | stackpop
122 | ret
123 |
124 | sys_bind_server:
125 | stackpush
126 |
127 | mov rsi, [listen_port]
128 | mov [sa + sin_port], rsi
129 |
130 | mov rdi, [listen_socket]
131 | mov rsi, sa
132 | mov rdx, 16
133 | mov rax, SYS_BIND
134 | syscall
135 | stackpop
136 | ret
137 |
138 | sys_create_tcp_socket:
139 | stackpush
140 | mov rdi, AF_INET
141 | mov rsi, SOCK_STREAM
142 | mov rdx, PROTO_TCP
143 | mov rax, SYS_SOCKET
144 | syscall
145 | stackpop
146 | ret
147 |
148 | sys_open_directory:;rdi = path, rax = ret ( fd ), rdx = flags
149 | stackpush
150 | mov rsi, rdx ;flags
151 | mov rax, SYS_OPEN
152 | syscall
153 | stackpop
154 | ret
155 |
156 | sys_get_dir_listing:;rdi = fd, rsi = buffer, rdx = buffer_size
157 | stackpush
158 | mov rax, SYS_GETDENTS
159 | syscall
160 | stackpop
161 | ret
162 |
163 | sys_write:
164 | stackpush
165 | mov rdx, rsi ;length
166 | mov rsi, rdi ;buffer
167 | mov rdi, FD_STDOUT
168 | mov rax, SYS_WRITE
169 | syscall
170 | stackpop
171 | ret
172 |
173 | sys_nanosleep:
174 | stackpush
175 | mov qword [tv_usec], rdi
176 | mov qword [tv_sec],0
177 | xor rsi, rsi
178 | mov rdi, timeval
179 | mov rax, SYS_NANOSLEEP
180 | syscall
181 | stackpop
182 | ret
183 |
184 | sys_sleep:
185 | stackpush
186 | mov qword [tv_sec], rdi
187 | mov qword [tv_usec],0
188 | xor rsi, rsi
189 | mov rdi, timeval
190 | mov rax, SYS_NANOSLEEP
191 | syscall
192 | stackpop
193 | ret
194 |
195 | sys_mmap_mem:
196 | stackpush
197 | mov rsi, rdi ;Size
198 | xor rdi, rdi ;Preferred address (don't care)
199 | mov rdx, MMAP_PROT_READ | MMAP_PROT_WRITE ;Protection Flags
200 | mov r10, MMAP_MAP_PRIVATE | MMAP_MAP_ANON ;Flags
201 | xor r8, r8
202 | dec r8 ;-1 fd because of MMAP_MAP_ANON
203 | xor r9, r9 ;Offset
204 | mov rax, SYS_MMAP
205 | syscall
206 | stackpop
207 | ret
208 |
209 | sys_mmap_stack:
210 | stackpush
211 | mov rsi, rdi ;Size
212 | xor rdi, rdi ;Preferred address (don't care)
213 | mov rdx, MMAP_PROT_READ | MMAP_PROT_WRITE ;Protection Flags
214 | mov r10, MMAP_MAP_PRIVATE | MMAP_MAP_ANON | MMAP_MAP_GROWSDOWN ;Flags
215 | xor r8, r8
216 | dec r8 ;-1 fd because of MMAP_MAP_ANON
217 | xor r9, r9 ;Offset
218 | mov rax, SYS_MMAP
219 | syscall
220 | stackpop
221 | ret
222 |
223 | sys_clone:
224 | mov r14, rdi ;Address of the thread_func
225 | mov r15, rsi ;Thread Param
226 | mov rdi, THREAD_STACK_SIZE
227 | call sys_mmap_stack
228 | lea rsi, [rax + THREAD_STACK_SIZE] ;Set newly allocated memory
229 | mov rdi, CLONE_FILES | CLONE_VM | CLONE_FS | CLONE_THREAD | CLONE_SIGHAND | SIGCHILD ;Flags
230 | xor r10, r10 ;parent_tid
231 | xor r8, r8 ;child_tid
232 | xor r9, r9 ;regs
233 | mov rax, SYS_CLONE
234 | syscall
235 | cmp rax, 0 ;If ret is not 0, then it's the ID of the new thread
236 | jnz parent
237 | push r14 ;Else, set new return address
238 | mov rdi, r15 ;and set param
239 | ret ;Return to thread_proc
240 | parent:
241 | ret
242 |
243 |
--------------------------------------------------------------------------------
/web_root/index.html:
--------------------------------------------------------------------------------
1 | hihello world
--------------------------------------------------------------------------------