Added native PING application 83/10783/4
authorMauro Sardara <[email protected]>
Fri, 23 Feb 2018 14:25:32 +0000 (15:25 +0100)
committerMauro Sardara <[email protected]>
Fri, 23 Feb 2018 17:34:34 +0000 (18:34 +0100)
Change-Id: If76818fdc90e7223e811ece0c21f8a7c67defa4c
Signed-off-by: Mauro Sardara <[email protected]>
apps/consumers/CMakeLists.txt
apps/consumers/icnet_ping_client.cc [new file with mode: 0644]
apps/http/icnet_iget.cc
apps/producers/CMakeLists.txt
apps/producers/icnet_ping_server.cc [new file with mode: 0644]
icnet/ccnx/icnet_ccnx_content_object.cc
icnet/ccnx/icnet_ccnx_content_object.h

index 757d021..4cf2d2a 100755 (executable)
@@ -15,6 +15,7 @@ cmake_minimum_required(VERSION 3.2)
 
 set(CONSUMER_SOURCE_FILES icnet_consumer_test.cc)
 set(CONSUMER__HELLO_WORLD_SOURCE_FILES icnet_consumer_hello_world.cc)
+set(CONSUMER_PING_CLIENT_SOURCE_FILES icnet_ping_client.cc)
 
 add_executable(consumer-test ${CONSUMER_SOURCE_FILES})
 
