/programs/network/ftpc/ftpc.asm |
---|
27,6 → 27,7 |
OPERATION_LIST = 1 |
OPERATION_RETR = 2 |
OPERATION_STOR = 3 |
OPERATION_RDIR = 4 |
use32 |
; standard header |
36,7 → 37,7 |
dd i_end ; initialized size |
dd mem+0x1000 ; required memory |
dd mem+0x1000 ; stack pointer |
dd s ; parameters |
dd buf_cmd ; parameters |
dd 0 ; path |
include '../../macros.inc' |
49,6 → 50,11 |
include 'servercommands.inc' |
start: |
; initialize heap for using dynamic blocks |
mcall 68,11 |
test eax,eax |
je exit2 |
; disable all events except network event |
mcall 40, EV_STACK |
; load libraries |
59,7 → 65,7 |
invoke con_start, 1 |
invoke con_init, 80, 25, 80, 250, str_title |
; Check for parameters, if there are some, resolve the address right away |
cmp byte [s], 0 |
cmp byte [buf_cmd], 0 |
jne resolve |
main: |
71,11 → 77,11 |
invoke con_set_flags, 0x0a |
invoke con_write_asciiz, str_prompt |
; read string |
invoke con_gets, s, 256 |
invoke con_gets, buf_cmd, 256 |
; check for exit |
test eax, eax |
jz done |
cmp byte [s], 10 |
cmp byte [buf_cmd], 10 |
jz done |
; reset color back to grey and print newline |
invoke con_set_flags, 0x07 |
83,7 → 89,7 |
resolve: |
; delete terminating '\n' |
mov esi, s |
mov esi, buf_cmd |
@@: |
lodsb |
cmp al, 0x20 |
91,10 → 97,10 |
mov byte [esi-1], 0 |
; Say to the user that we're resolving |
invoke con_write_asciiz, str_resolve |
invoke con_write_asciiz, s |
invoke con_write_asciiz, buf_cmd |
; resolve name |
push esp ; reserve stack place |
invoke getaddrinfo, s, 0, 0, esp |
invoke getaddrinfo, buf_cmd, 0, 0, esp |
pop esi |
; test for error |
test eax, eax |
130,7 → 136,7 |
cmp [offset], 0 |
je .receive ; nope, receive some more |
mov esi, [offset] |
mov edi, s |
mov edi, buf_cmd |
mov ecx, [size] |
add ecx, esi |
jmp .byteloop |
145,7 → 151,7 |
mcall 26, 9 |
cmp eax, [timeout] |
jge error_timeout |
mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT |
mcall recv, [socketnum], buf_buffer1, BUFFERSIZE, MSG_DONTWAIT |
test eax, eax |
jnz .got_data |
cmp ebx, EWOULDBLOCK |
155,10 → 161,10 |
.got_data: |
mov [offset], 0 |
; extract commands, copy them to "s" buffer |
lea ecx, [eax + buffer_ptr] ; ecx = end pointer |
mov esi, buffer_ptr ; esi = current pointer |
mov edi, s |
; extract commands, copy them to "buf_cmd" buffer |
lea ecx, [eax + buf_buffer1] ; ecx = end pointer |
mov esi, buf_buffer1 ; esi = current pointer |
mov edi, buf_cmd |
.byteloop: |
cmp esi, ecx |
jae wait_for_servercommand |
179,12 → 185,12 |
.no_more_data: |
mov [offset], 0 |
.go_cmd: |
lea ecx, [edi - s] ; length of command |
lea ecx, [edi - buf_cmd] ; length of command |
xor al, al |
stosb |
invoke con_set_flags, 0x03 ; change color |
invoke con_write_asciiz, s ; print servercommand |
invoke con_write_asciiz, buf_cmd ; print servercommand |
invoke con_write_asciiz, str_newline |
invoke con_set_flags, 0x07 ; reset color |
194,6 → 200,11 |
wait_for_usercommand: |
; Are there any files in the transfer queue? |
cmp [queued], 0 |
ja transfer_queued ; Yes, transfer those first. |
; change color to green for user input |
invoke con_set_flags, 0x0a |
207,53 → 218,56 |
; write prompt |
invoke con_write_asciiz, str_prompt |
; read string |
invoke con_gets, s, 256 |
invoke con_gets, buf_cmd, 256 |
; print a newline and reset the color back to grey |
invoke con_write_asciiz, str_newline |
invoke con_set_flags, 0x07 |
cmp dword[s], "cwd " |
cmp dword[buf_cmd], "cwd " |
je cmd_cwd |
cmp dword[s], "mkd " |
cmp dword[buf_cmd], "mkd " |
je cmd_mkd |
cmp dword[s], "rmd " |
cmp dword[buf_cmd], "rmd " |
je cmd_rmd |
cmp dword[s], "pwd" + 10 shl 24 |
cmp dword[buf_cmd], "pwd" + 10 shl 24 |
je cmd_pwd |
cmp dword[s], "bye" + 10 shl 24 |
cmp dword[buf_cmd], "bye" + 10 shl 24 |
je cmd_bye |
cmp byte[s+4], " " |
cmp dword[buf_cmd], "rdir" |
je cmd_rdir |
cmp byte[buf_cmd+4], " " |
jne @f |
cmp dword[s], "lcwd" |
cmp dword[buf_cmd], "lcwd" |
je cmd_lcwd |
cmp dword[s], "retr" |
cmp dword[buf_cmd], "retr" |
je cmd_retr |
cmp dword[s], "stor" |
cmp dword[buf_cmd], "stor" |
je cmd_stor |
cmp dword[s], "dele" |
cmp dword[buf_cmd], "dele" |
je cmd_dele |
@@: |
cmp byte[s+4], 10 |
cmp byte[buf_cmd+4], 10 |
jne @f |
cmp dword[s], "list" |
cmp dword[buf_cmd], "list" |
je cmd_list |
cmp dword[s], "help" |
cmp dword[buf_cmd], "help" |
je cmd_help |
cmp dword[s], "cdup" |
cmp dword[buf_cmd], "cdup" |
je cmd_cdup |
@@: |
265,8 → 279,8 |
.connected: |
; request username |
invoke con_write_asciiz, str_user |
mov dword[s], "USER" |
mov byte[s+4], " " |
mov dword[buf_cmd], "USER" |
mov byte[buf_cmd+4], " " |
jmp .send |
273,24 → 287,24 |
.needpass: |
; request password |
invoke con_write_asciiz, str_pass |
mov dword[s], "PASS" |
mov byte[s+4], " " |
mov dword[buf_cmd], "PASS" |
mov byte[buf_cmd+4], " " |
invoke con_set_flags, 0x00 ; black text on black background for password |
.send: |
; read string |
mov esi, s+5 |
mov esi, buf_cmd+5 |
invoke con_gets, esi, 256 |
; find end of string |
mov edi, s+5 |
mov edi, buf_cmd+5 |
mov ecx, 256 |
xor al, al |
repne scasb |
lea esi, [edi-s] |
lea esi, [edi-buf_cmd] |
mov word[edi-2], 0x0a0d |
; and send it to the server |
mcall send, [socketnum], s, , 0 |
mcall send, [socketnum], buf_cmd, , 0 |
invoke con_write_asciiz, str_newline |
invoke con_set_flags, 0x07 ; reset color |
332,6 → 346,10 |
invoke con_set_flags, 0x0c ; print errors in red |
invoke con_write_asciiz, str_err_resolve |
error_heap: |
invoke con_set_flags, 0x0c ; print errors in red |
invoke con_write_asciiz, str_err_heap |
wait_for_keypress: |
invoke con_set_flags, 0x07 ; reset color to grey |
invoke con_write_asciiz, str_push |
344,6 → 362,7 |
exit: |
mcall close, [socketnum] |
exit2: |
mcall -1 |
359,6 → 378,7 |
str_newline db 10,0 |
str_err_resolve db 10,'Name resolution failed.',10,0 |
str_err_socket db 10,'Socket error.',10,0 |
str_err_heap db 10,'Cannot allocate memory from heap.',10,0 |
str_err_timeout db 10,'Timeout - no response from server.',10,0 |
str_err_connect db 10,'Cannot connect to the server.',10,0 |
str8 db ' (',0 |
372,8 → 392,8 |
str_lcwd db "Local working directory is now: ",0 |
str_open db "opening data socket",10,0 |
str_close db "closing data socket",10,0 |
str2b db '.',0 |
str_close db 10,"closing data socket",10,0 |
str_dot db '.',0 |
str_help db "available commands:",10 |
db 10 |
388,8 → 408,10 |
db "retr <file> - retreive file from the server",10 |
db "rmd <directory> - remove directory from the server",10 |
db "stor <file> - store file on the server",10 |
db "rdir - retreive all files from current server dir",10 |
db 10,0 |
queued dd 0 |
; FTP strings |
446,7 → 468,10 |
size dd ? |
operation dd ? |
size_fname dd ? |
ptr_queue dd ? |
timeout dd ? |
ptr_fname_start dd ? |
filestruct: |
.subfn dd ? |
456,9 → 481,8 |
.ptr dd ? |
.name rb 1024 |
buffer_ptr rb BUFFERSIZE+1 |
buffer_ptr2 rb BUFFERSIZE+1 |
buf_buffer1 rb BUFFERSIZE+1 |
buf_buffer2 rb BUFFERSIZE+1 |
buf_cmd rb 1024 ; buffer for holding command string |
s rb 1024 |
mem: |
/programs/network/ftpc/servercommands.inc |
---|
5,40 → 5,40 |
; first lines will have a dash instead of space after numbers, |
; thus they are simply ignored in this simple command parser. |
cmp dword[s], "150 " |
cmp dword[buf_cmd], "150 " |
je data_loop |
cmp dword[s], "220 " |
cmp dword[buf_cmd], "220 " |
je welcome |
; cmp dword[s], "226 " |
; cmp dword[buf_cmd], "226 " |
; je transfer_ok |
cmp dword[s], "227 " |
cmp dword[buf_cmd], "227 " |
je pasv_ok |
cmp dword[s], "230 " |
cmp dword[buf_cmd], "230 " |
je login_ok |
; cmp dword[s], "250" |
; cmp dword[buf_cmd], "250" |
; je op_ok |
cmp dword[s], "331 " |
cmp dword[buf_cmd], "331 " |
je pass |
; cmp dword[s], "421 " |
; cmp dword[buf_cmd], "421 " |
; je timeout |
cmp dword[s], "503 " ; login first |
cmp dword[buf_cmd], "503 " ; login first |
je welcome |
cmp dword[s], "530 " ; password incorrect |
cmp dword[buf_cmd], "530 " ; password incorrect |
je welcome |
cmp dword[s], "550 " |
cmp dword[buf_cmd], "550 " |
je close_datacon |
cmp byte[s+3], "-" |
cmp byte[buf_cmd+3], "-" |
je wait_for_servercommand |
jmp wait_for_usercommand |
66,7 → 66,7 |
sub ecx, 4 |
jb .fail |
mov al, "(" |
mov edi, s + 4 |
mov edi, buf_cmd + 4 |
repne scasb |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
102,27 → 102,30 |
data_loop: |
invoke con_write_asciiz, str2b |
invoke con_write_asciiz, str_dot |
cmp [operation], OPERATION_STOR |
je .stor |
; we are receiving data |
mcall recv, [datasocket], buffer_ptr2, BUFFERSIZE, 0 |
mcall recv, [datasocket], buf_buffer2, BUFFERSIZE, 0 |
test ebx, ebx |
jnz .done |
mov byte[buffer_ptr2 + eax], 0 |
mov byte[buf_buffer2 + eax], 0 |
cmp [operation], OPERATION_RETR |
je .retr |
cmp [operation], OPERATION_RDIR |
je .rdir |
; not retreiving, just print to console |
invoke con_write_asciiz, buffer_ptr2 |
invoke con_write_asciiz, buf_buffer2 |
jmp data_loop |
; retreiving, save to file |
.retr: |
mov [filestruct.ptr], buffer_ptr2 |
mov [filestruct.ptr], buf_buffer2 |
mov [filestruct.size], eax |
push eax |
mcall 70, filestruct |
139,12 → 142,12 |
; jne .fileerror |
add [filestruct.offset], ebx |
mov esi, ebx |
mcall send, [datasocket], buffer_ptr2, , 0 |
mcall send, [datasocket], buf_buffer2, , 0 |
jmp .stor |
.last_call: |
mov esi, ebx |
mcall send, [datasocket], buffer_ptr2, , 0 |
mcall send, [datasocket], buf_buffer2, , 0 |
.done: |
invoke con_write_asciiz, str_close |
153,6 → 156,108 |
jmp wait_for_servercommand |
.rdir: |
cmp [size_fname], 0 |
jne .realloc |
.malloc: ; create a new dynamic block |
mov ecx, eax |
inc ecx |
mcall 68,12 ; eax now points to new buffer |
test eax,eax |
je error_heap |
mov [ptr_fname_start], eax |
jmp .rdir_init |
.realloc: ; expand block created with .malloc |
mov ecx, eax ; eax is size of buffer received |
inc ecx |
add ecx, [size_fname] ; added old size to form new required size |
mcall 68,20,,[ptr_fname_start] |
test eax, eax |
je error_heap |
mov [ptr_fname_start], eax ; eax contains the new block now |
add eax, [size_fname] |
.rdir_init: ; copies filenames into our buffer |
mov esi, buf_buffer2 |
mov edi, eax |
.copy_buf: |
lodsb |
cmp al,13 ; ignore any \r character |
je .copy_buf |
stosb |
cmp al, 10 |
jne .not_end |
inc [queued] |
.not_end: |
test al,al |
jne .copy_buf |
dec edi |
dec edi |
mov eax, [ptr_fname_start] |
mov [ptr_queue], eax |
sub edi, eax ; edi contains the current size now |
mov [size_fname], edi |
jmp data_loop |
; files for rdir operation are queued |
transfer_queued: |
mov esi, [ptr_queue] ; always pointing to current part of ptr_fname_start |
mov edi, buf_cmd+5 ; always point to filename for retr command |
.build_filename: |
lodsb |
stosb |
cmp al,10 |
je .get_file ; filename ends with character 10 |
test al,al |
jz .null_found ; this should be end of buffer |
jmp .build_filename |
.null_found: |
mov [queued],0 |
jmp .free |
.get_file: |
dec [queued] |
jnz .after_free |
.free: |
mcall 68,13,[ptr_fname_start] ; freeing the buffer |
test eax,eax |
jz error_heap |
jmp wait_for_usercommand |
.after_free: |
xor al,al ; appending 0 after retr command |
stosb |
mov eax, esi |
mov [ptr_queue], eax |
jmp cmd_retr |
close_datacon: |
cmp [operation], OPERATION_NONE |
je wait_for_usercommand |
/programs/network/ftpc/usercommands.inc |
---|
9,9 → 9,9 |
cmd_bye: |
; Send BYE message to the server |
mov dword[s], "BYE" + 13 shl 24 |
mov byte[s+4], 10 |
mcall send, [socketnum], s, 5, 0 |
mov dword[buf_cmd], "BYE" + 13 shl 24 |
mov byte[buf_cmd+4], 10 |
mcall send, [socketnum], buf_cmd, 5, 0 |
; Close the control connection |
mcall close, [socketnum] |
20,9 → 20,9 |
cmd_pwd: |
mov dword[s], "PWD" + 13 shl 24 |
mov byte[s+4], 10 |
mcall send, [socketnum], s, 5, 0 |
mov dword[buf_cmd], "PWD" + 13 shl 24 |
mov byte[buf_cmd+4], 10 |
mcall send, [socketnum], buf_cmd, 5, 0 |
jmp wait_for_servercommand |
29,16 → 29,16 |
cmd_cwd: |
mov dword[s], "CWD " |
mov dword[buf_cmd], "CWD " |
mov ecx, 256 |
xor al, al |
mov edi, s |
mov edi, buf_cmd |
repne scasb |
lea esi, [edi - s] |
lea esi, [edi - buf_cmd] |
mov word [edi - 2], 0x0a0d |
mcall send, [socketnum], s, , 0 |
mcall send, [socketnum], buf_cmd, , 0 |
jmp wait_for_servercommand |
45,17 → 45,17 |
cmd_dele: |
mov dword[s], "DELE" |
mov byte[s], " " |
mov dword[buf_cmd], "DELE" |
mov byte[buf_cmd], " " |
mov ecx, 256 |
xor al, al |
mov edi, s |
mov edi, buf_cmd |
repne scasb |
lea esi, [edi - s] |
lea esi, [edi - buf_cmd] |
mov word [edi - 2], 0x0a0d |
mcall send, [socketnum], s, , 0 |
mcall send, [socketnum], buf_cmd, , 0 |
jmp wait_for_servercommand |
65,9 → 65,9 |
mov [operation], OPERATION_LIST |
mov dword[s], "LIST" |
mov word[s+4], 0x0a0d |
mcall send, [socketnum], s, 6, 0 |
mov dword[buf_cmd], "LIST" |
mov word[buf_cmd+4], 0x0a0d |
mcall send, [socketnum], buf_cmd, 6, 0 |
jmp wait_for_servercommand |
77,7 → 77,9 |
; Create/open the file |
mov esi, s+5 |
; Create/open the file |
mov esi, buf_cmd+5 |
mov ecx, 256-5 |
call set_filename |
98,21 → 100,35 |
; Request the file from server |
mov dword[s], "RETR" |
mov byte[s+4], " " |
mov dword[buf_cmd], "RETR" |
mov byte[buf_cmd+4], " " |
mov ecx, 256 |
xor al, al |
mov edi, s |
mov edi, buf_cmd |
repne scasb |
lea esi, [edi - s] |
lea esi, [edi - buf_cmd] |
mov dword[edi - 2], 0x0a0d |
mcall send, [socketnum], s, , 0 |
mcall send, [socketnum], buf_cmd, , 0 |
invoke con_write_asciiz, s ; print command |
invoke con_write_asciiz, buf_cmd ; print command |
jmp wait_for_servercommand |
cmd_rdir: |
mov [operation], OPERATION_RDIR |
; Request filename list from the server |
call open_dataconnection |
mov [size_fname], 0 |
mov dword[buf_cmd], "NLST" |
mov word[buf_cmd+4], 0x0a0d |
mcall send, [socketnum], buf_cmd, 6, 0 |
jmp wait_for_servercommand |
cmd_stor: |
call open_dataconnection |
123,22 → 139,22 |
mov [filestruct.offset], 0 |
mov [filestruct.offset+4], 0 |
mov [filestruct.size], BUFFERSIZE |
mov [filestruct.ptr], buffer_ptr2 |
mov [filestruct.ptr], buf_buffer2 |
mov esi, s+5 |
mov esi, buf_cmd+5 |
mov ecx, 256-5 |
call set_filename |
mov dword[s], "STOR" |
mov byte[s+4], " " |
mov dword[buf_cmd], "STOR" |
mov byte[buf_cmd+4], " " |
mov ecx, 256 |
xor al, al |
mov edi, s |
mov edi, buf_cmd |
repne scasb |
lea esi, [edi - s] |
lea esi, [edi - buf_cmd] |
mov word [edi - 2], 0x0a0d |
mcall send, [socketnum], s, , 0 |
mcall send, [socketnum], buf_cmd, , 0 |
jmp wait_for_servercommand |
145,7 → 161,7 |
cmd_lcwd: |
mov esi, s+5 |
mov esi, buf_cmd+5 |
mov ecx, 256-5 |
.loop: |
lodsb |
156,11 → 172,11 |
loop .loop |
.done: |
mov byte[esi-1], 0 |
mcall 30, 1, s+5 ; set working directory |
mcall 30, 2, s, 256 ; and read it again |
mcall 30, 1, buf_cmd+5 ; set working directory |
mcall 30, 2, buf_cmd, 256 ; and read it again |
invoke con_write_asciiz, str_lcwd |
invoke con_write_asciiz, s |
invoke con_write_asciiz, buf_cmd |
invoke con_write_asciiz, str_newline |
jmp wait_for_usercommand |
168,9 → 184,9 |
cmd_cdup: |
mov dword[s], "CDUP" |
mov word[s+4], 0x0d0a |
mcall send, [socketnum], s, 6, 0 |
mov dword[buf_cmd], "CDUP" |
mov word[buf_cmd+4], 0x0d0a |
mcall send, [socketnum], buf_cmd, 6, 0 |
jmp wait_for_servercommand |
177,16 → 193,16 |
cmd_rmd: |
mov dword[s], "RMD " |
mov dword[buf_cmd], "RMD " |
mov ecx, 256 |
xor al, al |
mov edi, s |
mov edi, buf_cmd |
repne scasb |
lea esi, [edi - s] |
lea esi, [edi - buf_cmd] |
mov word [edi - 2], 0x0a0d |
mcall send, [socketnum], s, , 0 |
mcall send, [socketnum], buf_cmd, , 0 |
jmp wait_for_servercommand |
193,16 → 209,16 |
cmd_mkd: |
mov dword[s], "MKD " |
mov dword[buf_cmd], "MKD " |
mov ecx, 256 |
xor al, al |
mov edi, s |
mov edi, buf_cmd |
repne scasb |
lea esi, [edi - s] |
lea esi, [edi - buf_cmd] |
mov word [edi - 2], 0x0a0d |
mcall send, [socketnum], s, , 0 |
mcall send, [socketnum], buf_cmd, , 0 |
jmp wait_for_servercommand |