ThreadedSSLSocketAcceptor.cpp
Go to the documentation of this file.
1/* ====================================================================
2 * Copyright (c) 1998-2006 Ralf S. Engelschall. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials
14 * provided with the distribution.
15 *
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by
19 * Ralf S. Engelschall <rse@engelschall.com> for use in the
20 * mod_ssl project (http://www.modssl.org/)."
21 *
22 * 4. The names "mod_ssl" must not be used to endorse or promote
23 * products derived from this software without prior written
24 * permission. For written permission, please contact
25 * rse@engelschall.com.
26 *
27 * 5. Products derived from this software may not be called "mod_ssl"
28 * nor may "mod_ssl" appear in their names without prior
29 * written permission of Ralf S. Engelschall.
30 *
31 * 6. Redistributions of any form whatsoever must retain the following
32 * acknowledgment:
33 * "This product includes software developed by
34 * Ralf S. Engelschall <rse@engelschall.com> for use in the
35 * mod_ssl project (http://www.modssl.org/)."
36 *
37 * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
38 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
41 * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
46 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
48 * OF THE POSSIBILITY OF SUCH DAMAGE.
49 * ====================================================================
50 */
51
52/* ====================================================================
53 * Copyright (c) 1995-1999 Ben Laurie. All rights reserved.
54 *
55 * Redistribution and use in source and binary forms, with or without
56 * modification, are permitted provided that the following conditions
57 * are met:
58 *
59 * 1. Redistributions of source code must retain the above copyright
60 * notice, this list of conditions and the following disclaimer.
61 *
62 * 2. Redistributions in binary form must reproduce the above copyright
63 * notice, this list of conditions and the following disclaimer in
64 * the documentation and/or other materials provided with the
65 * distribution.
66 *
67 * 3. All advertising materials mentioning features or use of this
68 * software must display the following acknowledgment:
69 * "This product includes software developed by Ben Laurie
70 * for use in the Apache-SSL HTTP server project."
71 *
72 * 4. The name "Apache-SSL Server" must not be used to
73 * endorse or promote products derived from this software without
74 * prior written permission.
75 *
76 * 5. Redistributions of any form whatsoever must retain the following
77 * acknowledgment:
78 * "This product includes software developed by Ben Laurie
79 * for use in the Apache-SSL HTTP server project."
80 *
81 * THIS SOFTWARE IS PROVIDED BY BEN LAURIE ``AS IS'' AND ANY
82 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
83 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
84 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BEN LAURIE OR
85 * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
86 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
87 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
88 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
89 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
90 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
91 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
92 * OF THE POSSIBILITY OF SUCH DAMAGE.
93 * ====================================================================
94 */
95
96/****************************************************************************
97** Copyright (c) 2001-2014
98**
99** This file is part of the QuickFIX FIX Engine
100**
101** This file may be distributed under the terms of the quickfixengine.org
102** license as defined by quickfixengine.org and appearing in the file
103** LICENSE included in the packaging of this file.
104**
105** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
106** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
107**
108** See http://www.quickfixengine.org/LICENSE for licensing information.
109**
110** Contact ask@quickfixengine.org if any conditions of this licensing are
111** not clear to you.
112**
113****************************************************************************/
114
115#ifdef _MSC_VER
116#include "stdafx.h"
117#else
118#include "config.h"
119#endif
120
121#if (HAVE_SSL > 0)
122
124#include "Settings.h"
125#include "Utility.h"
126
127namespace FIX
128{
129
130FIX::ThreadedSSLSocketAcceptor *acceptObjT = 0;
131
132int ThreadedSSLSocketAcceptor::passPhraseHandleCB(char *buf, int bufsize, int verify, void *job)
133{
134 return acceptObjT->passwordHandleCallback(buf, bufsize, verify, job);
135}
136
137ThreadedSSLSocketAcceptor::ThreadedSSLSocketAcceptor(
138 Application &application, MessageStoreFactory &factory,
139 const SessionSettings &settings) throw(ConfigError)
140 : Acceptor(application, factory, settings), m_sslInit(false),
141 m_verify(SSL_CLIENT_VERIFY_NOTSET), m_ctx(0), m_revocationStore(0)
142{
143 socket_init();
144 acceptObjT = this;
145}
146
147ThreadedSSLSocketAcceptor::ThreadedSSLSocketAcceptor(
148 Application &application, MessageStoreFactory &factory,
149 const SessionSettings &settings, LogFactory &logFactory) throw(ConfigError)
150 : Acceptor(application, factory, settings, logFactory), m_sslInit(false),
151 m_verify(SSL_CLIENT_VERIFY_NOTSET), m_ctx(0), m_revocationStore(0)
152{
153 socket_init();
154 acceptObjT = this;
155}
156
157ThreadedSSLSocketAcceptor::~ThreadedSSLSocketAcceptor()
158{
159 if (m_sslInit)
160 {
161 SSL_CTX_free(m_ctx);
162 m_ctx = 0;
163 ssl_term();
164 }
165
166 socket_term();
167}
168
169void ThreadedSSLSocketAcceptor::onConfigure(const SessionSettings &s) throw(
170 ConfigError)
171{
172 std::set< SessionID > sessions = s.getSessions();
173 std::set< SessionID >::iterator i;
174 for (i = sessions.begin(); i != sessions.end(); ++i)
175 {
176 const Dictionary &settings = s.get(*i);
177 settings.getInt(SOCKET_ACCEPT_PORT);
178 if (settings.has(SOCKET_REUSE_ADDRESS))
179 settings.getBool(SOCKET_REUSE_ADDRESS);
180 if (settings.has(SOCKET_NODELAY))
181 settings.getBool(SOCKET_NODELAY);
182 }
183}
184
185void ThreadedSSLSocketAcceptor::onInitialize(const SessionSettings &s) throw(
186 RuntimeError)
187{
188 if (!m_sslInit)
189 {
190
191 ssl_init();
192
193 std::string errStr;
194
195 /* set up the application context */
196 if ((m_ctx = createSSLContext(true, m_settings, errStr)) == 0)
197 {
198 ssl_term();
199 throw RuntimeError(errStr);
200 }
201
202 if (!loadSSLCert(m_ctx, true, m_settings, getLog(), ThreadedSSLSocketAcceptor::passPhraseHandleCB, errStr))
203 {
204 ssl_term();
205 throw RuntimeError(errStr);
206 }
207
208 if (!loadCAInfo(m_ctx, true, m_settings, getLog(), errStr, m_verify))
209 {
210 ssl_term();
211 throw RuntimeError(errStr);
212 }
213
214 m_revocationStore = loadCRLInfo(m_ctx, m_settings, getLog(), errStr);
215 if (!m_revocationStore && !errStr.empty())
216 {
217 ssl_term();
218 throw RuntimeError(errStr);
219 }
220
221 m_sslInit = true;
222 }
223
224 short port = 0;
225 std::set< int > ports;
226
227 std::set< SessionID > sessions = s.getSessions();
228 std::set< SessionID >::iterator i = sessions.begin();
229 for (; i != sessions.end(); ++i)
230 {
231 const Dictionary &settings = s.get(*i);
232 port = (short)settings.getInt(SOCKET_ACCEPT_PORT);
233
234 m_portToSessions[port].insert(*i);
235
236 if (ports.find(port) != ports.end())
237 continue;
238 ports.insert(port);
239
240 const bool reuseAddress = settings.has(SOCKET_REUSE_ADDRESS)
241 ? settings.getBool(SOCKET_REUSE_ADDRESS)
242 : true;
243
244 const bool noDelay =
245 settings.has(SOCKET_NODELAY) ? settings.getBool(SOCKET_NODELAY) : false;
246
247 const int sendBufSize = settings.has(SOCKET_SEND_BUFFER_SIZE)
248 ? settings.getInt(SOCKET_SEND_BUFFER_SIZE)
249 : 0;
250
251 const int rcvBufSize = settings.has(SOCKET_RECEIVE_BUFFER_SIZE)
252 ? settings.getInt(SOCKET_RECEIVE_BUFFER_SIZE)
253 : 0;
254
255 int socket = socket_createAcceptor(port, reuseAddress);
256 if (socket < 0)
257 {
258 SocketException e;
259 socket_close(socket);
260 throw RuntimeError("Unable to create, bind, or listen to port " +
261 IntConvertor::convert((unsigned short)port) + " (" +
262 e.what() + ")");
263 }
264 if (noDelay)
265 socket_setsockopt(socket, TCP_NODELAY);
266 if (sendBufSize)
267 socket_setsockopt(socket, SO_SNDBUF, sendBufSize);
268 if (rcvBufSize)
269 socket_setsockopt(socket, SO_RCVBUF, rcvBufSize);
270
271 m_socketToPort[socket] = port;
272 m_sockets.insert(socket);
273 }
274}
275
276void ThreadedSSLSocketAcceptor::onStart()
277{
278 Sockets::iterator i;
279 for (i = m_sockets.begin(); i != m_sockets.end(); ++i)
280 {
281 Locker l(m_mutex);
282 int port = m_socketToPort[*i];
283 AcceptorThreadInfo *info = new AcceptorThreadInfo(this, *i, port);
284 thread_id thread;
285 thread_spawn(&socketAcceptorThread, info, thread);
286 addThread(SocketKey(*i, 0), thread);
287 }
288}
289
290bool ThreadedSSLSocketAcceptor::onPoll(double timeout) { return false; }
291
292void ThreadedSSLSocketAcceptor::onStop()
293{
294 SocketToThread threads;
295 SocketToThread::iterator i;
296
297 {
298 Locker l(m_mutex);
299
300 time_t start = 0;
301 time_t now = 0;
302
303 ::time(&start);
304 while (isLoggedOn())
305 {
306 if (::time(&now) - 5 >= start)
307 break;
308 }
309
310 threads = m_threads;
311 m_threads.clear();
312 }
313
314 for (i = threads.begin(); i != threads.end(); ++i)
315 ssl_socket_close(i->first.first, i->first.second);
316 for (i = threads.begin(); i != threads.end(); ++i)
317 {
318 thread_join(i->second);
319 if (i->first.second != 0)
320 SSL_free(i->first.second);
321 }
322}
323
324void ThreadedSSLSocketAcceptor::addThread(SocketKey s, thread_id t)
325{
326 Locker l(m_mutex);
327
328 m_threads[s] = t;
329}
330
331void ThreadedSSLSocketAcceptor::removeThread(SocketKey s)
332{
333 Locker l(m_mutex);
334 SocketToThread::iterator i = m_threads.find(s);
335 if (i != m_threads.end())
336 {
337 thread_detach(i->second);
338 if (i->first.second != 0)
339 SSL_free(i->first.second);
340 m_threads.erase(i);
341 }
342}
343
344THREAD_PROC ThreadedSSLSocketAcceptor::socketAcceptorThread(void *p)
345{
346 AcceptorThreadInfo *info = reinterpret_cast< AcceptorThreadInfo * >(p);
347
348 ThreadedSSLSocketAcceptor *pAcceptor = info->m_pAcceptor;
349 int s = info->m_socket;
350 int port = info->m_port;
351 delete info;
352
353 int noDelay = 0;
354 int sendBufSize = 0;
355 int rcvBufSize = 0;
356 socket_getsockopt(s, TCP_NODELAY, noDelay);
357 socket_getsockopt(s, SO_SNDBUF, sendBufSize);
358 socket_getsockopt(s, SO_RCVBUF, rcvBufSize);
359
360 int socket = 0;
361 while ((!pAcceptor->isStopped() && (socket = socket_accept(s)) >= 0))
362 {
363 if (noDelay)
364 socket_setsockopt(socket, TCP_NODELAY);
365 if (sendBufSize)
366 socket_setsockopt(socket, SO_SNDBUF, sendBufSize);
367 if (rcvBufSize)
368 socket_setsockopt(socket, SO_RCVBUF, rcvBufSize);
369
370 Sessions sessions = pAcceptor->m_portToSessions[port];
371
372 SSL *ssl = SSL_new(pAcceptor->sslContext());
373 ThreadedSSLSocketConnection *pConnection = new ThreadedSSLSocketConnection(
374 socket, ssl, sessions, pAcceptor->getLog());
375 SSL_clear(ssl);
376 BIO *sBio = BIO_new_socket(socket, BIO_CLOSE);
377 SSL_set_bio(ssl, sBio, sBio);
378 // TODO - check this
379 SSL_set_app_data(ssl, pAcceptor->revocationStore());
380 SSL_set_verify_result(ssl, X509_V_OK);
381
382 ConnectionThreadInfo *info =
383 new ConnectionThreadInfo(pAcceptor, pConnection);
384
385 {
386 Locker l(pAcceptor->m_mutex);
387
388 std::stringstream stream;
389 stream << "Accepted connection from " << socket_peername(socket)
390 << " on port " << port;
391
392 if (pAcceptor->getLog())
393 pAcceptor->getLog()->onEvent(stream.str());
394
395 thread_id thread;
396 if (!thread_spawn(&socketConnectionThread, info, thread))
397 {
398 delete info;
399 delete pConnection;
400 SSL_free(ssl);
401 }
402 else
403 pAcceptor->addThread(SocketKey(socket, ssl), thread);
404 }
405 }
406
407 if (!pAcceptor->isStopped())
408 pAcceptor->removeThread(SocketKey(s, 0));
409
410 return 0;
411}
412
413THREAD_PROC ThreadedSSLSocketAcceptor::socketConnectionThread(void *p)
414{
415 ConnectionThreadInfo *info = reinterpret_cast< ConnectionThreadInfo * >(p);
416
417 ThreadedSSLSocketAcceptor *pAcceptor = info->m_pAcceptor;
418 ThreadedSSLSocketConnection *pConnection = info->m_pConnection;
419 delete info;
420
421 int socket = pConnection->getSocket();
422
423 if (acceptSSLConnection(pConnection->getSocket(), pConnection->sslObject(), pAcceptor->getLog(), pAcceptor->m_verify) != 0)
424 {
425 if (pAcceptor->getLog())
426 pAcceptor->getLog()->onEvent("Failed to accept new SSL connection");
427 SSL *ssl = pConnection->sslObject();
428 delete pConnection;
429 if (!pAcceptor->isStopped())
430 pAcceptor->removeThread(SocketKey(socket, ssl));
431 return 0;
432 }
433
434 while (pConnection->read())
435 {
436 }
437 SSL *ssl = pConnection->sslObject();
438 delete pConnection;
439 if (!pAcceptor->isStopped())
440 pAcceptor->removeThread(SocketKey(socket, ssl));
441 return 0;
442}
443
444int ThreadedSSLSocketAcceptor::passwordHandleCallback(char *buf, size_t bufsize,
445 int verify, void *job)
446{
447 if (m_password.length() > bufsize)
448 return -1;
449
450 std::strcpy(buf, m_password.c_str());
451 return m_password.length();
452}
453}
454
455#endif
#define THREAD_PROC
Definition Utility.h:184
const char SOCKET_SEND_BUFFER_SIZE[]
int socket_accept(int s)
Definition Utility.cpp:164
const char SOCKET_ACCEPT_PORT[]
int socket_setsockopt(int s, int opt)
Definition Utility.cpp:208
void thread_detach(thread_id thread)
Definition Utility.cpp:447
const char SOCKET_REUSE_ADDRESS[]
pthread_t thread_id
Definition Utility.h:190
bool thread_spawn(THREAD_START_ROUTINE func, void *var, thread_id &thread)
Definition Utility.cpp:416
void socket_close(int s)
Definition Utility.cpp:180
void thread_join(thread_id thread)
Definition Utility.cpp:437
int socket_getsockopt(int s, int opt, int &optval)
Definition Utility.cpp:233
const char SOCKET_NODELAY[]
void socket_init()
Definition Utility.cpp:81
const char SOCKET_RECEIVE_BUFFER_SIZE[]
void socket_term()
Definition Utility.cpp:96
int socket_createAcceptor(int port, bool reuse)
Definition Utility.cpp:120
const char * socket_peername(int socket)
Definition Utility.cpp:353
static std::string convert(signed_int value)

Generated on Thu Feb 29 2024 22:38:19 for QuickFIX by doxygen 1.9.8 written by Dimitri van Heesch, © 1997-2001