@@ -25,3 +26,8 @@ add_executable(consumer-hello-world ${CONSUMER__HELLO_WORLD_SOURCE_FILES})
 
 target_link_libraries(consumer-hello-world icnet ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
 install(TARGETS consumer-hello-world DESTINATION ${CMAKE_INSTALL_PREFIX}/bin COMPONENT library)
+
+add_executable(icnet-ping-client ${CONSUMER_PING_CLIENT_SOURCE_FILES})
+
+target_link_libraries(icnet-ping-client icnet ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
+install(TARGETS icnet-ping-client DESTINATION ${CMAKE_INSTALL_PREFIX}/bin COMPONENT library)
diff --git a/apps/consumers/icnet_ping_client.cc b/apps/consumers/icnet_ping_client.cc
new file mode 100644 (file)
index 0000000..42a0ab1
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "icnet_ccnx_portal.h"
+#include "icnet_ccnx_name.h"
+
+#include <boost/asio/steady_timer.hpp>
+
+#include <iostream>
+#include <iomanip>
+
+namespace icnet {
+
+namespace ccnx {
+
+namespace ping {
+
+typedef std::map<uint64_t, uint64_t> SendTimeMap;
+
+class Configuration {
+ public:
+  uint64_t interestLifetime_;
+  uint64_t pingInterval_;
+  uint64_t maxPing_;
+  std::string name_;
+  uint8_t ttl_;
+
+  Configuration() {
+    interestLifetime_ = 500;                            //ms
+    pingInterval_ = 1000000;                            //us
+    maxPing_ = std::numeric_limits<uint64_t>::max();    //number of interests
+    name_ = "ccnx:/pingserver";                         //string
+    ttl_ = 64;
+  }
+};
+
+class Client {
+ public:
+  Client(Configuration &c)
+    : config_(c),
+      sequence_number_(0),
+      sent_(0),
+      received_(0),
+      timedout_(0),
+      duplicated_(0),
+      rtt_sum_(0),
+      rtt_sum2_(0),
+      rtt_min_(std::numeric_limits<uint64_t>::max()),
+      rtt_max_(0),
+      timer_(new boost::asio::steady_timer(portal_.getIoService())),
+      signals_(new boost::asio::signal_set(portal_.getIoService(), SIGINT, SIGQUIT)) {
+    signals_->async_wait(std::bind(&Client::afterSignal,
+                                 this,
+                                 std::placeholders::_1,
+                                 std::placeholders::_2));
+  }
+
+  void ping() {
+    doPing();
+    portal_.runEventsLoop();
+  }
+
+  void OnContentObjectCallback(const Interest &interest, const ContentObject &object) {
+
+    uint64_t rtt = 0;
+
+    auto it = send_timestamps_.find(interest.getName().get(-1).toSegment());
+
+    if (it != send_timestamps_.end()) {
+      rtt = std::chrono::duration_cast<std::chrono::microseconds>(
+          std::chrono::steady_clock::now().time_since_epoch()).count() - it->second;
+
+      send_timestamps_.erase(it);
+
+      if (rtt > rtt_max_) {
+        rtt_max_ = rtt;
+      }
+
+      if (rtt < rtt_min_) {
+        rtt_min_ = rtt;
+      }
+
+      rtt_sum_ += rtt;
+      rtt_sum2_ += rtt * rtt;
+    } else {
+      // Duplicated packet!!!!
+      duplicated_++;
+    }
+
+    std::cout << object.getContent().size() << " bytes content object with name ";
+    std::cout << object.getName().getPrefix(-1);
+    std::cout << ": ping_seq=" << object.getName().get(-1).toSegment();
+    if (rtt) {
+      std::cout << " time=" << std::fixed << std::setprecision(1) << float(rtt) / 1000 << " ms" << std::endl;
+    } else  {
+      std::cout << "DUPLICATED!!!";
+      return;
+    }
+
+    received_++;
+    if (sent_ >= config_.maxPing_) {
+      stopPing();
+    }
+  }
+
+  void OnInterestTimeoutCallback(const Interest &interest) {
+    timedout_++;
+    if (sent_ >= config_.maxPing_) {
+      stopPing();
+    }
+  }
+
+  void doPing() {
+
+    Name interest_name(config_.name_);
+    interest_name.appendSegment(sequence_number_);
+    std::shared_ptr<Interest> interest = std::make_shared<Interest>(std::move(interest_name));
+
+    interest->setInterestLifetime(uint32_t(config_.interestLifetime_));
+    interest->setHopLimit(config_.ttl_);
+
+    portal_.sendInterest(*interest,
+                         std::bind(&Client::OnContentObjectCallback,
+                                   this,
+                                   std::placeholders::_1,
+                                   std::placeholders::_2),
+                         std::bind(&Client::OnInterestTimeoutCallback, this, std::placeholders::_1));
+
+    send_timestamps_[sequence_number_] =
+        std::chrono::duration_cast<std::chrono::microseconds>(
+            std::chrono::steady_clock::now().time_since_epoch()).count();
+
+    sequence_number_++;
+    sent_++;
+
+    if (sent_ < config_.maxPing_) {
+      this->timer_->expires_from_now(std::chrono::microseconds(config_.pingInterval_));
+      this->timer_->async_wait([this](const boost::system::error_code e) {
+        doPing();
+      });
+    }
+  }
+
+  void stopPing() {
+
+    std::cout << std::endl;
+    std::cout << "--- " << config_.name_ << " ping statistics ---" << std::endl;
+    std::cout << sent_ << " packets transmitted, " << received_ << " packets received, ";
+    std::cout << std::fixed << std::setprecision(1) << (1 - float(received_) / float(sent_)) * 100;
+    std::cout << " % packet loss" << std::endl;
+
+    if (received_ > 0) {
+      float rtt_avg = float(rtt_sum_) / float(received_);
+      float rtt2_avg = float(rtt_sum2_) / float(received_);
+      float rtt_mdev = std::sqrt(rtt2_avg - rtt_avg * rtt_avg);
+
+      std::cout << "rtt min/avg/max/mdev = ";
+      std::cout << std::fixed << std::setprecision(3) << float(rtt_min_) / 1000
+                << "/";
+      std::cout << std::fixed << std::setprecision(3) << rtt_avg / 1000 << "/";
+      std::cout << std::fixed << std::setprecision(3) << float(rtt_max_) / 1000
+                << "/";
+      std::cout << std::fixed << std::setprecision(3) << rtt_mdev / 1000
+                << " ms";
+    }
+
+    portal_.stopEventsLoop();
+  }
+
+  void afterSignal(const boost::system::error_code& ec, int signal_number) {
+    stopPing();
+  }
+
+ private:
+  Portal portal_;
+
+  Configuration config_;
+  SendTimeMap send_timestamps_;
+  uint64_t sequence_number_;
+  uint32_t sent_;
+  uint32_t received_;
+  uint32_t timedout_;
+  uint32_t duplicated_;
+  uint64_t rtt_sum_;
+  uint64_t rtt_sum2_;
+  uint64_t rtt_min_;
+  uint64_t rtt_max_;
+  std::unique_ptr<boost::asio::steady_timer> timer_;
+  std::unique_ptr<boost::asio::signal_set> signals_;
+};
+
+void help(char * program_name) {
+  std::cout << "usage: " << program_name << " [options]" << std::endl;
+  std::cout << "PING options" << std::endl;
+  std::cout << "-i <val>          ping interval in microseconds (default 1000ms)" << std::endl;
+  std::cout << "-m <val>          maximum number of pings to send (default unlimited)" << std::endl;
+  std::cout << "-t <val>          set packet ttl (default 64)" << std::endl;
+  //std::cout << "-j <val1> <val2>  jump <val2> sequence numbers every <val1> interests (default disabled)" << std::endl;
+  std::cout << "ICN options" << std::endl;
+  std::cout << "-n <val>          icn name (default ccnx:/pingserver)" << std::endl;
+  std::cout << "-l <val>          interest lifetime in milliseconds (default 500ms)" << std::endl;
+  std::cout << "OUTPUT options" << std::endl;
+  std::cout << "-H                prints this message" << std::endl;
+}
+
+int main(int argc, char *argv[]) {
+
+  Configuration c;
+  int opt;
+
+  while ((opt = getopt(argc, argv, "j::t:i:m:s:d:n:l:SAOqVDH")) != -1) {
+    switch (opt) {
+      case 't':
+        c.ttl_ = (uint8_t) std::stoi(optarg);
+        break;
+      case 'i':
+        c.pingInterval_ = std::stoi(optarg);
+        break;
+      case 'm':
+        c.maxPing_ = std::stoi(optarg);
+        break;
+      case 'l':
+        c.interestLifetime_ = std::stoi(optarg);
+        break;
+      case 'H':
+      default:
+        help(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+  }
+
+  if (argv[optind] == 0) {
+    std::cerr << "Using default name " << c.name_ << std::endl;
+  } else {
+    c.name_ = argv[optind];
+  }
+
+  Client *ping = new Client(c);
+  ping->ping();
+
+  exit(1);
+}
+
+//close name spaces
+}
+
+}
+
+}
+
+int main(int argc, char *argv[]) {
+  return icnet::ccnx::ping::main(argc, argv);
+}
index 4a50786..0e5121e 100644 (file)
@@ -66,7 +66,7 @@ int main(int argc, char **argv) {
 
 } // end namespace http
 
-} // end namespace hicnet
+} // end namespace icnet
 
 int main(int argc, char **argv) {
   return icnet::http::main(argc, argv);
index 3736636..2d97eb2 100755 (executable)
@@ -20,11 +20,18 @@ set(PRODUCER_SOURCE_FILES
 set(PRODUCER_HELLO_WORLD_SOURCE_FILES
         icnet_producer_hello_world.cc)
 
+set(PRODUCER_PING_SOURCE_FILES
+    icnet_ping_server.cc)
+
 add_executable(producer-test ${PRODUCER_SOURCE_FILES})
 add_executable(producer-hello-world ${PRODUCER_HELLO_WORLD_SOURCE_FILES})
+add_executable(icnet-ping-server ${PRODUCER_PING_SOURCE_FILES})
+
 
 target_link_libraries(producer-test icnet ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
 target_link_libraries(producer-hello-world icnet ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
+target_link_libraries(icnet-ping-server icnet ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
 
 install(TARGETS producer-test DESTINATION ${CMAKE_INSTALL_PREFIX}/bin COMPONENT library)
 install(TARGETS producer-hello-world DESTINATION ${CMAKE_INSTALL_PREFIX}/bin COMPONENT library)
+install(TARGETS icnet-ping-server DESTINATION ${CMAKE_INSTALL_PREFIX}/bin COMPONENT library)
diff --git a/apps/producers/icnet_ping_server.cc b/apps/producers/icnet_ping_server.cc
new file mode 100644 (file)
index 0000000..57f0d88
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "icnet_transport_socket_producer.h"
+#include "icnet_utils_daemonizator.h"
+
+namespace icnet {
+
+namespace transport {
+
+class CallbackContainer {
+ public:
+  CallbackContainer(const std::string &prefix,
+                    uint32_t object_size)
+      : buffer_(object_size, 0xFF),
+        content_object_(std::make_shared<ContentObject>(Name(prefix), (const uint8_t *) buffer_.data(), buffer_.size())) {
+    content_object_->setExpiryTime(0);
+  }
+
+  void processInterest(ProducerSocket &p, const Interest &interest) {
+
+    std::cout << "<<< received interest " << interest.getName() << std::endl;
+    content_object_->setName(interest.getName());
+    std::cout << ">>> send object " << content_object_->getName() << std::endl;
+    std::cout << std::endl;
+
+    p.produce(*content_object_);
+  }
+
+ private:
+  std::string buffer_;
+  std::shared_ptr<ContentObject> content_object_;
+};
+
+void help(char * program_name) {
+  std::cout << "usage: " << program_name <<" [options]" << std::endl;
+  std::cout << "PING options" << std::endl;
+  std::cout << "-s <val>  object content size (default 64B)" << std::endl;
+  std::cout << "-n <val>  icn name (default ccnx:/webserver)" << std::endl;
+  std::cout << "OUTPUT options" << std::endl;
+  std::cout << "-H        prints this message" << std::endl;
+}
+
+int main(int argc, char **argv) {
+  std::string name_prefix = "ccnx:/pingserver";
+  bool daemon = false;
+  uint32_t object_size = 64;
+  uint8_t ttl = 64;
+
+  int opt;
+  while ((opt = getopt(argc, argv, "s:n:t:dH")) != -1) {
+    switch (opt) {
+      case 's':
+        object_size = std::stoi(optarg);
+        break;
+      case 't':
+        ttl = (uint8_t) std::stoi(optarg);
+        break;
+      case 'd':
+        daemon = true;
+        break;
+      case 'H':
+      default:
+        help(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+  }
+
+  if (argv[optind] != 0) {
+    name_prefix = argv[optind];
+  }
+
+  if (daemon) {
+    utils::Daemonizator::daemonize();
+  }
+
+  if (object_size > 1350)
+    object_size = 1350;
+
+  std::cout << "Using prefix [" << name_prefix << "]" << std::endl;
+
+  CallbackContainer stubs(name_prefix, object_size);
+
+  boost::asio::io_service io_service;
+
+  ProducerSocket p(Name(name_prefix.c_str()));
+  p.setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, false);
+
+  //  setting callbacks
+  p.setSocketOption(ProducerCallbacksOptions::INTEREST_INPUT,
+                    (ProducerInterestCallback) bind(&CallbackContainer::processInterest,
+                                                    &stubs,
+                                                    std::placeholders::_1,
+                                                    std::placeholders::_2));
+
+  p.attach();
+
+  p.serveForever();
+
+  return 0;
+}
+
+} // end namespace transport
+
+} // end namespace icnet
+
+int main(int argc, char **argv) {
+  return icnet::transport::main(argc, argv);
+}
+
index e407019..da9a71f 100644 (file)
@@ -29,7 +29,7 @@ ContentObject::ContentObject()
       content_type_(PayloadType::DATA) {
 }
 
-ContentObject::ContentObject(const Name &name, uint8_t *payload, std::size_t size)
+ContentObject::ContentObject(const Name &name, const uint8_t *payload, std::size_t size)
     : name_(name), content_type_(PayloadType::DATA) {
   PARCBuffer *buffer = parcBuffer_CreateFromArray(payload, size);
   buffer = parcBuffer_Flip(buffer);
index e7e641e..367df0b 100644 (file)
@@ -59,7 +59,7 @@ class ContentObject : public std::enable_shared_from_this<ContentObject> {
  public:
   ContentObject();
 
-  ContentObject(const Name &name, uint8_t *payload, std::size_t size);
+  ContentObject(const Name &name, const uint8_t *payload, std::size_t size);
 
   ContentObject(const CCNxContentObjectStructure *content_object);