123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- /**
- * 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 application.
- *
- **/
- /* This file was modified by ST */
- #include "lwip/debug.h"
- #include "lwip/stats.h"
- #include "lwip/tcp.h"
- #if LWIP_TCP
- static struct tcp_pcb *tcp_server_pcb;
- /* ECHO protocol states */
- enum tcp_server_states
- {
- ES_NONE = 0,
- ES_ACCEPTED,
- ES_RECEIVED,
- ES_CLOSING
- };
- /* structure for maintaing connection infos to be passed as argument
- to LwIP callbacks*/
- struct tcp_server_struct
- {
- u8_t state; /* current connection state */
- u8_t retries;
- struct tcp_pcb *pcb; /* pointer on the current tcp_pcb */
- struct pbuf *p; /* pointer on the received/to be transmitted pbuf */
- };
- static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err);
- static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
- static void tcp_server_error(void *arg, err_t err);
- static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb);
- static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
- static void tcp_server_send(struct tcp_pcb *tpcb, struct tcp_server_struct *es);
- static void tcp_server_connection_close(struct tcp_pcb *tpcb, struct tcp_server_struct *es);
- /**
- * @brief Initializes the tcp server
- * @param None
- * @retval None
- */
- void tcp_server_init(void)
- {
- /* create new tcp pcb */
- tcp_server_pcb = tcp_new();
- if (tcp_server_pcb != NULL)
- {
- err_t err;
-
- /* bind _pcb to port 7 (ECHO protocol) */
- err = tcp_bind(tcp_server_pcb, IP_ADDR_ANY, 7);
-
- if (err == ERR_OK)
- {
- /* start tcp listening for _pcb */
- tcp_server_pcb = tcp_listen(tcp_server_pcb);
-
- /* initialize LwIP tcp_accept callback function */
- tcp_accept(tcp_server_pcb, tcp_server_accept);
- }
- else
- {
- /* deallocate the pcb */
- memp_free(MEMP_TCP_PCB, tcp_server_pcb);
- }
- }
- }
- /**
- * @brief This function is the implementation of tcp_accept LwIP callback
- * @param arg: not used
- * @param newpcb: pointer on tcp_pcb struct for the newly created tcp connection
- * @param err: not used
- * @retval err_t: error status
- */
- static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
- {
- err_t ret_err;
- struct tcp_server_struct *es;
- LWIP_UNUSED_ARG(arg);
- LWIP_UNUSED_ARG(err);
- /* set priority for the newly accepted tcp connection newpcb */
- tcp_setprio(newpcb, TCP_PRIO_MIN);
- /* allocate structure es to maintain tcp connection informations */
- es = (struct tcp_server_struct *)mem_malloc(sizeof(struct tcp_server_struct));
- if (es != NULL)
- {
- es->state = ES_ACCEPTED;
- es->pcb = newpcb;
- es->retries = 0;
- es->p = NULL;
-
- /* pass newly allocated es structure as argument to newpcb */
- tcp_arg(newpcb, es);
-
- /* initialize lwip tcp_recv callback function for newpcb */
- tcp_recv(newpcb, tcp_server_recv);
-
- /* initialize lwip tcp_err callback function for newpcb */
- tcp_err(newpcb, tcp_server_error);
-
- /* initialize lwip tcp_poll callback function for newpcb */
- tcp_poll(newpcb, tcp_server_poll, 0);
-
- ret_err = ERR_OK;
- }
- else
- {
- /* close tcp connection */
- tcp_server_connection_close(newpcb, es);
- /* return memory error */
- ret_err = ERR_MEM;
- }
- return ret_err;
- }
- /**
- * @brief This function is the implementation for tcp_recv LwIP callback
- * @param arg: pointer on a argument for the tcp_pcb connection
- * @param tpcb: pointer on the tcp_pcb connection
- * @param pbuf: pointer on the received pbuf
- * @param err: error information regarding the reveived pbuf
- * @retval err_t: error code
- */
- static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
- {
- struct tcp_server_struct *es;
- err_t ret_err;
- LWIP_ASSERT("arg != NULL",arg != NULL);
-
- es = (struct tcp_server_struct *)arg;
-
- /* if we receive an empty tcp frame from client => close connection */
- if (p == NULL)
- {
- /* remote host closed connection */
- es->state = ES_CLOSING;
- if(es->p == NULL)
- {
- /* we're done sending, close connection */
- tcp_server_connection_close(tpcb, es);
- }
- else
- {
- /* we're not done yet */
- /* acknowledge received packet */
- tcp_sent(tpcb, tcp_server_sent);
-
- /* send remaining data*/
- tcp_server_send(tpcb, es);
- }
- ret_err = ERR_OK;
- }
- /* else : a non empty frame was received from client but for some reason err != ERR_OK */
- else if(err != ERR_OK)
- {
- /* free received pbuf*/
- if (p != NULL)
- {
- es->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;
-
- /* initialize LwIP tcp_sent callback function */
- tcp_sent(tpcb, tcp_server_sent);
-
- /* send back the received data () */
- tcp_server_send(tpcb, es);
-
- ret_err = ERR_OK;
- }
- else if (es->state == ES_RECEIVED)
- {
- /* more data received from client and previous data has been already sent*/
- if(es->p == NULL)
- {
- es->p = p;
- /*
- TODO: Process income data here
- */
- char aa[128];
- memcpy(aa, p->payload, p->len);
- aa[p->len] = 0x00;
- DEBUG_INFO("Payload: %s\r\n", aa);
-
-
-
-
- /* send back received data */
- tcp_server_send(tpcb, es);
- }
- else
- {
- struct pbuf *ptr;
- /* chain pbufs to the end of what we recv'ed previously */
- ptr = es->p;
- pbuf_chain(ptr,p);
- }
- ret_err = ERR_OK;
- }
- else if(es->state == ES_CLOSING)
- {
- /* odd case, remote side closing twice, trash data */
- tcp_recved(tpcb, p->tot_len);
- es->p = NULL;
- pbuf_free(p);
- ret_err = ERR_OK;
- }
- else
- {
- /* unkown es->state, trash data */
- tcp_recved(tpcb, p->tot_len);
- es->p = NULL;
- pbuf_free(p);
- ret_err = ERR_OK;
- }
- return ret_err;
- }
- /**
- * @brief This function implements the tcp_err callback function (called
- * when a fatal tcp_connection error occurs.
- * @param arg: pointer on argument parameter
- * @param err: not used
- * @retval None
- */
- static void tcp_server_error(void *arg, err_t err)
- {
- struct tcp_server_struct *es;
- LWIP_UNUSED_ARG(err);
- es = (struct tcp_server_struct *)arg;
- if (es != NULL)
- {
- /* free es structure */
- mem_free(es);
- }
- }
- /**
- * @brief This function implements the tcp_poll LwIP callback function
- * @param arg: pointer on argument passed to callback
- * @param tpcb: pointer on the tcp_pcb for the current tcp connection
- * @retval err_t: error code
- */
- static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb)
- {
- err_t ret_err;
- struct tcp_server_struct *es;
- es = (struct tcp_server_struct *)arg;
- if (es != NULL)
- {
- if (es->p != NULL)
- {
- tcp_sent(tpcb, tcp_server_sent);
- /* there is a remaining pbuf (chain) , try to send data */
- DEBUG_INFO("Poll...\r\n");
- tcp_server_send(tpcb, es);
- }
- else
- {
- /* no remaining pbuf (chain) */
- if(es->state == ES_CLOSING)
- {
- /* close tcp connection */
- tcp_server_connection_close(tpcb, es);
- }
- }
- ret_err = ERR_OK;
- }
- else
- {
- /* nothing to be done */
- tcp_abort(tpcb);
- ret_err = ERR_ABRT;
- }
-
- return ret_err;
- }
- /**
- * @brief This function implements the tcp_sent LwIP callback (called when ACK
- * is received from remote host for sent data)
- * @param None
- * @retval None
- */
- static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
- {
- struct tcp_server_struct *es;
- LWIP_UNUSED_ARG(len);
- es = (struct tcp_server_struct *)arg;
- es->retries = 0;
-
- if(es->p != NULL)
- {
- /* still got pbufs to send */
- tcp_sent(tpcb, tcp_server_sent);
- tcp_server_send(tpcb, es);
- }
- else
- {
- /* if no more data to send and client closed connection*/
- if(es->state == ES_CLOSING)
- tcp_server_connection_close(tpcb, es);
- }
- return ERR_OK;
- }
- /**
- * @brief This function is used to send data for tcp connection
- * @param tpcb: pointer on the tcp_pcb connection
- * @param es: pointer on _state structure
- * @retval None
- */
- static void tcp_server_send(struct tcp_pcb *tpcb, struct tcp_server_struct *es)
- {
- struct pbuf *ptr;
- err_t wr_err = ERR_OK;
-
- while ((wr_err == ERR_OK) &&
- (es->p != NULL) &&
- (es->p->len <= tcp_sndbuf(tpcb)))
- {
-
- /* get pointer on pbuf from es structure */
- 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;
- u8_t freed;
- plen = ptr->len;
-
- /* continue with next pbuf in chain (if any) */
- es->p = ptr->next;
-
- if(es->p != NULL)
- {
- /* increment reference count for es->p */
- pbuf_ref(es->p);
- }
-
- /* chop first pbuf from chain */
- do
- {
- /* try hard to free pbuf */
- freed = pbuf_free(ptr);
- }
- while(freed == 0);
- /* 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 ?? */
- }
- }
- }
- /**
- * @brief This functions closes the tcp connection
- * @param tcp_pcb: pointer on the tcp connection
- * @param es: pointer on _state structure
- * @retval None
- */
- static void tcp_server_connection_close(struct tcp_pcb *tpcb, struct tcp_server_struct *es)
- {
-
- /* remove all callbacks */
- tcp_arg(tpcb, NULL);
- tcp_sent(tpcb, NULL);
- tcp_recv(tpcb, NULL);
- tcp_err(tpcb, NULL);
- tcp_poll(tpcb, NULL, 0);
-
- /* delete es structure */
- if (es != NULL)
- {
- mem_free(es);
- }
-
- /* close tcp connection */
- tcp_close(tpcb);
- }
- #endif /* LWIP_TCP */
|