IGNITE-6810: Implemented SSL support for ODBC.
authorIgor Sapego <isapego@gridgain.com>
Tue, 30 Jan 2018 12:56:17 +0000 (15:56 +0300)
committerIgor Sapego <isapego@gridgain.com>
Tue, 30 Jan 2018 12:57:30 +0000 (15:57 +0300)
This closes #3361

60 files changed:
modules/core/src/main/java/org/apache/ignite/configuration/ClientConnectorConfiguration.java
modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerBufferedParser.java
modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java
modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioServerBuffer.java
modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerProcessor.java
modules/platforms/cpp/common/include/ignite/common/platform_utils.h
modules/platforms/cpp/common/include/ignite/common/utils.h
modules/platforms/cpp/common/os/linux/src/common/platform_utils.cpp
modules/platforms/cpp/common/os/win/src/common/dynamic_load_os.cpp
modules/platforms/cpp/common/os/win/src/common/platform_utils.cpp
modules/platforms/cpp/common/src/common/utils.cpp
modules/platforms/cpp/core-test/src/cache_query_test.cpp
modules/platforms/cpp/odbc-test/Makefile.am
modules/platforms/cpp/odbc-test/config/queries-default.xml
modules/platforms/cpp/odbc-test/config/queries-ssl-32.xml [moved from modules/platforms/cpp/odbc-test/config/queries-test-noodbc-32.xml with 59% similarity]
modules/platforms/cpp/odbc-test/config/queries-ssl.xml [moved from modules/platforms/cpp/odbc-test/config/queries-test-default.xml with 54% similarity]
modules/platforms/cpp/odbc-test/config/queries-test-32.xml
modules/platforms/cpp/odbc-test/config/queries-test-noodbc.xml [deleted file]
modules/platforms/cpp/odbc-test/config/queries-test.xml
modules/platforms/cpp/odbc-test/config/ssl/ca.pem [new file with mode: 0644]
modules/platforms/cpp/odbc-test/config/ssl/client_full.pem [new file with mode: 0644]
modules/platforms/cpp/odbc-test/config/ssl/client_unknown.pem [new file with mode: 0644]
modules/platforms/cpp/odbc-test/config/ssl/server.jks [new file with mode: 0644]
modules/platforms/cpp/odbc-test/config/ssl/trust.jks [new file with mode: 0644]
modules/platforms/cpp/odbc-test/include/odbc_test_suite.h
modules/platforms/cpp/odbc-test/include/test_utils.h
modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
modules/platforms/cpp/odbc-test/src/errors_test.cpp
modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
modules/platforms/cpp/odbc-test/src/odbc_test_suite.cpp
modules/platforms/cpp/odbc-test/src/queries_ssl_test.cpp [new file with mode: 0644]
modules/platforms/cpp/odbc-test/src/queries_test.cpp
modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp
modules/platforms/cpp/odbc-test/src/test_utils.cpp
modules/platforms/cpp/odbc/Makefile.am
modules/platforms/cpp/odbc/include/Makefile.am
modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h
modules/platforms/cpp/odbc/include/ignite/odbc/connection.h
modules/platforms/cpp/odbc/include/ignite/odbc/socket_client.h [new file with mode: 0644]
modules/platforms/cpp/odbc/include/ignite/odbc/ssl/secure_socket_client.h [new file with mode: 0644]
modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_bindings.h [new file with mode: 0644]
modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_gateway.h [new file with mode: 0644]
modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h [new file with mode: 0644]
modules/platforms/cpp/odbc/include/ignite/odbc/system/tcp_socket_client.h [moved from modules/platforms/cpp/odbc/include/ignite/odbc/system/socket_client.h with 73% similarity]
modules/platforms/cpp/odbc/include/ignite/odbc/system/ui/dsn_configuration_window.h
modules/platforms/cpp/odbc/os/linux/src/system/tcp_socket_client.cpp [moved from modules/platforms/cpp/odbc/os/linux/src/system/socket_client.cpp with 88% similarity]
modules/platforms/cpp/odbc/os/win/src/system/tcp_socket_client.cpp [moved from modules/platforms/cpp/odbc/os/win/src/system/socket_client.cpp with 86% similarity]
modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp
modules/platforms/cpp/odbc/os/win/src/system/ui/window.cpp
modules/platforms/cpp/odbc/project/vs/odbc.vcxproj
modules/platforms/cpp/odbc/project/vs/odbc.vcxproj.filters
modules/platforms/cpp/odbc/src/config/configuration.cpp
modules/platforms/cpp/odbc/src/connection.cpp
modules/platforms/cpp/odbc/src/dsn_config.cpp
modules/platforms/cpp/odbc/src/odbc.cpp
modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp [new file with mode: 0644]
modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp [new file with mode: 0644]
modules/platforms/cpp/odbc/src/ssl/ssl_mode.cpp [new file with mode: 0644]

index 5827333..ed30db3 100644 (file)
 
 package org.apache.ignite.configuration;
 
+import javax.cache.configuration.Factory;
+import javax.net.ssl.SSLContext;
 import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.ssl.SslContextFactory;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -45,6 +48,9 @@ public class ClientConnectorConfiguration {
     /** Default idle timeout. */
     public static final int DFLT_IDLE_TIMEOUT = 0;
 
+    /** Default value of whether to use Ignite SSL context factory. */
+    public static final boolean DFLT_USE_IGNITE_SSL_CTX_FACTORY = true;
+
     /** Host. */
     private String host;
 
@@ -81,6 +87,18 @@ public class ClientConnectorConfiguration {
     /** JDBC connections enabled flag. */
     private boolean thinCliEnabled = true;
 
+    /** SSL enable flag, default is disabled. */
+    private boolean sslEnabled;
+
+    /** If to use SSL context factory from Ignite configuration. */
+    private boolean useIgniteSslCtxFactory = DFLT_USE_IGNITE_SSL_CTX_FACTORY;
+
+    /** SSL need client auth flag. */
+    private boolean sslClientAuth;
+
+    /** SSL connection factory. */
+    private Factory<SSLContext> sslCtxFactory;
+
     /**
      * Creates SQL connector configuration with all default values.
      */
@@ -105,6 +123,10 @@ public class ClientConnectorConfiguration {
         tcpNoDelay = cfg.isTcpNoDelay();
         threadPoolSize = cfg.getThreadPoolSize();
         idleTimeout = cfg.getIdleTimeout();
+        sslEnabled = cfg.isSslEnabled();
+        sslClientAuth = cfg.isSslClientAuth();
+        useIgniteSslCtxFactory = cfg.isUseIgniteSslContextFactory();
+        sslCtxFactory = cfg.getSslContextFactory();
     }
 
     /**
@@ -385,6 +407,100 @@ public class ClientConnectorConfiguration {
         return this;
     }
 
+    /**
+     * Whether secure socket layer should be enabled on client connector.
+     * <p>
+     * Note that if this flag is set to {@code true}, an instance of {@code Factory&lt;SSLContext&gt;}
+     * should be provided, otherwise client connector will fail to start.
+     *
+     * @return {@code True} if SSL should be enabled.
+     */
+    public boolean isSslEnabled() {
+        return sslEnabled;
+    }
+
+    /**
+     * Sets whether Secure Socket Layer should be enabled for client connector.
+     * <p/>
+     * Note that if this flag is set to {@code true}, then a valid instance of {@code Factory&lt;SSLContext&gt;}
+     * should be provided in {@link IgniteConfiguration}. Otherwise, TCP binary protocol will fail to start.
+     *
+     * @param sslEnabled {@code True} if SSL should be enabled.
+     * @return {@code this} for chaining.
+     */
+    public ClientConnectorConfiguration setSslEnabled(boolean sslEnabled) {
+        this.sslEnabled = sslEnabled;
+
+        return this;
+    }
+
+    /**
+     * Gets whether to use Ignite SSL context factory configured through
+     * {@link IgniteConfiguration#getSslContextFactory()} if {@link #getSslContextFactory()} is not set.
+     *
+     * @return {@code True} if Ignite SSL context factory can be used.
+     */
+    public boolean isUseIgniteSslContextFactory() {
+        return useIgniteSslCtxFactory;
+    }
+
+    /**
+     * Sets whether to use Ignite SSL context factory. See {@link #isUseIgniteSslContextFactory()} for more information.
+     *
+     * @param useIgniteSslCtxFactory Whether to use Ignite SSL context factory
+     * @return {@code this} for chaining.
+     */
+    public ClientConnectorConfiguration setUseIgniteSslContextFactory(boolean useIgniteSslCtxFactory) {
+        this.useIgniteSslCtxFactory = useIgniteSslCtxFactory;
+
+        return this;
+    }
+
+    /**
+     * Gets a flag indicating whether or not remote clients will be required to have a valid SSL certificate which
+     * validity will be verified with trust manager.
+     *
+     * @return Whether or not client authentication is required.
+     */
+    public boolean isSslClientAuth() {
+        return sslClientAuth;
+    }
+
+    /**
+     * Sets flag indicating whether or not SSL client authentication is required.
+     *
+     * @param sslClientAuth Whether or not client authentication is required.
+     * @return {@code this} for chaining.
+     */
+    public ClientConnectorConfiguration setSslClientAuth(boolean sslClientAuth) {
+        this.sslClientAuth = sslClientAuth;
+
+        return this;
+    }
+
+    /**
+     * Sets SSL context factory that will be used for creating a secure socket layer.
+     *
+     * @param sslCtxFactory Ssl context factory.
+     * @see SslContextFactory
+     * @return {@code this} for chaining.
+     */
+    public ClientConnectorConfiguration setSslContextFactory(Factory<SSLContext> sslCtxFactory) {
+        this.sslCtxFactory = sslCtxFactory;
+
+        return this;
+    }
+
+    /**
+     * Returns SSL context factory that will be used for creating a secure socket layer.
+     *
+     * @return SSL connection factory.
+     * @see SslContextFactory
+     */
+    public Factory<SSLContext> getSslContextFactory() {
+        return sslCtxFactory;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(ClientConnectorConfiguration.class, this);
index eb7bfe8..8dd26b6 100644 (file)
@@ -55,7 +55,9 @@ public class ClientListenerBufferedParser implements GridNioParser {
             assert old == null;
         }
 
-        return nioBuf.read(buf);
+        boolean checkHandshake = ses.meta(ClientListenerNioListener.CONN_CTX_HANDSHAKE_PASSED) == null;
+
+        return nioBuf.read(buf, checkHandshake);
     }
 
     /** {@inheritDoc} */
@@ -78,4 +80,4 @@ public class ClientListenerBufferedParser implements GridNioParser {
     @Override public String toString() {
         return ClientListenerBufferedParser.class.getSimpleName();
     }
-}
\ No newline at end of file
+}
index 43276a5..f472a9f 100644 (file)
@@ -48,6 +48,12 @@ public class ClientListenerNioListener extends GridNioServerListenerAdapter<byte
     /** Thin client handshake code. */
     public static final byte THIN_CLIENT = 2;
 
+    /** Connection handshake passed. */
+    public static final int CONN_CTX_HANDSHAKE_PASSED = GridNioSessionMetaKey.nextUniqueKey();
+
+    /** Maximum size of the handshake message. */
+    public static final int MAX_HANDSHAKE_MSG_SIZE = 128;
+
     /** Connection-related metadata key. */
     private static final int CONN_CTX_META_KEY = GridNioSessionMetaKey.nextUniqueKey();
 
@@ -114,6 +120,8 @@ public class ClientListenerNioListener extends GridNioServerListenerAdapter<byte
         if (connCtx == null) {
             onHandshake(ses, msg);
 
+            ses.addMeta(CONN_CTX_HANDSHAKE_PASSED, true);
+
             return;
         }
 
index 30ee69f..6ee6e71 100644 (file)
@@ -64,10 +64,11 @@ public class ClientListenerNioServerBuffer {
 
     /**
      * @param buf Buffer.
+     * @param checkHandshake Check handshake.
      * @return Message bytes or {@code null} if message is not fully read yet.
      * @throws IgniteCheckedException If failed to parse message.
      */
-    @Nullable public byte[] read(ByteBuffer buf) throws IgniteCheckedException {
+    @Nullable public byte[] read(ByteBuffer buf, boolean checkHandshake) throws IgniteCheckedException {
         if (cnt < 0) {
             for (; cnt < 0 && buf.hasRemaining(); cnt++)
                 msgSize |= (buf.get() & 0xFF) << (8*(4 + cnt));
@@ -108,7 +109,12 @@ public class ClientListenerNioServerBuffer {
 
             return data0;
         }
-        else
+        else {
+            if (checkHandshake && cnt > 0 && (msgSize > ClientListenerNioListener.MAX_HANDSHAKE_MSG_SIZE
+                || data[0] != ClientListenerRequest.HANDSHAKE))
+                throw new IgniteCheckedException("Invalid handshake message");
+
             return null;
+        }
     }
-}
\ No newline at end of file
+}
index a490cfc..eaa9c7a 100644 (file)
@@ -21,6 +21,8 @@ import java.net.InetAddress;
 import java.nio.ByteOrder;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.LinkedBlockingQueue;
+import javax.cache.configuration.Factory;
+import javax.net.ssl.SSLContext;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.configuration.ClientConnectorConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
@@ -35,10 +37,12 @@ import org.apache.ignite.internal.util.nio.GridNioCodecFilter;
 import org.apache.ignite.internal.util.nio.GridNioFilter;
 import org.apache.ignite.internal.util.nio.GridNioServer;
 import org.apache.ignite.internal.util.nio.GridNioSession;
+import org.apache.ignite.internal.util.nio.ssl.GridNioSslFilter;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.spi.IgnitePortProtocol;
 import org.apache.ignite.thread.IgniteThreadPoolExecutor;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -110,20 +114,13 @@ public class ClientListenerProcessor extends GridProcessorAdapter {
                 if (portTo <= 0) // Handle int overflow.
                     portTo = Integer.MAX_VALUE;
 
+                GridNioFilter[] filters = makeFilters(cliConnCfg);
+
+                int maxOpenCursors = cliConnCfg.getMaxOpenCursorsPerConnection();
+                long idleTimeout = cliConnCfg.getIdleTimeout();
+
                 for (int port = cliConnCfg.getPort(); port <= portTo && port <= 65535; port++) {
                     try {
-                        GridNioFilter[] filters = new GridNioFilter[] {
-                            new GridNioAsyncNotifyFilter(ctx.igniteInstanceName(), execSvc, log) {
-                                @Override public void onSessionOpened(GridNioSession ses)
-                                    throws IgniteCheckedException {
-                                    proceedSessionOpened(ses);
-                                }
-                            },
-                            new GridNioCodecFilter(new ClientListenerBufferedParser(), log, false)
-                        };
-
-                        long idleTimeout = cliConnCfg.getIdleTimeout();
-
                         GridNioServer<byte[]> srv0 = GridNioServer.<byte[]>builder()
                             .address(hostAddr)
                             .port(port)
@@ -173,6 +170,54 @@ public class ClientListenerProcessor extends GridProcessorAdapter {
         }
     }
 
+     /**
+      * Make NIO server filters.
+      * @param cliConnCfg Client configuration.
+      * @return Array of filters, suitable for the configuration.
+      * @throws IgniteCheckedException if provided SslContextFactory is null.
+      */
+    @NotNull private GridNioFilter[] makeFilters(@NotNull ClientConnectorConfiguration cliConnCfg)
+        throws IgniteCheckedException {
+        GridNioFilter openSesFilter = new GridNioAsyncNotifyFilter(ctx.igniteInstanceName(), execSvc, log) {
+            @Override public void onSessionOpened(GridNioSession ses)
+                throws IgniteCheckedException {
+                proceedSessionOpened(ses);
+            }
+        };
+
+        GridNioFilter codecFilter = new GridNioCodecFilter(new ClientListenerBufferedParser(), log, false);
+
+        if (cliConnCfg.isSslEnabled()) {
+            Factory<SSLContext> sslCtxFactory = cliConnCfg.isUseIgniteSslContextFactory() ?
+                ctx.config().getSslContextFactory() : cliConnCfg.getSslContextFactory();
+
+            if (sslCtxFactory == null)
+                throw new IgniteCheckedException("Failed to create client listener " +
+                    "(SSL is enabled but factory is null). Check the ClientConnectorConfiguration");
+
+            GridNioSslFilter sslFilter = new GridNioSslFilter(sslCtxFactory.create(),
+                    true, ByteOrder.nativeOrder(), log);
+
+            sslFilter.directMode(false);
+
+            boolean auth = cliConnCfg.isSslClientAuth();
+
+            sslFilter.wantClientAuth(auth);
+            sslFilter.needClientAuth(auth);
+
+            return new GridNioFilter[] {
+                openSesFilter,
+                codecFilter,
+                sslFilter
+            };
+        } else {
+            return new GridNioFilter[] {
+                openSesFilter,
+                codecFilter
+            };
+        }
+    }
+
     /** {@inheritDoc} */
     @Override public void onKernalStop(boolean cancel) {
         if (srv != null) {
@@ -203,7 +248,7 @@ public class ClientListenerProcessor extends GridProcessorAdapter {
     /**
      * Prepare connector configuration.
      *
-     * @param cfg Ignote configuration.
+     * @param cfg Ignite configuration.
      * @return Connector configuration.
      * @throws IgniteCheckedException If failed.
      */
index b8c6aa6..83da6ec 100644 (file)
 #ifndef _IGNITE_COMMON_PLATFORM_UTILS
 #define _IGNITE_COMMON_PLATFORM_UTILS
 
+#include <iostream>
 #include <ignite/common/common.h>
 
 namespace ignite
 {
     namespace common
     {
+        typedef std::basic_ostream<char, std::char_traits<char> > StdCharOutStream;
+
         /**
          * Convert struct tm to time_t (UTC).
          *
@@ -87,6 +90,20 @@ namespace ignite
          * @return @c true if the provided path is the valid directory.
          */
         IGNITE_IMPORT_EXPORT bool IsValidDirectory(const std::string& path);
+
+        /**
+         * Write file separator to a stream.
+         * @param ostr Stream.
+         * @return The same stream for chaining.
+         */
+        IGNITE_IMPORT_EXPORT StdCharOutStream& Fs(StdCharOutStream& ostr);
+
+        /**
+         * Write dynamic library expansion to a stream.
+         * @param ostr Stream.
+         * @return The same stream for chaining.
+         */
+        IGNITE_IMPORT_EXPORT StdCharOutStream& Dle(StdCharOutStream& ostr);
     }
 }
 
index 5022897..792bd60 100644 (file)
@@ -476,6 +476,13 @@ namespace ignite
         {
             return BoundInstance<R, T>(instance, mfunc);
         }
+
+        /**
+         * Get dynamic library full name.
+         * @param name Name without extension.
+         * @return Full name.
+         */
+        IGNITE_IMPORT_EXPORT std::string GetDynamicLibraryName(const char* name);
     }
 }
 
index b74f11c..88ba8ed 100644 (file)
@@ -89,5 +89,20 @@ namespace ignite
 
             return stat(path.c_str(), &pathStat) != -1 && S_ISDIR(pathStat.st_mode);
         }
+
+        StdCharOutStream& Fs(StdCharOutStream& ostr)
+        {
+            ostr.put('/');
+            return ostr;
+        }
+
+        StdCharOutStream& Dle(StdCharOutStream& ostr)
+        {
+            static const char expansion[] = ".so";
+
+            ostr.write(expansion, sizeof(expansion) - 1);
+
+            return ostr;
+        }
     }
 }
index f7812cd..76ca28b 100644 (file)
@@ -85,7 +85,11 @@ namespace ignite
             void Module::Unload()
             {
                 if (IsLoaded())
+                {
                     FreeLibrary(handle);
+
+                    handle = NULL;
+                }
             }
 
             Module LoadModule(const char* path)
index a0f4505..057a3d4 100644 (file)
@@ -91,5 +91,20 @@ namespace ignite
 
             return attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
         }
+
+        StdCharOutStream& Fs(StdCharOutStream& ostr)
+        {
+            ostr.put('\\');
+            return ostr;
+        }
+
+        StdCharOutStream& Dle(StdCharOutStream& ostr)
+        {
+            static const char expansion[] = ".dll";
+
+            ostr.write(expansion, sizeof(expansion) - 1);
+
+            return ostr;
+        }
     }
 }
