INET Framework for OMNeT++/OMNEST
queues/TCPVirtualDataRcvQueue.cc
Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2004 Andras Varga
00003 // Copyright (C) 2009 Thomas Reschka
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 
00020 #include "TCPVirtualDataRcvQueue.h"
00021 
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 
00170 uint32 TCPVirtualDataRcvQueue::getAmountOfBufferedBytes()
00171 {
00172     uint32 bytes=0;
00173 
00174     RegionList::iterator i = regionList.begin();
00175     if (i==regionList.end()) // is queue empty?
00176         return 0;
00177 
00178     while (i!=regionList.end())
00179     {
00180         bytes = bytes + (i->end - i->begin);
00181         i++;
00182     }
00183     return bytes;
00184 }
00185 
00186 uint32 TCPVirtualDataRcvQueue::getAmountOfFreeBytes(uint32 maxRcvBuffer)
00187 {
00188     uint32 usedRcvBuffer = getAmountOfBufferedBytes();
00189     uint32 freeRcvBuffer = maxRcvBuffer - usedRcvBuffer;
00190     return freeRcvBuffer;
00191 }
00192 
00193 uint32 TCPVirtualDataRcvQueue::getQueueLength()
00194 {
00195     return regionList.size();
00196 }
00197 
00198 void TCPVirtualDataRcvQueue::getQueueStatus()
00199 {
00200     tcpEV << "receiveQLength=" << regionList.size() << " " << info() << "\n";
00201 }
00202 
00203 
00204 uint32 TCPVirtualDataRcvQueue::getLE(uint32 fromSeqNum)
00205 {
00206     RegionList::iterator i = regionList.begin();
00207     while (i!=regionList.end())
00208     {
00209         if (seqLE(i->begin, fromSeqNum) && seqLE(fromSeqNum, i->end))
00210         {
00211 //            tcpEV << "Enqueued region: [" << i->begin << ".." << i->end << ")\n";
00212             if (seqLess(i->begin, fromSeqNum))
00213                 return i->begin;
00214             return fromSeqNum;
00215         }
00216         i++;
00217     }
00218     return fromSeqNum;
00219 }
00220 
00221 uint32 TCPVirtualDataRcvQueue::getRE(uint32 toSeqNum)
00222 {
00223     RegionList::iterator i = regionList.begin();
00224     while (i!=regionList.end())
00225     {
00226         if (seqLE(i->begin, toSeqNum) && seqLE(toSeqNum, i->end))
00227         {
00228 //            tcpEV << "Enqueued region: [" << i->begin << ".." << i->end << ")\n";
00229             if (seqLess(toSeqNum, i->end))
00230                 return i->end;
00231             return toSeqNum;
00232         }
00233         i++;
00234     }
00235     return toSeqNum;
00236 }