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

/*
 * HTTPSConnection.cpp
 *
 *  Created on: Dec 6, 2017
 *      Author: frank
 */

#include "HTTPSConnection.hpp"

namespace httpsserver {


HTTPSConnection::HTTPSConnection(ResourceResolver * resResolver):
	_resResolver(resResolver) {
	_socket = -1;
	_addrLen = 0;
	_ssl = NULL;

	_bufferProcessed = 0;
	_bufferUnusedIdx = 0;

	_connectionState = STATE_UNDEFINED;
	_clientState = CSTATE_UNDEFINED;
	_httpHeaders = NULL;
	_defaultHeaders = NULL;
	_isKeepAlive = false;
	_lastTransmissionTS = millis();
	_shutdownTS = 0;
}

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

/**
 * 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, SSL_CTX * sslCtx, HTTPHeaders *defaultHeaders) {
	if (_connectionState == STATE_UNDEFINED) {
		_defaultHeaders = defaultHeaders;
		_socket = accept(serverSocketID, (struct sockaddr * )&_sockAddr, &_addrLen);

		// Build up SSL Connection context if the socket has been created successfully
		if (_socket >= 0) {
			HTTPS_DLOGHEX("[-->] New connection. Socket fid is: ", _socket);

			_ssl = SSL_new(sslCtx);

			if (_ssl) {
				// Bind SSL to the socket
				int success = SSL_set_fd(_ssl, _socket);
				if (success) {

					// Perform the handshake
					success = SSL_accept(_ssl);
					if (success) {
						_connectionState = STATE_INITIAL;
						_httpHeaders = new HTTPHeaders();
						refreshTimeout();
						return _socket;
					} else {
						HTTPS_DLOG("[ERR] SSL_accept failed. Aborting handshake.");
					}
				} else {
					HTTPS_DLOG("[ERR] SSL_set_fd failed. Aborting handshake.");
				}
			} else {
				HTTPS_DLOG("[ERR] SSL_new failed. Aborting handshake.");
			}
		} else {
			HTTPS_DLOG("[ERR] Could not accept() new connection");
		}
		_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;
}


/**
 * True if the connection is timed out.
 *
 * (Should be checkd in the loop and transition should go to CONNECTION_CLOSE if exceeded)
 */
bool HTTPSConnection::isTimeoutExceeded() {
	return _lastTransmissionTS + HTTPS_CONNECTION_TIMEOUT < millis();
}

/**
 * Resets the timeout to allow again the full HTTPS_CONNECTION_TIMEOUT milliseconds
 */
void HTTPSConnection::refreshTimeout() {
	_lastTransmissionTS = millis();
}

/**
 * Returns true, if the connection has been closed.
 */
bool HTTPSConnection::isClosed() {
	return (_connectionState == STATE_ERROR || _connectionState == STATE_CLOSED);
}

/**
 * Returns true, if the connection has been closed due to error
 */
bool HTTPSConnection::isError() {
	return (_connectionState == STATE_ERROR);
}

void HTTPSConnection::closeConnection() {
	// TODO: Call an event handler here, maybe?


	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 (_ssl) {
		if(_connectionState == STATE_ERROR || SSL_shutdown(_ssl) == 0) {
			// SSL_shutdown will return 1 as soon as the client answered with close notify
			// This means we are safe to close the socket
			SSL_free(_ssl);
			_ssl = NULL;
		} else if (_shutdownTS + HTTPS_SHUTDOWN_TIMEOUT < millis()) {
			// The timeout has been hit, we force SSL shutdown now by freeing the context
			SSL_free(_ssl);
			_ssl = NULL;
			HTTPS_DLOG("[ERR] SSL_shutdown did not receive close notification from the client");
			_connectionState = STATE_ERROR;
		}
	}

	// If SSL has been brought down, close the socket
	if (!_ssl) {
		// Tear down the socket
		if (_socket >= 0) {
			HTTPS_DLOGHEX("[

Web Proxy Viewer  |  New URL  |  Original Page