cd ../gtk ==> cd ../ui/gtk
[obnox/wireshark/wip.git] / tap-icmpstat.c
old mode 100755 (executable)
new mode 100644 (file)
index 8ff7ff4..b8abbb2
@@ -51,13 +51,15 @@ typedef struct _icmpstat_t {
     GSList *rt_list;
     guint num_rqsts;
     guint num_resps;
+    guint min_frame;
+    guint max_frame;
     double min_msecs;
     double max_msecs;
     double tot_msecs;
 } icmpstat_t;
 
 
-/* This callback is never used by tshark but it is here for completeness. When
+/* This callback is never used by tshark but it is here for completeness.  When
  * registering below, we could just have left this function as NULL.
  *
  * When used by wireshark, this function will be called whenever we would need
@@ -74,12 +76,23 @@ icmpstat_reset(void *tapdata)
     icmpstat_t *icmpstat = tapdata;
 
     g_slist_free(icmpstat->rt_list);
-    icmpstat->rt_list = NULL;
-    icmpstat->num_rqsts = 0;
-    icmpstat->num_resps = 0;
+    memset(icmpstat, 0, sizeof(icmpstat_t));
     icmpstat->min_msecs = 1.0 * G_MAXUINT;
-    icmpstat->max_msecs = 0.0;
-    icmpstat->tot_msecs = 0.0;
+}
+
+
+static gint compare_doubles(gconstpointer a, gconstpointer b)
+{
+    double ad, bd;
+
+    ad = *(double *)a;
+    bd = *(double *)b;
+
+    if (ad < bd)
+        return -1;
+    if (ad > bd)
+        return 1;
+    return 0;
 }
 
 
@@ -106,7 +119,7 @@ icmpstat_reset(void *tapdata)
  * !0: state has changed, call (*draw) sometime later
  */
 static int
-icmpstat_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
+icmpstat_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *data)
 {
     icmpstat_t *icmpstat = tapdata;
     const icmp_transaction_t *trans = data;
@@ -120,12 +133,16 @@ icmpstat_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, cons
         if (rt == NULL)
             return 0;
         *rt = trans->resp_time;
-        icmpstat->rt_list = g_slist_prepend(icmpstat->rt_list, rt);
+        icmpstat->rt_list = g_slist_insert_sorted(icmpstat->rt_list, rt, compare_doubles);
         icmpstat->num_resps++;
-        if (icmpstat->min_msecs > trans->resp_time)
+        if (icmpstat->min_msecs > trans->resp_time) {
+            icmpstat->min_frame = trans->resp_frame;
             icmpstat->min_msecs = trans->resp_time;
-        if (icmpstat->max_msecs < trans->resp_time)
+        }
+        if (icmpstat->max_msecs < trans->resp_time) {
+            icmpstat->max_frame = trans->resp_frame;
             icmpstat->max_msecs = trans->resp_time;
+        }
         icmpstat->tot_msecs += trans->resp_time;
     } else if (trans->rqst_frame)
         icmpstat->num_rqsts++;
@@ -136,20 +153,45 @@ icmpstat_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, cons
 }
 
 
