kolibrios/programs/network/vncc/network.inc
2015-08-20 09:30:24 +00:00

513 lines
14 KiB
PHP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2010-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; VNC client for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
thread_start:
mcall 40, 0 ; disable all events for this thread
; Extract port number from server address
mov esi, serveraddr
@@:
lodsb
test al, al
jz .port_done
cmp al, ':'
jne @r
mov byte[esi-1], 0 ; replace colon with 0 byte, we dont want to upset getaddrinfo
xor eax, eax
xor ebx, ebx ; port number
@@:
lodsb
test al, al
jz @f
sub al, '0'
jb err_dns
cmp al, 9
ja err_dns
lea ebx, [ebx*4+ebx]
lea ebx, [ebx*2+eax]
jmp @b
@@:
xchg bl, bh
mov [sockaddr1.port], bx
.port_done:
; Resolve hostname
push esp ; reserve stack place
invoke getaddrinfo, serveraddr, 0, 0, esp
pop esi
test eax, eax
jnz err_dns
mov eax, [esi+addrinfo.ai_addr]
mov eax, [eax+sockaddr_in.sin_addr]
mov [sockaddr1.ip], eax
invoke freeaddrinfo, esi
DEBUGF 1, "Connecting to %u.%u.%u.%u:%u\n", \
[sockaddr1.ip]:1, [sockaddr1.ip+1]:1, [sockaddr1.ip+2]:1, [sockaddr1.ip+3]:1, \
[sockaddr1.port]:2
; Open socket
mcall socket, AF_INET4, SOCK_STREAM, 0
cmp eax, -1
je err_sock
mov [socketnum], eax
; Connect to the server
mcall connect, [socketnum], sockaddr1, 18
cmp eax, -1
je err_connect
; Verify handshake from server
call read_data
cmp eax, 12
jb err_proto
cmp dword[esi], "RFB "
jne err_proto
add esi, 12
; Did we get an error message already?
cmp eax, 16
jb @f
lodsd
test eax, eax
je err_handshake
@@:
; Reply to handshake
DEBUGF 1, "Sending handshake\n"
mcall send, [socketnum], HandShake, 12, 0
; VNC 3.3 protocol: server decides security type
call read_data
cmp eax, 4
jb err_proto
lodsd
cmp eax, 0x00000000
je err_handshake
cmp eax, 0x01000000 ; no security
je initialize
cmp eax, 0x02000000 ; VNC security
je vnc_security
jmp err_proto
vnc_security:
lea eax, [esi+8]
cmp [datapointer], eax
jb err_proto
push esi ; pointer to message
mov dword[password], 0
mov dword[password+4], 0
and [USERbox.flags], not ed_focus
or [USERbox.flags], ed_disabled
or [PASSbox.flags], ed_focus
mov [status], STATUS_REQ_LOGIN
or [work], WORK_GUI
@@:
mcall 5, 10
cmp [status], STATUS_LOGIN
je @f
cmp [status], STATUS_REQ_LOGIN
je @r
mcall -1
@@:
DEBUGF 1, "VNC authentication\n"
; Bit reverse the password and create DES keys
mov ebx, dword[password]
mov edx, ebx
and ebx, 0xf0f0f0f0
shr ebx, 4
and edx, 0x0f0f0f0f
shl edx, 4
or ebx, edx
mov edx, ebx
and ebx, 0xCCCCCCCC
shr ebx, 2
and edx, 0x33333333
shl edx, 2
or ebx, edx
mov edx, ebx
and ebx, 0xAAAAAAAA
shr ebx, 1
and edx, 0x55555555
shl edx, 1
or ebx, edx
bswap ebx
mov eax, dword[password+4]
mov edx, eax
and eax, 0xf0f0f0f0
shr eax, 4
and edx, 0x0f0f0f0f
shl edx, 4
or eax, edx
mov edx, eax
and eax, 0xCCCCCCCC
shr eax, 2
and edx, 0x33333333
shl edx, 2
or eax, edx
mov edx, eax
and eax, 0xAAAAAAAA
shr eax, 1
and edx, 0x55555555
shl edx, 1
or edx, eax
bswap edx
mov edi, keys
call DES_create_keys
; Encrypt message with DES
mov esi, [esp]
mov ebx, dword[esi+0]
mov edx, dword[esi+4]
call encrypt_DES
mov esi, [esp]
mov dword[esi+0], ebx
mov dword[esi+4], edx
mov ebx, dword[esi+8]
mov edx, dword[esi+12]
call encrypt_DES
mov esi, [esp]
mov dword[esi+8], ebx
mov dword[esi+12], edx
; Blank out the password and key fields in RAM
mov edi, password
mov ecx, 384/4
xor eax, eax
rep stosd
; Send the authentication response to server
pop edx
mcall send, [socketnum], , 16, 0
securityresult:
; Wait for SecurityResult from server
call read_data
cmp eax, 4
jb err_proto
cmp dword[esi], 0 ; OK
jne err_login
initialize:
DEBUGF 1, "Sending ClientInit\n"
mcall send, [socketnum], ClientInit, 1, 0
call read_data ; now the server should send init message
cmp eax, ServerInit.name
jb err_proto
DEBUGF 2, "Serverinit: bpp: %u depth: %u bigendian: %u truecolor: %u\n", \
[esi+ServerInit.pixelformat.bpp]:1, \
[esi+ServerInit.pixelformat.depth]:1, \
[esi+ServerInit.pixelformat.big_endian]:1, \
[esi+ServerInit.pixelformat.true_color]:1
mov eax, dword[esi+ServerInit.width]
mov dword[FramebufferUpdateRequest.width], eax
bswap eax
mov dword[screen], eax
DEBUGF 1, "Screen width=%u, height=%u\n", [screen.width]:2, [screen.height]:2
; Set main window caption to servername
mov ecx, dword[esi+ServerInit.name_length]
bswap ecx
add esi, ServerInit.name
lea eax, [esi+ecx]
cmp [datapointer], eax
jb err_proto
cmp ecx, 64 ; Limit name length to 64 chars
jbe @f
mov ecx, 64
@@:
mov edi, servername
rep movsb
mov byte[edi], 0
mov [name.dash], "-"
DEBUGF 1, "Sending pixel format\n"
mcall send, [socketnum], SetPixelFormat, 20, 0
DEBUGF 1, "Sending encoding info\n"
mcall send, [socketnum], SetEncodings, SetEncodings.length, 0
; Tell the main thread we are ready for business!
mov [status], STATUS_CONNECTED
; Request initial framebuffer update from server
mov [FramebufferUpdateRequest.inc], 0
request_fbu:
DEBUGF 1, "Requesting framebuffer update\n"
mcall send, [socketnum], FramebufferUpdateRequest, 10, 0
mov [FramebufferUpdateRequest.inc], 1
thread_loop:
call read_data ; Read the data into the buffer
lodsb
cmp al, 0
je framebufferupdate
cmp al, 1
je setcolourmapentries
cmp al, 2
je bell
cmp al, 3
je servercuttext
DEBUGF 2, "Unknown server command: %u\n", al
jmp thread_loop
framebufferupdate:
@@:
lea eax, [esi+6]
cmp [datapointer], eax
jae @f
call read_data.more
jmp @b
@@:
inc esi ; padding
lodsw
xchg al, ah
mov [rectangles], ax
DEBUGF 1, "Framebufferupdate: %u rectangles\n", ax
rectangle_loop:
@@:
lea eax, [esi+12]
cmp [datapointer], eax
jae @f
call read_data.more
jmp @b
@@:
xor eax, eax
lodsw
xchg al, ah
mov [rectangle.x], eax
lodsw
xchg al, ah
mov [rectangle.y], eax
lodsw
xchg al, ah
mov [rectangle.width], eax
lodsw
xchg al, ah
mov [rectangle.height], eax
lodsd ; encoding
bswap eax
DEBUGF 1, "Rectangle: x=%u y=%u width=%u height=%u encoding: ",\
[rectangle.x]:2, [rectangle.y]:2, [rectangle.width]:2, [rectangle.height]:2
cmp eax, 0
je encoding_raw
cmp eax, 1
je encoding_CopyRect
cmp eax, 2
je encoding_RRE
cmp eax, 15
je encoding_TRLE
cmp eax, 16
je encoding_ZRLE
cmp eax, 0xffffff11
je encoding_cursor
DEBUGF 2, "unknown encoding: %u\n", eax
jmp thread_loop
next_rectangle:
or [work], WORK_FRAMEBUFFER
dec [rectangles]
jnz rectangle_loop
jmp request_fbu
setcolourmapentries:
DEBUGF 1, "Server sent SetColourMapEntries message\n"
@@:
lea eax, [esi+5]
cmp [datapointer], eax
jae @f
call read_data.more
jmp @b
@@:
inc esi ; padding
xor eax, eax
lodsw ; first color (just ignore for now)
lodsw ; number of colors (use to find end of message)
xchg al, ah
lea eax, [eax*2+eax]
shl eax, 1
@@:
push eax
add eax, esi
cmp [datapointer], eax
jae @f
call read_data.more
pop eax
jmp @b
@@:
pop eax
add esi, eax ; Just skip it for now.
jmp thread_loop
bell:
mcall 55, 55, , , beep
jmp thread_loop
servercuttext:
DEBUGF 1, "Server cut text\n"
@@:
lea eax, [esi+7]
cmp [datapointer], eax
jae @f
call read_data.more
jmp @b
@@:
add esi, 3
lodsd
bswap eax
mov ecx, eax
@@:
lea eax, [esi+ecx]
cmp [datapointer], eax
jae @f
call read_data.more
jmp @b
@@:
; TODO: paste text to clipboard
DEBUGF 1, "%u bytes of text\n", ecx
add esi, ecx
jmp thread_loop
read_data:
mov [datapointer], receive_buffer
mov esi, receive_buffer
.more:
push ebx ecx edx esi edi
neg esi
add esi, receive_buffer + RECEIVE_BUFFER_SIZE
jz .buffer_end_reached
xor edi, edi
mcall recv, [socketnum], [datapointer]
pop edi esi edx ecx ebx
cmp eax, -1
je err_sock
test eax, eax
jz err_disconnected
add [datapointer], eax
ret
.buffer_end_reached:
DEBUGF 1, "end of buffer reached, re-organizing\n"
pop edi esi edx ecx ebx
; Buffer is full, first needed data by program is pointed to by esi.
; Move all usefull data to begin of buffer
cmp esi, receive_buffer
je err_proto
mov ecx, [datapointer]
sub ecx, esi
mov edi, receive_buffer
rep movsb
mov [datapointer], edi ; new end of data
mov esi, receive_buffer ; new start of data
jmp .more
err_disconnected:
mov [status], STATUS_DISCONNECTED
or [work], WORK_GUI
mcall -1
err_dns:
mov [status], STATUS_DNS_ERR
or [work], WORK_GUI
mcall -1
err_sock:
; TODO: distinguish between different socket errors!
DEBUGF 2, "Socket error: %u\n", ebx
mov [status], STATUS_SOCK_ERR
or [work], WORK_GUI
mcall -1
err_connect:
mov [status], STATUS_CONNECT_ERR
or [work], WORK_GUI
mcall -1
ret
err_proto:
mov [status], STATUS_PROTO_ERR
or [work], WORK_GUI
mcall -1
ret
err_handshake:
mov [status], STATUS_SECURITY_ERR
lodsd ; Custom message from server?
test eax, eax
jz .no_msg
bswap eax
mov ecx, eax
cmp ecx, 512
jb @f
mov ecx, 512
@@:
mov edi, sz_err_security_c
rep movsb
mov byte[edi], 0
mov [status], STATUS_SECURITY_ERR_C
.no_msg:
or [work], WORK_GUI
mcall -1
ret
err_login:
mov [status], STATUS_LOGIN_FAILED
or [work], WORK_GUI
mcall -1
ret