Base Framework
testsuite/ping.cpp
/***************************************************************************
The Base Framework
A framework for developing platform independent applications
See COPYRIGHT.txt for details.
This framework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For the licensing terms refer to the file 'LICENSE'.
***************************************************************************/
#include <base/Application.h>
#include <base/Timer.h>
#include <base/UnsignedInteger.h>
#include <base/math/Math.h>
#include <base/net/StreamSocket.h>
#include <base/net/InetInterface.h>
#include <base/net/InetService.h>
#include <base/net/InetEndPoint.h>
#include <base/concurrency/Thread.h>
#include <base/string/FormatOutputStream.h>
#include <base/string/StringOutputStream.h>
using namespace com::azure::dev::base;
class PingApplication : public Application {
private:
static const unsigned int MAJOR_VERSION = 1;
static const unsigned int MINOR_VERSION = 0;
static const unsigned short ECHO_SERVICE_PORT = 7;
unsigned short port = 0;
unsigned int dataSize = 0;
unsigned int timeout = 0;
unsigned int packetsToTransmit = 0;
enum Command {
COMMAND_HELP,
COMMAND_VERSION,
COMMAND_PING
};
public:
PingApplication()
: Application("ping")
{
port = ECHO_SERVICE_PORT;
dataSize = 32;
timeout = 1000000;
packetsToTransmit = 0;
}
void onTermination() noexcept {
}
String getTimeAsString2(uint64 microseconds) noexcept {
return Literal("");
}
String getTimeAsString(uint64 microseconds) noexcept {
if (microseconds < 1000) {
stream << microseconds << "us";
} else if (microseconds < 1000000) {
stream << FIXED
<< setPrecision(3) << microseconds/1000.0 << "ms";
} else {
stream << FIXED
<< setPrecision(3) << microseconds/1000000.0 << "s";
}
stream << FLUSH;
return stream.getString();
}
void ping(const String& host) noexcept {
bool byName = true;
InetAddress address;
// if (InetAddress.isIPAddress(host)) {
// address = InetAddress(host);
// byName = false;
// }
try {
address = InetAddress::getAddressByName(host); // the address of the remote host
} catch (HostNotFound&) {
ferr << "Error: " << "Unable to resolve host." << ENDL;
setExitCode(EXIT_CODE_ERROR);
return;
}
String name = host;
try {
name = address.getHostName(true);
} catch (...) {
}
if (byName) {
fout << "Pinging " << name << ' ' << '(' << address << ')' << " with "
<< dataSize << " bytes of data" << EOL
<< ENDL;
} else {
fout << "Pinging " << ' ' << '(' << address << ')' << " with "
<< dataSize << " bytes of data" << EOL
<< ENDL;
}
InetEndPoint endPoint(address, port);
StreamSocket socket;
try {
socket.connect(endPoint.getAddress(), endPoint.getPort());
} catch (IOException&) {
ferr << "Error: " << "Unable to connect." << ENDL;
setExitCode(EXIT_CODE_ERROR);
return;
}
socket.setReceiveBufferSize(dataSize);
socket.setSendBufferSize(dataSize);
socket.setTcpNoDelay(true);
Timer timeoutTimer;
Timer timer;
unsigned int packetsTransmitted = 0;
unsigned int packetsReceived = 0;
uint64 minimumTime = PrimitiveTraits<uint64>::MAXIMUM;
uint64 maximumTime = 0;
uint64 totalTime = 0;
Allocator<uint8> outgoing(dataSize);
Allocator<uint8> incoming(dataSize);
fill<uint8>(outgoing.getElements(), outgoing.getSize(), 0);
while (!isTerminated() &&
((packetsToTransmit == 0) ||
(packetsTransmitted < packetsToTransmit))) {
uint8* dest = outgoing.getElements();
*dest++ = packetsTransmitted;
timeoutTimer.start();
timer.start();
socket.write(outgoing.getElements(), outgoing.getSize());
++packetsTransmitted;
socket.wait(timeout); // minimum(250, timeout)
// TAG: use timer to check for timeout
unsigned int bytesAvailable = socket.available();
if (bytesAvailable < incoming.getSize()) {
fout << name << ' ' << '(' << address << ')'
<< ':' << " request timed out" << ENDL;
} else {
timer.stop();
minimumTime = minimum(minimumTime, timer.getMicroseconds());
maximumTime = maximum(maximumTime, timer.getMicroseconds());
totalTime += timer.getMicroseconds();
while (bytesAvailable >= incoming.getSize()) {
socket.read(incoming.getElements(), incoming.getSize());
if (compare(incoming.getElements(), outgoing.getElements(), dataSize) == 0) {
++packetsReceived;
fout << incoming.getSize()
<< " bytes from " << name << ' '
<< '(' << address << ')' << ':' << ' '
<< "n=" << packetsReceived << ' '
<< "time=" << getTimeAsString(timer.getMicroseconds())
<< ENDL;
break;
}
}
}
timeoutTimer.stop();
if (timeoutTimer.getMicroseconds() < timeout) {
Thread::microsleep(timeout - timeoutTimer.getMicroseconds());
}
}
socket.close();
unsigned int packetsLost = packetsTransmitted - packetsReceived;
double meanTime = (packetsReceived > 0) ? totalTime/packetsReceived : 0;
fout << EOL
<< "--- statistics for " << name << " ---" << EOL
<< "Packets transmitted: " << packetsTransmitted << EOL
<< "Packets received: " << packetsReceived << EOL
<< "Packets lost: " << packetsLost << ' '
<< '(' << static_cast<int>((packetsTransmitted > 0) ? (100*packetsLost/packetsTransmitted) : 0) << '%' << ')' << EOL
<< "Time minimum/maximum/mean: "
<< getTimeAsString(minimumTime) << '/'
<< getTimeAsString(maximumTime) << '/'
<< getTimeAsString(static_cast<uint64>(meanTime)) << EOL
<< ENDL;
}
void version() noexcept
{
fout << getFormalName() << " version "
<< MAJOR_VERSION << '.' << MINOR_VERSION << EOL
<< "The Base Framework (Test Suite)" << EOL
<< ENDL;
}
void help() noexcept
{
version();
fout << getFormalName()
<< " [--help] [--port PORT] [--data SIZE] [--time MS] host" << ENDL;
}
void main()
{
Command command = COMMAND_PING;
String host;
const Array<String> arguments = getArguments();
if (arguments.getSize() > 0) {
while (enu.hasNext()) {
String argument = enu.next();
if (argument == "--help") {
command = COMMAND_HELP;
break;
} else if (argument == "--version") {
command = COMMAND_VERSION;
break;
} else if (argument == "--port") {
String temp = enu.next();
try {
UnsignedInteger value(temp);
if (value > 0xffff) {
ferr << "Error: " << "Invalid port" << ENDL;
setExitCode(EXIT_CODE_ERROR);
return;
}
port = value;
} catch (InvalidFormat&) {
try {
InetService service(temp);
port = service.getPort();
} catch (ServiceNotFound& e) {
ferr << "Error: " << e.getMessage() << ENDL;
setExitCode(EXIT_CODE_ERROR);
return;
}
}
} else {
host = argument;
}
}
}
if (host.isEmpty()) {
ferr << "Error: " << "Host not specified" << ENDL;
setExitCode(EXIT_CODE_ERROR);
return;
}
switch (command) {
case COMMAND_HELP:
help();
break;
case COMMAND_VERSION:
version();
break;
case COMMAND_PING:
ping(host);
break;
}
}
};
APPLICATION_STUB(PingApplication);
ServiceNotFound
Internet Protocol service exception.
Definition: ServiceNotFound.h:28
InetEndPoint
Internet end point.
Definition: InetEndPoint.h:30
IOException
IO exception.
Definition: IOException.h:32
StreamSocket::available
unsigned int available() const
Definition: StreamSocket.h:352
InetAddress::getAddressByName
static InetAddress getAddressByName(const String &name)
Timer::getMicroseconds
uint64 getMicroseconds() const noexcept
Definition: Timer.h:317
StreamSocket::close
void close()
Definition: StreamSocket.h:116
StreamSocket::connect
void connect(const InetAddress &address, unsigned short port)
Definition: StreamSocket.h:127
Allocator< uint8 >
StreamSocket::write
unsigned int write(const uint8 *buffer, unsigned int size, bool nonblocking=false)
Definition: StreamSocket.h:380
InetAddress::getHostName
String getHostName(bool fullyQualified=false) const
Literal
A string literal.
Definition: Literal.h:28
StreamSocket::setTcpNoDelay
void setTcpNoDelay(bool value)
Definition: StreamSocket.h:317
InetEndPoint::getAddress
const InetAddress & getAddress() const noexcept
Definition: InetEndPoint.h:130
StreamSocket
Stream socket.
Definition: StreamSocket.h:33
PrimitiveTraits
Provides information for a primitive type.
Definition: Primitives.h:630
StreamSocket::setSendBufferSize
void setSendBufferSize(int size)
Definition: StreamSocket.h:301
UnsignedInteger
Unsigned integer.
Definition: UnsignedInteger.h:31
String
String.
Definition: String.h:102
Allocator::getSize
MemorySize getSize() const noexcept
Definition: Allocator.h:533
StringOutputStream
String output stream.
Definition: StringOutputStream.h:86
String::isEmpty
bool isEmpty() const noexcept
Definition: String.h:518
Array::getSize
MemorySize getSize() const noexcept
Definition: Array.h:339
InvalidFormat
Invalid formation exception.
Definition: InvalidFormat.h:29
Thread::microsleep
static void microsleep(unsigned int microseconds)
Allocator::getElements
TYPE * getElements() noexcept
Definition: Allocator.h:427
Timer::stop
void stop() noexcept
Definition: Timer.h:293
Application
Application.
Definition: Application.h:53
StringOutputStream::getString
const String & getString() const
StreamSocket::wait
void wait() const
Definition: StreamSocket.h:391
StreamSocket::setReceiveBufferSize
void setReceiveBufferSize(int size)
Definition: StreamSocket.h:285
Timer::start
void start() noexcept
Definition: Timer.h:285
Timer
Timer.
Definition: Timer.h:27
Array::getReadEnumerator
ReadEnumerator getReadEnumerator() const noexcept
Definition: Array.h:489
StreamSocket::read
unsigned int read(uint8 *buffer, unsigned int size, bool nonblocking=false)
Definition: StreamSocket.h:365
InetEndPoint::getPort
static unsigned short getPort(const String &service)
Array< String >
HostNotFound
Host not found exception.
Definition: HostNotFound.h:28
InetService
Internet Protocol service.
Definition: InetService.h:31
InetAddress
Internet Protocol address.
Definition: InetAddress.h:38
Exception::getMessage
const char * getMessage() const noexcept
Definition: Exception.h:234
InetService::getPort
unsigned short getPort() const noexcept