1 /*
2 Copyright 2005-2017 Jay Sorg
3
4 Permission to use, copy, modify, distribute, and sell this software and its
5 documentation for any purpose is hereby granted without fee, provided that
6 the above copyright notice appear in all copies and that both that
7 copyright notice and this permission notice appear in supporting
8 documentation.
9
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
20 Client connection to xrdp
21
22 */
23
24 #if defined(HAVE_CONFIG_H)
25 #include "config_ac.h"
26 #endif
27
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <signal.h>
33 #include <sys/types.h>
34 #include <sys/ipc.h>
35 #include <sys/shm.h>
36 #include <limits.h>
37
38 /* this should be before all X11 .h files */
39 #include <xorg-server.h>
40 #include <xorgVersion.h>
41
42 /* all driver need this */
43 #include <xf86.h>
44 #include <xf86_OSproc.h>
45
46 #include "rdp.h"
47 #include "rdpDraw.h"
48 #include "rdpClientCon.h"
49 #include "rdpMisc.h"
50 #include "rdpInput.h"
51 #include "rdpReg.h"
52 #include "rdpCapture.h"
53 #include "rdpRandR.h"
54
55 #define LOG_LEVEL 1
56 #define LLOGLN(_level, _args) \
57 do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0)
58
59 #define LTOUI32(_in) ((unsigned int)(_in))
60
61 #define USE_MAX_OS_BYTES 1
62 #define MAX_OS_BYTES (16 * 1024 * 1024)
63
64 /*
65 0 GXclear, 0
66 1 GXnor, DPon
67 2 GXandInverted, DPna
68 3 GXcopyInverted, Pn
69 4 GXandReverse, PDna
70 5 GXinvert, Dn
71 6 GXxor, DPx
72 7 GXnand, DPan
73 8 GXand, DPa
74 9 GXequiv, DPxn
75 a GXnoop, D
76 b GXorInverted, DPno
77 c GXcopy, P
78 d GXorReverse, PDno
79 e GXor, DPo
80 f GXset 1
81 */
82
83 static int g_rdp_opcodes[16] =
84 {
85 0x00, /* GXclear 0x0 0 */
86 0x88, /* GXand 0x1 src AND dst */
87 0x44, /* GXandReverse 0x2 src AND NOT dst */
88 0xcc, /* GXcopy 0x3 src */
89 0x22, /* GXandInverted 0x4 NOT src AND dst */
90 0xaa, /* GXnoop 0x5 dst */
91 0x66, /* GXxor 0x6 src XOR dst */
92 0xee, /* GXor 0x7 src OR dst */
93 0x11, /* GXnor 0x8 NOT src AND NOT dst */
94 0x99, /* GXequiv 0x9 NOT src XOR dst */
95 0x55, /* GXinvert 0xa NOT dst */
96 0xdd, /* GXorReverse 0xb src OR NOT dst */
97 0x33, /* GXcopyInverted 0xc NOT src */
98 0xbb, /* GXorInverted 0xd NOT src OR dst */
99 0x77, /* GXnand 0xe NOT src OR NOT dst */
100 0xff /* GXset 0xf 1 */
101 };
102
103 static int
104 rdpClientConDisconnect(rdpPtr dev, rdpClientCon *clientCon);
105 static CARD32
106 rdpDeferredIdleDisconnectCallback(OsTimerPtr timer, CARD32 now, pointer arg);
107 static void
108 rdpScheduleDeferredUpdate(rdpClientCon *clientCon);
109
110 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 5, 0, 0)
111
112 /******************************************************************************/
113 static int
rdpClientConAddEnabledDevice(ScreenPtr pScreen,int fd)114 rdpClientConAddEnabledDevice(ScreenPtr pScreen, int fd)
115 {
116 AddEnabledDevice(fd);
117 return 0;
118 }
119
120 /******************************************************************************/
121 static int
rdpClientConRemoveEnabledDevice(int fd)122 rdpClientConRemoveEnabledDevice(int fd)
123 {
124 RemoveEnabledDevice(fd);
125 return 0;
126 }
127
128 #else
129
130 /******************************************************************************/
131 static void
rdpClientConNotifyFdProcPtr(int fd,int ready,void * data)132 rdpClientConNotifyFdProcPtr(int fd, int ready, void *data)
133 {
134 ScreenPtr pScreen = (ScreenPtr) data;
135 rdpClientConCheck(pScreen);
136 }
137
138 /******************************************************************************/
139 static int
rdpClientConAddEnabledDevice(ScreenPtr pScreen,int fd)140 rdpClientConAddEnabledDevice(ScreenPtr pScreen, int fd)
141 {
142 SetNotifyFd(fd, rdpClientConNotifyFdProcPtr, X_NOTIFY_READ, pScreen);
143 return 0;
144 }
145
146 /******************************************************************************/
147 static int
rdpClientConRemoveEnabledDevice(int fd)148 rdpClientConRemoveEnabledDevice(int fd)
149 {
150 RemoveNotifyFd(fd);
151 return 0;
152 }
153
154 #endif
155
156 /******************************************************************************/
157 static void
rdpAddClientConToDev(rdpPtr dev,rdpClientCon * clientCon)158 rdpAddClientConToDev(rdpPtr dev, rdpClientCon *clientCon)
159 {
160 clientCon->next = NULL;
161 clientCon->prev = dev->clientConTail;
162
163 if (dev->clientConTail == NULL)
164 {
165 LLOGLN(0, ("rdpAddClientConToDev: adding first clientCon %p",
166 clientCon));
167 dev->clientConHead = clientCon;
168 }
169 else
170 {
171 LLOGLN(0, ("rdpAddClientConToDev: adding clientCon %p",
172 clientCon));
173 dev->clientConTail->next = clientCon;
174 }
175 dev->clientConTail = clientCon;
176 }
177
178 /******************************************************************************/
179 static void
rdpRemoveClientConFromDev(rdpPtr dev,rdpClientCon * clientCon)180 rdpRemoveClientConFromDev(rdpPtr dev, rdpClientCon *clientCon)
181 {
182 LLOGLN(0, ("rdpRemoveClientConFromDev: removing clientCon %p",
183 clientCon));
184
185 if (clientCon->prev == NULL)
186 {
187 /* first in list */
188 dev->clientConHead = clientCon->next;
189 }
190 else
191 {
192 clientCon->prev->next = clientCon->next;
193 }
194
195 if (clientCon->next == NULL)
196 {
197 /* last in list */
198 dev->clientConTail = clientCon->prev;
199 }
200 else
201 {
202 clientCon->next->prev = clientCon->prev;
203 }
204 }
205
206 /******************************************************************************/
207 static int
rdpClientConGotConnection(ScreenPtr pScreen,rdpPtr dev)208 rdpClientConGotConnection(ScreenPtr pScreen, rdpPtr dev)
209 {
210 rdpClientCon *clientCon;
211 int new_sck;
212
213 LLOGLN(0, ("rdpClientConGotConnection:"));
214 clientCon = g_new0(rdpClientCon, 1);
215 clientCon->shmemstatus = SHM_UNINITIALIZED;
216 clientCon->updateRetries = 0;
217 clientCon->dev = dev;
218 dev->last_event_time_ms = GetTimeInMillis();
219 dev->do_dirty_ons = 1;
220
221 make_stream(clientCon->in_s);
222 init_stream(clientCon->in_s, 8192);
223 make_stream(clientCon->out_s);
224 init_stream(clientCon->out_s, 8192 * 4 + 100);
225
226 new_sck = g_sck_accept(dev->listen_sck);
227 if (new_sck == -1)
228 {
229 LLOGLN(0, ("rdpClientConGotConnection: g_sck_accept failed"));
230 }
231 else
232 {
233 LLOGLN(0, ("rdpClientConGotConnection: g_sck_accept ok new_sck %d",
234 new_sck));
235 clientCon->sck = new_sck;
236 g_sck_set_non_blocking(clientCon->sck);
237 g_sck_tcp_set_no_delay(clientCon->sck); /* only works if TCP */
238 clientCon->connected = TRUE;
239 clientCon->begin = FALSE;
240 dev->conNumber++;
241 clientCon->conNumber = dev->conNumber;
242 rdpClientConAddEnabledDevice(pScreen, clientCon->sck);
243 }
244
245 #if 1
246 if (dev->clientConTail != NULL)
247 {
248 /* Only allow one client at a time */
249 LLOGLN(0, ("rdpClientConGotConnection: "
250 "marking only clientCon %p for disconnect",
251 dev->clientConTail));
252 dev->clientConTail->connected = FALSE;
253 }
254 #endif
255
256 /* set idle timer to disconnect */
257 if (dev->idle_disconnect_timeout_s > 0)
258 {
259 LLOGLN(0, ("rdpClientConGetConnection: "
260 "engaging idle timer, timeout [%d] sec", dev->idle_disconnect_timeout_s));
261 dev->idleDisconnectTimer = TimerSet(dev->idleDisconnectTimer, 0, dev->idle_disconnect_timeout_s * 1000,
262 rdpDeferredIdleDisconnectCallback, dev);
263 }
264 else
265 {
266 LLOGLN(0, ("rdpClientConGetConnection: "
267 "idle_disconnect_timeout set to non-positive value, idle timer turned off"));
268 }
269
270 rdpAddClientConToDev(dev, clientCon);
271
272 clientCon->dirtyRegion = rdpRegionCreate(NullBox, 0);
273 clientCon->shmRegion = rdpRegionCreate(NullBox, 0);
274
275 return 0;
276 }
277
278 /******************************************************************************/
279 static CARD32
rdpDeferredDisconnectCallback(OsTimerPtr timer,CARD32 now,pointer arg)280 rdpDeferredDisconnectCallback(OsTimerPtr timer, CARD32 now, pointer arg)
281 {
282 rdpPtr dev;
283
284 dev = (rdpPtr) arg;
285 LLOGLN(10, ("rdpDeferredDisconnectCallback"));
286 if (dev->clientConHead != NULL)
287 {
288 /* this should not happen */
289 LLOGLN(0, ("rdpDeferredDisconnectCallback: connected"));
290 if (dev->disconnectTimer != NULL)
291 {
292 LLOGLN(0, ("rdpDeferredDisconnectCallback: disengaging disconnect timer"));
293 TimerCancel(dev->disconnectTimer);
294 TimerFree(dev->disconnectTimer);
295 dev->disconnectTimer = NULL;
296 }
297 dev->disconnect_scheduled = FALSE;
298 return 0;
299 }
300 else
301 {
302 LLOGLN(10, ("rdpDeferredDisconnectCallback: not connected"));
303 }
304 if (now - dev->disconnect_time_ms > dev->disconnect_timeout_s * 1000)
305 {
306 LLOGLN(0, ("rdpDeferredDisconnectCallback: "
307 "disconnect timeout exceeded, exiting"));
308 kill(getpid(), SIGTERM);
309 return 0;
310 }
311 dev->disconnectTimer = TimerSet(dev->disconnectTimer, 0, 1000 * 10,
312 rdpDeferredDisconnectCallback, dev);
313 return 0;
314 }
315
316 /*****************************************************************************/
317 static CARD32
rdpDeferredIdleDisconnectCallback(OsTimerPtr timer,CARD32 now,pointer arg)318 rdpDeferredIdleDisconnectCallback(OsTimerPtr timer, CARD32 now, pointer arg)
319 {
320 LLOGLN(10, ("rdpDeferredIdleDisconnectCallback:"));
321
322 rdpPtr dev;
323
324 dev = (rdpPtr) arg;
325
326 CARD32 millis_since_last_event;
327
328 /* how many millis was the last event ago? */
329 millis_since_last_event = now - dev->last_event_time_ms;
330
331 /* we MUST compare to equal otherwise we could restart the idle timer with 0! */
332 if (millis_since_last_event >= (dev->idle_disconnect_timeout_s * 1000))
333 {
334 LLOGLN(0, ("rdpDeferredIdleDisconnectCallback: session has been idle for %d seconds, disconnecting",
335 dev->idle_disconnect_timeout_s));
336
337 /* disconnect all clients */
338 while (dev->clientConHead != NULL)
339 {
340 rdpClientConDisconnect(dev, dev->clientConHead);
341 }
342
343 LLOGLN(0, ("rdpDeferredIdleDisconnectCallback: disconnected idle session"));
344
345 TimerCancel(dev->idleDisconnectTimer);
346 TimerFree(dev->idleDisconnectTimer);
347 dev->idleDisconnectTimer = NULL;
348 LLOGLN(0, ("rdpDeferredIdleDisconnectCallback: idle timer disengaged"));
349 return 0;
350 }
351
352 /* restart the idle timer with last_event + idle timeout */
353 dev->idleDisconnectTimer = TimerSet(dev->idleDisconnectTimer, 0, (dev->idle_disconnect_timeout_s * 1000) - millis_since_last_event,
354 rdpDeferredIdleDisconnectCallback, dev);
355 return 0;
356 }
357 /*****************************************************************************/
358 static int
rdpClientConDisconnect(rdpPtr dev,rdpClientCon * clientCon)359 rdpClientConDisconnect(rdpPtr dev, rdpClientCon *clientCon)
360 {
361 int index;
362
363 LLOGLN(0, ("rdpClientConDisconnect:"));
364
365 if (dev->idleDisconnectTimer != NULL && dev->idle_disconnect_timeout_s > 0)
366 {
367 LLOGLN(0, ("rdpClientConDisconnect: disconnected, idle timer disengaged"));
368 TimerCancel(dev->idleDisconnectTimer);
369 TimerFree(dev->idleDisconnectTimer);
370 dev->idleDisconnectTimer = NULL;
371 }
372
373 if (dev->do_kill_disconnected)
374 {
375 if (dev->disconnect_scheduled == FALSE)
376 {
377 LLOGLN(0, ("rdpClientConDisconnect: engaging disconnect timer, "
378 "exit after %d seconds", dev->disconnect_timeout_s));
379 dev->disconnectTimer = TimerSet(dev->disconnectTimer, 0, 1000 * 10,
380 rdpDeferredDisconnectCallback, dev);
381 dev->disconnect_scheduled = TRUE;
382 }
383 dev->disconnect_time_ms = GetTimeInMillis();
384 }
385
386 rdpClientConRemoveEnabledDevice(clientCon->sck);
387 g_sck_close(clientCon->sck);
388 if (clientCon->maxOsBitmaps > 0)
389 {
390 for (index = 0; index < clientCon->maxOsBitmaps; index++)
391 {
392 if (clientCon->osBitmaps[index].used)
393 {
394 if (clientCon->osBitmaps[index].priv != NULL)
395 {
396 clientCon->osBitmaps[index].priv->status = 0;
397 }
398 }
399 }
400 }
401 free(clientCon->osBitmaps);
402
403 rdpRemoveClientConFromDev(dev, clientCon);
404
405 rdpRegionDestroy(clientCon->dirtyRegion);
406 rdpRegionDestroy(clientCon->shmRegion);
407 if (clientCon->updateTimer != NULL)
408 {
409 TimerCancel(clientCon->updateTimer);
410 TimerFree(clientCon->updateTimer);
411 }
412 free_stream(clientCon->out_s);
413 free_stream(clientCon->in_s);
414 if (clientCon->shmemptr != NULL)
415 {
416 shmdt(clientCon->shmemptr);
417 }
418 free(clientCon);
419 return 0;
420 }
421
422 /*****************************************************************************/
423 /* returns error */
424 static int
rdpClientConSend(rdpPtr dev,rdpClientCon * clientCon,const char * data,int len)425 rdpClientConSend(rdpPtr dev, rdpClientCon *clientCon, const char *data, int len)
426 {
427 int sent;
428
429 LLOGLN(10, ("rdpClientConSend - sending %d bytes", len));
430
431 if (!clientCon->connected)
432 {
433 return 1;
434 }
435
436 while (len > 0)
437 {
438 sent = g_sck_send(clientCon->sck, data, len, 0);
439
440 if (sent == -1)
441 {
442 if (g_sck_last_error_would_block(clientCon->sck))
443 {
444 g_sleep(1);
445 }
446 else
447 {
448 LLOGLN(0, ("rdpClientConSend: g_tcp_send failed(returned -1)"));
449 clientCon->connected = FALSE;
450 return 1;
451 }
452 }
453 else if (sent == 0)
454 {
455 LLOGLN(0, ("rdpClientConSend: g_tcp_send failed(returned zero)"));
456 clientCon->connected = FALSE;
457 return 1;
458 }
459 else
460 {
461 data += sent;
462 len -= sent;
463 }
464 }
465
466 return 0;
467 }
468
469 /******************************************************************************/
470 static int
rdpClientConSendMsg(rdpPtr dev,rdpClientCon * clientCon)471 rdpClientConSendMsg(rdpPtr dev, rdpClientCon *clientCon)
472 {
473 int len;
474 int rv;
475 struct stream *s;
476
477 rv = 1;
478 s = clientCon->out_s;
479 if (s != NULL)
480 {
481 len = (int) (s->end - s->data);
482
483 if (len > s->size)
484 {
485 LLOGLN(0, ("rdpClientConSendMsg: overrun error len, %d "
486 "stream size %d, client count %d",
487 len, s->size, clientCon->count));
488 }
489
490 s_pop_layer(s, iso_hdr);
491 out_uint16_le(s, 3);
492 out_uint16_le(s, clientCon->count);
493 out_uint32_le(s, len - 8);
494 rv = rdpClientConSend(dev, clientCon, s->data, len);
495 }
496
497 if (rv != 0)
498 {
499 LLOGLN(0, ("rdpClientConSendMsg: error in rdpup_send_msg"));
500 }
501
502 return rv;
503 }
504
505 /******************************************************************************/
506 static int
rdpClientConSendPending(rdpPtr dev,rdpClientCon * clientCon)507 rdpClientConSendPending(rdpPtr dev, rdpClientCon *clientCon)
508 {
509 int rv;
510
511 rv = 0;
512 if (clientCon->connected && clientCon->begin)
513 {
514 out_uint16_le(clientCon->out_s, 2); /* XR_SERVER_END_UPDATE */
515 out_uint16_le(clientCon->out_s, 4); /* size */
516 clientCon->count++;
517 s_mark_end(clientCon->out_s);
518 if (rdpClientConSendMsg(dev, clientCon) != 0)
519 {
520 LLOGLN(0, ("rdpClientConSendPending: rdpClientConSendMsg failed"));
521 rv = 1;
522 }
523 }
524 clientCon->count = 0;
525 clientCon->begin = FALSE;
526 return rv;
527 }
528
529 /******************************************************************************/
530 /* returns error */
531 static int
rdpClientConRecv(rdpPtr dev,rdpClientCon * clientCon,char * data,int len)532 rdpClientConRecv(rdpPtr dev, rdpClientCon *clientCon, char *data, int len)
533 {
534 int rcvd;
535
536 if (!clientCon->connected)
537 {
538 return 1;
539 }
540
541 while (len > 0)
542 {
543 rcvd = g_sck_recv(clientCon->sck, data, len, 0);
544
545 if (rcvd == -1)
546 {
547 if (g_sck_last_error_would_block(clientCon->sck))
548 {
549 g_sleep(1);
550 }
551 else
552 {
553 LLOGLN(0, ("rdpClientConRecv: g_sck_recv failed(returned -1)"));
554 clientCon->connected = FALSE;
555 return 1;
556 }
557 }
558 else if (rcvd == 0)
559 {
560 LLOGLN(0, ("rdpClientConRecv: g_sck_recv failed(returned 0)"));
561 clientCon->connected = FALSE;
562 return 1;
563 }
564 else
565 {
566 data += rcvd;
567 len -= rcvd;
568 }
569 }
570
571 return 0;
572 }
573
574 /******************************************************************************/
575 static int
rdpClientConRecvMsg(rdpPtr dev,rdpClientCon * clientCon)576 rdpClientConRecvMsg(rdpPtr dev, rdpClientCon *clientCon)
577 {
578 int len;
579 int rv;
580 struct stream *s;
581
582 rv = 1;
583
584 s = clientCon->in_s;
585 if (s != 0)
586 {
587 init_stream(s, 4);
588 rv = rdpClientConRecv(dev, clientCon, s->data, 4);
589
590 if (rv == 0)
591 {
592 s->end = s->data + 4;
593 in_uint32_le(s, len);
594
595 if (len > 3)
596 {
597 init_stream(s, len);
598 rv = rdpClientConRecv(dev, clientCon, s->data, len - 4);
599 if (rv == 0)
600 {
601 s->end = s->data + len;
602 }
603 }
604 }
605 }
606
607 if (rv != 0)
608 {
609 LLOGLN(0, ("rdpClientConRecvMsg: error"));
610 }
611
612 return rv;
613 }
614
615 /******************************************************************************/
616 static int
rdpClientConSendCaps(rdpPtr dev,rdpClientCon * clientCon)617 rdpClientConSendCaps(rdpPtr dev, rdpClientCon *clientCon)
618 {
619 struct stream *ls;
620 int len;
621 int rv;
622 int cap_count;
623 int cap_bytes;
624
625 make_stream(ls);
626 init_stream(ls, 8192);
627 s_push_layer(ls, iso_hdr, 8);
628
629 cap_count = 0;
630 cap_bytes = 0;
631
632 #if 0
633 out_uint16_le(ls, 0);
634 out_uint16_le(ls, 4);
635 cap_count++;
636 cap_bytes += 4;
637
638 out_uint16_le(ls, 1);
639 out_uint16_le(ls, 4);
640 cap_count++;
641 cap_bytes += 4;
642 #endif
643
644 s_mark_end(ls);
645 len = (int)(ls->end - ls->data);
646 s_pop_layer(ls, iso_hdr);
647 out_uint16_le(ls, 2); /* caps */
648 out_uint16_le(ls, cap_count); /* num caps */
649 out_uint32_le(ls, cap_bytes); /* caps len after header */
650
651 rv = rdpClientConSend(dev, clientCon, ls->data, len);
652
653 if (rv != 0)
654 {
655 LLOGLN(0, ("rdpClientConSendCaps: rdpup_send failed"));
656 }
657
658 free_stream(ls);
659 return rv;
660 }
661
662 /******************************************************************************/
663 static int
rdpClientConProcessMsgVersion(rdpPtr dev,rdpClientCon * clientCon,int param1,int param2,int param3,int param4)664 rdpClientConProcessMsgVersion(rdpPtr dev, rdpClientCon *clientCon,
665 int param1, int param2, int param3, int param4)
666 {
667 LLOGLN(0, ("rdpClientConProcessMsgVersion: version %d %d %d %d",
668 param1, param2, param3, param4));
669
670 if ((param1 > 0) || (param2 > 0) || (param3 > 0) || (param4 > 0))
671 {
672 rdpClientConSendCaps(dev, clientCon);
673 }
674
675 return 0;
676 }
677
678 /******************************************************************************/
679 /*
680 this from miScreenInit
681 pScreen->mmWidth = (xsize * 254 + dpix * 5) / (dpix * 10);
682 pScreen->mmHeight = (ysize * 254 + dpiy * 5) / (dpiy * 10);
683 */
684 static int
rdpClientConProcessScreenSizeMsg(rdpPtr dev,rdpClientCon * clientCon,int width,int height,int bpp)685 rdpClientConProcessScreenSizeMsg(rdpPtr dev, rdpClientCon *clientCon,
686 int width, int height, int bpp)
687 {
688 ScrnInfoPtr pScrn;
689 int mmwidth;
690 int mmheight;
691 int bytes;
692 Bool ok;
693
694 LLOGLN(0, ("rdpClientConProcessScreenSizeMsg: set width %d height %d "
695 "bpp %d", width, height, bpp));
696 clientCon->shmemstatus = SHM_RESIZING;
697 clientCon->rdp_width = width;
698 clientCon->rdp_height = height;
699 clientCon->rdp_bpp = bpp;
700 clientCon->cap_width = width;
701 clientCon->cap_height = height;
702
703 if (bpp < 15)
704 {
705 clientCon->rdp_Bpp = 1;
706 clientCon->rdp_Bpp_mask = 0xff;
707 clientCon->rdp_format = XRDP_r3g3b2;
708 }
709 else if (bpp == 15)
710 {
711 clientCon->rdp_Bpp = 2;
712 clientCon->rdp_Bpp_mask = 0x7fff;
713 clientCon->rdp_format = XRDP_a1r5g5b5;
714 }
715 else if (bpp == 16)
716 {
717 clientCon->rdp_Bpp = 2;
718 clientCon->rdp_Bpp_mask = 0xffff;
719 clientCon->rdp_format = XRDP_r5g6b5;
720 }
721 else if (bpp > 16)
722 {
723 clientCon->rdp_Bpp = 4;
724 clientCon->rdp_Bpp_mask = 0xffffff;
725 clientCon->rdp_format = XRDP_a8r8g8b8;
726 }
727
728 clientCon->cap_stride_bytes = clientCon->rdp_width * clientCon->rdp_Bpp;
729
730 if (clientCon->shmemptr != 0)
731 {
732 shmdt(clientCon->shmemptr);
733 }
734 bytes = clientCon->rdp_width * clientCon->rdp_height *
735 clientCon->rdp_Bpp;
736 clientCon->shmemid = shmget(IPC_PRIVATE, bytes, IPC_CREAT | 0777);
737 clientCon->shmemptr = shmat(clientCon->shmemid, 0, 0);
738 shmctl(clientCon->shmemid, IPC_RMID, NULL);
739 LLOGLN(0, ("rdpClientConProcessScreenSizeMsg: shmemid %d shmemptr %p",
740 clientCon->shmemid, clientCon->shmemptr));
741 clientCon->shmem_lineBytes = clientCon->rdp_Bpp * clientCon->rdp_width;
742
743 if (clientCon->shmRegion != 0)
744 {
745 rdpRegionDestroy(clientCon->shmRegion);
746 }
747 clientCon->shmRegion = rdpRegionCreate(NullBox, 0);
748
749 pScrn = xf86Screens[dev->pScreen->myNum];
750 mmwidth = PixelToMM(width, pScrn->xDpi);
751 mmheight = PixelToMM(height, pScrn->yDpi);
752
753 if ((dev->width != width) || (dev->height != height))
754 {
755 dev->allow_screen_resize = 1;
756 ok = RRScreenSizeSet(dev->pScreen, width, height, mmwidth, mmheight);
757 dev->allow_screen_resize = 0;
758 LLOGLN(0, ("rdpClientConProcessScreenSizeMsg: RRScreenSizeSet ok=[%d]", ok));
759 RRTellChanged(dev->pScreen);
760 }
761
762 return 0;
763 }
764
765 /******************************************************************************/
766 static int
rdpClientConProcessMsgClientInput(rdpPtr dev,rdpClientCon * clientCon)767 rdpClientConProcessMsgClientInput(rdpPtr dev, rdpClientCon *clientCon)
768 {
769 struct stream *s;
770 int msg;
771 int param1;
772 int param2;
773 int param3;
774 int param4;
775 int x;
776 int y;
777 int cx;
778 int cy;
779
780 s = clientCon->in_s;
781 in_uint32_le(s, msg);
782 in_uint32_le(s, param1);
783 in_uint32_le(s, param2);
784 in_uint32_le(s, param3);
785 in_uint32_le(s, param4);
786
787 LLOGLN(10, ("rdpClientConProcessMsgClientInput: msg %d param1 %d param2 %d "
788 "param3 %d param4 %d", msg, param1, param2, param3, param4));
789
790 if (msg < 100)
791 {
792 rdpInputKeyboardEvent(dev, msg, param1, param2, param3, param4);
793 }
794 else if (msg < 200)
795 {
796 rdpInputMouseEvent(dev, msg, param1, param2, param3, param4);
797 }
798 else if (msg == 200) /* invalidate */
799 {
800 x = (param1 >> 16) & 0xffff;
801 y = param1 & 0xffff;
802 cx = (param2 >> 16) & 0xffff;
803 cy = param2 & 0xffff;
804 LLOGLN(0, ("rdpClientConProcessMsgClientInput: invalidate x %d y %d "
805 "cx %d cy %d", x, y, cx, cy));
806 rdpClientConAddDirtyScreen(dev, clientCon, x, y, cx, cy);
807 }
808 else if (msg == 300) /* resize desktop */
809 {
810 rdpClientConProcessScreenSizeMsg(dev, clientCon, param1,
811 param2, param3);
812 }
813 else if (msg == 301) /* version */
814 {
815 rdpClientConProcessMsgVersion(dev, clientCon,
816 param1, param2, param3, param4);
817 }
818 else
819 {
820 LLOGLN(0, ("rdpClientConProcessMsgClientInput: unknown msg %d", msg));
821 }
822
823 return 0;
824 }
825
826 /******************************************************************************/
827 static int
rdpClientConProcessMsgClientInfo(rdpPtr dev,rdpClientCon * clientCon)828 rdpClientConProcessMsgClientInfo(rdpPtr dev, rdpClientCon *clientCon)
829 {
830 struct stream *s;
831 int bytes;
832 int i1;
833 int index;
834 BoxRec box;
835 enum shared_memory_status shmemstatus = SHM_ACTIVE;
836
837 LLOGLN(0, ("rdpClientConProcessMsgClientInfo:"));
838 s = clientCon->in_s;
839 in_uint32_le(s, bytes);
840 if (bytes > sizeof(clientCon->client_info))
841 {
842 bytes = sizeof(clientCon->client_info);
843 }
844 memcpy(&(clientCon->client_info), s->p - 4, bytes);
845 clientCon->client_info.size = bytes;
846
847 if (clientCon->client_info.version != CLIENT_INFO_CURRENT_VERSION)
848 {
849 LLOGLN(0, ("expected xrdp client_info version %d, got %d",
850 CLIENT_INFO_CURRENT_VERSION,
851 clientCon->client_info.version));
852 FatalError("Incompatible xrdp version detected - please recompile");
853 }
854
855 LLOGLN(0, (" got client info bytes %d", bytes));
856 LLOGLN(0, (" jpeg support %d", clientCon->client_info.jpeg));
857 i1 = clientCon->client_info.offscreen_support_level;
858 LLOGLN(0, (" offscreen support %d", i1));
859 i1 = clientCon->client_info.offscreen_cache_size;
860 LLOGLN(0, (" offscreen size %d", i1));
861 i1 = clientCon->client_info.offscreen_cache_entries;
862 LLOGLN(0, (" offscreen entries %d", i1));
863
864 if (clientCon->client_info.capture_code == 2) /* RFX */
865 {
866 LLOGLN(0, ("rdpClientConProcessMsgClientInfo: got RFX capture"));
867 clientCon->cap_width = RDPALIGN(clientCon->rdp_width, 64);
868 clientCon->cap_height = RDPALIGN(clientCon->rdp_height, 64);
869 LLOGLN(0, (" cap_width %d cap_height %d",
870 clientCon->cap_width, clientCon->cap_height));
871 if (clientCon->shmemptr != 0)
872 {
873 shmdt(clientCon->shmemptr);
874 }
875 bytes = clientCon->cap_width * clientCon->cap_height *
876 clientCon->rdp_Bpp;
877 clientCon->shmemid = shmget(IPC_PRIVATE, bytes, IPC_CREAT | 0777);
878 clientCon->shmemptr = shmat(clientCon->shmemid, 0, 0);
879 shmctl(clientCon->shmemid, IPC_RMID, NULL);
880 LLOGLN(0, ("rdpClientConProcessMsgClientInfo: shmemid %d shmemptr %p "
881 "bytes %d", clientCon->shmemid, clientCon->shmemptr, bytes));
882 clientCon->shmem_lineBytes = clientCon->rdp_Bpp * clientCon->cap_width;
883 clientCon->cap_stride_bytes = clientCon->cap_width * 4;
884 shmemstatus = SHM_RFX_ACTIVE;
885 }
886 else if (clientCon->client_info.capture_code == 3) /* H264 */
887 {
888 LLOGLN(0, ("rdpClientConProcessMsgClientInfo: got H264 capture"));
889 clientCon->cap_width = clientCon->rdp_width;
890 clientCon->cap_height = clientCon->rdp_height;
891 LLOGLN(0, (" cap_width %d cap_height %d",
892 clientCon->cap_width, clientCon->cap_height));
893 if (clientCon->shmemptr != 0)
894 {
895 shmdt(clientCon->shmemptr);
896 }
897 bytes = clientCon->cap_width * clientCon->cap_height * 2;
898 clientCon->shmemid = shmget(IPC_PRIVATE, bytes, IPC_CREAT | 0777);
899 clientCon->shmemptr = shmat(clientCon->shmemid, 0, 0);
900 shmctl(clientCon->shmemid, IPC_RMID, NULL);
901 LLOGLN(0, ("rdpClientConProcessMsgClientInfo: shmemid %d shmemptr %p "
902 "bytes %d", clientCon->shmemid, clientCon->shmemptr, bytes));
903 clientCon->shmem_lineBytes = clientCon->rdp_Bpp * clientCon->cap_width;
904 clientCon->cap_stride_bytes = clientCon->cap_width * 4;
905 shmemstatus = SHM_H264_ACTIVE;
906 }
907
908 if (clientCon->client_info.capture_format != 0)
909 {
910 clientCon->rdp_format = clientCon->client_info.capture_format;
911 switch (clientCon->rdp_format)
912 {
913 case XRDP_a8r8g8b8:
914 case XRDP_a8b8g8r8:
915 clientCon->cap_stride_bytes = clientCon->cap_width * 4;
916 break;
917 case XRDP_r5g6b5:
918 case XRDP_a1r5g5b5:
919 clientCon->cap_stride_bytes = clientCon->cap_width * 2;
920 break;
921 default:
922 clientCon->cap_stride_bytes = clientCon->cap_width * 1;
923 break;
924 }
925 }
926
927 if (clientCon->client_info.offscreen_support_level > 0)
928 {
929 if (clientCon->client_info.offscreen_cache_entries > 0)
930 {
931 clientCon->maxOsBitmaps = clientCon->client_info.offscreen_cache_entries;
932 free(clientCon->osBitmaps);
933 clientCon->osBitmaps = g_new0(struct rdpup_os_bitmap,
934 clientCon->maxOsBitmaps);
935 }
936 }
937
938 if (clientCon->client_info.orders[0x1b]) /* 27 NEG_GLYPH_INDEX_INDEX */
939 {
940 LLOGLN(0, (" client supports glyph cache but server disabled"));
941 //clientCon->doGlyphCache = 1;
942 }
943 if (clientCon->client_info.order_flags_ex & 0x100)
944 {
945 clientCon->doComposite = 1;
946 }
947 if (clientCon->doGlyphCache)
948 {
949 LLOGLN(0, (" using glyph cache"));
950 }
951 if (clientCon->doComposite)
952 {
953 LLOGLN(0, (" using client composite"));
954 }
955 LLOGLN(10, ("order_flags_ex 0x%x", clientCon->client_info.order_flags_ex));
956 if (clientCon->client_info.offscreen_cache_entries == 2000)
957 {
958 LLOGLN(0, (" client can do offscreen to offscreen blits"));
959 clientCon->canDoPixToPix = 1;
960 }
961 else
962 {
963 LLOGLN(0, (" client can not do offscreen to offscreen blits"));
964 clientCon->canDoPixToPix = 0;
965 }
966 if (clientCon->client_info.pointer_flags & 1)
967 {
968 LLOGLN(0, (" client can do new(color) cursor"));
969 }
970 else
971 {
972 LLOGLN(0, (" client can not do new(color) cursor"));
973 }
974 if (clientCon->client_info.monitorCount > 0)
975 {
976 LLOGLN(0, (" client can do multimon"));
977 LLOGLN(0, (" client monitor data, monitorCount=%d", clientCon->client_info.monitorCount));
978 clientCon->doMultimon = 1;
979 dev->doMultimon = 1;
980 memcpy(dev->minfo, clientCon->client_info.minfo, sizeof(dev->minfo));
981 dev->monitorCount = clientCon->client_info.monitorCount;
982
983 box.x1 = dev->minfo[0].left;
984 box.y1 = dev->minfo[0].top;
985 box.x2 = dev->minfo[0].right;
986 box.y2 = dev->minfo[0].bottom;
987 /* adjust monitor info so it's not negative */
988 for (index = 1; index < dev->monitorCount; index++)
989 {
990 box.x1 = min(box.x1, dev->minfo[index].left);
991 box.y1 = min(box.y1, dev->minfo[index].top);
992 box.x2 = max(box.x2, dev->minfo[index].right);
993 box.y2 = max(box.y2, dev->minfo[index].bottom);
994 }
995 for (index = 0; index < dev->monitorCount; index++)
996 {
997 dev->minfo[index].left -= box.x1;
998 dev->minfo[index].top -= box.y1;
999 dev->minfo[index].right -= box.x1;
1000 dev->minfo[index].bottom -= box.y1;
1001 LLOGLN(0, (" left %d top %d right %d bottom %d",
1002 dev->minfo[index].left,
1003 dev->minfo[index].top,
1004 dev->minfo[index].right,
1005 dev->minfo[index].bottom));
1006 }
1007
1008 rdpRRSetRdpOutputs(dev);
1009 RRTellChanged(dev->pScreen);
1010 }
1011 else
1012 {
1013 LLOGLN(0, (" client can not do multimon"));
1014 clientCon->doMultimon = 0;
1015 dev->doMultimon = 0;
1016 dev->monitorCount = 0;
1017 rdpRRSetRdpOutputs(dev);
1018 RRTellChanged(dev->pScreen);
1019 }
1020
1021 /* rdpLoadLayout */
1022 rdpInputKeyboardEvent(dev, 18, (long)(&(clientCon->client_info)),
1023 0, 0, 0);
1024
1025 if (clientCon->shmemstatus == SHM_UNINITIALIZED || clientCon->shmemstatus == SHM_RESIZING) {
1026 clientCon->shmemstatus = shmemstatus;
1027 }
1028
1029 return 0;
1030 }
1031
1032 /******************************************************************************/
1033 static int
rdpClientConProcessMsgClientRegion(rdpPtr dev,rdpClientCon * clientCon)1034 rdpClientConProcessMsgClientRegion(rdpPtr dev, rdpClientCon *clientCon)
1035 {
1036 struct stream *s;
1037 int flags;
1038 int x;
1039 int y;
1040 int cx;
1041 int cy;
1042 RegionRec reg;
1043 BoxRec box;
1044
1045 LLOGLN(10, ("rdpClientConProcessMsgClientRegion:"));
1046 s = clientCon->in_s;
1047
1048 in_uint32_le(s, flags);
1049 in_uint32_le(s, clientCon->rect_id_ack);
1050 in_uint32_le(s, x);
1051 in_uint32_le(s, y);
1052 in_uint32_le(s, cx);
1053 in_uint32_le(s, cy);
1054 LLOGLN(10, ("rdpClientConProcessMsgClientRegion: %d %d %d %d flags 0x%8.8x",
1055 x, y, cx, cy, flags));
1056 LLOGLN(10, ("rdpClientConProcessMsgClientRegion: rect_id %d rect_id_ack %d",
1057 clientCon->rect_id, clientCon->rect_id_ack));
1058
1059 box.x1 = x;
1060 box.y1 = y;
1061 box.x2 = box.x1 + cx;
1062 box.y2 = box.y1 + cy;
1063
1064 rdpRegionInit(®, &box, 0);
1065 LLOGLN(10, ("rdpClientConProcessMsgClientRegion: %d %d %d %d",
1066 box.x1, box.y1, box.x2, box.y2));
1067 rdpRegionSubtract(clientCon->shmRegion, clientCon->shmRegion, ®);
1068 rdpRegionUninit(®);
1069
1070 return 0;
1071 }
1072
1073 /******************************************************************************/
1074 static int
rdpClientConProcessMsgClientRegionEx(rdpPtr dev,rdpClientCon * clientCon)1075 rdpClientConProcessMsgClientRegionEx(rdpPtr dev, rdpClientCon *clientCon)
1076 {
1077 struct stream *s;
1078 int flags;
1079
1080 LLOGLN(10, ("rdpClientConProcessMsgClientRegionEx:"));
1081 s = clientCon->in_s;
1082
1083 in_uint32_le(s, flags);
1084 in_uint32_le(s, clientCon->rect_id_ack);
1085 LLOGLN(10, ("rdpClientConProcessMsgClientRegionEx: flags 0x%8.8x", flags));
1086 LLOGLN(10, ("rdpClientConProcessMsgClientRegionEx: rect_id %d "
1087 "rect_id_ack %d", clientCon->rect_id, clientCon->rect_id_ack));
1088 return 0;
1089 }
1090
1091 /******************************************************************************/
1092 static int
rdpClientConProcessMsgClientSuppressOutput(rdpPtr dev,rdpClientCon * clientCon)1093 rdpClientConProcessMsgClientSuppressOutput(rdpPtr dev, rdpClientCon *clientCon)
1094 {
1095 int suppress;
1096 int left;
1097 int top;
1098 int right;
1099 int bottom;
1100 struct stream *s;
1101
1102 s = clientCon->in_s;
1103 in_uint32_le(s, suppress);
1104 in_uint32_le(s, left);
1105 in_uint32_le(s, top);
1106 in_uint32_le(s, right);
1107 in_uint32_le(s, bottom);
1108 LLOGLN(10, ("rdpClientConProcessMsgClientSuppressOutput: "
1109 "suppress %d left %d top %d right %d bottom %d",
1110 suppress, left, top, right, bottom));
1111 clientCon->suppress_output = suppress;
1112 if (suppress == 0)
1113 {
1114 rdpClientConAddDirtyScreen(dev, clientCon, left, top,
1115 right - left, bottom - top);
1116 }
1117 return 0;
1118 }
1119
1120 /******************************************************************************/
1121 static int
rdpClientConProcessMsg(rdpPtr dev,rdpClientCon * clientCon)1122 rdpClientConProcessMsg(rdpPtr dev, rdpClientCon *clientCon)
1123 {
1124 int msg_type;
1125 struct stream *s;
1126
1127 LLOGLN(10, ("rdpClientConProcessMsg:"));
1128 s = clientCon->in_s;
1129 in_uint16_le(s, msg_type);
1130 LLOGLN(10, ("rdpClientConProcessMsg: msg_type %d", msg_type));
1131 switch (msg_type)
1132 {
1133 case 103: /* client input */
1134 rdpClientConProcessMsgClientInput(dev, clientCon);
1135 break;
1136 case 104: /* client info */
1137 rdpClientConProcessMsgClientInfo(dev, clientCon);
1138 break;
1139 case 105: /* client region */
1140 rdpClientConProcessMsgClientRegion(dev, clientCon);
1141 break;
1142 case 106: /* client region ex */
1143 rdpClientConProcessMsgClientRegionEx(dev, clientCon);
1144 break;
1145 case 108: /* client suppress output */
1146 rdpClientConProcessMsgClientSuppressOutput(dev, clientCon);
1147 break;
1148 default:
1149 LLOGLN(0, ("rdpClientConProcessMsg: unknown msg_type %d",
1150 msg_type));
1151 break;
1152 }
1153
1154 return 0;
1155 }
1156
1157 /******************************************************************************/
1158 static int
rdpClientConGotData(ScreenPtr pScreen,rdpPtr dev,rdpClientCon * clientCon)1159 rdpClientConGotData(ScreenPtr pScreen, rdpPtr dev, rdpClientCon *clientCon)
1160 {
1161 int rv;
1162
1163 LLOGLN(10, ("rdpClientConGotData:"));
1164
1165 rv = rdpClientConRecvMsg(dev, clientCon);
1166 if (rv == 0)
1167 {
1168 rv = rdpClientConProcessMsg(dev, clientCon);
1169 }
1170
1171 return rv;
1172 }
1173
1174 /******************************************************************************/
1175 static int
rdpClientConGotControlConnection(ScreenPtr pScreen,rdpPtr dev,rdpClientCon * clientCon)1176 rdpClientConGotControlConnection(ScreenPtr pScreen, rdpPtr dev,
1177 rdpClientCon *clientCon)
1178 {
1179 LLOGLN(0, ("rdpClientConGotControlConnection:"));
1180 return 0;
1181 }
1182
1183 /******************************************************************************/
1184 static int
rdpClientConGotControlData(ScreenPtr pScreen,rdpPtr dev,rdpClientCon * clientCon)1185 rdpClientConGotControlData(ScreenPtr pScreen, rdpPtr dev,
1186 rdpClientCon *clientCon)
1187 {
1188 LLOGLN(0, ("rdpClientConGotControlData:"));
1189 return 0;
1190 }
1191
1192 /******************************************************************************/
1193 int
rdpClientConCheck(ScreenPtr pScreen)1194 rdpClientConCheck(ScreenPtr pScreen)
1195 {
1196 rdpPtr dev;
1197 rdpClientCon *clientCon;
1198 rdpClientCon *nextCon;
1199 fd_set rfds;
1200 struct timeval time;
1201 int max;
1202 int sel;
1203 int count;
1204 char buf[8];
1205
1206 LLOGLN(10, ("rdpClientConCheck:"));
1207 dev = rdpGetDevFromScreen(pScreen);
1208 time.tv_sec = 0;
1209 time.tv_usec = 0;
1210 FD_ZERO(&rfds);
1211 count = 0;
1212 max = 0;
1213
1214 if (dev->disconnect_sck > 0)
1215 {
1216 count++;
1217 FD_SET(LTOUI32(dev->disconnect_sck), &rfds);
1218 max = RDPMAX(dev->disconnect_sck, max);
1219 }
1220
1221 if (dev->listen_sck > 0)
1222 {
1223 count++;
1224 FD_SET(LTOUI32(dev->listen_sck), &rfds);
1225 max = RDPMAX(dev->listen_sck, max);
1226 }
1227 clientCon = dev->clientConHead;
1228 while (clientCon != NULL)
1229 {
1230 if (!clientCon->connected)
1231 {
1232 /* I/O error on this client - remove it */
1233 nextCon = clientCon->next;
1234 rdpClientConDisconnect(dev, clientCon);
1235 clientCon = nextCon;
1236 continue;
1237 }
1238
1239 if (clientCon->sck > 0)
1240 {
1241 count++;
1242 FD_SET(LTOUI32(clientCon->sck), &rfds);
1243 max = RDPMAX(clientCon->sck, max);
1244 }
1245 if (clientCon->sckControl > 0)
1246 {
1247 count++;
1248 FD_SET(LTOUI32(clientCon->sckControl), &rfds);
1249 max = RDPMAX(clientCon->sckControl, max);
1250 }
1251 if (clientCon->sckControlListener > 0)
1252 {
1253 count++;
1254 FD_SET(LTOUI32(clientCon->sckControlListener), &rfds);
1255 max = RDPMAX(clientCon->sckControlListener, max);
1256 }
1257 clientCon = clientCon->next;
1258 }
1259 if (count < 1)
1260 {
1261 sel = 0;
1262 }
1263 else
1264 {
1265 sel = select(max + 1, &rfds, 0, 0, &time);
1266 }
1267 if (sel < 1)
1268 {
1269 LLOGLN(10, ("rdpClientConCheck: no select"));
1270 return 0;
1271 }
1272
1273 if (dev->listen_sck > 0)
1274 {
1275 if (FD_ISSET(LTOUI32(dev->listen_sck), &rfds))
1276 {
1277 rdpClientConGotConnection(pScreen, dev);
1278 }
1279 }
1280
1281 if (dev->disconnect_sck > 0)
1282 {
1283 if (FD_ISSET(LTOUI32(dev->disconnect_sck), &rfds))
1284 {
1285
1286 if (g_sck_recv(dev->disconnect_sck, buf, sizeof(buf), 0))
1287 {
1288 LLOGLN(0, ("rdpClientConCheck: got disconnection request"));
1289
1290 /* disconnect all clients */
1291 while (dev->clientConHead != NULL)
1292 {
1293 rdpClientConDisconnect(dev, dev->clientConHead);
1294 }
1295 }
1296 }
1297 }
1298
1299 for (clientCon = dev->clientConHead;
1300 clientCon != NULL;
1301 clientCon = clientCon->next)
1302 {
1303 if (clientCon->sck > 0)
1304 {
1305 if (FD_ISSET(LTOUI32(clientCon->sck), &rfds))
1306 {
1307 if (rdpClientConGotData(pScreen, dev, clientCon) != 0)
1308 {
1309 LLOGLN(0, ("rdpClientConCheck: rdpClientConGotData failed"));
1310 continue; /* skip other socket checks for this clientCon */
1311 }
1312 }
1313 }
1314 if (clientCon->sckControlListener > 0)
1315 {
1316 if (FD_ISSET(LTOUI32(clientCon->sckControlListener), &rfds))
1317 {
1318 if (rdpClientConGotControlConnection(pScreen, dev, clientCon) != 0)
1319 {
1320 LLOGLN(0, ("rdpClientConCheck: rdpClientConGotControlConnection failed"));
1321 continue;
1322 }
1323 }
1324 }
1325 if (clientCon->sckControl > 0)
1326 {
1327 if (FD_ISSET(LTOUI32(clientCon->sckControl), &rfds))
1328 {
1329 if (rdpClientConGotControlData(pScreen, dev, clientCon) != 0)
1330 {
1331 LLOGLN(0, ("rdpClientConCheck: rdpClientConGotControlData failed"));
1332 continue;
1333 }
1334 }
1335 }
1336 }
1337 return 0;
1338 }
1339
1340 /******************************************************************************/
1341 int
rdpClientConInit(rdpPtr dev)1342 rdpClientConInit(rdpPtr dev)
1343 {
1344 int i;
1345 char *ptext;
1346 char *endptr = NULL;
1347 const char *socket_dir;
1348
1349 socket_dir = g_socket_dir();
1350 if (!g_directory_exist(socket_dir))
1351 {
1352 if (!g_create_dir(socket_dir))
1353 {
1354 if (!g_directory_exist(socket_dir))
1355 {
1356 LLOGLN(0, ("rdpClientConInit: g_create_dir(%s) failed", socket_dir));
1357 return 0;
1358 }
1359 }
1360 g_chmod_hex(socket_dir, 0x1777);
1361 }
1362
1363 errno = 0;
1364 i = (int)strtol(display, &endptr, 10);
1365 if (errno != 0 || display == endptr || *endptr != 0)
1366 {
1367 LLOGLN(0, ("rdpClientConInit: can not run at non-interger display"));
1368 return 0;
1369 }
1370
1371 /* TODO: don't hardcode socket name */
1372 g_sprintf(dev->uds_data, "%s/xrdp_display_%s", socket_dir, display);
1373 if (dev->listen_sck == 0)
1374 {
1375 unlink(dev->uds_data);
1376 dev->listen_sck = g_sck_local_socket_stream();
1377 if (g_sck_local_bind(dev->listen_sck, dev->uds_data) != 0)
1378 {
1379 LLOGLN(0, ("rdpClientConInit: g_tcp_local_bind failed"));
1380 return 1;
1381 }
1382 g_sck_listen(dev->listen_sck);
1383 g_chmod_hex(dev->uds_data, 0x0660);
1384 rdpClientConAddEnabledDevice(dev->pScreen, dev->listen_sck);
1385 }
1386
1387 /* disconnect socket */ /* TODO: don't hardcode socket name */
1388 g_sprintf(dev->disconnect_uds, "%s/xrdp_disconnect_display_%s", socket_dir, display);
1389 if (dev->disconnect_sck == 0)
1390 {
1391 unlink(dev->disconnect_uds);
1392 dev->disconnect_sck = g_sck_local_socket_dgram();
1393 if (g_sck_local_bind(dev->disconnect_sck, dev->disconnect_uds) != 0)
1394 {
1395 LLOGLN(0, ("rdpClientConInit: g_tcp_local_bind failed at %s:%d", __FILE__, __LINE__));
1396 return 1;
1397 }
1398 g_sck_listen(dev->disconnect_sck);
1399 g_chmod_hex(dev->disconnect_uds, 0x0660);
1400 rdpClientConAddEnabledDevice(dev->pScreen, dev->disconnect_sck);
1401 }
1402
1403 /* disconnect idle */
1404 ptext = getenv("XRDP_SESMAN_MAX_IDLE_TIME");
1405 if (ptext != 0)
1406 {
1407 i = atoi(ptext);
1408 if (i > 0)
1409 {
1410 dev->idle_disconnect_timeout_s = i;
1411 }
1412
1413 }
1414 LLOGLN(0, ("rdpClientConInit: disconnect idle session after [%d] sec",
1415 dev->idle_disconnect_timeout_s));
1416
1417 /* kill disconnected */
1418 ptext = getenv("XRDP_SESMAN_MAX_DISC_TIME");
1419 if (ptext != 0)
1420 {
1421 i = atoi(ptext);
1422 if (i > 0)
1423 {
1424 dev->disconnect_timeout_s = atoi(ptext);
1425 }
1426 }
1427 ptext = getenv("XRDP_SESMAN_KILL_DISCONNECTED");
1428 if (ptext != 0)
1429 {
1430 i = atoi(ptext);
1431 if (i == 0)
1432 {
1433 dev->do_kill_disconnected = 0;
1434 }
1435 else
1436 {
1437 dev->do_kill_disconnected = 1;
1438 }
1439 }
1440
1441 if (dev->do_kill_disconnected && (dev->disconnect_timeout_s < 60))
1442 {
1443 dev->disconnect_timeout_s = 60;
1444 }
1445
1446 LLOGLN(0, ("rdpClientConInit: kill disconnected [%d] timeout [%d] sec",
1447 dev->do_kill_disconnected, dev->disconnect_timeout_s));
1448
1449
1450 return 0;
1451 }
1452
1453 /******************************************************************************/
1454 int
rdpClientConDeinit(rdpPtr dev)1455 rdpClientConDeinit(rdpPtr dev)
1456 {
1457 LLOGLN(0, ("rdpClientConDeinit:"));
1458
1459 while (dev->clientConTail != NULL)
1460 {
1461 LLOGLN(0, ("rdpClientConDeinit: disconnecting clientCon"));
1462 rdpClientConDisconnect(dev, dev->clientConTail);
1463 }
1464
1465 if (dev->listen_sck != 0)
1466 {
1467 rdpClientConRemoveEnabledDevice(dev->listen_sck);
1468 g_sck_close(dev->listen_sck);
1469 LLOGLN(0, ("rdpClientConDeinit: deleting file %s", dev->uds_data));
1470 if (unlink(dev->uds_data) < 0)
1471 {
1472 LLOGLN(0, ("rdpClientConDeinit: failed to delete %s (%s)",
1473 dev->uds_data, strerror(errno)));
1474 }
1475 }
1476
1477 if (dev->disconnect_sck != 0)
1478 {
1479 rdpClientConRemoveEnabledDevice(dev->disconnect_sck);
1480 g_sck_close(dev->disconnect_sck);
1481 LLOGLN(0, ("rdpClientConDeinit: deleting file %s", dev->disconnect_uds));
1482 if (unlink(dev->disconnect_uds) < 0)
1483 {
1484 LLOGLN(0, ("rdpClientConDeinit: failed to delete %s (%s)",
1485 dev->disconnect_uds, strerror(errno)));
1486 }
1487 }
1488
1489 return 0;
1490 }
1491
1492 /******************************************************************************/
1493 int
rdpClientConBeginUpdate(rdpPtr dev,rdpClientCon * clientCon)1494 rdpClientConBeginUpdate(rdpPtr dev, rdpClientCon *clientCon)
1495 {
1496 LLOGLN(10, ("rdpClientConBeginUpdate:"));
1497
1498 if (clientCon->begin)
1499 {
1500 return 0;
1501 }
1502 init_stream(clientCon->out_s, 0);
1503 s_push_layer(clientCon->out_s, iso_hdr, 8);
1504 out_uint16_le(clientCon->out_s, 1); /* begin update */
1505 out_uint16_le(clientCon->out_s, 4); /* size */
1506 clientCon->begin = TRUE;
1507 clientCon->count = 1;
1508
1509 return 0;
1510 }
1511
1512 /******************************************************************************/
1513 int
rdpClientConEndUpdate(rdpPtr dev,rdpClientCon * clientCon)1514 rdpClientConEndUpdate(rdpPtr dev, rdpClientCon *clientCon)
1515 {
1516 LLOGLN(10, ("rdpClientConEndUpdate"));
1517
1518 if (clientCon->connected && clientCon->begin)
1519 {
1520 if (dev->do_dirty_ons)
1521 {
1522 /* in this mode, end update is only called in check dirty */
1523 rdpClientConSendPending(dev, clientCon);
1524 }
1525 else
1526 {
1527 rdpClientConScheduleDeferredUpdate(dev);
1528 }
1529 }
1530
1531 return 0;
1532 }
1533
1534 /******************************************************************************/
1535 int
rdpClientConPreCheck(rdpPtr dev,rdpClientCon * clientCon,int in_size)1536 rdpClientConPreCheck(rdpPtr dev, rdpClientCon *clientCon, int in_size)
1537 {
1538 int rv;
1539
1540 rv = 0;
1541 if (clientCon->begin == FALSE)
1542 {
1543 rdpClientConBeginUpdate(dev, clientCon);
1544 }
1545
1546 if ((clientCon->out_s->p - clientCon->out_s->data) >
1547 (clientCon->out_s->size - (in_size + 20)))
1548 {
1549 s_mark_end(clientCon->out_s);
1550 if (rdpClientConSendMsg(dev, clientCon) != 0)
1551 {
1552 LLOGLN(0, ("rdpClientConPreCheck: rdpup_send_msg failed"));
1553 rv = 1;
1554 }
1555 clientCon->count = 0;
1556 init_stream(clientCon->out_s, 0);
1557 s_push_layer(clientCon->out_s, iso_hdr, 8);
1558 }
1559
1560 return rv;
1561 }
1562
1563 /******************************************************************************/
1564 int
rdpClientConFillRect(rdpPtr dev,rdpClientCon * clientCon,short x,short y,int cx,int cy)1565 rdpClientConFillRect(rdpPtr dev, rdpClientCon *clientCon,
1566 short x, short y, int cx, int cy)
1567 {
1568 if (clientCon->connected)
1569 {
1570 LLOGLN(10, ("rdpClientConFillRect:"));
1571 rdpClientConPreCheck(dev, clientCon, 12);
1572 out_uint16_le(clientCon->out_s, 3); /* fill rect */
1573 out_uint16_le(clientCon->out_s, 12); /* size */
1574 clientCon->count++;
1575 out_uint16_le(clientCon->out_s, x);
1576 out_uint16_le(clientCon->out_s, y);
1577 out_uint16_le(clientCon->out_s, cx);
1578 out_uint16_le(clientCon->out_s, cy);
1579 }
1580
1581 return 0;
1582 }
1583
1584 /******************************************************************************/
1585 int
rdpClientConScreenBlt(rdpPtr dev,rdpClientCon * clientCon,short x,short y,int cx,int cy,short srcx,short srcy)1586 rdpClientConScreenBlt(rdpPtr dev, rdpClientCon *clientCon,
1587 short x, short y, int cx, int cy, short srcx, short srcy)
1588 {
1589 if (clientCon->connected)
1590 {
1591 LLOGLN(10, ("rdpClientConScreenBlt: x %d y %d cx %d cy %d "
1592 "srcx %d srcy %d",
1593 x, y, cx, cy, srcx, srcy));
1594 rdpClientConPreCheck(dev, clientCon, 16);
1595 out_uint16_le(clientCon->out_s, 4); /* screen blt */
1596 out_uint16_le(clientCon->out_s, 16); /* size */
1597 clientCon->count++;
1598 out_uint16_le(clientCon->out_s, x);
1599 out_uint16_le(clientCon->out_s, y);
1600 out_uint16_le(clientCon->out_s, cx);
1601 out_uint16_le(clientCon->out_s, cy);
1602 out_uint16_le(clientCon->out_s, srcx);
1603 out_uint16_le(clientCon->out_s, srcy);
1604 }
1605
1606 return 0;
1607 }
1608
1609 /******************************************************************************/
1610 int
rdpClientConSetClip(rdpPtr dev,rdpClientCon * clientCon,short x,short y,int cx,int cy)1611 rdpClientConSetClip(rdpPtr dev, rdpClientCon *clientCon,
1612 short x, short y, int cx, int cy)
1613 {
1614 if (clientCon->connected)
1615 {
1616 LLOGLN(10, ("rdpClientConSetClip:"));
1617 rdpClientConPreCheck(dev, clientCon, 12);
1618 out_uint16_le(clientCon->out_s, 10); /* set clip */
1619 out_uint16_le(clientCon->out_s, 12); /* size */
1620 clientCon->count++;
1621 out_uint16_le(clientCon->out_s, x);
1622 out_uint16_le(clientCon->out_s, y);
1623 out_uint16_le(clientCon->out_s, cx);
1624 out_uint16_le(clientCon->out_s, cy);
1625 }
1626
1627 return 0;
1628 }
1629
1630 /******************************************************************************/
1631 int
rdpClientConResetClip(rdpPtr dev,rdpClientCon * clientCon)1632 rdpClientConResetClip(rdpPtr dev, rdpClientCon *clientCon)
1633 {
1634 if (clientCon->connected)
1635 {
1636 LLOGLN(10, ("rdpClientConResetClip:"));
1637 rdpClientConPreCheck(dev, clientCon, 4);
1638 out_uint16_le(clientCon->out_s, 11); /* reset clip */
1639 out_uint16_le(clientCon->out_s, 4); /* size */
1640 clientCon->count++;
1641 }
1642
1643 return 0;
1644 }
1645
1646 /******************************************************************************/
1647 int
rdpClientConConvertPixel(rdpPtr dev,rdpClientCon * clientCon,int in_pixel)1648 rdpClientConConvertPixel(rdpPtr dev, rdpClientCon *clientCon, int in_pixel)
1649 {
1650 int red;
1651 int green;
1652 int blue;
1653 int rv;
1654
1655 rv = 0;
1656
1657 if (dev->depth == 24)
1658 {
1659 if (clientCon->rdp_bpp == 24)
1660 {
1661 rv = in_pixel;
1662 SPLITCOLOR32(red, green, blue, rv);
1663 rv = COLOR24(red, green, blue);
1664 }
1665 else if (clientCon->rdp_bpp == 16)
1666 {
1667 rv = in_pixel;
1668 SPLITCOLOR32(red, green, blue, rv);
1669 rv = COLOR16(red, green, blue);
1670 }
1671 else if (clientCon->rdp_bpp == 15)
1672 {
1673 rv = in_pixel;
1674 SPLITCOLOR32(red, green, blue, rv);
1675 rv = COLOR15(red, green, blue);
1676 }
1677 else if (clientCon->rdp_bpp == 8)
1678 {
1679 rv = in_pixel;
1680 SPLITCOLOR32(red, green, blue, rv);
1681 rv = COLOR8(red, green, blue);
1682 }
1683 }
1684 else if (dev->depth == clientCon->rdp_bpp)
1685 {
1686 return in_pixel;
1687 }
1688
1689 return rv;
1690 }
1691
1692 /******************************************************************************/
1693 int
rdpClientConConvertPixels(rdpPtr dev,rdpClientCon * clientCon,const void * src,void * dst,int num_pixels)1694 rdpClientConConvertPixels(rdpPtr dev, rdpClientCon *clientCon,
1695 const void *src, void *dst, int num_pixels)
1696 {
1697 uint32_t pixel;
1698 uint32_t red;
1699 uint32_t green;
1700 uint32_t blue;
1701 const uint32_t *src32;
1702 uint32_t *dst32;
1703 uint16_t *dst16;
1704 uint8_t *dst8;
1705 int index;
1706
1707 if (dev->depth == clientCon->rdp_bpp)
1708 {
1709 memcpy(dst, src, num_pixels * dev->Bpp);
1710 return 0;
1711 }
1712
1713 if (dev->depth == 24)
1714 {
1715 src32 = (const uint32_t *) src;
1716
1717 if (clientCon->rdp_bpp == 24)
1718 {
1719 dst32 = (uint32_t *) dst;
1720
1721 for (index = 0; index < num_pixels; index++)
1722 {
1723 pixel = *src32;
1724 *dst32 = pixel;
1725 dst32++;
1726 src32++;
1727 }
1728 }
1729 else if (clientCon->rdp_bpp == 16)
1730 {
1731 dst16 = (uint16_t *) dst;
1732
1733 for (index = 0; index < num_pixels; index++)
1734 {
1735 pixel = *src32;
1736 SPLITCOLOR32(red, green, blue, pixel);
1737 pixel = COLOR16(red, green, blue);
1738 *dst16 = pixel;
1739 dst16++;
1740 src32++;
1741 }
1742 }
1743 else if (clientCon->rdp_bpp == 15)
1744 {
1745 dst16 = (uint16_t *) dst;
1746
1747 for (index = 0; index < num_pixels; index++)
1748 {
1749 pixel = *src32;
1750 SPLITCOLOR32(red, green, blue, pixel);
1751 pixel = COLOR15(red, green, blue);
1752 *dst16 = pixel;
1753 dst16++;
1754 src32++;
1755 }
1756 }
1757 else if (clientCon->rdp_bpp == 8)
1758 {
1759 dst8 = (uint8_t *) dst;
1760
1761 for (index = 0; index < num_pixels; index++)
1762 {
1763 pixel = *src32;
1764 SPLITCOLOR32(red, green, blue, pixel);
1765 pixel = COLOR8(red, green, blue);
1766 *dst8 = pixel;
1767 dst8++;
1768 src32++;
1769 }
1770 }
1771 }
1772
1773 return 0;
1774 }
1775
1776 /******************************************************************************/
1777 int
rdpClientConAlphaPixels(const void * src,void * dst,int num_pixels)1778 rdpClientConAlphaPixels(const void *src, void *dst, int num_pixels)
1779 {
1780 const uint32_t *src32;
1781 uint8_t *dst8;
1782 int index;
1783
1784 src32 = (const uint32_t *) src;
1785 dst8 = (uint8_t *) dst;
1786 for (index = 0; index < num_pixels; index++)
1787 {
1788 *dst8 = (*src32) >> 24;
1789 dst8++;
1790 src32++;
1791 }
1792 return 0;
1793 }
1794
1795 /******************************************************************************/
1796 int
rdpClientConSetFgcolor(rdpPtr dev,rdpClientCon * clientCon,int fgcolor)1797 rdpClientConSetFgcolor(rdpPtr dev, rdpClientCon *clientCon, int fgcolor)
1798 {
1799 if (clientCon->connected)
1800 {
1801 LLOGLN(10, ("rdpClientConSetFgcolor:"));
1802 rdpClientConPreCheck(dev, clientCon, 8);
1803 out_uint16_le(clientCon->out_s, 12); /* set fgcolor */
1804 out_uint16_le(clientCon->out_s, 8); /* size */
1805 clientCon->count++;
1806 fgcolor = fgcolor & dev->Bpp_mask;
1807 fgcolor = rdpClientConConvertPixel(dev, clientCon, fgcolor) &
1808 clientCon->rdp_Bpp_mask;
1809 out_uint32_le(clientCon->out_s, fgcolor);
1810 }
1811
1812 return 0;
1813 }
1814
1815 /******************************************************************************/
1816 int
rdpClientConSetBgcolor(rdpPtr dev,rdpClientCon * clientCon,int bgcolor)1817 rdpClientConSetBgcolor(rdpPtr dev, rdpClientCon *clientCon, int bgcolor)
1818 {
1819 if (clientCon->connected)
1820 {
1821 LLOGLN(10, ("rdpClientConSetBgcolor:"));
1822 rdpClientConPreCheck(dev, clientCon, 8);
1823 out_uint16_le(clientCon->out_s, 13); /* set bg color */
1824 out_uint16_le(clientCon->out_s, 8); /* size */
1825 clientCon->count++;
1826 bgcolor = bgcolor & dev->Bpp_mask;
1827 bgcolor = rdpClientConConvertPixel(dev, clientCon, bgcolor) &
1828 clientCon->rdp_Bpp_mask;
1829 out_uint32_le(clientCon->out_s, bgcolor);
1830 }
1831
1832 return 0;
1833 }
1834
1835 /******************************************************************************/
1836 int
rdpClientConSetOpcode(rdpPtr dev,rdpClientCon * clientCon,int opcode)1837 rdpClientConSetOpcode(rdpPtr dev, rdpClientCon *clientCon, int opcode)
1838 {
1839 if (clientCon->connected)
1840 {
1841 LLOGLN(10, ("rdpClientConSetOpcode:"));
1842 rdpClientConPreCheck(dev, clientCon, 6);
1843 out_uint16_le(clientCon->out_s, 14); /* set opcode */
1844 out_uint16_le(clientCon->out_s, 6); /* size */
1845 clientCon->count++;
1846 out_uint16_le(clientCon->out_s, g_rdp_opcodes[opcode & 0xf]);
1847 }
1848
1849 return 0;
1850 }
1851
1852 /******************************************************************************/
1853 int
rdpClientConSetPen(rdpPtr dev,rdpClientCon * clientCon,int style,int width)1854 rdpClientConSetPen(rdpPtr dev, rdpClientCon *clientCon, int style, int width)
1855 {
1856 if (clientCon->connected)
1857 {
1858 LLOGLN(10, ("rdpClientConSetPen:"));
1859 rdpClientConPreCheck(dev, clientCon, 8);
1860 out_uint16_le(clientCon->out_s, 17); /* set pen */
1861 out_uint16_le(clientCon->out_s, 8); /* size */
1862 clientCon->count++;
1863 out_uint16_le(clientCon->out_s, style);
1864 out_uint16_le(clientCon->out_s, width);
1865 }
1866
1867 return 0;
1868 }
1869
1870 /******************************************************************************/
1871 int
rdpClientConDrawLine(rdpPtr dev,rdpClientCon * clientCon,short x1,short y1,short x2,short y2)1872 rdpClientConDrawLine(rdpPtr dev, rdpClientCon *clientCon,
1873 short x1, short y1, short x2, short y2)
1874 {
1875 if (clientCon->connected)
1876 {
1877 LLOGLN(10, ("rdpClientConDrawLine:"));
1878 rdpClientConPreCheck(dev, clientCon, 12);
1879 out_uint16_le(clientCon->out_s, 18); /* draw line */
1880 out_uint16_le(clientCon->out_s, 12); /* size */
1881 clientCon->count++;
1882 out_uint16_le(clientCon->out_s, x1);
1883 out_uint16_le(clientCon->out_s, y1);
1884 out_uint16_le(clientCon->out_s, x2);
1885 out_uint16_le(clientCon->out_s, y2);
1886 }
1887
1888 return 0;
1889 }
1890
1891 /******************************************************************************/
1892 int
rdpClientConSetCursor(rdpPtr dev,rdpClientCon * clientCon,short x,short y,uint8_t * cur_data,uint8_t * cur_mask)1893 rdpClientConSetCursor(rdpPtr dev, rdpClientCon *clientCon,
1894 short x, short y, uint8_t *cur_data, uint8_t *cur_mask)
1895 {
1896 int size;
1897
1898 if (clientCon->connected)
1899 {
1900 LLOGLN(10, ("rdpClientConSetCursor:"));
1901 size = 8 + 32 * (32 * 3) + 32 * (32 / 8);
1902 rdpClientConPreCheck(dev, clientCon, size);
1903 out_uint16_le(clientCon->out_s, 19); /* set cursor */
1904 out_uint16_le(clientCon->out_s, size); /* size */
1905 clientCon->count++;
1906 x = RDPMAX(0, x);
1907 x = RDPMIN(31, x);
1908 y = RDPMAX(0, y);
1909 y = RDPMIN(31, y);
1910 out_uint16_le(clientCon->out_s, x);
1911 out_uint16_le(clientCon->out_s, y);
1912 out_uint8a(clientCon->out_s, cur_data, 32 * (32 * 3));
1913 out_uint8a(clientCon->out_s, cur_mask, 32 * (32 / 8));
1914 }
1915
1916 return 0;
1917 }
1918
1919 /******************************************************************************/
1920 int
rdpClientConSetCursorEx(rdpPtr dev,rdpClientCon * clientCon,short x,short y,uint8_t * cur_data,uint8_t * cur_mask,int bpp)1921 rdpClientConSetCursorEx(rdpPtr dev, rdpClientCon *clientCon,
1922 short x, short y, uint8_t *cur_data,
1923 uint8_t *cur_mask, int bpp)
1924 {
1925 int size;
1926 int Bpp;
1927
1928 if (clientCon->connected)
1929 {
1930 LLOGLN(10, ("rdpClientConSetCursorEx:"));
1931 Bpp = (bpp == 0) ? 3 : (bpp + 7) / 8;
1932 size = 10 + 32 * (32 * Bpp) + 32 * (32 / 8);
1933 rdpClientConPreCheck(dev, clientCon, size);
1934 out_uint16_le(clientCon->out_s, 51); /* set cursor ex */
1935 out_uint16_le(clientCon->out_s, size); /* size */
1936 clientCon->count++;
1937 x = RDPMAX(0, x);
1938 x = RDPMIN(31, x);
1939 y = RDPMAX(0, y);
1940 y = RDPMIN(31, y);
1941 out_uint16_le(clientCon->out_s, x);
1942 out_uint16_le(clientCon->out_s, y);
1943 out_uint16_le(clientCon->out_s, bpp);
1944 out_uint8a(clientCon->out_s, cur_data, 32 * (32 * Bpp));
1945 out_uint8a(clientCon->out_s, cur_mask, 32 * (32 / 8));
1946 }
1947
1948 return 0;
1949 }
1950
1951 /******************************************************************************/
1952 int
rdpClientConCreateOsSurface(rdpPtr dev,rdpClientCon * clientCon,int rdpindex,int width,int height)1953 rdpClientConCreateOsSurface(rdpPtr dev, rdpClientCon *clientCon,
1954 int rdpindex, int width, int height)
1955 {
1956 LLOGLN(10, ("rdpClientConCreateOsSurface:"));
1957
1958 if (clientCon->connected)
1959 {
1960 LLOGLN(10, ("rdpClientConCreateOsSurface: width %d height %d", width, height));
1961 rdpClientConPreCheck(dev, clientCon, 12);
1962 out_uint16_le(clientCon->out_s, 20);
1963 out_uint16_le(clientCon->out_s, 12);
1964 clientCon->count++;
1965 out_uint32_le(clientCon->out_s, rdpindex);
1966 out_uint16_le(clientCon->out_s, width);
1967 out_uint16_le(clientCon->out_s, height);
1968 }
1969
1970 return 0;
1971 }
1972
1973 /******************************************************************************/
1974 int
rdpClientConCreateOsSurfaceBpp(rdpPtr dev,rdpClientCon * clientCon,int rdpindex,int width,int height,int bpp)1975 rdpClientConCreateOsSurfaceBpp(rdpPtr dev, rdpClientCon *clientCon,
1976 int rdpindex, int width, int height, int bpp)
1977 {
1978 LLOGLN(10, ("rdpClientConCreateOsSurfaceBpp:"));
1979 if (clientCon->connected)
1980 {
1981 LLOGLN(10, ("rdpClientConCreateOsSurfaceBpp: width %d height %d "
1982 "bpp %d", width, height, bpp));
1983 rdpClientConPreCheck(dev, clientCon, 13);
1984 out_uint16_le(clientCon->out_s, 31);
1985 out_uint16_le(clientCon->out_s, 13);
1986 clientCon->count++;
1987 out_uint32_le(clientCon->out_s, rdpindex);
1988 out_uint16_le(clientCon->out_s, width);
1989 out_uint16_le(clientCon->out_s, height);
1990 out_uint8(clientCon->out_s, bpp);
1991 }
1992 return 0;
1993 }
1994
1995 /******************************************************************************/
1996 int
rdpClientConSwitchOsSurface(rdpPtr dev,rdpClientCon * clientCon,int rdpindex)1997 rdpClientConSwitchOsSurface(rdpPtr dev, rdpClientCon *clientCon, int rdpindex)
1998 {
1999 LLOGLN(10, ("rdpClientConSwitchOsSurface:"));
2000
2001 if (clientCon->connected)
2002 {
2003 if (clientCon->rdpIndex == rdpindex)
2004 {
2005 return 0;
2006 }
2007
2008 clientCon->rdpIndex = rdpindex;
2009 LLOGLN(10, ("rdpClientConSwitchOsSurface: rdpindex %d", rdpindex));
2010 /* switch surface */
2011 rdpClientConPreCheck(dev, clientCon, 8);
2012 out_uint16_le(clientCon->out_s, 21);
2013 out_uint16_le(clientCon->out_s, 8);
2014 out_uint32_le(clientCon->out_s, rdpindex);
2015 clientCon->count++;
2016 }
2017
2018 return 0;
2019 }
2020
2021 /******************************************************************************/
2022 int
rdpClientConDeleteOsSurface(rdpPtr dev,rdpClientCon * clientCon,int rdpindex)2023 rdpClientConDeleteOsSurface(rdpPtr dev, rdpClientCon *clientCon, int rdpindex)
2024 {
2025 LLOGLN(10, ("rdpClientConDeleteOsSurface: rdpindex %d", rdpindex));
2026
2027 if (clientCon->connected)
2028 {
2029 LLOGLN(10, ("rdpClientConDeleteOsSurface: rdpindex %d", rdpindex));
2030 rdpClientConPreCheck(dev, clientCon, 8);
2031 out_uint16_le(clientCon->out_s, 22);
2032 out_uint16_le(clientCon->out_s, 8);
2033 clientCon->count++;
2034 out_uint32_le(clientCon->out_s, rdpindex);
2035 }
2036
2037 return 0;
2038 }
2039
2040 /*****************************************************************************/
2041 /* returns -1 on error */
2042 int
rdpClientConAddOsBitmap(rdpPtr dev,rdpClientCon * clientCon,PixmapPtr pixmap,rdpPixmapPtr priv)2043 rdpClientConAddOsBitmap(rdpPtr dev, rdpClientCon *clientCon,
2044 PixmapPtr pixmap, rdpPixmapPtr priv)
2045 {
2046 int index;
2047 int rv;
2048 int oldest;
2049 int oldest_index;
2050 int this_bytes;
2051
2052 LLOGLN(10, ("rdpClientConAddOsBitmap:"));
2053 if (clientCon->connected == FALSE)
2054 {
2055 LLOGLN(10, ("rdpClientConAddOsBitmap: test error 1"));
2056 return -1;
2057 }
2058
2059 if (clientCon->osBitmaps == NULL)
2060 {
2061 LLOGLN(10, ("rdpClientConAddOsBitmap: test error 2"));
2062 return -1;
2063 }
2064
2065 this_bytes = pixmap->devKind * pixmap->drawable.height;
2066 if (this_bytes > MAX_OS_BYTES)
2067 {
2068 LLOGLN(10, ("rdpClientConAddOsBitmap: error, too big this_bytes %d "
2069 "width %d height %d", this_bytes,
2070 pixmap->drawable.height, pixmap->drawable.height));
2071 return -1;
2072 }
2073
2074 oldest = INT_MAX;
2075 oldest_index = -1;
2076 rv = -1;
2077 index = 0;
2078
2079 while (index < clientCon->maxOsBitmaps)
2080 {
2081 if (clientCon->osBitmaps[index].used == FALSE)
2082 {
2083 clientCon->osBitmaps[index].used = TRUE;
2084 clientCon->osBitmaps[index].pixmap = pixmap;
2085 clientCon->osBitmaps[index].priv = priv;
2086 clientCon->osBitmaps[index].stamp = clientCon->osBitmapStamp;
2087 clientCon->osBitmapStamp++;
2088 clientCon->osBitmapNumUsed++;
2089 rv = index;
2090 break;
2091 }
2092 else
2093 {
2094 if (clientCon->osBitmaps[index].stamp < oldest)
2095 {
2096 oldest = clientCon->osBitmaps[index].stamp;
2097 oldest_index = index;
2098 }
2099 }
2100 index++;
2101 }
2102
2103 if (rv == -1)
2104 {
2105 if (oldest_index == -1)
2106 {
2107 LLOGLN(0, ("rdpClientConAddOsBitmap: error"));
2108 }
2109 else
2110 {
2111 LLOGLN(10, ("rdpClientConAddOsBitmap: too many pixmaps removing "
2112 "oldest_index %d", oldest_index));
2113 rdpClientConRemoveOsBitmap(dev, clientCon, oldest_index);
2114 rdpClientConDeleteOsSurface(dev, clientCon, oldest_index);
2115 clientCon->osBitmaps[oldest_index].used = TRUE;
2116 clientCon->osBitmaps[oldest_index].pixmap = pixmap;
2117 clientCon->osBitmaps[oldest_index].priv = priv;
2118 clientCon->osBitmaps[oldest_index].stamp = clientCon->osBitmapStamp;
2119 clientCon->osBitmapStamp++;
2120 clientCon->osBitmapNumUsed++;
2121 rv = oldest_index;
2122 }
2123 }
2124
2125 if (rv < 0)
2126 {
2127 LLOGLN(10, ("rdpClientConAddOsBitmap: test error 3"));
2128 return rv;
2129 }
2130
2131 clientCon->osBitmapAllocSize += this_bytes;
2132 LLOGLN(10, ("rdpClientConAddOsBitmap: this_bytes %d "
2133 "clientCon->osBitmapAllocSize %d",
2134 this_bytes, clientCon->osBitmapAllocSize));
2135 #if USE_MAX_OS_BYTES
2136 while (clientCon->osBitmapAllocSize > MAX_OS_BYTES)
2137 {
2138 LLOGLN(10, ("rdpClientConAddOsBitmap: must delete "
2139 "clientCon->osBitmapNumUsed %d",
2140 clientCon->osBitmapNumUsed));
2141 /* find oldest */
2142 oldest = INT_MAX;
2143 oldest_index = -1;
2144 index = 0;
2145 while (index < clientCon->maxOsBitmaps)
2146 {
2147 if (clientCon->osBitmaps[index].used &&
2148 (clientCon->osBitmaps[index].stamp < oldest))
2149 {
2150 oldest = clientCon->osBitmaps[index].stamp;
2151 oldest_index = index;
2152 }
2153 index++;
2154 }
2155 if (oldest_index == -1)
2156 {
2157 LLOGLN(0, ("rdpClientConAddOsBitmap: error 1"));
2158 break;
2159 }
2160 if (oldest_index == rv)
2161 {
2162 LLOGLN(0, ("rdpClientConAddOsBitmap: error 2"));
2163 break;
2164 }
2165 rdpClientConRemoveOsBitmap(dev, clientCon, oldest_index);
2166 rdpClientConDeleteOsSurface(dev, clientCon, oldest_index);
2167 }
2168 #endif
2169 LLOGLN(10, ("rdpClientConAddOsBitmap: new bitmap index %d", rv));
2170 LLOGLN(10, ("rdpClientConAddOsBitmap: clientCon->osBitmapNumUsed %d "
2171 "clientCon->osBitmapStamp 0x%8.8x",
2172 clientCon->osBitmapNumUsed, clientCon->osBitmapStamp));
2173 return rv;
2174 }
2175
2176 /*****************************************************************************/
2177 int
rdpClientConRemoveOsBitmap(rdpPtr dev,rdpClientCon * clientCon,int rdpindex)2178 rdpClientConRemoveOsBitmap(rdpPtr dev, rdpClientCon *clientCon, int rdpindex)
2179 {
2180 PixmapPtr pixmap;
2181 rdpPixmapPtr priv;
2182 int this_bytes;
2183
2184 if (clientCon->osBitmaps == NULL)
2185 {
2186 LLOGLN(10, ("rdpClientConRemoveOsBitmap: test error 1"));
2187 return 1;
2188 }
2189
2190 LLOGLN(10, ("rdpClientConRemoveOsBitmap: index %d stamp %d",
2191 rdpindex, clientCon->osBitmaps[rdpindex].stamp));
2192
2193 if ((rdpindex < 0) && (rdpindex >= clientCon->maxOsBitmaps))
2194 {
2195 LLOGLN(10, ("rdpClientConRemoveOsBitmap: test error 2"));
2196 return 1;
2197 }
2198
2199 if (clientCon->osBitmaps[rdpindex].used)
2200 {
2201 pixmap = clientCon->osBitmaps[rdpindex].pixmap;
2202 priv = clientCon->osBitmaps[rdpindex].priv;
2203 rdpDrawItemRemoveAll(dev, priv);
2204 this_bytes = pixmap->devKind * pixmap->drawable.height;
2205 clientCon->osBitmapAllocSize -= this_bytes;
2206 LLOGLN(10, ("rdpClientConRemoveOsBitmap: this_bytes %d "
2207 "clientCon->osBitmapAllocSize %d", this_bytes,
2208 clientCon->osBitmapAllocSize));
2209 clientCon->osBitmaps[rdpindex].used = 0;
2210 clientCon->osBitmaps[rdpindex].pixmap = 0;
2211 clientCon->osBitmaps[rdpindex].priv = 0;
2212 clientCon->osBitmapNumUsed--;
2213 priv->status = 0;
2214 priv->con_number = 0;
2215 priv->use_count = 0;
2216 }
2217 else
2218 {
2219 LLOGLN(0, ("rdpup_remove_os_bitmap: error"));
2220 }
2221
2222 LLOGLN(10, ("rdpup_remove_os_bitmap: clientCon->osBitmapNumUsed %d",
2223 clientCon->osBitmapNumUsed));
2224 return 0;
2225 }
2226
2227 /*****************************************************************************/
2228 int
rdpClientConUpdateOsUse(rdpPtr dev,rdpClientCon * clientCon,int rdpindex)2229 rdpClientConUpdateOsUse(rdpPtr dev, rdpClientCon *clientCon, int rdpindex)
2230 {
2231 if (clientCon->osBitmaps == NULL)
2232 {
2233 return 1;
2234 }
2235
2236 LLOGLN(10, ("rdpClientConUpdateOsUse: index %d stamp %d",
2237 rdpindex, clientCon->osBitmaps[rdpindex].stamp));
2238
2239 if ((rdpindex < 0) && (rdpindex >= clientCon->maxOsBitmaps))
2240 {
2241 return 1;
2242 }
2243
2244 if (clientCon->osBitmaps[rdpindex].used)
2245 {
2246 clientCon->osBitmaps[rdpindex].stamp = clientCon->osBitmapStamp;
2247 clientCon->osBitmapStamp++;
2248 }
2249 else
2250 {
2251 LLOGLN(0, ("rdpClientConUpdateOsUse: error rdpindex %d", rdpindex));
2252 }
2253
2254 return 0;
2255 }
2256
2257 /******************************************************************************/
2258 static CARD32
rdpClientConDeferredUpdateCallback(OsTimerPtr timer,CARD32 now,pointer arg)2259 rdpClientConDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg)
2260 {
2261 rdpPtr dev;
2262 rdpClientCon *clientCon;
2263
2264 LLOGLN(10, ("rdpClientConDeferredUpdateCallback"));
2265
2266 dev = (rdpPtr) arg;
2267 clientCon = dev->clientConHead;
2268 while (clientCon != NULL)
2269 {
2270 if (dev->do_dirty_ons)
2271 {
2272 if (clientCon->rectId == clientCon->rectIdAck)
2273 {
2274 rdpClientConCheckDirtyScreen(dev, clientCon);
2275 }
2276 else
2277 {
2278 LLOGLN(0, ("rdpClientConDeferredUpdateCallback: skipping"));
2279 }
2280 }
2281 else
2282 {
2283 rdpClientConSendPending(dev, clientCon);
2284 }
2285 clientCon = clientCon->next;
2286 }
2287 dev->sendUpdateScheduled = FALSE;
2288 return 0;
2289 }
2290
2291 /******************************************************************************/
2292 void
rdpClientConScheduleDeferredUpdate(rdpPtr dev)2293 rdpClientConScheduleDeferredUpdate(rdpPtr dev)
2294 {
2295 if (dev->sendUpdateScheduled == FALSE)
2296 {
2297 dev->sendUpdateScheduled = TRUE;
2298 dev->sendUpdateTimer =
2299 TimerSet(dev->sendUpdateTimer, 0, 40,
2300 rdpClientConDeferredUpdateCallback, dev);
2301 }
2302 }
2303
2304 /******************************************************************************/
2305 int
rdpClientConCheckDirtyScreen(rdpPtr dev,rdpClientCon * clientCon)2306 rdpClientConCheckDirtyScreen(rdpPtr dev, rdpClientCon *clientCon)
2307 {
2308 return 0;
2309 }
2310
2311 /******************************************************************************/
2312 static int
rdpClientConSendPaintRectShmEx(rdpPtr dev,rdpClientCon * clientCon,struct image_data * id,RegionPtr dirtyReg,BoxPtr copyRects,int numCopyRects)2313 rdpClientConSendPaintRectShmEx(rdpPtr dev, rdpClientCon *clientCon,
2314 struct image_data *id,
2315 RegionPtr dirtyReg,
2316 BoxPtr copyRects, int numCopyRects)
2317 {
2318 int index;
2319 int size;
2320 int num_rects_d;
2321 int num_rects_c;
2322 short x;
2323 short y;
2324 short cx;
2325 short cy;
2326 struct stream *s;
2327 BoxRec box;
2328
2329 rdpClientConBeginUpdate(dev, clientCon);
2330
2331 num_rects_d = REGION_NUM_RECTS(dirtyReg);
2332 num_rects_c = numCopyRects;
2333 if ((num_rects_c < 1) || (num_rects_d < 1))
2334 {
2335 LLOGLN(10, ("rdpClientConSendPaintRectShmEx: nothing to send"));
2336 return 0;
2337 }
2338 size = 2 + 2 + 2 + num_rects_d * 8 + 2 + num_rects_c * 8;
2339 size += 4 + 4 + 4 + 4 + 2 + 2;
2340 rdpClientConPreCheck(dev, clientCon, size);
2341
2342 s = clientCon->out_s;
2343 out_uint16_le(s, 61);
2344 out_uint16_le(s, size);
2345 clientCon->count++;
2346
2347 out_uint16_le(s, num_rects_d);
2348 for (index = 0; index < num_rects_d; index++)
2349 {
2350 box = REGION_RECTS(dirtyReg)[index];
2351 x = box.x1;
2352 y = box.y1;
2353 cx = box.x2 - box.x1;
2354 cy = box.y2 - box.y1;
2355 out_uint16_le(s, x);
2356 out_uint16_le(s, y);
2357 out_uint16_le(s, cx);
2358 out_uint16_le(s, cy);
2359 }
2360
2361 out_uint16_le(s, num_rects_c);
2362 for (index = 0; index < num_rects_c; index++)
2363 {
2364 box = copyRects[index];
2365 x = box.x1;
2366 y = box.y1;
2367 cx = box.x2 - box.x1;
2368 cy = box.y2 - box.y1;
2369 out_uint16_le(s, x);
2370 out_uint16_le(s, y);
2371 out_uint16_le(s, cx);
2372 out_uint16_le(s, cy);
2373 }
2374
2375 out_uint32_le(s, 0);
2376 clientCon->rect_id++;
2377 out_uint32_le(s, clientCon->rect_id);
2378 out_uint32_le(s, id->shmem_id);
2379 out_uint32_le(s, id->shmem_offset);
2380 out_uint16_le(s, clientCon->cap_width);
2381 out_uint16_le(s, clientCon->cap_height);
2382
2383 rdpClientConEndUpdate(dev, clientCon);
2384
2385 return 0;
2386 }
2387
2388 /******************************************************************************/
2389 /* this is called to capture a rect from the screen, if in a multi monitor
2390 session, this will get called for each monitor, if no monitor info
2391 from the client, the rect will be a band of less than MAX_CAPTURE_PIXELS
2392 pixels
2393 after the capture, it sends the info to xrdp
2394 returns error */
2395 static int
rdpCapRect(rdpClientCon * clientCon,BoxPtr cap_rect,struct image_data * id)2396 rdpCapRect(rdpClientCon *clientCon, BoxPtr cap_rect, struct image_data *id)
2397 {
2398 RegionPtr cap_dirty;
2399 BoxRec rect;
2400 BoxPtr rects;
2401 int num_rects;
2402
2403 cap_dirty = rdpRegionCreate(cap_rect, 0);
2404 LLOGLN(10, ("rdpCapRect: cap_rect x1 %d y1 %d x2 %d y2 %d",
2405 cap_rect->x1, cap_rect->y1, cap_rect->x2, cap_rect->y2));
2406 rdpRegionIntersect(cap_dirty, cap_dirty, clientCon->dirtyRegion);
2407 num_rects = REGION_NUM_RECTS(cap_dirty);
2408 if (num_rects > 0)
2409 {
2410 if (num_rects > MAX_CAPTURE_RECTS)
2411 {
2412 /* the dirty region is too complex, just get a rect that
2413 covers the whole region */
2414 rect = *rdpRegionExtents(cap_dirty);
2415 rdpRegionDestroy(cap_dirty);
2416 cap_dirty = rdpRegionCreate(&rect, 0);
2417 }
2418 rects = 0;
2419 num_rects = 0;
2420 LLOGLN(10, ("rdpCapRect: capture_code %d",
2421 clientCon->client_info.capture_code));
2422 if (rdpCapture(clientCon, cap_dirty, &rects, &num_rects, id))
2423 {
2424 LLOGLN(10, ("rdpCapRect: num_rects %d", num_rects));
2425 rdpClientConSendPaintRectShmEx(clientCon->dev, clientCon, id,
2426 cap_dirty, rects, num_rects);
2427 free(rects);
2428 }
2429 else
2430 {
2431 LLOGLN(0, ("rdpCapRect: rdpCapture failed"));
2432 }
2433 }
2434 rdpRegionSubtract(clientCon->dirtyRegion, clientCon->dirtyRegion,
2435 cap_dirty);
2436 rdpRegionDestroy(cap_dirty);
2437 return 0;
2438 }
2439
2440 /******************************************************************************/
2441 static CARD32
rdpDeferredUpdateCallback(OsTimerPtr timer,CARD32 now,pointer arg)2442 rdpDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg)
2443 {
2444 rdpClientCon *clientCon;
2445 struct image_data id;
2446 int index;
2447 int monitor_index;
2448 int monitor_count;
2449 int band_index;
2450 int band_count;
2451 int band_height;
2452 BoxRec cap_rect;
2453 BoxRec dirty_extents;
2454 int de_width;
2455 int de_height;
2456
2457 LLOGLN(10, ("rdpDeferredUpdateCallback:"));
2458 clientCon = (rdpClientCon *) arg;
2459 clientCon->updateScheduled = FALSE;
2460 clientCon->lastUpdateTime = now;
2461
2462 if (clientCon->suppress_output)
2463 {
2464 LLOGLN(10, ("rdpDeferredUpdateCallback: suppress_output set"));
2465 return 0;
2466 }
2467 if (clientCon->shmemstatus == SHM_UNINITIALIZED || clientCon->shmemstatus == SHM_RESIZING) {
2468 LLOGLN(10, ("rdpDeferredUpdateCallback: clientCon->shmemstatus "
2469 "is not valid for capture operations: %d"
2470 " reschedule rect_id %d rect_id_ack %d",
2471 clientCon->shmemstatus, clientCon->rect_id, clientCon->rect_id_ack));
2472 return 0;
2473 }
2474 if ((clientCon->rect_id > clientCon->rect_id_ack) ||
2475 /* do not allow captures until we have the client_info */
2476 clientCon->client_info.size == 0)
2477 {
2478 LLOGLN(10, ("rdpDeferredUpdateCallback: reschedule rect_id %d "
2479 "rect_id_ack %d",
2480 clientCon->rect_id, clientCon->rect_id_ack));
2481 rdpScheduleDeferredUpdate(clientCon);
2482 return 0;
2483 }
2484 LLOGLN(10, ("rdpDeferredUpdateCallback: sending"));
2485 clientCon->updateRetries = 0;
2486 rdpClientConGetScreenImageRect(clientCon->dev, clientCon, &id);
2487 LLOGLN(10, ("rdpDeferredUpdateCallback: rdp_width %d rdp_height %d "
2488 "rdp_Bpp %d screen width %d screen height %d",
2489 clientCon->rdp_width, clientCon->rdp_height, clientCon->rdp_Bpp,
2490 id.width, id.height));
2491 if (clientCon->dev->monitorCount < 1)
2492 {
2493 dirty_extents = *rdpRegionExtents(clientCon->dirtyRegion);
2494 dirty_extents.x1 = RDPMAX(dirty_extents.x1, 0);
2495 dirty_extents.y1 = RDPMAX(dirty_extents.y1, 0);
2496 dirty_extents.x2 = RDPMIN(dirty_extents.x2, clientCon->rdp_width);
2497 dirty_extents.y2 = RDPMIN(dirty_extents.y2, clientCon->rdp_height);
2498 LLOGLN(10, ("rdpDeferredUpdateCallback: dirty_extents %d %d %d %d",
2499 dirty_extents.x1, dirty_extents.y1,
2500 dirty_extents.x2, dirty_extents.y2));
2501 de_width = dirty_extents.x2 - dirty_extents.x1;
2502 de_height = dirty_extents.y2 - dirty_extents.y1;
2503 if ((de_width > 0) && (de_height > 0))
2504 {
2505 band_height = MAX_CAPTURE_PIXELS / de_width;
2506 band_index = 0;
2507 band_count = (de_width * de_height / MAX_CAPTURE_PIXELS) + 1;
2508 LLOGLN(10, ("rdpDeferredUpdateCallback: band_index %d "
2509 "band_count %d", band_index, band_count));
2510 while (band_index < band_count)
2511 {
2512 if (clientCon->rect_id > clientCon->rect_id_ack)
2513 {
2514 LLOGLN(10, ("rdpDeferredUpdateCallback: reschedule "
2515 "rect_id %d rect_id_ack %d",
2516 clientCon->rect_id, clientCon->rect_id_ack));
2517 break;
2518 }
2519 index = (clientCon->rect_id + band_index) % band_count;
2520 cap_rect.x1 = dirty_extents.x1;
2521 cap_rect.y1 = dirty_extents.y1 + index * band_height;
2522 cap_rect.x2 = dirty_extents.x2;
2523 cap_rect.y2 = RDPMIN(cap_rect.y1 + band_height,
2524 dirty_extents.y2);
2525 rdpCapRect(clientCon, &cap_rect, &id);
2526 band_index++;
2527 }
2528 if (band_index == band_count)
2529 {
2530 /* gone through all bands, nothing changed */
2531 rdpRegionDestroy(clientCon->dirtyRegion);
2532 clientCon->dirtyRegion = rdpRegionCreate(NullBox, 0);
2533 }
2534 }
2535 else
2536 {
2537 /* nothing changed in visible area */
2538 rdpRegionDestroy(clientCon->dirtyRegion);
2539 clientCon->dirtyRegion = rdpRegionCreate(NullBox, 0);
2540 }
2541 }
2542 else
2543 {
2544 monitor_index = 0;
2545 monitor_count = clientCon->dev->monitorCount;
2546 while (monitor_index < monitor_count)
2547 {
2548 if (clientCon->rect_id > clientCon->rect_id_ack)
2549 {
2550 LLOGLN(10, ("rdpDeferredUpdateCallback: reschedule rect_id %d "
2551 "rect_id_ack %d",
2552 clientCon->rect_id, clientCon->rect_id_ack));
2553 break;
2554 }
2555 index = (clientCon->rect_id + monitor_index) % monitor_count;
2556 cap_rect.x1 = clientCon->dev->minfo[index].left;
2557 cap_rect.y1 = clientCon->dev->minfo[index].top;
2558 cap_rect.x2 = clientCon->dev->minfo[index].right + 1;
2559 cap_rect.y2 = clientCon->dev->minfo[index].bottom + 1;
2560 rdpCapRect(clientCon, &cap_rect, &id);
2561 monitor_index++;
2562 }
2563 if (monitor_index == monitor_count)
2564 {
2565 /* gone through all monitors, nothing changed */
2566 rdpRegionDestroy(clientCon->dirtyRegion);
2567 clientCon->dirtyRegion = rdpRegionCreate(NullBox, 0);
2568 }
2569 }
2570 if (rdpRegionNotEmpty(clientCon->dirtyRegion))
2571 {
2572 rdpScheduleDeferredUpdate(clientCon);
2573 }
2574 return 0;
2575 }
2576
2577
2578 /******************************************************************************/
2579 #define MIN_MS_BETWEEN_FRAMES 40
2580 #define MIN_MS_TO_WAIT_FOR_MORE_UPDATES 4
2581 #define UPDATE_RETRY_TIMEOUT 200 // After this number of retries, give up and perform the capture anyway. This prevents an infinite loop.
2582 static void
rdpScheduleDeferredUpdate(rdpClientCon * clientCon)2583 rdpScheduleDeferredUpdate(rdpClientCon *clientCon)
2584 {
2585 uint32_t curTime;
2586 uint32_t msToWait;
2587 uint32_t minNextUpdateTime;
2588
2589 if (clientCon->updateRetries > UPDATE_RETRY_TIMEOUT) {
2590 LLOGLN(10, ("rdpScheduleDeferredUpdate: clientCon->updateRetries is %d"
2591 " and has exceeded the timeout of %d retries."
2592 " Overriding rect_id_ack to INT_MAX.", clientCon->updateRetries, UPDATE_RETRY_TIMEOUT));
2593 clientCon->rect_id_ack = INT_MAX;
2594 }
2595
2596 curTime = (uint32_t) GetTimeInMillis();
2597 /* use two separate delays in order to limit the update rate and wait a bit
2598 for more changes before sending an update. Always waiting the longer
2599 delay would introduce unnecessarily much latency. */
2600 msToWait = MIN_MS_TO_WAIT_FOR_MORE_UPDATES;
2601 minNextUpdateTime = clientCon->lastUpdateTime + MIN_MS_BETWEEN_FRAMES;
2602 /* the first check is to gracefully handle the infrequent case of
2603 the time wrapping around */
2604 if(clientCon->lastUpdateTime < curTime &&
2605 minNextUpdateTime > curTime + msToWait)
2606 {
2607 msToWait = minNextUpdateTime - curTime;
2608 }
2609
2610 clientCon->updateTimer = TimerSet(clientCon->updateTimer, 0,
2611 (CARD32) msToWait,
2612 rdpDeferredUpdateCallback,
2613 clientCon);
2614 clientCon->updateScheduled = TRUE;
2615 ++clientCon->updateRetries;
2616 }
2617
2618 /******************************************************************************/
2619 int
rdpClientConAddDirtyScreenReg(rdpPtr dev,rdpClientCon * clientCon,RegionPtr reg)2620 rdpClientConAddDirtyScreenReg(rdpPtr dev, rdpClientCon *clientCon,
2621 RegionPtr reg)
2622 {
2623 LLOGLN(10, ("rdpClientConAddDirtyScreenReg:"));
2624 rdpRegionUnion(clientCon->dirtyRegion, clientCon->dirtyRegion, reg);
2625 if (clientCon->updateScheduled == FALSE)
2626 {
2627 rdpScheduleDeferredUpdate(clientCon);
2628 }
2629 return 0;
2630 }
2631
2632 /******************************************************************************/
2633 int
rdpClientConAddDirtyScreenBox(rdpPtr dev,rdpClientCon * clientCon,BoxPtr box)2634 rdpClientConAddDirtyScreenBox(rdpPtr dev, rdpClientCon *clientCon,
2635 BoxPtr box)
2636 {
2637 RegionPtr reg;
2638
2639 reg = rdpRegionCreate(box, 0);
2640 rdpClientConAddDirtyScreenReg(dev, clientCon, reg);
2641 rdpRegionDestroy(reg);
2642 return 0;
2643 }
2644
2645 /******************************************************************************/
2646 int
rdpClientConAddDirtyScreen(rdpPtr dev,rdpClientCon * clientCon,int x,int y,int cx,int cy)2647 rdpClientConAddDirtyScreen(rdpPtr dev, rdpClientCon *clientCon,
2648 int x, int y, int cx, int cy)
2649 {
2650 BoxRec box;
2651
2652 box.x1 = x;
2653 box.y1 = y;
2654 box.x2 = box.x1 + cx;
2655 box.y2 = box.y1 + cy;
2656 rdpClientConAddDirtyScreenBox(dev, clientCon, &box);
2657 return 0;
2658 }
2659
2660 /******************************************************************************/
2661 void
rdpClientConGetScreenImageRect(rdpPtr dev,rdpClientCon * clientCon,struct image_data * id)2662 rdpClientConGetScreenImageRect(rdpPtr dev, rdpClientCon *clientCon,
2663 struct image_data *id)
2664 {
2665 id->width = dev->width;
2666 id->height = dev->height;
2667 id->bpp = clientCon->rdp_bpp;
2668 id->Bpp = clientCon->rdp_Bpp;
2669 id->lineBytes = dev->paddedWidthInBytes;
2670 id->pixels = dev->pfbMemory;
2671 id->shmem_pixels = clientCon->shmemptr;
2672 id->shmem_id = clientCon->shmemid;
2673 id->shmem_offset = 0;
2674 id->shmem_lineBytes = clientCon->shmem_lineBytes;
2675 }
2676
2677 /******************************************************************************/
2678 void
rdpClientConGetPixmapImageRect(rdpPtr dev,rdpClientCon * clientCon,PixmapPtr pPixmap,struct image_data * id)2679 rdpClientConGetPixmapImageRect(rdpPtr dev, rdpClientCon *clientCon,
2680 PixmapPtr pPixmap, struct image_data *id)
2681 {
2682 id->width = pPixmap->drawable.width;
2683 id->height = pPixmap->drawable.height;
2684 id->bpp = clientCon->rdp_bpp;
2685 id->Bpp = clientCon->rdp_Bpp;
2686 id->lineBytes = pPixmap->devKind;
2687 id->pixels = (uint8_t *)(pPixmap->devPrivate.ptr);
2688 id->shmem_pixels = 0;
2689 id->shmem_id = 0;
2690 id->shmem_offset = 0;
2691 id->shmem_lineBytes = 0;
2692 }
2693
2694 /******************************************************************************/
2695 void
rdpClientConSendArea(rdpPtr dev,rdpClientCon * clientCon,struct image_data * id,int x,int y,int w,int h)2696 rdpClientConSendArea(rdpPtr dev, rdpClientCon *clientCon,
2697 struct image_data *id, int x, int y, int w, int h)
2698 {
2699 struct image_data lid;
2700 BoxRec box;
2701 int ly;
2702 int size;
2703 const uint8_t *src;
2704 uint8_t *dst;
2705 struct stream *s;
2706
2707 LLOGLN(10, ("rdpClientConSendArea: id %p x %d y %d w %d h %d", id, x, y, w, h));
2708
2709 if (id == NULL)
2710 {
2711 rdpClientConGetScreenImageRect(dev, clientCon, &lid);
2712 id = &lid;
2713 }
2714
2715 if (x >= id->width)
2716 {
2717 return;
2718 }
2719
2720 if (y >= id->height)
2721 {
2722 return;
2723 }
2724
2725 if (x < 0)
2726 {
2727 w += x;
2728 x = 0;
2729 }
2730
2731 if (y < 0)
2732 {
2733 h += y;
2734 y = 0;
2735 }
2736
2737 if (w <= 0)
2738 {
2739 return;
2740 }
2741
2742 if (h <= 0)
2743 {
2744 return;
2745 }
2746
2747 if (x + w > id->width)
2748 {
2749 w = id->width - x;
2750 }
2751
2752 if (y + h > id->height)
2753 {
2754 h = id->height - y;
2755 }
2756
2757 if (clientCon->connected && clientCon->begin)
2758 {
2759 if (id->shmem_pixels != 0)
2760 {
2761 LLOGLN(10, ("rdpClientConSendArea: using shmem"));
2762 box.x1 = x;
2763 box.y1 = y;
2764 box.x2 = box.x1 + w;
2765 box.y2 = box.y1 + h;
2766 src = id->pixels;
2767 src += y * id->lineBytes;
2768 src += x * dev->Bpp;
2769 dst = id->shmem_pixels + id->shmem_offset;
2770 dst += y * id->shmem_lineBytes;
2771 dst += x * clientCon->rdp_Bpp;
2772 ly = y;
2773 while (ly < y + h)
2774 {
2775 rdpClientConConvertPixels(dev, clientCon, src, dst, w);
2776 src += id->lineBytes;
2777 dst += id->shmem_lineBytes;
2778 ly += 1;
2779 }
2780 size = 36;
2781 rdpClientConPreCheck(dev, clientCon, size);
2782 s = clientCon->out_s;
2783 out_uint16_le(s, 60);
2784 out_uint16_le(s, size);
2785 clientCon->count++;
2786 LLOGLN(10, ("rdpClientConSendArea: 2 x %d y %d w %d h %d", x, y, w, h));
2787 out_uint16_le(s, x);
2788 out_uint16_le(s, y);
2789 out_uint16_le(s, w);
2790 out_uint16_le(s, h);
2791 out_uint32_le(s, 0);
2792 clientCon->rect_id++;
2793 out_uint32_le(s, clientCon->rect_id);
2794 out_uint32_le(s, id->shmem_id);
2795 out_uint32_le(s, id->shmem_offset);
2796 out_uint16_le(s, id->width);
2797 out_uint16_le(s, id->height);
2798 out_uint16_le(s, x);
2799 out_uint16_le(s, y);
2800 rdpRegionUnionRect(clientCon->shmRegion, &box);
2801 return;
2802 }
2803 }
2804 }
2805
2806 /******************************************************************************/
2807 int
rdpClientConAddAllReg(rdpPtr dev,RegionPtr reg,DrawablePtr pDrawable)2808 rdpClientConAddAllReg(rdpPtr dev, RegionPtr reg, DrawablePtr pDrawable)
2809 {
2810 rdpClientCon *clientCon;
2811 Bool drw_is_vis;
2812
2813 drw_is_vis = XRDP_DRAWABLE_IS_VISIBLE(dev, pDrawable);
2814 if (!drw_is_vis)
2815 {
2816 return 0;
2817 }
2818 clientCon = dev->clientConHead;
2819 while (clientCon != NULL)
2820 {
2821 rdpClientConAddDirtyScreenReg(dev, clientCon, reg);
2822 clientCon = clientCon->next;
2823 }
2824 return 0;
2825 }
2826
2827 /******************************************************************************/
2828 int
rdpClientConAddAllBox(rdpPtr dev,BoxPtr box,DrawablePtr pDrawable)2829 rdpClientConAddAllBox(rdpPtr dev, BoxPtr box, DrawablePtr pDrawable)
2830 {
2831 rdpClientCon *clientCon;
2832 Bool drw_is_vis;
2833
2834 drw_is_vis = XRDP_DRAWABLE_IS_VISIBLE(dev, pDrawable);
2835 if (!drw_is_vis)
2836 {
2837 return 0;
2838 }
2839 clientCon = dev->clientConHead;
2840 while (clientCon != NULL)
2841 {
2842 rdpClientConAddDirtyScreenBox(dev, clientCon, box);
2843 clientCon = clientCon->next;
2844 }
2845 return 0;
2846 }
2847