diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 7c74bb4f..10a42ef9 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -69,59 +69,132 @@ struct xrdp_api_data }; /*****************************************************************************/ +/* add data to chan_item, on its way to the client */ /* returns error */ -int APP_CC -send_channel_data(int chan_id, char* data, int size) +static int APP_CC +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; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +send_data_from_chan_item(struct chan_item* chan_item) { - struct stream * s; + struct stream* s; + struct chan_out_data* cod; + int bytes_left; + int size; int chan_flags; - int total_size; - int sent; - int rv; + int error; - if (chan_id == -1) + if (chan_item->head == 0) { - return 1; + 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); - if (s == 0) + 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_channel_data: -- " + "size %d chan_flags 0x%8.8x", size, chan_flags)); + error = trans_force_write(g_con_trans); + if (error != 0) { return 1; } - rv = 0; - sent = 0; - total_size = size; - while (sent < total_size) + cod->s->p += size; + if (cod->s->p >= cod->s->end) { - size = MIN(1600, total_size - sent); - chan_flags = 0; - if (sent == 0) + free_stream(cod->s); + chan_item->head = chan_item->head->next; + if (chan_item->head == 0) { - chan_flags |= 1; /* first */ + chan_item->tail = 0; } - if (size + sent == total_size) + g_free(cod); + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +check_chan_items(void) +{ + int index; + + for (index = 0; index < g_num_chan_items; index++) + { + if (g_chan_items[index].head != 0) { - chan_flags |= 2; /* last */ + send_data_from_chan_item(g_chan_items + index); } - 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) + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +send_channel_data(int chan_id, char* data, int size) +{ + int index; + + LOGM((LOG_LEVEL_DEBUG, "chansrv::send_channel_data: size %d", size)); + if (chan_id == -1) + { + return 1; + } + for (index = 0; index < g_num_chan_items; index++) + { + if (g_chan_items[index].id == chan_id) { - break; + add_data_to_chan_item(g_chan_items + index, data, size); + check_chan_items(); + return 0; } - sent += size; - s = trans_get_out_s(g_con_trans, 8192); } - return rv; + return 1; } /*****************************************************************************/ @@ -131,7 +204,7 @@ send_init_response_message(void) { struct stream * s = (struct stream *)NULL; - LOGM((LOG_LEVEL_INFO,"send_init_response_message:")) + LOGM((LOG_LEVEL_INFO, "send_init_response_message:")); s = trans_get_out_s(g_con_trans, 8192); if (s == 0) { @@ -339,6 +412,7 @@ static int APP_CC process_message_channel_data_response(struct stream* s) { LOG(10, ("process_message_channel_data_response:")); + check_chan_items(); return 0; } @@ -911,21 +985,41 @@ main(int argc, char** argv) { tbus waiters[4]; int pid = 0; - char text[256] = ""; - char* display_text = (char *)NULL; -#if XRDP_CHANNEL_LOG - char cfg_file[256]; + char text[256]; + char* home_text; + char* display_text; + char log_file[256]; enum logReturns error; -#endif + struct log_config logconfig; g_init("xrdp-chansrv"); /* os_calls */ + + home_text = g_getenv("HOME"); + if (home_text == 0) + { + g_writeln("error reading HOME environment variable"); + g_deinit(); + return 1; + } + read_ini(); pid = g_getpid(); -#if XRDP_CHANNEL_LOG /* starting logging subsystem */ - g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH); - error = log_start(cfg_file,"XRDP-Chansrv"); + g_memset(&logconfig, 0, sizeof(struct log_config)); + logconfig.program_name = "XRDP-Chansrv"; + g_snprintf(log_file, 255, "%s/xrdp-chansrv.log", home_text); + g_writeln("chansrv::main: using log file [%s]", log_file); + if (g_file_exist(log_file)) + { + g_file_delete(log_file); + } + logconfig.log_file = log_file; + logconfig.fd = -1; + logconfig.log_level = LOG_LEVEL_ERROR; + logconfig.enable_syslog = 0; + logconfig.syslog_level = 0; + error = log_start_from_param(&logconfig); if (error != LOG_STARTUP_OK) { switch (error) @@ -942,10 +1036,9 @@ main(int argc, char** argv) break; } g_deinit(); - g_exit(1); + return 1; } LOGM((LOG_LEVEL_ALWAYS, "main: app started pid %d(0x%8.8x)", pid, pid)); -#endif /* set up signal handler */ g_signal_kill(term_signal_handler); /* SIGKILL */ g_signal_terminate(term_signal_handler); /* SIGTERM */ @@ -958,6 +1051,7 @@ main(int argc, char** argv) if (g_display_num == 0) { LOGM((LOG_LEVEL_ERROR, "main: error, display is zero")); + g_deinit(); return 1; } LOGM((LOG_LEVEL_INFO, "main: using DISPLAY %d", g_display_num)); diff --git a/sesman/chansrv/chansrv.h b/sesman/chansrv/chansrv.h index a7a0f3e7..ba593461 100644 --- a/sesman/chansrv/chansrv.h +++ b/sesman/chansrv/chansrv.h @@ -21,14 +21,21 @@ #include "arch.h" #include "parse.h" +#include "log.h" -#define XRDP_CHANNEL_LOG 0 +struct chan_out_data +{ + 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 APP_CC @@ -47,12 +54,7 @@ main_cleanup(void); } \ } -#if XRDP_CHANNEL_LOG -#include "log.h" #define LOGM(_args) do { log_message _args ; } while (0) -#else -#define LOGM(_args) -#endif #ifndef GSET_UINT8 #define GSET_UINT8(_ptr, _offset, _data) \ diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c index abb17e3e..3bea9704 100644 --- a/sesman/chansrv/clipboard.c +++ b/sesman/chansrv/clipboard.c @@ -95,14 +95,14 @@ static int g_want_image_data = 0; static XSelectionRequestEvent g_saved_selection_req_event; /* for clipboard INCR transfers */ -static Atom g_incr_atom; -static Atom g_incr_atom_type; -static Atom g_incr_atom_target; -static char* g_incr_data; -static int g_incr_data_size; -static int g_incr_in_progress = 0; +static Atom g_incr_atom; +static Atom g_incr_atom_type; +static Atom g_incr_atom_target; +static char* g_incr_data = 0; +static int g_incr_data_size = 0; +static int g_incr_in_progress = 0; -static clipboard_format_id = CB_FORMAT_UNICODETEXT; +static int clipboard_format_id = CB_FORMAT_UNICODETEXT; /*****************************************************************************/ /* this is one way to get the current time from the x server */ @@ -176,10 +176,10 @@ clipboard_init(void) } if (rv == 0) { - LOGM((LOG_LEVEL_ERROR, "clipboard_init: g_xfixes_event_base %d", + LOGM((LOG_LEVEL_DEBUG, "clipboard_init: g_xfixes_event_base %d", g_xfixes_event_base)); st = XFixesQueryVersion(g_display, &ver_maj, &ver_min); - LOGM((LOG_LEVEL_ERROR, "clipboard_init st %d, maj %d min %d", st, + LOGM((LOG_LEVEL_DEBUG, "clipboard_init st %d, maj %d min %d", st, ver_maj, ver_min)); g_clip_property_atom = XInternAtom(g_display, "XRDP_CLIP_PROPERTY_ATOM", False); @@ -194,6 +194,11 @@ clipboard_init(void) g_image_bmp_atom = XInternAtom(g_display, "image/bmp", False); g_incr_atom = XInternAtom(g_display, "INCR", False); + if (g_image_bmp_atom == None) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_init: g_image_bmp_atom was " + "not allocated")); + } g_wnd = XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, 4, 4, 0, 0, 0); @@ -327,10 +332,7 @@ clipboard_send_format_announce(tui32 format_id, char* format_name) struct stream* s; int size; int rv; - unsigned char format_buf[32]; - g_memset(format_buf, 0, 32); - g_snprintf(format_buf, 31, "Native"); make_stream(s); init_stream(s, 8192); out_uint16_le(s, 2); /* CLIPRDR_FORMAT_ANNOUNCE */ @@ -521,6 +523,9 @@ clipboard_refuse_selection(XSelectionRequestEvent* req) } /*****************************************************************************/ +/* sent by client or server when its local system clipboard is + updated with new clipboard data; contains Clipboard Format ID + and name pairs of new Clipboard Formats on the clipboard. */ static int APP_CC clipboard_process_format_announce(struct stream* s, int clip_msg_status, int clip_msg_len) @@ -540,6 +545,8 @@ clipboard_process_format_announce(struct stream* s, int clip_msg_status, } /*****************************************************************************/ +/* response to CB_FORMAT_LIST; used to indicate whether + processing of the Format List PDU was successful */ static int APP_CC clipboard_prcoess_format_ack(struct stream* s, int clip_msg_status, int clip_msg_len) @@ -550,6 +557,8 @@ clipboard_prcoess_format_ack(struct stream* s, int clip_msg_status, } /*****************************************************************************/ +/* sent by recipient of CB_FORMAT_LIST; used to request data for one + of the formats that was listed in CB_FORMAT_LIST */ static int APP_CC clipboard_process_data_request(struct stream* s, int clip_msg_status, int clip_msg_len) @@ -576,7 +585,6 @@ clipboard_process_data_response_for_image(struct stream * s, char cdata; int len; int index; - int data_in_len; LOGM((LOG_LEVEL_DEBUG, "clipboard_process_data_response_for_image: " "CLIPRDR_DATA_RESPONSE_FOR_IMAGE")); @@ -600,7 +608,7 @@ clipboard_process_data_response_for_image(struct stream * s, } else { - return; + return 0; } while (s_check(s)) { @@ -783,7 +791,8 @@ clipboard_data_in(struct stream* s, int chan_id, int chan_flags, int length, /*****************************************************************************/ /* this happens when a new app copies something to the clipboard 'CLIPBOARD' Atom - typedef struct { + typedef struct + { int type; unsigned long serial; Bool send_event; @@ -794,7 +803,7 @@ clipboard_data_in(struct stream* s, int chan_id, int chan_flags, int length, Atom selection; Time timestamp; Time selection_timestamp; -} XFixesSelectionNotifyEvent; */ + } XFixesSelectionNotifyEvent; */ static int APP_CC clipboard_event_selection_owner_notify(XEvent* xevent) { @@ -836,7 +845,10 @@ clipboard_get_window_property(Window wnd, Atom prop, Atom* type, int* fmt, XGetWindowProperty(g_display, g_wnd, prop, 0, 0, 0, AnyPropertyType, <ype, &lfmt, &ln_items, &llen_after, &lxdata); - XFree(lxdata); + if (lxdata != 0) + { + XFree(lxdata); + } if (ltype == 0) { /* XGetWindowProperty failed */ @@ -845,13 +857,14 @@ clipboard_get_window_property(Window wnd, Atom prop, Atom* type, int* fmt, if (ltype == g_incr_atom) { + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_property_notify: INCR start")); g_incr_in_progress = 1; g_incr_atom_type = prop; g_incr_data_size = 0; g_free(g_incr_data); g_incr_data = 0; XDeleteProperty(g_display, g_wnd, prop); - return; + return 0; } if (llen_after < 1) @@ -867,20 +880,29 @@ clipboard_get_window_property(Window wnd, Atom prop, Atom* type, int* fmt, if (ltype == 0) { /* XGetWindowProperty failed */ - XFree(lxdata); + if (lxdata != 0) + { + XFree(lxdata); + } return 1; } lxdata_size = (lfmt / 8) * ln_items; if (lxdata_size < 1) { /* should not happen */ - XFree(lxdata); + if (lxdata != 0) + { + XFree(lxdata); + } return 2; } if (llen_after > 0) { /* should not happen */ - XFree(lxdata); + if (lxdata != 0) + { + XFree(lxdata); + } return 3; } if (xdata != 0) @@ -888,7 +910,10 @@ clipboard_get_window_property(Window wnd, Atom prop, Atom* type, int* fmt, *xdata = (char*)g_malloc(lxdata_size, 0); g_memcpy(*xdata, lxdata, lxdata_size); } - XFree(lxdata); + if (lxdata != 0) + { + XFree(lxdata); + } if (xdata_size != 0) { *xdata_size = lxdata_size; @@ -937,10 +962,10 @@ clipboard_event_selection_notify(XEvent* xevent) int convert_to_bmp_image; int send_format_announce; int atom; - int* atoms; + Atom* atoms; Atom type; tui32 format_id; - unsigned char format_name[32]; + char format_name[32]; LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify:")); data_size = 0; @@ -948,7 +973,9 @@ clipboard_event_selection_notify(XEvent* xevent) fmt = 0; convert_to_string = 0; convert_to_utf8 = 0; + convert_to_bmp_image = 0; send_format_announce = 0; + format_id = 0; rv = 0; data = 0; type = 0; @@ -985,9 +1012,10 @@ clipboard_event_selection_notify(XEvent* xevent) { if (lxevent->target == g_targets_atom) { + /* on a 64 bit machine, actual_format_return of 32 implies long */ if ((type == XA_ATOM) && (fmt == 32)) { - atoms = (int*)data; + atoms = (Atom*)data; for (index = 0; index < n_items; index++) { atom = atoms[index]; @@ -1026,6 +1054,7 @@ clipboard_event_selection_notify(XEvent* xevent) g_memcpy(g_last_clip_data, data, g_last_clip_size); g_last_clip_data[g_last_clip_size] = 0; send_format_announce = 1; + format_id = CB_FORMAT_UNICODETEXT; } else if (lxevent->target == XA_STRING) { @@ -1124,7 +1153,6 @@ clipboard_event_selection_request(XEvent* xevent) int n_items; int xdata_size; char* xdata; - int i; lxev = (XSelectionRequestEvent*)xevent; LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: g_wnd %d, " @@ -1163,7 +1191,6 @@ clipboard_event_selection_request(XEvent* xevent) /* target, property pairs */ LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: " "g_multiple_atom")); -#if 0 if (clipboard_get_window_property(xev.xselection.requestor, xev.xselection.property, &type, &fmt, &n_items, &xdata, @@ -1174,7 +1201,6 @@ clipboard_event_selection_request(XEvent* xevent) /* todo */ g_free(xdata); } -#endif } else if ((lxev->target == XA_STRING) || (lxev->target == g_utf8_atom)) { @@ -1205,6 +1231,18 @@ clipboard_event_selection_request(XEvent* xevent) return 0; } } + else if (lxev->target == g_image_bmp_atom) + { + g_memcpy(&g_saved_selection_req_event, lxev, + sizeof(g_saved_selection_req_event)); + g_last_clip_type = g_image_bmp_atom; + g_want_image_data = 1; + clipboard_format_id = CB_FORMAT_DIB; + clipboard_send_data_request(); + g_waiting_for_data_response = 1; + g_waiting_for_data_response_time = clipboard_get_local_time(); + return 0; + } else { LOGM((LOG_LEVEL_ERROR,"clipboard_event_selection_request: unknown " @@ -1257,7 +1295,7 @@ clipboard_event_property_notify(XEvent* xevent) int format_in_bytes; int new_data_len; char* cptr; - unsigned char format_name[32]; + char format_name[32]; LOG(10, ("clipboard_check_wait_objs: PropertyNotify .window %d " ".state %d .atom %d", xevent->xproperty.window, @@ -1276,11 +1314,13 @@ clipboard_event_property_notify(XEvent* xevent) } if (bytes_left <= 0) { + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_property_notify: INCR done")); g_memset(format_name, 0, 32); /* clipboard INCR cycle has completed */ g_incr_in_progress = 0; g_last_clip_size = g_incr_data_size; g_last_clip_data = g_incr_data; + g_incr_data = 0; g_last_clip_type = g_incr_atom_target; if (g_incr_atom_target == g_image_bmp_atom) { @@ -1296,25 +1336,22 @@ clipboard_event_property_notify(XEvent* xevent) &nitems_returned, &bytes_left, (unsigned char **) &data); format_in_bytes = actual_format_return / 8; - if (actual_format_return == 32 && sizeof(long) == 8) + if ((actual_format_return == 32) && (sizeof(long) == 8)) { /* on a 64 bit machine, actual_format_return of 32 implies long */ format_in_bytes = 8; } new_data_len = nitems_returned * format_in_bytes; -#if 1 + cptr = (char*)g_malloc(g_incr_data_size + new_data_len, 0); + g_memcpy(cptr, g_incr_data, g_incr_data_size); g_free(g_incr_data); - cptr = (char *) g_malloc(g_incr_data_size + new_data_len, 0); -#else - cptr = (char *) realloc(g_incr_data, g_incr_data_size + new_data_len); -#endif if (cptr == NULL) { + g_incr_data = 0; /* cannot add any more data */ if (data != 0) { XFree(data); - data = 0; } XDeleteProperty(g_display, g_wnd, g_incr_atom_type); return 0; @@ -1325,7 +1362,6 @@ clipboard_event_property_notify(XEvent* xevent) if (data) { XFree(data); - data = 0; } XDeleteProperty(g_display, g_wnd, g_incr_atom_type); } diff --git a/sesman/chansrv/xcommon.c b/sesman/chansrv/xcommon.c index 5510a055..70b52694 100644 --- a/sesman/chansrv/xcommon.c +++ b/sesman/chansrv/xcommon.c @@ -164,7 +164,7 @@ xcommon_check_wait_objs(void) { time_diff = xcommon_get_local_time() - g_waiting_for_data_response_time; - if (time_diff > 1000) + if (time_diff > 10000) { LOGM((LOG_LEVEL_ERROR, "xcommon_check_wait_objs: warning, " "waiting for data response too long"));