/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * @file * @brief implementation file for the ping subcommand of the cmscli application * @author Dominik Meyer * @date 2019-01-07 * @copyright 2019 no yet defined */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __MINGW64__ #include #endif /// variable for stopping sending pings bool running=true; /* * signal handler for Ctrl-C */ #ifdef __MINGW64__ BOOL WINAPI killHandlerPing(DWORD dwType) { switch(dwType) { case CTRL_C_EVENT: running=false; break; case CTRL_BREAK_EVENT: running=false; break; default: printf("Some other event\n"); } return TRUE; } #else void killHandlerPing(int s){ if (s == SIGINT) { running=false; } } #endif /** * @brief receiver for pong messages */ class pongReceiver : public BC::receiveable { private: /// last received sequence number for identifying missing messages uint64_t lastSequenceNumber=0; /// number of missing messages uint32_t missing; public: /** * @brief constructor for initializing member attributes */ pongReceiver() : lastSequenceNumber(0), missing(0), transmitted(0),nrMessages(0) {} /// number of transmitted messages uint64_t transmitted; /// number of received messages uint32_t nrMessages; /// callback for receiving messages void receive(BC::Message *m) override { BC::Payloads::Pong pong(m->getRawData()); nrMessages++; if (lastSequenceNumber > 0 && pong.sequenceNr != lastSequenceNumber ) { missing++; } //claculate latency float latency = (float) (m->receptionTime - pong.pingTransmissionTime)/ (float)1000000.0; std::cout << m->size() << " bytes from " << m->sourceID<<": seq="<< pong.sequenceNr << " time=" << std::setprecision(3) << latency << " ms" << std::endl; } }; /** * @brief function implemting the ping subcommand */ void BCCLI::ping(const std::string &broadcastAddress, const std::string &srcAddress, unsigned short port, BC::DataTypes::deviceIdType dest) { // die if no destination is given if (dest == 0) { std::cerr << "Fatal Error: a valid destination address is mandatory" << std::endl; throw(CLI::RuntimeError(-1)); } // initialize the signal handler #ifdef __MINGW64__ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)killHandlerPing,TRUE)) { return; } #else struct sigaction sigIntHandler; sigIntHandler.sa_handler = killHandlerPing; sigemptyset(&sigIntHandler.sa_mask); sigIntHandler.sa_flags = 0; sigaction(SIGINT, &sigIntHandler, NULL); #endif // fetch us required random number device std::random_device rd; std::mt19937 mt(rd()); // set the distribution range of the numbers std::uniform_int_distribution dist(UINT16_MAX, UINT32_MAX); // instantiate a receiver pongReceiver pR; // create a service to send pings and receive pongs BC::SimpleServiceUDP service(dist(mt), BC::DataTypes::deviceMajorType::UNKNOWN, "bccli ping service",port, broadcastAddress, srcAddress); // subscribe to pong messages only service.subscribe(&pR,BC::Constants::cManagementDomain,BC::Constants::cPong); service.connect(); // create the base ping message BC::Message msg; msg.domain=BC::Constants::cManagementDomain; msg.topic=BC::Constants::cPing; msg.destinationID=dest; BC::Payloads::Ping ping; msg.setData(ping); std::cout << "ping " << dest << " " << msg.size() << " bytes of data" << std::endl; int seq=0; while(running) { // update ping message and payload ping.sequenceNr=seq; std::chrono::time_point now = std::chrono::high_resolution_clock::now(); ping.pingTime=std::chrono::duration_cast(now.time_since_epoch()).count(); msg.setData(ping); // publish message service.publish(msg); pR.transmitted++; std::this_thread::sleep_for(std::chrono::milliseconds(500)); seq++; } service.disconnect(); std::cout << "--- " << dest << " ping statistics ---" << std::endl; std::cout << pR.transmitted << " messages transmitted, " << pR.nrMessages << " received " << std::endl; }