|
|
|
|
@ -40,7 +40,6 @@
|
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lwip/opt.h" |
|
|
|
|
#include "lwip/debug.h" |
|
|
|
|
#include "lwip/stats.h" |
|
|
|
|
@ -68,150 +67,70 @@ struct tcpecho_raw_state
|
|
|
|
|
struct pbuf *p; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
err_t tcpecho_raw_accept(void *arg, struct tcp_pcb *newpcb, err_t err); |
|
|
|
|
err_t tcpecho_raw_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); |
|
|
|
|
void tcpecho_raw_error(void *arg, err_t err); |
|
|
|
|
err_t tcpecho_raw_poll(void *arg, struct tcp_pcb *tpcb); |
|
|
|
|
err_t tcpecho_raw_sent(void *arg, struct tcp_pcb *tpcb, u16_t len); |
|
|
|
|
void tcpecho_raw_send(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es); |
|
|
|
|
void tcpecho_raw_close(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es); |
|
|
|
|
void tcpecho_raw_free(struct tcpecho_raw_state *es); |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
tcpecho_raw_init(void) |
|
|
|
|
static void |
|
|
|
|
tcpecho_raw_free(struct tcpecho_raw_state *es) |
|
|
|
|
{ |
|
|
|
|
tcpecho_raw_pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); |
|
|
|
|
if (tcpecho_raw_pcb != NULL) |
|
|
|
|
{ |
|
|
|
|
err_t err; |
|
|
|
|
|
|
|
|
|
err = tcp_bind(tcpecho_raw_pcb, IP_ANY_TYPE, 7); |
|
|
|
|
if (err == ERR_OK) |
|
|
|
|
{ |
|
|
|
|
tcpecho_raw_pcb = tcp_listen(tcpecho_raw_pcb); |
|
|
|
|
tcp_accept(tcpecho_raw_pcb, tcpecho_raw_accept); |
|
|
|
|
} |
|
|
|
|
else
|
|
|
|
|
{ |
|
|
|
|
/* abort? output diagnostic? */ |
|
|
|
|
if (es != NULL) { |
|
|
|
|
if (es->p) { |
|
|
|
|
/* free the buffer chain if present */ |
|
|
|
|
pbuf_free(es->p); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* abort? output diagnostic? */ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
mem_free(es); |
|
|
|
|
}
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
err_t |
|
|
|
|
tcpecho_raw_accept(void *arg, struct tcp_pcb *newpcb, err_t err) |
|
|
|
|
static void |
|
|
|
|
tcpecho_raw_close(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es) |
|
|
|
|
{ |
|
|
|
|
err_t ret_err; |
|
|
|
|
struct tcpecho_raw_state *es; |
|
|
|
|
|
|
|
|
|
LWIP_UNUSED_ARG(arg); |
|
|
|
|
if ((err != ERR_OK) || (newpcb == NULL)) { |
|
|
|
|
return ERR_VAL; |
|
|
|
|
} |
|
|
|
|
tcp_arg(tpcb, NULL); |
|
|
|
|
tcp_sent(tpcb, NULL); |
|
|
|
|
tcp_recv(tpcb, NULL); |
|
|
|
|
tcp_err(tpcb, NULL); |
|
|
|
|
tcp_poll(tpcb, NULL, 0); |
|
|
|
|
|
|
|
|
|
/* 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. */ |
|
|
|
|
tcp_setprio(newpcb, TCP_PRIO_MIN); |
|
|
|
|
tcpecho_raw_free(es); |
|
|
|
|
|
|
|
|
|
es = (struct tcpecho_raw_state *)mem_malloc(sizeof(struct tcpecho_raw_state)); |
|
|
|
|
if (es != NULL) |
|
|
|
|
{ |
|
|
|
|
es->state = ES_ACCEPTED; |
|
|
|
|
es->pcb = newpcb; |
|
|
|
|
es->retries = 0; |
|
|
|
|
es->p = NULL; |
|
|
|
|
/* pass newly allocated es to our callbacks */ |
|
|
|
|
tcp_arg(newpcb, es); |
|
|
|
|
tcp_recv(newpcb, tcpecho_raw_recv); |
|
|
|
|
tcp_err(newpcb, tcpecho_raw_error); |
|
|
|
|
tcp_poll(newpcb, tcpecho_raw_poll, 0); |
|
|
|
|
tcp_sent(newpcb, tcpecho_raw_sent); |
|
|
|
|
ret_err = ERR_OK; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
ret_err = ERR_MEM; |
|
|
|
|
} |
|
|
|
|
return ret_err; |
|
|
|
|
tcp_close(tpcb); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
err_t |
|
|
|
|
tcpecho_raw_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) |
|
|
|
|
static void |
|
|
|
|
tcpecho_raw_send(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es) |
|
|
|
|
{ |
|
|
|
|
struct tcpecho_raw_state *es; |
|
|
|
|
err_t ret_err; |
|
|
|
|
|
|
|
|
|
LWIP_ASSERT("arg != NULL",arg != NULL); |
|
|
|
|
es = (struct tcpecho_raw_state *)arg; |
|
|
|
|
if (p == NULL) |
|
|
|
|
{ |
|
|
|
|
/* remote host closed connection */ |
|
|
|
|
es->state = ES_CLOSING; |
|
|
|
|
if(es->p == NULL) |
|
|
|
|
{ |
|
|
|
|
/* we're done sending, close it */ |
|
|
|
|
tcpecho_raw_close(tpcb, es); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* we're not done yet */ |
|
|
|
|
tcpecho_raw_send(tpcb, es); |
|
|
|
|
} |
|
|
|
|
ret_err = ERR_OK; |
|
|
|
|
} |
|
|
|
|
else if(err != ERR_OK) |
|
|
|
|
{ |
|
|
|
|
/* cleanup, for unkown reason */ |
|
|
|
|
if (p != NULL) |
|
|
|
|
{ |
|
|
|
|
pbuf_free(p); |
|
|
|
|
} |
|
|
|
|
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_raw_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_raw_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); |
|
|
|
|
struct pbuf *ptr; |
|
|
|
|
err_t wr_err = ERR_OK; |
|
|
|
|
|
|
|
|
|
while ((wr_err == ERR_OK) && |
|
|
|
|
(es->p != NULL) &&
|
|
|
|
|
(es->p->len <= tcp_sndbuf(tpcb))) { |
|
|
|
|
ptr = es->p; |
|
|
|
|
|
|
|
|
|
/* enqueue data for transmission */ |
|
|
|
|
wr_err = tcp_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 */ |
|
|
|
|
tcp_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 ?? */ |
|
|
|
|
} |
|
|
|
|
ret_err = ERR_OK; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* unkown es->state, trash data */ |
|
|
|
|
tcp_recved(tpcb, p->tot_len); |
|
|
|
|
pbuf_free(p); |
|
|
|
|
ret_err = ERR_OK; |
|
|
|
|
} |
|
|
|
|
return ret_err; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
static void |
|
|
|
|
tcpecho_raw_error(void *arg, err_t err) |
|
|
|
|
{ |
|
|
|
|
struct tcpecho_raw_state *es; |
|
|
|
|
@ -223,32 +142,25 @@ tcpecho_raw_error(void *arg, err_t err)
|
|
|
|
|
tcpecho_raw_free(es); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
err_t |
|
|
|
|
static err_t |
|
|
|
|
tcpecho_raw_poll(void *arg, struct tcp_pcb *tpcb) |
|
|
|
|
{ |
|
|
|
|
err_t ret_err; |
|
|
|
|
struct tcpecho_raw_state *es; |
|
|
|
|
|
|
|
|
|
es = (struct tcpecho_raw_state *)arg; |
|
|
|
|
if (es != NULL) |
|
|
|
|
{ |
|
|
|
|
if (es->p != NULL) |
|
|
|
|
{ |
|
|
|
|
if (es != NULL) { |
|
|
|
|
if (es->p != NULL) { |
|
|
|
|
/* there is a remaining pbuf (chain) */ |
|
|
|
|
tcpecho_raw_send(tpcb, es); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
} else { |
|
|
|
|
/* no remaining pbuf (chain) */ |
|
|
|
|
if(es->state == ES_CLOSING) |
|
|
|
|
{ |
|
|
|
|
if(es->state == ES_CLOSING) { |
|
|
|
|
tcpecho_raw_close(tpcb, es); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ret_err = ERR_OK; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
} else { |
|
|
|
|
/* nothing to be done */ |
|
|
|
|
tcp_abort(tpcb); |
|
|
|
|
ret_err = ERR_ABRT; |
|
|
|
|
@ -256,7 +168,7 @@ tcpecho_raw_poll(void *arg, struct tcp_pcb *tpcb)
|
|
|
|
|
return ret_err; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
err_t |
|
|
|
|
static err_t |
|
|
|
|
tcpecho_raw_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) |
|
|
|
|
{ |
|
|
|
|
struct tcpecho_raw_state *es; |
|
|
|
|
@ -266,92 +178,126 @@ tcpecho_raw_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
|
|
|
|
|
es = (struct tcpecho_raw_state *)arg; |
|
|
|
|
es->retries = 0; |
|
|
|
|
|
|
|
|
|
if(es->p != NULL) |
|
|
|
|
{ |
|
|
|
|
if(es->p != NULL) { |
|
|
|
|
/* still got pbufs to send */ |
|
|
|
|
tcp_sent(tpcb, tcpecho_raw_sent); |
|
|
|
|
tcpecho_raw_send(tpcb, es); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
} else { |
|
|
|
|
/* no more pbufs to send */ |
|
|
|
|
if(es->state == ES_CLOSING) |
|
|
|
|
{ |
|
|
|
|
if(es->state == ES_CLOSING) { |
|
|
|
|
tcpecho_raw_close(tpcb, es); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return ERR_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
tcpecho_raw_send(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es) |
|
|
|
|
static err_t |
|
|
|
|
tcpecho_raw_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) |
|
|
|
|
{ |
|
|
|
|
struct pbuf *ptr; |
|
|
|
|
err_t wr_err = ERR_OK; |
|
|
|
|
|
|
|
|
|
while ((wr_err == ERR_OK) && |
|
|
|
|
(es->p != NULL) &&
|
|
|
|
|
(es->p->len <= tcp_sndbuf(tpcb))) |
|
|
|
|
{ |
|
|
|
|
ptr = es->p; |
|
|
|
|
|
|
|
|
|
/* enqueue data for transmission */ |
|
|
|
|
wr_err = tcp_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 */ |
|
|
|
|
tcp_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 ?? */ |
|
|
|
|
} |
|
|
|
|
struct tcpecho_raw_state *es; |
|
|
|
|
err_t ret_err; |
|
|
|
|
|
|
|
|
|
LWIP_ASSERT("arg != NULL",arg != NULL); |
|
|
|
|
es = (struct tcpecho_raw_state *)arg; |
|
|
|
|
if (p == NULL) { |
|
|
|
|
/* remote host closed connection */ |
|
|
|
|
es->state = ES_CLOSING; |
|
|
|
|
if(es->p == NULL) { |
|
|
|
|
/* we're done sending, close it */ |
|
|
|
|
tcpecho_raw_close(tpcb, es); |
|
|
|
|
} else { |
|
|
|
|
/* we're not done yet */ |
|
|
|
|
tcpecho_raw_send(tpcb, es); |
|
|
|
|
} |
|
|
|
|
ret_err = ERR_OK; |
|
|
|
|
} else if(err != ERR_OK) { |
|
|
|
|
/* cleanup, for unknown reason */ |
|
|
|
|
if (p != NULL) { |
|
|
|
|
pbuf_free(p); |
|
|
|
|
} |
|
|
|
|
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_raw_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_raw_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 { |
|
|
|
|
/* unkown es->state, trash data */ |
|
|
|
|
tcp_recved(tpcb, p->tot_len); |
|
|
|
|
pbuf_free(p); |
|
|
|
|
ret_err = ERR_OK; |
|
|
|
|
} |
|
|
|
|
return ret_err; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
tcpecho_raw_close(struct tcp_pcb *tpcb, struct tcpecho_raw_state *es) |
|
|
|
|
static err_t |
|
|
|
|
tcpecho_raw_accept(void *arg, struct tcp_pcb *newpcb, err_t err) |
|
|
|
|
{ |
|
|
|
|
tcp_arg(tpcb, NULL); |
|
|
|
|
tcp_sent(tpcb, NULL); |
|
|
|
|
tcp_recv(tpcb, NULL); |
|
|
|
|
tcp_err(tpcb, NULL); |
|
|
|
|
tcp_poll(tpcb, NULL, 0); |
|
|
|
|
err_t ret_err; |
|
|
|
|
struct tcpecho_raw_state *es; |
|
|
|
|
|
|
|
|
|
tcpecho_raw_free(es); |
|
|
|
|
LWIP_UNUSED_ARG(arg); |
|
|
|
|
if ((err != ERR_OK) || (newpcb == NULL)) { |
|
|
|
|
return ERR_VAL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tcp_close(tpcb); |
|
|
|
|
/* 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. */ |
|
|
|
|
tcp_setprio(newpcb, TCP_PRIO_MIN); |
|
|
|
|
|
|
|
|
|
es = (struct tcpecho_raw_state *)mem_malloc(sizeof(struct tcpecho_raw_state)); |
|
|
|
|
if (es != NULL) { |
|
|
|
|
es->state = ES_ACCEPTED; |
|
|
|
|
es->pcb = newpcb; |
|
|
|
|
es->retries = 0; |
|
|
|
|
es->p = NULL; |
|
|
|
|
/* pass newly allocated es to our callbacks */ |
|
|
|
|
tcp_arg(newpcb, es); |
|
|
|
|
tcp_recv(newpcb, tcpecho_raw_recv); |
|
|
|
|
tcp_err(newpcb, tcpecho_raw_error); |
|
|
|
|
tcp_poll(newpcb, tcpecho_raw_poll, 0); |
|
|
|
|
tcp_sent(newpcb, tcpecho_raw_sent); |
|
|
|
|
ret_err = ERR_OK; |
|
|
|
|
} else { |
|
|
|
|
ret_err = ERR_MEM; |
|
|
|
|
} |
|
|
|
|
return ret_err; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void tcpecho_raw_free(struct tcpecho_raw_state *es) |
|
|
|
|
void |
|
|
|
|
tcpecho_raw_init(void) |
|
|
|
|
{ |
|
|
|
|
if (es != NULL) |
|
|
|
|
{ |
|
|
|
|
if (es->p) |
|
|
|
|
{ |
|
|
|
|
/* free the buffer chain if present */ |
|
|
|
|
pbuf_free(es->p); |
|
|
|
|
} |
|
|
|
|
tcpecho_raw_pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); |
|
|
|
|
if (tcpecho_raw_pcb != NULL) { |
|
|
|
|
err_t err; |
|
|
|
|
|
|
|
|
|
mem_free(es); |
|
|
|
|
}
|
|
|
|
|
err = tcp_bind(tcpecho_raw_pcb, IP_ANY_TYPE, 7); |
|
|
|
|
if (err == ERR_OK) { |
|
|
|
|
tcpecho_raw_pcb = tcp_listen(tcpecho_raw_pcb); |
|
|
|
|
tcp_accept(tcpecho_raw_pcb, tcpecho_raw_accept); |
|
|
|
|
} else { |
|
|
|
|
/* abort? output diagnostic? */ |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
/* abort? output diagnostic? */ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif /* LWIP_TCP */ |
|
|
|
|
|