summaryrefslogtreecommitdiffstats
path: root/apps/ping/src/ping_client.cc
diff options
context:
space:
mode:
Diffstat (limited to 'apps/ping/src/ping_client.cc')
-rw-r--r--apps/ping/src/ping_client.cc441
1 files changed, 441 insertions, 0 deletions
diff --git a/apps/ping/src/ping_client.cc b/apps/ping/src/ping_client.cc
new file mode 100644
index 000000000..24e0bf3ed
--- /dev/null
+++ b/apps/ping/src/ping_client.cc
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/auth/verifier.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/interfaces/portal.h>
+
+#include <asio/signal_set.hpp>
+#include <asio/steady_timer.hpp>
+#include <chrono>
+#include <map>
+
+#define SYN_STATE 1
+#define ACK_STATE 2
+
+namespace transport {
+
+namespace core {
+
+namespace ping {
+
+typedef std::map<uint64_t, uint64_t> SendTimeMap;
+typedef auth::AsymmetricVerifier Verifier;
+
+class Configuration {
+ public:
+ uint64_t interestLifetime_;
+ uint64_t pingInterval_;
+ uint64_t maxPing_;
+ uint64_t first_suffix_;
+ std::string name_;
+ std::string certificate_;
+ uint16_t srcPort_;
+ uint16_t dstPort_;
+ bool verbose_;
+ bool dump_;
+ bool jump_;
+ bool open_;
+ bool always_syn_;
+ bool always_ack_;
+ bool quiet_;
+ uint32_t jump_freq_;
+ uint32_t jump_size_;
+ uint8_t ttl_;
+
+ Configuration() {
+ interestLifetime_ = 500; // ms
+ pingInterval_ = 1000000; // us
+ maxPing_ = 10; // number of interests
+ first_suffix_ = 0;
+ name_ = "b001::1"; // string
+ srcPort_ = 9695;
+ dstPort_ = 8080;
+ verbose_ = false;
+ dump_ = false;
+ jump_ = false;
+ open_ = false;
+ always_syn_ = false;
+ always_ack_ = false;
+ quiet_ = false;
+ jump_freq_ = 0;
+ jump_size_ = 0;
+ ttl_ = 64;
+ }
+};
+
+class Client : interface::Portal::ConsumerCallback {
+ public:
+ Client(Configuration *c)
+ : portal_(), signals_(portal_.getIoService(), SIGINT) {
+ // Let the main thread to catch SIGINT
+ portal_.connect();
+ portal_.setConsumerCallback(this);
+
+ signals_.async_wait(std::bind(&Client::afterSignal, this));
+
+ timer_.reset(new asio::steady_timer(portal_.getIoService()));
+ config_ = c;
+ sequence_number_ = config_->first_suffix_;
+ last_jump_ = 0;
+ processed_ = 0;
+ state_ = SYN_STATE;
+ sent_ = 0;
+ received_ = 0;
+ timedout_ = 0;
+ if (!c->certificate_.empty()) {
+ verifier_.useCertificate(c->certificate_);
+ }
+ }
+
+ virtual ~Client() {}
+
+ void ping() {
+ std::cout << "start ping" << std::endl;
+ doPing();
+ portal_.runEventsLoop();
+ }
+
+ void onContentObject(Interest &interest, ContentObject &object) override {
+ uint64_t rtt = 0;
+
+ if (!config_->certificate_.empty()) {
+ auto t0 = std::chrono::steady_clock::now();
+ if (verifier_.verifyPacket(&object)) {
+ auto t1 = std::chrono::steady_clock::now();
+ auto dt =
+ std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0);
+ std::cout << "Verification time: " << dt.count() << std::endl;
+ std::cout << "<<< Signature Ok." << std::endl;
+ } else {
+ std::cout << "<<< Signature verification failed!" << std::endl;
+ }
+ }
+
+ auto it = send_timestamps_.find(interest.getName().getSuffix());
+ 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 (config_->verbose_) {
+ std::cout << "<<< recevied object. " << std::endl;
+ std::cout << "<<< interest name: " << interest.getName()
+ << " src port: " << interest.getSrcPort()
+ << " dst port: " << interest.getDstPort()
+ << " flags: " << interest.printFlags() << std::endl;
+ std::cout << "<<< object name: " << object.getName()
+ << " src port: " << object.getSrcPort()
+ << " dst port: " << object.getDstPort()
+ << " flags: " << object.printFlags() << " path label "
+ << object.getPathLabel() << " ("
+ << (object.getPathLabel() >> 24) << ")"
+ << " TTL: " << (int)object.getTTL() << std::endl;
+ } else if (!config_->quiet_) {
+ std::cout << "<<< received object. " << std::endl;
+ std::cout << "<<< round trip: " << rtt << " [us]" << std::endl;
+ std::cout << "<<< interest name: " << interest.getName() << std::endl;
+ std::cout << "<<< object name: " << object.getName() << std::endl;
+ std::cout << "<<< content object size: "
+ << object.payloadSize() + object.headerSize() << " [bytes]"
+ << std::endl;
+ }
+
+ if (config_->dump_) {
+ std::cout << "----- interest dump -----" << std::endl;
+ interest.dump();
+ std::cout << "-------------------------" << std::endl;
+ std::cout << "----- object dump -------" << std::endl;
+ object.dump();
+ std::cout << "-------------------------" << std::endl;
+ }
+
+ if (!config_->quiet_) std::cout << std::endl;
+
+ if (!config_->always_syn_) {
+ if (object.testSyn() && object.testAck() && state_ == SYN_STATE) {
+ state_ = ACK_STATE;
+ }
+ }
+
+ received_++;
+ processed_++;
+ if (processed_ >= config_->maxPing_) {
+ afterSignal();
+ }
+ }
+
+ void onTimeout(Interest::Ptr &interest, const Name &name) override {
+ if (config_->verbose_) {
+ std::cout << "### timeout for " << name
+ << " src port: " << interest->getSrcPort()
+ << " dst port: " << interest->getDstPort()
+ << " flags: " << interest->printFlags() << std::endl;
+ } else if (!config_->quiet_) {
+ std::cout << "### timeout for " << name << std::endl;
+ }
+
+ if (config_->dump_) {
+ std::cout << "----- interest dump -----" << std::endl;
+ interest->dump();
+ std::cout << "-------------------------" << std::endl;
+ }
+
+ if (!config_->quiet_) std::cout << std::endl;
+
+ timedout_++;
+ processed_++;
+ if (processed_ >= config_->maxPing_) {
+ afterSignal();
+ }
+ }
+
+ void onError(std::error_code ec) override {}
+
+ void doPing() {
+ const Name interest_name(config_->name_, (uint32_t)sequence_number_);
+ hicn_format_t format;
+ if (interest_name.getAddressFamily() == AF_INET) {
+ format = HF_INET_TCP;
+ } else {
+ format = HF_INET6_TCP;
+ }
+
+ auto interest = std::make_shared<Interest>(interest_name, format);
+
+ interest->setLifetime(uint32_t(config_->interestLifetime_));
+ interest->resetFlags();
+
+ if (config_->open_ || config_->always_syn_) {
+ if (state_ == SYN_STATE) {
+ interest->setSyn();
+ } else if (state_ == ACK_STATE) {
+ interest->setAck();
+ }
+ } else if (config_->always_ack_) {
+ interest->setAck();
+ }
+
+ interest->setSrcPort(config_->srcPort_);
+ interest->setDstPort(config_->dstPort_);
+ interest->setTTL(config_->ttl_);
+
+ if (config_->verbose_) {
+ std::cout << ">>> send interest " << interest->getName()
+ << " src port: " << interest->getSrcPort()
+ << " dst port: " << interest->getDstPort()
+ << " flags: " << interest->printFlags()
+ << " TTL: " << (int)interest->getTTL() << std::endl;
+ } else if (!config_->quiet_) {
+ std::cout << ">>> send interest " << interest->getName() << std::endl;
+ }
+
+ if (config_->dump_) {
+ std::cout << "----- interest dump -----" << std::endl;
+ interest->dump();
+ std::cout << "-------------------------" << std::endl;
+ }
+
+ if (!config_->quiet_) std::cout << std::endl;
+
+ send_timestamps_[sequence_number_] =
+ std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+
+ portal_.sendInterest(std::move(interest));
+
+ sequence_number_++;
+ sent_++;
+
+ if (sent_ < config_->maxPing_) {
+ this->timer_->expires_from_now(
+ std::chrono::microseconds(config_->pingInterval_));
+ this->timer_->async_wait([this](const std::error_code e) { doPing(); });
+ }
+ }
+
+ void afterSignal() {
+ std::cout << "Stop ping" << std::endl;
+ std::cout << "Sent: " << sent_ << " Received: " << received_
+ << " Timeouts: " << timedout_ << std::endl;
+ portal_.stopEventsLoop();
+ }
+
+ void reset() {
+ timer_.reset(new asio::steady_timer(portal_.getIoService()));
+ sequence_number_ = config_->first_suffix_;
+ last_jump_ = 0;
+ processed_ = 0;
+ state_ = SYN_STATE;
+ sent_ = 0;
+ received_ = 0;
+ timedout_ = 0;
+ }
+
+ private:
+ SendTimeMap send_timestamps_;
+ interface::Portal portal_;
+ asio::signal_set signals_;
+ uint64_t sequence_number_;
+ uint64_t last_jump_;
+ uint64_t processed_;
+ uint32_t state_;
+ uint32_t sent_;
+ uint32_t received_;
+ uint32_t timedout_;
+ std::unique_ptr<asio::steady_timer> timer_;
+ Configuration *config_;
+ Verifier verifier_;
+};
+
+void help() {
+ std::cout << "usage: hicn-consumer-ping [options]" << std::endl;
+ std::cout << "PING options" << std::endl;
+ std::cout
+ << "-i <val> ping interval in microseconds (default 1000000ms)"
+ << std::endl;
+ std::cout << "-m <val> maximum number of pings to send (default 10)"
+ << std::endl;
+ std::cout << "-s <val> sorce port (default 9695)" << std::endl;
+ std::cout << "-d <val> destination port (default 8080)" << std::endl;
+ std::cout << "-t <val> set packet ttl (default 64)" << std::endl;
+ std::cout << "-O open tcp connection (three way handshake) "
+ "(default false)"
+ << std::endl;
+ std::cout << "-S send always syn messages (default false)"
+ << std::endl;
+ std::cout << "-A send always ack messages (default false)"
+ << std::endl;
+ std::cout << "HICN options" << std::endl;
+ std::cout << "-n <val> hicn name (default b001::1)" << std::endl;
+ std::cout
+ << "-l <val> interest lifetime in milliseconds (default 500ms)"
+ << std::endl;
+ std::cout << "OUTPUT options" << std::endl;
+ std::cout << "-V verbose, prints statistics about the "
+ "messagges sent and received (default false)"
+ << std::endl;
+ std::cout << "-D dump, dumps sent and received packets "
+ "(default false)"
+ << std::endl;
+ std::cout << "-q quiet, not prints (default false)"
+ << std::endl;
+ std::cout << "-H prints this message" << std::endl;
+}
+
+int main(int argc, char *argv[]) {
+#ifdef _WIN32
+ WSADATA wsaData = {0};
+ WSAStartup(MAKEWORD(2, 2), &wsaData);
+#endif
+
+ Configuration *c = new Configuration();
+ int opt;
+ std::string producer_certificate = "";
+
+ while ((opt = getopt(argc, argv, "j::t:i:m:s:d:n:l:f:c: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 'f':
+ c->first_suffix_ = std::stoul(optarg);
+ break;
+ case 's':
+ c->srcPort_ = std::stoi(optarg);
+ break;
+ case 'd':
+ c->dstPort_ = std::stoi(optarg);
+ break;
+ case 'n':
+ c->name_ = optarg;
+ break;
+ case 'l':
+ c->interestLifetime_ = std::stoi(optarg);
+ break;
+ case 'V':
+ c->verbose_ = true;
+ ;
+ break;
+ case 'D':
+ c->dump_ = true;
+ break;
+ case 'O':
+ c->always_syn_ = false;
+ c->always_ack_ = false;
+ c->open_ = true;
+ break;
+ case 'S':
+ c->always_syn_ = true;
+ c->always_ack_ = false;
+ c->open_ = false;
+ break;
+ case 'A':
+ c->always_syn_ = false;
+ c->always_ack_ = true;
+ c->open_ = false;
+ break;
+ case 'q':
+ c->quiet_ = true;
+ c->verbose_ = false;
+ c->dump_ = false;
+ break;
+ case 'c':
+ c->certificate_ = std::string(optarg);
+ break;
+ case 'H':
+ default:
+ help();
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ auto ping = std::make_unique<Client>(c);
+
+ auto t0 = std::chrono::steady_clock::now();
+ ping->ping();
+ auto t1 = std::chrono::steady_clock::now();
+
+ std::cout
+ << "Elapsed time: "
+ << std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0).count()
+ << std::endl;
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+ return 0;
+}
+
+} // namespace ping
+
+} // namespace core
+
+} // namespace transport
+
+int main(int argc, char *argv[]) {
+ return transport::core::ping::main(argc, argv);
+}