kolibrios/programs/network/tftpc/tftpc.asm

669 lines
17 KiB
NASM
Raw Permalink Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2010-2017. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; tftpc.asm - TFTP client for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
format binary as ""
__DEBUG__ = 0
__DEBUG_LEVEL__ = 1
use32
org 0x0
db 'MENUET01'
dd 0x1
dd START
dd I_END
dd IM_END+0x1000
dd IM_END+0x1000
dd 0, 0
include '../../proc32.inc'
include '../../macros.inc'
include '../../develop/libraries/libs-dev/libio/libio.inc'
include '../../dll.inc'
include '../../develop/libraries/box_lib/trunk/box_lib.mac'
include '../../network.inc'
include '../../debug-fdo.inc'
TIMEOUT = 100
buffer_len = 4096
opcode_rrq = 1 shl 8
opcode_wrq = 2 shl 8
opcode_data = 3 shl 8
opcode_ack = 4 shl 8
opcode_error = 5 shl 8
; read/write request packet
;
; 2 bytes string 1 byte string 1 byte
; ------------------------------------------------
; | Opcode | Filename | 0 | Mode | 0 |
; ------------------------------------------------
; data packet
;
; 2 bytes 2 bytes n bytes
; ----------------------------------
; | Opcode | Block # | Data |
; ----------------------------------
; acknowledgement packet
;
; 2 bytes 2 bytes
; ---------------------
; | Opcode | Block # |
; ---------------------
; error packet
;
; 2 bytes 2 bytes string 1 byte
; ----------------------------------------
; | Opcode | ErrorCode | ErrMsg | 0 |
; ----------------------------------------
START:
mcall 68, 11
stdcall dll.Load, @IMPORT
or eax, eax
jnz exit
home:
mcall 40, EVM_MOUSE + EVM_MOUSE_FILTER + EVM_REDRAW + EVM_BUTTON + EVM_KEY + EVM_STACK
redraw:
call draw_window
mainloop:
mcall 10
dec eax
jz redraw
dec eax
jz key
dec eax
jz button
invoke edit_box_mouse, edit1
invoke edit_box_mouse, edit2
invoke edit_box_mouse, edit3
invoke edit_box_mouse, edit4
invoke option_box_mouse, Option_boxs1
invoke option_box_mouse, Option_boxs2
jmp mainloop
button:
mcall 17
cmp ah, 0x10 ; connect button
je start_transfer
test ah , ah
jz mainloop
exit:
mcall -1
key:
mcall 2
invoke edit_box_key, edit1
invoke edit_box_key, edit2
invoke edit_box_key, edit3
invoke edit_box_key, edit4
jmp mainloop
draw_window:
; get system colors
mcall 48, 3, sc, 40
mcall 12, 1
mov edx, [sc.work]
or edx, 0x34000000
xor esi, esi
mov edi, str_title
mcall 0, 50 shl 16 + 400, 30 shl 16 + 180
mov ebx, 35 shl 16 + 10
mov ecx, 0x80000000
or ecx, [sc.work_text]
mov edx, str_server
mcall 4
mov ebx, 5 shl 16 + 30
mov edx, str_source
mcall
mov ebx, 11 shl 16 + 50
mov edx, str_destination
mcall
mov ebx, 47 shl 16 + 72
mov edx, str_mode
mcall
mov ebx, 160 shl 16 + 72
mov edx, str_method
mcall
mov ebx, 270 shl 16 + 72
mov edx, str_blocksize
mcall
invoke edit_box_draw, edit1
invoke edit_box_draw, edit2
invoke edit_box_draw, edit3
invoke edit_box_draw, edit4
invoke option_box_draw, Option_boxs1
invoke option_box_draw, Option_boxs2
mov esi, [sc.work_button]
mcall 8, 210 shl 16 + 170, 105 shl 16 + 16, 0x10
mcall 38, 10 shl 16 + 380, 130 shl 16 + 130, [sc.work_graph]
cmp [errormsg], 0
je .no_error
mov ecx, 0x80000000
or ecx, [sc.work_text]
mcall 4, 20 shl 16 + 137, , [errormsg]
mcall 12, 2
jmp .draw_btn
.no_error:
mov ecx, 0x80000000
or ecx, [sc.work_text]
mcall 4, 350 shl 16 + 137, , str_kb_s
mcall 4, 50 shl 16 + 137, , str_complete
mcall 47, 1 shl 31 + 7 shl 16 + 1, kbps, 305 shl 16 + 137, [sc.work_text]
mcall 47, 1 shl 31 + 3 shl 16 + 1, done, 25 shl 16 + 137
.draw_btn:
cmp [socketnum], 0
je .no_transfer
mov ecx, 0x80000000
or ecx, [sc.work_button_text]
mcall 4, 270 shl 16 + 110, , str_stop
mcall 12, 2
ret
.no_transfer:
mov ecx, 0x80000000
or ecx, [sc.work_button_text]
mcall 4, 260 shl 16 + 110, , str_transfer
mcall 12, 2
ret
start_transfer:
; resolve the hostname
mov [errormsg], str_err_resolve
push esp ; reserve stack place
push esp ; fourth parameter
push 0 ; third parameter
push 0 ; second parameter
push dword SRV ; first parameter
call [getaddrinfo]
pop esi
; test for error
test eax, eax
jnz home
mov eax, [esi + addrinfo.ai_addr]
mov eax, [eax + sockaddr_in.sin_addr]
mov [sockaddr.ip], eax
; free allocated memory
push esi
call [freeaddrinfo]
; Open a socket & connect to server
mov [errormsg], str_err_socket
mcall socket, AF_INET4, SOCK_DGRAM, 0
cmp eax, -1
je home
mov [socketnum], eax
mcall connect, [socketnum], sockaddr, sockaddr_len
cmp eax, -1
je home
; Create the read/write request packet
mov word[buffer], opcode_rrq
cmp [option_group2], op3
je @f
mov word[buffer], opcode_wrq
@@:
; Copy in the remote filename (asciiz)
xor al, al
mov edi, remote_addr
mov ecx, 255
repnz scasb
lea ecx, [edi - remote_addr - 1]
mov esi, remote_addr
mov edi, buffer+2
rep movsb
stosb
; Append the data type (asciiz)
cmp [option_group1], op1
je .ascii
mov esi, octet
movsd
movsb
jmp .send_request
.ascii:
mov esi, netascii
movsd
movsd
; Send the request to the server
.send_request:
xor al, al
stosb
lea esi, [edi - buffer]
xor edi, edi
mcall send, [socketnum], buffer
cmp eax, -1
je home
; Jump to send/receive code
cmp word[buffer], opcode_wrq
je tftp_send
tftp_receive:
mcall 40, EVM_REDRAW + EVM_BUTTON + EVM_STACK
mov [last_ack], 0
mov [errormsg], 0
call draw_window
; Open/create local file
mov [file_struct.subfn], 2
mov [file_struct.offset], 0
mov [file_struct.size], 0
mcall 70, file_struct
; Truncate it to 0 bytes
mov [file_struct.subfn], 4
mcall 70, file_struct
; Set parameters for writing to file
mov [file_struct.subfn], 3
mov [file_struct.data], buffer + 4
.loop:
mcall 23, TIMEOUT
dec eax
jz .red
dec eax
dec eax
jz .button
mcall recv, [socketnum], buffer, buffer_len, MSG_DONTWAIT ; receive data
cmp eax, -1
je .loop
DEBUGF 1, "Got %u bytes\n", eax
cmp word[buffer], opcode_error
je tftp_error
cmp word[buffer], opcode_data
jne .error
; Verify ACK number
mov bx, word[buffer + 2]
rol bx, 8
cmp [last_ack], 0
je @f
cmp [last_ack], bx
jne .packet_got_lost
inc bx
@@:
mov [last_ack], bx
; Write to the file
lea ecx, [eax - 4]
mov [file_struct.size], ecx
mcall 70, file_struct
add [file_struct.offset], ecx
; Send ACK
mov word[buffer], opcode_ack
mcall send, [socketnum], buffer, 4, 0
jmp .loop
.packet_got_lost:
;TODO
jmp .loop
.red:
call draw_window
jmp .loop
.button:
mcall 17
cmp ah, 1
jne .abort
mcall close, [socketnum]
mcall -1
.abort:
mcall close, [socketnum]
xor eax, eax
mov [socketnum], eax
mov [errormsg], str_abort
jmp home
.error:
mcall close, [socketnum]
xor eax, eax
mov [socketnum], eax
mov [errormsg], str_err_unexp
jmp home
.done:
mcall close, [socketnum]
xor eax, eax
mov [socketnum], eax
mov [errormsg], str_success
jmp home
tftp_send:
mcall 40, EVM_REDRAW + EVM_BUTTON + EVM_STACK
mov [last_ack], 0
mov [errormsg], 0
call draw_window
mov [file_struct.subfn], 0
mov [file_struct.offset], 0
mov [file_struct.size], buffer_len
mov [file_struct.data], buffer + 4
.next:
mov edi, buffer
mov ax, opcode_data
stosw
mov ax, [last_ack]
stosw
mcall 70, file_struct
test eax, eax
; jnz .done
mov [size], ebx
.resend:
mov ebx, [size]
lea esi, [ebx + 4]
xor edi, edi
mcall send, [socketnum], buffer
.loop:
mcall 23, TIMEOUT
dec eax
jz .red
dec eax
dec eax
jz .button
mcall recv, [socketnum], buffer, buffer_len, MSG_DONTWAIT
cmp eax, -1
je .loop
cmp word[buffer], opcode_error
je tftp_error
cmp word[buffer], opcode_ack
jne .error
mov ax, [last_ack]
cmp word[buffer+2], ax
jne .resend
mov eax, [size]
cmp eax, buffer_len
jb .done
add [file_struct.offset], eax
inc [last_ack]
jmp .next
.red:
call draw_window
jmp .loop
.button:
mcall 17
cmp ah, 1
jne .abort
mcall close, [socketnum]
mcall -1
.abort:
mcall close, [socketnum]
xor eax, eax
mov [socketnum], eax
mov [errormsg], str_abort
jmp home
.error:
mcall close, [socketnum]
xor eax, eax
mov [socketnum], eax
mov [errormsg], str_err_unexp
jmp home
.done:
mcall close, [socketnum]
xor eax, eax
mov [socketnum], eax
mov [errormsg], str_success
jmp home
tftp_error:
mcall close, [socketnum]
xor eax, eax
mov [socketnum], eax
mov ax, word[buffer+2]
xchg al, ah
test ax, ax
jz .0
dec ax
jz .1
dec ax
jz .2
dec ax
jz .3
dec ax
jz .4
dec ax
jz .5
dec ax
jz .6
dec ax
jz .7
.0:
mov [errormsg], str_error.0
jmp home
.1:
mov [errormsg], str_error.1
jmp redraw
.2:
mov [errormsg], str_error.2
jmp home
.3:
mov [errormsg], str_error.3
jmp home
.4:
mov [errormsg], str_error.4
jmp home
.5:
mov [errormsg], str_error.5
jmp home
.6:
mov [errormsg], str_error.6
jmp home
.7:
mov [errormsg], str_error.7
jmp home
;-------------------------
; DATA
socketnum dd 0
kbps dd 0
done dd 0
errormsg dd str_welcome
sockaddr:
dw AF_INET4
dw 0x4500 ; 69
.ip dd ?
sockaddr_len = $ - sockaddr
file_struct:
.subfn dd ?
.offset dd ?
dd 0
.size dd ?
.data dd ?
db 0
.filename dd local_addr
align 16
@IMPORT:
library box_lib , 'box_lib.obj' ,\
network , 'network.obj'
import box_lib ,\
edit_box_draw , 'edit_box' ,\
edit_box_key , 'edit_box_key' ,\
edit_box_mouse , 'edit_box_mouse' ,\
version_ed , 'version_ed' ,\
init_checkbox , 'init_checkbox2' ,\
check_box_draw , 'check_box_draw2' ,\
check_box_mouse , 'check_box_mouse2' ,\
version_ch , 'version_ch2' ,\
option_box_draw , 'option_box_draw' ,\
option_box_mouse, 'option_box_mouse' ,\
version_op , 'version_op'
import network ,\
inet_ntoa , 'inet_ntoa' ,\
getaddrinfo , 'getaddrinfo' ,\
freeaddrinfo , 'freeaddrinfo'
edit1 edit_box 300, 80, 5, 0xffffff, 0x6f9480, 0, 0, 0, 255, SRV, mouse_dd, ed_focus, 13, 13
edit2 edit_box 300, 80, 25, 0xffffff, 0x6f9480, 0, 0, 0, 255, remote_addr, mouse_dd, 0, 4, 4
edit3 edit_box 300, 80, 45, 0xffffff, 0x6f9480, 0, 0, 0, 255, local_addr, mouse_dd, 0, 12, 12
edit4 edit_box 40, 340, 68, 0xffffff, 0x6f9480, 0, 0, 0, 5, BLK, mouse_dd, ed_figure_only, 3, 3
op1 option_box option_group1, 80, 68, 6, 12, 0xffffff, 0, 0, netascii, octet-netascii
op2 option_box option_group1, 80, 85, 6, 12, 0xFFFFFF, 0, 0, octet, get-octet
op3 option_box option_group2, 210, 68, 6, 12, 0xffffff, 0, 0, get, put-get
op4 option_box option_group2, 210, 85, 6, 12, 0xFFFFFF, 0, 0, put, BLK-put
option_group1 dd op1
option_group2 dd op3
Option_boxs1 dd op1, op2, 0
Option_boxs2 dd op3, op4, 0
str_title db 'TFTP client', 0
str_server db 'Server:', 0
str_source db 'Remote file:', 0
str_destination db 'Local file:', 0
str_mode db 'Mode:', 0
str_method db 'Method:', 0
str_blocksize db 'Blocksize:', 0
str_kb_s db 'kB/s', 0
str_complete db '% complete', 0
str_transfer db 'Transfer', 0
str_stop db 'Stop', 0
str_error:
.0 db 'Error.', 0 ; not further defined error
.1 db 'File not found.', 0
.2 db 'Access violation.', 0
.3 db 'Disk full or allocation exceeded.', 0
.4 db 'Illegal TFTP operation.', 0
.5 db 'Unknown transfer ID.', 0
.6 db 'File already exists.', 0
.7 db 'No such user.', 0
str_welcome db 'Welcome.', 0
str_err_resolve db 'Unable to resolve server address.', 0
str_err_socket db 'Socket error.', 0
str_err_unexp db 'Unexpected command from server.', 0
str_success db 'Operation completed successfully.', 0
str_abort db 'Operation aborted by user.', 0
netascii db 'NetASCII'
octet db 'Octet'
get db 'GET'
put db 'PUT'
BLK db "512", 0, 0, 0
SRV db "192.168.1.115", 0
rb (SRV + 256 - $)
remote_addr db "file", 0
rb (remote_addr + 256 - $)
local_addr db "/tmp0/1/file", 0
rb (local_addr + 256 - $)
include_debug_strings
I_END:
last_ack dw ?
size dd ?
mouse_dd dd ?
sc system_colors
buffer rb buffer_len
IM_END: