[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ns] fix to "bad ACK for our SYN"--a possible FullTcp bug



Hi,
 I found something could be a bug in tcp-full.cc.
 When to establish a two-way data channel using FullTcp like
a client/server model, error occurs during client actively connects
to the server.
 My configuration is like this
server---client

 Tcl code:
 $ns attach-agent $server $stcp ;#stcp and ctcp are FullTcp agents
 $ns attache-agent $client $ctcp
 $ctcp set fid_ 0
 $stcp set fid_ 0
 $ns connect $ctcp $stcp
 set ctarget $ctcp target
 set starget $stcp target
 $ctcp target $stcp  ;# seldom used in this way, but needed in
connector::send/recv
 $stcp target $ctcp
 $stcp listen
 $ctcp connection ;# my exported command from tcp-full.cc, just call
connect() in it.
 # when connecting, the above mentioned error occurs
 $ctcp target $ctarget ;#purely for trace....
 $stcp target $starget
 $ctcp advanceby 1 ;# client request
 $stcp advanceby 1 ;#server response

That just mimics the real world code.

 In tcp-full.cc, the sendpacket() in output() is placed above maxseq_ =
highest, which
is fine in real systems, but incorrect in simulations. the sendpacket()
actually calls the target_->recv()
(in agent.h), and in turn comes into FullTcp::recv() which checks the
maxseq_ with the incoming ack.
So the update of maxseq_ should come before sendpacket().
 The modification to 2.1b7 is:
tcp-full.cc line616:
-----------------------------------------
// sendpacket(seqno, rcv_nxt_, pflags, datalen, reason);


 /*
  * if we have reacted to congestion recently, the
  * slowdown() procedure will have set cong_action_ and
  * sendpacket will have copied that to the outgoing pkt
  * CACT field. If that packet contains data, then
  * it will be reliably delivered, so we are free to turn off the
  * cong_action_ state now  If only a pure ACK, we keep the state
  * around until we actually send a segment
  */

 int reliable = datalen + syn + fin; // seq #'s reliably sent
 if (cong_action_ && reliable > 0)
  cong_action_ = FALSE;

 /*
  * SYNs and FINs each use up one sequence number, but
  * there's no reason to advance t_seqno_ by one for a FIN
  */

 if (!fin && seqno == t_seqno_) {
  t_seqno_ += reliable;
 }


 // highest: greatest sequence number sent + 1
 // and adjusted for SYNs and FINs which use up one number

 int highest = seqno + reliable;
 if (highest > maxseq_) {
  maxseq_ = highest;
  //
  // if we are using conventional RTT estimation,
  // establish timing on this segment
  //
  if (!ts_option_ && rtt_active_ == FALSE) {
   rtt_active_ = TRUE; // set timer
   rtt_seq_ = seqno;  // timed seq #
   rtt_ts_ = now(); // when set
  }
 }
/*sendpacket moved here*/
sendpacket(seqno, rcv_nxt_, pflags, datalen, reason);
        /*
         * Data sent (as far as we can tell).
         * Any pending ACK has now been sent.
         */
 flags_ &= ~(TF_ACKNOW|TF_DELACK);

------------------------------
This works for 2.1b7.

Cheers
Huamin