index 786d0fb..54a7d03 100644 (file)
@@ -180,5 +180,14 @@ namespace ignite
 
             return CTimeToTimestamp(localTime, ns);
         }
+
+        std::string GetDynamicLibraryName(const char* name)
+        {
+            std::stringstream libNameBuffer;
+
+            libNameBuffer << name << Dle;
+
+            return libNameBuffer.str();
+        }
     }
 }
index 4993279..9dfd879 100644 (file)
@@ -969,10 +969,11 @@ BOOST_AUTO_TEST_CASE(TestSqlQueryDistributedJoins)
     // Starting second node.
     Ignite node2 = StartNode("Node2");
 
+    int firstKey = 0;
     int entryCnt = 1000;
 
     // Filling caches
-    for (int i = 0; i < entryCnt; i++)
+    for (int i = firstKey; i < firstKey + entryCnt; i++)
     {
         std::stringstream stream;
 
@@ -987,7 +988,8 @@ BOOST_AUTO_TEST_CASE(TestSqlQueryDistributedJoins)
     // Test query with no results.
     SqlQuery qry("QueryPerson",
         "from \"QueryPerson\".QueryPerson, \"QueryRelation\".QueryRelation "
-        "where \"QueryPerson\".QueryPerson.age = \"QueryRelation\".QueryRelation.someVal");
+        "where (\"QueryPerson\".QueryPerson.age = \"QueryRelation\".QueryRelation.someVal) "
+        "and (\"QueryPerson\".QueryPerson._key < 1000)");
 
     QueryCursor<int, QueryPerson> cursor = cache1.Query(qry);
 
@@ -1245,17 +1247,18 @@ BOOST_AUTO_TEST_CASE(TestSqlFieldsQueryDistributedJoins)
     // Starting second node.
     Ignite node2 = StartNode("Node2");
 
+    int firstKey = 2000;
     int entryCnt = 1000;
 
     // Filling caches
-    for (int i = 0; i < entryCnt; i++)
+    for (int i = firstKey; i < firstKey + entryCnt; i++)
     {
         std::stringstream stream;
 
         stream << "A" << i;
 
         cache1.Put(i, QueryPerson(stream.str(), i * 10, MakeDateGmt(1970 + i),
-            MakeTimestampGmt(2016, 1, 1, i / 60, i % 60)));
+            MakeTimestampGmt(2016, 1, 1, (i / 60) % 24, i % 60)));
 
         cache2.Put(i + 1, QueryRelation(i, i * 10));
     }
@@ -1265,7 +1268,9 @@ BOOST_AUTO_TEST_CASE(TestSqlFieldsQueryDistributedJoins)
         "select age, name "
         "from \"QueryPerson\".QueryPerson "
         "inner join \"QueryRelation\".QueryRelation "
-        "on \"QueryPerson\".QueryPerson.age = \"QueryRelation\".QueryRelation.someVal");
+        "on \"QueryPerson\".QueryPerson.age = \"QueryRelation\".QueryRelation.someVal "
+        "where (\"QueryPerson\".QueryPerson._key < 3000) and "
+        "(\"QueryPerson\".QueryPerson._key >= 2000)");
 
     QueryFieldsCursor cursor = cache1.Query(qry);
 
index b025e2c..3e6467c 100644 (file)
@@ -65,6 +65,7 @@ ignite_odbc_tests_SOURCES = \
     src/meta_queries_test.cpp \
     src/utility_test.cpp \
     src/queries_test.cpp \
+    src/queries_ssl_test.cpp \
     src/test_utils.cpp \
     src/sql_test_suite_fixture.cpp \
     src/sql_string_functions_test.cpp \
index 56040f1..dbe3a10 100644 (file)
         http://www.springframework.org/schema/util
         http://www.springframework.org/schema/util/spring-util.xsd">
 
-    <bean abstract="true" id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+    <bean abstract="true" id="queries.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
         <property name="localHost" value="127.0.0.1"/>
         <property name="connectorConfiguration"><null/></property>
 
+        <property name="clientConnectorConfiguration">
+            <bean class="org.apache.ignite.configuration.ClientConnectorConfiguration">
+                <property name="host" value="127.0.0.1"/>
+                <property name="port" value="11110"/>
+                <property name="portRange" value="10"/>
+            </bean>
+        </property>
+
         <property name="cacheConfiguration">
             <list>
                 <bean class="org.apache.ignite.configuration.CacheConfiguration">
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
 
-    <!-- Imports no-ODBC Ignite configuration -->
     <import resource="queries-default.xml"/>
 
-    <bean parent="ignite.cfg">
+    <!--
+        Initialize property configurer so we can reference environment variables.
+    -->
+    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_FALLBACK"/>
+        <property name="searchSystemEnvironment" value="true"/>
+    </bean>
+  
+    <bean parent="queries.cfg">
         <property name="clientConnectorConfiguration">
-            <null/>
+            <bean class="org.apache.ignite.configuration.ClientConnectorConfiguration">
+                <property name="host" value="127.0.0.1"/>
+                <property name="port" value="11110"/>
+                <property name="portRange" value="10"/>
+                <property name="sslEnabled" value="true"/>
+                <property name="useIgniteSslContextFactory" value="false"/>
+                <property name="sslClientAuth" value="true"/>
+
+                <!-- Provide Ssl context. -->
+                <property name="sslContextFactory">
+                    <bean class="org.apache.ignite.ssl.SslContextFactory">
+                        <property name="keyStoreFilePath" value="${IGNITE_NATIVE_TEST_ODBC_CONFIG_PATH}/ssl/server.jks"/>
+                        <property name="keyStorePassword" value="123456"/>
+                        <property name="trustStoreFilePath" value="${IGNITE_NATIVE_TEST_ODBC_CONFIG_PATH}/ssl/trust.jks"/>
+                        <property name="trustStorePassword" value="123456"/>
+                    </bean>
+                </property>
+            </bean>
         </property>
 
         <property name="memoryConfiguration">
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
 
-    <!-- Imports no-ODBC Ignite configuration -->
     <import resource="queries-default.xml"/>
 
-    <bean abstract="true" id="queries.cfg" parent="ignite.cfg">
+    <!--
+        Initialize property configurer so we can reference environment variables.
+    -->
+    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_FALLBACK"/>
+        <property name="searchSystemEnvironment" value="true"/>
+    </bean>
+
+    <bean parent="queries.cfg">
         <property name="clientConnectorConfiguration">
             <bean class="org.apache.ignite.configuration.ClientConnectorConfiguration">
                 <property name="host" value="127.0.0.1"/>
                 <property name="port" value="11110"/>
-                <property name="portRange" value="0"/>
+                <property name="portRange" value="10"/>
+                <property name="sslEnabled" value="true"/>
+                <property name="useIgniteSslContextFactory" value="false"/>
+                <property name="sslClientAuth" value="true"/>
+
+                <!-- Provide Ssl context. -->
+                <property name="sslContextFactory">
+                    <bean class="org.apache.ignite.ssl.SslContextFactory">
+                        <property name="keyStoreFilePath" value="${IGNITE_NATIVE_TEST_ODBC_CONFIG_PATH}/ssl/server.jks"/>
+                        <property name="keyStorePassword" value="123456"/>
+                        <property name="trustStoreFilePath" value="${IGNITE_NATIVE_TEST_ODBC_CONFIG_PATH}/ssl/trust.jks"/>
+                        <property name="trustStorePassword" value="123456"/>
+                    </bean>
+                </property>
             </bean>
         </property>
     </bean>
index f7d9ff4..a2bac82 100644 (file)
@@ -24,8 +24,7 @@
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
 
-    <!-- Imports no-ODBC Ignite configuration -->
-    <import resource="queries-test-default.xml"/>
+    <import resource="queries-default.xml"/>
 
     <bean parent="queries.cfg">
         <property name="memoryConfiguration">
diff --git a/modules/platforms/cpp/odbc-test/config/queries-test-noodbc.xml b/modules/platforms/cpp/odbc-test/config/queries-test-noodbc.xml
deleted file mode 100644 (file)
index 29fee23..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-  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.
--->
-
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xmlns:util="http://www.springframework.org/schema/util"
-       xsi:schemaLocation="
-        http://www.springframework.org/schema/beans
-        http://www.springframework.org/schema/beans/spring-beans.xsd">
-
-    <!-- Imports no-ODBC Ignite configuration -->
-    <import resource="queries-default.xml"/>
-
-    <bean parent="ignite.cfg">
-        <property name="clientConnectorConfiguration">
-            <null/>
-        </property>
-    </bean>
-</beans>
index 882eb1e..46e89aa 100644 (file)
@@ -24,8 +24,7 @@
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
 
-    <!-- Imports no-ODBC Ignite configuration -->
-    <import resource="queries-test-default.xml"/>
+    <import resource="queries-default.xml"/>
 
     <bean parent="queries.cfg"/>
 </beans>
