1101 lines
36 KiB
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|