From 2742b89042d045ec3ab775cac7c1fdbb675e2dae Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:13:29 +0000 Subject: [PATCH] Replace g_time3() with g_get_elapsed_ms() The function as specified used gettimeofday() which is susceptible to manual time changes, and is obsoleted in POSIX.1-2008. The replacement uses clock_gettime(CLOCK_MONOTONIC, ) which is not susceptible to manual time changes (at least on Linux) and cannot run backwards. Also, on systems with 32-bit integers, the value returned by this function wraps around every 49.7 days. To cope with a wraparound in a way compliant with the C standard, this value needs to return an unsigned integer type rather than a signed integer type. --- common/os_calls.c | 24 +++++++++++++----------- common/os_calls.h | 18 +++++++++++++++++- common/trans.c | 12 ++++++------ sesman/chansrv/chansrv.c | 6 +++--- sesman/chansrv/sound.c | 24 ++++++++++++------------ sesman/chansrv/xcommon.c | 9 --------- sesman/chansrv/xcommon.h | 2 -- xrdp/xrdp.h | 4 ++-- xrdp/xrdp_mm.c | 19 ++++++++++--------- xrdp/xrdp_types.h | 2 +- 10 files changed, 64 insertions(+), 56 deletions(-) diff --git a/common/os_calls.c b/common/os_calls.c index 5d65fd4caf..95f6aca834 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -3764,19 +3764,21 @@ g_check_user_in_group(const char *username, int gid, int *ok) #endif // HAVE_GETGROUPLIST /*****************************************************************************/ -/* returns time in milliseconds, uses gettimeofday - does not work in win32 */ -int -g_time3(void) +unsigned int +g_get_elapsed_ms(void) { -#if defined(_WIN32) - return 0; -#else - struct timeval tp; + unsigned int result = 0; + struct timespec tp; - gettimeofday(&tp, 0); - return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); -#endif + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) + { + result = (unsigned int)tp.tv_sec * 1000; + // POSIX 1003.1, 2004 that tv_nsec is a long (i.e. a signed type), + // but can only contain [0..999,999,999] + result += tp.tv_nsec / 1000000; + } + + return result; } /******************************************************************************/ diff --git a/common/os_calls.h b/common/os_calls.h index 0ef5cdba06..51c609508b 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -393,7 +393,23 @@ int g_getgroup_info(const char *groupname, int *gid); * Primary group of username is also checked */ int g_check_user_in_group(const char *username, int gid, int *ok); -int g_time3(void); + +/** + * Gets elapsed milliseconds since some arbitrary point in the past + * + * The returned value is unaffected by leap-seconds or time zone changes. + * + * @returns elaped ms since some arbirtary point + * + * The value wraps every so often (every 49.7 days on a 32-bit system), + * but as we are using unsigned arithmetic, the difference of any of these + * two values can be used to calculate elapsed time, whether-or-not a wrap + * occurs during the interval - provided of course the time being measured + * is less than the total wraparound interval. + */ +unsigned int +g_get_elapsed_ms(void); + int g_save_to_bmp(const char *filename, char *data, int stride_bytes, int width, int height, int depth, int bits_per_pixel); void *g_shmat(int shmid); diff --git a/common/trans.c b/common/trans.c index 780b4c52a7..3f74834ff7 100644 --- a/common/trans.c +++ b/common/trans.c @@ -696,7 +696,7 @@ local_connect_shim(int fd, const char *server, const char *port) /**************************************************************************//** * Waits for an asynchronous connect to complete. * @param self - Transport object - * @param start_time Start time of connect (from g_time3()) + * @param start_time Start time of connect (from g_get_elapsed_ms()) * @param timeout Total wait timeout * @return 0 - connect succeeded, 1 - Connect failed * @@ -704,10 +704,10 @@ local_connect_shim(int fd, const char *server, const char *port) * on a regular basis. */ static int -poll_for_async_connect(struct trans *self, int start_time, int timeout) +poll_for_async_connect(struct trans *self, unsigned int start_time, int timeout) { int rv = 1; - int ms_remaining = timeout - (g_time3() - start_time); + int ms_remaining = timeout - (g_get_elapsed_ms() - start_time); while (ms_remaining > 0) { @@ -736,7 +736,7 @@ poll_for_async_connect(struct trans *self, int start_time, int timeout) break; } - ms_remaining = timeout - (g_time3() - start_time); + ms_remaining = timeout - (g_get_elapsed_ms() - start_time); } return rv; } @@ -747,7 +747,7 @@ int trans_connect(struct trans *self, const char *server, const char *port, int timeout) { - int start_time = g_time3(); + unsigned int start_time = g_get_elapsed_ms(); int error; int ms_before_next_connect; @@ -826,7 +826,7 @@ trans_connect(struct trans *self, const char *server, const char *port, } /* Have we reached the total timeout yet? */ - int ms_left = timeout - (g_time3() - start_time); + int ms_left = timeout - (g_get_elapsed_ms() - start_time); if (ms_left <= 0) { error = 1; diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index e890febcc2..9aa480d96e 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -132,7 +132,7 @@ add_timeout(int msoffset, void (*callback)(void *data), void *data) tui32 now; LOG_DEVEL(LOG_LEVEL_DEBUG, "add_timeout:"); - now = g_time3(); + now = g_get_elapsed_ms(); tobj = g_new0(struct timeout_obj, 1); tobj->mstime = now + msoffset; tobj->callback = callback; @@ -167,7 +167,7 @@ get_timeout(int *timeout) tobj = g_timeout_head; if (tobj != 0) { - now = g_time3(); + now = g_get_elapsed_ms(); while (tobj != 0) { LOG_DEVEL(LOG_LEVEL_DEBUG, " now %u tobj->mstime %u", now, tobj->mstime); @@ -215,7 +215,7 @@ check_timeout(void) while (tobj != 0) { count++; - now = g_time3(); + now = g_get_elapsed_ms(); if (now >= tobj->mstime) { tobj->callback(tobj->data); diff --git a/sesman/chansrv/sound.c b/sesman/chansrv/sound.c index 2c862f99bd..ba3685ae79 100644 --- a/sesman/chansrv/sound.c +++ b/sesman/chansrv/sound.c @@ -71,7 +71,7 @@ static struct trans *g_audio_c_trans_out = 0; /* connection */ static struct trans *g_audio_l_trans_in = 0; /* listener */ static struct trans *g_audio_c_trans_in = 0; /* connection */ -static int g_training_sent_time = 0; +static unsigned int g_training_sent_time = 0; static int g_cBlockNo = 0; static int g_bytes_in_stream = 0; struct fifo *g_in_fifo; @@ -86,7 +86,7 @@ static struct stream *g_stream_incoming_packet = NULL; #define MAX_BBUF_SIZE (1024 * 16) static char g_buffer[MAX_BBUF_SIZE]; static int g_buf_index = 0; -static int g_sent_time[256]; +static unsigned int g_sent_time[256]; static int g_bbuf_size = 1024 * 8; /* may change later */ @@ -341,7 +341,7 @@ sound_send_training(void) { struct stream *s; int bytes; - int time; + unsigned int time; char *size_ptr; make_stream(s); @@ -349,7 +349,7 @@ sound_send_training(void) out_uint16_le(s, SNDC_TRAINING); size_ptr = s->p; out_uint16_le(s, 0); /* size, set later */ - time = g_time3(); + time = g_get_elapsed_ms(); g_training_sent_time = time; out_uint16_le(s, time); out_uint16_le(s, 1024); @@ -885,7 +885,7 @@ sound_send_wave_data_chunk(char *data, int data_bytes) { struct stream *s; int bytes; - int time; + unsigned int time; int format_index; char *size_ptr; @@ -912,7 +912,7 @@ sound_send_wave_data_chunk(char *data, int data_bytes) out_uint16_le(s, SNDC_WAVE); size_ptr = s->p; out_uint16_le(s, 0); /* size, set later */ - time = g_time3(); + time = g_get_elapsed_ms(); out_uint16_le(s, time); out_uint16_le(s, format_index); /* wFormatNo */ g_cBlockNo++; @@ -1040,7 +1040,7 @@ sound_process_training(struct stream *s, int size) { int time_diff; - time_diff = g_time3() - g_training_sent_time; + time_diff = g_get_elapsed_ms() - g_training_sent_time; LOG(LOG_LEVEL_INFO, "sound_process_training: round trip time %u", time_diff); return 0; } @@ -1052,12 +1052,12 @@ sound_process_wave_confirm(struct stream *s, int size) { int wTimeStamp; int cConfirmedBlockNo; - int time; + unsigned int time; int time_diff; int index; int acc; - time = g_time3(); + time = g_get_elapsed_ms(); in_uint16_le(s, wTimeStamp); in_uint8(s, cConfirmedBlockNo); time_diff = time - g_sent_time[cConfirmedBlockNo & 0xff]; @@ -1095,13 +1095,13 @@ static int process_pcm_message(int id, int size, struct stream *s) { static int sending_silence = 0; - static int silence_start_time = 0; + static unsigned int silence_start_time = 0; switch (id) { case 0: if ((g_client_does_fdk_aac || g_client_does_mp3lame) && sending_silence) { - if ((g_time3() - silence_start_time) < (int)g_cfg->msec_do_not_send) + if ((g_get_elapsed_ms() - silence_start_time) < g_cfg->msec_do_not_send) { /* do not send data within msec_do_not_send msec after SNDC_CLOSE is sent, to avoid stutter. setting from sesman.ini */ return 0; @@ -1119,7 +1119,7 @@ process_pcm_message(int id, int size, struct stream *s) if (buf != NULL) { int i; - silence_start_time = g_time3(); + silence_start_time = g_get_elapsed_ms(); sending_silence = 1; for (i = 0; i < send_silence_times; i++) { diff --git a/sesman/chansrv/xcommon.c b/sesman/chansrv/xcommon.c index 5655176772..2067bbd6f4 100644 --- a/sesman/chansrv/xcommon.c +++ b/sesman/chansrv/xcommon.c @@ -85,15 +85,6 @@ xcommon_fatal_handler(Display *dis) return 0; } -/*****************************************************************************/ -/* returns time in milliseconds since a point in the past - this is a time value similar to what the xserver uses */ -int -xcommon_get_local_time(void) -{ - return g_time3(); -} - /******************************************************************************/ /* this should be called first */ int diff --git a/sesman/chansrv/xcommon.h b/sesman/chansrv/xcommon.h index 75e93c0957..3195eda2a9 100644 --- a/sesman/chansrv/xcommon.h +++ b/sesman/chansrv/xcommon.h @@ -28,8 +28,6 @@ typedef void (*x_server_fatal_cb_type)(void); -int -xcommon_get_local_time(void); int xcommon_init(void); int diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 072df9cc0a..96ee93c222 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -489,8 +489,8 @@ struct display_control_monitor_layout_data { struct display_size_description description; enum display_resize_state state; - int last_state_update_timestamp; - int start_time; + unsigned int last_state_update_timestamp; + unsigned int start_time; /// This flag is set if the state machine needs to /// shutdown/startup EGFX int using_egfx; diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 5d276c3b88..ecfb0773af 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -1280,9 +1280,9 @@ advance_resize_state_machine(struct xrdp_mm *mm, description->description.session_height, XRDP_DISPLAY_RESIZE_STATE_TO_STR(description->state), XRDP_DISPLAY_RESIZE_STATE_TO_STR(new_state), - g_time3() - description->last_state_update_timestamp); + g_get_elapsed_ms() - description->last_state_update_timestamp); description->state = new_state; - description->last_state_update_timestamp = g_time3(); + description->last_state_update_timestamp = g_get_elapsed_ms(); g_set_wait_obj(mm->resize_ready); return 0; } @@ -1829,7 +1829,7 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) // ever is, advance the state machine! if (chan->drdynvcs[mm->egfx->channel_id].status == XRDP_DRDYNVC_STATUS_CLOSED - || (g_time3() - description->last_state_update_timestamp) > 100) + || (g_get_elapsed_ms() - description->last_state_update_timestamp) > 100) { advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSED); break; @@ -2045,7 +2045,7 @@ dynamic_monitor_process_queue(struct xrdp_mm *self) g_malloc(LAYOUT_DATA_SIZE, 1); g_memcpy(&(self->resize_data->description), queue_head, sizeof(struct display_size_description)); - const int time = g_time3(); + const unsigned int time = g_get_elapsed_ms(); self->resize_data->start_time = time; self->resize_data->last_state_update_timestamp = time; self->resize_data->using_egfx = (self->egfx != NULL); @@ -2075,7 +2075,7 @@ dynamic_monitor_process_queue(struct xrdp_mm *self) " completed resize (w: %d x h: %d). It took %d milliseconds.", self->resize_data->description.session_width, self->resize_data->description.session_height, - g_time3() - self->resize_data->start_time); + g_get_elapsed_ms() - self->resize_data->start_time); g_set_wait_obj(self->resize_ready); } else if (self->resize_data->state == WMRZ_ERROR) @@ -3532,9 +3532,10 @@ xrdp_mm_get_wait_objs(struct xrdp_mm *self, { if (xrdp_region_not_empty(self->wm->screen_dirty_region)) { - int now = g_time3(); - int next_screen_draw_time = self->wm->last_screen_draw_time + - MIN_MS_BETWEEN_FRAMES; + unsigned int now = g_get_elapsed_ms(); + unsigned int next_screen_draw_time = + self->wm->last_screen_draw_time + + MIN_MS_BETWEEN_FRAMES; int diff = next_screen_draw_time - now; int ltimeout = *timeout; diff = MAX(diff, MIN_MS_TO_WAIT_FOR_MORE_UPDATES); @@ -3924,7 +3925,7 @@ xrdp_mm_check_wait_objs(struct xrdp_mm *self) { if (xrdp_region_not_empty(self->wm->screen_dirty_region)) { - int now = g_time3(); + unsigned int now = g_get_elapsed_ms(); int diff = now - self->wm->last_screen_draw_time; LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_check_wait_objs: not empty diff %d", diff); if ((diff < 0) || (diff >= 40)) diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index d972e02fd3..f4ef5cd143 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -589,7 +589,7 @@ struct xrdp_wm struct xrdp_tconfig_gfx *gfx_config; struct xrdp_region *screen_dirty_region; - int last_screen_draw_time; + unsigned int last_screen_draw_time; }; /* rdp process */