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