1817 lines
62 KiB
C
1817 lines
62 KiB
C
|
/*
|
||
|
* ESPRESSIF MIT License
|
||
|
*
|
||
|
* Copyright (c) 2017 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||
|
*
|
||
|
* 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
|