diff --git a/modules/platforms/cpp/odbc-test/config/ssl/ca.pem b/modules/platforms/cpp/odbc-test/config/ssl/ca.pem
new file mode 100644 (file)
index 0000000..10bf7af
--- /dev/null
@@ -0,0 +1,24 @@
+-----BEGIN TRUSTED CERTIFICATE-----
+MIID8DCCAtgCCQCo436SJYMUcjANBgkqhkiG9w0BAQsFADCBuTELMAkGA1UEBhMC
+UlUxGTAXBgNVBAgMEFNhaW50LVBldGVyc2J1cmcxGTAXBgNVBAcMEFNhaW50LVBl
+dGVyc2J1cmcxIzAhBgNVBAoMGkFwYWNoZSBTcGZ0d2FyZSBGb3VuZGF0aW9uMRYw
+FAYDVQQLDA1BcGFjaGUgSWduaXRlMRQwEgYDVQQDDAtJZ29yIFNhcGVnbzEhMB8G
+CSqGSIb3DQEJARYSaXNhcGVnb0BhcGFjaGUub3JnMB4XDTE3MTEyODE3MzExNloX
+DTI3MTEyNjE3MzExNlowgbkxCzAJBgNVBAYTAlJVMRkwFwYDVQQIDBBTYWludC1Q
+ZXRlcnNidXJnMRkwFwYDVQQHDBBTYWludC1QZXRlcnNidXJnMSMwIQYDVQQKDBpB
+cGFjaGUgU3BmdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIElnbml0
+ZTEUMBIGA1UEAwwLSWdvciBTYXBlZ28xITAfBgkqhkiG9w0BCQEWEmlzYXBlZ29A
+YXBhY2hlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALMcDfYN
+Ixc0o4bLX/3T5MQE4pk+Bv9Dfr7vBYNPJKSr/GKQJN+5QA/tr1uxTsMSBoE19y5e
+N1vXFtlWMJ2um3ojNbGeqSGuzuDKk0htbgmisyctvEFTqtiYI7D+f7dalEM2KnLj
+f0jIV6NJVilkFKmgsfuZpbZFRkqJDEx74ZqNAYQQ0qJ+zGv7diEak8FwWa4n6xe7
+VHt7VZIbKIkMgTljJLULbExxCRvTHpSeXPP5IMr5x1RGuSavCu4GDl+HmrXac7ot
+L7sqIFHL9JGXTWO16accOQnQIdLQmhj6qh2Em8z41udabzUyIQmOSP6mmwnJEIdz
+jNyWLA8XtYZOgcsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAT6jBgiQjCdQ02cxe
+H9YDFw5+cfb6YQJcjJW94BspySftUGfJ6GQm/Ybcc/ZqW7lhEILKfifdpHPfWby/
+sqhwA0nsLt5hNCjMsDcBq5onggy9ymZYak0VVWT/XkHiK27sQLK6BXo6wqRDwT4h
+F9CgUWNcLGDVAaVpjLaR8itZZgx98q9MAZ680oERUZWTsj17oO0RK/x9TBWUm7OR
+f9g9VNRz3mwT5dTtuqrSq4NlF1nVD7BN3lRddZUW4KnU6et2mXtIKMnUT/+XyIW3
+g+f6LuhR+Q6yhmVdfBVa8opJQIR5trb0eKnQf4pEQcvT/EX+vWkThNJkdZ4qm0mY
+eIl/jQ==
+-----END TRUSTED CERTIFICATE-----
diff --git a/modules/platforms/cpp/odbc-test/config/ssl/client_full.pem b/modules/platforms/cpp/odbc-test/config/ssl/client_full.pem
new file mode 100644 (file)
index 0000000..9a54f43
--- /dev/null
@@ -0,0 +1,84 @@
+Bag Attributes
+    friendlyName: client
+    localKeyID: 54 69 6D 65 20 31 35 31 31 39 36 35 31 38 31 32 33 37 
+Key Attributes: <No Attributes>
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAmm+QSwc1yvJWjTG8L4rAiHOg38rM1AtOFInzYizT/B6wzsmx
+3Ql4fb+aHm3dPt5kjhQLZToq1QCUsS9B/47ZFd0waDHGgLiSNKn1WdX7Q+4GgplY
+wznc5j+GM65F2aI3tRnn2Jorfss9OElzU5vLh0aD3e5cEpgYSAGEFl1O9t8b6dHq
+YMERtdTCNQVeBUQPiaNNTwOXixtdsPvGKNgMZtVpvV+AMlgVmV+VTYUqQhlX+ro4
+9E4n00+iDIk/REwAiQi/Kb08kovLY9sF2pqC24zU5swyIopEijoa6Z2WYekq1fyL
+P9NknOiMOmWaKqu5ThVbP6c2xGeCdAGbNi+74wIDAQABAoIBAH2oALPLbg1vGNVR
+flkAgJ+F1YPBst9lQ2aayBk9eE5PenUGz12V8x/94hyYL8iTkyW3UX5P0cH18wYn
++X9Cb4fGrThaJ7VceDm5gBRUc1lWNp3Uv9A5KG9/iGZMijEGOGV2appm9rT4ERvX
+R6rjvLqYuXq+EtReRINyGFNKIJHkuwM7Ycy9Rk7O6SrcjjUEj1Z5gEUP0B7Z0jVI
+bsOGqghRflRVqnFT61+koFWBn8taemWmXNa835beN2lRIWezNqfd+9kL72UUt6sl
+VmkqBydDQ+IXCOgLZDYUu3N0bfrKuYmilsRg9XuKTUv+jvwtfGUWTO1+6eSrFD+B
+3j0YeKECgYEA0XrsUOGVl2O4JWBOa36TRHMz0tRBrZUJMK7apEEiGx7jc7q22PI+
+RyPrf9TR7JOLN1AdXoHrJsKCadnTr6g/CAOZSV1V+lUeQkcDmG4OkY814fESxlBA
+jHg7FnJdjzs6VfA1Cv0eT2KxU0ld461AN77WBgG21E2Gw3AGSddbflcCgYEAvLtV
+fhy3+WOUutFsLv1uTz/y+Emih6pmgwsuRG7WgQD9s2KZS+ejh5TQAq4sD+9MSkKk
+XnvdbwGQkHppdtVP5wMeSfY6tG/9YmY7X5rTG9PTsrzAzNJwrnE9hFv7Xnj3SMnC
+0D9eBnA8XWq49vsair7gxBWwhGYR/5WDicGn31UCgYEAgJb6lbPEhkgadCcoPGhY
+sn4dY+AT6SBBofbUFFw/OXK+oP4O3CHoBPeRysizjIwNu4icXrVVyldAgwXKIlwf
+RSYgZJ689oxlpL2/AUUeAFBu/SFlKwN8fD4Z12+g6xmqd7KafQJgJs8olz3EOszR
+TOcCrnFC8BQfE72ivpVKfsUCgYBBZw3maR9cHiUxZFeAJTTv47JYVnQrXWKu8NX0
+wxA0nlpMqtOC2V/zIR/Afgko8H1YkqWRVI1U5Y7qcnFPy/YnkQ4TBXAsjU6apeDX
+bbjQwORw4TZTBG4mFXoC/zkp8POI1tpa/kqgIo7YtJ4qgLQe9qy/ZuDH0PNVxcNS
+nriFDQKBgF70vrmuYEobLpBD/whcOqMDjn3Zj+xx3TSRmjmjc4w5eRR4+9iquKs5
+lhY1NsAcq3SYA8P5rNDV39FpiPErFqDTjsf0AaOXbpaqo2jOANmvyT15CKW8325R
+yEcxaA8sSbBaz8QRkydzpoKT+4WFJnYzCZtG+kUU+Pgu6uahAs4N
+-----END RSA PRIVATE KEY-----
+Bag Attributes
+    friendlyName: client
+    localKeyID: 54 69 6D 65 20 31 35 31 31 39 36 35 31 38 31 32 33 37 
+subject=/CN=ODBC
+issuer=/C=RU/ST=Saint-Petersburg/L=Saint-Petersburg/O=Apache Spftware Foundation/OU=Apache Ignite/CN=Igor Sapego/emailAddress=isapego@apache.org
+-----BEGIN CERTIFICATE-----
+MIIDPTCCAiUCAQIwDQYJKoZIhvcNAQEFBQAwgbkxCzAJBgNVBAYTAlJVMRkwFwYD
+VQQIDBBTYWludC1QZXRlcnNidXJnMRkwFwYDVQQHDBBTYWludC1QZXRlcnNidXJn
+MSMwIQYDVQQKDBpBcGFjaGUgU3BmdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwN
+QXBhY2hlIElnbml0ZTEUMBIGA1UEAwwLSWdvciBTYXBlZ28xITAfBgkqhkiG9w0B
+CQEWEmlzYXBlZ29AYXBhY2hlLm9yZzAeFw0xNzExMjkxNDAwNDhaFw0yNzExMjcx
+NDAwNDhaMA8xDTALBgNVBAMTBE9EQkMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCab5BLBzXK8laNMbwvisCIc6DfyszUC04UifNiLNP8HrDOybHdCXh9
+v5oebd0+3mSOFAtlOirVAJSxL0H/jtkV3TBoMcaAuJI0qfVZ1ftD7gaCmVjDOdzm
+P4YzrkXZoje1GefYmit+yz04SXNTm8uHRoPd7lwSmBhIAYQWXU723xvp0epgwRG1
+1MI1BV4FRA+Jo01PA5eLG12w+8Yo2Axm1Wm9X4AyWBWZX5VNhSpCGVf6ujj0TifT
+T6IMiT9ETACJCL8pvTySi8tj2wXamoLbjNTmzDIiikSKOhrpnZZh6SrV/Is/02Sc
+6Iw6ZZoqq7lOFVs/pzbEZ4J0AZs2L7vjAgMBAAEwDQYJKoZIhvcNAQEFBQADggEB
+AH8heMPYkC/abqg9xtC5WFgYxnXWA6jwjKVuCSnrEhZGQem9HFvFXmZckJr25RXc
+9i8WIehN5oeJgmPioK6j8ylwCJxo9lRii4NFBVpS6IjmqMdYHa+4K1R9Y7XdDEBL
+nVzlL8Hjlv4ESjg+1LW4nSt8f4oBdAvfds4uNTtAwABqmfqXWaOKYdh9OJs84QJa
+pA4PQvxqUz6c4tyPi/VucVAV8uKxR7P+uoy6qKKZK6NkY3RuXwHXxJ5lDr6ET1mb
+St0BbAt4KSktPonCu0qoHWqcynw79KcoPhmQWpzbijVs+y/SlHmZje+H4R7j7xt7
+aw7dWxUa096x4vsi1WvlMOY=
+-----END CERTIFICATE-----
+Bag Attributes
+    friendlyName: 1.2.840.113549.1.9.1=#16126973617065676f406170616368652e6f7267,CN=Igor Sapego,OU=Apache Ignite,O=Apache Spftware Foundation,L=Saint-Petersburg,ST=Saint-Petersburg,C=RU
+subject=/C=RU/ST=Saint-Petersburg/L=Saint-Petersburg/O=Apache Spftware Foundation/OU=Apache Ignite/CN=Igor Sapego/emailAddress=isapego@apache.org
+issuer=/C=RU/ST=Saint-Petersburg/L=Saint-Petersburg/O=Apache Spftware Foundation/OU=Apache Ignite/CN=Igor Sapego/emailAddress=isapego@apache.org
+-----BEGIN CERTIFICATE-----
+MIID8DCCAtgCCQCo436SJYMUcjANBgkqhkiG9w0BAQsFADCBuTELMAkGA1UEBhMC
+UlUxGTAXBgNVBAgMEFNhaW50LVBldGVyc2J1cmcxGTAXBgNVBAcMEFNhaW50LVBl
+dGVyc2J1cmcxIzAhBgNVBAoMGkFwYWNoZSBTcGZ0d2FyZSBGb3VuZGF0aW9uMRYw
+FAYDVQQLDA1BcGFjaGUgSWduaXRlMRQwEgYDVQQDDAtJZ29yIFNhcGVnbzEhMB8G
+CSqGSIb3DQEJARYSaXNhcGVnb0BhcGFjaGUub3JnMB4XDTE3MTEyODE3MzExNloX
+DTI3MTEyNjE3MzExNlowgbkxCzAJBgNVBAYTAlJVMRkwFwYDVQQIDBBTYWludC1Q
+ZXRlcnNidXJnMRkwFwYDVQQHDBBTYWludC1QZXRlcnNidXJnMSMwIQYDVQQKDBpB
+cGFjaGUgU3BmdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIElnbml0
+ZTEUMBIGA1UEAwwLSWdvciBTYXBlZ28xITAfBgkqhkiG9w0BCQEWEmlzYXBlZ29A
+YXBhY2hlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALMcDfYN
+Ixc0o4bLX/3T5MQE4pk+Bv9Dfr7vBYNPJKSr/GKQJN+5QA/tr1uxTsMSBoE19y5e
+N1vXFtlWMJ2um3ojNbGeqSGuzuDKk0htbgmisyctvEFTqtiYI7D+f7dalEM2KnLj
+f0jIV6NJVilkFKmgsfuZpbZFRkqJDEx74ZqNAYQQ0qJ+zGv7diEak8FwWa4n6xe7
+VHt7VZIbKIkMgTljJLULbExxCRvTHpSeXPP5IMr5x1RGuSavCu4GDl+HmrXac7ot
+L7sqIFHL9JGXTWO16accOQnQIdLQmhj6qh2Em8z41udabzUyIQmOSP6mmwnJEIdz
+jNyWLA8XtYZOgcsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAT6jBgiQjCdQ02cxe
+H9YDFw5+cfb6YQJcjJW94BspySftUGfJ6GQm/Ybcc/ZqW7lhEILKfifdpHPfWby/
+sqhwA0nsLt5hNCjMsDcBq5onggy9ymZYak0VVWT/XkHiK27sQLK6BXo6wqRDwT4h
+F9CgUWNcLGDVAaVpjLaR8itZZgx98q9MAZ680oERUZWTsj17oO0RK/x9TBWUm7OR
+f9g9VNRz3mwT5dTtuqrSq4NlF1nVD7BN3lRddZUW4KnU6et2mXtIKMnUT/+XyIW3
+g+f6LuhR+Q6yhmVdfBVa8opJQIR5trb0eKnQf4pEQcvT/EX+vWkThNJkdZ4qm0mY
+eIl/jQ==
+-----END CERTIFICATE-----
diff --git a/modules/platforms/cpp/odbc-test/config/ssl/client_unknown.pem b/modules/platforms/cpp/odbc-test/config/ssl/client_unknown.pem
new file mode 100644 (file)
index 0000000..b9a8e43
--- /dev/null
@@ -0,0 +1,50 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC0HaDP3KkkgcT7
+3FWWxXEgiT5vAsW+ZByiWg5Yh5XtU7rAjiXT9VmOm1h/5GNdngF7ofhT+qal1k8W
+yiLsbqWL6qYXkc0e8aKw9ciBaWDWDkgXNnV03butu70hNvm/fzYp/6/WQ5SXUJdm
+mJZyeVjgU4NXnOe0lv2PlzUr5q1yjJCSnTbsHBvs0qfoy7DYqPQFbrwiuIOeYtVg
+mjjL/y6SUCY/uNY8McLG0YFubNsnOCEIyZOgAM1RdmARt+iYZuLVZkicgkaxYtLB
+pbUB8K2Y/A+0WjL7JceZVWbUaQKkDncegccMmHzEOBsJyLRWu+/5ztan7xh+jIGd
+vtlgoz8/AgMBAAECggEBAKx4TnucHW7ywFA3/NEBwUDZiqo8KmQUcwLXXzNQqbT2
+3zXxJ7HeF2KhyE22wZtsaJkdULABrL/SBiuZZXWmwejHyUF6gMMnuJTg1Z1t7acr
+R8bKhBBjHorO4dzDSsUfKBtxVcvDLK70IfXBGRcGsZ8k+PjVK15W0vhDX0vpeJ7c
+9E6FS+Kfz31d8/xLETF3QdevfPTTMliakL0Tr37NKefdGXU8O07tvL/Chq40VWzl
+KqdU0ti+mI18fNsTgpe16JLvEpQBQ1ZRm/ip5ZJPkPloZn7sP7KIpmZOuMplbYlJ
+ZyINe+OKOLB8/65XK8eqwgEyQQi9Iq7/2bWgMbZKP8ECgYEA54ysuNUEVtwhmcXK
+CGiTfuCqguvKmaFraenoCxvf+aY3TU7dguA8soI+yQraqt9nW1fqrMEOnzr/mEFI
+3NE81k3uWLPdcbk/sPKKI2iQqkmlCR7XQYch0Kq2KZ3A4kXvT0M6njBb/8UFtSai
+dWiit9/9c40PGUA28+dYCSnnn2ECgYEAxyKT/+hrCHauj7Enz2jqIBsIJGRq6bc0
+rZZf4yoQO4wJTs7zTUa3REYHQOGYM/zb6BkmO5SaHiUxwrAvWi+3UvSwzSC7SZEw
+2Ym8FRFZLcjG2n9CeHK4jcp8kXnoeoKnD9K9ztQszmjl+YJ5LLAXEQuXlwG0ZSld
+Nz2OHuHYgp8CgYEAnrJequtsZu/Go7LYzjyGYp4unz5mBDeK+/NRk1OOhXczTevw
+i8OONjZoO7gRuK0XFJbEA5TppZ51EXAlNRq/HI4a/naAHnJ9wZPps2z2QY/p6b9W
+ftXUCkUGRq2VRj/yTZvhMAwq8biiOc7554hIhceh2TFjmMXXJAF56AXtduECgYA6
+Y1kh3/QCN0pXt4oEtq5vW323rfnrLVy0yTK0WNEJpLXV9bhBIEr8KcxWqc8G701L
+cJRVQ+0siZtdimtX9kW6fSSaAM7pczjvkAMl6kBLvGMSDd5fksOqT4TW4vfXdBen
+/BLLYksA+qDz193PzJH23X9FN6q9PrOmTtYtF+tz4QKBgQDeUhgpylS0sjTzS36b
+8V86DJ4mj22B7H6jp826Y696V79a2/jSacs1KKExOYXeJBUdhDoutVS0PiT10br9
+lSIKiExbrddmBUd5OEtZKz1bXqRoMZlAvjuOhqadU0DciSQjiZ8CSmSzCX31++7G
+velIMG6xcMV3LKtY4dr7B6KuiA==
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgIJAJy64S/DycmkMA0GCSqGSIb3DQEBCwUAMGcxCzAJBgNV
+BAYTAlJVMRkwFwYDVQQIDBBTYWludCBQZXRlcnNidXJnMRkwFwYDVQQHDBBTYWlu
+dCBQZXRlcnNidXJnMRAwDgYDVQQKDAdVbmtub3duMRAwDgYDVQQDDAdVbmtub3du
+MB4XDTE4MDEyNDEwMTUwNFoXDTE5MDEyNDEwMTUwNFowZzELMAkGA1UEBhMCUlUx
+GTAXBgNVBAgMEFNhaW50IFBldGVyc2J1cmcxGTAXBgNVBAcMEFNhaW50IFBldGVy
+c2J1cmcxEDAOBgNVBAoMB1Vua25vd24xEDAOBgNVBAMMB1Vua25vd24wggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0HaDP3KkkgcT73FWWxXEgiT5vAsW+
+ZByiWg5Yh5XtU7rAjiXT9VmOm1h/5GNdngF7ofhT+qal1k8WyiLsbqWL6qYXkc0e
+8aKw9ciBaWDWDkgXNnV03butu70hNvm/fzYp/6/WQ5SXUJdmmJZyeVjgU4NXnOe0
+lv2PlzUr5q1yjJCSnTbsHBvs0qfoy7DYqPQFbrwiuIOeYtVgmjjL/y6SUCY/uNY8
+McLG0YFubNsnOCEIyZOgAM1RdmARt+iYZuLVZkicgkaxYtLBpbUB8K2Y/A+0WjL7
+JceZVWbUaQKkDncegccMmHzEOBsJyLRWu+/5ztan7xh+jIGdvtlgoz8/AgMBAAGj
+UDBOMB0GA1UdDgQWBBSmehz8ReTNQ6IQmMBXhns97I3U6jAfBgNVHSMEGDAWgBSm
+ehz8ReTNQ6IQmMBXhns97I3U6jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
+A4IBAQAjtzZtXSqIrWJfCJCp0Kal/swR9EDIhvdZNpH3VJMUKENRPKZF2AdlGLwx
+sSAL6oUkCjew3NC4UM7CH1LZR+RZOQXhLxh+xmlIUDJukjftPcEAXAymCJyEShjD
+qr/YH3SrrVfzf/ViZOa3YrlWXuP9WqEYYAMJcNmgl2A1vhpIwrF0+GLrvnUV2E6a
+qHqBmA8GforiiOye+TQKNuFCgd+m8nr3AUCBaY2aVgFBg5Z2uumMzx5qmejQIdDr
+tiKsr7+QiaY97lXIThMCDxPt63Jk2uO9yUJZSzDJlY2JHuRnMmyO+TnVrUAyCr60
+dBkPpbvH/kMPPFkOhDk6e40YvqWY
+-----END CERTIFICATE-----
diff --git a/modules/platforms/cpp/odbc-test/config/ssl/server.jks b/modules/platforms/cpp/odbc-test/config/ssl/server.jks
new file mode 100644 (file)
index 0000000..2632662
Binary files /dev/null and b/modules/platforms/cpp/odbc-test/config/ssl/server.jks differ
diff --git a/modules/platforms/cpp/odbc-test/config/ssl/trust.jks b/modules/platforms/cpp/odbc-test/config/ssl/trust.jks
new file mode 100644 (file)
index 0000000..a0f3bcf
Binary files /dev/null and b/modules/platforms/cpp/odbc-test/config/ssl/trust.jks differ
index f79d65f..c535679 100644 (file)
@@ -29,9 +29,6 @@
 
 #include "ignite/ignite.h"
 
-#include "test_type.h"
-#include "complex_type.h"
-
 namespace ignite
 {
     namespace odbc
@@ -42,6 +39,11 @@ namespace ignite
         struct OdbcTestSuite
         {
             /**
+             * Prepare environment.
+             */
+            void Prepare();
+
+            /**
              * Establish connection to node.
              *
              * @param connectStr Connection string.
index e65e187..786c2be 100644 (file)
@@ -68,6 +68,11 @@ namespace ignite_test
     std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle);
 
     /**
+     * @return Test config directory path.
+     */
+    std::string GetTestConfigDir();
+
+    /**
      * Initialize configuration for a node.
      *
      * Inits Ignite node configuration from specified config file.
index d565306..b1074b2 100644 (file)
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <SDLCheck>true</SDLCheck>
-      <AdditionalIncludeDirectories>$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\jni\include;$(ProjectDir)\..\..\..\jni\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\..\core\include;$(ProjectDir)\..\..\..\odbc\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win;$(ProjectDir)\..\..\src;$(BOOST_HOME)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\jni\include;$(ProjectDir)\..\..\..\jni\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\..\core\include;$(ProjectDir)\..\..\..\odbc\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win;$(ProjectDir)\..\..\src;$(BOOST_HOME);$(OPENSSL_HOME)\include</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;BOOST_DATE_TIME_NO_LIB;BOOST_REGEX_NO_LIB;IGNITE_IMPL;IGNITE_FRIEND;IGNITE_TESTS_32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ExceptionHandling>Async</ExceptionHandling>
+      <WholeProgramOptimization>false</WholeProgramOptimization>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <SDLCheck>true</SDLCheck>
-      <AdditionalIncludeDirectories>$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\jni\include;$(ProjectDir)\..\..\..\jni\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\..\core\include;$(ProjectDir)\..\..\..\odbc\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win;$(ProjectDir)\..\..\src;$(BOOST_HOME)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\jni\include;$(ProjectDir)\..\..\..\jni\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\..\core\include;$(ProjectDir)\..\..\..\odbc\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win;$(ProjectDir)\..\..\src;$(BOOST_HOME);$(OPENSSL_HOME)\include</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;BOOST_DATE_TIME_NO_LIB;BOOST_REGEX_NO_LIB;IGNITE_IMPL;IGNITE_FRIEND;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ExceptionHandling>Async</ExceptionHandling>
     </ClCompile>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
-      <AdditionalIncludeDirectories>$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\jni\include;$(ProjectDir)\..\..\..\jni\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\..\core\include;$(ProjectDir)\..\..\..\odbc\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win;$(ProjectDir)\..\..\src;$(BOOST_HOME)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\jni\include;$(ProjectDir)\..\..\..\jni\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\..\core\include;$(ProjectDir)\..\..\..\odbc\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win;$(ProjectDir)\..\..\src;$(BOOST_HOME);$(OPENSSL_HOME)\include</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;BOOST_DATE_TIME_NO_LIB;BOOST_REGEX_NO_LIB;IGNITE_IMPL;IGNITE_FRIEND;IGNITE_TESTS_32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ExceptionHandling>Async</ExceptionHandling>
     </ClCompile>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
-      <AdditionalIncludeDirectories>$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\jni\include;$(ProjectDir)\..\..\..\jni\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\..\core\include;$(ProjectDir)\..\..\..\odbc\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win;$(ProjectDir)\..\..\src;$(BOOST_HOME)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\jni\include;$(ProjectDir)\..\..\..\jni\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\..\core\include;$(ProjectDir)\..\..\..\odbc\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win;$(ProjectDir)\..\..\src;$(BOOST_HOME);$(OPENSSL_HOME)\include</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;BOOST_DATE_TIME_NO_LIB;BOOST_REGEX_NO_LIB;IGNITE_IMPL;IGNITE_FRIEND;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ExceptionHandling>Async</ExceptionHandling>
     </ClCompile>
     <ClCompile Include="..\..\src\errors_test.cpp" />
     <ClCompile Include="..\..\src\meta_queries_test.cpp" />
     <ClCompile Include="..\..\src\odbc_test_suite.cpp" />
+    <ClCompile Include="..\..\src\queries_ssl_test.cpp" />
     <ClCompile Include="..\..\src\queries_test.cpp" />
     <ClCompile Include="..\..\src\parser_test.cpp" />
     <ClCompile Include="..\..\src\row_test.cpp" />
   </ItemGroup>
   <ItemGroup>
     <None Include="..\..\config\queries-default.xml" />
-    <None Include="..\..\config\queries-test-noodbc-32.xml" />
-    <None Include="..\..\config\queries-test-noodbc.xml" />
-    <None Include="..\..\config\queries-test-default.xml" />
+    <None Include="..\..\config\queries-ssl-32.xml" />
+    <None Include="..\..\config\queries-ssl.xml" />
     <None Include="..\..\config\queries-test-32.xml" />
     <None Include="..\..\config\queries-test.xml" />
   </ItemGroup>
index 58cf045..417fac9 100644 (file)
     <ClCompile Include="..\..\src\odbc_test_suite.cpp">
       <Filter>Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\queries_ssl_test.cpp">
+      <Filter>Code</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\include\test_type.h">
     <None Include="..\..\config\queries-test.xml">
       <Filter>Configs</Filter>
     </None>
-    <None Include="..\..\config\queries-test-noodbc-32.xml">
-      <Filter>Configs</Filter>
-    </None>
-    <None Include="..\..\config\queries-test-noodbc.xml">
+    <None Include="..\..\config\queries-default.xml">
       <Filter>Configs</Filter>
     </None>
-    <None Include="..\..\config\queries-default.xml">
+    <None Include="..\..\config\queries-ssl.xml">
       <Filter>Configs</Filter>
     </None>
-    <None Include="..\..\config\queries-test-default.xml">
+    <None Include="..\..\config\queries-ssl-32.xml">
       <Filter>Configs</Filter>
     </None>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
index c17e079..293d8bc 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "test_type.h"
 #include "test_utils.h"
+#include "odbc_test_suite.h"
 
 using namespace ignite;
 using namespace ignite::cache;
@@ -51,98 +52,21 @@ using ignite::impl::binary::BinaryUtils;
 /**
  * Test setup fixture.
  */
-struct ApiRobustnessTestSuiteFixture
+struct ApiRobustnessTestSuiteFixture : public odbc::OdbcTestSuite
 {
-    void Prepare()
-    {
-        // Allocate an environment handle
-        SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
-
-        BOOST_REQUIRE(env != NULL);
-
-        // We want ODBC 3 support
-        SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0);
-
-        // Allocate a connection handle
-        SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
-
-        BOOST_REQUIRE(dbc != NULL);
-    }
-
-    /**
-     * Establish connection to node.
-     *
-     * @param connectStr Connection string.
-     */
-    void Connect(const std::string& connectStr)
-    {
-        Prepare();
-
-        // Connect string
-        std::vector<SQLCHAR> connectStr0;
-
-        connectStr0.reserve(connectStr.size() + 1);
-        std::copy(connectStr.begin(), connectStr.end(), std::back_inserter(connectStr0));
-
-        SQLCHAR outstr[ODBC_BUFFER_SIZE];
-        SQLSMALLINT outstrlen;
-
-        // Connecting to ODBC server.
-        SQLRETURN ret = SQLDriverConnect(dbc, NULL, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()),
-            outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
-
-        ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
-
-        // Allocate a statement handle
-        SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
-
-        BOOST_REQUIRE(stmt != NULL);
-    }
-
-    void Disconnect()
-    {
-        // Releasing statement handle.
-        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-
-        // Disconneting from the server.
-        SQLDisconnect(dbc);
-
-        // Releasing allocated handles.
-        SQLFreeHandle(SQL_HANDLE_DBC, dbc);
-        SQLFreeHandle(SQL_HANDLE_ENV, env);
-    }
-
     static Ignite StartAdditionalNode(const char* name)
     {
-        const char* config = NULL;
-
-#ifdef IGNITE_TESTS_32
-        config = "queries-test-noodbc-32.xml";
-#else
-        config = "queries-test-noodbc.xml";
-#endif
-
-        return StartNode(config, name);
+        return StartTestNode("queries-test.xml", name);
     }
 
     /**
      * Constructor.
      */
     ApiRobustnessTestSuiteFixture() :
-        testCache(0),
-        env(NULL),
-        dbc(NULL),
-        stmt(NULL)
+        grid(),
+        testCache(0)
     {
-        const char* config = NULL;
-
-#ifdef IGNITE_TESTS_32
-          config = "queries-test-32.xml";
-#else
-          config = "queries-test.xml";
-#endif
-
-        grid = StartNode(config, "NodeMain");
+        grid = StartAdditionalNode("NodeMain");
 
         testCache = grid.GetCache<int64_t, TestType>("cache");
     }
@@ -227,9 +151,7 @@ struct ApiRobustnessTestSuiteFixture
      */
     ~ApiRobustnessTestSuiteFixture()
     {
-        Disconnect();
-
-        Ignition::StopAll(true);
+        // No-op.
     }
 
     /** Node started during the test. */
@@ -237,15 +159,6 @@ struct ApiRobustnessTestSuiteFixture
 
     /** Test cache instance. */
     Cache<int64_t, TestType> testCache;
-
-    /** ODBC Environment. */
-    SQLHENV env;
-
-    /** ODBC Connect. */
-    SQLHDBC dbc;
-
-    /** ODBC Statement. */
-    SQLHSTMT stmt;
 };
 
 SQLSMALLINT unsupportedC[] = {
index bac9fd4..9c640ba 100644 (file)
@@ -42,6 +42,7 @@
 #include "test_type.h"
 #include "complex_type.h"
 #include "test_utils.h"
+#include "odbc_test_suite.h"
 
 using namespace ignite;
 using namespace ignite::cache;
@@ -59,83 +60,18 @@ using ignite::impl::binary::BinaryUtils;
 /**
  * Test setup fixture.
  */
-struct ErrorTestSuiteFixture 
+struct ErrorTestSuiteFixture : odbc::OdbcTestSuite
 {
-    /**
-     * Establish connection to node.
-     *
-     * @param connectStr Connection string.
-     */
-    void Connect(const std::string& connectStr)
-    {
-        // Allocate an environment handle
-        SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
-
-        BOOST_REQUIRE(env != NULL);
-
-        // We want ODBC 3 support
-        SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0);
-
-        // Allocate a connection handle
-        SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
-
-        BOOST_REQUIRE(dbc != NULL);
-
-        // Connect string
-        std::vector<SQLCHAR> connectStr0;
-
-        connectStr0.reserve(connectStr.size() + 1);
-        std::copy(connectStr.begin(), connectStr.end(), std::back_inserter(connectStr0));
-
-        SQLCHAR outstr[ODBC_BUFFER_SIZE];
-        SQLSMALLINT outstrlen;
-
-        // Connecting to ODBC server.
-        SQLRETURN ret = SQLDriverConnect(dbc, NULL, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()),
-            outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
-
-        if (!SQL_SUCCEEDED(ret))
-        {
-            Ignition::StopAll(true);
-
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc));
-        }
-
-        // Allocate a statement handle
-        SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
-
-        BOOST_REQUIRE(stmt != NULL);
-    }
-
-    void Disconnect()
-    {
-        // Releasing statement handle.
-        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-
-        // Disconneting from the server.
-        SQLDisconnect(dbc);
-
-        // Releasing allocated handles.
-        SQLFreeHandle(SQL_HANDLE_DBC, dbc);
-        SQLFreeHandle(SQL_HANDLE_ENV, env);
-    }
-
     static Ignite StartAdditionalNode(const char* name)
     {
-#ifdef IGNITE_TESTS_32
-        return StartNode("queries-test-32.xml", name);
-#else
-        return StartNode("queries-test.xml", name);
-#endif
+        return StartTestNode("queries-test.xml", name);
     }
 
     /**
      * Constructor.
      */
     ErrorTestSuiteFixture() :
