summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sesman/chansrv/chansrv.c216
-rw-r--r--sesman/chansrv/chansrv.h74
-rw-r--r--sesman/chansrv/drdynvc.c501
-rw-r--r--sesman/chansrv/drdynvc.h70
-rw-r--r--xrdpapi/simple.c189
-rw-r--r--xrdpapi/xrdpapi.c406
-rw-r--r--xrdpapi/xrdpapi.h72
7 files changed, 1160 insertions, 368 deletions
diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c
index 0f69f1f6..392d6eff 100644
--- a/sesman/chansrv/chansrv.c
+++ b/sesman/chansrv/chansrv.c
@@ -2,6 +2,7 @@
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2009-2012
+ * Copyright (C) Laxmikant Rashinkar 2009-2012
*
* Licensed under the Apache License, Version 2.0 (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_rdpdr_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_thread_done_event = 0;
@@ -50,9 +55,10 @@ static int g_use_unix_socket = 0;
int g_display_num = 0;
int g_cliprdr_chan_id = -1; /* cliprdr */
-int g_rdpsnd_chan_id = -1; /* rdpsnd */
-int g_rdpdr_chan_id = -1; /* rdpdr */
-int g_rail_chan_id = -1; /* rail */
+int g_rdpsnd_chan_id = -1; /* rdpsnd */
+int g_rdpdr_chan_id = -1; /* rdpdr */
+int g_rail_chan_id = -1; /* rail */
+int g_drdynvc_chan_id = -1; /* drdynvc */
char *g_exec_name;
tbus g_exec_event;
@@ -60,13 +66,9 @@ tbus g_exec_mutex;
tbus g_exec_sem;
int g_exec_pid = 0;
-/* data in struct trans::callback_data */
-struct xrdp_api_data
-{
- int chan_id;
- char header[64];
- int flags;
-};
+/* each time we create a DVC we need a unique DVC channel id */
+/* this variable gets bumped up once per DVC we create */
+uint32_t g_dvc_chan_id = 100;
/*****************************************************************************/
/* 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_rdpdr_chan_id = -1;
g_rail_chan_id = -1;
+ g_drdynvc_chan_id = -1;
LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup:"));
in_uint16_le(s, num_chans);
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_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
{
LOG(10, ("other %s", ci->name));
@@ -375,6 +383,12 @@ process_message_channel_setup(struct stream *s)
rail_init();
}
+ if (g_drdynvc_index >= 0)
+ {
+ memset(&g_dvc_channels[0], 0, sizeof(g_dvc_channels));
+ drdynvc_init();
+ }
+
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);
}
+ 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 *)
(g_api_con_trans->callback_data))->chan_id)
{
@@ -550,13 +568,15 @@ my_trans_data_in(struct trans *trans)
return error;
}
-/*****************************************************************************/
-/* returns error */
+/*
+ * called when WTSVirtualChannelWrite() is invoked in xrdpapi.c
+ *
+ ******************************************************************************/
int DEFAULT_CC
my_api_trans_data_in(struct trans *trans)
{
- struct stream *s;
- int error;
+ struct stream *s;
+ int bytes_read;
struct xrdp_api_data *ad;
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:"));
+
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));
- ad = (struct xrdp_api_data *)(trans->callback_data);
+ LOG(10, ("my_api_trans_data_in: got data %d", bytes_read));
+ 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)
{
- LOG(0, ("my_api_trans_data_in: send_channel_data failed"));
+ /* 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"));
+ }
+ }
+ else
+ {
+ /* writing data to a dynamic virtual channel */
+ drdynvc_write_data(ad->dvc_chan_id, s->data, bytes_read);
}
}
else
{
- LOG(10, ("my_api_trans_data_in: g_tcp_recv failed, or disconnected"));
+ 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;
}
@@ -628,37 +670,30 @@ my_trans_conn_in(struct trans *trans, struct trans *new_trans)
return 0;
}
-/*****************************************************************************/
+/*
+ * called when WTSVirtualChannelOpenEx is invoked in xrdpapi.c
+ *
+ ******************************************************************************/
int DEFAULT_CC
my_api_trans_conn_in(struct trans *trans, struct trans *new_trans)
{
struct xrdp_api_data *ad;
- int error;
- int index;
- int found;
- struct stream *s;
-
- if (trans == 0)
- {
- return 1;
- }
+ struct stream *s;
+ int error;
+ int index;
+ char chan_pri;
- if (trans != g_api_lis_trans)
- {
- return 1;
- }
-
- if (new_trans == 0)
+ if ((trans == 0) || (trans != g_api_lis_trans) || (new_trans == 0))
{
return 1;
}
LOGM((LOG_LEVEL_DEBUG, "my_api_trans_conn_in:"));
-
LOG(10, ("my_api_trans_conn_in: got incoming"));
s = trans_get_in_s(new_trans);
s->end = s->data;
+
error = trans_force_read(new_trans, 64);
if (error != 0)
@@ -669,21 +704,37 @@ my_api_trans_conn_in(struct trans *trans, struct trans *new_trans)
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);
ad->flags = GGET_UINT32(ad->header, 16);
+ ad->chan_id = -1;
+ ad->dvc_chan_id = -1;
- found = 0;
-
- if (ad->flags | 1) /* WTS_CHANNEL_OPTION_DYNAMIC */
+ if (ad->flags > 0)
{
- /* TODO */
- found = 0;
+ /* opening a dynamic virtual channel */
+
+ 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
{
+ /* opening a static virtual channel */
+
for (index = 0; index < g_num_chan_items; index++)
{
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));
ad->chan_id = g_chan_items[index].id;
- found = 1;
break;
}
}
}
- LOG(10, ("my_api_trans_conn_in: found %d", found));
-
- if (!found)
- {
- ad->chan_id = -1;
- }
-
new_trans->callback_data = ad;
trans_delete(g_api_con_trans);
@@ -759,7 +802,7 @@ setup_api_listen(void)
char port[256];
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_api_lis_trans->trans_conn_in = my_api_trans_conn_in;
error = trans_listen(g_api_lis_trans, port);
@@ -1206,3 +1249,68 @@ main(int argc, char **argv)
g_deinit();
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;
+}
diff --git a/sesman/chansrv/chansrv.h b/sesman/chansrv/chansrv.h
index ba593461..78efe29a 100644
--- a/sesman/chansrv/chansrv.h
+++ b/sesman/chansrv/chansrv.h
@@ -2,6 +2,7 @@
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2009-2012
+ * Copyright (C) Laxmikant Rashinkar 2009-2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,60 +20,77 @@
#if !defined(CHANSRV_H)
#define CHANSRV_H
+#include <stdint.h>
#include "arch.h"
#include "parse.h"
#include "log.h"
+#define MAX_DVC_CHANNELS 32
+
struct chan_out_data
{
- struct stream* s;
- struct chan_out_data* next;
+ 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;
+ 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;
+ 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 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(_a, _params) \
-{ \
- if (_a < LOG_LEVEL) \
- { \
- g_write("xrdp-chansrv [%10.10u]: ", g_time3()); \
- g_writeln _params ; \
- } \
-}
+ { \
+ if (_a < LOG_LEVEL) \
+ { \
+ g_write("xrdp-chansrv [%10.10u]: ", g_time3()); \
+ g_writeln _params ; \
+ } \
+ }
#define LOGM(_args) do { log_message _args ; } while (0)
#ifndef GSET_UINT8
#define GSET_UINT8(_ptr, _offset, _data) \
- *((unsigned char*) (((unsigned char*)(_ptr)) + (_offset))) = (unsigned char)(_data)
+ *((unsigned char*) (((unsigned char*)(_ptr)) + (_offset))) = (unsigned char)(_data)
#define GGET_UINT8(_ptr, _offset) \
- (*((unsigned char*) (((unsigned char*)(_ptr)) + (_offset))))
+ (*((unsigned char*) (((unsigned char*)(_ptr)) + (_offset))))
#define GSET_UINT16(_ptr, _offset, _data) \
- GSET_UINT8(_ptr, _offset, _data); \
- GSET_UINT8(_ptr, (_offset) + 1, (_data) >> 8)
+ GSET_UINT8(_ptr, _offset, _data); \
+ GSET_UINT8(_ptr, (_offset) + 1, (_data) >> 8)
#define GGET_UINT16(_ptr, _offset) \
- (GGET_UINT8(_ptr, _offset)) | \
- ((GGET_UINT8(_ptr, (_offset) + 1)) << 8)
+ (GGET_UINT8(_ptr, _offset)) | \
+ ((GGET_UINT8(_ptr, (_offset) + 1)) << 8)
#define GSET_UINT32(_ptr, _offset, _data) \
- GSET_UINT16(_ptr, _offset, _data); \
- GSET_UINT16(_ptr, (_offset) + 2, (_data) >> 16)
+ GSET_UINT16(_ptr, _offset, _data); \
+ GSET_UINT16(_ptr, (_offset) + 2, (_data) >> 16)
#define GGET_UINT32(_ptr, _offset) \
- (GGET_UINT16(_ptr, _offset)) | \
- ((GGET_UINT16(_ptr, (_offset) + 2)) << 16)
+ (GGET_UINT16(_ptr, _offset)) | \
+ ((GGET_UINT16(_ptr, (_offset) + 2)) << 16)
#endif
#endif
diff --git a/sesman/chansrv/drdynvc.c b/sesman/chansrv/drdynvc.c
index da0e8fe3..6bcac45e 100644
--- a/sesman/chansrv/drdynvc.c
+++ b/sesman/chansrv/drdynvc.c
@@ -1,7 +1,7 @@
/**
* 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");
* 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
* 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;
+}
diff --git a/sesman/chansrv/drdynvc.h b/sesman/chansrv/drdynvc.h
index 14237835..fcf46249 100644
--- a/sesman/chansrv/drdynvc.h
+++ b/sesman/chansrv/drdynvc.h
@@ -1,7 +1,7 @@
/**
* 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");
* you may not use this file except in compliance with the License.
@@ -16,10 +16,72 @@
* limitations under the License.
*/
-#if !defined(DRDYNVC_H)
-#define DRDYNVC_H
+#ifndef _DRDYNVC_H_
+#define _DRDYNVC_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.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
diff --git a/xrdpapi/simple.c b/xrdpapi/simple.c
index 7f309ab8..e6f5bd16 100644
--- a/xrdpapi/simple.c
+++ b/xrdpapi/simple.c
@@ -1,7 +1,8 @@
/**
* 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");
* 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.
* See the License for the specific language governing permissions and
* 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 <stdlib.h>
#include <stdio.h>
@@ -28,92 +36,143 @@
#include <string.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)
{
-
- // 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)
+ if (argc < 2)
{
-
- long err = errno;
- printf("error 1 0x%8.8x\n", err);
- usleep(100000);
+ printf("usage: simple <echo|tsmf>\n");
return 1;
}
- else
- {
- printf("Sent bytes!\n");
- }
- if (written != DSIZE)
+ if (strcasecmp(argv[1], "echo") == 0)
{
- long err = errno;
- printf("error 2 0x%8.8x\n", err);
- usleep(100000);
- return 1;
+ return run_echo_test();
}
- else
+ else if (strcasecmp(argv[1], "tsmf") == 0)
{
- printf("Read bytes!\n");
+ return run_tsmf_test();
}
-
- ret = WTSVirtualChannelRead(channel, 100, data1, DSIZE, &written);
-
- if (!ret)
+ else
{
- long err = errno;
- printf("error 3 0x%8.8x\n", err);
- usleep(100000);
+ printf("usage: simple <echo|tsmf>\n");
return 1;
}
+}
- if (written != DSIZE)
+/**
+ * perform an ECHO test with a Microsoft Windows RDP client
+ *
+ * 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()
+{
+ char out_buf[8192];
+ char in_buf[1700];
+ void *channel;
+ 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++)
{
- long err = errno;
- printf("error 4 0x%8.8x\n", err);
- usleep(100000);
- return 1;
+ out_buf[i] = c;
}
- else
+
+ /* open a virtual channel named ECHO */
+ channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "ECHO", WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW);
+ if (channel == NULL)
{
- printf("Read bytes!\n");
+ printf("### WTSVirtualChannelOpenEx() failed!\n");
+ return -1;
}
- 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 */
+ count = (bytes_left > 1700) ? 1700 : bytes_left;
+ rv = WTSVirtualChannelWrite(channel, wr_ptr, count, &bytes_written);
+ if ((rv == 0) || (bytes_written == 0))
+ {
+ printf("### WTSVirtualChannelWrite() failed\n");
+ return -1;
+ }
+
+ count = bytes_written;
+
+ 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++);
}
- else
+
+ 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("error data no match\n");
+ printf("### WTSVirtualChannelOpenEx() failed!\n");
return 1;
}
- printf("Done!\n");
-
- usleep(100000);
- return 0;
+ WTSVirtualChannelClose(channel);
+ return 0;
}
diff --git a/xrdpapi/xrdpapi.c b/xrdpapi/xrdpapi.c
index 85a13a8e..e320ef5d 100644
--- a/xrdpapi/xrdpapi.c
+++ b/xrdpapi/xrdpapi.c
@@ -1,8 +1,8 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
- * Copyright (C) Thomas Goddard 2012
* Copyright (C) Jay Sorg 2012
+ * Copyright (C) Laxmikant Rashinkar 2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,6 @@
* limitations under the License.
*/
-/* do not use os_calls in here */
-
#define LOG_LEVEL 1
#define LLOG(_level, _args) \
do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0)
@@ -29,6 +27,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <stdint.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
@@ -40,69 +39,31 @@
struct wts_obj
{
- int fd;
- int status;
- char name[8];
- char dname[128];
- int display_num;
- int flags;
+ int fd;
+ int status;
+ char name[8];
+ char dname[128];
+ int display_num;
+ uint32_t flags;
};
-/*****************************************************************************/
-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;
+/* 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);
- 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);
-}
-
-/*****************************************************************************/
+/*
+ * Opens a handle to the server end of a specified virtual channel - this
+ * call is deprecated - use WTSVirtualChannelOpenEx() instead
+ *
+ * @param hServer
+ * @param SessionId - current session ID; *must* be WTS_CURRENT_SERVER_HANDLE
+ * @param pVirtualName - virtual channel name when using SVC
+ * - name of endpoint listener when using DVC
+ *
+ * @return a valid pointer on success, NULL on error
+ ******************************************************************************/
void *
WTSVirtualChannelOpen(void *hServer, unsigned int SessionId,
const char *pVirtualName)
@@ -115,98 +76,34 @@ WTSVirtualChannelOpen(void *hServer, unsigned int SessionId,
return WTSVirtualChannelOpenEx(SessionId, pVirtualName, 0);
}
-/*****************************************************************************/
-static int
-can_send(int sck, int millis)
-{
- struct timeval time;
- fd_set wfds;
- int select_rv;
-
- FD_ZERO(&wfds);
- 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;
-}
-
-/*****************************************************************************/
+/*
+ * Opens a handle to the server end of a specified virtual channel
+ *
+ * @param SessionId - current session ID; *must* be WTS_CURRENT_SERVER_HANDLE
+ * @param pVirtualName - virtual channel name when using SVC
+ * - name of endpoint listener when using DVC
+ * @param flags - type of channel and channel priority if DVC
+ *
+ * @return a valid pointer on success, NULL on error
+ ******************************************************************************/
void *
-WTSVirtualChannelOpenEx(unsigned int SessionId,
- const char *pVirtualName,
+WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
unsigned int flags)
{
- struct wts_obj *wts;
- char *display_text;
- struct sockaddr_un s;
- int bytes;
- unsigned long llong;
+ struct wts_obj *wts;
+ char *display_text;
+ int bytes;
+ unsigned long llong;
+ struct sockaddr_un s;
if (SessionId != WTS_CURRENT_SESSION)
{
- LLOGLN(0, ("WTSVirtualChannelOpenEx: SessionId bad"));
+ LLOGLN(0, ("WTSVirtualChannelOpenEx: bad SessionId"));
return 0;
}
- wts = (struct wts_obj *)malloc(sizeof(struct wts_obj));
- memset(wts, 0, sizeof(struct wts_obj));
+ wts = (struct wts_obj *) calloc(1, sizeof(struct wts_obj));
+
wts->fd = -1;
wts->flags = flags;
display_text = getenv("DISPLAY");
@@ -216,37 +113,40 @@ WTSVirtualChannelOpenEx(unsigned int SessionId,
wts->display_num = get_display_num_from_display(display_text);
}
- if (wts->display_num > 0)
+ if (wts->display_num <= 0)
{
- wts->fd = socket(AF_UNIX, SOCK_STREAM, 0);
- /* set non blocking */
- llong = fcntl(wts->fd, F_GETFL);
- llong = llong | O_NONBLOCK;
- fcntl(wts->fd, F_SETFL, llong);
- /* connect to session chansrv */
- memset(&s, 0, sizeof(struct sockaddr_un));
- s.sun_family = AF_UNIX;
- bytes = sizeof(s.sun_path);
- snprintf(s.sun_path, bytes - 1, "/tmp/.xrdp/xrdpapi_%d", wts->display_num);
- s.sun_path[bytes - 1] = 0;
- bytes = sizeof(struct sockaddr_un);
-
- 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)
- {
- /* all ok */
- wts->status = 1;
- }
- }
+ LLOGLN(0, ("WTSVirtualChannelOpenEx: fatal errror; display is 0"));
+ free(wts);
+ return NULL;
}
- else
+
+ /* we use unix domain socket to communicate with chansrv */
+ wts->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ /* set non blocking */
+ llong = fcntl(wts->fd, F_GETFL);
+ llong = llong | O_NONBLOCK;
+ fcntl(wts->fd, F_SETFL, llong);
+
+ /* connect to chansrv session */
+ memset(&s, 0, sizeof(struct sockaddr_un));
+ s.sun_family = AF_UNIX;
+ bytes = sizeof(s.sun_path);
+ snprintf(s.sun_path, bytes - 1, "/tmp/.xrdp/xrdpapi_%d", wts->display_num);
+ s.sun_path[bytes - 1] = 0;
+ bytes = sizeof(struct sockaddr_un);
+
+ if (connect(wts->fd, (struct sockaddr *) &s, bytes) == 0)
{
- LLOGLN(0, ("WTSVirtualChannelOpenEx: display is 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)
+ {
+ /* all ok */
+ wts->status = 1;
+ }
}
return wts;
@@ -312,7 +212,7 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
unsigned int *pBytesRead)
{
struct wts_obj *wts;
- int error;
+ int rv;
int lerrno;
wts = (struct wts_obj *)hChannelHandle;
@@ -329,9 +229,9 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int 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;
@@ -341,16 +241,15 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
*pBytesRead = 0;
return 1;
}
-
return 0;
}
- else if (error == 0)
+ else if (rv == 0)
{
return 0;
}
- else if (error > 0)
+ else if (rv > 0)
{
- *pBytesRead = error;
+ *pBytesRead = rv;
return 1;
}
}
@@ -419,3 +318,148 @@ WTSFreeMemory(void *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);
+}
diff --git a/xrdpapi/xrdpapi.h b/xrdpapi/xrdpapi.h
index 82f9b809..fdb998cf 100644
--- a/xrdpapi/xrdpapi.h
+++ b/xrdpapi/xrdpapi.h
@@ -1,8 +1,9 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
- * Copyright (C) Thomas Goddard 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");
* you may not use this file except in compliance with the License.
@@ -29,46 +30,47 @@
extern "C" {
#endif
-#define WTS_CURRENT_SERVER_HANDLE 0
-#define WTS_CURRENT_SESSION 0xffffffff
-#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001
-#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW 0x00000000
-#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED 0x00000002
-#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_HIGH 0x00000004
-#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL 0x00000006
-#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_COMPRESS 0x00000008
+#define WTS_CURRENT_SERVER_HANDLE 0x00000000
+#define WTS_CURRENT_SESSION 0xffffffff
+
+#define WTS_CHANNEL_OPTION_STATIC 0x00000000
+#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001
+#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_HIGH 0x00000003
+#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL 0x00000004
typedef enum _WTS_VIRTUAL_CLASS
{
- WTSVirtualClientData,
- WTSVirtualFileHandle
+ WTSVirtualClientData,
+ WTSVirtualFileHandle
} WTS_VIRTUAL_CLASS;
/*
- Reference:
- http://msdn.microsoft.com/en-us/library/windows/desktop/aa383464(v=vs.85).aspx
-*/
-void*
-WTSVirtualChannelOpen(void* hServer, unsigned int SessionId,
- const char* pVirtualName);
-void*
-WTSVirtualChannelOpenEx(unsigned int SessionId,
- const char* pVirtualName,
- unsigned int flags);
-int
-WTSVirtualChannelWrite(void* hChannelHandle, const char* Buffer,
- unsigned int Length, unsigned int* pBytesWritten);
-int
-WTSVirtualChannelRead(void* hChannelHandle, unsigned int TimeOut,
- char* Buffer, unsigned int BufferSize,
- unsigned int* pBytesRead);
-int
-WTSVirtualChannelClose(void* hChannelHandle);
-int
-WTSVirtualChannelQuery(void* hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
- void** ppBuffer, unsigned int* pBytesReturned);
-void
-WTSFreeMemory(void* pMemory);
+ * Reference:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/aa383464(v=vs.85).aspx
+ */
+
+void* WTSVirtualChannelOpen(void* hServer, unsigned int SessionId,
+ const char* pVirtualName);
+
+void* WTSVirtualChannelOpenEx(unsigned int SessionId,
+ const char* pVirtualName, unsigned int flags);
+
+int WTSVirtualChannelWrite(void* hChannelHandle, const char* Buffer,
+ unsigned int Length, unsigned int* pBytesWritten);
+
+int WTSVirtualChannelRead(void* hChannelHandle, unsigned int TimeOut,
+ char* Buffer, unsigned int BufferSize,
+ unsigned int* pBytesRead);
+
+int WTSVirtualChannelClose(void* hChannelHandle);
+
+int WTSVirtualChannelQuery(void* hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
+ void** ppBuffer, unsigned int* pBytesReturned);
+
+void WTSFreeMemory(void* pMemory);
#ifdef __cplusplus
}