コード例 #1
0
ファイル: tcp_unix.c プロジェクト: RsrchBoy/dpkg-alpine
long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
{
  unsigned long n;
				/* make sure socket still alive */
  if (stream->tcpsi < 0) return NIL;
				/* can transfer bytes from buffer? */
  if (n = min (size,stream->ictr)) {
    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
    s += n;			/* update pointer */
    stream->iptr +=n;
    size -= n;			/* update # of bytes to do */
    stream->ictr -=n;
  }
  if (size) {
    int i;
    fd_set fds,efds;
    struct timeval tmo;
    time_t t = time (0);
    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
    (*bn) (BLOCK_TCPREAD,NIL);
    while (size > 0) {		/* until request satisfied */
      time_t tl = time (0);
      time_t now = tl;
      time_t ti = ttmo_read ? now + ttmo_read : 0;
      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
      tmo.tv_usec = 0;
      FD_ZERO (&fds);		/* initialize selection vector */
      FD_ZERO (&efds);		/* handle errors too */
				/* set bit in selection vectors */
      FD_SET (stream->tcpsi,&fds);
      FD_SET (stream->tcpsi,&efds);
      errno = NIL;		/* initially no error */
      do {			/* block under timeout */
	tmo.tv_sec = ti ? ti - now : 0;
	i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL);
	now = time (0);		/* fake timeout if interrupt & time expired */
	if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
      } while ((i < 0) && (errno == EINTR));
      if (i) {			/* non-timeout result from select? */
	if (i > 0)		/* read what we can */
	  while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0)
		 && (errno == EINTR));
	if (i <= 0) {		/* error seen? */
	  if (tcpdebug) {
	    char tmp[MAILTMPLEN];
	    if (i) sprintf (s = tmp,"TCP buffer read I/O error %d",errno);
	    else s = "TCP buffer read end of file";
	    mm_log (s,TCPDEBUG);
	  }
	  return tcp_abort (stream);
	}
	s += i;			/* success, point at new place to write */
	size -= i;		/* reduce byte count */
	if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
      }
				/* timeout, punt unless told not to */
      else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->host)) {
	if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
	return tcp_abort (stream);
      }
    }
    (*bn) (BLOCK_NONE,NIL);
  }
  *s = '\0';			/* tie off string */
  return LONGT;
}
コード例 #2
0
ファイル: test_tcp.c プロジェクト: tansinan/lwIP
END_TEST

START_TEST(test_tcp_persist_split)
{
  struct netif netif;
  struct test_tcp_txcounters txcounters;
  struct test_tcp_counters counters;
  struct tcp_pcb *pcb;
  struct pbuf* p;
  err_t err;
  size_t i;
  LWIP_UNUSED_ARG(_i);

  /* Setup data for four segments */
  for (i = 0; i < 4 * TCP_MSS; i++) {
    tx_data[i] = (u8_t)i;
  }

  /* initialize local vars */
  test_tcp_init_netif(&netif, &txcounters, &test_local_ip, &test_netmask);
  memset(&counters, 0, sizeof(counters));

  /* create and initialize the pcb */
  tcp_ticks = SEQNO1 - ISS;
  pcb = test_tcp_new_counters_pcb(&counters);
  EXPECT_RET(pcb != NULL);
  tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT);
  pcb->mss = TCP_MSS;
  /* set window to three segments */
  pcb->cwnd = 3 * TCP_MSS;
  pcb->snd_wnd = 3 * TCP_MSS;
  pcb->snd_wnd_max = 3 * TCP_MSS;

  /* send three segments */
  err = tcp_write(pcb, &tx_data[0], 3 * TCP_MSS, TCP_WRITE_FLAG_COPY);
  EXPECT(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT(err == ERR_OK);

  /* verify segments are in-flight */
  EXPECT(pcb->unsent == NULL);
  EXPECT(pcb->unacked != NULL);
  check_seqnos(pcb->unacked, 3, seqnos);
  EXPECT(txcounters.num_tx_calls == 3);
  EXPECT(txcounters.num_tx_bytes == 3 * (TCP_MSS + 40U));
  memset(&txcounters, 0, sizeof(txcounters));

  /* ACK the segments and update the window to only 1/2 TCP_MSS */
  p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, 3 * TCP_MSS, TCP_ACK, TCP_MSS / 2);
  test_tcp_input(p, &netif);
  EXPECT(pcb->unacked == NULL);
  EXPECT(pcb->unsent == NULL);
  EXPECT(pcb->persist_backoff == 0);
  EXPECT(pcb->snd_wnd == TCP_MSS / 2);

  /* send fourth segment, which is larger than snd_wnd */
  err = tcp_write(pcb, &tx_data[3 * TCP_MSS], TCP_MSS, TCP_WRITE_FLAG_COPY);
  EXPECT(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT(err == ERR_OK);

  /* ensure it is buffered and persist timer started */
  EXPECT(pcb->unacked == NULL);
  EXPECT(pcb->unsent != NULL);
  check_seqnos(pcb->unsent, 1, &seqnos[3]);
  EXPECT(txcounters.num_tx_calls == 0);
  EXPECT(txcounters.num_tx_bytes == 0);
  EXPECT(pcb->persist_backoff == 1);

  /* ensure no errors have been recorded */
  EXPECT(counters.err_calls == 0);
  EXPECT(counters.last_err == ERR_OK);

  /* call tcp_timer some more times to let persist timer count up */
    for (i = 0; i < 4; i++) {
      test_tcp_tmr();
      EXPECT(txcounters.num_tx_calls == 0);
      EXPECT(txcounters.num_tx_bytes == 0);
    }

  /* this should be the first timer shot, which should split the
   * segment and send a runt (of the remaining window size) */
  txcounters.copy_tx_packets = 1;
  test_tcp_tmr();
  txcounters.copy_tx_packets = 0;
  /* persist will be disabled as RTO timer takes over */
  EXPECT(pcb->persist_backoff == 0);
  EXPECT(txcounters.num_tx_calls == 1);
  EXPECT(txcounters.num_tx_bytes == ((TCP_MSS /2) + 40U));
  /* verify half segment sent, half still buffered */
  EXPECT(pcb->unsent != NULL);
  EXPECT(pcb->unsent->len == TCP_MSS / 2);
  EXPECT(pcb->unacked != NULL);
  EXPECT(pcb->unacked->len == TCP_MSS / 2);

  /* verify first half segment */
  EXPECT(txcounters.tx_packets != NULL);
  if (txcounters.tx_packets != NULL) {
    u8_t sent[TCP_MSS / 2];
    u16_t ret;
    ret = pbuf_copy_partial(txcounters.tx_packets, &sent, TCP_MSS / 2, 40U);
    EXPECT(ret == TCP_MSS / 2);
    EXPECT(memcmp(sent, &tx_data[3 * TCP_MSS], TCP_MSS / 2) == 0);
  }
  if (txcounters.tx_packets != NULL) {
    pbuf_free(txcounters.tx_packets);
    txcounters.tx_packets = NULL;
  }
  memset(&txcounters, 0, sizeof(txcounters));

  /* ACK the half segment, leave window at half segment */
  p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, TCP_MSS / 2, TCP_ACK, TCP_MSS / 2);
  txcounters.copy_tx_packets = 1;
  test_tcp_input(p, &netif);
  txcounters.copy_tx_packets = 0;
  /* ensure remaining half segment was sent */
  EXPECT(txcounters.num_tx_calls == 1);
  EXPECT(txcounters.num_tx_bytes == ((TCP_MSS /2 ) + 40U));
  EXPECT(pcb->unsent == NULL);
  EXPECT(pcb->unacked != NULL);
  EXPECT(pcb->unacked->len == TCP_MSS / 2);
  EXPECT(pcb->snd_wnd == TCP_MSS / 2);

  /* verify second half segment */
  EXPECT(txcounters.tx_packets != NULL);
  if (txcounters.tx_packets != NULL) {
    u8_t sent[TCP_MSS / 2];
    u16_t ret;
    ret = pbuf_copy_partial(txcounters.tx_packets, &sent, TCP_MSS / 2, 40U);
    EXPECT(ret == TCP_MSS / 2);
    EXPECT(memcmp(sent, &tx_data[(3 * TCP_MSS) + TCP_MSS / 2], TCP_MSS / 2) == 0);
  }
  if (txcounters.tx_packets != NULL) {
    pbuf_free(txcounters.tx_packets);
    txcounters.tx_packets = NULL;
  }

  /* ensure no errors have been recorded */
  EXPECT(counters.err_calls == 0);
  EXPECT(counters.last_err == ERR_OK);

  /* make sure the pcb is freed */
  EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1);
  tcp_abort(pcb);
  EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
}
コード例 #3
0
int lwip_connect(int s, struct sockaddr *name, socklen_t namelen) {
	sockfd_t	* fd;
	struct ip_addr	ip;
	int		port, rv = 0;

	s = sock_for_fd(s);
	if (s < 0) {
		errno = EBADF;
		return -1;
	}
	fd = fds + s;

	// Make sure it's an internet address we understand.
	if (namelen != sizeof(struct sockaddr_in)) {
		errno = ENAMETOOLONG;
		return -1;
	}

	// Get access
	mutex_lock(fd->mutex);

	// Copy it over
	memcpy(&fd->name, name, namelen);

	// Convert this to an lwIP-happy format
	ip.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
	port = ((struct sockaddr_in *)name)->sin_port;

	// Are we TCP or UDP?
	switch (fd->type) {
	case SOCK_STREAM:
		// This might have gotten made already, bind is valid on
		// outgoing sockets too.
		if (!fd->tcppcb)
			fd->tcppcb = tcp_new();
		tcp_arg(fd->tcppcb, (void *)s);
		tcp_recv(fd->tcppcb, recv_tcp);
		tcp_sent(fd->tcppcb, sent_tcp);
		tcp_poll(fd->tcppcb, poll_tcp, 4);	// 4 == 4 TCP timer intervals
		tcp_err(fd->tcppcb, err_tcp);
		if (tcp_connect(fd->tcppcb, &ip, ntohs(port), connect_tcp) != ERR_OK) {
			if (tcp_close(fd->tcppcb) != ERR_OK)
				tcp_abort(fd->tcppcb);
			fd->tcppcb = NULL;
			errno = EINVAL;
			rv = -1; goto out;
		}
		break;
	case SOCK_DGRAM:
		// This might have gotten made already, bind is valid on
		// outgoing sockets too.
		if (!fd->udppcb)
			fd->udppcb = udp_new();
		udp_recv(fd->udppcb, recv_udp, (void *)s);
		udp_connect(fd->udppcb, &ip, ntohs(port));
		break;
	default:
		assert( 0 );
		errno = EINVAL;
		rv = -1; goto out;
	}

	// If we are doing a TCP connect, we need to wait for the results
	// of the operation.
	if (fd->type == SOCK_STREAM) {
		// Wait for the result
		fd->connerr = 10;
		while (fd->connerr > 0) {
			cond_wait(fd->connect, fd->mutex);
		}

		// Convert error codes
		switch (fd->connerr) {
		case ERR_OK: break;
		
		case ERR_MEM:
		case ERR_BUF:
		case ERR_VAL:
		case ERR_ARG:
		case ERR_IF:
			errno = EINVAL;
			rv = -1;
			goto out;

		case ERR_ABRT:
		case ERR_RST:
		case ERR_CLSD:
		case ERR_CONN:
			errno = ECONNREFUSED;
			rv = -1;
			goto out;

		case ERR_RTE:
			errno = ENETUNREACH;
			rv = -1;
			goto out;

		case ERR_USE:
			errno = EADDRINUSE;
			rv = -1;
			goto out;
		}

		if (fd->connerr == ERR_OK) {
			// Init our counters
			fd->recv = 0;
			fd->send = tcp_sndbuf(fd->tcppcb);
		}
	}

out:
	mutex_unlock(fd->mutex);
	return rv;
}
コード例 #4
0
ファイル: esp_mg_net_if.c プロジェクト: yonglehou/smart.js
static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
                                 struct pbuf *p, err_t err) {
  struct mg_connection *nc = (struct mg_connection *) arg;
  DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err));
  if (p == NULL) {
    if (nc != NULL) {
      mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
    } else {
      /* Tombstoned connection, do nothing. */
    }
    return ERR_OK;
  } else if (nc == NULL) {
    tcp_abort(tpcb);
    return ERR_ARG;
  }
  struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
  /*
   * If we get a chain of more than one segment at once, we need to bump
   * refcount on the subsequent bufs to make them independent.
   */
  if (p->next != NULL) {
    struct pbuf *q = p->next;
    for (; q != NULL; q = q->next) pbuf_ref(q);
  }
  if (cs->rx_chain == NULL) {
    cs->rx_chain = p;
    cs->rx_offset = 0;
  } else {
    if (pbuf_clen(cs->rx_chain) >= 4) {
      /* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX
       * will be completely blocked. We already have at least 4 in the chain,
       * this one is, so we have to make a copy and release this one. */
      struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
      if (np != NULL) {
        pbuf_copy(np, p);
        pbuf_free(p);
        p = np;
      }
    }
    pbuf_chain(cs->rx_chain, p);
  }

