SCTPAssociationSendAll.cc

Go to the documentation of this file.
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 }