git-subtree-dir: libs/CommService git-subtree-split: 7ccc0fce88bbc5969df060058cf0fb57abe3bcf9
180 lines
4.6 KiB
C++
180 lines
4.6 KiB
C++
/* 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 <dmeyer@hsu-hh.de>
|
|
* @date 2019-01-07
|
|
* @copyright 2019 no yet defined
|
|
*/
|
|
#include <CLI/CLI.hpp>
|
|
#include <ping/ping.hpp>
|
|
#include <BC/BC.hpp>
|
|
#include <BC/SimpleServiceUDP.hpp>
|
|
#include <BC/Message.hpp>
|
|
#include <BC/Payloads/Ping.hpp>
|
|
#include <BC/Payloads/Pong.hpp>
|
|
#include <BC/receiveable.hpp>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <chrono>
|
|
#include <random>
|
|
#include <cstdint>
|
|
#include <iomanip>
|
|
#include <signal.h>
|
|
|
|
#ifdef __MINGW64__
|
|
#include <windows.h>
|
|
#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<uint64_t> 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<std::chrono::high_resolution_clock> now = std::chrono::high_resolution_clock::now();
|
|
ping.pingTime=std::chrono::duration_cast<std::chrono::nanoseconds>(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;
|
|
}
|