#ifdef SSL_KRYPTON
  if (nc->ssl != NULL) {
    if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
      mg_lwip_ssl_recv(nc);
    } else {
      mg_lwip_ssl_do_hs(nc);
    }
    return ERR_OK;
  }
#endif

  while (cs->rx_chain != NULL) {
    struct pbuf *seg = cs->rx_chain;
    size_t len = (seg->len - cs->rx_offset);
    char *data = (char *) malloc(len);
    if (data == NULL) {
      DBG(("OOM"));
      return ERR_MEM;
    }
    pbuf_copy_partial(seg, data, len, cs->rx_offset);
    mg_if_recv_tcp_cb(nc, data, len); /* callee takes over data */
    cs->rx_offset += len;
    if (cs->rx_offset == cs->rx_chain->len) {
      cs->rx_chain = pbuf_dechain(cs->rx_chain);
      pbuf_free(seg);
      cs->rx_offset = 0;
    }
  }

  if (nc->send_mbuf.len > 0) {
    mg_lwip_mgr_schedule_poll(nc->mgr);
  }
  return ERR_OK;
}
コード例 #5
0
END_TEST


/** create multiple segments and pass them to tcp_input in a wrong
 * order to see if ooseq-caching works correctly
 * FIN is received IN-SEQUENCE at the end */
