diff --git a/VERSION b/VERSION index ea788fa9..71dd711a 100644 --- a/VERSION +++ b/VERSION @@ -1,7 +1,6 @@ gwen: - espconn: 730c7f0 espnow: 1aafc07 - main: 730c7f0 + main: 4e7f435 mesh: 1aafc07 net80211: 730c7f0 pp: 1474356 @@ -9,6 +8,7 @@ gwen: wps: 1aafc07 gitlab: + espconn: 3a998034 lwip: 2235ad17 driver: 7bee5263 mbedtls: 1ac9f1f4 diff --git a/include/espconn/espconn.h b/include/espconn/espconn.h new file mode 100755 index 00000000..4802be91 --- /dev/null +++ b/include/espconn/espconn.h @@ -0,0 +1,757 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ESPCONN_H__ +#define __ESPCONN_H__ + +#include "lwip/dns.h" +#include "arch/sys_arch.h" +#include "esp_common.h" +#include "espconn/espconn_buf.h" + +#if 0 +#define espconn_printf(fmt, args...) os_printf(fmt,## args) +#else +#define espconn_printf(fmt, args...) +#endif + +#if !NO_SYS +#define ESPCONN_API_MUTEX_TAKE() taskENTER_CRITICAL() //vTaskSuspendAll()//taskENTER_CRITICAL()//API_MUTEX_TAKE() +#define ESPCONN_API_MUTEX_GIVE() taskEXIT_CRITICAL() //xTaskResumeAll()//taskEXIT_CRITICAL()//API_MUTEX_GIVE() +#else +#define ESPCONN_API_MUTEX_TAKE() +#define ESPCONN_API_MUTEX_GIVE() +#endif + +typedef void* espconn_handle; +typedef void (* espconn_connect_callback)(void* arg); +typedef void (* espconn_reconnect_callback)(void* arg, sint8 err); + +/* Definitions for error constants. */ + +#define ESPCONN_OK 0 /* No error, everything OK. */ +#define ESPCONN_MEM -1 /* Out of memory error. */ +#define ESPCONN_TIMEOUT -3 /* Timeout. */ +#define ESPCONN_RTE -4 /* Routing problem. */ +#define ESPCONN_INPROGRESS -5 /* Operation in progress */ +#define ESPCONN_MAXNUM -7 /* Total number exceeds the set maximum*/ + +#define ESPCONN_ABRT -8 /* Connection aborted. */ +#define ESPCONN_RST -9 /* Connection reset. */ +#define ESPCONN_CLSD -10 /* Connection closed. */ +#define ESPCONN_CONN -11 /* Not connected. */ + +#define ESPCONN_ARG -12 /* Illegal argument. */ +#define ESPCONN_IF -14 /* Low_level error */ +#define ESPCONN_ISCONN -15 /* Already connected. */ +#define ESPCONN_TIME -16 /* Sync Time error */ +#define ESPCONN_NODATA -17 /* No data can be read */ + +#define ESPCONN_HANDSHAKE -28 /* ssl handshake failed */ +#define ESPCONN_RESP_TIMEOUT -29 /* ssl handshake no response*/ +#define ESPCONN_PROTO_MSG -61 /* ssl application invalid */ + +#define ESPCONN_SSL 0x01 +#define ESPCONN_NORM 0x00 + +#define ESPCONN_STA 0x01 +#define ESPCONN_AP 0x02 +#define ESPCONN_AP_STA 0x03 + +#define STA_NETIF 0x00 +#define AP_NETIF 0x01 + +/** Protocol family and type of the espconn */ +enum espconn_type { + ESPCONN_INVALID = 0, + /* ESPCONN_TCP Group */ + ESPCONN_TCP = 0x10, + /* ESPCONN_UDP Group */ + ESPCONN_UDP = 0x20, +}; + +/** Current state of the espconn. Non-TCP espconn are always in state ESPCONN_NONE! */ +enum espconn_state { + ESPCONN_NONE, + ESPCONN_WAIT, + ESPCONN_LISTEN, + ESPCONN_CONNECT, + ESPCONN_WRITE, + ESPCONN_READ, + ESPCONN_CLOSE +}; + +typedef struct _esp_tcp { + int remote_port; + int local_port; + uint8 local_ip[4]; + uint8 remote_ip[4]; + espconn_connect_callback connect_callback; + espconn_reconnect_callback reconnect_callback; + espconn_connect_callback disconnect_callback; + espconn_connect_callback write_finish_fn; +} esp_tcp; + +typedef struct _esp_udp { + int remote_port; + int local_port; + uint8 local_ip[4]; + uint8 remote_ip[4]; +} esp_udp; + +typedef struct _remot_info { + enum espconn_state state; + int remote_port; + uint8 remote_ip[4]; +} remot_info; + +/** A callback prototype to inform about events for a espconn */ +typedef void (* espconn_recv_callback)(void* arg, char* pdata, unsigned short len); +typedef void (* espconn_sent_callback)(void* arg); + +/** A espconn descriptor */ +struct espconn { + /** type of the espconn (TCP, UDP) */ + enum espconn_type type; + /** current state of the espconn */ + enum espconn_state state; + union { + esp_tcp* tcp; + esp_udp* udp; + } proto; + /** A callback function that is informed about events for this espconn */ + espconn_recv_callback recv_callback; + espconn_sent_callback sent_callback; + uint8 link_cnt; + void* reverse; +}; + +enum espconn_option { + ESPCONN_START = 0x00, + ESPCONN_REUSEADDR = 0x01, + ESPCONN_NODELAY = 0x02, + ESPCONN_COPY = 0x04, + ESPCONN_KEEPALIVE = 0x08, + ESPCONN_END +}; + +enum espconn_level { + ESPCONN_KEEPIDLE, + ESPCONN_KEEPINTVL, + ESPCONN_KEEPCNT +}; + +enum espconn_mode { + ESPCONN_NOMODE, + ESPCONN_TCPSERVER_MODE, + ESPCONN_TCPCLIENT_MODE, + ESPCONN_UDP_MODE, + ESPCONN_NUM_MODE +}; + +struct espconn_packet { + uint16 sent_length; /* sent length successful*/ + uint16 snd_buf_size; /* Available buffer size for sending */ + uint16 snd_queuelen; /* Available buffer space for sending */ + uint16 total_queuelen; /* total Available buffer space for sending */ + uint32 packseqno; /* seqno to be sent */ + uint32 packseq_nxt; /* seqno expected */ + uint32 packnum; +}; + +typedef struct _espconn_buf { + uint8* payload; + uint8* punsent; + uint16 unsent; + uint16 len; + uint16 tot_len; + struct _espconn_buf* pnext; +} espconn_buf; + +typedef struct _comon_pkt { + void* pcb; + int remote_port; + uint8 remote_ip[4]; + uint32 local_port; + uint32 local_ip; + espconn_buf* pbuf; + espconn_buf* ptail; + uint8* ptrbuf; + uint16 cntr; + sint8 err; + uint32 timeout; + uint32 recv_check; + uint8 pbuf_num; + struct espconn_packet packet_info; + bool write_flag; + enum espconn_option espconn_opt; +} comon_pkt; + +typedef struct _espconn_msg { + struct espconn* pespconn; + comon_pkt pcommon; + uint8 count_opt; + uint8 espconn_mode; + uint8 sig_type; + sint16 hs_status; //the status of the handshake + void* preverse; + void* pssl; + struct _espconn_msg* pnext; + +//***********Code for WIFI_BLOCK from upper************** + uint8 recv_hold_flag; + uint16 recv_holded_buf_Len; +//******************************************************* + ringbuf* readbuf; +} espconn_msg; + +#ifndef _MDNS_INFO +#define _MDNS_INFO +struct mdns_info { + char* host_name; + char* server_name; + uint16 server_port; + unsigned long ipAddr; + char* txt_data[10]; +}; +#endif + +#define linkMax 15 + +#define espconn_delay_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) != 0) +#define espconn_delay_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) == 0) +#define espconn_reuse_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_REUSEADDR) != 0) +#define espconn_copy_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) != 0) +#define espconn_copy_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) == 0) +#define espconn_keepalive_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) != 0) +#define espconn_keepalive_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) == 0) + +#define espconn_TaskPrio 26 +#define espconn_TaskQueueLen 15 + +enum espconn_sig { + SIG_ESPCONN_NONE, + SIG_ESPCONN_ERRER, + SIG_ESPCONN_LISTEN, + SIG_ESPCONN_CONNECT, + SIG_ESPCONN_WRITE, + SIG_ESPCONN_SEND, + SIG_ESPCONN_READ, + SIG_ESPCONN_CLOSE +}; + +#if !NO_SYS +/** + * ESPCONN_THREAD_NAME: The name assigned to the main espconn thread. + */ +#ifndef ESPCONN_THREAD_NAME +#define ESPCONN_THREAD_NAME "espconn_thread" +#endif +/** + * ESPCONN_THREAD_STACKSIZE: The stack size used by the main espconn thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#define ESPCONN_THREAD_STACKSIZE 512 //not ok:384 +/** + * ESPCONN_THREAD_PRIO: The priority assigned to the main espconn thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#define ESPCONN_THREAD_PRIO (configMAX_PRIORITIES-7) +//#define ESPCONN_THREAD_PRIO (configMAX_PRIORITIES-1) +/** + * ESPCONN_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#define ESPCONN_MBOX_SIZE 16 + +#define ESPCONN_MAX_DELAY portMAX_DELAY +/** + * ESPCONN_LOCKING: + */ +#ifndef ESPCONN_LOCKING +#define ESPCONN_LOCKING 0 +#endif +/** The global semaphore to lock the task. */ +#if ESPCONN_LOCKING +extern sys_mutex_t lock_espconn_task; +#define LOCK_ESPCONN_TASK() sys_mutex_lock(&lock_espconn_task) +#define UNLOCK_ESPCONN_TASK() sys_mutex_unlock(&lock_espconn_task) +#else +#define LOCK_ESPCONN_TASK() +#define UNLOCK_ESPCONN_TASK() +#endif +#else + +#endif +/****************************************************************************** + * FunctionName : espconn_copy_partial + * Description : reconnect with host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ + +void espconn_copy_partial(struct espconn* pesp_dest, struct espconn* pesp_source); + +/****************************************************************************** + * FunctionName : espconn_copy_partial + * Description : insert the node to the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ + +void espconn_list_creat(espconn_msg** phead, espconn_msg* pinsert); + +/****************************************************************************** + * FunctionName : espconn_list_delete + * Description : remove the node from the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ + +void espconn_list_delete(espconn_msg** phead, espconn_msg* pdelete); + +/****************************************************************************** + * FunctionName : espconn_find_connection + * Description : Initialize the server: set up a listening PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build server + * Returns : none + *******************************************************************************/ + +bool espconn_find_connection(struct espconn* pespconn, espconn_msg** pnode); + +/****************************************************************************** + * FunctionName : espconn_get_connection_info + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +sint8 espconn_get_connection_info(struct espconn* pespconn, remot_info** pcon_info, uint8 typeflags); + +/****************************************************************************** + * FunctionName : espconn_get_packet_info + * Description : get the packet info with host + * Parameters : espconn -- the espconn used to disconnect the connection + * infoarg -- the packet info + * Returns : the errur code +*******************************************************************************/ + +sint8 espconn_get_packet_info(struct espconn* espconn, struct espconn_packet* infoarg); + +/****************************************************************************** + * FunctionName : espconn_connect + * Description : The function given as the connect + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_connect(struct espconn* espconn); + +/****************************************************************************** + * FunctionName : espconn_disconnect + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_disconnect(struct espconn* espconn); + +/****************************************************************************** + * FunctionName : espconn_delete + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_delete(struct espconn* espconn); + +/****************************************************************************** + * FunctionName : espconn_accept + * Description : The function given as the listen + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_accept(struct espconn* espconn); + +/****************************************************************************** + * FunctionName : espconn_create + * Description : sent data for client or server + * Parameters : espconn -- espconn to the data transmission + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_create(struct espconn* espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_wnd + * Description : get the window size of simulatenously active TCP connections + * Parameters : none + * Returns : the number of TCP_MSS active TCP connections +*******************************************************************************/ +extern uint8 espconn_tcp_get_wnd(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the window size simulatenously active TCP connections + * Parameters : num -- the number of TCP_MSS + * Returns : ESPCONN_ARG -- Illegal argument + * ESPCONN_OK -- No error +*******************************************************************************/ +extern sint8 espconn_tcp_set_wnd(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con + * Description : get the number of simulatenously active TCP connections + * Parameters : none + * Returns : none +*******************************************************************************/ + +extern uint8 espconn_tcp_get_max_con(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the number of simulatenously active TCP connections + * Parameters : num -- total number + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_con(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_retran + * Description : get the Maximum number of retransmissions of data active TCP connections + * Parameters : none + * Returns : the Maximum number of retransmissions +*******************************************************************************/ +extern uint8 espconn_tcp_get_max_retran(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_retran + * Description : set the Maximum number of retransmissions of data active TCP connections + * Parameters : num -- the Maximum number of retransmissions + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_retran(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_syn + * Description : get the Maximum number of retransmissions of SYN segments + * Parameters : none + * Returns : the Maximum number of retransmissions +*******************************************************************************/ + +extern uint8 espconn_tcp_get_max_syn(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_syn + * Description : set the Maximum number of retransmissions of SYN segments + * Parameters : num -- the Maximum number of retransmissions + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_syn(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con_allow + * Description : get the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to get the count + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_get_max_con_allow(struct espconn* espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con_allow + * Description : set the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to set the count + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_con_allow(struct espconn* espconn, uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_buf_count + * Description : set the total number of espconn_buf on the unsent lists + * Parameters : espconn -- espconn to set the count + * num -- the total number of espconn_buf + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_buf_count(struct espconn* espconn, uint8 num); + +/****************************************************************************** + * FunctionName : espconn_regist_time + * Description : used to specify the time that should be called when don't recv data + * Parameters : espconn -- the espconn used to the connection + * interval -- the timer when don't recv data + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_time(struct espconn* espconn, uint32 interval, uint8 type_flag); + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : struct espconn *espconn -- espconn to set the sent callback + * espconn_sent_callback sent_cb -- sent callback function to + * call for this espconn when data is successfully sent + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_sentcb(struct espconn* espconn, espconn_sent_callback sent_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : espconn -- espconn to set the sent callback + * sent_cb -- sent callback function to call for this espconn + * when data is successfully sent + * Returns : none +*******************************************************************************/ +extern sint8 espconn_regist_write_finish(struct espconn* espconn, espconn_connect_callback write_finish_fn); + +/****************************************************************************** + * FunctionName : espconn_sent + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_sent(struct espconn* espconn, uint8* psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_regist_connectcb + * Description : used to specify the function that should be called when + * connects to host. + * Parameters : espconn -- espconn to set the connect callback + * connect_cb -- connected callback function to call when connected + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_connectcb(struct espconn* espconn, espconn_connect_callback connect_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_recvcb + * Description : used to specify the function that should be called when recv + * data from host. + * Parameters : espconn -- espconn to set the recv callback + * recv_cb -- recv callback function to call when recv data + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_recvcb(struct espconn* espconn, espconn_recv_callback recv_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_reconcb + * Description : used to specify the function that should be called when connection + * because of err disconnect. + * Parameters : espconn -- espconn to set the err callback + * recon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_reconcb(struct espconn* espconn, espconn_reconnect_callback recon_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_disconcb + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_disconcb(struct espconn* espconn, espconn_connect_callback discon_cb); + +/****************************************************************************** + * FunctionName : espconn_port + * Description : access port value for client so that we don't end up bouncing + * all connections at the same time . + * Parameters : none + * Returns : access port value +*******************************************************************************/ + +extern uint32 espconn_port(void); + +/****************************************************************************** + * FunctionName : espconn_set_opt + * Description : access port value for client so that we don't end up bouncing + * all connections at the same time . + * Parameters : none + * Returns : access port value +*******************************************************************************/ +extern sint8 espconn_set_opt(struct espconn* espconn, uint8 opt); + +/****************************************************************************** + * FunctionName : espconn_set_keepalive + * Description : access level value for connection so that we set the value for + * keep alive + * Parameters : espconn -- the espconn used to set the connection + * level -- the connection's level + * value -- the value of time(s) + * Returns : access port value +*******************************************************************************/ +extern sint8 espconn_set_keepalive(struct espconn* espconn, uint8 level, void* optarg); + +/****************************************************************************** + * FunctionName : espconn_get_keepalive + * Description : access level value for connection so that we get the value for + * keep alive + * Parameters : espconn -- the espconn used to get the connection + * level -- the connection's level + * Returns : access keep alive value +*******************************************************************************/ +extern sint8 espconn_get_keepalive(struct espconn* espconn, uint8 level, void* optarg); + +/****************************************************************************** + * FunctionName : espconn_gethostbyname + * Description : Resolve a hostname (string) into an IP address. + * Parameters : pespconn -- espconn to resolve a hostname + * hostname -- the hostname that is to be queried + * addr -- pointer to a ip_addr_t where to store the address if + * it is already cached in the dns_table (only valid if + * ESPCONN_OK is returned!) + * found -- a callback function to be called on success, failure + * or timeout (only if ERR_INPROGRESS is returned!) + * Returns : err_t return code + * - ESPCONN_OK if hostname is a valid IP address string or the host + * name is already in the local names table. + * - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server + * for resolution if no errors are present. + * - ESPCONN_ARG: dns client not initialized or invalid hostname +*******************************************************************************/ + +extern err_t espconn_gethostbyname(struct espconn* pespconn, const char* name, ip_addr_t* addr, dns_found_callback found); + +/****************************************************************************** + * FunctionName : espconn_igmp_join + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +extern sint8 espconn_igmp_join(ip_addr_t* host_ip, ip_addr_t* multicast_ip); + +/****************************************************************************** + * FunctionName : espconn_igmp_leave + * Description : leave a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +extern sint8 espconn_igmp_leave(ip_addr_t* host_ip, ip_addr_t* multicast_ip); + +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : register a device with mdns + * Parameters : ipAddr -- the ip address of device + * hostname -- the hostname of device + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_init(struct mdns_info* info); +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : close mdns socket + * Parameters : void + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_close(void); +/****************************************************************************** + * FunctionName : mdns_server_register + * Description : register a server and join a multicast group + * Parameters : none + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_server_register(void); +/****************************************************************************** + * FunctionName : mdns_server_register + * Description : unregister server and leave multicast group + * Parameters : none + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_server_unregister(void); +/****************************************************************************** + * FunctionName : espconn_mdns_get_servername + * Description : get server name + * Parameters : none + * Returns : server name +*******************************************************************************/ +extern char* espconn_mdns_get_servername(void); +/****************************************************************************** + * FunctionName : espconn_mdns_get_servername + * Description : set server name + * Parameters : server name + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_set_servername(const char* name); +/****************************************************************************** + * FunctionName : espconn_mdns_set_hostname + * Description : set host name + * Parameters : host name + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_set_hostname(char* name); +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : get host name + * Parameters : void + * Returns : hostname +*******************************************************************************/ +extern char* espconn_mdns_get_hostname(void); +/****************************************************************************** + * FunctionName : espconn_mdns_disable + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_disable(void); +/****************************************************************************** + * FunctionName : espconn_mdns_enable + * Description : enable mdns + * Parameters : void + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_enable(void); +/****************************************************************************** + * FunctionName : espconn_dns_setserver + * Description : Initialize one of the DNS servers. + * Parameters : numdns -- the index of the DNS server to set must + * be < DNS_MAX_SERVERS = 2 + * dnsserver -- IP address of the DNS server to set + * Returns : none +*******************************************************************************/ +extern void espconn_dns_setserver(u8_t numdns, ip_addr_t* dnsserver); +#endif + diff --git a/include/espconn/espconn_buf.h b/include/espconn/espconn_buf.h new file mode 100755 index 00000000..3453c3cf --- /dev/null +++ b/include/espconn/espconn_buf.h @@ -0,0 +1,68 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _ESPCONN_BUF_H_ +#define _ESPCONN_BUF_H_ + +#include "c_types.h" + +typedef struct ringbuf_t { + uint8_t* buf; + uint8_t* head, *tail; + size_t size; +} ringbuf, *ringbuf_t; + +ringbuf_t ringbuf_new(size_t capacity); + +size_t ringbuf_buffer_size(const struct ringbuf_t* rb); + +void ringbuf_reset(ringbuf_t rb); + +void ringbuf_free(ringbuf_t* rb); + +size_t ringbuf_capacity(const struct ringbuf_t* rb); + +size_t ringbuf_bytes_free(const struct ringbuf_t* rb); + +size_t ringbuf_bytes_used(const struct ringbuf_t* rb); + +int ringbuf_is_full(const struct ringbuf_t* rb); + +int ringbuf_is_empty(const struct ringbuf_t* rb); + +const void* ringbuf_tail(const struct ringbuf_t* rb); + +const void* ringbuf_head(const struct ringbuf_t* rb); + +static uint8_t* ringbuf_nextp(ringbuf_t rb, const uint8_t* p); + +size_t ringbuf_findchr(const struct ringbuf_t* rb, int c, size_t offset); + +size_t ringbuf_memset(ringbuf_t dst, int c, size_t len); + +void* ringbuf_memcpy_into(ringbuf_t dst, const void* src, size_t count); + +void* ringbuf_memcpy_from(void* dst, ringbuf_t src, size_t count); + +#endif /* RINGBUF_H_ */ diff --git a/include/espconn/espconn_tcp.h b/include/espconn/espconn_tcp.h new file mode 100755 index 00000000..2b68a159 --- /dev/null +++ b/include/espconn/espconn_tcp.h @@ -0,0 +1,80 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ESPCONN_TCP_H__ +#define __ESPCONN_TCP_H__ + +#ifndef ESPCONN_TCP_DEBUG +#define ESPCONN_TCP_DEBUG LWIP_DBG_OFF +#endif + +#include "espconn/espconn.h" + +#ifndef ESPCONN_TCP_TIMER +#define ESPCONN_TCP_TIMER 40 +#endif + +#define espconn_keepalive_enable(pcb) ((pcb)->so_options |= SOF_KEEPALIVE) +#define espconn_keepalive_disable(pcb) ((pcb)->so_options &= ~SOF_KEEPALIVE) + +/****************************************************************************** + * FunctionName : espconn_kill_oldest_pcb + * Description : A oldest incoming connection has been killed. + * Parameters : none + * Returns : none +*******************************************************************************/ + +extern void espconn_kill_oldest_pcb(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ + +extern void espconn_tcp_disconnect(espconn_msg* pdiscon, u8 type); + +/****************************************************************************** + * FunctionName : espconn_tcp_client + * Description : Initialize the client: set up a connect PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_tcp_client(struct espconn* espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_server + * Description : Initialize the server: set up a listening PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build server + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_tcp_server(struct espconn* espconn); + +#endif /* __CLIENT_TCP_H__ */ + diff --git a/include/espconn/espconn_udp.h b/include/espconn/espconn_udp.h new file mode 100755 index 00000000..75659817 --- /dev/null +++ b/include/espconn/espconn_udp.h @@ -0,0 +1,88 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ESPCONN_UDP_H__ +#define __ESPCONN_UDP_H__ + +#ifndef ESPCONN_UDP_DEBUG +#define ESPCONN_UDP_DEBUG LWIP_DBG_OFF +#endif + +#include "espconn/espconn.h" + +/****************************************************************************** + * FunctionName : espconn_udp_client + * Description : Initialize the client: set up a PCB and bind it to the port + * Parameters : pespconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_udp_client(struct espconn* pespconn); + +/****************************************************************************** + * FunctionName : espconn_udp_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ + +extern void espconn_udp_disconnect(espconn_msg* pdiscon); + +/****************************************************************************** + * FunctionName : espconn_udp_server + * Description : Initialize the server: set up a PCB and bind it to the port + * Parameters : pespconn -- the espconn used to build server + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_udp_server(struct espconn* espconn); + +/****************************************************************************** + * FunctionName : espconn_udp_sent + * Description : sent data for client or server + * Parameters : void *arg -- client or server to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : none +*******************************************************************************/ + +extern err_t espconn_udp_sent(void* arg, uint8* psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_udp_sendto + * Description : sent data for UDP + * Parameters : void *arg -- UDP to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : return espconn error code. + * - ESPCONN_OK. Successful. No error occured. + * - ESPCONN_MEM. Out of memory. + * - ESPCONN_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. +*******************************************************************************/ +extern err_t espconn_udp_sendto(void* arg, uint8* psent, uint16 length); + +#endif /* __ESPCONN_UDP_H__ */ + + diff --git a/lib/libespconn.a b/lib/libespconn.a index 8a89f766..9c7bccb8 100644 Binary files a/lib/libespconn.a and b/lib/libespconn.a differ diff --git a/lib/libmain.a b/lib/libmain.a index 450f5052..d94a1589 100644 Binary files a/lib/libmain.a and b/lib/libmain.a differ diff --git a/third_party/espconn/Makefile b/third_party/espconn/Makefile new file mode 100755 index 00000000..c63bf19f --- /dev/null +++ b/third_party/espconn/Makefile @@ -0,0 +1,47 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = libespconn.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += +CCFLAGS += -ffunction-sections -fdata-sections + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/third_party/espconn/espconn.c b/third_party/espconn/espconn.c new file mode 100755 index 00000000..d9ec944b --- /dev/null +++ b/third_party/espconn/espconn.c @@ -0,0 +1,1606 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "netif/etharp.h" +#include "lwip/tcp.h" +#include "lwip/ip.h" +#include "lwip/init.h" +#include "lwip/mem.h" + +#include "esp_common.h" +#include "espconn/espconn_tcp.h" +#include "espconn/espconn_udp.h" +#include "espconn/espconn.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +espconn_msg* plink_active = NULL; +espconn_msg* pserver_list = NULL; +remot_info premot[linkMax]; + +struct espconn_packet pktinfo[2]; + +static uint8 espconn_tcp_get_buf_count(espconn_buf* pesp_buf); + +/****************************************************************************** + * FunctionName : espconn_copy_partial + * Description : reconnect with host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_copy_partial(struct espconn* pesp_dest, struct espconn* pesp_source) +{ + pesp_dest->type = pesp_source->type; + pesp_dest->state = pesp_source->state; + + if (pesp_source->type == ESPCONN_TCP) { + pesp_dest->proto.tcp->remote_port = pesp_source->proto.tcp->remote_port; + pesp_dest->proto.tcp->local_port = pesp_source->proto.tcp->local_port; + memcpy(pesp_dest->proto.tcp->remote_ip, pesp_source->proto.tcp->remote_ip, 4); + memcpy(pesp_dest->proto.tcp->local_ip, pesp_source->proto.tcp->local_ip, 4); + pesp_dest->proto.tcp->connect_callback = pesp_source->proto.tcp->connect_callback; + pesp_dest->proto.tcp->reconnect_callback = pesp_source->proto.tcp->reconnect_callback; + pesp_dest->proto.tcp->disconnect_callback = pesp_source->proto.tcp->disconnect_callback; + } else { + pesp_dest->proto.udp->remote_port = pesp_source->proto.udp->remote_port; + pesp_dest->proto.udp->local_port = pesp_source->proto.udp->local_port; + memcpy(pesp_dest->proto.udp->remote_ip, pesp_source->proto.udp->remote_ip, 4); + memcpy(pesp_dest->proto.udp->local_ip, pesp_source->proto.udp->local_ip, 4); + } + + pesp_dest->recv_callback = pesp_source->recv_callback; + pesp_dest->sent_callback = pesp_source->sent_callback; + pesp_dest->link_cnt = pesp_source->link_cnt; + pesp_dest->reverse = pesp_source->reverse; +} + +/****************************************************************************** + * FunctionName : espconn_copy_partial + * Description : insert the node to the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_list_creat(espconn_msg** phead, espconn_msg* pinsert) +{ + espconn_msg* plist = NULL; + +// espconn_msg *ptest = NULL; + if (*phead == NULL) { + *phead = pinsert; + } else { + plist = *phead; + + while (plist->pnext != NULL) { + plist = plist->pnext; + } + + plist->pnext = pinsert; + } + + pinsert->pnext = NULL; + + /* ptest = *phead; + while(ptest != NULL){ + os_printf("espconn_list_creat %p\n", ptest); + ptest = ptest->pnext; + }*/ +} + +/****************************************************************************** + * FunctionName : espconn_list_delete + * Description : remove the node from the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_list_delete(espconn_msg** phead, espconn_msg* pdelete) +{ + espconn_msg* plist = NULL; +// espconn_msg *ptest = NULL; + plist = *phead; + + if (plist == NULL) { + *phead = NULL; + } else { + if (plist == pdelete) { + *phead = plist->pnext; + } else { + while (plist != NULL) { + if (plist->pnext == pdelete) { + plist->pnext = pdelete->pnext; + } + + plist = plist->pnext; + } + } + } + + /* ptest = *phead; + while(ptest != NULL){ + os_printf("espconn_list_delete %p\n", ptest); + ptest = ptest->pnext; + }*/ +} + +/****************************************************************************** + * FunctionName : espconn_pbuf_create + * Description : insert the node to the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_pbuf_create(espconn_buf** phead, espconn_buf* pinsert) +{ + espconn_buf* plist = NULL; + + if (*phead == NULL) { + *phead = pinsert; + } else { + plist = *phead; + + while (plist->pnext != NULL) { + plist = plist->pnext; + } + + plist->pnext = pinsert; + } + + pinsert->pnext = NULL; +} + +/****************************************************************************** + * FunctionName : espconn_pbuf_delete + * Description : remove the node from the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_pbuf_delete(espconn_buf** phead, espconn_buf* pdelete) +{ + espconn_buf* plist = NULL; + + plist = *phead; + + if (plist == NULL) { + *phead = NULL; + } else { + if (plist == pdelete) { + *phead = plist->pnext; + } else { + while (plist != NULL) { + if (plist->pnext == pdelete) { + plist->pnext = pdelete->pnext; + } + + plist = plist->pnext; + } + } + } +} + +/****************************************************************************** + * FunctionName : espconn_find_connection + * Description : Initialize the server: set up a listening PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build server + * Returns : true or false + *******************************************************************************/ +bool ICACHE_FLASH_ATTR espconn_find_connection(struct espconn* pespconn, espconn_msg** pnode) +{ + espconn_msg* plist = NULL; + struct ip_addr ip_remot; + struct ip_addr ip_list; + + if (pespconn == NULL) { + return false; + } + + /*find the active connection node*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + if (pespconn == plist->pespconn) { + *pnode = plist; + return true; + } + } + + /*find the active server node*/ + for (plist = pserver_list; plist != NULL; plist = plist->pnext) { + if (pespconn == plist->pespconn) { + if (pespconn->proto.tcp == NULL) { + return false; + } + + IP4_ADDR(&ip_remot, pespconn->proto.tcp->remote_ip[0], + pespconn->proto.tcp->remote_ip[1], + pespconn->proto.tcp->remote_ip[2], + pespconn->proto.tcp->remote_ip[3]); + + if ((ip_remot.addr == IPADDR_ANY) || (pespconn->proto.tcp->remote_port == 0)) { + return false; + } + + /*find the active connection node*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + IP4_ADDR(&ip_list, plist->pcommon.remote_ip[0], + plist->pcommon.remote_ip[1], plist->pcommon.remote_ip[2], + plist->pcommon.remote_ip[3]); + + if ((ip_list.addr == ip_remot.addr) && (pespconn->proto.tcp->remote_port == plist->pcommon.remote_port)) { + *pnode = plist; + return true; + } + } + + return false; + } + } + + return false; +} + +/****************************************************************************** + * FunctionName : espconn_get_acticve_num + * Description : get the count of simulatenously active connections + * Parameters : type -- the type + * Returns : the count of simulatenously active connections + *******************************************************************************/ +static uint8 ICACHE_FLASH_ATTR +espconn_get_acticve_num(uint8 type) +{ + espconn_msg* plist = NULL; + uint8 num_tcp_active = 0; + + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + if (plist->pespconn != NULL && plist->pespconn->type == type) { + num_tcp_active++; + } + } + + return num_tcp_active; +} + +/****************************************************************************** + * FunctionName : espconn_connect + * Description : The function given as the connect + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_connect(struct espconn* espconn) +{ + struct ip_addr ipaddr; + struct ip_info ipinfo; + uint8 connect_status = 0; + sint8 value = ESPCONN_OK; + espconn_msg* plist = NULL; + remot_info* pinfo = NULL; + + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } else if (espconn ->type != ESPCONN_TCP) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*Check the active node count whether is the limit or not*/ + if (espconn_get_acticve_num(ESPCONN_TCP) >= espconn_tcp_get_max_con()) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ISCONN; + } + + /*Check the IP address whether is zero or not in different mode*/ + if (wifi_get_opmode() == ESPCONN_STA) { + wifi_get_ip_info(STA_NETIF, &ipinfo); + + if (ipinfo.ip.addr == 0) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_RTE; + } + } else if (wifi_get_opmode() == ESPCONN_AP) { + wifi_get_ip_info(AP_NETIF, &ipinfo); + + if (ipinfo.ip.addr == 0) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_RTE; + } + } else if (wifi_get_opmode() == ESPCONN_AP_STA) { + IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0], + espconn->proto.tcp->remote_ip[1], + espconn->proto.tcp->remote_ip[2], + espconn->proto.tcp->remote_ip[3]); + ipaddr.addr <<= 8; + wifi_get_ip_info(AP_NETIF, &ipinfo); + ipinfo.ip.addr <<= 8; + espconn_printf("softap_addr = %x, remote_addr = %x\n", ipinfo.ip.addr, ipaddr.addr); + + if (ipaddr.addr != ipinfo.ip.addr) { + connect_status = wifi_station_get_connect_status(); + + if (connect_status == STATION_GOT_IP) { + wifi_get_ip_info(STA_NETIF, &ipinfo); + + if (ipinfo.ip.addr == 0) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_RTE; + } + } else if (connect_status == STATION_IDLE) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_RTE; + } else { + ESPCONN_API_MUTEX_GIVE(); + return connect_status; + } + } + } + + /*check the active node information whether is the same as the entity or not*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + if (plist->pespconn && plist->pespconn->type == ESPCONN_TCP) { + if (espconn->proto.tcp->local_port == plist->pespconn->proto.tcp->local_port) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ISCONN; + } + } + } + + value = espconn_tcp_client(espconn); + ESPCONN_API_MUTEX_GIVE(); + return value; +} + +/****************************************************************************** + * FunctionName : espconn_create + * Description : sent data for client or server + * Parameters : espconn -- espconn to the data transmission + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_create(struct espconn* espconn) +{ + sint8 value = ESPCONN_OK; + espconn_msg* plist = NULL; + + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } else if (espconn ->type != ESPCONN_UDP) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*check the active node information whether is the same as the entity or not*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + if (plist->pespconn && plist->pespconn->type == ESPCONN_UDP) { + if (espconn->proto.udp->local_port == plist->pespconn->proto.udp->local_port) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ISCONN; + } + } + } + + value = espconn_udp_server(espconn); + ESPCONN_API_MUTEX_GIVE(); + return value; +} + +/****************************************************************************** + * FunctionName : espconn_sent + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_sent(struct espconn* espconn, uint8* psent, uint16 length) +{ + espconn_msg* pnode = NULL; + bool value = false; + err_t error = ESPCONN_OK; + + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL || psent == NULL || length == 0) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value) { + espconn ->state = ESPCONN_WRITE; + + switch (espconn ->type) { + case ESPCONN_TCP: + + /* calling sent function frequently,make sure last packet has been backup or sent fully*/ + if (pnode->pcommon.write_flag) { + espconn_buf* pbuf = NULL; + + /*If total number of espconn_buf on the unsent lists exceeds the set maximum, return an error */ + if (espconn_copy_enabled(pnode)) { + if (espconn_tcp_get_buf_count(pnode->pcommon.pbuf) >= pnode ->pcommon.pbuf_num) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_MAXNUM; + } + } else { + struct tcp_pcb* pcb = pnode->pcommon.pcb; + + if (pcb->snd_queuelen >= TCP_SND_QUEUELEN) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_MAXNUM; + } + } + + pbuf = (espconn_buf*) os_zalloc(sizeof(espconn_buf)); + + if (pbuf == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_MEM; + } else { + /*Backup the application packet information for send more data*/ + pbuf->payload = psent; + pbuf->punsent = pbuf->payload; + pbuf->unsent = length; + pbuf->len = length; + /*insert the espconn_pbuf to the list*/ + espconn_pbuf_create(&pnode->pcommon.pbuf, pbuf); + + if (pnode->pcommon.ptail == NULL) { + pnode->pcommon.ptail = pbuf; + } + } + + /*when set the data copy option. change the flag for next packet*/ + if (espconn_copy_disabled(pnode)) { + pnode->pcommon.write_flag = false; + } + + error = espconn_tcp_write(pnode); +// if (error != ESPCONN_OK){ +// /*send the application packet fail, +// * ensure that each allocated is deleted*/ +// espconn_pbuf_delete(&pnode->pcommon.pbuf, pbuf); +// os_free(pbuf); +// pbuf = NULL; +// } + ESPCONN_API_MUTEX_GIVE(); + return error; + } else { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + break; + + case ESPCONN_UDP: + error = espconn_udp_sent(pnode, psent, length); + ESPCONN_API_MUTEX_GIVE(); + return error; + break; + + default : + break; + } + } + + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; +} + +sint16 ICACHE_FLASH_ATTR espconn_recv(struct espconn* espconn, void* mem, size_t len) +{ + espconn_msg* pnode = NULL; + bool value = false; + int bytes_used = 0; + + if (espconn == NULL || mem == NULL || len == 0) { + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value && espconn->type == ESPCONN_TCP) { + if (pnode->readbuf != NULL) { + bytes_used = ringbuf_bytes_used(pnode->readbuf); + + if (bytes_used != 0) { + if (len > bytes_used) { + len = bytes_used; + } + + ringbuf_memcpy_from(mem, pnode->readbuf, len); + espconn_recv_unhold(pnode->pespconn); + return len; + } else { + return ESPCONN_OK; + } + } else { + return ESPCONN_OK; + } + } else { + return ESPCONN_ARG; + } + + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_sendto + * Description : send data for UDP + * Parameters : espconn -- espconn to set for UDP + * psent -- data to send + * length -- length of data to send + * Returns : error +*******************************************************************************/ +sint16 ICACHE_FLASH_ATTR +espconn_sendto(struct espconn* espconn, uint8* psent, uint16 length) +{ + espconn_msg* pnode = NULL; + bool value = false; + err_t error = ESPCONN_OK; + + if (espconn == NULL || psent == NULL || length == 0) { + return ESPCONN_ARG; + } + + ESPCONN_API_MUTEX_TAKE(); + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value && espconn->type == ESPCONN_UDP) { + error = espconn_udp_sendto(pnode, psent, length); + } else { + error = ESPCONN_ARG; + } + + ESPCONN_API_MUTEX_GIVE(); + + return error; +} + +/****************************************************************************** + * FunctionName : espconn_send + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +sint8 espconn_send(struct espconn* espconn, uint8* psent, uint16 length) __attribute__((alias("espconn_sent"))); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_wnd + * Description : get the window size of simulatenously active TCP connections + * Parameters : none + * Returns : the number of TCP_MSS active TCP connections +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR espconn_tcp_get_wnd(void) +{ + uint8 tcp_num = 0; + + tcp_num = (TCP_WND / TCP_MSS); + + return tcp_num; +} + +#if 0 +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the window size simulatenously active TCP connections + * Parameters : num -- the number of TCP_MSS + * Returns : ESPCONN_ARG -- Illegal argument + * ESPCONN_OK -- No error +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_wnd(uint8 num) +{ + if (num == 0 || num > linkMax) { + return ESPCONN_ARG; + } + + TCP_WND = (num * TCP_MSS); + return ESPCONN_OK; +} +#endif + +/****************************************************************************** + * FunctionName : espconn_tcp_get_mss + * Description : get the mss size of simulatenously active TCP connections + * Parameters : none + * Returns : the size of TCP_MSS active TCP connections +*******************************************************************************/ +uint16 ICACHE_FLASH_ATTR espconn_tcp_get_mss(void) +{ + uint16 tcp_num = 0; + + tcp_num = TCP_MSS; + + return tcp_num; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con + * Description : get the number of simulatenously active TCP connections + * Parameters : espconn -- espconn to set the connect callback + * Returns : none +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_con(void) +{ + uint8 tcp_num = 0; + + tcp_num = MEMP_NUM_TCP_PCB; + + return tcp_num; +} + +#if 0 +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the number of simulatenously active TCP connections + * Parameters : espconn -- espconn to set the connect callback + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_con(uint8 num) +{ + if (num == 0 || num > linkMax) { + return ESPCONN_ARG; + } + + MEMP_NUM_TCP_PCB = num; + return ESPCONN_OK; +} +#endif + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_retran + * Description : get the Maximum number of retransmissions of data active TCP connections + * Parameters : none + * Returns : the Maximum number of retransmissions +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_retran(void) +{ + uint8 tcp_num = 0; + + tcp_num = TCP_MAXRTX; + + return tcp_num; +} + +#if 0 +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_retran + * Description : set the Maximum number of retransmissions of data active TCP connections + * Parameters : num -- the Maximum number of retransmissions + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_retran(uint8 num) +{ + if (num == 0 || num > 12) { + return ESPCONN_ARG; + } + + TCP_MAXRTX = num; + return ESPCONN_OK; +} +#endif + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_syn + * Description : get the Maximum number of retransmissions of SYN segments + * Parameters : none + * Returns : the Maximum number of retransmissions +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_syn(void) +{ + uint8 tcp_num = 0; + + tcp_num = TCP_SYNMAXRTX; + + return tcp_num; +} + +#if 0 +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_syn + * Description : set the Maximum number of retransmissions of SYN segments + * Parameters : num -- the Maximum number of retransmissions + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_syn(uint8 num) +{ + if (num == 0 || num > 12) { + return ESPCONN_ARG; + } + + TCP_SYNMAXRTX = num; + return ESPCONN_OK; +} +#endif + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con_allow + * Description : get the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to get the count + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_con_allow(struct espconn* espconn) +{ + espconn_msg* pget_msg = NULL; + sint8 count_opt = -1; + ESPCONN_API_MUTEX_TAKE(); + + if ((espconn == NULL) || (espconn->type == ESPCONN_UDP)) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + pget_msg = pserver_list; + + while (pget_msg != NULL) { + if (pget_msg->pespconn == espconn) { + count_opt = pget_msg->count_opt; + ESPCONN_API_MUTEX_GIVE(); + return count_opt; + } + + pget_msg = pget_msg->pnext; + } + + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con_allow + * Description : set the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to set the count + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_con_allow(struct espconn* espconn, uint8 num) +{ + espconn_msg* pset_msg = NULL; + ESPCONN_API_MUTEX_TAKE(); + + if ((espconn == NULL) || (num > MEMP_NUM_TCP_PCB) || (espconn->type == ESPCONN_UDP)) { + ESPCONN_API_MUTEX_GIVE(); + } + + return ESPCONN_ARG; + + pset_msg = pserver_list; + + while (pset_msg != NULL) { + if (pset_msg->pespconn == espconn) { + pset_msg->count_opt = num; + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; + } + + pset_msg = pset_msg->pnext; + } + + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_set_buf_count + * Description : set the total number of espconn_buf on the unsent lists for one + * activate connection + * Parameters : espconn -- espconn to set the count + * num -- the total number of espconn_buf + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_buf_count(struct espconn* espconn, uint8 num) +{ + espconn_msg* plist = NULL; + + if (espconn == NULL || (num > TCP_SND_QUEUELEN)) { + return ESPCONN_ARG; + } + + ESPCONN_API_MUTEX_TAKE(); + + /*find the node from the active connection list*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + if (plist->pespconn && plist->pespconn == espconn && espconn->type == ESPCONN_TCP) { + plist->pcommon.pbuf_num = num; + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; + } + } + + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_get_buf_count + * Description : get the count of the current node which has espconn_buf + * Parameters : pesp_buf -- the list head of espconn_buf type + * Returns : the count of the current node which has espconn_buf +*******************************************************************************/ +static uint8 ICACHE_FLASH_ATTR espconn_tcp_get_buf_count(espconn_buf* pesp_buf) +{ + espconn_buf* pbuf_list = NULL; + uint8 pbuf_num = 0; + + ESPCONN_API_MUTEX_TAKE(); + pbuf_list = pesp_buf; + + /*polling the list get the count of the current node*/ + while (pbuf_list != NULL) { + pbuf_list = pbuf_list->pnext; + pbuf_num ++; + } + + ESPCONN_API_MUTEX_GIVE(); + return pbuf_num; +} + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : espconn -- espconn to set the sent callback + * sent_cb -- sent callback function to call for this espconn + * when data is successfully sent + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_sentcb(struct espconn* espconn, espconn_sent_callback sent_cb) +{ + if (espconn == NULL) { + return ESPCONN_ARG; + } + + espconn ->sent_callback = sent_cb; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : espconn -- espconn to set the sent callback + * sent_cb -- sent callback function to call for this espconn + * when data is successfully sent + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_write_finish(struct espconn* espconn, espconn_connect_callback write_finish_fn) +{ + if (espconn == NULL || espconn ->proto.tcp == NULL || espconn->type == ESPCONN_UDP) { + return ESPCONN_ARG; + } + + espconn ->proto.tcp->write_finish_fn = write_finish_fn; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_regist_connectcb + * Description : used to specify the function that should be called when + * connects to host. + * Parameters : espconn -- espconn to set the connect callback + * connect_cb -- connected callback function to call when connected + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_connectcb(struct espconn* espconn, espconn_connect_callback connect_cb) +{ + if (espconn == NULL) { + return ESPCONN_ARG; + } + + espconn->proto.tcp->connect_callback = connect_cb; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_regist_recvcb + * Description : used to specify the function that should be called when recv + * data from host. + * Parameters : espconn -- espconn to set the recv callback + * recv_cb -- recv callback function to call when recv data + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_recvcb(struct espconn* espconn, espconn_recv_callback recv_cb) +{ + if (espconn == NULL) { + return ESPCONN_ARG; + } + + espconn ->recv_callback = recv_cb; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_regist_reconcb + * Description : used to specify the function that should be called when connection + * because of err disconnect. + * Parameters : espconn -- espconn to set the err callback + * recon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_reconcb(struct espconn* espconn, espconn_reconnect_callback recon_cb) +{ + if (espconn == NULL) { + return ESPCONN_ARG; + } + + espconn ->proto.tcp->reconnect_callback = recon_cb; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_regist_disconcb + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_disconcb(struct espconn* espconn, espconn_connect_callback discon_cb) +{ + if (espconn == NULL) { + return ESPCONN_ARG; + } + + espconn ->proto.tcp->disconnect_callback = discon_cb; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_get_connection_info + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_get_connection_info(struct espconn* pespconn, remot_info** pcon_info, uint8 typeflags) +{ + espconn_msg* plist = NULL; + + if (pespconn == NULL) { + return ESPCONN_ARG; + } + + ESPCONN_API_MUTEX_TAKE(); + memset(premot, 0, sizeof(premot)); + pespconn->link_cnt = 0; + plist = plink_active; + + switch (pespconn->type) { + case ESPCONN_TCP: + while (plist != NULL) { + if (plist->preverse == pespconn) { + premot[pespconn->link_cnt].state = plist->pespconn->state; + premot[pespconn->link_cnt].remote_port = plist->pcommon.remote_port; + memcpy(premot[pespconn->link_cnt].remote_ip, plist->pcommon.remote_ip, 4); + pespconn->link_cnt ++; + } + + plist = plist->pnext; + } + + break; + + case ESPCONN_UDP: + while (plist != NULL) { + if (plist->pespconn == pespconn) { + premot[pespconn->link_cnt].state = plist->pespconn->state; + premot[pespconn->link_cnt].remote_port = plist->pcommon.remote_port; + memcpy(premot[pespconn->link_cnt].remote_ip, plist->pcommon.remote_ip, 4); + pespconn->link_cnt ++; + } + + plist = plist->pnext; + } + + break; + + default: + break; + } + + *pcon_info = premot; + + if (pespconn->link_cnt == 0) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_accept + * Description : The function given as the listen + * Parameters : espconn -- the espconn used to listen the connection + * Returns : +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_accept(struct espconn* espconn) +{ + sint8 value = ESPCONN_OK; + espconn_msg* plist = NULL; + + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } else if (espconn ->type != ESPCONN_TCP) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*check the active node information whether is the same as the entity or not*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + if (plist->pespconn && plist->pespconn->type == ESPCONN_TCP) { + if (espconn->proto.tcp->local_port == plist->pespconn->proto.tcp->local_port) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ISCONN; + } + } + } + + value = espconn_tcp_server(espconn); + ESPCONN_API_MUTEX_GIVE(); + return value; +} + +/****************************************************************************** + * FunctionName : espconn_regist_time + * Description : used to specify the time that should be called when don't recv data + * Parameters : espconn -- the espconn used to the connection + * interval -- the timer when don't recv data + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_regist_time(struct espconn* espconn, uint32 interval, uint8 type_flag) +{ + espconn_msg* pnode = NULL; + espconn_msg* ptime_msg = NULL; + bool value = false; + + if ((espconn == NULL) || (type_flag > 0x01)) { + return ESPCONN_ARG; + } + + ESPCONN_API_MUTEX_TAKE(); + + if (type_flag == 0x01) { + /*set the timeout time for one active connection of the server*/ + value = espconn_find_connection(espconn, &pnode); + + if (value) { + pnode->pcommon.timeout = interval; + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; + } else { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + } else { + /*set the timeout time for all active connection of the server*/ + ptime_msg = pserver_list; + + while (ptime_msg != NULL) { + if (ptime_msg->pespconn == espconn) { + ptime_msg->pcommon.timeout = interval; + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; + } + + ptime_msg = ptime_msg->pnext; + } + } + + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_disconnect + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_disconnect(struct espconn* espconn) +{ + espconn_msg* pnode = NULL; + bool value = false; + + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG;; + } else if (espconn ->type != ESPCONN_TCP) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value) { + /*protect for redisconnection*/ + if (pnode->preverse == NULL && espconn->state == ESPCONN_CLOSE) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_INPROGRESS; + } + + espconn_tcp_disconnect(pnode, 0);//1 force, 0 normal + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; + } else { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } +} + +/****************************************************************************** + * FunctionName : espconn_abort + * Description : Forcely abort with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_abort(struct espconn* espconn) +{ + espconn_msg* pnode = NULL; + bool value = false; + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG;; + } else if (espconn ->type != ESPCONN_TCP) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value) { + /*protect for redisconnection*/ + if (pnode->preverse == NULL && espconn->state == ESPCONN_CLOSE) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_INPROGRESS; + } + + espconn_tcp_disconnect(pnode, 1); //1 force, 0 normal + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; + } + + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; +} +/****************************************************************************** + * FunctionName : espconn_get_packet_info + * Description : get the packet info with host + * Parameters : espconn -- the espconn used to disconnect the connection + * infoarg -- the packet info + * Returns : the errur code +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_get_packet_info(struct espconn* espconn, struct espconn_packet* infoarg) +{ + espconn_msg* pnode = NULL; + err_t err; + bool value = false; + + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL || infoarg == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG;; + } else if (espconn->type != ESPCONN_TCP) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value) { + struct tcp_pcb* pcb = pnode->pcommon.pcb; + + if (pcb == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + pnode->pcommon.packet_info.packseq_nxt = pcb->rcv_nxt; + pnode->pcommon.packet_info.packseqno = pcb->snd_nxt; + pnode->pcommon.packet_info.snd_buf_size = pcb->snd_buf; + pnode->pcommon.packet_info.total_queuelen = TCP_SND_QUEUELEN; + pnode->pcommon.packet_info.snd_queuelen = pnode->pcommon.packet_info.total_queuelen - pcb->snd_queuelen; + memcpy(infoarg, (void*)&pnode->pcommon.packet_info, sizeof(struct espconn_packet)); + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; + } else { + switch (espconn->state) { + case ESPCONN_CLOSE: + memcpy(infoarg, (void*)&pktinfo[0], sizeof(struct espconn_packet)); + err = ESPCONN_OK; + break; + + case ESPCONN_NONE: + memcpy(infoarg, (void*)&pktinfo[1], sizeof(struct espconn_packet)); + err = ESPCONN_OK; + break; + + default: + err = ESPCONN_ARG; + break; + } + + ESPCONN_API_MUTEX_GIVE(); + return err; + } +} + +/****************************************************************************** + * FunctionName : espconn_set_opt + * Description : set the option for connections so that we don't end up bouncing + * all connections at the same time . + * Parameters : espconn -- the espconn used to set the connection + * opt -- the option for set + * Returns : the result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_set_opt(struct espconn* espconn, uint8 opt) +{ + espconn_msg* pnode = NULL; + struct tcp_pcb* tpcb; + bool value = false; + + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG;; + } else if (espconn->type != ESPCONN_TCP) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value) { + pnode->pcommon.espconn_opt |= opt; + tpcb = pnode->pcommon.pcb; + + if (espconn_delay_disabled(pnode)) { + tcp_nagle_disable(tpcb); + } + + if (espconn_keepalive_disabled(pnode)) { + espconn_keepalive_enable(tpcb); + } + + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; + } else { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } +} + +/****************************************************************************** + * FunctionName : espconn_clear_opt + * Description : clear the option for connections so that we don't end up bouncing + * all connections at the same time . + * Parameters : espconn -- the espconn used to set the connection + * opt -- the option for clear + * Returns : the result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_clear_opt(struct espconn* espconn, uint8 opt) +{ + espconn_msg* pnode = NULL; + struct tcp_pcb* tpcb; + bool value = false; + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG;; + } else if (espconn->type != ESPCONN_TCP) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value) { + pnode->pcommon.espconn_opt &= ~opt; + tpcb = pnode->pcommon.pcb; + + if (espconn_keepalive_enabled(pnode)) { + espconn_keepalive_disable(tpcb); + } + + if (espconn_delay_enabled(pnode)) { + tcp_nagle_enable(tpcb); + } + + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; + } else { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } +} + +/****************************************************************************** + * FunctionName : espconn_set_keepalive + * Description : access level value for connection so that we set the value for + * keep alive + * Parameters : espconn -- the espconn used to set the connection + * level -- the connection's level + * value -- the value of time(s) + * Returns : access port value +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_set_keepalive(struct espconn* espconn, uint8 level, void* optarg) +{ + espconn_msg* pnode = NULL; + bool value = false; + sint8 ret = ESPCONN_OK; + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL || optarg == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG;; + } else if (espconn->type != ESPCONN_TCP) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value && espconn_keepalive_disabled(pnode)) { + struct tcp_pcb* pcb = pnode->pcommon.pcb; + + switch (level) { + case ESPCONN_KEEPIDLE: + pcb->keep_idle = 1000 * (u32_t)(*(int*)optarg); + ret = ESPCONN_OK; + break; + + case ESPCONN_KEEPINTVL: + pcb->keep_intvl = 1000 * (u32_t)(*(int*)optarg); + ret = ESPCONN_OK; + break; + + case ESPCONN_KEEPCNT: + pcb->keep_cnt = (u32_t)(*(int*)optarg); + ret = ESPCONN_OK; + break; + + default: + ret = ESPCONN_ARG; + break; + } + + ESPCONN_API_MUTEX_GIVE(); + return ret; + } else { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } +} + +/****************************************************************************** + * FunctionName : espconn_get_keepalive + * Description : access level value for connection so that we get the value for + * keep alive + * Parameters : espconn -- the espconn used to get the connection + * level -- the connection's level + * Returns : access keep alive value +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_get_keepalive(struct espconn* espconn, uint8 level, void* optarg) +{ + espconn_msg* pnode = NULL; + bool value = false; + sint8 ret = ESPCONN_OK; + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL || optarg == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG;; + } else if (espconn->type != ESPCONN_TCP) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value && espconn_keepalive_disabled(pnode)) { + struct tcp_pcb* pcb = pnode->pcommon.pcb; + + switch (level) { + case ESPCONN_KEEPIDLE: + *(int*)optarg = (int)(pcb->keep_idle / 1000); + ret = ESPCONN_OK; + break; + + case ESPCONN_KEEPINTVL: + *(int*)optarg = (int)(pcb->keep_intvl / 1000); + ret = ESPCONN_OK; + break; + + case ESPCONN_KEEPCNT: + *(int*)optarg = (int)(pcb->keep_cnt); + ret = ESPCONN_OK; + break; + + default: + ret = ESPCONN_ARG; + break; + } + + ESPCONN_API_MUTEX_GIVE(); + return ret; + } else { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } +} + +/****************************************************************************** + * FunctionName : espconn_delete + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_delete(struct espconn* espconn) +{ + espconn_msg* pnode = NULL; + bool value = false; + ESPCONN_API_MUTEX_TAKE(); + + if (espconn == NULL) { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } else if (espconn ->type != ESPCONN_UDP) { + ESPCONN_API_MUTEX_GIVE(); + return espconn_tcp_delete(espconn); + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value) { + espconn_udp_disconnect(pnode); + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_OK; + } else { + ESPCONN_API_MUTEX_GIVE(); + return ESPCONN_ARG; + } +} + +/****************************************************************************** + * FunctionName : espconn_port + * Description : access port value for client so that we don't end up bouncing + * all connections at the same time . + * Parameters : none + * Returns : access port value +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +espconn_port(void) +{ + uint32 port = 0; + static uint32 randnum = 0; + ESPCONN_API_MUTEX_TAKE(); + + do { + port = os_random(); + + if (port < 0) { + port = os_random() - port; + } + + port %= 0xc350; + + if (port < 0x400) { + port += 0x400; + } + + } while (port == randnum); + + randnum = port; + ESPCONN_API_MUTEX_GIVE(); + return port; +} + +/****************************************************************************** + * FunctionName : espconn_gethostbyname + * Description : Resolve a hostname (string) into an IP address. + * Parameters : pespconn -- espconn to resolve a hostname + * hostname -- the hostname that is to be queried + * addr -- pointer to a ip_addr_t where to store the address if + * it is already cached in the dns_table (only valid if + * ESPCONN_OK is returned!) + * found -- a callback function to be called on success, failure + * or timeout (only if ERR_INPROGRESS is returned!) + * Returns : err_t return code + * - ESPCONN_OK if hostname is a valid IP address string or the host + * name is already in the local names table. + * - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server + * for resolution if no errors are present. + * - ESPCONN_ARG: dns client not initialized or invalid hostname +*******************************************************************************/ +err_t ICACHE_FLASH_ATTR +espconn_gethostbyname(struct espconn* pespconn, const char* hostname, ip_addr_t* addr, dns_found_callback found) +{ + err_t err = ERR_OK; + ESPCONN_API_MUTEX_TAKE(); + err = dns_gethostbyname(hostname, addr, found, pespconn); + ESPCONN_API_MUTEX_GIVE(); + return err; +} + +/****************************************************************************** + * FunctionName : espconn_dns_setserver + * Description : Initialize one of the DNS servers. + * Parameters : numdns -- the index of the DNS server to set must + * be < DNS_MAX_SERVERS = 2 + * dnsserver -- IP address of the DNS server to set + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_dns_setserver(u8_t numdns, ip_addr_t* dnsserver) +{ + ESPCONN_API_MUTEX_TAKE(); + dns_setserver(numdns, dnsserver); + ESPCONN_API_MUTEX_GIVE(); +} + diff --git a/third_party/espconn/espconn_buf.c b/third_party/espconn/espconn_buf.c new file mode 100755 index 00000000..9633edf5 --- /dev/null +++ b/third_party/espconn/espconn_buf.c @@ -0,0 +1,229 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include + +#include "lwip/def.h" +#include "esp_libc.h" + +#include "espconn/espconn_buf.h" + +#if (!defined(lwIP_unlikely)) +#define lwIP_unlikely(Expression) !!(Expression) +#endif + +#define lwIP_ASSERT(Expression) do{if(!(Expression)) {os_printf("%s %d\n", __func__, __LINE__);return;}}while(0) + +ringbuf_t ringbuf_new(size_t capacity) +{ + ringbuf_t rb = (ringbuf_t)os_zalloc(sizeof(struct ringbuf_t)); + + if (rb) { + rb->size = capacity + 1; + rb->buf = (uint8*)os_zalloc(rb->size); + + if (rb->buf) { + ringbuf_reset(rb); + } else { + os_free(rb); + return NULL; + } + } + + return rb; +} + +size_t ringbuf_buffer_size(const struct ringbuf_t* rb) +{ + return rb->size; +} + +void ringbuf_reset(ringbuf_t rb) +{ + rb ->head = rb->tail = rb->buf; +} + +void ringbuf_free(ringbuf_t* rb) +{ + lwIP_ASSERT(rb && *rb); + os_free((*rb)->buf); + os_free(*rb); + *rb = NULL; +} + +size_t ringbuf_capacity(const struct ringbuf_t* rb) +{ + return ringbuf_buffer_size(rb) - 1; +} + +static const uint8_t* ringbuf_end(const struct ringbuf_t* rb) +{ + return rb->buf + ringbuf_buffer_size(rb); +} + +size_t ringbuf_bytes_free(const struct ringbuf_t* rb) +{ + if (rb->head >= rb->tail) { + return ringbuf_capacity(rb) - (rb->head - rb->tail); + } else { + return rb->tail - rb->head - 1; + } +} + +size_t ringbuf_bytes_used(const struct ringbuf_t* rb) +{ + return ringbuf_capacity(rb) - ringbuf_bytes_free(rb); +} + +int ringbuf_is_full(const struct ringbuf_t* rb) +{ + return ringbuf_bytes_free(rb) == 0; +} + +int ringbuf_is_empty(const struct ringbuf_t* rb) +{ + return ringbuf_bytes_free(rb) == ringbuf_capacity(rb); +} + +const void* ringbuf_tail(const struct ringbuf_t* rb) +{ + return rb->tail; +} +const void* ringbuf_head(const struct ringbuf_t* rb) +{ + return rb->head; +} + +static uint8_t* ringbuf_nextp(ringbuf_t rb, const uint8_t* p) +{ + lwIP_ASSERT((p >= rb->buf) && (p < ringbuf_end(rb))); + return rb->buf + ((++p - rb->buf) % ringbuf_buffer_size(rb)); +} + +size_t ringbuf_findchr(const struct ringbuf_t* rb, int c, size_t offset) +{ + const uint8_t* bufend = ringbuf_end(rb); + size_t bytes_used = ringbuf_bytes_used(rb); + + if (offset >= bytes_used) { + return bytes_used; + } + + const uint8_t* start = rb ->buf + (((rb->tail - rb->buf) + offset) % ringbuf_buffer_size(rb)); + lwIP_ASSERT(bufend > start); + size_t n = LWIP_MIN(bufend - start, bytes_used - offset); + const uint8_t* found = (const uint8_t*)memchr(start, c, n); + + if (found) { + return offset + (found - start); + } else { + return ringbuf_findchr(rb, c, offset + n); + } +} + +size_t ringbuf_memset(ringbuf_t dst, int c, size_t len) +{ + const uint8_t* bufend = ringbuf_end(dst); + size_t nwritten = 0; + size_t count = LWIP_MIN(len, ringbuf_buffer_size(dst)); + int overflow = count > ringbuf_bytes_free(dst); + + while (nwritten != count) { + + lwIP_ASSERT(bufend > dst->head); + size_t n = LWIP_MIN(bufend - dst->head, count - nwritten); + os_memset(dst->head, c, n); + dst->head += n; + nwritten += n; + + if (dst->head == bufend) { + dst->head = dst->buf; + } + } + + if (overflow) { + dst->tail = ringbuf_nextp(dst, dst->head); + lwIP_ASSERT(ringbuf_is_full(dst)); + } + + return nwritten; +} + +void* ringbuf_memcpy_into(ringbuf_t dst, const void* src, size_t count) +{ + const uint8_t* u8src = src; + const uint8_t* bufend = ringbuf_end(dst); + int overflow = count > ringbuf_bytes_free(dst); + size_t nread = 0; + + while (nread != count) { + lwIP_ASSERT(bufend > dst->head); + size_t n = LWIP_MIN(bufend - dst->head, count - nread); + memcpy(dst->head, u8src + nread, n); + dst->head += n; + nread += n; + + if (dst->head == bufend) { + dst->head = dst->buf; + } + } + + if (overflow) { + dst->tail = ringbuf_nextp(dst, dst->head); + lwIP_ASSERT(ringbuf_is_full(dst)); + } + + return dst->head; +} + +void* ringbuf_memcpy_from(void* dst, ringbuf_t src, size_t count) +{ + size_t bytes_used = ringbuf_bytes_used(src); + + if (count > bytes_used) { + return NULL; + } + + const uint8_t* u8dst = dst; + const uint8_t* bufend = ringbuf_end(src); + size_t nwritten = 0; + + while (nwritten != count) { + lwIP_ASSERT(bufend > src->tail); + size_t n = LWIP_MIN(bufend - src->tail, count - nwritten); + memcpy((uint8_t*)u8dst + nwritten, src->tail, n); + src->tail += n; + nwritten += n; + + if (src->tail == bufend) { + src->tail = src->buf; + } + } + + lwIP_ASSERT(count + ringbuf_bytes_used(src) == bytes_used); + return src->tail; +} + + + diff --git a/third_party/espconn/espconn_tcp.c b/third_party/espconn/espconn_tcp.c new file mode 100755 index 00000000..09776d3e --- /dev/null +++ b/third_party/espconn/espconn_tcp.c @@ -0,0 +1,1816 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "netif/etharp.h" +#include "lwip/tcp.h" +#include "lwip/ip.h" +#include "lwip/init.h" +#include "lwip/tcp_impl.h" +#include "lwip/memp.h" +#include "lwip/mem.h" +#include "esp_common.h" +#include "espconn/espconn_tcp.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +extern espconn_msg* plink_active; +extern espconn_msg* pserver_list; +extern struct espconn_packet pktinfo[2]; +extern struct tcp_pcb** const tcp_pcb_lists[]; + +#if !NO_SYS +static void os_post(uint8 prio, uint32 type, uint32 arg); +#else +os_event_t espconn_TaskQueue[espconn_TaskQueueLen]; +#endif + +static err_t +espconn_client_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err); +static void +espconn_client_close(void* arg, struct tcp_pcb* pcb, u8 type); + +static err_t +espconn_server_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err); +static void +espconn_server_close(void* arg, struct tcp_pcb* pcb, u8 type); + +///////////////////////////////common function///////////////////////////////// +/****************************************************************************** + * FunctionName : espconn_kill_oldest + * Description : kill the oldest TCP block + * Parameters : none + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_kill_oldest(void) +{ + struct tcp_pcb* pcb, *inactive; + u32_t inactivity; + + inactivity = 0; + inactive = NULL; + + /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + + if (inactive != NULL) { + tcp_abort(inactive); + } + + /* Go through the list of FIN_WAIT_2 pcbs and get the oldest pcb. */ + inactivity = 0; + inactive = NULL; + + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->state == FIN_WAIT_1 || pcb->state == FIN_WAIT_2) { + if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + } + + /*Purges the PCB, removes it from a PCB list and frees the memory*/ + if (inactive != NULL) { + tcp_pcb_remove(&tcp_active_pcbs, inactive); + memp_free(MEMP_TCP_PCB, inactive); + } + + /* Go through the list of LAST_ACK pcbs and get the oldest pcb. */ + inactivity = 0; + inactive = NULL; + + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->state == LAST_ACK) { + if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + } + + /*Purges the PCB, removes it from a PCB list and frees the memory*/ + if (inactive != NULL) { + tcp_pcb_remove(&tcp_active_pcbs, inactive); + memp_free(MEMP_TCP_PCB, inactive); + } +} + +/****************************************************************************** + * FunctionName : espconn_kill_oldest_pcb + * Description : find the oldest TCP block by state + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_kill_oldest_pcb(void) +{ + struct tcp_pcb* cpcb = NULL; + uint8 i = 0; + uint8 num_tcp_fin = 0; + + for (i = 2; i < 4; i ++) { + for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { + if (cpcb->state == TIME_WAIT) { + num_tcp_fin ++; + + if (num_tcp_fin == MEMP_NUM_TCP_PCB) { + break; + } + } + + if (cpcb->state == FIN_WAIT_1 || cpcb->state == FIN_WAIT_2 || cpcb->state == LAST_ACK) { + num_tcp_fin++; + + if (num_tcp_fin == MEMP_NUM_TCP_PCB) { + break; + } + } + } + + if (num_tcp_fin == MEMP_NUM_TCP_PCB) { + num_tcp_fin = 0; + espconn_kill_oldest(); + } else if (cpcb == NULL) { + num_tcp_fin = 0; + } + } +} + +/****************************************************************************** + * FunctionName : espconn_kill_pcb + * Description : kill all the TCP block by port + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_kill_pcb(u16_t port) +{ + struct tcp_pcb* cpcb = NULL; + uint8 i = 0; + struct tcp_pcb* inactive = NULL; + struct tcp_pcb* prev = NULL; + u8_t pcb_remove; + + /* Check if the address already is in use (on all lists) */ + for (i = 1; i < 4; i++) { + cpcb = *tcp_pcb_lists[i]; + + while (cpcb != NULL) { + pcb_remove = 0; + + if (cpcb->local_port == port) { + ++pcb_remove; + } + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + /* Remove PCB from tcp_pcb_lists list. */ + inactive = cpcb; + cpcb = inactive->next; + tcp_pcb_remove(tcp_pcb_lists[i], inactive); + memp_free(MEMP_TCP_PCB, inactive); + } else { + cpcb = cpcb->next; + } + } + } +} + +/****************************************************************************** + * FunctionName : espconn_find_current_pcb + * Description : find the TCP block which option + * Parameters : pcurrent_msg -- the node in the list which active + * Returns : TCP block point +*******************************************************************************/ +struct tcp_pcb* ICACHE_FLASH_ATTR espconn_find_current_pcb(espconn_msg* pcurrent_msg) +{ + uint16 local_port = pcurrent_msg->pcommon.local_port; + uint32 local_ip = pcurrent_msg->pcommon.local_ip; + uint16 remote_port = pcurrent_msg->pcommon.remote_port; + uint32 remote_ip = *((uint32*)&pcurrent_msg->pcommon.remote_ip); + struct tcp_pcb* find_pcb = NULL; + + if (pcurrent_msg ->preverse == NULL) { /*Find the server's TCP block*/ + if (local_ip == 0 || local_port == 0) { + return pcurrent_msg->pcommon.pcb; + } + + for (find_pcb = tcp_active_pcbs; find_pcb != NULL; find_pcb = find_pcb->next) { + if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.ip4.addr == remote_ip) && + (find_pcb->local_port == local_port) && (find_pcb->local_ip.ip4.addr == local_ip)) { + return find_pcb; + } + } + + for (find_pcb = tcp_tw_pcbs; find_pcb != NULL; find_pcb = find_pcb->next) { + if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.ip4.addr == remote_ip) && + (find_pcb->local_port == local_port) && (find_pcb->local_ip.ip4.addr == local_ip)) { + return find_pcb; + } + } + } else {/*Find the client's TCP block*/ + if (remote_ip == 0 || remote_port == 0) { + return pcurrent_msg->pcommon.pcb; + } + + for (find_pcb = tcp_active_pcbs; find_pcb != NULL; find_pcb = find_pcb->next) { + if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.ip4.addr == remote_ip)) { + return find_pcb; + } + } + + for (find_pcb = tcp_tw_pcbs; find_pcb != NULL; find_pcb = find_pcb->next) { + if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.ip4.addr == remote_ip)) { + return find_pcb; + } + } + } + + return NULL; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_memp_free + * Description : frees the connection memory in the server mode + * Parameters : arg -- Additional argument to pass to the function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_tcp_memp_free(espconn_msg* pmemp) +{ + struct espconn* espconn = NULL; + + if (pmemp == NULL) { + return; + } + + if (pmemp->espconn_mode == ESPCONN_TCPSERVER_MODE) { + if (pmemp->pespconn != NULL && pmemp->pespconn->proto.tcp != NULL) { + os_free(pmemp->pespconn->proto.tcp); + } + + pmemp->pespconn->proto.tcp = NULL; + + os_free(pmemp->pespconn); + pmemp->pespconn = NULL; + } + + if (pmemp->readbuf != NULL) { + ringbuf_free(&pmemp->readbuf); + } + + os_free(pmemp); + pmemp = NULL; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_reconnect + * Description : reconnect with host,MUST be only used in espconn_thread + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_tcp_reconnect(void* arg) +{ + espconn_msg* precon_cb = arg; + sint8 re_err = 0; + espconn_buf* perr_buf = NULL; + espconn_buf* perr_back = NULL; + espconn_kill_oldest_pcb(); + + if (precon_cb != NULL) { + struct espconn* espconn = precon_cb->preverse; + + re_err = precon_cb->pcommon.err; + + if (precon_cb->pespconn != NULL) { + if (espconn != NULL) { /*Process the server's message block*/ + if (precon_cb->pespconn->proto.tcp != NULL) { + espconn_copy_partial(espconn, precon_cb->pespconn); + } + } else {/*Process the client's message block*/ + espconn = precon_cb->pespconn; + } + } + + /*to prevent memory leaks, ensure that each allocated is deleted*/ + perr_buf = precon_cb->pcommon.pbuf; + + while (perr_buf != NULL) { + perr_back = perr_buf; + perr_buf = perr_back->pnext; + espconn_pbuf_delete(&precon_cb->pcommon.pbuf, perr_back); + os_free(perr_back); + perr_back = NULL; + } + + bzero(&pktinfo[1], sizeof(struct espconn_packet)); + memcpy(&pktinfo[1], (void*)&precon_cb->pcommon.packet_info, sizeof(struct espconn_packet)); + + if (espconn && espconn->proto.tcp && espconn->proto.tcp->reconnect_callback != NULL) { + espconn_reconnect_callback reconnect_callback = espconn->proto.tcp->reconnect_callback; + ESPCONN_API_MUTEX_GIVE(); + reconnect_callback(espconn, re_err); + ESPCONN_API_MUTEX_TAKE(); + } + + /*frees the connection memory*/ + espconn_tcp_memp_free(precon_cb); + } else { + espconn_printf("espconn_tcp_reconnect err\n"); + } +} + +/****************************************************************************** + * FunctionName : espconn_tcp_disconnect + * Description : disconnect with host,MUST be only used in espconn_thread + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_tcp_disconnect_successful(void* arg) +{ + espconn_msg* pdiscon_cb = arg; + sint8 dis_err = 0; + espconn_buf* pdis_buf = NULL; + espconn_buf* pdis_back = NULL; + espconn_kill_oldest_pcb(); + + if (pdiscon_cb != NULL) { + struct espconn* espconn = pdiscon_cb->preverse; + + dis_err = pdiscon_cb->pcommon.err; + + if (pdiscon_cb->pespconn != NULL) { + struct tcp_pcb* pcb = NULL; + + if (espconn != NULL) { /*Process the server's message block*/ + if (pdiscon_cb->pespconn->proto.tcp != NULL && espconn->proto.tcp) { + espconn_copy_partial(espconn, pdiscon_cb->pespconn); + } + } else {/*Process the client's message block*/ + espconn = pdiscon_cb->pespconn; + } + + /*process the current TCP block*/ + pcb = espconn_find_current_pcb(pdiscon_cb); + + if (pcb != NULL) { + if (espconn_reuse_disabled(pdiscon_cb)) { + struct tcp_pcb* cpcb = NULL; + struct tcp_pcb* prev = NULL; + u8_t pcb_remove; + espconn_printf("espconn_tcp_disconnect_successful %d, %d\n", pcb->state, pcb->local_port); + cpcb = tcp_tw_pcbs; + + while (cpcb != NULL) { + pcb_remove = 0; + + if (cpcb->local_port == pcb->local_port) { + ++pcb_remove; + } + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + struct tcp_pcb* backup_pcb = NULL; + tcp_pcb_purge(cpcb); + + /* Remove PCB from tcp_tw_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("espconn_tcp_delete: middle cpcb != tcp_tw_pcbs", cpcb != tcp_tw_pcbs); + prev->next = cpcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("espconn_tcp_delete: first cpcb == tcp_tw_pcbs", tcp_tw_pcbs == cpcb); + tcp_tw_pcbs = cpcb->next; + } + + backup_pcb = cpcb; + cpcb = cpcb->next; + memp_free(MEMP_TCP_PCB, backup_pcb); + } else { + prev = cpcb; + cpcb = cpcb->next; + } + } + + } else { + tcp_arg(pcb, NULL); + tcp_err(pcb, NULL); + } + } + } + + /*to prevent memory leaks, ensure that each allocated is deleted*/ + pdis_buf = pdiscon_cb->pcommon.pbuf; + + while (pdis_buf != NULL) { + pdis_back = pdis_buf; + pdis_buf = pdis_back->pnext; + espconn_pbuf_delete(&pdiscon_cb->pcommon.pbuf, pdis_back); + os_free(pdis_back); + pdis_back = NULL; + } + + bzero(&pktinfo[0], sizeof(struct espconn_packet)); + memcpy(&pktinfo[0], (void*)&pdiscon_cb->pcommon.packet_info, sizeof(struct espconn_packet)); + + if (espconn->proto.tcp && espconn->proto.tcp->disconnect_callback != NULL) { + espconn_connect_callback disconnect_callback = espconn->proto.tcp->disconnect_callback; + ESPCONN_API_MUTEX_GIVE(); + disconnect_callback(espconn); + ESPCONN_API_MUTEX_TAKE(); + } + + /*frees the connection memory*/ + espconn_tcp_memp_free(pdiscon_cb); + } else { + espconn_printf("espconn_tcp_disconnect err\n"); + } +} +/****************************************************************************** + * FunctionName : espconn_tcp_sent + * Description : sent data for client or server + * Parameters : void *arg -- client or server to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : return espconn error code. + * - ESPCONN_OK. Successful. No error occured. + * - ESPCONN_MEM. Out of memory. + * - ESPCONN_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. +*******************************************************************************/ +err_t ICACHE_FLASH_ATTR +espconn_tcp_sent(void* arg, uint8* psent, uint16 length) +{ + espconn_msg* ptcp_sent = arg; + struct tcp_pcb* pcb = NULL; + err_t err = 0; + u16_t len = 0; + u8_t data_to_send = false; + + espconn_printf("espconn_tcp_sent ptcp_sent %p psent %p length %d\n", ptcp_sent, psent, length); + + /*Check the parameters*/ + if (ptcp_sent == NULL || psent == NULL || length == 0) { + return ESPCONN_ARG; + } + + /*Set the packet length depend on the sender buffer space*/ + pcb = ptcp_sent->pcommon.pcb; + + if (tcp_sndbuf(pcb) < length) { + len = tcp_sndbuf(pcb); + } else { + len = length; + LWIP_ASSERT("length did not fit into uint16!", (len == length)); + } + + if (len > (2 * pcb->mss)) { + len = 2 * pcb->mss; + } + + /*Write data for sending, but does not send it immediately*/ + do { + espconn_printf("espconn_tcp_sent writing %d bytes %p\n", len, pcb); + + if (espconn_copy_disabled(ptcp_sent)) { + err = tcp_write(pcb, psent, len, 1); + } else { + err = tcp_write(pcb, psent, len, 0); + } + + if (err == ERR_MEM) { + if (len < 3) { + len--; + } else { + len /= 2; + } + } + + } while (err == ERR_MEM && len > 0); + + /*Find out what we can send and send it, offset the buffer point for next send*/ + if (err == ERR_OK) { + ptcp_sent->pcommon.ptail->punsent = psent + len; + ptcp_sent->pcommon.ptail->unsent = length - len; + err = tcp_output(pcb); + + /*If enable the copy option, change the flag for next write*/ + if (espconn_copy_disabled(ptcp_sent)) { + if (ptcp_sent->pcommon.ptail->unsent == 0) { + ptcp_sent->pcommon.write_flag = true; + os_post(espconn_TaskPrio, SIG_ESPCONN_WRITE, (uint32_t)ptcp_sent); + } + } + + espconn_printf("espconn_tcp_sent %d\n", err); + } + + return err; +} + +/****************************************************************************** + * FunctionName : espconn_close + * Description : The connection has been successfully closed. + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_tcp_disconnect(espconn_msg* pdiscon, u8 type) +{ + if (pdiscon != NULL) { + /*disconnect with the host by send the FIN frame*/ + if (pdiscon->preverse != NULL) { + espconn_server_close(pdiscon, pdiscon->pcommon.pcb, type); + } else { + espconn_client_close(pdiscon, pdiscon->pcommon.pcb, type); + } + } else { + espconn_printf("espconn_tcp_disconnect err.\n"); + } +} + +///////////////////////////////client function///////////////////////////////// +/****************************************************************************** + * FunctionName : espconn_client_close + * Description : The connection shall be actively closed. + * Parameters : pcb -- Additional argument to pass to the callback function + * pcb -- the pcb to close + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_client_close(void* arg, struct tcp_pcb* pcb, u8 type) +{ + err_t err; + espconn_msg* pclose = arg; + + pclose->pcommon.pcb = pcb; + /*avoid recalling the disconnect function*/ + tcp_recv(pcb, NULL); + + if (type == 0) { + err = tcp_close(pcb); + } else { + tcp_sent(pcb, NULL); + tcp_err(pcb, NULL); + tcp_abort(pcb); + err = ERR_OK; + } + + if (err != ERR_OK) { + /* closing failed, try again later */ + tcp_recv(pcb, espconn_client_recv); + } else { + /* closing succeeded */ + if (type == 0) { + tcp_sent(pcb, NULL); + tcp_err(pcb, NULL); + } + + /*switch the state of espconn for application process*/ + pclose->pespconn->state = ESPCONN_CLOSE; + os_post(espconn_TaskPrio, SIG_ESPCONN_CLOSE, (uint32_t)pclose); + } +} + +//***********Code for WIFI_BLOCK from upper************** +sint8 ICACHE_FLASH_ATTR +espconn_recv_hold(struct espconn* pespconn) +{ + //1st, according to espconn code, have to find out the escpconn_msg by pespconn; + espconn_msg* pnode = NULL; + bool value = false; + + if (pespconn == NULL) { + return ESPCONN_ARG; + } + + value = espconn_find_connection(pespconn, &pnode); + + if (value != true) { + espconn_printf("RecvHold, By pespconn,find conn_msg fail\n"); + return ESPCONN_ARG; + } + + //2nd, the actual operation + if (pnode->recv_hold_flag == 0) { + pnode->recv_hold_flag = 1; + pnode->recv_holded_buf_Len = 0; + } + + return ESPCONN_OK; +} + +sint8 ICACHE_FLASH_ATTR +espconn_recv_unhold(struct espconn* pespconn) +{ + //1st, according to espconn code, have to find out the escpconn_msg by pespconn; + espconn_msg* pnode = NULL; + bool value = false; + + if (pespconn == NULL) { + return ESPCONN_ARG; + } + + value = espconn_find_connection(pespconn, &pnode); + + if (value != true) { + espconn_printf("RecvHold, By pespconn,find conn_msg fail\n"); + return ESPCONN_ARG; + } + + //2nd, the actual operation + if (pnode->recv_hold_flag == 1) { + if (pespconn->type == ESPCONN_TCP) { + tcp_recved(pnode->pcommon.pcb, pnode->recv_holded_buf_Len); + } + + pnode->recv_holded_buf_Len = 0; + pnode->recv_hold_flag = 0; + } + + return ESPCONN_OK; +} + +//***********Code for WIFI_BLOCK from upper************** +sint8 ICACHE_FLASH_ATTR +espconn_lock_recv(espconn_msg* plockmsg) +{ + if (plockmsg == NULL || plockmsg->pespconn == NULL) { + return ESPCONN_ARG; + } + + if (plockmsg->pespconn->recv_callback == NULL) { + if (plockmsg->readbuf == NULL) { + plockmsg->readbuf = ringbuf_new(TCP_WND); + + if (plockmsg->readbuf == NULL) { + return ESPCONN_MEM; + } + } + + return espconn_recv_hold(plockmsg->pespconn); + } + + return ESPCONN_OK; +} + +sint8 ICACHE_FLASH_ATTR +espconn_unlock_recv(espconn_msg* punlockmsg) +{ + if (punlockmsg == NULL || punlockmsg->pespconn == NULL) { + return ESPCONN_ARG; + } + + if (punlockmsg->pespconn->recv_callback != NULL) { + return espconn_recv_unhold(punlockmsg->pespconn); + } + + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_client_recv + * Description : Data has been received on this pcb. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb which received data + * p -- The received data (or NULL when the connection has been closed!) + * err -- An error code if there has been an error receiving + * Returns : ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_client_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) +{ + espconn_msg* precv_cb = arg; + //ESPCONN_API_MUTEX_TAKE(); + tcp_arg(pcb, arg); + /*lock the window because of application layer don't need the data*/ + espconn_lock_recv(precv_cb); + + if (p != NULL) { + /*To update and advertise a larger window*/ + if (precv_cb->recv_hold_flag == 0) { + tcp_recved(pcb, p->tot_len); + } else { + precv_cb->recv_holded_buf_Len += p->tot_len; + } + } + + if (precv_cb->pespconn->recv_callback != NULL) { + if (err == ERR_OK && p != NULL) { + char* pdata = NULL; + u16_t length = 0; + /*Copy the contents of a packet buffer to an application buffer. + *to prevent memory leaks, ensure that each allocated is deleted*/ + pdata = (char*)os_zalloc(p ->tot_len + 1); + length = pbuf_copy_partial(p, pdata, p ->tot_len, 0); + pbuf_free(p); + + if (length != 0) { + /*switch the state of espconn for application process*/ + precv_cb->pespconn ->state = ESPCONN_READ; + precv_cb->pcommon.pcb = pcb; + precv_cb->pespconn->recv_callback(precv_cb->pespconn, pdata, length); + + /*switch the state of espconn for next packet copy*/ + if (pcb->state == ESTABLISHED) { + precv_cb->pespconn ->state = ESPCONN_CONNECT; + } + } + + /*to prevent memory leaks, ensure that each allocated is deleted*/ + os_free(pdata); + pdata = NULL; + } + } else { + /*unregister receive function*/ + struct pbuf* pthis = NULL; + + for (pthis = p; pthis != NULL; pthis = pthis->next) { + ringbuf_memcpy_into(precv_cb->readbuf, pthis->payload, pthis->len); + pbuf_free(pthis); + } + } + + if (err == ERR_OK && p == NULL) { + espconn_client_close(precv_cb, pcb, 0); + } + + //ESPCONN_API_MUTEX_GIVE(); + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_write + * Description : write the packet which in the active connection's list. + * Parameters : arg -- the node pointer which reverse the packet + * Returns : ESPCONN_MEM: memory error + * ESPCONN_OK:have enough space for write packet +*******************************************************************************/ +err_t ICACHE_FLASH_ATTR espconn_tcp_write(void* arg) +{ + espconn_msg* pwrite = arg; + err_t err = ERR_OK; + struct tcp_pcb* pcb = pwrite->pcommon.pcb; + + /*for one active connection,limit the sender buffer space*/ + if (tcp_nagle_disabled(pcb) && (pcb->snd_queuelen >= TCP_SND_QUEUELEN)) { + return ESPCONN_MEM; + } + + while (tcp_sndbuf(pcb) != 0) { + if (pwrite->pcommon.ptail != NULL) { + /*Find the node whether in the list's tail or not*/ + if (pwrite->pcommon.ptail->unsent == 0) { + pwrite->pcommon.ptail = pwrite->pcommon.ptail->pnext; + continue; + } + + /*Send the packet for the active connection*/ + err = espconn_tcp_sent(pwrite, pwrite->pcommon.ptail->punsent, pwrite->pcommon.ptail->unsent); + + if (err != ERR_OK) { + break; + } + } else { + break; + } + } + + return err; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_reconnect + * Description : reconnect with host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR espconn_tcp_finish(void* arg) +{ + espconn_msg* pfinish = arg; + espconn_buf* premove = NULL; + uint16 len = 0; + espconn_tcp_write(pfinish); + + while (pfinish->pcommon.pbuf != NULL) { + premove = pfinish->pcommon.pbuf; + pfinish->pcommon.pbuf->tot_len += len; + + /*application packet has been sent and acknowledged by the remote host, + * to prevent memory leaks, ensure that each allocated is deleted*/ + if (premove->tot_len >= premove->len) { + espconn_pbuf_delete(&pfinish->pcommon.pbuf, premove); + len = premove->tot_len - premove->len; + pfinish->pcommon.packet_info.sent_length = premove->len; + os_free(premove); + premove = NULL; + pfinish->pespconn->state = ESPCONN_CONNECT; + + if (pfinish->pespconn->sent_callback != NULL) { + pfinish->pespconn->sent_callback(pfinish->pespconn); + } + + pfinish->pcommon.packet_info.sent_length = len; + } else { + break; + } + } +} + +/****************************************************************************** + * FunctionName : espconn_client_sent + * Description : Data has been sent and acknowledged by the remote host. + * This means that more data can be sent. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb for which data has been acknowledged + * len -- The amount of bytes acknowledged + * Returns : ERR_OK: try to send some data by calling tcp_output + * ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_client_sent(void* arg, struct tcp_pcb* pcb, u16_t len) +{ + espconn_msg* psent_cb = arg; + + psent_cb->pcommon.pcb = pcb; + psent_cb->pcommon.pbuf->tot_len += len; + psent_cb->pcommon.packet_info.sent_length = len; + + /*Send more data for one active connection*/ + espconn_tcp_finish(psent_cb); + + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : espconn_client_err + * Description : The pcb had an error and is already deallocated. + * The argument might still be valid (if != NULL). + * Parameters : arg -- Additional argument to pass to the callback function + * err -- Error code to indicate why the pcb has been closed + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_client_err(void* arg, err_t err) +{ + espconn_msg* perr_cb = arg; + struct tcp_pcb* pcb = NULL; + LWIP_UNUSED_ARG(err); + + if (perr_cb != NULL) { + pcb = perr_cb->pcommon.pcb; + perr_cb->pespconn->state = ESPCONN_CLOSE; + espconn_printf("espconn_client_err %d %d %d\n", pcb->state, pcb->nrtx, err); + +// /*remove the node from the client's active connection list*/ +// espconn_list_delete(&plink_active, perr_cb); + + /*Set the error code depend on the error type and control block state*/ + if (err == ERR_ABRT) { + switch (pcb->state) { + case SYN_SENT: + if (pcb->nrtx == TCP_SYNMAXRTX) { + perr_cb->pcommon.err = ESPCONN_CONN; + } else { + perr_cb->pcommon.err = err; + } + + break; + + case ESTABLISHED: + if (pcb->nrtx == TCP_MAXRTX) { + perr_cb->pcommon.err = ESPCONN_TIMEOUT; + } else { + perr_cb->pcommon.err = err; + } + + break; + + case FIN_WAIT_1: + if (pcb->nrtx == TCP_MAXRTX) { + perr_cb->pcommon.err = ESPCONN_CLSD; + } else { + perr_cb->pcommon.err = err; + } + + break; + + case FIN_WAIT_2: + perr_cb->pcommon.err = ESPCONN_CLSD; + break; + + case CLOSED: + perr_cb->pcommon.err = ESPCONN_CONN; + break; + } + } else { + perr_cb->pcommon.err = err; + } + + /*post the singer to the task for processing the connection*/ + os_post(espconn_TaskPrio, SIG_ESPCONN_ERRER, (uint32_t)perr_cb); + } +} + +/****************************************************************************** + * FunctionName : espconn_client_connect + * Description : A new incoming connection has been connected. + * Parameters : arg -- Additional argument to pass to the callback function + * tpcb -- The connection pcb which is connected + * err -- An unused error code, always ERR_OK currently + * Returns : connection result +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_client_connect(void* arg, struct tcp_pcb* tpcb, err_t err) +{ + espconn_msg* pcon = arg; + + espconn_printf("espconn_client_connect pcon %p tpcb %p\n", pcon, tpcb); + + if (err == ERR_OK) { + /*Reserve the remote information for current active connection*/ + pcon->pespconn->state = ESPCONN_CONNECT; + pcon->pcommon.err = err; + pcon->pcommon.pcb = tpcb; + pcon->pcommon.local_port = tpcb->local_port; + pcon->pcommon.local_ip = tpcb->local_ip.ip4.addr; + pcon->pcommon.remote_port = tpcb->remote_port; + pcon->pcommon.remote_ip[0] = ip4_addr1_16(&tpcb->remote_ip); + pcon->pcommon.remote_ip[1] = ip4_addr2_16(&tpcb->remote_ip); + pcon->pcommon.remote_ip[2] = ip4_addr3_16(&tpcb->remote_ip); + pcon->pcommon.remote_ip[3] = ip4_addr4_16(&tpcb->remote_ip); + pcon->pcommon.write_flag = true; + tcp_arg(tpcb, (void*) pcon); + + /*Set the specify function that should be called + * when TCP data has been successfully delivered, + * when active connection receives data*/ + tcp_sent(tpcb, espconn_client_sent); + tcp_recv(tpcb, espconn_client_recv); + /*Disable Nagle algorithm default*/ + tcp_nagle_disable(tpcb); + /*Default set the total number of espconn_buf on the unsent lists for one*/ + espconn_tcp_set_buf_count(pcon->pespconn, 1); + + if (pcon->pespconn->proto.tcp->connect_callback != NULL) { + pcon->pespconn->proto.tcp->connect_callback(pcon->pespconn); + } + + /*Enable keep alive option*/ + if (espconn_keepalive_disabled(pcon)) { + espconn_keepalive_enable(tpcb); + } + +// /*lock the window because of application layer don't need the data*/ +// espconn_lock_recv(pcon); + } else { + espconn_printf("err in host connected (%s)\n", lwip_strerr(err)); + } + + return err; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_client + * Description : Initialize the client: set up a connect PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_tcp_client(struct espconn* espconn) +{ + struct tcp_pcb* pcb = NULL; + struct ip_addr ipaddr; + espconn_msg* pclient = NULL; + + /*Creates a new client control message*/ + pclient = (espconn_msg*)os_zalloc(sizeof(espconn_msg)); + + if (pclient == NULL) { + return ESPCONN_MEM; + } + + /*Set an IP address given for Little-endian.*/ + IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0], + espconn->proto.tcp->remote_ip[1], + espconn->proto.tcp->remote_ip[2], + espconn->proto.tcp->remote_ip[3]); + + /*Creates a new TCP protocol control block*/ + pcb = tcp_new(); + + if (pcb == NULL) { + /*to prevent memory leaks, ensure that each allocated is deleted*/ + os_free(pclient); + pclient = NULL; + return ESPCONN_MEM; + } else { + + /*insert the node to the active connection list*/ + espconn_list_creat(&plink_active, pclient); + tcp_arg(pcb, (void*)pclient); + tcp_err(pcb, espconn_client_err); + pclient->preverse = NULL; + pclient->pespconn = espconn; + pclient->pespconn->state = ESPCONN_WAIT; + pclient->pcommon.pcb = pcb; + tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port); +#if 0 + pclient->pcommon.err = tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port); + + if (pclient->pcommon.err != ERR_OK) { + /*remove the node from the client's active connection list*/ + espconn_list_delete(&plink_active, pclient); + memp_free(MEMP_TCP_PCB, pcb); + os_free(pclient); + pclient = NULL; + return ERR_USE; + } + +#endif + /*Establish the connection*/ + pclient->espconn_mode = ESPCONN_TCPCLIENT_MODE; + pclient->pcommon.err = tcp_connect(pcb, &ipaddr, + pclient->pespconn->proto.tcp->remote_port, espconn_client_connect); + + if (pclient->pcommon.err == ERR_RTE) { + /*remove the node from the client's active connection list*/ + espconn_list_delete(&plink_active, pclient); + espconn_kill_pcb(pcb->local_port); + os_free(pclient); + pclient = NULL; + return ESPCONN_RTE; + } + + return pclient->pcommon.err; + } +} + +///////////////////////////////server function///////////////////////////////// +/****************************************************************************** + * FunctionName : espconn_server_close + * Description : The connection shall be actively closed. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- the pcb to close + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_server_close(void* arg, struct tcp_pcb* pcb, u8 type) +{ + err_t err; + espconn_msg* psclose = arg; + + psclose->pcommon.pcb = pcb; + /*avoid recalling the disconnect function*/ + tcp_recv(pcb, NULL); + + if (type == 0) { + err = tcp_close(pcb); + } else { + tcp_poll(pcb, NULL, 0); + tcp_sent(pcb, NULL); + tcp_err(pcb, NULL); + tcp_abort(pcb); + err = ERR_OK; + } + + if (err != ERR_OK) { + /* closing failed, try again later */ + tcp_recv(pcb, espconn_server_recv); + } else { + /* closing succeeded */ + if (type == 0) { + tcp_poll(pcb, NULL, 0); + tcp_sent(pcb, NULL); + tcp_err(pcb, NULL); + } + + /*switch the state of espconn for application process*/ + psclose->pespconn->state = ESPCONN_CLOSE; +#if TCP_LISTEN_BACKLOG + struct tcp_pcb* lpcb = NULL; + struct espconn* pespconn = psclose->preverse; + espconn_msg* plist = NULL; + + /*find the active server node*/ + for (plist = pserver_list; plist != NULL; plist = plist->pnext) { + if (pespconn == plist->pespconn) { + /*find the tcp_pcb in the LISTEN state*/ + lpcb = plist->preverse; + tcp_accepted(lpcb); + break; + } + } + +#endif + os_post(espconn_TaskPrio, SIG_ESPCONN_CLOSE, (uint32_t)psclose); + } +} + +/****************************************************************************** + * FunctionName : espconn_server_recv + * Description : Data has been received on this pcb. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb which received data + * p -- The received data (or NULL when the connection has been closed!) + * err -- An error code if there has been an error receiving + * Returns : ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_server_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) +{ + espconn_msg* precv_cb = arg; + //ESPCONN_API_MUTEX_TAKE(); + tcp_arg(pcb, arg); + espconn_printf("server has application data received: %d\n", system_get_free_heap_size()); + /*lock the window because of application layer don't need the data*/ + espconn_lock_recv(precv_cb); + + if (p != NULL) { + /*To update and advertise a larger window*/ + if (precv_cb->recv_hold_flag == 0) { + tcp_recved(pcb, p->tot_len); + } else { + precv_cb->recv_holded_buf_Len += p->tot_len; + } + } + + /*register receive function*/ + if (precv_cb->pespconn->recv_callback != NULL) { + if (err == ERR_OK && p != NULL) { + u8_t* data_ptr = NULL; + u32_t data_cntr = 0; + /*clear the count for connection timeout*/ + precv_cb->pcommon.recv_check = 0; + /*Copy the contents of a packet buffer to an application buffer. + *to prevent memory leaks, ensure that each allocated is deleted*/ + data_ptr = (u8_t*) os_zalloc(p ->tot_len + 1); + data_cntr = pbuf_copy_partial(p, data_ptr, p->tot_len, 0); + pbuf_free(p); + + if (data_cntr != 0) { + /*switch the state of espconn for application process*/ + precv_cb->pespconn->state = ESPCONN_READ; + precv_cb->pcommon.pcb = pcb; + precv_cb->pespconn->recv_callback(precv_cb->pespconn, data_ptr, data_cntr); + + /*switch the state of espconn for next packet copy*/ + if (pcb->state == ESTABLISHED) { + precv_cb->pespconn->state = ESPCONN_CONNECT; + } + } + + /*to prevent memory leaks, ensure that each allocated is deleted*/ + os_free(data_ptr); + data_ptr = NULL; + espconn_printf("server's application data has been processed: %d\n", system_get_free_heap_size()); + } + } else { + /*unregister receive function*/ + struct pbuf* pthis = NULL; + + for (pthis = p; pthis != NULL; pthis = pthis->next) { + ringbuf_memcpy_into(precv_cb->readbuf, pthis->payload, pthis->len); + pbuf_free(pthis); + } + } + + if (err == ERR_OK && p == NULL) { + espconn_server_close(precv_cb, pcb, 0); + } + + //ESPCONN_API_MUTEX_GIVE(); + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : espconn_server_sent + * Description : Data has been sent and acknowledged by the remote host. + * This means that more data can be sent. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb for which data has been acknowledged + * len -- The amount of bytes acknowledged + * Returns : ERR_OK: try to send some data by calling tcp_output + * ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_server_sent(void* arg, struct tcp_pcb* pcb, u16_t len) +{ + espconn_msg* psent_cb = arg; + + psent_cb->pcommon.pcb = pcb; + psent_cb->pcommon.recv_check = 0; + psent_cb->pcommon.pbuf->tot_len += len; + psent_cb->pcommon.packet_info.sent_length = len; + + /*Send more data for one active connection*/ + espconn_tcp_finish(psent_cb); + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : espconn_server_poll + * Description : The poll function is called every 3nd second. + * If there has been no data sent (which resets the retries) in 3 seconds, close. + * If the last portion of a file has not been sent in 3 seconds, close. + * + * This could be increased, but we don't want to waste resources for bad connections. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb for which data has been acknowledged + * Returns : ERR_OK: try to send some data by calling tcp_output + * ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_server_poll(void* arg, struct tcp_pcb* pcb) +{ + espconn_msg* pspoll_cb = arg; + + /*exception calling abandon the connection for send a RST frame*/ + if (arg == NULL) { + tcp_abandon(pcb, 0); + tcp_poll(pcb, NULL, 0); + return ERR_OK; + } + + espconn_printf("espconn_server_poll %d %d\n", pspoll_cb->pcommon.recv_check, pcb->state); + pspoll_cb->pcommon.pcb = pcb; + + if (pcb->state == ESTABLISHED) { + pspoll_cb->pcommon.recv_check++; + + if (pspoll_cb->pcommon.timeout != 0) { /*no data sent in one active connection's set timeout, close.*/ + if (pspoll_cb->pcommon.recv_check >= pspoll_cb->pcommon.timeout) { + pspoll_cb->pcommon.recv_check = 0; + espconn_server_close(pspoll_cb, pcb, 0); + } + } else { + espconn_msg* ptime_msg = pserver_list; + + while (ptime_msg != NULL) { + if (ptime_msg->pespconn == pspoll_cb->preverse) { + if (ptime_msg->pcommon.timeout != 0) { /*no data sent in server's set timeout, close.*/ + if (pspoll_cb->pcommon.recv_check >= ptime_msg->pcommon.timeout) { + pspoll_cb->pcommon.recv_check = 0; + espconn_server_close(pspoll_cb, pcb, 0); + } + } else {/*don't close for ever*/ + pspoll_cb->pcommon.recv_check = 0; + } + + break; + } + + ptime_msg = ptime_msg->pnext; + } + } + } else { + espconn_server_close(pspoll_cb, pcb, 0); + } + + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : esponn_server_err + * Description : The pcb had an error and is already deallocated. + * The argument might still be valid (if != NULL). + * Parameters : arg -- Additional argument to pass to the callback function + * err -- Error code to indicate why the pcb has been closed + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +esponn_server_err(void* arg, err_t err) +{ + espconn_msg* pserr_cb = arg; + struct tcp_pcb* pcb = NULL; + + if (pserr_cb != NULL) { + + pcb = pserr_cb->pcommon.pcb; + pserr_cb->pespconn->state = ESPCONN_CLOSE; + +// /*remove the node from the server's active connection list*/ +// espconn_list_delete(&plink_active, pserr_cb); + + /*Set the error code depend on the error type and control block state*/ + if (err == ERR_ABRT) { + switch (pcb->state) { + case SYN_RCVD: + if (pcb->nrtx == TCP_SYNMAXRTX) { + pserr_cb->pcommon.err = ESPCONN_CONN; + } else { + pserr_cb->pcommon.err = err; + } + + break; + + case ESTABLISHED: + if (pcb->nrtx == TCP_MAXRTX) { + pserr_cb->pcommon.err = ESPCONN_TIMEOUT; + } else { + pserr_cb->pcommon.err = err; + } + + break; + + case CLOSE_WAIT: + if (pcb->nrtx == TCP_MAXRTX) { + pserr_cb->pcommon.err = ESPCONN_CLSD; + } else { + pserr_cb->pcommon.err = err; + } + + break; + + case LAST_ACK: + pserr_cb->pcommon.err = ESPCONN_CLSD; + break; + + case CLOSED: + pserr_cb->pcommon.err = ESPCONN_CONN; + break; + + default : + break; + } + } else { + pserr_cb->pcommon.err = err; + } + + /*post the singer to the task for processing the connection*/ + os_post(espconn_TaskPrio, SIG_ESPCONN_ERRER, (uint32_t)pserr_cb); + } +} + +/****************************************************************************** + * FunctionName : espconn_tcp_accept + * Description : A new incoming connection has been accepted. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb which is accepted + * err -- An unused error code, always ERR_OK currently + * Returns : acception result +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_tcp_accept(void* arg, struct tcp_pcb* pcb, err_t err) +{ + struct espconn* espconn = arg; + espconn_msg* paccept = NULL; + remot_info* pinfo = NULL; + LWIP_UNUSED_ARG(err); + + if (!espconn || !espconn->proto.tcp) { + return ERR_ARG; + } + + tcp_arg(pcb, paccept); + tcp_err(pcb, esponn_server_err); + /*Ensure the active connection is less than the count of active connections on the server*/ + espconn_get_connection_info(espconn, &pinfo , 0); + espconn_printf("espconn_tcp_accept link_cnt: %d\n", espconn->link_cnt); + + if (espconn->link_cnt == espconn_tcp_get_max_con_allow(espconn)) { + return ERR_ISCONN; + } + + /*Creates a new active connect control message*/ + paccept = (espconn_msg*)os_zalloc(sizeof(espconn_msg)); + tcp_arg(pcb, paccept); + + if (paccept == NULL) { + return ERR_MEM; + } + + /*Insert the node to the active connection list*/ + espconn_list_creat(&plink_active, paccept); + + paccept->preverse = espconn; + paccept->espconn_mode = ESPCONN_TCPSERVER_MODE; + paccept->pespconn = (struct espconn*)os_zalloc(sizeof(struct espconn)); + + if (paccept->pespconn == NULL) { + return ERR_MEM; + } + + paccept->pespconn->proto.tcp = (esp_tcp*)os_zalloc(sizeof(esp_tcp)); + + if (paccept->pespconn->proto.tcp == NULL) { + return ERR_MEM; + } + + /*Reserve the remote information for current active connection*/ + paccept->pcommon.pcb = pcb; + + paccept->pcommon.remote_port = pcb->remote_port; + paccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip); + paccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip); + paccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip); + paccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip); + paccept->pcommon.write_flag = true; + + memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4); + espconn->proto.tcp->remote_port = pcb->remote_port; + espconn->state = ESPCONN_CONNECT; + espconn_copy_partial(paccept->pespconn, espconn); + + /*Set the specify function that should be called + * when TCP data has been successfully delivered, + * when active connection receives data, + * or periodically from active connection*/ + tcp_sent(pcb, espconn_server_sent); + tcp_recv(pcb, espconn_server_recv); + tcp_poll(pcb, espconn_server_poll, 4); /* every 1 seconds */ + /*Disable Nagle algorithm default*/ + tcp_nagle_disable(pcb); + /*Default set the total number of espconn_buf on the unsent lists for one*/ + espconn_tcp_set_buf_count(paccept->pespconn, 1); + + if (paccept->pespconn->proto.tcp->connect_callback != NULL) { + paccept->pespconn->proto.tcp->connect_callback(paccept->pespconn); + } + + /*Enable keep alive option*/ + if (espconn_keepalive_disabled(paccept)) { + espconn_keepalive_enable(pcb); + } + +// /*lock the window because of application layer don't need the data*/ +// espconn_lock_recv(paccept); + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_server + * Description : Initialize the server: set up a listening PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build server + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_tcp_server(struct espconn* espconn) +{ + struct tcp_pcb* pcb = NULL; + espconn_msg* pserver = NULL; + + /*Creates a new server control message*/ + pserver = (espconn_msg*)os_zalloc(sizeof(espconn_msg)); + + if (pserver == NULL) { + return ESPCONN_MEM; + } + + /*Creates a new TCP protocol control block*/ + pcb = tcp_new(); + + if (pcb == NULL) { + /*to prevent memory leaks, ensure that each allocated is deleted*/ + os_free(pserver); + pserver = NULL; + return ESPCONN_MEM; + } else { + struct tcp_pcb* lpcb = NULL; + /*Binds the connection to a local port number and any IP address*/ + tcp_bind(pcb, IP_ADDR_ANY, espconn->proto.tcp->local_port); + lpcb = pcb; + /*malloc and set the state of the connection to be LISTEN*/ + pcb = tcp_listen(pcb); + + if (pcb != NULL) { + /*insert the node to the active connection list*/ + espconn_list_creat(&pserver_list, pserver); + pserver->preverse = pcb; + pserver->pespconn = espconn; + pserver->count_opt = MEMP_NUM_TCP_PCB; + pserver->pcommon.timeout = 0x0a; + espconn ->state = ESPCONN_LISTEN; + /*set the specify argument that should be passed callback function*/ + tcp_arg(pcb, (void*)espconn); + /*accept callback function to call for this control block*/ + tcp_accept(pcb, espconn_tcp_accept); + return ESPCONN_OK; + } else { + /*to prevent memory leaks, ensure that each allocated is deleted*/ + memp_free(MEMP_TCP_PCB, lpcb); + os_free(pserver); + pserver = NULL; + return ESPCONN_MEM; + } + } +} + +/****************************************************************************** + * FunctionName : espconn_tcp_delete + * Description : delete the server: delete a listening PCB and free it + * Parameters : pdeletecon -- the espconn used to delete a server + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_delete(struct espconn* pdeletecon) +{ + err_t err; + remot_info* pinfo = NULL; + espconn_msg* pdelete_msg = NULL; + struct tcp_pcb* pcb = NULL; + + if (pdeletecon == NULL) { + return ESPCONN_ARG; + } + + espconn_get_connection_info(pdeletecon, &pinfo , 0); + + /*make sure all the active connection have been disconnect*/ + if (pdeletecon->link_cnt != 0) { + return ESPCONN_INPROGRESS; + } else { + espconn_printf("espconn_tcp_delete %p\n", pdeletecon); + pdelete_msg = pserver_list; + + while (pdelete_msg != NULL) { + if (pdelete_msg->pespconn == pdeletecon) { + /*remove the node from the client's active connection list*/ + espconn_list_delete(&pserver_list, pdelete_msg); + pcb = pdelete_msg->preverse; + espconn_printf("espconn_tcp_delete %d, %d\n", pcb->state, pcb->local_port); + espconn_kill_pcb(pcb->local_port); + err = tcp_close(pcb); + os_free(pdelete_msg); + pdelete_msg = NULL; + break; + } + + pdelete_msg = pdelete_msg->pnext; + } + + if (err == ERR_OK) { + return err; + } else { + return ESPCONN_ARG; + } + } +} + +#if !NO_SYS +/****************************************************************************** + * FunctionName : espconn_thread + * Description : This thread has exclusive access to espconn task functions + * (unless access to them is not locked). + * Other threads communicate with this thread using message boxes. + * Parameters : arg -- message boxes + * Returns : none + *****************************************************************************/ +static sys_mutex_t EspMsgMutex = NULL; +#if ESPCONN_LOCKING +sys_mutex_t lock_espconn_task; +#endif +static sys_mbox_t EspMbox; + +static void ICACHE_FLASH_ATTR +espconn_thread(void* arg) +{ + espconn_msg* thread_msg = NULL; + struct espconn* pespconn = NULL; + + LOCK_ESPCONN_TASK(); + + while (1) { + UNLOCK_ESPCONN_TASK(); + /* wait for a message, timeouts are processed while waiting */ + sys_arch_mbox_fetch(&EspMbox, (void**) &thread_msg, ESPCONN_MAX_DELAY); + LOCK_ESPCONN_TASK(); +// printf("%s %d,message[%p]\n",__func__,__LINE__, thread_msg); + ESPCONN_API_MUTEX_TAKE(); + + bool active_flag = false; + espconn_msg* plist = NULL; + + /*find the active connection node*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + if (thread_msg == plist) { + active_flag = true; + break; + } + } + + if (active_flag) { + pespconn = (thread_msg != NULL) ? thread_msg->pespconn : NULL; + + if (pespconn == NULL) { + goto THREAD_END; + } + + switch (pespconn->type) { + case ESPCONN_TCP: + if (pespconn->proto.tcp == NULL) { + goto THREAD_END; + } + + break; + + case ESPCONN_UDP: + if (pespconn->proto.udp == NULL) { + goto THREAD_END; + } + + break; + + default: + goto THREAD_END; + break; + } + +// printf("%s %d,sig_type[%d]\n", __func__, __LINE__, thread_msg->sig_type); + switch (thread_msg->sig_type) { + case SIG_ESPCONN_WRITE: + if (pespconn ->proto.tcp->write_finish_fn != NULL) { + espconn_connect_callback write_finish_fn = pespconn->proto.tcp->write_finish_fn; + ESPCONN_API_MUTEX_GIVE(); + write_finish_fn(pespconn); + ESPCONN_API_MUTEX_TAKE(); + } + + break; + + case SIG_ESPCONN_SEND: + if (pespconn ->sent_callback != NULL) { + espconn_sent_callback sent_callback = pespconn->sent_callback; + ESPCONN_API_MUTEX_GIVE(); + sent_callback(pespconn); + ESPCONN_API_MUTEX_TAKE(); + } + + break; + + case SIG_ESPCONN_ERRER: + /*remove the node from the client's active connection list*/ + espconn_list_delete(&plink_active, thread_msg); + espconn_tcp_reconnect(thread_msg); + break; + + case SIG_ESPCONN_CLOSE: + /*remove the node from the client's active connection list*/ + espconn_list_delete(&plink_active, thread_msg); + espconn_tcp_disconnect_successful(thread_msg); + break; + + default: + + break; + } + } + +THREAD_END: + ESPCONN_API_MUTEX_GIVE(); +// printf("%s %d\n", __func__, __LINE__); + } +} + +/****************************************************************************** + * FunctionName : os_post + * Description : Call the part of a call back function + * This function is then running in the thread context + * of espconn_thread and has exclusive access to lwIP core code. + * + * Parameters : apimsg -- a struct containing the function to call and its parameters + * Returns : none + *****************************************************************************/ +static void os_post(uint8 prio, uint32 type, uint32 arg) +{ + espconn_msg* post_msg = (espconn_msg*)arg; + + if (sys_mbox_valid(&EspMbox)) { + post_msg->sig_type = type; + sys_mbox_post(&EspMbox, post_msg); + } +} + +/****************************************************************************** + * FunctionName : espconn_init + * Description : Initialize espconn module: + * initialize all sub modules + * start the espconn_thread. + * + * Parameters : none + * Returns : none + *****************************************************************************/ +void ICACHE_FLASH_ATTR espconn_init(void) +{ + if (sys_mbox_new(&EspMbox, ESPCONN_MBOX_SIZE) != ERR_OK) { + LWIP_ASSERT("failed to create espconn_thread mbox", 0); + } + +#if ESPCONN_LOCKING + + if (sys_mutex_new(&lock_espconn_task) != ERR_OK) { + LWIP_ASSERT("failed to create lock_espconn_task", 0); + } + +#endif /* ESPCONN_LOCKING */ + + sys_mutex_new(&EspMsgMutex); + + if (EspMsgMutex == NULL) { + printf("EspMsgMutex create fail\n"); + } else { + printf("EspMsgMutex created\n"); + } + + sys_thread_new(ESPCONN_THREAD_NAME, espconn_thread, NULL, ESPCONN_THREAD_STACKSIZE, ESPCONN_THREAD_PRIO); +} +#else +/****************************************************************************** + * FunctionName : espconn_Task + * Description : espconn processing task + * Parameters : events -- contain the espconn processing data + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_Task(os_event_t* events) +{ + espconn_msg* plist = NULL; + bool active_flag = false; + espconn_msg* task_msg = NULL; + struct espconn* pespconn = NULL; + + task_msg = (espconn_msg*) events->par; + + /*find the active connection node*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + if (task_msg == plist) { + active_flag = true; + break; + } + } + + if (active_flag) { + switch (events->sig) { + case SIG_ESPCONN_WRITE: { + pespconn = task_msg->pespconn; + + if (pespconn == NULL) { + return; + } + + if (pespconn->proto.tcp->write_finish_fn != NULL) { + pespconn->proto.tcp->write_finish_fn(pespconn); + } + } + break; + + case SIG_ESPCONN_ERRER: + /*remove the node from the client's active connection list*/ + espconn_list_delete(&plink_active, task_msg); + espconn_tcp_reconnect(task_msg); + break; + + case SIG_ESPCONN_CLOSE: + /*remove the node from the client's active connection list*/ + espconn_list_delete(&plink_active, task_msg); + espconn_tcp_disconnect_successful(task_msg); + break; + + default: + break; + } + } +} + +/****************************************************************************** + * FunctionName : espconn_init + * Description : used to init the function that should be used when + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_init(void) +{ + os_task(espconn_Task, espconn_TaskPrio, espconn_TaskQueue, espconn_TaskQueueLen); +} + +#endif diff --git a/third_party/espconn/espconn_udp.c b/third_party/espconn/espconn_udp.c new file mode 100755 index 00000000..d4aebc09 --- /dev/null +++ b/third_party/espconn/espconn_udp.c @@ -0,0 +1,477 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2017 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "lwip/inet.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/mem.h" +#include "lwip/tcp_impl.h" +#include "lwip/udp.h" + +#include "esp_common.h" +#include "espconn/espconn_udp.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +#define IP_MAX_MTU 1500 +extern espconn_msg* plink_active; +uint8 default_interface; + +enum send_opt { + ESPCONN_SENDTO, + ESPCONN_SEND +}; + +static void ICACHE_FLASH_ATTR espconn_data_sentcb(struct espconn* pespconn) +{ + if (pespconn == NULL) { + return; + } + + if (pespconn->sent_callback != NULL) { + pespconn->sent_callback(pespconn); + } +} + +static void ICACHE_FLASH_ATTR espconn_data_sent(void* arg, enum send_opt opt) +{ + espconn_msg* psent = arg; + + if (psent == NULL) { + return; + } + + if (psent->pcommon.cntr == 0) { + psent->pespconn->state = ESPCONN_CONNECT; + + if (psent->pcommon.err == 0) { + espconn_data_sentcb(psent->pespconn); + } + } else { + if (opt == ESPCONN_SEND) { + espconn_udp_sent(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr); + } else { + espconn_udp_sendto(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr); + } + } +} + +/****************************************************************************** + * FunctionName : espconn_udp_sent + * Description : sent data for client or server + * Parameters : void *arg -- client or server to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : return espconn error code. + * - ESPCONN_OK. Successful. No error occured. + * - ESPCONN_MEM. Out of memory. + * - ESPCONN_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. +*******************************************************************************/ +err_t ICACHE_FLASH_ATTR +espconn_udp_sent(void* arg, uint8* psent, uint16 length) +{ + espconn_msg* pudp_sent = arg; + struct udp_pcb* upcb = pudp_sent->pcommon.pcb; + struct pbuf* p, *q , *p_temp; + u8_t* data = NULL; + u16_t cnt = 0; + u16_t datalen = 0; + u16_t i = 0; + err_t err; + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d %p\n", __LINE__, length, upcb)); + + if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) { + return ESPCONN_ARG; + } + + if ((IP_MAX_MTU - 20 - 8) < length) { + datalen = IP_MAX_MTU - 20 - 8; + } else { + datalen = length; + } + + p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p)); + + if (p != NULL) { + q = p; + + while (q != NULL) { + data = (u8_t*)q->payload; + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, data)); + + for (i = 0; i < q->len; i++) { + data[i] = ((u8_t*) psent)[cnt++]; + } + + q = q->next; + } + } else { + return ESPCONN_MEM; + } + + upcb->remote_port = pudp_sent->pespconn->proto.udp->remote_port; + IP4_ADDR(&(upcb->remote_ip.ip4), pudp_sent->pespconn->proto.udp->remote_ip[0], + pudp_sent->pespconn->proto.udp->remote_ip[1], + pudp_sent->pespconn->proto.udp->remote_ip[2], + pudp_sent->pespconn->proto.udp->remote_ip[3]); + + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %x %d\n", __LINE__, upcb->remote_ip, upcb->remote_port)); + + struct netif* sta_netif = (struct netif*)eagle_lwip_getif(0x00); + struct netif* ap_netif = (struct netif*)eagle_lwip_getif(0x01); + + if (wifi_get_opmode() == ESPCONN_AP_STA && default_interface == ESPCONN_AP_STA && sta_netif != NULL && ap_netif != NULL) { + if (netif_is_up(sta_netif) && netif_is_up(ap_netif) && \ + ip_addr_isbroadcast(&(upcb->remote_ip.ip4), sta_netif) && \ + ip_addr_isbroadcast(&(upcb->remote_ip.ip4), ap_netif)) { + + p_temp = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); + + if (pbuf_copy(p_temp, p) != ERR_OK) { + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent: copying to new pbuf failed\n")); + return ESPCONN_ARG; + } + + netif_set_default(sta_netif); + err = udp_send(upcb, p_temp); + pbuf_free(p_temp); + netif_set_default(ap_netif); + } + } + + err = udp_send(upcb, p); + + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d\n", __LINE__, err)); + + if (p->ref != 0) { + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p)); + pbuf_free(p); + pudp_sent->pcommon.ptrbuf = psent + datalen; + pudp_sent->pcommon.cntr = length - datalen; + pudp_sent->pcommon.err = err; + espconn_data_sent(pudp_sent, ESPCONN_SEND); + + if (err > 0) { + return ESPCONN_IF; + } + + return err; + } else { + pbuf_free(p); + return ESPCONN_RTE; + } +} + +/****************************************************************************** + * FunctionName : espconn_udp_sendto + * Description : sent data for UDP + * Parameters : void *arg -- UDP to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : return espconn error code. + * - ESPCONN_OK. Successful. No error occured. + * - ESPCONN_MEM. Out of memory. + * - ESPCONN_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. +*******************************************************************************/ +err_t ICACHE_FLASH_ATTR +espconn_udp_sendto(void* arg, uint8* psent, uint16 length) +{ + espconn_msg* pudp_sent = arg; + struct udp_pcb* upcb = pudp_sent->pcommon.pcb; + struct espconn* pespconn = pudp_sent->pespconn; + struct pbuf* p, *q , *p_temp; + struct ip_addr dst_ip; + u16_t dst_port; + u8_t* data = NULL; + u16_t cnt = 0; + u16_t datalen = 0; + u16_t i = 0; + err_t err; + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d %p\n", __LINE__, length, upcb)); + + if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) { + return ESPCONN_ARG; + } + + if ((IP_MAX_MTU - 20 - 8) < length) { + datalen = IP_MAX_MTU - 20 - 8; + } else { + datalen = length; + } + + p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p)); + + if (p != NULL) { + q = p; + + while (q != NULL) { + data = (u8_t*)q->payload; + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, data)); + + for (i = 0; i < q->len; i++) { + data[i] = ((u8_t*) psent)[cnt++]; + } + + q = q->next; + } + } else { + return ESPCONN_MEM; + } + + dst_port = pespconn->proto.udp->remote_port; + IP4_ADDR(&dst_ip, pespconn->proto.udp->remote_ip[0], + pespconn->proto.udp->remote_ip[1], pespconn->proto.udp->remote_ip[2], + pespconn->proto.udp->remote_ip[3]); + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %x %d\n", __LINE__, upcb->remote_ip, upcb->remote_port)); + +#if LWIP_IPV6 || LWIP_IGMP + ipX_addr_t* dst_ip_route = ip_2_ipX(&dst_ip); + + if (ipX_addr_ismulticast(PCB_ISIPV6(upcb), dst_ip_route)) { + /* For multicast, find a netif based on source address. */ +#if LWIP_IPV6 + if (PCB_ISIPV6(upcb)) { + dst_ip_route = &upcb->local_ip; + } else +#endif /* LWIP_IPV6 */ + { +#if LWIP_IGMP + upcb->multicast_ip.addr = dst_ip.addr; +#endif /* LWIP_IGMP */ + } + } + +#endif /* LWIP_IPV6 || LWIP_IGMP */ + + struct netif* sta_netif = (struct netif*)eagle_lwip_getif(0x00); + struct netif* ap_netif = (struct netif*)eagle_lwip_getif(0x01); + + if (wifi_get_opmode() == ESPCONN_AP_STA && default_interface == ESPCONN_AP_STA && sta_netif != NULL && ap_netif != NULL) { + if (netif_is_up(sta_netif) && netif_is_up(ap_netif) && \ + ip_addr_isbroadcast(&(upcb->remote_ip.ip4), sta_netif) && \ + ip_addr_isbroadcast(&(upcb->remote_ip.ip4), ap_netif)) { + + p_temp = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); + + if (pbuf_copy(p_temp, p) != ERR_OK) { + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sendto: copying to new pbuf failed\n")); + return ESPCONN_ARG; + } + + netif_set_default(sta_netif); + err = udp_sendto(upcb, p_temp, &dst_ip, dst_port); + pbuf_free(p_temp); + netif_set_default(ap_netif); + } + } + + err = udp_sendto(upcb, p, &dst_ip, dst_port); + + if (p->ref != 0) { + pbuf_free(p); + pudp_sent->pcommon.ptrbuf = psent + datalen; + pudp_sent->pcommon.cntr = length - datalen; + pudp_sent->pcommon.err = err; + espconn_data_sent(pudp_sent, ESPCONN_SENDTO); + + if (err > 0) { + return ESPCONN_IF; + } + + return err; + } else { + pbuf_free(p); + return ESPCONN_RTE; + } +} + +/****************************************************************************** + * FunctionName : espconn_udp_server_recv + * Description : This callback will be called when receiving a datagram. + * Parameters : arg -- user supplied argument + * upcb -- the udp_pcb which received data + * p -- the packet buffer that was received + * addr -- the remote IP address from which the packet was received + * port -- the remote port from which the packet was received + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_udp_recv(void* arg, struct udp_pcb* upcb, struct pbuf* p, + struct ip_addr* addr, u16_t port) +{ + espconn_msg* precv = arg; + u8_t* pdata = NULL; + u16_t length = 0; + struct ip_info ipconfig; + + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_server_recv %d %p\n", __LINE__, upcb)); + //ESPCONN_API_MUTEX_TAKE(); + + precv->pcommon.remote_ip[0] = ip4_addr1_16(addr); + precv->pcommon.remote_ip[1] = ip4_addr2_16(addr); + precv->pcommon.remote_ip[2] = ip4_addr3_16(addr); + precv->pcommon.remote_ip[3] = ip4_addr4_16(addr); + precv->pcommon.remote_port = port; + precv->pcommon.pcb = upcb; + + if (wifi_get_opmode() != 1) { + wifi_get_ip_info(1, &ipconfig); + + if (!ip_addr_netcmp(addr, &ipconfig.ip, &ipconfig.netmask)) { + wifi_get_ip_info(0, &ipconfig); + } + } else { + wifi_get_ip_info(0, &ipconfig); + } + + precv->pespconn->proto.udp->local_ip[0] = ip4_addr1_16(&ipconfig.ip); + precv->pespconn->proto.udp->local_ip[1] = ip4_addr2_16(&ipconfig.ip); + precv->pespconn->proto.udp->local_ip[2] = ip4_addr3_16(&ipconfig.ip); + precv->pespconn->proto.udp->local_ip[3] = ip4_addr4_16(&ipconfig.ip); + + if (p != NULL) { + pdata = (u8_t*)os_zalloc(p ->tot_len + 1); + length = pbuf_copy_partial(p, pdata, p ->tot_len, 0); + precv->pcommon.pcb = upcb; + pbuf_free(p); + + if (length != 0) { + if (precv->pespconn->recv_callback != NULL) { + precv->pespconn->recv_callback(precv->pespconn, pdata, length); + } + } + + os_free(pdata); + //ESPCONN_API_MUTEX_GIVE(); + } else { + //ESPCONN_API_MUTEX_GIVE(); + return; + } +} + +/****************************************************************************** + * FunctionName : espconn_udp_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_udp_disconnect(espconn_msg* pdiscon) +{ + if (pdiscon == NULL) { + return; + } + + struct udp_pcb* upcb = pdiscon->pcommon.pcb; + + udp_disconnect(upcb); + + udp_remove(upcb); + + espconn_list_delete(&plink_active, pdiscon); + + os_free(pdiscon); + + pdiscon = NULL; +} + +/****************************************************************************** + * FunctionName : espconn_udp_server + * Description : Initialize the server: set up a PCB and bind it to the port + * Parameters : pespconn -- the espconn used to build server + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_udp_server(struct espconn* pespconn) +{ + struct udp_pcb* upcb = NULL; + espconn_msg* pserver = NULL; + upcb = udp_new(); + + if (upcb == NULL) { + return ESPCONN_MEM; + } else { + pserver = (espconn_msg*)os_zalloc(sizeof(espconn_msg)); + + if (pserver == NULL) { + udp_remove(upcb); + return ESPCONN_MEM; + } + + pserver->pcommon.pcb = upcb; + pserver->pespconn = pespconn; + espconn_list_creat(&plink_active, pserver); + udp_bind(upcb, IP_ADDR_ANY, pserver->pespconn->proto.udp->local_port); + udp_recv(upcb, espconn_udp_recv, (void*)pserver); + return ESPCONN_OK; + } +} + +/****************************************************************************** + * FunctionName : espconn_igmp_leave + * Description : leave a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_igmp_leave(ip_addr_t* host_ip, ip_addr_t* multicast_ip) +{ +#if LWIP_IGMP + + if (igmp_leavegroup(host_ip, multicast_ip) != ERR_OK) { + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_leave_multigrup failed!\n")); + return -1; + }; + +#endif + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_igmp_join + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_igmp_join(ip_addr_t* host_ip, ip_addr_t* multicast_ip) +{ +#if LWIP_IGMP + + if (igmp_joingroup(host_ip, multicast_ip) != ERR_OK) { + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_join_multigrup failed!\n")); + return -1; + }; + +#endif + /* join to any IP address at the port */ + return ESPCONN_OK; +}