old/TCPConnectionRcvSegment.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 "TCP_old.h"
00021 #include "TCPConnection_old.h"
00022 #include "TCPSegment.h"
00023 #include "TCPCommand_m.h"
00024 #include "TCPSendQueue_old.h"
00025 #include "TCPReceiveQueue_old.h"
00026 #include "TCPAlgorithm_old.h"
00027 
00028 using namespace tcp_old;
00029 
00030 bool TCPConnection::tryFastRoute(TCPSegment *tcpseg)
00031 {
00032     // fast route processing not yet implemented
00033     return false;
00034 }
00035 
00036 
00037 void TCPConnection::segmentArrivalWhileClosed(TCPSegment *tcpseg, IPvXAddress srcAddr, IPvXAddress destAddr)
00038 {
00039     tcpEV << "Seg arrived: ";
00040     printSegmentBrief(tcpseg);
00041 
00042     // This segment doesn't belong to any connection, so this object
00043     // must be a temp object created solely for the purpose of calling us
00044     ASSERT(state==NULL);
00045     tcpEV << "Segment doesn't belong to any existing connection\n";
00046 
00047     // RFC 793:
00048     //"
00049     // all data in the incoming segment is discarded.  An incoming
00050     // segment containing a RST is discarded.  An incoming segment not
00051     // containing a RST causes a RST to be sent in response.  The
00052     // acknowledgment and sequence field values are selected to make the
00053     // reset sequence acceptable to the TCP that sent the offending
00054     // segment.
00055     //
00056     // If the ACK bit is off, sequence number zero is used,
00057     //
00058     //    <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
00059     //
00060     // If the ACK bit is on,
00061     //
00062     //    <SEQ=SEG.ACK><CTL=RST>
00063     //"
00064     if (tcpseg->getRstBit())
00065     {
00066         tcpEV << "RST bit set: dropping segment\n";
00067         return;
00068     }
00069 
00070     if (!tcpseg->getAckBit())
00071     {
00072         tcpEV << "ACK bit not set: sending RST+ACK\n";
00073         uint32 ackNo = tcpseg->getSequenceNo() + (uint32)tcpseg->getPayloadLength();
00074         sendRstAck(0,ackNo,destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort());
00075     }
00076     else
00077     {
00078         tcpEV << "ACK bit set: sending RST\n";
00079         sendRst(tcpseg->getAckNo(),destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort());
00080     }
00081 }
00082 
00083 TCPEventCode TCPConnection::process_RCV_SEGMENT(TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
00084 {
00085     tcpEV << "Seg arrived: ";
00086     printSegmentBrief(tcpseg);
00087     tcpEV << "TCB: " << state->info() << "\n";
00088 
00089     if (rcvSeqVector) rcvSeqVector->record(tcpseg->getSequenceNo());
00090     if (rcvAckVector) rcvAckVector->record(tcpseg->getAckNo());
00091 
00092     //
00093     // Note: this code is organized exactly as RFC 793, section "3.9 Event
00094     // Processing", subsection "SEGMENT ARRIVES".
00095     //
00096     TCPEventCode event;
00097     if (fsm.getState()==TCP_S_LISTEN)
00098     {
00099         event = processSegmentInListen(tcpseg, src, dest);
00100     }
00101     else if (fsm.getState()==TCP_S_SYN_SENT)
00102     {
00103         event = processSegmentInSynSent(tcpseg, src, dest);
00104     }
00105     else
00106     {
00107         // RFC 793 steps "first check sequence number", "second check the RST bit", etc
00108         event = processSegment1stThru8th(tcpseg);
00109     }
00110     delete tcpseg;
00111     return event;
00112 }
00113 
00114 TCPEventCode TCPConnection::processSegment1stThru8th(TCPSegment *tcpseg)
00115 {
00116     //
00117     // RFC 793: first check sequence number
00118     //
00119     bool acceptable = isSegmentAcceptable(tcpseg);
00120     if (!acceptable)
00121     {
00122         //"
00123         // If an incoming segment is not acceptable, an acknowledgment
00124         // should be sent in reply (unless the RST bit is set, if so drop
00125         // the segment and return):
00126         //
00127         //  <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
00128         //"
00129         if (tcpseg->getRstBit())
00130         {
00131             tcpEV << "RST with unacceptable seqNum: dropping\n";
00132         }
00133         else
00134         {
00135             tcpEV << "Segment seqNum not acceptable, sending ACK with current receive seq\n";
00136             sendAck();
00137         }
00138         return TCP_E_IGNORE;
00139     }
00140 
00141     //
00142     // RFC 793: second check the RST bit,
00143     //
00144     if (tcpseg->getRstBit())
00145     {
00146         // Note: if we come from LISTEN, processSegmentInListen() has already handled RST.
00147         switch (fsm.getState())
00148         {
00149             case TCP_S_SYN_RCVD:
00150                 //"
00151                 // If this connection was initiated with a passive OPEN (i.e.,
00152                 // came from the LISTEN state), then return this connection to
00153                 // LISTEN state and return.  The user need not be informed.  If
00154                 // this connection was initiated with an active OPEN (i.e., came
00155                 // from SYN-SENT state) then the connection was refused, signal
00156                 // the user "connection refused".  In either case, all segments
00157                 // on the retransmission queue should be removed.  And in the
00158                 // active OPEN case, enter the CLOSED state and delete the TCB,
00159                 // and return.
00160                 //"
00161                 return processRstInSynReceived(tcpseg);
00162 
00163             case TCP_S_ESTABLISHED:
00164             case TCP_S_FIN_WAIT_1:
00165             case TCP_S_FIN_WAIT_2:
00166             case TCP_S_CLOSE_WAIT:
00167                 //"
00168                 // If the RST bit is set then, any outstanding RECEIVEs and SEND
00169                 // should receive "reset" responses.  All segment queues should be
00170                 // flushed.  Users should also receive an unsolicited general
00171                 // "connection reset" signal.
00172                 //
00173                 // Enter the CLOSED state, delete the TCB, and return.
00174                 //"
00175                 tcpEV << "RST: performing connection reset, closing connection\n";
00176                 sendIndicationToApp(TCP_I_CONNECTION_RESET);
00177                 return TCP_E_RCV_RST;  // this will trigger state transition
00178 
00179             case TCP_S_CLOSING:
00180             case TCP_S_LAST_ACK:
00181             case TCP_S_TIME_WAIT:
00182                 //"
00183                 // enter the CLOSED state, delete the TCB, and return.
00184                 //"
00185                 tcpEV << "RST: closing connection\n";
00186                 if (fsm.getState()!=TCP_S_TIME_WAIT)
00187                     sendIndicationToApp(TCP_I_CLOSED); // in TIME_WAIT, we've already sent it
00188                 return TCP_E_RCV_RST; // this will trigger state transition
00189 
00190             default: ASSERT(0);
00191         }
00192     }
00193 
00194     // RFC 793: third check security and precedence
00195     // This step is ignored.
00196 
00197     //
00198     // RFC 793: fourth, check the SYN bit,
00199     //
00200     if (tcpseg->getSynBit())
00201     {
00202         //"
00203         // If the SYN is in the window it is an error, send a reset, any
00204         // outstanding RECEIVEs and SEND should receive "reset" responses,
00205         // all segment queues should be flushed, the user should also
00206         // receive an unsolicited general "connection reset" signal, enter
00207         // the CLOSED state, delete the TCB, and return.
00208         //
00209         // If the SYN is not in the window this step would not be reached
00210         // and an ack would have been sent in the first step (sequence
00211         // number check).
00212         //"
00213 
00214         ASSERT(isSegmentAcceptable(tcpseg));  // assert SYN is in the window
00215         tcpEV << "SYN is in the window: performing connection reset, closing connection\n";
00216         sendIndicationToApp(TCP_I_CONNECTION_RESET);
00217         return TCP_E_RCV_UNEXP_SYN;
00218     }
00219 
00220     //
00221     // RFC 793: fifth check the ACK field,
00222     //
00223     if (!tcpseg->getAckBit())
00224     {
00225         // if the ACK bit is off drop the segment and return
00226         tcpEV << "ACK not set, dropping segment\n";
00227         return TCP_E_IGNORE;
00228     }
00229 
00230     uint32 old_snd_una = state->snd_una;
00231 
00232     TCPEventCode event = TCP_E_IGNORE;
00233 
00234     if (fsm.getState()==TCP_S_SYN_RCVD)
00235     {
00236         //"
00237         // If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state
00238         // and continue processing.
00239         //
00240         // If the segment acknowledgment is not acceptable, form a
00241         // reset segment,
00242         //
00243         //  <SEQ=SEG.ACK><CTL=RST>
00244         //
00245         // and send it.
00246         //"
00247         if (!seqLE(state->snd_una,tcpseg->getAckNo()) || !seqLE(tcpseg->getAckNo(),state->snd_nxt))
00248         {
00249             sendRst(tcpseg->getAckNo());
00250             return TCP_E_IGNORE;
00251         }
00252 
00253         // notify tcpAlgorithm and app layer
00254         tcpAlgorithm->established(false);
00255         sendEstabIndicationToApp();
00256 
00257         // This will trigger transition to ESTABLISHED. Timers and notifying
00258         // app will be taken care of in stateEntered().
00259         event = TCP_E_RCV_ACK;
00260     }
00261 
00262     uint32 old_snd_nxt = state->snd_nxt; // later we'll need to see if snd_nxt changed
00263     // Note: If one of the last data segments is lost while already in LAST-ACK state (e.g. if using TCPEchoApps)
00264     // TCP must be able to process acceptable acknowledgments, however please note RFC 793, page 73:
00265         // "LAST-ACK STATE
00266     //    The only thing that can arrive in this state is an
00267     //    acknowledgment of our FIN.  If our FIN is now acknowledged,
00268     //    delete the TCB, enter the CLOSED state, and return."
00269     if (fsm.getState()==TCP_S_SYN_RCVD || fsm.getState()==TCP_S_ESTABLISHED ||
00270         fsm.getState()==TCP_S_FIN_WAIT_1 || fsm.getState()==TCP_S_FIN_WAIT_2 ||
00271         fsm.getState()==TCP_S_CLOSE_WAIT || fsm.getState()==TCP_S_CLOSING || fsm.getState()==TCP_S_LAST_ACK)
00272     {
00273         //
00274         // ESTABLISHED processing:
00275         //"
00276         //  If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
00277         //  Any segments on the retransmission queue which are thereby
00278         //  entirely acknowledged are removed.  Users should receive
00279         //  positive acknowledgments for buffers which have been SENT and
00280         //  fully acknowledged (i.e., SEND buffer should be returned with
00281         //  "ok" response).  If the ACK is a duplicate
00282         //  (SEG.ACK < SND.UNA), it can be ignored.  If the ACK acks
00283         //  something not yet sent (SEG.ACK > SND.NXT) then send an ACK,
00284         //  drop the segment, and return.
00285         //
00286         //  If SND.UNA < SEG.ACK =< SND.NXT, the send window should be
00287         //  updated.  If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and
00288         //  SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set
00289         //  SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK.
00290         //
00291         //  Note that SND.WND is an offset from SND.UNA, that SND.WL1
00292         //  records the sequence number of the last segment used to update
00293         //  SND.WND, and that SND.WL2 records the acknowledgment number of
00294         //  the last segment used to update SND.WND.  The check here
00295         //  prevents using old segments to update the window.
00296         //"
00297         bool ok = processAckInEstabEtc(tcpseg);
00298         if (!ok)
00299             return TCP_E_IGNORE;  // if acks something not yet sent, drop it
00300     }
00301 
00302     if ((fsm.getState()==TCP_S_FIN_WAIT_1 && state->fin_ack_rcvd))
00303     {
00304         //"
00305         // FIN-WAIT-1 STATE
00306         //   In addition to the processing for the ESTABLISHED state, if
00307         //   our FIN is now acknowledged then enter FIN-WAIT-2 and continue
00308         //   processing in that state.
00309         //"
00310         event = TCP_E_RCV_ACK;  // will trigger transition to FIN-WAIT-2
00311     }
00312 
00313     if (fsm.getState()==TCP_S_FIN_WAIT_2)
00314     {
00315         //"
00316         // FIN-WAIT-2 STATE
00317         //  In addition to the processing for the ESTABLISHED state, if
00318         //  the retransmission queue is empty, the user's CLOSE can be
00319         //  acknowledged ("ok") but do not delete the TCB.
00320         //"
00321         // nothing to do here (in our model, used commands don't need to be
00322         // acknowledged)
00323     }
00324 
00325     if (fsm.getState()==TCP_S_CLOSING)
00326     {
00327         //"
00328         // In addition to the processing for the ESTABLISHED state, if
00329         // the ACK acknowledges our FIN then enter the TIME-WAIT state,
00330         // otherwise ignore the segment.
00331         //"
00332         if (state->fin_ack_rcvd)
00333         {
00334             tcpEV << "Our FIN acked -- can go to TIME_WAIT now\n";
00335             event = TCP_E_RCV_ACK;  // will trigger transition to TIME-WAIT
00336             scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);  // start timer
00337 
00338             // we're entering TIME_WAIT, so we can signal CLOSED the user
00339             // (the only thing left to do is wait until the 2MSL timer expires)
00340             sendIndicationToApp(TCP_I_CLOSED);
00341         }
00342     }
00343 
00344     if (fsm.getState()==TCP_S_LAST_ACK)
00345     {
00346         //"
00347         // The only thing that can arrive in this state is an
00348         // acknowledgment of our FIN.  If our FIN is now acknowledged,
00349         // delete the TCB, enter the CLOSED state, and return.
00350         //"
00351         if (state->send_fin && tcpseg->getAckNo()==state->snd_fin_seq+1)
00352         {
00353             tcpEV << "Last ACK arrived\n";
00354             sendIndicationToApp(TCP_I_CLOSED);
00355             return TCP_E_RCV_ACK; // will trigger transition to CLOSED
00356         }
00357     }
00358 
00359     if (fsm.getState()==TCP_S_TIME_WAIT)
00360     {
00361         //"
00362         // The only thing that can arrive in this state is a
00363         // retransmission of the remote FIN.  Acknowledge it, and restart
00364         // the 2 MSL timeout.
00365         //"
00366         // And we are staying in the TIME_WAIT state.
00367         //
00368         sendAck();
00369         cancelEvent(the2MSLTimer);
00370         scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00371     }
00372 
00373     //
00374     // RFC 793: sixth, check the URG bit,
00375     //
00376     if (tcpseg->getUrgBit() && (fsm.getState()==TCP_S_ESTABLISHED || fsm.getState()==TCP_S_FIN_WAIT_1 ||
00377         fsm.getState()==TCP_S_FIN_WAIT_2))
00378     {
00379         //"
00380         // If the URG bit is set, RCV.UP <- max(RCV.UP,SEG.UP), and signal
00381         // the user that the remote side has urgent data if the urgent
00382         // pointer (RCV.UP) is in advance of the data consumed.  If the
00383         // user has already been signaled (or is still in the "urgent
00384         // mode") for this continuous sequence of urgent data, do not
00385         // signal the user again.
00386         //"
00387 
00388         // TBD: URG currently not supported
00389     }
00390 
00391     //
00392     // RFC 793: seventh, process the segment text,
00393     //
00394     uint32 old_rcv_nxt = state->rcv_nxt; // if rcv_nxt changes, we need to send/schedule an ACK
00395     if (fsm.getState()==TCP_S_SYN_RCVD || fsm.getState()==TCP_S_ESTABLISHED || fsm.getState()==TCP_S_FIN_WAIT_1 || fsm.getState()==TCP_S_FIN_WAIT_2)
00396     {
00397         //"
00398         // Once in the ESTABLISHED state, it is possible to deliver segment
00399         // text to user RECEIVE buffers.  Text from segments can be moved
00400         // into buffers until either the buffer is full or the segment is
00401         // empty.  If the segment empties and carries an PUSH flag, then
00402         // the user is informed, when the buffer is returned, that a PUSH
00403         // has been received.
00404         //
00405         // When the TCP takes responsibility for delivering the data to the
00406         // user it must also acknowledge the receipt of the data.
00407         //
00408         // Once the TCP takes responsibility for the data it advances
00409         // RCV.NXT over the data accepted, and adjusts RCV.WND as
00410         // apporopriate to the current buffer availability.  The total of
00411         // RCV.NXT and RCV.WND should not be reduced.
00412         //
00413         // Please note the window management suggestions in section 3.7.
00414         //
00415         // Send an acknowledgment of the form:
00416         //
00417         //   <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
00418         //
00419         // This acknowledgment should be piggybacked on a segment being
00420         // transmitted if possible without incurring undue delay.
00421         //"
00422         if (tcpseg->getPayloadLength()>0)
00423         {
00424             tcpEV2 << "Processing segment text in a data transfer state\n";
00425 
00426             // insert into receive buffers. If this segment is contiguous with
00427             // previously received ones (seqNo==rcv_nxt), rcv_nxt can be increased;
00428             // otherwise it stays the same but the data must be cached nevertheless
00429             // (to avoid "Failure to retain above-sequence data" problem, RFC 2525
00430             // section 2.5).
00431             uint32 old_rcv_nxt = state->rcv_nxt;
00432             state->rcv_nxt = receiveQueue->insertBytesFromSegment(tcpseg);
00433 
00434             if (seqGreater(state->snd_una, old_snd_una))
00435             {
00436                 // notify
00437                 tcpAlgorithm->receivedDataAck(old_snd_una);
00438 
00439                 // in the receivedDataAck we need the old value
00440                 state->dupacks = 0;
00441             }
00442 
00443             // out-of-order segment?
00444             if (old_rcv_nxt==state->rcv_nxt)
00445             {
00446                 // we'll probably want to send an ACK here
00447                 tcpAlgorithm->receivedOutOfOrderSegment();
00448             }
00449             else
00450             {
00451                 // forward data to app
00452                 //
00453                 // FIXME observe PSH bit
00454                 //
00455                 // FIXME we should implement socket READ command, and pass up only
00456                 // as many bytes as requested. rcv_wnd should be decreased
00457                 // accordingly! (right now we *always* advertise win=16384,
00458                 // that is, there's practically no receiver-imposed flow control!)
00459                 //
00460                 cPacket *msg;
00461                 while ((msg=receiveQueue->extractBytesUpTo(state->rcv_nxt))!=NULL)
00462                 {
00463                     msg->setKind(TCP_I_DATA);  // TBD currently we never send TCP_I_URGENT_DATA
00464                     TCPCommand *cmd = new TCPCommand();
00465                     cmd->setConnId(connId);
00466                     msg->setControlInfo(cmd);
00467                     sendToApp(msg);
00468                 }
00469 
00470                 // if this segment "filled the gap" until the previously arrived segment
00471                 // that carried a FIN (i.e.rcv_nxt==rcv_fin_seq), we have to advance
00472                 // rcv_nxt over the FIN.
00473                 if (state->fin_rcvd && state->rcv_nxt==state->rcv_fin_seq)
00474                 {
00475                     tcpEV << "All segments arrived up to the FIN segment, advancing rcv_nxt over the FIN\n";
00476                     state->rcv_nxt = state->rcv_fin_seq+1;
00477                     // state transitions will be done in the state machine, here we just set
00478                     // the proper event code (TCP_E_RCV_FIN or TCP_E_RCV_FIN_ACK)
00479                     event = TCP_E_RCV_FIN;
00480                     switch (fsm.getState())
00481                     {
00482                         case TCP_S_FIN_WAIT_1:
00483                             if (state->fin_ack_rcvd)
00484                             {
00485                                 event = TCP_E_RCV_FIN_ACK;
00486                                 // start the time-wait timer, turn off the other timers
00487                                 cancelEvent(finWait2Timer);
00488                                 scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00489 
00490                                 // we're entering TIME_WAIT, so we can signal CLOSED the user
00491                                 // (the only thing left to do is wait until the 2MSL timer expires)
00492                                 sendIndicationToApp(TCP_I_CLOSED);
00493                             }
00494                             break;
00495                         case TCP_S_FIN_WAIT_2:
00496                             // Start the time-wait timer, turn off the other timers.
00497                             cancelEvent(finWait2Timer);
00498                             scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00499 
00500                             // we're entering TIME_WAIT, so we can signal CLOSED the user
00501                             // (the only thing left to do is wait until the 2MSL timer expires)
00502                             sendIndicationToApp(TCP_I_CLOSED);
00503                             break;
00504                         case TCP_S_TIME_WAIT:
00505                             // Restart the 2 MSL time-wait timeout.
00506                             cancelEvent(the2MSLTimer);
00507                             scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00508                             break;
00509                     }
00510                     sendIndicationToApp(TCP_I_PEER_CLOSED);
00511                 }
00512             }
00513         }
00514     }
00515 
00516     //
00517     // RFC 793: eighth, check the FIN bit,
00518     //
00519     if (tcpseg->getFinBit())
00520     {
00521         //"
00522         // If the FIN bit is set, signal the user "connection closing" and
00523         // return any pending RECEIVEs with same message, advance RCV.NXT
00524         // over the FIN, and send an acknowledgment for the FIN.  Note that
00525         // FIN implies PUSH for any segment text not yet delivered to the
00526         // user.
00527         //"
00528 
00529         // Note: seems like RFC 793 is not entirely correct here: if the
00530         // segment is "above sequence" (ie. RCV.NXT < SEG.SEQ), we cannot
00531         // advance RCV.NXT over the FIN. Instead we remember this sequence
00532         // number and do it later.
00533         uint32 fin_seq = (uint32)tcpseg->getSequenceNo() + (uint32)tcpseg->getPayloadLength();
00534         if (state->rcv_nxt==fin_seq)
00535         {
00536             // advance rcv_nxt over FIN now
00537             tcpEV << "FIN arrived, advancing rcv_nxt over the FIN\n";
00538             state->rcv_nxt++;
00539             // state transitions will be done in the state machine, here we just set
00540             // the proper event code (TCP_E_RCV_FIN or TCP_E_RCV_FIN_ACK)
00541             event = TCP_E_RCV_FIN;
00542             switch (fsm.getState())
00543             {
00544                 case TCP_S_FIN_WAIT_1:
00545                     if (state->fin_ack_rcvd)
00546                     {
00547                         event = TCP_E_RCV_FIN_ACK;
00548                         // start the time-wait timer, turn off the other timers
00549                         cancelEvent(finWait2Timer);
00550                         scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00551 
00552                         // we're entering TIME_WAIT, so we can signal CLOSED the user
00553                         // (the only thing left to do is wait until the 2MSL timer expires)
00554                         sendIndicationToApp(TCP_I_CLOSED);
00555                     }
00556                     break;
00557                 case TCP_S_FIN_WAIT_2:
00558                     // Start the time-wait timer, turn off the other timers.
00559                     cancelEvent(finWait2Timer);
00560                     scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00561 
00562                     // we're entering TIME_WAIT, so we can signal CLOSED the user
00563                     // (the only thing left to do is wait until the 2MSL timer expires)
00564                     sendIndicationToApp(TCP_I_CLOSED);
00565                     break;
00566                 case TCP_S_TIME_WAIT:
00567                     // Restart the 2 MSL time-wait timeout.
00568                     cancelEvent(the2MSLTimer);
00569                     scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00570                     break;
00571             }
00572             sendIndicationToApp(TCP_I_PEER_CLOSED);
00573         }
00574         else
00575         {
00576             // we'll have to do it later (when an arriving segment "fills the gap")
00577             tcpEV << "FIN segment above sequence, storing sequence number of FIN\n";
00578             state->fin_rcvd = true;
00579             state->rcv_fin_seq = fin_seq;
00580         }
00581 
00582         // TBD do PUSH stuff
00583     }
00584 
00585     if (old_rcv_nxt!=state->rcv_nxt)
00586     {
00587         // if rcv_nxt changed, either because we received segment text or we
00588         // received a FIN that needs to be acked (or both), we need to send or
00589         // schedule an ACK.
00590 
00591         // tcpAlgorithm decides when and how to do ACKs
00592         tcpAlgorithm->receiveSeqChanged();
00593     }
00594 
00595     if ((fsm.getState()==TCP_S_ESTABLISHED || fsm.getState()==TCP_S_SYN_RCVD) &&
00596         state->send_fin && state->snd_nxt==state->snd_fin_seq+1)
00597     {
00598         // if the user issued the CLOSE command a long time ago and we've just
00599         // managed to send off FIN, we simulate a CLOSE command now (we had to
00600         // defer it at that time because we still had data in the send queue.)
00601         // This CLOSE will take us into the FIN_WAIT_1 state.
00602         tcpEV << "Now we can do the CLOSE which was deferred a while ago\n";
00603         event = TCP_E_CLOSE;
00604     }
00605 
00606     if (fsm.getState()==TCP_S_CLOSE_WAIT && state->send_fin &&
00607         state->snd_nxt==state->snd_fin_seq+1 && old_snd_nxt!=state->snd_nxt)
00608     {
00609         // if we're in CLOSE_WAIT and we just got to sent our long-pending FIN,
00610         // we simulate a CLOSE command now (we had to defer it at that time because
00611         // we still had data in the send queue.) This CLOSE will take us into the
00612         // LAST_ACK state.
00613         tcpEV << "Now we can do the CLOSE which was deferred a while ago\n";
00614         event = TCP_E_CLOSE;
00615     }
00616 
00617     return event;
00618 }
00619 
00620 //----
00621 
00622 TCPEventCode TCPConnection::processSegmentInListen(TCPSegment *tcpseg, IPvXAddress srcAddr, IPvXAddress destAddr)
00623 {
00624     tcpEV2 << "Processing segment in LISTEN\n";
00625 
00626     //"
00627     // first check for an RST
00628     //   An incoming RST should be ignored.  Return.
00629     //"
00630     if (tcpseg->getRstBit())
00631     {
00632         tcpEV << "RST bit set: dropping segment\n";
00633         return TCP_E_IGNORE;
00634     }
00635 
00636     //"
00637     // second check for an ACK
00638     //    Any acknowledgment is bad if it arrives on a connection still in
00639     //    the LISTEN state.  An acceptable reset segment should be formed
00640     //    for any arriving ACK-bearing segment.  The RST should be
00641     //    formatted as follows:
00642     //
00643     //      <SEQ=SEG.ACK><CTL=RST>
00644     //
00645     //    Return.
00646     //"
00647     if (tcpseg->getAckBit())
00648     {
00649         tcpEV << "ACK bit set: dropping segment and sending RST\n";
00650         sendRst(tcpseg->getAckNo(),destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort());
00651         return TCP_E_IGNORE;
00652     }
00653 
00654     //"
00655     // third check for a SYN
00656     //"
00657     if (tcpseg->getSynBit())
00658     {
00659         if (tcpseg->getFinBit())
00660         {
00661             // Looks like implementations vary on how to react to SYN+FIN.
00662             // Some treat it as plain SYN (and reply with SYN+ACK), some send RST+ACK.
00663             // Let's just do the former here.
00664             tcpEV << "SYN+FIN received: ignoring FIN\n";
00665         }
00666 
00667         tcpEV << "SYN bit set: filling in foreign socket and sending SYN+ACK\n";
00668 
00669         //"
00670         // If the listen was not fully specified (i.e., the foreign socket was not
00671         // fully specified), then the unspecified fields should be filled in now.
00672         //"
00673         //
00674         // Also, we may need to fork, in order to leave another connection
00675         // LISTENing on the port. Note: forking will change our connId.
00676         //
00677         if (state->fork)
00678         {
00679             TCPConnection *conn = cloneListeningConnection(); // this will stay LISTENing
00680             tcpMain->addForkedConnection(this, conn, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
00681             tcpEV << "Connection forked: this connection got new connId=" << connId << ", "
00682                      "spinoff keeps LISTENing with connId=" << conn->connId << "\n";
00683         }
00684         else
00685         {
00686             tcpMain->updateSockPair(this, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
00687         }
00688 
00689         //"
00690         //  Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ and any other
00691         //  control or text should be queued for processing later.  ISS
00692         //  should be selected and a SYN segment sent of the form:
00693         //
00694         //    <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
00695         //
00696         //  SND.NXT is set to ISS+1 and SND.UNA to ISS.  The connection
00697         //  state should be changed to SYN-RECEIVED.
00698         //"
00699         state->rcv_nxt = tcpseg->getSequenceNo()+1;
00700         state->irs = tcpseg->getSequenceNo();
00701         receiveQueue->init(state->rcv_nxt);   // FIXME may init twice...
00702         selectInitialSeqNum();
00703 
00704         // although not mentioned in RFC 793, seems like we have to pick up
00705         // initial snd_wnd from the segment here.
00706         state->snd_wnd = tcpseg->getWindow();
00707         state->snd_wl1 = tcpseg->getSequenceNo();
00708         state->snd_wl2 = state->iss;
00709         if (sndWndVector) sndWndVector->record(state->snd_wnd);
00710 
00711         sendSynAck();
00712         startSynRexmitTimer();
00713         if (!connEstabTimer->isScheduled())
00714             scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB);
00715 
00716         //"
00717         // Note that any other incoming control or data (combined with SYN)
00718         // will be processed in the SYN-RECEIVED state, but processing of SYN
00719         // and ACK should not be repeated.
00720         //"
00721         // We don't send text in SYN or SYN+ACK, but accept it. Otherwise
00722         // there isn't much left to do: RST, SYN, ACK, FIN got processed already,
00723         // so there's only URG and PSH left to handle.
00724         //
00725         if (tcpseg->getPayloadLength()>0)
00726             receiveQueue->insertBytesFromSegment(tcpseg);
00727         if (tcpseg->getUrgBit() || tcpseg->getPshBit())
00728             tcpEV << "Ignoring URG and PSH bits in SYN\n"; // TBD
00729 
00730         return TCP_E_RCV_SYN;  // this will take us to SYN_RCVD
00731     }
00732 
00733     //"
00734     //  fourth other text or control
00735     //   So you are unlikely to get here, but if you do, drop the segment, and return.
00736     //"
00737     tcpEV << "Unexpected segment: dropping it\n";
00738     return TCP_E_IGNORE;
00739 }
00740 
00741 TCPEventCode TCPConnection::processSegmentInSynSent(TCPSegment *tcpseg, IPvXAddress srcAddr, IPvXAddress destAddr)
00742 {
00743     tcpEV2 << "Processing segment in SYN_SENT\n";
00744 
00745     //"
00746     // first check the ACK bit
00747     //
00748     //   If the ACK bit is set
00749     //
00750     //     If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset (unless
00751     //     the RST bit is set, if so drop the segment and return)
00752     //
00753     //       <SEQ=SEG.ACK><CTL=RST>
00754     //
00755     //     and discard the segment.  Return.
00756     //
00757     //     If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable.
00758     //"
00759     if (tcpseg->getAckBit())
00760     {
00761         if (seqLE(tcpseg->getAckNo(),state->iss) || seqGreater(tcpseg->getAckNo(),state->snd_nxt))
00762         {
00763             tcpEV << "ACK bit set but wrong AckNo, sending RST\n";
00764             sendRst(tcpseg->getAckNo(),destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort());
00765             return TCP_E_IGNORE;
00766         }
00767         tcpEV << "ACK bit set, AckNo acceptable\n";
00768     }
00769 
00770     //"
00771     // second check the RST bit
00772     //
00773     //   If the RST bit is set
00774     //
00775     //     If the ACK was acceptable then signal the user "error:
00776     //     connection reset", drop the segment, enter CLOSED state,
00777     //     delete TCB, and return.  Otherwise (no ACK) drop the segment
00778     //     and return.
00779     //"
00780     if (tcpseg->getRstBit())
00781     {
00782         if (tcpseg->getAckBit())
00783         {
00784             tcpEV << "RST+ACK: performing connection reset\n";
00785             sendIndicationToApp(TCP_I_CONNECTION_RESET);
00786             return TCP_E_RCV_RST;
00787         }
00788         else
00789         {
00790             tcpEV << "RST without ACK: dropping segment\n";
00791             return TCP_E_IGNORE;
00792         }
00793     }
00794 
00795     //"
00796     // third check the security and precedence -- not done
00797     //
00798     // fourth check the SYN bit
00799     //
00800     //   This step should be reached only if the ACK is ok, or there is
00801     //   no ACK, and it the segment did not contain a RST.
00802     //
00803     //   If the SYN bit is on and the security/compartment and precedence
00804     //   are acceptable then,
00805     //"
00806     if (tcpseg->getSynBit())
00807     {
00808         //
00809         //   RCV.NXT is set to SEG.SEQ+1, IRS is set to
00810         //   SEG.SEQ.  SND.UNA should be advanced to equal SEG.ACK (if there
00811         //   is an ACK), and any segments on the retransmission queue which
00812         //   are thereby acknowledged should be removed.
00813         //
00814         state->rcv_nxt = tcpseg->getSequenceNo()+1;
00815         state->irs = tcpseg->getSequenceNo();
00816         receiveQueue->init(state->rcv_nxt);
00817 
00818         if (tcpseg->getAckBit())
00819         {
00820             state->snd_una = tcpseg->getAckNo();
00821             sendQueue->discardUpTo(state->snd_una);
00822 
00823             // although not mentioned in RFC 793, seems like we have to pick up
00824             // initial snd_wnd from the segment here.
00825             state->snd_wnd = tcpseg->getWindow();
00826             state->snd_wl1 = tcpseg->getSequenceNo();
00827             state->snd_wl2 = tcpseg->getAckNo();
00828             if (sndWndVector) sndWndVector->record(state->snd_wnd);
00829         }
00830 
00831         // this also seems to be a good time to learn our local IP address
00832         // (was probably unspecified at connection open)
00833         tcpMain->updateSockPair(this, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
00834 
00835         //"
00836         //   If SND.UNA > ISS (our SYN has been ACKed), change the connection
00837         //   state to ESTABLISHED, form an ACK segment
00838         //
00839         //     <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
00840         //
00841         //   and send it.  Data or controls which were queued for
00842         //   transmission may be included.  If there are other controls or
00843         //   text in the segment then continue processing at the sixth step
00844         //   below where the URG bit is checked, otherwise return.
00845         //"
00846         if (seqGreater(state->snd_una, state->iss))
00847         {
00848             tcpEV << "SYN+ACK bits set, connection established.\n";
00849 
00850             // RFC says "continue processing at the sixth step below where
00851             // the URG bit is checked". Those steps deal with: URG, segment text
00852             // (and PSH), and FIN.
00853             // Now: URG and PSH we don't support yet; in SYN+FIN we ignore FIN;
00854             // with segment text we just take it easy and put it in the receiveQueue
00855             // -- we'll forward it to the user when more data arrives.
00856             if (tcpseg->getFinBit())
00857                 tcpEV << "SYN+ACK+FIN received: ignoring FIN\n";
00858             if (tcpseg->getPayloadLength()>0)
00859                 state->rcv_nxt = receiveQueue->insertBytesFromSegment(tcpseg); // TBD forward to app, etc.
00860             if (tcpseg->getUrgBit() || tcpseg->getPshBit())
00861                 tcpEV << "Ignoring URG and PSH bits in SYN+ACK\n"; // TBD
00862 
00863             // notify tcpAlgorithm (it has to send ACK of SYN) and app layer
00864             tcpAlgorithm->established(true);
00865             sendEstabIndicationToApp();
00866 
00867             // This will trigger transition to ESTABLISHED. Timers and notifying
00868             // app will be taken care of in stateEntered().
00869             return TCP_E_RCV_SYN_ACK;
00870         }
00871 
00872         //"
00873         //   Otherwise enter SYN-RECEIVED, form a SYN,ACK segment
00874         //
00875         //     <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
00876         //
00877         //   and send it.  If there are other controls or text in the
00878         //   segment, queue them for processing after the ESTABLISHED state
00879         //   has been reached, return.
00880         //"
00881         tcpEV << "SYN bit set: sending SYN+ACK\n";
00882         state->snd_max = state->snd_nxt = state->iss;
00883         sendSynAck();
00884         startSynRexmitTimer();
00885 
00886         // Note: code below is similar to processing SYN in LISTEN.
00887 
00888         // For consistency with that code, we ignore SYN+FIN here
00889         if (tcpseg->getFinBit())
00890             tcpEV << "SYN+FIN received: ignoring FIN\n";
00891 
00892         // We don't send text in SYN or SYN+ACK, but accept it. Otherwise
00893         // there isn't much left to do: RST, SYN, ACK, FIN got processed already,
00894         // so there's only URG and PSH left to handle.
00895         if (tcpseg->getPayloadLength()>0)
00896             receiveQueue->insertBytesFromSegment(tcpseg);
00897         if (tcpseg->getUrgBit() || tcpseg->getPshBit())
00898             tcpEV << "Ignoring URG and PSH bits in SYN\n"; // TBD
00899         return TCP_E_RCV_SYN;
00900     }
00901 
00902     //"
00903     // fifth, if neither of the SYN or RST bits is set then drop the
00904     // segment and return.
00905     //"
00906     return TCP_E_IGNORE;
00907 }
00908 
00909 TCPEventCode TCPConnection::processRstInSynReceived(TCPSegment *tcpseg)
00910 {
00911     tcpEV2 << "Processing RST in SYN_RCVD\n";
00912 
00913     //"
00914     // If this connection was initiated with a passive OPEN (i.e.,
00915     // came from the LISTEN state), then return this connection to
00916     // LISTEN state and return.  The user need not be informed.  If
00917     // this connection was initiated with an active OPEN (i.e., came
00918     // from SYN-SENT state) then the connection was refused, signal
00919     // the user "connection refused".  In either case, all segments
00920     // on the retransmission queue should be removed.  And in the
00921     // active OPEN case, enter the CLOSED state and delete the TCB,
00922     // and return.
00923     //"
00924 
00925     sendQueue->discardUpTo(sendQueue->getBufferEndSeq()); // flush send queue
00926 
00927     if (state->active)
00928     {
00929         // signal "connection refused"
00930         sendIndicationToApp(TCP_I_CONNECTION_REFUSED);
00931     }
00932 
00933     // on RCV_RST, FSM will go either to LISTEN or to CLOSED, depending on state->active
00934     return TCP_E_RCV_RST;
00935 }
00936 
00937 bool TCPConnection::processAckInEstabEtc(TCPSegment *tcpseg)
00938 {
00939     tcpEV2 << "Processing ACK in a data transfer state\n";
00940 
00941     //
00942     //"
00943     //  If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
00944     //  Any segments on the retransmission queue which are thereby
00945     //  entirely acknowledged are removed.  Users should receive
00946     //  positive acknowledgments for buffers which have been SENT and
00947     //  fully acknowledged (i.e., SEND buffer should be returned with
00948     //  "ok" response).  If the ACK is a duplicate
00949     //  (SEG.ACK < SND.UNA), it can be ignored.  If the ACK acks
00950     //  something not yet sent (SEG.ACK > SND.NXT) then send an ACK,
00951     //  drop the segment, and return.
00952     //
00953     //  If SND.UNA < SEG.ACK =< SND.NXT, the send window should be
00954     //  updated.  If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and
00955     //  SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set
00956     //  SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK.
00957     //
00958     //  Note that SND.WND is an offset from SND.UNA, that SND.WL1
00959     //  records the sequence number of the last segment used to update
00960     //  SND.WND, and that SND.WL2 records the acknowledgment number of
00961     //  the last segment used to update SND.WND.  The check here
00962     //  prevents using old segments to update the window.
00963     //"
00964     // Note: should use SND.MAX instead of SND.NXT in above checks
00965     //
00966     if (seqGE(state->snd_una, tcpseg->getAckNo()))
00967     {
00968         //
00969         // duplicate ACK? A received TCP segment is a duplicate ACK if all of
00970         // the following apply:
00971         //    (1) snd_una==ackNo
00972         //    (2) segment contains no data
00973         //    (3) there's unacked data (snd_una!=snd_max)
00974         //
00975         // Note: ssfnet uses additional constraint "window is the same as last
00976         // received (not an update)" -- we don't do that because window updates
00977         // are ignored anyway if neither seqNo nor ackNo has changed.
00978         //
00979         if (state->snd_una==tcpseg->getAckNo() && tcpseg->getPayloadLength()==0 &&
00980             state->snd_una!=state->snd_max)
00981         {
00982             state->dupacks++;
00983             tcpAlgorithm->receivedDuplicateAck();
00984         }
00985         else
00986         {
00987             // if doesn't qualify as duplicate ACK, just ignore it.
00988             if (tcpseg->getPayloadLength()==0)
00989             {
00990                 if (state->snd_una!=tcpseg->getAckNo())
00991                     tcpEV << "Old ACK: ackNo<snd_una\n";
00992                 else if (state->snd_una==state->snd_max)
00993                     tcpEV << "ACK looks duplicate but we have currently no unacked data (snd_una==snd_max)\n";
00994             }
00995 
00996             // reset counter
00997             state->dupacks = 0;
00998         }
00999     }
01000     else if (seqLE(tcpseg->getAckNo(), state->snd_max))
01001     {
01002         // ack in window.
01003         uint32 old_snd_una = state->snd_una;
01004         state->snd_una = tcpseg->getAckNo();
01005         if (unackedVector) unackedVector->record(state->snd_max - state->snd_una);
01006 
01007         // after retransmitting a lost segment, we may get an ack well ahead of snd_nxt
01008         if (seqLess(state->snd_nxt, state->snd_una))
01009             state->snd_nxt = state->snd_una;
01010 
01011         uint32 discardUpToSeq = state->snd_una;
01012 
01013         // our FIN acked?
01014         if (state->send_fin && tcpseg->getAckNo()==state->snd_fin_seq+1)
01015         {
01016             // set flag that our FIN has been acked
01017             tcpEV << "ACK acks our FIN\n";
01018             state->fin_ack_rcvd = true;
01019             discardUpToSeq--; // the FIN sequence number is not real data
01020         }
01021 
01022         // acked data no longer needed in send queue
01023         sendQueue->discardUpTo(discardUpToSeq);
01024 
01025         if (seqLess(state->snd_wl1, tcpseg->getSequenceNo()) ||
01026             (state->snd_wl1==tcpseg->getSequenceNo() && seqLE(state->snd_wl2, tcpseg->getAckNo())))
01027         {
01028             // send window should be updated
01029             tcpEV << "Updating send window from segment: new wnd=" << tcpseg->getWindow() << "\n";
01030             state->snd_wnd = tcpseg->getWindow();
01031             state->snd_wl1 = tcpseg->getSequenceNo();
01032             state->snd_wl2 = tcpseg->getAckNo();
01033             if (sndWndVector) sndWndVector->record(state->snd_wnd);
01034         }
01035 
01036         if (tcpseg->getPayloadLength() == 0 && fsm.getState()!=TCP_S_SYN_RCVD) // if segment contains data, wait until data has been forwarded to app before sending ACK, otherwise we would use an old ACKNo
01037         {
01038             // notify
01039             tcpAlgorithm->receivedDataAck(old_snd_una);
01040 
01041             // in the receivedDataAck we need the old value
01042             state->dupacks = 0;
01043         }
01044     }
01045     else
01046     {
01047         ASSERT(seqGreater(tcpseg->getAckNo(), state->snd_max)); // from if-ladder
01048 
01049         // send an ACK, drop the segment, and return.
01050         tcpAlgorithm->receivedAckForDataNotYetSent(tcpseg->getAckNo());
01051         state->dupacks = 0;
01052         return false;  // means "drop"
01053     }
01054     return true;
01055 }
01056 
01057 //----
01058 
01059 void TCPConnection::process_TIMEOUT_CONN_ESTAB()
01060 {
01061     switch(fsm.getState())
01062     {
01063         case TCP_S_SYN_RCVD:
01064         case TCP_S_SYN_SENT:
01065             // Nothing to do here. TIMEOUT_CONN_ESTAB event will automatically
01066             // take the connection to LISTEN or CLOSED, and cancel SYN-REXMIT timer.
01067             if (state->active)
01068             {
01069                 // notify user if we're on the active side
01070                 sendIndicationToApp(TCP_I_TIMED_OUT);
01071             }
01072             break;
01073         default:
01074             // We should not receive this timeout in this state.
01075             opp_error("Internal error: received CONN_ESTAB timeout in state %s", stateName(fsm.getState()));
01076     }
01077 }
01078 
01079 void TCPConnection::process_TIMEOUT_2MSL()
01080 {
01081     //"
01082     // If the time-wait timeout expires on a connection delete the TCB,
01083     // enter the CLOSED state and return.
01084     //"
01085     switch(fsm.getState())
01086     {
01087         case TCP_S_TIME_WAIT:
01088             // Nothing to do here. The TIMEOUT_2MSL event will automatically take
01089             // the connection to CLOSED. We already notified the user
01090             // (TCP_I_CLOSED) when we entered the TIME_WAIT state from CLOSING,
01091             // FIN_WAIT_1 or FIN_WAIT_2.
01092             break;
01093         default:
01094             // We should not receive this timeout in this state.
01095             opp_error("Internal error: received time-wait (2MSL) timeout in state %s", stateName(fsm.getState()));
01096     }
01097 
01098 }
01099 
01100 void TCPConnection::process_TIMEOUT_FIN_WAIT_2()
01101 {
01102     switch(fsm.getState())
01103     {
01104         case TCP_S_FIN_WAIT_2:
01105             // Nothing to do here. The TIMEOUT_FIN_WAIT_2 event will automatically take
01106             // the connection to CLOSED.
01107             sendIndicationToApp(TCP_I_CLOSED);
01108             break;
01109         default:
01110             // We should not receive this timeout in this state.
01111             opp_error("Internal error: received FIN_WAIT_2 timeout in state %s", stateName(fsm.getState()));
01112     }
01113 }
01114 
01115 void TCPConnection::startSynRexmitTimer()
01116 {
01117     state->syn_rexmit_count = 0;
01118     state->syn_rexmit_timeout = TCP_TIMEOUT_SYN_REXMIT;
01119 
01120     if (synRexmitTimer->isScheduled())
01121         cancelEvent(synRexmitTimer);
01122     scheduleTimeout(synRexmitTimer, state->syn_rexmit_timeout);
01123 }
01124 
01125 void TCPConnection::process_TIMEOUT_SYN_REXMIT(TCPEventCode& event)
01126 {
01127     if (++state->syn_rexmit_count>MAX_SYN_REXMIT_COUNT)
01128     {
01129         tcpEV << "Retransmission count during connection setup exceeds " << MAX_SYN_REXMIT_COUNT << ", giving up\n";
01130         // Note ABORT will take the connection to closed, and cancel CONN-ESTAB timer as well
01131         event = TCP_E_ABORT;
01132         return;
01133     }
01134 
01135     tcpEV << "Performing retransmission #" << state->syn_rexmit_count << "\n";
01136 
01137     // resend what's needed
01138     switch(fsm.getState())
01139     {
01140         case TCP_S_SYN_SENT: sendSyn(); break;
01141         case TCP_S_SYN_RCVD: sendSynAck(); break;
01142         default:  opp_error("Internal error: SYN-REXMIT timer expired while in state %s", stateName(fsm.getState()));
01143     }
01144 
01145     // reschedule timer
01146     state->syn_rexmit_timeout *= 2;
01147 
01148     if (state->syn_rexmit_timeout > TCP_TIMEOUT_SYN_REXMIT_MAX)
01149         state->syn_rexmit_timeout = TCP_TIMEOUT_SYN_REXMIT_MAX;
01150     scheduleTimeout(synRexmitTimer, state->syn_rexmit_timeout);
01151 }
01152 
01153 
01154 //
01155 //TBD:
01156 //"
01157 // USER TIMEOUT
01158 //
01159 //    For any state if the user timeout expires, flush all queues, signal
01160 //    the user "error:  connection aborted due to user timeout" in general
01161 //    and for any outstanding calls, delete the TCB, enter the CLOSED
01162 //    state and return.
01163 //"
01164