Compare commits
4 Commits
devel
...
extended-v
Author | SHA1 | Date | |
---|---|---|---|
|
8945b49e61 | ||
|
7d305b0085 | ||
|
3293370faf | ||
|
79c8ed8579 |
@ -63,6 +63,10 @@ scp_session_set_type(struct SCP_SESSION *s, tui8 type)
|
|||||||
s->type = SCP_SESSION_TYPE_XVNC;
|
s->type = SCP_SESSION_TYPE_XVNC;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SCP_SESSION_TYPE_RESIZABLE_XVNC:
|
||||||
|
s->type = SCP_SESSION_TYPE_RESIZABLE_XVNC;
|
||||||
|
break;
|
||||||
|
|
||||||
case SCP_SESSION_TYPE_XRDP:
|
case SCP_SESSION_TYPE_XRDP:
|
||||||
s->type = SCP_SESSION_TYPE_XRDP;
|
s->type = SCP_SESSION_TYPE_XRDP;
|
||||||
break;
|
break;
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
* XRDP sends this command to let sesman verify if the user is allowed
|
* XRDP sends this command to let sesman verify if the user is allowed
|
||||||
* to use the gateway */
|
* to use the gateway */
|
||||||
#define SCP_GW_AUTHENTICATION 0x04
|
#define SCP_GW_AUTHENTICATION 0x04
|
||||||
|
#define SCP_SESSION_TYPE_RESIZABLE_XVNC 0x05
|
||||||
|
|
||||||
#define SCP_ADDRESS_TYPE_IPV4 0x00
|
#define SCP_ADDRESS_TYPE_IPV4 0x00
|
||||||
#define SCP_ADDRESS_TYPE_IPV6 0x01
|
#define SCP_ADDRESS_TYPE_IPV6 0x01
|
||||||
|
@ -56,6 +56,10 @@ scp_v0c_connect(struct SCP_CONNECTION *c, struct SCP_SESSION *s)
|
|||||||
{
|
{
|
||||||
out_uint16_be(c->out_s, 0);
|
out_uint16_be(c->out_s, 0);
|
||||||
}
|
}
|
||||||
|
else if (s->type == SCP_SESSION_TYPE_RESIZABLE_XVNC)
|
||||||
|
{
|
||||||
|
out_uint16_be(c->out_s, 1);
|
||||||
|
}
|
||||||
else if (s->type == SCP_SESSION_TYPE_XRDP)
|
else if (s->type == SCP_SESSION_TYPE_XRDP)
|
||||||
{
|
{
|
||||||
out_uint16_be(c->out_s, 10);
|
out_uint16_be(c->out_s, 10);
|
||||||
@ -199,7 +203,7 @@ scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
|
|||||||
|
|
||||||
in_uint16_be(c->in_s, code);
|
in_uint16_be(c->in_s, code);
|
||||||
|
|
||||||
if (code == 0 || code == 10 || code == 20)
|
if (code == 0 || code == 1 || code == 10 || code == 20)
|
||||||
{
|
{
|
||||||
session = scp_session_create();
|
session = scp_session_create();
|
||||||
|
|
||||||
@ -215,6 +219,10 @@ scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
|
|||||||
{
|
{
|
||||||
scp_session_set_type(session, SCP_SESSION_TYPE_XVNC);
|
scp_session_set_type(session, SCP_SESSION_TYPE_XVNC);
|
||||||
}
|
}
|
||||||
|
else if (code == 1)
|
||||||
|
{
|
||||||
|
scp_session_set_type(session, SCP_SESSION_TYPE_RESIZABLE_XVNC);
|
||||||
|
}
|
||||||
else if (code == 10)
|
else if (code == 10)
|
||||||
{
|
{
|
||||||
scp_session_set_type(session, SCP_SESSION_TYPE_XRDP);
|
scp_session_set_type(session, SCP_SESSION_TYPE_XRDP);
|
||||||
|
@ -120,7 +120,8 @@ scp_v0_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s)
|
|||||||
"username %s", s->username);
|
"username %s", s->username);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SCP_SESSION_TYPE_XVNC == s->type)
|
if (SCP_SESSION_TYPE_XVNC == s->type ||
|
||||||
|
SCP_SESSION_TYPE_RESIZABLE_XVNC == s->type)
|
||||||
{
|
{
|
||||||
log_message( LOG_LEVEL_INFO, "starting Xvnc session...");
|
log_message( LOG_LEVEL_INFO, "starting Xvnc session...");
|
||||||
display = session_start(data, SESMAN_SESSION_TYPE_XVNC, c, s);
|
display = session_start(data, SESMAN_SESSION_TYPE_XVNC, c, s);
|
||||||
|
@ -124,7 +124,8 @@ scp_v1_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s)
|
|||||||
log_message(LOG_LEVEL_INFO, "++ created session (access granted): username %s", s->username);
|
log_message(LOG_LEVEL_INFO, "++ created session (access granted): username %s", s->username);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SCP_SESSION_TYPE_XVNC == s->type)
|
if (SCP_SESSION_TYPE_XVNC == s->type ||
|
||||||
|
SCP_SESSION_TYPE_RESIZABLE_XVNC == s->type)
|
||||||
{
|
{
|
||||||
log_message(LOG_LEVEL_INFO, "starting Xvnc session...");
|
log_message(LOG_LEVEL_INFO, "starting Xvnc session...");
|
||||||
display = session_start(data, SESMAN_SESSION_TYPE_XVNC, c, s);
|
display = session_start(data, SESMAN_SESSION_TYPE_XVNC, c, s);
|
||||||
|
@ -105,10 +105,13 @@ session_get_bydata(const char *name, int width, int height, int bpp, int type,
|
|||||||
{
|
{
|
||||||
case SCP_SESSION_TYPE_XVNC: /* 0 */
|
case SCP_SESSION_TYPE_XVNC: /* 0 */
|
||||||
type = SESMAN_SESSION_TYPE_XVNC; /* 2 */
|
type = SESMAN_SESSION_TYPE_XVNC; /* 2 */
|
||||||
/* Xvnc cannot resize */
|
/* standard Xvnc can never resize */
|
||||||
policy = (enum SESMAN_CFG_SESS_POLICY)
|
policy = (enum SESMAN_CFG_SESS_POLICY)
|
||||||
(policy | SESMAN_CFG_SESS_POLICY_D);
|
(policy | SESMAN_CFG_SESS_POLICY_D);
|
||||||
break;
|
break;
|
||||||
|
case SCP_SESSION_TYPE_RESIZABLE_XVNC:
|
||||||
|
type = SESMAN_SESSION_TYPE_XVNC;
|
||||||
|
break;
|
||||||
case SCP_SESSION_TYPE_XRDP: /* 1 */
|
case SCP_SESSION_TYPE_XRDP: /* 1 */
|
||||||
type = SESMAN_SESSION_TYPE_XRDP; /* 1 */
|
type = SESMAN_SESSION_TYPE_XRDP; /* 1 */
|
||||||
break;
|
break;
|
||||||
|
@ -31,6 +31,10 @@
|
|||||||
#include "sesman.h"
|
#include "sesman.h"
|
||||||
#include "tcp.h"
|
#include "tcp.h"
|
||||||
|
|
||||||
|
#if !defined(PACKAGE_VERSION)
|
||||||
|
#define PACKAGE_VERSION "???"
|
||||||
|
#endif
|
||||||
|
|
||||||
struct config_sesman g_cfg; /* config.h */
|
struct config_sesman g_cfg; /* config.h */
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -61,10 +65,14 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
if (argc == 1)
|
if (argc == 1)
|
||||||
{
|
{
|
||||||
g_printf("xrdp session starter v0.1\n");
|
g_printf("xrdp session starter v" PACKAGE_VERSION "\n");
|
||||||
g_printf("\nusage:\n");
|
g_printf("\nusage:\n");
|
||||||
g_printf("sesrun <server> <username> <password> <width> <height> <bpp> <session_cod>\n");
|
g_printf("sesrun <server> <username> <password> <width> <height> <bpp> <session_code>\n");
|
||||||
g_printf("session code 0 for Xvnc, 10 for X11RDP, 20 for Xorg\n");
|
g_printf("session code:-\n");
|
||||||
|
g_printf(" - 0 for fixed Xvnc\n");
|
||||||
|
g_printf(" - 1 for resizeable Xvnc\n");
|
||||||
|
g_printf(" - 10 for X11RDP\n");
|
||||||
|
g_printf(" - 20 for Xorg\n");
|
||||||
}
|
}
|
||||||
else if (argc == 8)
|
else if (argc == 8)
|
||||||
{
|
{
|
||||||
|
488
vnc/vnc.c
488
vnc/vnc.c
@ -16,6 +16,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
* libvnc
|
* libvnc
|
||||||
|
*
|
||||||
|
* The message definitions used in this source file can be found mostly
|
||||||
|
* in RFC6143 - "The Remote Framebuffer Protocol".
|
||||||
|
*
|
||||||
|
* The ExtendedDesktopSize encoding is reserved in RFC6143, but not
|
||||||
|
* documented there. It is documented by the RFB protocol community
|
||||||
|
* wiki currently held at https://github.com/rfbproto/rfbroto. This is
|
||||||
|
* referred to below as the "RFB community wiki"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(HAVE_CONFIG_H)
|
#if defined(HAVE_CONFIG_H)
|
||||||
@ -26,6 +34,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "trans.h"
|
#include "trans.h"
|
||||||
#include "ssl_calls.h"
|
#include "ssl_calls.h"
|
||||||
|
#include "xrdp_client_info.h"
|
||||||
|
|
||||||
#define LLOG_LEVEL 1
|
#define LLOG_LEVEL 1
|
||||||
#define LLOGLN(_level, _args) \
|
#define LLOGLN(_level, _args) \
|
||||||
@ -41,6 +50,13 @@
|
|||||||
|
|
||||||
#define AS_LOG_MESSAGE log_message
|
#define AS_LOG_MESSAGE log_message
|
||||||
|
|
||||||
|
/* Encodings and pseudo-encodings from RFC6143 */
|
||||||
|
#define ENC_RAW 0
|
||||||
|
#define ENC_COPY_RECT 1
|
||||||
|
#define ENC_CURSOR (unsigned int)-239
|
||||||
|
#define ENC_DESKTOP_SIZE (unsigned int)-223
|
||||||
|
#define ENC_EXTENDED_DESKTOP_SIZE (unsigned int)-308
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lib_mod_process_message(struct vnc *v, struct stream *s);
|
lib_mod_process_message(struct vnc *v, struct stream *s);
|
||||||
|
|
||||||
@ -256,6 +272,356 @@ lib_process_channel_data(struct vnc *v, int chanid, int flags, int size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
static void
|
||||||
|
log_debug_screen_layout(const char *source,
|
||||||
|
const struct vnc_screen_layout *layout)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
char text[256];
|
||||||
|
size_t pos;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
res = g_snprintf(text, sizeof(text) - pos,
|
||||||
|
"Layout from %s (#screens=%d) :",
|
||||||
|
source, layout->count);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (res > 0 && (size_t)res < sizeof(text) - pos && i < layout->count)
|
||||||
|
{
|
||||||
|
pos += res;
|
||||||
|
res = g_snprintf(&text[pos], sizeof(text) - pos,
|
||||||
|
" %d:(%dx%d+%d+%d)",
|
||||||
|
layout->s[i].id,
|
||||||
|
layout->s[i].width, layout->s[i].height,
|
||||||
|
layout->s[i].x, layout->s[i].y);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "%s", text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Compares two vnc_screen structures, returning a value which can
|
||||||
|
* also be used for sorting on id
|
||||||
|
*/
|
||||||
|
static int cmp_vnc_screen(const struct vnc_screen *a,
|
||||||
|
const struct vnc_screen *b)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
if (a->id != b->id)
|
||||||
|
{
|
||||||
|
result = a->id - b->id;
|
||||||
|
}
|
||||||
|
else if (a->x != b->x)
|
||||||
|
{
|
||||||
|
result = a->x - b->x;
|
||||||
|
}
|
||||||
|
else if (a->y != b->y)
|
||||||
|
{
|
||||||
|
result = a->y - b->y;
|
||||||
|
}
|
||||||
|
else if (a->width != b->width)
|
||||||
|
{
|
||||||
|
result = a->width - b->width;
|
||||||
|
}
|
||||||
|
else if (a->height != b->height)
|
||||||
|
{
|
||||||
|
result = a->height - b->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Compares two vnc_screen_layout structures
|
||||||
|
*
|
||||||
|
* Result can only be used for equality testing
|
||||||
|
*/
|
||||||
|
static int cmp_vnc_screen_layout(const struct vnc_screen_layout *a,
|
||||||
|
const struct vnc_screen_layout *b)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
int result = b->count - a->count;
|
||||||
|
|
||||||
|
for (i = 0 ; result == 0 && i < a->count ; ++i)
|
||||||
|
{
|
||||||
|
result = cmp_vnc_screen(&a->s[i], &b->s[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Reads an extended desktop size rectangle from the VNC server
|
||||||
|
*
|
||||||
|
* Returned structure is in increasing ID order, rather than order on-the-wire
|
||||||
|
*
|
||||||
|
* On a successful return, layout->s has been allocated, and must be
|
||||||
|
* freed after use.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
read_extended_desktop_size_rect(struct vnc *v,
|
||||||
|
struct vnc_screen_layout *layout)
|
||||||
|
{
|
||||||
|
struct stream *s;
|
||||||
|
int error;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
layout->count = 0;
|
||||||
|
|
||||||
|
make_stream(s);
|
||||||
|
init_stream(s, 8192);
|
||||||
|
|
||||||
|
/* Read in the current screen config */
|
||||||
|
error = trans_force_read_s(v->trans, s, 4);
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
/* Get the number of screens */
|
||||||
|
in_uint8(s, layout->count);
|
||||||
|
in_uint8s(s, 3);
|
||||||
|
|
||||||
|
error = trans_force_read_s(v->trans, s, 16 * layout->count);
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
layout->s = g_new(struct vnc_screen, layout->count);
|
||||||
|
if (layout->s == NULL)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR,
|
||||||
|
"VNC : Can't alloc for %d screens", layout->count);
|
||||||
|
layout->count = 0;
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0 ; i < layout->count ; ++i)
|
||||||
|
{
|
||||||
|
in_uint32_be(s, layout->s[i].id);
|
||||||
|
in_uint16_be(s, layout->s[i].x);
|
||||||
|
in_uint16_be(s, layout->s[i].y);
|
||||||
|
in_uint16_be(s, layout->s[i].width);
|
||||||
|
in_uint16_be(s, layout->s[i].height);
|
||||||
|
in_uint32_be(s, layout->s[i].flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort monitors in increasing ID order */
|
||||||
|
qsort(layout->s, layout->count, sizeof(layout->s[0]),
|
||||||
|
(int (*)(const void *, const void *))cmp_vnc_screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_stream(s);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Check to see if a SetDesktopSize message should be sent, based on the
|
||||||
|
* current Xvnc geometry and screen layout
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
set_desktop_size_is_needed(struct vnc *v, int vnc_width, int vnc_height,
|
||||||
|
const struct vnc_screen_layout *vnc_layout)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (v->mod_width != vnc_width || v->mod_height != vnc_height)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "VNC SetDesktopSize needed "
|
||||||
|
"for size change from (%d,%d) to (%d,%d)",
|
||||||
|
vnc_width, vnc_height, v->mod_width, v->mod_height);
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
else if (cmp_vnc_screen_layout(vnc_layout, &v->screen_layout) != 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "VNC SetDesktopSize needed "
|
||||||
|
"for changed screen layouts");
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "VNC SetDesktopSize not needed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Send a SetDesktopSize message based on the initial RDP parameters
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
send_set_desktop_size_msg(struct vnc *v)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
struct stream *s;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
make_stream(s);
|
||||||
|
init_stream(s, 8192);
|
||||||
|
out_uint8(s, 251);
|
||||||
|
out_uint8(s, 0);
|
||||||
|
out_uint16_be(s, v->mod_width);
|
||||||
|
out_uint16_be(s, v->mod_height);
|
||||||
|
|
||||||
|
out_uint8(s, v->screen_layout.count);
|
||||||
|
out_uint8(s, 0);
|
||||||
|
for (i = 0 ; i < v->screen_layout.count ; ++i)
|
||||||
|
{
|
||||||
|
out_uint32_be(s, v->screen_layout.s[i].id);
|
||||||
|
out_uint16_be(s, v->screen_layout.s[i].x);
|
||||||
|
out_uint16_be(s, v->screen_layout.s[i].y);
|
||||||
|
out_uint16_be(s, v->screen_layout.s[i].width);
|
||||||
|
out_uint16_be(s, v->screen_layout.s[i].height);
|
||||||
|
out_uint32_be(s, v->screen_layout.s[i].flags);
|
||||||
|
}
|
||||||
|
s_mark_end(s);
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "VNC Sending SetDesktopSize");
|
||||||
|
error = lib_send_copy(v, s);
|
||||||
|
free_stream(s);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Check to resize the attached client
|
||||||
|
*
|
||||||
|
* The resizing of multi-screen layouts isn't supported. If
|
||||||
|
* we end up in this situation we currently throw an error, resulting in
|
||||||
|
* a disconnect.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
check_to_resize_client(struct vnc *v, int width, int height,
|
||||||
|
const struct vnc_screen_layout *layout)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if (width != v->mod_width || height != v->mod_height ||
|
||||||
|
cmp_vnc_screen_layout(&v->screen_layout, layout) != 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* we don't have the capability to cope with a rearrangement
|
||||||
|
* of a multi-screen layout.
|
||||||
|
*/
|
||||||
|
if (layout->count != 1 || v->screen_layout.count != 1)
|
||||||
|
{
|
||||||
|
char text[256];
|
||||||
|
g_sprintf(text, "VNC Resize to %d screen(s) from %d screen(s) "
|
||||||
|
"not implemented",
|
||||||
|
v->screen_layout.count, layout->count);
|
||||||
|
v->server_msg(v, text, 0);
|
||||||
|
|
||||||
|
/* Dump some useful info, in case we get here when we don't
|
||||||
|
* need to */
|
||||||
|
log_debug_screen_layout("OldLayout", layout);
|
||||||
|
log_debug_screen_layout("NewLayout", layout);
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v->mod_width = width;
|
||||||
|
v->mod_height = height;
|
||||||
|
v->screen_layout.s[0] = layout->s[0];
|
||||||
|
error = v->server_reset(v, width, height, v->mod_bpp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Process an ExtendedDesktopSize message
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
process_extended_desktop_size(struct vnc *v, int x, int y, int cx, int cy,
|
||||||
|
const struct vnc_screen_layout *layout)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
switch (x)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
/* Spec says to treat unknown values as a zero */
|
||||||
|
if (x != 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR,
|
||||||
|
"VNC got ExtendedDesktopSize rectangle type %d", x);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v->first_framebuffer_update)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This is a response to our first framebuffer update
|
||||||
|
* request. At this point, we want to impose our will
|
||||||
|
* on the client. After that, the server may request
|
||||||
|
* size changes of its own.
|
||||||
|
*/
|
||||||
|
log_message(LOG_LEVEL_DEBUG,
|
||||||
|
"VNC got first ExtendedDesktopSize rectangle "
|
||||||
|
"x=%d, y=%d, cx=%d, cy=%d", x, y, cx, cy);
|
||||||
|
log_debug_screen_layout("Xvnc", layout);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we've only got one screen, and the other side has
|
||||||
|
* only got one screen, we will preserve their screen
|
||||||
|
* ID and any flags. This may prevent us sending
|
||||||
|
* an unwanted SetDesktopSize message if the screen
|
||||||
|
* dimensions are a match. We can't do this with more than
|
||||||
|
* one screen, as we have no way to map different IDs
|
||||||
|
*/
|
||||||
|
if (layout->count == 1 && v->screen_layout.count == 1)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "VNC "
|
||||||
|
"setting screen id to %d from server",
|
||||||
|
layout->s[0].id);
|
||||||
|
|
||||||
|
v->screen_layout.s[0].id = layout->s[0].id;
|
||||||
|
v->screen_layout.s[0].flags = layout->s[0].flags;
|
||||||
|
}
|
||||||
|
if (set_desktop_size_is_needed(v, cx, cy, layout))
|
||||||
|
{
|
||||||
|
error = send_set_desktop_size_msg(v);
|
||||||
|
v->set_desktop_size_in_progress = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (v->set_desktop_size_in_progress)
|
||||||
|
{
|
||||||
|
/* Ignore this, until the X server has responded */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Could be a response to another framebuffer update request,
|
||||||
|
* or a server-side change (i.e. with xrandr)
|
||||||
|
*/
|
||||||
|
error = check_to_resize_client(v, cx, cy, layout);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: /* Response to a SetDesktopSize message from us */
|
||||||
|
v->set_desktop_size_in_progress = 0;
|
||||||
|
if (y == 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_DEBUG,
|
||||||
|
"VNC SetDesktopSize was successful");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR,
|
||||||
|
"VNC SetDesktopSize failed and returned %d", y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
/*
|
||||||
|
* Another client has resized or re-arranged the screen
|
||||||
|
*/
|
||||||
|
error = check_to_resize_client(v, cx, cy, layout);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
int
|
int
|
||||||
lib_mod_event(struct vnc *v, int msg, long param1, long param2,
|
lib_mod_event(struct vnc *v, int msg, long param1, long param2,
|
||||||
long param3, long param4)
|
long param3, long param4)
|
||||||
@ -385,7 +751,7 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2,
|
|||||||
/* FramebufferUpdateRequest */
|
/* FramebufferUpdateRequest */
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
out_uint8(s, 3);
|
out_uint8(s, 3);
|
||||||
out_uint8(s, 0);
|
out_uint8(s, 0); /* incremental == 0 : Full contents */
|
||||||
x = (param1 >> 16) & 0xffff;
|
x = (param1 >> 16) & 0xffff;
|
||||||
out_uint16_be(s, x);
|
out_uint16_be(s, x);
|
||||||
y = param1 & 0xffff;
|
y = param1 & 0xffff;
|
||||||
@ -615,6 +981,8 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
int need_size;
|
int need_size;
|
||||||
struct stream *s;
|
struct stream *s;
|
||||||
struct stream *pixel_s;
|
struct stream *pixel_s;
|
||||||
|
int extended_desktop_size_msg_received = 0;
|
||||||
|
struct vnc_screen_layout layout = { 0 };
|
||||||
|
|
||||||
num_recs = 0;
|
num_recs = 0;
|
||||||
Bpp = (v->mod_bpp + 7) / 8;
|
Bpp = (v->mod_bpp + 7) / 8;
|
||||||
@ -655,7 +1023,7 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
in_uint16_be(s, cy);
|
in_uint16_be(s, cy);
|
||||||
in_uint32_be(s, encoding);
|
in_uint32_be(s, encoding);
|
||||||
|
|
||||||
if (encoding == 0) /* raw */
|
if (encoding == ENC_RAW)
|
||||||
{
|
{
|
||||||
need_size = cx * cy * Bpp;
|
need_size = cx * cy * Bpp;
|
||||||
init_stream(pixel_s, need_size);
|
init_stream(pixel_s, need_size);
|
||||||
@ -666,7 +1034,7 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
error = v->server_paint_rect(v, x, y, cx, cy, pixel_s->data, cx, cy, 0, 0);
|
error = v->server_paint_rect(v, x, y, cx, cy, pixel_s->data, cx, cy, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (encoding == 1) /* copy rect */
|
else if (encoding == ENC_COPY_RECT)
|
||||||
{
|
{
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
error = trans_force_read_s(v->trans, s, 4);
|
error = trans_force_read_s(v->trans, s, 4);
|
||||||
@ -678,7 +1046,7 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
error = v->server_screen_blt(v, x, y, cx, cy, srcx, srcy);
|
error = v->server_screen_blt(v, x, y, cx, cy, srcx, srcy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (encoding == 0xffffff11) /* cursor */
|
else if (encoding == ENC_CURSOR)
|
||||||
{
|
{
|
||||||
g_memset(cursor_data, 0, 32 * (32 * 3));
|
g_memset(cursor_data, 0, 32 * (32 * 3));
|
||||||
g_memset(cursor_mask, 0, 32 * (32 / 8));
|
g_memset(cursor_mask, 0, 32 * (32 / 8));
|
||||||
@ -723,12 +1091,24 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
error = v->server_set_cursor(v, x, y, cursor_data, cursor_mask);
|
error = v->server_set_cursor(v, x, y, cursor_data, cursor_mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (encoding == 0xffffff21) /* desktop size */
|
else if (encoding == ENC_DESKTOP_SIZE)
|
||||||
{
|
{
|
||||||
|
/* Only received for non-resizeable desktops */
|
||||||
v->mod_width = cx;
|
v->mod_width = cx;
|
||||||
v->mod_height = cy;
|
v->mod_height = cy;
|
||||||
error = v->server_reset(v, cx, cy, v->mod_bpp);
|
error = v->server_reset(v, cx, cy, v->mod_bpp);
|
||||||
}
|
}
|
||||||
|
else if (encoding == ENC_EXTENDED_DESKTOP_SIZE)
|
||||||
|
{
|
||||||
|
extended_desktop_size_msg_received = 1;
|
||||||
|
error = read_extended_desktop_size_rect(v, &layout);
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
error = process_extended_desktop_size(v, x, y, cx, cy,
|
||||||
|
&layout);
|
||||||
|
g_free(layout.s);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_sprintf(text, "VNC error in lib_framebuffer_update encoding = %8.8x",
|
g_sprintf(text, "VNC error in lib_framebuffer_update encoding = %8.8x",
|
||||||
@ -743,6 +1123,20 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
error = v->server_end_update(v);
|
error = v->server_end_update(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (v->first_framebuffer_update)
|
||||||
|
{
|
||||||
|
v->first_framebuffer_update = 0;
|
||||||
|
if (v->resizeable_mode && !extended_desktop_size_msg_received)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR, "Resizeable mode requested, "
|
||||||
|
"but X server does not support it");
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
if (v->suppress_output == 0)
|
if (v->suppress_output == 0)
|
||||||
@ -750,7 +1144,7 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
/* FramebufferUpdateRequest */
|
/* FramebufferUpdateRequest */
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
out_uint8(s, 3);
|
out_uint8(s, 3);
|
||||||
out_uint8(s, 1);
|
out_uint8(s, 1); /* incremental == 1 : Changes only */
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, v->mod_width);
|
out_uint16_be(s, v->mod_width);
|
||||||
@ -1187,9 +1581,15 @@ lib_mod_connect(struct vnc *v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
|
{
|
||||||
|
/* In resizeable mode, we're not interested at this stage how
|
||||||
|
* big the X server is, as we're going to go for the size set
|
||||||
|
* by the "client_info" param */
|
||||||
|
if (!v->resizeable_mode)
|
||||||
{
|
{
|
||||||
in_uint16_be(s, v->mod_width);
|
in_uint16_be(s, v->mod_width);
|
||||||
in_uint16_be(s, v->mod_height);
|
in_uint16_be(s, v->mod_height);
|
||||||
|
}
|
||||||
init_stream(pixel_format, 8192);
|
init_stream(pixel_format, 8192);
|
||||||
v->server_msg(v, "VNC receiving pixel format", 0);
|
v->server_msg(v, "VNC receiving pixel format", 0);
|
||||||
error = trans_force_read_s(v->trans, pixel_format, 16);
|
error = trans_force_read_s(v->trans, pixel_format, 16);
|
||||||
@ -1329,11 +1729,20 @@ lib_mod_connect(struct vnc *v)
|
|||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
out_uint8(s, 2);
|
out_uint8(s, 2);
|
||||||
out_uint8(s, 0);
|
out_uint8(s, 0);
|
||||||
out_uint16_be(s, 4);
|
out_uint16_be(s, 4); /* Number of encodings following */
|
||||||
out_uint32_be(s, 0); /* raw */
|
out_uint32_be(s, ENC_RAW);
|
||||||
out_uint32_be(s, 1); /* copy rect */
|
out_uint32_be(s, ENC_COPY_RECT);
|
||||||
out_uint32_be(s, 0xffffff11); /* cursor */
|
out_uint32_be(s, ENC_CURSOR);
|
||||||
out_uint32_be(s, 0xffffff21); /* desktop size */
|
if (v->resizeable_mode)
|
||||||
|
{
|
||||||
|
v->server_msg(v, "VNC with ExtendedDesktopSize pseudo-encoding", 0);
|
||||||
|
out_uint32_be(s, ENC_EXTENDED_DESKTOP_SIZE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v->server_msg(v, "VNC with DesktopSize pseudo-encoding", 0);
|
||||||
|
out_uint32_be(s, ENC_DESKTOP_SIZE);
|
||||||
|
}
|
||||||
v->server_msg(v, "VNC sending encodings", 0);
|
v->server_msg(v, "VNC sending encodings", 0);
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
error = trans_force_write_s(v->trans, s);
|
error = trans_force_write_s(v->trans, s);
|
||||||
@ -1344,6 +1753,7 @@ lib_mod_connect(struct vnc *v)
|
|||||||
error = v->server_reset(v, v->mod_width, v->mod_height, v->mod_bpp);
|
error = v->server_reset(v, v->mod_width, v->mod_height, v->mod_bpp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v->first_framebuffer_update = 1;
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
if (v->suppress_output == 0)
|
if (v->suppress_output == 0)
|
||||||
@ -1351,7 +1761,7 @@ lib_mod_connect(struct vnc *v)
|
|||||||
/* FramebufferUpdateRequest */
|
/* FramebufferUpdateRequest */
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
out_uint8(s, 3);
|
out_uint8(s, 3);
|
||||||
out_uint8(s, 0);
|
out_uint8(s, 0); /* incremental == 0 : Full contents */
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, v->mod_width);
|
out_uint16_be(s, v->mod_width);
|
||||||
@ -1459,6 +1869,57 @@ lib_mod_set_param(struct vnc *v, const char *name, const char *value)
|
|||||||
v->got_guid = 1;
|
v->got_guid = 1;
|
||||||
g_memcpy(v->guid, value, 16);
|
g_memcpy(v->guid, value, 16);
|
||||||
}
|
}
|
||||||
|
else if (g_strcasecmp(name, "code") == 0)
|
||||||
|
{
|
||||||
|
v->resizeable_mode = (g_atoi(value) == 1);
|
||||||
|
}
|
||||||
|
else if (g_strcasecmp(name, "client_info") == 0)
|
||||||
|
{
|
||||||
|
const struct xrdp_client_info *client_info =
|
||||||
|
(const struct xrdp_client_info *) value;
|
||||||
|
|
||||||
|
g_free(v->screen_layout.s);
|
||||||
|
|
||||||
|
/* The RDP client (width,height) is requested for the X server
|
||||||
|
* later on if we're in resizeable mode. If we're not, these
|
||||||
|
* settings will be overwritten later by the ServerInit
|
||||||
|
* message from the X server */
|
||||||
|
v->mod_width = client_info->width;
|
||||||
|
v->mod_height = client_info->height;
|
||||||
|
|
||||||
|
/* Save info needed for resizeable support */
|
||||||
|
if (!client_info->multimon || client_info->monitorCount < 1)
|
||||||
|
{
|
||||||
|
v->screen_layout.count = 1;
|
||||||
|
v->screen_layout.s = g_new(struct vnc_screen, 1);
|
||||||
|
v->screen_layout.s[0].id = 0;
|
||||||
|
v->screen_layout.s[0].x = 0;
|
||||||
|
v->screen_layout.s[0].y = 0;
|
||||||
|
v->screen_layout.s[0].width = client_info->width;
|
||||||
|
v->screen_layout.s[0].height = client_info->height;
|
||||||
|
v->screen_layout.s[0].flags = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
v->screen_layout.count = client_info->monitorCount;
|
||||||
|
v->screen_layout.s = g_new(struct vnc_screen,
|
||||||
|
v->screen_layout.count);
|
||||||
|
for (i = 0 ; i < client_info->monitorCount ; ++i)
|
||||||
|
{
|
||||||
|
v->screen_layout.s[i].id = i;
|
||||||
|
v->screen_layout.s[i].x = client_info->minfo[i].left;
|
||||||
|
v->screen_layout.s[i].y = client_info->minfo[i].top;
|
||||||
|
v->screen_layout.s[i].width = client_info->minfo[i].right -
|
||||||
|
client_info->minfo[i].left + 1;
|
||||||
|
v->screen_layout.s[i].height = client_info->minfo[i].bottom -
|
||||||
|
client_info->minfo[i].top + 1;
|
||||||
|
v->screen_layout.s[i].flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_debug_screen_layout("client_info", &v->screen_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1526,7 +1987,7 @@ lib_mod_suppress_output(struct vnc* v, int suppress,
|
|||||||
make_stream(s);
|
make_stream(s);
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
out_uint8(s, 3);
|
out_uint8(s, 3);
|
||||||
out_uint8(s, 0);
|
out_uint8(s, 0); /* incremental == 0 : Full contents */
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, v->mod_width);
|
out_uint16_be(s, v->mod_width);
|
||||||
@ -1575,5 +2036,6 @@ mod_exit(tintptr handle)
|
|||||||
}
|
}
|
||||||
trans_delete(v->trans);
|
trans_delete(v->trans);
|
||||||
g_free(v);
|
g_free(v);
|
||||||
|
g_free(v->screen_layout.s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
23
vnc/vnc.h
23
vnc/vnc.h
@ -26,6 +26,24 @@
|
|||||||
|
|
||||||
#define CURRENT_MOD_VER 4
|
#define CURRENT_MOD_VER 4
|
||||||
|
|
||||||
|
/* Screen used for ExtendedDesktopSize / Set DesktopSize */
|
||||||
|
struct vnc_screen
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vnc_screen_layout
|
||||||
|
{
|
||||||
|
unsigned int count;
|
||||||
|
/* For comparison, screens are sorted in increasing order of ID */
|
||||||
|
struct vnc_screen *s;
|
||||||
|
};
|
||||||
|
|
||||||
struct vnc
|
struct vnc
|
||||||
{
|
{
|
||||||
int size; /* size of this struct */
|
int size; /* size of this struct */
|
||||||
@ -120,4 +138,9 @@ struct vnc
|
|||||||
int got_guid;
|
int got_guid;
|
||||||
tui8 guid[16];
|
tui8 guid[16];
|
||||||
int suppress_output;
|
int suppress_output;
|
||||||
|
/* Resizeable support */
|
||||||
|
int resizeable_mode; /* true for resizeable mode, false for traditional */
|
||||||
|
struct vnc_screen_layout screen_layout;
|
||||||
|
int first_framebuffer_update; /* Identifies the first framebuffer_update */
|
||||||
|
int set_desktop_size_in_progress; /* Waiting for SetDesktopSize response */
|
||||||
};
|
};
|
||||||
|
@ -171,6 +171,12 @@ ip=127.0.0.1
|
|||||||
port=-1
|
port=-1
|
||||||
#xserverbpp=24
|
#xserverbpp=24
|
||||||
#delay_ms=2000
|
#delay_ms=2000
|
||||||
|
; If your Xvnc server supports the ExtendedDesktopSize encoding, you can
|
||||||
|
; uncomment the following line for resizeable session support. This includes
|
||||||
|
; support for multiple monitors.
|
||||||
|
; Unlike traditional VNC sessions, you can connect to (and resize) active
|
||||||
|
; VNC sessions on the same machine which have different sizes.
|
||||||
|
#code=1
|
||||||
|
|
||||||
[vnc-any]
|
[vnc-any]
|
||||||
name=vnc-any
|
name=vnc-any
|
||||||
|
@ -197,7 +197,7 @@ xrdp_mm_send_login(struct xrdp_mm *self)
|
|||||||
}
|
}
|
||||||
else if (g_strcasecmp(name, "code") == 0)
|
else if (g_strcasecmp(name, "code") == 0)
|
||||||
{
|
{
|
||||||
/* this code is either 0 for Xvnc, 10 for X11rdp or 20 for Xorg */
|
/* this code is either 0/1 for Xvnc, 10 for X11rdp or 20 for Xorg */
|
||||||
self->code = g_atoi(value);
|
self->code = g_atoi(value);
|
||||||
}
|
}
|
||||||
else if (g_strcasecmp(name, "xserverbpp") == 0)
|
else if (g_strcasecmp(name, "xserverbpp") == 0)
|
||||||
@ -215,7 +215,7 @@ xrdp_mm_send_login(struct xrdp_mm *self)
|
|||||||
|
|
||||||
s = trans_get_out_s(self->sesman_trans, 8192);
|
s = trans_get_out_s(self->sesman_trans, 8192);
|
||||||
s_push_layer(s, channel_hdr, 8);
|
s_push_layer(s, channel_hdr, 8);
|
||||||
/* this code is either 0 for Xvnc, 10 for X11rdp or 20 for Xorg */
|
/* this code is either 0/1 for Xvnc, 10 for X11rdp or 20 for Xorg */
|
||||||
out_uint16_be(s, self->code);
|
out_uint16_be(s, self->code);
|
||||||
index = g_strlen(username);
|
index = g_strlen(username);
|
||||||
out_uint16_be(s, index);
|
out_uint16_be(s, index);
|
||||||
@ -515,7 +515,7 @@ xrdp_mm_setup_mod2(struct xrdp_mm *self, tui8 *guid)
|
|||||||
{
|
{
|
||||||
if (self->display > 0)
|
if (self->display > 0)
|
||||||
{
|
{
|
||||||
if (self->code == 0) /* Xvnc */
|
if (self->code == 0 || self->code == 1) /* Xvnc */
|
||||||
{
|
{
|
||||||
g_snprintf(text, 255, "%d", 5900 + self->display);
|
g_snprintf(text, 255, "%d", 5900 + self->display);
|
||||||
}
|
}
|
||||||
@ -1903,7 +1903,7 @@ cleanup_states(struct xrdp_mm *self)
|
|||||||
self-> sesman_trans_up = 0; /* true once connected to sesman */
|
self-> sesman_trans_up = 0; /* true once connected to sesman */
|
||||||
self-> delete_sesman_trans = 0; /* boolean set when done with sesman connection */
|
self-> delete_sesman_trans = 0; /* boolean set when done with sesman connection */
|
||||||
self-> display = 0; /* 10 for :10.0, 11 for :11.0, etc */
|
self-> display = 0; /* 10 for :10.0, 11 for :11.0, etc */
|
||||||
self-> code = 0; /* 0 Xvnc session, 10 X11rdp session, 20 Xorg session */
|
self-> code = 0; /* 0/1 Xvnc session, 10 X11rdp session, 20 Xorg session */
|
||||||
self-> sesman_controlled = 0; /* true if this is a sesman session */
|
self-> sesman_controlled = 0; /* true if this is a sesman session */
|
||||||
self-> chan_trans = NULL; /* connection to chansrv */
|
self-> chan_trans = NULL; /* connection to chansrv */
|
||||||
self-> chan_trans_up = 0; /* true once connected to chansrv */
|
self-> chan_trans_up = 0; /* true once connected to chansrv */
|
||||||
|
@ -290,7 +290,7 @@ struct xrdp_mm
|
|||||||
int (*mod_exit)(struct xrdp_mod*);
|
int (*mod_exit)(struct xrdp_mod*);
|
||||||
struct xrdp_mod* mod; /* module interface */
|
struct xrdp_mod* mod; /* module interface */
|
||||||
int display; /* 10 for :10.0, 11 for :11.0, etc */
|
int display; /* 10 for :10.0, 11 for :11.0, etc */
|
||||||
int code; /* 0=Xvnc session, 10=X11rdp session, 20=xorg driver mode */
|
int code; /* 0/1=Xvnc session, 10=X11rdp session, 20=xorg driver mode */
|
||||||
int sesman_controlled; /* true if this is a sesman session */
|
int sesman_controlled; /* true if this is a sesman session */
|
||||||
struct trans* chan_trans; /* connection to chansrv */
|
struct trans* chan_trans; /* connection to chansrv */
|
||||||
int chan_trans_up; /* true once connected to chansrv */
|
int chan_trans_up; /* true once connected to chansrv */
|
||||||
|
Loading…
Reference in New Issue
Block a user