-        env(NULL),
-        dbc(NULL),
-        stmt(NULL)
+        OdbcTestSuite()
     {
         // No-op.
     }
@@ -145,22 +81,8 @@ struct ErrorTestSuiteFixture
      */
     ~ErrorTestSuiteFixture()
     {
-        Disconnect();
-
-        Ignition::StopAll(true);
+        // No-op.
     }
-
-    /** Frist cache instance. */
-    //Cache<int64_t, TestType> cache;
-
-    /** ODBC Environment. */
-    SQLHENV env;
-
-    /** ODBC Connect. */
-    SQLHDBC dbc;
-
-    /** ODBC Statement. */
-    SQLHSTMT stmt;
 };
 
 BOOST_FIXTURE_TEST_SUITE(ErrorTestSuite, ErrorTestSuiteFixture)
@@ -181,7 +103,7 @@ BOOST_AUTO_TEST_CASE(TestConnectFail)
     BOOST_REQUIRE(dbc != NULL);
 
     // Connect string
-    SQLCHAR connectStr[] = "DRIVER={Apache Ignite};ADDRESS=127.0.0.1:9999;SCHEMA=cache";
+    SQLCHAR connectStr[] = "DRIVER={Apache Ignite};ADDRESS=127.0.0.1:1111;SCHEMA=cache";
 
     SQLCHAR outstr[ODBC_BUFFER_SIZE];
     SQLSMALLINT outstrlen;
index ba9fd04..8e22e3d 100644 (file)
@@ -40,6 +40,7 @@
 #include "test_type.h"
 #include "complex_type.h"
 #include "test_utils.h"
+#include "odbc_test_suite.h"
 
 using namespace ignite;
 using namespace ignite::cache;
@@ -55,82 +56,16 @@ using namespace boost::unit_test;
 /**
  * Test setup fixture.
  */
-struct MetaQueriesTestSuiteFixture 
+struct MetaQueriesTestSuiteFixture : public odbc::OdbcTestSuite
 {
     /**
-     * Establish connection to node.
-     *
-     * @param connectStr Connection string.
-     */
-    void Connect(const std::string& connectStr)
-    {
-        // Allocate an environment handle
-        SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
-
-        BOOST_REQUIRE(env != NULL);
-
-        // We want ODBC 3 support
-        SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0);
-
-        // Allocate a connection handle
-        SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
-
-        BOOST_REQUIRE(dbc != NULL);
-
-        // Connect string
-        std::vector<SQLCHAR> connectStr0;
-
-        connectStr0.reserve(connectStr.size() + 1);
-        std::copy(connectStr.begin(), connectStr.end(), std::back_inserter(connectStr0));
-
-        SQLCHAR outstr[ODBC_BUFFER_SIZE];
-        SQLSMALLINT outstrlen;
-
-        // Connecting to ODBC server.
-        SQLRETURN ret = SQLDriverConnect(dbc, NULL, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()),
-            outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
-
-        if (!SQL_SUCCEEDED(ret))
-        {
-            Ignition::Stop(grid.GetName(), true);
-
-            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc));
-        }
-
-        // Allocate a statement handle
-        SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
-
-        BOOST_REQUIRE(stmt != NULL);
-    }
-
-    /**
-     * Disconnect.
-     */
-    void Disconnect()
-    {
-        // Releasing statement handle.
-        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-
-        // Disconneting from the server.
-        SQLDisconnect(dbc);
-
-        // Releasing allocated handles.
-        SQLFreeHandle(SQL_HANDLE_DBC, dbc);
-        SQLFreeHandle(SQL_HANDLE_ENV, env);
-    }
-
-    /**
      * Start additional node with the specified name.
      *
      * @param name Node name.
      */
     static Ignite StartAdditionalNode(const char* name)
     {
-#ifdef IGNITE_TESTS_32
-        return StartNode("queries-test-noodbc-32.xml", name);
-#else
-        return StartNode("queries-test-noodbc.xml", name);
-#endif
+        return StartTestNode("queries-test.xml", name);
     }
 
     /**
@@ -190,17 +125,11 @@ struct MetaQueriesTestSuiteFixture
      * Constructor.
      */
     MetaQueriesTestSuiteFixture() :
+        grid(0),
         cache1(0),
-        cache2(0),
-        env(NULL),
-        dbc(NULL),
-        stmt(NULL)
+        cache2(0)
     {
-#ifdef IGNITE_TESTS_32
-        grid = StartNode("queries-test-32.xml", "NodeMain");
-#else
-        grid = StartNode("queries-test.xml", "NodeMain");
-#endif
+        grid = StartTestNode("queries-test.xml", "NodeMain");
 
         cache1 = grid.GetCache<int64_t, TestType>("cache");
         cache2 = grid.GetCache<int64_t, ComplexType>("cache2");
@@ -211,9 +140,7 @@ struct MetaQueriesTestSuiteFixture
      */
     ~MetaQueriesTestSuiteFixture()
     {
-        Disconnect();
-
-        Ignition::StopAll(true);
+        // No-op.
     }
 
     /** Node started during the test. */
@@ -224,15 +151,6 @@ struct MetaQueriesTestSuiteFixture
 
     /** Second cache instance. */
     Cache<int64_t, ComplexType> cache2;
-
-    /** ODBC Environment. */
-    SQLHENV env;
-
-    /** ODBC Connect. */
-    SQLHDBC dbc;
-
-    /** ODBC Statement. */
-    SQLHSTMT stmt;
 };
 
 BOOST_FIXTURE_TEST_SUITE(MetaQueriesTestSuite, MetaQueriesTestSuiteFixture)
