Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contrib/Filelists.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ set(lwipcontribapps_SRCS
${LWIP_CONTRIB_DIR}/apps/shell/shell.c
${LWIP_CONTRIB_DIR}/apps/udpecho_raw/udpecho_raw.c
${LWIP_CONTRIB_DIR}/apps/tcpecho_raw/tcpecho_raw.c
${LWIP_CONTRIB_DIR}/apps/tcpecho_altcp/tcpecho_altcp.c
${LWIP_CONTRIB_DIR}/apps/netio/netio.c
${LWIP_CONTRIB_DIR}/apps/ping/ping.c
${LWIP_CONTRIB_DIR}/apps/socket_examples/socket_examples.c
Expand Down
1 change: 1 addition & 0 deletions contrib/Filelists.mk
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ CONTRIBAPPFILES=$(CONTRIBDIR)/apps/httpserver/httpserver-netconn.c \
$(CONTRIBDIR)/apps/shell/shell.c \
$(CONTRIBDIR)/apps/udpecho_raw/udpecho_raw.c \
$(CONTRIBDIR)/apps/tcpecho_raw/tcpecho_raw.c \
$(CONTRIBDIR)/apps/tcpecho_altcp/tcpecho_altcp.c \
$(CONTRIBDIR)/apps/netio/netio.c \
$(CONTRIBDIR)/apps/ping/ping.c \
$(CONTRIBDIR)/apps/socket_examples/socket_examples.c \
Expand Down
301 changes: 301 additions & 0 deletions contrib/apps/tcpecho_altcp/tcpecho_altcp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of and a contribution to the lwIP TCP/IP stack.
*
* Credits go to Adam Dunkels (and the current maintainers) of this software.
*
* Christiaan Simons rewrote this file to get a more stable echo example.
*/

/**
* @file
* TCP echo server example using altcp API.
*
* Echos all bytes sent by connecting client,
* and passively closes when client is done.
*
*/

#include "lwip/opt.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/altcp.h"
#include "tcpecho_altcp.h"

#if LWIP_ALTCP && LWIP_CALLBACK_API

static struct altcp_pcb *tcpecho_altcp_pcb;

enum tcpecho_altcp_states
{
ES_NONE = 0,
ES_ACCEPTED,
ES_RECEIVED,
ES_CLOSING
};

struct tcpecho_altcp_state
{
u8_t state;
u8_t retries;
struct altcp_pcb *pcb;
/* pbuf (chain) to recycle */
struct pbuf *p;
};

static void
tcpecho_altcp_free(struct tcpecho_altcp_state *es)
{
if (es != NULL) {
if (es->p) {
/* free the buffer chain if present */
pbuf_free(es->p);
}

mem_free(es);
}
}

static void
tcpecho_altcp_close(struct altcp_pcb *tpcb, struct tcpecho_altcp_state *es)
{
altcp_arg(tpcb, NULL);
altcp_sent(tpcb, NULL);
altcp_recv(tpcb, NULL);
altcp_err(tpcb, NULL);
altcp_poll(tpcb, NULL, 0);

tcpecho_altcp_free(es);

altcp_close(tpcb);
}

static void
tcpecho_altcp_send(struct altcp_pcb *tpcb, struct tcpecho_altcp_state *es)
{
struct pbuf *ptr;
err_t wr_err = ERR_OK;

while ((wr_err == ERR_OK) &&
(es->p != NULL) &&
(es->p->len <= altcp_sndbuf(tpcb))) {
ptr = es->p;

/* enqueue data for transmission */
wr_err = altcp_write(tpcb, ptr->payload, ptr->len, 1);
if (wr_err == ERR_OK) {
u16_t plen;

plen = ptr->len;
/* continue with next pbuf in chain (if any) */
es->p = ptr->next;
if(es->p != NULL) {
/* new reference! */
pbuf_ref(es->p);
}
/* chop first pbuf from chain */
pbuf_free(ptr);
/* we can read more data now */
altcp_recved(tpcb, plen);
} else if(wr_err == ERR_MEM) {
/* we are low on memory, try later / harder, defer to poll */
es->p = ptr;
} else {
/* other problem ?? */
}
}
}

static void
tcpecho_altcp_error(void *arg, err_t err)
{
struct tcpecho_altcp_state *es;

LWIP_UNUSED_ARG(err);

es = (struct tcpecho_altcp_state *)arg;

tcpecho_altcp_free(es);
}

static err_t
tcpecho_altcp_poll(void *arg, struct altcp_pcb *tpcb)
{
err_t ret_err;
struct tcpecho_altcp_state *es;

es = (struct tcpecho_altcp_state *)arg;
if (es != NULL) {
if (es->p != NULL) {
/* there is a remaining pbuf (chain) */
tcpecho_altcp_send(tpcb, es);
} else {
/* no remaining pbuf (chain) */
if(es->state == ES_CLOSING) {
tcpecho_altcp_close(tpcb, es);
}
}
ret_err = ERR_OK;
} else {
/* nothing to be done */
altcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
}

static err_t
tcpecho_altcp_sent(void *arg, struct altcp_pcb *tpcb, u16_t len)
{
struct tcpecho_altcp_state *es;

LWIP_UNUSED_ARG(len);

es = (struct tcpecho_altcp_state *)arg;
es->retries = 0;

if(es->p != NULL) {
/* still got pbufs to send */
altcp_sent(tpcb, tcpecho_altcp_sent);
tcpecho_altcp_send(tpcb, es);
} else {
/* no more pbufs to send */
if(es->state == ES_CLOSING) {
tcpecho_altcp_close(tpcb, es);
}
}
return ERR_OK;
}

static err_t
tcpecho_altcp_recv(void *arg, struct altcp_pcb *tpcb, struct pbuf *p, err_t err)
{
struct tcpecho_altcp_state *es;
err_t ret_err;

LWIP_ASSERT("arg != NULL",arg != NULL);
es = (struct tcpecho_altcp_state *)arg;
if (p == NULL) {
/* remote host closed connection */
es->state = ES_CLOSING;
if(es->p == NULL) {
/* we're done sending, close it */
tcpecho_altcp_close(tpcb, es);
} else {
/* we're not done yet */
tcpecho_altcp_send(tpcb, es);
}
ret_err = ERR_OK;
} else if(err != ERR_OK) {
/* cleanup, for unknown reason */
LWIP_ASSERT("no pbuf expected here", p == NULL);
ret_err = err;
}
else if(es->state == ES_ACCEPTED) {
/* first data chunk in p->payload */
es->state = ES_RECEIVED;
/* store reference to incoming pbuf (chain) */
es->p = p;
tcpecho_altcp_send(tpcb, es);
ret_err = ERR_OK;
} else if (es->state == ES_RECEIVED) {
/* read some more data */
if(es->p == NULL) {
es->p = p;
tcpecho_altcp_send(tpcb, es);
} else {
struct pbuf *ptr;

/* chain pbufs to the end of what we recv'ed previously */
ptr = es->p;
pbuf_cat(ptr,p);
}
ret_err = ERR_OK;
} else {
/* unknown es->state, trash data */
altcp_recved(tpcb, p->tot_len);
pbuf_free(p);
ret_err = ERR_OK;
}
return ret_err;
}

static err_t
tcpecho_altcp_accept(void *arg, struct altcp_pcb *newpcb, err_t err)
{
err_t ret_err;
struct tcpecho_altcp_state *es;

LWIP_UNUSED_ARG(arg);
if ((err != ERR_OK) || (newpcb == NULL)) {
return ERR_VAL;
}

/* Unless this pcb should have NORMAL priority, set its priority now.
When running out of pcbs, low priority pcbs can be aborted to create
new pcbs of higher priority. */
altcp_setprio(newpcb, TCP_PRIO_MIN);

es = (struct tcpecho_altcp_state *)mem_malloc(sizeof(struct tcpecho_altcp_state));
if (es != NULL) {
es->state = ES_ACCEPTED;
es->pcb = newpcb;
es->retries = 0;
es->p = NULL;
/* pass newly allocated es to our callbacks */
altcp_arg(newpcb, es);
altcp_recv(newpcb, tcpecho_altcp_recv);
altcp_err(newpcb, tcpecho_altcp_error);
altcp_poll(newpcb, tcpecho_altcp_poll, 0);
altcp_sent(newpcb, tcpecho_altcp_sent);
ret_err = ERR_OK;
} else {
ret_err = ERR_MEM;
}
return ret_err;
}

void
tcpecho_altcp_init(void)
{
tcpecho_altcp_pcb = altcp_new_ip_type(NULL, IPADDR_TYPE_ANY);
if (tcpecho_altcp_pcb != NULL) {
err_t err;

err = altcp_bind(tcpecho_altcp_pcb, IP_ANY_TYPE, 7);
if (err == ERR_OK) {
tcpecho_altcp_pcb = altcp_listen(tcpecho_altcp_pcb);
altcp_accept(tcpecho_altcp_pcb, tcpecho_altcp_accept);
} else {
/* abort? output diagnostic? */
}
} else {
/* abort? output diagnostic? */
}
}

#endif /* LWIP_TCP && LWIP_CALLBACK_API */
35 changes: 35 additions & 0 deletions contrib/apps/tcpecho_altcp/tcpecho_altcp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#ifndef LWIP_TCPECHO_ALTCP_H
#define LWIP_TCPECHO_ALTCP_H

void tcpecho_altcp_init(void);

#endif /* LWIP_TCPECHO_RAW_H */
3 changes: 3 additions & 0 deletions contrib/examples/example_app/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#include "apps/tcpecho/tcpecho.h"
#include "apps/udpecho/udpecho.h"
#include "apps/tcpecho_raw/tcpecho_raw.h"
#include "apps/tcpecho_altcp/tcpecho_altcp.h"
#include "apps/socket_examples/socket_examples.h"

#include "examples/lwiperf/lwiperf_example.h"
Expand Down Expand Up @@ -558,6 +559,8 @@ apps_init(void)
#if LWIP_TCPECHO_APP
#if LWIP_NETCONN && defined(LWIP_TCPECHO_APP_NETCONN)
tcpecho_init();
#elif LWIP_ALTCP
tcpecho_altcp_init();
#else /* LWIP_NETCONN && defined(LWIP_TCPECHO_APP_NETCONN) */
tcpecho_raw_init();
#endif
Expand Down
2 changes: 2 additions & 0 deletions contrib/ports/win32/msvc/lwIP_Test.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@
<ClCompile Include="..\..\..\addons\ipv6_static_routing\ip6_route_table.c" />
<ClCompile Include="..\..\..\addons\tcp_isn\tcp_isn.c" />
<ClCompile Include="..\..\..\apps\tcpecho_raw\tcpecho_raw.c" />
<ClCompile Include="..\..\..\apps\tcpecho_altcp\tcpecho_altcp.c" />
<ClCompile Include="..\..\..\apps\udpecho_raw\udpecho_raw.c" />
<ClCompile Include="..\..\..\examples\example_app\test.c" />
<ClCompile Include="..\..\..\examples\httpd\cgi_example\cgi_example.c" />
Expand Down Expand Up @@ -285,6 +286,7 @@
<ClInclude Include="..\..\..\apps\socket_examples\socket_examples.h" />
<ClInclude Include="..\..\..\apps\tcpecho\tcpecho.h" />
<ClInclude Include="..\..\..\apps\tcpecho_raw\tcpecho_raw.h" />
<ClInclude Include="..\..\..\apps\tcpecho_altcp\tcpecho_altcp.h" />
<ClInclude Include="..\..\..\apps\udpecho\udpecho.h" />
<ClInclude Include="..\..\..\apps\udpecho_raw\udpecho_raw.h" />
<ClInclude Include="..\..\..\examples\httpd\cgi_example\cgi_example.h" />
Expand Down