drdynvc: Improve dynamic channel support
The dynamic channel handler in xrdp_channel.c is updated to allow the procs `data_first` pointer to be NULL. If this is done, the channel handler performs all the dechunking necessary for the channel, and only complete data PDUs are passed to procs 'data' callback. This facility is applied to the dynamic channels supported by xrdp_mm.c. The incoming callbacks for these channels now provide complete support for the specification in [MS-RDPEDYC]. The existing channels were incomplete in these respects: 1) The "Microsoft::Windows::RDS::Graphics" channel handler did not support incoming PDUs between 1591 and 1600 bytes. The specification calls for these to be sent as a single DATA_FIRST PDU. 2) The "Microsoft::Windows::RDS::DisplayControl" channel handler did not support incoming PDUs over 1590 bytes.
This commit is contained in:
@@ -87,6 +87,9 @@
|
|||||||
#define XRDP_MAX_BITMAP_CACHE_IDX 2000
|
#define XRDP_MAX_BITMAP_CACHE_IDX 2000
|
||||||
#define XRDP_BITMAP_CACHE_ENTRIES 2048
|
#define XRDP_BITMAP_CACHE_ENTRIES 2048
|
||||||
|
|
||||||
|
/* Max number of dynamic channels we support */
|
||||||
|
#define DRDYNVC_CHANNEL_COUNT 256
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constants come from ITU-T Recommendations
|
* Constants come from ITU-T Recommendations
|
||||||
*/
|
*/
|
||||||
|
|||||||
+2
-1
@@ -143,6 +143,7 @@ struct xrdp_drdynvc
|
|||||||
int status; /* see XRDP_DRDYNVC_STATUS_* */
|
int status; /* see XRDP_DRDYNVC_STATUS_* */
|
||||||
int flags;
|
int flags;
|
||||||
int pad0;
|
int pad0;
|
||||||
|
struct dyn_dechunker *dc; // Use to dechunk fragments
|
||||||
int (*open_response)(struct xrdp_process *id, int chan_id,
|
int (*open_response)(struct xrdp_process *id, int chan_id,
|
||||||
int creation_status);
|
int creation_status);
|
||||||
int (*close_response)(struct xrdp_process *id, int chan_id);
|
int (*close_response)(struct xrdp_process *id, int chan_id);
|
||||||
@@ -161,7 +162,7 @@ struct xrdp_channel
|
|||||||
int drdynvc_channel_id;
|
int drdynvc_channel_id;
|
||||||
int drdynvc_state;
|
int drdynvc_state;
|
||||||
struct vc_dechunker *drdynvc_dc;
|
struct vc_dechunker *drdynvc_dc;
|
||||||
struct xrdp_drdynvc drdynvcs[256];
|
struct xrdp_drdynvc drdynvcs[DRDYNVC_CHANNEL_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* rdp */
|
/* rdp */
|
||||||
|
|||||||
@@ -91,6 +91,9 @@ struct xrdp_drdynvc_procs
|
|||||||
int (*open_response)(struct xrdp_process *id, int chan_id,
|
int (*open_response)(struct xrdp_process *id, int chan_id,
|
||||||
int creation_status);
|
int creation_status);
|
||||||
int (*close_response)(struct xrdp_process *id, int chan_id);
|
int (*close_response)(struct xrdp_process *id, int chan_id);
|
||||||
|
// Only set data_first if you want to be responsible for
|
||||||
|
// defragging your own PDUs. Otherwise the channel
|
||||||
|
// process will do it for you.
|
||||||
int (*data_first)(struct xrdp_process *id, int chan_id, struct stream *s,
|
int (*data_first)(struct xrdp_process *id, int chan_id, struct stream *s,
|
||||||
int total_bytes);
|
int total_bytes);
|
||||||
int (*data)(struct xrdp_process *id, int chan_id, struct stream *s);
|
int (*data)(struct xrdp_process *id, int chan_id, struct stream *s);
|
||||||
|
|||||||
+217
-88
@@ -74,11 +74,16 @@ xrdp_channel_create(struct xrdp_sec *owner, struct xrdp_mcs *mcs_layer)
|
|||||||
void
|
void
|
||||||
xrdp_channel_delete(struct xrdp_channel *self)
|
xrdp_channel_delete(struct xrdp_channel *self)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
if (self == 0)
|
if (self == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vc_dechunker_free(self->drdynvc_dc);
|
vc_dechunker_free(self->drdynvc_dc);
|
||||||
|
for (i = 0 ; i < DRDYNVC_CHANNEL_COUNT ; ++i)
|
||||||
|
{
|
||||||
|
dyn_dechunker_free(self->drdynvcs[i].dc);
|
||||||
|
}
|
||||||
g_memset(self, 0, sizeof(struct xrdp_channel));
|
g_memset(self, 0, sizeof(struct xrdp_channel));
|
||||||
g_free(self);
|
g_free(self);
|
||||||
}
|
}
|
||||||
@@ -338,10 +343,10 @@ drdynvc_process_open_channel_response(struct xrdp_channel *self,
|
|||||||
in_uint32_le(s, creation_status); /* CreationStatus */
|
in_uint32_le(s, creation_status); /* CreationStatus */
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPEDYC] DYNVC_CREATE_RSP "
|
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPEDYC] DYNVC_CREATE_RSP "
|
||||||
"ChannelId %d, CreationStatus %d", chan_id, creation_status);
|
"ChannelId %d, CreationStatus %d", chan_id, creation_status);
|
||||||
if (chan_id > 255)
|
if (chan_id >= DRDYNVC_CHANNEL_COUNT)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "Received [MS-RDPEDYC] DYNVC_CREATE_RSP for an "
|
LOG(LOG_LEVEL_ERROR, "Received [MS-RDPEDYC] DYNVC_CREATE_RSP "
|
||||||
"invalid channel id. Max allowed 255, received %d", chan_id);
|
"for an invalid channel id %d", chan_id);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,6 +359,8 @@ drdynvc_process_open_channel_response(struct xrdp_channel *self,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
drdynvc->status = XRDP_DRDYNVC_STATUS_CLOSED;
|
drdynvc->status = XRDP_DRDYNVC_STATUS_CLOSED;
|
||||||
|
dyn_dechunker_free(drdynvc->dc);
|
||||||
|
drdynvc->dc = NULL;
|
||||||
}
|
}
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG,
|
LOG_DEVEL(LOG_LEVEL_DEBUG,
|
||||||
"Dynamic Virtual Channel %s (%d) updated: status = %s",
|
"Dynamic Virtual Channel %s (%d) updated: status = %s",
|
||||||
@@ -392,15 +399,28 @@ drdynvc_process_close_channel_response(struct xrdp_channel *self,
|
|||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPEDYC] DYNVC_CLOSE "
|
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPEDYC] DYNVC_CLOSE "
|
||||||
"ChannelId %d", chan_id);
|
"ChannelId %d", chan_id);
|
||||||
session = self->sec_layer->rdp_layer->session;
|
session = self->sec_layer->rdp_layer->session;
|
||||||
if (chan_id > 255)
|
if (chan_id >= DRDYNVC_CHANNEL_COUNT)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "Received message for an invalid "
|
LOG(LOG_LEVEL_ERROR, "Received message for an invalid "
|
||||||
"channel id. channel id %d", chan_id);
|
"channel id %d", chan_id);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
drdynvc = self->drdynvcs + chan_id;
|
drdynvc = self->drdynvcs + chan_id;
|
||||||
|
|
||||||
|
if (dyn_dechunker_pending(drdynvc->dc))
|
||||||
|
{
|
||||||
|
// The last PDU wasn't completed
|
||||||
|
LOG(LOG_LEVEL_WARNING,
|
||||||
|
"Dynamic Virtual Channel %s (%d) closing with outstanding data",
|
||||||
|
XRDP_DRDYNVC_CHANNEL_ID_TO_NAME(self, chan_id),
|
||||||
|
chan_id);
|
||||||
|
}
|
||||||
|
|
||||||
drdynvc->status = XRDP_DRDYNVC_STATUS_CLOSED;
|
drdynvc->status = XRDP_DRDYNVC_STATUS_CLOSED;
|
||||||
|
dyn_dechunker_free(drdynvc->dc);
|
||||||
|
drdynvc->dc = NULL;
|
||||||
|
|
||||||
LOG_DEVEL(LOG_LEVEL_DEBUG,
|
LOG_DEVEL(LOG_LEVEL_DEBUG,
|
||||||
"Dynamic Virtual Channel %s (%d) updated: status = %s",
|
"Dynamic Virtual Channel %s (%d) updated: status = %s",
|
||||||
XRDP_DRDYNVC_CHANNEL_ID_TO_NAME(self, chan_id),
|
XRDP_DRDYNVC_CHANNEL_ID_TO_NAME(self, chan_id),
|
||||||
@@ -426,75 +446,113 @@ static int
|
|||||||
drdynvc_process_data_first(struct xrdp_channel *self,
|
drdynvc_process_data_first(struct xrdp_channel *self,
|
||||||
int cmd, struct stream *s)
|
int cmd, struct stream *s)
|
||||||
{
|
{
|
||||||
struct xrdp_session *session;
|
|
||||||
uint32_t chan_id;
|
uint32_t chan_id;
|
||||||
int len;
|
int rv = 0;
|
||||||
int bytes;
|
|
||||||
int total_bytes;
|
|
||||||
struct xrdp_drdynvc *drdynvc;
|
|
||||||
|
|
||||||
if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0) /* ChannelId */
|
if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0) /* ChannelId */
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR,
|
LOG(LOG_LEVEL_ERROR,
|
||||||
"Parsing [MS-RDPEDYC] DYNVC_DATA_FIRST failed");
|
"Parsing [MS-RDPEDYC] DYNVC_DATA_FIRST channel ID failed");
|
||||||
return 1;
|
rv = 1;
|
||||||
}
|
|
||||||
len = (cmd >> 2) & 0x03;
|
|
||||||
if (len == 0)
|
|
||||||
{
|
|
||||||
if (!s_check_rem_and_log(s, 1, "Parsing [MS-RDPEDYC] DYNVC_DATA_FIRST"))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
in_uint8(s, total_bytes); /* Length */
|
|
||||||
}
|
|
||||||
else if (len == 1)
|
|
||||||
{
|
|
||||||
if (!s_check_rem_and_log(s, 2, "Parsing [MS-RDPEDYC] DYNVC_DATA_FIRST"))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
in_uint16_le(s, total_bytes); /* Length */
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!s_check_rem_and_log(s, 4, "Parsing [MS-RDPEDYC] DYNVC_DATA_FIRST"))
|
int len = (cmd >> 2) & 0x03;
|
||||||
|
int total_bytes;
|
||||||
|
switch (len)
|
||||||
{
|
{
|
||||||
return 1;
|
case 0:
|
||||||
|
// Technically this can't happen as DATA_FIRST is only used for
|
||||||
|
// PDUs over 1590 bytes ([MS-RDPEDYC] 2.2.3)
|
||||||
|
if (!s_check_rem(s, 1))
|
||||||
|
{
|
||||||
|
goto short_pdu;
|
||||||
|
}
|
||||||
|
in_uint8(s, total_bytes); /* Length */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if (!s_check_rem(s, 2))
|
||||||
|
{
|
||||||
|
goto short_pdu;
|
||||||
|
}
|
||||||
|
in_uint16_le(s, total_bytes); /* Length */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if (!s_check_rem(s, 4))
|
||||||
|
{
|
||||||
|
goto short_pdu;
|
||||||
}
|
}
|
||||||
in_uint32_le(s, total_bytes); /* Length */
|
in_uint32_le(s, total_bytes); /* Length */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG(LOG_LEVEL_ERROR,
|
||||||
|
"[MS-RDPEDYC] DYNVC_DATA_FIRST has bad Len field");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
bytes = (int) (s->end - s->p);
|
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPEDYC] DYNVC_DATA_FIRST "
|
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPEDYC] DYNVC_DATA_FIRST "
|
||||||
"ChannelId %d, Length %d, Data (omitted from the log)",
|
"ChannelId %d, Length %d, Data (omitted from the log)",
|
||||||
chan_id, total_bytes);
|
chan_id, total_bytes);
|
||||||
|
|
||||||
// See [MS-RDPBCGR] 2.2.3
|
if (chan_id >= DRDYNVC_CHANNEL_COUNT)
|
||||||
if (total_bytes < 1590 || bytes > total_bytes)
|
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR,
|
LOG(LOG_LEVEL_ERROR, "Received [MS-RDPEDYC] DYNVC_DATA_FIRST "
|
||||||
"Badly formed DYNVC_DATA_FIRST PDU received on dynamic channel %d",
|
"for an invalid channel id %d", chan_id);
|
||||||
chan_id);
|
rv = 1;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct xrdp_drdynvc *drdynvc = self->drdynvcs + chan_id;
|
||||||
|
|
||||||
session = self->sec_layer->rdp_layer->session;
|
|
||||||
if (chan_id > 255)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "Received [MS-RDPEDYC] DYNVC_DATA_FIRST for an "
|
|
||||||
"invalid channel id. Max allowed 255, received %d", chan_id);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
drdynvc = self->drdynvcs + chan_id;
|
|
||||||
if (drdynvc->data_first != NULL)
|
if (drdynvc->data_first != NULL)
|
||||||
{
|
{
|
||||||
return drdynvc->data_first(session->id, chan_id, s, total_bytes);
|
// Caller has requested to defragment PDUs themself
|
||||||
|
struct xrdp_session *session =
|
||||||
|
self->sec_layer->rdp_layer->session;
|
||||||
|
rv = drdynvc->data_first(session->id, chan_id, s, total_bytes);
|
||||||
}
|
}
|
||||||
LOG_DEVEL(LOG_LEVEL_WARNING, "Dynamic Virtual Channel %s (%d): "
|
else
|
||||||
"callback 'data_first' is NULL",
|
{
|
||||||
XRDP_DRDYNVC_CHANNEL_ID_TO_NAME(self, chan_id),
|
// Get the dechunker working on the stream
|
||||||
chan_id);
|
enum dyn_dechunker_status status;
|
||||||
return 0;
|
status = dyn_dechunker_process_first_chunk(drdynvc->dc,
|
||||||
|
s, total_bytes);
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case E_DYN_INLINE_CHUNK:
|
||||||
|
// Pass through as data PDU
|
||||||
|
if (drdynvc->data != NULL)
|
||||||
|
{
|
||||||
|
struct xrdp_session *session =
|
||||||
|
self->sec_layer->rdp_layer->session;
|
||||||
|
rv = drdynvc->data(session->id, chan_id, s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case E_DYN_IN_PROGRESS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case E_DYN_ERROR:
|
||||||
|
rv = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG(LOG_LEVEL_ERROR,
|
||||||
|
"Dechunker returned unknown error %d",
|
||||||
|
(int)status);
|
||||||
|
rv = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
short_pdu:
|
||||||
|
LOG(LOG_LEVEL_ERROR, "[MS-RDPEDYC] DYNVC_DATA_FIRST is too short");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -505,37 +563,86 @@ static int
|
|||||||
drdynvc_process_data(struct xrdp_channel *self,
|
drdynvc_process_data(struct xrdp_channel *self,
|
||||||
int cmd, struct stream *s)
|
int cmd, struct stream *s)
|
||||||
{
|
{
|
||||||
struct xrdp_session *session;
|
int rv = 0;
|
||||||
uint32_t chan_id;
|
uint32_t chan_id;
|
||||||
int bytes;
|
|
||||||
struct xrdp_drdynvc *drdynvc;
|
|
||||||
|
|
||||||
if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0) /* ChannelId */
|
if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0) /* ChannelId */
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "drdynvc_process_data: drdynvc_get_chan_id failed");
|
LOG(LOG_LEVEL_ERROR,
|
||||||
return 1;
|
"Parsing [MS-RDPEDYC] DYNVC_DATA channel ID failed");
|
||||||
|
rv = 1;
|
||||||
}
|
}
|
||||||
bytes = (int) (s->end - s->p);
|
else
|
||||||
|
{
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPEDYC] DYNVC_DATA "
|
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPEDYC] DYNVC_DATA "
|
||||||
"ChannelId %d, (re-assembled) Length %d, Data (omitted from the log)",
|
"ChannelId %d, Length %d, Data (omitted from the log)",
|
||||||
chan_id, bytes);
|
chan_id, s_rem(s));
|
||||||
session = self->sec_layer->rdp_layer->session;
|
if (chan_id >= DRDYNVC_CHANNEL_COUNT)
|
||||||
if (chan_id > 255)
|
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "Received DYNVC_DATA PDU for an invalid "
|
LOG(LOG_LEVEL_ERROR, "Received DYNVC_DATA PDU for an invalid "
|
||||||
"channel id. channel id %d", chan_id);
|
"channel id %d", chan_id);
|
||||||
return 1;
|
rv = 1;
|
||||||
}
|
}
|
||||||
drdynvc = self->drdynvcs + chan_id;
|
else
|
||||||
|
{
|
||||||
|
struct stream *ls = NULL; // Set if the application to be called
|
||||||
|
int free_ls = 0; // Set if we need to clear ls when we're done
|
||||||
|
struct xrdp_drdynvc *drdynvc = self->drdynvcs + chan_id;
|
||||||
|
if (drdynvc->data_first != NULL)
|
||||||
|
{
|
||||||
|
// Caller is processing all PDUs directly
|
||||||
|
ls = s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Pass the PDU to the dechunker
|
||||||
|
enum dyn_dechunker_status dechunker_status =
|
||||||
|
dyn_dechunker_process_data_chunk(drdynvc->dc, s);
|
||||||
|
switch (dechunker_status)
|
||||||
|
{
|
||||||
|
case E_DYN_INLINE_CHUNK:
|
||||||
|
ls = s;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case E_DYN_IN_PROGRESS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case E_DYN_READY:
|
||||||
|
ls = dyn_dechunker_get_stream(drdynvc->dc);
|
||||||
|
// We now own the stream, so must delete it
|
||||||
|
free_ls = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case E_DYN_ERROR:
|
||||||
|
// Error has been logged
|
||||||
|
rv = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG(LOG_LEVEL_ERROR,
|
||||||
|
"Dechunker returned unknown error %d",
|
||||||
|
(int)dechunker_status);
|
||||||
|
rv = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ls != NULL)
|
||||||
|
{
|
||||||
if (drdynvc->data != NULL)
|
if (drdynvc->data != NULL)
|
||||||
{
|
{
|
||||||
return drdynvc->data(session->id, chan_id, s);
|
struct xrdp_session *session =
|
||||||
|
self->sec_layer->rdp_layer->session;
|
||||||
|
rv = drdynvc->data(session->id, chan_id, ls);
|
||||||
}
|
}
|
||||||
LOG_DEVEL(LOG_LEVEL_WARNING, "Dynamic Virtual Channel %s (%d): "
|
|
||||||
"callback 'data' is NULL",
|
if (free_ls)
|
||||||
XRDP_DRDYNVC_CHANNEL_ID_TO_NAME(self, chan_id),
|
{
|
||||||
chan_id);
|
free_stream(ls);
|
||||||
return 0;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -819,6 +926,7 @@ xrdp_channel_drdynvc_open(struct xrdp_channel *self, const char *name,
|
|||||||
int total_data_len;
|
int total_data_len;
|
||||||
int static_flags;
|
int static_flags;
|
||||||
char *cmd_ptr;
|
char *cmd_ptr;
|
||||||
|
struct dyn_dechunker *dc = NULL;
|
||||||
|
|
||||||
make_stream(s);
|
make_stream(s);
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
@@ -826,8 +934,18 @@ xrdp_channel_drdynvc_open(struct xrdp_channel *self, const char *name,
|
|||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR,
|
LOG(LOG_LEVEL_ERROR,
|
||||||
"xrdp_channel_drdynvc_open: xrdp_channel_init failed");
|
"xrdp_channel_drdynvc_open: xrdp_channel_init failed");
|
||||||
free_stream(s);
|
goto cleanup;
|
||||||
return 1;
|
}
|
||||||
|
|
||||||
|
// If there's no 'data_first' proc, we need a dechunker for the
|
||||||
|
// channel
|
||||||
|
if (procs->data_first == NULL)
|
||||||
|
{
|
||||||
|
if ((dc = dyn_dechunker_init(name)) == NULL)
|
||||||
|
{
|
||||||
|
// Error logged
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cmd_ptr = s->p;
|
cmd_ptr = s->p;
|
||||||
out_uint8(s, 0); /* set later */
|
out_uint8(s, 0); /* set later */
|
||||||
@@ -835,14 +953,12 @@ xrdp_channel_drdynvc_open(struct xrdp_channel *self, const char *name,
|
|||||||
while (self->drdynvcs[ChId].status != XRDP_DRDYNVC_STATUS_CLOSED)
|
while (self->drdynvcs[ChId].status != XRDP_DRDYNVC_STATUS_CLOSED)
|
||||||
{
|
{
|
||||||
ChId++;
|
ChId++;
|
||||||
if (ChId > 255)
|
if (ChId >= DRDYNVC_CHANNEL_COUNT)
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR,
|
LOG(LOG_LEVEL_ERROR,
|
||||||
"Attempting to create a new channel when the maximum "
|
"Attempting to create a new channel when the maximum "
|
||||||
"number of channels have already been created. "
|
"number of channels have already been created.");
|
||||||
"XRDP only supports 255 open channels.");
|
goto cleanup;
|
||||||
free_stream(s);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cbChId = drdynvc_insert_uint_124(s, ChId); /* ChannelId */
|
cbChId = drdynvc_insert_uint_124(s, ChId); /* ChannelId */
|
||||||
@@ -864,17 +980,30 @@ xrdp_channel_drdynvc_open(struct xrdp_channel *self, const char *name,
|
|||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR,
|
LOG(LOG_LEVEL_ERROR,
|
||||||
"Sending [MS-RDPEDYC] DYNVC_CREATE_REQ failed");
|
"Sending [MS-RDPEDYC] DYNVC_CREATE_REQ failed");
|
||||||
free_stream(s);
|
goto cleanup;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
free_stream(s);
|
|
||||||
|
if (procs->data == NULL)
|
||||||
|
{
|
||||||
|
// Not expected. Log this once.
|
||||||
|
LOG(LOG_LEVEL_WARNING, "Dynamic Virtual Channel %s (%d): "
|
||||||
|
"callback 'data' is NULL", name, ChId);
|
||||||
|
}
|
||||||
|
|
||||||
*chan_id = ChId;
|
*chan_id = ChId;
|
||||||
self->drdynvcs[ChId].open_response = procs->open_response;
|
self->drdynvcs[ChId].open_response = procs->open_response;
|
||||||
self->drdynvcs[ChId].close_response = procs->close_response;
|
self->drdynvcs[ChId].close_response = procs->close_response;
|
||||||
self->drdynvcs[ChId].data_first = procs->data_first;
|
self->drdynvcs[ChId].data_first = procs->data_first;
|
||||||
self->drdynvcs[ChId].data = procs->data;
|
self->drdynvcs[ChId].data = procs->data;
|
||||||
self->drdynvcs[ChId].status = XRDP_DRDYNVC_STATUS_OPEN_SENT;
|
self->drdynvcs[ChId].status = XRDP_DRDYNVC_STATUS_OPEN_SENT;
|
||||||
|
self->drdynvcs[ChId].dc = dc;
|
||||||
|
free_stream(s);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
free_stream(s);
|
||||||
|
dyn_dechunker_free(dc);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -892,9 +1021,9 @@ xrdp_channel_drdynvc_close(struct xrdp_channel *self, int chan_id)
|
|||||||
int static_flags;
|
int static_flags;
|
||||||
char *cmd_ptr;
|
char *cmd_ptr;
|
||||||
|
|
||||||
if ((chan_id < 0) || (chan_id > 255))
|
if ((chan_id < 0) || (chan_id >= DRDYNVC_CHANNEL_COUNT))
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "Attempting to close an invalid channel id. "
|
LOG(LOG_LEVEL_ERROR, "Attempting to close an invalid "
|
||||||
"channel id %d", chan_id);
|
"channel id %d", chan_id);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -962,10 +1091,10 @@ xrdp_channel_drdynvc_data_first(struct xrdp_channel *self, int chan_id,
|
|||||||
int static_flags;
|
int static_flags;
|
||||||
char *cmd_ptr;
|
char *cmd_ptr;
|
||||||
|
|
||||||
if ((chan_id < 0) || (chan_id > 255))
|
if ((chan_id < 0) || (chan_id >= DRDYNVC_CHANNEL_COUNT))
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "Attempting to send data to an invalid "
|
LOG(LOG_LEVEL_ERROR, "Attempting to send data to an invalid "
|
||||||
"channel id. channel id %d", chan_id);
|
"channel id %d", chan_id);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN)
|
if (self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN)
|
||||||
@@ -1034,10 +1163,10 @@ xrdp_channel_drdynvc_data(struct xrdp_channel *self, int chan_id,
|
|||||||
int static_flags;
|
int static_flags;
|
||||||
char *cmd_ptr;
|
char *cmd_ptr;
|
||||||
|
|
||||||
if ((chan_id < 0) || (chan_id > 255))
|
if ((chan_id < 0) || (chan_id >= DRDYNVC_CHANNEL_COUNT))
|
||||||
{
|
{
|
||||||
LOG(LOG_LEVEL_ERROR, "Attempting to send data to an invalid "
|
LOG(LOG_LEVEL_ERROR, "Attempting to send data to an invalid "
|
||||||
"channel id. channel id %d", chan_id);
|
"channel id %d", chan_id);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN)
|
if (self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN)
|
||||||
|
|||||||
+1
-49
@@ -942,37 +942,11 @@ xrdp_egfx_close_response(struct xrdp_process *id, int chan_id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/* from client */
|
|
||||||
static int
|
|
||||||
xrdp_egfx_data_first(struct xrdp_process *id, int chan_id,
|
|
||||||
struct stream *s, int total_bytes)
|
|
||||||
{
|
|
||||||
struct xrdp_egfx *egfx;
|
|
||||||
int bytes = s_rem(s);
|
|
||||||
|
|
||||||
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_data_first: bytes %d"
|
|
||||||
" total_bytes %d", bytes, total_bytes);
|
|
||||||
egfx = id->wm->mm->egfx;
|
|
||||||
if (egfx->s != NULL)
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "DYNVC_DATA_FIRST PDU received while"
|
|
||||||
" another stream is active on channel %d", chan_id);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
make_stream(egfx->s);
|
|
||||||
// Caller has checked total_bytes is >= 0 and bytes is < total_bytes
|
|
||||||
init_stream(egfx->s, total_bytes);
|
|
||||||
out_uint8a(egfx->s, s->p, bytes);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* from client */
|
/* from client */
|
||||||
static int
|
static int
|
||||||
xrdp_egfx_data(struct xrdp_process *id, int chan_id, struct stream *s)
|
xrdp_egfx_data(struct xrdp_process *id, int chan_id, struct stream *s)
|
||||||
{
|
{
|
||||||
int error;
|
|
||||||
struct xrdp_wm *wm;
|
struct xrdp_wm *wm;
|
||||||
struct xrdp_mm *mm;
|
struct xrdp_mm *mm;
|
||||||
struct xrdp_egfx *egfx;
|
struct xrdp_egfx *egfx;
|
||||||
@@ -1002,30 +976,8 @@ xrdp_egfx_data(struct xrdp_process *id, int chan_id, struct stream *s)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (egfx->s == NULL)
|
|
||||||
{
|
|
||||||
return xrdp_egfx_process(egfx, s);
|
return xrdp_egfx_process(egfx, s);
|
||||||
}
|
}
|
||||||
int bytes = s_rem(s);
|
|
||||||
|
|
||||||
if (!s_check_rem_out(egfx->s, bytes))
|
|
||||||
{
|
|
||||||
LOG(LOG_LEVEL_ERROR, "DYNVC_DATA PDU data overflow on channel %d",
|
|
||||||
chan_id);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
out_uint8a(egfx->s, s->p, bytes);
|
|
||||||
if (!s_check_rem_out(egfx->s, 1))
|
|
||||||
{
|
|
||||||
s_mark_end(egfx->s);
|
|
||||||
egfx->s->p = egfx->s->data;
|
|
||||||
error = xrdp_egfx_process(egfx, egfx->s);
|
|
||||||
free_stream(egfx->s);
|
|
||||||
egfx->s = NULL;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
int
|
int
|
||||||
@@ -1045,7 +997,7 @@ xrdp_egfx_create(struct xrdp_mm *mm, struct xrdp_egfx **egfx)
|
|||||||
}
|
}
|
||||||
procs.open_response = xrdp_egfx_open_response;
|
procs.open_response = xrdp_egfx_open_response;
|
||||||
procs.close_response = xrdp_egfx_close_response;
|
procs.close_response = xrdp_egfx_close_response;
|
||||||
procs.data_first = xrdp_egfx_data_first;
|
procs.data_first = NULL; // Defragging handled elsewere
|
||||||
procs.data = xrdp_egfx_data;
|
procs.data = xrdp_egfx_data;
|
||||||
process = mm->wm->pro_layer;
|
process = mm->wm->pro_layer;
|
||||||
error = libxrdp_drdynvc_open(process->session,
|
error = libxrdp_drdynvc_open(process->session,
|
||||||
|
|||||||
@@ -127,7 +127,6 @@ struct xrdp_egfx
|
|||||||
int channel_id;
|
int channel_id;
|
||||||
int surface_id;
|
int surface_id;
|
||||||
int frame_id;
|
int frame_id;
|
||||||
struct stream *s;
|
|
||||||
void *user;
|
void *user;
|
||||||
struct xrdp_egfx_bulk *bulk;
|
struct xrdp_egfx_bulk *bulk;
|
||||||
int (*caps_advertise)(void *user, int num_caps, int *version, int *flags);
|
int (*caps_advertise)(void *user, int num_caps, int *version, int *flags);
|
||||||
|
|||||||
+1
-10
@@ -1044,15 +1044,6 @@ dynamic_monitor_close_response(struct xrdp_process *id, int chan_id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
static int
|
|
||||||
dynamic_monitor_data_first(struct xrdp_process *id, int chan_id,
|
|
||||||
struct stream *s, int total_bytes)
|
|
||||||
{
|
|
||||||
LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_data_first:");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
int
|
int
|
||||||
advance_resize_state_machine(struct xrdp_mm *mm,
|
advance_resize_state_machine(struct xrdp_mm *mm,
|
||||||
@@ -1967,7 +1958,7 @@ dynamic_monitor_initialize(struct xrdp_mm *self)
|
|||||||
g_memset(&d_procs, 0, sizeof(d_procs));
|
g_memset(&d_procs, 0, sizeof(d_procs));
|
||||||
d_procs.open_response = dynamic_monitor_open_response;
|
d_procs.open_response = dynamic_monitor_open_response;
|
||||||
d_procs.close_response = dynamic_monitor_close_response;
|
d_procs.close_response = dynamic_monitor_close_response;
|
||||||
d_procs.data_first = dynamic_monitor_data_first;
|
d_procs.data_first = NULL; // Defragging handled elsewhere
|
||||||
d_procs.data = dynamic_monitor_data;
|
d_procs.data = dynamic_monitor_data;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
error = libxrdp_drdynvc_open(self->wm->session,
|
error = libxrdp_drdynvc_open(self->wm->session,
|
||||||
|
|||||||
Reference in New Issue
Block a user