From 5b0eaa4a9b828da75563238c245061284ef09a73 Mon Sep 17 00:00:00 2001 From: Laxmikant Rashinkar Date: Thu, 27 Sep 2012 19:48:44 -0700 Subject: [PATCH] o added support for dynamic virtual channels o added echo test routine in simple.c for testing DVC using Microsoft's ECHO protocol --- sesman/chansrv/chansrv.c | 216 ++++++++++++----- sesman/chansrv/chansrv.h | 74 +++--- sesman/chansrv/drdynvc.c | 501 ++++++++++++++++++++++++++++++++++++++- sesman/chansrv/drdynvc.h | 70 +++++- xrdpapi/simple.c | 189 ++++++++++----- xrdpapi/xrdpapi.c | 406 +++++++++++++++++-------------- xrdpapi/xrdpapi.h | 72 +++--- 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 #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 +#include +#include +#include #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 +#endif + #include "xrdpapi.h" #include #include @@ -28,92 +36,143 @@ #include #include -#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 \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 \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 #include #include +#include #include #include #include @@ -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 }