|
INET Framework for OMNeT++/OMNEST
|
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 = numPongs = 0; 00057 WATCH(dropCount); 00058 WATCH(outOfOrderArrivalCount); 00059 WATCH(numPongs); 00060 00061 // schedule first ping (use empty destAddr or stopTime<=startTime to disable) 00062 if (par("destAddr").stringValue()[0] && (stopTime==0 || stopTime>=startTime)) 00063 { 00064 cMessage *msg = new cMessage("sendPing"); 00065 scheduleAt(startTime, msg); 00066 } 00067 } 00068 00069 void PingApp::handleMessage(cMessage *msg) 00070 { 00071 if (msg->isSelfMessage()) 00072 { 00073 // on first call we need to initialize 00074 if (destAddr.isUnspecified()) 00075 { 00076 destAddr = IPAddressResolver().resolve(par("destAddr")); 00077 ASSERT(!destAddr.isUnspecified()); 00078 srcAddr = IPAddressResolver().resolve(par("srcAddr")); 00079 EV << "Starting up: dest=" << destAddr << " src=" << srcAddr << "\n"; 00080 } 00081 00082 // send a ping 00083 sendPing(); 00084 00085 // then schedule next one if needed 00086 scheduleNextPing(msg); 00087 } 00088 else 00089 { 00090 // process ping response 00091 processPingResponse(check_and_cast<PingPayload *>(msg)); 00092 } 00093 } 00094 00095 void PingApp::sendPing() 00096 { 00097 EV << "Sending ping #" << sendSeqNo << "\n"; 00098 00099 char name[32]; 00100 sprintf(name,"ping%ld", sendSeqNo); 00101 00102 PingPayload *msg = new PingPayload(name); 00103 msg->setOriginatorId(getId()); 00104 msg->setSeqNo(sendSeqNo); 00105 msg->setByteLength(packetSize); 00106 00107 sendToICMP(msg, destAddr, srcAddr, hopLimit); 00108 } 00109 00110 void PingApp::scheduleNextPing(cMessage *timer) 00111 { 00112 simtime_t nextPing = simTime() + intervalp->doubleValue(); 00113 sendSeqNo++; 00114 if ((count==0 || sendSeqNo<count) && (stopTime==0 || nextPing<stopTime)) 00115 scheduleAt(nextPing, timer); 00116 else 00117 delete timer; 00118 } 00119 00120 void PingApp::sendToICMP(cMessage *msg, const IPvXAddress& destAddr, const IPvXAddress& srcAddr, int hopLimit) 00121 { 00122 if (!destAddr.isIPv6()) 00123 { 00124 // send to IPv4 00125 IPControlInfo *ctrl = new IPControlInfo(); 00126 ctrl->setSrcAddr(srcAddr.get4()); 00127 ctrl->setDestAddr(destAddr.get4()); 00128 ctrl->setTimeToLive(hopLimit); 00129 msg->setControlInfo(ctrl); 00130 send(msg, "pingOut"); 00131 } 00132 else 00133 { 00134 // send to IPv6 00135 IPv6ControlInfo *ctrl = new IPv6ControlInfo(); 00136 ctrl->setSrcAddr(srcAddr.get6()); 00137 ctrl->setDestAddr(destAddr.get6()); 00138 ctrl->setHopLimit(hopLimit); 00139 msg->setControlInfo(ctrl); 00140 send(msg, "pingv6Out"); 00141 } 00142 } 00143 00144 void PingApp::processPingResponse(PingPayload *msg) 00145 { 00146 // get src, hopCount etc from packet, and print them 00147 IPvXAddress src, dest; 00148 int msgHopCount = -1; 00149 if (dynamic_cast<IPControlInfo *>(msg->getControlInfo())!=NULL) 00150 { 00151 IPControlInfo *ctrl = (IPControlInfo *)msg->getControlInfo(); 00152 src = ctrl->getSrcAddr(); 00153 dest = ctrl->getDestAddr(); 00154 msgHopCount = ctrl->getTimeToLive(); 00155 } 00156 else if (dynamic_cast<IPv6ControlInfo *>(msg->getControlInfo())!=NULL) 00157 { 00158 IPv6ControlInfo *ctrl = (IPv6ControlInfo *)msg->getControlInfo(); 00159 src = ctrl->getSrcAddr(); 00160 dest = ctrl->getDestAddr(); 00161 msgHopCount = ctrl->getHopLimit(); 00162 } 00163 00164 simtime_t rtt = simTime() - msg->getCreationTime(); 00165 00166 if (printPing) 00167 { 00168 cout << getFullPath() << ": reply of " << std::dec << msg->getByteLength() 00169 << " bytes from " << src 00170 << " icmp_seq=" << msg->getSeqNo() << " ttl=" << msgHopCount 00171 << " time=" << (rtt * 1000) << " msec" 00172 << " (" << msg->getName() << ")" << endl; 00173 } 00174 00175 // update statistics 00176 countPingResponse(msg->getByteLength(), msg->getSeqNo(), rtt); 00177 delete msg; 00178 } 00179 00180 void PingApp::countPingResponse(int bytes, long seqNo, simtime_t rtt) 00181 { 00182 EV << "Ping reply #" << seqNo << " arrived, rtt=" << rtt << "\n"; 00183 00184 numPongs++; 00185 00186 delayStat.collect(rtt); 00187 delayVector.record(rtt); 00188 00189 if (seqNo == expectedReplySeqNo) 00190 { 00191 // expected ping reply arrived; expect next sequence number 00192 expectedReplySeqNo++; 00193 } 00194 else if (seqNo > expectedReplySeqNo) 00195 { 00196 EV << "Jump in seq numbers, assuming pings since #" << expectedReplySeqNo << " got lost\n"; 00197 00198 // jump in the sequence: count pings in gap as lost 00199 long jump = seqNo - expectedReplySeqNo; 00200 dropCount += jump; 00201 dropVector.record(dropCount); 00202 00203 // expect sequence numbers to continue from here 00204 expectedReplySeqNo = seqNo+1; 00205 } 00206 else // seqNo < expectedReplySeqNo 00207 { 00208 // ping arrived too late: count as out of order arrival 00209 EV << "Arrived out of order (too late)\n"; 00210 outOfOrderArrivalCount++; 00211 } 00212 } 00213 00214 void PingApp::finish() 00215 { 00216 if (sendSeqNo==0) 00217 { 00218 if (printPing) 00219 EV << getFullPath() << ": No pings sent, skipping recording statistics and printing results.\n"; 00220 recordScalar("Pings sent", sendSeqNo); 00221 return; 00222 } 00223 00224 // record statistics 00225 recordScalar("Pings sent", sendSeqNo); 00226 recordScalar("Pings dropped", dropCount); 00227 recordScalar("Out-of-order ping arrivals", outOfOrderArrivalCount); 00228 recordScalar("Pings outstanding at end", sendSeqNo-expectedReplySeqNo); 00229 00230 recordScalar("Ping drop rate (%)", 100 * dropCount / (double)sendSeqNo); 00231 recordScalar("Ping out-of-order rate (%)", 100 * outOfOrderArrivalCount / (double)sendSeqNo); 00232 00233 delayStat.recordAs("Ping roundtrip delays"); 00234 00235 // print it to stdout as well 00236 if (printPing) 00237 { 00238 cout << "--------------------------------------------------------" << endl; 00239 cout << "\t" << getFullPath() << endl; 00240 cout << "--------------------------------------------------------" << endl; 00241 00242 cout << "sent: " << sendSeqNo 00243 << " drop rate (%): " << (100 * dropCount / (double)sendSeqNo) << endl; 00244 cout << "round-trip min/avg/max (ms): " 00245 << (delayStat.getMin()*1000.0) << "/" 00246 << (delayStat.getMean()*1000.0) << "/" 00247 << (delayStat.getMax()*1000.0) << endl; 00248 cout << "stddev (ms): "<< (delayStat.getStddev()*1000.0) 00249 << " variance:" << delayStat.getVariance() << endl; 00250 cout <<"--------------------------------------------------------" << endl; 00251 } 00252 } 00253 00254