index 970c77d..fca3604 100644 (file)
@@ -40,7 +40,7 @@ namespace ignite
 {
     namespace odbc
     {
-        void OdbcTestSuite::Connect(const std::string& connectStr)
+        void OdbcTestSuite::Prepare()
         {
             // Allocate an environment handle
             SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
@@ -54,12 +54,14 @@ namespace ignite
             SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
 
             BOOST_REQUIRE(dbc != NULL);
+        }
 
-            // Connect string
-            std::vector<SQLCHAR> connectStr0;
+        void OdbcTestSuite::Connect(const std::string& connectStr)
+        {
+            Prepare();
 
-            connectStr0.reserve(connectStr.size() + 1);
-            std::copy(connectStr.begin(), connectStr.end(), std::back_inserter(connectStr0));
+            // Connect string
+            std::vector<SQLCHAR> connectStr0(connectStr.begin(), connectStr.end());
 
             SQLCHAR outstr[ODBC_BUFFER_SIZE];
             SQLSMALLINT outstrlen;
@@ -81,15 +83,29 @@ namespace ignite
 
         void OdbcTestSuite::Disconnect()
         {
-            // Releasing statement handle.
-            SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+            if (stmt)
+            {
+                // Releasing statement handle.
+                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+                stmt = NULL;
+            }
+
+            if (dbc)
+            {
+                // Disconneting from the server.
+                SQLDisconnect(dbc);
 
-            // Disconneting from the server.
-            SQLDisconnect(dbc);
+                // Releasing allocated handles.
+                SQLFreeHandle(SQL_HANDLE_DBC, dbc);
+                dbc = NULL;
+            }
 
-            // Releasing allocated handles.
-            SQLFreeHandle(SQL_HANDLE_DBC, dbc);
-            SQLFreeHandle(SQL_HANDLE_ENV, env);
+            if (env)
+            {
+                // Releasing allocated handles.
+                SQLFreeHandle(SQL_HANDLE_ENV, env);
+                env = NULL;
+            }
         }
 
         Ignite OdbcTestSuite::StartTestNode(const char* cfg, const char* name)
diff --git a/modules/platforms/cpp/odbc-test/src/queries_ssl_test.cpp b/modules/platforms/cpp/odbc-test/src/queries_ssl_test.cpp
new file mode 100644 (file)
index 0000000..897544e
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * 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.
+ */
+
+#ifdef _WIN32
+#   include <windows.h>
+#endif
+
+#include <sql.h>
+#include <sqlext.h>
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+#ifndef _MSC_VER
+#   define BOOST_TEST_DYN_LINK
+#endif
+
+#include <boost/regex.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include "ignite/ignite.h"
+#include "ignite/common/fixed_size_array.h"
+#include "ignite/ignition.h"
+#include "ignite/impl/binary/binary_utils.h"
+#include "ignite/binary/binary_object.h"
+
+#include "test_type.h"
+#include "complex_type.h"
+#include "test_utils.h"
+#include "odbc_test_suite.h"
+
+using namespace ignite;
+using namespace ignite::cache;
+using namespace ignite::cache::query;
+using namespace ignite::common;
+using namespace ignite_test;
+using namespace ignite::binary;
+using namespace ignite::impl::binary;
+using namespace ignite::impl::interop;
+
+using namespace boost::unit_test;
+
+using ignite::impl::binary::BinaryUtils;
+
+/**
+ * Test setup fixture.
+ */
+struct SslQueriesTestSuiteFixture : odbc::OdbcTestSuite
+{
+    static Ignite StartAdditionalNode(const char* name)
+    {
+        return StartTestNode("queries-ssl.xml", name);
+    }
+
+    /**
+     * Constructor.
+     */
+    SslQueriesTestSuiteFixture() :
+        OdbcTestSuite(),
+        cache1(0),
+        cache2(0)
+    {
+        grid = StartAdditionalNode("NodeMain");
+
+        cache1 = grid.GetCache<int64_t, TestType>("cache");
+        cache2 = grid.GetCache<int64_t, ComplexType>("cache2");
+    }
+
+    /**
+     * Destructor.
+     */
+    virtual ~SslQueriesTestSuiteFixture()
+    {
+        // No-op.
+    }
+
+    /**
+     * Create default connection string.
+     * @return Default connection string.
+     */
+    std::string MakeDefaultConnectionString()
+    {
+        std::string cfgDirPath = GetTestConfigDir();
+
+        std::stringstream connectString;
+
+        connectString <<
+            "DRIVER={Apache Ignite};"
+            "ADDRESS=127.0.0.1:11110;"
+            "SCHEMA=cache;"
+            "SSL_MODE=require;"
+            "SSL_KEY_FILE=" << cfgDirPath << Fs << "ssl" << Fs << "client_full.pem;"
+            "SSL_CERT_FILE=" << cfgDirPath << Fs << "ssl" << Fs << "client_full.pem;"
+            "SSL_CA_FILE=" << cfgDirPath << Fs << "ssl" << Fs << "ca.pem;";
+
+        return connectString.str();
+    }
+
+    /** Node started during the test. */
+    Ignite grid;
+
+    /** Frist cache instance. */
+    Cache<int64_t, TestType> cache1;
+
+    /** Second cache instance. */
+    Cache<int64_t, ComplexType> cache2;
+};
+
+BOOST_FIXTURE_TEST_SUITE(SslQueriesTestSuite, SslQueriesTestSuiteFixture)
+
+BOOST_AUTO_TEST_CASE(TestConnectionSslSuccess)
+{
+    Connect(MakeDefaultConnectionString());
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 2000, 1989);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionSslReject)
+{
+    std::string cfgDirPath = GetTestConfigDir();
+
+    std::stringstream connectString;
+
+    connectString <<
+        "DRIVER={Apache Ignite};"
+        "ADDRESS=127.0.0.1:11110;"
+        "SCHEMA=cache;"
+        "SSL_MODE=require;"
+        "SSL_KEY_FILE=" << cfgDirPath << Fs << "ssl" << Fs << "client_unknown.pem;"
+        "SSL_CERT_FILE=" << cfgDirPath << Fs << "ssl" << Fs << "client_unknown.pem;"
+        "SSL_CA_FILE=" << cfgDirPath << Fs << "ssl" << Fs << "ca.pem;";
+
+    Prepare();
+
+    // Connect string
+    std::string str = connectString.str();
+    std::vector<SQLCHAR> connectStr0(str.begin(), str.end());
+
+    SQLCHAR outstr[ODBC_BUFFER_SIZE];
+    SQLSMALLINT outstrlen;
+
+    // Connecting to ODBC server.
+    SQLRETURN ret = SQLDriverConnect(dbc, NULL, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()),
+        outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
+
+    // Checking that there is an error.
+    BOOST_REQUIRE_EQUAL(ret, SQL_ERROR);
+
+    // Checking that error is the connection error.
+    BOOST_CHECK_EQUAL(std::string("08001"), GetOdbcErrorState(SQL_HANDLE_DBC, dbc));
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionTimeoutQuery)
+{
+    Connect(MakeDefaultConnectionString());
+
+    SQLRETURN ret = SQLSetConnectAttr(dbc, SQL_ATTR_CONNECTION_TIMEOUT, reinterpret_cast<SQLPOINTER>(5), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
+
+    InsertTestStrings(10, false);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionTimeoutBatch)
+{
+    Connect(MakeDefaultConnectionString());
+
+    SQLRETURN ret = SQLSetConnectAttr(dbc, SQL_ATTR_CONNECTION_TIMEOUT, reinterpret_cast<SQLPOINTER>(5), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
+
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectionTimeoutBoth)
+{
+    Connect(MakeDefaultConnectionString());
+
+    SQLRETURN ret = SQLSetConnectAttr(dbc, SQL_ATTR_CONNECTION_TIMEOUT, reinterpret_cast<SQLPOINTER>(5), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestQueryTimeoutQuery)
+{
+    Connect(MakeDefaultConnectionString());
+
+    SQLRETURN ret = SQLSetStmtAttr(stmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>(5), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+    InsertTestStrings(10, false);
+}
+
+BOOST_AUTO_TEST_CASE(TestQueryTimeoutBatch)
+{
+    Connect(MakeDefaultConnectionString());
+
+    SQLRETURN ret = SQLSetStmtAttr(stmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>(5), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestQueryTimeoutBoth)
+{
+    Connect(MakeDefaultConnectionString());
+
+    SQLRETURN ret = SQLSetStmtAttr(stmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>(5), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestQueryAndConnectionTimeoutQuery)
+{
+    Connect(MakeDefaultConnectionString());
+
+    SQLRETURN ret = SQLSetStmtAttr(stmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>(5), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+    ret = SQLSetConnectAttr(dbc, SQL_ATTR_CONNECTION_TIMEOUT, reinterpret_cast<SQLPOINTER>(3), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
+
+    InsertTestStrings(10, false);
+}
+
+BOOST_AUTO_TEST_CASE(TestQueryAndConnectionTimeoutBatch)
+{
+    Connect(MakeDefaultConnectionString());
+
+    SQLRETURN ret = SQLSetStmtAttr(stmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>(5), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+    ret = SQLSetConnectAttr(dbc, SQL_ATTR_CONNECTION_TIMEOUT, reinterpret_cast<SQLPOINTER>(3), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
+
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_CASE(TestQueryAndConnectionTimeoutBoth)
+{
+    Connect(MakeDefaultConnectionString());
+
+    SQLRETURN ret = SQLSetStmtAttr(stmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>(5), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+
+    ret = SQLSetConnectAttr(dbc, SQL_ATTR_CONNECTION_TIMEOUT, reinterpret_cast<SQLPOINTER>(3), 0);
+
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
+
+    InsertTestStrings(10, false);
+    InsertTestBatch(11, 20, 9);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
index bf9876a..639e16f 100644 (file)
@@ -228,7 +228,7 @@ struct QueriesTestSuiteFixture : odbc::OdbcTestSuite
 
     static Ignite StartAdditionalNode(const char* name)
     {
-        return StartTestNode("queries-test-noodbc.xml", name);
+        return StartTestNode("queries-test.xml", name);
     }
 
     /** Node started during the test. */
@@ -1340,7 +1340,7 @@ void CheckObjectData(int8_t* data, int32_t len, T const& value)
     BinaryObject obj(BinaryObjectImpl::FromMemory(mem, 0, 0));
 
     T actual = obj.Deserialize<T>();
-    
+
     BOOST_CHECK_EQUAL(value, actual);
 }
 
@@ -1374,7 +1374,7 @@ BOOST_AUTO_TEST_CASE(TestKeyVal)
     int8_t column6[ODBC_BUFFER_SIZE] = { 0 };
     //strField
     char column7[ODBC_BUFFER_SIZE] = { 0 };
-    
+
     SQLLEN column1Len = sizeof(column1);
     SQLLEN column2Len = sizeof(column2);
     SQLLEN column3Len = sizeof(column3);
@@ -1438,7 +1438,7 @@ BOOST_AUTO_TEST_CASE(TestKeyVal)
     CheckObjectData(column4, static_cast<int32_t>(column4Len), obj);
 
     BOOST_CHECK_EQUAL(column5, obj.i32Field);
-    
+
     CheckObjectData(column6, static_cast<int32_t>(column6Len), obj.objField);
 
     BOOST_CHECK_EQUAL(column7, obj.strField);
@@ -1446,6 +1446,10 @@ BOOST_AUTO_TEST_CASE(TestKeyVal)
     ret = SQLFetch(stmt);
     BOOST_CHECK(ret == SQL_NO_DATA);
 
+    ret = SQLFreeStmt(stmt, SQL_CLOSE);
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
     SQLCHAR requestStar[] = "SELECT _key, _val, * FROM ComplexType";
 
     ret = SQLExecDirect(stmt, requestStar, SQL_NTS);
@@ -1534,7 +1538,7 @@ BOOST_AUTO_TEST_CASE(TestExecuteAfterCursorClose)
         BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
 
     ret = SQLFetch(stmt);
-    
+
     if (!SQL_SUCCEEDED(ret))
         BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
 
index f905ff7..42dd3f7 100644 (file)
@@ -110,6 +110,10 @@ namespace ignite
 
         ret = SQLFetch(stmt);
         BOOST_CHECK(ret == SQL_NO_DATA);
+
+        ret = SQLFreeStmt(stmt, SQL_CLOSE);
+        if (!SQL_SUCCEEDED(ret))
+            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
     }
 
     template<>
index eb08660..6d9ed6b 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <cassert>
 
+#include <ignite/common/platform_utils.h>
+
 #include "test_utils.h"
 
 namespace ignite_test
@@ -54,6 +56,11 @@ namespace ignite_test
         return res;
     }
 
+    std::string GetTestConfigDir()
+    {
+        return ignite::common::GetEnv("IGNITE_NATIVE_TEST_ODBC_CONFIG_PATH");
+    }
+
     void InitConfig(ignite::IgniteConfiguration& cfg, const char* cfgFile)
     {
         using namespace ignite;
@@ -70,6 +77,8 @@ namespace ignite_test
         cfg.jvmOpts.push_back("-DIGNITE_CONSOLE_APPENDER=false");
         cfg.jvmOpts.push_back("-DIGNITE_UPDATE_NOTIFIER=false");
         cfg.jvmOpts.push_back("-Duser.language=en");
+        // Un-comment to debug SSL
+        //cfg.jvmOpts.push_back("-Djavax.net.debug=ssl");
 
         cfg.igniteHome = jni::ResolveIgniteHome();
         cfg.jvmClassPath = jni::CreateIgniteHomeClasspath(cfg.igniteHome, true);
index 8d7693c..ea74c34 100644 (file)
@@ -49,7 +49,7 @@ libignite_odbc_la_DEPENDENCIES = \
     @top_srcdir@/binary/libignite-binary.la
 
 libignite_odbc_la_SOURCES = \
-    os/linux/src/system/socket_client.cpp \
+    os/linux/src/system/tcp_socket_client.cpp \
     src/app/application_data_buffer.cpp \
     src/app/parameter.cpp \
     src/app/parameter_set.cpp \
@@ -75,6 +75,9 @@ libignite_odbc_la_SOURCES = \
     src/query/table_metadata_query.cpp \
     src/query/type_info_query.cpp \
     src/query/special_columns_query.cpp \
+    src/ssl/ssl_gateway.cpp \
+    src/ssl/secure_socket_client.cpp \
+    src/ssl/ssl_mode.cpp \
     src/protocol_version.cpp \
     src/result_page.cpp \
     src/row.cpp \
index 7c64754..9bdb803 100644 (file)
@@ -42,7 +42,7 @@ noinst_HEADERS = \
     ignite/odbc/environment.h \
     ignite/odbc/dsn_config.h \
     ignite/odbc/system/odbc_constants.h \
-    ignite/odbc/system/socket_client.h \
+    ignite/odbc/system/tcp_socket_client.h \
     ignite/odbc/meta/primary_key_meta.h \
     ignite/odbc/meta/column_meta.h \
     ignite/odbc/meta/table_meta.h \
@@ -50,6 +50,10 @@ noinst_HEADERS = \
     ignite/odbc/diagnostic/diagnostic_record_storage.h \
     ignite/odbc/diagnostic/diagnosable.h \
     ignite/odbc/diagnostic/diagnosable_adapter.h \
+    ignite/odbc/ssl/ssl_mode.h \
+    ignite/odbc/ssl/ssl_bindings.h \
+    ignite/odbc/ssl/secure_socket_client.h \
+    ignite/odbc/ssl/ssl_gateway.h \
     ignite/odbc/connection.h \
     ignite/odbc/odbc_error.h \
     ignite/odbc/message.h \
index 419a65e..89018f5 100644 (file)
@@ -85,6 +85,18 @@ namespace ignite
 
                     /** Connection attribute keyword for skipReducerOnUpdate attribute. */
                     static const std::string skipReducerOnUpdate;
+
+                    /** Connection attribute keyword for sslMode attribute. */
+                    static const std::string sslMode;
+
+                    /** Connection attribute keyword for sslKeyFile attribute. */
+                    static const std::string sslKeyFile;
+
+                    /** Connection attribute keyword for sslCertFile attribute. */
+                    static const std::string sslCertFile;
+
+                    /** Connection attribute keyword for sslCaFile attribute. */
+                    static const std::string sslCaFile;
                 };
 
                 /** Default values for configuration. */
@@ -105,6 +117,18 @@ namespace ignite
                     /** Default value for server attribute. */
                     static const std::string server;
 
+                    /** Default value for sslMode attribute. */
+                    static const std::string sslMode;
+
+                    /** Default value for sslKeyFile attribute. */
+                    static const std::string sslKeyFile;
+
+                    /** Default value for sslCertFile attribute. */
+                    static const std::string sslCertFile;
+
+                    /** Default value for sslCaFile attribute. */
+                    static const std::string sslCaFile;
+
                     /** Default value for protocol version. */
                     static const ProtocolVersion& protocolVersion;
 
@@ -183,8 +207,8 @@ namespace ignite
                 /**
                  * Fill configuration data using config attributes string.
                  *
-                 * @param str Pointer to list of zero-terminated strings.
-                 *            Terminated by two zero bytes.
+                 * @param attributes Pointer to list of zero-terminated strings.
+                 *     Terminated by two zero bytes.
                  */
                 void FillFromConfigAttributes(const char* attributes);
 
@@ -290,6 +314,86 @@ namespace ignite
                 void SetAddress(const std::string& address);
 
                 /**
+                 * Get SSL mode.
+                 *
+                 * @return SSL mode.
+                 */
+                const std::string& GetSslMode() const
+                {
+                    return GetStringValue(Key::sslMode, DefaultValue::sslMode);
+                }
+
+                /**
+                 * Set SSL mode.
+                 *
+                 * @param sslMode SSL mode.
+                 */
+                void SetSslMode(const std::string& sslMode)
+                {
+                    arguments[Key::sslMode] = sslMode;
+                }
+
+                /**
+                 * Get SSL key file path.
+                 *
+                 * @return SSL key file path.
+                 */
+                const std::string& GetSslKeyFile() const
+                {
+                    return GetStringValue(Key::sslKeyFile, DefaultValue::sslKeyFile);
+                }
+
+                /**
+                 * Set SSL key file path.
+                 *
+                 * @param sslKeyFile SSL key file path.
+                 */
+                void SetSslKeyFile(const std::string& sslKeyFile)
+                {
+                    arguments[Key::sslKeyFile] = sslKeyFile;
+                }
+
+                /**
+                 * Get SSL certificate file path.
+                 *
+                 * @return SSL certificate file path.
+                 */
+                const std::string& GetSslCertFile() const
+                {
+                    return GetStringValue(Key::sslCertFile, DefaultValue::sslCertFile);
+                }
+
+                /**
+                 * Set SSL certificate file path.
+                 *
+                 * @param sslCertFile SSL certificate file path.
+                 */
+                void SetSslCertFile(const std::string& sslCertFile)
+                {
+                    arguments[Key::sslCertFile] = sslCertFile;
+                }
+
+                /**
+                 * Get SSL certificate authority file path.
+                 *
+                 * @return SSL certificate authority file path.
+                 */
+                const std::string& GetSslCaFile() const
+                {
+                    return GetStringValue(Key::sslCaFile, DefaultValue::sslCaFile);
+                }
+
+                /**
+                 * Set SSL certificate authority file path.
+                 *
+                 * @param sslCaFile SSL certificate authority file path.
+                 */
+                void SetSslCaFile(const std::string& sslCaFile)
+                {
+                    arguments[Key::sslCaFile] = sslCaFile;
+                }
+
+                /**
                  * Check distributed joins flag.
                  *
                  * @return True if distributed joins are enabled.
@@ -495,7 +599,7 @@ namespace ignite
                  *
                  * @param str String to parse.
                  * @param len String length.
-                 * @param params Parsing result.
+                 * @param args Parsing result.
                  */
                 static void ParseAttributeList(const char* str, size_t len, char delimeter, ArgumentMap& args);
 
index 1577ee7..025b855 100644 (file)
@@ -23,7 +23,7 @@
 #include <vector>
 
 #include "ignite/odbc/parser.h"
-#include "ignite/odbc/system/socket_client.h"
+#include "ignite/odbc/socket_client.h"
 #include "ignite/odbc/config/connection_info.h"
 #include "ignite/odbc/config/configuration.h"
 #include "ignite/odbc/diagnostic/diagnosable_adapter.h"
@@ -367,11 +367,8 @@ namespace ignite
              */
             Connection();
 
-            /** Socket. */
-            tcp::SocketClient socket;
-
-            /** State flag. */
-            bool connected;
+            /** Client Socket. */
+            std::auto_ptr<SocketClient> socket;
 
             /** Connection timeout in seconds. */
             int32_t timeout;
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/socket_client.h b/modules/platforms/cpp/odbc/include/ignite/odbc/socket_client.h
new file mode 100644 (file)
index 0000000..2df035b
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_ODBC_SOCKET_CLIENT
+#define _IGNITE_ODBC_SOCKET_CLIENT
+
+#include <stdint.h>
+
+#include "ignite/odbc/diagnostic/diagnosable.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        /**
+         * Socket client implementation.
+         */
+        class SocketClient
+        {
+        public:
+            /** Connection establishment timeout in seconds. */
+            enum { CONNECT_TIMEOUT = 5 };
+
+            /**
+             * Non-negative timeout operation result.
+             */
+            struct WaitResult
+            {
+                enum T
+                {
+                    /** Timeout. */
+                    TIMEOUT = 0,
+
+                    /** Success. */
+                    SUCCESS = 1
+                };
+            };
+
+            /**
+             * Destructor.
+             */
+            virtual ~SocketClient()
+            {
+                // No-op.
+            }
+
+            /**
+             * Establish connection with remote service.
+             *
+             * @param hostname Remote host name.
+             * @param port Service port.
+             * @param diag Diagnostics collector.
+             * @return True on success.
+             */
+            virtual bool Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag) = 0;
+
+            /**
+             * Close established connection.
+             *
+             * @return True on success.
+             */
+            virtual void Close() = 0;
+
+            /**
+             * Send data by established connection.
+             *
+             * @param data Pointer to data to be sent.
+             * @param size Size of the data in bytes.
+             * @param timeout Timeout.
+             * @return Number of bytes that have been sent on success, 
+             *     WaitResult::TIMEOUT on timeout and -errno on failure.
+             */
+            virtual int Send(const int8_t* data, size_t size, int32_t timeout) = 0;
+
+            /**
+             * Receive data from established connection.
+             *
+             * @param buffer Pointer to data buffer.
+             * @param size Size of the buffer in bytes.
+             * @param timeout Timeout.
+             * @return Number of bytes that have been received on success,
+             *     WaitResult::TIMEOUT on timeout and -errno on failure.
+             */
+            virtual int Receive(int8_t* buffer, size_t size, int32_t timeout) = 0;
+
+            /**
+             * Check if the socket is blocking or not.
+             * @return @c true if the socket is blocking and false otherwise.
+             */
+            virtual bool IsBlocking() const = 0;
+        };
+    }
+}
+
+#endif //_IGNITE_ODBC_SYSTEM_SOCKET_CLIENT
\ No newline at end of file
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/secure_socket_client.h b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/secure_socket_client.h
new file mode 100644 (file)
index 0000000..4cd5844
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_ODBC_SSL_SECURE_SOCKET_CLIENT
+#define _IGNITE_ODBC_SSL_SECURE_SOCKET_CLIENT
+
+#include <stdint.h>
+#include <string>
+
+#include "ignite/odbc/diagnostic/diagnosable.h"
+#include "ignite/odbc/socket_client.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace ssl
+        {
+            /**
+             * Secure socket client.
+             */
+            class SecureSocketClient : public SocketClient
+            {
+            public:
+                /**
+                 * Constructor.
+                 *
+                 * @param certPath Certificate file path.
+                 * @param keyPath Private key file path.
+                 * @param caPath Certificate authority file path.
+                 */
+                SecureSocketClient(const std::string& certPath, const std::string& keyPath, const std::string& caPath);
+
+                /**
+                 * Destructor.
+                 */
+                virtual ~SecureSocketClient();
+
+                /**
+                 * Establish connection with the host.
+                 *
+                 * @param hostname Host name or address.
+                 * @param port TCP port.
+                 * @param diag Diagnostics collector to use for error-reporting.
+                 * @return @c true on success and @c false on fail.
+                 */
+                virtual bool Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag);
+
+                /**
+                 * Close the connection.
+                 */
+                virtual void Close();
+
+                /**
+                 * Send data using connection.
+                 * @param data Data to send.
+                 * @param size Number of bytes to send.
+                 * @param timeout Timeout.
+                 * @return Number of bytes that have been sent on success, 
+                 *     WaitResult::TIMEOUT on timeout and -errno on failure.
+                 */
+                virtual int Send(const int8_t* data, size_t size, int32_t timeout);
+
+                /**
+                 * Receive data from established connection.
+                 *
+                 * @param buffer Pointer to data buffer.
+                 * @param size Size of the buffer in bytes.
+                 * @param timeout Timeout.
+                 * @return Number of bytes that have been received on success,
+                 *     WaitResult::TIMEOUT on timeout and -errno on failure.
+                 */
+                virtual int Receive(int8_t* buffer, size_t size, int32_t timeout);
+
+                /**
+                 * Check if the socket is blocking or not.
+                 * @return @c true if the socket is blocking and false otherwise.
+                 */
+                virtual bool IsBlocking() const;
+
+            private:
+                /**
+                 * Close the connection.
+                 * Internal call.
+                 */
+                void CloseInteral();
+
+                /**
+                 * Wait on the socket for any event for specified time.
+                 * This function uses poll to achive timeout functionality
+                 * for every separate socket operation.
+                 *
+                 * @param timeout Timeout.
+                 * @param rd Wait for read if @c true, or for write if @c false.
+                 * @return -errno on error, WaitResult::TIMEOUT on timeout and
+                 *     WaitResult::SUCCESS on success.
+                 */
+                int WaitOnSocket(int32_t timeout, bool rd);
+
+                /**
+                 * Make new context instance.
+                 *
+                 * @param certPath Certificate file path.
+                 * @param keyPath Private key file path.
+                 * @param caPath Certificate authority file path.
+                 * @param diag Diagnostics collector to use for error-reporting.
+                 * @return New context instance on success and null-opinter on fail.
+                 */
+                static void* MakeContext(const std::string& certPath, const std::string& keyPath,
+                    const std::string& caPath, diagnostic::Diagnosable& diag);
+
+                /** Certificate file path. */
+                std::string certPath;
+
+                /** Private key file path. */
+                std::string keyPath;
+
+                /** Certificate authority file path. */
+                std::string caPath;
+
+                /** SSL context. */
+                void* context;
+
+                /** OpenSSL I/O stream abstraction */
+                void* sslBio;
+
+                /** Blocking flag. */
+                bool blocking;
+            };
+        }
+    }
+}
+
+#endif //_IGNITE_ODBC_SSL_SECURE_SOCKET_CLIENT
\ No newline at end of file
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_bindings.h b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_bindings.h
new file mode 100644 (file)
index 0000000..b23533a
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_ODBC_SSL_SSL_BINDINGS
+#define _IGNITE_ODBC_SSL_SSL_BINDINGS
+
+#include <openssl/ssl.h>
+#include <openssl/conf.h>
+
+#include "ignite/odbc/ssl/ssl_gateway.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace ssl
+        {
+            // Declaring constant used by OpenSSL for readability.
+            enum { OPERATION_SUCCESS = 1 };
+
+            inline SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
+            {
+                typedef SSL_CTX*(FuncType)(const SSL_METHOD*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_CTX_new);
+
+                return fp(meth);
+            }
+
+            inline void SSL_CTX_free(SSL_CTX *ctx)
+            {
+                typedef void(FuncType)(SSL_CTX*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_CTX_free);
+
+                fp(ctx);
+            }
+
+            inline void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int(*callback) (int, X509_STORE_CTX *))
+            {
+                typedef void(FuncType)(SSL_CTX*, int, int(*)(int, X509_STORE_CTX*));
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSL_CTX_set_verify);
+
+                fp(ctx, mode, callback);
+            }
+
+            inline void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth)
+            {
+                typedef void(FuncType)(SSL_CTX*, int);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSL_CTX_set_verify_depth);
+
+                fp(ctx, depth);
+            }
+
+            inline int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *cAfile, const char *cApath)
+            {
+                typedef int(FuncType)(SSL_CTX*, const char*, const char*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSL_CTX_load_verify_locations);
+
+                return fp(ctx, cAfile, cApath);
+            }
+
+            inline int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file)
+            {
+                typedef int(FuncType)(SSL_CTX*, const char*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSL_CTX_use_certificate_chain_file);
+
+                return fp(ctx, file);
+            }
+
+            inline int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type)
+            {
+                typedef int(FuncType)(SSL_CTX*, const char*, int);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSL_CTX_use_RSAPrivateKey_file);
+
+                return fp(ctx, file, type);
+            }
+
+            inline int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
+            {
+                typedef int(FuncType)(SSL_CTX*, const char*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSL_CTX_set_cipher_list);
+
+                return fp(ctx, str);
+            }
+
+            inline long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
+            {
+                typedef long(FuncType)(SSL_CTX*, int, long, void*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_CTX_ctrl);
+
+                return fp(ctx, cmd, larg, parg);
+            }
+
+            inline long SSL_get_verify_result(const SSL *s)
+            {
+                typedef long(FuncType)(const SSL*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSL_get_verify_result);
+
+                return fp(s);
+            }
+
+            inline int SSL_library_init()
+            {
+                typedef int(FuncType)();
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_library_init);
+
+                return fp();
+            }
+
+            inline void SSL_load_error_strings()
+            {
+                typedef void(FuncType)();
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSL_load_error_strings);
+
+                fp();
+            }
+
+            inline X509 *SSL_get_peer_certificate(const SSL *s)
+            {
+                typedef X509*(FuncType)(const SSL*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSL_get_peer_certificate);
+
+                return fp(s);
+            }
+
+            inline long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
+            {
+                typedef long(FuncType)(SSL*, int, long, void*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_ctrl);
+
+                return fp(s, cmd, larg ,parg);
+            }
+
+            inline long SSL_set_tlsext_host_name_(SSL *s, const char *name)
+            {
+                return ssl::SSL_ctrl(s, SSL_CTRL_SET_TLSEXT_HOSTNAME,
+                    TLSEXT_NAMETYPE_host_name, const_cast<char*>(name));
+            }
+
+
+
+            inline const SSL_METHOD *SSLv23_method()
+            {
+                typedef const SSL_METHOD*(FuncType)();
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSLv23_method);
+
+                return fp();
+            }
+
+            inline void OPENSSL_config(const char *configName)
+            {
+                typedef void(FuncType)(const char*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpOPENSSL_config);
+
+                fp(configName);
+            }
+
+            inline void X509_free(X509 *a)
+            {
+                typedef void(FuncType)(X509*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpX509_free);
+
+                fp(a);
+            }
+
+            inline BIO *BIO_new_ssl_connect(SSL_CTX *ctx)
+            {
+                typedef BIO*(FuncType)(SSL_CTX*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpBIO_new_ssl_connect);
+
+                return fp(ctx);
+            }
+
+            inline int BIO_write(BIO *b, const void *data, int len)
+            {
+                typedef int(FuncType)(BIO*, const void*, int);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpBIO_write);
+
+                return fp(b, data, len);
+            }
+
+            inline int BIO_read(BIO *b, void *data, int len)
+            {
+                typedef int(FuncType)(BIO*, const void*, int);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpBIO_read);
+
+                return fp(b, data, len);
+            }
+
+            inline void BIO_free_all(BIO *a)
+            {
+                typedef void(FuncType)(BIO*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpBIO_free_all);
+
+                fp(a);
+            }
+
+            inline int BIO_test_flags(const BIO *b, int flags)
+            {
+                typedef int(FuncType)(const BIO*, int);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpBIO_test_flags);
+
+                return fp(b, flags);
+            }
+
+            inline int BIO_should_retry_(const BIO *b)
+            {
+                return ssl::BIO_test_flags(b, BIO_FLAGS_SHOULD_RETRY);
+            }
+
+            inline long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg)
+            {
+                typedef long(FuncType)(BIO*, int, long, void*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpBIO_ctrl);
+
+                return fp(bp, cmd, larg, parg);
+            }
+
+            inline long BIO_get_fd_(BIO *bp, int *fd)
+            {
+                return ssl::BIO_ctrl(bp, BIO_C_GET_FD, 0, reinterpret_cast<void*>(fd));
+            }
+
+            inline long BIO_do_handshake_(BIO *bp)
+            {
+                return ssl::BIO_ctrl(bp, BIO_C_DO_STATE_MACHINE, 0, NULL);
+            }
+
+            inline long BIO_do_connect_(BIO *bp)
+            {
+                return ssl::BIO_do_handshake_(bp);
+            }
+
+            inline long BIO_get_ssl_(BIO *bp, SSL** ssl)
+            {
+                return ssl::BIO_ctrl(bp, BIO_C_GET_SSL, 0, reinterpret_cast<void*>(ssl));
+            }
+
+            inline long BIO_set_nbio_(BIO *bp, long n)
+            {
+                return ssl::BIO_ctrl(bp, BIO_C_SET_NBIO, n, NULL);
+            }
+
+            inline long BIO_set_conn_hostname_(BIO *bp, const char *name)
+            {
+                return ssl::BIO_ctrl(bp, BIO_C_SET_CONNECT, 0, const_cast<char*>(name));
+            }
+
+            inline long BIO_pending_(BIO *bp)
+            {
+                return ssl::BIO_ctrl(bp, BIO_CTRL_PENDING, 0, NULL);
+            }
+        }
+    }
+}
+
+#endif //_IGNITE_ODBC_SSL_SSL_BINDINGS
\ No newline at end of file
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_gateway.h b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_gateway.h
new file mode 100644 (file)
index 0000000..b131228
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_ODBC_SSL_SSL_LIBRARY
+#define _IGNITE_ODBC_SSL_SSL_LIBRARY
+
+#include "ignite/common/concurrent.h"
+#include "ignite/common/dynamic_load_os.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace ssl
+        {
+            /**
+             * Functions collection.
+             */
+            struct SslFunctions
+            {
+                void *fpSSL_CTX_new;
+                void *fpSSL_CTX_free;
+                void *fpSSL_CTX_set_verify;
+                void *fpSSL_CTX_set_verify_depth;
+                void *fpSSL_CTX_load_verify_locations;
+                void *fpSSL_CTX_use_certificate_chain_file;
+                void *fpSSL_CTX_use_RSAPrivateKey_file;
+                void *fpSSL_CTX_set_cipher_list;
+                void *fpSSL_CTX_ctrl;
+                void *fpSSL_get_verify_result;
+                void *fpSSL_library_init;
+                void *fpSSL_load_error_strings;
+                void *fpSSL_get_peer_certificate;
+                void *fpSSL_ctrl;
+                void *fpSSLv23_method;
+                void *fpOPENSSL_config;
+                void *fpX509_free;
+                void *fpBIO_new_ssl_connect;
+                void *fpBIO_write;
+                void *fpBIO_read;
+                void *fpBIO_free_all;
+                void *fpBIO_test_flags;
+                void *fpBIO_ctrl;
+            };
+
+            /**
+             * SSL Gateway abstraction.
+             * Used as a factory for secure sockets. Needed for dynamic loading
+             * of the SSL libraries.
+             */
+            class SslGateway
+            {
+            public:
+                /**
+                 * Get class instance.
+                 * @return SslLibrary instance.
+                 */
+                static SslGateway& GetInstance();
+
+                /**
+                 * Try loading SSL library.
+                 * @return @c true if loaded successfully, and false otherwise.
+                 */
+                bool LoadAll();
+
+                /**
+                 * Get functions.
+                 * @return Functions structure.
+                 */
+                SslFunctions& GetFunctions()
+                {
+                    return functions;
+                }
+
+                /**
+                 * Check whether the libraries are loaded.
+                 * @return @c true if loaded.
+                 */
+                bool Loaded() const
+                {
+                    return inited;
+                }
+
+            private:
+                /**
+                 * Constructor.
+                 */
+                SslGateway();
+
+                /**
+                 * Destructor.
+                 */
+                ~SslGateway();
+
+                /**
+                 * Load SSL library.
+                 * @param name Name.
+                 * @return Module.
+                 */
+                common::dynamic::Module LoadSslLibrary(const char* name);
+
+                /**
+                 * Load all SSL libraries.
+                 */
+                bool LoadSslLibraries();
+
+                /**
+                 * Load SSL method.
+                 * @param mod Module.
+                 * @param name Name.
+                 * @return Method pointer.
+                 */
+                void* LoadSslMethod(const char* name);
+
+                /** Indicates whether the library was inited. */
+                bool inited;
+
+                /** Critical section to prevent multiple instance creation. */
+                common::concurrent::CriticalSection initCs;
+
+                /** libeay32 module. */
+                common::dynamic::Module libeay32;
+
+                /** ssleay32 module. */
+                common::dynamic::Module ssleay32;
+
+                /** libssl module. */
+                common::dynamic::Module libssl;
+
+                /** Functions. */
+                SslFunctions functions;
+            };
+        }
+    }
+}
+
+#endif //_IGNITE_ODBC_SSL_SSL_LIBRARY
\ No newline at end of file
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h
new file mode 100644 (file)
index 0000000..20472c3
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_ODBC_SSL_SSL_MODE
+#define _IGNITE_ODBC_SSL_SSL_MODE
+
+#include <string>
+
+#include "ignite/odbc/diagnostic/diagnosable.h"
+
+namespace ignite
+{
+    namespace odbc
+    {
+        namespace ssl
+        {
+            /** SSL Mode enum. */
+            struct SslMode
+            {
+                enum T
+                {
+                    DISABLE = 0,
+
+                    REQUIRE = 1,
+
+                    UNKNOWN = 100
+                };
+
+                /**
+                 * Convert mode from string. 
+                 * @param val String value.
+                 * @param dflt Default value to return on error.
+                 * @return Corresponding enum value.
+                 */
+                static T FromString(const std::string& val, T dflt = UNKNOWN);
+            };
+        }
+    }
+}
+
+#endif //_IGNITE_ODBC_SSL_SSL_MODE
\ No newline at end of file
  * limitations under the License.
  */
 
