IPFragBuf.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2004 Andras Varga
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 
00019 #include <omnetpp.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022 
00023 #include "IPFragBuf.h"
00024 #include "ICMP.h"
00025 
00026 
00027 IPFragBuf::IPFragBuf()
00028 {
00029     icmpModule = NULL;
00030 }
00031 
00032 IPFragBuf::~IPFragBuf()
00033 {
00034 }
00035 
00036 void IPFragBuf::init(ICMP *icmp)
00037 {
00038     icmpModule = icmp;
00039 }
00040 
00041 IPDatagram *IPFragBuf::addFragment(IPDatagram *datagram, simtime_t now)
00042 {
00043     // find datagram buffer
00044     Key key;
00045     key.id = datagram->getIdentification();
00046     key.src = datagram->getSrcAddress();
00047     key.dest = datagram->getDestAddress();
00048 
00049     Buffers::iterator i = bufs.find(key);
00050 
00051     DatagramBuffer *buf = NULL;
00052     if (i==bufs.end())
00053     {
00054         // this is the first fragment of that datagram, create reassembly buffer for it
00055         buf = &bufs[key];
00056         buf->datagram = NULL;
00057     }
00058     else
00059     {
00060         // use existing buffer
00061         buf = &(i->second);
00062     }
00063 
00064     // add fragment into reassembly buffer
00065     int bytes = datagram->getByteLength() - datagram->getHeaderLength();
00066     bool isComplete = buf->buf.addFragment(datagram->getFragmentOffset(),
00067                                            datagram->getFragmentOffset() + bytes,
00068                                            !datagram->getMoreFragments());
00069 
00070     // store datagram. Only one fragment carries the actual modelled
00071     // content (getEncapsulatedMsg()), other (empty) ones are only
00072     // preserved so that we can send them in ICMP if reassembly times out.
00073     if (datagram->getEncapsulatedMsg())
00074     {
00075         delete buf->datagram;
00076         buf->datagram = datagram;
00077     }
00078     else
00079     {
00080         delete datagram;
00081     }
00082 
00083     // do we have the complete datagram?
00084     if (isComplete)
00085     {
00086         // datagram complete: deallocate buffer and return complete datagram
00087         IPDatagram *ret = buf->datagram;
00088         ret->setByteLength(ret->getHeaderLength()+buf->buf.getTotalLength());
00089         ret->setFragmentOffset(0);
00090         ret->setMoreFragments(false);
00091         bufs.erase(i);
00092         return ret;
00093     }
00094     else
00095     {
00096         // there are still missing fragments
00097         buf->lastupdate = now;
00098         return NULL;
00099     }
00100 }
00101 
00102 void IPFragBuf::purgeStaleFragments(simtime_t lastupdate)
00103 {
00104     // this method shouldn't be called too often because iteration on
00105     // an std::map is *very* slow...
00106 
00107     ASSERT(icmpModule);
00108 
00109     for (Buffers::iterator i=bufs.begin(); i!=bufs.end(); )
00110     {
00111         // if too old, remove it
00112         DatagramBuffer& buf = i->second;
00113         if (buf.lastupdate < lastupdate)
00114         {
00115             // send ICMP error.
00116             // Note: receiver MUST NOT call decapsulate() on the datagram fragment,
00117             // because its length (being a fragment) is smaller than the encapsulated
00118             // packet, resulting in "length became negative" error. Use getEncapsulatedMsg().
00119             EV << "datagram fragment timed out in reassembly buffer, sending ICMP_TIME_EXCEEDED\n";
00120             icmpModule->sendErrorMessage(buf.datagram, ICMP_TIME_EXCEEDED, 0);
00121 
00122             // delete
00123             Buffers::iterator oldi = i++;
00124             bufs.erase(oldi);
00125         }
00126         else
00127         {
00128             ++i;
00129         }
00130     }
00131 }
00132