tcpout.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:7k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /* TCP output segment processing
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include "global.h"
  5. #include "timer.h"
  6. #include "mbuf.h"
  7. #include "netuser.h"
  8. #include "internet.h"
  9. #include "tcp.h"
  10. #include "ip.h"
  11. /* Send a segment on the specified connection. One gets sent only
  12.  * if there is data to be sent or if "force" is non zero
  13.  */
  14. void
  15. tcp_output(tcb)
  16. register struct tcb *tcb;
  17. {
  18. struct mbuf *dbp; /* Header and data buffer pointers */
  19. struct tcp seg; /* Local working copy of header */
  20. uint16 ssize; /* Size of current segment being sent,
  21.  * including SYN and FIN flags */
  22. uint16 dsize; /* Size of segment less SYN and FIN */
  23. int32 usable; /* Usable window */
  24. int32 sent; /* Sequence count (incl SYN/FIN) already
  25.  * in the pipe but not yet acked */
  26. int32 rto; /* Retransmit timeout setting */
  27. if(tcb == NULL)
  28. return;
  29. switch(tcb->state){
  30. case TCP_LISTEN:
  31. case TCP_CLOSED:
  32. return; /* Don't send anything */
  33. }
  34. for(;;){
  35. memset(&seg,0,sizeof(seg));
  36. /* Compute data already in flight */
  37. sent = tcb->snd.ptr - tcb->snd.una;
  38. /* Compute usable send window as minimum of offered
  39.  * and congestion windows, minus data already in flight.
  40.  * Be careful that the window hasn't shrunk --
  41.  * these are unsigned vars.
  42.  */
  43. usable = min(tcb->snd.wnd,tcb->cwind);
  44. if(usable > sent)
  45. usable -= sent; /* Most common case */
  46. else if(usable == 0 && sent == 0)
  47. usable = 1; /* Closed window probe */
  48. else
  49. usable = 0; /* Window closed or shrunken */
  50. /* Compute size of segment we *could* send. This is the
  51.  * smallest of the usable window, the mss, or the amount
  52.  * we have on hand. (I don't like optimistic windows)
  53.  */
  54. ssize = min(tcb->sndcnt - sent,usable);
  55. ssize = min(ssize,tcb->mss);
  56. /* Now we decide if we actually want to send it.
  57.  * Apply John Nagle's "single outstanding segment" rule.
  58.  * If data is already in the pipeline, don't send
  59.  * more unless it is MSS-sized, the very last packet,
  60.  * or we're being forced to transmit anyway (e.g., to
  61.  * ack incoming data).
  62.  */
  63. if(!tcb->flags.force && sent != 0 && ssize < tcb->mss
  64.  && !(tcb->state == TCP_FINWAIT1 && ssize == tcb->sndcnt-sent)){
  65. ssize = 0;
  66. }
  67.   /* Unless the tcp syndata option is on, inhibit data until
  68.  * our SYN has been acked. This ought to be OK, but some
  69.  * old TCPs have problems with data piggybacked on SYNs.
  70.  */
  71. if(!tcb->flags.synack && !Tcp_syndata){
  72. if(tcb->snd.ptr == tcb->iss)
  73. ssize = min(1,ssize); /* Send only SYN */
  74. else
  75. ssize = 0; /* Don't send anything */
  76. }
  77. /* If we're forced to send an ack while retransmitting,
  78.  * don't send any data. This will let us use the current
  79.  * sequence number, which may be necessary for the
  80.  * ack to be accepted by the receiver
  81.  */
  82. if(tcb->flags.force && tcb->snd.ptr != tcb->snd.nxt)
  83. ssize = 0;
  84. if(ssize == 0 && !tcb->flags.force)
  85. break; /* No need to send anything */
  86. tcb->flags.force = 0; /* Only one forced segment! */
  87. seg.source = tcb->conn.local.port;
  88. seg.dest = tcb->conn.remote.port;
  89. /* Set the flags according to the state we're in. It is
  90.  * assumed that if this segment is associated with a state
  91.  * transition, then the state change will already have been
  92.  * made. This allows this routine to be called from a
  93.  * retransmission timeout with force=1.
  94.  */
  95. seg.flags.ack = 1; /* Every state except TCP_SYN_SENT */
  96. seg.flags.congest = tcb->flags.congest;
  97. if(tcb->state == TCP_SYN_SENT)
  98. seg.flags.ack = 0; /* Haven't seen anything yet */
  99. dsize = ssize;
  100. if(!tcb->flags.synack && tcb->snd.ptr == tcb->iss){
  101. /* Send SYN */
  102. seg.flags.syn = 1;
  103. dsize--; /* SYN isn't really in snd queue */
  104. /* Also send MSS, wscale and tstamp (if OK) */
  105. seg.mss = Tcp_mss;
  106. seg.flags.mss = 1;
  107. seg.wsopt = DEF_WSCALE;
  108. seg.flags.wscale = 1;
  109. if(Tcp_tstamps){
  110. seg.flags.tstamp = 1;
  111. seg.tsval = msclock();
  112. }
  113. }
  114. /* If there's no data, use snd.nxt rather than snd.ptr to
  115.  * ensure ack acceptance in case we were retransmitting
  116.  */
  117. if(ssize == 0)
  118. seg.seq = tcb->snd.nxt;
  119. else
  120. seg.seq = tcb->snd.ptr;
  121. tcb->last_ack_sent = seg.ack = tcb->rcv.nxt;
  122. if(seg.flags.syn || !tcb->flags.ws_ok)
  123. seg.wnd = tcb->rcv.wnd;
  124. else
  125. seg.wnd = tcb->rcv.wnd >> tcb->rcv.wind_scale;
  126. /* Now try to extract some data from the send queue. Since
  127.  * SYN and FIN occupy sequence space and are reflected in
  128.  * sndcnt but don't actually sit in the send queue, extract
  129.  * will return one less than dsize if a FIN needs to be sent.
  130.  */
  131. dbp = ambufw(TCP_HDR_PAD+dsize);
  132. dbp->data += TCP_HDR_PAD; /* Allow room for other hdrs */
  133. if(dsize != 0){
  134. int32 offset;
  135. /* SYN doesn't actually take up space on the sndq,
  136.  * so take it out of the sent count
  137.  */
  138. offset = sent;
  139. if(!tcb->flags.synack && sent != 0)
  140. offset--;
  141. dbp->cnt = extract(tcb->sndq,(uint16)offset,dbp->data,dsize);
  142. if(dbp->cnt != dsize){
  143. /* We ran past the end of the send queue;
  144.  * send a FIN
  145.  */
  146. seg.flags.fin = 1;
  147. dsize--;
  148. }
  149. }
  150. /* If the entire send queue will now be in the pipe, set the
  151.  * push flag
  152.  */
  153. if(dsize != 0 && sent + ssize == tcb->sndcnt)
  154. seg.flags.psh = 1;
  155. /* If this transmission includes previously transmitted data,
  156.  * snd.nxt will already be past snd.ptr. In this case,
  157.  * compute the amount of retransmitted data and keep score
  158.  */
  159. if(tcb->snd.ptr < tcb->snd.nxt)
  160. tcb->resent += min(tcb->snd.nxt - tcb->snd.ptr,ssize);
  161. tcb->snd.ptr += ssize;
  162. /* If this is the first transmission of a range of sequence
  163.  * numbers, record it so we'll accept acknowledgments
  164.  * for it later
  165.  */
  166. if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
  167. tcb->snd.nxt = tcb->snd.ptr;
  168. if(tcb->flags.ts_ok && seg.flags.ack){
  169. seg.flags.tstamp = 1;
  170. seg.tsval = msclock();
  171. seg.tsecr = tcb->ts_recent;
  172. }
  173. /* Generate TCP header, compute checksum, and link in data */
  174. htontcp(&seg,&dbp,tcb->conn.local.address,
  175.  tcb->conn.remote.address);
  176. /* If we're sending some data or flags, start retransmission
  177.  * and round trip timers if they aren't already running.
  178.  */
  179. if(ssize != 0){
  180. /* Set round trip timer. */
  181. rto = backoff(tcb->backoff) * (4 * tcb->mdev + tcb->srtt);
  182. set_timer(&tcb->timer,max(MIN_RTO,rto));
  183. if(!run_timer(&tcb->timer))
  184. start_timer(&tcb->timer);
  185. /* If round trip timer isn't running, start it */
  186. if(tcb->flags.ts_ok || !tcb->flags.rtt_run){
  187. tcb->flags.rtt_run = 1;
  188. tcb->rtt_time = msclock();
  189. tcb->rttseq = tcb->snd.ptr;
  190. tcb->rttack = tcb->snd.una;
  191. }
  192. }
  193. if(tcb->flags.retran)
  194. tcpRetransSegs++;
  195. else
  196. tcpOutSegs++;
  197. ip_send(tcb->conn.local.address,tcb->conn.remote.address,
  198.  TCP_PTCL,tcb->tos,0,&dbp,len_p(dbp),0,0);
  199. }
  200. }