old/TCPConnectionUtil.cc

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