-#ifndef _IGNITE_ODBC_SYSTEM_SOCKET_CLIENT
-#define _IGNITE_ODBC_SYSTEM_SOCKET_CLIENT
+#ifndef _IGNITE_ODBC_SYSTEM_TCP_SOCKET_CLIENT
+#define _IGNITE_ODBC_SYSTEM_TCP_SOCKET_CLIENT
 
 #include <stdint.h>
 
 #include "ignite/common/common.h"
 #include "ignite/odbc/diagnostic/diagnosable.h"
+#include "ignite/odbc/socket_client.h"
 
 namespace ignite
 {
     namespace odbc
     {
-        namespace tcp
+        namespace system
         {
             /**
              * Socket client implementation.
              */
-            class SocketClient
+            class TcpSocketClient : public SocketClient
             {
             public:
                 /** Buffers size */
@@ -44,31 +45,15 @@ namespace ignite
                 /** The time in seconds between individual keepalive probes. */
                 enum { KEEP_ALIVE_PROBES_PERIOD = 1 };
 
-                /** Connection establishment timeout in seconds. */
-                enum { CONNECT_TIMEOUT = 5 };
-
-                /**
-                 * Non-negative timeout operation result.
-                 */
-                struct WaitResult
-                {
-                    enum T
-                    {
-                        TIMEOUT = 0,
-
-                        SUCCESS = 1
-                    };
-                };
-
                 /**
                  * Constructor.
                  */
-                SocketClient();
+                TcpSocketClient();
 
                 /**
                  * Destructor.
                  */
-                ~SocketClient();
+                virtual ~TcpSocketClient();
 
                 /**
                  * Establish connection with remote TCP service.
@@ -78,14 +63,14 @@ namespace ignite
                  * @param diag Diagnostics collector.
                  * @return True on success.
                  */
-                bool Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag);
+                virtual bool Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag);
 
                 /**
                  * Close established connection.
                  *
                  * @return True on success.
                  */
-                void Close();
+                virtual void Close();
 
                 /**
                  * Send data by established connection.
@@ -96,7 +81,7 @@ namespace ignite
                  * @return Number of bytes that have been sent on success, 
                  *     WaitResult::TIMEOUT on timeout and -errno on failure.
                  */
-                int Send(const int8_t* data, size_t size, int32_t timeout);
+                virtual int Send(const int8_t* data, size_t size, int32_t timeout);
 
                 /**
                  * Receive data from established connection.
@@ -104,20 +89,35 @@ namespace ignite
                  * @param buffer Pointer to data buffer.
                  * @param size Size of the buffer in bytes.
                  * @param timeout Timeout.
-                 * @return Number of bytes that have been sent on success,
+                 * @return Number of bytes that have been received on success,
                  *     WaitResult::TIMEOUT on timeout and -errno on failure.
                  */
-                int Receive(int8_t* buffer, size_t size, int32_t timeout);
+                virtual int Receive(int8_t* buffer, size_t size, int32_t timeout);
 
                 /**
                  * Check if the socket is blocking or not.
                  * @return @c true if the socket is blocking and false otherwise.
                  */
-                bool IsBlocking() const
-                {
-                    return blocking;
-                }
+                virtual bool IsBlocking() const;
 
+                /**
+                 * Get socket error.
+                 * @return Last socket error.
+                 */
+                static int GetLastSocketError();
+
+                /**
+                 * Get socket error.
+                 * @param handle Socket handle.
+                 * @return Last socket error.
+                 */
+                static int GetLastSocketError(int handle);
+
+                /**
+                 * Check whether socket operation was interupted.
+                 * @return @c true if the socket operation was interupted.
+                 */
+                static bool IsSocketOperationInterrupted(int errorCode);
             private:
                 /**
                  * Tries set socket options.
@@ -142,7 +142,7 @@ namespace ignite
                 /** Blocking flag. */
                 bool blocking;
 
-                IGNITE_NO_COPY_ASSIGNMENT(SocketClient)
+                IGNITE_NO_COPY_ASSIGNMENT(TcpSocketClient)
             };
         }
     }
index 90286b9..b903414 100644 (file)
@@ -41,7 +41,9 @@ namespace ignite
                     {
                         enum Type
                         {
-                            CONNECTION_SETTINGS_GROUP_BOX,
+                            CONNECTION_SETTINGS_GROUP_BOX = 100,
+                            SSL_SETTINGS_GROUP_BOX,
+                            ADDITIONAL_SETTINGS_GROUP_BOX,
                             NAME_EDIT,
                             NAME_LABEL,
                             ADDRESS_EDIT,
@@ -58,11 +60,34 @@ namespace ignite
                             SKIP_REDUCER_ON_UPDATE_CHECK_BOX,
                             PROTOCOL_VERSION_LABEL,
                             PROTOCOL_VERSION_COMBO_BOX,
+                            SSL_MODE_LABEL,
+                            SSL_MODE_COMBO_BOX,
+                            SSL_KEY_FILE_LABEL,
+                            SSL_KEY_FILE_EDIT,
+                            SSL_CERT_FILE_LABEL,
+                            SSL_CERT_FILE_EDIT,
+                            SSL_CA_FILE_LABEL,
+                            SSL_CA_FILE_EDIT,
                             OK_BUTTON,
                             CANCEL_BUTTON
                         };
                     };
 
+                    // Window margin size.
+                    enum { MARGIN = 10 };
+
+                    // Standard interval between UI elements.
+                    enum { INTERVAL = 10 };
+
+                    // Standard row height.
+                    enum { ROW_HEIGHT = 20 };
+
+                    // Standard button width.
+                    enum { BUTTON_WIDTH = 80 };
+
+                    // Standard button height.
+                    enum { BUTTON_HEIGHT = 25 };
+
                 public:
                     /**
                      * Constructor.
@@ -102,6 +127,60 @@ namespace ignite
                      */
                     void RetrieveParameters(config::Configuration& cfg) const;
 
+                    /**
+                     * Retrieves current values from the connection UI group and
+                     * stores them to the specified configuration.
+                     *
+                     * @param cfg Configuration.
+                     */
+                    void RetrieveConnectionParameters(config::Configuration& cfg) const;
+
+                    /**
+                     * Retrieves current values from the SSL UI group and
+                     * stores them to the specified configuration.
+                     *
+                     * @param cfg Configuration.
+                     */
+                    void RetrieveSslParameters(config::Configuration& cfg) const;
+
+                    /**
+                     * Retrieves current values from the additional UI group and
+                     * stores them to the specified configuration.
+                     *
+                     * @param cfg Configuration.
+                     */
+                    void RetrieveAdditionalParameters(config::Configuration& cfg) const;
+
+                    /**
+                     * Create connection settings group box.
+                     *
+                     * @param posX X position.
+                     * @param posY Y position.
+                     * @param sizeX Width.
+                     * @return Size by Y.
+                     */
+                    int CreateConnectionSettingsGroup(int posX, int posY, int sizeX);
+
+                    /**
+                     * Create SSL settings group box.
+                     *
+                     * @param posX X position.
+                     * @param posY Y position.
+                     * @param sizeX Width.
+                     * @return Size by Y.
+                     */
+                    int CreateSslSettingsGroup(int posX, int posY, int sizeX);
+
+                    /**
+                     * Create additional settings group box.
+                     *
+                     * @param posX X position.
+                     * @param posY Y position.
+                     * @param sizeX Width.
+                     * @return Size by Y.
+                     */
+                    int CreateAdditionalSettingsGroup(int posX, int posY, int sizeX);
+
                     /** Window width. */
                     int width;
 
@@ -111,6 +190,12 @@ namespace ignite
                     /** Connection settings group box. */
                     std::auto_ptr<Window> connectionSettingsGroupBox;
 
+                    /** SSL settings group box. */
+                    std::auto_ptr<Window> sslSettingsGroupBox;
+
+                    /** Additional settings group box. */
+                    std::auto_ptr<Window> additionalSettingsGroupBox;
+
                     /** DSN name edit field label. */
                     std::auto_ptr<Window> nameLabel;
 
@@ -165,6 +250,30 @@ namespace ignite
                     /** Cancel button. */
                     std::auto_ptr<Window> cancelButton;
 
+                    /** SSL Mode label. */
+                    std::auto_ptr<Window> sslModeLabel;
+
+                    /** SSL Mode ComboBox. */
+                    std::auto_ptr<Window> sslModeComboBox;
+
+                    /** SSL Private Key File label. */
+                    std::auto_ptr<Window> sslKeyFileLabel;
+
+                    /** SSL Private Key File edit. */
+                    std::auto_ptr<Window> sslKeyFileEdit;
+
+                    /** SSL Certificate File label. */
+                    std::auto_ptr<Window> sslCertFileLabel;
+
+                    /** SSL Certificate File edit. */
+                    std::auto_ptr<Window> sslCertFileEdit;
+
+                    /** SSL Certificate Authority File label. */
+                    std::auto_ptr<Window> sslCaFileLabel;
+
+                    /** SSL Certificate Authority File edit. */
+                    std::auto_ptr<Window> sslCaFileEdit;
+
                     /** Configuration. */
                     config::Configuration& config;
 
@@ -176,4 +285,4 @@ namespace ignite
     }
 }
 
-#endif //_IGNITE_ODBC_SYSTEM_UI_DSN_CONFIGURATION_WINDOW
\ No newline at end of file
+#endif //_IGNITE_ODBC_SYSTEM_UI_DSN_CONFIGURATION_WINDOW
@@ -26,7 +26,7 @@
 
 #include <sstream>
 
-#include "ignite/odbc/system/socket_client.h"
+#include "ignite/odbc/system/tcp_socket_client.h"
 #include "ignite/odbc/utility.h"
 #include "ignite/odbc/log.h"
 
