o added support for dynamic virtual channels
o added echo test routine in simple.c for testing DVC using Microsoft's ECHO protocol
This commit is contained in:
parent
42a56cd33e
commit
5b0eaa4a9b
@ -2,6 +2,7 @@
|
|||||||
* xrdp: A Remote Desktop Protocol server.
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
*
|
*
|
||||||
* Copyright (C) Jay Sorg 2009-2012
|
* Copyright (C) Jay Sorg 2009-2012
|
||||||
|
* Copyright (C) Laxmikant Rashinkar 2009-2012
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -42,6 +43,10 @@ static int g_cliprdr_index = -1;
|
|||||||
static int g_rdpsnd_index = -1;
|
static int g_rdpsnd_index = -1;
|
||||||
static int g_rdpdr_index = -1;
|
static int g_rdpdr_index = -1;
|
||||||
static int g_rail_index = -1;
|
static int g_rail_index = -1;
|
||||||
|
static int g_drdynvc_index = -1;
|
||||||
|
|
||||||
|
/* state info for dynamic virtual channels */
|
||||||
|
static struct xrdp_api_data *g_dvc_channels[MAX_DVC_CHANNELS];
|
||||||
|
|
||||||
static tbus g_term_event = 0;
|
static tbus g_term_event = 0;
|
||||||
static tbus g_thread_done_event = 0;
|
static tbus g_thread_done_event = 0;
|
||||||
@ -53,6 +58,7 @@ int g_cliprdr_chan_id = -1; /* cliprdr */
|
|||||||
int g_rdpsnd_chan_id = -1; /* rdpsnd */
|
int g_rdpsnd_chan_id = -1; /* rdpsnd */
|
||||||
int g_rdpdr_chan_id = -1; /* rdpdr */
|
int g_rdpdr_chan_id = -1; /* rdpdr */
|
||||||
int g_rail_chan_id = -1; /* rail */
|
int g_rail_chan_id = -1; /* rail */
|
||||||
|
int g_drdynvc_chan_id = -1; /* drdynvc */
|
||||||
|
|
||||||
char *g_exec_name;
|
char *g_exec_name;
|
||||||
tbus g_exec_event;
|
tbus g_exec_event;
|
||||||
@ -60,13 +66,9 @@ tbus g_exec_mutex;
|
|||||||
tbus g_exec_sem;
|
tbus g_exec_sem;
|
||||||
int g_exec_pid = 0;
|
int g_exec_pid = 0;
|
||||||
|
|
||||||
/* data in struct trans::callback_data */
|
/* each time we create a DVC we need a unique DVC channel id */
|
||||||
struct xrdp_api_data
|
/* this variable gets bumped up once per DVC we create */
|
||||||
{
|
uint32_t g_dvc_chan_id = 100;
|
||||||
int chan_id;
|
|
||||||
char header[64];
|
|
||||||
int flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* add data to chan_item, on its way to the client */
|
/* add data to chan_item, on its way to the client */
|
||||||
@ -310,6 +312,7 @@ process_message_channel_setup(struct stream *s)
|
|||||||
g_rdpsnd_chan_id = -1;
|
g_rdpsnd_chan_id = -1;
|
||||||
g_rdpdr_chan_id = -1;
|
g_rdpdr_chan_id = -1;
|
||||||
g_rail_chan_id = -1;
|
g_rail_chan_id = -1;
|
||||||
|
g_drdynvc_chan_id = -1;
|
||||||
LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup:"));
|
LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup:"));
|
||||||
in_uint16_le(s, num_chans);
|
in_uint16_le(s, num_chans);
|
||||||
LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup: num_chans %d",
|
LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup: num_chans %d",
|
||||||
@ -345,6 +348,11 @@ process_message_channel_setup(struct stream *s)
|
|||||||
g_rail_index = g_num_chan_items;
|
g_rail_index = g_num_chan_items;
|
||||||
g_rail_chan_id = ci->id;
|
g_rail_chan_id = ci->id;
|
||||||
}
|
}
|
||||||
|
else if (g_strcasecmp(ci->name, "drdynvc") == 0)
|
||||||
|
{
|
||||||
|
g_drdynvc_index = g_num_chan_items; // LK_TODO use this
|
||||||
|
g_drdynvc_chan_id = ci->id; // LK_TODO use this
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(10, ("other %s", ci->name));
|
LOG(10, ("other %s", ci->name));
|
||||||
@ -375,6 +383,12 @@ process_message_channel_setup(struct stream *s)
|
|||||||
rail_init();
|
rail_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_drdynvc_index >= 0)
|
||||||
|
{
|
||||||
|
memset(&g_dvc_channels[0], 0, sizeof(g_dvc_channels));
|
||||||
|
drdynvc_init();
|
||||||
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,6 +431,10 @@ process_message_channel_data(struct stream *s)
|
|||||||
{
|
{
|
||||||
rv = rail_data_in(s, chan_id, chan_flags, length, total_length);
|
rv = rail_data_in(s, chan_id, chan_flags, length, total_length);
|
||||||
}
|
}
|
||||||
|
else if (chan_id == g_drdynvc_chan_id)
|
||||||
|
{
|
||||||
|
rv = drdynvc_data_in(s, chan_id, chan_flags, length, total_length);
|
||||||
|
}
|
||||||
else if (chan_id == ((struct xrdp_api_data *)
|
else if (chan_id == ((struct xrdp_api_data *)
|
||||||
(g_api_con_trans->callback_data))->chan_id)
|
(g_api_con_trans->callback_data))->chan_id)
|
||||||
{
|
{
|
||||||
@ -550,13 +568,15 @@ my_trans_data_in(struct trans *trans)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*
|
||||||
/* returns error */
|
* called when WTSVirtualChannelWrite() is invoked in xrdpapi.c
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
int DEFAULT_CC
|
int DEFAULT_CC
|
||||||
my_api_trans_data_in(struct trans *trans)
|
my_api_trans_data_in(struct trans *trans)
|
||||||
{
|
{
|
||||||
struct stream *s;
|
struct stream *s;
|
||||||
int error;
|
int bytes_read;
|
||||||
struct xrdp_api_data *ad;
|
struct xrdp_api_data *ad;
|
||||||
|
|
||||||
LOG(10, ("my_api_trans_data_in:"));
|
LOG(10, ("my_api_trans_data_in:"));
|
||||||
@ -572,22 +592,44 @@ my_api_trans_data_in(struct trans *trans)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOGM((LOG_LEVEL_DEBUG, "my_api_trans_data_in:"));
|
LOGM((LOG_LEVEL_DEBUG, "my_api_trans_data_in:"));
|
||||||
|
|
||||||
s = trans_get_in_s(trans);
|
s = trans_get_in_s(trans);
|
||||||
error = g_tcp_recv(trans->sck, s->data, 8192, 0);
|
bytes_read = g_tcp_recv(trans->sck, s->data, 8192, 0);
|
||||||
|
|
||||||
if (error > 0)
|
if (bytes_read > 0)
|
||||||
{
|
{
|
||||||
LOG(10, ("my_api_trans_data_in: got data %d", error));
|
LOG(10, ("my_api_trans_data_in: got data %d", bytes_read));
|
||||||
ad = (struct xrdp_api_data *)(trans->callback_data);
|
ad = (struct xrdp_api_data *) trans->callback_data;
|
||||||
|
|
||||||
if (send_channel_data(ad->chan_id, s->data, error) != 0)
|
if (ad->dvc_chan_id < 0)
|
||||||
|
{
|
||||||
|
/* writing data to a static virtual channel */
|
||||||
|
if (send_channel_data(ad->chan_id, s->data, bytes_read) != 0)
|
||||||
{
|
{
|
||||||
LOG(0, ("my_api_trans_data_in: send_channel_data failed"));
|
LOG(0, ("my_api_trans_data_in: send_channel_data failed"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG(10, ("my_api_trans_data_in: g_tcp_recv failed, or disconnected"));
|
/* writing data to a dynamic virtual channel */
|
||||||
|
drdynvc_write_data(ad->dvc_chan_id, s->data, bytes_read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ad = (struct xrdp_api_data *) trans->callback_data;
|
||||||
|
if ((ad != NULL) && (ad->dvc_chan_id > 0))
|
||||||
|
{
|
||||||
|
/* WTSVirtualChannelClose() was invoked, or connection dropped */
|
||||||
|
LOG(10, ("my_api_trans_data_in: g_tcp_recv failed or disconnected for DVC"));
|
||||||
|
ad->transp = NULL;
|
||||||
|
ad->is_connected = 0;
|
||||||
|
remove_struct_with_chan_id(ad->dvc_chan_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(10, ("my_api_trans_data_in: g_tcp_recv failed or disconnected for SVC"));
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,37 +670,30 @@ my_trans_conn_in(struct trans *trans, struct trans *new_trans)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*
|
||||||
|
* called when WTSVirtualChannelOpenEx is invoked in xrdpapi.c
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
int DEFAULT_CC
|
int DEFAULT_CC
|
||||||
my_api_trans_conn_in(struct trans *trans, struct trans *new_trans)
|
my_api_trans_conn_in(struct trans *trans, struct trans *new_trans)
|
||||||
{
|
{
|
||||||
struct xrdp_api_data *ad;
|
struct xrdp_api_data *ad;
|
||||||
|
struct stream *s;
|
||||||
int error;
|
int error;
|
||||||
int index;
|
int index;
|
||||||
int found;
|
char chan_pri;
|
||||||
struct stream *s;
|
|
||||||
|
|
||||||
if (trans == 0)
|
if ((trans == 0) || (trans != g_api_lis_trans) || (new_trans == 0))
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trans != g_api_lis_trans)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_trans == 0)
|
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGM((LOG_LEVEL_DEBUG, "my_api_trans_conn_in:"));
|
LOGM((LOG_LEVEL_DEBUG, "my_api_trans_conn_in:"));
|
||||||
|
|
||||||
LOG(10, ("my_api_trans_conn_in: got incoming"));
|
LOG(10, ("my_api_trans_conn_in: got incoming"));
|
||||||
|
|
||||||
s = trans_get_in_s(new_trans);
|
s = trans_get_in_s(new_trans);
|
||||||
s->end = s->data;
|
s->end = s->data;
|
||||||
|
|
||||||
error = trans_force_read(new_trans, 64);
|
error = trans_force_read(new_trans, 64);
|
||||||
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
@ -670,20 +705,36 @@ my_api_trans_conn_in(struct trans *trans, struct trans *new_trans)
|
|||||||
s->end = s->data;
|
s->end = s->data;
|
||||||
|
|
||||||
ad = (struct xrdp_api_data *) g_malloc(sizeof(struct xrdp_api_data), 1);
|
ad = (struct xrdp_api_data *) g_malloc(sizeof(struct xrdp_api_data), 1);
|
||||||
|
|
||||||
g_memcpy(ad->header, s->data, 64);
|
g_memcpy(ad->header, s->data, 64);
|
||||||
|
|
||||||
ad->flags = GGET_UINT32(ad->header, 16);
|
ad->flags = GGET_UINT32(ad->header, 16);
|
||||||
|
ad->chan_id = -1;
|
||||||
|
ad->dvc_chan_id = -1;
|
||||||
|
|
||||||
found = 0;
|
if (ad->flags > 0)
|
||||||
|
|
||||||
if (ad->flags | 1) /* WTS_CHANNEL_OPTION_DYNAMIC */
|
|
||||||
{
|
{
|
||||||
/* TODO */
|
/* opening a dynamic virtual channel */
|
||||||
found = 0;
|
|
||||||
|
if ((index = find_empty_slot_in_dvc_channels()) < 0)
|
||||||
|
{
|
||||||
|
/* exceeded MAX_DVC_CHANNELS */
|
||||||
|
LOG(0, ("my_api_trans_conn_in: MAX_DVC_CHANNELS reached; giving up!"))
|
||||||
|
free(ad);
|
||||||
|
trans_delete(new_trans);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dvc_channels[index] = ad;
|
||||||
|
chan_pri = 4 - ad->flags;
|
||||||
|
ad->dvc_chan_id = g_dvc_chan_id++;
|
||||||
|
ad->is_connected = 0;
|
||||||
|
ad->transp = new_trans;
|
||||||
|
drdynvc_send_open_channel_request(chan_pri, ad->dvc_chan_id, ad->header);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* opening a static virtual channel */
|
||||||
|
|
||||||
for (index = 0; index < g_num_chan_items; index++)
|
for (index = 0; index < g_num_chan_items; index++)
|
||||||
{
|
{
|
||||||
LOG(10, (" %s %s", ad->header, g_chan_items[index].name));
|
LOG(10, (" %s %s", ad->header, g_chan_items[index].name));
|
||||||
@ -692,19 +743,11 @@ my_api_trans_conn_in(struct trans *trans, struct trans *new_trans)
|
|||||||
{
|
{
|
||||||
LOG(10, ("my_api_trans_conn_in: found it at %d", index));
|
LOG(10, ("my_api_trans_conn_in: found it at %d", index));
|
||||||
ad->chan_id = g_chan_items[index].id;
|
ad->chan_id = g_chan_items[index].id;
|
||||||
found = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(10, ("my_api_trans_conn_in: found %d", found));
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
ad->chan_id = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_trans->callback_data = ad;
|
new_trans->callback_data = ad;
|
||||||
|
|
||||||
trans_delete(g_api_con_trans);
|
trans_delete(g_api_con_trans);
|
||||||
@ -759,7 +802,7 @@ setup_api_listen(void)
|
|||||||
char port[256];
|
char port[256];
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
g_api_lis_trans = trans_create(2, 8192, 8192);
|
g_api_lis_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192);
|
||||||
g_snprintf(port, 255, "/tmp/.xrdp/xrdpapi_%d", g_display_num);
|
g_snprintf(port, 255, "/tmp/.xrdp/xrdpapi_%d", g_display_num);
|
||||||
g_api_lis_trans->trans_conn_in = my_api_trans_conn_in;
|
g_api_lis_trans->trans_conn_in = my_api_trans_conn_in;
|
||||||
error = trans_listen(g_api_lis_trans, port);
|
error = trans_listen(g_api_lis_trans, port);
|
||||||
@ -1206,3 +1249,68 @@ main(int argc, char **argv)
|
|||||||
g_deinit();
|
g_deinit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return unused slot in dvc_channels[]
|
||||||
|
*
|
||||||
|
* @return unused slot index on success, -1 on failure
|
||||||
|
******************************************************************************/
|
||||||
|
int APP_CC
|
||||||
|
find_empty_slot_in_dvc_channels()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
if (g_dvc_channels[i] == NULL)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return struct xrdp_api_data that contains specified dvc_chan_id
|
||||||
|
*
|
||||||
|
* @param dvc_chan_id channel id to look for
|
||||||
|
*
|
||||||
|
* @return xrdp_api_data struct containing dvc_chan_id or NULL on failure
|
||||||
|
******************************************************************************/
|
||||||
|
struct xrdp_api_data *APP_CC
|
||||||
|
struct_from_dvc_chan_id(uint32_t dvc_chan_id)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
if (g_dvc_channels[i]->dvc_chan_id == dvc_chan_id)
|
||||||
|
{
|
||||||
|
return g_dvc_channels[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
remove_struct_with_chan_id(uint32_t dvc_chan_id)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (dvc_chan_id < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_DVC_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
if (g_dvc_channels[i]->dvc_chan_id == dvc_chan_id)
|
||||||
|
{
|
||||||
|
g_dvc_channels[i] = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* xrdp: A Remote Desktop Protocol server.
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
*
|
*
|
||||||
* Copyright (C) Jay Sorg 2009-2012
|
* Copyright (C) Jay Sorg 2009-2012
|
||||||
|
* Copyright (C) Laxmikant Rashinkar 2009-2012
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -19,10 +20,13 @@
|
|||||||
#if !defined(CHANSRV_H)
|
#if !defined(CHANSRV_H)
|
||||||
#define CHANSRV_H
|
#define CHANSRV_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
#define MAX_DVC_CHANNELS 32
|
||||||
|
|
||||||
struct chan_out_data
|
struct chan_out_data
|
||||||
{
|
{
|
||||||
struct stream *s;
|
struct stream *s;
|
||||||
@ -38,10 +42,24 @@ struct chan_item
|
|||||||
struct chan_out_data *tail;
|
struct chan_out_data *tail;
|
||||||
};
|
};
|
||||||
|
|
||||||
int APP_CC
|
/* data in struct trans::callback_data */
|
||||||
send_channel_data(int chan_id, char* data, int size);
|
struct xrdp_api_data
|
||||||
int APP_CC
|
{
|
||||||
main_cleanup(void);
|
int chan_id;
|
||||||
|
char header[64];
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
/* for dynamic virtual channels */
|
||||||
|
struct trans *transp;
|
||||||
|
uint32_t dvc_chan_id;
|
||||||
|
int is_connected;
|
||||||
|
};
|
||||||
|
|
||||||
|
int APP_CC send_channel_data(int chan_id, char *data, int size);
|
||||||
|
int APP_CC main_cleanup(void);
|
||||||
|
int APP_CC find_empty_slot_in_dvc_channels();
|
||||||
|
struct xrdp_api_data *APP_CC struct_from_dvc_chan_id(uint32_t dvc_chan_id);
|
||||||
|
int remove_struct_with_chan_id(uint32_t dvc_chan_id);
|
||||||
|
|
||||||
#define LOG_LEVEL 5
|
#define LOG_LEVEL 5
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* xrdp: A Remote Desktop Protocol server.
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
*
|
*
|
||||||
* Copyright (C) Jay Sorg 2012
|
* Copyright (C) Laxmikant Rashinkar 2012 LK.Rashinkar@gmail.com
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -15,3 +15,502 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "drdynvc.h"
|
||||||
|
|
||||||
|
int g_drdynvc_chan_id;
|
||||||
|
int g_drdynvc_inited = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bring up dynamic virtual channel
|
||||||
|
*
|
||||||
|
* @return 0 on success, -1 on response
|
||||||
|
******************************************************************************/
|
||||||
|
int APP_CC
|
||||||
|
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 APP_CC
|
||||||
|
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 APP_CC
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
LOG(0, ("drdynvc_process_capability_response: incompatible DVC version %d detected", cap_version));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(0, ("drdynvc_process_capability_response: DVC version 2 selected"));
|
||||||
|
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 APP_CC
|
||||||
|
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 APP_CC
|
||||||
|
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 APP_CC
|
||||||
|
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 APP_CC
|
||||||
|
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 APP_CC 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 APP_CC
|
||||||
|
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 data_len;
|
||||||
|
int Len;
|
||||||
|
|
||||||
|
drdynvc_get_chan_id(s, cmd, &chan_id);
|
||||||
|
|
||||||
|
Len = (cmd >> 2) & 0x03;
|
||||||
|
|
||||||
|
if (Len == 0)
|
||||||
|
{
|
||||||
|
in_uint8(s, data_len);
|
||||||
|
}
|
||||||
|
else if (Len == 1)
|
||||||
|
{
|
||||||
|
in_uint16_le(s, data_len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
in_uint32_le(s, data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 APP_CC
|
||||||
|
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 chand_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 APP_CC
|
||||||
|
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 APP_CC
|
||||||
|
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 APP_CC
|
||||||
|
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,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* xrdp: A Remote Desktop Protocol server.
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
*
|
*
|
||||||
* Copyright (C) Jay Sorg 2012
|
* Copyright (C) Laxmikant Rashinkar 2012 LK.Rashinkar@gmail.com
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -16,10 +16,72 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(DRDYNVC_H)
|
#ifndef _DRDYNVC_H_
|
||||||
#define DRDYNVC_H
|
#define _DRDYNVC_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
#include "parse.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 APP_CC drdynvc_init(void);
|
||||||
|
|
||||||
|
static int APP_CC drdynvc_send_capability_request(uint16_t version);
|
||||||
|
static int APP_CC drdynvc_process_capability_response(struct stream* s,
|
||||||
|
unsigned char cmd);
|
||||||
|
|
||||||
|
int APP_CC drdynvc_send_open_channel_request(int chan_pri, unsigned int chan_id,
|
||||||
|
char *chan_name);
|
||||||
|
|
||||||
|
static int APP_CC drdynvc_process_open_channel_response(struct stream *s,
|
||||||
|
unsigned char cmd);
|
||||||
|
|
||||||
|
int APP_CC drdynvc_send_close_channel_request(unsigned int chan_id);
|
||||||
|
|
||||||
|
static int APP_CC drdynvc_process_close_channel_response(struct stream *s,
|
||||||
|
unsigned char cmd);
|
||||||
|
|
||||||
|
int APP_CC drdynvc_write_data(uint32_t chan_id, char *data, int data_size);
|
||||||
|
|
||||||
|
int APP_CC drdynvc_data_in(struct stream* s, int chan_id, int chan_flags,
|
||||||
|
int length, int total_length);
|
||||||
|
|
||||||
|
static int APP_CC drdynvc_process_data_first(struct stream* s, unsigned char cmd);
|
||||||
|
static int APP_CC drdynvc_process_data(struct stream* s, unsigned char cmd);
|
||||||
|
|
||||||
|
static int APP_CC drdynvc_insert_uint_124(struct stream *s, uint32_t val);
|
||||||
|
static int APP_CC drdynvc_get_chan_id(struct stream *s, char cmd, uint32_t *chan_id_p);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
193
xrdpapi/simple.c
193
xrdpapi/simple.c
@ -1,7 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* xrdp: A Remote Desktop Protocol server.
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
*
|
*
|
||||||
* Copyright (C) Jay Sorg 2004-2012
|
* Copyright (C) Jay Sorg 2012
|
||||||
|
* Copyright (C) Laxmikant Rashinkar 2012
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -14,13 +15,20 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* sample program to demonstrate use of xrdpapi
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic test for virtual channel use
|
* build instructions:
|
||||||
|
* gcc simple.c -o simple -L./.libs -lxrdpapi
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// These headers are required for the windows terminal services calls.
|
#ifdef __WIN32__
|
||||||
|
#include <mstsapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "xrdpapi.h"
|
#include "xrdpapi.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -28,92 +36,143 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#define DSIZE (1024 * 4)
|
/* forward declarations */
|
||||||
|
int run_echo_test();
|
||||||
|
int run_tsmf_test();
|
||||||
|
|
||||||
int main()
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
if (argc < 2)
|
||||||
// Initialize the data for send/receive
|
|
||||||
void *hFile;
|
|
||||||
char *data;
|
|
||||||
char *data1;
|
|
||||||
data = (char *)malloc(DSIZE);
|
|
||||||
data1 = (char *)malloc(DSIZE);
|
|
||||||
int ret;
|
|
||||||
void *vcFileHandlePtr = NULL;
|
|
||||||
memset(data, 0xca, DSIZE);
|
|
||||||
memset(data1, 0, DSIZE);
|
|
||||||
unsigned int written = 0;
|
|
||||||
|
|
||||||
// Open the skel channel in current session
|
|
||||||
|
|
||||||
//void* channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "skel", 0);
|
|
||||||
void *channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "TSMF", WTS_CHANNEL_OPTION_DYNAMIC);
|
|
||||||
ret = WTSVirtualChannelQuery(channel, WTSVirtualFileHandle, vcFileHandlePtr, &written);
|
|
||||||
|
|
||||||
// Write the data to the channel
|
|
||||||
ret = WTSVirtualChannelWrite(channel, data, DSIZE, &written);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
{
|
{
|
||||||
|
printf("usage: simple <echo|tsmf>\n");
|
||||||
long err = errno;
|
|
||||||
printf("error 1 0x%8.8x\n", err);
|
|
||||||
usleep(100000);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcasecmp(argv[1], "echo") == 0)
|
||||||
|
{
|
||||||
|
return run_echo_test();
|
||||||
|
}
|
||||||
|
else if (strcasecmp(argv[1], "tsmf") == 0)
|
||||||
|
{
|
||||||
|
return run_tsmf_test();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Sent bytes!\n");
|
printf("usage: simple <echo|tsmf>\n");
|
||||||
}
|
|
||||||
|
|
||||||
if (written != DSIZE)
|
|
||||||
{
|
|
||||||
long err = errno;
|
|
||||||
printf("error 2 0x%8.8x\n", err);
|
|
||||||
usleep(100000);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Read bytes!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = WTSVirtualChannelRead(channel, 100, data1, DSIZE, &written);
|
/**
|
||||||
|
* perform an ECHO test with a Microsoft Windows RDP client
|
||||||
if (!ret)
|
*
|
||||||
|
* A Microsoft Windows RDP client echos data written
|
||||||
|
* to a dynamic virtual channel named ECHO
|
||||||
|
*
|
||||||
|
* NOTE: THIS TEST WILL FAIL IF CONNECTED FROM A NON
|
||||||
|
* WINDOWS RDP CLIENT
|
||||||
|
*
|
||||||
|
* @return 0 on success, -1 on failure
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
run_echo_test()
|
||||||
{
|
{
|
||||||
long err = errno;
|
char out_buf[8192];
|
||||||
printf("error 3 0x%8.8x\n", err);
|
char in_buf[1700];
|
||||||
usleep(100000);
|
void *channel;
|
||||||
return 1;
|
int bytes_left;
|
||||||
|
int rv;
|
||||||
|
int count;
|
||||||
|
int pkt_count;
|
||||||
|
int i;
|
||||||
|
int bytes_written;
|
||||||
|
int bytes_read;
|
||||||
|
|
||||||
|
unsigned char c;
|
||||||
|
unsigned char *rd_ptr;
|
||||||
|
unsigned char *wr_ptr;
|
||||||
|
|
||||||
|
/* fill out_buf[] with incremental values */
|
||||||
|
for (i = 0, c = 0; i < 8192; i++, c++)
|
||||||
|
{
|
||||||
|
out_buf[i] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (written != DSIZE)
|
/* open a virtual channel named ECHO */
|
||||||
|
channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "ECHO", WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW);
|
||||||
|
if (channel == NULL)
|
||||||
{
|
{
|
||||||
long err = errno;
|
printf("### WTSVirtualChannelOpenEx() failed!\n");
|
||||||
printf("error 4 0x%8.8x\n", err);
|
return -1;
|
||||||
usleep(100000);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Read bytes!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = WTSVirtualChannelClose(channel);
|
bytes_left = 8192;
|
||||||
|
wr_ptr = out_buf;
|
||||||
|
rd_ptr = out_buf;
|
||||||
|
pkt_count = 1;
|
||||||
|
|
||||||
if (memcmp(data, data1, DSIZE) == 0)
|
while (bytes_left > 0)
|
||||||
{
|
{
|
||||||
}
|
/* write data to virtual channel */
|
||||||
else
|
count = (bytes_left > 1700) ? 1700 : bytes_left;
|
||||||
|
rv = WTSVirtualChannelWrite(channel, wr_ptr, count, &bytes_written);
|
||||||
|
if ((rv == 0) || (bytes_written == 0))
|
||||||
{
|
{
|
||||||
printf("error data no match\n");
|
printf("### WTSVirtualChannelWrite() failed\n");
|
||||||
return 1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Done!\n");
|
count = bytes_written;
|
||||||
|
|
||||||
usleep(100000);
|
while (count)
|
||||||
|
{
|
||||||
|
/* read back the echo */
|
||||||
|
rv = WTSVirtualChannelRead(channel, 5000, in_buf, count, &bytes_read);
|
||||||
|
if ((rv == 0) || (bytes_read == 0))
|
||||||
|
{
|
||||||
|
printf("### WTSVirtualChannelRead() failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* validate the echo */
|
||||||
|
for (i = 0; i < bytes_read; i++, rd_ptr++)
|
||||||
|
{
|
||||||
|
if (*rd_ptr != (unsigned char) in_buf[i])
|
||||||
|
{
|
||||||
|
printf("### data mismatch: expected 0x%x got 0x%x\n",
|
||||||
|
(unsigned char) *rd_ptr, (unsigned char) in_buf[i]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count -= bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_left -= bytes_written;
|
||||||
|
wr_ptr += bytes_written;
|
||||||
|
printf("### pkt %d passed echo test\n", pkt_count++);
|
||||||
|
}
|
||||||
|
|
||||||
|
WTSVirtualChannelClose(channel);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
run_tsmf_test()
|
||||||
|
{
|
||||||
|
void *channel;
|
||||||
|
|
||||||
|
printf("this test not yet implemented!\n");
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* open virtual channel */
|
||||||
|
channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "TSMF", WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW);
|
||||||
|
if (channel == NULL)
|
||||||
|
{
|
||||||
|
printf("### WTSVirtualChannelOpenEx() failed!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
WTSVirtualChannelClose(channel);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* xrdp: A Remote Desktop Protocol server.
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
*
|
*
|
||||||
* Copyright (C) Thomas Goddard 2012
|
|
||||||
* Copyright (C) Jay Sorg 2012
|
* Copyright (C) Jay Sorg 2012
|
||||||
|
* Copyright (C) Laxmikant Rashinkar 2012
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -17,8 +17,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* do not use os_calls in here */
|
|
||||||
|
|
||||||
#define LOG_LEVEL 1
|
#define LOG_LEVEL 1
|
||||||
#define LLOG(_level, _args) \
|
#define LLOG(_level, _args) \
|
||||||
do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0)
|
do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0)
|
||||||
@ -29,6 +27,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -45,64 +44,26 @@ struct wts_obj
|
|||||||
char name[8];
|
char name[8];
|
||||||
char dname[128];
|
char dname[128];
|
||||||
int display_num;
|
int display_num;
|
||||||
int flags;
|
uint32_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/* helper functions used by WTSxxx API - do not invoke directly */
|
||||||
static int
|
static int get_display_num_from_display(char *display_text);
|
||||||
get_display_num_from_display(char *display_text)
|
static int send_init(struct wts_obj *wts);
|
||||||
{
|
static int can_send(int sck, int millis);
|
||||||
int index;
|
static int can_recv(int sck, int millis);
|
||||||
int mode;
|
|
||||||
int host_index;
|
|
||||||
int disp_index;
|
|
||||||
int scre_index;
|
|
||||||
char host[256];
|
|
||||||
char disp[256];
|
|
||||||
char scre[256];
|
|
||||||
|
|
||||||
index = 0;
|
/*
|
||||||
host_index = 0;
|
* Opens a handle to the server end of a specified virtual channel - this
|
||||||
disp_index = 0;
|
* call is deprecated - use WTSVirtualChannelOpenEx() instead
|
||||||
scre_index = 0;
|
*
|
||||||
mode = 0;
|
* @param hServer
|
||||||
|
* @param SessionId - current session ID; *must* be WTS_CURRENT_SERVER_HANDLE
|
||||||
while (display_text[index] != 0)
|
* @param pVirtualName - virtual channel name when using SVC
|
||||||
{
|
* - name of endpoint listener when using DVC
|
||||||
if (display_text[index] == ':')
|
*
|
||||||
{
|
* @return a valid pointer on success, NULL on error
|
||||||
mode = 1;
|
******************************************************************************/
|
||||||
}
|
|
||||||
else if (display_text[index] == '.')
|
|
||||||
{
|
|
||||||
mode = 2;
|
|
||||||
}
|
|
||||||
else if (mode == 0)
|
|
||||||
{
|
|
||||||
host[host_index] = display_text[index];
|
|
||||||
host_index++;
|
|
||||||
}
|
|
||||||
else if (mode == 1)
|
|
||||||
{
|
|
||||||
disp[disp_index] = display_text[index];
|
|
||||||
disp_index++;
|
|
||||||
}
|
|
||||||
else if (mode == 2)
|
|
||||||
{
|
|
||||||
scre[scre_index] = display_text[index];
|
|
||||||
scre_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
host[host_index] = 0;
|
|
||||||
disp[disp_index] = 0;
|
|
||||||
scre[scre_index] = 0;
|
|
||||||
return atoi(disp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
void *
|
void *
|
||||||
WTSVirtualChannelOpen(void *hServer, unsigned int SessionId,
|
WTSVirtualChannelOpen(void *hServer, unsigned int SessionId,
|
||||||
const char *pVirtualName)
|
const char *pVirtualName)
|
||||||
@ -115,98 +76,34 @@ WTSVirtualChannelOpen(void *hServer, unsigned int SessionId,
|
|||||||
return WTSVirtualChannelOpenEx(SessionId, pVirtualName, 0);
|
return WTSVirtualChannelOpenEx(SessionId, pVirtualName, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*
|
||||||
static int
|
* Opens a handle to the server end of a specified virtual channel
|
||||||
can_send(int sck, int millis)
|
*
|
||||||
{
|
* @param SessionId - current session ID; *must* be WTS_CURRENT_SERVER_HANDLE
|
||||||
struct timeval time;
|
* @param pVirtualName - virtual channel name when using SVC
|
||||||
fd_set wfds;
|
* - name of endpoint listener when using DVC
|
||||||
int select_rv;
|
* @param flags - type of channel and channel priority if DVC
|
||||||
|
*
|
||||||
FD_ZERO(&wfds);
|
* @return a valid pointer on success, NULL on error
|
||||||
FD_SET(sck, &wfds);
|
******************************************************************************/
|
||||||
time.tv_sec = millis / 1000;
|
|
||||||
time.tv_usec = (millis * 1000) % 1000000;
|
|
||||||
select_rv = select(sck + 1, 0, &wfds, 0, &time);
|
|
||||||
|
|
||||||
if (select_rv > 0)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int
|
|
||||||
can_recv(int sck, int millis)
|
|
||||||
{
|
|
||||||
struct timeval time;
|
|
||||||
fd_set rfds;
|
|
||||||
int select_rv;
|
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
|
||||||
FD_SET(sck, &rfds);
|
|
||||||
time.tv_sec = millis / 1000;
|
|
||||||
time.tv_usec = (millis * 1000) % 1000000;
|
|
||||||
select_rv = select(sck + 1, &rfds, 0, 0, &time);
|
|
||||||
|
|
||||||
if (select_rv > 0)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int
|
|
||||||
send_init(struct wts_obj *wts)
|
|
||||||
{
|
|
||||||
char initmsg[64];
|
|
||||||
|
|
||||||
memset(initmsg, 0, 64);
|
|
||||||
strncpy(initmsg, wts->name, 8);
|
|
||||||
initmsg[16] = (wts->flags >> 0) & 0xff;
|
|
||||||
initmsg[17] = (wts->flags >> 8) & 0xff;
|
|
||||||
initmsg[18] = (wts->flags >> 16) & 0xff;
|
|
||||||
initmsg[19] = (wts->flags >> 24) & 0xff;
|
|
||||||
LLOGLN(10, ("send_init: sending %s", initmsg));
|
|
||||||
|
|
||||||
if (!can_send(wts->fd, 500))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (send(wts->fd, initmsg, 64, 0) != 64)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
LLOGLN(10, ("send_init: send ok!"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
void *
|
void *
|
||||||
WTSVirtualChannelOpenEx(unsigned int SessionId,
|
WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
|
||||||
const char *pVirtualName,
|
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct wts_obj *wts;
|
struct wts_obj *wts;
|
||||||
char *display_text;
|
char *display_text;
|
||||||
struct sockaddr_un s;
|
|
||||||
int bytes;
|
int bytes;
|
||||||
unsigned long llong;
|
unsigned long llong;
|
||||||
|
struct sockaddr_un s;
|
||||||
|
|
||||||
if (SessionId != WTS_CURRENT_SESSION)
|
if (SessionId != WTS_CURRENT_SESSION)
|
||||||
{
|
{
|
||||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: SessionId bad"));
|
LLOGLN(0, ("WTSVirtualChannelOpenEx: bad SessionId"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
wts = (struct wts_obj *)malloc(sizeof(struct wts_obj));
|
wts = (struct wts_obj *) calloc(1, sizeof(struct wts_obj));
|
||||||
memset(wts, 0, sizeof(struct wts_obj));
|
|
||||||
wts->fd = -1;
|
wts->fd = -1;
|
||||||
wts->flags = flags;
|
wts->flags = flags;
|
||||||
display_text = getenv("DISPLAY");
|
display_text = getenv("DISPLAY");
|
||||||
@ -216,14 +113,22 @@ WTSVirtualChannelOpenEx(unsigned int SessionId,
|
|||||||
wts->display_num = get_display_num_from_display(display_text);
|
wts->display_num = get_display_num_from_display(display_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wts->display_num > 0)
|
if (wts->display_num <= 0)
|
||||||
{
|
{
|
||||||
|
LLOGLN(0, ("WTSVirtualChannelOpenEx: fatal errror; display is 0"));
|
||||||
|
free(wts);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we use unix domain socket to communicate with chansrv */
|
||||||
wts->fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
wts->fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
/* set non blocking */
|
/* set non blocking */
|
||||||
llong = fcntl(wts->fd, F_GETFL);
|
llong = fcntl(wts->fd, F_GETFL);
|
||||||
llong = llong | O_NONBLOCK;
|
llong = llong | O_NONBLOCK;
|
||||||
fcntl(wts->fd, F_SETFL, llong);
|
fcntl(wts->fd, F_SETFL, llong);
|
||||||
/* connect to session chansrv */
|
|
||||||
|
/* connect to chansrv session */
|
||||||
memset(&s, 0, sizeof(struct sockaddr_un));
|
memset(&s, 0, sizeof(struct sockaddr_un));
|
||||||
s.sun_family = AF_UNIX;
|
s.sun_family = AF_UNIX;
|
||||||
bytes = sizeof(s.sun_path);
|
bytes = sizeof(s.sun_path);
|
||||||
@ -243,11 +148,6 @@ WTSVirtualChannelOpenEx(unsigned int SessionId,
|
|||||||
wts->status = 1;
|
wts->status = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LLOGLN(0, ("WTSVirtualChannelOpenEx: display is 0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return wts;
|
return wts;
|
||||||
}
|
}
|
||||||
@ -312,7 +212,7 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
|
|||||||
unsigned int *pBytesRead)
|
unsigned int *pBytesRead)
|
||||||
{
|
{
|
||||||
struct wts_obj *wts;
|
struct wts_obj *wts;
|
||||||
int error;
|
int rv;
|
||||||
int lerrno;
|
int lerrno;
|
||||||
|
|
||||||
wts = (struct wts_obj *)hChannelHandle;
|
wts = (struct wts_obj *)hChannelHandle;
|
||||||
@ -329,9 +229,9 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
|
|||||||
|
|
||||||
if (can_recv(wts->fd, TimeOut))
|
if (can_recv(wts->fd, TimeOut))
|
||||||
{
|
{
|
||||||
error = recv(wts->fd, Buffer, BufferSize, 0);
|
rv = recv(wts->fd, Buffer, BufferSize, 0);
|
||||||
|
|
||||||
if (error == -1)
|
if (rv == -1)
|
||||||
{
|
{
|
||||||
lerrno = errno;
|
lerrno = errno;
|
||||||
|
|
||||||
@ -341,16 +241,15 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
|
|||||||
*pBytesRead = 0;
|
*pBytesRead = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (error == 0)
|
else if (rv == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (error > 0)
|
else if (rv > 0)
|
||||||
{
|
{
|
||||||
*pBytesRead = error;
|
*pBytesRead = rv;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -419,3 +318,148 @@ WTSFreeMemory(void *pMemory)
|
|||||||
free(pMemory);
|
free(pMemory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
** **
|
||||||
|
** **
|
||||||
|
** Helper functions used by WTSxxx API - do not invoke directly **
|
||||||
|
** **
|
||||||
|
** **
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check if socket is in a writable state - i.e will not block on write
|
||||||
|
*
|
||||||
|
* @param sck socket to check
|
||||||
|
* @param millis timeout value in milliseconds
|
||||||
|
*
|
||||||
|
* @return 0 if write will block
|
||||||
|
* @return 1 if write will not block
|
||||||
|
******************************************************************************/
|
||||||
|
static int
|
||||||
|
can_send(int sck, int millis)
|
||||||
|
{
|
||||||
|
struct timeval time;
|
||||||
|
fd_set wfds;
|
||||||
|
int select_rv;
|
||||||
|
|
||||||
|
/* setup for a select call */
|
||||||
|
FD_ZERO(&wfds);
|
||||||
|
FD_SET(sck, &wfds);
|
||||||
|
time.tv_sec = millis / 1000;
|
||||||
|
time.tv_usec = (millis * 1000) % 1000000;
|
||||||
|
|
||||||
|
/* check if it is ok to write to specified socket */
|
||||||
|
select_rv = select(sck + 1, 0, &wfds, 0, &time);
|
||||||
|
|
||||||
|
return (select_rv > 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
static int
|
||||||
|
can_recv(int sck, int millis)
|
||||||
|
{
|
||||||
|
struct timeval time;
|
||||||
|
fd_set rfds;
|
||||||
|
int select_rv;
|
||||||
|
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(sck, &rfds);
|
||||||
|
time.tv_sec = millis / 1000;
|
||||||
|
time.tv_usec = (millis * 1000) % 1000000;
|
||||||
|
select_rv = select(sck + 1, &rfds, 0, 0, &time);
|
||||||
|
|
||||||
|
if (select_rv > 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
int mode;
|
||||||
|
int host_index;
|
||||||
|
int disp_index;
|
||||||
|
int scre_index;
|
||||||
|
char host[256];
|
||||||
|
char disp[256];
|
||||||
|
char scre[256];
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
host_index = 0;
|
||||||
|
disp_index = 0;
|
||||||
|
scre_index = 0;
|
||||||
|
mode = 0;
|
||||||
|
|
||||||
|
while (display_text[index] != 0)
|
||||||
|
{
|
||||||
|
if (display_text[index] == ':')
|
||||||
|
{
|
||||||
|
mode = 1;
|
||||||
|
}
|
||||||
|
else if (display_text[index] == '.')
|
||||||
|
{
|
||||||
|
mode = 2;
|
||||||
|
}
|
||||||
|
else if (mode == 0)
|
||||||
|
{
|
||||||
|
host[host_index] = display_text[index];
|
||||||
|
host_index++;
|
||||||
|
}
|
||||||
|
else if (mode == 1)
|
||||||
|
{
|
||||||
|
disp[disp_index] = display_text[index];
|
||||||
|
disp_index++;
|
||||||
|
}
|
||||||
|
else if (mode == 2)
|
||||||
|
{
|
||||||
|
scre[scre_index] = display_text[index];
|
||||||
|
scre_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
host[host_index] = 0;
|
||||||
|
disp[disp_index] = 0;
|
||||||
|
scre[scre_index] = 0;
|
||||||
|
return atoi(disp);
|
||||||
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* xrdp: A Remote Desktop Protocol server.
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
*
|
*
|
||||||
* Copyright (C) Thomas Goddard 2012
|
|
||||||
* Copyright (C) Jay Sorg 2012
|
* Copyright (C) Jay Sorg 2012
|
||||||
|
* Copyright (C) Thomas Goddard 2012
|
||||||
|
* Copyright (C) Laxmikant Rashinkar 2012
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -29,14 +30,16 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WTS_CURRENT_SERVER_HANDLE 0
|
#define WTS_CURRENT_SERVER_HANDLE 0x00000000
|
||||||
#define WTS_CURRENT_SESSION 0xffffffff
|
#define WTS_CURRENT_SESSION 0xffffffff
|
||||||
|
|
||||||
|
#define WTS_CHANNEL_OPTION_STATIC 0x00000000
|
||||||
#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001
|
#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001
|
||||||
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW 0x00000000
|
#define WTS_CHANNEL_OPTION_DYNAMIC_NO_COMPRESS 0x00000001
|
||||||
|
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW 0x00000001
|
||||||
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED 0x00000002
|
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED 0x00000002
|
||||||
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_HIGH 0x00000004
|
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_HIGH 0x00000003
|
||||||
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL 0x00000006
|
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL 0x00000004
|
||||||
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_COMPRESS 0x00000008
|
|
||||||
|
|
||||||
typedef enum _WTS_VIRTUAL_CLASS
|
typedef enum _WTS_VIRTUAL_CLASS
|
||||||
{
|
{
|
||||||
@ -45,30 +48,29 @@ typedef enum _WTS_VIRTUAL_CLASS
|
|||||||
} WTS_VIRTUAL_CLASS;
|
} WTS_VIRTUAL_CLASS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reference:
|
* Reference:
|
||||||
http://msdn.microsoft.com/en-us/library/windows/desktop/aa383464(v=vs.85).aspx
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa383464(v=vs.85).aspx
|
||||||
*/
|
*/
|
||||||
void*
|
|
||||||
WTSVirtualChannelOpen(void* hServer, unsigned int SessionId,
|
void* WTSVirtualChannelOpen(void* hServer, unsigned int SessionId,
|
||||||
const char* pVirtualName);
|
const char* pVirtualName);
|
||||||
void*
|
|
||||||
WTSVirtualChannelOpenEx(unsigned int SessionId,
|
void* WTSVirtualChannelOpenEx(unsigned int SessionId,
|
||||||
const char* pVirtualName,
|
const char* pVirtualName, unsigned int flags);
|
||||||
unsigned int flags);
|
|
||||||
int
|
int WTSVirtualChannelWrite(void* hChannelHandle, const char* Buffer,
|
||||||
WTSVirtualChannelWrite(void* hChannelHandle, const char* Buffer,
|
|
||||||
unsigned int Length, unsigned int* pBytesWritten);
|
unsigned int Length, unsigned int* pBytesWritten);
|
||||||
int
|
|
||||||
WTSVirtualChannelRead(void* hChannelHandle, unsigned int TimeOut,
|
int WTSVirtualChannelRead(void* hChannelHandle, unsigned int TimeOut,
|
||||||
char* Buffer, unsigned int BufferSize,
|
char* Buffer, unsigned int BufferSize,
|
||||||
unsigned int* pBytesRead);
|
unsigned int* pBytesRead);
|
||||||
int
|
|
||||||
WTSVirtualChannelClose(void* hChannelHandle);
|
int WTSVirtualChannelClose(void* hChannelHandle);
|
||||||
int
|
|
||||||
WTSVirtualChannelQuery(void* hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
|
int WTSVirtualChannelQuery(void* hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
|
||||||
void** ppBuffer, unsigned int* pBytesReturned);
|
void** ppBuffer, unsigned int* pBytesReturned);
|
||||||
void
|
|
||||||
WTSFreeMemory(void* pMemory);
|
void WTSFreeMemory(void* pMemory);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user