nodemcu-firmware/app/ssl/app/espconn_ssl.c

1101 lines
36 KiB
C

/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: espconn_ssl.c
*
* Description: ssl encrypt interface
*
* Modification history:
* 2014/3/31, v1.0 create this file.
*******************************************************************************/
#include "lwip/netif.h"
#include "netif/etharp.h"
#include "lwip/tcp.h"
#include "lwip/ip.h"
#include "lwip/init.h"
#include "lwip/tcp_impl.h"
#include "ssl/ssl_os_port.h"
#include "ssl/app/espconn_ssl.h"
#include "ets_sys.h"
#include "os_type.h"
//#include "os.h"
#include "lwip/app/espconn.h"
struct pbuf *psslpbuf = NULL;
extern espconn_msg *plink_active;
static err_t espconn_ssl_crecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
static err_t espconn_ssl_srecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
static void espconn_ssl_sclose(void *arg, struct tcp_pcb *pcb);
static void espconn_ssl_cclose(void *arg, struct tcp_pcb *pcb);
/////////////////////////////common function///////////////////////////////////
/******************************************************************************
* FunctionName : display_session_id
* Description : Display what session id we have.
* Parameters :
* Returns :
*******************************************************************************/
static void ICACHE_FLASH_ATTR display_session_id(SSL *ssl)
{
int i;
const uint8_t *session_id = ssl_get_session_id(ssl);
int sess_id_size = ssl_get_session_id_size(ssl);
if (sess_id_size > 0) {
ssl_printf("-----BEGIN SSL SESSION PARAMETERS-----\n");
for (i = 0; i < sess_id_size; i++) {
ssl_printf("%02x", session_id[i]);
}
ssl_printf("\n-----END SSL SESSION PARAMETERS-----\n");
//TTY_FLUSH();
}
}
/******************************************************************************
* FunctionName : display_cipher
* Description : Display what cipher we are using
* Parameters :
* Returns :
*******************************************************************************/
static void ICACHE_FLASH_ATTR display_cipher(SSL *ssl)
{
ssl_printf("CIPHER is ");
switch (ssl_get_cipher_id(ssl)) {
case SSL_AES128_SHA:
ssl_printf("AES128-SHA");
break;
case SSL_AES256_SHA:
ssl_printf("AES256-SHA");
break;
case SSL_RC4_128_SHA:
ssl_printf("RC4-SHA");
break;
case SSL_RC4_128_MD5:
ssl_printf("RC4-MD5");
break;
default:
ssl_printf("Unknown - %d", ssl_get_cipher_id(ssl));
break;
}
ssl_printf("\n");
//TTY_FLUSH();
}
/******************************************************************************
* FunctionName : espconn_ssl_reconnect
* Description : reconnect with host
* Parameters : arg -- Additional argument to pass to the callback function
* Returns : none
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_reconnect(void *arg)
{
espconn_msg *pssl_recon = arg;
struct espconn *espconn = NULL;
ssl_msg *pssl = NULL;
sint8 ssl_reerr = 0;
if (pssl_recon != NULL) {
espconn = pssl_recon->preverse;
if (pssl_recon->pespconn != NULL){
if (espconn != NULL){
/*espconn_copy_partial(espconn, pssl_recon->pespconn);
if (pssl_recon->pespconn->proto.tcp != NULL){
os_free(pssl_recon->pespconn->proto.tcp);
pssl_recon->pespconn->proto.tcp = NULL;
}
os_free(pssl_recon->pespconn);
pssl_recon->pespconn = NULL;*/
espconn = pssl_recon->preverse;
} else {
espconn = pssl_recon->pespconn;
}
}
pssl = pssl_recon->pssl;
ssl_reerr = pssl_recon->pcommon.err;
if (pssl != NULL) {
if (pssl->ssl) {
ssl_free(pssl->ssl);
}
if (pssl->ssl_ctx) {
ssl_ctx_free(pssl->ssl_ctx);
}
os_free(pssl);
pssl = NULL;
pssl_recon->pssl = pssl;
}
os_free(pssl_recon);
pssl_recon = NULL;
if (espconn ->proto.tcp->reconnect_callback != NULL) {
espconn ->proto.tcp->reconnect_callback(espconn, ssl_reerr);
}
} else {
ssl_printf("espconn_ssl_reconnect err\n");
}
}
/******************************************************************************
* FunctionName : espconn_ssl_dissuccessful
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_dissuccessful(void *arg)
{
espconn_msg *pdiscon = arg;
struct espconn *espconn = NULL;
struct tcp_pcb *pcb = NULL;
ssl_msg *pssl = NULL;
if (pdiscon != NULL) {
espconn = pdiscon->preverse;
if (pdiscon->pespconn != NULL){
if (espconn != NULL){
/*espconn_copy_partial(espconn, pdiscon->pespconn);
if (pdiscon->pespconn->proto.tcp != NULL){
os_free(pdiscon->pespconn->proto.tcp);
pdiscon->pespconn->proto.tcp = NULL;
}
os_free(pdiscon->pespconn);
pdiscon->pespconn = NULL;*/
espconn = pdiscon->preverse;
} else{
espconn = pdiscon->pespconn;
}
pcb = pdiscon->pcommon.pcb;
tcp_arg(pcb, NULL);
tcp_err(pcb, NULL);
}
pssl = pdiscon->pssl;
if (pssl != NULL) {
if (pssl->ssl) {
ssl_free(pssl->ssl);
}
if (pssl->ssl_ctx) {
ssl_ctx_free(pssl->ssl_ctx);
}
os_free(pssl);
pssl = NULL;
pdiscon->pssl = pssl;
}
os_free(pdiscon);
pdiscon = NULL;
if (espconn ->proto.tcp->disconnect_callback != NULL) {
espconn ->proto.tcp->disconnect_callback(espconn);
}
} else {
espconn_printf("espconn_ssl_dissuccessful err\n");
}
}
/******************************************************************************
* FunctionName : espconn_ssl_write
* Description : sent data for client or server
* Parameters : void *arg -- client or server to send
* uint8* psent -- Data to send
* uint16 length -- Length of data to send
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
espconn_ssl_sent(void *arg, uint8 *psent, uint16 length)
{
espconn_msg *pssl_sent = arg;
struct tcp_pcb *pcb = NULL;
ssl_msg *pssl = NULL;
u16_t len = 0;
int res = 0;
ssl_printf("espconn_ssl_sent pcb %p psent %p length %d\n", arg, psent, length);
if (pssl_sent == NULL || psent == NULL || length == 0) {
return;
}
pcb = pssl_sent->pcommon.pcb;
pssl = pssl_sent->pssl;
if (RT_MAX_PLAIN_LENGTH < length) {
len = RT_MAX_PLAIN_LENGTH;
} else {
len = length;
}
if (pssl != NULL) {
if (pssl->ssl != NULL) {
pssl->ssl->SslClient_pcb = pcb;
res = ssl_write(pssl->ssl, psent, len);
pssl_sent->pcommon.ptrbuf = psent + len;
pssl_sent->pcommon.cntr = length - len;
}
}
}
/******************************************************************************
* FunctionName : espconn_sent_packet
* Description : sent data for client or server
* Parameters : void *arg -- client or server to send
* uint8* psent -- Data to send
* uint16 length -- Length of data to send
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
espconn_sent_packet(struct tcp_pcb *pcb, uint8 *psent, uint16 length)
{
err_t err = 0;
u16_t len = 0;
if (pcb == NULL || psent == NULL || length == 0) {
return;
}
if (tcp_sndbuf(pcb) < length) {
len = tcp_sndbuf(pcb);
} else {
len = length;
}
if (len > (2 * pcb->mss)) {
len = 2 * pcb->mss;
}
do {
err = tcp_write(pcb, psent, len, 0);
if (err == ERR_MEM) {
len /= 2;
}
} while (err == ERR_MEM && len > 1);
if (err == ERR_OK) {
err = tcp_output(pcb);
}
}
////////////////////////////////client function////////////////////////////////
/******************************************************************************
* FunctionName : espconn_ssl_cclose_cb
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_cclose_cb(void *arg)
{
static uint16 timecount = 0;
espconn_msg *pcclose_cb = arg;
if (pcclose_cb == NULL) {
return;
}
struct tcp_pcb *pcb = pcclose_cb->pcommon.pcb;
ssl_printf("espconn_ssl_cclose_cb %d %d\n", pcb->state, pcb->nrtx);
if (pcb->state == TIME_WAIT || pcb->state == CLOSED) {
pcclose_cb->pespconn ->state = ESPCONN_CLOSE;
/*remove the node from the client's active connection list*/
espconn_list_delete(&plink_active, pcclose_cb);
espconn_ssl_dissuccessful((void *)pcclose_cb);
} else {
os_timer_arm(&pcclose_cb->pcommon.ptimer, TCP_FAST_INTERVAL, 0);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_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_ssl_cclose(void *arg, struct tcp_pcb *pcb)
{
espconn_msg *pcclose = arg;
os_timer_disarm(&pcclose->pcommon.ptimer);
os_timer_setfn(&pcclose->pcommon.ptimer, espconn_ssl_cclose_cb, pcclose);
os_timer_arm(&pcclose->pcommon.ptimer, TCP_FAST_INTERVAL, 0);
tcp_recv(pcb, NULL);
pcclose->pcommon.err = tcp_close(pcb);
ssl_printf("espconn_ssl_cclose %d\n", pcclose->pcommon.err);
if (pcclose->pcommon.err != ERR_OK) {
/* closing failed, try again later */
tcp_recv(pcb, espconn_ssl_crecv);
} else {
tcp_sent(pcb, NULL);
tcp_poll(pcb, NULL, 0);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_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_ssl_csent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
espconn_msg *psent = arg;
ssl_msg *pssl = psent->pssl;
psent->pcommon.pcb = pcb;
if (pssl->quiet == true) {
int pkt_size = pssl->ssl->bm_index + SSL_RECORD_SIZE;
u16_t max_len = 2 * pcb->mss;
pssl->pkt_length += len;
ssl_printf("espconn_ssl_csent %d %d %d\n", len, pssl->pkt_length, pkt_size);
if (pssl->pkt_length == pkt_size){
pssl->ssl->bm_index = 0;
pssl->pkt_length = 0;
if (psent->pcommon.cntr == 0) {
psent->pespconn->state = ESPCONN_CONNECT;
if (psent->pespconn->sent_callback != NULL) {
psent->pespconn->sent_callback(psent->pespconn);
}
} else {
espconn_ssl_sent(psent, psent->pcommon.ptrbuf, psent->pcommon.cntr);
}
} else {
if (len == max_len){
espconn_sent_packet(pcb, &pssl->ssl->bm_all_data[pssl->pkt_length], pkt_size - pssl->pkt_length);
}
}
} else {
ssl_printf("espconn_ssl_csent %p %p %d\n", pcb, pssl->ssl->bm_all_data, len);
}
return ERR_OK;
}
/******************************************************************************
* FunctionName : espconn_sslclient_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_ssl_crecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
u16_t ret = 0;
espconn_msg *precv = arg;
ssl_msg *pssl = precv->pssl;
ssl_printf("espconn_ssl_crecv %d %p %p\n", __LINE__, pssl->ssl, p);
if (p != NULL) {
tcp_recved(pcb, p ->tot_len);
if (pssl->ssl == NULL) {
pbuf_free(p);
} else {
pssl->ssl->ssl_pbuf = p;
if (ssl_handshake_status(pssl->ssl) != SSL_OK) {
ret = ssl_read(pssl->ssl, NULL);
pbuf_free(p);
if (ret != SSL_OK){
os_printf("client handshake failed\n");
espconn_ssl_cclose(arg, pcb);
}
}
if (ssl_handshake_status(pssl->ssl) == SSL_OK) {
if (!pssl->quiet) {
ssl_printf("client handshake need size %d\n", system_get_free_heap_size());
const char *common_name = ssl_get_cert_dn(pssl->ssl,
SSL_X509_CERT_COMMON_NAME);
if (common_name) {
ssl_printf("Common Name:\t\t\t%s\n", common_name);
}
display_session_id(pssl->ssl);
display_cipher(pssl->ssl);
pssl->quiet = true;
os_printf("client handshake ok!\n");
REG_CLR_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(80);
precv->pespconn->state = ESPCONN_CONNECT;
precv->pcommon.pcb = pcb;
pbuf_free(p);
if (precv->pespconn->proto.tcp->connect_callback != NULL) {
precv->pespconn->proto.tcp->connect_callback(precv->pespconn);
}
} else {
uint8_t *read_buf = NULL;
ret = ssl_read(pssl->ssl, &read_buf);
precv->pespconn->state = ESPCONN_READ;
precv->pcommon.pcb = pcb;
pbuf_free(p);
if (precv->pespconn->recv_callback != NULL && read_buf != NULL) {
precv->pespconn->recv_callback(precv->pespconn, read_buf, ret);
}
precv->pespconn->state = ESPCONN_CONNECT;
}
}
}
}
if (err == ERR_OK && p == NULL) {
espconn_ssl_cclose(precv, pcb);
}
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_ssl_cerr(void *arg, err_t err)
{
espconn_msg *pssl_cerr = arg;
struct tcp_pcb *pcb = NULL;
LWIP_UNUSED_ARG(err);
if (pssl_cerr != NULL) {
os_timer_disarm(&pssl_cerr->pcommon.ptimer);
pcb = pssl_cerr->pcommon.pcb;
pssl_cerr->pespconn->state = ESPCONN_CLOSE;
espconn_printf("espconn_ssl_cerr %d %d %d\n", pcb->state, pcb->nrtx, err);
/*remove the node from the client's active connection list*/
espconn_list_delete(&plink_active, pssl_cerr);
if (err == ERR_ABRT) {
switch (pcb->state) {
case SYN_SENT:
if (pcb->nrtx == TCP_SYNMAXRTX) {
pssl_cerr->pcommon.err = ESPCONN_CONN;
} else {
pssl_cerr->pcommon.err = err;
}
break;
case ESTABLISHED:
if (pcb->nrtx == TCP_MAXRTX) {
pssl_cerr->pcommon.err = ESPCONN_TIMEOUT;
} else {
pssl_cerr->pcommon.err = err;
}
break;
case FIN_WAIT_1:
if (pcb->nrtx == TCP_MAXRTX) {
pssl_cerr->pcommon.err = ESPCONN_CLSD;
} else {
pssl_cerr->pcommon.err = err;
}
break;
case FIN_WAIT_2:
pssl_cerr->pcommon.err = ESPCONN_CLSD;
break;
case CLOSED:
pssl_cerr->pcommon.err = ESPCONN_CONN;
break;
default :
break;
}
} else {
pssl_cerr->pcommon.err = err;
}
os_timer_setfn(&pssl_cerr->pcommon.ptimer, espconn_ssl_reconnect, pssl_cerr);
os_timer_arm(&pssl_cerr->pcommon.ptimer, 10, 0);
}
}
#if 0
/******************************************************************************
* FunctionName : espconn_ssl_cpoll
* 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_ssl_cpoll(void *arg, struct tcp_pcb *pcb)
{
ssl_printf("espconn_ssl_cpoll %p %d\n", pcb, pcb->state);
struct espconn *espconn = arg;
if (arg == NULL) {
tcp_abandon(pcb, 0);
tcp_poll(pcb, NULL, 0);
return ERR_ABRT;
}
if (pcb ->state == ESTABLISHED) {
espconn->recv_check ++;
if (espconn ->recv_check == 0x05){
//tcp_poll(pcb, espconn_ssl_cpoll, 0);
espconn->recv_check = 0;
espconn_ssl_cclose(arg, pcb);
}
} else {
//tcp_poll(pcb, espconn_ssl_cpoll, 0);
espconn_ssl_cclose(arg, pcb);
}
return ERR_OK;
}
#endif
/******************************************************************************
* FunctionName : espconn_sslclient_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_ssl_connect(void *arg, struct tcp_pcb *tpcb, err_t err)
{
espconn_msg *pconnect = arg;
ssl_msg *pssl = NULL;
uint32_t options;
options = SSL_SERVER_VERIFY_LATER | SSL_DISPLAY_CERTS | SSL_NO_DEFAULT_KEY;
ssl_printf("espconn_ssl_connect %p %p %p %d\n", tpcb, arg, pespconn->psecure, system_get_free_heap_size());
//if (pespconn->psecure != NULL){
// return ERR_ISCONN;
//}
pconnect->pcommon.pcb = tpcb;
pssl = (ssl_msg *)os_zalloc(sizeof(ssl_msg));
pconnect->pssl = pssl;
if (pssl == NULL) {
return ERR_MEM;
}
REG_SET_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(160);
os_printf("client handshake start.\n");
pssl->quiet = false;
pssl->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS);
if (pssl->ssl_ctx == NULL) {
return ERR_MEM;
}
ssl_printf("espconn_ssl_client ssl_ctx %p\n", pssl->ssl_ctx);
pssl->ssl = SSLClient_new(pssl->ssl_ctx, tpcb, NULL, 0);
if (pssl->ssl == NULL) {
return ERR_MEM;
}
tcp_arg(tpcb, arg);
tcp_sent(tpcb, espconn_ssl_csent);
tcp_recv(tpcb, espconn_ssl_crecv);
//tcp_poll(tpcb, espconn_ssl_cpoll, 6);
return ERR_OK;
}
/******************************************************************************
* FunctionName : espconn_ssl_disconnect
* Description : A new incoming connection has been disconnected.
* Parameters : espconn -- the espconn used to disconnect with host
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR espconn_ssl_disconnect(espconn_msg *pdis)
{
if (pdis != NULL) {
if (pdis->preverse == NULL)
espconn_ssl_cclose(pdis, pdis->pcommon.pcb);
else
espconn_ssl_sclose(pdis, pdis->pcommon.pcb);
} else {
ssl_printf("espconn_ssl_disconnect err.\n");
}
}
/******************************************************************************
* FunctionName : espconn_ssl_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_ssl_client(struct espconn *espconn)
{
struct tcp_pcb *pcb;
struct ip_addr ipaddr;
espconn_msg *pclient = NULL;
pclient = plink_active;
while(pclient != NULL){
if (pclient->pssl != NULL)
return ESPCONN_ISCONN;
pclient = pclient->pnext;
}
pclient = (espconn_msg *)os_zalloc(sizeof(espconn_msg));
if (pclient == NULL){
return ESPCONN_MEM;
}
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]);
pcb = tcp_new();
if (pcb == NULL) {
espconn ->state = ESPCONN_NONE;
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_ssl_cerr);
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);
pclient->pcommon.err = tcp_connect(pcb, &ipaddr, pclient->pespconn->proto.tcp->remote_port, espconn_ssl_connect);
return ESPCONN_OK;
}
}
/////////////////////////////server's function/////////////////////////////////
/******************************************************************************
* FunctionName : espconn_ssl_sclose_cb
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_sclose_cb(void *arg)
{
static uint16 timecount = 0;
espconn_msg *psclose_cb = arg;
if (psclose_cb == NULL) {
return;
}
struct tcp_pcb *pcb = psclose_cb->pcommon.pcb;
ssl_printf("espconn_ssl_sclose_cb %d %d\n", pcb->state, pcb->nrtx);
if (pcb->state == CLOSED || pcb->state == TIME_WAIT) {
psclose_cb ->pespconn ->state = ESPCONN_CLOSE;
psclose_cb->pespconn->link_cnt --;
/*remove the node from the server's active connection list*/
espconn_list_delete(&plink_active, psclose_cb);
espconn_ssl_dissuccessful((void *)psclose_cb);
} else {
os_timer_arm(&psclose_cb->pcommon.ptimer, TCP_FAST_INTERVAL, 0);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_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_ssl_sclose(void *arg, struct tcp_pcb *pcb)
{
espconn_msg *psclose = arg;
os_timer_disarm(&psclose->pcommon.ptimer);
os_timer_setfn(&psclose->pcommon.ptimer, espconn_ssl_sclose_cb, psclose);
os_timer_arm(&psclose->pcommon.ptimer, TCP_FAST_INTERVAL, 0);
tcp_recv(pcb, NULL);
psclose->pcommon.err = tcp_close(pcb);
if (psclose->pcommon.err != ERR_OK) {
/* closing failed, try again later */
tcp_recv(pcb, espconn_ssl_srecv);
} else {
tcp_sent(pcb, NULL);
tcp_poll(pcb, NULL, 0);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_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_ssl_ssent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
espconn_msg *psent = arg;
ssl_msg *pssl = psent->pssl;
psent->pcommon.pcb = pcb;
psent->pcommon.recv_check = 0;
if (ssl_handshake_status(pssl->ssl) == SSL_OK) {
if (!pssl->quiet) {
ssl_printf("espconn_ssl_ssent %p %d\n",pcb, system_get_free_heap_size());
const char *common_name = ssl_get_cert_dn(pssl->ssl, SSL_X509_CERT_COMMON_NAME);
if (common_name) {
ssl_printf("Common Name:\t\t\t%s\n", common_name);
}
display_session_id(pssl->ssl);
display_cipher(pssl->ssl);
pssl->quiet = true;
os_printf("server handshake ok!\n");
REG_CLR_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(80);
psent->pespconn->state = ESPCONN_CONNECT;
if (psent->pespconn->proto.tcp->connect_callback != NULL) {
psent->pespconn->proto.tcp->connect_callback(psent->pespconn);
}
} else {
int pkt_size = pssl->ssl->bm_index + SSL_RECORD_SIZE;
u16_t max_len = 2 * pcb->mss;
pssl->pkt_length += len;
ssl_printf("espconn_ssl_ssent %d %d %d\n", len, pssl->pkt_length, pkt_size);
if (pssl->pkt_length == pkt_size){
pssl->ssl->bm_index = 0;
pssl->pkt_length = 0;
if (psent->pcommon.cntr == 0) {
psent->pespconn->state = ESPCONN_CONNECT;
if (psent->pespconn->sent_callback != NULL) {
psent->pespconn->sent_callback(psent->pespconn);
}
} else {
espconn_ssl_sent(psent, psent->pcommon.ptrbuf, psent->pcommon.cntr);
}
} else {
if (len == max_len){
espconn_sent_packet(pcb, &pssl->ssl->bm_all_data[pssl->pkt_length], pkt_size - pssl->pkt_length);
}
}
}
} else {
ssl_printf("espconn_ssl_ssent %p %p %d\n",pcb, pssl->ssl->bm_all_data, len);
}
return ERR_OK;
}
/******************************************************************************
* FunctionName : espconn_sslclient_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_ssl_srecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
u16_t ret = 0;
espconn_msg *precv = arg;
ssl_msg *pssl = precv->pssl;
ssl_printf("espconn_ssl_srecv %d %p %p\n", __LINE__, pcb, p);
if (p != NULL) {
tcp_recved(pcb, p ->tot_len);
precv->pcommon.recv_check = 0;
if (pssl->ssl == NULL) {
pbuf_free(p);
} else {
pssl->ssl->ssl_pbuf = p;
if (ssl_handshake_status(pssl->ssl) != SSL_OK) {
ret = ssl_read(pssl->ssl, NULL);
pbuf_free(p);
if (ret != SSL_OK){
os_printf("server handshake failed.\n");
espconn_ssl_sclose(arg, pcb);
}
} else {
uint8_t *read_buf = NULL;
ret = ssl_read(pssl->ssl, &read_buf);
precv->pespconn->state = ESPCONN_READ;
precv->pcommon.pcb = pcb;
pbuf_free(p);
if (precv->pespconn->recv_callback != NULL && read_buf != NULL) {
precv->pespconn->recv_callback(precv->pespconn, read_buf, ret);
}
precv->pespconn->state = ESPCONN_CONNECT;
}
}
}
if (err == ERR_OK && p == NULL) {
espconn_ssl_sclose(precv, pcb);
}
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_ssl_spoll(void *arg, struct tcp_pcb *pcb)
{
ssl_printf("espconn_ssl_spoll %p %d\n", pcb, pcb->state);
espconn_msg *pspoll = arg;
if (arg == NULL) {
tcp_abandon(pcb, 0);
tcp_poll(pcb, NULL, 0);
return ERR_ABRT;
}
if (pcb ->state == ESTABLISHED) {
pspoll ->pcommon.recv_check ++;
if (pspoll ->pcommon.recv_check == pspoll ->pcommon.timeout){
tcp_poll(pcb, NULL, 0);
pspoll ->pcommon.recv_check = 0;
espconn_ssl_sclose(arg, pcb);
}
} else {
tcp_poll(pcb, NULL, 0);
espconn_ssl_sclose(arg, pcb);
}
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
espconn_ssl_serr(void *arg, err_t err)
{
espconn_msg *pserr = arg;
struct tcp_pcb *pcb = NULL;
LWIP_UNUSED_ARG(err);
if (pserr != NULL) {
os_timer_disarm(&pserr->pcommon.ptimer);
pcb = pserr->pcommon.pcb;
pserr->pespconn->state = ESPCONN_CLOSE;
/*remove the node from the server's active connection list*/
espconn_list_delete(&plink_active, pserr);
if (err == ERR_ABRT) {
switch (pcb->state) {
case SYN_RCVD:
if (pcb->nrtx == TCP_SYNMAXRTX) {
pserr->pcommon.err = ESPCONN_CONN;
} else {
pserr->pcommon.err = err;
}
break;
case ESTABLISHED:
if (pcb->nrtx == TCP_MAXRTX) {
pserr->pcommon.err = ESPCONN_TIMEOUT;
} else {
pserr->pcommon.err = err;
}
break;
case CLOSE_WAIT:
if (pcb->nrtx == TCP_MAXRTX) {
pserr->pcommon.err = ESPCONN_CLSD;
} else {
pserr->pcommon.err = err;
}
break;
case LAST_ACK:
pserr->pcommon.err = ESPCONN_CLSD;
break;
case CLOSED:
pserr->pcommon.err = ESPCONN_CONN;
break;
default :
break;
}
} else {
pserr->pcommon.err = err;
}
os_timer_setfn(&pserr->pcommon.ptimer, espconn_ssl_reconnect, pserr);
os_timer_arm(&pserr->pcommon.ptimer, 10, 0);
}
}
/******************************************************************************
* 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_ssl_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct espconn *espconn = arg;
ssl_msg *pssl = NULL;
espconn_msg *paccept = NULL;
remot_info *pinfo = NULL;
ssl_printf("espconn_ssl_accept %p %p %p %d\n", pcb, arg, espconn->psecure, system_get_free_heap_size());
LWIP_UNUSED_ARG(err);
paccept = (espconn_msg *)os_zalloc(sizeof(espconn_msg));
tcp_arg(pcb, paccept);
tcp_err(pcb, espconn_ssl_serr);
if (paccept == NULL)
return ERR_MEM;
/*insert the node to the active connection list*/
espconn_list_creat(&plink_active, paccept);
paccept->preverse = espconn;
paccept->pespconn = espconn;
paccept->pcommon.timeout = 0x0a;
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);
os_memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4);
espconn->proto.tcp->remote_port = pcb->remote_port;
espconn_get_connection_info(espconn, &pinfo , ESPCONN_SSL);
if (espconn->link_cnt == 0x01)
return ERR_ISCONN;
pssl = (ssl_msg *)os_zalloc(sizeof(ssl_msg));
paccept->pssl = pssl;
if (pssl == NULL) {
return ERR_MEM;
}
REG_SET_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(160);
os_printf("server handshake start.\n");
pssl->quiet = false;
pssl->ssl_ctx = ssl_ctx_new(SSL_DISPLAY_CERTS, SSL_DEFAULT_SVR_SESS);
if (pssl->ssl_ctx == NULL) {
ssl_printf("Error: Server context is invalid\n");
return ERR_MEM;
}
ssl_printf("Server context %p\n", pssl->ssl_ctx);
pssl->ssl = sslserver_new(pssl->ssl_ctx, pcb);
if (pssl->ssl == NULL) {
ssl_printf("Error: Server ssl connection is invalid\n");
return ERR_MEM;
}
tcp_sent(pcb, espconn_ssl_ssent);
tcp_recv(pcb, espconn_ssl_srecv);
tcp_poll(pcb, espconn_ssl_spoll, 2);
return ERR_OK;
}
/******************************************************************************
* FunctionName : espconn_ssl_server
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR espconn_ssl_server(struct espconn *espconn)
{
struct tcp_pcb *pcb;
pcb = tcp_new();
if (pcb == NULL) {
espconn ->state = ESPCONN_NONE;
return ESPCONN_MEM;
} else {
tcp_bind(pcb, IP_ADDR_ANY, espconn->proto.tcp->local_port);
pcb = tcp_listen(pcb);
if (pcb != NULL) {
espconn ->state = ESPCONN_LISTEN;
tcp_arg(pcb, (void *)espconn);
tcp_accept(pcb, espconn_ssl_accept);
return ESPCONN_OK;
} else {
espconn ->state = ESPCONN_NONE;
return ESPCONN_MEM;
}
}
}