@@ -72,22 +72,22 @@ namespace ignite
 {
     namespace odbc
     {
-        namespace tcp
+        namespace system
         {
 
-            SocketClient::SocketClient() :
+            TcpSocketClient::TcpSocketClient() :
                 socketHandle(SOCKET_ERROR),
                 blocking(true)
             {
                 // No-op.
             }
 
-            SocketClient::~SocketClient()
+            TcpSocketClient::~TcpSocketClient()
             {
                 Close();
             }
 
-            bool SocketClient::Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag)
+            bool TcpSocketClient::Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag)
             {
                 LOG_MSG("Host: " << hostname << ", port: " << port);
 
@@ -172,7 +172,7 @@ namespace ignite
                 return socketHandle != SOCKET_ERROR;
             }
 
-            void SocketClient::Close()
+            void TcpSocketClient::Close()
             {
                 if (socketHandle != SOCKET_ERROR)
                 {
@@ -182,7 +182,7 @@ namespace ignite
                 }
             }
 
-            int SocketClient::Send(const int8_t* data, size_t size, int32_t timeout)
+            int TcpSocketClient::Send(const int8_t* data, size_t size, int32_t timeout)
             {
                 if (!blocking)
                 {
@@ -195,7 +195,7 @@ namespace ignite
                 return send(socketHandle, reinterpret_cast<const char*>(data), static_cast<int>(size), 0);
             }
 
-            int SocketClient::Receive(int8_t* buffer, size_t size, int32_t timeout)
+            int TcpSocketClient::Receive(int8_t* buffer, size_t size, int32_t timeout)
             {
                 if (!blocking)
                 {
@@ -208,7 +208,12 @@ namespace ignite
                 return recv(socketHandle, reinterpret_cast<char*>(buffer), static_cast<int>(size), 0);
             }
 
-            void SocketClient::TrySetOptions(diagnostic::Diagnosable& diag)
+            bool TcpSocketClient::IsBlocking() const
+            {
+                return blocking;
+            }
+
+            void TcpSocketClient::TrySetOptions(diagnostic::Diagnosable& diag)
             {
                 int trueOpt = 1;
                 int bufSizeOpt = BUFFER_SIZE;
@@ -310,7 +315,7 @@ namespace ignite
 
             }
 
-            int SocketClient::WaitOnSocket(int32_t timeout, bool rd)
+            int TcpSocketClient::WaitOnSocket(int32_t timeout, bool rd)
             {
                 int ready = 0;
                 int lastError = 0;
@@ -336,9 +341,9 @@ namespace ignite
                         readFds, writeFds, NULL, (timeout == 0 ? NULL : &tv));
 
                     if (ready == SOCKET_ERROR)
-                        lastError = errno;
+                        lastError = GetLastSocketError();
 
-                } while (ready == SOCKET_ERROR && lastError == EINTR);
+                } while (ready == SOCKET_ERROR && IsSocketOperationInterrupted(lastError));
 
                 if (ready == SOCKET_ERROR)
                     return -lastError;
@@ -354,6 +359,25 @@ namespace ignite
 
                 return WaitResult::SUCCESS;
             }
+
+            int TcpSocketClient::GetLastSocketError()
+            {
+                return errno;
+            }
+
+            int TcpSocketClient::GetLastSocketError(int handle)
+            {
+                int lastError = 0;
+                socklen_t size = sizeof(lastError);
+                int res = getsockopt(handle, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&lastError), &size);
+
+                return res == SOCKET_ERROR ? 0 : lastError;
+            }
+
+            bool TcpSocketClient::IsSocketOperationInterrupted(int errorCode)
+            {
+                return errorCode == EINTR;
+            }
         }
     }
 }
@@ -27,7 +27,8 @@
 
 #include <sstream>
 
-#include "ignite/odbc/system/socket_client.h"
+#include "ignite/common/concurrent.h"
+#include "ignite/odbc/system/tcp_socket_client.h"
 #include "ignite/odbc/utility.h"
 #include "ignite/odbc/log.h"
 
@@ -94,39 +95,44 @@ namespace ignite
 {
     namespace odbc
     {
-        namespace tcp
+        namespace system
         {
 
-            SocketClient::SocketClient() :
+            TcpSocketClient::TcpSocketClient() :
                 socketHandle(INVALID_SOCKET),
                 blocking(true)
             {
                 // No-op.
             }
 
-            SocketClient::~SocketClient()
+            TcpSocketClient::~TcpSocketClient()
             {
                 Close();
             }
 
-            bool SocketClient::Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag)
+            bool TcpSocketClient::Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag)
             {
+                static common::concurrent::CriticalSection initCs;
                 static bool networkInited = false;
 
                 // Initing networking if is not inited.
                 if (!networkInited)
                 {
-                    WSADATA wsaData;
-
-                    networkInited = (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0);
-
+                    common::concurrent::CsLockGuard lock(initCs);
                     if (!networkInited)
                     {
-                        LOG_MSG("Networking initialisation failed: " << GetLastSocketErrorMessage());
+                        WSADATA wsaData;
 
-                        diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not initialize Windows networking.");
+                        networkInited = (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0);
 
-                        return false;
+                        if (!networkInited)
+                        {
+                            LOG_MSG("Networking initialisation failed: " << GetLastSocketErrorMessage());
+
+                            diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not initialize Windows networking.");
+
+                            return false;
+                        }
                     }
                 }
 
@@ -213,7 +219,7 @@ namespace ignite
                 return socketHandle != INVALID_SOCKET;
             }
 
-            void SocketClient::Close()
+            void TcpSocketClient::Close()
             {
                 if (socketHandle != INVALID_SOCKET)
                 {
@@ -223,7 +229,7 @@ namespace ignite
                 }
             }
 
-            int SocketClient::Send(const int8_t* data, size_t size, int32_t timeout)
+            int TcpSocketClient::Send(const int8_t* data, size_t size, int32_t timeout)
             {
                 if (!blocking)
                 {
@@ -236,7 +242,7 @@ namespace ignite
                 return send(socketHandle, reinterpret_cast<const char*>(data), static_cast<int>(size), 0);
             }
 
-            int SocketClient::Receive(int8_t* buffer, size_t size, int32_t timeout)
+            int TcpSocketClient::Receive(int8_t* buffer, size_t size, int32_t timeout)
             {
                 if (!blocking)
                 {
@@ -249,7 +255,12 @@ namespace ignite
                 return recv(socketHandle, reinterpret_cast<char*>(buffer), static_cast<int>(size), 0);
             }
 
-            void SocketClient::TrySetOptions(diagnostic::Diagnosable& diag)
+            bool TcpSocketClient::IsBlocking() const
+            {
+                return blocking;
+            }
+
+            void TcpSocketClient::TrySetOptions(diagnostic::Diagnosable& diag)
             {
                 BOOL trueOpt = TRUE;
                 ULONG uTrueOpt = TRUE;
@@ -388,7 +399,7 @@ namespace ignite
 #endif
             }
 
-            int SocketClient::WaitOnSocket(int32_t timeout, bool rd)
+            int TcpSocketClient::WaitOnSocket(int32_t timeout, bool rd)
             {
                 int ready = 0;
                 int lastError = 0;
@@ -414,9 +425,9 @@ namespace ignite
                         readFds, writeFds, NULL, (timeout == 0 ? NULL : &tv));
 
                     if (ready == SOCKET_ERROR)
-                        lastError = WSAGetLastError();
+                        lastError = GetLastSocketError();
 
-                } while (ready == SOCKET_ERROR && lastError == WSAEINTR);
+                } while (ready == SOCKET_ERROR && IsSocketOperationInterrupted(lastError));
 
                 if (ready == SOCKET_ERROR)
                     return -lastError;
@@ -426,6 +437,25 @@ namespace ignite
 
                 return WaitResult::SUCCESS;
             }
+
+            int TcpSocketClient::GetLastSocketError()
+            {
+                return WSAGetLastError();
+            }
+
+            int TcpSocketClient::GetLastSocketError(int handle)
+            {
+                int lastError = 0;
+                socklen_t size = sizeof(lastError);
+                int res = getsockopt(handle, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&lastError), &size);
+
+                return res == SOCKET_ERROR ? 0 : lastError;
+            }
+
+            bool TcpSocketClient::IsSocketOperationInterrupted(int errorCode)
+            {
+                return errorCode == WSAEINTR;
+            }
         }
     }
 }
index d5aa0db..0e742be 100644 (file)
  */
 
 #include <Windowsx.h>
+#include <Shlwapi.h>
 
 #include "ignite/odbc/log.h"
+#include "ignite/odbc/ssl/ssl_mode.h"
 
 #include "ignite/odbc/system/ui/dsn_configuration_window.h"
 
@@ -32,7 +34,7 @@ namespace ignite
                 DsnConfigurationWindow::DsnConfigurationWindow(Window* parent, config::Configuration& config):
                     CustomWindow(parent, "IgniteConfigureDsn", "Configure Apache Ignite DSN"),
                     width(360),
-                    height(300),
+                    height(480),
                     connectionSettingsGroupBox(),
                     nameLabel(),
                     nameEdit(),
@@ -89,53 +91,56 @@ namespace ignite
 
                 void DsnConfigurationWindow::OnCreate()
                 {
-                    int margin = 10;
-                    int interval = 10;
+                    int groupPosY = MARGIN;
+                    int groupSizeY = width - 2 * MARGIN;
 
-                    int labelSizeX = 80;
-                    int labelPosX = margin + interval;
+                    groupPosY += INTERVAL + CreateConnectionSettingsGroup(MARGIN, groupPosY, groupSizeY);
+                    groupPosY += INTERVAL + CreateSslSettingsGroup(MARGIN, groupPosY, groupSizeY);
+                    groupPosY += INTERVAL + CreateAdditionalSettingsGroup(MARGIN, groupPosY, groupSizeY);
 
-                    int editSizeX = width - labelSizeX - 2 * margin - 3 * interval;
-                    int editPosX = margin + labelSizeX + 2 * interval;
+                    int cancelPosX = width - MARGIN - BUTTON_WIDTH;
+                    int okPosX = cancelPosX - INTERVAL - BUTTON_WIDTH;
 
-                    int rowSize = 20;
-                    int rowPos = margin + 2 * interval;
+                    okButton = CreateButton(okPosX, groupPosY, BUTTON_WIDTH, BUTTON_HEIGHT, "Ok", ChildId::OK_BUTTON);
+                    cancelButton = CreateButton(cancelPosX, groupPosY, BUTTON_WIDTH, BUTTON_HEIGHT,
+                        "Cancel", ChildId::CANCEL_BUTTON);
+                }
+
+                int DsnConfigurationWindow::CreateConnectionSettingsGroup(int posX, int posY, int sizeX)
+                {
+                    enum { LABEL_WIDTH = 100 };
+
+                    int labelPosX = posX + INTERVAL;
 
-                    int checkBoxSize = (editSizeX - interval) / 2;
+                    int editSizeX = sizeX - LABEL_WIDTH - 3 * INTERVAL;
+                    int editPosX = labelPosX + LABEL_WIDTH + INTERVAL;
 
-                    int sectionBegin = margin;
+                    int rowPos = posY + 2 * INTERVAL;
 
                     const char* val = config.GetDsn().c_str();
-                    nameLabel = CreateLabel(labelPosX, rowPos, labelSizeX, rowSize, "DSN name:", ChildId::NAME_LABEL);
-                    nameEdit = CreateEdit(editPosX, rowPos, editSizeX, rowSize, val, ChildId::NAME_EDIT);
+                    nameLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT,
+                        "Data Source Name:", ChildId::NAME_LABEL);
+                    nameEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::NAME_EDIT);
 
-                    rowPos += interval + rowSize;
+                    rowPos += INTERVAL + ROW_HEIGHT;
 
                     val = config.GetAddress().c_str();
-                    addressLabel = CreateLabel(labelPosX, rowPos, labelSizeX, rowSize, "Address:", ChildId::ADDRESS_LABEL);
-                    addressEdit = CreateEdit(editPosX, rowPos, editSizeX, rowSize, val, ChildId::ADDRESS_EDIT);
+                    addressLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT,
+                        "Address:", ChildId::ADDRESS_LABEL);
+                    addressEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::ADDRESS_EDIT);
 
-                    rowPos += interval + rowSize;
+                    rowPos += INTERVAL + ROW_HEIGHT;
 
                     val = config.GetSchema().c_str();
-                    schemaLabel = CreateLabel(labelPosX, rowPos, labelSizeX, rowSize, "Schema name:", ChildId::SCHEMA_LABEL);
-                    schemaEdit = CreateEdit(editPosX, rowPos, editSizeX, rowSize, val, ChildId::SCHEMA_EDIT);
-
-                    rowPos += interval + rowSize;
-
-                    std::string tmp = common::LexicalCast<std::string>(config.GetPageSize());
-                    val = tmp.c_str();
-                    pageSizeLabel = CreateLabel(labelPosX, rowPos, labelSizeX,
-                        rowSize, "Page size:", ChildId::PAGE_SIZE_LABEL);
+                    schemaLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT,
+                        "Schema name:", ChildId::SCHEMA_LABEL);
+                    schemaEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::SCHEMA_EDIT);
 
-                    pageSizeEdit = CreateEdit(editPosX, rowPos, editSizeX, 
-                        rowSize, val, ChildId::PAGE_SIZE_EDIT, ES_NUMBER);
+                    rowPos += INTERVAL + ROW_HEIGHT;
 
-                    rowPos += interval + rowSize;
-
-                    protocolVersionLabel = CreateLabel(labelPosX, rowPos, labelSizeX, rowSize,
+                    protocolVersionLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT,
                         "Protocol version:", ChildId::PROTOCOL_VERSION_LABEL);
-                    protocolVersionComboBox = CreateComboBox(editPosX, rowPos, editSizeX, rowSize,
+                    protocolVersionComboBox = CreateComboBox(editPosX, rowPos, editSizeX, ROW_HEIGHT,
                         "Protocol version", ChildId::PROTOCOL_VERSION_COMBO_BOX);
 
                     int id = 0;
@@ -157,48 +162,132 @@ namespace ignite
                         ++id;
                     }
 
-                    rowPos += interval + rowSize;
+                    rowPos += INTERVAL + ROW_HEIGHT;
+
+                    connectionSettingsGroupBox = CreateGroupBox(posX, posY, sizeX, rowPos - posY,
+                        "Connection settings", ChildId::CONNECTION_SETTINGS_GROUP_BOX);
+
+                    return rowPos - posY;
+                }
+
+                int DsnConfigurationWindow::CreateSslSettingsGroup(int posX, int posY, int sizeX)
+                {
+                    using ssl::SslMode;
+
+                    enum { LABEL_WIDTH = 120 };
+
+                    int labelPosX = posX + INTERVAL;
+
+                    int editSizeX = sizeX - LABEL_WIDTH - 3 * INTERVAL;
+                    int editPosX = labelPosX + LABEL_WIDTH + INTERVAL;
+
+                    int rowPos = posY + 2 * INTERVAL;
+
+                    const char* val = config.GetSslMode().c_str();
+                    SslMode::T sslMode = SslMode::FromString(val, SslMode::DISABLE);
+
+                    sslModeLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, "SSL Mode:", ChildId::SSL_MODE_LABEL);
+                    sslModeComboBox = CreateComboBox(editPosX, rowPos, editSizeX, ROW_HEIGHT, "", ChildId::SSL_MODE_COMBO_BOX);
+
+                    sslModeComboBox->AddString("disable");
+                    sslModeComboBox->AddString("require");
+
+                    sslModeComboBox->SetSelection(sslMode);
+
+                    rowPos += INTERVAL + ROW_HEIGHT;
+
+                    val = config.GetSslKeyFile().c_str();
+                    sslKeyFileLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, "SSL Private Key:", ChildId::SSL_KEY_FILE_LABEL);
+                    sslKeyFileEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::SSL_KEY_FILE_EDIT);
+
+                    SHAutoComplete(sslKeyFileEdit->GetHandle(), SHACF_DEFAULT);
+
+                    rowPos += INTERVAL + ROW_HEIGHT;
+
+                    val = config.GetSslCertFile().c_str();
+                    sslCertFileLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, "SSL Certificate:", ChildId::SSL_CERT_FILE_LABEL);
+                    sslCertFileEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::SSL_CERT_FILE_EDIT);
+
+                    SHAutoComplete(sslCertFileEdit->GetHandle(), SHACF_DEFAULT);
 