START_TEST(test_tcp_recv_ooseq_FIN_INSEQ)
{
  struct test_tcp_counters counters;
  struct tcp_pcb* pcb;
  struct pbuf *p_1_2, *p_4_8, *p_3_11, *p_2_12, *p_15_1, *p_15_1a, *pinseq, *pinseqFIN;
  char data[] = {
     1,  2,  3,  4,
     5,  6,  7,  8,
     9, 10, 11, 12,
    13, 14, 15, 16};
  ip_addr_t remote_ip, local_ip, netmask;
  u16_t data_len;
  u16_t remote_port = 0x100, local_port = 0x101;
  struct netif netif;
  LWIP_UNUSED_ARG(_i);

  /* initialize local vars */
  memset(&netif, 0, sizeof(netif));
  IP_ADDR4(&local_ip, 192, 168, 1, 1);
  IP_ADDR4(&remote_ip, 192, 168, 1, 2);
  IP_ADDR4(&netmask,   255, 255, 255, 0);
  test_tcp_init_netif(&netif, NULL, &local_ip, &netmask);
  data_len = sizeof(data);
  /* initialize counter struct */
  memset(&counters, 0, sizeof(counters));
  counters.expected_data_len = data_len;
  counters.expected_data = data;

  /* create and initialize the pcb */
  pcb = test_tcp_new_counters_pcb(&counters);
  EXPECT_RET(pcb != NULL);
  tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);

  /* create segments */
  /* p1: 7 bytes - 2 before FIN */
  /*     seqno: 1..2 */
  p_1_2  = tcp_create_rx_segment(pcb, &data[1],  2, 1, 0, TCP_ACK);
  /* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */
  /*     seqno: 4..11 */
  p_4_8  = tcp_create_rx_segment(pcb, &data[4],  8, 4, 0, TCP_ACK);
  /* p3: same as p2 but 2 bytes longer and one byte more at the front */
  /*     seqno: 3..13 */
  p_3_11 = tcp_create_rx_segment(pcb, &data[3], 11, 3, 0, TCP_ACK);
  /* p4: 13 bytes - 2 before FIN - should be ignored as contained in p1 and p3 */
  /*     seqno: 2..13 */
  p_2_12 = tcp_create_rx_segment(pcb, &data[2], 12, 2, 0, TCP_ACK);
  /* pinseq is the first segment that is held back to create ooseq! */
  /*     seqno: 0..3 */
  pinseq = tcp_create_rx_segment(pcb, &data[0],  4, 0, 0, TCP_ACK);
  /* p5: last byte before FIN */
  /*     seqno: 15 */
  p_15_1 = tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK);
  /* p6: same as p5, should be ignored */
  p_15_1a= tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK);
  /* pinseqFIN: last 2 bytes plus FIN */
  /*     only segment containing seqno 14 and FIN */
  pinseqFIN = tcp_create_rx_segment(pcb,  &data[14], 2, 14, 0, TCP_ACK|TCP_FIN);
  EXPECT(pinseq != NULL);
  EXPECT(p_1_2 != NULL);
  EXPECT(p_4_8 != NULL);
  EXPECT(p_3_11 != NULL);
  EXPECT(p_2_12 != NULL);
  EXPECT(p_15_1 != NULL);
  EXPECT(p_15_1a != NULL);
  EXPECT(pinseqFIN != NULL);
  if ((pinseq != NULL) && (p_1_2 != NULL) && (p_4_8 != NULL) && (p_3_11 != NULL) && (p_2_12 != NULL)
    && (p_15_1 != NULL) && (p_15_1a != NULL) && (pinseqFIN != NULL)) {
    /* pass the segment to tcp_input */
    test_tcp_input(p_1_2, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 0);
    EXPECT(counters.recv_calls == 0);
    EXPECT(counters.recved_bytes == 0);
    EXPECT(counters.err_calls == 0);
    /* check ooseq queue */
    EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2);

    /* pass the segment to tcp_input */
    test_tcp_input(p_4_8, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 0);
    EXPECT(counters.recv_calls == 0);
    EXPECT(counters.recved_bytes == 0);
    EXPECT(counters.err_calls == 0);
    /* check ooseq queue */
    EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2);
    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 4);
    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 8);

    /* pass the segment to tcp_input */
    test_tcp_input(p_3_11, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 0);
    EXPECT(counters.recv_calls == 0);
    EXPECT(counters.recved_bytes == 0);
    EXPECT(counters.err_calls == 0);
    /* check ooseq queue */
    EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2);
    /* p_3_11 has removed p_4_8 from ooseq */
    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 3);
    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 11);

    /* pass the segment to tcp_input */
    test_tcp_input(p_2_12, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 0);
    EXPECT(counters.recv_calls == 0);
    EXPECT(counters.recved_bytes == 0);
    EXPECT(counters.err_calls == 0);
    /* check ooseq queue */
    EXPECT_OOSEQ(tcp_oos_count(pcb) == 2);
    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1);
    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);
    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 2);
    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 12);

    /* pass the segment to tcp_input */
    test_tcp_input(pinseq, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 0);
    EXPECT(counters.recv_calls == 1);
    EXPECT(counters.recved_bytes == 14);
    EXPECT(counters.err_calls == 0);
    EXPECT(pcb->ooseq == NULL);

    /* pass the segment to tcp_input */
    test_tcp_input(p_15_1, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 0);
    EXPECT(counters.recv_calls == 1);
    EXPECT(counters.recved_bytes == 14);
    EXPECT(counters.err_calls == 0);
    /* check ooseq queue */
    EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15);
    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);

    /* pass the segment to tcp_input */
    test_tcp_input(p_15_1a, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 0);
    EXPECT(counters.recv_calls == 1);
    EXPECT(counters.recved_bytes == 14);
    EXPECT(counters.err_calls == 0);
    /* check ooseq queue: unchanged */
    EXPECT_OOSEQ(tcp_oos_count(pcb) == 1);
    EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15);
    EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1);

    /* pass the segment to tcp_input */
    test_tcp_input(pinseqFIN, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 1);
    EXPECT(counters.recv_calls == 2);
    EXPECT(counters.recved_bytes == data_len);
    EXPECT(counters.err_calls == 0);
    EXPECT(pcb->ooseq == NULL);
  }

  /* make sure the pcb is freed */
  EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1);
  tcp_abort(pcb);
  EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
}
コード例 #6
0
ファイル: tcp_in.c プロジェクト: YTakami/makecontroller
/**
 * Implements the TCP state machine. Called by tcp_input. In some
 * states tcp_receive() is called to receive data. The tcp_seg
 * argument will be freed by the caller (tcp_input()) unless the
 * recv_data pointer in the pcb is set.
 *
 * @param pcb the tcp_pcb for which a segment arrived
 *
 * @note the segment which arrived is saved in global variables, therefore only the pcb
 *       involved is passed as a parameter to this function
 */
