|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2007-2009 Irene Ruengeler 00003 // Copyright (C) 2009-2010 Thomas Dreibholz 00004 // 00005 // This program is free software; you can redistribute it and/or 00006 // modify it under the terms of the GNU 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 General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with this program; if not, write to the Free Software 00017 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 // 00019 00020 #include "SCTPAssociation.h" 00021 #include "SCTPAlgorithm.h" 00022 #include "SCTPCommand_m.h" 00023 00024 #include <assert.h> 00025 #include <algorithm> 00026 00027 00028 void SCTPAssociation::increaseOutstandingBytes(SCTPDataVariables* chunk, 00029 SCTPPathVariables* path) 00030 { 00031 path->outstandingBytes += chunk->booksize; 00032 state->outstandingBytes += chunk->booksize; 00033 00034 CounterMap::iterator iterator = qCounter.roomRetransQ.find(path->remoteAddress); 00035 iterator->second += ADD_PADDING(chunk->booksize + SCTP_DATA_CHUNK_LENGTH); 00036 } 00037 00038 int32 SCTPAssociation::calculateBytesToSendOnPath(const SCTPPathVariables* pathVar) 00039 { 00040 int32 bytesToSend; 00041 const SCTPDataMsg* datMsg = peekOutboundDataMsg(); 00042 if(datMsg != NULL) { 00043 const uint32 ums = datMsg->getBooksize(); // Get user message size 00044 const uint32 num = (uint32)floor((double)(pathVar->pmtu - 32) / (ums + SCTP_DATA_CHUNK_LENGTH)); 00045 if (num * ums > state->peerRwnd) { 00046 // Receiver cannot handle data yet 00047 bytesToSend = 0; 00048 } 00049 else { 00050 // Receiver will accept data 00051 bytesToSend = num * ums; 00052 } 00053 } 00054 else { 00055 bytesToSend = 0; 00056 } 00057 return(bytesToSend); 00058 } 00059 00060 void SCTPAssociation::storePacket(SCTPPathVariables* pathVar, 00061 SCTPMessage* sctpMsg, 00062 const uint16 chunksAdded, 00063 const uint16 dataChunksAdded, 00064 const uint32 packetBytes, 00065 const bool authAdded) 00066 { 00067 for (uint16 i = 0; i < sctpMsg->getChunksArraySize(); i++) { 00068 retransmissionQ->payloadQueue.find(((SCTPDataChunk*)sctpMsg->getChunks(i))->getTsn())->second->countsAsOutstanding = false; 00069 } 00070 state->sctpMsg = sctpMsg; 00071 state->chunksAdded = chunksAdded; 00072 state->dataChunksAdded = dataChunksAdded; 00073 state->packetBytes = packetBytes; 00074 sctpEV3 << "storePacket: path=" << pathVar->remoteAddress 00075 << " osb=" << pathVar->outstandingBytes << " -> " 00076 << pathVar->outstandingBytes - state->packetBytes << endl; 00077 assert(pathVar->outstandingBytes >= state->packetBytes); 00078 pathVar->outstandingBytes -= state->packetBytes; 00079 qCounter.roomSumSendStreams += state->packetBytes + (dataChunksAdded * SCTP_DATA_CHUNK_LENGTH); 00080 qCounter.bookedSumSendStreams += state->packetBytes; 00081 00082 } 00083 00084 void SCTPAssociation::loadPacket(SCTPPathVariables* pathVar, 00085 SCTPMessage** sctpMsg, 00086 uint16* chunksAdded, 00087 uint16* dataChunksAdded, 00088 uint32* packetBytes, 00089 bool* authAdded) 00090 { 00091 *sctpMsg = state->sctpMsg; 00092 *chunksAdded = state->chunksAdded; 00093 *dataChunksAdded = state->dataChunksAdded; 00094 *packetBytes = state->packetBytes; 00095 sctpEV3 << "loadPacket: path=" << pathVar->remoteAddress << " osb=" << pathVar->outstandingBytes << " -> " << pathVar->outstandingBytes + state->packetBytes << endl; 00096 pathVar->outstandingBytes += state->packetBytes; 00097 qCounter.bookedSumSendStreams -= state->packetBytes; 00098 00099 for (uint16 i = 0; i < (*sctpMsg)->getChunksArraySize(); i++) 00100 retransmissionQ->payloadQueue.find(((SCTPDataChunk*)(*sctpMsg)->getChunks(i))->getTsn())->second->countsAsOutstanding = true; 00101 00102 } 00103 00104 00105 00106 SCTPDataVariables* SCTPAssociation::makeDataVarFromDataMsg(SCTPDataMsg* datMsg, 00107 SCTPPathVariables* path) 00108 { 00109 SCTPDataVariables* datVar = new SCTPDataVariables(); 00110 00111 datMsg->setInitialDestination(path->remoteAddress); 00112 datVar->setInitialDestination(path); 00113 00114 datVar->bbit = datMsg->getBBit(); 00115 datVar->ebit = datMsg->getEBit(); 00116 datVar->enqueuingTime = datMsg->getEnqueuingTime(); 00117 datVar->expiryTime = datMsg->getExpiryTime(); 00118 datVar->ppid = datMsg->getPpid(); 00119 datVar->len = datMsg->getBitLength(); 00120 datVar->sid = datMsg->getSid(); 00121 datVar->allowedNoRetransmissions = datMsg->getRtx(); 00122 datVar->booksize = datMsg->getBooksize(); 00123 00124 // ------ Stream handling --------------------------------------- 00125 SCTPSendStreamMap::iterator iterator = sendStreams.find(datMsg->getSid()); 00126 SCTPSendStream* stream = iterator->second; 00127 uint32 nextSSN = stream->getNextStreamSeqNum(); 00128 datVar->userData = datMsg->decapsulate(); 00129 if (datMsg->getOrdered()) { 00130 // ------ Ordered mode: assign SSN --------- 00131 if (datMsg->getEBit()) 00132 { 00133 datVar->ssn = nextSSN++; 00134 } 00135 else 00136 { 00137 datVar->ssn = nextSSN; 00138 } 00139 00140 datVar->ordered = true; 00141 if (nextSSN > 65535) { 00142 stream->setNextStreamSeqNum(0); 00143 } 00144 else { 00145 stream->setNextStreamSeqNum(nextSSN); 00146 } 00147 } 00148 else { 00149 // ------ Ordered mode: no SSN needed ------ 00150 datVar->ssn = 0; 00151 datVar->ordered = false; 00152 } 00153 00154 00155 return(datVar); 00156 } 00157 00158 SCTPPathVariables* SCTPAssociation::choosePathForRetransmission() 00159 { 00160 uint32 max = 0; 00161 SCTPPathVariables* temp = NULL; 00162 00163 for (SCTPPathMap::iterator iterator = sctpPathMap.begin(); iterator != sctpPathMap.end(); ++iterator) { 00164 SCTPPathVariables* path = iterator->second; 00165 CounterMap::const_iterator tq = qCounter.roomTransQ.find(path->remoteAddress); 00166 if ((tq != qCounter.roomTransQ.end()) && (tq->second > max)) { 00167 max = tq->second; 00168 temp = path; 00169 } 00170 } 00171 return temp; 00172 } 00173 00174 void SCTPAssociation::timeForSack(bool& sackOnly, bool& sackWithData) 00175 { 00176 sackOnly = sackWithData = false; 00177 if (((state->numGaps > 0) || (state->dupList.size() > 0)) && 00178 (state->sackAllowed)) { 00179 // Schedule sending of SACKs at once, when we have fragments to report 00180 state->ackState = sackFrequency; 00181 sackOnly = sackWithData = true; // SACK necessary, regardless of data available 00182 } 00183 if (state->ackState >= sackFrequency) { 00184 sackOnly = sackWithData = true; // SACK necessary, regardless of data available 00185 } 00186 else if (SackTimer->isScheduled()) { 00187 sackOnly = false; 00188 sackWithData = true; // Only send SACK when data is present. 00189 } 00190 } 00191 00192 00193 void SCTPAssociation::sendOnAllPaths(SCTPPathVariables* firstPath) 00194 { 00195 // ------ Send on provided path first ... ----------------------------- 00196 if(firstPath != NULL) { 00197 sendOnPath(firstPath); 00198 } 00199 00200 // ------ ... then, try sending on all other paths -------------------- 00201 for (SCTPPathMap::iterator iterator = sctpPathMap.begin(); iterator != sctpPathMap.end(); ++iterator) { 00202 SCTPPathVariables* path = iterator->second; 00203 if(path != firstPath) { 00204 sendOnPath(path); 00205 } 00206 } 00207 00208 } 00209 00210 00211 00212 00213 void SCTPAssociation::bytesAllowedToSend(SCTPPathVariables* path, 00214 const bool firstPass) 00215 { 00216 assert(path != NULL); 00217 00218 bytes.chunk = false; 00219 bytes.packet = false; 00220 bytes.bytesToSend = 0; 00221 00222 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "):" 00223 << " osb=" << path->outstandingBytes << " cwnd=" << path->cwnd << endl; 00224 00225 // ====== First transmission ============================================= 00226 if (!state->firstDataSent) { 00227 bytes.chunk = true; 00228 } 00229 00230 // ====== Transmission allowed by peer's receiver window? ================ 00231 else if (state->peerWindowFull) 00232 { 00233 if (path->outstandingBytes == 0) { 00234 // Zero Window Probing 00235 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): zeroWindowProbing" << endl; 00236 state->zeroWindowProbing = true; 00237 bytes.chunk = true; 00238 } 00239 } 00240 00241 // ====== Retransmissions ================================================ 00242 else { 00243 CounterMap::const_iterator it = qCounter.roomTransQ.find(path->remoteAddress); 00244 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): bytes in transQ=" << it->second << endl; 00245 if (it->second > 0) { 00246 const int32 allowance = path->cwnd - path->outstandingBytes; 00247 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd-osb=" << allowance << endl; 00248 if (state->peerRwnd < path->pmtu) { 00249 bytes.bytesToSend = state->peerRwnd; 00250 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): rwnd<pmtu" << endl; 00251 return; 00252 } 00253 else if (allowance > 0) { 00254 CounterMap::const_iterator bit = qCounter.bookedTransQ.find(path->remoteAddress); 00255 if (bit->second > (uint32)allowance) { 00256 bytes.bytesToSend = allowance; 00257 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd does not allow all RTX" << endl; 00258 return; // More bytes available than allowed -> just return what is allowed. 00259 } 00260 else { 00261 bytes.bytesToSend = bit->second; 00262 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd allows more than those " 00263 << bytes.bytesToSend << " bytes for retransmission" << endl; 00264 } 00265 } 00266 else { // You may retransmit one packet 00267 bytes.packet = true; 00268 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): allowance<=0: retransmit one packet" << endl; 00269 } 00270 } 00271 00272 // ====== New transmissions =========================================== 00273 if (!bytes.chunk && !bytes.packet) { 00274 if ((path->outstandingBytes < path->cwnd) && 00275 (!state->peerWindowFull)) { 00276 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "):" 00277 << " bookedSumSendStreams=" << qCounter.bookedSumSendStreams 00278 << " bytes.bytesToSend=" << bytes.bytesToSend << endl; 00279 const int32 allowance = path->cwnd - path->outstandingBytes - bytes.bytesToSend; 00280 if (allowance > 0) { 00281 if (qCounter.bookedSumSendStreams > (uint32)allowance) { 00282 bytes.bytesToSend = path->cwnd - path->outstandingBytes; 00283 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): bytesToSend are limited by cwnd: " 00284 << bytes.bytesToSend << endl; 00285 } 00286 else { 00287 bytes.bytesToSend += qCounter.bookedSumSendStreams; 00288 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): send all stored bytes: " 00289 << bytes.bytesToSend << endl; 00290 } 00291 } 00292 } 00293 } 00294 } 00295 00296 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "):" 00297 << " osb=" << path->outstandingBytes 00298 << " cwnd=" << path->cwnd 00299 << " bytes.packet=" << (bytes.packet ? "YES!" : "no") 00300 << " bytes.chunk=" << (bytes.chunk ? "YES!" : "no") 00301 << " bytes.bytesToSend=" << bytes.bytesToSend << endl; 00302 } 00303 00304 00305 void SCTPAssociation::sendOnPath(SCTPPathVariables* pathId, bool firstPass) 00306 { 00307 // ====== Variables ====================================================== 00308 SCTPPathVariables* path = NULL; // Path to send next message to 00309 SCTPMessage* sctpMsg = NULL; 00310 SCTPSackChunk* sackChunk = NULL; 00311 SCTPDataChunk* chunkPtr = NULL; 00312 00313 uint16 chunksAdded = 0; 00314 uint16 dataChunksAdded = 0; 00315 uint32 totalChunksSent = 0; 00316 uint32 totalPacketsSent = 0; 00317 uint32 packetBytes = 0; 00318 uint32 outstandingBytes = 0; 00319 00320 uint32 tcount = 0; // Bytes in transmission queue on the selected path 00321 uint32 scount = 0; // Bytes in send streams 00322 int32 bytesToSend = 0; 00323 00324 bool headerCreated = false; 00325 bool rtxActive = false; 00326 bool sendOneMorePacket = false; 00327 bool sendingAllowed = true; 00328 bool authAdded = false; 00329 bool sackAdded = false; 00330 00331 // ====== Obtain path ==================================================== 00332 sctpEV3 << endl << "##### sendAll("; 00333 if(pathId) { 00334 sctpEV3 << pathId->remoteAddress; 00335 } 00336 sctpEV3 << ") #####" << endl; 00337 while(sendingAllowed) 00338 { 00339 headerCreated = false; 00340 if (state->bytesToRetransmit > 0) { 00341 // There are bytes in the transmissionQ. They have to be sent first. 00342 path = choosePathForRetransmission(); 00343 assert(path != NULL); 00344 rtxActive = true; 00345 } 00346 else { 00347 if (pathId == NULL) { // No path given => use primary path. 00348 path = state->getPrimaryPath(); 00349 } 00350 else { 00351 path = pathId; 00352 } 00353 } 00354 00355 outstandingBytes = path->outstandingBytes; 00356 assert((int32)outstandingBytes >= 0); 00357 CounterMap::iterator tq = qCounter.roomTransQ.find(path->remoteAddress); 00358 tcount = tq->second; 00359 scount = qCounter.roomSumSendStreams; // includes header and padding 00360 sctpEV3 << "\nsendAll: on " << path->remoteAddress << ":" 00361 << " tcount=" << tcount 00362 << " scount=" << scount 00363 << " nextTSN=" << state->nextTSN << endl; 00364 00365 bool sackOnly; 00366 bool sackWithData; 00367 timeForSack(sackOnly, sackWithData); 00368 if (tcount == 0 && scount == 0) { 00369 // ====== No DATA chunks to send =================================== 00370 sctpEV3 << "No DATA chunk available!" << endl; 00371 if (!sackOnly) { // SACK?, no data to send 00372 sctpEV3 << "No SACK to send either" << endl; 00373 return; 00374 } 00375 else { 00376 bytes.bytesToSend = 0; 00377 } 00378 } 00379 else { 00380 bytesAllowedToSend(path, firstPass); 00381 } 00382 bytesToSend = bytes.bytesToSend; 00383 00384 // As there is at least a SACK to be sent, a header can be created 00385 00386 if (state->sctpMsg) // ??? Robin: Ist das in Ordnung??? 00387 { 00388 loadPacket(path, &sctpMsg, &chunksAdded, &dataChunksAdded, &packetBytes, &authAdded); 00389 headerCreated = true; 00390 } 00391 else if (bytesToSend > 0 || bytes.chunk || bytes.packet || sackWithData || sackOnly) { 00392 sctpMsg = new SCTPMessage("send"); 00393 //printf("%d Name=%s Pointer=%p\n", __LINE__, sctpMsg->getName(), sctpMsg); 00394 sctpMsg->setByteLength(SCTP_COMMON_HEADER); 00395 packetBytes = 0; 00396 headerCreated = true; 00397 } 00398 00399 00400 if (sackWithData || sackOnly) 00401 { 00402 // SACK can be sent 00403 assert(headerCreated==true); 00404 sackChunk = createSack(); 00405 chunksAdded++; 00406 totalChunksSent++; 00407 // ------ Create AUTH chunk, if necessary -------------------------- 00408 00409 // ------ Add SACK chunk ------------------------------------------- 00410 sctpMsg->addChunk(sackChunk); 00411 sackAdded = true; 00412 if (sackOnly) // ????? Robin: SACK mit FORWARD_TSN???? 00413 { 00414 // send the packet and leave 00415 //printf("%d Name=%s Pointer=%p, sctpMsg\n", __LINE__, sctpMsg->getName(), sctpMsg); 00416 state->ackState = 0; 00417 // Stop SACK timer if it is running... 00418 stopTimer(SackTimer); 00419 sctpAlgorithm->sackSent(); 00420 state->sackAllowed = false; 00421 sendToIP(sctpMsg, state->lastDataSourceAddress); 00422 if ((bytesToSend > 0) || (bytes.chunk) || (bytes.packet)) { 00423 sctpMsg = new SCTPMessage("send"); 00424 sctpMsg->setByteLength(SCTP_COMMON_HEADER); 00425 packetBytes = 0; 00426 headerCreated = true; 00427 sackAdded = false; 00428 } 00429 else 00430 return; 00431 } 00432 } 00433 00434 00435 // #################################################################### 00436 // #### Data Transmission #### 00437 // #################################################################### 00438 00439 bool packetFull = false; 00440 00441 while(!packetFull && headerCreated) { 00442 assert(headerCreated == true); 00443 sctpEV3 << "bytesToSend=" << bytesToSend 00444 << " bytes.chunk=" << bytes.chunk 00445 << " bytes.packet=" << bytes.packet << endl; 00446 00447 // ====== How many bytes may be transmitted in next packet? ======== 00448 int32 allowance = path->pmtu; // Default behaviour: send 1 path MTU 00449 if ((bytesToSend > 0) || (bytes.chunk) || (bytes.packet)) { 00450 // Allow 1 more MTU 00451 } 00452 else { 00453 // No more sending allowed. 00454 allowance = 0; 00455 bytesToSend = 0; 00456 } 00457 00458 if ((allowance > 0) || (bytes.chunk) || (bytes.packet)) { 00459 bool firstTime = false; // Is DATA chunk send for the first time? 00460 00461 // ====== Retransmission ======================================== 00462 // T.D. 05.01.2010: If bytes.packet is true, one packet is allowed 00463 // to be retransmitted! 00464 SCTPDataVariables* datVar = getOutboundDataChunk(path, 00465 path->pmtu - sctpMsg->getByteLength() - 20, 00466 (bytes.packet == true) ? path->pmtu : allowance); 00467 if (chunksAdded==1 && sackAdded && !sackOnly && datVar==NULL) { 00468 sctpMsg->removeChunk(); 00469 delete sackChunk; 00470 datVar = getOutboundDataChunk(path, 00471 path->pmtu - sctpMsg->getByteLength() - 20, 00472 (bytes.packet == true) ? path->pmtu : allowance); 00473 } 00474 if (datVar != NULL) { 00475 assert(datVar->getNextDestinationPath() == path); 00476 datVar->numberOfRetransmissions++; 00477 if (chunkHasBeenAcked(datVar) == false) { 00478 sctpEV3 << simTime() << ": Retransmission #" << datVar->numberOfRetransmissions 00479 << " of TSN " << datVar->tsn 00480 << " on path " << datVar->getNextDestination() 00481 << " (last was " << datVar->getLastDestination() << ")" << endl; 00482 00483 datVar->countsAsOutstanding = true; 00484 datVar->hasBeenReneged = false; 00485 increaseOutstandingBytes(datVar, path); // NOTE: path == datVar->getNextDestinationPath() 00486 } 00487 } 00488 00489 // ====== First Transmission ==================================== 00490 else if ( ((scount > 0) && (!state->nagleEnabled)) || // Data to send and Nagle off 00491 ((uint32)scount >= path->pmtu - 32 - 20) || // Data to fill at least one path MTU 00492 ((scount > 0) && (state->nagleEnabled) && (outstandingBytes == 0)) ) { // Data to send, Nagle on and no outstanding bytes 00493 00494 if(path == state->getPrimaryPath()) { 00495 00496 // ------ Dequeue data message ---------------------------- 00497 sctpEV3 << "sendAll: sctpMsg->length=" << sctpMsg->getByteLength() 00498 << " length datMsg=" << path->pmtu-sctpMsg->getByteLength() - 20 << endl; 00499 SCTPDataMsg* datMsg = dequeueOutboundDataMsg(path->pmtu-sctpMsg->getByteLength() - 20, 00500 allowance); 00501 if (chunksAdded==1 && sackAdded && !sackOnly && datMsg==NULL) 00502 { 00503 sctpMsg->removeChunk(); 00504 delete sackChunk; 00505 datMsg = dequeueOutboundDataMsg(path->pmtu-sctpMsg->getByteLength() - 20, 00506 allowance); 00507 } 00508 // ------ Handle data message ----------------------------- 00509 if (datMsg) { 00510 firstTime = true; 00511 00512 state->queuedMessages--; 00513 if ((state->queueLimit > 0) && 00514 (state->queuedMessages < state->queueLimit) && 00515 (state->queueUpdate == false)) { 00516 // Tell upper layer readiness to accept more data 00517 sendIndicationToApp(SCTP_I_SEND_MSG); 00518 state->queueUpdate = true; 00519 } 00520 00521 datVar = makeDataVarFromDataMsg(datMsg, path); 00522 delete datMsg; 00523 00524 sctpEV3 << "sendAll: chunk " << datVar << " dequeued from StreamQ " 00525 << datVar->sid << ": tsn=" << datVar->tsn 00526 << ", bytes now " << qCounter.roomSumSendStreams << "\n"; 00527 } 00528 00529 // ------ No data message has been dequeued --------------- 00530 else { 00531 // ------ Are there any chunks to send? ---------------- 00532 if (chunksAdded == 0) { 00533 // No -> nothing more to do. 00534 if (state->sctpMsg == sctpMsg) 00535 { 00536 state->sctpMsg = NULL; 00537 state->packetBytes = 0; 00538 } 00539 packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop 00540 } 00541 else { 00542 // Yes. 00543 if (state->nagleEnabled && (outstandingBytes > 0) && 00544 nextChunkFitsIntoPacket(path->pmtu-sctpMsg->getByteLength() - 20) && 00545 (sctpMsg->getByteLength() < path->pmtu - 32 - 20) && (tcount == 0)) 00546 { 00547 storePacket(path, sctpMsg, chunksAdded, dataChunksAdded, packetBytes, authAdded); 00548 packetBytes = 0; 00549 } 00550 //chunksAdded = 0; 00551 packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop 00552 sctpEV3 << "sendAll: packetFull: msg length = " << sctpMsg->getBitLength() / 8 + 20 << "\n"; 00553 } 00554 } 00555 } 00556 } 00557 00558 00559 // ------ Handle DATA chunk ------------------------------------- 00560 if (datVar != NULL && !packetFull) { 00561 // ------ Assign TSN ----------------------------------------- 00562 if (firstTime) { 00563 assert(datVar->tsn == 0); 00564 datVar->tsn = state->nextTSN; 00565 sctpEV3 << "sendAll: set TSN=" << datVar->tsn 00566 << " sid=" << datVar->sid << ", ssn=" << datVar->ssn << "\n"; 00567 state->nextTSN++; 00568 } 00569 00570 SCTP::AssocStatMap::iterator iterator = sctpMain->assocStatMap.find(assocId); 00571 iterator->second.transmittedBytes += datVar->len / 8; 00572 00573 datVar->setLastDestination(path); 00574 datVar->countsAsOutstanding = true; 00575 datVar->hasBeenReneged = false; 00576 datVar->sendTime = simTime(); //I.R. to send Fast RTX just once a RTT 00577 00578 // ------ First transmission of datVar ----------------------- 00579 if (datVar->numberOfTransmissions == 0) { 00580 00581 sctpEV3 << "sendAll: " << simTime() << " firstTime, TSN " 00582 << datVar->tsn << ": lastDestination set to " 00583 << datVar->getLastDestination() << endl; 00584 00585 if (!state->firstDataSent) { 00586 state->firstDataSent = true; 00587 } 00588 sctpEV3 << "sendAll: insert in retransmissionQ tsn=" << datVar->tsn << "\n"; 00589 if(!retransmissionQ->checkAndInsertChunk(datVar->tsn, datVar)) { 00590 opp_error("Cannot add datVar to retransmissionQ!"); 00591 // Falls es hier aufschlaegt, muss ueberlegt werden, ob es OK ist, dass datVars nicht eingefuegt werden koennen. 00592 } 00593 else { 00594 sctpEV3 << "sendAll: size of retransmissionQ=" << retransmissionQ->getQueueSize() << "\n"; 00595 unackChunk(datVar); 00596 increaseOutstandingBytes(datVar, path); 00597 } 00598 } 00599 00600 /* datVar is already in the retransmissionQ */ 00601 datVar->numberOfTransmissions++; 00602 datVar->gapReports = 0; 00603 datVar->hasBeenFastRetransmitted = false; 00604 sctpEV3<<"sendAll(): adding new outbound data datVar to packet (tsn="<<datVar->tsn<<")...!!!\n"; 00605 00606 chunkPtr = transformDataChunk(datVar); 00607 00608 /* update counters */ 00609 totalChunksSent++; 00610 chunksAdded++; 00611 dataChunksAdded++; 00612 sctpMsg->addChunk(chunkPtr); 00613 if(nextChunkFitsIntoPacket(path->pmtu - sctpMsg->getByteLength() - 20) == false) { 00614 // ???? Robin: Ist diese Annahme so richtig? 00615 packetFull = true; 00616 } 00617 00618 state->peerRwnd -= datVar->booksize; 00619 if ((bytes.chunk == false) && (bytes.packet == false)) { 00620 bytesToSend -= datVar->booksize; 00621 } 00622 else if (bytes.chunk) { 00623 bytes.chunk = false; 00624 } 00625 else if ((bytes.packet) && (packetFull)) { 00626 bytes.packet = false; 00627 } 00628 00629 if (bytesToSend <= 0) { 00630 if ((!packetFull) && (qCounter.roomSumSendStreams > path->pmtu - 32 - 20 || tcount > 0)) { 00631 sendOneMorePacket = true; 00632 bytes.packet = true; 00633 sctpEV3 << "sendAll: one more packet allowed\n"; 00634 } 00635 else { 00636 if (state->nagleEnabled && (outstandingBytes > 0) && 00637 nextChunkFitsIntoPacket(path->pmtu-sctpMsg->getByteLength() - 20) && 00638 (sctpMsg->getByteLength() < path->pmtu - 32 - 20) && (tcount == 0)) 00639 { 00640 storePacket(path, sctpMsg, chunksAdded, dataChunksAdded, packetBytes, authAdded); 00641 packetBytes = 0; 00642 chunksAdded = 0; 00643 packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop 00644 } 00645 else { 00646 packetFull = true; 00647 } 00648 } 00649 bytesToSend = 0; 00650 } 00651 else if ((qCounter.roomSumSendStreams == 0) && (tq->second==0)) { 00652 packetFull = true; 00653 sctpEV3 << "sendAll: no data in send and transQ: packet full\n"; 00654 } 00655 sctpEV3 << "sendAll: bytesToSend after reduction: " << bytesToSend << "\n"; 00656 } 00657 00658 // ------ There is no DATA chunk, only control chunks possible -- 00659 else { 00660 // ????? Robin: Kann dieser Fall wirklich eintreten? 00661 if (chunksAdded == 0) { // Nothing to do -> return 00662 packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop 00663 } 00664 else { 00665 packetFull = true; 00666 sctpEV3 << "sendAll: packetFull: msg length = " << sctpMsg->getBitLength() / 8 + 20 << "\n"; 00667 datVar = NULL; 00668 } 00669 } 00670 00671 00672 // ====== Send packet =========================================== 00673 if (packetFull) { 00674 if(chunksAdded == 0) { // Nothing to send 00675 delete sctpMsg; 00676 sendingAllowed = false; // sendingAllowed==false => leave outer while loop 00677 } 00678 else { 00679 sctpEV3 << "sendAll: " << simTime() << " packet full:" 00680 << " totalLength=" << sctpMsg->getBitLength() / 8 + 20 00681 << ", path=" << path->remoteAddress 00682 << " " << dataChunksAdded << " chunks added, outstandingBytes now " 00683 << path->outstandingBytes << "\n"; 00684 00685 /* new chunks would exceed MTU, so we send old packet and build a new one */ 00686 /* this implies that at least one data chunk is send here */ 00687 if (dataChunksAdded > 0) { 00688 if (!path->T3_RtxTimer->isScheduled()) { 00689 // Start retransmission timer, if not scheduled before 00690 startTimer(path->T3_RtxTimer, path->pathRto); 00691 } 00692 else { 00693 sctpEV3 << "sendAll: RTX Timer already scheduled -> no need to schedule it\n"; 00694 } 00695 } 00696 if (sendOneMorePacket) { 00697 sendOneMorePacket = false; 00698 bytesToSend = 0; 00699 bytes.packet = false; 00700 } 00701 00702 00703 sendToIP(sctpMsg, path->remoteAddress); 00704 pmDataIsSentOn(path); 00705 totalPacketsSent++; 00706 00707 // ------ Reset status ------------------------------------ 00708 if (state->sctpMsg == sctpMsg) 00709 { 00710 state->sctpMsg = NULL; 00711 path->outstandingBytes += packetBytes; 00712 packetBytes = 0; 00713 } 00714 headerCreated = false; 00715 chunksAdded = 0; 00716 dataChunksAdded = 0; 00717 firstTime = false; 00718 00719 sctpEV3 << "sendAll: sending Packet to path " << path->remoteAddress 00720 << " scount=" << scount 00721 << " tcount=" << tcount 00722 << " bytesToSend=" << bytesToSend << endl; 00723 } 00724 } 00725 sctpEV3 << "sendAll: still " << bytesToSend 00726 << " bytes to send, headerCreated=" << headerCreated << endl; 00727 00728 } // if (bytesToSend > 0 || bytes.chunk || bytes.packet) 00729 else { 00730 packetFull = true; // Leave inner while loop 00731 delete sctpMsg; // T.D. 19.01.2010: Free unsent message 00732 } 00733 00734 sctpEV3 << "packetFull=" << packetFull << endl; 00735 } // while(!packetFull) 00736 00737 sctpEV3 << "bytesToSend=" << bytesToSend 00738 << " bytes.chunk=" << bytes.chunk 00739 << " bytes.packet=" << bytes.packet << endl; 00740 if (!(bytesToSend > 0 || bytes.chunk || bytes.packet)) { 00741 sendingAllowed = false; 00742 } 00743 } // while(sendingAllowed) 00744 00745 sctpEV3 << "sendAll: nothing more to send... BYE!\n"; 00746 }