/********** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. (See .) This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // "liveMedia" // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. // State encapsulating a TLS connection // Implementation #include "TLSState.hh" #include "RTSPClient.hh" TLSState::TLSState(RTSPClient& client) : isNeeded(False) #ifndef NO_OPENSSL , fClient(client), fHasBeenSetup(False), fCtx(NULL), fCon(NULL) #endif { } TLSState::~TLSState() { reset(); } int TLSState::connect(int socketNum) { #ifndef NO_OPENSSL if (!fHasBeenSetup && !setup(socketNum)) return -1; // error // Complete the SSL-level connection to the server: int sslConnectResult = SSL_connect(fCon); int sslGetErrorResult = SSL_get_error(fCon, sslConnectResult); if (sslConnectResult > 0) { return sslConnectResult; // connection has completed } else if (sslConnectResult < 0 && (sslGetErrorResult == SSL_ERROR_WANT_READ || sslGetErrorResult == SSL_ERROR_WANT_WRITE)) { // We need to wait until the socket is readable or writable: fClient.envir().taskScheduler() .setBackgroundHandling(socketNum, sslGetErrorResult == SSL_ERROR_WANT_READ ? SOCKET_READABLE : SOCKET_WRITABLE, (TaskScheduler::BackgroundHandlerProc*)&RTSPClient::connectionHandler, &fClient); return 0; // connection is pending } else { fClient.envir().setResultErrMsg("TLS connection to server failed: ", sslGetErrorResult); return -1; // error } #else return -1; #endif } int TLSState::write(const char* data, unsigned count) { #ifndef NO_OPENSSL return SSL_write(fCon, data, count); #else return -1; #endif } int TLSState::read(u_int8_t* buffer, unsigned bufferSize) { #ifndef NO_OPENSSL int result = SSL_read(fCon, buffer, bufferSize); if (result < 0 && SSL_get_error(fCon, result) == SSL_ERROR_WANT_READ) { // The data can't be delivered yet. Return 0 (bytes read); we'll try again later return 0; } return result; #else return 0; #endif } void TLSState::reset() { #ifndef NO_OPENSSL if (fHasBeenSetup) SSL_shutdown(fCon); if (fCon != NULL) { SSL_free(fCon); fCon = NULL; } if (fCtx != NULL) { SSL_CTX_free(fCtx); fCtx = NULL; } #endif } Boolean TLSState::setup(int socketNum) { #ifndef NO_OPENSSL do { (void)SSL_library_init(); SSL_METHOD const* meth = SSLv23_client_method(); if (meth == NULL) break; fCtx = SSL_CTX_new(meth); if (fCtx == NULL) break; fCon = SSL_new(fCtx); if (fCon == NULL) break; BIO* bio = BIO_new_socket(socketNum, BIO_NOCLOSE); SSL_set_bio(fCon, bio, bio); SSL_set_connect_state(fCon); fHasBeenSetup = True; return True; } while (0); #endif // An error occurred: reset(); return False; }