static err_t
tcp_process(struct tcp_pcb *pcb)
{
  struct tcp_seg *rseg;
  u8_t acceptable = 0;
  err_t err;
  u8_t accepted_inseq;

  err = ERR_OK;

  /* Process incoming RST segments. */
  if (flags & TCP_RST) {
    /* First, determine if the reset is acceptable. */
    if (pcb->state == SYN_SENT) {
      if (ackno == pcb->snd_nxt) {
        acceptable = 1;
      }
    } else {
      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 
                          pcb->rcv_nxt+pcb->rcv_ann_wnd)) {
        acceptable = 1;
      }
    }

    if (acceptable) {
      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
      LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
      recv_flags = TF_RESET;
      pcb->flags &= ~TF_ACK_DELAY;
      return ERR_RST;
    } else {
      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
       seqno, pcb->rcv_nxt));
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
       seqno, pcb->rcv_nxt));
      return ERR_OK;
    }
  }

  /* Update the PCB (in)activity timer. */
  pcb->tmr = tcp_ticks;
  pcb->keep_cnt_sent = 0;

  /* Do different things depending on the TCP state. */
  switch (pcb->state) {
  case SYN_SENT:
    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
     pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
    /* received SYN ACK with expected sequence number? */
    if ((flags & TCP_ACK) && (flags & TCP_SYN)
        && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
      pcb->snd_buf++;
      pcb->rcv_nxt = seqno + 1;
      pcb->lastack = ackno;
      pcb->snd_wnd = tcphdr->wnd;
      pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
      pcb->state = ESTABLISHED;

      /* Parse any options in the SYNACK before using pcb->mss since that
       * can be changed by the received options! */
      tcp_parseopt(pcb);
#if TCP_CALCULATE_EFF_SEND_MSS
      pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
#endif /* TCP_CALCULATE_EFF_SEND_MSS */

      /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
       * but for the default value of pcb->mss) */
      pcb->ssthresh = pcb->mss * 10;

      pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
      LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
      --pcb->snd_queuelen;
      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
      rseg = pcb->unacked;
      pcb->unacked = rseg->next;

      /* If there's nothing left to acknowledge, stop the retransmit
         timer, otherwise reset it to start again */
      if(pcb->unacked == NULL)
        pcb->rtime = -1;
      else {
        pcb->rtime = 0;
        pcb->nrtx = 0;
      }

      tcp_seg_free(rseg);

      /* Call the user specified function to call when sucessfully
       * connected. */
      TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
      tcp_ack_now(pcb);
    }
    /* received ACK? possibly a half-open connection */
    else if (flags & TCP_ACK) {
      /* send a RST to bring the other side in a non-synchronized state. */
      tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
        tcphdr->dest, tcphdr->src);
    }
    break;
  case SYN_RCVD:
    if (flags & TCP_ACK &&
       !(flags & TCP_RST)) {
      /* expected ACK number? */
      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
        u16_t old_cwnd;
        pcb->state = ESTABLISHED;
        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
#if LWIP_CALLBACK_API
        LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
#endif
        /* Call the accept function. */
        TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
        if (err != ERR_OK) {
          /* If the accept function returns with an error, we abort
           * the connection. */
          tcp_abort(pcb);
          return ERR_ABRT;
        }
        old_cwnd = pcb->cwnd;
        /* If there was any data contained within this ACK,
         * we'd better pass it on to the application as well. */
        accepted_inseq = tcp_receive(pcb);

        pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);

        if ((flags & TCP_FIN) && accepted_inseq) {
          tcp_ack_now(pcb);
          pcb->state = CLOSE_WAIT;
        }
      }
      /* incorrect ACK number */
      else {
        /* send RST */
        tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
                tcphdr->dest, tcphdr->src);
      }
    }
    break;
  case CLOSE_WAIT:
    /* FALLTHROUGH */
  case ESTABLISHED:
    accepted_inseq = tcp_receive(pcb);
    if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */
      tcp_ack_now(pcb);
      pcb->state = CLOSE_WAIT;
    }
    break;
  case FIN_WAIT_1:
    tcp_receive(pcb);
    if (flags & TCP_FIN) {
      if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
        LWIP_DEBUGF(TCP_DEBUG,
          ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
        tcp_ack_now(pcb);
        tcp_pcb_purge(pcb);
        TCP_RMV(&tcp_active_pcbs, pcb);
        pcb->state = TIME_WAIT;
        TCP_REG(&tcp_tw_pcbs, pcb);
      } else {
        tcp_ack_now(pcb);
        pcb->state = CLOSING;
      }
    } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
      pcb->state = FIN_WAIT_2;
    }
    break;
  case FIN_WAIT_2:
    tcp_receive(pcb);
    if (flags & TCP_FIN) {
      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
      tcp_ack_now(pcb);
      tcp_pcb_purge(pcb);
      TCP_RMV(&tcp_active_pcbs, pcb);
      pcb->state = TIME_WAIT;
      TCP_REG(&tcp_tw_pcbs, pcb);
    }
    break;
  case CLOSING:
    tcp_receive(pcb);
    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
      tcp_ack_now(pcb);
      tcp_pcb_purge(pcb);
      TCP_RMV(&tcp_active_pcbs, pcb);
      pcb->state = TIME_WAIT;
      TCP_REG(&tcp_tw_pcbs, pcb);
    }
    break;
  case LAST_ACK:
    tcp_receive(pcb);
    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
      /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
      recv_flags = TF_CLOSED;
    }
    break;
  default:
    break;
  }
  return ERR_OK;
}
コード例 #7
0
ファイル: cos_net.c プロジェクト: songjiguo/Monitor_ML
static err_t cos_net_lwip_tcp_recv(void *arg, struct tcp_pcb *tp, struct pbuf *p, err_t err)
{
	struct intern_connection *ic;
	struct packet_queue *pq, *last;
	void *headers;
	struct pbuf *first;
	
	ic = (struct intern_connection*)arg;
	assert(NULL != ic);
	assert(TCP == ic->conn_type);
	if (NULL == p) {
		assert(ic->conn.tp == tp);
		/* 
		 * This should call our registered error function
		 * above with ERR_ABRT, which will make progress
		 * towards closing the connection.
		 *
		 * Later, when the app calls some function in the API,
		 * TCP_CLOSED will be seen and the internal connection
		 * will be deallocated, and the application notified.
		 */
		tcp_abort(tp);
		assert(ic->conn_type == TCP_CLOSED && NULL == ic->conn.tp);
		/* tcp_close(tp);  // Jiguo: aggressive close */
		return ERR_CLSD;
	}
	first = p;
	while (p) {
		struct pbuf *q;

		if (p->ref != 1) printc("pbuf with len %d, totlen %d and refcnt %d", p->len, p->tot_len, p->ref);
		assert(p->len > 0);
		assert(p->type == PBUF_ROM || p->type == PBUF_REF);
		headers = cos_net_header_start(p, TCP);
		assert (NULL != headers);
		pq = net_packet_pq(headers);
		pq->data = p->payload;
		pq->len = p->len;
		pq->next = NULL;
#ifdef TEST_TIMING
		pq->ts_start = timing_record(RECV, pq->ts_start);
#endif
	
		assert((NULL == ic->incoming) == (NULL == ic->incoming_last));
		/* Is the queue empty? */
		if (NULL == ic->incoming) {
			assert(NULL == ic->incoming_last);
			ic->incoming = ic->incoming_last = pq;
		} else {
			last = ic->incoming_last;
			last->next = pq;
			ic->incoming_last = pq;
		}
		ic->incoming_size += p->len;
		//assert(1 == p->ref);
		q = p->next;
		p->payload = p->alloc_track = NULL;
		assert(NULL != q || p->len == p->tot_len);
		assert(p->ref == 1);
		p = q;
	}
	/* Just make sure lwip is doing what we think its doing */
	assert(first->ref == 1);
	/* This should deallocate the entire chain */
	pbuf_free(first);

	/* printc("thd in %ld tcp_recv call trigger evt id %d\n", cos_get_thd_id(), ic->data); */
	if (-1 != ic->data && evt_trigger(cos_spd_id(), ic->data)) BUG();
	tcp_recv_cnt++;
/* 	/\* If the thread blocked waiting for a packet, wake it up *\/ */
/* 	if (RECVING == ic->thd_status) { */
/* 		ic->thd_status = ACTIVE; */
/* 		assert(ic->thd_status == ACTIVE); /\* Detect races *\/ */
/* 		if (sched_wakeup(cos_spd_id(), ic->tid)) BUG(); */
/* 	} */

	return ERR_OK;
}
コード例 #8
0
ファイル: test_tcp.c プロジェクト: tansinan/lwIP
END_TEST

/** Send data with sequence numbers that wrap around the u32_t range.
 * Then, provoke RTO retransmission and check that all
 * segment lists are still properly sorted. */
START_TEST(test_tcp_rto_rexmit_wraparound)
{
  struct netif netif;
  struct test_tcp_txcounters txcounters;
  struct test_tcp_counters counters;
  struct tcp_pcb* pcb;
  err_t err;
  size_t i;
  u16_t sent_total = 0;
  LWIP_UNUSED_ARG(_i);

  for (i = 0; i < sizeof(tx_data); i++) {
    tx_data[i] = (u8_t)i;
  }

  /* initialize local vars */
  test_tcp_init_netif(&netif, &txcounters, &test_local_ip, &test_netmask);
  memset(&counters, 0, sizeof(counters));

  /* create and initialize the pcb */
  tcp_ticks = 0;
  tcp_ticks = 0 - tcp_next_iss(NULL);
  tcp_ticks = SEQNO1 - tcp_next_iss(NULL);
  pcb = test_tcp_new_counters_pcb(&counters);
  EXPECT_RET(pcb != NULL);
  tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT);
  pcb->mss = TCP_MSS;
  /* disable initial congestion window (we don't send a SYN here...) */
  pcb->cwnd = 2*TCP_MSS;

  /* send 6 mss-sized segments */
  for (i = 0; i < 6; i++) {
    err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
    EXPECT_RET(err == ERR_OK);
    sent_total += TCP_MSS;
  }
  check_seqnos(pcb->unsent, 6, seqnos);
  EXPECT(pcb->unacked == NULL);
  err = tcp_output(pcb);
  EXPECT(txcounters.num_tx_calls == 2);
  EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U));
  memset(&txcounters, 0, sizeof(txcounters));

  check_seqnos(pcb->unacked, 2, seqnos);
  check_seqnos(pcb->unsent, 4, &seqnos[2]);

  /* call the tcp timer some times */
  for (i = 0; i < 10; i++) {
    test_tcp_tmr();
    EXPECT(txcounters.num_tx_calls == 0);
  }
  /* 11th call to tcp_tmr: RTO rexmit fires */
  test_tcp_tmr();
  EXPECT(txcounters.num_tx_calls == 1);
  check_seqnos(pcb->unacked, 1, seqnos);
  check_seqnos(pcb->unsent, 5, &seqnos[1]);

  /* fake greater cwnd */
  pcb->cwnd = pcb->snd_wnd;
  /* send more data */
  err = tcp_output(pcb);
  EXPECT(err == ERR_OK);
  /* check queues are sorted */
  EXPECT(pcb->unsent == NULL);
  check_seqnos(pcb->unacked, 6, seqnos);

  /* make sure the pcb is freed */
  EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1);
  tcp_abort(pcb);
  EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
}
コード例 #9
0
ファイル: AsyncTCP.cpp プロジェクト: RitterRBC/Arduino
static err_t _tcp_abort_api(struct tcpip_api_call *api_call_msg){
    tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
    msg->err = 0;
    tcp_abort(msg->pcb);
    return msg->err;
}
コード例 #10
0
ファイル: esp_mg_net_if.c プロジェクト: kirikiwi/smart.js
static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
                                 struct pbuf *p, err_t err) {
  struct mg_connection *nc = (struct mg_connection *) arg;
  DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err));
  if (p == NULL) {
    if (nc != NULL) {
      system_os_post(MG_TASK_PRIORITY, MG_SIG_CLOSE_CONN, (uint32_t) nc);
    } else {
      /* Tombstoned connection, do nothing. */
    }
    return ERR_OK;
  } else if (nc == NULL) {
    tcp_abort(tpcb);
    return ERR_ARG;
  }
  struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
  /*
   * If we get a chain of more than one segment at once, we need to bump
   * refcount on the subsequent bufs to make them independent.
   */
  if (p->next != NULL) {
    struct pbuf *q = p->next;
    for (; q != NULL; q = q->next) pbuf_ref(q);
  }
  if (cs->rx_chain == NULL) {
    cs->rx_chain = p;
    cs->rx_offset = 0;
  } else {
    pbuf_chain(cs->rx_chain, p);
  }

