summaryrefslogtreecommitdiffstats
path: root/sesman/chansrv/chansrv.c
diff options
context:
space:
mode:
Diffstat (limited to 'sesman/chansrv/chansrv.c')
-rw-r--r--sesman/chansrv/chansrv.c1251
1 files changed, 725 insertions, 526 deletions
diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c
index 6ec05e53..7a0de556 100644
--- a/sesman/chansrv/chansrv.c
+++ b/sesman/chansrv/chansrv.c
@@ -36,7 +36,6 @@
#include "rail.h"
#include "xcommon.h"
#include "chansrv_fuse.h"
-#include "drdynvc.h"
#include "xrdp_sockets.h"
static struct trans *g_lis_trans = 0;
@@ -49,25 +48,17 @@ 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;
static int g_use_unix_socket = 0;
-static const unsigned char g_xrdpapi_magic[12] =
-{ 0x78, 0x32, 0x10, 0x67, 0x00, 0x92, 0x30, 0x56, 0xff, 0xd8, 0xa9, 0x1f };
-
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_drdynvc_chan_id = -1; /* drdynvc */
char *g_exec_name;
tbus g_exec_event;
@@ -76,10 +67,36 @@ tbus g_exec_sem;
int g_exec_pid = 0;
#define ARRAYSIZE(x) (sizeof(x)/sizeof(*(x)))
+/* max total channel bytes size */
+#define MAX_CHANNEL_BYTES (1 * 1024 * 1024 * 1024) /* 1 GB */
+#define MAX_CHANNEL_FRAG_BYTES 1600
+
+#define CHANSRV_DRDYNVC_STATUS_CLOSED 0
+#define CHANSRV_DRDYNVC_STATUS_OPEN_SENT 1
+#define CHANSRV_DRDYNVC_STATUS_OPEN 2
+#define CHANSRV_DRDYNVC_STATUS_CLOSE_SENT 3
+
+struct chansrv_drdynvc
+{
+ int chan_id;
+ int status; /* see CHANSRV_DRDYNVC_STATUS_* */
+ int flags;
+ int pad0;
+ int (*open_response)(int chan_id, int creation_status);
+ int (*close_response)(int chan_id);
+ int (*data_first)(int chan_id, char *data, int bytes, int total_bytes);
+ int (*data)(int chan_id, char *data, int bytes);
+ struct trans *xrdp_api_trans;
+};
+
+static struct chansrv_drdynvc g_drdynvcs[256];
-/* each time we create a DVC we need a unique DVC channel id */
-/* this variable gets bumped up once per DVC we create */
-tui32 g_dvc_chan_id = 100;
+/* data in struct trans::callback_data */
+struct xrdp_api_data
+{
+ int chan_flags;
+ int chan_id;
+};
struct timeout_obj
{
@@ -226,151 +243,60 @@ g_is_term(void)
}
/*****************************************************************************/
-/* add data to chan_item, on its way to the client */
-/* returns error */
-static int
-add_data_to_chan_item(struct chan_item *chan_item, char *data, int size)
-{
- struct stream *s;
- struct chan_out_data *cod;
-
- make_stream(s);
- init_stream(s, size);
- g_memcpy(s->data, data, size);
- s->end = s->data + size;
- cod = (struct chan_out_data *)g_malloc(sizeof(struct chan_out_data), 1);
- cod->s = s;
-
- if (chan_item->tail == 0)
- {
- chan_item->tail = cod;
- chan_item->head = cod;
- }
- else
- {
- chan_item->tail->next = cod;
- chan_item->tail = cod;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
+/* send data to a static virtual channel
+ size can be > MAX_CHANNEL_FRAG_BYTES, in which case, > 1 message
+ will be sent*/
/* returns error */
-static int
-send_data_from_chan_item(struct chan_item *chan_item)
+int
+send_channel_data(int chan_id, const char *data, int size)
{
- struct stream *s;
- struct chan_out_data *cod;
- int bytes_left;
- int size;
+ int sending_bytes;
int chan_flags;
int error;
+ int total_size;
+ struct stream *s;
- if (chan_item->head == 0)
- {
- return 0;
- }
-
- cod = chan_item->head;
- bytes_left = (int)(cod->s->end - cod->s->p);
- size = MIN(1600, bytes_left);
- chan_flags = 0;
-
- if (cod->s->p == cod->s->data)
- {
- chan_flags |= 1; /* first */
- }
-
- if (cod->s->p + size >= cod->s->end)
- {
- chan_flags |= 2; /* last */
- }
-
- s = trans_get_out_s(g_con_trans, 8192);
- out_uint32_le(s, 0); /* version */
- out_uint32_le(s, 8 + 8 + 2 + 2 + 2 + 4 + size); /* size */
- out_uint32_le(s, 8); /* msg id */
- out_uint32_le(s, 8 + 2 + 2 + 2 + 4 + size); /* size */
- out_uint16_le(s, chan_item->id);
- out_uint16_le(s, chan_flags);
- out_uint16_le(s, size);
- out_uint32_le(s, cod->s->size);
- out_uint8a(s, cod->s->p, size);
- s_mark_end(s);
- LOGM((LOG_LEVEL_DEBUG, "chansrv::send_data_from_chan_item: -- "
- "size %d chan_flags 0x%8.8x", size, chan_flags));
-
- error = trans_write_copy(g_con_trans);
- if (error != 0)
+ if ((chan_id < 0) || (chan_id > 31) ||
+ (data == NULL) ||
+ (size < 1) || (size > MAX_CHANNEL_BYTES))
{
+ /* bad param */
return 1;
}
-
- cod->s->p += size;
-
- if (cod->s->p >= cod->s->end)
+ total_size = size;
+ chan_flags = 1; /* first */
+ while (size > 0)
{
- free_stream(cod->s);
- chan_item->head = chan_item->head->next;
-
- if (chan_item->head == 0)
+ sending_bytes = MIN(MAX_CHANNEL_FRAG_BYTES, size);
+ if (sending_bytes >= size)
{
- chan_item->tail = 0;
+ chan_flags |= 2; /* last */
}
-
- g_free(cod);
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-/* returns error */
-static int
-check_chan_items(void)
-{
- int index;
-
- for (index = 0; index < g_num_chan_items; index++)
- {
- if (g_chan_items[index].head != 0)
+ s = trans_get_out_s(g_con_trans, 26 + sending_bytes);
+ if (s == NULL)
{
- send_data_from_chan_item(g_chan_items + index);
+ return 2;
}
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-/* returns error */
-int
-send_channel_data(int chan_id, char *data, int size)
-{
- int index;
-
- //g_writeln("send_channel_data chan_id %d size %d", chan_id, size);
-
- LOGM((LOG_LEVEL_DEBUG, "chansrv::send_channel_data: size %d", size));
-
- if (chan_id == -1)
- {
- g_writeln("send_channel_data: error, chan_id is -1");
- return 1;
- }
-
- for (index = 0; index < g_num_chan_items; index++)
- {
- if (g_chan_items[index].id == chan_id)
+ out_uint32_le(s, 0); /* version */
+ out_uint32_le(s, 26 + sending_bytes);
+ out_uint32_le(s, 8); /* msg id */
+ out_uint32_le(s, 18 + sending_bytes);
+ out_uint16_le(s, chan_id);
+ out_uint16_le(s, chan_flags);
+ out_uint16_le(s, sending_bytes);
+ out_uint32_le(s, total_size);
+ out_uint8a(s, data, sending_bytes);
+ s_mark_end(s);
+ size -= sending_bytes;
+ data += sending_bytes;
+ error = trans_write_copy(g_con_trans);
+ if (error != 0)
{
- add_data_to_chan_item(g_chan_items + index, data, size);
- check_chan_items();
- return 0;
+ return 3;
}
+ chan_flags = 0;
}
-
- return 1;
+ return 0;
}
/*****************************************************************************/
@@ -401,92 +327,12 @@ send_rail_drawing_orders(char* data, int size)
/*****************************************************************************/
/* returns error */
static int
-send_init_response_message(void)
-{
- struct stream *s = (struct stream *)NULL;
-
- LOGM((LOG_LEVEL_INFO, "send_init_response_message:"));
- s = trans_get_out_s(g_con_trans, 8192);
-
- if (s == 0)
- {
- return 1;
- }
-
- out_uint32_le(s, 0); /* version */
- out_uint32_le(s, 8 + 8); /* size */
- out_uint32_le(s, 2); /* msg id */
- out_uint32_le(s, 8); /* size */
- s_mark_end(s);
- return trans_write_copy(g_con_trans);
-}
-
-/*****************************************************************************/
-/* returns error */
-static int
-send_channel_setup_response_message(void)
-{
- struct stream *s = (struct stream *)NULL;
-
- LOGM((LOG_LEVEL_DEBUG, "send_channel_setup_response_message:"));
- s = trans_get_out_s(g_con_trans, 8192);
-
- if (s == 0)
- {
- return 1;
- }
-
- out_uint32_le(s, 0); /* version */
- out_uint32_le(s, 8 + 8); /* size */
- out_uint32_le(s, 4); /* msg id */
- out_uint32_le(s, 8); /* size */
- s_mark_end(s);
- return trans_write_copy(g_con_trans);
-}
-
-/*****************************************************************************/
-/* returns error */
-static int
-send_channel_data_response_message(void)
-{
- struct stream *s = (struct stream *)NULL;
-
- LOGM((LOG_LEVEL_DEBUG, "send_channel_data_response_message:"));
- s = trans_get_out_s(g_con_trans, 8192);
-
- if (s == 0)
- {
- return 1;
- }
-
- out_uint32_le(s, 0); /* version */
- out_uint32_le(s, 8 + 8); /* size */
- out_uint32_le(s, 6); /* msg id */
- out_uint32_le(s, 8); /* size */
- s_mark_end(s);
- return trans_write_copy(g_con_trans);
-}
-
-/*****************************************************************************/
-/* returns error */
-static int
-process_message_init(struct stream *s)
-{
- LOGM((LOG_LEVEL_DEBUG, "process_message_init:"));
- return send_init_response_message();
-}
-
-/*****************************************************************************/
-/* returns error */
-static int
process_message_channel_setup(struct stream *s)
{
int num_chans;
int index;
int rv;
struct chan_item *ci;
- struct chan_out_data *cod;
- struct chan_out_data *old_cod;
g_num_chan_items = 0;
g_cliprdr_index = -1;
@@ -497,7 +343,6 @@ 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",
@@ -509,25 +354,6 @@ process_message_channel_setup(struct stream *s)
g_memset(ci->name, 0, sizeof(ci->name));
in_uint8a(s, ci->name, 8);
in_uint16_le(s, ci->id);
- /* there might be leftover data from last session after reconnecting
- so free it */
- if (ci->head != 0)
- {
- cod = ci->head;
- while (1)
- {
- free_stream(cod->s);
- old_cod = cod;
- cod = cod->next;
- g_free(old_cod);
- if (ci->tail == old_cod)
- {
- break;
- }
- }
- }
- ci->head = 0;
- ci->tail = 0;
in_uint16_le(s, ci->flags);
LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup: chan name '%s' "
"id %d flags %8.8x", ci->name, ci->id, ci->flags));
@@ -556,11 +382,6 @@ 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));
@@ -569,7 +390,7 @@ process_message_channel_setup(struct stream *s)
g_num_chan_items++;
}
- rv = send_channel_setup_response_message();
+ rv = 0;
if (g_cliprdr_index >= 0)
{
@@ -593,12 +414,6 @@ process_message_channel_setup(struct stream *s)
rail_init();
}
- if (g_drdynvc_index >= 0)
- {
- g_memset(&g_dvc_channels[0], 0, sizeof(g_dvc_channels));
- drdynvc_init();
- }
-
return rv;
}
@@ -607,12 +422,13 @@ process_message_channel_setup(struct stream *s)
static int
process_message_channel_data(struct stream *s)
{
- int chan_id = 0;
- int chan_flags = 0;
- int rv = 0;
- int length = 0;
- int total_length = 0;
+ int chan_id;
+ int chan_flags;
+ int rv;
+ int length;
+ int total_length;
int index;
+ int found;
struct stream *ls;
struct trans *ltran;
struct xrdp_api_data *api_data;
@@ -624,7 +440,7 @@ process_message_channel_data(struct stream *s)
LOGM((LOG_LEVEL_DEBUG, "process_message_channel_data: chan_id %d "
"chan_flags %d", chan_id, chan_flags));
LOG(10, ("process_message_channel_data"));
- rv = send_channel_data_response_message();
+ rv = 0;
if (rv == 0)
{
@@ -644,22 +460,20 @@ 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 (g_api_con_trans_list != 0)
+ else
{
+ found = 0;
for (index = 0; index < g_api_con_trans_list->count; index++)
{
ltran = (struct trans *) list_get_item(g_api_con_trans_list, index);
- if (ltran != 0)
+ if (ltran != NULL)
{
api_data = (struct xrdp_api_data *) (ltran->callback_data);
- if (api_data != 0)
+ if (api_data != NULL)
{
if (api_data->chan_id == chan_id)
{
+ found = 1;
ls = ltran->out_s;
if (chan_flags & 1) /* first */
{
@@ -669,25 +483,333 @@ process_message_channel_data(struct stream *s)
if (chan_flags & 2) /* last */
{
s_mark_end(ls);
- rv = trans_force_write(ltran);
+ rv = trans_write_copy(ltran);
}
break;
}
}
}
}
+ if (found == 0)
+ {
+ LOG(0, ("process_message_channel_data: not found channel %d", chan_id));
+ }
}
+
}
return rv;
}
/*****************************************************************************/
/* returns error */
+/* open response from client */
+static int
+process_message_drdynvc_open_response(struct stream *s)
+{
+ struct chansrv_drdynvc *drdynvc;
+ int chan_id;
+ int creation_status;
+
+ LOG(10, ("process_message_drdynvc_open_response:"));
+ if (!s_check_rem(s, 8))
+ {
+ return 1;
+ }
+ in_uint32_le(s, chan_id);
+ in_uint32_le(s, creation_status);
+ if ((chan_id < 0) || (chan_id > 255))
+ {
+ return 1;
+ }
+ drdynvc = g_drdynvcs + chan_id;
+ if (drdynvc->status != CHANSRV_DRDYNVC_STATUS_OPEN_SENT)
+ {
+ g_writeln("process_message_drdynvc_open_response: status not right");
+ return 1;
+ }
+ if (creation_status == 0)
+ {
+ drdynvc->status = CHANSRV_DRDYNVC_STATUS_OPEN;
+ }
+ else
+ {
+ drdynvc->status = CHANSRV_DRDYNVC_STATUS_CLOSED;
+ }
+ if (drdynvc->open_response != NULL)
+ {
+ if (drdynvc->open_response(chan_id, creation_status) != 0)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* returns error */
+/* close response from client */
static int
-process_message_channel_data_response(struct stream *s)
+process_message_drdynvc_close_response(struct stream *s)
{
- LOG(10, ("process_message_channel_data_response:"));
- check_chan_items();
+ struct chansrv_drdynvc *drdynvc;
+ int chan_id;
+
+ LOG(10, ("process_message_drdynvc_close_response:"));
+ if (!s_check_rem(s, 4))
+ {
+ return 1;
+ }
+ in_uint32_le(s, chan_id);
+ if ((chan_id < 0) || (chan_id > 255))
+ {
+ return 1;
+ }
+ drdynvc = g_drdynvcs + chan_id;
+ if (drdynvc->status != CHANSRV_DRDYNVC_STATUS_CLOSE_SENT)
+ {
+ g_writeln("process_message_drdynvc_close_response: status not right");
+ return 0;
+ }
+ drdynvc->status = CHANSRV_DRDYNVC_STATUS_CLOSED;
+ if (drdynvc->close_response != NULL)
+ {
+ if (drdynvc->close_response(chan_id) != 0)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* returns error */
+/* data from client */
+static int
+process_message_drdynvc_data_first(struct stream *s)
+{
+ struct chansrv_drdynvc *drdynvc;
+ int chan_id;
+ int bytes;
+ int total_bytes;
+ char *data;
+
+ LOG(10, ("process_message_drdynvc_data_first:"));
+ if (!s_check_rem(s, 12))
+ {
+ return 1;
+ }
+ in_uint32_le(s, chan_id);
+ in_uint32_le(s, bytes);
+ in_uint32_le(s, total_bytes);
+ if (!s_check_rem(s, bytes))
+ {
+ return 1;
+ }
+ in_uint8p(s, data, bytes);
+ if ((chan_id < 0) || (chan_id > 255))
+ {
+ return 1;
+ }
+ drdynvc = g_drdynvcs + chan_id;
+ if (drdynvc->data_first != NULL)
+ {
+ if (drdynvc->data_first(chan_id, data, bytes, total_bytes) != 0)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* returns error */
+/* data from client */
+static int
+process_message_drdynvc_data(struct stream *s)
+{
+ struct chansrv_drdynvc *drdynvc;
+ int chan_id;
+ int bytes;
+ char *data;
+
+ LOG(10, ("process_message_drdynvc_data:"));
+ if (!s_check_rem(s, 8))
+ {
+ return 1;
+ }
+ in_uint32_le(s, chan_id);
+ in_uint32_le(s, bytes);
+ if (!s_check_rem(s, bytes))
+ {
+ return 1;
+ }
+ in_uint8p(s, data, bytes);
+ drdynvc = g_drdynvcs + chan_id;
+ if (drdynvc->data != NULL)
+ {
+ if (drdynvc->data(chan_id, data, bytes) != 0)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* open call from chansrv */
+int
+chansrv_drdynvc_open(const char *name, int flags,
+ struct chansrv_drdynvc_procs *procs, int *chan_id)
+{
+ struct stream *s;
+ int name_bytes;
+ int lchan_id;
+ int error;
+
+ lchan_id = 1;
+ while (g_drdynvcs[lchan_id].status != CHANSRV_DRDYNVC_STATUS_CLOSED)
+ {
+ lchan_id++;
+ if (lchan_id > 255)
+ {
+ return 1;
+ }
+ }
+ s = trans_get_out_s(g_con_trans, 8192);
+ if (s == NULL)
+ {
+ return 1;
+ }
+ name_bytes = g_strlen(name);
+ out_uint32_le(s, 0); /* version */
+ out_uint32_le(s, 8 + 8 + 4 + name_bytes + 4 + 4);
+ out_uint32_le(s, 12); /* msg id */
+ out_uint32_le(s, 8 + 4 + name_bytes + 4 + 4);
+ out_uint32_le(s, name_bytes);
+ out_uint8a(s, name, name_bytes);
+ out_uint32_le(s, flags);
+ out_uint32_le(s, lchan_id);
+ s_mark_end(s);
+ error = trans_write_copy(g_con_trans);
+ if (error == 0)
+ {
+ if (chan_id != NULL)
+ {
+ *chan_id = lchan_id;
+ g_drdynvcs[lchan_id].open_response = procs->open_response;
+ g_drdynvcs[lchan_id].close_response = procs->close_response;
+ g_drdynvcs[lchan_id].data_first = procs->data_first;
+ g_drdynvcs[lchan_id].data = procs->data;
+ g_drdynvcs[lchan_id].status = CHANSRV_DRDYNVC_STATUS_OPEN_SENT;
+
+ }
+ }
+ return error;
+}
+
+/*****************************************************************************/
+/* close call from chansrv */
+int
+chansrv_drdynvc_close(int chan_id)
+{
+ struct stream *s;
+ int error;
+
+ s = trans_get_out_s(g_con_trans, 8192);
+ if (s == NULL)
+ {
+ return 1;
+ }
+ out_uint32_le(s, 0); /* version */
+ out_uint32_le(s, 20);
+ out_uint32_le(s, 14); /* msg id */
+ out_uint32_le(s, 12);
+ out_uint32_le(s, chan_id);
+ s_mark_end(s);
+ error = trans_write_copy(g_con_trans);
+ g_drdynvcs[chan_id].status = CHANSRV_DRDYNVC_STATUS_CLOSE_SENT;
+ return error;
+}
+
+/*****************************************************************************/
+int
+chansrv_drdynvc_data_first(int chan_id, const char *data, int data_bytes,
+ int total_data_bytes)
+{
+ struct stream *s;
+ int error;
+
+ //g_writeln("chansrv_drdynvc_data_first: data_bytes %d total_data_bytes %d",
+ // data_bytes, total_data_bytes);
+ s = trans_get_out_s(g_con_trans, 8192);
+ if (s == NULL)
+ {
+ return 1;
+ }
+ out_uint32_le(s, 0); /* version */
+ out_uint32_le(s, 28 + data_bytes);
+ out_uint32_le(s, 16); /* msg id */
+ out_uint32_le(s, 20 + data_bytes);
+ out_uint32_le(s, chan_id);
+ out_uint32_le(s, data_bytes);
+ out_uint32_le(s, total_data_bytes);
+ out_uint8a(s, data, data_bytes);
+ s_mark_end(s);
+ error = trans_write_copy(g_con_trans);
+ return error;
+}
+
+/*****************************************************************************/
+int
+chansrv_drdynvc_data(int chan_id, const char *data, int data_bytes)
+{
+ struct stream *s;
+ int error;
+
+ //g_writeln("chansrv_drdynvc_data: data_bytes %d", data_bytes);
+ s = trans_get_out_s(g_con_trans, 8192);
+ if (s == NULL)
+ {
+ return 1;
+ }
+ out_uint32_le(s, 0); /* version */
+ out_uint32_le(s, 24 + data_bytes);
+ out_uint32_le(s, 18); /* msg id */
+ out_uint32_le(s, 16 + data_bytes);
+ out_uint32_le(s, chan_id);
+ out_uint32_le(s, data_bytes);
+ out_uint8a(s, data, data_bytes);
+ s_mark_end(s);
+ error = trans_write_copy(g_con_trans);
+ return error;
+}
+
+/*****************************************************************************/
+int
+chansrv_drdynvc_send_data(int chan_id, const char *data, int data_bytes)
+{
+ int this_send_bytes;
+
+ //g_writeln("chansrv_drdynvc_send_data: data_bytes %d", data_bytes);
+ if (data_bytes > 1590)
+ {
+ if (chansrv_drdynvc_data_first(chan_id, data, 1590, data_bytes) != 0)
+ {
+ return 1;
+ }
+ data_bytes -= 1590;
+ data += 1590;
+ }
+ while (data_bytes > 0)
+ {
+ this_send_bytes = MIN(1590, data_bytes);
+ if (chansrv_drdynvc_data(chan_id, data, this_send_bytes) != 0)
+ {
+ return 1;
+ }
+ data_bytes -= this_send_bytes;
+ data += this_send_bytes;
+ }
return 0;
}
@@ -725,17 +847,23 @@ process_message(void)
switch (id)
{
- case 1: /* init */
- rv = process_message_init(s);
- break;
case 3: /* channel setup */
rv = process_message_channel_setup(s);
break;
case 5: /* channel data */
rv = process_message_channel_data(s);
break;
- case 7: /* channel data response */
- rv = process_message_channel_data_response(s);
+ case 13: /* drdynvc open response */
+ rv = process_message_drdynvc_open_response(s);
+ break;
+ case 15: /* drdynvc close response */
+ rv = process_message_drdynvc_close_response(s);
+ break;
+ case 17: /* drdynvc data first */
+ rv = process_message_drdynvc_data_first(s);
+ break;
+ case 19: /* drdynvc data */
+ rv = process_message_drdynvc_data(s);
break;
default:
LOGM((LOG_LEVEL_ERROR, "process_message: unknown msg %d", id));
@@ -744,7 +872,8 @@ process_message(void)
if (rv != 0)
{
- break;
+ g_writeln("process_message: error rv %d id %d", rv, id);
+ rv = 0;
}
s->p = next_msg;
@@ -782,11 +911,119 @@ my_trans_data_in(struct trans *trans)
{
/* here, the entire message block is read in, process it */
error = process_message();
+ if (error == 0)
+ {
+ }
+ else
+ {
+ g_writeln("my_trans_data_in: process_message failed");
+ }
+ }
+ else
+ {
+ g_writeln("my_trans_data_in: trans_force_read failed");
}
return error;
}
+/*****************************************************************************/
+struct trans *
+get_api_trans_from_chan_id(int chan_id)
+{
+ return g_drdynvcs[chan_id].xrdp_api_trans;
+}
+
+/*****************************************************************************/
+static int
+my_api_open_response(int chan_id, int creation_status)
+{
+ struct trans *trans;
+ struct stream *s;
+
+ //g_writeln("my_api_open_response: chan_id %d creation_status %d",
+ // chan_id, creation_status);
+ trans = get_api_trans_from_chan_id(chan_id);
+ if (trans == NULL)
+ {
+ return 1;
+ }
+ s = trans_get_out_s(trans, 8192);
+ if (s == NULL)
+ {
+ return 1;
+ }
+ out_uint32_le(s, creation_status);
+ s_mark_end(s);
+ if (trans_write_copy(trans) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+my_api_close_response(int chan_id)
+{
+ //g_writeln("my_api_close_response:");
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+my_api_data_first(int chan_id, char *data, int bytes, int total_bytes)
+{
+ struct trans *trans;
+ struct stream *s;
+
+ //g_writeln("my_api_data_first: bytes %d total_bytes %d", bytes, total_bytes);
+ trans = get_api_trans_from_chan_id(chan_id);
+ if (trans == NULL)
+ {
+ return 1;
+ }
+ s = trans_get_out_s(trans, bytes);
+ if (s == NULL)
+ {
+ return 1;
+ }
+ out_uint8a(s, data, bytes);
+ s_mark_end(s);
+ if (trans_write_copy(trans) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+my_api_data(int chan_id, char *data, int bytes)
+{
+ struct trans *trans;
+ struct stream *s;
+
+ //g_writeln("my_api_data: bytes %d", bytes);
+ trans = get_api_trans_from_chan_id(chan_id);
+ if (trans == NULL)
+ {
+ return 1;
+ }
+ s = trans_get_out_s(trans, bytes);
+ if (s == NULL)
+ {
+ return 1;
+ }
+ out_uint8a(s, data, bytes);
+ s_mark_end(s);
+ if (trans_write_copy(trans) != 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
/*
* called when WTSVirtualChannelWrite() is invoked in xrdpapi.c
*
@@ -794,94 +1031,130 @@ my_trans_data_in(struct trans *trans)
int
my_api_trans_data_in(struct trans *trans)
{
- struct stream *s;
- int bytes_read;
- int i32;
+ struct stream *s;
+ struct stream *out_s;
struct xrdp_api_data *ad;
+ int index;
+ int rv;
+ int bytes;
+ int ver;
+ int channel_name_bytes;
+ struct chansrv_drdynvc_procs procs;
+ char *chan_name;
- //g_writeln("my_api_trans_data_in:");
-
- LOG(10, ("my_api_trans_data_in:"));
-
- if (trans == 0)
- {
- return 0;
- }
-
- if (g_api_con_trans_list != 0)
+ //g_writeln("my_api_trans_data_in: extra_flags %d", trans->extra_flags);
+ rv = 0;
+ ad = (struct xrdp_api_data *) (trans->callback_data);
+ s = trans_get_in_s(trans);
+ if (trans->extra_flags == 0)
{
- if (list_index_of(g_api_con_trans_list, (tintptr) trans) == -1)
+ in_uint32_le(s, bytes);
+ in_uint32_le(s, ver);
+ //g_writeln("my_api_trans_data_in: bytes %d ver %d", bytes, ver);
+ if (ver != 0)
{
return 1;
}
+ trans->header_size = bytes;
+ trans->extra_flags = 1;
}
-
- LOGM((LOG_LEVEL_DEBUG, "my_api_trans_data_in:"));
-
- s = trans_get_in_s(trans);
- bytes_read = g_tcp_recv(trans->sck, s->data, 16, 0);
- if (bytes_read == 16)
+ else if (trans->extra_flags == 1)
{
- if (g_memcmp(s->data, g_xrdpapi_magic, 12) == 0)
+ rv = 1;
+ in_uint32_le(s, channel_name_bytes);
+ //g_writeln("my_api_trans_data_in: channel_name_bytes %d", channel_name_bytes);
+ chan_name = g_new0(char, channel_name_bytes + 1);
+ if (chan_name == NULL)
{
- in_uint8s(s, 12);
- in_uint32_le(s, bytes_read);
- init_stream(s, bytes_read);
- if (trans_force_read(trans, bytes_read))
- log_message(LOG_LEVEL_ERROR, "chansrv.c: error reading from transport");
+ return 1;
}
- else if (g_tcp_select(trans->sck, 0) & 1)
+ in_uint8a(s, chan_name, channel_name_bytes);
+ in_uint32_le(s, ad->chan_flags);
+ //g_writeln("my_api_trans_data_in: chan_name %s chan_flags 0x%8.8x", chan_name, ad->chan_flags);
+ if (ad->chan_flags == 0)
{
- i32 = bytes_read;
- bytes_read = g_tcp_recv(trans->sck, s->data + bytes_read,
- 8192 * 4 - bytes_read, 0);
- if (bytes_read > 0)
+ /* SVC */
+ for (index = 0; index < g_num_chan_items; index++)
{
- bytes_read += i32;
+ if (g_strcasecmp(g_chan_items[index].name, chan_name) == 0)
+ {
+ ad->chan_id = g_chan_items[index].id;
+ rv = 0;
+ break;
+ }
}
- }
- }
-
- //g_writeln("bytes_read %d", bytes_read);
-
- if (bytes_read > 0)
- {
- LOG(10, ("my_api_trans_data_in: got data %d", bytes_read));
- ad = (struct xrdp_api_data *) trans->callback_data;
-
- 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)
+ if (rv == 0)
+ {
+ /* open ok */
+ out_s = trans_get_out_s(trans, 8192);
+ if (out_s == NULL)
+ {
+ return 1;
+ }
+ out_uint32_le(out_s, 0);
+ s_mark_end(out_s);
+ if (trans_write_copy(trans) != 0)
+ {
+ return 1;
+ }
+ }
+ else
{
- LOG(0, ("my_api_trans_data_in: send_channel_data failed"));
+ /* open failed */
+ out_s = trans_get_out_s(trans, 8192);
+ if (out_s == NULL)
+ {
+ return 1;
+ }
+ out_uint32_le(out_s, 1);
+ s_mark_end(out_s);
+ if (trans_write_copy(trans) != 0)
+ {
+ return 1;
+ }
}
}
else
{
- /* writing data to a dynamic virtual channel */
- drdynvc_write_data(ad->dvc_chan_id, s->data, bytes_read);
+ /* DVS */
+ g_memset(&procs, 0, sizeof(procs));
+ procs.open_response = my_api_open_response;
+ procs.close_response = my_api_close_response;
+ procs.data_first = my_api_data_first;
+ procs.data = my_api_data;
+ rv = chansrv_drdynvc_open(chan_name, ad->chan_flags,
+ &procs, &(ad->chan_id));
+ //g_writeln("my_api_trans_data_in: chansrv_drdynvc_open rv %d "
+ // "chan_id %d", rv, ad->chan_id);
+ g_drdynvcs[ad->chan_id].xrdp_api_trans = trans;
}
+ g_free(chan_name);
+ init_stream(s, 0);
+ trans->extra_flags = 2;
+ trans->header_size = 0;
}
else
{
- ad = (struct xrdp_api_data *) (trans->callback_data);
- if ((ad != NULL) && (ad->dvc_chan_id > 0))
+ bytes = g_sck_recv(trans->sck, s->data, s->size, 0);
+ if (bytes < 1)
+ {
+ //g_writeln("my_api_trans_data_in: disconnect");
+ return 1;
+ }
+ if (ad->chan_flags == 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);
+ /* SVC */
+ rv = send_channel_data(ad->chan_id, s->data, bytes);
}
else
{
- LOG(10, ("my_api_trans_data_in: g_tcp_recv failed or disconnected for SVC"));
+ /* DVS */
+ //g_writeln("my_api_trans_data_in: s->size %d bytes %d", s->size, bytes);
+ rv = chansrv_drdynvc_send_data(ad->chan_id, s->data, bytes);
}
- return 1;
+ init_stream(s, 0);
}
-
- return 0;
+ return rv;
}
/*****************************************************************************/
@@ -926,92 +1199,24 @@ int
my_api_trans_conn_in(struct trans *trans, struct trans *new_trans)
{
struct xrdp_api_data *ad;
- struct stream *s;
- int error;
- int index;
- char chan_pri;
- if ((trans == 0) || (trans != g_api_lis_trans) || (new_trans == 0))
+ //g_writeln("my_api_trans_conn_in:");
+ if ((trans == NULL) || (trans != g_api_lis_trans) || (new_trans == NULL))
{
+ g_writeln("my_api_trans_conn_in: error");
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)
+ new_trans->trans_data_in = my_api_trans_data_in;
+ new_trans->header_size = 8;
+ new_trans->no_stream_init_on_data_in = 1;
+ ad = g_new0(struct xrdp_api_data, 1);
+ if (ad == NULL)
{
- LOG(0, ("my_api_trans_conn_in: trans_force_read failed"));
- trans_delete(new_trans);
+ g_writeln("my_api_trans_conn_in: error");
return 1;
}
-
- s->end = s->data;
-
- 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;
-
- if (ad->flags > 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!"))
- g_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, ("my_api_trans_conn_in: %s %s", ad->header,
- g_chan_items[index].name));
-
- if (g_strcasecmp(ad->header, g_chan_items[index].name) == 0)
- {
- LOG(10, ("my_api_trans_conn_in: found it at %d", index));
- ad->chan_id = g_chan_items[index].id;
- break;
- }
- }
- if (index == g_num_chan_items)
- {
- g_writeln("did not find SVC named %s", ad->header);
- }
- }
-
new_trans->callback_data = ad;
-
- if (g_api_con_trans_list == 0)
- {
- g_api_con_trans_list = list_create();
- }
- new_trans->trans_data_in = my_api_trans_data_in;
- new_trans->header_size = 0;
- list_add_item(g_api_con_trans_list, (tintptr) new_trans);
-
+ list_add_item(g_api_con_trans_list, (intptr_t) new_trans);
return 0;
}
@@ -1077,6 +1282,96 @@ setup_api_listen(void)
}
/*****************************************************************************/
+static int
+api_con_trans_list_get_wait_objs_rw(intptr_t *robjs, int *rcount,
+ intptr_t *wobjs, int *wcount,
+ int *timeout)
+{
+ int api_con_index;
+ struct trans *ltran;
+
+ for (api_con_index = g_api_con_trans_list->count - 1;
+ api_con_index >= 0;
+ api_con_index--)
+ {
+ ltran = (struct trans *)
+ list_get_item(g_api_con_trans_list, api_con_index);
+ if (ltran != NULL)
+ {
+ trans_get_wait_objs_rw(ltran, robjs, rcount, wobjs, wcount,
+ timeout);
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+api_con_trans_list_check_wait_objs(void)
+{
+ int api_con_index;
+ int drdynvc_index;
+ struct trans *ltran;
+ struct xrdp_api_data *ad;
+
+ for (api_con_index = g_api_con_trans_list->count - 1;
+ api_con_index >= 0;
+ api_con_index--)
+ {
+ ltran = (struct trans *)
+ list_get_item(g_api_con_trans_list, api_con_index);
+ if (ltran != NULL)
+ {
+ if (trans_check_wait_objs(ltran) != 0)
+ {
+ /* disconnect */
+ list_remove_item(g_api_con_trans_list, api_con_index);
+ ad = (struct xrdp_api_data *) (ltran->callback_data);
+ if (ad->chan_flags != 0)
+ {
+ chansrv_drdynvc_close(ad->chan_id);
+ }
+ for (drdynvc_index = 0;
+ drdynvc_index < (int) ARRAYSIZE(g_drdynvcs);
+ drdynvc_index++)
+ {
+ if (g_drdynvcs[drdynvc_index].xrdp_api_trans == ltran)
+ {
+ g_drdynvcs[drdynvc_index].xrdp_api_trans = NULL;
+ }
+ }
+ g_free(ad);
+ trans_delete(ltran);
+ }
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+api_con_trans_list_remove_all(void)
+{
+ int api_con_index;
+ struct trans *ltran;
+
+ for (api_con_index = g_api_con_trans_list->count - 1;
+ api_con_index >= 0;
+ api_con_index--)
+ {
+ ltran = (struct trans *)
+ list_get_item(g_api_con_trans_list, api_con_index);
+ if (ltran != NULL)
+ {
+ list_remove_item(g_api_con_trans_list, api_con_index);
+ g_free(ltran->callback_data);
+ trans_delete(ltran);
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
THREAD_RV THREAD_CC
channel_thread_loop(void *in_val)
{
@@ -1086,12 +1381,11 @@ channel_thread_loop(void *in_val)
int num_wobjs;
int timeout;
int error;
- int index;
THREAD_RV rv;
- struct trans *ltran;
LOGM((LOG_LEVEL_INFO, "channel_thread_loop: thread start"));
rv = 0;
+ g_api_con_trans_list = list_create();
setup_api_listen();
error = setup_listen();
@@ -1105,6 +1399,7 @@ channel_thread_loop(void *in_val)
trans_get_wait_objs(g_lis_trans, objs, &num_objs);
trans_get_wait_objs(g_api_lis_trans, objs, &num_objs);
+ //g_writeln("timeout %d", timeout);
while (g_obj_wait(objs, num_objs, wobjs, num_wobjs, timeout) == 0)
{
check_timeout();
@@ -1157,24 +1452,8 @@ channel_thread_loop(void *in_val)
LOG(0, ("channel_thread_loop: trans_check_wait_objs failed"));
}
}
-
- if (g_api_con_trans_list != 0)
- {
- for (index = g_api_con_trans_list->count - 1; index >= 0; index--)
- {
- ltran = (struct trans *) list_get_item(g_api_con_trans_list, index);
- if (ltran != 0)
- {
- if (trans_check_wait_objs(ltran) != 0)
- {
- list_remove_item(g_api_con_trans_list, index);
- g_free(ltran->callback_data);
- trans_delete(ltran);
- }
- }
- }
- }
-
+ /* check the wait_objs in g_api_con_trans_list */
+ api_con_trans_list_check_wait_objs();
xcommon_check_wait_objs();
sound_check_wait_objs();
dev_redir_check_wait_objs();
@@ -1184,23 +1463,16 @@ channel_thread_loop(void *in_val)
num_wobjs = 0;
objs[num_objs] = g_term_event;
num_objs++;
- trans_get_wait_objs(g_lis_trans, objs, &num_objs);
+ trans_get_wait_objs_rw(g_lis_trans, objs, &num_objs,
+ wobjs, &num_wobjs, &timeout);
trans_get_wait_objs_rw(g_con_trans, objs, &num_objs,
wobjs, &num_wobjs, &timeout);
- trans_get_wait_objs(g_api_lis_trans, objs, &num_objs);
-
- if (g_api_con_trans_list != 0)
- {
- for (index = g_api_con_trans_list->count - 1; index >= 0; index--)
- {
- ltran = (struct trans *) list_get_item(g_api_con_trans_list, index);
- if (ltran != 0)
- {
- trans_get_wait_objs(ltran, objs, &num_objs);
- }
- }
- }
-
+ trans_get_wait_objs_rw(g_api_lis_trans, objs, &num_objs,
+ wobjs, &num_wobjs, &timeout);
+ /* get the wait_objs from in g_api_con_trans_list */
+ api_con_trans_list_get_wait_objs_rw(objs, &num_objs,
+ wobjs, &num_wobjs,
+ &timeout);
xcommon_get_wait_objs(objs, &num_objs, &timeout);
sound_get_wait_objs(objs, &num_objs, &timeout);
dev_redir_get_wait_objs(objs, &num_objs, &timeout);
@@ -1215,20 +1487,8 @@ channel_thread_loop(void *in_val)
g_con_trans = 0;
trans_delete(g_api_lis_trans);
g_api_lis_trans = 0;
- if (g_api_con_trans_list != 0)
- {
- for (index = g_api_con_trans_list->count - 1; index >= 0; index--)
- {
- ltran = (struct trans *) list_get_item(g_api_con_trans_list, index);
- if (ltran != 0)
- {
- list_remove_item(g_api_con_trans_list, index);
- g_free(ltran->callback_data);
- trans_delete(ltran);
- }
- }
- list_delete(g_api_con_trans_list);
- }
+ api_con_trans_list_remove_all();
+ list_delete(g_api_con_trans_list);
LOGM((LOG_LEVEL_INFO, "channel_thread_loop: thread stop"));
g_set_wait_obj(g_thread_done_event);
return rv;
@@ -1551,6 +1811,8 @@ main(int argc, char **argv)
g_file_delete(log_file);
}
+ g_memset(g_drdynvcs, 0, sizeof(g_drdynvcs));
+
logconfig.log_file = log_file;
logconfig.fd = -1;
logconfig.log_level = log_level;
@@ -1649,66 +1911,3 @@ main(int argc, char **argv)
return 0;
}
-/*
- * return unused slot in dvc_channels[]
- *
- * @return unused slot index on success, -1 on failure
- ******************************************************************************/
-int
-find_empty_slot_in_dvc_channels(void)
-{
- 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 *
-struct_from_dvc_chan_id(tui32 dvc_chan_id)
-{
- int i;
-
- for (i = 0; i < MAX_DVC_CHANNELS; i++)
- {
- if (g_dvc_channels[i] != NULL &&
- g_dvc_channels[i]->dvc_chan_id >= 0 &&
- (tui32) g_dvc_channels[i]->dvc_chan_id == dvc_chan_id)
- {
- return g_dvc_channels[i];
- }
- }
-
- return NULL;
-}
-
-int
-remove_struct_with_chan_id(tui32 dvc_chan_id)
-{
- int i;
-
- for (i = 0; i < MAX_DVC_CHANNELS; i++)
- {
- if (g_dvc_channels[i] != NULL &&
- g_dvc_channels[i]->dvc_chan_id >= 0 &&
- (tui32) g_dvc_channels[i]->dvc_chan_id == dvc_chan_id)
- {
- g_dvc_channels[i] = NULL;
- return 0;
- }
- }
- return -1;
-}