INET Framework for OMNeT++/OMNEST
old/queues/TCPVirtualDataRcvQueue.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 "TCPVirtualDataRcvQueue_old.h"
00020 
00021 using namespace tcp_old;
00022 
00023 Register_Class(TCPVirtualDataRcvQueue);
00024 
00025 
00026 TCPVirtualDataRcvQueue::TCPVirtualDataRcvQueue() : TCPReceiveQueue()
00027 {
00028 }
00029 
00030 TCPVirtualDataRcvQueue::~TCPVirtualDataRcvQueue()
00031 {
00032 }
00033 
00034 void TCPVirtualDataRcvQueue::init(uint32 startSeq)
00035 {
00036     rcv_nxt = startSeq;
00037 }
00038 
00039 std::string TCPVirtualDataRcvQueue::info() const
00040 {
00041     std::string res;
00042     char buf[32];
00043     sprintf(buf, "rcv_nxt=%u ", rcv_nxt);
00044     res = buf;
00045 
00046     for (RegionList::const_iterator i=regionList.begin(); i!=regionList.end(); ++i)
00047     {
00048         sprintf(buf, "[%u..%u) ", i->begin, i->end);
00049         res+=buf;
00050     }
00051     return res;
00052 }
00053 
00054 uint32 TCPVirtualDataRcvQueue::insertBytesFromSegment(TCPSegment *tcpseg)
00055 {
00056     merge(tcpseg->getSequenceNo(), tcpseg->getSequenceNo()+tcpseg->getPayloadLength());
00057     if (seqGE(rcv_nxt, regionList.begin()->begin))
00058         rcv_nxt = regionList.begin()->end;
00059     return rcv_nxt;
00060 }
00061 
00062 void TCPVirtualDataRcvQueue::merge(uint32 segmentBegin, uint32 segmentEnd)
00063 {
00064     // Here we have to update our existing regions with the octet range
00065     // tcpseg represents. We either have to insert tcpseg as a separate region
00066     // somewhere, or (if it overlaps with an existing region) extend
00067     // existing regions; we also may have to merge existing regions if
00068     // they become overlapping (or touching) after adding tcpseg.
00069 
00070     Region seg;
00071     seg.begin = segmentBegin;
00072     seg.end = segmentEnd;
00073 
00074     RegionList::iterator i = regionList.begin();
00075     if (i==regionList.end())
00076     {
00077         // insert as first and only region
00078         regionList.insert(regionList.begin(), seg);
00079         return;
00080     }
00081 
00082     // skip regions which fall entirely before seg (no overlap or touching)
00083     while (i!=regionList.end() && seqLess(i->end,seg.begin))
00084     {
00085         ++i;
00086     }
00087 
00088     if (i==regionList.end())
00089     {
00090         // seg is entirely past last region: insert as separate region at end
00091         regionList.insert(regionList.end(), seg);
00092         return;
00093     }
00094 
00095     if (seqLess(seg.end,i->begin))
00096     {
00097         // segment entirely before region "i": insert as separate region before "i"
00098         regionList.insert(i, seg);
00099         return;
00100     }
00101 
00102     if (seqLess(seg.begin,i->begin))
00103     {
00104         // segment starts before region "i": extend region
00105         i->begin = seg.begin;
00106     }
00107 
00108     if (seqLess(i->end,seg.end))
00109     {
00110         // segment ends past end of region "i": extend region
00111         i->end = seg.end;
00112 
00113         // maybe we have to merge region "i" with next one(s)
00114         RegionList::iterator j = i;
00115         ++j;
00116         while (j!=regionList.end() && seqGE(i->end,j->begin)) // while there's overlap
00117         {
00118             // if "j" is longer: extend "i"
00119             if (seqLess(i->end,j->end))
00120                 i->end = j->end;
00121 
00122             // erase "j" (it was merged into "i")
00123             RegionList::iterator oldj = j++;
00124             regionList.erase(oldj);
00125         }
00126     }
00127 }
00128 
00129 cPacket *TCPVirtualDataRcvQueue::extractBytesUpTo(uint32 seq)
00130 {
00131     ulong numBytes = extractTo(seq);
00132     if (numBytes==0)
00133         return NULL;
00134 
00135     cPacket *msg = new cPacket("data");
00136     msg->setByteLength(numBytes);
00137     return msg;
00138 }
00139 
00140 ulong TCPVirtualDataRcvQueue::extractTo(uint32 seq)
00141 {
00142     ASSERT(seqLE(seq,rcv_nxt));
00143 
00144     RegionList::iterator i = regionList.begin();
00145     if (i==regionList.end())
00146         return 0;
00147 
00148     ASSERT(seqLess(i->begin,i->end)); // empty regions cannot exist
00149 
00150     // seq below 1st region
00151     if (seqLE(seq,i->begin))
00152         return 0;
00153 
00154     if (seqLess(seq,i->end))
00155     {
00156         // part of 1st region
00157         ulong octets = seq - i->begin;
00158         i->begin = seq;
00159         return octets;
00160     }
00161     else
00162     {
00163         // full 1st region
00164         ulong octets = i->end - i->begin;
00165         regionList.erase(i);
00166         return octets;
00167     }
00168 }
00169