xref: /haiku/src/kits/network/libnetapi/SecureSocket.cpp (revision 99d027cd0238c1d86da86d7c3f4200509ccc61a6)
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 
26 class BSecureSocket::Private {
27 public:
28 			SSL_CTX*			fCTX;
29 			SSL*				fSSL;
30 			BIO*				fBIO;
31 };
32 
33 
34 BSecureSocket::BSecureSocket()
35 	:
36 	fPrivate(NULL)
37 {
38 }
39 
40 
41 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
42 	:
43 	fPrivate(NULL)
44 {
45 	Connect(peer, timeout);
46 }
47 
48 
49 BSecureSocket::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 
62 BSecureSocket::~BSecureSocket()
63 {
64 	free(fPrivate);
65 }
66 
67 
68 status_t
69 BSecureSocket::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 
98 void
99 BSecureSocket::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 
119 status_t
120 BSecureSocket::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 
137 ssize_t
138 BSecureSocket::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 
152 ssize_t
153 BSecureSocket::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 
173 BSecureSocket::BSecureSocket()
174 {
175 }
176 
177 
178 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
179 {
180 	fInitStatus = B_UNSUPPORTED;
181 }
182 
183 
184 BSecureSocket::BSecureSocket(const BSecureSocket& other)
185 	:
186 	BSocket(other)
187 {
188 }
189 
190 
191 BSecureSocket::~BSecureSocket()
192 {
193 }
194 
195 
196 status_t
197 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
198 {
199 	return fInitStatus = B_UNSUPPORTED;
200 }
201 
202 
203 void
204 BSecureSocket::Disconnect()
205 {
206 }
207 
208 
209 status_t
210 BSecureSocket::WaitForReadable(bigtime_t timeout) const
211 {
212 	return B_UNSUPPORTED;
213 }
214 
215 
216 //	#pragma mark - BDataIO implementation
217 
218 
219 ssize_t
220 BSecureSocket::Read(void* buffer, size_t size)
221 {
222 	return B_UNSUPPORTED;
223 }
224 
225 
226 ssize_t
227 BSecureSocket::Write(const void* buffer, size_t size)
228 {
229 	return B_UNSUPPORTED;
230 }
231 
232 
233 #endif	// !OPENSSL_ENABLED
234