Repository: ignite
Updated Branches:
  refs/heads/master a824ba8e1 -> 394019eef


http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/connection.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/connection.cpp 
b/modules/platforms/cpp/odbc/src/connection.cpp
index 4e8f4ab..11105b6 100644
--- a/modules/platforms/cpp/odbc/src/connection.cpp
+++ b/modules/platforms/cpp/odbc/src/connection.cpp
@@ -28,6 +28,10 @@
 #include "ignite/odbc/connection.h"
 #include "ignite/odbc/message.h"
 #include "ignite/odbc/config/configuration.h"
+#include "ignite/odbc/ssl/ssl_mode.h"
+#include "ignite/odbc/ssl/ssl_gateway.h"
+#include "ignite/odbc/ssl/secure_socket_client.h"
+#include "ignite/odbc/system/tcp_socket_client.h"
 
 // Uncomment for per-byte debug.
 //#define PER_BYTE_DEBUG
@@ -49,7 +53,6 @@ namespace ignite
     {
         Connection::Connection() :
             socket(),
-            connected(false),
             timeout(0),
             parser(),
             config(),
@@ -122,21 +125,44 @@ namespace ignite
 
         SqlResult::Type Connection::InternalEstablish(const 
config::Configuration cfg)
         {
+            using ssl::SslMode;
+
             config = cfg;
 
-            if (connected)
+            if (socket.get() != 0)
             {
                 AddStatusRecord(SqlState::S08002_ALREADY_CONNECTED, "Already 
connected.");
 
                 return SqlResult::AI_ERROR;
             }
 
-            connected = socket.Connect(cfg.GetHost().c_str(), 
cfg.GetTcpPort(), *this);
+            SslMode::T sslMode = SslMode::FromString(cfg.GetSslMode(), 
SslMode::DISABLE);
+
+            if (sslMode != SslMode::DISABLE)
+            {
+                bool loaded = ssl::SslGateway::GetInstance().LoadAll();
+
+                if (!loaded)
+                {
+                    AddStatusRecord(SqlState::SHY000_GENERAL_ERROR,
+                        "Can not load OpenSSL library (did you set 
OPENSSL_HOME environment variable?).");
+
+                    return SqlResult::AI_ERROR;
+                }
+
+                socket.reset(new ssl::SecureSocketClient(cfg.GetSslCertFile(), 
cfg.GetSslKeyFile(), cfg.GetSslCaFile()));
+            }
+            else
+                socket.reset(new system::TcpSocketClient());
+
+            bool connected = socket->Connect(cfg.GetHost().c_str(), 
cfg.GetTcpPort(), *this);
 
             if (!connected)
             {
                 AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, "Failed to 
establish connection with the host.");
 
+                Close();
+
                 return SqlResult::AI_ERROR;
             }
 
@@ -157,7 +183,7 @@ namespace ignite
 
         SqlResult::Type Connection::InternalRelease()
         {
-            if (!connected)
+            if (socket.get() == 0)
             {
                 AddStatusRecord(SqlState::S08003_NOT_CONNECTED, "Connection is 
not open.");
 
@@ -171,9 +197,12 @@ namespace ignite
 
         void Connection::Close()
         {
-            socket.Close();
+            if (socket.get() != 0)
+            {
+                socket->Close();
 
-            connected = false;
+                socket.reset();
+            }
         }
 
         Statement* Connection::CreateStatement()
@@ -201,7 +230,7 @@ namespace ignite
 
         bool Connection::Send(const int8_t* data, size_t len, int32_t timeout)
         {
-            if (!connected)
+            if (socket.get() == 0)
                 throw OdbcError(SqlState::S08003_NOT_CONNECTED, "Connection is 
not established");
 
             int32_t newLen = static_cast<int32_t>(len + 
sizeof(OdbcProtocolHeader));
@@ -235,11 +264,11 @@ namespace ignite
 
             while (sent != static_cast<int64_t>(len))
             {
-                int res = socket.Send(data + sent, len - sent, timeout);
+                int res = socket->Send(data + sent, len - sent, timeout);
 
                 LOG_MSG("Sent: " << res);
 
-                if (res < 0 || res == tcp::SocketClient::WaitResult::TIMEOUT)
+                if (res < 0 || res == SocketClient::WaitResult::TIMEOUT)
                 {
                     Close();
 
@@ -256,7 +285,7 @@ namespace ignite
 
         bool Connection::Receive(std::vector<int8_t>& msg, int32_t timeout)
         {
-            if (!connected)
+            if (socket.get() == 0)
                 throw OdbcError(SqlState::S08003_NOT_CONNECTED, "Connection is 
not established");
 
             msg.clear();
@@ -307,10 +336,10 @@ namespace ignite
             {
                 size_t received = len - remain;
 
-                int res = socket.Receive(buffer + received, remain, timeout);
+                int res = socket->Receive(buffer + received, remain, timeout);
                 LOG_MSG("Receive res: " << res << " remain: " << remain);
 
-                if (res < 0 || res == tcp::SocketClient::WaitResult::TIMEOUT)
+                if (res < 0 || res == SocketClient::WaitResult::TIMEOUT)
                 {
                     Close();
 
@@ -382,7 +411,7 @@ namespace ignite
                 {
                     SQLUINTEGER *val = reinterpret_cast<SQLUINTEGER*>(buf);
 
-                    *val = connected ? SQL_CD_FALSE : SQL_CD_TRUE;
+                    *val = socket.get() != 0 ? SQL_CD_FALSE : SQL_CD_TRUE;
 
                     if (valueLen)
                         *valueLen = SQL_IS_INTEGER;
@@ -441,7 +470,7 @@ namespace ignite
                 {
                     SQLUINTEGER uTimeout = 
static_cast<SQLUINTEGER>(reinterpret_cast<ptrdiff_t>(value));
 
-                    if (uTimeout != 0 && connected && socket.IsBlocking())
+                    if (uTimeout != 0 && socket.get() != 0 && 
socket->IsBlocking())
                     {
                         timeout = 0;
 
@@ -524,12 +553,13 @@ namespace ignite
             try
             {
                 // Workaround for some Linux systems that report connection on 
non-blocking
-                // sockets as successfull but fail to establish real 
connection.
-                bool sent = SyncMessage(req, rsp, 
tcp::SocketClient::CONNECT_TIMEOUT);
+                // sockets as successful but fail to establish real connection.
+                bool sent = SyncMessage(req, rsp, 
SocketClient::CONNECT_TIMEOUT);
 
                 if (!sent)
                 {
-                    AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, "Failed 
to establish connection with the host.");
+                    AddStatusRecord(SqlState::S08001_CANNOT_CONNECT,
+                        "Failed to get handshake response (Did you forget to 
enable SSL?).");
 
                     return SqlResult::AI_ERROR;
                 }
@@ -549,7 +579,7 @@ namespace ignite
 
             if (!rsp.IsAccepted())
             {
-                LOG_MSG("Hanshake message has been rejected.");
+                LOG_MSG("Handshake message has been rejected.");
 
                 std::stringstream constructor;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/dsn_config.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/dsn_config.cpp 
b/modules/platforms/cpp/odbc/src/dsn_config.cpp
index 536f679..845c8bd 100644
--- a/modules/platforms/cpp/odbc/src/dsn_config.cpp
+++ b/modules/platforms/cpp/odbc/src/dsn_config.cpp
@@ -51,13 +51,13 @@ namespace ignite
                 ThrowLastSetupError();
         }
 
-        std::string ReadDsnString(const char* dsn, const std::string& key, 
const char* dflt)
+        std::string ReadDsnString(const char* dsn, const std::string& key, 
const std::string& dflt)
         {
             char buf[BUFFER_SIZE];
 
             memset(buf, 0, sizeof(buf));
 
-            SQLGetPrivateProfileString(dsn, key.c_str(), dflt, buf, 
sizeof(buf), CONFIG_FILE);
+            SQLGetPrivateProfileString(dsn, key.c_str(), dflt.c_str(), buf, 
sizeof(buf), CONFIG_FILE);
 
             return std::string(buf);
         }
@@ -90,13 +90,13 @@ namespace ignite
 
         void ReadDsnConfiguration(const char* dsn, Configuration& config)
         {
-            std::string address = ReadDsnString(dsn, 
Configuration::Key::address, config.GetAddress().c_str());
+            std::string address = ReadDsnString(dsn, 
Configuration::Key::address, config.GetAddress());
 
-            std::string server = ReadDsnString(dsn, 
Configuration::Key::server, config.GetHost().c_str());
+            std::string server = ReadDsnString(dsn, 
Configuration::Key::server, config.GetHost());
 
             uint16_t port = ReadDsnInt(dsn, Configuration::Key::port, 
config.GetTcpPort());
 
-            std::string schema = ReadDsnString(dsn, 
Configuration::Key::schema, config.GetSchema().c_str());
+            std::string schema = ReadDsnString(dsn, 
Configuration::Key::schema, config.GetSchema());
 
             bool distributedJoins = ReadDsnBool(dsn, 
Configuration::Key::distributedJoins, config.IsDistributedJoins());
 
@@ -112,13 +112,21 @@ namespace ignite
                 ReadDsnBool(dsn, Configuration::Key::skipReducerOnUpdate, 
config.IsSkipReducerOnUpdate());
 
             std::string version = ReadDsnString(dsn, 
Configuration::Key::protocolVersion,
-                config.GetProtocolVersion().ToString().c_str());
+                config.GetProtocolVersion().ToString());
 
             int32_t pageSize = ReadDsnInt(dsn, Configuration::Key::pageSize, 
config.GetPageSize());
 
             if (pageSize <= 0)
                 pageSize = config.GetPageSize();
 
+            std::string sslMode = ReadDsnString(dsn, 
Configuration::Key::sslMode, config.GetSslMode());
+
+            std::string sslKeyFile = ReadDsnString(dsn, 
Configuration::Key::sslKeyFile, config.GetSslKeyFile());
+
+            std::string sslCertFile = ReadDsnString(dsn, 
Configuration::Key::sslCertFile, config.GetSslCertFile());
+
+            std::string sslCaFile = ReadDsnString(dsn, 
Configuration::Key::sslCaFile, config.GetSslCaFile());
+
             config.SetAddress(address);
             config.SetHost(server);
             config.SetTcpPort(port);
@@ -131,6 +139,10 @@ namespace ignite
             config.SetSkipReducerOnUpdate(skipReducerOnUpdate);
             config.SetProtocolVersion(version);
             config.SetPageSize(pageSize);
+            config.SetSslMode(sslMode);
+            config.SetSslKeyFile(sslKeyFile);
+            config.SetSslCertFile(sslCertFile);
+            config.SetSslCaFile(sslCaFile);
         }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/odbc.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/odbc.cpp 
b/modules/platforms/cpp/odbc/src/odbc.cpp
index 1480d0b..e4b47b9 100644
--- a/modules/platforms/cpp/odbc/src/odbc.cpp
+++ b/modules/platforms/cpp/odbc/src/odbc.cpp
@@ -180,7 +180,7 @@ namespace ignite
     {
         using odbc::Environment;
 
-        LOG_MSG("SQLFreeEnv called");
+        LOG_MSG("SQLFreeEnv called: " << env);
 
         Environment *environment = reinterpret_cast<Environment*>(env);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp 
b/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp
new file mode 100644
index 0000000..c305b87
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp
@@ -0,0 +1,419 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <cstdio>
+
+#include "ignite/odbc/log.h"
+#include "ignite/common/concurrent.h"
+#include "ignite/odbc/system/tcp_socket_client.h"
+#include "ignite/odbc/ssl/secure_socket_client.h"
+#include "ignite/odbc/ssl/ssl_bindings.h"
+
+#ifndef SOCKET_ERROR
+#   define SOCKET_ERROR (-1)
+#endif // SOCKET_ERROR
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace ssl
+        {
+            SecureSocketClient::SecureSocketClient(const std::string& 
certPath, const std::string& keyPath,
+                const std::string& caPath):
+                certPath(certPath),
+                keyPath(keyPath),
+                caPath(caPath),
+                context(0),
+                sslBio(0),
+                blocking(true)
+            {
+                // No-op.
+            }
+
+            SecureSocketClient::~SecureSocketClient()
+            {
+                CloseInteral();
+
+                if (context)
+                    ssl::SSL_CTX_free(reinterpret_cast<SSL_CTX*>(context));
+            }
+
+            bool SecureSocketClient::Connect(const char* hostname, uint16_t 
port, diagnostic::Diagnosable& diag)
+            {
+                assert(SslGateway::GetInstance().Loaded());
+
+                if (!context)
+                {
+                    context = MakeContext(certPath, keyPath, caPath, diag);
+
+                    if (!context)
+                    {
+                        diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR,
+                            "Can not create SSL context. Aborting connect.");
+
+                        return false;
+                    }
+                }
+
+                BIO* bio = 
ssl::BIO_new_ssl_connect(reinterpret_cast<SSL_CTX*>(context));
+                if (!bio)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can 
not create SSL connection.");
+
+                    return false;
+                }
+
+                blocking = false;
+                long res = ssl::BIO_set_nbio_(bio, 1);
+                if (res != OPERATION_SUCCESS)
+                {
+                    blocking = true;
+
+                    diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                        "Can not set up non-blocking mode. Timeouts are not 
available.");
+                }
+
+                std::stringstream stream;
+                stream << hostname << ":" << port;
+
+                std::string address = stream.str();
+
+                res = ssl::BIO_set_conn_hostname_(bio, address.c_str());
+                if (res != OPERATION_SUCCESS)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can 
not set SSL connection hostname.");
+
+                    ssl::BIO_free_all(bio);
+
+                    return false;
+                }
+
+                SSL* ssl = 0;
+                ssl::BIO_get_ssl_(bio, &ssl);
+                if (!ssl)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can 
not get SSL instance from BIO.");
+
+                    ssl::BIO_free_all(bio);
+
+                    return false;
+                }
+
+                res = ssl::SSL_set_tlsext_host_name_(ssl, hostname);
+                if (res != OPERATION_SUCCESS)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can 
not set host name for secure connection");
+
+                    ssl::BIO_free_all(bio);
+
+                    return false;
+                }
+
+                do
+                {
+                    res = ssl::BIO_do_connect_(bio);
+                } while (ssl::BIO_should_retry_(bio));
+
+                if (res != OPERATION_SUCCESS)
+                {
+                    diag.AddStatusRecord(SqlState::S08001_CANNOT_CONNECT,
+                        "Failed to establish secure connection with the 
host.");
+
+                    ssl::BIO_free_all(bio);
+
+                    return false;
+                }
+
+                do
+                {
+                    res = ssl::BIO_do_handshake_(bio);
+                } while (ssl::BIO_should_retry_(bio));
+
+                if (res != OPERATION_SUCCESS)
+                {
+                    diag.AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, "SSL 
handshake failed.");
+
+                    ssl::BIO_free_all(bio);
+
+                    return false;
+                }
+
+                // Verify a server certificate was presented during the 
negotiation
+                X509* cert = ssl::SSL_get_peer_certificate(ssl);
+                if (cert)
+                    ssl::X509_free(cert);
+                else
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, 
"Remote host did not provide certificate.");
+
+                    ssl::BIO_free_all(bio);
+
+                    return false;
+                }
+
+                // Verify the result of chain verification
+                // Verification performed according to RFC 4158
+                res = ssl::SSL_get_verify_result(ssl);
+                if (X509_V_OK != res)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, 
"Certificate chain verification failed.");
+
+                    ssl::BIO_free_all(bio);
+
+                    return false;
+                }
+
+                sslBio = reinterpret_cast<void*>(bio);
+
+                return true;
+            }
+
+            void SecureSocketClient::Close()
+            {
+                CloseInteral();
+            }
+
+            int SecureSocketClient::Send(const int8_t* data, size_t size, 
int32_t timeout)
+            {
+                assert(SslGateway::GetInstance().Loaded());
+
+                if (!sslBio)
+                {
+                    LOG_MSG("Trying to send data using closed connection");
+
+                    return -1;
+                }
+
+                BIO* sslBio0 = reinterpret_cast<BIO*>(sslBio);
+
+                int res = 0;
+
+                do
+                {
+                    res = ssl::BIO_write(sslBio0, data, 
static_cast<int>(size));
+                }
+                while (ssl::BIO_should_retry_(sslBio0));
+
+                return res;
+            }
+
+            int SecureSocketClient::Receive(int8_t* buffer, size_t size, 
int32_t timeout)
+            {
+                assert(SslGateway::GetInstance().Loaded());
+
+                if (!sslBio)
+                {
+                    LOG_MSG("Trying to receive data using closed connection");
+
+                    return -1;
+                }
+
+                BIO* sslBio0 = reinterpret_cast<BIO*>(sslBio);
+
+                int res = 0;
+
+                if (!blocking && BIO_pending_(sslBio0) == 0)
+                {
+                    res = WaitOnSocket(timeout, true);
+
+                    if (res < 0 || res == WaitResult::TIMEOUT)
+                        return res;
+                }
+
+                do
+                {
+                    res = ssl::BIO_read(sslBio0, buffer, 
static_cast<int>(size));
+                }
+                while (ssl::BIO_should_retry_(sslBio0));
+
+                return res;
+            }
+
+            bool SecureSocketClient::IsBlocking() const
+            {
+                return blocking;
+            }
+
+            void* SecureSocketClient::MakeContext(const std::string& certPath, 
const std::string& keyPath,
+                const std::string& caPath, diagnostic::Diagnosable& diag)
+            {
+                assert(SslGateway::GetInstance().Loaded());
+
+                static bool sslLibInited = false;
+                static common::concurrent::CriticalSection sslCs;
+
+                if (!sslLibInited)
+                {
+                    common::concurrent::CsLockGuard lock(sslCs);
+
+                    if (!sslLibInited)
+                    {
+                        LOG_MSG("Initializing SSL library");
+
+                        (void)SSL_library_init();
+
+                        SSL_load_error_strings();
+
+                        OPENSSL_config(0);
+
+                        sslLibInited = true;
+                    }
+                }
+
+                const SSL_METHOD* method = SSLv23_method();
+                if (!method)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can 
not create new SSL method.");
+
+                    return 0;
+                }
+
+                SSL_CTX* ctx = ssl::SSL_CTX_new(method);
+                if (!ctx)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can 
not create new SSL context.");
+
+                    return 0;
+                }
+
+                ssl::SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 0);
+
+                ssl::SSL_CTX_set_verify_depth(ctx, 8);
+
+                const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | 
SSL_OP_NO_COMPRESSION;
+                ssl::SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, flags, NULL);
+
+                const char* cCaPath = caPath.empty() ? 0 : caPath.c_str();
+
+                long res = ssl::SSL_CTX_load_verify_locations(ctx, cCaPath, 0);
+                if (res != OPERATION_SUCCESS)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR,
+                        "Can not set Certificate Authority path for secure 
connection.");
+
+                    ssl::SSL_CTX_free(ctx);
+
+                    return 0;
+                }
+
+                res = ssl::SSL_CTX_use_certificate_chain_file(ctx, 
certPath.c_str());
+                if (res != OPERATION_SUCCESS)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR,
+                        "Can not set client certificate file for secure 
connection.");
+
+                    ssl::SSL_CTX_free(ctx);
+
+                    return 0;
+                }
+
+                res = ssl::SSL_CTX_use_RSAPrivateKey_file(ctx, 
keyPath.c_str(), SSL_FILETYPE_PEM);
+                if (res != OPERATION_SUCCESS)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR,
+                        "Can not set private key file for secure connection.");
+
+                    ssl::SSL_CTX_free(ctx);
+
+                    return 0;
+                }
+
+                const char* const PREFERRED_CIPHERS = 
"HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
+                res = ssl::SSL_CTX_set_cipher_list(ctx, PREFERRED_CIPHERS);
+                if (res != OPERATION_SUCCESS)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR,
+                        "Can not set ciphers list for secure connection.");
+
+                    ssl::SSL_CTX_free(ctx);
+
+                    return 0;
+                }
+
+                return ctx;
+            }
+
+            void SecureSocketClient::CloseInteral()
+            {
+                assert(SslGateway::GetInstance().Loaded());
+
+                if (sslBio)
+                {
+                    ssl::BIO_free_all(reinterpret_cast<BIO*>(sslBio));
+
+                    sslBio = 0;
+                }
+            }
+
+            int SecureSocketClient::WaitOnSocket(int32_t timeout, bool rd)
+            {
+                int ready = 0;
+                int lastError = 0;
+                int fdSocket = 0;
+                BIO* sslBio0 = reinterpret_cast<BIO*>(sslBio);
+
+                fd_set fds;
+
+                long res = ssl::BIO_get_fd_(sslBio0, &fdSocket);
+
+                if (res < 0)
+                {
+                    LOG_MSG("Can not get file descriptor from the SSL socket: 
" << res);
+
+                    return res;
+                }
+
+                do {
+                    struct timeval tv = { 0 };
+                    tv.tv_sec = timeout;
+
+                    FD_ZERO(&fds);
+                    FD_SET(static_cast<long>(fdSocket), &fds);
+
+                    fd_set* readFds = 0;
+                    fd_set* writeFds = 0;
+
+                    if (rd)
+                        readFds = &fds;
+                    else
+                        writeFds = &fds;
+
+                    ready = select(fdSocket + 1, readFds, writeFds, NULL, 
(timeout == 0 ? NULL : &tv));
+
+                    if (ready == SOCKET_ERROR)
+                        lastError = 
system::TcpSocketClient::GetLastSocketError();
+
+                } while (ready == SOCKET_ERROR && 
system::TcpSocketClient::IsSocketOperationInterrupted(lastError));
+
+                if (ready == SOCKET_ERROR)
+                    return -lastError;
+
+                lastError = 
system::TcpSocketClient::GetLastSocketError(fdSocket);
+
+                if (lastError != 0)
+                    return -lastError;
+
+                if (ready == 0)
+                    return WaitResult::TIMEOUT;
+
+                return WaitResult::SUCCESS;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp 
b/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp
new file mode 100644
index 0000000..c91d44e
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp
@@ -0,0 +1,210 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+
+#include <openssl/ssl.h>
+#include <openssl/conf.h>
+
+#include "ignite/common/utils.h"
+
+#include "ignite/odbc/ssl/ssl_gateway.h"
+#include "ignite/odbc/log.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace ssl
+        {
+            SslGateway::SslGateway() :
+                inited(false),
+                functions()
+            {
+                // No-op.
+            }
+
+            SslGateway::~SslGateway()
+            {
+                // No-op.
+            }
+
+            common::dynamic::Module SslGateway::LoadSslLibrary(const char* 
name)
+            {
+                using namespace common;
+                using namespace dynamic;
+
+                std::string fullName = GetDynamicLibraryName(name);
+
+                Module libModule = LoadModule(fullName);
+
+                if (libModule.IsLoaded())
+                    return libModule;
+
+                std::string home = GetEnv("OPEN_SSL_HOME");
+
+                if (home.empty())
+                    home = GetEnv("OPENSSL_HOME");
+
+                if (home.empty())
+                    return libModule;
+
+                std::stringstream constructor;
+
+                constructor << home << Fs << "bin" << Fs << fullName;
+
+                std::string fullPath = constructor.str();
+
+                return LoadModule(fullPath);
+            }
+
+            bool SslGateway::LoadSslLibraries()
+            {
+                libeay32 = LoadSslLibrary("libeay32");
+                ssleay32 = LoadSslLibrary("ssleay32");
+                libssl = LoadSslLibrary("libssl");
+
+                if (!libssl.IsLoaded() && (!libeay32.IsLoaded() || 
!ssleay32.IsLoaded()))
+                {
+                    if (!libeay32.IsLoaded())
+                        LOG_MSG("Can not load libeay32.");
+
+                    if (!ssleay32.IsLoaded())
+                        LOG_MSG("Can not load ssleay32.");
+
+                    if (!libssl.IsLoaded())
+                        LOG_MSG("Can not load libssl.");
+
+                    libeay32.Unload();
+                    ssleay32.Unload();
+                    libssl.Unload();
+
+                    return false;
+                }
+
+                return true;
+            }
+
+            SslGateway& SslGateway::GetInstance()
+            {
+                static SslGateway self;
+
+                return self;
+            }
+
+            bool SslGateway::LoadAll()
+            {
+                using namespace common::dynamic;
+
+                if (inited)
+                    return true;
+
+                common::concurrent::CsLockGuard lock(initCs);
+
+                if (inited)
+                    return true;
+
+                if (!LoadSslLibraries())
+                {
+                    LOG_MSG("Can not load neccessary OpenSSL libraries.");
+
+                    return false;
+                }
+
+                functions.fpSSL_CTX_new = LoadSslMethod("SSL_CTX_new");
+                functions.fpSSL_CTX_free = LoadSslMethod("SSL_CTX_free");
+                functions.fpSSL_CTX_set_verify = 
LoadSslMethod("SSL_CTX_set_verify");
+                functions.fpSSL_CTX_set_verify_depth = 
LoadSslMethod("SSL_CTX_set_verify_depth");
+                functions.fpSSL_CTX_load_verify_locations = 
LoadSslMethod("SSL_CTX_load_verify_locations");
+                functions.fpSSL_CTX_use_certificate_chain_file = 
LoadSslMethod("SSL_CTX_use_certificate_chain_file");
+                functions.fpSSL_CTX_use_RSAPrivateKey_file = 
LoadSslMethod("SSL_CTX_use_RSAPrivateKey_file");
+                functions.fpSSL_CTX_set_cipher_list = 
LoadSslMethod("SSL_CTX_set_cipher_list");
+
+                functions.fpSSL_get_verify_result = 
LoadSslMethod("SSL_get_verify_result");
+                functions.fpSSL_library_init = 
LoadSslMethod("SSL_library_init");
+                functions.fpSSL_load_error_strings = 
LoadSslMethod("SSL_load_error_strings");
+                functions.fpSSL_get_peer_certificate = 
LoadSslMethod("SSL_get_peer_certificate");
+                functions.fpSSL_ctrl = LoadSslMethod("SSL_ctrl");
+                functions.fpSSL_CTX_ctrl = LoadSslMethod("SSL_CTX_ctrl");
+
+                functions.fpSSLv23_method = LoadSslMethod("SSLv23_method");
+                functions.fpBIO_new_ssl_connect = 
LoadSslMethod("BIO_new_ssl_connect");
+
+                functions.fpOPENSSL_config = LoadSslMethod("OPENSSL_config");
+                functions.fpX509_free = LoadSslMethod("X509_free");
+
+                functions.fpBIO_write = LoadSslMethod("BIO_write");
+                functions.fpBIO_read = LoadSslMethod("BIO_read");
+                functions.fpBIO_free_all = LoadSslMethod("BIO_free_all");
+                functions.fpBIO_test_flags = LoadSslMethod("BIO_test_flags");
+                functions.fpBIO_ctrl = LoadSslMethod("BIO_ctrl");
+
+                bool allLoaded =
+                    functions.fpSSL_CTX_new != 0 &&
+                    functions.fpSSL_CTX_free != 0 &&
+                    functions.fpSSL_CTX_set_verify != 0 &&
+                    functions.fpSSL_CTX_set_verify_depth != 0 &&
+                    functions.fpSSL_CTX_load_verify_locations != 0 &&
+                    functions.fpSSL_CTX_use_certificate_chain_file != 0 &&
+                    functions.fpSSL_CTX_use_RSAPrivateKey_file != 0 &&
+                    functions.fpSSL_CTX_set_cipher_list != 0 &&
+                    functions.fpSSL_get_verify_result != 0 &&
+                    functions.fpSSL_library_init != 0 &&
+                    functions.fpSSL_load_error_strings != 0 &&
+                    functions.fpSSL_get_peer_certificate != 0 &&
+                    functions.fpSSL_ctrl != 0 &&
+                    functions.fpSSL_CTX_ctrl != 0 &&
+                    functions.fpSSLv23_method != 0 &&
+                    functions.fpBIO_new_ssl_connect != 0 &&
+                    functions.fpOPENSSL_config != 0 &&
+                    functions.fpX509_free != 0 &&
+                    functions.fpBIO_write != 0 &&
+                    functions.fpBIO_read != 0 &&
+                    functions.fpBIO_free_all != 0 &&
+                    functions.fpBIO_test_flags != 0 &&
+                    functions.fpBIO_ctrl != 0;
+
+                if (!allLoaded)
+                {
+                    libeay32.Unload();
+                    ssleay32.Unload();
+                    libssl.Unload();
+                }
+
+                inited = allLoaded;
+
+                return inited;
+            }
+
+            void* SslGateway::LoadSslMethod(const char* name)
+            {
+                void* fp = libeay32.FindSymbol(name);
+
+                if (!fp)
+                    fp = ssleay32.FindSymbol(name);
+
+                if (!fp)
+                    fp = libssl.FindSymbol(name);
+
+                if (!fp)
+                    LOG_MSG("Can not load function " << name);
+
+                return fp;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp 
b/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp
new file mode 100644
index 0000000..0bdbc60
--- /dev/null
+++ b/modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ignite/common/utils.h"
+#include "ignite/odbc/ssl/ssl_mode.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace ssl
+        {
+            SslMode::T SslMode::FromString(const std::string& val, T dflt)
+            {
+                std::string lowerVal = common::ToLower(val);
+
+                common::StripSurroundingWhitespaces(lowerVal);
+
+                if (lowerVal == "disable")
+                    return SslMode::DISABLE;
+
+                if (lowerVal == "require")
+                    return SslMode::REQUIRE;
+
+                return dflt;
+            }
+        }
+    }
+}

Reply via email to