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
127namespace FIX
128{
129
130FIX::SSLSocketInitiator *initObj = 0;
131
132int SSLSocketInitiator::passwordHandleCB(char *buf, int bufsize, int verify, void *job)
133{
134 return initObj->passwordHandleCallback(buf, bufsize, verify, job);
135}
136
137SSLSocketInitiator::SSLSocketInitiator( Application& application,
138 MessageStoreFactory& factory,
139 const SessionSettings& settings )
140throw( 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
149SSLSocketInitiator::SSLSocketInitiator( Application& application,
150 MessageStoreFactory& factory,
151 const SessionSettings& settings,
152 LogFactory& logFactory )
153throw( 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
162SSLSocketInitiator::~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
181void SSLSocketInitiator::onConfigure( const SessionSettings& s )
182throw ( 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
196void SSLSocketInitiator::onInitialize( const SessionSettings& s )
197throw ( 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
242void 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
263bool 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
282void SSLSocketInitiator::onStop()
283{
284}
285
286void 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
346void 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
358void 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
367bool 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
375void 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
402void SSLSocketInitiator::onError( SocketConnector& connector )
403{
404 onTimeout( connector );
405}
406
407void 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
423void 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
474int 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
static Session * lookupSession(const SessionID &)
Definition Session.cpp:1496
const char SOCKET_CONNECT_PORT[]
const char SOCKET_SEND_BUFFER_SIZE[]
const char SOCKET_NODELAY[]
const char SOCKET_RECEIVE_BUFFER_SIZE[]
const char RECONNECT_INTERVAL[]
const char SOCKET_CONNECT_HOST[]
const char SOCKET_CONNECT_SOURCE_PORT[]
const char SOCKET_CONNECT_SOURCE_HOST[]
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