dynamic virtual channel improvements
remove not used chansrv <-> xrdp messages move static channel disable control into libxrdp remove some blocking read, write chansrv calls add drdynvc calls to libxrdp add drdynvc calls to chansrv channel cleanup
This commit is contained in:
parent
6049cf8dad
commit
ae1514c167
@ -1263,6 +1263,93 @@ libxrdp_send_to_channel(struct xrdp_session *session, int channel_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
libxrdp_disable_channel(struct xrdp_session *session, int channel_id,
|
||||
int is_disabled)
|
||||
{
|
||||
struct xrdp_rdp *rdp;
|
||||
struct xrdp_mcs *mcs;
|
||||
struct mcs_channel_item *channel_item;
|
||||
|
||||
rdp = (struct xrdp_rdp *) (session->rdp);
|
||||
mcs = rdp->sec_layer->mcs_layer;
|
||||
if (mcs->channel_list == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
channel_item = (struct mcs_channel_item *)
|
||||
list_get_item(mcs->channel_list, channel_id);
|
||||
if (channel_item == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
channel_item->disabled = is_disabled;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
|
||||
int flags, struct xrdp_drdynvc_procs *procs,
|
||||
int *chan_id)
|
||||
{
|
||||
struct xrdp_rdp *rdp;
|
||||
struct xrdp_sec *sec;
|
||||
struct xrdp_channel *chan;
|
||||
|
||||
rdp = (struct xrdp_rdp *) (session->rdp);
|
||||
sec = rdp->sec_layer;
|
||||
chan = sec->chan_layer;
|
||||
return xrdp_channel_drdynvc_open(chan, name, flags, procs, chan_id);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
libxrdp_drdynvc_close(struct xrdp_session *session, int chan_id)
|
||||
{
|
||||
struct xrdp_rdp *rdp;
|
||||
struct xrdp_sec *sec;
|
||||
struct xrdp_channel *chan;
|
||||
|
||||
rdp = (struct xrdp_rdp *) (session->rdp);
|
||||
sec = rdp->sec_layer;
|
||||
chan = sec->chan_layer;
|
||||
return xrdp_channel_drdynvc_close(chan, chan_id);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
libxrdp_drdynvc_data_first(struct xrdp_session *session, int chan_id,
|
||||
const char *data, int data_bytes,
|
||||
int total_data_bytes)
|
||||
{
|
||||
struct xrdp_rdp *rdp;
|
||||
struct xrdp_sec *sec;
|
||||
struct xrdp_channel *chan;
|
||||
|
||||
rdp = (struct xrdp_rdp *) (session->rdp);
|
||||
sec = rdp->sec_layer;
|
||||
chan = sec->chan_layer;
|
||||
return xrdp_channel_drdynvc_data_first(chan, chan_id, data, data_bytes,
|
||||
total_data_bytes);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
libxrdp_drdynvc_data(struct xrdp_session *session, int chan_id,
|
||||
const char *data, int data_bytes)
|
||||
{
|
||||
struct xrdp_rdp *rdp;
|
||||
struct xrdp_sec *sec;
|
||||
struct xrdp_channel *chan;
|
||||
|
||||
rdp = (struct xrdp_rdp *) (session->rdp);
|
||||
sec = rdp->sec_layer;
|
||||
chan = sec->chan_layer;
|
||||
return xrdp_channel_drdynvc_data(chan, chan_id, data, data_bytes);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int EXPORT_CC
|
||||
libxrdp_orders_send_brush(struct xrdp_session *session,
|
||||
|
@ -51,6 +51,8 @@ struct mcs_channel_item
|
||||
char name[16];
|
||||
int flags;
|
||||
int chanid;
|
||||
int disabled;
|
||||
int pad0;
|
||||
};
|
||||
|
||||
/* mcs */
|
||||
@ -128,11 +130,27 @@ struct xrdp_sec
|
||||
int is_security_header_present; /* boolean */
|
||||
};
|
||||
|
||||
struct xrdp_drdynvc
|
||||
{
|
||||
int chan_id;
|
||||
int status; /* see XRDP_DRDYNVC_STATUS_* */
|
||||
int flags;
|
||||
int pad0;
|
||||
int (*open_response)(intptr_t id, int chan_id, int creation_status);
|
||||
int (*close_response)(intptr_t id, int chan_id);
|
||||
int (*data_first)(intptr_t id, int chan_id, char *data, int bytes, int total_bytes);
|
||||
int (*data)(intptr_t id, int chan_id, char *data, int bytes);
|
||||
};
|
||||
|
||||
/* channel */
|
||||
struct xrdp_channel
|
||||
{
|
||||
struct xrdp_sec *sec_layer;
|
||||
struct xrdp_mcs *mcs_layer;
|
||||
int drdynvc_channel_id;
|
||||
int drdynvc_state;
|
||||
struct stream *s;
|
||||
struct xrdp_drdynvc drdynvcs[256];
|
||||
};
|
||||
|
||||
/* rdp */
|
||||
@ -285,7 +303,6 @@ struct xrdp_mppc_enc
|
||||
tui16 *hash_table;
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
compress_rdp(struct xrdp_mppc_enc *enc, tui8 *srcData, int len);
|
||||
struct xrdp_mppc_enc *
|
||||
@ -553,6 +570,21 @@ xrdp_channel_send(struct xrdp_channel *self, struct stream *s, int channel_id,
|
||||
int
|
||||
xrdp_channel_process(struct xrdp_channel *self, struct stream *s,
|
||||
int chanid);
|
||||
int
|
||||
xrdp_channel_drdynvc_start(struct xrdp_channel *self);
|
||||
int
|
||||
xrdp_channel_drdynvc_open(struct xrdp_channel *self, const char *name,
|
||||
int flags, struct xrdp_drdynvc_procs *procs,
|
||||
int *chan_id);
|
||||
int
|
||||
xrdp_channel_drdynvc_close(struct xrdp_channel *self, int chan_id);
|
||||
int
|
||||
xrdp_channel_drdynvc_data_first(struct xrdp_channel *self, int chan_id,
|
||||
const char *data, int data_bytes,
|
||||
int total_data_bytes);
|
||||
int
|
||||
xrdp_channel_drdynvc_data(struct xrdp_channel *self, int chan_id,
|
||||
const char *data, int data_bytes);
|
||||
|
||||
/* xrdp_fastpath.c */
|
||||
struct xrdp_fastpath *
|
||||
|
@ -76,6 +76,14 @@ struct xrdp_session
|
||||
struct source_info si;
|
||||
};
|
||||
|
||||
struct xrdp_drdynvc_procs
|
||||
{
|
||||
int (*open_response)(intptr_t id, int chan_id, int creation_status);
|
||||
int (*close_response)(intptr_t id, int chan_id);
|
||||
int (*data_first)(intptr_t id, int chan_id, char *data, int bytes, int total_bytes);
|
||||
int (*data)(intptr_t id, int chan_id, char *data, int bytes);
|
||||
};
|
||||
|
||||
struct xrdp_session *
|
||||
libxrdp_init(tbus id, struct trans *trans);
|
||||
int
|
||||
@ -195,6 +203,22 @@ libxrdp_send_to_channel(struct xrdp_session *session, int channel_id,
|
||||
char *data, int data_len,
|
||||
int total_data_len, int flags);
|
||||
int
|
||||
libxrdp_disable_channel(struct xrdp_session *session, int channel_id,
|
||||
int is_disabled);
|
||||
int
|
||||
libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
|
||||
int flags, struct xrdp_drdynvc_procs *procs,
|
||||
int *chan_id);
|
||||
int
|
||||
libxrdp_drdynvc_close(struct xrdp_session *session, int chan_id);
|
||||
int
|
||||
libxrdp_drdynvc_data_first(struct xrdp_session *session, int chan_id,
|
||||
const char *data, int data_bytes,
|
||||
int total_data_bytes);
|
||||
int
|
||||
libxrdp_drdynvc_data(struct xrdp_session *session, int chan_id,
|
||||
const char *data, int data_bytes);
|
||||
int
|
||||
libxrdp_orders_send_brush(struct xrdp_session *session,
|
||||
int width, int height, int bpp, int type,
|
||||
int size, char *data, int cache_id);
|
||||
|
@ -31,6 +31,17 @@
|
||||
#define CHANNEL_FLAG_LAST 0x02
|
||||
#define CHANNEL_FLAG_SHOW_PROTOCOL 0x10
|
||||
|
||||
#define CMD_DVC_OPEN_CHANNEL 0x10
|
||||
#define CMD_DVC_DATA_FIRST 0x20
|
||||
#define CMD_DVC_DATA 0x30
|
||||
#define CMD_DVC_CLOSE_CHANNEL 0x40
|
||||
#define CMD_DVC_CAPABILITY 0x50
|
||||
|
||||
#define XRDP_DRDYNVC_STATUS_CLOSED 0
|
||||
#define XRDP_DRDYNVC_STATUS_OPEN_SENT 1
|
||||
#define XRDP_DRDYNVC_STATUS_OPEN 2
|
||||
#define XRDP_DRDYNVC_STATUS_CLOSE_SENT 3
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns pointer or nil on error */
|
||||
static struct mcs_channel_item *
|
||||
@ -58,6 +69,7 @@ xrdp_channel_create(struct xrdp_sec *owner, struct xrdp_mcs *mcs_layer)
|
||||
self = (struct xrdp_channel *)g_malloc(sizeof(struct xrdp_channel), 1);
|
||||
self->sec_layer = owner;
|
||||
self->mcs_layer = mcs_layer;
|
||||
self->drdynvc_channel_id = -1;
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -70,7 +82,7 @@ xrdp_channel_delete(struct xrdp_channel *self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
free_stream(self->s);
|
||||
g_memset(self, 0, sizeof(struct xrdp_channel));
|
||||
g_free(self);
|
||||
}
|
||||
@ -106,6 +118,12 @@ xrdp_channel_send(struct xrdp_channel *self, struct stream *s, int channel_id,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (channel->disabled)
|
||||
{
|
||||
g_writeln("xrdp_channel_send, channel disabled");
|
||||
return 0; /* not an error */
|
||||
}
|
||||
|
||||
s_pop_layer(s, channel_hdr);
|
||||
out_uint32_le(s, total_data_len);
|
||||
|
||||
@ -175,6 +193,333 @@ xrdp_channel_call_callback(struct xrdp_channel *self, struct stream *s,
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
drdynvc_insert_uint_124(struct stream *s, uint32_t val)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
if (val <= 0xff)
|
||||
{
|
||||
out_uint8(s, val);
|
||||
ret_val = 0;
|
||||
}
|
||||
else if (val <= 0xffff)
|
||||
{
|
||||
out_uint16_le(s, val);
|
||||
ret_val = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_uint32_le(s, val);
|
||||
ret_val = 2;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
drdynvc_get_chan_id(struct stream *s, char cmd, uint32_t *chan_id_p)
|
||||
{
|
||||
int cbChId;
|
||||
int chan_id;
|
||||
|
||||
cbChId = cmd & 0x03;
|
||||
if (cbChId == 0)
|
||||
{
|
||||
if (!s_check_rem(s, 1))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint8(s, chan_id);
|
||||
}
|
||||
else if (cbChId == 1)
|
||||
{
|
||||
if (!s_check_rem(s, 2))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint16_le(s, chan_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, chan_id);
|
||||
}
|
||||
*chan_id_p = chan_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
drdynvc_process_capability_response(struct xrdp_channel *self,
|
||||
int cmd, struct stream *s)
|
||||
{
|
||||
struct xrdp_session *session;
|
||||
int cap_version;
|
||||
int rv;
|
||||
|
||||
/* skip padding */
|
||||
in_uint8s(s, 1);
|
||||
/* read client's version */
|
||||
in_uint16_le(s, cap_version);
|
||||
if ((cap_version != 2) && (cap_version != 3))
|
||||
{
|
||||
g_writeln("drdynvc_process_capability_response: incompatible DVC "
|
||||
"version %d detected", cap_version);
|
||||
return 1;
|
||||
}
|
||||
g_writeln("drdynvc_process_capability_response: DVC version %d selected",
|
||||
cap_version);
|
||||
self->drdynvc_state = 1;
|
||||
session = self->sec_layer->rdp_layer->session;
|
||||
rv = session->callback(session->id, 0x5558, 0, 0, 0, 0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
drdynvc_process_open_channel_response(struct xrdp_channel *self,
|
||||
int cmd, struct stream *s)
|
||||
{
|
||||
struct xrdp_session *session;
|
||||
int creation_status;
|
||||
uint32_t chan_id;
|
||||
struct xrdp_drdynvc *drdynvc;
|
||||
|
||||
if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, creation_status);
|
||||
//g_writeln("drdynvc_process_open_channel_response: chan_id 0x%x "
|
||||
// "creation_status %d", chan_id, creation_status);
|
||||
session = self->sec_layer->rdp_layer->session;
|
||||
if (chan_id > 255)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
drdynvc = self->drdynvcs + chan_id;
|
||||
if (creation_status == 0)
|
||||
{
|
||||
drdynvc->status = XRDP_DRDYNVC_STATUS_OPEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
drdynvc->status = XRDP_DRDYNVC_STATUS_CLOSED;
|
||||
}
|
||||
if (drdynvc->open_response != NULL)
|
||||
{
|
||||
return drdynvc->open_response(session->id, chan_id, creation_status);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
drdynvc_process_close_channel_response(struct xrdp_channel *self,
|
||||
int cmd, struct stream *s)
|
||||
{
|
||||
struct xrdp_session *session;
|
||||
uint32_t chan_id;
|
||||
struct xrdp_drdynvc *drdynvc;
|
||||
|
||||
if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
//g_writeln("drdynvc_process_close_channel_response: chan_id 0x%x", chan_id);
|
||||
session = self->sec_layer->rdp_layer->session;
|
||||
if (chan_id > 255)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
drdynvc = self->drdynvcs + chan_id;
|
||||
drdynvc->status = XRDP_DRDYNVC_STATUS_CLOSED;
|
||||
if (drdynvc->close_response != NULL)
|
||||
{
|
||||
return drdynvc->close_response(session->id, chan_id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
drdynvc_process_data_first(struct xrdp_channel *self,
|
||||
int cmd, struct stream *s)
|
||||
{
|
||||
struct xrdp_session *session;
|
||||
uint32_t chan_id;
|
||||
int len;
|
||||
int bytes;
|
||||
int total_bytes;
|
||||
struct xrdp_drdynvc *drdynvc;
|
||||
|
||||
if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
len = (cmd >> 2) & 0x03;
|
||||
if (len == 0)
|
||||
{
|
||||
if (!s_check_rem(s, 1))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint8(s, total_bytes);
|
||||
}
|
||||
else if (len == 1)
|
||||
{
|
||||
if (!s_check_rem(s, 2))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint16_le(s, total_bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, total_bytes);
|
||||
}
|
||||
bytes = (int) (s->end - s->p);
|
||||
//g_writeln("drdynvc_process_data_first: bytes %d total_bytes %d", bytes, total_bytes);
|
||||
session = self->sec_layer->rdp_layer->session;
|
||||
if (chan_id > 255)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
drdynvc = self->drdynvcs + chan_id;
|
||||
if (drdynvc->data_first != NULL)
|
||||
{
|
||||
return drdynvc->data_first(session->id, chan_id, s->p,
|
||||
bytes, total_bytes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
drdynvc_process_data(struct xrdp_channel *self,
|
||||
int cmd, struct stream *s)
|
||||
{
|
||||
struct xrdp_session *session;
|
||||
uint32_t chan_id;
|
||||
int bytes;
|
||||
struct xrdp_drdynvc *drdynvc;
|
||||
|
||||
if (drdynvc_get_chan_id(s, cmd, &chan_id) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
bytes = (int) (s->end - s->p);
|
||||
//g_writeln("drdynvc_process_data: bytes %d", bytes);
|
||||
session = self->sec_layer->rdp_layer->session;
|
||||
if (chan_id > 255)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
drdynvc = self->drdynvcs + chan_id;
|
||||
if (drdynvc->data != NULL)
|
||||
{
|
||||
return drdynvc->data(session->id, chan_id, s->p, bytes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
xrdp_channel_process_drdynvc(struct xrdp_channel *self,
|
||||
struct mcs_channel_item *channel,
|
||||
struct stream *s)
|
||||
{
|
||||
int total_length;
|
||||
int length;
|
||||
int flags;
|
||||
int cmd;
|
||||
int rv;
|
||||
struct stream *ls;
|
||||
|
||||
if (!s_check_rem(s, 8))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, total_length);
|
||||
in_uint32_le(s, flags);
|
||||
//g_writeln("xrdp_channel_process_drdynvc: total_length %d flags 0x%8.8x",
|
||||
// total_length, flags);
|
||||
ls = NULL;
|
||||
switch (flags & 3)
|
||||
{
|
||||
case 0:
|
||||
length = (int) (s->end - s->p);
|
||||
out_uint8a(self->s, s->p, length);
|
||||
in_uint8s(s, length);
|
||||
return 0;
|
||||
case 1:
|
||||
free_stream(self->s);
|
||||
make_stream(self->s);
|
||||
init_stream(self->s, total_length);
|
||||
length = (int) (s->end - s->p);
|
||||
out_uint8a(self->s, s->p, length);
|
||||
in_uint8s(s, length);
|
||||
return 0;
|
||||
case 2:
|
||||
length = (int) (s->end - s->p);
|
||||
out_uint8a(self->s, s->p, length);
|
||||
in_uint8s(s, length);
|
||||
ls = self->s;
|
||||
break;
|
||||
case 3:
|
||||
ls = s;
|
||||
break;
|
||||
default:
|
||||
g_writeln("xrdp_channel_process_drdynvc: error");
|
||||
return 1;
|
||||
}
|
||||
if (ls == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint8(ls, cmd); /* read command */
|
||||
//g_writeln("xrdp_channel_process_drdynvc: cmd 0x%x", cmd);
|
||||
rv = 1;
|
||||
switch (cmd & 0xf0)
|
||||
{
|
||||
case CMD_DVC_CAPABILITY:
|
||||
rv = drdynvc_process_capability_response(self, cmd, s);
|
||||
break;
|
||||
case CMD_DVC_OPEN_CHANNEL:
|
||||
rv = drdynvc_process_open_channel_response(self, cmd, s);
|
||||
break;
|
||||
case CMD_DVC_CLOSE_CHANNEL:
|
||||
rv = drdynvc_process_close_channel_response(self, cmd, s);
|
||||
break;
|
||||
case CMD_DVC_DATA_FIRST:
|
||||
rv = drdynvc_process_data_first(self, cmd, s);
|
||||
break;
|
||||
case CMD_DVC_DATA:
|
||||
rv = drdynvc_process_data(self, cmd, s);
|
||||
break;
|
||||
default:
|
||||
g_writeln("xrdp_channel_process_drdynvc: got unknown "
|
||||
"command 0x%x", cmd);
|
||||
break;
|
||||
}
|
||||
//g_writeln("xrdp_channel_process_drdynvc: rv %d", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns error */
|
||||
/* This is called from the secure layer to process an incoming non global
|
||||
@ -191,23 +536,319 @@ xrdp_channel_process(struct xrdp_channel *self, struct stream *s,
|
||||
int channel_id;
|
||||
struct mcs_channel_item *channel;
|
||||
|
||||
|
||||
/* this assumes that the channels are in order of chanid(mcs channel id)
|
||||
but they should be, see xrdp_sec_process_mcs_data_channels
|
||||
the first channel should be MCS_GLOBAL_CHANNEL + 1, second
|
||||
one should be MCS_GLOBAL_CHANNEL + 2, and so on */
|
||||
channel_id = (chanid - MCS_GLOBAL_CHANNEL) - 1;
|
||||
channel = xrdp_channel_get_item(self, channel_id);
|
||||
|
||||
if (channel == NULL)
|
||||
{
|
||||
g_writeln("xrdp_channel_process, channel not found");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (channel->disabled)
|
||||
{
|
||||
g_writeln("xrdp_channel_process, channel disabled");
|
||||
return 0; /* not an error */
|
||||
}
|
||||
if (channel_id == self->drdynvc_channel_id)
|
||||
{
|
||||
return xrdp_channel_process_drdynvc(self, channel, s);
|
||||
}
|
||||
rv = 0;
|
||||
in_uint32_le(s, length);
|
||||
in_uint32_le(s, flags);
|
||||
rv = xrdp_channel_call_callback(self, s, channel_id, length, flags);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* drdynvc */
|
||||
static int
|
||||
xrdp_channel_drdynvc_send_capability_request(struct xrdp_channel *self)
|
||||
{
|
||||
struct stream *s;
|
||||
int flags;
|
||||
int total_data_len;
|
||||
int channel_id;
|
||||
char *phold;
|
||||
|
||||
/* setup stream */
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
if (xrdp_channel_init(self, s) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
phold = s->p;
|
||||
out_uint8(s, 0x50); /* insert cmd */
|
||||
out_uint8(s, 0x00); /* insert padding */
|
||||
out_uint16_le(s, 2); /* insert version */
|
||||
/* channel priority unused for now */
|
||||
out_uint16_le(s, 0x0000); /* priority charge 0 */
|
||||
out_uint16_le(s, 0x0000); /* priority charge 1 */
|
||||
out_uint16_le(s, 0x0000); /* priority charge 2 */
|
||||
out_uint16_le(s, 0x0000); /* priority charge 3 */
|
||||
s_mark_end(s);
|
||||
/* send command to client */
|
||||
total_data_len = (int) (s->end - phold);
|
||||
flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
|
||||
channel_id = self->drdynvc_channel_id;
|
||||
if (xrdp_channel_send(self, s, channel_id, total_data_len, flags) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
free_stream(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_channel_drdynvc_start(struct xrdp_channel *self)
|
||||
{
|
||||
int index;
|
||||
int count;
|
||||
struct mcs_channel_item *ci;
|
||||
struct mcs_channel_item *dci;
|
||||
|
||||
g_writeln("xrdp_channel_drdynvc_start:");
|
||||
dci = NULL;
|
||||
count = self->mcs_layer->channel_list->count;
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
ci = (struct mcs_channel_item *)
|
||||
list_get_item(self->mcs_layer->channel_list, index);
|
||||
if (ci != NULL)
|
||||
{
|
||||
if (g_strcasecmp(ci->name, "drdynvc") == 0)
|
||||
{
|
||||
dci = ci;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dci != NULL)
|
||||
{
|
||||
self->drdynvc_channel_id = (dci->chanid - MCS_GLOBAL_CHANNEL) - 1;
|
||||
xrdp_channel_drdynvc_send_capability_request(self);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_channel_drdynvc_open(struct xrdp_channel *self, const char *name,
|
||||
int flags, struct xrdp_drdynvc_procs *procs,
|
||||
int *chan_id)
|
||||
{
|
||||
struct stream *s;
|
||||
int ChId;
|
||||
int cbChId;
|
||||
int chan_pri;
|
||||
int static_channel_id;
|
||||
int name_length;
|
||||
int total_data_len;
|
||||
int static_flags;
|
||||
char *cmd_ptr;
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
if (xrdp_channel_init(self, s) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
cmd_ptr = s->p;
|
||||
out_uint8(s, 0);
|
||||
ChId = 1;
|
||||
while (self->drdynvcs[ChId].status != XRDP_DRDYNVC_STATUS_CLOSED)
|
||||
{
|
||||
ChId++;
|
||||
if (ChId > 255)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
cbChId = drdynvc_insert_uint_124(s, ChId);
|
||||
name_length = g_strlen(name);
|
||||
out_uint8a(s, name, name_length + 1);
|
||||
chan_pri = 0;
|
||||
cmd_ptr[0] = CMD_DVC_OPEN_CHANNEL | ((chan_pri << 2) & 0x0c) | cbChId;
|
||||
static_channel_id = self->drdynvc_channel_id;
|
||||
static_flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
|
||||
s_mark_end(s);
|
||||
total_data_len = (int) (s->end - cmd_ptr);
|
||||
if (xrdp_channel_send(self, s, static_channel_id, total_data_len,
|
||||
static_flags) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
free_stream(s);
|
||||
*chan_id = ChId;
|
||||
self->drdynvcs[ChId].open_response = procs->open_response;
|
||||
self->drdynvcs[ChId].close_response = procs->close_response;
|
||||
self->drdynvcs[ChId].data_first = procs->data_first;
|
||||
self->drdynvcs[ChId].data = procs->data;
|
||||
self->drdynvcs[ChId].status = XRDP_DRDYNVC_STATUS_OPEN_SENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_channel_drdynvc_close(struct xrdp_channel *self, int chan_id)
|
||||
{
|
||||
struct stream *s;
|
||||
int ChId;
|
||||
int cbChId;
|
||||
int static_channel_id;
|
||||
int total_data_len;
|
||||
int static_flags;
|
||||
char *cmd_ptr;
|
||||
|
||||
if ((chan_id < 0) || (chan_id > 255))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if ((self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN) &&
|
||||
(self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN_SENT))
|
||||
{
|
||||
/* not open */
|
||||
return 1;
|
||||
}
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
if (xrdp_channel_init(self, s) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
cmd_ptr = s->p;
|
||||
out_uint8(s, 0);
|
||||
ChId = chan_id;
|
||||
cbChId = drdynvc_insert_uint_124(s, ChId);
|
||||
cmd_ptr[0] = CMD_DVC_CLOSE_CHANNEL | cbChId;
|
||||
static_channel_id = self->drdynvc_channel_id;
|
||||
static_flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
|
||||
s_mark_end(s);
|
||||
total_data_len = (int) (s->end - cmd_ptr);
|
||||
if (xrdp_channel_send(self, s, static_channel_id, total_data_len,
|
||||
static_flags) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
free_stream(s);
|
||||
self->drdynvcs[ChId].status = XRDP_DRDYNVC_STATUS_CLOSE_SENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_channel_drdynvc_data_first(struct xrdp_channel *self, int chan_id,
|
||||
const char *data, int data_bytes,
|
||||
int total_data_bytes)
|
||||
{
|
||||
struct stream *s;
|
||||
int ChId;
|
||||
int cbChId;
|
||||
int cbTotalDataSize;
|
||||
int static_channel_id;
|
||||
int total_data_len;
|
||||
int static_flags;
|
||||
char *cmd_ptr;
|
||||
|
||||
if ((chan_id < 0) || (chan_id > 255))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (data_bytes > 1590)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
if (xrdp_channel_init(self, s) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
cmd_ptr = s->p;
|
||||
out_uint8(s, 0);
|
||||
ChId = chan_id;
|
||||
cbChId = drdynvc_insert_uint_124(s, ChId);
|
||||
cbTotalDataSize = drdynvc_insert_uint_124(s, total_data_bytes);
|
||||
out_uint8p(s, data, data_bytes);
|
||||
cmd_ptr[0] = CMD_DVC_DATA_FIRST | (cbTotalDataSize << 2) | cbChId;
|
||||
static_channel_id = self->drdynvc_channel_id;
|
||||
static_flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
|
||||
s_mark_end(s);
|
||||
total_data_len = (int) (s->end - cmd_ptr);
|
||||
if (xrdp_channel_send(self, s, static_channel_id, total_data_len,
|
||||
static_flags) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
free_stream(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_channel_drdynvc_data(struct xrdp_channel *self, int chan_id,
|
||||
const char *data, int data_bytes)
|
||||
{
|
||||
struct stream *s;
|
||||
int ChId;
|
||||
int cbChId;
|
||||
int static_channel_id;
|
||||
int total_data_len;
|
||||
int static_flags;
|
||||
char *cmd_ptr;
|
||||
|
||||
if ((chan_id < 0) || (chan_id > 255))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (self->drdynvcs[chan_id].status != XRDP_DRDYNVC_STATUS_OPEN)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (data_bytes > 1590)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
if (xrdp_channel_init(self, s) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
cmd_ptr = s->p;
|
||||
out_uint8(s, 0);
|
||||
ChId = chan_id;
|
||||
cbChId = drdynvc_insert_uint_124(s, ChId);
|
||||
out_uint8p(s, data, data_bytes);
|
||||
cmd_ptr[0] = CMD_DVC_DATA | cbChId;
|
||||
static_channel_id = self->drdynvc_channel_id;
|
||||
static_flags = CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST;
|
||||
s_mark_end(s);
|
||||
total_data_len = (int) (s->end - cmd_ptr);
|
||||
if (xrdp_channel_send(self, s, static_channel_id, total_data_len,
|
||||
static_flags) != 0)
|
||||
{
|
||||
free_stream(s);
|
||||
return 1;
|
||||
}
|
||||
free_stream(s);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1125,6 +1125,7 @@ xrdp_rdp_process_data_font(struct xrdp_rdp *self, struct stream *s)
|
||||
g_writeln("yeah, up_and_running");
|
||||
DEBUG(("up_and_running set"));
|
||||
xrdp_rdp_send_data_update_sync(self);
|
||||
xrdp_channel_drdynvc_start(self->sec_layer->chan_layer);
|
||||
}
|
||||
|
||||
DEBUG(("out xrdp_rdp_process_data_font"));
|
||||
|
@ -1840,57 +1840,54 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s)
|
||||
{
|
||||
int num_channels;
|
||||
int index;
|
||||
struct xrdp_client_info *client_info = (struct xrdp_client_info *)NULL;
|
||||
struct xrdp_client_info *client_info;
|
||||
struct mcs_channel_item *channel_item;
|
||||
|
||||
client_info = &(self->rdp_layer->client_info);
|
||||
|
||||
|
||||
DEBUG(("processing channels, channels_allowed is %d", client_info->channels_allowed));
|
||||
|
||||
DEBUG(("processing channels, channels_allowed is %d",
|
||||
client_info->channels_allowed));
|
||||
/* this is an option set in xrdp.ini */
|
||||
if (client_info->channels_allowed != 1) /* are channels on? */
|
||||
if (client_info->channels_allowed == 0) /* are channels on? */
|
||||
{
|
||||
g_writeln("xrdp_sec_process_mcs_data_channels: all channels are disabled by configuration");
|
||||
log_message(LOG_LEVEL_INFO, "all channels are disabled by "
|
||||
"configuration");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
in_uint32_le(s, num_channels);
|
||||
|
||||
if (num_channels > 31)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (index = 0; index < num_channels; index++)
|
||||
{
|
||||
struct mcs_channel_item *channel_item;
|
||||
|
||||
channel_item = (struct mcs_channel_item *)
|
||||
g_malloc(sizeof(struct mcs_channel_item), 1);
|
||||
channel_item = g_new0(struct mcs_channel_item, 1);
|
||||
if (!s_check_rem(s, 12))
|
||||
{
|
||||
g_free(channel_item);
|
||||
return 1;
|
||||
}
|
||||
in_uint8a(s, channel_item->name, 8);
|
||||
if (g_strlen(channel_item->name) == 0)
|
||||
{
|
||||
log_message(LOG_LEVEL_WARNING, "xrdp_sec_process_mcs_data_channels: got an empty channel name, ignoring it");
|
||||
g_free(channel_item);
|
||||
continue;
|
||||
}
|
||||
in_uint32_le(s, channel_item->flags);
|
||||
channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1);
|
||||
list_add_item(self->mcs_layer->channel_list, (tintptr) channel_item);
|
||||
DEBUG(("got channel flags %8.8x name %s", channel_item->flags,
|
||||
channel_item->name));
|
||||
if (g_strlen(channel_item->name) > 0)
|
||||
{
|
||||
channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1);
|
||||
log_message(LOG_LEVEL_INFO, "adding channel item name %s chan_id "
|
||||
"%d flags 0x%8.8x", channel_item->name,
|
||||
channel_item->chanid, channel_item->flags);
|
||||
list_add_item(self->mcs_layer->channel_list,
|
||||
(intptr_t) channel_item);
|
||||
DEBUG(("got channel flags %8.8x name %s", channel_item->flags,
|
||||
channel_item->name));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_free(channel_item);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -56,8 +56,6 @@ xrdp_chansrv_SOURCES = \
|
||||
clipboard_file.h \
|
||||
devredir.c \
|
||||
devredir.h \
|
||||
drdynvc.c \
|
||||
drdynvc.h \
|
||||
fifo.c \
|
||||
fifo.h \
|
||||
irp.c \
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,46 +24,20 @@
|
||||
#include "parse.h"
|
||||
#include "log.h"
|
||||
|
||||
#define MAX_DVC_CHANNELS 32
|
||||
|
||||
struct chan_out_data
|
||||
{
|
||||
struct stream *s;
|
||||
struct chan_out_data *next;
|
||||
};
|
||||
|
||||
struct chan_item
|
||||
{
|
||||
int id;
|
||||
int flags;
|
||||
char name[16];
|
||||
struct chan_out_data *head;
|
||||
struct chan_out_data *tail;
|
||||
};
|
||||
|
||||
/* data in struct trans::callback_data */
|
||||
struct xrdp_api_data
|
||||
{
|
||||
int chan_id;
|
||||
char header[64];
|
||||
int flags;
|
||||
|
||||
/* for dynamic virtual channels */
|
||||
struct trans *transp;
|
||||
int dvc_chan_id;
|
||||
int is_connected;
|
||||
};
|
||||
|
||||
int
|
||||
g_is_term(void);
|
||||
|
||||
int send_channel_data(int chan_id, char *data, int size);
|
||||
int send_channel_data(int chan_id, const char *data, int size);
|
||||
int send_rail_drawing_orders(char* data, int size);
|
||||
int main_cleanup(void);
|
||||
int add_timeout(int msoffset, void (*callback)(void* data), void* data);
|
||||
int find_empty_slot_in_dvc_channels(void);
|
||||
struct xrdp_api_data * struct_from_dvc_chan_id(tui32 dvc_chan_id);
|
||||
int remove_struct_with_chan_id(tui32 dvc_chan_id);
|
||||
|
||||
#define LOG_LEVEL 5
|
||||
|
||||
@ -97,4 +71,25 @@ int remove_struct_with_chan_id(tui32 dvc_chan_id);
|
||||
((GGET_UINT16(_ptr, (_offset) + 2)) << 16)
|
||||
#endif
|
||||
|
||||
struct chansrv_drdynvc_procs
|
||||
{
|
||||
int (*open_response)(int chan_id, int creation_status);
|
||||
int (*close_response)(int chan_id);
|
||||
int (*data_first)(int chan_id, char *data, int bytes, int total_bytes);
|
||||
int (*data)(int chan_id, char *data, int bytes);
|
||||
};
|
||||
|
||||
int
|
||||
chansrv_drdynvc_open(const char *name, int flags,
|
||||
struct chansrv_drdynvc_procs *procs, int *chan_id);
|
||||
int
|
||||
chansrv_drdynvc_close(int chan_id);
|
||||
int
|
||||
chansrv_drdynvc_data_first(int chan_id, const char *data, int data_bytes,
|
||||
int total_data_bytes);
|
||||
int
|
||||
chansrv_drdynvc_data(int chan_id, const char *data, int data_bytes);
|
||||
int
|
||||
chansrv_drdynvc_send_data(int chan_id, const char *data, int data_bytes);
|
||||
|
||||
#endif
|
||||
|
@ -1,531 +0,0 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Laxmikant Rashinkar 2012 LK.Rashinkar@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include "drdynvc.h"
|
||||
|
||||
extern int g_drdynvc_chan_id; /* in chansrv.c */
|
||||
int g_drdynvc_inited = 0;
|
||||
|
||||
static int drdynvc_send_capability_request(uint16_t version);
|
||||
static int drdynvc_process_capability_response(struct stream* s, unsigned char cmd);
|
||||
static int drdynvc_process_open_channel_response(struct stream *s, unsigned char cmd);
|
||||
static int drdynvc_process_close_channel_response(struct stream *s, unsigned char cmd);
|
||||
static int drdynvc_process_data_first(struct stream* s, unsigned char cmd);
|
||||
static int drdynvc_process_data(struct stream* s, unsigned char cmd);
|
||||
static int drdynvc_insert_uint_124(struct stream *s, uint32_t val);
|
||||
static int drdynvc_get_chan_id(struct stream *s, char cmd, uint32_t *chan_id_p);
|
||||
|
||||
/**
|
||||
* bring up dynamic virtual channel
|
||||
*
|
||||
* @return 0 on success, -1 on response
|
||||
******************************************************************************/
|
||||
int
|
||||
drdynvc_init(void)
|
||||
{
|
||||
/* bring up X11 */
|
||||
xcommon_init();
|
||||
|
||||
/* let client know what version of DVC we support */
|
||||
drdynvc_send_capability_request(2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* let DVC Manager on client end know what version of protocol we support
|
||||
* client will respond with version that it supports
|
||||
*
|
||||
* @return 0 on success, -1 on response
|
||||
******************************************************************************/
|
||||
static int
|
||||
drdynvc_send_capability_request(uint16_t version)
|
||||
{
|
||||
struct stream *s;
|
||||
int bytes_in_stream;
|
||||
|
||||
/* setup stream */
|
||||
make_stream(s);
|
||||
init_stream(s, MAX_PDU_SIZE);
|
||||
|
||||
out_uint8(s, 0x50); /* insert cmd */
|
||||
out_uint8(s, 0x00); /* insert padding */
|
||||
out_uint16_le(s, version); /* insert version */
|
||||
|
||||
/* channel priority unused for now */
|
||||
out_uint16_le(s, 0x0000); /* priority charge 0 */
|
||||
out_uint16_le(s, 0x0000); /* priority charge 1 */
|
||||
out_uint16_le(s, 0x0000); /* priority charge 2 */
|
||||
out_uint16_le(s, 0x0000); /* priority charge 3 */
|
||||
|
||||
/* send command to client */
|
||||
bytes_in_stream = stream_length_before_p(s);
|
||||
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
|
||||
free_stream(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* process capability response received from DVC manager at client end
|
||||
*
|
||||
* @param s stream containing client response
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
******************************************************************************/
|
||||
static int
|
||||
drdynvc_process_capability_response(struct stream *s, unsigned char cmd)
|
||||
{
|
||||
int cap_version;
|
||||
|
||||
/* skip padding */
|
||||
in_uint8s(s, 1);
|
||||
|
||||
/* read client's version */
|
||||
in_uint16_le(s, cap_version);
|
||||
|
||||
if ((cap_version != 2) && (cap_version != 3))
|
||||
{
|
||||
LOG(0, ("drdynvc_process_capability_response: incompatible DVC "
|
||||
"version %d detected", cap_version));
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG(0, ("drdynvc_process_capability_response: DVC version %d selected",
|
||||
cap_version));
|
||||
g_drdynvc_inited = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a new dynamic virtual channel
|
||||
*
|
||||
* @pram channel_id channel id number
|
||||
* @pram channel_name name of channel
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
******************************************************************************/
|
||||
int
|
||||
drdynvc_send_open_channel_request(int chan_pri, unsigned int chan_id,
|
||||
char *chan_name)
|
||||
{
|
||||
struct stream *s;
|
||||
int bytes_in_stream;
|
||||
int cbChId;
|
||||
int name_length;
|
||||
|
||||
if ((chan_name == NULL) || (strlen(chan_name) == 0))
|
||||
{
|
||||
LOG(0, ("drdynvc_send_open_channel_request: bad channel name specified"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, MAX_PDU_SIZE);
|
||||
|
||||
name_length = strlen(chan_name);
|
||||
|
||||
/* dummy command for now */
|
||||
out_uint8(s, 0);
|
||||
|
||||
/* insert channel id */
|
||||
cbChId = drdynvc_insert_uint_124(s, chan_id);
|
||||
|
||||
/* insert channel name */
|
||||
out_uint8a(s, chan_name, name_length + 1);
|
||||
|
||||
/* insert command */
|
||||
s->data[0] = CMD_DVC_OPEN_CHANNEL | ((chan_pri << 2) & 0x0c) | cbChId;
|
||||
|
||||
/* send command */
|
||||
bytes_in_stream = stream_length_before_p(s);
|
||||
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
|
||||
free_stream(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
drdynvc_process_open_channel_response(struct stream *s, unsigned char cmd)
|
||||
{
|
||||
struct xrdp_api_data *adp;
|
||||
|
||||
uint32_t chan_id;
|
||||
int creation_status;
|
||||
|
||||
drdynvc_get_chan_id(s, cmd, &chan_id);
|
||||
in_uint32_le(s, creation_status);
|
||||
|
||||
/* LK_TODO now do something using useful! */
|
||||
|
||||
if (creation_status < 0)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
/* get struct xrdp_api_data containing this channel id */
|
||||
if ((adp = struct_from_dvc_chan_id(chan_id)) == NULL)
|
||||
{
|
||||
LOG(0, ("drdynvc_process_open_channel_response: error : "
|
||||
"could not find xrdp_api_data containing chan_id %d", chan_id));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
adp->is_connected = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
drdynvc_send_close_channel_request(unsigned int chan_id)
|
||||
{
|
||||
struct stream *s;
|
||||
int bytes_in_stream;
|
||||
int cbChId;
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, MAX_PDU_SIZE);
|
||||
|
||||
/* insert dummy cmd for now */
|
||||
out_uint8(s, 0);
|
||||
|
||||
/* insert channel id */
|
||||
cbChId = drdynvc_insert_uint_124(s, chan_id);
|
||||
|
||||
/* insert command */
|
||||
s->data[0] = CMD_DVC_CLOSE_CHANNEL | cbChId;
|
||||
|
||||
/* send command */
|
||||
bytes_in_stream = stream_length_before_p(s);
|
||||
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
|
||||
|
||||
free_stream(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
drdynvc_process_close_channel_response(struct stream *s, unsigned char cmd)
|
||||
{
|
||||
uint32_t chan_id;
|
||||
|
||||
drdynvc_get_chan_id(s, cmd, &chan_id);
|
||||
|
||||
/* LK_TODO now do something using useful! */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* send data to client
|
||||
*
|
||||
* @param chan_id the virtual channel to write to
|
||||
* @param data data to write
|
||||
* @param data_size number of bytes to write
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
******************************************************************************/
|
||||
int drdynvc_write_data(uint32_t chan_id, char *data, int data_size)
|
||||
{
|
||||
struct stream *s;
|
||||
char *saved_ptr;
|
||||
int cbChId;
|
||||
int Len;
|
||||
int bytes_in_stream;
|
||||
int frag_size;
|
||||
|
||||
if (data == NULL)
|
||||
{
|
||||
LOG(0, ("drdynvc_write_data: data is NULL\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data_size <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, MAX_PDU_SIZE);
|
||||
|
||||
/* this is a dummy write */
|
||||
out_uint8(s, 0);
|
||||
|
||||
/* insert channel id */
|
||||
cbChId = drdynvc_insert_uint_124(s, chan_id);
|
||||
|
||||
/* will data fit into one pkt? */
|
||||
bytes_in_stream = stream_length_before_p(s);
|
||||
|
||||
if ((bytes_in_stream + data_size) <= MAX_PDU_SIZE)
|
||||
{
|
||||
/* yes it will - insert data */
|
||||
out_uint8p(s, data, data_size);
|
||||
|
||||
/* insert command */
|
||||
s->data[0] = CMD_DVC_DATA | cbChId;
|
||||
|
||||
/* write data to client */
|
||||
bytes_in_stream = stream_length_before_p(s);
|
||||
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
|
||||
free_stream(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no it won't - fragment it */
|
||||
|
||||
saved_ptr = s->p;
|
||||
|
||||
/* let client know how much data to expect */
|
||||
Len = drdynvc_insert_uint_124(s, data_size);
|
||||
|
||||
/* insert data into first fragment */
|
||||
frag_size = MAX_PDU_SIZE - stream_length_before_p(s);
|
||||
out_uint8p(s, data, frag_size);
|
||||
|
||||
/* insert command */
|
||||
s->data[0] = CMD_DVC_DATA_FIRST | Len << 2 | cbChId;
|
||||
|
||||
/* write first fragment to client */
|
||||
bytes_in_stream = stream_length_before_p(s);
|
||||
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
|
||||
data_size -= frag_size;
|
||||
data += frag_size;
|
||||
s->data[0] = CMD_DVC_DATA | cbChId;
|
||||
s->p = saved_ptr;
|
||||
|
||||
/* now send rest of the data using CMD_DVC_DATA */
|
||||
while (data_size > 0)
|
||||
{
|
||||
frag_size = MAX_PDU_SIZE - stream_length_before_p(s);
|
||||
|
||||
if (frag_size > data_size)
|
||||
{
|
||||
frag_size = data_size;
|
||||
}
|
||||
|
||||
out_uint8p(s, data, frag_size);
|
||||
bytes_in_stream = stream_length_before_p(s);
|
||||
send_channel_data(g_drdynvc_chan_id, s->data, bytes_in_stream);
|
||||
data_size -= frag_size;
|
||||
data += frag_size;
|
||||
s->p = saved_ptr;
|
||||
}
|
||||
|
||||
free_stream(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
drdynvc_process_data_first(struct stream *s, unsigned char cmd)
|
||||
{
|
||||
struct xrdp_api_data *adp;
|
||||
struct stream *ls;
|
||||
|
||||
uint32_t chan_id;
|
||||
int bytes_in_stream;
|
||||
int Len;
|
||||
|
||||
drdynvc_get_chan_id(s, cmd, &chan_id);
|
||||
|
||||
Len = (cmd >> 2) & 0x03;
|
||||
|
||||
/* skip data_len */
|
||||
if (Len == 0)
|
||||
{
|
||||
in_uint8s(s, 1);
|
||||
}
|
||||
else if (Len == 1)
|
||||
{
|
||||
in_uint8s(s, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
in_uint8s(s, 4);
|
||||
}
|
||||
|
||||
bytes_in_stream = stream_length_after_p(s);
|
||||
|
||||
/* get struct xrdp_api_data containing this channel id */
|
||||
if ((adp = struct_from_dvc_chan_id(chan_id)) == NULL)
|
||||
{
|
||||
LOG(0, ("drdynvc_process_data_first: error : "
|
||||
"could not find xrdp_api_data containing chan_id %d", chan_id));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ls = trans_get_out_s(adp->transp, MAX_PDU_SIZE);
|
||||
out_uint8p(ls, s->p, bytes_in_stream);
|
||||
s_mark_end(ls);
|
||||
trans_force_write(adp->transp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
drdynvc_process_data(struct stream *s, unsigned char cmd)
|
||||
{
|
||||
struct xrdp_api_data *adp;
|
||||
struct stream *ls;
|
||||
|
||||
uint32_t chan_id;
|
||||
int bytes_in_stream;
|
||||
|
||||
drdynvc_get_chan_id(s, cmd, &chan_id);
|
||||
bytes_in_stream = stream_length_after_p(s);
|
||||
|
||||
/* get struct xrdp_api_data containing this channel id */
|
||||
if ((adp = struct_from_dvc_chan_id(chan_id)) == NULL)
|
||||
{
|
||||
LOG(0, ("drdynvc_process_data: error : "
|
||||
"could not find xrdp_api_data containing chan_id %d", chan_id));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ls = trans_get_out_s(adp->transp, MAX_PDU_SIZE);
|
||||
out_uint8p(ls, s->p, bytes_in_stream);
|
||||
s_mark_end(ls);
|
||||
trans_force_write(adp->transp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* process incoming data on a dynamic virtual channel
|
||||
*
|
||||
* @pram s stream containing the incoming data
|
||||
* @pram chan_id LK_TODO
|
||||
* @pram chan_flags LK_TODO
|
||||
* @pram length LK_TODO
|
||||
* @pram total_length LK_TODO
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
******************************************************************************/
|
||||
int
|
||||
drdynvc_data_in(struct stream *s, int chan_id, int chan_flags, int length,
|
||||
int total_length)
|
||||
{
|
||||
unsigned char cmd;
|
||||
|
||||
in_uint8(s, cmd); /* read command */
|
||||
|
||||
switch (cmd & 0xf0)
|
||||
{
|
||||
case CMD_DVC_CAPABILITY:
|
||||
drdynvc_process_capability_response(s, cmd);
|
||||
break;
|
||||
|
||||
case CMD_DVC_OPEN_CHANNEL:
|
||||
drdynvc_process_open_channel_response(s, cmd);
|
||||
break;
|
||||
|
||||
case CMD_DVC_CLOSE_CHANNEL:
|
||||
drdynvc_process_close_channel_response(s, cmd);
|
||||
break;
|
||||
|
||||
case CMD_DVC_DATA_FIRST:
|
||||
drdynvc_process_data_first(s, cmd);
|
||||
break;
|
||||
|
||||
case CMD_DVC_DATA:
|
||||
drdynvc_process_data(s, cmd);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG(0, ("drdynvc_data_in: got unknown command 0x%x", cmd));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* insert a byte, short or 32bit value into specified stream
|
||||
*
|
||||
* @param s stream used for insertion
|
||||
* @param val value to insert
|
||||
*
|
||||
* @return 0 for byte insertions
|
||||
* @return 1 for short insertion
|
||||
* @return 2 for uint32_t insertions
|
||||
******************************************************************************/
|
||||
static int
|
||||
drdynvc_insert_uint_124(struct stream *s, uint32_t val)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
if (val <= 0xff)
|
||||
{
|
||||
out_uint8(s, val);
|
||||
ret_val = 0;
|
||||
}
|
||||
else if (val <= 0xffff)
|
||||
{
|
||||
out_uint16_le(s, val);
|
||||
ret_val = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_uint32_le(s, val);
|
||||
ret_val = 2;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* extract channel id from stream
|
||||
*
|
||||
* @param s stream containing channel id
|
||||
* @param cmd first byte in stream
|
||||
* @param chan_id return channel id here
|
||||
******************************************************************************/
|
||||
static int
|
||||
drdynvc_get_chan_id(struct stream *s, char cmd, uint32_t *chan_id_p)
|
||||
{
|
||||
int cbChId;
|
||||
int chan_id;
|
||||
|
||||
cbChId = cmd & 0x03;
|
||||
|
||||
if (cbChId == 0)
|
||||
{
|
||||
in_uint8(s, chan_id);
|
||||
}
|
||||
else if (cbChId == 1)
|
||||
{
|
||||
in_uint16_le(s, chan_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
in_uint32_le(s, chan_id);
|
||||
}
|
||||
|
||||
*chan_id_p = chan_id;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Laxmikant Rashinkar 2012 LK.Rashinkar@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _DRDYNVC_H_
|
||||
#define _DRDYNVC_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "arch.h"
|
||||
#include "chansrv.h"
|
||||
#include "xcommon.h"
|
||||
#include "log.h"
|
||||
#include "os_calls.h"
|
||||
#include "trans.h"
|
||||
|
||||
/* move this to tsmf.c */
|
||||
#define TSMF_CHAN_ID 0x1000
|
||||
|
||||
/* get number of bytes in stream before s->p */
|
||||
#define stream_length_before_p(s) (int) ((s)->p - (s)->data)
|
||||
|
||||
/* get number of bytes in stream after s->p */
|
||||
#define stream_length_after_p(s) (int) ((s)->end - (s)->p)
|
||||
|
||||
#define rewind_stream(s) do \
|
||||
{ \
|
||||
(s)->p = (s)->data; \
|
||||
(s)->end = (s)->data; \
|
||||
} while (0)
|
||||
|
||||
/* max number of bytes we can send in one pkt */
|
||||
#define MAX_PDU_SIZE 1600
|
||||
|
||||
/* commands used to manage dynamic virtual channels */
|
||||
#define CMD_DVC_OPEN_CHANNEL 0x10
|
||||
#define CMD_DVC_DATA_FIRST 0x20
|
||||
#define CMD_DVC_DATA 0x30
|
||||
#define CMD_DVC_CLOSE_CHANNEL 0x40
|
||||
#define CMD_DVC_CAPABILITY 0x50
|
||||
|
||||
int drdynvc_init(void);
|
||||
int drdynvc_send_open_channel_request(int chan_pri, unsigned int chan_id,
|
||||
char *chan_name);
|
||||
int drdynvc_send_close_channel_request(unsigned int chan_id);
|
||||
int drdynvc_write_data(uint32_t chan_id, char *data, int data_size);
|
||||
int drdynvc_data_in(struct stream* s, int chan_id, int chan_flags,
|
||||
int length, int total_length);
|
||||
|
||||
#endif
|
@ -138,6 +138,8 @@ int
|
||||
callback(intptr_t id, int msg, intptr_t param1, intptr_t param2,
|
||||
intptr_t param3, intptr_t param4);
|
||||
int
|
||||
xrdp_wm_drdynvc_up(intptr_t id);
|
||||
int
|
||||
xrdp_wm_delete_all_children(struct xrdp_wm* self);
|
||||
int
|
||||
xrdp_wm_show_log(struct xrdp_wm *self);
|
||||
@ -367,6 +369,8 @@ xrdp_bitmap_compress(char* in_data, int width, int height,
|
||||
int e);
|
||||
|
||||
/* xrdp_mm.c */
|
||||
int
|
||||
xrdp_mm_drdynvc_up(struct xrdp_mm* self);
|
||||
struct xrdp_mm*
|
||||
xrdp_mm_create(struct xrdp_wm* owner);
|
||||
void
|
||||
|
741
xrdp/xrdp_mm.c
741
xrdp/xrdp_mm.c
@ -679,71 +679,28 @@ xrdp_mm_trans_send_channel_setup(struct xrdp_mm *self, struct trans *trans)
|
||||
return trans_force_write(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns error */
|
||||
static int
|
||||
xrdp_mm_trans_send_channel_data_response(struct xrdp_mm *self,
|
||||
struct trans *trans)
|
||||
{
|
||||
struct stream *s;
|
||||
|
||||
s = trans_get_out_s(trans, 8192);
|
||||
|
||||
if (s == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
out_uint32_le(s, 0); /* version */
|
||||
out_uint32_le(s, 8 + 8); /* size */
|
||||
out_uint32_le(s, 7); /* msg id */
|
||||
out_uint32_le(s, 8); /* size */
|
||||
s_mark_end(s);
|
||||
return trans_force_write(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns error
|
||||
init is done, sent channel setup */
|
||||
static int
|
||||
xrdp_mm_trans_process_init_response(struct xrdp_mm *self, struct trans *trans)
|
||||
{
|
||||
return xrdp_mm_trans_send_channel_setup(self, trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns error
|
||||
data coming in from the channel handler, send it to the client */
|
||||
static int
|
||||
xrdp_mm_trans_process_channel_data(struct xrdp_mm *self, struct trans *trans)
|
||||
xrdp_mm_trans_process_channel_data(struct xrdp_mm *self, struct stream *s)
|
||||
{
|
||||
struct stream *s;
|
||||
int size;
|
||||
int total_size;
|
||||
int chan_id;
|
||||
int chan_flags;
|
||||
int rv;
|
||||
|
||||
s = trans_get_in_s(trans);
|
||||
|
||||
if (s == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
in_uint16_le(s, chan_id);
|
||||
in_uint16_le(s, chan_flags);
|
||||
in_uint16_le(s, size);
|
||||
in_uint32_le(s, total_size);
|
||||
rv = xrdp_mm_trans_send_channel_data_response(self, trans);
|
||||
rv = 0;
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
if (is_channel_allowed(self->wm, chan_id))
|
||||
{
|
||||
rv = libxrdp_send_to_channel(self->wm->session, chan_id, s->p, size, total_size,
|
||||
chan_flags);
|
||||
}
|
||||
rv = libxrdp_send_to_channel(self->wm->session, chan_id, s->p, size, total_size,
|
||||
chan_flags);
|
||||
}
|
||||
|
||||
return rv;
|
||||
@ -970,12 +927,11 @@ xrdp_mm_process_rail_update_window_text(struct xrdp_mm* self, struct stream* s)
|
||||
{
|
||||
int size;
|
||||
int flags;
|
||||
int rv = 0;
|
||||
int rv;
|
||||
int window_id;
|
||||
struct rail_window_state_order rwso;
|
||||
|
||||
g_writeln("xrdp_mm_process_rail_update_window_text:");
|
||||
|
||||
in_uint32_le(s, window_id);
|
||||
in_uint32_le(s, flags);
|
||||
g_writeln(" update window title info: 0x%8.8x", window_id);
|
||||
@ -1006,17 +962,12 @@ xrdp_mm_process_rail_update_window_text(struct xrdp_mm* self, struct stream* s)
|
||||
/* returns error
|
||||
process alternate secondary drawing orders for rail channel */
|
||||
static int
|
||||
xrdp_mm_process_rail_drawing_orders(struct xrdp_mm* self, struct trans* trans)
|
||||
xrdp_mm_process_rail_drawing_orders(struct xrdp_mm* self, struct stream *s)
|
||||
{
|
||||
struct stream* s;
|
||||
int order_type;
|
||||
int rv = 0;
|
||||
int rv;
|
||||
|
||||
s = trans_get_in_s(trans);
|
||||
if (s == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
rv = 0;
|
||||
in_uint32_le(s, order_type);
|
||||
|
||||
switch(order_type)
|
||||
@ -1040,6 +991,302 @@ xrdp_mm_process_rail_drawing_orders(struct xrdp_mm* self, struct trans* trans)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
xrdp_mm_drdynvc_up(struct xrdp_mm* self)
|
||||
{
|
||||
LLOGLN(0, ("xrdp_mm_drdynvc_up:"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* open response from client going to channel server */
|
||||
static int
|
||||
xrdp_mm_drdynvc_open_response(intptr_t id, int chan_id, int creation_status)
|
||||
{
|
||||
struct trans *trans;
|
||||
struct stream *s;
|
||||
struct xrdp_wm* wm;
|
||||
struct xrdp_process *pro;
|
||||
int chansrv_chan_id;
|
||||
|
||||
LLOGLN(10, ("xrdp_mm_drdynvc_open_response: chan_id %d creation_status %d",
|
||||
chan_id, creation_status));
|
||||
pro = (struct xrdp_process *) id;
|
||||
wm = pro->wm;
|
||||
trans = wm->mm->chan_trans;
|
||||
s = trans_get_out_s(trans, 8192);
|
||||
if (s == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
out_uint32_le(s, 0); /* version */
|
||||
out_uint32_le(s, 24); /* size */
|
||||
out_uint32_le(s, 13); /* msg id */
|
||||
out_uint32_le(s, 16); /* size */
|
||||
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
|
||||
out_uint32_le(s, chansrv_chan_id);
|
||||
out_uint32_le(s, creation_status); /* status */
|
||||
s_mark_end(s);
|
||||
return trans_write_copy(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* close response from client going to channel server */
|
||||
static int
|
||||
xrdp_mm_drdynvc_close_response(intptr_t id, int chan_id)
|
||||
{
|
||||
struct trans *trans;
|
||||
struct stream *s;
|
||||
struct xrdp_wm* wm;
|
||||
struct xrdp_process *pro;
|
||||
int chansrv_chan_id;
|
||||
|
||||
pro = (struct xrdp_process *) id;
|
||||
wm = pro->wm;
|
||||
trans = wm->mm->chan_trans;
|
||||
s = trans_get_out_s(trans, 8192);
|
||||
if (s == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
out_uint32_le(s, 0); /* version */
|
||||
out_uint32_le(s, 20); /* size */
|
||||
out_uint32_le(s, 15); /* msg id */
|
||||
out_uint32_le(s, 12); /* size */
|
||||
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
|
||||
out_uint32_le(s, chansrv_chan_id);
|
||||
s_mark_end(s);
|
||||
return trans_write_copy(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* part data from client going to channel server */
|
||||
static int
|
||||
xrdp_mm_drdynvc_data_first(intptr_t id, int chan_id, char *data,
|
||||
int bytes, int total_bytes)
|
||||
{
|
||||
struct trans *trans;
|
||||
struct stream *s;
|
||||
struct xrdp_wm* wm;
|
||||
struct xrdp_process *pro;
|
||||
int chansrv_chan_id;
|
||||
|
||||
pro = (struct xrdp_process *) id;
|
||||
wm = pro->wm;
|
||||
trans = wm->mm->chan_trans;
|
||||
s = trans_get_out_s(trans, 8192);
|
||||
if (s == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
out_uint32_le(s, 0); /* version */
|
||||
out_uint32_le(s, 8 + 8 + 4 + 4 + 4 + bytes);
|
||||
out_uint32_le(s, 17); /* msg id */
|
||||
out_uint32_le(s, 8 + 4 + 4 + 4 + bytes);
|
||||
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
|
||||
out_uint32_le(s, chansrv_chan_id);
|
||||
out_uint32_le(s, bytes);
|
||||
out_uint32_le(s, total_bytes);
|
||||
out_uint8a(s, data, bytes);
|
||||
s_mark_end(s);
|
||||
return trans_write_copy(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data from client going to channel server */
|
||||
static int
|
||||
xrdp_mm_drdynvc_data(intptr_t id, int chan_id, char *data, int bytes)
|
||||
{
|
||||
struct trans *trans;
|
||||
struct stream *s;
|
||||
struct xrdp_wm* wm;
|
||||
struct xrdp_process *pro;
|
||||
int chansrv_chan_id;
|
||||
|
||||
pro = (struct xrdp_process *) id;
|
||||
wm = pro->wm;
|
||||
trans = wm->mm->chan_trans;
|
||||
s = trans_get_out_s(trans, 8192);
|
||||
if (s == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
out_uint32_le(s, 0); /* version */
|
||||
out_uint32_le(s, 8 + 8 + 4 + 4 + bytes);
|
||||
out_uint32_le(s, 19); /* msg id */
|
||||
out_uint32_le(s, 8 + 4 + 4 + bytes);
|
||||
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
|
||||
out_uint32_le(s, chansrv_chan_id);
|
||||
out_uint32_le(s, bytes);
|
||||
out_uint8a(s, data, bytes);
|
||||
s_mark_end(s);
|
||||
return trans_write_copy(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* open message from channel server going to client */
|
||||
static int
|
||||
xrdp_mm_trans_process_drdynvc_channel_open(struct xrdp_mm* self,
|
||||
struct stream *s)
|
||||
{
|
||||
int name_bytes;
|
||||
int flags;
|
||||
int error;
|
||||
int chan_id;
|
||||
int chansrv_chan_id;
|
||||
char *name;
|
||||
struct xrdp_drdynvc_procs procs;
|
||||
|
||||
if (!s_check_rem(s, 2))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, name_bytes);
|
||||
if ((name_bytes < 1) || (name_bytes > 1024))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
name = g_new(char, name_bytes + 1);
|
||||
if (name == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (!s_check_rem(s, name_bytes))
|
||||
{
|
||||
g_free(name);
|
||||
return 1;
|
||||
}
|
||||
in_uint8a(s, name, name_bytes);
|
||||
name[name_bytes] = 0;
|
||||
if (!s_check_rem(s, 8))
|
||||
{
|
||||
g_free(name);
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, flags);
|
||||
in_uint32_le(s, chansrv_chan_id);
|
||||
if (flags == 0)
|
||||
{
|
||||
/* open static channel, not supported */
|
||||
g_free(name);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* dynamic channel */
|
||||
g_memset(&procs, 0, sizeof(procs));
|
||||
procs.open_response = xrdp_mm_drdynvc_open_response;
|
||||
procs.close_response = xrdp_mm_drdynvc_close_response;
|
||||
procs.data_first = xrdp_mm_drdynvc_data_first;
|
||||
procs.data = xrdp_mm_drdynvc_data;
|
||||
chan_id = 0;
|
||||
error = libxrdp_drdynvc_open(self->wm->session, name, flags, &procs,
|
||||
&chan_id);
|
||||
if (error != 0)
|
||||
{
|
||||
g_free(name);
|
||||
return 1;
|
||||
}
|
||||
self->xr2cr_cid_map[chan_id] = chansrv_chan_id;
|
||||
self->cs2xr_cid_map[chansrv_chan_id] = chan_id;
|
||||
}
|
||||
g_free(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* close message from channel server going to client */
|
||||
static int
|
||||
xrdp_mm_trans_process_drdynvc_channel_close(struct xrdp_mm* self,
|
||||
struct stream *s)
|
||||
{
|
||||
int chansrv_chan_id;
|
||||
int chan_id;
|
||||
int error;
|
||||
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, chansrv_chan_id);
|
||||
chan_id = self->cs2xr_cid_map[chansrv_chan_id];
|
||||
/* close dynamic channel */
|
||||
error = libxrdp_drdynvc_close(self->wm->session, chan_id);
|
||||
if (error != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data from channel server going to client */
|
||||
static int
|
||||
xrdp_mm_trans_process_drdynvc_data_first(struct xrdp_mm* self,
|
||||
struct stream *s)
|
||||
{
|
||||
int chansrv_chan_id;
|
||||
int chan_id;
|
||||
int error;
|
||||
int data_bytes;
|
||||
int total_bytes;
|
||||
char *data;
|
||||
|
||||
if (!s_check_rem(s, 12))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, chansrv_chan_id);
|
||||
in_uint32_le(s, data_bytes);
|
||||
in_uint32_le(s, total_bytes);
|
||||
if ((!s_check_rem(s, data_bytes)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint8p(s, data, data_bytes);
|
||||
chan_id = self->cs2xr_cid_map[chansrv_chan_id];
|
||||
error = libxrdp_drdynvc_data_first(self->wm->session, chan_id, data,
|
||||
data_bytes, total_bytes);
|
||||
if (error != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data from channel server going to client */
|
||||
static int
|
||||
xrdp_mm_trans_process_drdynvc_data(struct xrdp_mm* self,
|
||||
struct stream *s)
|
||||
{
|
||||
int chansrv_chan_id;
|
||||
int chan_id;
|
||||
int error;
|
||||
int data_bytes;
|
||||
char *data;
|
||||
|
||||
if (!s_check_rem(s, 8))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, chansrv_chan_id);
|
||||
in_uint32_le(s, data_bytes);
|
||||
if ((!s_check_rem(s, data_bytes)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint8p(s, data, data_bytes);
|
||||
chan_id = self->cs2xr_cid_map[chansrv_chan_id];
|
||||
error = libxrdp_drdynvc_data(self->wm->session, chan_id, data, data_bytes);
|
||||
if (error != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns error
|
||||
process a message for the channel handler */
|
||||
@ -1051,6 +1298,7 @@ xrdp_mm_chan_process_msg(struct xrdp_mm *self, struct trans *trans,
|
||||
int id;
|
||||
int size;
|
||||
char *next_msg;
|
||||
char *s_end;
|
||||
|
||||
rv = 0;
|
||||
|
||||
@ -1059,31 +1307,47 @@ xrdp_mm_chan_process_msg(struct xrdp_mm *self, struct trans *trans,
|
||||
next_msg = s->p;
|
||||
in_uint32_le(s, id);
|
||||
in_uint32_le(s, size);
|
||||
if (size < 8)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (!s_check_rem(s, size - 8))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
next_msg += size;
|
||||
|
||||
s_end = s->end;
|
||||
s->end = next_msg;
|
||||
LLOGLN(10, ("xrdp_mm_chan_process_msg: got msg id %d", id));
|
||||
switch (id)
|
||||
{
|
||||
case 2: /* channel init response */
|
||||
rv = xrdp_mm_trans_process_init_response(self, trans);
|
||||
break;
|
||||
case 4: /* channel setup response */
|
||||
break;
|
||||
case 6: /* channel data response */
|
||||
break;
|
||||
case 8: /* channel data */
|
||||
rv = xrdp_mm_trans_process_channel_data(self, trans);
|
||||
rv = xrdp_mm_trans_process_channel_data(self, s);
|
||||
break;
|
||||
case 10: /* rail alternate secondary drawing orders */
|
||||
rv = xrdp_mm_process_rail_drawing_orders(self, trans);
|
||||
rv = xrdp_mm_process_rail_drawing_orders(self, s);
|
||||
break;
|
||||
case 12:
|
||||
rv = xrdp_mm_trans_process_drdynvc_channel_open(self, s);
|
||||
break;
|
||||
case 14:
|
||||
rv = xrdp_mm_trans_process_drdynvc_channel_close(self, s);
|
||||
break;
|
||||
case 16:
|
||||
rv = xrdp_mm_trans_process_drdynvc_data_first(self, s);
|
||||
break;
|
||||
case 18:
|
||||
rv = xrdp_mm_trans_process_drdynvc_data(self, s);
|
||||
break;
|
||||
default:
|
||||
log_message(LOG_LEVEL_ERROR,"xrdp_mm_chan_process_msg: unknown id %d", id);
|
||||
break;
|
||||
}
|
||||
|
||||
s->end = s_end;
|
||||
if (rv != 0)
|
||||
{
|
||||
break;
|
||||
LLOGLN(0, ("xrdp_mm_chan_process_msg: error rv %d id %d", rv, id));
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
s->p = next_msg;
|
||||
@ -1116,40 +1380,28 @@ xrdp_mm_chan_data_in(struct trans *trans)
|
||||
return 1;
|
||||
}
|
||||
|
||||
in_uint8s(s, 4); /* id */
|
||||
in_uint32_le(s, size);
|
||||
error = trans_force_read(trans, size - 8);
|
||||
|
||||
if (error == 0)
|
||||
if (trans->extra_flags == 0)
|
||||
{
|
||||
/* here, the entire message block is read in, process it */
|
||||
error = xrdp_mm_chan_process_msg(self, trans, s);
|
||||
in_uint8s(s, 4); /* id */
|
||||
in_uint32_le(s, size);
|
||||
LLOGLN(10, ("xrdp_mm_chan_data_in: got header, size %d", size));
|
||||
if (size > 8)
|
||||
{
|
||||
self->chan_trans->header_size = size;
|
||||
trans->extra_flags = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* here, the entire message block is read in, process it */
|
||||
error = xrdp_mm_chan_process_msg(self, trans, s);
|
||||
self->chan_trans->header_size = 8;
|
||||
trans->extra_flags = 0;
|
||||
init_stream(s, 0);
|
||||
LLOGLN(10, ("xrdp_mm_chan_data_in: got whole message, reset for "
|
||||
"next header"));
|
||||
return error;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
xrdp_mm_chan_send_init(struct xrdp_mm *self)
|
||||
{
|
||||
struct stream *s;
|
||||
|
||||
s = trans_get_out_s(self->chan_trans, 8192);
|
||||
|
||||
if (s == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
out_uint32_le(s, 0); /* version */
|
||||
out_uint32_le(s, 8 + 8); /* size */
|
||||
out_uint32_le(s, 1); /* msg id */
|
||||
out_uint32_le(s, 8); /* size */
|
||||
s_mark_end(s);
|
||||
return trans_force_write(self->chan_trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* connect to chansrv */
|
||||
static int
|
||||
@ -1177,6 +1429,8 @@ xrdp_mm_connect_chansrv(struct xrdp_mm *self, const char *ip, const char *port)
|
||||
self->chan_trans->trans_data_in = xrdp_mm_chan_data_in;
|
||||
self->chan_trans->header_size = 8;
|
||||
self->chan_trans->callback_data = self;
|
||||
self->chan_trans->no_stream_init_on_data_in = 1;
|
||||
self->chan_trans->extra_flags = 0;
|
||||
|
||||
/* try to connect up to 4 times */
|
||||
for (index = 0; index < 4; index++)
|
||||
@ -1200,10 +1454,10 @@ xrdp_mm_connect_chansrv(struct xrdp_mm *self, const char *ip, const char *port)
|
||||
|
||||
if (self->chan_trans_up)
|
||||
{
|
||||
if (xrdp_mm_chan_send_init(self) != 0)
|
||||
if (xrdp_mm_trans_send_channel_setup(self, self->chan_trans) != 0)
|
||||
{
|
||||
log_message(LOG_LEVEL_ERROR,"xrdp_mm_connect_chansrv: error in "
|
||||
"xrdp_mm_chan_send_init");
|
||||
"xrdp_mm_trans_send_channel_setup");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1227,6 +1481,47 @@ static void cleanup_sesman_connection(struct xrdp_mm *self)
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* does the section in xrdp.ini has any channel.*=true | false */
|
||||
static int
|
||||
xrdp_mm_update_allowed_channels(struct xrdp_mm *self)
|
||||
{
|
||||
int index;
|
||||
int count;
|
||||
int chan_id;
|
||||
int disabled;
|
||||
const char *name;
|
||||
const char *value;
|
||||
const char *chan_name;
|
||||
struct xrdp_session *session;
|
||||
|
||||
session = self->wm->session;
|
||||
count = self->login_names->count;
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
name = (const char *) list_get_item(self->login_names, index);
|
||||
if (g_strncasecmp(name, "channel.", 8) == 0)
|
||||
{
|
||||
value = (const char *) list_get_item(self->login_values, index);
|
||||
chan_name = name + 8;
|
||||
chan_id = libxrdp_get_channel_id(session, chan_name);
|
||||
disabled = !g_text2bool(value);
|
||||
libxrdp_disable_channel(session, chan_id, disabled);
|
||||
if (disabled)
|
||||
{
|
||||
g_writeln("xrdp_mm_update_allowed_channels: channel %s "
|
||||
"channel id %d is disabled", chan_name, chan_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_writeln("xrdp_mm_update_allowed_channels: channel %s "
|
||||
"channel id %d is allowed", chan_name, chan_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s)
|
||||
@ -1271,7 +1566,7 @@ xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s)
|
||||
{
|
||||
g_snprintf(port, 255, "%d", 7200 + display);
|
||||
}
|
||||
|
||||
xrdp_mm_update_allowed_channels(self);
|
||||
xrdp_mm_connect_chansrv(self, ip, port);
|
||||
}
|
||||
}
|
||||
@ -2068,7 +2363,8 @@ xrdp_mm_get_wait_objs(struct xrdp_mm *self,
|
||||
|
||||
if ((self->chan_trans != 0) && self->chan_trans_up)
|
||||
{
|
||||
trans_get_wait_objs(self->chan_trans, read_objs, rcount);
|
||||
trans_get_wait_objs_rw(self->chan_trans, read_objs, rcount,
|
||||
write_objs, wcount, timeout);
|
||||
}
|
||||
|
||||
if (self->mod != 0)
|
||||
@ -2975,220 +3271,6 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read the channel section of the ini file into lists
|
||||
* return 1 on success 0 on failure */
|
||||
int read_allowed_channel_names(struct list *names, struct list *values)
|
||||
{
|
||||
int fd;
|
||||
int ret = 0;
|
||||
char cfg_file[256];
|
||||
|
||||
g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH);
|
||||
fd = g_file_open(cfg_file);
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
names->auto_free = 1;
|
||||
values->auto_free = 1;
|
||||
|
||||
/* all values in this section can be valid channel names */
|
||||
if (file_read_section(fd, "channels", names, values) == 0)
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message(LOG_LEVEL_ERROR,"Failure reading channel section of configuration");
|
||||
}
|
||||
|
||||
g_file_close(fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* internal function return -1 if name is not in list
|
||||
* otherwise return the index 0->count-1*/
|
||||
int
|
||||
find_name_in_lists(char *inName, struct list *names)
|
||||
{
|
||||
int reply = -1; /*means not in the list*/
|
||||
int index;
|
||||
char *name;
|
||||
|
||||
for (index = 0; index < names->count; index++)
|
||||
{
|
||||
name = (char *)list_get_item(names, index);
|
||||
if ( (name != 0) && (g_strncasecmp(name, inName, MAX_CHANNEL_NAME) == 0) )
|
||||
{
|
||||
reply = index;
|
||||
break; /* stop loop - item found*/
|
||||
}
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
#define CHANNEL_NAME_PREFIX "channel."
|
||||
/* update the channel lists from connection specific overrides
|
||||
* return 1 on success 0 on failure */
|
||||
int update_allowed_channel_names(struct xrdp_wm *wm, struct list *names, struct list *values)
|
||||
{
|
||||
int ret = 1;
|
||||
int index;
|
||||
int oldindex;
|
||||
char *val;
|
||||
char *name;
|
||||
//wm->mm->login_names,wm->mm->login_values
|
||||
for (index = 0; index < wm->mm->login_names->count; index++)
|
||||
{
|
||||
name = (char *)list_get_item(wm->mm->login_names, index);
|
||||
if ( (name != 0) && (g_strncmp( name, CHANNEL_NAME_PREFIX, g_strlen(CHANNEL_NAME_PREFIX)) == 0 ) )
|
||||
{
|
||||
name += g_strlen(CHANNEL_NAME_PREFIX);
|
||||
// locate and remove from list
|
||||
oldindex = find_name_in_lists(name, names);
|
||||
if (oldindex >= 0)
|
||||
{
|
||||
list_remove_item(names, oldindex);
|
||||
list_remove_item(values, oldindex);
|
||||
}
|
||||
val = (char *)list_get_item(wm->mm->login_values, index);
|
||||
// (re)add to lists
|
||||
list_add_item(names, (tbus)g_strdup(name));
|
||||
list_add_item(values, (tbus)g_strdup(val));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* internal function return 1 if name is in list of channels
|
||||
* and if the value is allowed */
|
||||
int
|
||||
is_channel_enabled(char *inName, struct list *names, struct list *values)
|
||||
{
|
||||
int reply = 0; /*means not in the list*/
|
||||
int index;
|
||||
char *val;
|
||||
|
||||
index = find_name_in_lists(inName, names);
|
||||
if ( index >= 0 )
|
||||
{
|
||||
val = (char *)list_get_item(values, index);
|
||||
reply = g_text2bool(val);
|
||||
if (reply == 0)
|
||||
{
|
||||
log_message(LOG_LEVEL_INFO,"This channel is disabled: %s", inName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message(LOG_LEVEL_INFO,"This channel is disabled (not in List): %s", inName);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
/* internal function only used once per session
|
||||
* creates the list of allowed channels and store the information
|
||||
* in wm struct */
|
||||
void init_channel_allowed(struct xrdp_wm *wm)
|
||||
{
|
||||
int error;
|
||||
int i;
|
||||
char channelname[MAX_CHANNEL_NAME];
|
||||
int index = 0;
|
||||
int allowindex = 0;
|
||||
struct list *names;
|
||||
struct list *values;
|
||||
|
||||
/* first reset allowedchannels */
|
||||
for (i = 0; i < MAX_NR_CHANNELS; i++)
|
||||
{
|
||||
/* 0 is a valid channel so we use -1 to mark the index as unused */
|
||||
wm->allowedchannels[i] = -1;
|
||||
}
|
||||
|
||||
names = list_create();
|
||||
values = list_create();
|
||||
/* You can override the list of allowed channels individually for each
|
||||
* session type. */
|
||||
if ( read_allowed_channel_names(names, values)
|
||||
&& update_allowed_channel_names(wm, names, values) )
|
||||
{
|
||||
do
|
||||
{
|
||||
/* libxrdp_query_channel return 1 on error*/
|
||||
error = libxrdp_query_channel(wm->session, index, channelname, NULL);
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
/* examples of channel names: rdpdr ; rdpsnd ; drdynvc ; cliprdr */
|
||||
if (is_channel_enabled(channelname, names, values))
|
||||
{
|
||||
log_message(LOG_LEVEL_INFO,"The following channel is allowed: %s (%d)", channelname, index);
|
||||
wm->allowedchannels[allowindex] = index;
|
||||
allowindex++;
|
||||
|
||||
if (allowindex >= MAX_NR_CHANNELS)
|
||||
{
|
||||
log_message(LOG_LEVEL_ALWAYS,"Programming error in is_channel_allowed");
|
||||
error = 1; /* end loop */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message(LOG_LEVEL_INFO,"The following channel is not allowed: %s (%d)", channelname, index);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
while ((error == 0) && (index < MAX_NR_CHANNELS));
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message(LOG_LEVEL_ERROR,"Error reading channel section in inifile");
|
||||
}
|
||||
|
||||
list_delete(names);
|
||||
list_delete(values);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* This function returns 1 if the channelID is allowed by rule set
|
||||
* returns 0 if not allowed */
|
||||
int is_channel_allowed(struct xrdp_wm *wm, int channel_id)
|
||||
{
|
||||
int i;
|
||||
int reply = 0; /* not allowed */
|
||||
|
||||
/* The first time each client is using this function we have to
|
||||
* define the list of allowed channels */
|
||||
if (wm->allowedinitialized == 0)
|
||||
{
|
||||
init_channel_allowed(wm);
|
||||
log_message(LOG_LEVEL_DEBUG,"The allow channel list now initialized for this session");
|
||||
wm->allowedinitialized = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_NR_CHANNELS; i++)
|
||||
{
|
||||
if (channel_id == wm->allowedchannels[i])
|
||||
{
|
||||
/*g_writeln("Channel allowed: %d",channel_id);*/
|
||||
reply = 1; /*channel allowed*/
|
||||
break;
|
||||
}
|
||||
else if (wm->allowedchannels[i] == -1)
|
||||
{
|
||||
/* We are in the unused space of the allowedchannels list
|
||||
* We can end the loop */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*return 0 if the index is not found*/
|
||||
int
|
||||
@ -3235,25 +3317,18 @@ server_send_to_channel(struct xrdp_mod *mod, int channel_id,
|
||||
|
||||
wm = (struct xrdp_wm *)(mod->wm);
|
||||
|
||||
if (is_channel_allowed(wm, channel_id))
|
||||
if (wm->mm->usechansrv)
|
||||
{
|
||||
if (wm->mm->usechansrv)
|
||||
{
|
||||
/*
|
||||
* Xvnc backend reaches here
|
||||
* should not return 1 as this case is not an error
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Xvnc backend reaches here
|
||||
* should not return 1 as this case is not an error
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vnc proxy mode reaches here */
|
||||
return libxrdp_send_to_channel(wm->session, channel_id, data, data_len,
|
||||
total_data_len, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
/* vnc proxy mode reaches here */
|
||||
return libxrdp_send_to_channel(wm->session, channel_id, data, data_len,
|
||||
total_data_len, flags);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -295,6 +295,8 @@ struct xrdp_mm
|
||||
int delete_chan_trans; /* boolean set when done with channel connection */
|
||||
int usechansrv; /* true if chansrvport is set in xrdp.ini or using sesman */
|
||||
struct xrdp_encoder *encoder;
|
||||
int cs2xr_cid_map[256];
|
||||
int xr2cr_cid_map[256];
|
||||
};
|
||||
|
||||
struct xrdp_key_info
|
||||
@ -376,8 +378,6 @@ struct xrdp_wm
|
||||
struct xrdp_bitmap* target_surface; /* either screen or os surface */
|
||||
int current_surface_index;
|
||||
int hints;
|
||||
int allowedchannels[MAX_NR_CHANNELS];
|
||||
int allowedinitialized ;
|
||||
char pamerrortxt[256];
|
||||
|
||||
/* configuration derived from xrdp.ini */
|
||||
|
102
xrdp/xrdp_wm.c
102
xrdp/xrdp_wm.c
@ -27,6 +27,18 @@
|
||||
#include "xrdp.h"
|
||||
#include "log.h"
|
||||
|
||||
#define LLOG_LEVEL 1
|
||||
#define LLOGLN(_level, _args) \
|
||||
do \
|
||||
{ \
|
||||
if (_level < LLOG_LEVEL) \
|
||||
{ \
|
||||
g_write("xrdp:xrdp_wm [%10.10u]: ", g_time3()); \
|
||||
g_writeln _args ; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/*****************************************************************************/
|
||||
struct xrdp_wm *
|
||||
xrdp_wm_create(struct xrdp_process *owner,
|
||||
@ -563,6 +575,69 @@ xrdp_wm_init(struct xrdp_wm *self)
|
||||
|
||||
load_xrdp_config(self->xrdp_config, self->screen->bpp);
|
||||
|
||||
/* global channels allow */
|
||||
names = list_create();
|
||||
names->auto_free = 1;
|
||||
values = list_create();
|
||||
values->auto_free = 1;
|
||||
g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH);
|
||||
if (file_by_name_read_section(cfg_file, "Channels", names, values) == 0)
|
||||
{
|
||||
int error;
|
||||
int ii;
|
||||
int chan_id;
|
||||
int chan_flags;
|
||||
int disabled;
|
||||
char chan_name[16];
|
||||
|
||||
ii = 0;
|
||||
error = libxrdp_query_channel(self->session, ii, chan_name,
|
||||
&chan_flags);
|
||||
while (error == 0)
|
||||
{
|
||||
r = NULL;
|
||||
for (index = 0; index < names->count; index++)
|
||||
{
|
||||
q = (char *) list_get_item(names, index);
|
||||
if (g_strcasecmp(q, chan_name) == 0)
|
||||
{
|
||||
r = (char *) list_get_item(values, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (r == NULL)
|
||||
{
|
||||
/* not found, disable the channel */
|
||||
chan_id = libxrdp_get_channel_id(self->session, chan_name);
|
||||
libxrdp_disable_channel(self->session, chan_id, 1);
|
||||
g_writeln("xrdp_wm_init: channel %s channel id %d is "
|
||||
"disabled", chan_name, chan_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* found */
|
||||
chan_id = libxrdp_get_channel_id(self->session, q);
|
||||
disabled = !g_text2bool(r);
|
||||
libxrdp_disable_channel(self->session, chan_id, disabled);
|
||||
if (disabled)
|
||||
{
|
||||
g_writeln("xrdp_wm_init: channel %s channel id %d is "
|
||||
"disabled", chan_name, chan_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_writeln("xrdp_wm_init: channel %s channel id %d is "
|
||||
"allowed", chan_name, chan_id);
|
||||
}
|
||||
}
|
||||
ii++;
|
||||
error = libxrdp_query_channel(self->session, ii, chan_name,
|
||||
&chan_flags);
|
||||
}
|
||||
}
|
||||
list_delete(names);
|
||||
list_delete(values);
|
||||
|
||||
xrdp_wm_load_static_colors_plus(self, autorun_name);
|
||||
xrdp_wm_load_static_pointers(self);
|
||||
self->screen->bg_color = self->xrdp_config->cfg_globals.ls_top_window_bg_color;
|
||||
@ -1758,27 +1833,21 @@ xrdp_wm_process_channel_data(struct xrdp_wm *self,
|
||||
tbus param3, tbus param4)
|
||||
{
|
||||
int rv;
|
||||
int chanid ;
|
||||
rv = 1;
|
||||
|
||||
if (self->mm->mod != 0)
|
||||
{
|
||||
chanid = LOWORD(param1);
|
||||
|
||||
if (is_channel_allowed(self, chanid))
|
||||
if (self->mm->usechansrv)
|
||||
{
|
||||
if (self->mm->usechansrv)
|
||||
rv = xrdp_mm_process_channel_data(self->mm, param1, param2,
|
||||
param3, param4);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->mm->mod->mod_event != 0)
|
||||
{
|
||||
rv = xrdp_mm_process_channel_data(self->mm, param1, param2,
|
||||
param3, param4);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->mm->mod->mod_event != 0)
|
||||
{
|
||||
rv = self->mm->mod->mod_event(self->mm->mod, 0x5555, param1, param2,
|
||||
param3, param4);
|
||||
}
|
||||
rv = self->mm->mod->mod_event(self->mm->mod, 0x5555, param1, param2,
|
||||
param3, param4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1844,6 +1913,9 @@ callback(intptr_t id, int msg, intptr_t param1, intptr_t param2,
|
||||
//g_writeln("callback: frame ack %d", param1);
|
||||
xrdp_mm_frame_ack(wm->mm, param1);
|
||||
break;
|
||||
case 0x5558:
|
||||
xrdp_mm_drdynvc_up(wm->mm);
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
@ -44,24 +44,21 @@
|
||||
|
||||
struct wts_obj
|
||||
{
|
||||
int fd;
|
||||
int status;
|
||||
char name[9];
|
||||
char dname[128];
|
||||
int display_num;
|
||||
uint32_t flags;
|
||||
int fd;
|
||||
int display_num;
|
||||
};
|
||||
|
||||
/* helper functions used by WTSxxx API - do not invoke directly */
|
||||
static int get_display_num_from_display(char *display_text);
|
||||
static int send_init(struct wts_obj *wts);
|
||||
static int can_send(int sck, int millis);
|
||||
static int can_recv(int sck, int millis);
|
||||
|
||||
static const unsigned char g_xrdpapi_magic[12] =
|
||||
{
|
||||
0x78, 0x32, 0x10, 0x67, 0x00, 0x92, 0x30, 0x56, 0xff, 0xd8, 0xa9, 0x1f
|
||||
};
|
||||
static int
|
||||
get_display_num_from_display(char *display_text);
|
||||
static int
|
||||
can_send(int sck, int millis);
|
||||
static int
|
||||
can_recv(int sck, int millis);
|
||||
static int
|
||||
mysend(int sck, const void* adata, int bytes);
|
||||
static int
|
||||
myrecv(int sck, void* adata, int bytes);
|
||||
|
||||
/*
|
||||
* Opens a handle to the server end of a specified virtual channel - this
|
||||
@ -100,22 +97,27 @@ void *
|
||||
WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct wts_obj *wts;
|
||||
char *display_text;
|
||||
int bytes;
|
||||
unsigned long llong;
|
||||
struct sockaddr_un s;
|
||||
struct wts_obj *wts;
|
||||
char *display_text;
|
||||
int bytes;
|
||||
unsigned long long1;
|
||||
struct sockaddr_un s;
|
||||
char *connect_data;
|
||||
int chan_name_bytes;
|
||||
int lerrno;
|
||||
|
||||
if (SessionId != WTS_CURRENT_SESSION)
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: bad SessionId"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
wts = (struct wts_obj *) calloc(1, sizeof(struct wts_obj));
|
||||
|
||||
if (wts == NULL)
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: calloc failed"));
|
||||
return 0;
|
||||
}
|
||||
wts->fd = -1;
|
||||
wts->flags = flags;
|
||||
display_text = getenv("DISPLAY");
|
||||
|
||||
if (display_text != 0)
|
||||
@ -133,16 +135,17 @@ WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
|
||||
/* we use unix domain socket to communicate with chansrv */
|
||||
if ((wts->fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: socket failed"));
|
||||
free(wts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set non blocking */
|
||||
llong = fcntl(wts->fd, F_GETFL);
|
||||
llong = llong | O_NONBLOCK;
|
||||
if (fcntl(wts->fd, F_SETFL, llong) < 0)
|
||||
long1 = fcntl(wts->fd, F_GETFL);
|
||||
long1 = long1 | O_NONBLOCK;
|
||||
if (fcntl(wts->fd, F_SETFL, long1) < 0)
|
||||
{
|
||||
LLOGLN(10, ("WTSVirtualChannelOpenEx: set non-block mode failed"));
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: set non-block mode failed"));
|
||||
}
|
||||
|
||||
/* connect to chansrv session */
|
||||
@ -153,17 +156,93 @@ WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
|
||||
s.sun_path[bytes - 1] = 0;
|
||||
bytes = sizeof(struct sockaddr_un);
|
||||
|
||||
if (connect(wts->fd, (struct sockaddr *) &s, bytes) == 0)
|
||||
if (connect(wts->fd, (struct sockaddr *) &s, bytes) < 0)
|
||||
{
|
||||
LLOGLN(10, ("WTSVirtualChannelOpenEx: connected ok, name %s", pVirtualName));
|
||||
strncpy(wts->name, pVirtualName, 8);
|
||||
|
||||
/* wait for connection to complete and send init */
|
||||
if (send_init(wts) == 0)
|
||||
lerrno = errno;
|
||||
if ((lerrno == EWOULDBLOCK) || (lerrno == EAGAIN) ||
|
||||
(lerrno == EINPROGRESS))
|
||||
{
|
||||
/* all ok */
|
||||
wts->status = 1;
|
||||
/* ok */
|
||||
}
|
||||
else
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: connect failed"));
|
||||
free(wts);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* wait for connection to complete */
|
||||
if (!can_send(wts->fd, 500))
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: can_send failed"));
|
||||
free(wts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chan_name_bytes = strlen(pVirtualName);
|
||||
bytes = 4 + 4 + 4 + chan_name_bytes + 4;
|
||||
|
||||
LLOGLN(10, ("WTSVirtualChannelOpenEx: chan_name_bytes %d bytes %d pVirtualName %s", chan_name_bytes, bytes, pVirtualName));
|
||||
|
||||
connect_data = (char *) calloc(bytes, 1);
|
||||
if (connect_data == NULL)
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: calloc failed"));
|
||||
free(wts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
connect_data[0] = (bytes >> 0) & 0xFF;
|
||||
connect_data[1] = (bytes >> 8) & 0xFF;
|
||||
connect_data[2] = (bytes >> 16) & 0xFF;
|
||||
connect_data[3] = (bytes >> 24) & 0xFF;
|
||||
|
||||
/* version here(4-7), just leave 0 */
|
||||
|
||||
connect_data[8] = (chan_name_bytes >> 0) & 0xFF;
|
||||
connect_data[9] = (chan_name_bytes >> 8) & 0xFF;
|
||||
connect_data[10] = (chan_name_bytes >> 16) & 0xFF;
|
||||
connect_data[11] = (chan_name_bytes >> 24) & 0xFF;
|
||||
|
||||
memcpy(connect_data + 12, pVirtualName, chan_name_bytes);
|
||||
|
||||
connect_data[4 + 4 + 4 + chan_name_bytes + 0] = (flags >> 0) & 0xFF;
|
||||
connect_data[4 + 4 + 4 + chan_name_bytes + 1] = (flags >> 8) & 0xFF;
|
||||
connect_data[4 + 4 + 4 + chan_name_bytes + 2] = (flags >> 16) & 0xFF;
|
||||
connect_data[4 + 4 + 4 + chan_name_bytes + 3] = (flags >> 24) & 0xFF;
|
||||
|
||||
LLOGLN(10, ("WTSVirtualChannelOpenEx: calling mysend with %d bytes", bytes));
|
||||
|
||||
if (mysend(wts->fd, connect_data, bytes) != bytes)
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: mysend failed"));
|
||||
free(wts);
|
||||
return NULL;
|
||||
}
|
||||
LLOGLN(10, ("WTSVirtualChannelOpenEx: sent ok"));
|
||||
|
||||
if (!can_recv(wts->fd, 500))
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: can_recv failed"));
|
||||
free(wts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get response */
|
||||
if (myrecv(wts->fd, connect_data, 4) != 4)
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: myrecv failed"));
|
||||
free(wts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((connect_data[0] != 0) || (connect_data[1] != 0) ||
|
||||
(connect_data[2] != 0) || (connect_data[3] != 0))
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: connect_data not ok"));
|
||||
free(wts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wts;
|
||||
@ -179,18 +258,18 @@ WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
mysend(int sck, const void* adata, int bytes)
|
||||
mysend(int sck, const void *adata, int bytes)
|
||||
{
|
||||
int sent;
|
||||
int error;
|
||||
const char* data;
|
||||
const char *data;
|
||||
|
||||
#if defined(SO_NOSIGPIPE)
|
||||
const int on = 1;
|
||||
setsockopt(sck, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
|
||||
#endif
|
||||
|
||||
data = (const char*)adata;
|
||||
data = (const char *) adata;
|
||||
sent = 0;
|
||||
while (sent < bytes)
|
||||
{
|
||||
@ -207,6 +286,36 @@ mysend(int sck, const void* adata, int bytes)
|
||||
return sent;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
myrecv(int sck, void *adata, int bytes)
|
||||
{
|
||||
int recd;
|
||||
int error;
|
||||
char *data;
|
||||
|
||||
#if defined(SO_NOSIGPIPE)
|
||||
const int on = 1;
|
||||
setsockopt(sck, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
|
||||
#endif
|
||||
|
||||
data = (char *) adata;
|
||||
recd = 0;
|
||||
while (recd < bytes)
|
||||
{
|
||||
if (can_recv(sck, 100))
|
||||
{
|
||||
error = recv(sck, data + recd, bytes - recd, MSG_NOSIGNAL);
|
||||
if (error < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
recd += error;
|
||||
}
|
||||
}
|
||||
return recd;
|
||||
}
|
||||
|
||||
/*
|
||||
* write data to client connection
|
||||
*
|
||||
@ -217,8 +326,7 @@ WTSVirtualChannelWrite(void *hChannelHandle, const char *Buffer,
|
||||
unsigned int Length, unsigned int *pBytesWritten)
|
||||
{
|
||||
struct wts_obj *wts;
|
||||
int rv;
|
||||
int header[4];
|
||||
int rv;
|
||||
|
||||
wts = (struct wts_obj *) hChannelHandle;
|
||||
|
||||
@ -230,29 +338,12 @@ WTSVirtualChannelWrite(void *hChannelHandle, const char *Buffer,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wts->status != 1)
|
||||
{
|
||||
LLOGLN(10, ("WTSVirtualChannelWrite: wts->status != 1"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!can_send(wts->fd, 0))
|
||||
{
|
||||
return 1; /* can't write now, ok to try again */
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
memcpy(header, g_xrdpapi_magic, 12);
|
||||
header[3] = Length;
|
||||
if (mysend(wts->fd, header, 16) == 16)
|
||||
{
|
||||
rv = mysend(wts->fd, Buffer, Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLOGLN(0, ("WTSVirtualChannelWrite: header write failed"));
|
||||
return 0;
|
||||
}
|
||||
rv = mysend(wts->fd, Buffer, Length);
|
||||
|
||||
LLOGLN(10, ("WTSVirtualChannelWrite: mysend() returned %d", rv));
|
||||
|
||||
@ -263,14 +354,6 @@ WTSVirtualChannelWrite(void *hChannelHandle, const char *Buffer,
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0 /* coverity: this is dead code */
|
||||
/* error, but is it ok to try again? */
|
||||
if ((rv == EWOULDBLOCK) || (rv == EAGAIN) || (rv == EINPROGRESS))
|
||||
{
|
||||
return 0; /* failed to send, but should try again */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fatal error */
|
||||
return 0;
|
||||
}
|
||||
@ -296,11 +379,6 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wts->status != 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (can_recv(wts->fd, TimeOut))
|
||||
{
|
||||
rv = recv(wts->fd, Buffer, BufferSize, 0);
|
||||
@ -341,7 +419,7 @@ WTSVirtualChannelClose(void *hChannelHandle)
|
||||
|
||||
wts = (struct wts_obj *)hChannelHandle;
|
||||
|
||||
if (wts == 0)
|
||||
if (wts == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -364,12 +442,7 @@ WTSVirtualChannelQuery(void *hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
|
||||
|
||||
wts = (struct wts_obj *)hChannelHandle;
|
||||
|
||||
if (wts == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wts->status != 1)
|
||||
if (wts == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -378,6 +451,10 @@ WTSVirtualChannelQuery(void *hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
|
||||
{
|
||||
*pBytesReturned = 4;
|
||||
*ppBuffer = malloc(4);
|
||||
if (*ppBuffer == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
memcpy(*ppBuffer, &(wts->fd), 4);
|
||||
}
|
||||
|
||||
@ -388,7 +465,7 @@ WTSVirtualChannelQuery(void *hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
|
||||
void
|
||||
WTSFreeMemory(void *pMemory)
|
||||
{
|
||||
if (pMemory != 0)
|
||||
if (pMemory != NULL)
|
||||
{
|
||||
free(pMemory);
|
||||
}
|
||||
@ -452,39 +529,6 @@ can_recv(int sck, int millis)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
send_init(struct wts_obj *wts)
|
||||
{
|
||||
char initmsg[64];
|
||||
|
||||
memset(initmsg, 0, 64);
|
||||
|
||||
/* insert channel name */
|
||||
strncpy(initmsg, wts->name, 8);
|
||||
|
||||
/* insert open mode flags */
|
||||
initmsg[16] = (wts->flags >> 0) & 0xff;
|
||||
initmsg[17] = (wts->flags >> 8) & 0xff;
|
||||
initmsg[18] = (wts->flags >> 16) & 0xff;
|
||||
initmsg[19] = (wts->flags >> 24) & 0xff;
|
||||
|
||||
if (!can_send(wts->fd, 500))
|
||||
{
|
||||
LLOGLN(10, ("send_init: send() will block!"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (send(wts->fd, initmsg, 64, 0) != 64)
|
||||
{
|
||||
LLOGLN(10, ("send_init: send() failed!"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
LLOGLN(10, ("send_init: sent ok!"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
get_display_num_from_display(char *display_text)
|
||||
@ -513,7 +557,6 @@ get_display_num_from_display(char *display_text)
|
||||
disp[disp_index] = display_text[index];
|
||||
disp_index++;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user