#ifdef ESP_SSL_KRYPTON
  if (nc->ssl != NULL) {
    if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
      mg_lwip_ssl_recv(nc);
    } else {
      mg_lwip_ssl_do_hs(nc);
    }
    return ERR_OK;
  }
#endif

  while (cs->rx_chain != NULL) {
    struct pbuf *seg = cs->rx_chain;
    size_t len = (seg->len - cs->rx_offset);
    char *data = (char *) malloc(len);
    if (data == NULL) {
      DBG(("OOM"));
      return ERR_MEM;
    }
    pbuf_copy_partial(seg, data, len, cs->rx_offset);
    mg_if_recv_tcp_cb(nc, data, len); /* callee takes over data */
    cs->rx_offset += len;
    if (cs->rx_offset == cs->rx_chain->len) {
      cs->rx_chain = pbuf_dechain(cs->rx_chain);
      pbuf_free(seg);
      cs->rx_offset = 0;
    }
  }

  if (nc->send_mbuf.len > 0) {
    mg_lwip_mgr_schedule_poll(nc->mgr);
  }
  return ERR_OK;
}
コード例 #11
0
/* this test uses 4 packets:
 * - data (len=TCP_MSS)
 * - FIN
 * - data after FIN (len=1) (invalid)
 * - 2nd FIN (invalid)
 *
 * the parameter 'delay_packet' is a bitmask that choses which on these packets is ooseq
 */
static void test_tcp_recv_ooseq_double_FINs(int delay_packet)
{
  int i, k;
  struct test_tcp_counters counters;
  struct tcp_pcb* pcb;
  struct pbuf *p_normal_fin, *p_data_after_fin, *p, *p_2nd_fin_ooseq;
  ip_addr_t remote_ip, local_ip, netmask;
  u16_t remote_port = 0x100, local_port = 0x101;
  struct netif netif;
  u32_t exp_rx_calls = 0, exp_rx_bytes = 0, exp_close_calls = 0, exp_oos_pbufs = 0, exp_oos_tcplen = 0;
  int first_dropped = 0xff;

  for(i = 0; i < (int)sizeof(data_full_wnd); i++) {
    data_full_wnd[i] = (char)i;
  }

  /* initialize local vars */
  memset(&netif, 0, sizeof(netif));
  IP_ADDR4(&local_ip, 192, 168, 1, 1);
  IP_ADDR4(&remote_ip, 192, 168, 1, 2);
  IP_ADDR4(&netmask,   255, 255, 255, 0);
  test_tcp_init_netif(&netif, NULL, &local_ip, &netmask);
  /* initialize counter struct */
  memset(&counters, 0, sizeof(counters));
  counters.expected_data_len = TCP_WND;
  counters.expected_data = data_full_wnd;

  /* create and initialize the pcb */
  pcb = test_tcp_new_counters_pcb(&counters);
  EXPECT_RET(pcb != NULL);
  tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
  pcb->rcv_nxt = 0x8000;

  /* create segments */
  p = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK);
  p_normal_fin = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS, 0, TCP_ACK|TCP_FIN);
  k = 1;
  p_data_after_fin = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS+1], k, TCP_MSS+1, 0, TCP_ACK);
  p_2nd_fin_ooseq = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS+1+k, 0, TCP_ACK|TCP_FIN);

  if(delay_packet & 1) {
    /* drop normal data */
    first_dropped = 1;
  } else {
    /* send normal data */
    test_tcp_input(p, &netif);
    exp_rx_calls++;
    exp_rx_bytes += TCP_MSS;
  }
  /* check if counters are as expected */
  check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);

  if(delay_packet & 2) {
    /* drop FIN */
    if(first_dropped > 2) {
      first_dropped = 2;
    }
  } else {
    /* send FIN */
    test_tcp_input(p_normal_fin, &netif);
    if (first_dropped < 2) {
      /* already dropped packets, this one is ooseq */
      exp_oos_pbufs++;
      exp_oos_tcplen++;
    } else {
      /* inseq */
      exp_close_calls++;
    }
  }
  /* check if counters are as expected */
  check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);

  if(delay_packet & 4) {
    /* drop data-after-FIN */
    if(first_dropped > 3) {
      first_dropped = 3;
    }
  } else {
    /* send data-after-FIN */
    test_tcp_input(p_data_after_fin, &netif);
    if (first_dropped < 3) {
      /* already dropped packets, this one is ooseq */
      if (delay_packet & 2) {
        /* correct FIN was ooseq */
        exp_oos_pbufs++;
        exp_oos_tcplen += k;
      }
    } else {
      /* inseq: no change */
    }
  }
  /* check if counters are as expected */
  check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);

  if(delay_packet & 8) {
    /* drop 2nd-FIN */
    if(first_dropped > 4) {
      first_dropped = 4;
    }
  } else {
    /* send 2nd-FIN */
    test_tcp_input(p_2nd_fin_ooseq, &netif);
    if (first_dropped < 3) {
      /* already dropped packets, this one is ooseq */
      if (delay_packet & 2) {
        /* correct FIN was ooseq */
        exp_oos_pbufs++;
        exp_oos_tcplen++;
      }
    } else {
      /* inseq: no change */
    }
  }
  /* check if counters are as expected */
  check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);

  if(delay_packet & 1) {
    /* dropped normal data before */
    test_tcp_input(p, &netif);
    exp_rx_calls++;
    exp_rx_bytes += TCP_MSS;
    if((delay_packet & 2) == 0) {
      /* normal FIN was NOT delayed */
      exp_close_calls++;
      exp_oos_pbufs = exp_oos_tcplen = 0;
    }
  }
  /* check if counters are as expected */
  check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);

  if(delay_packet & 2) {
    /* dropped normal FIN before */
    test_tcp_input(p_normal_fin, &netif);
    exp_close_calls++;
    exp_oos_pbufs = exp_oos_tcplen = 0;
  }
  /* check if counters are as expected */
  check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);

  if(delay_packet & 4) {
    /* dropped data-after-FIN before */
    test_tcp_input(p_data_after_fin, &netif);
  }
  /* check if counters are as expected */
  check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);

  if(delay_packet & 8) {
    /* dropped 2nd-FIN before */
    test_tcp_input(p_2nd_fin_ooseq, &netif);
  }
  /* check if counters are as expected */
  check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen);

  /* check that ooseq data has been dumped */
  EXPECT(pcb->ooseq == NULL);

  /* make sure the pcb is freed */
  EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1);
  tcp_abort(pcb);
  EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
}
コード例 #12
0
END_TEST

