diff options
Diffstat (limited to 'apps/ping/src')
-rw-r--r-- | apps/ping/src/ping_client.cc | 441 | ||||
-rw-r--r-- | apps/ping/src/ping_server.cc | 340 |
2 files changed, 781 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); +} diff --git a/apps/ping/src/ping_server.cc b/apps/ping/src/ping_server.cc new file mode 100644 index 000000000..baf9c6698 --- /dev/null +++ b/apps/ping/src/ping_server.cc @@ -0,0 +1,340 @@ +/* + * 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/interfaces/socket_producer.h> +#ifndef _WIN32 +#include <hicn/transport/utils/daemonizator.h> +#include <unistd.h> +#else +#include <openssl/applink.c> +#endif + +#include <hicn/transport/auth/identity.h> +#include <hicn/transport/auth/signer.h> +#include <hicn/transport/core/content_object.h> +#include <hicn/transport/core/interest.h> +#include <hicn/transport/utils/string_tokenizer.h> + +#include <asio.hpp> + +namespace transport { + +namespace interface { + +using HashAlgorithm = core::HashAlgorithm; +using CryptoSuite = auth::CryptoSuite; + +auth::Identity setProducerIdentity(std::string keystore_name, + std::string keystore_password, + auth::CryptoHashType hash_algorithm) { + if (access(keystore_name.c_str(), F_OK) != -1) { + return auth::Identity(keystore_name, keystore_password, hash_algorithm); + } else { + return auth::Identity(keystore_name, keystore_password, + CryptoSuite::RSA_SHA256, 1024, 365, "producer-test"); + } +} + +class CallbackContainer { + const std::size_t log2_content_object_buffer_size = 12; + + public: + CallbackContainer(const Name &prefix, uint32_t object_size, bool verbose, + bool dump, bool quite, bool flags, bool reset, uint8_t ttl, + auth::Identity *identity, bool sign, uint32_t lifetime) + : buffer_(object_size, 'X'), + content_objects_((std::uint32_t)(1 << log2_content_object_buffer_size)), + mask_((std::uint16_t)(1 << log2_content_object_buffer_size) - 1), + content_objects_index_(0), + verbose_(verbose), + dump_(dump), + quite_(quite), + flags_(flags), + reset_(reset), + ttl_(ttl), + identity_(identity), + sign_(sign) { + core::Packet::Format format; + + if (prefix.getAddressFamily() == AF_INET) { + format = core::Packet::Format::HF_INET_TCP; + if (sign_) { + format = core::Packet::Format::HF_INET_TCP_AH; + } + } else { + format = core::Packet::Format::HF_INET6_TCP; + if (sign_) { + format = core::Packet::Format::HF_INET6_TCP_AH; + } + } + + for (int i = 0; i < (1 << log2_content_object_buffer_size); i++) { + content_objects_[i] = std::make_shared<ContentObject>( + prefix, format, 0, (const uint8_t *)buffer_.data(), buffer_.size()); + content_objects_[i]->setLifetime(lifetime); + } + } + + void processInterest(ProducerSocket &p, const Interest &interest, + uint32_t lifetime) { + if (verbose_) { + std::cout << "<<< received interest " << interest.getName() + << " src port: " << interest.getSrcPort() + << " dst port: " << interest.getDstPort() + << " flags: " << interest.printFlags() + << "TTL: " << (int)interest.getTTL() << std::endl; + } else if (!quite_) { + std::cout << "<<< received interest " << interest.getName() << std::endl; + } + + if (dump_) { + std::cout << "----- interest dump -----" << std::endl; + interest.dump(); + std::cout << "-------------------------" << std::endl; + } + + if (interest.testRst()) { + std::cout << "!!!got a reset, I don't reply" << std::endl; + } else { + auto &content_object = content_objects_[content_objects_index_++ & mask_]; + + content_object->setName(interest.getName()); + content_object->setLifetime(lifetime); + content_object->setLocator(interest.getLocator()); + content_object->setSrcPort(interest.getDstPort()); + content_object->setDstPort(interest.getSrcPort()); + content_object->setTTL(ttl_); + + if (!sign_) { + content_object->resetFlags(); + } + + if (flags_) { + if (interest.testSyn()) { + content_object->setSyn(); + content_object->setAck(); + } else if (interest.testAck()) { + content_object->setAck(); + } // here I may need to handle the FIN flag; + } else if (reset_) { + content_object->setRst(); + } + + if (verbose_) { + std::cout << ">>> send object " << content_object->getName() + << " src port: " << content_object->getSrcPort() + << " dst port: " << content_object->getDstPort() + << " flags: " << content_object->printFlags() + << " TTL: " << (int)content_object->getTTL() << std::endl; + } else if (!quite_) { + std::cout << ">>> send object " << content_object->getName() + << std::endl; + } + + if (dump_) { + std::cout << "----- object dump -----" << std::endl; + content_object->dump(); + std::cout << "-----------------------" << std::endl; + } + + if (!quite_) std::cout << std::endl; + + if (sign_) { + identity_->getSigner()->signPacket(content_object.get()); + } + + p.produce(*content_object); + } + } + + private: + std::string buffer_; + std::vector<std::shared_ptr<ContentObject>> content_objects_; + std::uint16_t mask_; + std::uint16_t content_objects_index_; + bool verbose_; + bool dump_; + bool quite_; + bool flags_; + bool reset_; + uint8_t ttl_; + auth::Identity *identity_; + bool sign_; +}; + +void help() { + std::cout << "usage: hicn-preoducer-ping [options]" << std::endl; + std::cout << "PING options" << std::endl; + std::cout << "-s <val> object content size (default 1350B)" << std::endl; + std::cout << "-n <val> hicn name (default b001::/64)" << std::endl; + std::cout << "-f set tcp flags according to the flag received " + "(default false)" + << std::endl; + std::cout << "-l data lifetime" << std::endl; + std::cout << "-r always reply with a reset flag (default false)" + << std::endl; + std::cout << "-t set ttl (default 64)" << 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 quite, not prints (default false)" << std::endl; +#ifndef _WIN32 + std::cout << "-d daemon mode" << std::endl; +#endif + std::cout << "-H prints this message" << std::endl; +} + +int main(int argc, char **argv) { +#ifdef _WIN32 + WSADATA wsaData = {0}; + WSAStartup(MAKEWORD(2, 2), &wsaData); +#else + bool daemon = false; +#endif + std::string name_prefix = "b001::0/64"; + std::string delimiter = "/"; + bool verbose = false; + bool dump = false; + bool quite = false; + bool flags = false; + bool reset = false; + uint32_t object_size = 1250; + uint8_t ttl = 64; + std::string keystore_path = "./rsa_crypto_material.p12"; + std::string keystore_password = "cisco"; + bool sign = false; + uint32_t data_lifetime = default_values::content_object_expiry_time; + + int opt; +#ifndef _WIN32 + while ((opt = getopt(argc, argv, "s:n:t:l:qfrVDdHk:p:")) != -1) { +#else + while ((opt = getopt(argc, argv, "s:n:t:l:qfrVDHk:p:")) != -1) { +#endif + switch (opt) { + case 's': + object_size = std::stoi(optarg); + break; + case 'n': + name_prefix = optarg; + break; + case 't': + ttl = (uint8_t)std::stoi(optarg); + break; + case 'l': + data_lifetime = std::stoi(optarg); + break; + case 'V': + verbose = true; + break; + case 'D': + dump = true; + break; + case 'q': + verbose = false; + dump = false; + quite = true; + break; +#ifndef _WIN32 + case 'd': + daemon = true; + break; +#endif + case 'f': + flags = true; + break; + case 'r': + reset = true; + break; + case 'k': + keystore_path = optarg; + sign = true; + break; + case 'p': + keystore_password = optarg; + break; + case 'H': + default: + help(); + exit(EXIT_FAILURE); + } + } + +#ifndef _WIN32 + if (daemon) { + utils::Daemonizator::daemonize(); + } +#endif + + core::Prefix producer_namespace(name_prefix); + + utils::StringTokenizer tokenizer(name_prefix, delimiter); + std::string ip_address = tokenizer.nextToken(); + Name n(ip_address); + + if (object_size > 1350) object_size = 1350; + + CallbackContainer *stubs; + auth::Identity identity = setProducerIdentity( + keystore_path, keystore_password, auth::CryptoHashType::SHA256); + + if (sign) { + stubs = new CallbackContainer(n, object_size, verbose, dump, quite, flags, + reset, ttl, &identity, sign, data_lifetime); + } else { + auth::Identity *identity = nullptr; + stubs = new CallbackContainer(n, object_size, verbose, dump, quite, flags, + reset, ttl, identity, sign, data_lifetime); + } + + ProducerSocket p; + p.registerPrefix(producer_namespace); + + p.setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 0U); + p.setSocketOption( + ProducerCallbacksOptions::CACHE_MISS, + (ProducerInterestCallback)bind(&CallbackContainer::processInterest, stubs, + std::placeholders::_1, + std::placeholders::_2, data_lifetime)); + + p.connect(); + + asio::io_service io_service; + asio::signal_set signal_set(io_service, SIGINT); + signal_set.async_wait( + [&p, &io_service](const std::error_code &, const int &) { + std::cout << "STOPPING!!" << std::endl; + p.stop(); + io_service.stop(); + }); + + io_service.run(); + +#ifdef _WIN32 + WSACleanup(); +#endif + return 0; +} + +} // namespace interface + +} // end namespace transport + +int main(int argc, char **argv) { + return transport::interface::main(argc, argv); +} |