35f6e3767b
git-svn-id: svn://kolibrios.org@5722 a494cfbc-eb01-0410-851d-a64ba20cac60
519 lines
14 KiB
PHP
519 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
|
|
inc [update_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"
|
|
if BITS_PER_PIXEL = 8
|
|
mcall send, [socketnum], SetPixelFormat8, 20, 0
|
|
else if BITS_PER_PIXEL = 16
|
|
mcall send, [socketnum], SetPixelFormat16, 20, 0
|
|
else if BITS_PER_PIXEL = 24
|
|
mcall send, [socketnum], SetPixelFormat24, 20, 0
|
|
else
|
|
mcall send, [socketnum], SetPixelFormat32, 20, 0
|
|
end if
|
|
|
|
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
|
|
|
|
DEBUGF 2, "unknown encoding: %u\n", eax
|
|
jmp thread_loop
|
|
|
|
next_rectangle:
|
|
inc [update_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
|
|
inc [update_gui]
|
|
mcall -1
|
|
|
|
err_dns:
|
|
mov [status], STATUS_DNS_ERR
|
|
inc [update_gui]
|
|
mcall -1
|
|
|
|
err_sock:
|
|
; TODO: distinguish between different socket errors!
|
|
DEBUGF 2, "Socket error: %u\n", ebx
|
|
mov [status], STATUS_SOCK_ERR
|
|
inc [update_gui]
|
|
mcall -1
|
|
|
|
err_connect:
|
|
mov [status], STATUS_CONNECT_ERR
|
|
inc [update_gui]
|
|
mcall -1
|
|
ret
|
|
|
|
err_proto:
|
|
mov [status], STATUS_PROTO_ERR
|
|
inc [update_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:
|
|
|
|
inc [update_gui]
|
|
mcall -1
|
|
ret
|
|
|
|
err_login:
|
|
mov [status], STATUS_LOGIN_FAILED
|
|
inc [update_gui]
|
|
mcall -1
|
|
ret
|