⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp_out.c

📁 基于DM642的网络传输
💻 C
📖 第 1 页 / 共 2 页
字号:
/**
 * @file
 *
 * Transmission Control Protocol, outgoing traffic
 *
 * The output functions of TCP.
 *
 */
#include "tcp.h"
#include "../skbuff.h"
/* Forward declarations.*/
static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);

err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
{
	   return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);
}

/*
 * NB. tcp_write() enqueues data for sending, but does not send it
 * straight away.  It waits in the expectation of more data being sent
 * soon (as it can send them more efficiently by combining them
 * together).  To prompt the system to send data now, call
 * tcp_output() after calling tcp_write().
 */

err_t tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
{

	  if (pcb->state == SYN_SENT ||
	      pcb->state == SYN_RCVD ||
	      pcb->state == ESTABLISHED ||
	      pcb->state == CLOSE_WAIT
	     ) 
	  {
		    if (len > 0) 
		    {
			      return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);
		    }
		    return ERR_OK;
	  } 
	  else 
	  {
		    return ERR_CONN;
	  }
}

err_t tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
                  u8_t flags, u8_t copy,u8_t *optdata, 
                  u8_t optlen
                 )
{
	  struct pbuf *p;
	  struct tcp_seg *seg, *useg, *queue;
	  u32_t left, seqno;
	  u16_t seglen;
	  void *ptr;
	  u8_t queuelen;
	
	
	  left = len;
	  ptr = arg;
	  /* fail on too much data */
	  if (len > pcb->snd_buf) 
	  {
		    return ERR_MEM;
	  }
	
	  /* seqno will be the sequence number of the first segment enqueued
	   * by the call to this function. */
	  seqno = pcb->snd_lbb;
	
	  queue = NULL;
	
	  /* Check if the queue length exceeds the configured maximum queue
	   * length. If so, we return an error. */
	  queuelen = pcb->snd_queuelen;
	  if (queuelen >= TCP_SND_QUEUELEN) 
	  {
		    goto memerr;
	  }
	
	  if (pcb->snd_queuelen != 0) 
	  {
	  
	  }
	
	  seg = useg = NULL;
	  seglen = 0;
	
	  /* First, break up the data into segments and tuck them together in
	   * the local "queue" variable. */
	  while (queue == NULL || left > 0) 
	  {
		    /* The segment length should be the MSS if the data to be enqueued
		     * is larger than the MSS. */
		    seglen = left > pcb->mss? pcb->mss: left;
		
		    /* Allocate memory for tcp_seg, and fill in fields. */
		    seg = memp_malloc(MEMP_TCP_SEG);
		    if (seg == NULL) 
		    {
			      goto memerr;
		    }
		    seg->next = NULL;
		    seg->p = NULL;
		
		    if (queue == NULL) 
		    {
			      useg = queue = seg;
		    }
		    else 
		    {
			      /* Attach the segment to the end of the queued segments. */
			      useg->next = seg;
			      useg = seg;
		    }
		
		    /* If copy is set, memory should be allocated
		     * and data copied into pbuf, otherwise data comes from
		     * ROM or other static memory, and need not be copied. If
		     * optdata is != NULL, we have options instead of data. */
		    if (optdata != NULL) 
		    {
			      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) 
			      {
				        goto memerr;
			      }
			      ++queuelen;
			      seg->dataptr = seg->p->payload;
		    }
		    else if (copy) 
		    {
			      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) 
			      {
				        goto memerr;
			      }
			      ++queuelen;
			      if (arg != NULL) 
			      {
				        memcpy(seg->p->payload, ptr, seglen);
			      }
			      seg->dataptr = seg->p->payload;
		    }
		    /* do not copy data */
		    else 
		    {
		
			      /* first, allocate a pbuf for holding the data.
			       * since the referenced data is available at least until it is sent out on the
			       * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
			       * instead of PBUF_REF here.
			       */
			      if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL)
			      {
				        goto memerr;
			      }
			      ++queuelen;
			      p->payload = ptr;
			      seg->dataptr = ptr;
			
			      /* Second, allocate a pbuf for the headers. */
			      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) 
			      {
				        /* If allocation fails, we have to deallocate the data pbuf as
				         * well. */
				        pbuf_free(p);
				        goto memerr;
			      }
			      ++queuelen;
			
			      /* Concatenate the headers and data pbufs together. */
			      pbuf_cat(seg->p, p);
			      p = NULL;
		    }
		
		    /* Now that there are more segments queued, we check again if the
		    length of the queue exceeds the configured maximum. */
		    if (queuelen > TCP_SND_QUEUELEN) 
		    {
			      goto memerr;
		    }
		
		    seg->len = seglen;
		    #if 0 /* Was commented out. TODO: can someone say why this is here? */
		    if ((flags & TCP_SYN) || (flags & TCP_FIN)) 
		    {
			      ++seg->len;
		    }
		    #endif
		    /* Build TCP header. */
		    if (pbuf_header(seg->p, TCP_HLEN)) 
		    {
			      TCP_STATS_INC(tcp.err);
			      goto memerr;
		    }
		    seg->tcphdr = seg->p->payload;
		    seg->tcphdr->src = htons(pcb->local_port);
		    seg->tcphdr->dest = htons(pcb->remote_port);
		    seg->tcphdr->seqno = htonl(seqno);
		    seg->tcphdr->urgp = 0;
		    TCPH_FLAGS_SET(seg->tcphdr, flags);
		    /* don't fill in tcphdr->ackno and tcphdr->wnd until later */
		
		    /* Copy the options into the header, if they are present. */
		    if (optdata == NULL) 
		    {
			      TCPH_HDRLEN_SET(seg->tcphdr, 5);
		    }
		    else 
		    {
			      TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));
			      /* Copy options into data portion of segment.
			       Options can thus only be sent in non data carrying
			       segments such as SYN|ACK. */
			      memcpy(seg->dataptr, optdata, optlen);
		    }
		
		    left -= seglen;
		    seqno += seglen;
		    ptr = (void *)((char *)ptr + seglen);
	  }
	
	
	  /* Now that the data to be enqueued has been broken up into TCP
	  segments in the queue variable, we add them to the end of the
	  pcb->unsent queue. */
	  if (pcb->unsent == NULL) 
	  {
		    useg = NULL;
	  }
	  else 
	  {
		    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
	  }
	
	  /* If there is room in the last pbuf on the unsent queue,
	  chain the first pbuf on the queue together with that. */
	  if (useg != NULL &&
	      TCP_TCPLEN(useg) != 0 &&
	      !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
	      !(flags & (TCP_SYN | TCP_FIN)) &&
	      useg->len + queue->len <= pcb->mss) 
	  {
		    /* Remove TCP header from first segment. */
		    pbuf_header(queue->p, -TCP_HLEN);
		    pbuf_cat(useg->p, queue->p);
		    useg->len += queue->len;
		    useg->next = queue->next;
		    if (seg == queue) 
		    {
			      seg = NULL;
		    }
		    memp_free(MEMP_TCP_SEG, queue);
	  }
	  else 
	  {
		    if (useg == NULL) 
		    {
			      pcb->unsent = queue;
		    }
		    else 
		    {
			      useg->next = queue;
		    }
	  }
	  if ((flags & TCP_SYN) || (flags & TCP_FIN)) 
	  {
		    ++len;
	  }
	  pcb->snd_lbb += len;
	  pcb->snd_buf -= len;
	  pcb->snd_queuelen = queuelen;
	  if (pcb->snd_queuelen != 0) 
	  {
	
	  }
	
	  /* Set the PSH flag in the last segment that we enqueued, but only
	  if the segment has data (indicated by seglen > 0). */
	  if (seg != NULL && seglen > 0 && seg->tcphdr != NULL) 
	  {
		    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
	  }
	
	  return ERR_OK;
	  memerr:
	  TCP_STATS_INC(tcp.memerr);
	  if (queue != NULL) 
	  {
		    tcp_segs_free(queue);
	  }
	  if (pcb->snd_queuelen != 0) 
	  {
	
	  }
	  return ERR_MEM;
}

/* find out what we can send and send it */
err_t tcp_output(struct tcp_pcb *pcb)
{
	  struct pbuf *p;
	  struct tcp_hdr *tcphdr;
	  struct tcp_seg *seg, *useg;
	  u32_t wnd;
	  struct  sk_buff skb;
	  Uint8   *DesData;
	
	
	  /* First, check if we are invoked by the TCP input processing
	     code. If so, we do not output anything. Instead, we rely on the
	     input processing code to call us when input processing is done
	     with. */
	  if (tcp_input_pcb == pcb) 
	  {
		    return ERR_OK;
	  }
	
	  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
	

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -