/****************************************************************************** * Copyright 2013-2014 Espressif Systems (Wuxi) * * FileName: espconn.c * * Description: espconn interface for user * * Modification history: * 2014/3/31, v1.0 create this file. *******************************************************************************/ #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 "ets_sys.h" #include "os_type.h" //#include "os.h" #include "lwip/mem.h" #include "lwip/app/espconn_tcp.h" #include "lwip/app/espconn_udp.h" #include "lwip/app/espconn.h" #include "user_interface.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; os_memcpy(pesp_dest->proto.tcp->remote_ip, pesp_source->proto.tcp->remote_ip, 4); os_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; os_memcpy(pesp_dest->proto.udp->remote_ip, pesp_source->proto.udp->remote_ip, 4); os_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; if (espconn == NULL) { return ESPCONN_ARG; } else if (espconn ->type != ESPCONN_TCP) 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()) 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){ return ESPCONN_RTE; } } else if(wifi_get_opmode() == ESPCONN_AP){ wifi_get_ip_info(AP_NETIF,&ipinfo); if (ipinfo.ip.addr == 0){ 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) return ESPCONN_RTE; } else if (connect_status == STATION_IDLE){ return ESPCONN_RTE; } else { 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){ return ESPCONN_ISCONN; } } } value = espconn_tcp_client(espconn); 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; if (espconn == NULL) { return ESPCONN_ARG; } else if (espconn ->type != ESPCONN_UDP){ 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){ return ESPCONN_ISCONN; } } } value = espconn_udp_server(espconn); 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; if (espconn == NULL || psent == NULL || length == 0) { 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) return ESPCONN_MAXNUM; } else { struct tcp_pcb *pcb = pnode->pcommon.pcb; if (pcb->snd_queuelen >= TCP_SND_QUEUELEN) return ESPCONN_MAXNUM; } pbuf = (espconn_buf*) os_zalloc(sizeof(espconn_buf)); if (pbuf == NULL) 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; // } return error; } else return ESPCONN_ARG; break; case ESPCONN_UDP: return espconn_udp_sent(pnode, psent, length); break; default : break; } } 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; } /*Find the node depend on the espconn message*/ value = espconn_find_connection(espconn, &pnode); if (value && espconn->type == ESPCONN_UDP) return espconn_udp_sendto(pnode, psent, length); else return ESPCONN_ARG; } /****************************************************************************** * 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; } /****************************************************************************** * 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; } /****************************************************************************** * 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; } /****************************************************************************** * 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; } /****************************************************************************** * 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; } /****************************************************************************** * 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; } /****************************************************************************** * 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; } /****************************************************************************** * 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; } /****************************************************************************** * 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; if ((espconn == NULL) || (espconn->type == ESPCONN_UDP)) return ESPCONN_ARG; pget_msg = pserver_list; while (pget_msg != NULL){ if (pget_msg->pespconn == espconn){ return pget_msg->count_opt; } pget_msg = pget_msg->pnext; } 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; if ((espconn == NULL) || (num > MEMP_NUM_TCP_PCB) || (espconn->type == ESPCONN_UDP)) return ESPCONN_ARG; pset_msg = pserver_list; while (pset_msg != NULL){ if (pset_msg->pespconn == espconn){ pset_msg->count_opt = num; return ESPCONN_OK; } pset_msg = pset_msg->pnext; } 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; /*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; return ESPCONN_OK; } } if (plist == NULL) 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 = pesp_buf; uint8 pbuf_num = 0; /*polling the list get the count of the current node*/ while (pbuf_list != NULL){ pbuf_list = pbuf_list->pnext; pbuf_num ++; } 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; os_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; os_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; os_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) return ESPCONN_ARG; 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; if (espconn == NULL) { return ESPCONN_ARG; } else if (espconn ->type != ESPCONN_TCP) 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){ return ESPCONN_ISCONN; } } } value = espconn_tcp_server(espconn); 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; 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; return ESPCONN_OK; } else 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; return ESPCONN_OK; } ptime_msg = ptime_msg->pnext; } } 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; if (espconn == NULL) { return ESPCONN_ARG;; } else if (espconn ->type != ESPCONN_TCP) 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) return ESPCONN_INPROGRESS; espconn_tcp_disconnect(pnode,0); //1 force, 0 normal return ESPCONN_OK; } else 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; if (espconn == NULL) { return ESPCONN_ARG;; } else if (espconn ->type != ESPCONN_TCP) return ESPCONN_ARG; /*Find the node depend on the espconn message*/ value = espconn_find_connection(espconn, &pnode); if (value){ /*protect for redisconnection*/ if (espconn->state == ESPCONN_CLOSE) return ESPCONN_INPROGRESS; espconn_tcp_disconnect(pnode,1); //1 force, 0 normal return ESPCONN_OK; } else 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; if (espconn == NULL || infoarg == NULL) { return ESPCONN_ARG;; } else if (espconn->type != ESPCONN_TCP) 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) 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; os_memcpy(infoarg,(void*)&pnode->pcommon.packet_info, sizeof(struct espconn_packet)); return ESPCONN_OK; } else { switch (espconn->state){ case ESPCONN_CLOSE: os_memcpy(infoarg,(void*)&pktinfo[0], sizeof(struct espconn_packet)); err = ESPCONN_OK; break; case ESPCONN_NONE: os_memcpy(infoarg,(void*)&pktinfo[1], sizeof(struct espconn_packet)); err = ESPCONN_OK; break; default: err = ESPCONN_ARG; break; } 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; if (espconn == NULL) { return ESPCONN_ARG;; } else if (espconn->type != ESPCONN_TCP) 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); return ESPCONN_OK; } else 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; if (espconn == NULL) { return ESPCONN_ARG;; } else if (espconn->type != ESPCONN_TCP) 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); return ESPCONN_OK; } else 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; if (espconn == NULL || optarg == NULL) { return ESPCONN_ARG;; } else if (espconn->type != ESPCONN_TCP) 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; } return ret; } else 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; if (espconn == NULL || optarg == NULL) { return ESPCONN_ARG;; } else if (espconn->type != ESPCONN_TCP) 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; } return ret; } else 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; if (espconn == NULL) { return ESPCONN_ARG; } else if (espconn ->type != ESPCONN_UDP) 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); return ESPCONN_OK; } else 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; do { port = os_random(); if (port < 0) { port = os_random() - port; } port %= 0xc350; if (port < 0x400) { port += 0x400; } } while (port == randnum); randnum = port; 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) { return dns_gethostbyname(hostname, addr, found, pespconn); } /****************************************************************************** * 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) { dns_setserver(numdns,dnsserver); }