From Jim Young via bug 4331:
authorgerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 2 Jun 2010 00:30:25 +0000 (00:30 +0000)
committergerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 2 Jun 2010 00:30:25 +0000 (00:30 +0000)
This patch adds a new '-S' option to editcap that will rewrite timestamps of
packets to insure that the new capture file is in strict chronological order.

This option's primary use case is to fixup the occasional timestamps that have
a negative delta time relative to previous packet.

This feature is related to (but does not depend on) capinfos enhancement
submitted in bug #4315 which helps identify tracefiles with "out-of-order"
packets.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@33042 f5534014-38df-0310-8fa8-9805f1628bb7

AUTHORS
doc/editcap.pod
docbook/release-notes.xml
editcap.c

diff --git a/AUTHORS b/AUTHORS
index 8106652a885073b8c11cb9d0672df0a5ffd0c6ee..c5e74135d70ddecbbabe774a5020ca6ed9094db4 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -2483,6 +2483,7 @@ Jim Young         <sysjhy [AT] langate.gsu.edu> {
        Improvements LLDP dissection (803.3 "PMD Auto-Negotiation Advertised
                Capability" and "Operational MAU Type")
        Capinfos time order checking
+       Editcap time order forcing
 
 }
 
index 54991547314d8f41d8b5a340ab08dd5e2b7f2d0d..f2cb2f7e348a72b9fbfd59e1833b3691cda97c45 100644 (file)
@@ -17,6 +17,7 @@ S<[ B<-i> E<lt>seconds per fileE<gt> ]>
 S<[ B<-r> ]>
 S<[ B<-s> E<lt>snaplenE<gt> ]>
 S<[ B<-t> E<lt>time adjustmentE<gt> ]>
+S<[ B<-S> E<lt>strict time adjustmentE<gt> ]>
 S<[ B<-T> E<lt>encapsulation typeE<gt> ]>
 S<[ B<-v> ]>
 I<infile>
@@ -204,6 +205,39 @@ This feature is useful when synchronizing dumps
 collected on different machines where the time difference between the
 two machines is known or can be estimated.
 
+=item -S  E<lt>strict time adjustmentE<gt>
+
+Time adjust selected packets to insure strict chronological order. 
+
+The <strict time adjustment> value represents relative seconds
+specified as [-]I<seconds>[I<.fractional seconds>].
+
+As the capture file is processed each packet's absolute time is 
+I<possibly> adjusted to be equal to or greater than the previous 
+packet's absolute timestamp depending on the <strict time 
+adjustment> value.  
+
+If <strict time adjustment> value is 0 or greater (e.g. 0.000001) 
+then B<only> packets with a timestamp less than the previous packet 
+will adjusted.  The adjusted timestamp value will be set to be 
+equal to the timestamp value of the previous packet plus the value 
+of the <strict time adjustment> value.  A <strict time adjustment> 
+value of 0 will adjust the minimum number of timestamp values 
+necessary to insure that the resulting capture file is in 
+strict chronological order.
+
+If <strict time adjustment> value is specified as a 
+negative value, then the timestamp values of B<all> 
+packets will be adjusted to be equal to the timestamp value 
+of the previous packet plus the absolute value of the 
+<lt>strict time adjustment<gt> value. A <strict time
+adjustment> value of -0 will result in all packets
+having the timestamp value of the first packet.
+
+This feature is useful when the trace file has an occasional
+packet with a negative delta time relative to the previous 
+packet.
+
 =item -T  E<lt>encapsulation typeE<gt>
 
 Sets the packet encapsulation type of the output capture file.
@@ -288,6 +322,14 @@ or on Windows systems
 
     editcap -v -D 0 capture.pcap NUL
 
+To advance the timestamps of each packet forward by 3.0827 seconds:
+
+    editcap -t 3.0827 capture.pcap adjusted.pcap
+
+To insure all timestamps are in strict chronological order:
+
+    editcap -S 0 capture.pcap adjusted.pcap
+
 To introduce 5% random errors in a capture file use:
 
 =over 4
index 62cc6af4b23d6f47cf9babc9544da8886fb99396..ccba280ecd39d94f19d49741d7934c3425acfd26 100644 (file)
@@ -137,7 +137,8 @@ Wireshark Info
 
         <listitem>
           <para>
-            Capinfos now checks the time order of capture files.
+            Capinfos and editcap now respectively support time order checking
+            and forcing.
           </para>
         </listitem>
 
index 3492fb75cca3744318153d2813efb94b3746fa22..3cdfe59ce0727bea46286b90bd66cd8e9c203ef6 100644 (file)
--- a/editcap.c
+++ b/editcap.c
@@ -134,6 +134,10 @@ static gboolean check_startstop = FALSE;
 static gboolean dup_detect = FALSE;
 static gboolean dup_detect_by_time = FALSE;
 
+static int do_strict_time_adjustment = FALSE;
+static struct time_adjustment strict_time_adj = {{0, 0}, 0}; /* strict time adjustment */
+static nstime_t previous_time = {0, 0}; /* previous time */
+
 static int find_dct2000_real_data(guint8 *buf);
 
 static gchar *
@@ -364,6 +368,81 @@ set_time_adjustment(char *optarg_str_p)
   time_adj.tv.tv_usec = val;
 }
 