START_TEST(test_tcp_recv_ooseq_max_pbufs)
{
#if TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_PBUFS < ((TCP_WND / TCP_MSS) + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))
  int i;
  struct test_tcp_counters counters;
  struct tcp_pcb* pcb;
  struct pbuf *p_ovr;
  ip_addr_t remote_ip, local_ip, netmask;
  u16_t remote_port = 0x100, local_port = 0x101;
  struct netif netif;
  int datalen = 0;
  int datalen2;

  for(i = 0; i < sizeof(data_full_wnd); i++) {
    data_full_wnd[i] = (char)i;
  }

  /* initialize local vars */
  memset(&netif, 0, sizeof(netif));
  IP_ADDR4(&local_ip, 192, 168, 1, 1);
  IP_ADDR4(&remote_ip, 192, 168, 1, 2);
  IP_ADDR4(&netmask,   255, 255, 255, 0);
  test_tcp_init_netif(&netif, NULL, &local_ip, &netmask);
  /* initialize counter struct */
  memset(&counters, 0, sizeof(counters));
  counters.expected_data_len = TCP_WND;
  counters.expected_data = data_full_wnd;

  /* create and initialize the pcb */
  pcb = test_tcp_new_counters_pcb(&counters);
  EXPECT_RET(pcb != NULL);
  tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
  pcb->rcv_nxt = 0x8000;

  /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */

  /* create segments and 'recv' them */
  for(i = 1; i <= TCP_OOSEQ_MAX_PBUFS; i++) {
    int count;
    struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[i],
                                           1, i, 0, TCP_ACK);
    EXPECT_RET(p != NULL);
    EXPECT_RET(p->next == NULL);
    /* pass the segment to tcp_input */
    test_tcp_input(p, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 0);
    EXPECT(counters.recv_calls == 0);
    EXPECT(counters.recved_bytes == 0);
    EXPECT(counters.err_calls == 0);
    /* check ooseq queue */
    count = tcp_oos_pbuf_count(pcb);
    EXPECT_OOSEQ(count == i);
    datalen = tcp_oos_tcplen(pcb);
    EXPECT_OOSEQ(datalen == i);
  }

  /* pass in one more segment, overrunning the limit */
  p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[i+1], 1, i+1, 0, TCP_ACK);
  EXPECT_RET(p_ovr != NULL);
  /* pass the segment to tcp_input */
  test_tcp_input(p_ovr, &netif);
  /* check if counters are as expected */
  EXPECT(counters.close_calls == 0);
  EXPECT(counters.recv_calls == 0);
  EXPECT(counters.recved_bytes == 0);
  EXPECT(counters.err_calls == 0);
  /* check ooseq queue (ensure the new segment was not accepted) */
  EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1));
  datalen2 = tcp_oos_tcplen(pcb);
  EXPECT_OOSEQ(datalen2 == (i-1));

  /* make sure the pcb is freed */
  EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1);
  tcp_abort(pcb);
  EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
#endif /* TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */
  LWIP_UNUSED_ARG(_i);
}
コード例 #13
0
END_TEST

/** similar to above test, except seqno starts near the max rxwin */
START_TEST(test_tcp_recv_ooseq_overrun_rxwin_edge)
{
#if !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS
  int i, k;
  struct test_tcp_counters counters;
  struct tcp_pcb* pcb;
  struct pbuf *pinseq, *p_ovr;
  ip_addr_t remote_ip, local_ip, netmask;
  u16_t remote_port = 0x100, local_port = 0x101;
  struct netif netif;
  int datalen = 0;
  int datalen2;

  for(i = 0; i < (int)sizeof(data_full_wnd); i++) {
    data_full_wnd[i] = (char)i;
  }

  /* initialize local vars */
  memset(&netif, 0, sizeof(netif));
  IP_ADDR4(&local_ip, 192, 168, 1, 1);
  IP_ADDR4(&remote_ip, 192, 168, 1, 2);
  IP_ADDR4(&netmask,   255, 255, 255, 0);
  test_tcp_init_netif(&netif, NULL, &local_ip, &netmask);
  /* initialize counter struct */
  memset(&counters, 0, sizeof(counters));
  counters.expected_data_len = TCP_WND;
  counters.expected_data = data_full_wnd;

  /* create and initialize the pcb */
  pcb = test_tcp_new_counters_pcb(&counters);
  EXPECT_RET(pcb != NULL);
  tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
  pcb->rcv_nxt = 0xffffffff - (TCP_WND / 2);

  /* create segments */
  /* pinseq is sent as last segment! */
  pinseq = tcp_create_rx_segment(pcb, &data_full_wnd[0],  TCP_MSS, 0, 0, TCP_ACK);

  for(i = TCP_MSS, k = 0; i < TCP_WND; i += TCP_MSS, k++) {
    int count, expected_datalen;
    struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)],
                                           TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK);
    EXPECT_RET(p != NULL);
    /* pass the segment to tcp_input */
    test_tcp_input(p, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 0);
    EXPECT(counters.recv_calls == 0);
    EXPECT(counters.recved_bytes == 0);
    EXPECT(counters.err_calls == 0);
    /* check ooseq queue */
    count = tcp_oos_count(pcb);
    EXPECT_OOSEQ(count == k+1);
    datalen = tcp_oos_tcplen(pcb);
    if (i + TCP_MSS < TCP_WND) {
      expected_datalen = (k+1)*TCP_MSS;
    } else {
      expected_datalen = TCP_WND - TCP_MSS;
    }
    if (datalen != expected_datalen) {
      EXPECT_OOSEQ(datalen == expected_datalen);
    }
  }

  /* pass in one more segment, cleary overrunning the rxwin */
  p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK);
  EXPECT_RET(p_ovr != NULL);
  /* pass the segment to tcp_input */
  test_tcp_input(p_ovr, &netif);
  /* check if counters are as expected */
  EXPECT(counters.close_calls == 0);
  EXPECT(counters.recv_calls == 0);
  EXPECT(counters.recved_bytes == 0);
  EXPECT(counters.err_calls == 0);
  /* check ooseq queue */
  EXPECT_OOSEQ(tcp_oos_count(pcb) == k);
  datalen2 = tcp_oos_tcplen(pcb);
  EXPECT_OOSEQ(datalen == datalen2);

  /* now pass inseq */
  test_tcp_input(pinseq, &netif);
  EXPECT(pcb->ooseq == NULL);

  /* make sure the pcb is freed */
  EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1);
  tcp_abort(pcb);
  EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
#endif /* !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS */
  LWIP_UNUSED_ARG(_i);
}
コード例 #14
0
ファイル: test_tcp.c プロジェクト: tansinan/lwIP
END_TEST

/** Check that we handle malformed tcp headers, and discard the pbuf(s) */
START_TEST(test_tcp_malformed_header)
{
  struct test_tcp_counters counters;
  struct tcp_pcb* pcb;
  struct pbuf* p;
  char data[] = {1, 2, 3, 4};
  u16_t data_len, chksum;
  struct netif netif;
  struct test_tcp_txcounters txcounters;
  struct tcp_hdr *hdr;
  LWIP_UNUSED_ARG(_i);

  /* initialize local vars */
  test_tcp_init_netif(&netif, &txcounters, &test_local_ip, &test_netmask);
  data_len = sizeof(data);
  /* initialize counter struct */
  memset(&counters, 0, sizeof(counters));
  counters.expected_data_len = data_len;
  counters.expected_data = data;

  /* create and initialize the pcb */
  pcb = test_tcp_new_counters_pcb(&counters);
  EXPECT_RET(pcb != NULL);
  tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT);

  /* create a segment */
  p = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0);

  pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));

  hdr = (struct tcp_hdr *)p->payload;
  TCPH_HDRLEN_FLAGS_SET(hdr, 15, 0x3d1);

  hdr->chksum = 0;

  chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len,
                             &test_remote_ip, &test_local_ip);

  hdr->chksum = chksum;

  pbuf_header(p, sizeof(struct ip_hdr));

  EXPECT(p != NULL);
  EXPECT(p->next == NULL);
  if (p != NULL) {
    /* pass the segment to tcp_input */
    test_tcp_input(p, &netif);
    /* check if counters are as expected */
    EXPECT(counters.close_calls == 0);
    EXPECT(counters.recv_calls == 0);
    EXPECT(counters.recved_bytes == 0);
    EXPECT(counters.err_calls == 0);
  }

  /* make sure the pcb is freed */
  EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1);
  tcp_abort(pcb);
  EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
}
コード例 #15
0
/**
 * Change the IP address of a network interface
 *
 * @param netif the network interface to change
 * @param ipaddr the new IP address
 *
 * @note call netif_set_addr() if you also want to change netmask and
 * default gateway
 */
