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 
127 namespace FIX
128 {
129 
130 FIX::ThreadedSSLSocketAcceptor *acceptObjT = 0;
131 
132 int ThreadedSSLSocketAcceptor::passPhraseHandleCB(char *buf, int bufsize, int verify, void *job)
133 {
134  return acceptObjT->passwordHandleCallback(buf, bufsize, verify, job);
135 }
136 
137 ThreadedSSLSocketAcceptor::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 
147 ThreadedSSLSocketAcceptor::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 
157 ThreadedSSLSocketAcceptor::~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 
169 void 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 
185 void 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 
276 void 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 
290 bool ThreadedSSLSocketAcceptor::onPoll(double timeout) { return false; }
291 
292 void 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 
324 void ThreadedSSLSocketAcceptor::addThread(SocketKey s, thread_id t)
325 {
326  Locker l(m_mutex);
327 
328  m_threads[s] = t;
329 }
330 
331 void 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 
344 THREAD_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 
413 THREAD_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 
444 int 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
FIX::thread_id
pthread_t thread_id
Definition: Utility.h:190
ThreadedSSLSocketAcceptor.h
FIX::SOCKET_RECEIVE_BUFFER_SIZE
const char SOCKET_RECEIVE_BUFFER_SIZE[]
Definition: SessionSettings.h:87
FIX::SOCKET_NODELAY
const char SOCKET_NODELAY[]
Definition: SessionSettings.h:85
FIX::socket_setsockopt
int socket_setsockopt(int s, int opt)
Definition: Utility.cpp:225
FIX::socket_init
void socket_init()
Definition: Utility.cpp:98
FIX::SOCKET_SEND_BUFFER_SIZE
const char SOCKET_SEND_BUFFER_SIZE[]
Definition: SessionSettings.h:86
FIX::thread_detach
void thread_detach(thread_id thread)
Definition: Utility.cpp:464
FIX::socket_getsockopt
int socket_getsockopt(int s, int opt, int &optval)
Definition: Utility.cpp:250
FIX::socket_term
void socket_term()
Definition: Utility.cpp:113
FIX::SOCKET_ACCEPT_PORT
const char SOCKET_ACCEPT_PORT[]
Definition: SessionSettings.h:79
THREAD_PROC
#define THREAD_PROC
Definition: Utility.h:184
FIX::IntConvertor::convert
static std::string convert(signed_int value)
Definition: FieldConvertors.h:170
FIX::socket_accept
int socket_accept(int s)
Definition: Utility.cpp:181
Settings.h
FIX
Definition: Acceptor.cpp:34
FIX::socket_createAcceptor
int socket_createAcceptor(int port, bool reuse)
Definition: Utility.cpp:137
FIX::socket_close
void socket_close(int s)
Definition: Utility.cpp:197
FIX::thread_join
void thread_join(thread_id thread)
Definition: Utility.cpp:454
Utility.h
FIX::SOCKET_REUSE_ADDRESS
const char SOCKET_REUSE_ADDRESS[]
Definition: SessionSettings.h:80
FIX::thread_spawn
bool thread_spawn(THREAD_START_ROUTINE func, void *var, thread_id &thread)
Definition: Utility.cpp:433
FIX::socket_peername
const char * socket_peername(int socket)
Definition: Utility.cpp:370

Generated on Wed Apr 29 2020 19:41:30 for QuickFIX by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2001