|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2004 Andras Varga 00003 // 00004 // This program is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public License 00006 // as published by the Free Software Foundation; either version 2 00007 // of the License, or (at your option) any later version. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU Lesser General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU Lesser General Public License 00015 // along with this program; if not, see <http://www.gnu.org/licenses/>. 00016 // 00017 00018 00019 #include <string.h> 00020 #include <algorithm> // min,max 00021 #include "TCP_old.h" 00022 #include "TCPConnection_old.h" 00023 #include "TCPSegment.h" 00024 #include "TCPCommand_m.h" 00025 #include "IPControlInfo.h" 00026 #include "IPv6ControlInfo.h" 00027 #include "TCPSendQueue_old.h" 00028 #include "TCPReceiveQueue_old.h" 00029 #include "TCPAlgorithm_old.h" 00030 00031 using namespace tcp_old; 00032 00033 // 00034 // helper functions 00035 // 00036 00037 const char *TCPConnection::stateName(int state) 00038 { 00039 #define CASE(x) case x: s=#x+6; break 00040 const char *s = "unknown"; 00041 switch (state) 00042 { 00043 CASE(TCP_S_INIT); 00044 CASE(TCP_S_CLOSED); 00045 CASE(TCP_S_LISTEN); 00046 CASE(TCP_S_SYN_SENT); 00047 CASE(TCP_S_SYN_RCVD); 00048 CASE(TCP_S_ESTABLISHED); 00049 CASE(TCP_S_CLOSE_WAIT); 00050 CASE(TCP_S_LAST_ACK); 00051 CASE(TCP_S_FIN_WAIT_1); 00052 CASE(TCP_S_FIN_WAIT_2); 00053 CASE(TCP_S_CLOSING); 00054 CASE(TCP_S_TIME_WAIT); 00055 } 00056 return s; 00057 #undef CASE 00058 } 00059 00060 const char *TCPConnection::eventName(int event) 00061 { 00062 #define CASE(x) case x: s=#x+6; break 00063 const char *s = "unknown"; 00064 switch (event) 00065 { 00066 CASE(TCP_E_IGNORE); 00067 CASE(TCP_E_OPEN_ACTIVE); 00068 CASE(TCP_E_OPEN_PASSIVE); 00069 CASE(TCP_E_SEND); 00070 CASE(TCP_E_CLOSE); 00071 CASE(TCP_E_ABORT); 00072 CASE(TCP_E_STATUS); 00073 CASE(TCP_E_RCV_DATA); 00074 CASE(TCP_E_RCV_ACK); 00075 CASE(TCP_E_RCV_SYN); 00076 CASE(TCP_E_RCV_SYN_ACK); 00077 CASE(TCP_E_RCV_FIN); 00078 CASE(TCP_E_RCV_FIN_ACK); 00079 CASE(TCP_E_RCV_RST); 00080 CASE(TCP_E_RCV_UNEXP_SYN); 00081 CASE(TCP_E_TIMEOUT_2MSL); 00082 CASE(TCP_E_TIMEOUT_CONN_ESTAB); 00083 CASE(TCP_E_TIMEOUT_FIN_WAIT_2); 00084 } 00085 return s; 00086 #undef CASE 00087 } 00088 00089 const char *TCPConnection::indicationName(int code) 00090 { 00091 #define CASE(x) case x: s=#x+6; break 00092 const char *s = "unknown"; 00093 switch (code) 00094 { 00095 CASE(TCP_I_DATA); 00096 CASE(TCP_I_URGENT_DATA); 00097 CASE(TCP_I_ESTABLISHED); 00098 CASE(TCP_I_PEER_CLOSED); 00099 CASE(TCP_I_CLOSED); 00100 CASE(TCP_I_CONNECTION_REFUSED); 00101 CASE(TCP_I_CONNECTION_RESET); 00102 CASE(TCP_I_TIMED_OUT); 00103 CASE(TCP_I_STATUS); 00104 } 00105 return s; 00106 #undef CASE 00107 } 00108 00109 void TCPConnection::printConnBrief() 00110 { 00111 tcpEV << "Connection "; 00112 tcpEV << localAddr << ":" << localPort << " to " << remoteAddr << ":" << remotePort; 00113 tcpEV << " on app[" << appGateIndex << "],connId=" << connId; 00114 tcpEV << " in " << stateName(fsm.getState()); 00115 tcpEV << " (ptr=0x" << this << ")\n"; 00116 } 00117 00118 void TCPConnection::printSegmentBrief(TCPSegment *tcpseg) 00119 { 00120 tcpEV << "." << tcpseg->getSrcPort() << " > "; 00121 tcpEV << "." << tcpseg->getDestPort() << ": "; 00122 00123 if (tcpseg->getSynBit()) tcpEV << (tcpseg->getAckBit() ? "SYN+ACK " : "SYN "); 00124 if (tcpseg->getFinBit()) tcpEV << "FIN(+ACK) "; 00125 if (tcpseg->getRstBit()) tcpEV << (tcpseg->getAckBit() ? "RST+ACK " : "RST "); 00126 if (tcpseg->getPshBit()) tcpEV << "PSH "; 00127 00128 if (tcpseg->getPayloadLength()>0 || tcpseg->getSynBit()) 00129 { 00130 tcpEV << tcpseg->getSequenceNo() << ":" << tcpseg->getSequenceNo()+tcpseg->getPayloadLength(); 00131 tcpEV << "(" << tcpseg->getPayloadLength() << ") "; 00132 } 00133 if (tcpseg->getAckBit()) tcpEV << "ack " << tcpseg->getAckNo() << " "; 00134 tcpEV << "win " << tcpseg->getWindow() << "\n"; 00135 if (tcpseg->getUrgBit()) tcpEV << "urg " << tcpseg->getUrgentPointer() << " "; 00136 } 00137 00138 TCPConnection *TCPConnection::cloneListeningConnection() 00139 { 00140 TCPConnection *conn = new TCPConnection(tcpMain,appGateIndex,connId); 00141 00142 // following code to be kept consistent with initConnection() 00143 const char *sendQueueClass = sendQueue->getClassName(); 00144 conn->sendQueue = check_and_cast<TCPSendQueue *>(createOne(sendQueueClass)); 00145 conn->sendQueue->setConnection(conn); 00146 00147 const char *receiveQueueClass = receiveQueue->getClassName(); 00148 conn->receiveQueue = check_and_cast<TCPReceiveQueue *>(createOne(receiveQueueClass)); 00149 conn->receiveQueue->setConnection(conn); 00150 00151 const char *tcpAlgorithmClass = tcpAlgorithm->getClassName(); 00152 conn->tcpAlgorithm = check_and_cast<TCPAlgorithm *>(createOne(tcpAlgorithmClass)); 00153 conn->tcpAlgorithm->setConnection(conn); 00154 00155 conn->state = conn->tcpAlgorithm->getStateVariables(); 00156 configureStateVariables(); 00157 conn->tcpAlgorithm->initialize(); 00158 00159 // put it into LISTEN, with our localAddr/localPort 00160 conn->state->active = false; 00161 conn->state->fork = true; 00162 conn->localAddr = localAddr; 00163 conn->localPort = localPort; 00164 FSM_Goto(conn->fsm, TCP_S_LISTEN); 00165 00166 return conn; 00167 } 00168 00169 void TCPConnection::sendToIP(TCPSegment *tcpseg) 00170 { 00171 // record seq (only if we do send data) and ackno 00172 if (sndNxtVector && tcpseg->getPayloadLength()!=0) 00173 sndNxtVector->record(tcpseg->getSequenceNo()); 00174 if (sndAckVector) sndAckVector->record(tcpseg->getAckNo()); 00175 00176 // final touches on the segment before sending 00177 tcpseg->setSrcPort(localPort); 00178 tcpseg->setDestPort(remotePort); 00179 tcpseg->setByteLength(TCP_HEADER_OCTETS+tcpseg->getPayloadLength()); 00180 // TBD account for Options (once they get implemented) 00181 00182 tcpEV << "Sending: "; 00183 printSegmentBrief(tcpseg); 00184 00185 // TBD reuse next function for sending 00186 00187 if (!remoteAddr.isIPv6()) 00188 { 00189 // send over IPv4 00190 IPControlInfo *controlInfo = new IPControlInfo(); 00191 controlInfo->setProtocol(IP_PROT_TCP); 00192 controlInfo->setSrcAddr(localAddr.get4()); 00193 controlInfo->setDestAddr(remoteAddr.get4()); 00194 tcpseg->setControlInfo(controlInfo); 00195 00196 tcpMain->send(tcpseg,"ipOut"); 00197 } 00198 else 00199 { 00200 // send over IPv6 00201 IPv6ControlInfo *controlInfo = new IPv6ControlInfo(); 00202 controlInfo->setProtocol(IP_PROT_TCP); 00203 controlInfo->setSrcAddr(localAddr.get6()); 00204 controlInfo->setDestAddr(remoteAddr.get6()); 00205 tcpseg->setControlInfo(controlInfo); 00206 00207 tcpMain->send(tcpseg,"ipv6Out"); 00208 } 00209 } 00210 00211 void TCPConnection::sendToIP(TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest) 00212 { 00213 tcpEV << "Sending: "; 00214 printSegmentBrief(tcpseg); 00215 00216 if (!dest.isIPv6()) 00217 { 00218 // send over IPv4 00219 IPControlInfo *controlInfo = new IPControlInfo(); 00220 controlInfo->setProtocol(IP_PROT_TCP); 00221 controlInfo->setSrcAddr(src.get4()); 00222 controlInfo->setDestAddr(dest.get4()); 00223 tcpseg->setControlInfo(controlInfo); 00224 00225 check_and_cast<TCP *>(simulation.getContextModule())->send(tcpseg,"ipOut"); 00226 } 00227 else 00228 { 00229 // send over IPv6 00230 IPv6ControlInfo *controlInfo = new IPv6ControlInfo(); 00231 controlInfo->setProtocol(IP_PROT_TCP); 00232 controlInfo->setSrcAddr(src.get6()); 00233 controlInfo->setDestAddr(dest.get6()); 00234 tcpseg->setControlInfo(controlInfo); 00235 00236 check_and_cast<TCP *>(simulation.getContextModule())->send(tcpseg,"ipv6Out"); 00237 } 00238 } 00239 00240 TCPSegment *TCPConnection::createTCPSegment(const char *name) 00241 { 00242 return new TCPSegment(name); 00243 } 00244 00245 void TCPConnection::signalConnectionTimeout() 00246 { 00247 sendIndicationToApp(TCP_I_TIMED_OUT); 00248 } 00249 00250 void TCPConnection::sendIndicationToApp(int code) 00251 { 00252 tcpEV << "Notifying app: " << indicationName(code) << "\n"; 00253 cMessage *msg = new cMessage(indicationName(code)); 00254 msg->setKind(code); 00255 TCPCommand *ind = new TCPCommand(); 00256 ind->setConnId(connId); 00257 msg->setControlInfo(ind); 00258 tcpMain->send(msg, "appOut", appGateIndex); 00259 } 00260 00261 void TCPConnection::sendEstabIndicationToApp() 00262 { 00263 tcpEV << "Notifying app: " << indicationName(TCP_I_ESTABLISHED) << "\n"; 00264 cMessage *msg = new cMessage(indicationName(TCP_I_ESTABLISHED)); 00265 msg->setKind(TCP_I_ESTABLISHED); 00266 00267 TCPConnectInfo *ind = new TCPConnectInfo(); 00268 ind->setConnId(connId); 00269 ind->setLocalAddr(localAddr); 00270 ind->setRemoteAddr(remoteAddr); 00271 ind->setLocalPort(localPort); 00272 ind->setRemotePort(remotePort); 00273 00274 msg->setControlInfo(ind); 00275 tcpMain->send(msg, "appOut", appGateIndex); 00276 } 00277 00278 void TCPConnection::sendToApp(cMessage *msg) 00279 { 00280 tcpMain->send(msg, "appOut", appGateIndex); 00281 } 00282 00283 void TCPConnection::initConnection(TCPOpenCommand *openCmd) 00284 { 00285 // create send/receive queues 00286 const char *sendQueueClass = openCmd->getSendQueueClass(); 00287 if (!sendQueueClass || !sendQueueClass[0]) 00288 sendQueueClass = tcpMain->par("sendQueueClass"); 00289 sendQueue = check_and_cast<TCPSendQueue *>(createOne(sendQueueClass)); 00290 sendQueue->setConnection(this); 00291 00292 const char *receiveQueueClass = openCmd->getReceiveQueueClass(); 00293 if (!receiveQueueClass || !receiveQueueClass[0]) 00294 receiveQueueClass = tcpMain->par("receiveQueueClass"); 00295 receiveQueue = check_and_cast<TCPReceiveQueue *>(createOne(receiveQueueClass)); 00296 receiveQueue->setConnection(this); 00297 00298 // create algorithm 00299 const char *tcpAlgorithmClass = openCmd->getTcpAlgorithmClass(); 00300 if (!tcpAlgorithmClass || !tcpAlgorithmClass[0]) 00301 tcpAlgorithmClass = tcpMain->par("tcpAlgorithmClass"); 00302 tcpAlgorithm = check_and_cast<TCPAlgorithm *>(createOne(tcpAlgorithmClass)); 00303 tcpAlgorithm->setConnection(this); 00304 00305 // create state block 00306 state = tcpAlgorithm->getStateVariables(); 00307 configureStateVariables(); 00308 tcpAlgorithm->initialize(); 00309 } 00310 00311 void TCPConnection::configureStateVariables() 00312 { 00313 state->snd_mss = tcpMain->par("mss").longValue(); // TODO: mss=-1 should mean autodetect 00314 long advertisedWindowPar = tcpMain->par("advertisedWindow").longValue(); 00315 if (advertisedWindowPar > TCP_MAX_WIN || advertisedWindowPar <= 0) 00316 throw cRuntimeError("Invalid advertisedWindow parameter: %d", advertisedWindowPar); 00317 state->rcv_wnd = advertisedWindowPar; 00318 } 00319 00320 void TCPConnection::selectInitialSeqNum() 00321 { 00322 // set the initial send sequence number 00323 state->iss = (unsigned long)fmod(SIMTIME_DBL(simTime())*250000.0, 1.0+(double)(unsigned)0xffffffffUL) & 0xffffffffUL; 00324 00325 state->snd_una = state->snd_nxt = state->snd_max = state->iss; 00326 00327 sendQueue->init(state->iss+1); // +1 is for SYN 00328 } 00329 00330 bool TCPConnection::isSegmentAcceptable(TCPSegment *tcpseg) 00331 { 00332 // check that segment entirely falls in receive window 00333 //FIXME probably not this simple, see old code segAccept() below... 00334 return seqGE(tcpseg->getSequenceNo(),state->rcv_nxt) && 00335 seqLE(tcpseg->getSequenceNo()+tcpseg->getPayloadLength(),state->rcv_nxt+state->rcv_wnd); 00336 } 00337 00338 void TCPConnection::sendSyn() 00339 { 00340 if (remoteAddr.isUnspecified() || remotePort==-1) 00341 opp_error("Error processing command OPEN_ACTIVE: foreign socket unspecified"); 00342 if (localPort==-1) 00343 opp_error("Error processing command OPEN_ACTIVE: local port unspecified"); 00344 00345 // create segment 00346 TCPSegment *tcpseg = createTCPSegment("SYN"); 00347 tcpseg->setSequenceNo(state->iss); 00348 tcpseg->setSynBit(true); 00349 tcpseg->setWindow(state->rcv_wnd); 00350 00351 state->snd_max = state->snd_nxt = state->iss+1; 00352 00353 // send it 00354 sendToIP(tcpseg); 00355 } 00356 00357 void TCPConnection::sendSynAck() 00358 { 00359 // create segment 00360 TCPSegment *tcpseg = createTCPSegment("SYN+ACK"); 00361 tcpseg->setSequenceNo(state->iss); 00362 tcpseg->setAckNo(state->rcv_nxt); 00363 tcpseg->setSynBit(true); 00364 tcpseg->setAckBit(true); 00365 tcpseg->setWindow(state->rcv_wnd); 00366 00367 state->snd_max = state->snd_nxt = state->iss+1; 00368 00369 // send it 00370 sendToIP(tcpseg); 00371 00372 // notify 00373 tcpAlgorithm->ackSent(); 00374 } 00375 00376 void TCPConnection::sendRst(uint32 seqNo) 00377 { 00378 sendRst(seqNo, localAddr, remoteAddr, localPort, remotePort); 00379 } 00380 00381 void TCPConnection::sendRst(uint32 seq, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort) 00382 { 00383 TCPSegment *tcpseg = createTCPSegment("RST"); 00384 00385 tcpseg->setSrcPort(srcPort); 00386 tcpseg->setDestPort(destPort); 00387 00388 tcpseg->setRstBit(true); 00389 tcpseg->setSequenceNo(seq); 00390 00391 // send it 00392 sendToIP(tcpseg, src, dest); 00393 } 00394 00395 void TCPConnection::sendRstAck(uint32 seq, uint32 ack, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort) 00396 { 00397 TCPSegment *tcpseg = createTCPSegment("RST+ACK"); 00398 00399 tcpseg->setSrcPort(srcPort); 00400 tcpseg->setDestPort(destPort); 00401 00402 tcpseg->setRstBit(true); 00403 tcpseg->setAckBit(true); 00404 tcpseg->setSequenceNo(seq); 00405 tcpseg->setAckNo(ack); 00406 00407 // send it 00408 sendToIP(tcpseg, src, dest); 00409 00410 // notify 00411 tcpAlgorithm->ackSent(); 00412 } 00413 00414 void TCPConnection::sendAck() 00415 { 00416 TCPSegment *tcpseg = createTCPSegment("ACK"); 00417 00418 tcpseg->setAckBit(true); 00419 tcpseg->setSequenceNo(state->snd_nxt); 00420 tcpseg->setAckNo(state->rcv_nxt); 00421 tcpseg->setWindow(state->rcv_wnd); 00422 00423 // send it 00424 sendToIP(tcpseg); 00425 00426 // notify 00427 tcpAlgorithm->ackSent(); 00428 } 00429 00430 void TCPConnection::sendFin() 00431 { 00432 TCPSegment *tcpseg = createTCPSegment("FIN"); 00433 00434 // Note: ACK bit *must* be set for both FIN and FIN+ACK. What makes 00435 // the difference for FIN+ACK is that its ackNo acks the remote TCP's FIN. 00436 tcpseg->setFinBit(true); 00437 tcpseg->setAckBit(true); 00438 tcpseg->setAckNo(state->rcv_nxt); 00439 tcpseg->setSequenceNo(state->snd_nxt); 00440 tcpseg->setWindow(state->rcv_wnd); 00441 00442 // send it 00443 sendToIP(tcpseg); 00444 00445 // notify 00446 tcpAlgorithm->ackSent(); 00447 } 00448 00449 void TCPConnection::sendSegment(uint32 bytes) 00450 { 00451 ulong buffered = sendQueue->getBytesAvailable(state->snd_nxt); 00452 if (bytes > buffered) // last segment? 00453 bytes = buffered; 00454 00455 // send one segment of 'bytes' bytes from snd_nxt, and advance snd_nxt 00456 TCPSegment *tcpseg = sendQueue->createSegmentWithBytes(state->snd_nxt, bytes); 00457 tcpseg->setAckNo(state->rcv_nxt); 00458 tcpseg->setAckBit(true); 00459 tcpseg->setWindow(state->rcv_wnd); 00460 // TBD when to set PSH bit? 00461 // TBD set URG bit if needed 00462 ASSERT(bytes==tcpseg->getPayloadLength()); 00463 00464 state->snd_nxt += bytes; 00465 00466 // check if afterRto bit can be reset 00467 if (state->afterRto && seqGE(state->snd_nxt, state->snd_max)) 00468 state->afterRto = false; 00469 00470 if (state->send_fin && state->snd_nxt==state->snd_fin_seq) 00471 { 00472 tcpEV << "Setting FIN on segment\n"; 00473 tcpseg->setFinBit(true); 00474 state->snd_nxt = state->snd_fin_seq+1; 00475 } 00476 00477 sendToIP(tcpseg); 00478 } 00479 00480 bool TCPConnection::sendData(bool fullSegmentsOnly, int congestionWindow) 00481 { 00482 if (!state->afterRto) 00483 { 00484 // we'll start sending from snd_max 00485 state->snd_nxt = state->snd_max; 00486 } 00487 00488 // check how many bytes we have 00489 ulong buffered = sendQueue->getBytesAvailable(state->snd_nxt); 00490 if (buffered==0) 00491 return false; 00492 00493 // maxWindow is smaller of (snd_wnd, congestionWindow) 00494 long maxWindow = state->snd_wnd; 00495 if (congestionWindow>=0 && maxWindow > congestionWindow) 00496 maxWindow = congestionWindow; 00497 00498 // effectiveWindow: number of bytes we're allowed to send now 00499 long effectiveWin = maxWindow - (state->snd_nxt - state->snd_una); 00500 if (effectiveWin <= 0) 00501 { 00502 tcpEV << "Effective window is zero (advertised window " << state->snd_wnd << 00503 ", congestion window " << congestionWindow << "), cannot send.\n"; 00504 return false; 00505 } 00506 00507 ulong bytesToSend = effectiveWin; 00508 00509 if (bytesToSend > buffered) 00510 bytesToSend = buffered; 00511 00512 if (fullSegmentsOnly && bytesToSend < state->snd_mss && buffered > (ulong) effectiveWin) // last segment could be less than state->snd_mss 00513 { 00514 tcpEV << "Cannot send, not enough data for a full segment (SMSS=" << state->snd_mss 00515 << ", in buffer " << buffered << ")\n"; 00516 return false; 00517 } 00518 00519 // start sending 'bytesToSend' bytes 00520 tcpEV << "Will send " << bytesToSend << " bytes (effectiveWindow " << effectiveWin 00521 << ", in buffer " << buffered << " bytes)\n"; 00522 00523 uint32 old_snd_nxt = state->snd_nxt; 00524 ASSERT(bytesToSend>0); 00525 00526 #ifdef TCP_SENDFRAGMENTS /* normally undefined */ 00527 // make agressive use of the window until the last byte 00528 while (bytesToSend>0) 00529 { 00530 ulong bytes = std::min(bytesToSend, state->snd_mss); 00531 sendSegment(bytes); 00532 bytesToSend -= bytes; 00533 } 00534 #else 00535 // send <MSS segments only if it's the only segment we can send now 00536 // FIXME this should probably obey Nagle's alg -- to be checked 00537 if (bytesToSend <= state->snd_mss) 00538 { 00539 sendSegment(bytesToSend); 00540 } 00541 else 00542 { 00543 // send whole segments only (nagle_enabled) 00544 while (bytesToSend>=state->snd_mss) 00545 { 00546 sendSegment(state->snd_mss); 00547 bytesToSend -= state->snd_mss; 00548 } 00549 // check how many bytes we have - last segment could be less than state->snd_mss 00550 buffered = sendQueue->getBytesAvailable(state->snd_nxt); 00551 if (bytesToSend==buffered && buffered!=0) // last segment? 00552 sendSegment(bytesToSend); 00553 else if (bytesToSend>0) 00554 tcpEV << bytesToSend << " bytes of space left in effectiveWindow\n"; 00555 } 00556 #endif 00557 00558 // remember highest seq sent (snd_nxt may be set back on retransmission, 00559 // but we'll need snd_max to check validity of ACKs -- they must ack 00560 // something we really sent) 00561 if (seqGreater(state->snd_nxt, state->snd_max)) 00562 state->snd_max = state->snd_nxt; 00563 if (unackedVector) unackedVector->record(state->snd_max - state->snd_una); 00564 00565 // notify (once is enough) 00566 tcpAlgorithm->ackSent(); 00567 tcpAlgorithm->dataSent(old_snd_nxt); 00568 00569 return true; 00570 } 00571 00572 bool TCPConnection::sendProbe() 00573 { 00574 // we'll start sending from snd_max 00575 state->snd_nxt = state->snd_max; 00576 00577 // check we have 1 byte to send 00578 if (sendQueue->getBytesAvailable(state->snd_nxt)==0) 00579 { 00580 tcpEV << "Cannot send probe because send buffer is empty\n"; 00581 return false; 00582 } 00583 00584 uint32 old_snd_nxt = state->snd_nxt; 00585 00586 tcpEV << "Sending 1 byte as probe, with seq=" << state->snd_nxt << "\n"; 00587 sendSegment(1); 00588 00589 // remember highest seq sent (snd_nxt may be set back on retransmission, 00590 // but we'll need snd_max to check validity of ACKs -- they must ack 00591 // something we really sent) 00592 state->snd_max = state->snd_nxt; 00593 if (unackedVector) unackedVector->record(state->snd_max - state->snd_una); 00594 00595 // notify 00596 tcpAlgorithm->ackSent(); 00597 tcpAlgorithm->dataSent(old_snd_nxt); 00598 00599 return true; 00600 } 00601 00602 void TCPConnection::retransmitOneSegment(bool called_at_rto) 00603 { 00604 // retransmit one segment at snd_una, and set snd_nxt accordingly (if not called at RTO) 00605 uint32 old_snd_nxt = state->snd_nxt; 00606 00607 state->snd_nxt = state->snd_una; 00608 00609 ulong bytes = std::min(state->snd_mss, state->snd_max - state->snd_nxt); 00610 ASSERT(bytes!=0); 00611 00612 sendSegment(bytes); 00613 00614 if (!called_at_rto) 00615 { 00616 if (seqGreater(old_snd_nxt, state->snd_nxt)) 00617 state->snd_nxt = old_snd_nxt; 00618 } 00619 // notify 00620 tcpAlgorithm->ackSent(); 00621 } 00622 00623 void TCPConnection::retransmitData() 00624 { 00625 // retransmit everything from snd_una 00626 state->snd_nxt = state->snd_una; 00627 00628 uint32 bytesToSend = state->snd_max - state->snd_nxt; 00629 ASSERT(bytesToSend!=0); 00630 00631 // TBD - avoid to send more than allowed - check cwnd and rwnd before retransmitting data! 00632 while (bytesToSend>0) 00633 { 00634 uint32 bytes = std::min(bytesToSend, state->snd_mss); 00635 bytes = std::min(bytes, (uint32)(sendQueue->getBytesAvailable(state->snd_nxt))); 00636 sendSegment(bytes); 00637 // Do not send packets after the FIN. 00638 // fixes bug that occurs in examples/inet/bulktransfer at event #64043 T=13.861159213744 00639 if (state->send_fin && state->snd_nxt==state->snd_fin_seq+1) 00640 break; 00641 bytesToSend -= bytes; 00642 } 00643 } 00644 00645