diff options
Diffstat (limited to 'apps')
-rwxr-xr-x | apps/CMakeLists.txt | 17 | ||||
-rwxr-xr-x | apps/consumers/CMakeLists.txt | 30 | ||||
-rwxr-xr-x | apps/consumers/icnet_consumer_dash.cc | 217 | ||||
-rwxr-xr-x | apps/consumers/icnet_consumer_test.cc | 208 | ||||
-rwxr-xr-x | apps/consumers/icnet_iget.cc | 159 | ||||
-rwxr-xr-x | apps/general/CMakeLists.txt | 19 | ||||
-rwxr-xr-x | apps/general/icnet_general_test.cc | 30 | ||||
-rw-r--r-- | apps/iping/CMakeLists.txt | 50 | ||||
-rw-r--r-- | apps/iping/client.keystore | bin | 0 -> 1646 bytes | |||
-rw-r--r-- | apps/iping/iPing_Client.c | 430 | ||||
-rw-r--r-- | apps/iping/iPing_Common.c | 63 | ||||
-rw-r--r-- | apps/iping/iPing_Common.h | 68 | ||||
-rw-r--r-- | apps/iping/iPing_Server.c | 215 | ||||
-rw-r--r-- | apps/iping/iPing_Stats.c | 139 | ||||
-rw-r--r-- | apps/iping/iPing_Stats.h | 124 | ||||
-rwxr-xr-x | apps/producers/CMakeLists.txt | 22 | ||||
-rwxr-xr-x | apps/producers/icnet_producer_test.cc | 163 |
17 files changed, 1954 insertions, 0 deletions
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt new file mode 100755 index 00000000..6708f3b3 --- /dev/null +++ b/apps/CMakeLists.txt @@ -0,0 +1,17 @@ +# 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. + +cmake_minimum_required(VERSION 3.2) +#include( CTest ) + +subdirs(consumers producers general iping) diff --git a/apps/consumers/CMakeLists.txt b/apps/consumers/CMakeLists.txt new file mode 100755 index 00000000..de9c254f --- /dev/null +++ b/apps/consumers/CMakeLists.txt @@ -0,0 +1,30 @@ +# 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. + +cmake_minimum_required(VERSION 3.4) + +set(CONSUMER_SOURCE_FILES icnet_consumer_test.cc) +set(IGET_SOURCE_FILES icnet_iget.cc) +set(CONSUMERDASH_SOURCE_FILES icnet_consumer_dash.cc) + +add_executable(consumer-test ${CONSUMER_SOURCE_FILES}) +add_executable(iget ${IGET_SOURCE_FILES}) +add_executable(consumer-dash ${CONSUMERDASH_SOURCE_FILES}) + +target_link_libraries(consumer-test icnet ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(iget icnet ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(consumer-dash icnet ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + +install(TARGETS consumer-test DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +install(TARGETS iget DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +install(TARGETS consumer-dash DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/apps/consumers/icnet_consumer_dash.cc b/apps/consumers/icnet_consumer_dash.cc new file mode 100755 index 00000000..4ec4a2c9 --- /dev/null +++ b/apps/consumers/icnet_consumer_dash.cc @@ -0,0 +1,217 @@ +/* + * 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_socket_consumer.h" + +#define DEFAULT_BETA 0.99 +#define DEFAULT_GAMMA 0.07 + +namespace icnet { + +class CallbackContainer { + public: + CallbackContainer() + : work_(new boost::asio::io_service::work(io_service_)), + handler_(std::async(std::launch::async, [this]() { io_service_.run(); })) { + seen_manifest_segments_ = 0; + seen_data_segments_ = 0; + byte_counter_ = 0; + } + + ~CallbackContainer() { + work_.reset(); + } + + void processPayload(ConsumerSocket &c, const uint8_t *buffer, size_t bufferSize) { + std::cout << "Content retrieved!! Size: " << bufferSize << std::endl; + } + + bool verifyData(ConsumerSocket &c, const ContentObject &contentObject) { + if (contentObject.getContentType() == PayloadType::DATA) { + std::cout << "VERIFY CONTENT" << std::endl; + } else if (contentObject.getContentType() == PayloadType::MANIFEST) { + std::cout << "VERIFY MANIFEST" << std::endl; + } + + return true; + } + + void processLeavingInterest(ConsumerSocket &c, const Interest &interest) { + // std::cout << "LEAVES " << interest.getName().toUri() << std::endl; + } + + private: + int seen_manifest_segments_; + int seen_data_segments_; + int byte_counter_; + boost::asio::io_service io_service_; + std::shared_ptr<boost::asio::io_service::work> work_; + std::future<void> handler_; +}; + +class Verificator { + public: + Verificator() { + }; + + ~Verificator() { + } + + bool onPacket(ConsumerSocket &c, const ContentObject &contentObject) { + return true; + } + +}; + +void becomeDaemon() { + pid_t process_id = 0; + pid_t sid = 0; + + // Create child process + process_id = fork(); + + // Indication of fork() failure + if (process_id < 0) { + printf("fork failed!\n"); + // Return failure in exit status + exit(EXIT_FAILURE); + } + + // PARENT PROCESS. Need to kill it. + if (process_id > 0) { + printf("process_id of child process %d \n", process_id); + // return success in exit status + exit(EXIT_SUCCESS); + } + + //unmask the file mode + umask(0); + + //set new session + sid = setsid(); + if (sid < 0) { + // Return failure + exit(EXIT_FAILURE); + } + + // Change the current working directory to root. + chdir("/"); + + // Close stdin. stdout and stderr + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + // Really start application +} + +int main(int argc, char **argv) { + double beta = DEFAULT_BETA; + double drop_factor = DEFAULT_GAMMA; + bool daemon = false; + bool rtt_stats = false; + int n_segment = 427; + bool looping = false; + + int opt; + while ((opt = getopt(argc, argv, "b:d:DRn:l")) != -1) { + switch (opt) { + case 'b': + beta = std::stod(optarg); + break; + case 'd': + drop_factor = std::stod(optarg); + break; + case 'D': + daemon = true; + break; + case 'R': + rtt_stats = true; + break; + case 'n': + n_segment = std::stoi(optarg); + break; + case 'l': + looping = true; + break; + default: + exit(EXIT_FAILURE); + } + } + + std::string name = "ccnx:/webserver/get/sintel/18000"; + + if (argv[optind] == 0) { + std::cerr << "Using default name ccnx:/webserver/sintel/18000" << std::endl; + } else { + name = argv[optind]; + } + + if (daemon) { + becomeDaemon(); + } + + ConsumerSocket c(Name(name.c_str()), TransportProtocolAlgorithms::RAAQM); + + CallbackContainer stubs; + Verificator verificator; + + c.setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, 1001); + c.setSocketOption(RaaqmTransportOptions::BETA_VALUE, beta); + c.setSocketOption(RaaqmTransportOptions::DROP_FACTOR, drop_factor); + c.setSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX, 10); + c.setSocketOption(OtherOptions::VIRTUAL_DOWNLOAD, true); + c.setSocketOption(RaaqmTransportOptions::RTT_STATS, rtt_stats); + + c.setSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY, + (ConsumerContentObjectVerificationCallback) std::bind(&Verificator::onPacket, + &verificator, + std::placeholders::_1, + std::placeholders::_2)); + + c.setSocketOption(ConsumerCallbacksOptions::CONTENT_RETRIEVED, + (ConsumerContentCallback) std::bind(&CallbackContainer::processPayload, + &stubs, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3)); + + c.setSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, + (ConsumerInterestCallback) std::bind(&CallbackContainer::processLeavingInterest, + &stubs, + std::placeholders::_1, + std::placeholders::_2)); + + do { + std::stringstream ss; + for (int i = 1; i < n_segment; i++) { + ss << "ccnx:/seg_" << i << ".m4s"; + auto str = ss.str(); + c.consume(Name(str)); + ss.str(""); + } + } while (looping); + + c.stop(); + + return 0; + +} + +} // end namespace icnet + +int main(int argc, char **argv) { + return icnet::main(argc, argv); +} diff --git a/apps/consumers/icnet_consumer_test.cc b/apps/consumers/icnet_consumer_test.cc new file mode 100755 index 00000000..d5b57d6f --- /dev/null +++ b/apps/consumers/icnet_consumer_test.cc @@ -0,0 +1,208 @@ +/* + * 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_socket_consumer.h" + +#define DEFAULT_BETA 0.99 +#define DEFAULT_GAMMA 0.07 + +namespace icnet { + +class CallbackContainer { + public: + CallbackContainer() + : work_(new boost::asio::io_service::work(io_service_)), + handler_(std::async(std::launch::async, [this]() { io_service_.run(); })) { + seen_manifest_segments_ = 0; + seen_data_segments_ = 0; + byte_counter_ = 0; + } + + ~CallbackContainer() { + work_.reset(); + } + + void processPayload(ConsumerSocket &c, const uint8_t *buffer, size_t bufferSize) { + std::cout << "Content retrieved!! Size: " << bufferSize << std::endl; + + io_service_.dispatch([buffer, bufferSize]() { + std::ofstream file("ciao.txt", std::ofstream::binary); + file.write((char *) buffer, bufferSize); + file.close(); + }); + } + + bool verifyData(ConsumerSocket &c, const ContentObject &contentObject) { + if (contentObject.getContentType() == PayloadType::DATA) { + std::cout << "VERIFY CONTENT" << std::endl; + } else if (contentObject.getContentType() == PayloadType::MANIFEST) { + std::cout << "VERIFY MANIFEST" << std::endl; + } + + return true; + } + + void processLeavingInterest(ConsumerSocket &c, const Interest &interest) { + // std::cout << "LEAVES " << interest.getName().toUri() << std::endl; + } + + private: + int seen_manifest_segments_; + int seen_data_segments_; + int byte_counter_; + boost::asio::io_service io_service_; + std::shared_ptr<boost::asio::io_service::work> work_; + std::future<void> handler_; +}; + +class Verificator { + public: + Verificator() { + }; + + ~Verificator() { + // m_keyChain.deleteIdentity(Name(IDENTITY_NAME)); + } + + bool onPacket(ConsumerSocket &c, const ContentObject &contentObject) { + + return true; + } +}; + +void becomeDaemon() { + pid_t process_id = 0; + pid_t sid = 0; + + // Create child process + process_id = fork(); + + // Indication of fork() failure + if (process_id < 0) { + printf("fork failed!\n"); + // Return failure in exit status + exit(EXIT_FAILURE); + } + + // PARENT PROCESS. Need to kill it. + if (process_id > 0) { + printf("process_id of child process %d \n", process_id); + // return success in exit status + exit(EXIT_SUCCESS); + } + + //unmask the file mode + umask(0); + + //set new session + sid = setsid(); + if (sid < 0) { + // Return failure + exit(EXIT_FAILURE); + } + + // Change the current working directory to root. + chdir("/"); + + // Close stdin. stdout and stderr + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + // Really start application +} + +int main(int argc, char *argv[]) { + double beta = DEFAULT_BETA; + double dropFactor = DEFAULT_GAMMA; + bool daemon = false; + bool rttStats = false; + + int opt; + while ((opt = getopt(argc, argv, "b:d:DR")) != -1) { + switch (opt) { + case 'b': + beta = std::stod(optarg); + break; + case 'd': + dropFactor = std::stod(optarg); + break; + case 'D': + daemon = true; + break; + case 'R': + rttStats = true; + break; + default: + exit(EXIT_FAILURE); + } + } + + std::string name = "ccnx:/ccnxtest"; + + if (argv[optind] == 0) { + std::cerr << "Using default name ccnx:/ccnxtest" << std::endl; + } else { + name = argv[optind]; + } + + if (daemon) { + becomeDaemon(); + } + + ConsumerSocket c(Name(name.c_str()), TransportProtocolAlgorithms::RAAQM); + + CallbackContainer stubs; + Verificator verificator; + + c.setSocketOption(GeneralTransportOptions::INTEREST_LIFETIME, 1001); + c.setSocketOption(RaaqmTransportOptions::BETA_VALUE, beta); + c.setSocketOption(RaaqmTransportOptions::DROP_FACTOR, dropFactor); + c.setSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX, 200); + c.setSocketOption(OtherOptions::VIRTUAL_DOWNLOAD, true); + c.setSocketOption(RaaqmTransportOptions::RTT_STATS, rttStats); + + c.setSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY, + (ConsumerContentObjectVerificationCallback) std::bind(&Verificator::onPacket, + &verificator, + std::placeholders::_1, + std::placeholders::_2)); + + c.setSocketOption(ConsumerCallbacksOptions::CONTENT_RETRIEVED, + (ConsumerContentCallback) std::bind(&CallbackContainer::processPayload, + &stubs, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3)); + + c.setSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, + (ConsumerInterestCallback) std::bind(&CallbackContainer::processLeavingInterest, + &stubs, + std::placeholders::_1, + std::placeholders::_2)); + + c.consume(Name()); + + c.stop(); + + return 0; + +} + +} // end namespace icnet + +int main(int argc, char *argv[]) { + return icnet::main(argc, argv); +} diff --git a/apps/consumers/icnet_iget.cc b/apps/consumers/icnet_iget.cc new file mode 100755 index 00000000..db5ef173 --- /dev/null +++ b/apps/consumers/icnet_iget.cc @@ -0,0 +1,159 @@ +/* + * 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_socket_consumer.h" + +typedef std::chrono::time_point<std::chrono::system_clock> Time; +typedef std::chrono::milliseconds TimeDuration; + +Time t1 = std::chrono::system_clock::now(); + +#define DEFAULT_BETA 0.99 +#define DEFAULT_GAMMA 0.07 + +namespace icnet { + +class CallbackContainer { + public: + CallbackContainer() + : work_(new boost::asio::io_service::work(io_service_)), + handler_(std::async(std::launch::async, [this]() { io_service_.run(); })) { + seen_manifest_segments_ = 0; + seen_data_segments_ = 0; + byte_counter_ = 0; + } + + ~CallbackContainer() { + work_.reset(); + } + + void processPayload(ConsumerSocket &c, const uint8_t *buffer, size_t buffer_size) { + Name m_name; + c.getSocketOption(GeneralTransportOptions::NAME_PREFIX, m_name); + std::string filename = m_name.toString().substr(1 + m_name.toString().find_last_of("/")); + io_service_.dispatch([buffer, buffer_size, filename]() { + std::cout << "Saving to: " << filename << " " << buffer_size / 1024 << "kB" << std::endl; + Time t3 = std::chrono::system_clock::now();; + std::ofstream file(filename.c_str(), std::ofstream::binary); + file.write((char *) buffer, buffer_size); + file.close(); + Time t2 = std::chrono::system_clock::now();; + TimeDuration dt = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1); + TimeDuration dt3 = std::chrono::duration_cast<std::chrono::milliseconds>(t3 - t1); + long msec = dt.count(); + long msec3 = dt3.count(); + std::cout << "Elapsed Time: " << msec / 1000.0 << " seconds -- " << buffer_size * 8 / msec / 1000.0 + << "[Mbps] -- " << buffer_size * 8 / msec3 / 1000.0 << "[Mbps]" << std::endl; + }); + } + + bool verifyData(ConsumerSocket &c, const ContentObject &content_object) { + if (content_object.getContentType() == PayloadType::DATA) { + std::cout << "VERIFY CONTENT" << std::endl; + } else if (content_object.getContentType() == PayloadType::MANIFEST) { + std::cout << "VERIFY MANIFEST" << std::endl; + } + + return true; + } + + void processLeavingInterest(ConsumerSocket &c, const Interest &interest) { + // std::cout << "OUTPUT: " << interest.getName() << std::endl; + } + + private: + int seen_manifest_segments_; + int seen_data_segments_; + int byte_counter_; + boost::asio::io_service io_service_; + std::shared_ptr<boost::asio::io_service::work> work_; + std::future<void> handler_; +}; + +/* + * The client signature verification is currently being reworked with the new API. + * The implementation is disabled for the moment. + */ + +class Verificator { + public: + Verificator() { + }; + + ~Verificator() { + // m_keyChain.deleteIdentity(Name(IDENTITY_NAME)); + } + + bool onPacket(ConsumerSocket &c, const ContentObject &contentObject) { + return true; + } +}; + +int main(int argc, char **argv) { + + std::string url = ""; + std::string locator = ""; + std::string path = ""; + std::string name = "ccnx:/locator/get/path"; + size_t found = 0; + size_t path_begin = 0; + + if (argv[optind] == 0) { + std::cerr << "Missing URL" << std::endl; + return 0; + } else { + url = argv[optind]; + std::cout << "Iget " << url << std::endl; + } + + found = url.find("//"); + path_begin = url.find('/', found + 2); + locator = url.substr(found + 2, path_begin - (found + 2)); + path = url.substr(path_begin, std::string::npos); + std::cout << "locator " << locator << std::endl; + std::cout << "path " << path << std::endl; + name = "ccnx:/" + locator + "/get" + path; + std::cout << "Iget ccnx name: " << name << std::endl; + + ConsumerSocket c(Name(name.c_str()), TransportProtocolAlgorithms::RAAQM); + CallbackContainer stubs; + Verificator verificator; + + c.setSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY, + (ConsumerContentObjectVerificationCallback) std::bind(&Verificator::onPacket, + &verificator, + std::placeholders::_1, + std::placeholders::_2)); + c.setSocketOption(ConsumerCallbacksOptions::CONTENT_RETRIEVED, + (ConsumerContentCallback) std::bind(&CallbackContainer::processPayload, + &stubs, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3)); + c.setSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT, + (ConsumerInterestCallback) std::bind(&CallbackContainer::processLeavingInterest, + &stubs, + std::placeholders::_1, + std::placeholders::_2)); + c.consume(Name()); + c.stop(); + return 0; +} + +} // end namespace icnet + +int main(int argc, char **argv) { + return icnet::main(argc, argv); +} diff --git a/apps/general/CMakeLists.txt b/apps/general/CMakeLists.txt new file mode 100755 index 00000000..6dde6fe3 --- /dev/null +++ b/apps/general/CMakeLists.txt @@ -0,0 +1,19 @@ +# 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. + +cmake_minimum_required(VERSION 3.2) + +set(CONSUMER_SOURCE_FILES icnet_general_test.cc) + +add_executable(general-test ${CONSUMER_SOURCE_FILES}) +target_link_libraries(general-test icnet ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) diff --git a/apps/general/icnet_general_test.cc b/apps/general/icnet_general_test.cc new file mode 100755 index 00000000..88b0203d --- /dev/null +++ b/apps/general/icnet_general_test.cc @@ -0,0 +1,30 @@ +/* + * 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_socket.h" + +namespace icnet { + +int main(int argc, char **argv) { + + return 0; + +} + +} // end namespace icnet + +int main(int argc, char **argv) { + return icnet::main(argc, argv); +}
\ No newline at end of file diff --git a/apps/iping/CMakeLists.txt b/apps/iping/CMakeLists.txt new file mode 100644 index 00000000..5bd2ec5f --- /dev/null +++ b/apps/iping/CMakeLists.txt @@ -0,0 +1,50 @@ +# 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. + +cmake_minimum_required(VERSION 3.2) + +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED ON) + +if ($ENV{CCNX_HOME}) + set(CCNX_HOME $ENV{CCNX_HOME}) +else ($ENV{CCNX_HOME}) + set(CCNX_HOME /usr/local) +endif ($ENV{CCNX_HOME}) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -D_GNU_SOURCE") + +set(CCNX_LIBRARIES longbow longbow-ansiterm parc ccnx_common ccnx_api_portal ccnx_transport_rta ccnx_api_control ccnx_api_notify) + +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") + +set(CCNX_PING_CLIENT_SOURCE_FILES + iPing_Client.c + iPing_Common.c + iPing_Stats.c) + +set(CCNX_PING_SERVER_SOURCE_FILES + iPing_Server.c + iPing_Common.c) + +include_directories(${CCNX_HOME}/include) + +link_directories(${CCNX_HOME}/lib) + +add_executable(iPing_Client ${CCNX_PING_CLIENT_SOURCE_FILES}) +target_link_libraries(iPing_Client ${CCNX_LIBRARIES}) +install(TARGETS iPing_Client RUNTIME DESTINATION bin) + +add_executable(iPing_Server ${CCNX_PING_SERVER_SOURCE_FILES}) +target_link_libraries(iPing_Server ${CCNX_LIBRARIES}) +install(TARGETS iPing_Server RUNTIME DESTINATION bin) diff --git a/apps/iping/client.keystore b/apps/iping/client.keystore Binary files differnew file mode 100644 index 00000000..f59eca9f --- /dev/null +++ b/apps/iping/client.keystore diff --git a/apps/iping/iPing_Client.c b/apps/iping/iPing_Client.c new file mode 100644 index 00000000..85d92eb0 --- /dev/null +++ b/apps/iping/iPing_Client.c @@ -0,0 +1,430 @@ +/* + * 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 <stdio.h> +#include <inttypes.h> +#include <getopt.h> +#include <LongBow/runtime.h> +#include <ccnx/api/ccnx_Portal/ccnx_Portal.h> +#include <ccnx/api/ccnx_Portal/ccnx_PortalRTA.h> +#include <parc/algol/parc_Clock.h> +#include <parc/security/parc_Security.h> +#include <parc/algol/parc_DisplayIndented.h> +#include "iPing_Stats.h" +#include "iPing_Common.h" + +typedef enum { + CCNxPingClientMode_None = 0, CCNxPingClientMode_Flood, CCNxPingClientMode_PingPong, CCNxPingClientMode_All +} CCNxPingClientMode; + +typedef struct ccnx_Ping_client { + CCNxPortal *portal; + CCNxPortalFactory *factory; + CCNxPingStats *stats; + CCNxPingClientMode mode; + + CCNxName *prefix; + + size_t numberOfOutstanding; + uint64_t receiveTimeoutInMs; + uint32_t interestLifetime; + int interestCounter; + size_t count; + uint64_t intervalInMs; + size_t payloadSize; + int nonce; +} CCNxPingClient; + +/** + * Create a new CCNxPortalFactory instance using a randomly generated identity saved to + * the specified keystore. + * + * @return A new CCNxPortalFactory instance which must eventually be released by calling ccnxPortalFactory_Release(). + */ +static CCNxPortalFactory *_setupClientPortalFactory(void) { + const char *keystoreName = "client.keystore"; + const char *keystorePassword = "keystore_password"; + const char *subjectName = "client"; + + return ccnxPingCommon_SetupPortalFactory(keystoreName, keystorePassword, subjectName); +} + +/** + * Release the references held by the `CCNxPingClient`. + */ +static bool _ccnxPingClient_Destructor(CCNxPingClient **clientPtr) { + CCNxPingClient *client = *clientPtr; + + if (client->factory != NULL) { + ccnxPortalFactory_Release(&(client->factory)); + } + if (client->portal != NULL) { + ccnxPortal_Release(&(client->portal)); + } + if (client->prefix != NULL) { + ccnxName_Release(&(client->prefix)); + } + if (client->stats != NULL) { + ccnxPingStats_Release(&client->stats); + } + return true; +} + +parcObject_Override(CCNxPingClient, PARCObject, .destructor = (PARCObjectDestructor *) _ccnxPingClient_Destructor); + +parcObject_ImplementAcquire(ccnxPingClient, CCNxPingClient); +parcObject_ImplementRelease(ccnxPingClient, CCNxPingClient); + +/** + * Create a new empty `CCNxPingClient` instance. + */ +static CCNxPingClient *ccnxPingClient_Create(void) { + CCNxPingClient *client = parcObject_CreateInstance(CCNxPingClient); + + client->stats = ccnxPingStats_Create(); + client->interestCounter = 100; + client->prefix = ccnxName_CreateFromCString(ccnxPing_DefaultPrefix); + client->receiveTimeoutInMs = ccnxPing_DefaultReceiveTimeoutInUs / 1000; + client->count = 10; + client->intervalInMs = 1000; + client->nonce = rand(); + client->numberOfOutstanding = 0; + client->interestLifetime = 4 * 1000; //4s + + return client; +} + +/** + * Get the next `CCNxName` to issue. Increment the interest counter + * for the client. + */ +static CCNxName *_ccnxPingClient_CreateNextName(CCNxPingClient *client) { + client->interestCounter++; + char *suffixBuffer = NULL; + + asprintf(&suffixBuffer, "%x", client->nonce); + CCNxName *name1 = ccnxName_ComposeNAME(client->prefix, suffixBuffer); + free(suffixBuffer); + + suffixBuffer = NULL; + asprintf(&suffixBuffer, "%u", (unsigned int) client->payloadSize); + CCNxName *name2 = ccnxName_ComposeNAME(name1, suffixBuffer); + free(suffixBuffer); + ccnxName_Release(&name1); + + suffixBuffer = NULL; + asprintf(&suffixBuffer, "%06lu", (long) client->interestCounter); + CCNxName *name3 = ccnxName_ComposeNAME(name2, suffixBuffer); + free(suffixBuffer); + ccnxName_Release(&name2); + + return name3; +} + +/** + * Convert a timeval struct to a single microsecond count. + */ +static uint64_t _ccnxPingClient_CurrentTimeInUs(PARCClock *clock) { + struct timeval currentTimeVal; + parcClock_GetTimeval(clock, ¤tTimeVal); + uint64_t microseconds = ((uint64_t) currentTimeVal.tv_sec) * 1000000 + currentTimeVal.tv_usec; + return microseconds; +} + +/** + * Run a single ping test. + */ +static void _ccnxPingClient_RunPing(CCNxPingClient *client, size_t totalPings) { + uint64_t delayInUs = client->intervalInMs * 1000; + uint64_t timeoutInUs = client->receiveTimeoutInMs * 1000; + PARCClock *clock = parcClock_Wallclock(); + + client->factory = _setupClientPortalFactory(); + client->portal = ccnxPortalFactory_CreatePortal(client->factory, ccnxPortalRTA_Message); + + size_t outstanding = 0; + + uint64_t nextPacketSendTime = 0; + uint64_t currentTimeInUs = 0; + + for (int pings = 0; pings < totalPings; pings++) { + + CCNxName *name; + CCNxInterest *interest; + CCNxMetaMessage *message; + + name = _ccnxPingClient_CreateNextName(client); + interest = ccnxInterest_CreateSimple(name); + message = ccnxMetaMessage_CreateFromInterest(interest); + ccnxInterest_SetLifetime(interest, client->interestLifetime); + + if (ccnxPortal_Send(client->portal, message, CCNxStackTimeout_Never)) { + currentTimeInUs = _ccnxPingClient_CurrentTimeInUs(clock); + nextPacketSendTime = currentTimeInUs + delayInUs; + + ccnxPingStats_RecordRequest(client->stats, name, currentTimeInUs); + } else { + printf("Error in sending\n"); + nextPacketSendTime = 0; + } + + ccnxMetaMessage_Release(&message); + ccnxInterest_Release(&interest); + outstanding++; + + /* Now wait for the responses and record their times + * First packet wait until its arrives or timeout + */ + currentTimeInUs = _ccnxPingClient_CurrentTimeInUs(clock); + uint64_t receiveDelay = timeoutInUs; + CCNxMetaMessage *response = ccnxPortal_Receive(client->portal, &receiveDelay); + + //Remove the timeout ping only if we are in the ping mode + if (response == NULL && (client->mode != CCNxPingClientMode_Flood)) { + ccnxPingStats_RecordLost(client->stats, name); + outstanding--; + } + ccnxName_Release(&name); + + /* Loop to handle content that arrives too late, that is after receiveDelay + * They will be just evicted from the hashtable and not considered in the + */ + while (response != NULL) { + printf("Received content\n"); + currentTimeInUs = _ccnxPingClient_CurrentTimeInUs(clock); + if (ccnxMetaMessage_IsContentObject(response)) { + CCNxContentObject *contentObject = ccnxMetaMessage_GetContentObject(response); + CCNxName *responseName = ccnxContentObject_GetName(contentObject); + bool existing; + uint64_t + delta = ccnxPingStats_RecordResponse(client->stats, responseName, currentTimeInUs, response, &existing); + // Only display output if we're in ping mode + if (client->mode == CCNxPingClientMode_PingPong && existing) { + size_t contentSize = parcBuffer_Remaining(ccnxContentObject_GetPayload(contentObject)); + char *nameString = ccnxName_ToString(responseName); + printf("%zu bytes from %s: time=%"PRIu64" us\n", contentSize, nameString, delta); + parcMemory_Deallocate(&nameString); + } + } + ccnxMetaMessage_Release(&response); + + outstanding--; + + currentTimeInUs = _ccnxPingClient_CurrentTimeInUs(clock); + + /* The following covers the case in which a content arrived after + * receiveDelay. If that happens, it will be read from the portal + * after the next interest sending, therefore we might have two + * contents to read rather than one. This code is fine as long as we + * do not consider in statistics content arriving after receiveDelay + */ + receiveDelay = nextPacketSendTime - currentTimeInUs; + response = ccnxPortal_Receive(client->portal, &receiveDelay); + } + } + + /* We're done with pings, so let's wait to see if we have any + * stragglers. We wait for 30s more + */ + currentTimeInUs = _ccnxPingClient_CurrentTimeInUs(clock); + nextPacketSendTime = currentTimeInUs + 10000000; //10s + + uint64_t receiveDelay = nextPacketSendTime - currentTimeInUs; + CCNxMetaMessage *response = ccnxPortal_Receive(client->portal, &receiveDelay); + + /* Loop to handle content that arrives too late, that is after receiveDelay + * They will be just evicted from the hashtable and not considered in the + */ + while (response != NULL) { + printf("Received content\n"); + currentTimeInUs = _ccnxPingClient_CurrentTimeInUs(clock); + if (ccnxMetaMessage_IsContentObject(response)) { + CCNxContentObject *contentObject = ccnxMetaMessage_GetContentObject(response); + CCNxName *responseName = ccnxContentObject_GetName(contentObject); + bool existing; + uint64_t delta = ccnxPingStats_RecordResponse(client->stats, responseName, currentTimeInUs, response, &existing); + // Only display output if we're in ping mode + if (client->mode == CCNxPingClientMode_PingPong && existing) { + size_t contentSize = parcBuffer_Remaining(ccnxContentObject_GetPayload(contentObject)); + char *nameString = ccnxName_ToString(responseName); + printf("%zu bytes from %s: time=%"PRIu64" us\n", contentSize, nameString, delta); + parcMemory_Deallocate(&nameString); + } + } + ccnxMetaMessage_Release(&response); + outstanding--; + currentTimeInUs = _ccnxPingClient_CurrentTimeInUs(clock); + /* The following covers the case in which a content arrived after + * receiveDelay. If that happens, it will be read from the portal + * after the next interest sending, therefore we might have two + * contents to read rather than one. This code is fine as long as we + * do not consider in statistics content arriving after receiveDelay + */ + receiveDelay = nextPacketSendTime - currentTimeInUs; + response = ccnxPortal_Receive(client->portal, &receiveDelay); + } + parcClock_Release(&clock); +} + +/** + * Display the usage message. + */ +static void _displayUsage(char *progName) { + printf("CCNx Simple Ping Performance Test\n"); + printf(" (you must have ccnxPing_Server running)\n"); + printf("\n"); + printf("Usage: %s -p [ -c count ] [ -s size ] [ -i interval ]\n", progName); + printf(" %s -f [ -c count ] [ -s size ]\n", progName); + printf(" %s -h\n", progName); + printf("\n"); + printf("Example:\n"); + printf(" ccnxPing_Client -l ccnx:/some/prefix -c 100 -f\n"); + printf("\n"); + printf("Options:\n"); + printf(" -h (--help) Show this help message\n"); + printf(" -p (--ping) ping mode - \n"); + printf( + " -f (--flood) flood mode - send as fast as possible. ATTENTION, NO MIGHT USE A LOT OF MEMORY IF THE NUMBER OF SENDING INTEREST IS HUGE\n"); + printf(" -c (--count) Number of count to run\n"); + printf( + " -i (--interval) Interval in milliseconds between interests in ping mode. Such interval cannot always be satisfied because in ping mode the application waits to receive a content before issuing the next interest. If any content is received interval==timeout\n"); + printf(" -s (--size) Size of the interests\n"); + printf(" -l (--locator) Set the locator for this server. The default is 'ccnx:/locator'. \n"); + printf( + " -t (--timeout) Time that the application waits for a content. When elapsed the content will be dropped and RTT not considered. Default timeout==1s\n"); + printf( + " -e (--lifetime) Set interest lifetime in milliseconds. When elapsed the interest is evicted only from the PIT. Eviction from the application internal state (used for recording interest sending time adn calculate RTT). Default lifetime==4s.\n"); +} + +/** + * Parse the command lines to initialize the state of the + */ +static bool _ccnxPingClient_ParseCommandline(CCNxPingClient *client, int argc, char *argv[argc]) { + static struct option longopts[] = + {{"ping", no_argument, NULL, 'p'}, {"flood", no_argument, NULL, 'f'}, {"count", required_argument, NULL, 'c'}, { + "size", required_argument, NULL, 's' + }, {"interval", required_argument, NULL, 'i'}, {"locator", required_argument, NULL, 'l'}, {"outstanding" + , required_argument + , NULL, 'o' + }, {"help", no_argument, NULL, 'h'}, {"timeout", required_argument, NULL, 't'}, {"lifetime", required_argument + , NULL, 'e' + }, {NULL, 0, NULL, 0}}; + + client->payloadSize = ccnxPing_DefaultPayloadSize; + + int c; + while ((c = getopt_long(argc, argv, "phfc:s:i:l:o:t:e:", longopts, NULL)) != -1) { + switch (c) { + case 'p': + if (client->mode != CCNxPingClientMode_None) { + return false; + } + client->mode = CCNxPingClientMode_PingPong; + break; + case 'f': + if (client->mode != CCNxPingClientMode_None) { + return false; + } + client->mode = CCNxPingClientMode_Flood; + client->intervalInMs = 0; + client->receiveTimeoutInMs = 0; + break; + case 'c': + sscanf(optarg, "%zu", &(client->count)); + break; + case 'i': + if (client->mode != CCNxPingClientMode_Flood) { + sscanf(optarg, "%"PRIu64"", &(client->intervalInMs)); + printf("Timer %"PRIu64"\n", (client->intervalInMs)); + } + break; + case 't': + if (client->mode != CCNxPingClientMode_Flood) { + sscanf(optarg, "%"PRIu64"", &(client->receiveTimeoutInMs)); + } + break; + case 's': + sscanf(optarg, "%zu", &(client->payloadSize)); + break; + case 'o': + sscanf(optarg, "%zu", &(client->numberOfOutstanding)); + break; + case 'l': + ccnxName_Release(&(client->prefix)); + client->prefix = ccnxName_CreateFromCString(optarg); + break; + case 'h': + _displayUsage(argv[0]); + return false; + case 'e': + sscanf(optarg, "%"PRIu32"", &(client->interestLifetime)); + break; + default: + break; + } + } + if (client->mode == CCNxPingClientMode_None) { + _displayUsage(argv[0]); + return false; + } + return true; +}; + +static void _ccnxPingClient_DisplayStatistics(CCNxPingClient *client) { + bool ableToCompute = ccnxPingStats_Display(client->stats); + if (!ableToCompute) { + parcDisplayIndented_PrintLine(0, + "No packets were received. Check to make sure the client and server are configured correctly and that the forwarder is running.\n"); + } +} + +static void _ccnxPingClient_RunPingormanceTest(CCNxPingClient *client) { + switch (client->mode) { + case CCNxPingClientMode_All: + _ccnxPingClient_RunPing(client, mediumNumberOfPings); + _ccnxPingClient_DisplayStatistics(client); + + ccnxPingStats_Release(&client->stats); + client->stats = ccnxPingStats_Create(); + + _ccnxPingClient_RunPing(client, smallNumberOfPings); + _ccnxPingClient_DisplayStatistics(client); + break; + case CCNxPingClientMode_Flood: + _ccnxPingClient_RunPing(client, client->count); + _ccnxPingClient_DisplayStatistics(client); + break; + case CCNxPingClientMode_PingPong: + _ccnxPingClient_RunPing(client, client->count); + _ccnxPingClient_DisplayStatistics(client); + break; + case CCNxPingClientMode_None: + default: + fprintf(stderr, "Error, unknown mode"); + break; + } +} + +int main(int argc, char *argv[argc]) { + parcSecurity_Init(); + CCNxPingClient *client = ccnxPingClient_Create(); + bool runPing = _ccnxPingClient_ParseCommandline(client, argc, argv); + if (runPing) { + _ccnxPingClient_RunPingormanceTest(client); + } + ccnxPingClient_Release(&client); + parcSecurity_Fini(); + return EXIT_SUCCESS; +} diff --git a/apps/iping/iPing_Common.c b/apps/iping/iPing_Common.c new file mode 100644 index 00000000..ec4fae69 --- /dev/null +++ b/apps/iping/iPing_Common.c @@ -0,0 +1,63 @@ +/* + * 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 <stdio.h> + +#include "iPing_Common.h" + +#include <parc/security/parc_Security.h> +#include <parc/security/parc_Pkcs12KeyStore.h> +#include <parc/security/parc_IdentityFile.h> + +const size_t ccnxPing_DefaultReceiveTimeoutInUs = 1000000; // 1 second +const size_t ccnxPing_DefaultPayloadSize = 4096; +const size_t mediumNumberOfPings = 100; +const size_t smallNumberOfPings = 10; + +static PARCIdentity *_ccnxPingCommon_CreateAndGetIdentity(const char *keystoreName, + const char *keystorePassword, + const char *subjectName) { + parcSecurity_Init(); + + unsigned int keyLength = 1024; + unsigned int validityDays = 30; + + bool success = parcPkcs12KeyStore_CreateFile(keystoreName, keystorePassword, subjectName, keyLength, validityDays); + assertTrue(success, + "parcPkcs12KeyStore_CreateFile('%s', '%s', '%s', %d, %d) failed.", + keystoreName, + keystorePassword, + subjectName, + keyLength, + validityDays); + + PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword); + PARCIdentity *result = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity); + parcIdentityFile_Release(&identityFile); + + parcSecurity_Fini(); + + return result; +} + +CCNxPortalFactory *ccnxPingCommon_SetupPortalFactory(const char *keystoreName, + const char *keystorePassword, + const char *subjectName) { + PARCIdentity *identity = _ccnxPingCommon_CreateAndGetIdentity(keystoreName, keystorePassword, subjectName); + CCNxPortalFactory *result = ccnxPortalFactory_Create(identity); + parcIdentity_Release(&identity); + + return result; +} diff --git a/apps/iping/iPing_Common.h b/apps/iping/iPing_Common.h new file mode 100644 index 00000000..1ffd15a1 --- /dev/null +++ b/apps/iping/iPing_Common.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#ifndef ccnxPingCommon_h +#define ccnxPingCommon_h + +#include <stdint.h> + +#include <ccnx/api/ccnx_Portal/ccnx_Portal.h> + +/** + * The `CCNxName` prefix for the server. + */ +#define ccnxPing_DefaultPrefix "ccnx:/localhost" + +/** + * The default client receive timeout (in microseconds). + */ +extern const size_t ccnxPing_DefaultReceiveTimeoutInUs; + +/** + * The default size of a content object payload. + */ +extern const size_t ccnxPing_DefaultPayloadSize; + +/** + * The maximum size of a content object payload. + * 64KB is the limit imposed by the packet structure + */ +#define ccnxPing_MaxPayloadSize 64000 + +/** + * A default "medium" number of messages to send. + */ +extern const size_t mediumNumberOfPings; + +/** + * A default "small" number of messages to send. + */ +extern const size_t smallNumberOfPings; + +/** + * Initialize and return a new instance of CCNxPortalFactory. A randomly generated identity is + * used to initialize the factory. The returned instance must eventually be released by calling + * ccnxPortalFactory_Release(). + * + * @param [in] keystoreName The name of the file to save the new identity. + * @param [in] keystorePassword The password of the file holding the identity. + * @param [in] subjectName The name of the owner of the identity. + * + * @return A new instance of a CCNxPortalFactory initialized with a randomly created identity. + */ +CCNxPortalFactory *ccnxPingCommon_SetupPortalFactory(const char *keystoreName, + const char *keystorePassword, + const char *subjectName); +#endif // ccnxPingCommon_h.h diff --git a/apps/iping/iPing_Server.c b/apps/iping/iPing_Server.c new file mode 100644 index 00000000..199823d5 --- /dev/null +++ b/apps/iping/iPing_Server.c @@ -0,0 +1,215 @@ +/* + * 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 <stdio.h> + +#include <getopt.h> + +#include <LongBow/runtime.h> + +#include <parc/algol/parc_Object.h> + +#include <parc/security/parc_Security.h> + +#include <ccnx/common/ccnx_Name.h> + +#include <ccnx/api/ccnx_Portal/ccnx_Portal.h> +#include <ccnx/api/ccnx_Portal/ccnx_PortalRTA.h> + +#include "iPing_Common.h" + +typedef struct ccnx_ping_server { + CCNxPortal *portal; + CCNxName *prefix; + size_t payloadSize; + + uint8_t generalPayload[ccnxPing_MaxPayloadSize]; +} CCNxPingServer; + +/** + * Create a new CCNxPortalFactory instance using a randomly generated identity saved to + * the specified keystore. + * + * @return A new CCNxPortalFactory instance which must eventually be released by calling ccnxPortalFactory_Release(). + */ +static CCNxPortalFactory *_setupServerPortalFactory(void) { + const char *keystoreName = "server.keystore"; + const char *keystorePassword = "keystore_password"; + const char *subjectName = "server"; + + return ccnxPingCommon_SetupPortalFactory(keystoreName, keystorePassword, subjectName); +} + +/** + * Release the references held by the `CCNxPingClient`. + */ +static bool _ccnxPingServer_Destructor(CCNxPingServer **serverPtr) { + CCNxPingServer *server = *serverPtr; + if (server->portal != NULL) { + ccnxPortal_Release(&(server->portal)); + } + if (server->prefix != NULL) { + ccnxName_Release(&(server->prefix)); + } + return true; +} + +parcObject_Override(CCNxPingServer, PARCObject, .destructor = (PARCObjectDestructor *) _ccnxPingServer_Destructor); + +parcObject_ImplementAcquire(ccnxPingServer, CCNxPingServer); +parcObject_ImplementRelease(ccnxPingServer, CCNxPingServer); + +/** + * Create a new empty `CCNxPingServer` instance. + */ +static CCNxPingServer *ccnxPingServer_Create(void) { + CCNxPingServer *server = parcObject_CreateInstance(CCNxPingServer); + + server->prefix = ccnxName_CreateFromCString(ccnxPing_DefaultPrefix); + server->payloadSize = ccnxPing_DefaultPayloadSize; + + return server; +} + +/** + * Create a `PARCBuffer` payload of the server-configured size. + */ +PARCBuffer *_ccnxPingServer_MakePayload(CCNxPingServer *server, int size) { + PARCBuffer *payload = parcBuffer_Wrap(server->generalPayload, size, 0, size); + return payload; +} + +/** + * Run the `CCNxPingServer` indefinitely. + */ +static void _ccnxPingServer_Run(CCNxPingServer *server) { + CCNxPortalFactory *factory = _setupServerPortalFactory(); + server->portal = ccnxPortalFactory_CreatePortal(factory, ccnxPortalRTA_Message); + ccnxPortalFactory_Release(&factory); + + size_t yearInSeconds = 60 * 60 * 24 * 365; + + size_t sizeIndex = ccnxName_GetSegmentCount(server->prefix) + 1; + + if (ccnxPortal_Listen(server->portal, server->prefix, yearInSeconds, CCNxStackTimeout_Never)) { + while (true) { + CCNxMetaMessage *request = ccnxPortal_Receive(server->portal, CCNxStackTimeout_Never); + + // This should never happen. + if (request == NULL) { + break; + } + + CCNxInterest *interest = ccnxMetaMessage_GetInterest(request); + if (interest != NULL) { + CCNxName *interestName = ccnxInterest_GetName(interest); + + // Extract the size of the payload response from the client + CCNxNameSegment *sizeSegment = ccnxName_GetSegment(interestName, sizeIndex); + char *segmentString = ccnxNameSegment_ToString(sizeSegment); + int size = atoi(segmentString); + size = size > ccnxPing_MaxPayloadSize ? ccnxPing_MaxPayloadSize : size; + + PARCBuffer *payload = _ccnxPingServer_MakePayload(server, size); + + CCNxContentObject *contentObject = ccnxContentObject_CreateWithNameAndPayload(interestName, payload); + CCNxMetaMessage *message = ccnxMetaMessage_CreateFromContentObject(contentObject); + + if (ccnxPortal_Send(server->portal, message, CCNxStackTimeout_Never) == false) { + fprintf(stderr, "ccnxPortal_Send failed: %d\n", ccnxPortal_GetError(server->portal)); + } + + parcMemory_Deallocate(&segmentString); + ccnxContentObject_Release(&contentObject); + ccnxMetaMessage_Release(&message); + parcBuffer_Release(&payload); + + } + ccnxMetaMessage_Release(&request); + } + } +} + +/** + * Display the usage message. + */ +static void _displayUsage(char *progName) { + printf("CCNx Simple Ping Performance Test\n"); + printf("\n"); + printf("Usage: %s [-l locator] [-s size] \n", progName); + printf(" %s -h\n", progName); + printf("\n"); + printf("Example:\n"); + printf(" ccnxPing_Server -l ccnx:/some/prefix -s 4096\n"); + printf("\n"); + printf("Options:\n"); + printf(" -h (--help) Show this help message\n"); + printf(" -l (--locator) Set the locator for this server. The default is 'ccnx:/locator'. \n"); + printf( + " -s (--size) Set the payload size (less than 64000 - see `ccnxPing_MaxPayloadSize` in ccnxPing_Common.h)\n"); +} + +/** + * Parse the command lines to initialize the state of the + */ +static bool _ccnxPingServer_ParseCommandline(CCNxPingServer *server, int argc, char *argv[argc]) { + static struct option longopts[] = + {{"locator", required_argument, NULL, 'l'}, {"size", required_argument, NULL, 's'}, {"help", no_argument, NULL + , 'h' + }, {NULL, 0, NULL, 0}}; + + // Default value + server->payloadSize = ccnxPing_MaxPayloadSize; + + int c; + while ((c = getopt_long(argc, argv, "l:s:h", longopts, NULL)) != -1) { + switch (c) { + case 'l': + server->prefix = ccnxName_CreateFromCString(optarg); + break; + case 's': + sscanf(optarg, "%zu", &(server->payloadSize)); + if (server->payloadSize > ccnxPing_MaxPayloadSize) { + _displayUsage(argv[0]); + return false; + } + break; + case 'h': + _displayUsage(argv[0]); + return false; + default: + break; + } + } + + return true; +}; + +int main(int argc, char *argv[argc]) { + parcSecurity_Init(); + + CCNxPingServer *server = ccnxPingServer_Create(); + bool runServer = _ccnxPingServer_ParseCommandline(server, argc, argv); + + if (runServer) { + _ccnxPingServer_Run(server); + } + + ccnxPingServer_Release(&server); + + parcSecurity_Fini(); + + return EXIT_SUCCESS; +} diff --git a/apps/iping/iPing_Stats.c b/apps/iping/iPing_Stats.c new file mode 100644 index 00000000..bf405294 --- /dev/null +++ b/apps/iping/iPing_Stats.c @@ -0,0 +1,139 @@ +/* + * 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 <stdio.h> + +#include <ccnx/common/ccnx_Name.h> +#include <ccnx/transport/common/transport_MetaMessage.h> + +#include <parc/algol/parc_HashMap.h> +#include <parc/algol/parc_DisplayIndented.h> + +#include "iPing_Stats.h" + +typedef struct ping_stats_entry { + uint64_t sendTimeInUs; + uint64_t rtt; + size_t size; + CCNxName *nameSent; +} CCNxPingStatsEntry; + +struct ping_stats { + uint64_t totalRtt; + size_t totalReceived; + size_t totalSent; + size_t totalLost; + PARCHashMap *pings; +}; + +static bool _ccnxPingStatsEntry_Destructor(CCNxPingStatsEntry **statsPtr) { + CCNxPingStatsEntry *entry = *statsPtr; + ccnxName_Release(&entry->nameSent); + + return true; +} + +static bool _ccnxPingStats_Destructor(CCNxPingStats **statsPtr) { + CCNxPingStats *stats = *statsPtr; + parcHashMap_Release(&stats->pings); + return true; +} + +parcObject_Override(CCNxPingStatsEntry, + PARCObject, + .destructor = (PARCObjectDestructor *) _ccnxPingStatsEntry_Destructor); + +parcObject_ImplementAcquire(ccnxPingStatsEntry, CCNxPingStatsEntry); +parcObject_ImplementRelease(ccnxPingStatsEntry, CCNxPingStatsEntry); + +CCNxPingStatsEntry *ccnxPingStatsEntry_Create() { + return parcObject_CreateInstance(CCNxPingStatsEntry); +} + +parcObject_Override(CCNxPingStats, PARCObject, .destructor = (PARCObjectDestructor *) _ccnxPingStats_Destructor); + +parcObject_ImplementAcquire(ccnxPingStats, CCNxPingStats); +parcObject_ImplementRelease(ccnxPingStats, CCNxPingStats); + +CCNxPingStats *ccnxPingStats_Create(void) { + CCNxPingStats *stats = parcObject_CreateInstance(CCNxPingStats); + + stats->pings = parcHashMap_Create(); + stats->totalSent = 0; + stats->totalReceived = 0; + stats->totalRtt = 0; + + return stats; +} + +void ccnxPingStats_RecordRequest(CCNxPingStats *stats, CCNxName *name, uint64_t currentTime) { + CCNxPingStatsEntry *entry = ccnxPingStatsEntry_Create(); + + entry->nameSent = ccnxName_Acquire(name); + entry->sendTimeInUs = currentTime; + + stats->totalSent++; + + char *nameString = ccnxName_ToString(name); + printf("Insert entry %s\n", nameString); + parcMemory_Deallocate(&nameString); + parcHashMap_Put(stats->pings, name, entry); +} + +uint64_t ccnxPingStats_RecordResponse(CCNxPingStats *stats, + CCNxName *nameResponse, + uint64_t currentTime, + CCNxMetaMessage *message, + bool *existing) { + CCNxPingStatsEntry *entry = (CCNxPingStatsEntry *) parcHashMap_Get(stats->pings, nameResponse); + if (entry != NULL) { + *existing = true; + stats->totalReceived++; + uint64_t rtt = currentTime - entry->sendTimeInUs; + stats->totalRtt += rtt; + ccnxPingStatsEntry_Release(&entry); + parcHashMap_Remove(stats->pings, nameResponse); + return rtt; + } else { + *existing = false; + char *nameString = ccnxName_ToString(nameResponse); + printf("No entry for name %s\n", nameString); + parcMemory_Deallocate(&nameString); + } + return 0; +} + +size_t ccnxPingStats_RecordLost(CCNxPingStats *stats, CCNxName *nameResponse) { + //size_t pingsReceived = stats->totalReceived + 1; + CCNxPingStatsEntry *entry = (CCNxPingStatsEntry *) parcHashMap_Get(stats->pings, nameResponse); + if (entry != NULL) { + stats->totalLost++; + ccnxPingStatsEntry_Release(&entry); + parcHashMap_Remove(stats->pings, nameResponse); + } + return 0; +} + +bool ccnxPingStats_Display(CCNxPingStats *stats) { + if (stats->totalReceived > 0) { + parcDisplayIndented_PrintLine(0, + "Sent = %zu : Received = %zu : AvgDelay %llu us", + stats->totalSent, + stats->totalReceived, + stats->totalRtt / stats->totalReceived); + return true; + } + return false; +} diff --git a/apps/iping/iPing_Stats.h b/apps/iping/iPing_Stats.h new file mode 100644 index 00000000..cf28aaf4 --- /dev/null +++ b/apps/iping/iPing_Stats.h @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#ifndef ccnxPing_Stats_h +#define ccnxPing_Stats_h + +/** + * Structure to collect and display the performance statistics. + */ +struct ping_stats; +typedef struct ping_stats CCNxPingStats; + +/** + * Create an empty `CCNxPingStats` instance. + * + * The returned result must be freed via {@link ccnxPingStats_Release} + * + * @return A newly allocated `CCNxPingStats`. + * + * Example + * @code + * { + * CCNxPingStats *stats = ccnxPingStats_Create(); + * } + * @endcode + */ +CCNxPingStats *ccnxPingStats_Create(void); + +/** + * Increase the number of references to a `CCNxPingStats`. + * + * Note that new `CCNxPingStats` is not created, + * only that the given `CCNxPingStats` reference count is incremented. + * Discard the reference by invoking `ccnxPingStats_Release`. + * + * @param [in] clock A pointer to a `CCNxPingStats` instance. + * + * @return The input `CCNxPingStats` pointer. + * + * Example: + * @code + * { + * CCNxPingStats *stats = ccnxPingStats_Create(); + * CCNxPingStats *copy = ccnxPingStats_Acquire(stats); + * ccnxPingStats_Release(&stats); + * ccnxPingStats_Release(©); + * } + * @endcode + */ +CCNxPingStats *ccnxPingStats_Acquire(const CCNxPingStats *stats); + +/** + * Release a previously acquired reference to the specified instance, + * decrementing the reference count for the instance. + * + * The pointer to the instance is set to NULL as a side-effect of this function. + * + * If the invocation causes the last reference to the instance to be released, + * the instance is deallocated and the instance's implementation will perform + * additional cleanup and release other privately held references. + * + * @param [in,out] clockPtr A pointer to a pointer to the instance to release. + * + * Example: + * @code + * { + * CCNxPingStats *stats = ccnxPingStats_Create(); + * CCNxPingStats *copy = ccnxPingStats_Acquire(stats); + * ccnxPingStats_Release(&stats); + * ccnxPingStats_Release(©); + * } + * @endcode + */ +void ccnxPingStats_Release(CCNxPingStats **statsPtr); + +/** + * Record the name and time for a request (e.g., interest). + * + * @param [in] stats The `CCNxPingStats` instance. + * @param [in] name The `CCNxName` name structure. + * @param [in] timeInUs The send time (in microseconds). + */ +void ccnxPingStats_RecordRequest(CCNxPingStats *stats, CCNxName *name, uint64_t timeInUs); + +/** + * Record the name and time for a response (e.g., content object). + * + * @param [in] stats The `CCNxPingStats` instance. + * @param [in] name The `CCNxName` name structure. + * @param [in] timeInUs The send time (in microseconds). + * @param [in] message The response `CCNxMetaMessage`. + * + * @return The delta between the request and response (in microseconds). + */ +uint64_t ccnxPingStats_RecordResponse(CCNxPingStats *stats, + CCNxName *name, + uint64_t timeInUs, + CCNxMetaMessage *message, + bool *existing); + +size_t ccnxPingStats_RecordLost(CCNxPingStats *stats, CCNxName *nameResponse); + +/** + * Display the average statistics stored in this `CCNxPingStats` instance. + * + * @param [in] stats The `CCNxPingStats` instance from which to draw the average data. + * + * @retval true If the stats were displayed correctly + * @retval false Otherwise + */ +bool ccnxPingStats_Display(CCNxPingStats *stats); +#endif // ccnxPing_Stats_h diff --git a/apps/producers/CMakeLists.txt b/apps/producers/CMakeLists.txt new file mode 100755 index 00000000..c478bf53 --- /dev/null +++ b/apps/producers/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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. + +cmake_minimum_required(VERSION 3.2) + + +set(PRODUCER_SOURCE_FILES + icnet_producer_test.cc) + +add_executable(producer-test ${PRODUCER_SOURCE_FILES}) +target_link_libraries(producer-test icnet ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +install(TARGETS producer-test DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/apps/producers/icnet_producer_test.cc b/apps/producers/icnet_producer_test.cc new file mode 100755 index 00000000..571e9615 --- /dev/null +++ b/apps/producers/icnet_producer_test.cc @@ -0,0 +1,163 @@ +/* + * 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_socket_producer.h" + +#define IDENTITY_NAME "ciao" + +namespace icnet { + +class CallbackContainer { + public: + CallbackContainer() : buffer_(1400, 'X') { + content_object_.setContent((uint8_t *) buffer_.c_str(), 1400); + } + + void processInterest(ProducerSocket &p, const Interest &interest) { + // std::cout << "Sending response to " << interest.getName() << std::endl; + } + + void processIncomingInterest(ProducerSocket &p, const Interest &interest) { + content_object_.setName(Name(interest.getName().getWrappedStructure())); + p.produce(content_object_); + } + private: + + ContentObject content_object_; + std::string buffer_; +}; + +class Signer { + public: + Signer() : counter_(0), identity_name_(IDENTITY_NAME) { + }; + + ~Signer() { + }; + + void onPacket(ProducerSocket &p, ContentObject &contentObject) { + counter_++; + KeyLocator kl; + contentObject.signWithSha256(kl); + } + + private: + int counter_; + Name identity_name_; +}; + +void becomeDaemon() { + pid_t process_id = 0; + pid_t sid = 0; + + // Create child process + process_id = fork(); + + // Indication of fork() failure + if (process_id < 0) { + printf("fork failed!\n"); + // Return failure in exit status + exit(EXIT_FAILURE); + } + + // PARENT PROCESS. Need to kill it. + if (process_id > 0) { + printf("process_id of child process %d \n", process_id); + // return success in exit status + exit(EXIT_SUCCESS); + } + + //unmask the file mode + umask(0); + + //set new session + sid = setsid(); + if (sid < 0) { + // Return failure + exit(EXIT_FAILURE); + } + + // Change the current working directory to root. + chdir("/"); + + // Close stdin. stdout and stderr + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + // Really start application +} + +int main(int argc, char **argv) { + std::string name = "ccnx:/ccnxtest"; + bool daemon = false; + + int opt; + while ((opt = getopt(argc, argv, "D")) != -1) { + + switch (opt) { + case 'D': + daemon = true; + break; + default: + exit(EXIT_FAILURE); + } + } + + if (argv[optind] == 0) { + std::cerr << "Using default name ccnx:/ccnxtest" << std::endl; + } else { + name = argv[optind]; + } + + if (daemon) { + becomeDaemon(); + } + + CallbackContainer stubs; + // Signer signer; + + std::cout << "Setting name.. " << name << std::endl; + + ProducerSocket p(Name(name.c_str())); + + p.setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, false); + + // setting callbacks + p.setSocketOption(ProducerCallbacksOptions::INTEREST_INPUT, + (ProducerInterestCallback) bind(&CallbackContainer::processIncomingInterest, + &stubs, + std::placeholders::_1, + std::placeholders::_2)); + + p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS, + (ProducerInterestCallback) bind(&CallbackContainer::processInterest, + &stubs, + std::placeholders::_1, + std::placeholders::_2)); + + p.attach(); + + p.serveForever(); + + return 0; +} + +} // end namespace icnet + +int main(int argc, char **argv) { + return icnet::main(argc, argv); +} + |