1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15**********/
16// "liveMedia"
17// Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved.
18// State encapsulating a TLS connection
19// Implementation
20
21#include "TLSState.hh"
22#include "RTSPClient.hh"
23
24TLSState::TLSState(RTSPClient& client)
25 : isNeeded(False)
26#ifndef NO_OPENSSL
27 , fClient(client), fHasBeenSetup(False)
28#endif
29{
30}
31
32TLSState::~TLSState() {
33 reset();
34}
35
36int TLSState::connect(int socketNum) {
37#ifndef NO_OPENSSL
38 if (!fHasBeenSetup && !setup(socketNum)) return -1; // error
39
40 // Complete the SSL-level connection to the server:
41 int sslConnectResult = SSL_connect(fCon);
42 int sslGetErrorResult = SSL_get_error(fCon, sslConnectResult);
43
44 if (sslConnectResult > 0) {
45 return sslConnectResult; // connection has completed
46 } else if (sslConnectResult < 0
47 && (sslGetErrorResult == SSL_ERROR_WANT_READ ||
48 sslGetErrorResult == SSL_ERROR_WANT_WRITE)) {
49 // We need to wait until the socket is readable or writable:
50 fClient.envir().taskScheduler()
51 .setBackgroundHandling(socketNum,
52 sslGetErrorResult == SSL_ERROR_WANT_READ ? SOCKET_READABLE : SOCKET_WRITABLE,
53 (TaskScheduler::BackgroundHandlerProc*)&RTSPClient::connectionHandler,
54 &fClient);
55 return 0; // connection is pending
56 } else {
57 fClient.envir().setResultErrMsg("TLS connection to server failed: ", sslGetErrorResult);
58 return -1; // error
59 }
60#else
61 return -1;
62#endif
63}
64
65int TLSState::write(const char* data, unsigned count) {
66#ifndef NO_OPENSSL
67 return SSL_write(fCon, data, count);
68#else
69 return -1;
70#endif
71}
72
73int TLSState::read(u_int8_t* buffer, unsigned bufferSize) {
74#ifndef NO_OPENSSL
75 return SSL_read(fCon, buffer, bufferSize);
76#else
77 return 0;
78#endif
79}
80
81void TLSState::reset() {
82#ifndef NO_OPENSSL
83 if (fHasBeenSetup) SSL_shutdown(fCon);
84
85 if (fCon != NULL) { SSL_free(fCon); fCon = NULL; }
86 if (fCtx != NULL) { SSL_CTX_free(fCtx); fCtx = NULL; }
87#endif
88}
89
90Boolean TLSState::setup(int socketNum) {
91#ifndef NO_OPENSSL
92 do {
93 (void)SSL_library_init();
94
95 SSL_METHOD const* meth = SSLv23_client_method();
96 if (meth == NULL) break;
97
98 fCtx = SSL_CTX_new(meth);
99 if (fCtx == NULL) break;
100
101 fCon = SSL_new(fCtx);
102 if (fCon == NULL) break;
103
104 BIO* bio = BIO_new_socket(socketNum, BIO_NOCLOSE);
105 SSL_set_bio(fCon, bio, bio);
106
107 SSL_set_connect_state(fCon);
108
109 fHasBeenSetup = True;
110 return True;
111 } while (0);
112#endif
113
114 // An error occurred:
115 reset();
116 return False;
117}
118