1 /* time_shift.c 2 * Routines for "Time Shift" window 3 * Submitted by Edwin Groothuis <wireshark@mavetju.org> 4 * 5 * Wireshark - Network traffic analyzer 6 * By Gerald Combs <gerald@wireshark.org> 7 * Copyright 1998 Gerald Combs 8 * 9 * SPDX-License-Identifier: GPL-2.0-or-later 10 */ 11 12 #include "config.h" 13 14 #include <stdio.h> 15 #include <string.h> 16 #include <math.h> 17 18 #include "time_shift.h" 19 20 #include "ui/ws_ui_util.h" 21 22 #define SHIFT_POS 0 23 #define SHIFT_NEG 1 24 #define SHIFT_SETTOZERO 1 25 #define SHIFT_KEEPOFFSET 0 26 27 #define CHECK_YEARS(Y) \ 28 if (*Y < 1970) { \ 29 return "Years must be larger than 1970"; \ 30 } 31 #define CHECK_MONTHS(M) \ 32 if (*M < 1 || *M > 12) { \ 33 return "Months must be between [1..12]"; \ 34 } 35 #define CHECK_DAYS(D) \ 36 if (*D < 1 || *D > 31) { \ sum_c4(gfc_array_c4 * const restrict retarray,gfc_array_c4 * const restrict array,const index_type * const restrict pdim)37 return "Days must be between [1..31]"; \ 38 } 39 #define CHECK_HOURS(h) \ 40 if (*h < 0 || *h > 23) { \ 41 return "Hours must be between [0..23]"; \ 42 } 43 #define CHECK_HOUR(h) \ 44 if (*h < 0) { \ 45 return "Negative hours. Have you specified more than " \ 46 "one minus character?"; \ 47 } 48 #define CHECK_MINUTE(m) \ 49 if (*m < 0 || *m > 59) { \ 50 return "Minutes must be between [0..59]"; \ 51 } 52 #define CHECK_SECOND(s) \ 53 if (*s < 0 || *s > 59) { \ 54 return "Seconds must be between [0..59]"; \ 55 } 56 57 static void 58 modify_time_perform(frame_data *fd, int neg, nstime_t *offset, int settozero) 59 { 60 /* The actual shift */ 61 if (settozero == SHIFT_SETTOZERO) { 62 nstime_subtract(&(fd->abs_ts), &(fd->shift_offset)); 63 nstime_set_zero(&(fd->shift_offset)); 64 } 65 66 if (neg == SHIFT_POS) { 67 nstime_add(&(fd->abs_ts), offset); 68 nstime_add(&(fd->shift_offset), offset); 69 } else if (neg == SHIFT_NEG) { 70 nstime_subtract(&(fd->abs_ts), offset); 71 nstime_subtract(&(fd->shift_offset), offset); 72 } else { 73 fprintf(stderr, "Modify_time_perform: neg = %d?\n", neg); 74 } 75 } 76 77 /* 78 * If the line between (OT1, NT1) and (OT2, NT2) is a straight line 79 * and (OT3, NT3) is on that line, 80 * then (NT2 - NT1) / (OT2 - OT2) = (NT3 - NT1) / (OT3 - OT1) and 81 * then (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) = (NT3 - NT1) and 82 * then NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) = NT3 and 83 * then NT3 = NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) and 84 * thus NT3 = NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT1) 85 * or NT3 = NT1 + (OT3 - OT1) * ( deltaNT12 / deltaOT12) 86 * 87 * All the things you come up when waiting for the train to come... 88 */ 89 static void 90 calcNT3(nstime_t *OT1, nstime_t *OT3, nstime_t *NT1, nstime_t *NT3, 91 nstime_t *deltaOT, nstime_t *deltaNT) 92 { 93 long double fnt, fot, f, secs, nsecs; 94 95 fnt = (long double)deltaNT->secs + (deltaNT->nsecs / 1000000000.0L); 96 fot = (long double)deltaOT->secs + (deltaOT->nsecs / 1000000000.0L); 97 f = fnt / fot; 98 99 nstime_copy(NT3, OT3); 100 nstime_subtract(NT3, OT1); 101 102 secs = f * (long double)NT3->secs; 103 nsecs = f * (long double)NT3->nsecs; 104 nsecs += (secs - floorl(secs)) * 1000000000.0L; 105 while (nsecs > 1000000000L) { 106 secs += 1; 107 nsecs -= 1000000000L; 108 } 109 while (nsecs < 0) { 110 secs -= 1; 111 nsecs += 1000000000L; 112 } 113 NT3->secs = (time_t)secs; 114 NT3->nsecs = (int)nsecs; 115 nstime_add(NT3, NT1); 116 } 117 118 const gchar * 119 time_string_parse(const gchar *time_text, int *year, int *month, int *day, gboolean *negative, int *hour, int *minute, long double *second) { 120 const gchar *pts = time_text; 121 122 if (!time_text || !hour || !minute || !second) 123 return "Unable to convert time."; 124 125 /* strip whitespace */ 126 while (g_ascii_isspace(pts[0])) 127 ++pts; 128 129 if (year && month && day) { 130 /* 131 * The following time format is allowed: 132 * [YYYY-MM-DD] hh:mm:ss(.decimals)? 133 * 134 * Since Wireshark doesn't support regular expressions (please prove me 135 * wrong :-) we will have to figure it out ourselves in the 136 * following order: 137 * 138 * 1. YYYY-MM-DD hh:mm:ss.decimals 139 * 2. hh:mm:ss.decimals 140 * 141 */ 142 143 /* check for empty string */ 144 if (pts[0] == '\0') 145 return "Time is empty."; 146 147 if (sscanf(pts, "%d-%d-%d %d:%d:%Lf", year, month, day, hour, minute, second) == 6) { 148 /* printf("%%d-%%d-%%d %%d:%%d:%%f\n"); */ 149 CHECK_YEARS(year); 150 CHECK_MONTHS(month); 151 CHECK_DAYS(day); 152 CHECK_HOURS(hour); 153 CHECK_MINUTE(minute); 154 CHECK_SECOND(second); 155 } else if (sscanf(pts, "%d:%d:%Lf", hour, minute, second) == 3) { 156 /* printf("%%d:%%d:%%f\n"); */ 157 *year = *month = *day = 0; 158 CHECK_HOUR(hour); 159 CHECK_MINUTE(minute); 160 CHECK_SECOND(second); 161 } else { 162 return "Could not parse the time. Expected [YYYY-MM-DD] " 163 "hh:mm:ss[.dec]."; 164 } 165 } else { 166 if (!negative) 167 return "Unable to convert time."; 168 169 /* 170 * The following offset types are allowed: 171 * -?((hh:)mm:)ss(.decimals)? 172 * 173 * Since Wireshark doesn't support regular expressions (please prove me 174 * wrong :-) we will have to figure it out ourselves in the 175 * following order: 176 * 177 * 1. hh:mm:ss.decimals 178 * 2. mm:ss.decimals 179 * 3. ss.decimals 180 * 181 */ 182 183 /* check for minus sign */ 184 *negative = FALSE; 185 if (pts[0] == '-') { 186 *negative = TRUE; 187 pts++; 188 } 189 190 /* check for empty string */ 191 if (pts[0] == '\0') 192 return "Time is empty."; 193 194 if (sscanf(pts, "%d:%d:%Lf", hour, minute, second) == 3) { 195 /* printf("%%d:%%d:%%d.%%d\n"); */ 196 CHECK_HOUR(hour); 197 CHECK_MINUTE(minute); 198 CHECK_SECOND(second); 199 } else if (sscanf(pts, "%d:%Lf", minute, second) == 2) { 200 /* printf("%%d:%%d.%%d\n"); */ 201 CHECK_MINUTE(minute); msum_c4(gfc_array_c4 * const restrict retarray,gfc_array_c4 * const restrict array,const index_type * const restrict pdim,gfc_array_l1 * const restrict mask)202 CHECK_SECOND(second); 203 *hour = 0; 204 } else if (sscanf(pts, "%Lf", second) == 1) { 205 /* printf("%%d.%%d\n"); */ 206 CHECK_SECOND(second); 207 *hour = *minute = 0; 208 } else { 209 return "Could not parse the time: Expected [[hh:]mm:]ss.[dec]."; 210 } 211 } 212 213 return NULL; 214 } 215 216 static const gchar * 217 time_string_to_nstime(const gchar *time_text, nstime_t *packettime, nstime_t *nstime) 218 { 219 int h, m, Y, M, D; 220 long double f; 221 struct tm tm, *tmptm; 222 time_t tt; 223 const gchar *err_str; 224 225 if ((err_str = time_string_parse(time_text, &Y, &M, &D, NULL, &h, &m, &f)) != NULL) 226 return err_str; 227 228 /* Convert the time entered in an epoch offset */ 229 tmptm = localtime(&(packettime->secs)); 230 if (tmptm) { 231 tm = *tmptm; 232 } else { 233 memset (&tm, 0, sizeof (tm)); 234 } 235 if (Y != 0) { 236 tm.tm_year = Y - 1900; 237 tm.tm_mon = M - 1; 238 tm.tm_mday = D; 239 } 240 tm.tm_hour = h; 241 tm.tm_min = m; 242 tm.tm_sec = (int)floorl(f); 243 tm.tm_isdst = -1; 244 tt = mktime(&tm); 245 if (tt == -1) { 246 return "Mktime went wrong. Is the time valid?"; 247 } 248 249 nstime->secs = tt; 250 f -= tm.tm_sec; 251 nstime->nsecs = (int)(f * 1000000000); 252 253 return NULL; 254 } 255 256 const gchar * 257 time_shift_all(capture_file *cf, const gchar *offset_text) 258 { 259 nstime_t offset; 260 long double offset_float = 0; 261 guint32 i; 262 frame_data *fd; 263 gboolean neg; 264 int h, m; 265 long double f; 266 const gchar *err_str; 267 268 if (!cf || !offset_text) 269 return "Nothing to work with."; 270 271 if ((err_str = time_string_parse(offset_text, NULL, NULL, NULL, &neg, &h, &m, &f)) != NULL) 272 return err_str; 273 274 offset_float = h * 3600 + m * 60 + f; 275 276 if (offset_float == 0) 277 return "Offset is zero."; 278 279 nstime_set_zero(&offset); 280 offset.secs = (time_t)floorl(offset_float); 281 offset_float -= offset.secs; 282 offset.nsecs = (int)(offset_float * 1000000000); 283 284 if (!frame_data_sequence_find(cf->provider.frames, 1)) 285 return "No frames found."; /* Shouldn't happen */ 286 287 for (i = 1; i <= cf->count; i++) { 288 if ((fd = frame_data_sequence_find(cf->provider.frames, i)) == NULL) 289 continue; /* Shouldn't happen */ 290 modify_time_perform(fd, neg ? SHIFT_NEG : SHIFT_POS, &offset, SHIFT_KEEPOFFSET); 291 } 292 cf->unsaved_changes = TRUE; 293 packet_list_queue_draw(); 294 295 return NULL; 296 } 297 298 const gchar * 299 time_shift_settime(capture_file *cf, guint packet_num, const gchar *time_text) 300 { 301 nstime_t set_time, diff_time, packet_time; 302 frame_data *fd, *packetfd; 303 guint32 i; 304 const gchar *err_str; 305 306 if (!cf || !time_text) 307 return "Nothing to work with."; 308 309 if (packet_num < 1 || packet_num > cf->count) 310 return "Packet out of range."; 311 312 /* 313 * Get a copy of the real time (abs_ts - shift_offset) do we can find out the 314 * difference between the specified time and the original packet 315 */ 316 if ((packetfd = frame_data_sequence_find(cf->provider.frames, packet_num)) == NULL) 317 return "No packets found."; 318 nstime_delta(&packet_time, &(packetfd->abs_ts), &(packetfd->shift_offset)); 319 320 if ((err_str = time_string_to_nstime(time_text, &packet_time, &set_time)) != NULL) 321 return err_str; 322 323 /* Calculate difference between packet time and requested time */ 324 nstime_delta(&diff_time, &set_time, &packet_time); 325 326 /* Up to here nothing is changed */ 327 328 if (!frame_data_sequence_find(cf->provider.frames, 1)) 329 return "No frames found."; /* Shouldn't happen */ 330 331 /* Set everything back to the original time */ 332 for (i = 1; i <= cf->count; i++) { 333 if ((fd = frame_data_sequence_find(cf->provider.frames, i)) == NULL) 334 continue; /* Shouldn't happen */ 335 modify_time_perform(fd, SHIFT_POS, &diff_time, SHIFT_SETTOZERO); 336 } 337 338 cf->unsaved_changes = TRUE; 339 packet_list_queue_draw(); 340 return NULL; 341 } 342 343 const gchar * 344 time_shift_adjtime(capture_file *cf, guint packet1_num, const gchar *time1_text, guint packet2_num, const gchar *time2_text) 345 { 346 nstime_t nt1, nt2, ot1, ot2, nt3; 347 nstime_t dnt, dot, d3t; 348 frame_data *fd, *packet1fd, *packet2fd; 349 guint32 i; 350 const gchar *err_str; 351 352 if (!cf || !time1_text || !time2_text) 353 return "Nothing to work with."; 354 355 if (packet1_num < 1 || packet1_num > cf->count || packet2_num < 1 || packet2_num > cf->count) 356 return "Packet out of range."; 357 358 /* 359 * The following time format is allowed: 360 * [YYYY-MM-DD] hh:mm:ss(.decimals)? 361 * 362 * Since Wireshark doesn't support regular expressions (please prove me 363 * wrong :-) we will have to figure it out ourselves in the 364 * following order: 365 * 366 * 1. YYYY-MM-DD hh:mm:ss.decimals 367 * 2. hh:mm:ss.decimals 368 * 369 */ 370 371 /* 372 * Get a copy of the real time (abs_ts - shift_offset) do we can find out the 373 * difference between the specified time and the original packet 374 */ 375 if ((packet1fd = frame_data_sequence_find(cf->provider.frames, packet1_num)) == NULL) 376 return "No frames found."; 377 nstime_copy(&ot1, &(packet1fd->abs_ts)); 378 nstime_subtract(&ot1, &(packet1fd->shift_offset)); 379 380 if ((err_str = time_string_to_nstime(time1_text, &ot1, &nt1)) != NULL) 381 return err_str; 382 383 /* 384 * Get a copy of the real time (abs_ts - shift_offset) do we can find out the 385 * difference between the specified time and the original packet 386 */ 387 if ((packet2fd = frame_data_sequence_find(cf->provider.frames, packet2_num)) == NULL) 388 return "No frames found."; 389 nstime_copy(&ot2, &(packet2fd->abs_ts)); 390 nstime_subtract(&ot2, &(packet2fd->shift_offset)); 391 392 if ((err_str = time_string_to_nstime(time2_text, &ot2, &nt2)) != NULL) 393 return err_str; 394 395 nstime_copy(&dot, &ot2); 396 nstime_subtract(&dot, &ot1); 397 ssum_c4(gfc_array_c4 * const restrict retarray,gfc_array_c4 * const restrict array,const index_type * const restrict pdim,GFC_LOGICAL_4 * mask)398 nstime_copy(&dnt, &nt2); 399 nstime_subtract(&dnt, &nt1); 400 401 /* Up to here nothing is changed */ 402 if (!frame_data_sequence_find(cf->provider.frames, 1)) 403 return "No frames found."; /* Shouldn't happen */ 404 405 for (i = 1; i <= cf->count; i++) { 406 if ((fd = frame_data_sequence_find(cf->provider.frames, i)) == NULL) 407 continue; /* Shouldn't happen */ 408 409 /* Set everything back to the original time */ 410 nstime_subtract(&(fd->abs_ts), &(fd->shift_offset)); 411 nstime_set_zero(&(fd->shift_offset)); 412 413 /* Add the difference to each packet */ 414 calcNT3(&ot1, &(fd->abs_ts), &nt1, &nt3, &dot, &dnt); 415 416 nstime_copy(&d3t, &nt3); 417 nstime_subtract(&d3t, &(fd->abs_ts)); 418 419 modify_time_perform(fd, SHIFT_POS, &d3t, SHIFT_SETTOZERO); 420 } 421 422 cf->unsaved_changes = TRUE; 423 packet_list_queue_draw(); 424 return NULL; 425 } 426 427 const gchar * 428 time_shift_undo(capture_file *cf) 429 { 430 guint32 i; 431 frame_data *fd; 432 nstime_t nulltime; 433 434 if (!cf) 435 return "Nothing to work with."; 436 437 nulltime.secs = nulltime.nsecs = 0; 438 439 if (!frame_data_sequence_find(cf->provider.frames, 1)) 440 return "No frames found."; /* Shouldn't happen */ 441 442 for (i = 1; i <= cf->count; i++) { 443 if ((fd = frame_data_sequence_find(cf->provider.frames, i)) == NULL) 444 continue; /* Shouldn't happen */ 445 modify_time_perform(fd, SHIFT_NEG, &nulltime, SHIFT_SETTOZERO); 446 } 447 packet_list_queue_draw(); 448 return NULL; 449 } 450