+static void
+set_strict_time_adj(char *optarg)
+{
+  char *frac, *end;
+  long val;
+  size_t frac_digits;
+
+  if (!optarg)
+    return;
+
+  /* skip leading whitespace */
+  while (*optarg == ' ' || *optarg == '\t') {
+      optarg++;
+  }
+
+  /* 
+   * check for a negative adjustment 
+   * A negative strict adjustment value is a flag 
+   * to adjust all frames by the specifed delta time.
+   */
+  if (*optarg == '-') {
+      strict_time_adj.is_negative = 1;
+      optarg++;
+  }
+
+  /* collect whole number of seconds, if any */
+  if (*optarg == '.') {         /* only fractional (i.e., .5 is ok) */
+      val  = 0;
+      frac = optarg;
+  } else {
+      val = strtol(optarg, &frac, 10);
+      if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) {
+          fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
+                  optarg);
+          exit(1);
+      }
+      if (val < 0) {            /* implies '--' since we caught '-' above  */
+          fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
+                  optarg);
+          exit(1);
+      }
+  }
+  strict_time_adj.tv.tv_sec = val;
+
+  /* now collect the partial seconds, if any */
+  if (*frac != '\0') {             /* chars left, so get fractional part */
+    val = strtol(&(frac[1]), &end, 10);
+    /* if more than 6 fractional digits truncate to 6 */
+    if((end - &(frac[1])) > 6) {
+        frac[7] = 't'; /* 't' for truncate */
+        val = strtol(&(frac[1]), &end, 10);
+    }
+    if (*frac != '.' || end == NULL || end == frac
+        || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
+      fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
+              optarg);
+      exit(1);
+    }
+  }
+  else {
+    return;                     /* no fractional digits */
+  }
+
+  /* adjust fractional portion from fractional to numerator
+   * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
+  if (frac && end) {            /* both are valid */
+    frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
+    while(frac_digits < 6) {    /* this is frac of 10^6 */
+      val *= 10;
+      frac_digits++;
+    }
+  }
+  strict_time_adj.tv.tv_usec = val;
+}
+
 static void
 set_rel_time(char *optarg_str_p)
 {
@@ -613,7 +692,7 @@ usage(gboolean is_error)
   fprintf(output, "\n");
   fprintf(output, "           NOTE: The use of the 'Duplicate packet removal' options with\n");
   fprintf(output, "           other editcap options except -v may not always work as expected.\n");
-  fprintf(output, "           Specifically the -r and -t options will very likely NOT have the\n");
+  fprintf(stderr, "           Specifically the -r, -t or -S options will very likely NOT have the\n");
   fprintf(output, "           desired effect if combined with the -d, -D or -w.\n");
   fprintf(output, "\n");
   fprintf(output, "Packet manipulation:\n");
@@ -621,6 +700,14 @@ usage(gboolean is_error)
   fprintf(output, "  -C <choplen>           chop each packet at the end by <choplen> bytes.\n");
   fprintf(output, "  -t <time adjustment>   adjust the timestamp of each packet;\n");
   fprintf(output, "                         <time adjustment> is in relative seconds (e.g. -0.5).\n");
+  fprintf(stderr, "  -S <strict adjustment> adjust timestamp of packets if necessary to insure\n");
+  fprintf(stderr, "                         strict chronological increasing order. The <strict\n");
+  fprintf(stderr, "                         adjustment> is specified in relative seconds with\n");
+  fprintf(stderr, "                         values of 0 or 0.000001 being the most reasonable.\n");
+  fprintf(stderr, "                         A negative adjustment value will modify timestamps so\n");
+  fprintf(stderr, "                         that each packet's delta time is the absolute value\n");
+  fprintf(stderr, "                         of the adjustment specified. A value of -0 will set\n");
+  fprintf(stderr, "                         all packets to the timestamp of the first packet.\n");
   fprintf(output, "  -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
   fprintf(output, "                         that a particular packet byte will be randomly changed.\n");
   fprintf(output, "\n");
@@ -734,7 +821,7 @@ main(int argc, char *argv[])
 #endif
 
   /* Process the options */
-  while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:T:vw:")) !=-1) {
+  while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:S:T:vw:")) !=-1) {
 
     switch (opt) {
 
@@ -846,6 +933,11 @@ main(int argc, char *argv[])
       set_time_adjustment(optarg);
       break;
 
+    case 'S':
+      set_strict_time_adj(optarg);
+      do_strict_time_adjustment = TRUE;
+      break;
+
     case 'T':
       out_frame_type = wtap_short_string_to_encap(optarg);
       if (out_frame_type < 0) {
@@ -1096,6 +1188,66 @@ main(int argc, char *argv[])
           phdr = &snap_phdr;
         }
 
+        /*
+         *  Do we adjust timestamps to insure strict chronologically order?
+         */
+
+        if (do_strict_time_adjustment) {
+          if (previous_time.secs || previous_time.nsecs) {
+            if (!strict_time_adj.is_negative) {
+              nstime_t current;
+              nstime_t delta;
+
+              current.secs = phdr->ts.secs;
+              current.nsecs = phdr->ts.nsecs;
+
+              nstime_delta(&delta, &current, &previous_time);
+
+              if (delta.secs < 0 || delta.nsecs < 0)
+              {
+                /*
+                 * A negative delta indicates that the current packet
+                 * has an absolute timestamp less than the previous packet
+                 * that it is being compared to.  This is NOT a normal
+                 * situation since trace files usually have packets in
+                 * chronological order (oldest to newest).
+                 */
+                /* printf("++out of order, need to adjust this packet!\n"); */
+                snap_phdr = *phdr;
+                snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
+                snap_phdr.ts.nsecs = previous_time.nsecs;
+                if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
+                  /* carry */
+                  snap_phdr.ts.secs++;
+                  snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
+                } else {
+                  snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
+                }
+                phdr = &snap_phdr;
+              }
+            } else {
+              /* 
+               * A negative strict time adjustment is requested. 
+               * Unconditionally set each timestamp to previous 
+               * packet's timestamp plus delta.
+               */
+              snap_phdr = *phdr;
+              snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
+              snap_phdr.ts.nsecs = previous_time.nsecs;
+              if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
+                /* carry */
+                snap_phdr.ts.secs++;
+                snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
+              } else {
+                snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
+              }
+              phdr = &snap_phdr;
+            }
+          }
+          previous_time.secs = phdr->ts.secs;
+          previous_time.nsecs = phdr->ts.nsecs;
+        }
+
         /* assume that if the frame's tv_sec is 0, then
          * the timestamp isn't supported */
         if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {