00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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();
00044 const uint32 num = (uint32)floor((double)(pathVar->pmtu - 32) / (ums + SCTP_DATA_CHUNK_LENGTH));
00045 if (num * ums > state->peerRwnd) {
00046
00047 bytesToSend = 0;
00048 }
00049 else {
00050
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
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
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
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
00180 state->ackState = sackFrequency;
00181 sackOnly = sackWithData = true;
00182 }
00183 if (state->ackState >= sackFrequency) {
00184 sackOnly = sackWithData = true;
00185 }
00186 else if (SackTimer->isScheduled()) {
00187 sackOnly = false;
00188 sackWithData = true;
00189 }
00190 }
00191
00192
00193 void SCTPAssociation::sendOnAllPaths(SCTPPathVariables* firstPath)
00194 {
00195
00196 if(firstPath != NULL) {
00197 sendOnPath(firstPath);
00198 }
00199
00200
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
00226 if (!state->firstDataSent) {
00227 bytes.chunk = true;
00228 }
00229
00230
00231 else if (state->peerWindowFull)
00232 {
00233 if (path->outstandingBytes == 0) {
00234
00235 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): zeroWindowProbing" << endl;
00236 state->zeroWindowProbing = true;
00237 bytes.chunk = true;
00238 }
00239 }
00240
00241
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;
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 {
00267 bytes.packet = true;
00268 sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): allowance<=0: retransmit one packet" << endl;
00269 }
00270 }
00271
00272
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
00308 SCTPPathVariables* path = NULL;
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;
00321 uint32 scount = 0;
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
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
00342 path = choosePathForRetransmission();
00343 assert(path != NULL);
00344 rtxActive = true;
00345 }
00346 else {
00347 if (pathId == NULL) {
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;
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
00370 sctpEV3 << "No DATA chunk available!" << endl;
00371 if (!sackOnly) {
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
00385
00386 if (state->sctpMsg)
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
00394 sctpMsg->setByteLength(SCTP_COMMON_HEADER);
00395 packetBytes = 0;
00396 headerCreated = true;
00397 }
00398
00399
00400 if (sackWithData || sackOnly)
00401 {
00402
00403 assert(headerCreated==true);
00404 sackChunk = createSack();
00405 chunksAdded++;
00406 totalChunksSent++;
00407
00408
00409
00410 sctpMsg->addChunk(sackChunk);
00411 sackAdded = true;
00412 if (sackOnly)
00413 {
00414
00415
00416 state->ackState = 0;
00417
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
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
00448 int32 allowance = path->pmtu;
00449 if ((bytesToSend > 0) || (bytes.chunk) || (bytes.packet)) {
00450
00451 }
00452 else {
00453
00454 allowance = 0;
00455 bytesToSend = 0;
00456 }
00457
00458 if ((allowance > 0) || (bytes.chunk) || (bytes.packet)) {
00459 bool firstTime = false;
00460
00461
00462
00463
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);
00486 }
00487 }
00488
00489
00490 else if ( ((scount > 0) && (!state->nagleEnabled)) ||
00491 ((uint32)scount >= path->pmtu - 32 - 20) ||
00492 ((scount > 0) && (state->nagleEnabled) && (outstandingBytes == 0)) ) {
00493
00494 if(path == state->getPrimaryPath()) {
00495
00496
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
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
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
00530 else {
00531
00532 if (chunksAdded == 0) {
00533
00534 if (state->sctpMsg == sctpMsg)
00535 {
00536 state->sctpMsg = NULL;
00537 state->packetBytes = 0;
00538 }
00539 packetFull = true;
00540 }
00541 else {
00542
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
00551 packetFull = true;
00552 sctpEV3 << "sendAll: packetFull: msg length = " << sctpMsg->getBitLength() / 8 + 20 << "\n";
00553 }
00554 }
00555 }
00556 }
00557
00558
00559
00560 if (datVar != NULL && !packetFull) {
00561
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();
00577
00578
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
00592 }
00593 else {
00594 sctpEV3 << "sendAll: size of retransmissionQ=" << retransmissionQ->getQueueSize() << "\n";
00595 unackChunk(datVar);
00596 increaseOutstandingBytes(datVar, path);
00597 }
00598 }
00599
00600
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
00609 totalChunksSent++;
00610 chunksAdded++;
00611 dataChunksAdded++;
00612 sctpMsg->addChunk(chunkPtr);
00613 if(nextChunkFitsIntoPacket(path->pmtu - sctpMsg->getByteLength() - 20) == false) {
00614
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;
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
00659 else {
00660
00661 if (chunksAdded == 0) {
00662 packetFull = true;
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
00673 if (packetFull) {
00674 if(chunksAdded == 0) {
00675 delete sctpMsg;
00676 sendingAllowed = false;
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
00686
00687 if (dataChunksAdded > 0) {
00688 if (!path->T3_RtxTimer->isScheduled()) {
00689
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
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 }
00729 else {
00730 packetFull = true;
00731 delete sctpMsg;
00732 }
00733
00734 sctpEV3 << "packetFull=" << packetFull << endl;
00735 }
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 }
00744
00745 sctpEV3 << "sendAll: nothing more to send... BYE!\n";
00746 }