-                    distributedJoinsCheckBox = CreateCheckBox(editPosX, rowPos, checkBoxSize, rowSize,
+                    rowPos += INTERVAL + ROW_HEIGHT;
+
+                    val = config.GetSslCaFile().c_str();
+                    sslCaFileLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, "SSL Certificate Authority:", ChildId::SSL_CA_FILE_LABEL);
+                    sslCaFileEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::SSL_CA_FILE_EDIT);
+
+                    SHAutoComplete(sslCaFileEdit->GetHandle(), SHACF_DEFAULT);
+
+                    rowPos += INTERVAL + ROW_HEIGHT;
+
+                    sslSettingsGroupBox = CreateGroupBox(posX, posY, sizeX, rowPos - posY,
+                        "SSL settings", ChildId::SSL_SETTINGS_GROUP_BOX);
+
+                    sslKeyFileEdit->SetEnabled(sslMode != SslMode::DISABLE);
+                    sslCertFileEdit->SetEnabled(sslMode != SslMode::DISABLE);
+                    sslCaFileEdit->SetEnabled(sslMode != SslMode::DISABLE);
+
+                    return rowPos - posY;
+                }
+
+                int DsnConfigurationWindow::CreateAdditionalSettingsGroup(int posX, int posY, int sizeX)
+                {
+                    enum { LABEL_WIDTH = 80 };
+
+                    int labelPosX = posX + INTERVAL;
+
+                    int editSizeX = sizeX - LABEL_WIDTH - 3 * INTERVAL;
+                    int editPosX = labelPosX + LABEL_WIDTH + INTERVAL;
+
+                    int checkBoxSize = (sizeX - 3 * INTERVAL) / 2;
+
+                    const ProtocolVersion version = config.GetProtocolVersion();
+
+                    int rowPos = posY + 2 * INTERVAL;
+
+                    std::string tmp = common::LexicalCast<std::string>(config.GetPageSize());
+                    const char* val = tmp.c_str();
+                    pageSizeLabel = CreateLabel(labelPosX, rowPos, LABEL_WIDTH,
+                        ROW_HEIGHT, "Page size:", ChildId::PAGE_SIZE_LABEL);
+
+                    pageSizeEdit = CreateEdit(editPosX, rowPos, editSizeX,
+                        ROW_HEIGHT, val, ChildId::PAGE_SIZE_EDIT, ES_NUMBER);
+
+                    rowPos += INTERVAL + ROW_HEIGHT;
+
+                    distributedJoinsCheckBox = CreateCheckBox(labelPosX, rowPos, checkBoxSize, ROW_HEIGHT,
                         "Distributed Joins", ChildId::DISTRIBUTED_JOINS_CHECK_BOX, config.IsDistributedJoins());
 
-                    enforceJoinOrderCheckBox = CreateCheckBox(editPosX + checkBoxSize + interval, rowPos, checkBoxSize,
-                        rowSize, "Enforce Join Order", ChildId::ENFORCE_JOIN_ORDER_CHECK_BOX, config.IsEnforceJoinOrder());
+                    enforceJoinOrderCheckBox = CreateCheckBox(labelPosX + checkBoxSize + INTERVAL, rowPos, checkBoxSize,
+                        ROW_HEIGHT, "Enforce Join Order", ChildId::ENFORCE_JOIN_ORDER_CHECK_BOX, config.IsEnforceJoinOrder());
 
-                    rowPos += rowSize;
+                    rowPos += ROW_HEIGHT;
 
-                    replicatedOnlyCheckBox = CreateCheckBox(editPosX, rowPos, checkBoxSize, rowSize,
+                    replicatedOnlyCheckBox = CreateCheckBox(labelPosX, rowPos, checkBoxSize, ROW_HEIGHT,
                         "Replicated Only", ChildId::REPLICATED_ONLY_CHECK_BOX, config.IsReplicatedOnly());
 
-                    collocatedCheckBox = CreateCheckBox(editPosX + checkBoxSize + interval, rowPos, checkBoxSize,
-                        rowSize, "Collocated", ChildId::COLLOCATED_CHECK_BOX, config.IsCollocated());
+                    collocatedCheckBox = CreateCheckBox(labelPosX + checkBoxSize + INTERVAL, rowPos, checkBoxSize,
+                        ROW_HEIGHT, "Collocated", ChildId::COLLOCATED_CHECK_BOX, config.IsCollocated());
 
-                    rowPos += rowSize;
+                    rowPos += ROW_HEIGHT;
 
-                    lazyCheckBox = CreateCheckBox(editPosX, rowPos, checkBoxSize, rowSize,
+                    lazyCheckBox = CreateCheckBox(labelPosX, rowPos, checkBoxSize, ROW_HEIGHT,
                         "Lazy", ChildId::LAZY_CHECK_BOX, config.IsLazy());
 
                     lazyCheckBox->SetEnabled(version >= ProtocolVersion::VERSION_2_1_5);
 
-                    skipReducerOnUpdateCheckBox = CreateCheckBox(editPosX + checkBoxSize + interval, rowPos,
-                        checkBoxSize, rowSize, "Skip reducer on update", ChildId::SKIP_REDUCER_ON_UPDATE_CHECK_BOX,
+                    skipReducerOnUpdateCheckBox = CreateCheckBox(labelPosX + checkBoxSize + INTERVAL, rowPos,
+                        checkBoxSize, ROW_HEIGHT, "Skip reducer on update", ChildId::SKIP_REDUCER_ON_UPDATE_CHECK_BOX,
                         config.IsSkipReducerOnUpdate());
 
                     skipReducerOnUpdateCheckBox->SetEnabled(version >= ProtocolVersion::VERSION_2_3_0);
 
-                    rowPos += interval * 2 + rowSize;
-
-                    connectionSettingsGroupBox = CreateGroupBox(margin, sectionBegin, width - 2 * margin,
-                        rowPos - interval - sectionBegin, "Connection settings", ChildId::CONNECTION_SETTINGS_GROUP_BOX);
+                    rowPos += ROW_HEIGHT + INTERVAL;
 
-                    int buttonSizeX = 80;
-                    int cancelPosX = width - margin - buttonSizeX;
-                    int okPosX = cancelPosX - interval - buttonSizeX;
+                    additionalSettingsGroupBox = CreateGroupBox(posX, posY, sizeX, rowPos - posY,
+                        "Additional settings", ChildId::ADDITIONAL_SETTINGS_GROUP_BOX);
 
-                    rowSize = 25;
-
-                    okButton = CreateButton(okPosX, rowPos, buttonSizeX, rowSize, "Ok", ChildId::OK_BUTTON);
-                    cancelButton = CreateButton(cancelPosX, rowPos, buttonSizeX, rowSize, "Cancel", ChildId::CANCEL_BUTTON);
+                    return rowPos - posY;
                 }
 
                 bool DsnConfigurationWindow::OnMessage(UINT msg, WPARAM wParam, LPARAM lParam)
@@ -289,6 +378,22 @@ namespace ignite
                                     break;
                                 }
 
+                                case ChildId::SSL_MODE_COMBO_BOX:
+                                {
+                                    using ssl::SslMode;
+
+                                    std::string sslModeStr;
+                                    sslModeComboBox->GetText(sslModeStr);
+
+                                    SslMode::T sslMode = SslMode::FromString(sslModeStr, SslMode::DISABLE);
+
+                                    sslKeyFileEdit->SetEnabled(sslMode != SslMode::DISABLE);
+                                    sslCertFileEdit->SetEnabled(sslMode != SslMode::DISABLE);
+                                    sslCaFileEdit->SetEnabled(sslMode != SslMode::DISABLE);
+
+                                    break;
+                                }
+
                                 default:
                                     return false;
                             }
@@ -312,54 +417,32 @@ namespace ignite
 
                 void DsnConfigurationWindow::RetrieveParameters(config::Configuration& cfg) const
                 {
+                    RetrieveConnectionParameters(cfg);
+                    RetrieveSslParameters(cfg);
+                    RetrieveAdditionalParameters(cfg);
+                }
+
+                void DsnConfigurationWindow::RetrieveConnectionParameters(config::Configuration& cfg) const
+                {
                     std::string dsn;
                     std::string address;
                     std::string schema;
-                    std::string pageSizeStr;
                     std::string version;
 
-                    bool distributedJoins;
-                    bool enforceJoinOrder;
-                    bool replicatedOnly;
-                    bool collocated;
-                    bool lazy;
-                    bool skipReducerOnUpdate;
-
                     nameEdit->GetText(dsn);
                     addressEdit->GetText(address);
                     schemaEdit->GetText(schema);
                     protocolVersionComboBox->GetText(version);
-                    pageSizeEdit->GetText(pageSizeStr);
-
-                    int32_t pageSize = common::LexicalCast<int32_t>(pageSizeStr);
-
-                    if (pageSize <= 0)
-                        pageSize = config.GetPageSize();
 
                     common::StripSurroundingWhitespaces(address);
                     common::StripSurroundingWhitespaces(dsn);
-
-                    distributedJoins = distributedJoinsCheckBox->IsEnabled() && distributedJoinsCheckBox->IsChecked();
-                    enforceJoinOrder = enforceJoinOrderCheckBox->IsEnabled() && enforceJoinOrderCheckBox->IsChecked();
-                    replicatedOnly = replicatedOnlyCheckBox->IsEnabled() && replicatedOnlyCheckBox->IsChecked();
-                    collocated = collocatedCheckBox->IsEnabled() && collocatedCheckBox->IsChecked();
-                    lazy = lazyCheckBox->IsEnabled() && lazyCheckBox->IsChecked();
-
-                    skipReducerOnUpdate =
-                        skipReducerOnUpdateCheckBox->IsEnabled() && skipReducerOnUpdateCheckBox->IsChecked();
+                    // Stripping of whitespaces off the schema skipped intentionally
 
                     LOG_MSG("Retriving arguments:");
                     LOG_MSG("DSN:                " << dsn);
                     LOG_MSG("Address:            " << address);
                     LOG_MSG("Schema:             " << schema);
-                    LOG_MSG("Page size:          " << pageSize);
                     LOG_MSG("Protocol version:   " << version);
-                    LOG_MSG("Distributed Joins:  " << (distributedJoins ? "true" : "false"));
-                    LOG_MSG("Enforce Join Order: " << (enforceJoinOrder ? "true" : "false"));
-                    LOG_MSG("Replicated only:    " << (replicatedOnly ? "true" : "false"));
-                    LOG_MSG("Collocated:         " << (collocated ? "true" : "false"));
-                    LOG_MSG("Lazy:               " << (lazy ? "true" : "false"));
-                    LOG_MSG("Skip reducer on update:   " << (skipReducerOnUpdate ? "true" : "false"));
 
                     if (dsn.empty())
                         throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "DSN name can not be empty.");
@@ -367,8 +450,68 @@ namespace ignite
                     cfg.SetDsn(dsn);
                     cfg.SetAddress(address);
                     cfg.SetSchema(schema);
-                    cfg.SetPageSize(pageSize);
                     cfg.SetProtocolVersion(version);
+                }
+
+                void DsnConfigurationWindow::RetrieveSslParameters(config::Configuration& cfg) const
+                {
+                    std::string sslMode;
+                    std::string sslKey;
+                    std::string sslCert;
+                    std::string sslCa;
+
+                    sslModeComboBox->GetText(sslMode);
+                    sslKeyFileEdit->GetText(sslKey);
+                    sslCertFileEdit->GetText(sslCert);
+                    sslCaFileEdit->GetText(sslCa);
+
+                    LOG_MSG("Retriving arguments:");
+                    LOG_MSG("SSL Mode:           " << sslMode);
+                    LOG_MSG("SSL Key:            " << sslKey);
+                    LOG_MSG("SSL Certificate:    " << sslCert);
+                    LOG_MSG("SSL CA:             " << sslCa);
+
+                    cfg.SetSslMode(sslMode);
+                    cfg.SetSslKeyFile(sslKey);
+                    cfg.SetSslCertFile(sslCert);
+                    cfg.SetSslCaFile(sslCa);
+                }
+
+                void DsnConfigurationWindow::RetrieveAdditionalParameters(config::Configuration& cfg) const
+                {
+                    std::string pageSizeStr;
+
+                    bool distributedJoins;
+                    bool enforceJoinOrder;
+                    bool replicatedOnly;
+                    bool collocated;
+                    bool lazy;
+                    bool skipReducerOnUpdate;
+
+                    pageSizeEdit->GetText(pageSizeStr);
+
+                    int32_t pageSize = common::LexicalCast<int32_t>(pageSizeStr);
+
+                    if (pageSize <= 0)
+                        pageSize = config.GetPageSize();
+
+                    distributedJoins = distributedJoinsCheckBox->IsChecked();
+                    enforceJoinOrder = enforceJoinOrderCheckBox->IsChecked();
+                    replicatedOnly = replicatedOnlyCheckBox->IsChecked();
+                    collocated = collocatedCheckBox->IsChecked();
+                    lazy = lazyCheckBox->IsChecked();
+                    skipReducerOnUpdate = skipReducerOnUpdateCheckBox->IsChecked();
+
+                    LOG_MSG("Retriving arguments:");
+                    LOG_MSG("Page size:                 " << pageSize);
+                    LOG_MSG("Distributed Joins:         " << (distributedJoins ? "true" : "false"));
+                    LOG_MSG("Enforce Join Order:        " << (enforceJoinOrder ? "true" : "false"));
+                    LOG_MSG("Replicated only:           " << (replicatedOnly ? "true" : "false"));
+                    LOG_MSG("Collocated:                " << (collocated ? "true" : "false"));
+                    LOG_MSG("Lazy:                      " << (lazy ? "true" : "false"));
+                    LOG_MSG("Skip reducer on update:    " << (skipReducerOnUpdate ? "true" : "false"));
+
+                    cfg.SetPageSize(pageSize);
                     cfg.SetDistributedJoins(distributedJoins);
                     cfg.SetEnforceJoinOrder(enforceJoinOrder);
                     cfg.SetReplicatedOnly(replicatedOnly);
index aca23eb..8f2340a 100644 (file)
@@ -130,6 +130,13 @@ namespace ignite
 
                 void Window::GetText(std::string& text) const
                 {
+                    if (!IsEnabled())
+                    {
+                        text.clear();
+
+                        return;
+                    }
+
                     int len = GetWindowTextLength(handle);
 
                     if (len <= 0)
@@ -154,7 +161,7 @@ namespace ignite
 
                 bool Window::IsChecked() const
                 {
-                    return Button_GetCheck(handle) == BST_CHECKED;
+                    return IsEnabled() && Button_GetCheck(handle) == BST_CHECKED;
                 }
 
                 void Window::SetChecked(bool state)
index c5783ff..239a30f 100644 (file)
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <SDLCheck>false</SDLCheck>
-      <AdditionalIncludeDirectories>$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win\include;$(ProjectDir)\..\..\src</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(OPENSSL_HOME)\include;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win\include;$(ProjectDir)\..\..\src</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;IGNITE_IMPL;IGNITE_FRIEND;TARGET_MODULE_FULL_NAME="$(TargetFileName)";_DEBUG;ODBC_DEBUG;ODBC_LOG_PATH="D:\\odbc.log";%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <ModuleDefinitionFile>module.def</ModuleDefinitionFile>
-      <AdditionalDependencies>Ws2_32.lib;Mswsock.lib;Advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>Ws2_32.lib;Mswsock.lib;Advapi32.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>$(OPENSSL_HOME)\lib\VC</AdditionalLibraryDirectories>
+      <DelayLoadDLLs>
+      </DelayLoadDLLs>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <SDLCheck>false</SDLCheck>
-      <AdditionalIncludeDirectories>$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win\include;$(ProjectDir)\..\..\src</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(OPENSSL_HOME)\include;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win\include;$(ProjectDir)\..\..\src</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;IGNITE_IMPL;IGNITE_FRIEND;TARGET_MODULE_FULL_NAME="$(TargetFileName)";_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <ModuleDefinitionFile>module.def</ModuleDefinitionFile>
-      <AdditionalDependencies>Ws2_32.lib;Mswsock.lib;Advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>Ws2_32.lib;Mswsock.lib;Advapi32.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>$(OPENSSL_HOME)\lib\VC</AdditionalLibraryDirectories>
+      <DelayLoadDLLs>
+      </DelayLoadDLLs>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <AdditionalIncludeDirectories>$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win\include;$(ProjectDir)\..\..\src</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(OPENSSL_HOME)\include;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win\include;$(ProjectDir)\..\..\src</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;IGNITE_IMPL;IGNITE_FRIEND;TARGET_MODULE_FULL_NAME="$(TargetFileName)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <BufferSecurityCheck>false</BufferSecurityCheck>
     </ClCompile>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <ModuleDefinitionFile>module.def</ModuleDefinitionFile>
-      <AdditionalDependencies>Ws2_32.lib;Mswsock.lib;Advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>Ws2_32.lib;Mswsock.lib;Advapi32.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>$(OPENSSL_HOME)\lib\VC</AdditionalLibraryDirectories>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <AdditionalIncludeDirectories>$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win\include;$(ProjectDir)\..\..\src</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(OPENSSL_HOME)\include;$(ProjectDir)\..\..\..\common\include;$(ProjectDir)\..\..\..\common\os\win\include;$(ProjectDir)\..\..\..\binary\include;$(ProjectDir)\..\..\..\binary\os\win\include;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\os\win\include;$(ProjectDir)\..\..\src</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;IGNITE_IMPL;IGNITE_FRIEND;TARGET_MODULE_FULL_NAME="$(TargetFileName)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <BufferSecurityCheck>false</BufferSecurityCheck>
     </ClCompile>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <ModuleDefinitionFile>module.def</ModuleDefinitionFile>
-      <AdditionalDependencies>Ws2_32.lib;Mswsock.lib;Advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>Ws2_32.lib;Mswsock.lib;Advapi32.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>$(OPENSSL_HOME)\lib\VC</AdditionalLibraryDirectories>
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClCompile Include="..\..\os\win\src\system_dsn.cpp" />
-    <ClCompile Include="..\..\os\win\src\system\socket_client.cpp" />
+    <ClCompile Include="..\..\os\win\src\system\tcp_socket_client.cpp" />
     <ClCompile Include="..\..\os\win\src\system\ui\custom_window.cpp" />
     <ClCompile Include="..\..\os\win\src\system\ui\dsn_configuration_window.cpp" />
     <ClCompile Include="..\..\os\win\src\system\ui\window.cpp" />
     <ClCompile Include="..\..\src\query\type_info_query.cpp" />
     <ClCompile Include="..\..\src\result_page.cpp" />
     <ClCompile Include="..\..\src\row.cpp" />
+    <ClCompile Include="..\..\src\ssl\secure_socket_client.cpp" />
+    <ClCompile Include="..\..\src\ssl\ssl_gateway.cpp" />
+    <ClCompile Include="..\..\src\ssl\ssl_mode.cpp" />
     <ClCompile Include="..\..\src\statement.cpp" />
     <ClCompile Include="..\..\src\type_traits.cpp" />
     <ClCompile Include="..\..\src\utility.cpp" />
     <ClInclude Include="..\..\include\ignite\odbc\query\type_info_query.h" />
     <ClInclude Include="..\..\include\ignite\odbc\result_page.h" />
     <ClInclude Include="..\..\include\ignite\odbc\row.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\socket_client.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\ssl\secure_socket_client.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\ssl\ssl_bindings.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\ssl\ssl_gateway.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\ssl\ssl_mode.h" />
     <ClInclude Include="..\..\include\ignite\odbc\statement.h" />
     <ClInclude Include="..\..\include\ignite\odbc\system\odbc_constants.h" />
-    <ClInclude Include="..\..\include\ignite\odbc\system\socket_client.h" />
+    <ClInclude Include="..\..\include\ignite\odbc\system\tcp_socket_client.h" />
     <ClInclude Include="..\..\include\ignite\odbc\system\ui\dsn_configuration_window.h" />
     <ClInclude Include="..\..\include\ignite\odbc\type_traits.h" />
     <ClInclude Include="..\..\include\ignite\odbc\utility.h" />
index 8934625..b203b21 100644 (file)
@@ -29,6 +29,9 @@
     <Filter Include="Code\system\ui">
       <UniqueIdentifier>{ff144e89-0a10-42c3-97dd-d22bfdbc7abb}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Code\ssl">
+      <UniqueIdentifier>{857734a3-6b29-412a-b75e-7fcc9d3fef8c}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\odbc.cpp">
     <ClCompile Include="..\..\src\diagnostic\diagnosable_adapter.cpp">
       <Filter>Code\diagnostic</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\os\win\src\system\socket_client.cpp">
-      <Filter>Code\system</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\query\type_info_query.cpp">
       <Filter>Code\query</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\message.cpp">
       <Filter>Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\ssl\secure_socket_client.cpp">
+      <Filter>Code\ssl</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\os\win\src\system\tcp_socket_client.cpp">
+      <Filter>Code\system</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\ssl\ssl_mode.cpp">
+      <Filter>Code\ssl</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\ssl\ssl_gateway.cpp">
+      <Filter>Code\ssl</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="module.def">
     <ClInclude Include="..\..\include\ignite\odbc\system\odbc_constants.h">
       <Filter>Code\system</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\include\ignite\odbc\system\socket_client.h">
-      <Filter>Code\system</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\include\ignite\odbc\query\type_info_query.h">
       <Filter>Code\query</Filter>
     </ClInclude>
     <ClInclude Include="..\..\include\ignite\odbc\odbc_error.h">
       <Filter>Code</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\ssl\secure_socket_client.h">
+      <Filter>Code\ssl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\socket_client.h">
+      <Filter>Code</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\system\tcp_socket_client.h">
+      <Filter>Code\system</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\ssl\ssl_mode.h">
+      <Filter>Code\ssl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\ssl\ssl_gateway.h">
+      <Filter>Code\ssl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\ignite\odbc\ssl\ssl_bindings.h">
+      <Filter>Code\ssl</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file
index be5a781..769e167 100644 (file)
@@ -46,12 +46,20 @@ namespace ignite
             const std::string Configuration::Key::collocated             = "collocated";
             const std::string Configuration::Key::lazy                   = "lazy";
             const std::string Configuration::Key::skipReducerOnUpdate    = "skip_reducer_on_update";
+            const std::string Configuration::Key::sslMode                = "ssl_mode";
+            const std::string Configuration::Key::sslKeyFile             = "ssl_key_file";
+            const std::string Configuration::Key::sslCertFile            = "ssl_cert_file";
+            const std::string Configuration::Key::sslCaFile              = "ssl_ca_file";
 
             const std::string Configuration::DefaultValue::dsn           = "Apache Ignite DSN";
             const std::string Configuration::DefaultValue::driver        = "Apache Ignite";
             const std::string Configuration::DefaultValue::schema        = "PUBLIC";
             const std::string Configuration::DefaultValue::address       = "";
             const std::string Configuration::DefaultValue::server        = "";
+            const std::string Configuration::DefaultValue::sslMode       = "disable";
+            const std::string Configuration::DefaultValue::sslKeyFile    = "";
+            const std::string Configuration::DefaultValue::sslCertFile   = "";
+            const std::string Configuration::DefaultValue::sslCaFile     = "";
 
             const uint16_t Configuration::DefaultValue::port    = 10800;
             const int32_t Configuration::DefaultValue::pageSize = 1024;
index 4e8f4ab..11105b6 100644 (file)
 #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;
 
index 536f679..845c8bd 100644 (file)
@@ -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
index 1480d0b..e4b47b9 100644 (file)
@@ -180,7 +180,7 @@ namespace ignite
     {
         using odbc::Environment;
 
-        LOG_MSG("SQLFreeEnv called");
+        LOG_MSG("SQLFreeEnv called: " << env);
 
         Environment *environment = reinterpret_cast<Environment*>(env);
 
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 (file)
index 0000000..c305b87
--- /dev/null
@@ -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;
+            }
+        }
+    }
+}
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 (file)
index 0000000..c91d44e
--- /dev/null
@@ -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;
+            }
+        }
+    }
+}
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 (file)
index 0000000..0bdbc60
--- /dev/null
@@ -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;
+            }
+        }
+    }
+}