blob: 418db9096ee62e62845d2b79de02767c6a2f2010 [file] [log] [blame]
/**********
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 <http://www.gnu.org/copyleft/lesser.html>.)
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;
}