PingApp.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2001, 2003, 2004 Johnny Lai, Monash University, Melbourne, Australia
00003 // Copyright (C) 2005 Andras Varga
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public License
00016 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 #include <limits.h>
00020 #include <stdlib.h>
00021 #include <iostream>
00022 
00023 #include "IPAddressResolver.h"
00024 #include "PingApp.h"
00025 #include "PingPayload_m.h"
00026 #include "IPControlInfo.h"
00027 #include "IPv6ControlInfo.h"
00028 
00029 using std::cout;
00030 
00031 Define_Module(PingApp);
00032 
00033 void PingApp::initialize()
00034 {
00035     // read params
00036     // (defer reading srcAddr/destAddr to when ping starts, maybe
00037     // addresses will be assigned later by some protocol)
00038     packetSize = par("packetSize");
00039     intervalp = & par("interval");
00040     hopLimit = par("hopLimit");
00041     count = par("count");
00042     startTime = par("startTime");
00043     stopTime = par("stopTime");
00044     printPing = (bool)par("printPing");
00045 
00046     // state
00047     sendSeqNo = expectedReplySeqNo = 0;
00048     WATCH(sendSeqNo);
00049     WATCH(expectedReplySeqNo);
00050 
00051     // statistics
00052     delayStat.setName("pingRTT");
00053     delayVector.setName("pingRTT");
00054     dropVector.setName("pingDrop");
00055 
00056     dropCount = outOfOrderArrivalCount = 0;
00057     WATCH(dropCount);
00058     WATCH(outOfOrderArrivalCount);
00059 
00060     // schedule first ping (use empty destAddr or stopTime<=startTime to disable)
00061     if (par("destAddr").stringValue()[0] && (stopTime==0 || stopTime>=startTime))
00062     {
00063         cMessage *msg = new cMessage("sendPing");
00064         scheduleAt(startTime, msg);
00065     }
00066 }
00067 
00068 void PingApp::handleMessage(cMessage *msg)
00069 {
00070     if (msg->isSelfMessage())
00071     {
00072         // on first call we need to initialize
00073         if (destAddr.isUnspecified())
00074         {
00075             destAddr = IPAddressResolver().resolve(par("destAddr"));
00076             ASSERT(!destAddr.isUnspecified());
00077             srcAddr = IPAddressResolver().resolve(par("srcAddr"));
00078             EV << "Starting up: dest=" << destAddr << "  src=" << srcAddr << "\n";
00079         }
00080 
00081         // send a ping
00082         sendPing();
00083 
00084         // then schedule next one if needed
00085         scheduleNextPing(msg);
00086     }
00087     else
00088     {
00089         // process ping response
00090         processPingResponse(check_and_cast<PingPayload *>(msg));
00091     }
00092 }
00093 
00094 void PingApp::sendPing()
00095 {
00096     EV << "Sending ping #" << sendSeqNo << "\n";
00097 
00098     char name[32];
00099     sprintf(name,"ping%ld", sendSeqNo);
00100 
00101     PingPayload *msg = new PingPayload(name);
00102     msg->setOriginatorId(getId());
00103     msg->setSeqNo(sendSeqNo);
00104     msg->setByteLength(packetSize);
00105 
00106     sendToICMP(msg, destAddr, srcAddr, hopLimit);
00107 }
00108 
00109 void PingApp::scheduleNextPing(cMessage *timer)
00110 {
00111     simtime_t nextPing = simTime() + intervalp->doubleValue();
00112     sendSeqNo++;
00113     if ((count==0 || sendSeqNo<count) && (stopTime==0 || nextPing<stopTime))
00114         scheduleAt(nextPing, timer);
00115     else
00116         delete timer;
00117 }
00118 
00119 void PingApp::sendToICMP(cMessage *msg, const IPvXAddress& destAddr, const IPvXAddress& srcAddr, int hopLimit)
00120 {
00121     if (!destAddr.isIPv6())
00122     {
00123         // send to IPv4
00124         IPControlInfo *ctrl = new IPControlInfo();
00125         ctrl->setSrcAddr(srcAddr.get4());
00126         ctrl->setDestAddr(destAddr.get4());
00127         ctrl->setTimeToLive(hopLimit);
00128         msg->setControlInfo(ctrl);
00129         send(msg, "pingOut");
00130     }
00131     else
00132     {
00133         // send to IPv6
00134         IPv6ControlInfo *ctrl = new IPv6ControlInfo();
00135         ctrl->setSrcAddr(srcAddr.get6());
00136         ctrl->setDestAddr(destAddr.get6());
00137         ctrl->setHopLimit(hopLimit);
00138         msg->setControlInfo(ctrl);
00139         send(msg, "pingv6Out");
00140     }
00141 }
00142 
00143 void PingApp::processPingResponse(PingPayload *msg)
00144 {
00145     // get src, hopCount etc from packet, and print them
00146     IPvXAddress src, dest;
00147     int msgHopCount = -1;
00148     if (dynamic_cast<IPControlInfo *>(msg->getControlInfo())!=NULL)
00149     {
00150         IPControlInfo *ctrl = (IPControlInfo *)msg->getControlInfo();
00151         src = ctrl->getSrcAddr();
00152         dest = ctrl->getDestAddr();
00153         msgHopCount = ctrl->getTimeToLive();
00154     }
00155     else if (dynamic_cast<IPv6ControlInfo *>(msg->getControlInfo())!=NULL)
00156     {
00157         IPv6ControlInfo *ctrl = (IPv6ControlInfo *)msg->getControlInfo();
00158         src = ctrl->getSrcAddr();
00159         dest = ctrl->getDestAddr();
00160         msgHopCount = ctrl->getHopLimit();
00161     }
00162 
00163     simtime_t rtt = simTime() - msg->getCreationTime();
00164 
00165     if (printPing)
00166     {
00167         cout << getFullPath() << ": reply of " << std::dec << msg->getByteLength()
00168              << " bytes from " << src
00169              << " icmp_seq=" << msg->getSeqNo() << " ttl=" << msgHopCount
00170              << " time=" << (rtt * 1000) << " msec"
00171              << " (" << msg->getName() << ")" << endl;
00172     }
00173 
00174     // update statistics
00175     countPingResponse(msg->getByteLength(), msg->getSeqNo(), rtt);
00176     delete msg;
00177 }
00178 
00179 void PingApp::countPingResponse(int bytes, long seqNo, simtime_t rtt)
00180 {
00181     EV << "Ping reply #" << seqNo << " arrived, rtt=" << rtt << "\n";
00182 
00183     delayStat.collect(rtt);
00184     delayVector.record(rtt);
00185 
00186     if (seqNo == expectedReplySeqNo)
00187     {
00188         // expected ping reply arrived; expect next sequence number
00189         expectedReplySeqNo++;
00190     }
00191     else if (seqNo > expectedReplySeqNo)
00192     {
00193         EV << "Jump in seq numbers, assuming pings since #" << expectedReplySeqNo << " got lost\n";
00194 
00195         // jump in the sequence: count pings in gap as lost
00196         long jump = seqNo - expectedReplySeqNo;
00197         dropCount += jump;
00198         dropVector.record(dropCount);
00199 
00200         // expect sequence numbers to continue from here
00201         expectedReplySeqNo = seqNo+1;
00202     }
00203     else // seqNo < expectedReplySeqNo
00204     {
00205         // ping arrived too late: count as out of order arrival
00206         EV << "Arrived out of order (too late)\n";
00207         outOfOrderArrivalCount++;
00208     }
00209 }
00210 
00211 void PingApp::finish()
00212 {
00213     if (sendSeqNo==0)
00214     {
00215         EV << getFullPath() << ": No pings sent, skipping recording statistics and printing results.\n";
00216         recordScalar("Pings sent", sendSeqNo);
00217         return;
00218     }
00219 
00220     // record statistics
00221     recordScalar("Pings sent", sendSeqNo);
00222     recordScalar("Pings dropped", dropCount);
00223     recordScalar("Out-of-order ping arrivals", outOfOrderArrivalCount);
00224     recordScalar("Pings outstanding at end", sendSeqNo-expectedReplySeqNo);
00225 
00226     recordScalar("Ping drop rate (%)", 100 * dropCount / (double)sendSeqNo);
00227     recordScalar("Ping out-of-order rate (%)", 100 * outOfOrderArrivalCount / (double)sendSeqNo);
00228 
00229     delayStat.recordAs("Ping roundtrip delays");
00230 
00231     // print it to stdout as well
00232     cout << "--------------------------------------------------------" << endl;
00233     cout << "\t" << getFullPath() << endl;
00234     cout << "--------------------------------------------------------" << endl;
00235 
00236     cout << "sent: " << sendSeqNo
00237          << "   drop rate (%): " << (100 * dropCount / (double)sendSeqNo) << endl;
00238     cout << "round-trip min/avg/max (ms): "
00239          << (delayStat.getMin()*1000.0) << "/"
00240          << (delayStat.getMean()*1000.0) << "/"
00241          << (delayStat.getMax()*1000.0) << endl;
00242     cout << "stddev (ms): "<< (delayStat.getStddev()*1000.0)
00243          << "   variance:" << delayStat.getVariance() << endl;
00244     cout <<"--------------------------------------------------------" << endl;
00245 }
00246 
00247