SSLSocketInitiator.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 
123 #include "SSLSocketInitiator.h"
124 #include "Session.h"
125 #include "Settings.h"
126 
127 namespace FIX
128 {
129 
130 FIX::SSLSocketInitiator *initObj = 0;
131 
132 int SSLSocketInitiator::passwordHandleCB(char *buf, int bufsize, int verify, void *job)
133 {
134  return initObj->passwordHandleCallback(buf, bufsize, verify, job);
135 }
136 
137 SSLSocketInitiator::SSLSocketInitiator( Application& application,
138  MessageStoreFactory& factory,
139  const SessionSettings& settings )
140 throw( ConfigError )
141 : Initiator( application, factory, settings ),
142  m_connector( 1 ), m_lastConnect( 0 ),
143  m_reconnectInterval( 30 ), m_noDelay( false ), m_sendBufSize( 0 ),
144  m_rcvBufSize( 0 ), m_sslInit(false), m_ctx(0), m_cert(0), m_key(0)
145 {
146  initObj = this;
147 }
148 
149 SSLSocketInitiator::SSLSocketInitiator( Application& application,
150  MessageStoreFactory& factory,
151  const SessionSettings& settings,
152  LogFactory& logFactory )
153 throw( ConfigError )
154 : Initiator( application, factory, settings, logFactory ),
155  m_connector( 1 ), m_lastConnect( 0 ),
156  m_reconnectInterval( 30 ), m_noDelay( false ), m_sendBufSize( 0 ),
157  m_rcvBufSize( 0 ), m_sslInit(false), m_ctx(0), m_cert(0), m_key(0)
158 {
159  initObj = this;
160 }
161 
162 SSLSocketInitiator::~SSLSocketInitiator()
163 {
164  SocketConnections::iterator i;
165  for (i = m_connections.begin();
166  i != m_connections.end(); ++i)
167  delete i->second;
168 
169  for (i = m_pendingConnections.begin();
170  i != m_pendingConnections.end(); ++i)
171  delete i->second;
172 
173  if (m_sslInit)
174  {
175  SSL_CTX_free(m_ctx);
176  m_ctx = 0;
177  ssl_term();
178  }
179 }
180 
181 void SSLSocketInitiator::onConfigure( const SessionSettings& s )
182 throw ( ConfigError )
183 {
184  const Dictionary& dict = s.get();
185 
186  if( dict.has( RECONNECT_INTERVAL ) )
187  m_reconnectInterval = dict.getInt( RECONNECT_INTERVAL );
188  if( dict.has( SOCKET_NODELAY ) )
189  m_noDelay = dict.getBool( SOCKET_NODELAY );
190  if( dict.has( SOCKET_SEND_BUFFER_SIZE ) )
191  m_sendBufSize = dict.getInt( SOCKET_SEND_BUFFER_SIZE );
192  if( dict.has( SOCKET_RECEIVE_BUFFER_SIZE ) )
193  m_rcvBufSize = dict.getInt( SOCKET_RECEIVE_BUFFER_SIZE );
194 }
195 
196 void SSLSocketInitiator::onInitialize( const SessionSettings& s )
197 throw ( RuntimeError )
198 {
199  if (m_sslInit)
200  return;
201 
202  ssl_init();
203 
204  std::string errStr;
205 
206  /* set up the application context */
207  if ((m_ctx = createSSLContext(false, s, errStr)) == 0)
208  {
209  throw RuntimeError(errStr);
210  }
211 
212  if (m_cert && m_key)
213  {
214  if (SSL_CTX_use_certificate(m_ctx, m_cert) < 1)
215  {
216  ssl_term();
217  throw RuntimeError("Failed to set certificate");
218  }
219 
220  if (SSL_CTX_use_RSAPrivateKey(m_ctx, m_key) <= 0)
221  {
222  ssl_term();
223  throw RuntimeError("Failed to set key");
224  }
225  }
226  else if (!loadSSLCert(m_ctx, false, s, getLog(), SSLSocketInitiator::passwordHandleCB, errStr))
227  {
228  ssl_term();
229  throw RuntimeError(errStr);
230  }
231 
232  int verifyLevel;
233  if (!loadCAInfo(m_ctx, false, s, getLog(), errStr, verifyLevel))
234  {
235  ssl_term();
236  throw RuntimeError(errStr);
237  }
238 
239  m_sslInit = true;
240 }
241 
242 void SSLSocketInitiator::onStart()
243 {
244  connect();
245 
246  while ( !isStopped() ) {
247  m_connector.block( *this, false, 1.0 );
248  onTimeout( m_connector );
249  }
250 
251  time_t start = 0;
252  time_t now = 0;
253 
254  ::time( &start );
255  while ( isLoggedOn() )
256  {
257  m_connector.block( *this );
258  if( ::time(&now) -5 >= start )
259  break;
260  }
261 }
262 
263 bool SSLSocketInitiator::onPoll( double timeout )
264 {
265  time_t start = 0;
266  time_t now = 0;
267 
268  if( isStopped() )
269  {
270  if( start == 0 )
271  ::time( &start );
272  if( !isLoggedOn() )
273  return false;
274  if( ::time(&now) - 5 >= start )
275  return false;
276  }
277 
278  m_connector.block( *this, true, timeout );
279  return true;
280 }
281 
282 void SSLSocketInitiator::onStop()
283 {
284 }
285 
286 void SSLSocketInitiator::doConnect( const SessionID& s, const Dictionary& d )
287 {
288  try
289  {
290  std::string address;
291  short port = 0;
292  std::string sourceAddress;
293  short sourcePort = 0;
294 
295  Session* session = Session::lookupSession( s );
296  if( !session->isSessionTime(UtcTimeStamp()) ) return;
297 
298  Log* log = session->getLog();
299 
300  getHost( s, d, address, port, sourceAddress, sourcePort );
301 
302  log->onEvent( "Connecting to " + address + " on port " + IntConvertor::convert((unsigned short)port) + " (Source " + sourceAddress + ":" + IntConvertor::convert((unsigned short)sourcePort) + ")");
303  int result = m_connector.connect( address, port, m_noDelay, m_sendBufSize, m_rcvBufSize, sourceAddress, sourcePort );
304 
305  SSL *ssl = SSL_new(m_ctx);
306  if (ssl == 0)
307  {
308  log->onEvent("Failed to create ssl object");
309  return;
310  }
311  SSL_clear(ssl);
312  BIO *sbio = BIO_new_socket(result, BIO_CLOSE);
313  if (sbio == 0)
314  {
315  log->onEvent("BIO_new_socket failed");
316  return;
317  }
318  SSL_set_bio(ssl, sbio, sbio);
319 
320  ERR_clear_error();
321  // Do the SSL handshake.
322  int rc = SSL_connect(ssl);
323  while (rc <= 0)
324  {
325  int err = SSL_get_error(ssl, rc);
326  if ((err == SSL_ERROR_WANT_READ) ||
327  (err == SSL_ERROR_WANT_WRITE))
328  {
329  errno = EINTR;
330  }
331  else
332  {
333  getLog()->onEvent("SSL_connect failed with SSL error " + IntConvertor::convert(err));
334  return;
335  }
336  ERR_clear_error();
337  rc = SSL_connect(ssl);
338  }
339 
340  setPending( s );
341  m_pendingConnections[ result ] = new SSLSocketConnection( *this, s, result, ssl, &m_connector.getMonitor() );
342  }
343  catch ( std::exception& ) {}
344 }
345 
346 void SSLSocketInitiator::onConnect( SocketConnector&, int s )
347 {
348  SocketConnections::iterator i = m_pendingConnections.find( s );
349  if( i == m_pendingConnections.end() ) return;
350  SSLSocketConnection* pSocketConnection = i->second;
351 
352  m_connections[s] = pSocketConnection;
353  m_pendingConnections.erase( i );
354  setConnected( pSocketConnection->getSession()->getSessionID() );
355  pSocketConnection->onTimeout();
356 }
357 
358 void SSLSocketInitiator::onWrite( SocketConnector& connector, int s )
359 {
360  SocketConnections::iterator i = m_connections.find( s );
361  if ( i == m_connections.end() ) return ;
362  SSLSocketConnection* pSocketConnection = i->second;
363  if( pSocketConnection->processQueue() )
364  pSocketConnection->unsignal();
365 }
366 
367 bool SSLSocketInitiator::onData( SocketConnector& connector, int s )
368 {
369  SocketConnections::iterator i = m_connections.find( s );
370  if ( i == m_connections.end() ) return false;
371  SSLSocketConnection* pSocketConnection = i->second;
372  return pSocketConnection->read( connector );
373 }
374 
375 void SSLSocketInitiator::onDisconnect( SocketConnector&, int s )
376 {
377  SocketConnections::iterator i = m_connections.find( s );
378  SocketConnections::iterator j = m_pendingConnections.find( s );
379 
380  SSLSocketConnection* pSocketConnection = 0;
381  if( i != m_connections.end() )
382  pSocketConnection = i->second;
383  if( j != m_pendingConnections.end() )
384  pSocketConnection = j->second;
385  if( !pSocketConnection )
386  return;
387 
388  setDisconnected( pSocketConnection->getSession()->getSessionID() );
389 
390  Session* pSession = pSocketConnection->getSession();
391  if ( pSession )
392  {
393  pSession->disconnect();
394  setDisconnected( pSession->getSessionID() );
395  }
396 
397  delete pSocketConnection;
398  m_connections.erase( s );
399  m_pendingConnections.erase( s );
400 }
401 
402 void SSLSocketInitiator::onError( SocketConnector& connector )
403 {
404  onTimeout( connector );
405 }
406 
407 void SSLSocketInitiator::onTimeout( SocketConnector& )
408 {
409  time_t now;
410  ::time( &now );
411 
412  if ( (now - m_lastConnect) >= m_reconnectInterval )
413  {
414  connect();
415  m_lastConnect = now;
416  }
417 
418  SocketConnections::iterator i;
419  for ( i = m_connections.begin(); i != m_connections.end(); ++i )
420  i->second->onTimeout();
421 }
422 
423 void SSLSocketInitiator::getHost( const SessionID& s, const Dictionary& d,
424  std::string& address, short& port,
425  std::string& sourceAddress, short& sourcePort)
426 {
427  int num = 0;
428  SessionToHostNum::iterator i = m_sessionToHostNum.find( s );
429  if ( i != m_sessionToHostNum.end() ) num = i->second;
430 
431  std::stringstream hostStream;
432  hostStream << SOCKET_CONNECT_HOST << num;
433  std::string hostString = hostStream.str();
434 
435  std::stringstream portStream;
436  portStream << SOCKET_CONNECT_PORT << num;
437  std::string portString = portStream.str();
438 
439  sourcePort = 0;
440  sourceAddress.empty();
441 
442  if( d.has(hostString) && d.has(portString) )
443  {
444  address = d.getString( hostString );
445  port = ( short ) d.getInt( portString );
446 
447  std::stringstream sourceHostStream;
448  sourceHostStream << SOCKET_CONNECT_SOURCE_HOST << num;
449  hostString = sourceHostStream.str();
450  if( d.has(hostString) )
451  sourceAddress = d.getString( hostString );
452 
453  std::stringstream sourcePortStream;
454  sourcePortStream << SOCKET_CONNECT_SOURCE_PORT << num;
455  portString = sourcePortStream.str();
456  if( d.has(portString) )
457  sourcePort = ( short ) d.getInt( portString );
458  }
459  else
460  {
461  num = 0;
462  address = d.getString( SOCKET_CONNECT_HOST );
463  port = ( short ) d.getInt( SOCKET_CONNECT_PORT );
464 
465  if( d.has(SOCKET_CONNECT_SOURCE_HOST) )
466  sourceAddress = d.getString( SOCKET_CONNECT_SOURCE_HOST );
467  if( d.has(SOCKET_CONNECT_SOURCE_PORT) )
468  sourcePort = ( short ) d.getInt( SOCKET_CONNECT_SOURCE_PORT );
469  }
470 
471  m_sessionToHostNum[ s ] = ++num;
472 }
473 
474 int SSLSocketInitiator::passwordHandleCallback(char *buf, size_t bufsize,
475  int verify, void *job)
476 {
477  if (m_password.length() > bufsize)
478  return -1;
479 
480  std::strcpy(buf, m_password.c_str());
481  return m_password.length();
482 }
483 }
484 
485 #endif
FIX::SOCKET_RECEIVE_BUFFER_SIZE
const char SOCKET_RECEIVE_BUFFER_SIZE[]
Definition: SessionSettings.h:87
FIX::Session::lookupSession
static Session * lookupSession(const SessionID &)
Definition: Session.cpp:1513
FIX::SOCKET_NODELAY
const char SOCKET_NODELAY[]
Definition: SessionSettings.h:85
SSLSocketInitiator.h
FIX::SOCKET_CONNECT_SOURCE_PORT
const char SOCKET_CONNECT_SOURCE_PORT[]
Definition: SessionSettings.h:84
FIX::SOCKET_CONNECT_SOURCE_HOST
const char SOCKET_CONNECT_SOURCE_HOST[]
Definition: SessionSettings.h:83
FIX::SOCKET_SEND_BUFFER_SIZE
const char SOCKET_SEND_BUFFER_SIZE[]
Definition: SessionSettings.h:86
FIX::TYPE::UtcTimeStamp
@ UtcTimeStamp
Definition: FieldTypes.h:940
FIX::IntConvertor::convert
static std::string convert(signed_int value)
Definition: FieldConvertors.h:170
FIX::RECONNECT_INTERVAL
const char RECONNECT_INTERVAL[]
Definition: SessionSettings.h:88
Settings.h
FIX::SOCKET_CONNECT_PORT
const char SOCKET_CONNECT_PORT[]
Definition: SessionSettings.h:82
FIX
Definition: Acceptor.cpp:34
Session.h
FIX::SOCKET_CONNECT_HOST
const char SOCKET_CONNECT_HOST[]
Definition: SessionSettings.h:81

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