void
netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
{
  /* TODO: Handling of obsolete pcbs */
  /* See:  http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
#if LWIP_TCP
  struct tcp_pcb *pcb;
  struct tcp_pcb_listen *lpcb;

  /* address is actually being changed? */
  if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
    /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
    LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));

	sys_lock_acquire( &tcp_lock );
    pcb = tcp_active_pcbs;
	tcp_active_pcbs = NULL;
	sys_lock_release( &tcp_lock );

    while (pcb != NULL) {
      /* PCB bound to current local interface address? */
      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
#if LWIP_AUTOIP
        /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
        && !ip_addr_islinklocal(&(pcb->local_ip))
#endif /* LWIP_AUTOIP */
        ) {
        /* this connection must be aborted */
        struct tcp_pcb *next = pcb->next;
        LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
        tcp_abort(pcb);
        pcb = next;
      } else {
        pcb = pcb->next;
      }
    }
    for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
      /* PCB bound to current local interface address? */
      if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
          (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
        /* The PCB is listening to the old ipaddr and
         * is set to listen to the new one instead */
        ip_addr_set(&(lpcb->local_ip), ipaddr);
      }
    }
  }
#endif
  snmp_delete_ipaddridx_tree(netif);
  snmp_delete_iprteidx_tree(0,netif);
  /* set new IP address to netif */
  ip_addr_set(&(netif->ip_addr), ipaddr);
  snmp_insert_ipaddridx_tree(netif);
  snmp_insert_iprteidx_tree(0,netif);

  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
    netif->name[0], netif->name[1],
    ip4_addr1_16(&netif->ip_addr),
    ip4_addr2_16(&netif->ip_addr),
    ip4_addr3_16(&netif->ip_addr),
    ip4_addr4_16(&netif->ip_addr)));
}
コード例 #16
0
ファイル: test_tcp.c プロジェクト: tansinan/lwIP
END_TEST


/** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data.
 * At the end, send more data. */
START_TEST(test_tcp_fast_retx_recover)
{
  struct netif netif;
  struct test_tcp_txcounters txcounters;
  struct test_tcp_counters counters;
  struct tcp_pcb* pcb;
  struct pbuf* p;
  char data1[] = { 1,  2,  3,  4};
  char data2[] = { 5,  6,  7,  8};
  char data3[] = { 9, 10, 11, 12};
  char data4[] = {13, 14, 15, 16};
  char data5[] = {17, 18, 19, 20};
  char data6[TCP_MSS] = {21, 22, 23, 24};
  err_t err;
  LWIP_UNUSED_ARG(_i);

  /* initialize local vars */
  test_tcp_init_netif(&netif, &txcounters, &test_local_ip, &test_netmask);
  memset(&counters, 0, sizeof(counters));

  /* create and initialize the pcb */
  pcb = test_tcp_new_counters_pcb(&counters);
  EXPECT_RET(pcb != NULL);
  tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT);
  pcb->mss = TCP_MSS;
  /* disable initial congestion window (we don't send a SYN here...) */
  pcb->cwnd = pcb->snd_wnd;

  /* send data1 */
  err = tcp_write(pcb, data1, sizeof(data1), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);
  EXPECT_RET(txcounters.num_tx_calls == 1);
  EXPECT_RET(txcounters.num_tx_bytes == sizeof(data1) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr));
  memset(&txcounters, 0, sizeof(txcounters));
 /* "recv" ACK for data1 */
  p = tcp_create_rx_segment(pcb, NULL, 0, 0, 4, TCP_ACK);
  EXPECT_RET(p != NULL);
  test_tcp_input(p, &netif);
  EXPECT_RET(txcounters.num_tx_calls == 0);
  EXPECT_RET(pcb->unacked == NULL);
  /* send data2 */
  err = tcp_write(pcb, data2, sizeof(data2), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);
  EXPECT_RET(txcounters.num_tx_calls == 1);
  EXPECT_RET(txcounters.num_tx_bytes == sizeof(data2) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr));
  memset(&txcounters, 0, sizeof(txcounters));
  /* duplicate ACK for data1 (data2 is lost) */
  p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
  EXPECT_RET(p != NULL);
  test_tcp_input(p, &netif);
  EXPECT_RET(txcounters.num_tx_calls == 0);
  EXPECT_RET(pcb->dupacks == 1);
  /* send data3 */
  err = tcp_write(pcb, data3, sizeof(data3), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);
  /* nagle enabled, no tx calls */
  EXPECT_RET(txcounters.num_tx_calls == 0);
  EXPECT_RET(txcounters.num_tx_bytes == 0);
  memset(&txcounters, 0, sizeof(txcounters));
  /* 2nd duplicate ACK for data1 (data2 and data3 are lost) */
  p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
  EXPECT_RET(p != NULL);
  test_tcp_input(p, &netif);
  EXPECT_RET(txcounters.num_tx_calls == 0);
  EXPECT_RET(pcb->dupacks == 2);
  /* queue data4, don't send it (unsent-oversize is != 0) */
  err = tcp_write(pcb, data4, sizeof(data4), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  /* 3nd duplicate ACK for data1 (data2 and data3 are lost) -> fast retransmission */
  p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
  EXPECT_RET(p != NULL);
  test_tcp_input(p, &netif);
  /*EXPECT_RET(txcounters.num_tx_calls == 1);*/
  EXPECT_RET(pcb->dupacks == 3);
  memset(&txcounters, 0, sizeof(txcounters));
  /* @todo: check expected data?*/
  
  /* send data5, not output yet */
  err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  /*err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);*/
  EXPECT_RET(txcounters.num_tx_calls == 0);
  EXPECT_RET(txcounters.num_tx_bytes == 0);
  memset(&txcounters, 0, sizeof(txcounters));
  {
    int i = 0;
    do
    {
      err = tcp_write(pcb, data6, TCP_MSS, TCP_WRITE_FLAG_COPY);
      i++;
    }while(err == ERR_OK);
    EXPECT_RET(err != ERR_OK);
  }
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);
  /*EXPECT_RET(txcounters.num_tx_calls == 0);
  EXPECT_RET(txcounters.num_tx_bytes == 0);*/
  memset(&txcounters, 0, sizeof(txcounters));

  /* send even more data */
  err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);
  /* ...and even more data */
  err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);
  /* ...and even more data */
  err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);
  /* ...and even more data */
  err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);

  /* send ACKs for data2 and data3 */
  p = tcp_create_rx_segment(pcb, NULL, 0, 0, 12, TCP_ACK);
  EXPECT_RET(p != NULL);
  test_tcp_input(p, &netif);
  /*EXPECT_RET(txcounters.num_tx_calls == 0);*/

  /* ...and even more data */
  err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);
  /* ...and even more data */
  err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);

#if 0
  /* create expected segment */
  p1 = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0);
  EXPECT_RET(p != NULL);
  if (p != NULL) {
    /* pass the segment to tcp_input */
    test_tcp_input(p, &netif);
    /* check if counters are as expected */
    EXPECT_RET(counters.close_calls == 0);
    EXPECT_RET(counters.recv_calls == 1);
    EXPECT_RET(counters.recved_bytes == data_len);
    EXPECT_RET(counters.err_calls == 0);
  }
#endif
  /* make sure the pcb is freed */
  EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1);
  tcp_abort(pcb);
  EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
}
コード例 #17
0
ファイル: test_tcp.c プロジェクト: reachingDef/lwip
END_TEST

/** Send data with sequence numbers that wrap around the u32_t range.
 * Then, provoke RTO retransmission and check that all
 * segment lists are still properly sorted. */
