3838#include "vnc_clip.h"
3939#include "rfb.h"
4040#include "log.h"
41+ #include "timers.h"
4142#include "trans.h"
4243#include "ssl_calls.h"
4344#include "string_calls.h"
5354 MSK_EXTENDED_DESKTOP_SIZE = (1 << 0 )
5455};
5556
57+ enum
58+ {
59+ /** Time to wait for a forwarded resize to complete */
60+ FORWARDED_RESIZE_TIMEOUT = 1500 /* milli-seconds */
61+ };
62+
5663/******************************************************************************/
5764int
5865lib_send_copy (struct vnc * v , struct stream * s )
@@ -309,7 +316,8 @@ send_set_desktop_size(struct vnc *v, const struct vnc_screen_layout *layout)
309316 out_uint32_be (s , layout -> s [i ].flags );
310317 }
311318 s_mark_end (s );
312- LOG (LOG_LEVEL_DEBUG , "VNC Sending SetDesktopSize" );
319+ LOG (LOG_LEVEL_DEBUG , "VNC_RESIZE: Sending SetDesktopSize %dx%d" ,
320+ layout -> total_width , layout -> total_height );
313321 error = lib_send_copy (v , s );
314322 free_stream (s );
315323
@@ -954,7 +962,7 @@ skip_encoding(struct vnc *v, int x, int y, int cx, int cy,
954962 {
955963 struct vnc_screen_layout layout = {0 };
956964 LOG (LOG_LEVEL_DEBUG ,
957- "Skipping RFB_ENC_EXTENDED_DESKTOP_SIZE encoding "
965+ "VNC_RESIZE: Skipping RFB_ENC_EXTENDED_DESKTOP_SIZE encoding "
958966 "x=%d, y=%d geom=%dx%d" ,
959967 x , y , cx , cy );
960968 error = read_extended_desktop_size_rect (v , & layout );
@@ -1033,7 +1041,7 @@ find_matching_extended_rect(struct vnc *v,
10331041 match (x , y , cx , cy ))
10341042 {
10351043 LOG (LOG_LEVEL_DEBUG ,
1036- "VNC matched ExtendedDesktopSize rectangle "
1044+ "VNC_RESIZE: VNC matched ExtendedDesktopSize rectangle "
10371045 "x=%d, y=%d geom=%dx%d" ,
10381046 x , y , cx , cy );
10391047 found = 1 ;
@@ -1149,6 +1157,18 @@ rect_is_reply_to_us(int x, int y, int cx, int cy)
11491157 return (x == 1 );
11501158}
11511159
1160+ /**************************************************************************/ /**
1161+ * Tests if extended desktop size rect is a general change.
1162+ *
1163+ * This happens when we are looking for a layout change that the
1164+ * VNC server has reported as forwarded to the real desktop.
1165+ */
1166+ static int
1167+ rect_is_general_change (int x , int y , int cx , int cy )
1168+ {
1169+ return (x == 0 );
1170+ }
1171+
11521172/**************************************************************************/ /**
11531173 * Handles the first framebuffer update from the server
11541174 *
@@ -1249,45 +1269,136 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
12491269 {
12501270 if (layout .count > 0 )
12511271 {
1252- if (response_code == 0 )
1272+ if (response_code == RFB_EDS_REQUEST_FORWARDED )
12531273 {
1254- LOG (LOG_LEVEL_DEBUG , "VNC server successfully resized" );
1255- log_screen_layout (LOG_LEVEL_INFO , "NewLayout" , & layout );
1256- v -> server_layout = layout ;
1274+ LOG (LOG_LEVEL_DEBUG , "VNC_RESIZE: VNC server resize forwarded" );
1275+ log_screen_layout (LOG_LEVEL_INFO , "ForwardedLayout" , & layout );
1276+ v -> forward_timer =
1277+ timers_oneshot_init (FORWARDED_RESIZE_TIMEOUT );
1278+ v -> forwarded_layout = layout ;
12571279 }
12581280 else
12591281 {
1260- LOG (LOG_LEVEL_WARNING ,
1261- "VNC server resize failed - error code %d [%s]" ,
1262- response_code ,
1263- rfb_get_eds_status_msg (response_code ));
1264- // This is awkward. The client has asked for a specific size
1265- // which we can't support.
1266- //
1267- // Currently we handle this by queueing a resize to our
1268- // supported size, and continuing with the resize state
1269- // machine in xrdp_mm.c
1270- LOG (LOG_LEVEL_WARNING , "Resizing client to server" );
1271- error = resize_client_to_server (v , 0 );
1282+ // The resize has either succeeded or failed
1283+ if (response_code == RFB_EDS_NO_ERROR )
1284+ {
1285+ LOG (LOG_LEVEL_DEBUG , "VNC_RESIZE:"
1286+ " VNC server successfully resized" );
1287+ log_screen_layout (LOG_LEVEL_INFO , "NewLayout" , & layout );
1288+ v -> server_layout = layout ;
1289+ }
1290+ else
1291+ {
1292+ LOG (LOG_LEVEL_WARNING ,
1293+ "VNC server resize failed - error code %d [%s]" ,
1294+ response_code ,
1295+ rfb_get_eds_status_msg (response_code ));
1296+ // This is awkward. The client has asked for a
1297+ // specific size which we can't support.
1298+ //
1299+ // Currently we handle this by queueing a resize
1300+ // to our supported size, and continuing with the
1301+ // resize state machine in xrdp_mm.c
1302+ LOG (LOG_LEVEL_WARNING , "Resizing client to server" );
1303+ error = resize_client_to_server (v , 0 );
1304+ }
1305+
1306+ v -> resize_status = VRS_DONE ;
1307+ if (error == 0 )
1308+ {
1309+ // If this resize was requested by the client mid-session
1310+ // (dynamic resize), we need to tell xrdp_mm that
1311+ // it's OK to continue with the resize state machine.
1312+ error = v -> server_monitor_resize_done (v );
1313+ if (error == 0 )
1314+ {
1315+ error = send_update_request_for_resize_status (v );
1316+ }
1317+ }
12721318 }
1319+ }
1320+ }
12731321
1274- if (error == 0 )
1322+
1323+ return error ;
1324+ }
1325+
1326+ /**************************************************************************/ /**
1327+ * Looks for the forwarded screen layout in a framebuffer update request
1328+ *
1329+ * Looks for an ExtendedDesktopSize rectangle following a notification
1330+ * from the VNC server that the request has been forwarded to the real
1331+ * desktop. See rfbproto/pfbproto#32 for more info.
1332+ *
1333+ * @param v VNC object
1334+ * @return != 0 for error
1335+ */
1336+ static int
1337+ lib_framebuffer_look_for_forwarded_layout (struct vnc * v )
1338+ {
1339+ int error ;
1340+ struct vnc_screen_layout layout = {0 };
1341+ int x = 0 ;
1342+ int y = 0 ;
1343+
1344+ error = find_matching_extended_rect (v ,
1345+ rect_is_general_change ,
1346+ & x ,
1347+ & y ,
1348+ & layout );
1349+ if (error == 0 )
1350+ {
1351+ if (layout .count > 0 )
1352+ {
1353+ if (vnc_screen_layouts_equal (& layout , & v -> forwarded_layout ))
12751354 {
1276- // If this resize was requested by the client mid-session
1277- // (dynamic resize), we need to tell xrdp_mm that
1278- // it's OK to continue with the resize state machine.
1355+ LOG (LOG_LEVEL_DEBUG ,
1356+ "VNC_RESIZE: VNC server forwarded resize complete" );
1357+ free (v -> forward_timer );
1358+ v -> forward_timer = NULL ;
1359+ v -> server_layout = layout ;
12791360 error = v -> server_monitor_resize_done (v );
1361+ v -> resize_status = VRS_DONE ;
12801362 }
1281- v -> resize_status = VRS_DONE ;
1363+ else
1364+ {
1365+ LOG (LOG_LEVEL_DEBUG ,
1366+ "VNC_RESIZE: Ignored ExtendedDesktopSize %dx%d x=%d y=%d" ,
1367+ layout .total_width , layout .total_height , x , y );
1368+ // Delay for a little before we send another request for
1369+ // the size
1370+ g_sleep (100 );
1371+ }
1372+
1373+ error = send_update_request_for_resize_status (v );
12821374 }
12831375 }
12841376
1285- if (error == 0 )
1377+ return error ;
1378+ }
1379+
1380+ /******************************************************************************/
1381+ /*
1382+ * The VNC server has not actioned a forwarded resize request
1383+ */
1384+ static int
1385+ forward_timer_expired (struct vnc * v )
1386+ {
1387+ LOG (LOG_LEVEL_WARNING , "VNC server forwarded resize timed out" );
1388+ LOG (LOG_LEVEL_DEBUG ,
1389+ "VNC_RESIZE: VNC server forwarded resize timed out" );
1390+ free (v -> forward_timer );
1391+ v -> forward_timer = NULL ;
1392+ v -> resize_status = VRS_DONE ;
1393+
1394+ int rv = v -> server_monitor_resize_done (v );
1395+ if (rv == 0 )
12861396 {
1287- error = send_update_request_for_resize_status (v );
1397+ LOG (LOG_LEVEL_WARNING , "Resizing client to server" );
1398+ rv = resize_client_to_server (v , 0 );
12881399 }
12891400
1290- return error ;
1401+ return rv ;
12911402}
12921403
12931404/******************************************************************************/
@@ -1433,6 +1544,9 @@ lib_framebuffer_update(struct vnc *v)
14331544 layout .total_height = cy ;
14341545 error = read_extended_desktop_size_rect (v , & layout );
14351546 /* If this is a reply to a request from us, x == 1 */
1547+ LOG (LOG_LEVEL_DEBUG ,
1548+ "VNC_RESIZE: Read ExtendedDesktopSize %dx%d x=%d y=%d" ,
1549+ layout .total_width , layout .total_height , x , y );
14361550 if (error == 0 && x != 1 )
14371551 {
14381552 if (!vnc_screen_layouts_equal (& v -> server_layout , & layout ))
@@ -1574,7 +1688,14 @@ lib_mod_process_message(struct vnc *v, struct stream *s)
15741688 break ;
15751689
15761690 case VRS_WAITING_FOR_RESIZE_CONFIRM :
1577- error = lib_framebuffer_waiting_for_resize_confirm (v );
1691+ if (v -> forward_timer != NULL )
1692+ {
1693+ error = lib_framebuffer_look_for_forwarded_layout (v );
1694+ }
1695+ else
1696+ {
1697+ error = lib_framebuffer_waiting_for_resize_confirm (v );
1698+ }
15781699 break ;
15791700
15801701 default :
@@ -2533,6 +2654,10 @@ lib_mod_get_wait_objs(struct vnc *v, tbus *read_objs, int *rcount,
25332654 trans_get_wait_objs_rw (v -> trans , read_objs , rcount ,
25342655 write_objs , wcount , timeout );
25352656 }
2657+
2658+ // Update timeout with any active timers
2659+ unsigned int now = g_get_elapsed_ms ();
2660+ timers_oneshot_update_poll (v -> forward_timer , now , timeout );
25362661 }
25372662
25382663 return 0 ;
@@ -2550,13 +2675,22 @@ lib_mod_check_wait_objs(struct vnc *v)
25502675 {
25512676 if (v -> trans != 0 )
25522677 {
2553- rv = trans_check_wait_objs (v -> trans );
2554- if (rv != 0 )
2678+ if ((rv = trans_check_wait_objs (v -> trans )) != 0 )
25552679 {
25562680 LOG (LOG_LEVEL_ERROR , "VNC server closed connection" );
25572681 }
2682+ else
2683+ {
2684+ // Check timers
2685+ unsigned int now = g_get_elapsed_ms ();
2686+ if (timers_oneshot_get_remaining (v -> forward_timer , now ) == 0 )
2687+ {
2688+ rv = forward_timer_expired (v );
2689+ }
2690+ }
25582691 }
25592692 }
2693+
25602694 return rv ;
25612695}
25622696
0 commit comments