/* * 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(); }