START_TEST(test_tcp_rto_rexmit_wraparound)
{
  struct netif netif;
  struct test_tcp_txcounters txcounters;
  struct test_tcp_counters counters;
  struct tcp_pcb* pcb;
  ip_addr_t remote_ip, local_ip, netmask;
  u16_t remote_port = 0x100, local_port = 0x101;
  err_t err;
#define SEQNO1 (0xFFFFFF00 - TCP_MSS)
#define ISS    6510
  u16_t i, sent_total = 0;
  u32_t seqnos[] = {
    SEQNO1,
    SEQNO1 + (1 * TCP_MSS),
    SEQNO1 + (2 * TCP_MSS),
    SEQNO1 + (3 * TCP_MSS),
    SEQNO1 + (4 * TCP_MSS),
    SEQNO1 + (5 * TCP_MSS)};
  LWIP_UNUSED_ARG(_i);

  for (i = 0; i < sizeof(tx_data); i++) {
    tx_data[i] = (u8_t)i;
  }

  /* initialize local vars */
  IP_ADDR4(&local_ip,  192, 168,   1, 1);
  IP_ADDR4(&remote_ip, 192, 168,   1, 2);
  IP_ADDR4(&netmask,   255, 255, 255, 0);
  test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
  memset(&counters, 0, sizeof(counters));

  /* create and initialize the pcb */
  tcp_ticks = 0;
  tcp_ticks = 0 - tcp_next_iss();
  tcp_ticks = SEQNO1 - tcp_next_iss();
  pcb = test_tcp_new_counters_pcb(&counters);
  EXPECT_RET(pcb != NULL);
  EXPECT(pcb->lastack == SEQNO1);
  tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
  pcb->mss = TCP_MSS;
  /* disable initial congestion window (we don't send a SYN here...) */
  pcb->cwnd = 2*TCP_MSS;

  /* send 6 mss-sized segments */
  for (i = 0; i < 6; i++) {
    err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
    EXPECT_RET(err == ERR_OK);
    sent_total += TCP_MSS;
  }
  check_seqnos(pcb->unsent, 6, seqnos);
  EXPECT(pcb->unacked == NULL);
  err = tcp_output(pcb);
  EXPECT(txcounters.num_tx_calls == 2);
  EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U));
  memset(&txcounters, 0, sizeof(txcounters));

  check_seqnos(pcb->unacked, 2, seqnos);
  check_seqnos(pcb->unsent, 4, &seqnos[2]);

  /* call the tcp timer some times */
  for (i = 0; i < 10; i++) {
    test_tcp_tmr();
    EXPECT(txcounters.num_tx_calls == 0);
  }
  /* 11th call to tcp_tmr: RTO rexmit fires */
  test_tcp_tmr();
  EXPECT(txcounters.num_tx_calls == 1);
  check_seqnos(pcb->unacked, 1, seqnos);
  check_seqnos(pcb->unsent, 5, &seqnos[1]);

  /* fake greater cwnd */
  pcb->cwnd = pcb->snd_wnd;
  /* send more data */
  err = tcp_output(pcb);
  EXPECT(err == ERR_OK);
  /* check queues are sorted */
  EXPECT(pcb->unsent == NULL);
  check_seqnos(pcb->unacked, 6, seqnos);

  /* make sure the pcb is freed */
  EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
  tcp_abort(pcb);
  EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
}
コード例 #18
0
ファイル: test_tcp.c プロジェクト: tansinan/lwIP
END_TEST

/** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data.
 * At the end, send more data. */
static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent)
{
  struct netif netif;
  struct test_tcp_txcounters txcounters;
  struct test_tcp_counters counters;
  struct tcp_pcb* pcb;
  struct pbuf *p;
  err_t err;
  size_t i;
  u16_t sent_total;
  u8_t expected = 0xFE;

  for (i = 0; i < sizeof(tx_data); i++) {
    u8_t d = (u8_t)i;
    if (d == 0xFE) {
      d = 0xF0;
    }
    tx_data[i] = d;
  }
  if (zero_window_probe_from_unsent) {
    tx_data[TCP_WND] = expected;
  } else {
    tx_data[0] = expected;
  }

  /* initialize local vars */
  test_tcp_init_netif(&netif, &txcounters, &test_local_ip, &test_netmask);
  memset(&counters, 0, sizeof(counters));

  /* create and initialize the pcb */
  pcb = test_tcp_new_counters_pcb(&counters);
  EXPECT_RET(pcb != NULL);
  tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT);
  pcb->mss = TCP_MSS;
  /* disable initial congestion window (we don't send a SYN here...) */
  pcb->cwnd = pcb->snd_wnd;

  /* send a full window (minus 1 packets) of TCP data in MSS-sized chunks */
  sent_total = 0;
  if ((TCP_WND - TCP_MSS) % TCP_MSS != 0) {
    u16_t initial_data_len = (TCP_WND - TCP_MSS) % TCP_MSS;
    err = tcp_write(pcb, &tx_data[sent_total], initial_data_len, TCP_WRITE_FLAG_COPY);
    EXPECT_RET(err == ERR_OK);
    err = tcp_output(pcb);
    EXPECT_RET(err == ERR_OK);
    EXPECT(txcounters.num_tx_calls == 1);
    EXPECT(txcounters.num_tx_bytes == initial_data_len + 40U);
    memset(&txcounters, 0, sizeof(txcounters));
    sent_total += initial_data_len;
  }
  for (; sent_total < (TCP_WND - TCP_MSS); sent_total += TCP_MSS) {
    err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
    EXPECT_RET(err == ERR_OK);
    err = tcp_output(pcb);
    EXPECT_RET(err == ERR_OK);
    EXPECT(txcounters.num_tx_calls == 1);
    EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U);
    memset(&txcounters, 0, sizeof(txcounters));
  }
  EXPECT(sent_total == (TCP_WND - TCP_MSS));

  /* now ACK the packet before the first */
  p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
  test_tcp_input(p, &netif);
  /* ensure this didn't trigger a retransmission */
  EXPECT(txcounters.num_tx_calls == 0);
  EXPECT(txcounters.num_tx_bytes == 0);

  EXPECT(pcb->persist_backoff == 0);
  /* send the last packet, now a complete window has been sent */
  err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
  sent_total += TCP_MSS;
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);
  EXPECT(txcounters.num_tx_calls == 1);
  EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U);
  memset(&txcounters, 0, sizeof(txcounters));
  EXPECT(pcb->persist_backoff == 0);

  if (zero_window_probe_from_unsent) {
    /* ACK all data but close the TX window */
    p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, TCP_WND, TCP_ACK, 0);
    test_tcp_input(p, &netif);
    /* ensure this didn't trigger any transmission */
    EXPECT(txcounters.num_tx_calls == 0);
    EXPECT(txcounters.num_tx_bytes == 0);
    /* window is completely full, but persist timer is off since send buffer is empty */
    EXPECT(pcb->snd_wnd == 0);
    EXPECT(pcb->persist_backoff == 0);
  }

  /* send one byte more (out of window) -> persist timer starts */
  err = tcp_write(pcb, &tx_data[sent_total], 1, TCP_WRITE_FLAG_COPY);
  EXPECT_RET(err == ERR_OK);
  err = tcp_output(pcb);
  EXPECT_RET(err == ERR_OK);
  EXPECT(txcounters.num_tx_calls == 0);
  EXPECT(txcounters.num_tx_bytes == 0);
  memset(&txcounters, 0, sizeof(txcounters));
  if (!zero_window_probe_from_unsent) {
    /* no persist timer unless a zero window announcement has been received */
    EXPECT(pcb->persist_backoff == 0);
  } else {
    EXPECT(pcb->persist_backoff == 1);

    /* call tcp_timer some more times to let persist timer count up */
    for (i = 0; i < 4; i++) {
      test_tcp_tmr();
      EXPECT(txcounters.num_tx_calls == 0);
      EXPECT(txcounters.num_tx_bytes == 0);
    }

    /* this should trigger the zero-window-probe */
    txcounters.copy_tx_packets = 1;
    test_tcp_tmr();
    txcounters.copy_tx_packets = 0;
    EXPECT(txcounters.num_tx_calls == 1);
    EXPECT(txcounters.num_tx_bytes == 1 + 40U);
    EXPECT(txcounters.tx_packets != NULL);
    if (txcounters.tx_packets != NULL) {
      u8_t sent;
      u16_t ret;
      ret = pbuf_copy_partial(txcounters.tx_packets, &sent, 1, 40U);
      EXPECT(ret == 1);
      EXPECT(sent == expected);
    }
    if (txcounters.tx_packets != NULL) {
      pbuf_free(txcounters.tx_packets);
      txcounters.tx_packets = NULL;
    }
  }

  /* make sure the pcb is freed */
  EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1);
  tcp_abort(pcb);
  EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
}
コード例 #19
0
ファイル: tcp.c プロジェクト: jkiiski/minix
static void tcp_backlog_free(void * data)
{
	tcp_abort((struct tcp_pcb *) data);
}