From d54596514c30343305b7cc4b8be36c712d536e7a Mon Sep 17 00:00:00 2001 From: root <> Date: Sun, 11 May 2025 08:22:07 +0000 Subject: [PATCH 01/10] echo then close connection --- main.s | 54 +++++++++++++++++++++++++++++++++++++++++++++++------- readline.s | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 readline.s diff --git a/main.s b/main.s index 881a3d5..8905309 100644 --- a/main.s +++ b/main.s @@ -24,8 +24,10 @@ POLLIN equ 1 POLLOUT equ 4 SHUT_RDWR equ 2 -pollfd_size equ 4 + 2 + 2 ; $ man 2 poll -pollfds_capacity equ 100 +pollfd_size equ 4 + 2 + 2 ; $ man 2 poll +pollfds_capacity equ 100 +client_size equ 1 + 256 + 256 ; state, line buffer, uri +clients_capacity equ pollfds_capacity - 1 SECTION .data server_path db "server.sock", 0x00 @@ -33,15 +35,18 @@ server_path_len equ $ - server_path sockaddr_size equ 2 + 108 ; $ man 7 unix goodbye db "goodbye", 0x0a goodbye_len equ $ - goodbye +pollfds_len dq 0 +clients_len dq 0 SECTION .bss sockaddr resb sockaddr_size pollfds resb pollfd_size * pollfds_capacity -pollfds_len resb 8 +clients resb (4 + client_size) * clients_capacity SECTION .text %include "server.s" +%include "readline.s" _start: call make_server @@ -84,11 +89,27 @@ pollfds__scan__found__client: ; TODO check r10w, incl for POLLNVAL & POLLERR push rdi + mov rdi, r14 + call clients__append + + mov r12, [clients_len] + add r12, -1 + imul r12, client_size + add r12, clients + add r12, 4 + + mov rdi, r14 + mov rsi, r12 + mov rdx, 256 + call readline + cmp rax, 0 ; TODO + jl exit + ;push rax ; TODO + + mov rdx, rax mov rax, SYS_WRITE - mov rdi, 0 - mov edi, r14d - mov rsi, goodbye - mov rdx, goodbye_len + mov rdi, r14 + mov rsi, r12 syscall cmp rax, 0 jl exit ; TODO handle this gracefully @@ -132,6 +153,7 @@ pollfds__scan__found__server: ; edi - fd ; si - events pollfds__append: + ; TODO check against pollfds_capacity mov r10, [pollfds_len] mov [pollfds + r10 * pollfd_size], edi mov [pollfds + r10 * pollfd_size + 4], si @@ -157,6 +179,24 @@ pollfds__clear: mov [pollfds_len], r10 ret +; esi - fd +clients__append: + ; TODO check against client_capacity + mov r10, [clients_len] + imul r10, client_size + add r10, clients + mov [r10], esi + add r10, 4 + mov r8b, 0 + mov r11, 0 + +clients__append__init: + cmp r11, client_size + jge return + mov [r10 + r11], r8b + add r11, 1 + jmp clients__append__init + return: ret diff --git a/readline.s b/readline.s new file mode 100644 index 0000000..aba4769 --- /dev/null +++ b/readline.s @@ -0,0 +1,36 @@ +; Returns length in rax +; Errors (in rax): +; -1024 - line too long +; other negative - error from read(2) +; Arguments: +; rdi - fd +; rsi - buffer +; rdx - max length +readline: + push rdi + push rsi + push rdx + mov rax, SYS_READ + syscall + pop rdx + pop rsi + pop rdi + cmp rax, 0 + jl return + mov r10, 0 + +readline__scan: + cmp r10, rax + jge readline__overflow + mov r11b, [rsi + r10] + add r10, 1 + cmp r11b, 0x0a ; '\n' + jne readline__scan + +readline__return: + mov rax, r10 + ret + +readline__overflow: + mov rax, -1024 + ret From 29f54ba779b0ac2c89f88a3d5c5825b0b8ec197d Mon Sep 17 00:00:00 2001 From: root <> Date: Tue, 13 May 2025 12:07:03 +0000 Subject: [PATCH 02/10] echo server, multiple clients, lines <256 bytes --- client.s | 104 ++++++++++++++++++++++++++++ clients.s | 69 +++++++++++++++++++ constants.c | 2 + main.s | 192 +++++++++++++++++++++++----------------------------- pollfds.s | 30 ++++++++ readline.s | 19 ++++-- 6 files changed, 304 insertions(+), 112 deletions(-) create mode 100644 client.s create mode 100644 clients.s create mode 100644 pollfds.s diff --git a/client.s b/client.s new file mode 100644 index 0000000..073f42c --- /dev/null +++ b/client.s @@ -0,0 +1,104 @@ +; Errors (in rax): +; 0 - EOF +; -1024 - line too long +; other negative - from read(2) +; Arguments: +; rdi - fd +; rsi - address of client within clients array +; rdx - pollfds index +client__pollin: + push rdi + push rsi + push rdx + + mov r10, 0 + mov r10b, [rsi + 4 + 2] ; buffer_len + + mov rdx, 0 + mov dl, 255 + sub dl, r10b ; rdx = 255 - buffer_len + add rsi, 8 + add rsi, r10 + call readline + + mov r10, rdi + + pop rdx + pop rsi + pop rdi + + cmp rax, 0 + jle return + + add [rsi + 4 + 2], al ; buffer_len += rax + + cmp r10, 0 + jg client__pollin__complete_line + + add [rsi + 4 + 1], al ; line_len += rax + ret + +client__pollin__complete_line: + add [rsi + 4 + 1], r10b ; line_len += r10 + mov word [pollfds + rdx * pollfd_size + 4], POLLOUT + ret + +; rdi - fd +; rsi - address of client within clients array +; rdx - pollfds index +client__pollout: + push rdi + push rsi + push rdx + + mov rax, SYS_WRITE + mov rdx, 0 + mov dl, [rsi + 4 + 1] + add rsi, 8 + syscall + + pop rdx + pop rsi + pop rdi + + cmp rax, 0 + jl return + + mov r10, rsi + add r10, 8 + mov r11, 0 + mov r11b, [rsi + 4 + 2] + sub r11, rax + add r11, r10 + +client__pollout__shunt: + cmp r10, r11 + jge client__pollout__shunt__finished + mov r8b, [r10 + rax] + mov [r10], r8b + add r10, 1 + jmp client__pollout__shunt + +client__pollout__shunt__finished: + sub [rsi + 4 + 2], al ; buffer_len -= rax + sub [rsi + 4 + 1], al ; line_len -= rax + cmp byte [rsi + 4 + 1], 0 + je client__pollout__wrote_line + ret + +client__pollout__wrote_line: + mov word [pollfds + rdx * pollfd_size + 4], POLLIN + ret + +; rdi - fd +client__shutdown_close: + mov rax, SYS_SHUTDOWN + push rdi + mov rsi, SHUT_RDWR + syscall + + mov rax, SYS_CLOSE + pop rdi + syscall + + ret diff --git a/clients.s b/clients.s new file mode 100644 index 0000000..1af458b --- /dev/null +++ b/clients.s @@ -0,0 +1,69 @@ +; edi - fd +clients__append: + ; TODO check against client_capacity + mov r10, [clients_len] + imul r10, client_size + add r10, clients + mov [r10], edi + + add qword [clients_len], 1 + + mov r11, 4 + +clients__append__write_zeros: + cmp r11, 8 + jge return + mov byte [r10 + r11], 0 + add r11, 1 + jmp clients__append__write_zeros + +; edi - fd +clients__search: + mov r11, [clients_len] + imul r11, client_size + add r11, clients + mov r10, clients + +clients__search__loop: + cmp r10, r11 + jge clients__search__fail + mov r8d, [r10] + cmp r8d, edi + je clients__search__succ + add r10, client_size + jmp clients__search__loop + +clients__search__fail: + mov r10, -1 + +clients__search__succ: + mov rax, r10 + ret + +; rdi - address of client within clients array +clients__remove: + mov r10, [clients_len] + cmp r10, 1 + jle clients__clear + + add r10, -1 + mov [clients_len], r10 + + mov r10, 0 + mov r11, r10 + imul r11, client_size + add r11, clients + +clients__remove__loop: + cmp r10, client_size + jge return + mov r8b, [r11 + r10] + mov [rdi + r10], r8b + add r10, 1 + jmp clients__remove__loop + +; rdi - address of client within clients array +clients__clear: + mov r10, 0 + mov [clients_len], r10 + ret diff --git a/constants.c b/constants.c index 2e7aab3..8239355 100644 --- a/constants.c +++ b/constants.c @@ -14,5 +14,7 @@ void main() { printf("sizeof(short) %d\n", sizeof(short)); printf("POLLIN %d\n", POLLIN); printf("POLLOUT %d\n", POLLOUT); + printf("POLLERR %d\n", POLLERR); + printf("POLLNVAL %d\n", POLLNVAL); printf("SHUT_RDWR %d\n", SHUT_RDWR); } diff --git a/main.s b/main.s index 8905309..190f240 100644 --- a/main.s +++ b/main.s @@ -22,11 +22,19 @@ F_SETFL equ 4 O_NONBLOCK equ 2048 POLLIN equ 1 POLLOUT equ 4 +POLLERR equ 8 +POLLNVAL equ 32 +; TODO(?) POLLPRI: see poll(2), tcp(7) SHUT_RDWR equ 2 +;STATE_READING equ 0 +;STATE_WRITING equ 1 + pollfd_size equ 4 + 2 + 2 ; $ man 2 poll pollfds_capacity equ 100 -client_size equ 1 + 256 + 256 ; state, line buffer, uri + +; fd, state, line_len, buffer_len, uri_len, buffer, uri +client_size equ 4 + 4 + 255 + 255 clients_capacity equ pollfds_capacity - 1 SECTION .data @@ -47,11 +55,14 @@ SECTION .text %include "server.s" %include "readline.s" +%include "clients.s" +%include "pollfds.s" +%include "client.s" _start: call make_server mov rbx, rax ; server fd - mov rdi, rax + mov rdi, rbx mov rsi, POLLIN call pollfds__append @@ -63,144 +74,113 @@ poll: syscall cmp rax, 0 je poll - jl exit ; TODO handle this gracefully - mov rdi, rbx + jl exit ; poll(2) returned error TODO -; rdi - server fd -pollfds__scan: +scan: mov r15, 0 -pollfds__scan__loop: +; Variables: +; r15 - pollfds index +; r14w - poll(2) revents +; r13d - fd +; r12 - client memory address +scan__loop: cmp r15, [pollfds_len] jge poll - mov r10w, [pollfds + r15 * pollfd_size + 6] - cmp r10w, 0 - jne pollfds__scan__found + mov r14w, [pollfds + r15 * pollfd_size + 6] + cmp r14w, 0 + jne scan__found add r15, 1 - jmp pollfds__scan__loop + jmp scan__loop -pollfds__scan__found: - mov r14, 0 - mov r14d, [pollfds + r15 * pollfd_size] - cmp r14d, edi - je pollfds__scan__found__server +scan__found: + mov r13, 0 + mov r13d, [pollfds + r15 * pollfd_size] + cmp r13d, ebx + je scan__found__server -pollfds__scan__found__client: - ; TODO check r10w, incl for POLLNVAL & POLLERR - push rdi +scan__found__client: + mov rdi, r13 + call clients__search + mov r12, rax + cmp r12, 0 + jl _client__not_stored - mov rdi, r14 - call clients__append + mov r10w, r14w + and r10w, POLLERR | POLLNVAL + cmp r10w, 0 + jne _client__error - mov r12, [clients_len] - add r12, -1 - imul r12, client_size - add r12, clients - add r12, 4 + mov r10w, r14w + and r10w, POLLIN + cmp r10w, 0 + jne _client__pollin - mov rdi, r14 - mov rsi, r12 - mov rdx, 256 - call readline - cmp rax, 0 ; TODO - jl exit - ;push rax ; TODO + mov r10w, r14w + and r10w, POLLOUT + cmp r10w, 0 + jne _client__pollout - mov rdx, rax - mov rax, SYS_WRITE - mov rdi, r14 - mov rsi, r12 - syscall - cmp rax, 0 - jl exit ; TODO handle this gracefully + ; TODO what did poll(2) detect in this case? + add r15, 1 + jmp scan__loop - mov rax, SYS_SHUTDOWN - mov rdi, 0 - mov edi, r14d - mov rsi, SHUT_RDWR - syscall - - mov rax, SYS_CLOSE - mov rdi, 0 - mov edi, r14d - syscall +_client__error: + mov rdi, r12 + call clients__remove +_client__not_stored: + mov rdi, r13 + call client__shutdown_close mov rdi, r15 call pollfds__remove + jmp scan__loop - pop rdi - jmp pollfds__scan__loop +_client__pollin: + mov rdi, r13 + mov rsi, r12 + mov rdx, r15 + call client__pollin + cmp rax, 0 + jle _client__error + add r15, rax + jmp scan__loop -pollfds__scan__found__server: - ; TODO check r10w, incl for POLLNVAL & POLLERR - push rdi +_client__pollout: + mov rdi, r13 + mov rsi, r12 + mov rdx, r15 + call client__pollout + add r15, 1 + jmp scan__loop + +scan__found__server: + cmp r14w, POLLIN + jne exit mov rax, SYS_ACCEPT + mov rdi, r13 mov rsi, 0 mov rdx, 0 syscall cmp rax, 0 - jl exit ; TODO handle this gracefully + jl exit ; accept(2) returned error TODO mov rdi, rax - mov si, POLLIN | POLLOUT + push rdi + mov si, POLLIN call pollfds__append pop rdi + call clients__append + add r15, 1 - jmp pollfds__scan__loop - -; edi - fd -; si - events -pollfds__append: - ; TODO check against pollfds_capacity - mov r10, [pollfds_len] - mov [pollfds + r10 * pollfd_size], edi - mov [pollfds + r10 * pollfd_size + 4], si - add r10, 1 - mov [pollfds_len], r10 - ret - -; rdi - pollfds array index to remove -pollfds__remove: - mov r11, [pollfds_len] - cmp rdi, r10 - jge return ; XXX index out of bounds, do some other error? - cmp r11, 1 - jle pollfds__clear - mov r10, [pollfds + (r11 - 1) * pollfd_size] - mov [pollfds + rdi * pollfd_size], r10 - sub r11, 1 - mov [pollfds_len], r11 - ret - -pollfds__clear: - mov r10, 0 - mov [pollfds_len], r10 - ret - -; esi - fd -clients__append: - ; TODO check against client_capacity - mov r10, [clients_len] - imul r10, client_size - add r10, clients - mov [r10], esi - add r10, 4 - mov r8b, 0 - mov r11, 0 - -clients__append__init: - cmp r11, client_size - jge return - mov [r10 + r11], r8b - add r11, 1 - jmp clients__append__init + jmp scan__loop return: ret exit: mov rax, SYS_EXIT - mov rdi, 0 + mov rdi, 255 syscall diff --git a/pollfds.s b/pollfds.s new file mode 100644 index 0000000..4eed357 --- /dev/null +++ b/pollfds.s @@ -0,0 +1,30 @@ +; edi - fd +; si - events +pollfds__append: + ; TODO check against pollfds_capacity + mov r10, [pollfds_len] + mov [pollfds + r10 * pollfd_size], edi + mov [pollfds + r10 * pollfd_size + 4], si + mov r11w, 0 + mov [pollfds + r10 * pollfd_size + 6], r11w + add r10, 1 + mov [pollfds_len], r10 + ret + +; rdi - pollfds array index to remove +pollfds__remove: + mov r11, [pollfds_len] + cmp rdi, r11 + jge return ; XXX index out of bounds, do some other error? + cmp r11, 1 + jle pollfds__clear + mov r10, [pollfds + (r11 - 1) * pollfd_size] + mov [pollfds + rdi * pollfd_size], r10 + sub r11, 1 + mov [pollfds_len], r11 + ret + +pollfds__clear: + mov r10, 0 + mov [pollfds_len], r10 + ret diff --git a/readline.s b/readline.s index aba4769..35e30dd 100644 --- a/readline.s +++ b/readline.s @@ -1,34 +1,41 @@ -; Returns length in rax +; Returns: +; rax - read(2) length +; rdi - if line is complete, line length; +; if line was incomplete, 0; +; if EOF or read(2) returned an error, undefined ; Errors (in rax): ; -1024 - line too long ; other negative - error from read(2) +; 0 - EOF from read(2) ; Arguments: ; rdi - fd ; rsi - buffer ; rdx - max length readline: - push rdi push rsi push rdx mov rax, SYS_READ syscall pop rdx pop rsi - pop rdi cmp rax, 0 jl return mov r10, 0 readline__scan: - cmp r10, rax + cmp r10, rdx jge readline__overflow + cmp r10, rax + jge readline__incomplete_line mov r11b, [rsi + r10] add r10, 1 cmp r11b, 0x0a ; '\n' jne readline__scan + mov rdi, r10 + ret -readline__return: - mov rax, r10 +readline__incomplete_line: + mov rdi, 0 ret readline__overflow: From 8ab750ba97160be5199589d3e82f6a8a35a65a10 Mon Sep 17 00:00:00 2001 From: root <> Date: Tue, 13 May 2025 12:22:34 +0000 Subject: [PATCH 03/10] bugfix: removing pollfds[0] actually removed pollfds[-1] this bug created this weird behaviour: 1. client 1 connects 2. client 2 connents 3. client 1 disconnects 4. client 2 sends a line 5. client 2 is disconnected by the server --- clients.s | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clients.s b/clients.s index 1af458b..e87dde4 100644 --- a/clients.s +++ b/clients.s @@ -49,11 +49,12 @@ clients__remove: add r10, -1 mov [clients_len], r10 - mov r10, 0 mov r11, r10 imul r11, client_size add r11, clients + mov r10, 0 + clients__remove__loop: cmp r10, client_size jge return From 484d81baa86e5151d15462a1153e65854f1abcfc Mon Sep 17 00:00:00 2001 From: root <> Date: Sat, 17 May 2025 08:10:55 +0000 Subject: [PATCH 04/10] client__pollin: read as much as possible; client__pollout: do processing --- client.s | 173 +++++++++++++++++++++++++++++++++++++---------------- main.s | 17 ++++-- readline.s | 51 +++++----------- 3 files changed, 149 insertions(+), 92 deletions(-) diff --git a/client.s b/client.s index 073f42c..557898f 100644 --- a/client.s +++ b/client.s @@ -1,75 +1,146 @@ +; Returns: +; rax - 0 ; Errors (in rax): -; 0 - EOF -; -1024 - line too long -; other negative - from read(2) +; rax - 0 - EOF +; rax - -1024 - line too long +; rax - other negative - from read(2) ; Arguments: ; rdi - fd ; rsi - address of client within clients array ; rdx - pollfds index +; Variables: +; rbx - pollfds index +; r12 - client buffer +; r13 - start of line scanning +; r14 - client buffer end client__pollin: - push rdi - push rsi - push rdx + push rbx + push r12 + push r13 + push r14 - mov r10, 0 - mov r10b, [rsi + 4 + 2] ; buffer_len + mov rbx, rdx + mov r12, rsi + add r12, OFFSET_CLIENT_BUFFER + mov r13, 0 + mov r13b, [rsi + OFFSET_CLIENT_BUFFER_LEN] + add r13, r12 + mov r14, r12 + add r14, 255 - mov rdx, 0 - mov dl, 255 - sub dl, r10b ; rdx = 255 - buffer_len - add rsi, 8 - add rsi, r10 - call readline - - mov r10, rdi - - pop rdx - pop rsi - pop rdi + mov rax, SYS_READ + mov rsi, r13 + mov rdx, 255 + sub rdx, [rsi + OFFSET_CLIENT_BUFFER_LEN] + syscall cmp rax, 0 - jle return + jle client__pollin__return ; TODO verify this shit - add [rsi + 4 + 2], al ; buffer_len += rax + ; buffer_len += read(2) length + add [rsi + OFFSET_CLIENT_BUFFER_LEN], al - cmp r10, 0 - jg client__pollin__complete_line + mov rdi, r13 + mov rsi, rax + call scanline - add [rsi + 4 + 1], al ; line_len += rax - ret + cmp rax, 0 + je client__pollin__no_line -client__pollin__complete_line: - add [rsi + 4 + 1], r10b ; line_len += r10 + mov rax, 1 mov word [pollfds + rdx * pollfd_size + 4], POLLOUT + +client__pollin__return: + pop r14 + pop r13 + pop r12 + pop rbx ret +client__pollin__no_line: + mov r10, r13 + add r10, rax + cmp r10, r14 + jge client__pollin__line_too_long + mov rax, 1 + jmp client__pollin__return + +client__pollin__line_too_long: + mov rax, -1024 + jmp client__pollin__return + +client__pollin__line: + pop rdx + mov word [pollfds + rdx * pollfd_size + 4], POLLOUT + push rdx + ; TODO do something to the line + ; problem: we can't write here because the socket may + ; block; + ; how do we deal with multiple lines? + ; XXX call read(2) trying to fill the whole buffer + ; - if we have at least 1 line, + ; update the state and go back to main loop; + ; do whatever logic is necessary until we need to + ; call read(2) or write(2) next, ie nothing; + ; set POLLOUT and process line(s) in write(2) block + ; - if we have no line and we filled the buffer, + ; return -1024 + ; - if we have no line, go back to main loop + ; we could have multiple lines, and that's okay + ; XXX so this plan will work actually + ; XXX should we do logic here or in the write(2) block? + ; probably there, so here we just accumulate lines + ret + +; Returns: +; rax - non-negative from write(2) +; Errors: +; rax - -1024 - no line was buffered +; rax - other negative - from write(2) +; Arguments: ; rdi - fd ; rsi - address of client within clients array ; rdx - pollfds index +; Variables: +; rbx - pollfds index +; r12 - address of client within clients array +; r13 - line length +; r11 - client buffer end of text after call to write(2) client__pollout: - push rdi - push rsi - push rdx + push rbx + push r12 + push r13 + + mov rbx, rdx + mov r12, rsi + + mov rdi, r12 + mov rsi, 255 + call scanline + + ; poll(2)'d for POLLOUT but we had no line buffered; + ; should be impossible + cmp rax, 0 + mov rax, -1024 + je client__pollout__return + + mov r13, rax mov rax, SYS_WRITE - mov rdx, 0 - mov dl, [rsi + 4 + 1] - add rsi, 8 + mov rsi, r12 + add rsi, OFFSET_CLIENT_BUFFER + mov rdx, r13 syscall - pop rdx - pop rsi - pop rdi - + ; error from write(2) cmp rax, 0 - jl return + jl client__pollout__return - mov r10, rsi - add r10, 8 + mov r10, r12 mov r11, 0 - mov r11b, [rsi + 4 + 2] + mov r11b, [r12 + OFFSET_CLIENT_BUFFER_LEN] + add r11, r12 sub r11, rax - add r11, r10 client__pollout__shunt: cmp r10, r11 @@ -80,14 +151,16 @@ client__pollout__shunt: jmp client__pollout__shunt client__pollout__shunt__finished: - sub [rsi + 4 + 2], al ; buffer_len -= rax - sub [rsi + 4 + 1], al ; line_len -= rax - cmp byte [rsi + 4 + 1], 0 - je client__pollout__wrote_line - ret + ; buffer_len -= rax + sub [r12 + OFFSET_CLIENT_BUFFER_LEN], al + cmp rax, r13 + jl client__pollout__return + mov word [pollfds + rbx * pollfd_size + 4], POLLIN -client__pollout__wrote_line: - mov word [pollfds + rdx * pollfd_size + 4], POLLIN +client__pollout__return: + pop r13 + pop r12 + pop rbx ret ; rdi - fd diff --git a/main.s b/main.s index 190f240..3331bd8 100644 --- a/main.s +++ b/main.s @@ -30,11 +30,18 @@ SHUT_RDWR equ 2 ;STATE_READING equ 0 ;STATE_WRITING equ 1 +; offsets into client struct +OFFSET_CLIENT_FD equ 0 +OFFSET_CLIENT_STATE equ 4 +OFFSET_CLIENT_BUFFER_LEN equ 5 +OFFSET_CLIENT_BUFFER equ 6 + pollfd_size equ 4 + 2 + 2 ; $ man 2 poll pollfds_capacity equ 100 -; fd, state, line_len, buffer_len, uri_len, buffer, uri -client_size equ 4 + 4 + 255 + 255 +client_buffer_size equ 255 +; fd, state, buffer_len, buffer +client_size equ 4 + 2 + client_buffer_size clients_capacity equ pollfds_capacity - 1 SECTION .data @@ -109,7 +116,7 @@ scan__found__client: mov r10w, r14w and r10w, POLLERR | POLLNVAL cmp r10w, 0 - jne _client__error + jne _client__error_or_eof mov r10w, r14w and r10w, POLLIN @@ -125,7 +132,7 @@ scan__found__client: add r15, 1 jmp scan__loop -_client__error: +_client__error_or_eof: mov rdi, r12 call clients__remove @@ -142,7 +149,7 @@ _client__pollin: mov rdx, r15 call client__pollin cmp rax, 0 - jle _client__error + jle _client__error_or_eof add r15, rax jmp scan__loop diff --git a/readline.s b/readline.s index 35e30dd..b1698a0 100644 --- a/readline.s +++ b/readline.s @@ -1,43 +1,20 @@ ; Returns: -; rax - read(2) length -; rdi - if line is complete, line length; -; if line was incomplete, 0; -; if EOF or read(2) returned an error, undefined -; Errors (in rax): -; -1024 - line too long -; other negative - error from read(2) -; 0 - EOF from read(2) +; rax - if line: line length; otherwise: 0 ; Arguments: -; rdi - fd -; rsi - buffer -; rdx - max length -readline: - push rsi - push rdx - mov rax, SYS_READ - syscall - pop rdx - pop rsi - cmp rax, 0 - jl return - mov r10, 0 +; rdi - buffer +; rsi - max length +scanline: + mov rax, 0 -readline__scan: - cmp r10, rdx - jge readline__overflow - cmp r10, rax - jge readline__incomplete_line - mov r11b, [rsi + r10] - add r10, 1 - cmp r11b, 0x0a ; '\n' - jne readline__scan - mov rdi, r10 +scanline__loop: + cmp rax, rsi + jge scanline__incomplete_line + mov r10b, [rdi + rax] + add rax, 1 + cmp r10b, 0x0a ; '\n' + jne scanline__loop ret -readline__incomplete_line: - mov rdi, 0 - ret - -readline__overflow: - mov rax, -1024 +scanline__incomplete_line: + mov rax, 0 ret From cbde04fc7c1d0237af2faad74db7bbb1fd97c89d Mon Sep 17 00:00:00 2001 From: root <> Date: Sat, 17 May 2025 08:15:07 +0000 Subject: [PATCH 05/10] client__pollin diagram --- client-pollin.txt | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 client-pollin.txt diff --git a/client-pollin.txt b/client-pollin.txt new file mode 100644 index 0000000..2e0f6b1 --- /dev/null +++ b/client-pollin.txt @@ -0,0 +1,50 @@ +client buffer + +##########++++++++A++++++A+++A++.......... +^ ^ ^ ^ ^ ^ ^ +| | | | | | | +| | | | | | +-- end of buffer +| | | | | | +| | | | | +-- end of read(2) bytes +| | | | | +| | +-- newlines +| | +| +-- start of line scanning +| ++-- start of line + + +# original idea + +- consume many lines in client__pollin +- problem: in the echo server case, we want to write each line but a call to + write(2) may block, so we can't do line processing in client__pollin +- solution: process lines in client__pollout + +i = scan_start +while i < buffer_end: + byte = mem[i] + i += 1 + if byte == '\n': + handle(line_start, i - line_start) + line_start = i + scan_start = i + +if line_start + read(2)_length >= buffer_end: + out_of_memory() + return + +i = line_start +while i < line_start + read(2)_length: + mem[i - line_start + buffer_start] = mem[i] + i += 1 + + +# better idea + +in pollin handler, just read once +indicate to the caller: +- we read a complete line (ie 0x0a is present) +- we read an incomplete non-empty line +- we read nothing (EOF) +- error from read(2) From 05f614b224dd13623e240a9075b0ade2b312b982 Mon Sep 17 00:00:00 2001 From: root <> Date: Sat, 17 May 2025 08:20:30 +0000 Subject: [PATCH 06/10] typo: writing POLLOUT beyond pollfds array bounds --- client.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.s b/client.s index 557898f..a8d670f 100644 --- a/client.s +++ b/client.s @@ -48,7 +48,7 @@ client__pollin: je client__pollin__no_line mov rax, 1 - mov word [pollfds + rdx * pollfd_size + 4], POLLOUT + mov word [pollfds + rbx * pollfd_size + 4], POLLOUT client__pollin__return: pop r14 From 65dc844f54aaa51aebd4db2078e138ac7aca6020 Mon Sep 17 00:00:00 2001 From: root <> Date: Sat, 17 May 2025 08:27:15 +0000 Subject: [PATCH 07/10] typo: writing buffer_len to somewhere undefined --- client.s | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/client.s b/client.s index a8d670f..85fed8d 100644 --- a/client.s +++ b/client.s @@ -38,7 +38,7 @@ client__pollin: jle client__pollin__return ; TODO verify this shit ; buffer_len += read(2) length - add [rsi + OFFSET_CLIENT_BUFFER_LEN], al + add [r12 - OFFSET_CLIENT_BUFFER + OFFSET_CLIENT_BUFFER_LEN], al mov rdi, r13 mov rsi, rax @@ -69,28 +69,6 @@ client__pollin__line_too_long: mov rax, -1024 jmp client__pollin__return -client__pollin__line: - pop rdx - mov word [pollfds + rdx * pollfd_size + 4], POLLOUT - push rdx - ; TODO do something to the line - ; problem: we can't write here because the socket may - ; block; - ; how do we deal with multiple lines? - ; XXX call read(2) trying to fill the whole buffer - ; - if we have at least 1 line, - ; update the state and go back to main loop; - ; do whatever logic is necessary until we need to - ; call read(2) or write(2) next, ie nothing; - ; set POLLOUT and process line(s) in write(2) block - ; - if we have no line and we filled the buffer, - ; return -1024 - ; - if we have no line, go back to main loop - ; we could have multiple lines, and that's okay - ; XXX so this plan will work actually - ; XXX should we do logic here or in the write(2) block? - ; probably there, so here we just accumulate lines - ret ; Returns: ; rax - non-negative from write(2) From 76b53ad30c5b9d1defa63bc3ef91b378e5e27c92 Mon Sep 17 00:00:00 2001 From: root <> Date: Sat, 17 May 2025 08:37:23 +0000 Subject: [PATCH 08/10] fix: negative line length, write(2) to bad fd --- client.s | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client.s b/client.s index 85fed8d..fa59078 100644 --- a/client.s +++ b/client.s @@ -92,15 +92,17 @@ client__pollout: mov rbx, rdx mov r12, rsi + push rdi mov rdi, r12 + add rdi, OFFSET_CLIENT_BUFFER mov rsi, 255 call scanline + pop rdi ; poll(2)'d for POLLOUT but we had no line buffered; ; should be impossible cmp rax, 0 - mov rax, -1024 - je client__pollout__return + je client__pollout__no_line mov r13, rax @@ -135,6 +137,9 @@ client__pollout__shunt__finished: jl client__pollout__return mov word [pollfds + rbx * pollfd_size + 4], POLLIN +client__pollout__no_line: + mov rax, -1024 + client__pollout__return: pop r13 pop r12 From c90622c5647bd45a1ee21b5453cbdf2192873f46 Mon Sep 17 00:00:00 2001 From: root <> Date: Sat, 17 May 2025 08:46:26 +0000 Subject: [PATCH 09/10] fix: client__pollout always returning error, not handling error --- client.s | 7 ++++--- main.s | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/client.s b/client.s index fa59078..38e08cb 100644 --- a/client.s +++ b/client.s @@ -137,15 +137,16 @@ client__pollout__shunt__finished: jl client__pollout__return mov word [pollfds + rbx * pollfd_size + 4], POLLIN -client__pollout__no_line: - mov rax, -1024 - client__pollout__return: pop r13 pop r12 pop rbx ret +client__pollout__no_line: + mov rax, -1024 + jmp client__pollout__return + ; rdi - fd client__shutdown_close: mov rax, SYS_SHUTDOWN diff --git a/main.s b/main.s index 3331bd8..ffa5496 100644 --- a/main.s +++ b/main.s @@ -158,6 +158,8 @@ _client__pollout: mov rsi, r12 mov rdx, r15 call client__pollout + cmp rax, 0 + jle _client__error_or_eof add r15, 1 jmp scan__loop From 44cf92c998c46811753c790c40157e490a5e0388 Mon Sep 17 00:00:00 2001 From: root <> Date: Sat, 17 May 2025 09:07:03 +0000 Subject: [PATCH 10/10] fix: read(2)ing too many bytes --- client.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.s b/client.s index 38e08cb..d3a1e7a 100644 --- a/client.s +++ b/client.s @@ -31,7 +31,7 @@ client__pollin: mov rax, SYS_READ mov rsi, r13 mov rdx, 255 - sub rdx, [rsi + OFFSET_CLIENT_BUFFER_LEN] + sub dl, [rsi + OFFSET_CLIENT_BUFFER_LEN] syscall cmp rax, 0