1/*
2 * Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <SecureSocket.h>
9
10#ifdef OPENSSL_ENABLED
11#	include <openssl/ssl.h>
12#endif
13
14
15//#define TRACE_SOCKET
16#ifdef TRACE_SOCKET
17#	define TRACE(x...) printf(x)
18#else
19#	define TRACE(x...) ;
20#endif
21
22
23#ifdef OPENSSL_ENABLED
24
25
26class BSecureSocket::Private {
27public:
28			SSL_CTX*			fCTX;
29			SSL*				fSSL;
30			BIO*				fBIO;
31};
32
33
34BSecureSocket::BSecureSocket()
35	:
36	fPrivate(NULL)
37{
38}
39
40
41BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
42	:
43	fPrivate(NULL)
44{
45	Connect(peer, timeout);
46}
47
48
49BSecureSocket::BSecureSocket(const BSecureSocket& other)
50	:
51	BSocket(other)
52{
53	// TODO: this won't work this way!
54	fPrivate = (BSecureSocket::Private*)malloc(sizeof(BSecureSocket::Private));
55	if (fPrivate != NULL)
56		memcpy(fPrivate, other.fPrivate, sizeof(BSecureSocket::Private));
57	else
58		fInitStatus = B_NO_MEMORY;
59}
60
61
62BSecureSocket::~BSecureSocket()
63{
64	free(fPrivate);
65}
66
67
68status_t
69BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
70{
71	if (fPrivate == NULL) {
72		fPrivate = (BSecureSocket::Private*)calloc(1,
73			sizeof(BSecureSocket::Private));
74		if (fPrivate == NULL)
75			return B_NO_MEMORY;
76	}
77
78	status_t status = BSocket::Connect(peer, timeout);
79	if (status != B_OK)
80		return status;
81
82	fPrivate->fCTX = SSL_CTX_new(SSLv23_method());
83	fPrivate->fSSL = SSL_new(fPrivate->fCTX);
84	fPrivate->fBIO = BIO_new_socket(fSocket, BIO_NOCLOSE);
85	SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO);
86
87	if (SSL_connect(fPrivate->fSSL) <= 0) {
88		TRACE("SSLConnection can't connect\n");
89		BSocket::Disconnect();
90		// TODO: translate ssl to Haiku error
91		return B_ERROR;
92	}
93
94	return B_OK;
95}
96
97
98void
99BSecureSocket::Disconnect()
100{
101	if (IsConnected()) {
102		if (fPrivate->fSSL != NULL) {
103			SSL_shutdown(fPrivate->fSSL);
104			fPrivate->fSSL = NULL;
105		}
106		if (fPrivate->fCTX != NULL) {
107			SSL_CTX_free(fPrivate->fCTX);
108			fPrivate->fCTX = NULL;
109		}
110		if (fPrivate->fBIO != NULL) {
111			BIO_free(fPrivate->fBIO);
112			fPrivate->fBIO = NULL;
113		}
114	}
115	return BSocket::Disconnect();
116}
117
118
119status_t
120BSecureSocket::WaitForReadable(bigtime_t timeout) const
121{
122	if (fInitStatus != B_OK)
123		return fInitStatus;
124	if (!IsConnected())
125		return B_ERROR;
126
127	if (SSL_pending(fPrivate->fSSL) > 0)
128		return B_OK;
129
130	return BSocket::WaitForReadable(timeout);
131}
132
133
134//	#pragma mark - BDataIO implementation
135
136
137ssize_t
138BSecureSocket::Read(void* buffer, size_t size)
139{
140	if (!IsConnected())
141		return B_ERROR;
142
143	int bytesRead = SSL_read(fPrivate->fSSL, buffer, size);
144	if (bytesRead > 0)
145		return bytesRead;
146
147	// TODO: translate SSL error codes!
148	return B_ERROR;
149}
150
151
152ssize_t
153BSecureSocket::Write(const void* buffer, size_t size)
154{
155	if (!IsConnected())
156		return B_ERROR;
157
158	int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size);
159	if (bytesWritten > 0)
160		return bytesWritten;
161
162	// TODO: translate SSL error codes!
163	return B_ERROR;
164}
165
166
167#else	// OPENSSL_ENABLED
168
169
170// #pragma mark - No-SSL stubs
171
172
173BSecureSocket::BSecureSocket()
174{
175}
176
177
178BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
179{
180	fInitStatus = B_UNSUPPORTED;
181}
182
183
184BSecureSocket::BSecureSocket(const BSecureSocket& other)
185	:
186	BSocket(other)
187{
188}
189
190
191BSecureSocket::~BSecureSocket()
192{
193}
194
195
196status_t
197BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
198{
199	return fInitStatus = B_UNSUPPORTED;
200}
201
202
203void
204BSecureSocket::Disconnect()
205{
206}
207
208
209status_t
210BSecureSocket::WaitForReadable(bigtime_t timeout) const
211{
212	return B_UNSUPPORTED;
213}
214
215
216//	#pragma mark - BDataIO implementation
217
218
219ssize_t
220BSecureSocket::Read(void* buffer, size_t size)
221{
222	return B_UNSUPPORTED;
223}
224
225
226ssize_t
227BSecureSocket::Write(const void* buffer, size_t size)
228{
229	return B_UNSUPPORTED;
230}
231
232
233#endif	// !OPENSSL_ENABLED
234