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(&reg, &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, &reg);
1068     rdpRegionUninit(&reg);
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