From e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 22:34:10 +0200 Subject: Adding upstream version 4.2.2. Signed-off-by: Daniel Baumann --- ui/time_shift.c | 449 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 449 insertions(+) create mode 100644 ui/time_shift.c (limited to 'ui/time_shift.c') diff --git a/ui/time_shift.c b/ui/time_shift.c new file mode 100644 index 0000000..e54aa21 --- /dev/null +++ b/ui/time_shift.c @@ -0,0 +1,449 @@ +/* time_shift.c + * Routines for "Time Shift" window + * Submitted by Edwin Groothuis + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include +#include +#include + +#include "time_shift.h" + +#include "ui/packet_list_utils.h" + +#define SHIFT_POS 0 +#define SHIFT_NEG 1 +#define SHIFT_SETTOZERO 1 +#define SHIFT_KEEPOFFSET 0 + +#define CHECK_YEARS(Y) \ + if (*Y < 1970) { \ + return "Years must be larger than 1970"; \ + } +#define CHECK_MONTHS(M) \ + if (*M < 1 || *M > 12) { \ + return "Months must be between [1..12]"; \ + } +#define CHECK_DAYS(D) \ + if (*D < 1 || *D > 31) { \ + return "Days must be between [1..31]"; \ + } +#define CHECK_HOURS(h) \ + if (*h < 0 || *h > 23) { \ + return "Hours must be between [0..23]"; \ + } +#define CHECK_HOUR(h) \ + if (*h < 0) { \ + return "Negative hours. Have you specified more than " \ + "one minus character?"; \ + } +#define CHECK_MINUTE(m) \ + if (*m < 0 || *m > 59) { \ + return "Minutes must be between [0..59]"; \ + } +#define CHECK_SECOND(s) \ + if (*s < 0 || *s > 59) { \ + return "Seconds must be between [0..59]"; \ + } + +static void +modify_time_perform(frame_data *fd, int neg, nstime_t *offset, int settozero) +{ + /* The actual shift */ + if (settozero == SHIFT_SETTOZERO) { + nstime_subtract(&(fd->abs_ts), &(fd->shift_offset)); + nstime_set_zero(&(fd->shift_offset)); + } + + if (neg == SHIFT_POS) { + nstime_add(&(fd->abs_ts), offset); + nstime_add(&(fd->shift_offset), offset); + } else if (neg == SHIFT_NEG) { + nstime_subtract(&(fd->abs_ts), offset); + nstime_subtract(&(fd->shift_offset), offset); + } else { + fprintf(stderr, "Modify_time_perform: neg = %d?\n", neg); + } +} + +/* + * If the line between (OT1, NT1) and (OT2, NT2) is a straight line + * and (OT3, NT3) is on that line, + * then (NT2 - NT1) / (OT2 - OT2) = (NT3 - NT1) / (OT3 - OT1) and + * then (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) = (NT3 - NT1) and + * then NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) = NT3 and + * then NT3 = NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) and + * thus NT3 = NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT1) + * or NT3 = NT1 + (OT3 - OT1) * ( deltaNT12 / deltaOT12) + * + * All the things you come up when waiting for the train to come... + */ +static void +calcNT3(nstime_t *OT1, nstime_t *OT3, nstime_t *NT1, nstime_t *NT3, + nstime_t *deltaOT, nstime_t *deltaNT) +{ + long double fnt, fot, f, secs, nsecs; + + fnt = (long double)deltaNT->secs + (deltaNT->nsecs / 1000000000.0L); + fot = (long double)deltaOT->secs + (deltaOT->nsecs / 1000000000.0L); + f = fnt / fot; + + nstime_copy(NT3, OT3); + nstime_subtract(NT3, OT1); + + secs = f * (long double)NT3->secs; + nsecs = f * (long double)NT3->nsecs; + nsecs += (secs - floorl(secs)) * 1000000000.0L; + while (nsecs > 1000000000L) { + secs += 1; + nsecs -= 1000000000L; + } + while (nsecs < 0) { + secs -= 1; + nsecs += 1000000000L; + } + NT3->secs = (time_t)secs; + NT3->nsecs = (int)nsecs; + nstime_add(NT3, NT1); +} + +const gchar * +time_string_parse(const gchar *time_text, int *year, int *month, int *day, gboolean *negative, int *hour, int *minute, long double *second) { + const gchar *pts = time_text; + + if (!time_text || !hour || !minute || !second) + return "Unable to convert time."; + + /* strip whitespace */ + while (g_ascii_isspace(pts[0])) + ++pts; + + if (year && month && day) { + /* + * The following time format is allowed: + * [YYYY-MM-DD] hh:mm:ss(.decimals)? + * + * Since Wireshark doesn't support regular expressions (please prove me + * wrong :-) we will have to figure it out ourselves in the + * following order: + * + * 1. YYYY-MM-DD hh:mm:ss.decimals + * 2. hh:mm:ss.decimals + * + */ + + /* check for empty string */ + if (pts[0] == '\0') + return "Time is empty."; + + if (sscanf(pts, "%d-%d-%d %d:%d:%Lf", year, month, day, hour, minute, second) == 6) { + /* printf("%%d-%%d-%%d %%d:%%d:%%f\n"); */ + CHECK_YEARS(year); + CHECK_MONTHS(month); + CHECK_DAYS(day); + CHECK_HOURS(hour); + CHECK_MINUTE(minute); + CHECK_SECOND(second); + } else if (sscanf(pts, "%d:%d:%Lf", hour, minute, second) == 3) { + /* printf("%%d:%%d:%%f\n"); */ + *year = *month = *day = 0; + CHECK_HOUR(hour); + CHECK_MINUTE(minute); + CHECK_SECOND(second); + } else { + return "Could not parse the time. Expected [YYYY-MM-DD] " + "hh:mm:ss[.dec]."; + } + } else { + if (!negative) + return "Unable to convert time."; + + /* + * The following offset types are allowed: + * -?((hh:)mm:)ss(.decimals)? + * + * Since Wireshark doesn't support regular expressions (please prove me + * wrong :-) we will have to figure it out ourselves in the + * following order: + * + * 1. hh:mm:ss.decimals + * 2. mm:ss.decimals + * 3. ss.decimals + * + */ + + /* check for minus sign */ + *negative = FALSE; + if (pts[0] == '-') { + *negative = TRUE; + pts++; + } + + /* check for empty string */ + if (pts[0] == '\0') + return "Time is empty."; + + if (sscanf(pts, "%d:%d:%Lf", hour, minute, second) == 3) { + /* printf("%%d:%%d:%%d.%%d\n"); */ + CHECK_HOUR(hour); + CHECK_MINUTE(minute); + CHECK_SECOND(second); + } else if (sscanf(pts, "%d:%Lf", minute, second) == 2) { + /* printf("%%d:%%d.%%d\n"); */ + CHECK_MINUTE(minute); + CHECK_SECOND(second); + *hour = 0; + } else if (sscanf(pts, "%Lf", second) == 1) { + /* printf("%%d.%%d\n"); */ + CHECK_SECOND(second); + *hour = *minute = 0; + } else { + return "Could not parse the time: Expected [[hh:]mm:]ss.[dec]."; + } + } + + return NULL; +} + +static const gchar * +time_string_to_nstime(const gchar *time_text, nstime_t *packettime, nstime_t *nstime) +{ + int h, m, Y, M, D; + long double f; + struct tm tm, *tmptm; + time_t tt; + const gchar *err_str; + + if ((err_str = time_string_parse(time_text, &Y, &M, &D, NULL, &h, &m, &f)) != NULL) + return err_str; + + /* Convert the time entered in an epoch offset */ + tmptm = localtime(&(packettime->secs)); + if (tmptm) { + tm = *tmptm; + } else { + memset (&tm, 0, sizeof (tm)); + } + if (Y != 0) { + tm.tm_year = Y - 1900; + tm.tm_mon = M - 1; + tm.tm_mday = D; + } + tm.tm_hour = h; + tm.tm_min = m; + tm.tm_sec = (int)floorl(f); + tm.tm_isdst = -1; + tt = mktime(&tm); + if (tt == -1) { + return "Mktime went wrong. Is the time valid?"; + } + + nstime->secs = tt; + f -= tm.tm_sec; + nstime->nsecs = (int)(f * 1000000000); + + return NULL; +} + +const gchar * +time_shift_all(capture_file *cf, const gchar *offset_text) +{ + nstime_t offset; + long double offset_float = 0; + guint32 i; + frame_data *fd; + gboolean neg; + int h, m; + long double f; + const gchar *err_str; + + if (!cf || !offset_text) + return "Nothing to work with."; + + if ((err_str = time_string_parse(offset_text, NULL, NULL, NULL, &neg, &h, &m, &f)) != NULL) + return err_str; + + offset_float = h * 3600 + m * 60 + f; + + if (offset_float == 0) + return "Offset is zero."; + + nstime_set_zero(&offset); + offset.secs = (time_t)floorl(offset_float); + offset_float -= offset.secs; + offset.nsecs = (int)(offset_float * 1000000000); + + if (!frame_data_sequence_find(cf->provider.frames, 1)) + return "No frames found."; /* Shouldn't happen */ + + for (i = 1; i <= cf->count; i++) { + if ((fd = frame_data_sequence_find(cf->provider.frames, i)) == NULL) + continue; /* Shouldn't happen */ + modify_time_perform(fd, neg ? SHIFT_NEG : SHIFT_POS, &offset, SHIFT_KEEPOFFSET); + } + cf->unsaved_changes = TRUE; + packet_list_queue_draw(); + + return NULL; +} + +const gchar * +time_shift_settime(capture_file *cf, guint packet_num, const gchar *time_text) +{ + nstime_t set_time, diff_time, packet_time; + frame_data *fd, *packetfd; + guint32 i; + const gchar *err_str; + + if (!cf || !time_text) + return "Nothing to work with."; + + if (packet_num < 1 || packet_num > cf->count) + return "Packet out of range."; + + /* + * Get a copy of the real time (abs_ts - shift_offset) do we can find out the + * difference between the specified time and the original packet + */ + if ((packetfd = frame_data_sequence_find(cf->provider.frames, packet_num)) == NULL) + return "No packets found."; + nstime_delta(&packet_time, &(packetfd->abs_ts), &(packetfd->shift_offset)); + + if ((err_str = time_string_to_nstime(time_text, &packet_time, &set_time)) != NULL) + return err_str; + + /* Calculate difference between packet time and requested time */ + nstime_delta(&diff_time, &set_time, &packet_time); + + /* Up to here nothing is changed */ + + if (!frame_data_sequence_find(cf->provider.frames, 1)) + return "No frames found."; /* Shouldn't happen */ + + /* Set everything back to the original time */ + for (i = 1; i <= cf->count; i++) { + if ((fd = frame_data_sequence_find(cf->provider.frames, i)) == NULL) + continue; /* Shouldn't happen */ + modify_time_perform(fd, SHIFT_POS, &diff_time, SHIFT_SETTOZERO); + } + + cf->unsaved_changes = TRUE; + packet_list_queue_draw(); + return NULL; +} + +const gchar * +time_shift_adjtime(capture_file *cf, guint packet1_num, const gchar *time1_text, guint packet2_num, const gchar *time2_text) +{ + nstime_t nt1, nt2, ot1, ot2, nt3; + nstime_t dnt, dot, d3t; + frame_data *fd, *packet1fd, *packet2fd; + guint32 i; + const gchar *err_str; + + if (!cf || !time1_text || !time2_text) + return "Nothing to work with."; + + if (packet1_num < 1 || packet1_num > cf->count || packet2_num < 1 || packet2_num > cf->count) + return "Packet out of range."; + + /* + * The following time format is allowed: + * [YYYY-MM-DD] hh:mm:ss(.decimals)? + * + * Since Wireshark doesn't support regular expressions (please prove me + * wrong :-) we will have to figure it out ourselves in the + * following order: + * + * 1. YYYY-MM-DD hh:mm:ss.decimals + * 2. hh:mm:ss.decimals + * + */ + + /* + * Get a copy of the real time (abs_ts - shift_offset) do we can find out the + * difference between the specified time and the original packet + */ + if ((packet1fd = frame_data_sequence_find(cf->provider.frames, packet1_num)) == NULL) + return "No frames found."; + nstime_copy(&ot1, &(packet1fd->abs_ts)); + nstime_subtract(&ot1, &(packet1fd->shift_offset)); + + if ((err_str = time_string_to_nstime(time1_text, &ot1, &nt1)) != NULL) + return err_str; + + /* + * Get a copy of the real time (abs_ts - shift_offset) do we can find out the + * difference between the specified time and the original packet + */ + if ((packet2fd = frame_data_sequence_find(cf->provider.frames, packet2_num)) == NULL) + return "No frames found."; + nstime_copy(&ot2, &(packet2fd->abs_ts)); + nstime_subtract(&ot2, &(packet2fd->shift_offset)); + + if ((err_str = time_string_to_nstime(time2_text, &ot2, &nt2)) != NULL) + return err_str; + + nstime_copy(&dot, &ot2); + nstime_subtract(&dot, &ot1); + + nstime_copy(&dnt, &nt2); + nstime_subtract(&dnt, &nt1); + + /* Up to here nothing is changed */ + if (!frame_data_sequence_find(cf->provider.frames, 1)) + return "No frames found."; /* Shouldn't happen */ + + for (i = 1; i <= cf->count; i++) { + if ((fd = frame_data_sequence_find(cf->provider.frames, i)) == NULL) + continue; /* Shouldn't happen */ + + /* Set everything back to the original time */ + nstime_subtract(&(fd->abs_ts), &(fd->shift_offset)); + nstime_set_zero(&(fd->shift_offset)); + + /* Add the difference to each packet */ + calcNT3(&ot1, &(fd->abs_ts), &nt1, &nt3, &dot, &dnt); + + nstime_copy(&d3t, &nt3); + nstime_subtract(&d3t, &(fd->abs_ts)); + + modify_time_perform(fd, SHIFT_POS, &d3t, SHIFT_SETTOZERO); + } + + cf->unsaved_changes = TRUE; + packet_list_queue_draw(); + return NULL; +} + +const gchar * +time_shift_undo(capture_file *cf) +{ + guint32 i; + frame_data *fd; + nstime_t nulltime; + + if (!cf) + return "Nothing to work with."; + + nulltime.secs = nulltime.nsecs = 0; + + if (!frame_data_sequence_find(cf->provider.frames, 1)) + return "No frames found."; /* Shouldn't happen */ + + for (i = 1; i <= cf->count; i++) { + if ((fd = frame_data_sequence_find(cf->provider.frames, i)) == NULL) + continue; /* Shouldn't happen */ + modify_time_perform(fd, SHIFT_NEG, &nulltime, SHIFT_SETTOZERO); + } + packet_list_queue_draw(); + return NULL; +} -- cgit v1.2.3