Rev 5677 | Rev 5708 | 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 | |
19 | ; resolve name |
||
5668 | hidnplayr | 20 | push esp ; reserve stack place |
5663 | hidnplayr | 21 | invoke getaddrinfo, serveraddr, 0, 0, esp |
3545 | hidnplayr | 22 | pop esi |
23 | ; test for error |
||
24 | test eax, eax |
||
5668 | hidnplayr | 25 | jnz err_dns |
3545 | hidnplayr | 26 | |
27 | mov eax, [esi+addrinfo.ai_addr] |
||
28 | mov eax, [eax+sockaddr_in.sin_addr] |
||
29 | mov [sockaddr1.ip], eax |
||
30 | |||
5663 | hidnplayr | 31 | DEBUGF 1, "Connecting to %u.%u.%u.%u:%u\n", \ |
5680 | hidnplayr | 32 | [sockaddr1.ip]:1, [sockaddr1.ip+1]:1, [sockaddr1.ip+2]:1, [sockaddr1.ip+3]:1, \ |
33 | [sockaddr1.port]:2 |
||
3545 | hidnplayr | 34 | |
5668 | hidnplayr | 35 | invoke freeaddrinfo, esi |
36 | |||
3545 | hidnplayr | 37 | mcall socket, AF_INET4, SOCK_STREAM, 0 |
5668 | hidnplayr | 38 | cmp eax, -1 |
39 | je err_sock |
||
40 | |||
3545 | hidnplayr | 41 | mov [socketnum], eax |
42 | mcall connect, [socketnum], sockaddr1, 18 |
||
5668 | hidnplayr | 43 | cmp eax, -1 |
44 | je err_connect |
||
3545 | hidnplayr | 45 | |
5663 | hidnplayr | 46 | ; TODO: implement timeout |
3545 | hidnplayr | 47 | call wait_for_data |
48 | |||
5663 | hidnplayr | 49 | cmp dword[receive_buffer], "RFB " |
5668 | hidnplayr | 50 | jne err_proto |
5680 | hidnplayr | 51 | DEBUGF 1, "Sending handshake\n" |
5668 | hidnplayr | 52 | mcall send, [socketnum], HandShake, 12, 0 |
3545 | hidnplayr | 53 | call wait_for_data |
54 | |||
5680 | hidnplayr | 55 | cmp dword[receive_buffer], 0x01000000 ; no security |
56 | je initialize |
||
57 | cmp dword[receive_buffer], 0x02000000 ; VNC security |
||
3545 | hidnplayr | 58 | je vnc_security |
5680 | hidnplayr | 59 | |
5668 | hidnplayr | 60 | jmp err_security |
3545 | hidnplayr | 61 | |
62 | vnc_security: |
||
63 | |||
5680 | hidnplayr | 64 | mov dword[password], 0 |
65 | mov dword[password+4], 0 |
||
66 | |||
67 | and [USERbox.flags], not ed_focus |
||
68 | or [USERbox.flags], ed_disabled |
||
69 | or [PASSbox.flags], ed_focus |
||
70 | |||
71 | mov [status], STATUS_REQ_LOGIN |
||
72 | inc [update_gui] |
||
73 | @@: |
||
74 | mcall 5, 10 |
||
75 | cmp [status], STATUS_LOGIN |
||
76 | je @f |
||
77 | cmp [status], STATUS_REQ_LOGIN |
||
78 | je @r |
||
79 | mcall -1 |
||
80 | @@: |
||
81 | DEBUGF 1, "VNC authentication\n" |
||
82 | |||
83 | ; Bit reverse the password and create DES keys |
||
84 | |||
85 | mov ebx, dword[password] |
||
86 | mov edx, ebx |
||
87 | and ebx, 0xf0f0f0f0 |
||
88 | shr ebx, 4 |
||
89 | and edx, 0x0f0f0f0f |
||
90 | shl edx, 4 |
||
91 | or ebx, edx |
||
92 | mov edx, ebx |
||
93 | and ebx, 0xCCCCCCCC |
||
94 | shr ebx, 2 |
||
95 | and edx, 0x33333333 |
||
96 | shl edx, 2 |
||
97 | or ebx, edx |
||
98 | mov edx, ebx |
||
99 | and ebx, 0xAAAAAAAA |
||
100 | shr ebx, 1 |
||
101 | and edx, 0x55555555 |
||
102 | shl edx, 1 |
||
103 | or ebx, edx |
||
104 | bswap ebx |
||
105 | |||
106 | mov eax, dword[password+4] |
||
107 | mov edx, eax |
||
108 | and eax, 0xf0f0f0f0 |
||
109 | shr eax, 4 |
||
110 | and edx, 0x0f0f0f0f |
||
111 | shl edx, 4 |
||
112 | or eax, edx |
||
113 | mov edx, eax |
||
114 | and eax, 0xCCCCCCCC |
||
115 | shr eax, 2 |
||
116 | and edx, 0x33333333 |
||
117 | shl edx, 2 |
||
118 | or eax, edx |
||
119 | mov edx, eax |
||
120 | and eax, 0xAAAAAAAA |
||
121 | shr eax, 1 |
||
122 | and edx, 0x55555555 |
||
123 | shl edx, 1 |
||
124 | or edx, eax |
||
125 | bswap edx |
||
126 | |||
127 | mov edi, keys |
||
128 | call DES_create_keys |
||
129 | |||
130 | ; Encrypt message with DES |
||
131 | |||
132 | mov ebx, dword[receive_buffer+4] |
||
133 | mov edx, dword[receive_buffer+8] |
||
134 | call encrypt_DES |
||
135 | mov dword[receive_buffer+4], ebx |
||
136 | mov dword[receive_buffer+8], edx |
||
137 | |||
138 | mov ebx, dword[receive_buffer+12] |
||
139 | mov edx, dword[receive_buffer+16] |
||
140 | call encrypt_DES |
||
141 | mov dword[receive_buffer+12], ebx |
||
142 | mov dword[receive_buffer+16], edx |
||
143 | |||
144 | ; Blank out the password and key fields in RAM |
||
145 | |||
146 | mov edi, password |
||
147 | mov ecx, 384/4 |
||
148 | xor eax, eax |
||
149 | rep stosd |
||
150 | |||
151 | ; Send the authentication response to server |
||
152 | |||
153 | mcall send, [socketnum], receive_buffer+4, 16, 0 |
||
154 | |||
155 | call wait_for_data |
||
156 | cmp dword[receive_buffer], 0 |
||
157 | jne err_login |
||
158 | ; jmp initialize |
||
159 | |||
160 | initialize: |
||
161 | DEBUGF 1, "Sending ClientInit\n" |
||
5663 | hidnplayr | 162 | mcall send, [socketnum], ClientInit, 1, 0 |
3545 | hidnplayr | 163 | |
164 | call wait_for_data ; now the server should send init message |
||
165 | |||
5663 | hidnplayr | 166 | DEBUGF 1, "Serverinit: bpp: %u depth: %u bigendian: %u truecolor: %u\n", \ |
167 | [receive_buffer+framebuffer.pixelformat.bpp]:1, \ |
||
168 | [receive_buffer+framebuffer.pixelformat.depth]:1, \ |
||
169 | [receive_buffer+framebuffer.pixelformat.big_endian]:1, \ |
||
170 | [receive_buffer+framebuffer.pixelformat.true_color]:1 |
||
3545 | hidnplayr | 171 | |
5663 | hidnplayr | 172 | mov eax, dword[receive_buffer+framebuffer.width] |
5668 | hidnplayr | 173 | mov dword[FramebufferUpdateRequest.width], eax |
3545 | hidnplayr | 174 | bswap eax |
5663 | hidnplayr | 175 | mov dword[screen], eax |
176 | DEBUGF 1, "Screen width=%u, height=%u\n", [screen.width]:2, [screen.height]:2 |
||
3545 | hidnplayr | 177 | |
5677 | hidnplayr | 178 | DEBUGF 1, "Sending pixel format\n" |
179 | if BITS_PER_PIXEL = 8 |
||
5668 | hidnplayr | 180 | mcall send, [socketnum], SetPixelFormat8, 20, 0 |
5677 | hidnplayr | 181 | else if BITS_PER_PIXEL = 16 |
182 | mcall send, [socketnum], SetPixelFormat16, 20, 0 |
||
183 | else |
||
184 | mcall send, [socketnum], SetPixelFormat24, 20, 0 |
||
185 | end if |
||
3545 | hidnplayr | 186 | |
5677 | hidnplayr | 187 | DEBUGF 1, "Sending encoding info\n" |
5668 | hidnplayr | 188 | mcall send, [socketnum], SetEncodings, 12, 0 |
3545 | hidnplayr | 189 | |
5668 | hidnplayr | 190 | ; Set main window caption to servername |
191 | mov ecx, dword[receive_buffer+framebuffer.name_length] |
||
192 | bswap ecx |
||
193 | cmp ecx, 64 |
||
194 | jbe @f |
||
195 | mov ecx, 64 |
||
196 | @@: |
||
197 | lea esi, [receive_buffer+framebuffer.name] |
||
198 | mov edi, servername |
||
199 | rep movsb |
||
200 | mov byte[edi], 0 |
||
201 | mov [name.dash], "-" |
||
3545 | hidnplayr | 202 | |
5668 | hidnplayr | 203 | ; Tell the main thread we are ready for business! |
204 | mov [status], STATUS_CONNECTED |
||
205 | |||
5663 | hidnplayr | 206 | ; Request initial update |
5668 | hidnplayr | 207 | mov [FramebufferUpdateRequest.inc], 0 |
5663 | hidnplayr | 208 | |
209 | request_fbu: |
||
210 | DEBUGF 1, "Requesting framebuffer update\n" |
||
5668 | hidnplayr | 211 | mcall send, [socketnum], FramebufferUpdateRequest, 10, 0 |
212 | mov [FramebufferUpdateRequest.inc], 1 |
||
3545 | hidnplayr | 213 | |
214 | thread_loop: |
||
215 | call read_data ; Read the data into the buffer |
||
216 | |||
5663 | hidnplayr | 217 | lodsb |
218 | cmp al, 0 |
||
3545 | hidnplayr | 219 | je framebufferupdate |
5663 | hidnplayr | 220 | cmp al, 1 |
3545 | hidnplayr | 221 | je setcolourmapentries |
5663 | hidnplayr | 222 | cmp al, 2 |
3545 | hidnplayr | 223 | je bell |
5663 | hidnplayr | 224 | cmp al, 3 |
3545 | hidnplayr | 225 | je servercuttext |
226 | |||
5670 | hidnplayr | 227 | DEBUGF 2, "Unknown server command: %u\n", al |
3545 | hidnplayr | 228 | jmp thread_loop |
229 | |||
230 | framebufferupdate: |
||
231 | |||
5663 | hidnplayr | 232 | @@: |
233 | lea eax, [esi+6] |
||
234 | cmp [datapointer], eax |
||
235 | jae @f |
||
236 | call read_data.more |
||
237 | jmp @b |
||
238 | @@: |
||
239 | |||
240 | inc esi ; padding |
||
241 | lodsw |
||
3545 | hidnplayr | 242 | xchg al, ah |
5663 | hidnplayr | 243 | mov [rectangles], ax |
244 | DEBUGF 1, "Framebufferupdate: %u rectangles\n", ax |
||
3545 | hidnplayr | 245 | |
5663 | hidnplayr | 246 | rectangle_loop: |
3545 | hidnplayr | 247 | |
5663 | hidnplayr | 248 | @@: |
249 | lea eax, [esi+12] |
||
250 | cmp [datapointer], eax |
||
251 | jae @f |
||
252 | call read_data.more |
||
253 | jmp @b |
||
254 | @@: |
||
3545 | hidnplayr | 255 | |
5668 | hidnplayr | 256 | xor eax, eax |
257 | lodsw |
||
258 | xchg al, ah |
||
259 | mov [rectangle.x], eax |
||
260 | lodsw |
||
261 | xchg al, ah |
||
262 | mov [rectangle.y], eax |
||
263 | lodsw |
||
264 | xchg al, ah |
||
265 | mov [rectangle.width], eax |
||
266 | lodsw |
||
267 | xchg al, ah |
||
268 | mov [rectangle.height], eax |
||
3545 | hidnplayr | 269 | |
5663 | hidnplayr | 270 | lodsd ; encoding |
271 | DEBUGF 1, "rectangle: width=%u height=%u x=%u y=%u encoding: ",\ |
||
272 | [rectangle.width]:2, [rectangle.height]:2, [rectangle.x]:2, [rectangle.y]:2 |
||
3545 | hidnplayr | 273 | |
274 | cmp eax, 0 |
||
275 | je encoding_raw |
||
5666 | hidnplayr | 276 | cmp eax, 1 |
5668 | hidnplayr | 277 | je encoding_CopyRect |
278 | cmp eax, 2 |
||
279 | je encoding_RRE |
||
5663 | hidnplayr | 280 | ; cmp eax, 5 |
281 | ; je encoding_hextile |
||
282 | ; cmp eax, 15 |
||
283 | ; je encoding_TRLE |
||
284 | ; cmp eax, 16 |
||
285 | ; je encoding_ZRLE |
||
3545 | hidnplayr | 286 | |
5670 | hidnplayr | 287 | DEBUGF 2, "unknown encoding: %u\n", eax |
3545 | hidnplayr | 288 | jmp thread_loop |
289 | |||
5663 | hidnplayr | 290 | next_rectangle: |
5670 | hidnplayr | 291 | inc [update_framebuffer] |
5663 | hidnplayr | 292 | dec [rectangles] |
293 | jnz rectangle_loop |
||
294 | jmp request_fbu |
||
3545 | hidnplayr | 295 | |
296 | |||
5663 | hidnplayr | 297 | setcolourmapentries: |
3545 | hidnplayr | 298 | |
5663 | hidnplayr | 299 | DEBUGF 1, "Server sent SetColourMapEntries message\n" |
3545 | hidnplayr | 300 | |
5677 | hidnplayr | 301 | @@: |
302 | lea eax, [esi+5] |
||
303 | cmp [datapointer], eax |
||
304 | jae @f |
||
305 | call read_data.more |
||
306 | jmp @b |
||
307 | @@: |
||
3545 | hidnplayr | 308 | |
5677 | hidnplayr | 309 | inc esi ; padding |
310 | |||
311 | xor eax, eax |
||
312 | lodsw ; first color (just ignore for now) |
||
313 | |||
314 | lodsw ; number of colors (use to find end of message) |
||
315 | xchg al, ah |
||
316 | lea eax, [eax*2+eax] |
||
317 | shl eax, 1 |
||
318 | @@: |
||
319 | push eax |
||
320 | add eax, esi |
||
321 | cmp [datapointer], eax |
||
322 | jae @f |
||
323 | call read_data.more |
||
324 | pop eax |
||
325 | jmp @b |
||
326 | @@: |
||
327 | pop eax |
||
328 | |||
329 | add esi, eax ; Just skip it for now. |
||
3545 | hidnplayr | 330 | jmp thread_loop |
331 | |||
332 | |||
333 | bell: |
||
334 | mcall 55, 55, , , beep |
||
335 | jmp thread_loop |
||
336 | |||
337 | |||
338 | servercuttext: |
||
339 | |||
5663 | hidnplayr | 340 | DEBUGF 1, "Server cut text\n" |
3545 | hidnplayr | 341 | |
5663 | hidnplayr | 342 | @@: |
343 | lea eax, [esi+7] |
||
344 | cmp [datapointer], eax |
||
345 | jae @f |
||
346 | call read_data.more |
||
347 | jmp @b |
||
348 | @@: |
||
349 | |||
350 | add esi, 3 |
||
351 | lodsd |
||
352 | bswap eax |
||
353 | mov ecx, eax |
||
354 | |||
355 | @@: |
||
356 | lea eax, [esi+ecx] |
||
357 | cmp [datapointer], eax |
||
358 | jae @f |
||
359 | call read_data.more |
||
360 | jmp @b |
||
361 | @@: |
||
362 | |||
363 | ; TODO: paste text to clipboard |
||
364 | |||
365 | DEBUGF 1, "%u bytes of text\n", ecx |
||
366 | add esi, ecx |
||
3545 | hidnplayr | 367 | jmp thread_loop |
368 | |||
369 | |||
370 | read_data: |
||
371 | mov [datapointer], receive_buffer |
||
5663 | hidnplayr | 372 | mov esi, receive_buffer |
373 | .more: |
||
374 | push ebx ecx edx esi edi |
||
5677 | hidnplayr | 375 | neg esi |
376 | add esi, receive_buffer + RECEIVE_BUFFER_SIZE |
||
377 | jz .buffer_end_reached |
||
378 | xor edi, edi |
||
379 | mcall recv, [socketnum], [datapointer] |
||
5663 | hidnplayr | 380 | pop edi esi edx ecx ebx |
3545 | hidnplayr | 381 | cmp eax, -1 |
5677 | hidnplayr | 382 | je err_sock |
383 | test eax, eax |
||
384 | jz err_disconnected |
||
5668 | hidnplayr | 385 | add [datapointer], eax |
5677 | hidnplayr | 386 | ret |
387 | |||
388 | .buffer_end_reached: |
||
5668 | hidnplayr | 389 | ; Buffer is full, first needed data by program is pointed to by esi. |
5677 | hidnplayr | 390 | ; Move all usefull data to begin of buffer |
5668 | hidnplayr | 391 | cmp esi, receive_buffer |
392 | je err_proto |
||
393 | mov ecx, [datapointer] |
||
394 | sub ecx, esi |
||
395 | mov edi, receive_buffer |
||
396 | rep movsb |
||
5677 | hidnplayr | 397 | mov [datapointer], edi ; new end of data |
398 | mov esi, receive_buffer ; new start of data |
||
399 | jmp .more |
||
3545 | hidnplayr | 400 | |
401 | |||
5677 | hidnplayr | 402 | |
5663 | hidnplayr | 403 | wait_for_data: ; FIXME: add timeout |
5677 | hidnplayr | 404 | mcall recv, [socketnum], receive_buffer, 4096, 0 ; MSG_DONTWAIT |
3545 | hidnplayr | 405 | cmp eax, -1 |
5677 | hidnplayr | 406 | je err_sock |
3545 | hidnplayr | 407 | test eax, eax |
5677 | hidnplayr | 408 | jz err_disconnected |
5668 | hidnplayr | 409 | ret |
3545 | hidnplayr | 410 | |
5668 | hidnplayr | 411 | |
412 | err_disconnected: |
||
413 | mov [status], STATUS_DISCONNECTED |
||
414 | inc [update_gui] |
||
415 | mcall -1 |
||
416 | |||
417 | err_dns: |
||
418 | mov [status], STATUS_DNS_ERR |
||
419 | inc [update_gui] |
||
420 | mcall -1 |
||
421 | |||
422 | err_sock: |
||
423 | mov [status], STATUS_SOCK_ERR |
||
424 | inc [update_gui] |
||
425 | mcall -1 |
||
426 | |||
427 | err_connect: |
||
428 | mov [status], STATUS_CONNECT_ERR |
||
429 | inc [update_gui] |
||
430 | mcall -1 |
||
3545 | hidnplayr | 431 | ret |
432 | |||
5668 | hidnplayr | 433 | err_proto: |
434 | mov [status], STATUS_PROTO_ERR |
||
435 | inc [update_gui] |
||
5663 | hidnplayr | 436 | mcall -1 |
437 | ret |
||
438 | |||
5668 | hidnplayr | 439 | err_security: |
440 | mov [status], STATUS_SECURITY_ERR |
||
441 | inc [update_gui] |
||
442 | mcall -1 |
||
443 | ret |
||
5680 | hidnplayr | 444 | |
445 | err_login: |
||
446 | mov [status], STATUS_LOGIN_FAILED |
||
447 | inc [update_gui] |
||
448 | mcall -1 |
||
449 | ret |