diff options
Diffstat (limited to 'sesman/chansrv')
-rw-r--r-- | sesman/chansrv/chansrv.c | 216 | ||||
-rw-r--r-- | sesman/chansrv/chansrv.h | 74 | ||||
-rw-r--r-- | sesman/chansrv/drdynvc.c | 501 | ||||
-rw-r--r-- | sesman/chansrv/drdynvc.h | 70 |
4 files changed, 774 insertions, 87 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 |