|
INET Framework for OMNeT++/OMNEST
|
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 }