Added multithread-capabilities to FTPd (net branch)

git-svn-id: svn://kolibrios.org@2578 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr 2012-04-06 18:37:00 +00:00
parent d324897069
commit 0d44338d5d
2 changed files with 356 additions and 254 deletions

View File

@ -1,9 +1,40 @@
struct thread_data
rb 1024
stack rb 0
home_dir rb 1024
work_dir rb 1024
fpath rb 1024*3
type db ? ; ASCII/EBDIC/IMAGE/..
mode db ? ; active/passive
socketnum dd ? ; Commands socket
state dd ? ; disconnected/logging in/logged in/..
passivesocknum dd ? ; when in passive mode, this is the listening socket
datasocketnum dd ? ; socket used for data transfers
datasock sockaddr_in
buffer rb BUFFERSIZE
ends
align 4 align 4
parse_cmd: ; esi must point to command parse_cmd: ; esi must point to command
cmp byte [esi], 0x20 ; skip all leading characters
ja .ok
inc esi
dec ecx
cmp ecx, 3
ja parse_cmd
ret
.ok:
cmp byte [esi+3], 0x20 cmp byte [esi+3], 0x20
jae @f jae @f
mov byte [esi+3], 0 mov byte [esi+3], 0
@ -24,7 +55,7 @@ parse_cmd: ; esi must point to command
jne .scanloop jne .scanloop
.error: .error:
mcall send, [socketnum2], str500, str500.length, 0 mcall send, [edx + thread_data.socketnum], str500, str500.length, 0
ret ret
@ -74,17 +105,19 @@ commands: ; all commands must be in uppercase
align 4 align 4
cmdABOR: cmdABOR:
; TODO: abort the current filetransfer
ret ret
align 4 align 4
cmdCDUP: cmdCDUP:
cmp byte [work_dir+1], 0 cmp byte [edx + thread_data.work_dir+1], 0
je .done je .done
mov ecx, 1024 mov ecx, 1024
xor al, al xor al, al
mov edi, work_dir+1024 lea edi, [edx + thread_data.work_dir+1024]
repne scasb repne scasb
std std
dec edi dec edi
@ -94,9 +127,7 @@ cmdCDUP:
mov byte[edi], 0 mov byte[edi], 0
.done: .done:
mcall send, [socketnum2], str250, str250.length, 0 ; command successful mcall send, [edx + thread_data.socketnum], str250, str250.length, 0 ; command successful
ret ret
align 4 align 4
@ -107,7 +138,16 @@ cmdCWD: ; Change Working Directory
add esi, 4 add esi, 4
.scan: .scan:
mov edi, work_dir + 1 lea edi, [edx + thread_data.work_dir + 1]
push ecx
mov ecx, 1024
.find_zero:
cmp byte [edi], 0
je .found_zero
inc edi
loop .find_zero
.found_zero:
pop ecx
cmp byte [esi], '/' cmp byte [esi], '/'
jne @f jne @f
@ -133,7 +173,7 @@ cmdCWD: ; Change Working Directory
@@: @@:
mov byte [edi], 0 mov byte [edi], 0
mcall send, [socketnum2], str250, str250.length, 0 mcall send, [edx + thread_data.socketnum], str250, str250.length, 0
ret ret
@ -142,10 +182,11 @@ cmdCWD: ; Change Working Directory
cmp al, '.' cmp al, '.'
jne .continue jne .continue
call cmdCDUP ;;;; call cmdCDUP ;;;;;; FIXME
jmp .scan jmp .scan
.err: .err:
; TODO: print correct error message (550?)
ret ret
@ -158,18 +199,23 @@ align 4
cmdLIST: cmdLIST:
; If we are in active mode, it's time to open a data socket.. ; If we are in active mode, it's time to open a data socket..
cmp [mode], MODE_ACTIVE cmp [edx + thread_data.mode], MODE_ACTIVE
jne @f jne @f
mcall connect, [datasocketnum], datasock, datasock.length mov ecx, [edx + thread_data.datasocketnum]
lea edx, [edx + thread_data.datasock]
mov esi, sizeof.thread_data.datasock
mcall connect
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1 cmp eax, -1
je socketerror je socketerror
mov [datasocketnum], eax mov [edx + thread_data.datasocketnum], eax
@@: @@:
; Create fpath from home_dir and work_dir ; Create fpath from home_dir and work_dir
call create_path call create_path
push fpath lea eax, [edx + thread_data.fpath]
push eax
call [con_write_asciiz] call [con_write_asciiz]
push str_newline push str_newline
call [con_write_asciiz] call [con_write_asciiz]
@ -177,21 +223,24 @@ cmdLIST:
; Start the search ; Start the search
push FA_ANY push FA_ANY
push str_mask push str_mask
push fpath lea eax, [edx + thread_data.fpath]
push eax
call [file.find.first] call [file.find.first]
mov edi, buffer test eax, eax
jz .nosuchdir
lea edi, [edx + thread_data.buffer]
.parse_file: .parse_file:
test eax, eax ; did we find a file? test eax, eax ; did we find a file?
jz .done jz .done
mov ebx, eax ; yes, save the descripter in ebx
mov edx, eax ; yes, save the descripter
; first, convert the attributes ; first, convert the attributes
test [edx + FileInfoA.Attributes], FA_FOLDER test [ebx + FileInfoA.Attributes], FA_FOLDER
jnz .folder jnz .folder
test [edx + FileInfoA.Attributes], FA_READONLY test [ebx + FileInfoA.Attributes], FA_READONLY
jnz .readonly jnz .readonly
mov eax, '-rw-' mov eax, '-rw-'
@ -225,32 +274,32 @@ cmdLIST:
stosd stosd
; now the filesize in ascii ; now the filesize in ascii
mov ebx, [edx + FileInfoA.FileSizeLow] mov eax, [ebx + FileInfoA.FileSizeLow]
call dword_to_ascii call dword_to_ascii
mov al, ' ' mov al, ' '
stosb stosb
; then date (month/day/year) ; then date (month/day/year)
movzx ebx, [edx + FileInfoA.DateModify + FileDateTime.month] movzx eax, [ebx + FileInfoA.DateModify + FileDateTime.month]
mov eax, [months + 4*ebx] mov eax, [months + 4*eax]
stosd stosd
movzx ebx, [edx + FileInfoA.DateModify + FileDateTime.day] movzx eax, [ebx + FileInfoA.DateModify + FileDateTime.day]
call dword_to_ascii call dword_to_ascii
mov al, ' ' mov al, ' '
stosb stosb
movzx ebx, [edx + FileInfoA.DateModify + FileDateTime.year] movzx eax, [ebx + FileInfoA.DateModify + FileDateTime.year]
call dword_to_ascii call dword_to_ascii
mov al, ' ' mov al, ' '
stosb stosb
; and last but not least, filename ; and last but not least, filename
lea esi, [edx + FileInfoA.FileName] lea esi, [ebx + FileInfoA.FileName]
mov ecx, 250 mov ecx, 264
.nameloop: .nameloop:
lodsb lodsb
test al, al test al, al
@ -264,13 +313,13 @@ cmdLIST:
stosw stosw
; check next file ; check next file
push edx push ebx
call [file.find.next] call [file.find.next]
jmp .parse_file jmp .parse_file
; close file desc ; close file desc
.done: .done:
push edx push ebx
call [file.find.close] call [file.find.close]
; append the string with a 0 ; append the string with a 0
@ -278,22 +327,33 @@ cmdLIST:
stosb stosb
; Warn the client we're about to send the data ; Warn the client we're about to send the data
mcall send, [socketnum2], str150, str150.length, 0 ; here it comes.. push edi edx
mcall send, [edx + thread_data.socketnum], str150, str150.length, 0 ; here it comes..
pop edx esi
; and send it to the client ; and send it to the client
lea esi, [edi - buffer] mov ecx, [edx + thread_data.datasocketnum]
mcall send, [datasocketnum], buffer, , 0 lea edx, [edx + thread_data.buffer]
sub esi, edx
xor edi, edi
mcall send
; close the data socket.. ; close the data socket..
mcall close, [datasocketnum] mov edx, [esp+4] ; thread_data pointer
mcall close, [edx + thread_data.datasocketnum]
cmp [mode], MODE_PASSIVE_OK cmp [edx + thread_data.mode], MODE_PASSIVE_OK
jne @f jne @f
mov [mode], MODE_PASSIVE_WAIT mov [edx + thread_data.mode], MODE_NOTREADY
@@: @@:
; And send "transfer ok" on the base connection ; And send "transfer ok" on the base connection
mcall send, [socketnum2], str226, str226.length, 0 mcall send, [edx + thread_data.socketnum], str226, str226.length, 0
ret
.nosuchdir:
mcall send, [edx + thread_data.socketnum], str550, str550.length, 0
ret ret
@ -301,6 +361,8 @@ cmdLIST:
align 4 align 4
cmdNLST: cmdNLST:
; TODO: same as list but simpler output format
ret ret
align 4 align 4
@ -311,38 +373,51 @@ cmdNOOP:
align 4 align 4
cmdPASS: cmdPASS:
mcall send, [socketnum2], str230, str230.length, 0 ; TODO: verify password
mcall send, [edx + thread_data.socketnum], str230, str230.length, 0
push str_pass_ok push str_pass_ok
call [con_write_asciiz] call [con_write_asciiz]
mov [state], STATE_ACTIVE mov edx, [esp+4] ; thread_data pointer
mov [edx + thread_data.state], STATE_ACTIVE
ret ret
align 4 align 4
cmdPASV: cmdPASV:
; 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) ; Open a new TCP socket
; where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number.
mcall socket, AF_INET4, SOCK_STREAM, 0 mcall socket, AF_INET4, SOCK_STREAM, 0
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1 cmp eax, -1
; je .err je socketerror
mov [passivesocknum], eax mov [edx + thread_data.passivesocknum], eax
mov [datasock.port], 2000 ; Bind it to a known local port
mov [datasock.ip], 0 mov [edx + thread_data.datasock.sin_family], AF_INET4
mov [edx + thread_data.datasock.sin_port], 2000
mov [edx + thread_data.datasock.sin_addr], 0
mcall bind, [passivesocknum], datasock, datasock.length mov ecx, eax ;[edx + thread_data.passivesocknum]
lea edx, [edx + thread_data.datasock]
mcall bind, , , sizeof.thread_data.datasock
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1 cmp eax, -1
je bind_err je bind_err
mcall listen, [passivesocknum], 1 ; And set it to listen!
mcall listen, [edx + thread_data.passivesocknum], 10 ;;;;; FIXME
mov [mode], MODE_PASSIVE_WAIT ; Tell our thread we are ready to accept incoming calls
mov edx, [esp+4] ; thread_data pointer
mov [edx + thread_data.mode], MODE_PASSIVE_WAIT
mov edi, buffer ; Now tell the client where to connect to in this format:
; 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
; where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number.
lea edi, [edx + thread_data.buffer]
mov eax, '227 ' ; FIXME (now hardcoded to 127.0.0.1:2000) mov eax, '227 ' ; FIXME (now hardcoded to 127.0.0.1:2000)
stosd stosd
mov eax, '(127' mov eax, '(127'
@ -360,20 +435,22 @@ cmdPASV:
xor al, al xor al, al
stosb stosb
lea esi, [edi - buffer] lea esi, [edi - thread_data.buffer]
sub esi, edx
mcall send, [socketnum2], buffer, ,0 mov ecx, [edx + thread_data.socketnum]
lea edx, [edx + thread_data.buffer]
mcall send, , , ,0
ret ret
align 4 align 4
cmdPWD: ; Print Working Directory cmdPWD: ; Print Working Directory
mov dword[buffer], '257 ' mov dword [edx + thread_data.buffer], '257 '
mov byte[buffer+4], '"' mov byte [edx + thread_data.buffer+4], '"'
lea edi, [buffer+5] lea edi, [edx + thread_data.buffer+5]
mov esi, work_dir lea esi, [edx + thread_data.work_dir]
mov ecx, 1024 mov ecx, 1024
.loop: .loop:
lodsb lodsb
@ -384,10 +461,12 @@ cmdPWD: ; Print Working Directory
jnz .loop jnz .loop
.ok: .ok:
mov dword[edi], '"' + 0x000a0d00 ; '"',13,10,0 mov dword [edi], '"' + 0x000a0d00 ; '"',13,10,0
lea esi, [edi - buffer + 4] lea esi, [edi - thread_data.buffer + 4]
sub esi, edx
mcall send, [socketnum2], buffer, , 0 mov ecx, [edx + thread_data.socketnum]
lea edx, [edx + thread_data.buffer]
mcall send, , , , 0
; push work_dir ; push work_dir
; push str_pwd ; push str_pwd
@ -401,55 +480,59 @@ cmdPORT:
; PORT a1,a2,a3,a4,p1,p2 ; PORT a1,a2,a3,a4,p1,p2
; IP address a1.a2.a3.a4, port p1*256+p2 ; IP address a1.a2.a3.a4, port p1*256+p2
mov [mode], MODE_ACTIVE mov [edx + thread_data.mode], MODE_ACTIVE
lea esi, [esi+5] lea esi, [esi+5]
xor edx, edx ; Convert the IP
call ascii_to_byte call ascii_to_byte
mov dh, bl mov bh, al
inc esi ; skip past ','
call ascii_to_byte
mov bl, al
shl ebx, 16
inc esi inc esi
call ascii_to_byte call ascii_to_byte
mov dl, bl mov bh, al
shl edx, 16
inc esi inc esi
call ascii_to_byte call ascii_to_byte
mov dh, bl mov bl, al
inc esi
call ascii_to_byte
mov dl, bl
inc esi inc esi
mov [datasock.ip], edx ; And put it in datasock
mov [edx + thread_data.datasock.sin_addr], ebx
; Now the same with portnumber
call ascii_to_byte call ascii_to_byte
mov dh, bl mov bh, al
inc esi inc esi
call ascii_to_byte call ascii_to_byte
mov dl, bl mov bl, al
mov [datasock.port], dx ; Save it in datasock too
mov [edx + thread_data.datasock.sin_port], bx
; We will open the socket, but do not connect yet!
mov [edx + thread_data.datasock.sin_family], AF_INET4
mcall socket, AF_INET4, SOCK_STREAM, 0 mcall socket, AF_INET4, SOCK_STREAM, 0
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1 cmp eax, -1
je .err je socketerror
mov [datasocketnum], eax mov [edx + thread_data.datasocketnum], eax
mcall send, [socketnum2], str225, str225.length, 0 ; Tell the client we are ready
mov edx, [esp+4] ; thread_data pointer
mcall send, [edx + thread_data.socketnum], str225, str225.length, 0
ret ret
.err:
mcall send, [socketnum2], str425, str425.length, 0
ret
align 4 align 4
cmdQUIT: cmdQUIT:
mcall send, [socketnum2], str221, str221.length, 0 mcall close, [edx + thread_data.datasocketnum]
mcall close, [socketnum2] mcall send, [edx + thread_data.socketnum], str221, str221.length, 0 ; 221 - bye!
mcall close;, [edx + thread_data.socketnum]
ret jmp thread_exit ; now close this thread
align 4 align 4
cmdRETR: cmdRETR:
@ -457,14 +540,17 @@ cmdRETR:
sub ecx, 5 sub ecx, 5
jb .cannot_open jb .cannot_open
cmp [mode], MODE_ACTIVE cmp [edx + thread_data.mode], MODE_ACTIVE
jne @f jne @f
push esi push esi
mcall connect, [datasocketnum], datasock, datasock.length mov ecx, [edx + thread_data.datasocketnum]
lea edx, [edx + thread_data.datasock]
mcall connect, , , sizeof.thread_data.datasock
pop esi pop esi
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1 cmp eax, -1
je socketerror je socketerror
mov [datasocketnum], eax mov [edx + thread_data.datasocketnum], eax
@@: @@:
push esi push esi
@ -483,24 +569,28 @@ cmdRETR:
xor al, al xor al, al
stosb stosb
push fpath lea eax, [edx + thread_data.fpath]
push eax
call [con_write_asciiz] call [con_write_asciiz]
push str_newline push str_newline
call [con_write_asciiz] call [con_write_asciiz]
push O_READ push O_READ
push fpath lea eax, [edx + thread_data.fpath]
push eax
call [file.open] call [file.open]
test eax, eax test eax, eax
jz .cannot_open jz .cannot_open
push eax push eax
mcall send, [socketnum2], str150, str150.length, 0 ; here it comes.. mcall send, [edx + thread_data.socketnum], str150, str150.length, 0 ; here it comes..
pop ebx pop ebx
mov edx, [esp+4] ; thread_data pointer
.read_more: .read_more:
push BUFFERSIZE push BUFFERSIZE
push buffer lea eax, [edx + thread_data.buffer]
push eax
push ebx push ebx
call [file.read] call [file.read]
cmp eax, -1 cmp eax, -1
@ -509,57 +599,58 @@ cmdRETR:
push eax push eax
push ebx push ebx
mov esi, eax mov esi, eax
mcall send, [datasocketnum], buffer, , 0 mov ecx, [edx + thread_data.datasocketnum]
lea edx, [edx + thread_data.buffer]
mcall send, , , , 0
pop ebx pop ebx
pop ecx pop ecx
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1 cmp eax, -1
je socketerror je socketerror
cmp ecx, BUFFERSIZE cmp ecx, BUFFERSIZE
je .read_more je .read_more
mcall close, [datasocketnum] mcall close, [edx + thread_data.datasocketnum]
cmp [mode], MODE_PASSIVE_OK cmp [edx + thread_data.mode], MODE_PASSIVE_OK
jne @f jne @f
mov [mode], MODE_PASSIVE_WAIT mov [edx + thread_data.mode], MODE_PASSIVE_WAIT
@@: @@:
mcall send, [socketnum2], str226, str226.length, 0 ; transfer ok mcall send, [edx + thread_data.socketnum], str226, str226.length, 0 ; transfer ok
ret ret
.cannot_open: .cannot_open:
pushd 0x0c pushd 0x0c
call [con_set_flags] call [con_set_flags]
push str_notfound push str_notfound
call [con_write_asciiz] call [con_write_asciiz]
pushd 0x07 pushd 0x07
call [con_set_flags] call [con_set_flags]
mcall send, [socketnum2], str550, str550.length, 0 ; file not found mcall send, [edx + thread_data.socketnum], str550, str550.length, 0 ; file not found
ret ret
align 4 align 4
cmdSTOR: cmdSTOR:
; TODO: check if user has write permission, and write file if so
ret ret
align 4 align 4
cmdSYST: cmdSYST:
mcall send, [socketnum2], str215, str215.length, 0 mcall send, [edx + thread_data.socketnum], str215, str215.length, 0
ret ret
align 4 align 4
cmdTYPE: cmdTYPE:
cmp ecx, 6 cmp ecx, 6
jb parse_cmd.error jb parse_cmd.error
@ -578,11 +669,11 @@ cmdTYPE:
jmp parse_cmd.error jmp parse_cmd.error
.ascii: .ascii:
mov [type], TYPE_ASCII mov [edx + thread_data.type], TYPE_ASCII
jmp .subtype jmp .subtype
.ebdic: .ebdic:
mov [type], TYPE_EBDIC mov [edx + thread_data.type], TYPE_EBDIC
.subtype: .subtype:
@ -602,19 +693,19 @@ cmdTYPE:
jmp parse_cmd.error jmp parse_cmd.error
.non_print: .non_print:
or [type], TYPE_NP or [edx + thread_data.type], TYPE_NP
jmp .ok jmp .ok
.telnet: .telnet:
or [type], TYPE_TELNET or [edx + thread_data.type], TYPE_TELNET
jmp .ok jmp .ok
.asacc: .asacc:
or [type], TYPE_ASA or [edx + thread_data.type], TYPE_ASA
jmp .ok jmp .ok
.image: .image:
mov [type], TYPE_IMAGE mov [edx + thread_data.type], TYPE_IMAGE
jmp .ok jmp .ok
.local: .local:
@ -627,21 +718,24 @@ cmdTYPE:
cmp al, 9 cmp al, 9
ja parse_cmd.error ja parse_cmd.error
or al, TYPE_LOCAL or al, TYPE_LOCAL
mov [type], al mov [edx + thread_data.type], al
.ok: .ok:
mcall send, [socketnum2], str200, str200.length, 0 mcall send, [edx + thread_data.socketnum], str200, str200.length, 0
ret ret
align 4 align 4
cmdUSER: cmdUSER:
mcall send, [socketnum2], str331, str331.length, 0 ; TODO: check user and set home directory (and permissions)
mov [state], STATE_LOGIN
mov byte [work_dir], "/" mcall send, [edx + thread_data.socketnum], str331, str331.length, 0
mov byte [work_dir+1], 0 mov edx, [esp+4] ; thread_data pointer
mov [edx + thread_data.state], STATE_LOGIN
mov byte [edx + thread_data.work_dir], "/"
mov byte [edx + thread_data.work_dir+1], 0
push str_logged_in push str_logged_in
call [con_write_asciiz] call [con_write_asciiz]
@ -650,34 +744,31 @@ cmdUSER:
align 4 ; esi = ptr to str, output in eax
align 4 ; esi = ptr to str
ascii_to_byte: ascii_to_byte:
xor ebx, ebx xor eax, eax
push ebx
.loop: .loop:
movzx ebx, byte[esi]
movzx eax, byte[esi] sub bl, '0'
sub al, '0'
jb .done jb .done
cmp al, 9 cmp bl, 9
ja .done ja .done
lea ebx, [ebx*4 + ebx] lea eax, [eax*4 + eax] ;
shl ebx, 1 shl eax, 1 ; eax = eax * 10
add ebx, eax add eax, ebx
inc esi inc esi
jmp .loop jmp .loop
.done: .done:
pop ebx
ret ret
align 4 align 4
dword_to_ascii: ; edi = ptr where to write, ebx is number dword_to_ascii: ; edi = ptr where to write, eax is number
mov eax, '1' mov eax, '1'
stosb stosb
@ -686,8 +777,8 @@ dword_to_ascii: ; edi = ptr where to write, ebx is number
align 4 align 4
create_path: ; combine home_dir and work_dir strings into fpath create_path: ; combine home_dir and work_dir strings into fpath
mov edi, fpath lea edi, [edx + thread_data.fpath]
mov esi, home_dir lea esi, [edx + thread_data.home_dir]
mov ecx, 1024 mov ecx, 1024
.loop1: .loop1:
@ -703,7 +794,7 @@ create_path: ; combine home_dir and work_dir strings into fpath
dec edi dec edi
@@: @@:
mov esi, work_dir lea esi, [edx + thread_data.work_dir]
mov ecx, 1024 mov ecx, 1024
.loop2: .loop2:
@ -724,14 +815,12 @@ socketerror:
pushd 0x0c pushd 0x0c
call [con_set_flags] call [con_set_flags]
push str_sockerr push str_sockerr
call [con_write_asciiz] call [con_write_asciiz]
pushd 0x07 pushd 0x07
call [con_set_flags] call [con_set_flags]
mcall send, [socketnum2], str425, str425.length, 0 ; data connection error mcall send, [edx + thread_data.socketnum], str425, str425.length, 0 ; data connection error
ret ret

