mirror of
https://github.com/eledio-devices/thirdparty-AsyncTCPSock.git
synced 2025-10-30 16:15:40 +01:00
Use TLS context on AsyncTCP if enabled
Compile tested only.
This commit is contained in:
140
src/AsyncTCP.cpp
140
src/AsyncTCP.cpp
@@ -294,6 +294,7 @@ AsyncClient::AsyncClient(int sockfd)
|
|||||||
, _handshake_done(true)
|
, _handshake_done(true)
|
||||||
, _psk_ident(0)
|
, _psk_ident(0)
|
||||||
, _psk(0)
|
, _psk(0)
|
||||||
|
, _sslctx(NULL)
|
||||||
#endif // ASYNC_TCP_SSL_ENABLED
|
#endif // ASYNC_TCP_SSL_ENABLED
|
||||||
, _writeSpaceRemaining(TCP_SND_BUF)
|
, _writeSpaceRemaining(TCP_SND_BUF)
|
||||||
, _conn_state(0)
|
, _conn_state(0)
|
||||||
@@ -561,6 +562,7 @@ bool AsyncClient::connect(const char* host, uint16_t port){
|
|||||||
if(err == ERR_OK) {
|
if(err == ERR_OK) {
|
||||||
log_v("\taddr resolved as %08x, connecting...", addr.u_addr.ip4.addr);
|
log_v("\taddr resolved as %08x, connecting...", addr.u_addr.ip4.addr);
|
||||||
#if ASYNC_TCP_SSL_ENABLED
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
_hostname = host;
|
||||||
return connect(IPAddress(addr.u_addr.ip4.addr), port, secure);
|
return connect(IPAddress(addr.u_addr.ip4.addr), port, secure);
|
||||||
#else
|
#else
|
||||||
return connect(IPAddress(addr.u_addr.ip4.addr), port);
|
return connect(IPAddress(addr.u_addr.ip4.addr), port);
|
||||||
@@ -570,6 +572,7 @@ bool AsyncClient::connect(const char* host, uint16_t port){
|
|||||||
_conn_state = 1;
|
_conn_state = 1;
|
||||||
_connect_port = port;
|
_connect_port = port;
|
||||||
#if ASYNC_TCP_SSL_ENABLED
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
_hostname = host;
|
||||||
_secure = secure;
|
_secure = secure;
|
||||||
_handshake_done = !secure;
|
_handshake_done = !secure;
|
||||||
#endif // ASYNC_TCP_SSL_ENABLED
|
#endif // ASYNC_TCP_SSL_ENABLED
|
||||||
@@ -601,7 +604,11 @@ void _tcpsock_dns_found(const char * name, struct ip_addr * ipaddr, void * arg)
|
|||||||
void AsyncClient::_sockDelayedConnect(void)
|
void AsyncClient::_sockDelayedConnect(void)
|
||||||
{
|
{
|
||||||
if (_connect_addr.u_addr.ip4.addr) {
|
if (_connect_addr.u_addr.ip4.addr) {
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
connect(IPAddress(_connect_addr.u_addr.ip4.addr), _connect_port, _secure);
|
||||||
|
#else
|
||||||
connect(IPAddress(_connect_addr.u_addr.ip4.addr), _connect_port);
|
connect(IPAddress(_connect_addr.u_addr.ip4.addr), _connect_port);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
_conn_state = 0;
|
_conn_state = 0;
|
||||||
if(_error_cb) {
|
if(_error_cb) {
|
||||||
@@ -613,6 +620,32 @@ void AsyncClient::_sockDelayedConnect(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
int AsyncClient::_runSSLHandshakeLoop(void)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
while (!_handshake_done) {
|
||||||
|
res = _sslctx->runSSLHandshake();
|
||||||
|
if (res == 0) {
|
||||||
|
// Handshake successful
|
||||||
|
_handshake_done = true;
|
||||||
|
} else if (ASYNCTCP_TLS_CAN_RETRY(res)) {
|
||||||
|
// Ran out of readable data or writable space on socket, must continue later
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// SSL handshake for AsyncTCP does not inform SSL errors
|
||||||
|
log_e("TLS setup failed with error %d, closing socket...", res);
|
||||||
|
_close();
|
||||||
|
// _sslctx should be NULL after this
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool AsyncClient::_sockIsWriteable(void)
|
bool AsyncClient::_sockIsWriteable(void)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@@ -635,6 +668,46 @@ bool AsyncClient::_sockIsWriteable(void)
|
|||||||
} else if (sockerr != 0) {
|
} else if (sockerr != 0) {
|
||||||
_error(sockerr);
|
_error(sockerr);
|
||||||
} else {
|
} else {
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
if (_secure) {
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
if (_sslctx == NULL) {
|
||||||
|
String remIP_str = remoteIP().toString();
|
||||||
|
const char * host_or_ip = _hostname.isEmpty()
|
||||||
|
? remIP_str.c_str()
|
||||||
|
: _hostname.c_str();
|
||||||
|
|
||||||
|
_sslctx = new AsyncTCP_TLS_Context();
|
||||||
|
if (_root_ca != NULL) {
|
||||||
|
res = _sslctx->startSSLClient(_socket, host_or_ip,
|
||||||
|
(const unsigned char *)_root_ca, _root_ca_len,
|
||||||
|
(const unsigned char *)_cli_cert, _cli_cert_len,
|
||||||
|
(const unsigned char *)_cli_key, _cli_key_len);
|
||||||
|
} else if (_psk_ident != NULL) {
|
||||||
|
res = _sslctx->startSSLClient(_socket, host_or_ip,
|
||||||
|
_psk_ident, _psk);
|
||||||
|
} else {
|
||||||
|
res = _sslctx->startSSLClientInsecure(_socket, host_or_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != 0) {
|
||||||
|
// SSL setup for AsyncTCP does not inform SSL errors
|
||||||
|
log_e("TLS setup failed with error %d, closing socket...", res);
|
||||||
|
_close();
|
||||||
|
// _sslctx should be NULL after this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _handshake_done is set to FALSE on connect() if encrypted connection
|
||||||
|
if (_sslctx != NULL && res == 0) res = _runSSLHandshakeLoop();
|
||||||
|
|
||||||
|
if (!_handshake_done) return ASYNCTCP_TLS_CAN_RETRY(res);
|
||||||
|
|
||||||
|
// Fallthrough to ordinary successful connection
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Socket is now fully connected
|
// Socket is now fully connected
|
||||||
_conn_state = 4;
|
_conn_state = 4;
|
||||||
activity = true;
|
activity = true;
|
||||||
@@ -681,7 +754,27 @@ bool AsyncClient::_flushWriteQueue(void)
|
|||||||
do {
|
do {
|
||||||
uint8_t * p = it->data + it->written;
|
uint8_t * p = it->data + it->written;
|
||||||
size_t n = it->length - it->written;
|
size_t n = it->length - it->written;
|
||||||
errno = 0; ssize_t r = lwip_write(_socket, p, n);
|
errno = 0;
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
if (_sslctx != NULL) {
|
||||||
|
r = _sslctx->write(p, n);
|
||||||
|
if (ASYNCTCP_TLS_CAN_RETRY(r)) {
|
||||||
|
r = -1;
|
||||||
|
errno = EAGAIN;
|
||||||
|
} else if (ASYNCTCP_TLS_EOF(r)) {
|
||||||
|
r = -1;
|
||||||
|
errno = EPIPE;
|
||||||
|
} else if (r < 0) {
|
||||||
|
if (errno == 0) errno = EIO;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
r = lwip_write(_socket, p, n);
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
// Written some data into the socket
|
// Written some data into the socket
|
||||||
@@ -755,7 +848,38 @@ void AsyncClient::_notifyWrittenBuffers(std::deque<notify_writebuf> & notifyqueu
|
|||||||
void AsyncClient::_sockIsReadable(void)
|
void AsyncClient::_sockIsReadable(void)
|
||||||
{
|
{
|
||||||
_rx_last_packet = millis();
|
_rx_last_packet = millis();
|
||||||
errno = 0; ssize_t r = lwip_read(_socket, _readBuffer, MAX_PAYLOAD_SIZE);
|
errno = 0;
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
if (_sslctx != NULL) {
|
||||||
|
if (!_handshake_done) {
|
||||||
|
// Handshake process has stopped for want of data, must be
|
||||||
|
// continued here for connection to complete.
|
||||||
|
_runSSLHandshakeLoop();
|
||||||
|
|
||||||
|
// If handshake was successful, this will be recognized when the socket
|
||||||
|
// next becomes writable. No other read operation should be done here.
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
r = _sslctx->read(_readBuffer, MAX_PAYLOAD_SIZE);
|
||||||
|
if (ASYNCTCP_TLS_CAN_RETRY(r)) {
|
||||||
|
r = -1;
|
||||||
|
errno = EAGAIN;
|
||||||
|
} else if (ASYNCTCP_TLS_EOF(r)) {
|
||||||
|
// Simulate "successful" end-of-stream condition
|
||||||
|
r = 0;
|
||||||
|
} else if (r < 0) {
|
||||||
|
if (errno == 0) errno = EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
r = lwip_read(_socket, _readBuffer, MAX_PAYLOAD_SIZE);
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
if(_recv_cb) {
|
if(_recv_cb) {
|
||||||
_recv_cb(_recv_cb_arg, this, _readBuffer, r);
|
_recv_cb(_recv_cb_arg, this, _readBuffer, r);
|
||||||
@@ -844,6 +968,12 @@ void AsyncClient::_close(void)
|
|||||||
_conn_state = 0;
|
_conn_state = 0;
|
||||||
::close(_socket);
|
::close(_socket);
|
||||||
_socket = -1;
|
_socket = -1;
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
if (_sslctx != NULL) {
|
||||||
|
delete _sslctx;
|
||||||
|
_sslctx = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
xSemaphoreGiveRecursive(_asyncsock_mutex);
|
xSemaphoreGiveRecursive(_asyncsock_mutex);
|
||||||
|
|
||||||
_clearWriteQueue();
|
_clearWriteQueue();
|
||||||
@@ -856,6 +986,12 @@ void AsyncClient::_error(int8_t err)
|
|||||||
_conn_state = 0;
|
_conn_state = 0;
|
||||||
::close(_socket);
|
::close(_socket);
|
||||||
_socket = -1;
|
_socket = -1;
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
if (_sslctx != NULL) {
|
||||||
|
delete _sslctx;
|
||||||
|
_sslctx = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
xSemaphoreGiveRecursive(_asyncsock_mutex);
|
xSemaphoreGiveRecursive(_asyncsock_mutex);
|
||||||
|
|
||||||
_clearWriteQueue();
|
_clearWriteQueue();
|
||||||
|
|||||||
@@ -203,6 +203,9 @@ class AsyncClient : public AsyncSocketBase
|
|||||||
bool _handshake_done;
|
bool _handshake_done;
|
||||||
const char* _psk_ident;
|
const char* _psk_ident;
|
||||||
const char* _psk;
|
const char* _psk;
|
||||||
|
|
||||||
|
String _hostname;
|
||||||
|
AsyncTCP_TLS_Context * _sslctx;
|
||||||
#endif // ASYNC_TCP_SSL_ENABLED
|
#endif // ASYNC_TCP_SSL_ENABLED
|
||||||
|
|
||||||
// The following private struct represents a buffer enqueued with the add()
|
// The following private struct represents a buffer enqueued with the add()
|
||||||
@@ -244,6 +247,10 @@ class AsyncClient : public AsyncSocketBase
|
|||||||
void _collectNotifyWrittenBuffers(std::deque<notify_writebuf> &, int &);
|
void _collectNotifyWrittenBuffers(std::deque<notify_writebuf> &, int &);
|
||||||
void _notifyWrittenBuffers(std::deque<notify_writebuf> &, int);
|
void _notifyWrittenBuffers(std::deque<notify_writebuf> &, int);
|
||||||
|
|
||||||
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
|
int _runSSLHandshakeLoop(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
friend void _tcpsock_dns_found(const char * name, struct ip_addr * ipaddr, void * arg);
|
friend void _tcpsock_dns_found(const char * name, struct ip_addr * ipaddr, void * arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user