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 "ThreadedSSLSocketConnection.h"
124 #include "ThreadedSSLSocketAcceptor.h"
125 #include "ThreadedSSLSocketInitiator.h"
126 #include "Session.h"
127 #include "Utility.h"
128 
129 namespace FIX
130 {
ThreadedSSLSocketConnection(int s,SSL * ssl,Sessions sessions,Log * pLog)131 ThreadedSSLSocketConnection::ThreadedSSLSocketConnection(int s, SSL *ssl,
132                                                          Sessions sessions,
133                                                          Log *pLog)
134     : m_socket(s), m_ssl(ssl), m_pLog(pLog), m_sessions(sessions),
135       m_pSession(0), m_disconnect(false)
136 {
137   FD_ZERO(&m_fds);
138   FD_SET(m_socket, &m_fds);
139 }
140 
ThreadedSSLSocketConnection(const SessionID & sessionID,int s,SSL * ssl,const std::string & address,short port,Log * pLog)141 ThreadedSSLSocketConnection::ThreadedSSLSocketConnection(
142     const SessionID &sessionID, int s, SSL *ssl, const std::string &address,
143     short port, Log *pLog)
144     : m_socket(s), m_ssl(ssl), m_address(address), m_port(port), m_pLog(pLog),
145       m_pSession(Session::lookupSession(sessionID)), m_disconnect(false)
146 {
147   FD_ZERO(&m_fds);
148   FD_SET(m_socket, &m_fds);
149   if (m_pSession)
150     m_pSession->setResponder(this);
151 }
152 
~ThreadedSSLSocketConnection()153 ThreadedSSLSocketConnection::~ThreadedSSLSocketConnection()
154 {
155   if (m_pSession)
156   {
157     m_pSession->setResponder(0);
158     Session::unregisterSession(m_pSession->getSessionID());
159   }
160 }
161 
send(const std::string & msg)162 bool ThreadedSSLSocketConnection::send(const std::string &msg)
163 {
164   int totalSent = 0;
165 
166   while (totalSent < (int)msg.length())
167   {
168     errno = 0;
169     int errCodeSSL = 0;
170     int sent = 0;
171     ERR_clear_error();
172 
173     // Cannot do concurrent SSL write and read as ssl context has to be
174     // protected.
175     {
176       Locker locker(m_mutex);
177 
178       sent = SSL_write(m_ssl, msg.c_str() + totalSent, msg.length() - totalSent);
179       if (sent <= 0)
180         errCodeSSL = SSL_get_error(m_ssl, sent);
181     }
182 
183     if (sent <= 0)
184     {
185       if ((errCodeSSL == SSL_ERROR_WANT_READ) ||
186           (errCodeSSL == SSL_ERROR_WANT_WRITE))
187       {
188         errno = EINTR;
189         sent = 0;
190       }
191       else
192       {
193         char errbuf[200];
194 
195         socket_error(errbuf, sizeof(errbuf));
196 
197         m_pSession->getLog()->onEvent("SSL send error <" +
198                                       IntConvertor::convert(errCodeSSL) + "> " +
199                                       errbuf);
200 
201         return false;
202       }
203     }
204 
205     totalSent += sent;
206   }
207 
208   return true;
209 }
210 
connect()211 bool ThreadedSSLSocketConnection::connect()
212 {
213   return socket_connect(getSocket(), m_address.c_str(), m_port) >= 0;
214 }
215 
disconnect()216 void ThreadedSSLSocketConnection::disconnect()
217 {
218   m_disconnect = true;
219   ssl_socket_close(m_socket, m_ssl);
220 }
221 
read()222 bool ThreadedSSLSocketConnection::read()
223 {
224   struct timeval timeout = {1, 0};
225   fd_set readset = m_fds;
226 
227   try
228   {
229     // Wait for input (1 second timeout)
230     int result = select(1 + m_socket, &readset, 0, 0, &timeout);
231 
232     if (result > 0) // Something to read
233     {
234       bool pending = false;
235 
236       do
237       {
238         pending = false;
239         errno = 0;
240         int size = 0;
241         int errCodeSSL = 0;
242         ERR_clear_error();
243 
244         // Cannot do concurrent SSL write and read as ssl context has to be
245         // protected.
246         {
247           Locker locker(m_mutex);
248 
249           size = SSL_read(m_ssl, m_buffer, sizeof(m_buffer));
250           if (size <= 0)
251             errCodeSSL = SSL_get_error(m_ssl, size);
252           else if (SSL_pending(m_ssl) > 0)
253             pending = true;
254         }
255 
256         if (size <= 0)
257         {
258           if ((errCodeSSL == SSL_ERROR_WANT_READ) ||
259               (errCodeSSL == SSL_ERROR_WANT_WRITE))
260           {
261             errno = EINTR;
262             size = 0;
263 
264             return true;
265           }
266           else
267           {
268             char errbuf[200];
269 
270             socket_error(errbuf, sizeof(errbuf));
271 
272             if (m_pSession)
273               m_pSession->getLog()->onEvent("SSL read error <" +
274                                             IntConvertor::convert(errCodeSSL) +
275                                             "> " + errbuf);
276             else
277             {
278               std::cerr << UtcTimeStampConvertor::convert(UtcTimeStamp())
279                         << "SSL read error <"
280                         << IntConvertor::convert(errCodeSSL) << "> " << errbuf
281                         << std::endl;
282             }
283 
284             throw SocketRecvFailed(size);
285           }
286         }
287 
288         m_parser.addToStream(m_buffer, size);
289       } while (pending);
290     }
291     else if (result == 0 && m_pSession) // Timeout
292     {
293       m_pSession->next();
294     }
295     else if (result < 0) // Error
296     {
297       throw SocketRecvFailed(result);
298     }
299 
300     processStream();
301 
302     if (m_disconnect)
303       return false;
304 
305     return true;
306   }
307   catch (SocketRecvFailed &e)
308   {
309     if (m_disconnect)
310       return false;
311 
312     if (m_pSession)
313     {
314       m_pSession->getLog()->onEvent(e.what());
315       m_pSession->disconnect();
316     }
317     else
318     {
319       disconnect();
320     }
321 
322     return false;
323   }
324 }
325 
readMessage(std::string & msg)326 bool ThreadedSSLSocketConnection::readMessage(std::string &msg) throw(
327     SocketRecvFailed)
328 {
329   try
330   {
331     return m_parser.readFixMessage(msg);
332   }
333   catch (MessageParseError &)
334   {
335   }
336   return true;
337 }
338 
processStream()339 void ThreadedSSLSocketConnection::processStream()
340 {
341   std::string msg;
342   while (readMessage(msg))
343   {
344     if (!m_pSession)
345     {
346       if (!setSession(msg))
347       {
348         disconnect();
349         continue;
350       }
351     }
352     try
353     {
354       m_pSession->next(msg, UtcTimeStamp());
355     }
356     catch (InvalidMessage &)
357     {
358       if (!m_pSession->isLoggedOn())
359       {
360         disconnect();
361         return;
362       }
363     }
364   }
365 }
366 
setSession(const std::string & msg)367 bool ThreadedSSLSocketConnection::setSession(const std::string &msg)
368 {
369   m_pSession = Session::lookupSession(msg, true);
370   if (!m_pSession)
371   {
372     if (m_pLog)
373     {
374       m_pLog->onEvent("Session not found for incoming message: " + msg);
375       m_pLog->onIncoming(msg);
376     }
377     return false;
378   }
379 
380   SessionID sessionID = m_pSession->getSessionID();
381   m_pSession = 0;
382 
383   // see if the session frees up within 5 seconds
384   for (int i = 1; i <= 5; i++)
385   {
386     if (!Session::isSessionRegistered(sessionID))
387       m_pSession = Session::registerSession(sessionID);
388     if (m_pSession)
389       break;
390     process_sleep(1);
391   }
392 
393   if (!m_pSession)
394     return false;
395   if (m_sessions.find(m_pSession->getSessionID()) == m_sessions.end())
396     return false;
397 
398   m_pSession->setResponder(this);
399   return true;
400 }
401 
402 } // namespace FIX
403 
404 #endif
405