[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/meshtastic/esp32_https_server/master/src/HTTPSConnection.cpp [Back]  [Original]

#include "HTTPSConnection.hpp"
#include "mbedtls/error.h"
#include "mbedtls/net_sockets.h"

namespace httpsserver {


HTTPSConnection::HTTPSConnection(ResourceResolver * resResolver):
  HTTPConnection(resResolver) {
  _sslCreated = false;
  _socket = 0;
}

HTTPSConnection::~HTTPSConnection() {
  // Close the socket
  closeConnection();
}

bool HTTPSConnection::isSecure() {
  return true;
}

bool HTTPSConnection::setup(mbedtls_ssl_config *sslConfig) {
  mbedtls_ssl_init(&_ssl);
  int res = mbedtls_ssl_setup(&_ssl, sslConfig);
  if (res == 0) {
    return true;
  } else {
    char buf[100];
    mbedtls_strerror(res, buf, sizeof(buf));
    HTTPS_LOGE("mbedtls_ssl_setup res=%X (%s)", res, buf);
    mbedtls_ssl_free(&_ssl);
    return false;
  }
}

bool HTTPSConnection::handshake() {
  int res;
  while (true) {
    res = mbedtls_ssl_handshake(&_ssl);
    if (res == 0) {
      return true;
    }
    if (res != MBEDTLS_ERR_SSL_WANT_READ && res != MBEDTLS_ERR_SSL_WANT_WRITE) {
      return false;
    }
  }
}

/**
 * Initializes the connection from a server socket.
 *
 * The call WILL BLOCK if accept(serverSocketID) blocks. So use select() to check for that in advance.
 */
int HTTPSConnection::initialize(int serverSocketID, mbedtls_ssl_config *sslConfig, HTTPHeaders *defaultHeaders) {
  if (_connectionState == STATE_UNDEFINED) {
    // Let the base class connect the plain tcp socket
    int resSocket = HTTPConnection::initialize(serverSocketID, defaultHeaders);

    // Build up SSL Connection context if the socket has been created successfully
    if (resSocket >= 0) {

      _socket = resSocket;
      _sslCreated = setup(sslConfig);

      if (_sslCreated) {
        // Bind SSL to the socket
        mbedtls_ssl_set_bio(&_ssl, &_socket, mbedtls_net_send, mbedtls_net_recv, NULL);

        // Perform the handshake
        if (handshake()) {
          return resSocket;
        } else {
          HTTPS_LOGE("SSL handshake failed. Aborting handshake. FID=%d", resSocket);
        }
      } else {
        HTTPS_LOGE("SSL setup failed. Aborting handshake. FID=%d", resSocket);
      }

    } else {
      HTTPS_LOGE("Could not accept() new connection. FID=%d", resSocket);
    }

    _connectionState = STATE_ERROR;
    _clientState = CSTATE_ACTIVE;

    // This will only be called if the connection could not be established and cleanup
    // variables like _ssl etc.
    closeConnection();
  }
  // Error: The connection has already been established or could not be established
  return -1;
}


void HTTPSConnection::closeConnection() {
  // FIXME: Copy from HTTPConnection, could be done better probably
  if (_connectionState != STATE_ERROR && _connectionState != STATE_CLOSED) {

    // First call to closeConnection - set the timestamp to calculate the timeout later on
    if (_connectionState != STATE_CLOSING) {
      _shutdownTS = millis();
    }

    // Set the connection state to closing. We stay in closing as long as SSL has not been shutdown
    // correctly
    _connectionState = STATE_CLOSING;
  }

  // Try to tear down SSL while we are in the _shutdownTS timeout period or if an error occurred
  if (_sslCreated) {
    if (_connectionState == STATE_ERROR || mbedtls_ssl_close_notify(&_ssl) == 0) {
      // SSL shutdown will return 0 as soon as the client answered with close notify
      // This means we are safe to close the socket
      mbedtls_ssl_free(&_ssl);
      _sslCreated = false;
    } else if (_shutdownTS + HTTPS_SHUTDOWN_TIMEOUT < millis()) {
      // The timeout has been hit, we force SSL shutdown now by resetting the session
      mbedtls_ssl_free(&_ssl);
      _sslCreated = false;
      HTTPS_LOGW("SSL shutdown did not receive close notification from the client");
      _connectionState = STATE_ERROR;
    }
  }

  // If SSL has been brought down, close the socket
  if (!_sslCreated) {
    HTTPConnection::closeConnection();
  }
}

size_t HTTPSConnection::writeBuffer(byte* buffer, size_t length) {
  while (true) {
    int res = mbedtls_ssl_write(&_ssl, buffer, length);
    if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE) {
      continue;
    }
    return res;
  }
}

size_t HTTPSConnection::readBytesToBuffer(byte* buffer, size_t length) {
  while (true) {
    int res = mbedtls_ssl_read(&_ssl, buffer, length);
    if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE) {
      continue;
    }
    return res;
  }
}

size_t HTTPSConnection::pendingByteCount() {
  return mbedtls_ssl_get_bytes_avail(&_ssl);
}

bool HTTPSConnection::canReadData() {
  return HTTPConnection::canReadData() || (mbedtls_ssl_get_bytes_avail(&_ssl) > 0);
}

} /* namespace httpsserver */

Web Proxy Viewer  |  New URL  |  Original Page