View File

@ -38,7 +38,7 @@ use32
dd i_end ; initialized size dd i_end ; initialized size
dd mem+0x1000 ; required memory dd mem+0x1000 ; required memory
dd mem+0x1000 ; stack pointer dd mem+0x1000 ; stack pointer
dd 0 ; parameters dd params ; parameters
dd path ; path dd path ; path
include '../macros.inc' include '../macros.inc'
@ -58,13 +58,15 @@ start:
test eax, eax test eax, eax
jnz exit jnz exit
mcall 68, 11 ; init heap
; find path to main settings file ; find path to main settings file
mov edi, path ; Calculate the length of zero-terminated string mov edi, path ; Calculate the length of zero-terminated string
xor al , al xor al , al
mov ecx, 1024 mov ecx, 1024
repne scasb repne scasb
dec edi dec edi
mov esi, filename mov esi, filename ; append it with '.ini'
movsd movsd
movsb movsb
@ -121,85 +123,99 @@ start:
push str2b push str2b
call [con_write_asciiz] call [con_write_asciiz]
mcall 10 mainloop:
mcall 10 ; Wait here for incoming connections on the base socket (socketnum)
mcall accept, [socketnum], sockaddr1, sockaddr1.length mcall 51, 1, threadstart, 0 ; Start a new thread for every incoming connection
; NOTE: upon initialisation of the thread, stack will not be available!
jmp mainloop
threadstart:
mcall 68, 12, sizeof.thread_data ; allocate the thread data struct
cmp eax, -1 cmp eax, -1
je acpt_err je exit
mov [socketnum2], eax lea esp, [eax + thread_data.stack] ; init stack
push eax ; save pointer to thread_data on stack
mcall send, [socketnum2], str220, str220.length, 0 ; send welcome string mcall 40, 1 shl 7 ; we only want network events for this thread
.loop: push str8
call [con_write_asciiz] ; print on the console that we have created the new thread successfully
mcall accept, [socketnum], sockaddr1, sockaddr1.length ; time to accept the awaiting connection..
cmp eax, -1
je thread_exit
mov edx, [esp] ; pointer to thread_data
mov [edx + thread_data.socketnum], eax
mcall send, [edx + thread_data.socketnum], str220, str220.length, 0 ; send welcome string to the FTP client
threadloop:
mcall 10 mcall 10
cmp [mode], MODE_PASSIVE_WAIT mov edx, [esp] ; pointer to thread_data
cmp [edx + thread_data.mode], MODE_PASSIVE_WAIT
jne @f jne @f
mcall accept, [passivesocknum], datasock, datasock.length mov ecx, [edx + thread_data.passivesocknum]
lea edx, [edx + thread_data.datasock]
mov esi, sizeof.thread_data.datasock
mcall accept
mov edx, [esp] ; pointer to thread_data
cmp eax, -1 cmp eax, -1
je @f je @f
mov [datasocketnum], eax mov [edx + thread_data.datasocketnum], eax
mov [mode], MODE_PASSIVE_OK mov [edx + thread_data.mode], MODE_PASSIVE_OK
push str_datasock push str_datasock
call [con_write_asciiz] call [con_write_asciiz] ; print on the console that the datasock is now ready
@@: @@:
mcall recv, [socketnum2], buffer, buffer.length mov ecx, [edx + thread_data.socketnum]
cmp eax, -1 lea edx, [edx + thread_data.buffer]
je .loop mov esi, sizeof.thread_data.buffer
or eax, eax mcall recv
jz .loop cmp eax, -1 ; error?
push eax je threadloop
or eax, eax ; 0 bytes read?
jz threadloop
push eax ; save number of bytes read on stack
mov byte[buffer+eax], 0 mov edx, [esp+4] ; pointer to thread_data
mov byte [edx + thread_data.buffer + eax], 0 ; append received data with a 0 byte
pushd 0x0a pushd 0x0a ; print received data to console (in green color)
call [con_set_flags] call [con_set_flags]
push buffer lea eax, [edx + thread_data.buffer]
push eax
call [con_write_asciiz] call [con_write_asciiz]
pushd 0x07 pushd 0x07
call [con_set_flags] call [con_set_flags]
pop ecx pop ecx ; number of bytes read
mov esi, buffer lea esi, [edx + thread_data.buffer]
call parse_cmd call parse_cmd
jmp .loop jmp threadloop
acpt_err:
pushd 0x0c
call [con_set_flags]
push str8
call [con_write_asciiz]
jmp done
listen_err: listen_err:
pushd 0x0c pushd 0x0c
call [con_set_flags] call [con_set_flags]
push str3 push str3
call [con_write_asciiz] call [con_write_asciiz]
jmp done jmp done
bind_err: bind_err:
pushd 0x0c pushd 0x0c
call [con_set_flags] call [con_set_flags]
push str4 push str4
call [con_write_asciiz] call [con_write_asciiz]
jmp done jmp done
sock_err: sock_err:
pushd 0x0c pushd 0x0c
call [con_set_flags] call [con_set_flags]
push str6 push str6
call [con_write_asciiz] call [con_write_asciiz]
jmp done jmp done
@ -212,18 +228,28 @@ exit:
mcall -1 mcall -1
thread_exit:
push str_bye
call [con_write_asciiz] ; say bye bye
pop ecx ; get the thread_data pointer from stack
mcall 68, 13 ; free the memory
mcall -1 ; and kill the thread
; initialized data
; data
title db 'KolibriOS FTP daemon 0.1', 0 title db 'KolibriOS FTP daemon 0.1', 0
str1 db 'Starting FTP daemon on port %u', 0 str1 db 'Starting FTP daemon on port %u', 0
str2 db '.', 0 str2 db '.', 0
str2b db ' OK!',10,10,0 str2b db ' OK!',10,10,0
str3 db 'Listen error',10,10,0 str3 db 'Listen error',10,10,0
str4 db 'Bind error',10,10,0 str4 db 'Bind error',10,10,0
str5 db 'Setsockopt error.',10,10,0 ;str5 db 'Setsockopt error.',10,10,0
str6 db 'Could not open socket',10,10,0 str6 db 'Could not open socket',10,10,0
str7 db 'Got data!',10,10,0 str7 db 'Got data!',10,10,0
str8 db 'Error accepting connection',10,10,0 str8 db 10,'New thread created!',10,10,0
str_bye db 10,'Closing thread!',10,10,0
str_logged_in db 'Login ok',10,10,0 str_logged_in db 'Login ok',10,10,0
str_pass_ok db 'Password ok - Logged in',10,10,0 str_pass_ok db 'Password ok - Logged in',10,10,0
@ -233,15 +259,21 @@ str_datasock db 'Passive data socket connected!',10,10,0
str_notfound db 'ERROR: file not found',10,10,0 str_notfound db 'ERROR: file not found',10,10,0
str_sockerr db 'ERROR: socket error',10,10,0 str_sockerr db 'ERROR: socket error',10,10,0
str_newline db 10,0 str_newline db 10, 0
str_mask db '*', 0 str_mask db '*', 0
months dd 'Jan '
months: dd 'Feb '
dd 'Jan ','Feb ','Mar ','Apr ','May ','Jun ' dd 'Mar '
dd 'Jul ','Aug ','Sep ','Oct ','Nov ','Dec ' dd 'Apr '
dd 'May '
dd 'Jun '
dd 'Jul '
dd 'Aug '
dd 'Sep '
dd 'Oct '
dd 'Nov '
dd 'Dec '
filename db '.ini', 0 filename db '.ini', 0
str_port db 'port', 0 str_port db 'port', 0
@ -250,24 +282,25 @@ str_conn db 'conn', 0
sockaddr1: sockaddr1:
dw AF_INET4 dw AF_INET4
.port dw 21 .port dw 21
.ip dd 0 .ip dd 0
rb 10 rb 10
.length = $ - sockaddr1 .length = $ - sockaddr1
; import ; import
align 4 align 4
@IMPORT: @IMPORT:
library console, 'console.obj', \ library console, 'console.obj',\
libini, 'libini.obj', \ libini, 'libini.obj', \
libio, 'libio.obj' libio, 'libio.obj'
import console, \ import console,\
con_start, 'START', \ con_start, 'START',\
con_init, 'con_init', \ con_init, 'con_init',\
con_write_asciiz, 'con_write_asciiz', \ con_write_asciiz, 'con_write_asciiz',\
con_exit, 'con_exit', \ con_exit, 'con_exit',\
con_gets, 'con_gets',\ con_gets, 'con_gets',\
con_cls, 'con_cls',\ con_cls, 'con_cls',\
con_printf, 'con_printf',\ con_printf, 'con_printf',\
@ -275,49 +308,29 @@ import console, \
con_set_cursor_pos, 'con_set_cursor_pos',\ con_set_cursor_pos, 'con_set_cursor_pos',\
con_set_flags, 'con_set_flags' con_set_flags, 'con_set_flags'
import libini, \ import libini,\
ini.get_str, 'ini_get_str',\ ini.get_str, 'ini_get_str',\
ini.get_int, 'ini_get_int' ini.get_int, 'ini_get_int'
import libio, \ import libio,\
libio.init , 'lib_init' , \ libio.init, 'lib_init',\
file.size , 'file_size' , \ file.size, 'file_size',\
file.open , 'file_open' , \ file.open, 'file_open',\
file.read , 'file_read' , \ file.read, 'file_read',\
file.close , 'file_close' , \ file.close, 'file_close',\
file.find.first , 'file_find_first', \ file.find.first, 'file_find_first',\
file.find.next , 'file_find_next', \ file.find.next, 'file_find_next',\
file.find.close , 'file_find_close' file.find.close, 'file_find_close'
i_end: i_end:
socketnum dd ? ; uninitialised data
socketnum dd ?
path rb 1024
params rb 1024
; thread specific data
socketnum2 dd ?
state dd ?
home_dir db '/rd/1/', 0
rb 1024
work_dir rb 1024
fpath rb 1024*3
type db ?
mode db ? ; active/passive
passivesocknum dd ?
datasocketnum dd ?
datasock:
dw AF_INET4
.port dw ?
.ip dd ?
rb 10
.length = $ - datasock
buffer rb BUFFERSIZE
.length = $ - buffer
path rb 1024
mem: mem: