[rygel/wip/basic-management: 123/138] core: Add ping command support to BasicManagement



commit 00b89595924e06ef9e2ddd9757bac89d06135ead
Author: Christophe Guiraud <christophe guiraud intel com>
Date:   Wed Jun 5 14:06:50 2013 +0200

    core: Add ping command support to BasicManagement
    
    - Add the ping command support: build and call the system command,
    parse its result output.
    - Fix a typo in update_test_ids_lists() funtion in file
    rygel-basic-management.vala

 .../rygel-basic-management-test-ping.vala          |  208 ++++++++++++++-----
 src/librygel-core/rygel-basic-management.vala      |   27 ++--
 2 files changed, 167 insertions(+), 68 deletions(-)
---
diff --git a/src/librygel-core/rygel-basic-management-test-ping.vala 
b/src/librygel-core/rygel-basic-management-test-ping.vala
index 06b6faa..bd20efb 100644
--- a/src/librygel-core/rygel-basic-management-test-ping.vala
+++ b/src/librygel-core/rygel-basic-management-test-ping.vala
@@ -25,96 +25,194 @@ using GLib;
 
 // Helper class for BasicManagementTestPing.
 internal class Rygel.BasicManagementTestPing : BasicManagementTest {
+    private enum ProcessState {
+        INIT,
+        STATISTICS,
+        RTT,
+    }
 
-    private string host;
-    private uint repeat_count;
-    private uint data_block_size;
-    private uint dscp;
-    private uint32 interval_time_out;
+    private enum Status {
+        SUCCESS,
+        ERROR_CANNOT_RESOLVE_HOSTNAME,
+        ERROR_INTERNAL,
+        ERROR_OTHER;
+
+        public string to_string() {
+            switch (this) {
+                case SUCCESS:
+                    return "Success";
+                case ERROR_CANNOT_RESOLVE_HOSTNAME:
+                    return "Error_CannotResolveHostName";
+                case ERROR_INTERNAL:
+                    return "Error_Internal";
+                case ERROR_OTHER:
+                    return "Error_Other";
+                default:
+                    assert_not_reached();
+            }
+        }
+    }
 
-    private string status;
+    private ProcessState state;
+    private Status status;
     private string additional_info;
     private uint success_count;
     private uint failure_count;
-    private uint32 average_response_time;
+    private uint32 avg_response_time;
     private uint32 min_response_time;
     private uint32 max_response_time;
 
-    private static const uint PING_MIN_REPEAT_COUNT = 1;
-    private static const uint PING_MAX_REPEAT_COUNT = 100;
-    private static const uint PING_DEFAULT_REPEAT_COUNT = 1;
-    private static const uint PING_MIN_REQUEST_INTERVAL_TIMEOUT = 1000;
-    private static const uint PING_MAX_REQUEST_INTERVAL_TIMEOUT = 30000;
-    private static const uint PING_DEFAULT_REQUEST_INTERVAL_TIMEOUT = 10000;
-    private static const uint PING_MIN_DATA_BLOCK_SIZE = 20;
-    private static const uint PING_MAX_DATA_BLOCK_SIZE = 2048;
-    private static const uint PING_DEFAULT_DATA_BLOCK_SIZE = 32;
-    private static const uint PING_MIN_DSCP = 1;
-    private static const uint PING_MAX_DSCP = 64;
-    private static const uint PING_DEFAULT_DSCP = 30;
-    private static const uint PING_MAX_ADDITIONAL_INFO_STR_SIZE = 1024;
-    private static const uint PING_MAX_STATUS_STR_SIZE = 32;
-    private static const uint PING_MAX_RESULT_ARRAY_SIZE = 7;
+    private static const uint MIN_REPEAT_COUNT = 1;
+    private static const uint MAX_REPEAT_COUNT = 100;
+    private static const uint DEFAULT_REPEAT_COUNT = 1;
+    private static const uint DEFAULT_REPLY_TIMEOUT = 10000;
+    private static const uint MIN_REQUEST_INTERVAL_TIMEOUT = 1000;
+    private static const uint MAX_REQUEST_INTERVAL_TIMEOUT = 30000;
+    private static const uint DEFAULT_REQUEST_INTERVAL_TIMEOUT = 10000;
+    private static const uint MIN_DATA_BLOCK_SIZE = 20;
+    private static const uint MAX_DATA_BLOCK_SIZE = 2048;
+    private static const uint DEFAULT_DATA_BLOCK_SIZE = 32;
+    private static const uint MIN_DSCP = 1;
+    private static const uint MAX_DSCP = 64;
+    private static const uint DEFAULT_DSCP = 30;
 
     public override string method_type { get { return "Ping"; } }
     public override string results_type { get { return "GetPingResult"; } }
 
-    public bool init(string host, uint repeat_count, uint data_block_size,
-                     uint dscp, uint32 interval_time_out) {
-        stdout.printf("*Ping* init()\n");
-
-        if (host == null || host == "") {
-            return false;
-        }
+    public void init(string host, uint repeat_count, uint data_block_size,
+                     uint dscp, uint32 interval_time_out)
+                     throws BasicManagementTestError {
+        this.command = { "ping" };
+        this.status = Status.ERROR_INTERNAL;
+        this.additional_info = "";
+        this.success_count = 0;
+        this.failure_count = 0;
+        this.avg_response_time = 0;
+        this.min_response_time = 0;
+        this.max_response_time = 0;
 
         if (repeat_count == 0) {
-            repeat_count = PING_DEFAULT_REPEAT_COUNT;
-        } else if (repeat_count < PING_MIN_REPEAT_COUNT &&
-                   repeat_count > PING_MAX_REPEAT_COUNT) {
-            return false;
+            repeat_count = DEFAULT_REPEAT_COUNT;
+        } else if (repeat_count < MIN_REPEAT_COUNT &&
+                   repeat_count > MAX_REPEAT_COUNT) {
+            throw new BasicManagementTestError.INIT_FAILED
+                                                ("Invalid repeat count");
         }
+        this.command += ("-c %u").printf (repeat_count);
+
+        this.command += ("-W %u").printf (DEFAULT_REPLY_TIMEOUT/1000);
 
         if (interval_time_out == 0) {
-            interval_time_out = PING_DEFAULT_REQUEST_INTERVAL_TIMEOUT;
-        } else if (interval_time_out < PING_MIN_REQUEST_INTERVAL_TIMEOUT &&
-                   interval_time_out > PING_MAX_REQUEST_INTERVAL_TIMEOUT) {
-            return false;
+            interval_time_out = DEFAULT_REQUEST_INTERVAL_TIMEOUT;
+        } else if (interval_time_out < MIN_REQUEST_INTERVAL_TIMEOUT &&
+                   interval_time_out > MAX_REQUEST_INTERVAL_TIMEOUT) {
+            throw new BasicManagementTestError.INIT_FAILED
+                                                ("Invalid interval timeout");
         }
+        this.command += ("-i %u").printf (interval_time_out/1000);
 
         if (data_block_size == 0) {
-            data_block_size = PING_DEFAULT_DATA_BLOCK_SIZE;
-        } else if (data_block_size < PING_MIN_DATA_BLOCK_SIZE &&
-                   data_block_size > PING_MAX_DATA_BLOCK_SIZE) {
-            return false;
+            data_block_size = DEFAULT_DATA_BLOCK_SIZE;
+        } else if (data_block_size < MIN_DATA_BLOCK_SIZE &&
+                   data_block_size > MAX_DATA_BLOCK_SIZE) {
+            throw new BasicManagementTestError.INIT_FAILED
+                                                ("Invalid data block size");
         }
+        this.command += ("-s %u").printf (data_block_size);
 
         if (dscp == 0) {
-            dscp = PING_DEFAULT_DSCP;
-        } else if (dscp < PING_MIN_DSCP && dscp > PING_MAX_DSCP) {
-            return false;
+            dscp = DEFAULT_DSCP;
+        } else if (dscp < MIN_DSCP && dscp > MAX_DSCP) {
+            throw new BasicManagementTestError.INIT_FAILED
+                                                ("Invalid DSCP");
         }
+        this.command += ("-Q %u").printf (dscp >> 2);
 
-        this.host = host;
-        this.repeat_count = repeat_count;
-        this.data_block_size = data_block_size;
-        this.dscp = dscp;
-        this.interval_time_out = interval_time_out;
+        if (host == null || host.length < 1) {
+            throw new BasicManagementTestError.INIT_FAILED
+                                                ("Host name is required");
+        }
 
-        return true;
+        this.command += host;
+    }
+
+    protected override void init_iteration () {
+        base.init_iteration ();
+
+        this.state = ProcessState.INIT;
+    }
+
+    protected override void finish_iteration () {
+        switch (this.execution_state) {
+            case ExecutionState.SPAWN_FAILED:
+                this.status = Status.ERROR_INTERNAL;
+                this.additional_info = "Failed spawn ping";
+                break;
+            default:
+                break;
+        }
+
+        base.finish_iteration ();
+    }
+
+    protected override void handle_error (string line) {
+        if (line.contains ("ping: unknown host")) {
+            this.status = Status.ERROR_CANNOT_RESOLVE_HOSTNAME;
+            this.execution_state = ExecutionState.COMPLETED;
+        } else if (line.contains ("ping:")) {
+            this.status = Status.ERROR_OTHER;
+            this.additional_info = line.substring ("ping:".length).strip ();
+            this.execution_state = ExecutionState.COMPLETED;
+        }
+    }
+
+    protected override void handle_output (string line) {
+        line.strip ();
+        if (this.state == ProcessState.INIT) {
+            if (line.contains ("statistics ---")) {
+                this.state = ProcessState.STATISTICS;
+                this.status = Status.SUCCESS;
+            }
+        } else if (this.state == ProcessState.STATISTICS) {
+            if (line.contains ("packets transmitted")) {
+                this.state = ProcessState.RTT;
+
+                var rtt_values = line.split (", ", 3);
+                uint tx = int.parse (rtt_values[0].split (" ", 3)[0]);
+                uint rx = int.parse (rtt_values[1].split (" ", 3)[0]);
+                this.failure_count = tx - rx;
+                this.success_count = rx;
+            }
+        } else if (this.state == ProcessState.RTT) {
+            if (line.contains ("min/avg/max")) {
+                this.execution_state = ExecutionState.COMPLETED;
+
+                var rtt = line.split ("=", 2);
+                if (rtt.length >= 2) {
+                    var rtt_values = rtt[1].split ("/", 4);
+                    if (rtt_values.length >= 3) {
+                        this.avg_response_time = (uint) Math.round (
+                                                  double.parse (rtt_values[0]));
+                        this.min_response_time = (uint) Math.round (
+                                                  double.parse (rtt_values[1]));
+                        this.max_response_time = (uint) Math.round (
+                                                  double.parse (rtt_values[2]));
+                    }
+                }
+            }
+        }
     }
 
     public void get_results(out string status, out string additional_info,
                             out uint success_count, out uint failure_count,
-                            out uint32 average_response_time,
+                            out uint32 avg_response_time,
                             out uint32 min_response_time,
                             out uint32 max_response_time) {
-        stdout.printf("*Ping* get_results()\n");
-
-        status = this.status;
+        status = this.status.to_string ();
         additional_info = this.additional_info;
         success_count = this.success_count;
         failure_count = this.failure_count;
-        average_response_time = this.average_response_time;
+        avg_response_time = this.avg_response_time;
         min_response_time = this.min_response_time;
         max_response_time = this.max_response_time;
     }
diff --git a/src/librygel-core/rygel-basic-management.vala b/src/librygel-core/rygel-basic-management.vala
index 1ed10f5..538c88b 100644
--- a/src/librygel-core/rygel-basic-management.vala
+++ b/src/librygel-core/rygel-basic-management.vala
@@ -108,7 +108,8 @@ public class Rygel.BasicManagement : Service {
         BasicManagementTest.ExecutionState execution_state = bm_test.execution_state;
 
         if ((execution_state == BasicManagementTest.ExecutionState.REQUESTED) ||
-            (execution_state == BasicManagementTest.ExecutionState.REQUESTED)) {
+            (execution_state == BasicManagementTest.ExecutionState.IN_PROGRESS)) {
+
             this.tests_map.set (bm_test.id, bm_test);
             this.notify ("TestIDs", typeof (string),
                          create_test_ids_list (false));
@@ -134,7 +135,6 @@ public class Rygel.BasicManagement : Service {
         update_test_ids_lists (bm_test);
 
         /* TODO: decide if test should really execute now */
-
         bm_test.execute.begin ((obj,res) => {
             try {
                 bm_test.execute.end (res);
@@ -278,14 +278,15 @@ public class Rygel.BasicManagement : Service {
                         out dscp);
 
         var ping = new BasicManagementTestPing();
-        if (!ping.init (host, repeat_count, interval_time_out,
-                        data_block_size, dscp)) {
-            action.return_error (402, _("Invalid argument"));
+        try {
+            ping.init (host, repeat_count, interval_time_out, data_block_size,
+                       dscp);
 
-            return;
+            this.add_test_and_return_action (ping as BasicManagementTest,
+                                             action);
+        } catch (BasicManagementTestError e) {
+            action.return_error (402, _("Invalid argument"));
         }
-
-        this.add_test_and_return_action (ping as BasicManagementTest, action);
     }
 
     private void ping_result_cb (Service             cm,
@@ -304,13 +305,13 @@ public class Rygel.BasicManagement : Service {
 
         string status, additional_info;
         uint success_count, failure_count;
-        uint32 average_response_time, min_response_time, max_response_time;
+        uint32 avg_response_time, min_response_time, max_response_time;
 
         (bm_test as BasicManagementTestPing).get_results (out status,
                                              out additional_info,
                                              out success_count,
                                              out failure_count,
-                                             out average_response_time,
+                                             out avg_response_time,
                                              out min_response_time,
                                              out max_response_time);
 
@@ -328,7 +329,7 @@ public class Rygel.BasicManagement : Service {
                         failure_count,
                     "AverageResponseTime",
                         typeof (uint32),
-                        average_response_time,
+                        avg_response_time,
                     "MinimumResponseTime",
                         typeof (uint32),
                         min_response_time,
@@ -367,8 +368,8 @@ public class Rygel.BasicManagement : Service {
 
         var nslookup = new BasicManagementTestNSLookup();
         try {
-            nslookup.init (hostname, dns_server,
-                           repeat_count, interval_time_out);
+            nslookup.init (hostname, dns_server, repeat_count,
+                           interval_time_out);
 
             this.add_test_and_return_action (nslookup as BasicManagementTest,
                                              action);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]