|
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 "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