modules/up/src/Core/network/ICMProbe.cc

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. icmprobeTimerHandler
  2. ICMProbe
  3. ICMProbe
  4. send
  5. handleTimer
  6. receive

   1 //
   2 // $Id: ICMProbe.cc,v 1.1.1.1 2000/03/10 16:32:19 engin Exp $
   3 //
   4 // Author(s): Ramesh Govindan
   5 
   6 #ifdef HAVE_CONFIG_H
   7 #include <config.h>
   8 #endif
   9 
  10 extern "C" {
  11 #include <sys/types.h>
  12 #include <netinet/in_systm.h>
  13 #include <netinet/in.h>
  14 #include <netinet/ip.h>
  15 }
  16 
  17 #include "util/Types.hh"
  18 #include "util/Trail.hh"
  19 #include "util/Handler.hh"
  20 #include "util/Buffer.hh"
  21 #include "sys/File.hh"
  22 #include "sys/Pipe.hh"
  23 #include "sys/Time.hh"
  24 #include "sched/Timer.hh"
  25 #include "sched/Dispatcher.hh"
  26 
  27 #include "network/ICMProbe.hh"
  28 #include "network/Headers.hh"
  29 #include "network/Network.hh"
  30 
  31 // Constants
  32 static const unsigned char      UDPProtocol = 17;
  33 
  34 // Locals
  35 static TraceCode        traceICMProbe("net");
  36 static TimeShort        maxWait(10, 0);
  37 static unsigned int     probeNumber = 0x80000000;
  38 
  39 static void
  40 icmprobeTimerHandler(void* ptr,
     /* [<][>][^][v][top][bottom][index][help] */
  41                    void*)
  42 {
  43     ((ICMProbe*) ptr)->handleTimer();
  44 }
  45 
  46 ICMProbe::ICMProbe(Address* a,
     /* [<][>][^][v][top][bottom][index][help] */
  47                    Handler& cb,
  48                    int hc,
  49                    Address* v)
  50    : ListNode()
  51 {
  52     done = cb;
  53     to = *a;
  54     hopcount = hc;
  55     if (v) {
  56         via = *v;
  57     }
  58     timer = NULL;
  59     result = ICMProbeResultNone;
  60     residualHops = 0;
  61     network->pendingICMProbes.append(this);
  62     probeId = 0;
  63     lastRtt = InfiniteInterval;
  64     sent = 0;
  65 }
  66 
  67 ICMProbe::~ICMProbe()
     /* [<][>][^][v][top][bottom][index][help] */
  68 {
  69     network->pendingICMProbes.remove(this);
  70     if (timer) {
  71         delete timer;
  72     }
  73 }
  74 
  75 void
  76 ICMProbe::send()
     /* [<][>][^][v][top][bottom][index][help] */
  77 {
  78     Handler     th(icmprobeTimerHandler, this);
  79     Handler     nh(NULL, NULL);
  80     Buffer*     buf;
  81     IP*         ip;
  82     IPOptLSRR*  ipopt;
  83     ICMP*       icmp;
  84     RawSocket*  raw;
  85     U32*        t;
  86     TimeLong    at;
  87     Address     srcaddr;
  88 
  89     responder.set(0);
  90     result = ICMProbeResultNone;
  91     sent++;
  92     network->icmprobesSent++;
  93 
  94     // Send packet
  95     raw = new RawSocket(nh, nh, RawSocketICMP);
  96     if (via.get()) {
  97         buf = new Buffer(sizeof(IP) + sizeof(IPOptLSRR) + sizeof(ICMP) + 8);
  98     } else {
  99         buf = new Buffer(sizeof(IP) + sizeof(ICMP) + 8);
 100     }
 101     buf->zeroFill();
 102 
 103     ip = (IP*) buf->contents;
 104     ip->headerLength = via.get() ? 
 105         (sizeof(IP) + sizeof(IPOptLSRR)) >> 2 :
 106          sizeof(IP) >> 2;
 107     ip->version = 4;
 108     ip->typeOfService = 0;
 109     ip->totalLength = (ip->headerLength << 2) + sizeof(ICMP);
 110     ip->identifier = 0;
 111     ip->fragmentOffset = 0;
 112     ip->timeToLive = hopcount;
 113     ip->protocol = IPPROTO_ICMP;
 114     ip->source = (network->interfaces.head())->address.get();
 115     ip->destination = (via.get()) ? via.get() : to.get();
 116     ip->hton();
 117     ip->checksum = 0;
 118     ip->checksum = network->cksum((U16*) ip, ip->headerLength << 2);
 119 
 120     if (via.get()) {
 121         IPOptLSRR*      lsrr;
 122 
 123         lsrr = (IPOptLSRR*) (ip + 1);
 124         lsrr->nullopt = IPOPT_NOP;
 125         lsrr->lsrropt = IPOPT_LSRR;
 126         lsrr->length = sizeof(U32) + 3;
 127         lsrr->pointer = IPOPT_MINOFF;
 128         lsrr->gateway = to.get();
 129         lsrr->hton();
 130         icmp = (ICMP*) (lsrr + 1);
 131     } else {
 132         icmp = (ICMP*) (ip + 1);
 133     }
 134 
 135     ASSERT(probeNumber != 0xffffffff);  // Wrap around
 136     probeNumber++;
 137     probeId = probeNumber;
 138 
 139     icmp->type = ICMPTypeEcho;
 140     icmp->code = 0;
 141     icmp->gateway = probeNumber;
 142     icmp->hton();
 143     icmp->checksum = 0;
 144     icmp->checksum = network->cksum((U16*) icmp, sizeof(ICMP) + 8);
 145 
 146     dispatcher.systemClock.sync();
 147     sentAt = dispatcher.systemClock;
 148 
 149     raw->sendTo(buf->contents, buf->size, to, 0);
 150 
 151     TRACE(traceICMProbe, "icmprobe to %s:%d\n", to.name(), hopcount);
 152 
 153     delete raw;
 154     delete buf;
 155     
 156     if (timer) {
 157         delete timer;
 158     }
 159     at = dispatcher.systemClock;
 160     at = at + maxWait;
 161     timer = new Timer(th, at);
 162 
 163     return;
 164 }
 165 
 166 void
 167 ICMProbe::handleTimer()
     /* [<][>][^][v][top][bottom][index][help] */
 168 {
 169     TRACE(traceICMProbe, "icmprobe failed to %s\n", to.name());
 170 
 171     timer = NULL;
 172     network->icmprobesTimedOut++;
 173     done.callBack((void*) this);
 174     lastRtt = InfiniteInterval;
 175     return;
 176 }
 177 
 178 Boolean
 179 ICMProbe::receive(IP* ip)
     /* [<][>][^][v][top][bottom][index][help] */
 180 {
 181     ICMP*               icmp;
 182     unsigned short      sum;
 183     IP*                 iip;
 184     int                 datalen;
 185 
 186     // Verify signature to see if it is for us
 187     icmp = (struct ICMP*) ((char*) ip + (ip->headerLength << 2));
 188     if (icmp->type != ICMPTypeTimeExceeded &&
 189         icmp->type != ICMPTypeDestinationUnreachable &&
 190         icmp->type != ICMPTypeEchoReply)
 191         return false;
 192 
 193     if (icmp->type == ICMPTypeTimeExceeded ||
 194         icmp->type == ICMPTypeDestinationUnreachable) {
 195 
 196        datalen = ip->totalLength - (ip->headerLength << 2) - sizeof(ICMP);
 197        if (datalen < sizeof(IP))
 198           return false;         // Malformed response, discard
 199 
 200        iip = (struct IP*) (icmp + 1);
 201        iip->ntoh();
 202 
 203        if (datalen < ((iip->headerLength << 2) + 2 * sizeof(unsigned long)))
 204           return false;         // Timestamp not there, discard
 205 
 206        if (iip->destination != to.get())
 207           return false;
 208 
 209        ICMP* icmpi = (ICMP*) (((char*) iip) + (iip->headerLength<<2));
 210        icmpi->ntoh();
 211 
 212        if (icmpi->gateway != probeNumber) // it is not the pkt we sent
 213           return false;
 214     }
 215 
 216     dispatcher.systemClock.sync();
 217     lastRtt = dispatcher.systemClock - sentAt;
 218 
 219     switch (icmp->type) {
 220     case ICMPTypeEchoReply:
 221        if (ip->source != to.get()) {
 222           return false;
 223        }
 224        if (icmp->gateway != probeNumber) {
 225           return false;
 226        }
 227         
 228        responder.set(ip->source);
 229        residualHops = 0;
 230        result = ICMProbeResultReachedNode;
 231 
 232        TRACE(traceICMProbe, "received icmprobe for %s:%d from %s\n",
 233              to.name(), hopcount, responder.name());
 234        done.callBack((void*) this);
 235        break;
 236 
 237     case ICMPTypeTimeExceeded:
 238        if (iip->timeToLive <= 1) {
 239           responder.set(ip->source);
 240           result = ICMProbeResultTimeExpired;
 241           TRACE(traceICMProbe, "received icmprobe for %s:%d from %s\n",
 242                 to.name(), hopcount, responder.name());
 243        } else {
 244           responder.set(ip->source);
 245           ERROR("unexpected ttl %d in ICMP TimeExceeded from %s\n",
 246                 iip->timeToLive, responder.name());
 247           result = ICMProbeResultDontCare;
 248        } 
 249        done.callBack((void*) this);
 250        break;
 251 
 252     case ICMPTypeDestinationUnreachable:
 253        residualHops = iip->timeToLive;
 254        responder.set(ip->source);
 255        switch (icmp->code) {
 256        case ICMPUnreachNet:
 257        case ICMPUnreachHost:
 258           result = ICMProbeResultUnreachable;
 259           break;
 260           
 261        case ICMPUnreachProto:
 262        case ICMPUnreachPort:
 263           result = ICMProbeResultReachedNode;
 264           break;
 265           
 266        case ICMPUnreachSrtFail:
 267           result = ICMProbeResultSourceRouteFailed;
 268           break;
 269           
 270        case ICMPUnreachNeedFrag:
 271        default:
 272           result = ICMProbeResultDontCare;
 273           break;
 274        }
 275        TRACE(traceICMProbe, "received icmprobe for %s:%d from %s\n",
 276              to.name(), hopcount, responder.name());
 277        done.callBack((void*) this);
 278        // FallThrough
 279        
 280     default:
 281        break;
 282     }
 283     return true;
 284 }
 285 
 286 //  Copyright (c) 1994 by the University of Southern California.
 287 //  All rights reserved.
 288 //
 289 //  Permission to use, copy, modify, and distribute this software and
 290 //  its documentation in source and binary forms for lawful
 291 //  non-commercial purposes and without fee is hereby granted, provided
 292 //  that the above copyright notice appear in all copies and that both
 293 //  the copyright notice and this permission notice appear in supporting
 294 //  documentation, and that any documentation, advertising materials,
 295 //  and other materials related to such distribution and use acknowledge
 296 //  that the software was developed by the University of Southern
 297 //  California and/or Information Sciences Institute.
 298 //  The name of the University of Southern California may not
 299 //  be used to endorse or promote products derived from this software
 300 //  without specific prior written permission.
 301 //
 302 //  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
 303 //  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
 304 //  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
 305 //  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 306 //  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 
 307 //  NON-INFRINGEMENT.
 308 //
 309 //  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
 310 //  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
 311 //  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
 312 //  THE USE OR PERFORMANCE OF THIS SOFTWARE.
 313 //
 314 //  Questions concerning this software should be directed to 
 315 //  scan@isi.edu.
 316 //
 317 
 318 

/* [<][>][^][v][top][bottom][index][help] */