From 95f3619c8be677bcd9cf3bb320c7262bbe6dc44b Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Fri, 23 Feb 2018 15:25:32 +0100 Subject: Added native PING application Change-Id: If76818fdc90e7223e811ece0c21f8a7c67defa4c Signed-off-by: Mauro Sardara --- apps/consumers/CMakeLists.txt | 6 + apps/consumers/icnet_ping_client.cc | 265 ++++++++++++++++++++++++++++++++++++ apps/http/icnet_iget.cc | 2 +- apps/producers/CMakeLists.txt | 7 + apps/producers/icnet_ping_server.cc | 122 +++++++++++++++++ 5 files changed, 401 insertions(+), 1 deletion(-) create mode 100644 apps/consumers/icnet_ping_client.cc create mode 100644 apps/producers/icnet_ping_server.cc (limited to 'apps') diff --git a/apps/consumers/CMakeLists.txt b/apps/consumers/CMakeLists.txt index 757d0219..4cf2d2a2 100755 --- a/apps/consumers/CMakeLists.txt +++ b/apps/consumers/CMakeLists.txt @@ -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 index 00000000..42a0ab19 --- /dev/null +++ b/apps/consumers/icnet_ping_client.cc @@ -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 + +#include +#include + +namespace icnet { + +namespace ccnx { + +namespace ping { + +typedef std::map 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::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::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::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 = std::make_shared(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::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 timer_; + std::unique_ptr signals_; +}; + +void help(char * program_name) { + std::cout << "usage: " << program_name << " [options]" << std::endl; + std::cout << "PING options" << std::endl; + std::cout << "-i ping interval in microseconds (default 1000ms)" << std::endl; + std::cout << "-m maximum number of pings to send (default unlimited)" << std::endl; + std::cout << "-t set packet ttl (default 64)" << std::endl; + //std::cout << "-j jump sequence numbers every interests (default disabled)" << std::endl; + std::cout << "ICN options" << std::endl; + std::cout << "-n icn name (default ccnx:/pingserver)" << std::endl; + std::cout << "-l 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); +} diff --git a/apps/http/icnet_iget.cc b/apps/http/icnet_iget.cc index 4a507864..0e5121e9 100644 --- a/apps/http/icnet_iget.cc +++ b/apps/http/icnet_iget.cc @@ -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); diff --git a/apps/producers/CMakeLists.txt b/apps/producers/CMakeLists.txt index 37366362..2d97eb2e 100755 --- a/apps/producers/CMakeLists.txt +++ b/apps/producers/CMakeLists.txt @@ -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 index 00000000..57f0d88f --- /dev/null +++ b/apps/producers/icnet_ping_server.cc @@ -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(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 content_object_; +}; + +void help(char * program_name) { + std::cout << "usage: " << program_name <<" [options]" << std::endl; + std::cout << "PING options" << std::endl; + std::cout << "-s object content size (default 64B)" << std::endl; + std::cout << "-n 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); +} + -- cgit 1.2.3-korg