-static double compute_sdev(double average, guint num, GSList *slist)
+/*
+ * Compute the mean, median and standard deviation.
+ */
+static void compute_stats(icmpstat_t *icmpstat, double *mean, double *med, double *sdev)
 {
+    GSList *slist = icmpstat->rt_list;
     double diff;
-    double sq_diff_sum;
+    double sq_diff_sum = 0.0;
 
-    if (num == 0)
-        return 0.0;
+    if (icmpstat->num_resps == 0 || slist == NULL) {
+        *mean = 0.0;
+        *med = 0.0;
+        *sdev = 0.0;
+        return;
+    }
 
-    for ( sq_diff_sum = 0.0; slist; slist = g_slist_next(slist)) {
-        diff = *(double *)slist->data - average;
-        sq_diff_sum += diff * diff;
+    /* (arithmetic) mean */
+    *mean = icmpstat->tot_msecs / icmpstat->num_resps;
+
+    /* median: If we have an odd number of elements in our list, then the
+     * median is simply the middle element, otherwise the median is computed by
+     * averaging the 2 elements on either side of the mid-point. */
+    if (icmpstat->num_resps & 1)
+        *med = *(double *)g_slist_nth_data(slist, icmpstat->num_resps / 2);
+    else {
+        *med =
+            (*(double *)g_slist_nth_data(slist, (icmpstat->num_resps - 1) / 2) +
+            *(double *)g_slist_nth_data(slist, icmpstat->num_resps / 2)) / 2;
     }
 
-    return sqrt(sq_diff_sum / num);
+    /* (sample) standard deviation */
+    for ( ; slist; slist = g_slist_next(slist)) {
+        diff = *(double *)slist->data - *mean;
+        sq_diff_sum += diff * diff;
+    }
+    if (icmpstat->num_resps > 1)
+        *sdev = sqrt(sq_diff_sum / (icmpstat->num_resps - 1));
+    else
+        *sdev = 0.0;
 }
 
 
@@ -187,25 +229,31 @@ icmpstat_draw(void *tapdata)
 {
     icmpstat_t *icmpstat = tapdata;
     unsigned int lost;
-    double average, sdev;
+    double mean, sdev, med;
 
     printf("\n");
     printf("==========================================================================\n");
-    printf("ICMP SRT Statistics (all times in ms):\n");
-    printf("Filter: %s\n", icmpstat->filter ? icmpstat->filter : "");
-    printf("Requests  Replies   Lost      %% Loss  Min SRT   Max SRT   Avg SRT   SDEV\n");
+    printf("ICMP Service Response Time (SRT) Statistics (all times in ms):\n");
+    printf("Filter: %s\n", icmpstat->filter ? icmpstat->filter : "<none>");
+    printf("\nRequests  Replies   Lost      %% Loss\n");
 
     if (icmpstat->num_rqsts) {
         lost =  icmpstat->num_rqsts - icmpstat->num_resps;
-        average = icmpstat->tot_msecs / icmpstat->num_resps;
-        sdev = compute_sdev(average, icmpstat->num_resps, icmpstat->rt_list);
-        printf("%-10u%-10u%-10u%5.1f%%  %-10.3f%-10.3f%-10.3f%-10.3f\n",
+        compute_stats(icmpstat, &mean, &med, &sdev);
+
+        printf("%-10u%-10u%-10u%5.1f%%\n\n",
             icmpstat->num_rqsts, icmpstat->num_resps, lost,
-            100.0 * lost / icmpstat->num_rqsts,
+            100.0 * lost / icmpstat->num_rqsts);
+        printf("Minimum   Maximum   Mean      Median    SDeviation     Min Frame Max Frame\n");
+        printf("%-10.3f%-10.3f%-10.3f%-10.3f%-10.3f     %-10u%-10u\n",
             icmpstat->min_msecs >= G_MAXUINT ? 0.0 : icmpstat->min_msecs,
-            icmpstat->max_msecs, average, sdev);
-    } else
-        printf("0         0         0           0.0%%  0.000     0.000     0.000     0.000\n");
+            icmpstat->max_msecs, mean, med, sdev,
+            icmpstat->min_frame, icmpstat->max_frame);
+    } else {
+        printf("0         0         0           0.0%%\n\n");
+        printf("Minimum   Maximum   Mean      Median    SDeviation     Min Frame Max Frame\n");
+        printf("0.000     0.000     0.000     0.000     0.000          0         0\n");
+    }
     printf("==========================================================================\n");
 }
 
@@ -226,12 +274,14 @@ icmpstat_init(const char *optarg, void* userdata _U_)
     if (strstr(optarg, "icmp,srt,"))
         filter = optarg + strlen("icmp,srt,");
 
-    icmpstat = g_malloc0(sizeof(icmpstat_t));
-    icmpstat->min_msecs = 1.0 * G_MAXUINT;
+    icmpstat = g_try_malloc(sizeof(icmpstat_t));
     if (icmpstat == NULL) {
-        fprintf(stderr, "tshark: g_malloc() fatal error.\n");
+        fprintf(stderr, "tshark: g_try_malloc() fatal error.\n");
         exit(1);
     }
+    memset(icmpstat, 0, sizeof(icmpstat_t));
+    icmpstat->min_msecs = 1.0 * G_MAXUINT;
+
     if (filter)
         icmpstat->filter = g_strdup(filter);