Rev 5720 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5663 | hidnplayr | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
3 | ;; Copyright (C) KolibriOS team 2010-2015. All rights reserved. ;; |
||
4 | ;; Distributed under terms of the GNU General Public License ;; |
||
5 | ;; ;; |
||
6 | ;; VNC client for KolibriOS ;; |
||
7 | ;; ;; |
||
8 | ;; Written by hidnplayr@kolibrios.org ;; |
||
9 | ;; ;; |
||
10 | ;; GNU GENERAL PUBLIC LICENSE ;; |
||
11 | ;; Version 2, June 1991 ;; |
||
12 | ;; ;; |
||
13 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
3545 | hidnplayr | 14 | |
15 | thread_start: |
||
16 | |||
5668 | hidnplayr | 17 | mcall 40, 0 ; disable all events for this thread |
3545 | hidnplayr | 18 | |
5715 | hidnplayr | 19 | ; Extract port number from server address |
20 | mov esi, serveraddr |
||
21 | @@: |
||
22 | lodsb |
||
23 | test al, al |
||
24 | jz .port_done |
||
25 | cmp al, ':' |
||
26 | jne @r |
||
27 | mov byte[esi-1], 0 ; replace colon with 0 byte, we dont want to upset getaddrinfo |
||
28 | xor eax, eax |
||
29 | xor ebx, ebx ; port number |
||
30 | @@: |
||
31 | lodsb |
||
32 | test al, al |
||
33 | jz @f |
||
34 | sub al, '0' |
||
35 | jb err_dns |
||
36 | cmp al, 9 |
||
37 | ja err_dns |
||
38 | lea ebx, [ebx*4+ebx] |
||
39 | lea ebx, [ebx*2+eax] |
||
40 | jmp @b |
||
41 | @@: |
||
42 | xchg bl, bh |
||
43 | mov [sockaddr1.port], bx |
||
44 | .port_done: |
||
45 | |||
46 | ; Resolve hostname |
||
5668 | hidnplayr | 47 | push esp ; reserve stack place |
5663 | hidnplayr | 48 | invoke getaddrinfo, serveraddr, 0, 0, esp |
3545 | hidnplayr | 49 | pop esi |
50 | test eax, eax |
||
5668 | hidnplayr | 51 | jnz err_dns |
3545 | hidnplayr | 52 | |
53 | mov eax, [esi+addrinfo.ai_addr] |
||
54 | mov eax, [eax+sockaddr_in.sin_addr] |
||
55 | mov [sockaddr1.ip], eax |
||
5715 | hidnplayr | 56 | invoke freeaddrinfo, esi |
3545 | hidnplayr | 57 | |
5663 | hidnplayr | 58 | DEBUGF 1, "Connecting to %u.%u.%u.%u:%u\n", \ |
5680 | hidnplayr | 59 | [sockaddr1.ip]:1, [sockaddr1.ip+1]:1, [sockaddr1.ip+2]:1, [sockaddr1.ip+3]:1, \ |
60 | [sockaddr1.port]:2 |
||
3545 | hidnplayr | 61 | |
5715 | hidnplayr | 62 | ; Open socket |
3545 | hidnplayr | 63 | mcall socket, AF_INET4, SOCK_STREAM, 0 |
5668 | hidnplayr | 64 | cmp eax, -1 |
65 | je err_sock |
||
5715 | hidnplayr | 66 | mov [socketnum], eax |
5668 | hidnplayr | 67 | |
5715 | hidnplayr | 68 | ; Connect to the server |
3545 | hidnplayr | 69 | mcall connect, [socketnum], sockaddr1, 18 |
5668 | hidnplayr | 70 | cmp eax, -1 |
71 | je err_connect |
||
3545 | hidnplayr | 72 | |
5720 | hidnplayr | 73 | ; Verify handshake from server |
5722 | hidnplayr | 74 | call read_data |
75 | cmp eax, 12 |
||
76 | jb err_proto |
||
77 | cmp dword[esi], "RFB " |
||
5668 | hidnplayr | 78 | jne err_proto |
5720 | hidnplayr | 79 | add esi, 12 |
5715 | hidnplayr | 80 | |
5720 | hidnplayr | 81 | ; Did we get an error message already? |
82 | cmp eax, 16 |
||
83 | jb @f |
||
84 | lodsd |
||
85 | test eax, eax |
||
86 | je err_handshake |
||
87 | @@: |
||
88 | |||
5715 | hidnplayr | 89 | ; Reply to handshake |
5680 | hidnplayr | 90 | DEBUGF 1, "Sending handshake\n" |
5668 | hidnplayr | 91 | mcall send, [socketnum], HandShake, 12, 0 |
5720 | hidnplayr | 92 | |
93 | ; VNC 3.3 protocol: server decides security type |
||
5722 | hidnplayr | 94 | call read_data |
95 | cmp eax, 4 |
||
96 | jb err_proto |
||
5720 | hidnplayr | 97 | lodsd |
98 | cmp eax, 0x00000000 |
||
99 | je err_handshake |
||
100 | cmp eax, 0x01000000 ; no security |
||
5680 | hidnplayr | 101 | je initialize |
5720 | hidnplayr | 102 | cmp eax, 0x02000000 ; VNC security |
3545 | hidnplayr | 103 | je vnc_security |
5720 | hidnplayr | 104 | jmp err_proto |
5680 | hidnplayr | 105 | |
3545 | hidnplayr | 106 | vnc_security: |
107 | |||
5722 | hidnplayr | 108 | lea eax, [esi+8] |
109 | cmp [datapointer], eax |
||
110 | jb err_proto |
||
111 | |||
5720 | hidnplayr | 112 | push esi ; pointer to message |
113 | |||
5680 | hidnplayr | 114 | mov dword[password], 0 |
115 | mov dword[password+4], 0 |
||
116 | |||
117 | and [USERbox.flags], not ed_focus |
||
118 | or [USERbox.flags], ed_disabled |
||
119 | or [PASSbox.flags], ed_focus |
||
120 | |||
121 | mov [status], STATUS_REQ_LOGIN |
||
122 | inc [update_gui] |
||
123 | @@: |
||
124 | mcall 5, 10 |
||
125 | cmp [status], STATUS_LOGIN |
||
126 | je @f |
||
127 | cmp [status], STATUS_REQ_LOGIN |
||
128 | je @r |
||
129 | mcall -1 |
||
130 | @@: |
||
131 | DEBUGF 1, "VNC authentication\n" |
||
132 | |||
133 | ; Bit reverse the password and create DES keys |
||
134 | mov ebx, dword[password] |
||
135 | mov edx, ebx |
||
136 | and ebx, 0xf0f0f0f0 |
||
137 | shr ebx, 4 |
||
138 | and edx, 0x0f0f0f0f |
||
139 | shl edx, 4 |
||
140 | or ebx, edx |
||
141 | mov edx, ebx |
||
142 | and ebx, 0xCCCCCCCC |
||
143 | shr ebx, 2 |
||
144 | and edx, 0x33333333 |
||
145 | shl edx, 2 |
||
146 | or ebx, edx |
||
147 | mov edx, ebx |
||
148 | and ebx, 0xAAAAAAAA |
||
149 | shr ebx, 1 |
||
150 | and edx, 0x55555555 |
||
151 | shl edx, 1 |
||
152 | or ebx, edx |
||
153 | bswap ebx |
||
154 | |||
155 | mov eax, dword[password+4] |
||
156 | mov edx, eax |
||
157 | and eax, 0xf0f0f0f0 |
||
158 | shr eax, 4 |
||
159 | and edx, 0x0f0f0f0f |
||
160 | shl edx, 4 |
||
161 | or eax, edx |
||
162 | mov edx, eax |
||
163 | and eax, 0xCCCCCCCC |
||
164 | shr eax, 2 |
||
165 | and edx, 0x33333333 |
||
166 | shl edx, 2 |
||
167 | or eax, edx |
||
168 | mov edx, eax |
||
169 | and eax, 0xAAAAAAAA |
||
170 | shr eax, 1 |
||
171 | and edx, 0x55555555 |
||
172 | shl edx, 1 |
||
173 | or edx, eax |
||
174 | bswap edx |
||
175 | |||
176 | mov edi, keys |
||
177 | call DES_create_keys |
||
178 | |||
179 | ; Encrypt message with DES |
||
5720 | hidnplayr | 180 | mov esi, [esp] |
181 | mov ebx, dword[esi+0] |
||
182 | mov edx, dword[esi+4] |
||
5680 | hidnplayr | 183 | call encrypt_DES |
5720 | hidnplayr | 184 | mov esi, [esp] |
185 | mov dword[esi+0], ebx |
||
186 | mov dword[esi+4], edx |
||
5680 | hidnplayr | 187 | |
5720 | hidnplayr | 188 | mov ebx, dword[esi+8] |
189 | mov edx, dword[esi+12] |
||
5680 | hidnplayr | 190 | call encrypt_DES |
5720 | hidnplayr | 191 | mov esi, [esp] |
192 | mov dword[esi+8], ebx |
||
193 | mov dword[esi+12], edx |
||
5680 | hidnplayr | 194 | |
195 | ; Blank out the password and key fields in RAM |
||
196 | mov edi, password |
||
197 | mov ecx, 384/4 |
||
198 | xor eax, eax |
||
199 | rep stosd |
||
200 | |||
201 | ; Send the authentication response to server |
||
5720 | hidnplayr | 202 | pop edx |
203 | mcall send, [socketnum], , 16, 0 |
||
5680 | hidnplayr | 204 | |
5720 | hidnplayr | 205 | securityresult: |
206 | ; Wait for SecurityResult from server |
||
5722 | hidnplayr | 207 | call read_data |
208 | cmp eax, 4 |
||
209 | jb err_proto |
||
210 | cmp dword[esi], 0 ; OK |
||
5680 | hidnplayr | 211 | jne err_login |
212 | |||
213 | initialize: |
||
214 | DEBUGF 1, "Sending ClientInit\n" |
||
5663 | hidnplayr | 215 | mcall send, [socketnum], ClientInit, 1, 0 |
3545 | hidnplayr | 216 | |
5722 | hidnplayr | 217 | call read_data ; now the server should send init message |
218 | cmp eax, ServerInit.name |
||
219 | jb err_proto |
||
3545 | hidnplayr | 220 | |
5722 | hidnplayr | 221 | DEBUGF 2, "Serverinit: bpp: %u depth: %u bigendian: %u truecolor: %u\n", \ |
222 | [esi+ServerInit.pixelformat.bpp]:1, \ |
||
223 | [esi+ServerInit.pixelformat.depth]:1, \ |
||
224 | [esi+ServerInit.pixelformat.big_endian]:1, \ |
||
225 | [esi+ServerInit.pixelformat.true_color]:1 |
||
3545 | hidnplayr | 226 | |
5722 | hidnplayr | 227 | mov eax, dword[esi+ServerInit.width] |
5668 | hidnplayr | 228 | mov dword[FramebufferUpdateRequest.width], eax |
3545 | hidnplayr | 229 | bswap eax |
5663 | hidnplayr | 230 | mov dword[screen], eax |
231 | DEBUGF 1, "Screen width=%u, height=%u\n", [screen.width]:2, [screen.height]:2 |
||
3545 | hidnplayr | 232 | |
5722 | hidnplayr | 233 | ; Set main window caption to servername |
234 | mov ecx, dword[esi+ServerInit.name_length] |
||
235 | bswap ecx |
||
236 | add esi, ServerInit.name |
||
237 | lea eax, [esi+ecx] |
||
238 | cmp [datapointer], eax |
||
239 | jb err_proto |
||
240 | cmp ecx, 64 ; Limit name length to 64 chars |
||
241 | jbe @f |
||
242 | mov ecx, 64 |
||
243 | @@: |
||
244 | mov edi, servername |
||
245 | rep movsb |
||
246 | mov byte[edi], 0 |
||
247 | mov [name.dash], "-" |
||
248 | |||
5677 | hidnplayr | 249 | DEBUGF 1, "Sending pixel format\n" |
250 | if BITS_PER_PIXEL = 8 |
||
5668 | hidnplayr | 251 | mcall send, [socketnum], SetPixelFormat8, 20, 0 |
5677 | hidnplayr | 252 | else if BITS_PER_PIXEL = 16 |
253 | mcall send, [socketnum], SetPixelFormat16, 20, 0 |
||
5722 | hidnplayr | 254 | else if BITS_PER_PIXEL = 24 |
255 | mcall send, [socketnum], SetPixelFormat24, 20, 0 |
||
5677 | hidnplayr | 256 | else |
5722 | hidnplayr | 257 | mcall send, [socketnum], SetPixelFormat32, 20, 0 |
5677 | hidnplayr | 258 | end if |
3545 | hidnplayr | 259 | |
5677 | hidnplayr | 260 | DEBUGF 1, "Sending encoding info\n" |
5708 | hidnplayr | 261 | mcall send, [socketnum], SetEncodings, SetEncodings.length, 0 |
3545 | hidnplayr | 262 | |
5668 | hidnplayr | 263 | ; Tell the main thread we are ready for business! |
264 | mov [status], STATUS_CONNECTED |
||
265 | |||
5715 | hidnplayr | 266 | ; Request initial framebuffer update from server |
5668 | hidnplayr | 267 | mov [FramebufferUpdateRequest.inc], 0 |
5663 | hidnplayr | 268 | |
269 | request_fbu: |
||
270 | DEBUGF 1, "Requesting framebuffer update\n" |
||
5668 | hidnplayr | 271 | mcall send, [socketnum], FramebufferUpdateRequest, 10, 0 |
272 | mov [FramebufferUpdateRequest.inc], 1 |
||
3545 | hidnplayr | 273 | |
274 | thread_loop: |
||
275 | call read_data ; Read the data into the buffer |
||
276 | |||
5663 | hidnplayr | 277 | lodsb |
278 | cmp al, 0 |
||
3545 | hidnplayr | 279 | je framebufferupdate |
5663 | hidnplayr | 280 | cmp al, 1 |
3545 | hidnplayr | 281 | je setcolourmapentries |
5663 | hidnplayr | 282 | cmp al, 2 |
3545 | hidnplayr | 283 | je bell |
5663 | hidnplayr | 284 | cmp al, 3 |
3545 | hidnplayr | 285 | je servercuttext |
286 | |||
5670 | hidnplayr | 287 | DEBUGF 2, "Unknown server command: %u\n", al |
3545 | hidnplayr | 288 | jmp thread_loop |
289 | |||
290 | framebufferupdate: |
||
291 | |||
5663 | hidnplayr | 292 | @@: |
293 | lea eax, [esi+6] |
||
294 | cmp [datapointer], eax |
||
295 | jae @f |
||
296 | call read_data.more |
||
297 | jmp @b |
||
298 | @@: |
||
299 | |||
300 | inc esi ; padding |
||
301 | lodsw |
||
3545 | hidnplayr | 302 | xchg al, ah |
5663 | hidnplayr | 303 | mov [rectangles], ax |
304 | DEBUGF 1, "Framebufferupdate: %u rectangles\n", ax |
||
3545 | hidnplayr | 305 | |
5663 | hidnplayr | 306 | rectangle_loop: |
3545 | hidnplayr | 307 | |
5663 | hidnplayr | 308 | @@: |
309 | lea eax, [esi+12] |
||
310 | cmp [datapointer], eax |
||
311 | jae @f |
||
312 | call read_data.more |
||
313 | jmp @b |
||
314 | @@: |
||
3545 | hidnplayr | 315 | |
5668 | hidnplayr | 316 | xor eax, eax |
317 | lodsw |
||
318 | xchg al, ah |
||
319 | mov [rectangle.x], eax |
||
320 | lodsw |
||
321 | xchg al, ah |
||
322 | mov [rectangle.y], eax |
||
323 | lodsw |
||
324 | xchg al, ah |
||
325 | mov [rectangle.width], eax |
||
326 | lodsw |
||
327 | xchg al, ah |
||
328 | mov [rectangle.height], eax |
||
3545 | hidnplayr | 329 | |
5663 | hidnplayr | 330 | lodsd ; encoding |
5708 | hidnplayr | 331 | bswap eax |
5715 | hidnplayr | 332 | DEBUGF 1, "Rectangle: x=%u y=%u width=%u height=%u encoding: ",\ |
333 | [rectangle.x]:2, [rectangle.y]:2, [rectangle.width]:2, [rectangle.height]:2 |
||
3545 | hidnplayr | 334 | |
335 | cmp eax, 0 |
||
336 | je encoding_raw |
||
5666 | hidnplayr | 337 | cmp eax, 1 |
5668 | hidnplayr | 338 | je encoding_CopyRect |
339 | cmp eax, 2 |
||
340 | je encoding_RRE |
||
5720 | hidnplayr | 341 | cmp eax, 15 |
342 | je encoding_TRLE |
||
343 | cmp eax, 16 |
||
344 | je encoding_ZRLE |
||
3545 | hidnplayr | 345 | |
5670 | hidnplayr | 346 | DEBUGF 2, "unknown encoding: %u\n", eax |
3545 | hidnplayr | 347 | jmp thread_loop |
348 | |||
5663 | hidnplayr | 349 | next_rectangle: |
5670 | hidnplayr | 350 | inc [update_framebuffer] |
5663 | hidnplayr | 351 | dec [rectangles] |
352 | jnz rectangle_loop |
||
353 | jmp request_fbu |
||
3545 | hidnplayr | 354 | |
355 | |||
5663 | hidnplayr | 356 | setcolourmapentries: |
3545 | hidnplayr | 357 | |
5663 | hidnplayr | 358 | DEBUGF 1, "Server sent SetColourMapEntries message\n" |
3545 | hidnplayr | 359 | |
5677 | hidnplayr | 360 | @@: |
361 | lea eax, [esi+5] |
||
362 | cmp [datapointer], eax |
||
363 | jae @f |
||
364 | call read_data.more |
||
365 | jmp @b |
||
366 | @@: |
||
3545 | hidnplayr | 367 | |
5677 | hidnplayr | 368 | inc esi ; padding |
369 | |||
370 | xor eax, eax |
||
371 | lodsw ; first color (just ignore for now) |
||
372 | |||
373 | lodsw ; number of colors (use to find end of message) |
||
374 | xchg al, ah |
||
375 | lea eax, [eax*2+eax] |
||
376 | shl eax, 1 |
||
377 | @@: |
||
378 | push eax |
||
379 | add eax, esi |
||
380 | cmp [datapointer], eax |
||
381 | jae @f |
||
382 | call read_data.more |
||
383 | pop eax |
||
384 | jmp @b |
||
385 | @@: |
||
386 | pop eax |
||
387 | |||
388 | add esi, eax ; Just skip it for now. |
||
3545 | hidnplayr | 389 | jmp thread_loop |
390 | |||
391 | |||
392 | bell: |
||
393 | mcall 55, 55, , , beep |
||
394 | jmp thread_loop |
||
395 | |||
396 | |||
397 | servercuttext: |
||
398 | |||
5663 | hidnplayr | 399 | DEBUGF 1, "Server cut text\n" |
3545 | hidnplayr | 400 | |
5663 | hidnplayr | 401 | @@: |
402 | lea eax, [esi+7] |
||
403 | cmp [datapointer], eax |
||
404 | jae @f |
||
405 | call read_data.more |
||
406 | jmp @b |
||
407 | @@: |
||
408 | |||
409 | add esi, 3 |
||
410 | lodsd |
||
411 | bswap eax |
||
412 | mov ecx, eax |
||
413 | |||
414 | @@: |
||
415 | lea eax, [esi+ecx] |
||
416 | cmp [datapointer], eax |
||
417 | jae @f |
||
418 | call read_data.more |
||
419 | jmp @b |
||
420 | @@: |
||
421 | |||
422 | ; TODO: paste text to clipboard |
||
423 | |||
424 | DEBUGF 1, "%u bytes of text\n", ecx |
||
425 | add esi, ecx |
||
3545 | hidnplayr | 426 | jmp thread_loop |
427 | |||
428 | |||
429 | read_data: |
||
430 | mov [datapointer], receive_buffer |
||
5663 | hidnplayr | 431 | mov esi, receive_buffer |
432 | .more: |
||
433 | push ebx ecx edx esi edi |
||
5677 | hidnplayr | 434 | neg esi |
435 | add esi, receive_buffer + RECEIVE_BUFFER_SIZE |
||
436 | jz .buffer_end_reached |
||
437 | xor edi, edi |
||
438 | mcall recv, [socketnum], [datapointer] |
||
5663 | hidnplayr | 439 | pop edi esi edx ecx ebx |
3545 | hidnplayr | 440 | cmp eax, -1 |
5677 | hidnplayr | 441 | je err_sock |
442 | test eax, eax |
||
443 | jz err_disconnected |
||
5668 | hidnplayr | 444 | add [datapointer], eax |
5677 | hidnplayr | 445 | ret |
446 | |||
447 | .buffer_end_reached: |
||
5720 | hidnplayr | 448 | DEBUGF 1, "end of buffer reached, re-organizing\n" |
449 | pop edi esi edx ecx ebx |
||
5668 | hidnplayr | 450 | ; Buffer is full, first needed data by program is pointed to by esi. |
5677 | hidnplayr | 451 | ; Move all usefull data to begin of buffer |
5668 | hidnplayr | 452 | cmp esi, receive_buffer |
453 | je err_proto |
||
454 | mov ecx, [datapointer] |
||
455 | sub ecx, esi |
||
456 | mov edi, receive_buffer |
||
457 | rep movsb |
||
5677 | hidnplayr | 458 | mov [datapointer], edi ; new end of data |
459 | mov esi, receive_buffer ; new start of data |
||
460 | jmp .more |
||
3545 | hidnplayr | 461 | |
462 | |||
5668 | hidnplayr | 463 | err_disconnected: |
464 | mov [status], STATUS_DISCONNECTED |
||
465 | inc [update_gui] |
||
466 | mcall -1 |
||
467 | |||
468 | err_dns: |
||
469 | mov [status], STATUS_DNS_ERR |
||
470 | inc [update_gui] |
||
471 | mcall -1 |
||
472 | |||
473 | err_sock: |
||
5722 | hidnplayr | 474 | ; TODO: distinguish between different socket errors! |
475 | DEBUGF 2, "Socket error: %u\n", ebx |
||
5668 | hidnplayr | 476 | mov [status], STATUS_SOCK_ERR |
477 | inc [update_gui] |
||
478 | mcall -1 |
||
479 | |||
480 | err_connect: |
||
481 | mov [status], STATUS_CONNECT_ERR |
||
482 | inc [update_gui] |
||
483 | mcall -1 |
||
3545 | hidnplayr | 484 | ret |
485 | |||
5668 | hidnplayr | 486 | err_proto: |
487 | mov [status], STATUS_PROTO_ERR |
||
488 | inc [update_gui] |
||
5663 | hidnplayr | 489 | mcall -1 |
490 | ret |
||
491 | |||
5720 | hidnplayr | 492 | err_handshake: |
5668 | hidnplayr | 493 | mov [status], STATUS_SECURITY_ERR |
5720 | hidnplayr | 494 | |
495 | lodsd ; Custom message from server? |
||
496 | test eax, eax |
||
497 | jz .no_msg |
||
498 | bswap eax |
||
499 | mov ecx, eax |
||
500 | cmp ecx, 512 |
||
501 | jb @f |
||
502 | mov ecx, 512 |
||
503 | @@: |
||
504 | mov edi, sz_err_security_c |
||
505 | rep movsb |
||
506 | mov byte[edi], 0 |
||
507 | mov [status], STATUS_SECURITY_ERR_C |
||
508 | .no_msg: |
||
509 | |||
5668 | hidnplayr | 510 | inc [update_gui] |
511 | mcall -1 |
||
512 | ret |
||
5680 | hidnplayr | 513 | |
514 | err_login: |
||
515 | mov [status], STATUS_LOGIN_FAILED |
||
516 | inc [update_gui] |
||
517 | mcall -1 |
||
518 | ret |