symbian-qemu-0.9.1-12/qemu-symbian-svp/slirp/tcp_timer.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * Copyright (c) 1982, 1986, 1988, 1990, 1993
       
     3  *	The Regents of the University of California.  All rights reserved.
       
     4  *
       
     5  * Redistribution and use in source and binary forms, with or without
       
     6  * modification, are permitted provided that the following conditions
       
     7  * are met:
       
     8  * 1. Redistributions of source code must retain the above copyright
       
     9  *    notice, this list of conditions and the following disclaimer.
       
    10  * 2. Redistributions in binary form must reproduce the above copyright
       
    11  *    notice, this list of conditions and the following disclaimer in the
       
    12  *    documentation and/or other materials provided with the distribution.
       
    13  * 3. All advertising materials mentioning features or use of this software
       
    14  *    must display the following acknowledgement:
       
    15  *	This product includes software developed by the University of
       
    16  *	California, Berkeley and its contributors.
       
    17  * 4. Neither the name of the University nor the names of its contributors
       
    18  *    may be used to endorse or promote products derived from this software
       
    19  *    without specific prior written permission.
       
    20  *
       
    21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
       
    22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
       
    24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
       
    25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
       
    26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
       
    27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
       
    28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
       
    29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
       
    30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
       
    31  * SUCH DAMAGE.
       
    32  *
       
    33  *	@(#)tcp_timer.c	8.1 (Berkeley) 6/10/93
       
    34  * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp
       
    35  */
       
    36 
       
    37 #include <slirp.h>
       
    38 
       
    39 #ifdef LOG_ENABLED
       
    40 struct   tcpstat tcpstat;        /* tcp statistics */
       
    41 #endif
       
    42 
       
    43 u_int32_t        tcp_now;                /* for RFC 1323 timestamps */
       
    44 
       
    45 static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer);
       
    46 
       
    47 /*
       
    48  * Fast timeout routine for processing delayed acks
       
    49  */
       
    50 void
       
    51 tcp_fasttimo()
       
    52 {
       
    53 	register struct socket *so;
       
    54 	register struct tcpcb *tp;
       
    55 
       
    56 	DEBUG_CALL("tcp_fasttimo");
       
    57 
       
    58 	so = tcb.so_next;
       
    59 	if (so)
       
    60 	for (; so != &tcb; so = so->so_next)
       
    61 		if ((tp = (struct tcpcb *)so->so_tcpcb) &&
       
    62 		    (tp->t_flags & TF_DELACK)) {
       
    63 			tp->t_flags &= ~TF_DELACK;
       
    64 			tp->t_flags |= TF_ACKNOW;
       
    65 			STAT(tcpstat.tcps_delack++);
       
    66 			(void) tcp_output(tp);
       
    67 		}
       
    68 }
       
    69 
       
    70 /*
       
    71  * Tcp protocol timeout routine called every 500 ms.
       
    72  * Updates the timers in all active tcb's and
       
    73  * causes finite state machine actions if timers expire.
       
    74  */
       
    75 void
       
    76 tcp_slowtimo()
       
    77 {
       
    78 	register struct socket *ip, *ipnxt;
       
    79 	register struct tcpcb *tp;
       
    80 	register int i;
       
    81 
       
    82 	DEBUG_CALL("tcp_slowtimo");
       
    83 
       
    84 	/*
       
    85 	 * Search through tcb's and update active timers.
       
    86 	 */
       
    87 	ip = tcb.so_next;
       
    88 	if (ip == 0)
       
    89 	   return;
       
    90 	for (; ip != &tcb; ip = ipnxt) {
       
    91 		ipnxt = ip->so_next;
       
    92 		tp = sototcpcb(ip);
       
    93 		if (tp == 0)
       
    94 			continue;
       
    95 		for (i = 0; i < TCPT_NTIMERS; i++) {
       
    96 			if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
       
    97 				tcp_timers(tp,i);
       
    98 				if (ipnxt->so_prev != ip)
       
    99 					goto tpgone;
       
   100 			}
       
   101 		}
       
   102 		tp->t_idle++;
       
   103 		if (tp->t_rtt)
       
   104 		   tp->t_rtt++;
       
   105 tpgone:
       
   106 		;
       
   107 	}
       
   108 	tcp_iss += TCP_ISSINCR/PR_SLOWHZ;		/* increment iss */
       
   109 #ifdef TCP_COMPAT_42
       
   110 	if ((int)tcp_iss < 0)
       
   111 		tcp_iss = 0;				/* XXX */
       
   112 #endif
       
   113 	tcp_now++;					/* for timestamps */
       
   114 }
       
   115 
       
   116 /*
       
   117  * Cancel all timers for TCP tp.
       
   118  */
       
   119 void
       
   120 tcp_canceltimers(tp)
       
   121 	struct tcpcb *tp;
       
   122 {
       
   123 	register int i;
       
   124 
       
   125 	for (i = 0; i < TCPT_NTIMERS; i++)
       
   126 		tp->t_timer[i] = 0;
       
   127 }
       
   128 
       
   129 const int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
       
   130    { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
       
   131 
       
   132 /*
       
   133  * TCP timer processing.
       
   134  */
       
   135 static struct tcpcb *
       
   136 tcp_timers(register struct tcpcb *tp, int timer)
       
   137 {
       
   138 	register int rexmt;
       
   139 
       
   140 	DEBUG_CALL("tcp_timers");
       
   141 
       
   142 	switch (timer) {
       
   143 
       
   144 	/*
       
   145 	 * 2 MSL timeout in shutdown went off.  If we're closed but
       
   146 	 * still waiting for peer to close and connection has been idle
       
   147 	 * too long, or if 2MSL time is up from TIME_WAIT, delete connection
       
   148 	 * control block.  Otherwise, check again in a bit.
       
   149 	 */
       
   150 	case TCPT_2MSL:
       
   151 		if (tp->t_state != TCPS_TIME_WAIT &&
       
   152 		    tp->t_idle <= TCP_MAXIDLE)
       
   153 			tp->t_timer[TCPT_2MSL] = TCPTV_KEEPINTVL;
       
   154 		else
       
   155 			tp = tcp_close(tp);
       
   156 		break;
       
   157 
       
   158 	/*
       
   159 	 * Retransmission timer went off.  Message has not
       
   160 	 * been acked within retransmit interval.  Back off
       
   161 	 * to a longer retransmit interval and retransmit one segment.
       
   162 	 */
       
   163 	case TCPT_REXMT:
       
   164 
       
   165 		/*
       
   166 		 * XXXXX If a packet has timed out, then remove all the queued
       
   167 		 * packets for that session.
       
   168 		 */
       
   169 
       
   170 		if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
       
   171 			/*
       
   172 			 * This is a hack to suit our terminal server here at the uni of canberra
       
   173 			 * since they have trouble with zeroes... It usually lets them through
       
   174 			 * unharmed, but under some conditions, it'll eat the zeros.  If we
       
   175 			 * keep retransmitting it, it'll keep eating the zeroes, so we keep
       
   176 			 * retransmitting, and eventually the connection dies...
       
   177 			 * (this only happens on incoming data)
       
   178 			 *
       
   179 			 * So, if we were gonna drop the connection from too many retransmits,
       
   180 			 * don't... instead halve the t_maxseg, which might break up the NULLs and
       
   181 			 * let them through
       
   182 			 *
       
   183 			 * *sigh*
       
   184 			 */
       
   185 
       
   186 			tp->t_maxseg >>= 1;
       
   187 			if (tp->t_maxseg < 32) {
       
   188 				/*
       
   189 				 * We tried our best, now the connection must die!
       
   190 				 */
       
   191 				tp->t_rxtshift = TCP_MAXRXTSHIFT;
       
   192 				STAT(tcpstat.tcps_timeoutdrop++);
       
   193 				tp = tcp_drop(tp, tp->t_softerror);
       
   194 				/* tp->t_softerror : ETIMEDOUT); */ /* XXX */
       
   195 				return (tp); /* XXX */
       
   196 			}
       
   197 
       
   198 			/*
       
   199 			 * Set rxtshift to 6, which is still at the maximum
       
   200 			 * backoff time
       
   201 			 */
       
   202 			tp->t_rxtshift = 6;
       
   203 		}
       
   204 		STAT(tcpstat.tcps_rexmttimeo++);
       
   205 		rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
       
   206 		TCPT_RANGESET(tp->t_rxtcur, rexmt,
       
   207 		    (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
       
   208 		tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
       
   209 		/*
       
   210 		 * If losing, let the lower level know and try for
       
   211 		 * a better route.  Also, if we backed off this far,
       
   212 		 * our srtt estimate is probably bogus.  Clobber it
       
   213 		 * so we'll take the next rtt measurement as our srtt;
       
   214 		 * move the current srtt into rttvar to keep the current
       
   215 		 * retransmit times until then.
       
   216 		 */
       
   217 		if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
       
   218 /*			in_losing(tp->t_inpcb); */
       
   219 			tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
       
   220 			tp->t_srtt = 0;
       
   221 		}
       
   222 		tp->snd_nxt = tp->snd_una;
       
   223 		/*
       
   224 		 * If timing a segment in this window, stop the timer.
       
   225 		 */
       
   226 		tp->t_rtt = 0;
       
   227 		/*
       
   228 		 * Close the congestion window down to one segment
       
   229 		 * (we'll open it by one segment for each ack we get).
       
   230 		 * Since we probably have a window's worth of unacked
       
   231 		 * data accumulated, this "slow start" keeps us from
       
   232 		 * dumping all that data as back-to-back packets (which
       
   233 		 * might overwhelm an intermediate gateway).
       
   234 		 *
       
   235 		 * There are two phases to the opening: Initially we
       
   236 		 * open by one mss on each ack.  This makes the window
       
   237 		 * size increase exponentially with time.  If the
       
   238 		 * window is larger than the path can handle, this
       
   239 		 * exponential growth results in dropped packet(s)
       
   240 		 * almost immediately.  To get more time between
       
   241 		 * drops but still "push" the network to take advantage
       
   242 		 * of improving conditions, we switch from exponential
       
   243 		 * to linear window opening at some threshold size.
       
   244 		 * For a threshold, we use half the current window
       
   245 		 * size, truncated to a multiple of the mss.
       
   246 		 *
       
   247 		 * (the minimum cwnd that will give us exponential
       
   248 		 * growth is 2 mss.  We don't allow the threshold
       
   249 		 * to go below this.)
       
   250 		 */
       
   251 		{
       
   252 		u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
       
   253 		if (win < 2)
       
   254 			win = 2;
       
   255 		tp->snd_cwnd = tp->t_maxseg;
       
   256 		tp->snd_ssthresh = win * tp->t_maxseg;
       
   257 		tp->t_dupacks = 0;
       
   258 		}
       
   259 		(void) tcp_output(tp);
       
   260 		break;
       
   261 
       
   262 	/*
       
   263 	 * Persistence timer into zero window.
       
   264 	 * Force a byte to be output, if possible.
       
   265 	 */
       
   266 	case TCPT_PERSIST:
       
   267 		STAT(tcpstat.tcps_persisttimeo++);
       
   268 		tcp_setpersist(tp);
       
   269 		tp->t_force = 1;
       
   270 		(void) tcp_output(tp);
       
   271 		tp->t_force = 0;
       
   272 		break;
       
   273 
       
   274 	/*
       
   275 	 * Keep-alive timer went off; send something
       
   276 	 * or drop connection if idle for too long.
       
   277 	 */
       
   278 	case TCPT_KEEP:
       
   279 		STAT(tcpstat.tcps_keeptimeo++);
       
   280 		if (tp->t_state < TCPS_ESTABLISHED)
       
   281 			goto dropit;
       
   282 
       
   283 /*		if (tp->t_socket->so_options & SO_KEEPALIVE && */
       
   284 		if ((SO_OPTIONS) && tp->t_state <= TCPS_CLOSE_WAIT) {
       
   285 		    	if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE)
       
   286 				goto dropit;
       
   287 			/*
       
   288 			 * Send a packet designed to force a response
       
   289 			 * if the peer is up and reachable:
       
   290 			 * either an ACK if the connection is still alive,
       
   291 			 * or an RST if the peer has closed the connection
       
   292 			 * due to timeout or reboot.
       
   293 			 * Using sequence number tp->snd_una-1
       
   294 			 * causes the transmitted zero-length segment
       
   295 			 * to lie outside the receive window;
       
   296 			 * by the protocol spec, this requires the
       
   297 			 * correspondent TCP to respond.
       
   298 			 */
       
   299 			STAT(tcpstat.tcps_keepprobe++);
       
   300 #ifdef TCP_COMPAT_42
       
   301 			/*
       
   302 			 * The keepalive packet must have nonzero length
       
   303 			 * to get a 4.2 host to respond.
       
   304 			 */
       
   305 			tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
       
   306 			    tp->rcv_nxt - 1, tp->snd_una - 1, 0);
       
   307 #else
       
   308 			tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
       
   309 			    tp->rcv_nxt, tp->snd_una - 1, 0);
       
   310 #endif
       
   311 			tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
       
   312 		} else
       
   313 			tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
       
   314 		break;
       
   315 
       
   316 	dropit:
       
   317 		STAT(tcpstat.tcps_keepdrops++);
       
   318 		tp = tcp_drop(tp, 0); /* ETIMEDOUT); */
       
   319 		break;
       
   320 	}
       
   321 
       
   322 	return (tp);
       
   323 }