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.c511
1 files changed, 511 insertions, 0 deletions
diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c
new file mode 100644
index 00000000..0ce6c74c
--- /dev/null
+++ b/sesman/chansrv/chansrv.c
@@ -0,0 +1,511 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ xrdp: A Remote Desktop Protocol server.
+ Copyright (C) Jay Sorg 2009
+*/
+
+#include "arch.h"
+#include "os_calls.h"
+#include "thread_calls.h"
+#include "trans.h"
+#include "chansrv.h"
+#include "defines.h"
+#include "sound.h"
+
+static tbus g_thread_done_event = 0;
+static struct trans* g_lis_trans = 0;
+static struct trans* g_con_trans = 0;
+static struct chan_item g_chan_items[32];
+static int g_num_chan_items = 0;
+static int g_clip_index = -1;
+static int g_sound_index = -1;
+
+tbus g_term_event = 0;
+int g_display = 0;
+int g_clip_chan_id = -1;
+int g_sound_chan_id = -1;
+
+/*****************************************************************************/
+/* returns error */
+int APP_CC
+send_channel_data(int chan_id, char* data, int size)
+{
+ struct stream* s;
+ int chan_flags;
+ int total_size;
+ int sent;
+ int rv;
+
+ s = trans_get_out_s(g_con_trans, 8192);
+ if (s == 0)
+ {
+ return 1;
+ }
+ rv = 0;
+ sent = 0;
+ total_size = size;
+ while (sent < total_size)
+ {
+ size = MIN(1600, total_size - sent);
+ chan_flags = 0;
+ if (sent == 0)
+ {
+ chan_flags |= 1; /* first */
+ }
+ if (size + sent == total_size)
+ {
+ chan_flags |= 2; /* last */
+ }
+ 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_id);
+ out_uint16_le(s, chan_flags);
+ out_uint16_le(s, size);
+ out_uint32_le(s, total_size);
+ out_uint8a(s, data + sent, size);
+ s_mark_end(s);
+ rv = trans_force_write(g_con_trans);
+ if (rv != 0)
+ {
+ break;
+ }
+ sent += size;
+ }
+ return rv;
+}
+
+/*****************************************************************************/
+/* returns error */
+static int APP_CC
+send_init_response_message(void)
+{
+ struct stream* s;
+
+ g_writeln("xrdp-chansrv: in 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_force_write(g_con_trans);
+}
+
+/*****************************************************************************/
+/* returns error */
+static int APP_CC
+send_channel_setup_response_message(void)
+{
+ struct stream* s;
+
+ g_writeln("xrdp-chansrv: in 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_force_write(g_con_trans);
+}
+
+/*****************************************************************************/
+/* returns error */
+static int APP_CC
+send_channel_data_response_message(void)
+{
+ struct stream* s;
+
+ g_writeln("xrdp-chansrv: in 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_force_write(g_con_trans);
+}
+
+/*****************************************************************************/
+/* returns error */
+static int APP_CC
+process_message_init(struct stream* s)
+{
+ g_writeln("xrdp-chansrv: in process_message_init");
+ return send_init_response_message();
+}
+
+/*****************************************************************************/
+/* returns error */
+static int APP_CC
+process_message_channel_setup(struct stream* s)
+{
+ int num_chans;
+ int index;
+ int rv;
+ struct chan_item* ci;
+
+ g_writeln("xrdp-chansrv: in process_message_channel_setup");
+ in_uint16_le(s, num_chans);
+ for (index = 0; index < num_chans; index++)
+ {
+ ci = &(g_chan_items[g_num_chan_items]);
+ g_memset(ci->name, 0, sizeof(ci->name));
+ in_uint8a(s, ci->name, 8);
+ in_uint16_le(s, ci->id);
+ in_uint16_le(s, ci->flags);
+ g_writeln("xrdp-chansrv: chan name %s id %d flags %d", ci->name, ci->id,
+ ci->flags);
+ if (g_strcasecmp(ci->name, "cliprdr") == 0)
+ {
+ g_clip_index = g_num_chan_items;
+ g_clip_chan_id = ci->id;
+ }
+ else if (g_strcasecmp(ci->name, "rdpsnd") == 0)
+ {
+ g_sound_index = g_num_chan_items;
+ g_sound_chan_id = ci->id;
+ }
+ g_num_chan_items++;
+ }
+ rv = send_channel_setup_response_message();
+ if (g_clip_index >= 0)
+ {
+ clipboard_init();
+ }
+ if (g_sound_index >= 0)
+ {
+ sound_init();
+ }
+ return rv;
+}
+
+/*****************************************************************************/
+/* returns error */
+static int APP_CC
+process_message_channel_data(struct stream* s)
+{
+ int chan_id;
+ int chan_flags;
+ int rv;
+ int length;
+ int total_length;
+
+ in_uint16_le(s, chan_id);
+ in_uint16_le(s, chan_flags);
+ in_uint16_le(s, length);
+ in_uint32_le(s, total_length);
+ g_writeln("xrdp-chansrv: log channel data chan_id %d chan_flags %d",
+ chan_id, chan_flags);
+ rv = send_channel_data_response_message();
+ if (rv == 0)
+ {
+ if (chan_id == g_clip_chan_id)
+ {
+ rv = clipboard_data_in(s, chan_id, chan_flags, length, total_length);
+ }
+ else if (chan_id == g_sound_chan_id)
+ {
+ rv = sound_data_in(s, chan_id, chan_flags, length, total_length);
+ }
+ }
+ return rv;
+}
+
+/*****************************************************************************/
+/* returns error */
+static int APP_CC
+process_message_channel_data_response(struct stream* s)
+{
+ g_writeln("xrdp-chansrv: in process_message_channel_data_response");
+ return 0;
+}
+
+/*****************************************************************************/
+/* returns error */
+static int APP_CC
+process_message(void)
+{
+ struct stream* s;
+ int size;
+ int id;
+ int rv;
+ char* next_msg;
+
+ if (g_con_trans == 0)
+ {
+ return 1;
+ }
+ s = trans_get_in_s(g_con_trans);
+ if (s == 0)
+ {
+ return 1;
+ }
+ rv = 0;
+ while (s_check_rem(s, 8))
+ {
+ next_msg = s->p;
+ in_uint32_le(s, id);
+ in_uint32_le(s, size);
+ next_msg += size;
+ 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);
+ break;
+ default:
+ g_writeln("xrdp-chansrv: error in process_message unknown msg %d",
+ id);
+ break;
+ }
+ if (rv != 0)
+ {
+ break;
+ }
+ s->p = next_msg;
+ }
+ return rv;
+}
+
+/*****************************************************************************/
+/* returns error */
+int DEFAULT_CC
+my_trans_data_in(struct trans* trans)
+{
+ struct stream* s;
+ int id;
+ int size;
+ int error;
+
+ if (trans == 0)
+ {
+ return 0;
+ }
+ if (trans != g_con_trans)
+ {
+ return 1;
+ }
+ g_writeln("xrdp-chansrv: my_trans_data_in");
+ s = trans_get_in_s(trans);
+ in_uint32_le(s, id);
+ in_uint32_le(s, size);
+ error = trans_force_read(trans, size - 8);
+ if (error == 0)
+ {
+ /* here, the entire message block is read in, process it */
+ error = process_message();
+ }
+ return error;
+}
+
+/*****************************************************************************/
+int DEFAULT_CC
+my_trans_conn_in(struct trans* trans, struct trans* new_trans)
+{
+ if (trans == 0)
+ {
+ return 1;
+ }
+ if (trans != g_lis_trans)
+ {
+ return 1;
+ }
+ if (g_con_trans != 0) /* if already set, error */
+ {
+ return 1;
+ }
+ if (new_trans == 0)
+ {
+ return 1;
+ }
+ g_writeln("xrdp-chansrv: my_trans_conn_in");
+ g_con_trans = new_trans;
+ g_con_trans->trans_data_in = my_trans_data_in;
+ g_con_trans->header_size = 8;
+ /* stop listening */
+ trans_delete(g_lis_trans);
+ g_lis_trans = 0;
+ return 0;
+}
+
+/*****************************************************************************/
+THREAD_RV THREAD_CC
+channel_thread_loop(void* in_val)
+{
+ tbus objs[32];
+ int num_objs;
+ int timeout;
+ int error;
+ char text[256];
+ THREAD_RV rv;
+
+ g_writeln("xrdp-chansrv: thread start");
+ rv = 0;
+ g_lis_trans = trans_create(1, 8192, 8192);
+ g_lis_trans->trans_conn_in = my_trans_conn_in;
+ g_snprintf(text, 255, "%d", 7200 + g_display);
+ error = trans_listen(g_lis_trans, text);
+ if (error != 0)
+ {
+ g_writeln("xrdp-chansrv: trans_listen failed");
+ }
+ if (error == 0)
+ {
+ timeout = 0;
+ num_objs = 0;
+ objs[num_objs] = g_term_event;
+ num_objs++;
+ trans_get_wait_objs(g_lis_trans, objs, &num_objs, &timeout);
+ while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0)
+ {
+ if (g_is_wait_obj_set(g_term_event))
+ {
+ g_writeln("xrdp-chansrv: g_term_event set");
+ break;
+ }
+ if (g_lis_trans != 0)
+ {
+ if (trans_check_wait_objs(g_lis_trans) != 0)
+ {
+ g_writeln("xrdp-chansrv: trans_check_wait_objs error");
+ }
+ }
+ if (g_con_trans != 0)
+ {
+ if (trans_check_wait_objs(g_con_trans) != 0)
+ {
+ g_writeln("xrdp-chansrv: trans_check_wait_objs error resetting");
+ /* delete g_con_trans */
+ trans_delete(g_con_trans);
+ g_con_trans = 0;
+ /* create new listener */
+ g_lis_trans = trans_create(1, 8192, 8192);
+ g_lis_trans->trans_conn_in = my_trans_conn_in;
+ g_snprintf(text, 255, "%d", 7200 + g_display);
+ error = trans_listen(g_lis_trans, text);
+ if (error != 0)
+ {
+ g_writeln("xrdp-chansrv: trans_listen failed");
+ break;
+ }
+ }
+ }
+ clipboard_check_wait_objs();
+ sound_check_wait_objs();
+ timeout = 0;
+ num_objs = 0;
+ objs[num_objs] = g_term_event;
+ num_objs++;
+ trans_get_wait_objs(g_lis_trans, objs, &num_objs, &timeout);
+ trans_get_wait_objs(g_con_trans, objs, &num_objs, &timeout);
+ clipboard_get_wait_objs(objs, &num_objs, &timeout);
+ sound_get_wait_objs(objs, &num_objs, &timeout);
+ }
+ }
+ trans_delete(g_lis_trans);
+ g_lis_trans = 0;
+ trans_delete(g_con_trans);
+ g_con_trans = 0;
+ g_writeln("xrdp-chansrv: thread stop");
+ g_set_wait_obj(g_thread_done_event);
+ return rv;
+}
+
+/*****************************************************************************/
+void DEFAULT_CC
+term_signal_handler(int sig)
+{
+ g_writeln("xrdp-chansrv: term_signal_handler: got signal %d", sig);
+ g_set_wait_obj(g_term_event);
+}
+
+/*****************************************************************************/
+void DEFAULT_CC
+nil_signal_handler(int sig)
+{
+ g_writeln("xrdp-chansrv: nil_signal_handler: got signal %d", sig);
+}
+
+/*****************************************************************************/
+int DEFAULT_CC
+main(int argc, char** argv)
+{
+ int pid;
+ char text[256];
+ char* display_text;
+
+ pid = g_getpid();
+ g_writeln("xrdp-chansrv: started pid %d(0x%8.8x)", pid, pid);
+ g_signal_kill(term_signal_handler); /* SIGKILL */
+ g_signal_terminate(term_signal_handler); /* SIGTERM */
+ g_signal_user_interrupt(term_signal_handler); /* SIGINT */
+ g_signal_pipe(nil_signal_handler); /* SIGPIPE */
+ display_text = g_getenv("XRDP_SESSVC_DISPLAY");
+ if (display_text == 0)
+ {
+ g_writeln("xrdp-chansrv: error, XRDP_SESSVC_DISPLAY not set");
+ return 1;
+ }
+ else
+ {
+ g_display = g_atoi(display_text);
+ }
+ if (g_display == 0)
+ {
+ g_writeln("xrdp-chansrv: error, display is zero");
+ return 1;
+ }
+ g_snprintf(text, 255, "xrdp_chansrv_term_%8.8x", pid);
+ g_term_event = g_create_wait_obj(text);
+ g_snprintf(text, 255, "xrdp_chansrv_thread_done_%8.8x", pid);
+ g_thread_done_event = g_create_wait_obj(text);
+ tc_thread_create(channel_thread_loop, 0);
+ if (g_obj_wait(&g_term_event, 1, 0, 0, 0) != 0)
+ {
+ g_writeln("xrdp-chansrv: error, g_obj_wait failed");
+ }
+ /* wait for thread to exit */
+ if (g_obj_wait(&g_thread_done_event, 1, 0, 0, 0) != 0)
+ {
+ g_writeln("xrdp-chansrv: error, g_obj_wait failed");
+ }
+ /* cleanup */
+ g_delete_wait_obj(g_term_event);
+ g_delete_wait_obj(g_thread_done_event);
+ return 0;
+}