http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc-test/src/queries_ssl_test.cpp ---------------------------------------------------------------------- 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 index 0000000..897544e --- /dev/null +++ b/modules/platforms/cpp/odbc-test/src/queries_ssl_test.cpp @@ -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()
http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc-test/src/queries_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/queries_test.cpp b/modules/platforms/cpp/odbc-test/src/queries_test.cpp index bf9876a..639e16f 100644 --- a/modules/platforms/cpp/odbc-test/src/queries_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp @@ -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)); http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp b/modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp index f905ff7..42dd3f7 100644 --- a/modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp +++ b/modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp @@ -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<> http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc-test/src/test_utils.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/test_utils.cpp b/modules/platforms/cpp/odbc-test/src/test_utils.cpp index eb08660..6d9ed6b 100644 --- a/modules/platforms/cpp/odbc-test/src/test_utils.cpp +++ b/modules/platforms/cpp/odbc-test/src/test_utils.cpp @@ -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); http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/Makefile.am b/modules/platforms/cpp/odbc/Makefile.am index 8d7693c..ea74c34 100644 --- a/modules/platforms/cpp/odbc/Makefile.am +++ b/modules/platforms/cpp/odbc/Makefile.am @@ -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 \ http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/Makefile.am b/modules/platforms/cpp/odbc/include/Makefile.am index 7c64754..9bdb803 100644 --- a/modules/platforms/cpp/odbc/include/Makefile.am +++ b/modules/platforms/cpp/odbc/include/Makefile.am @@ -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 \ http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h b/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h index 419a65e..89018f5 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/config/configuration.h @@ -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); http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h b/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h index 1577ee7..025b855 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/connection.h @@ -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; http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/ignite/odbc/socket_client.h ---------------------------------------------------------------------- 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 index 0000000..2df035b --- /dev/null +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/socket_client.h @@ -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 http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/secure_socket_client.h ---------------------------------------------------------------------- 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 index 0000000..4cd5844 --- /dev/null +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/secure_socket_client.h @@ -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 http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_bindings.h ---------------------------------------------------------------------- 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 index 0000000..b23533a --- /dev/null +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_bindings.h @@ -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 http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_gateway.h ---------------------------------------------------------------------- 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 index 0000000..b131228 --- /dev/null +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_gateway.h @@ -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 http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h ---------------------------------------------------------------------- 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 index 0000000..20472c3 --- /dev/null +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_mode.h @@ -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 http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/ignite/odbc/system/socket_client.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/system/socket_client.h b/modules/platforms/cpp/odbc/include/ignite/odbc/system/socket_client.h deleted file mode 100644 index 2a3cfa3..0000000 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/system/socket_client.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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_SYSTEM_SOCKET_CLIENT -#define _IGNITE_ODBC_SYSTEM_SOCKET_CLIENT - -#include <stdint.h> - -#include "ignite/common/common.h" -#include "ignite/odbc/diagnostic/diagnosable.h" - -namespace ignite -{ - namespace odbc - { - namespace tcp - { - /** - * Socket client implementation. - */ - class SocketClient - { - public: - /** Buffers size */ - enum { BUFFER_SIZE = 0x10000 }; - - /** The time in seconds the connection needs to remain idle before starts sending keepalive probes. */ - enum { KEEP_ALIVE_IDLE_TIME = 60 }; - - /** 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(); - - /** - * Destructor. - */ - ~SocketClient(); - - /** - * Establish connection with remote TCP service. - * - * @param hostname Remote host name. - * @param port TCP service port. - * @param diag Diagnostics collector. - * @return True on success. - */ - bool Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag); - - /** - * Close established connection. - * - * @return True on success. - */ - void Close(); - - /** - * 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. - */ - 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 sent on success, - * WaitResult::TIMEOUT on timeout and -errno on failure. - */ - 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; - } - - private: - /** - * Tries set socket options. - */ - void TrySetOptions(diagnostic::Diagnosable& diag); - - /** - * 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); - - /** Handle. */ - intptr_t socketHandle; - - /** Blocking flag. */ - bool blocking; - - IGNITE_NO_COPY_ASSIGNMENT(SocketClient) - }; - } - } -} - -#endif //_IGNITE_ODBC_SYSTEM_SOCKET_CLIENT \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/ignite/odbc/system/tcp_socket_client.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/system/tcp_socket_client.h b/modules/platforms/cpp/odbc/include/ignite/odbc/system/tcp_socket_client.h new file mode 100644 index 0000000..a3c9c30 --- /dev/null +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/system/tcp_socket_client.h @@ -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_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 system + { + /** + * Socket client implementation. + */ + class TcpSocketClient : public SocketClient + { + public: + /** Buffers size */ + enum { BUFFER_SIZE = 0x10000 }; + + /** The time in seconds the connection needs to remain idle before starts sending keepalive probes. */ + enum { KEEP_ALIVE_IDLE_TIME = 60 }; + + /** The time in seconds between individual keepalive probes. */ + enum { KEEP_ALIVE_PROBES_PERIOD = 1 }; + + /** + * Constructor. + */ + TcpSocketClient(); + + /** + * Destructor. + */ + virtual ~TcpSocketClient(); + + /** + * Establish connection with remote TCP service. + * + * @param hostname Remote host name. + * @param port TCP service port. + * @param diag Diagnostics collector. + * @return True on success. + */ + virtual bool Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag); + + /** + * Close established connection. + * + * @return True on success. + */ + virtual void Close(); + + /** + * 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); + + /** + * 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; + + /** + * 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. + */ + void TrySetOptions(diagnostic::Diagnosable& diag); + + /** + * 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); + + /** Handle. */ + intptr_t socketHandle; + + /** Blocking flag. */ + bool blocking; + + IGNITE_NO_COPY_ASSIGNMENT(TcpSocketClient) + }; + } + } +} + +#endif //_IGNITE_ODBC_SYSTEM_SOCKET_CLIENT \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/include/ignite/odbc/system/ui/dsn_configuration_window.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/system/ui/dsn_configuration_window.h b/modules/platforms/cpp/odbc/include/ignite/odbc/system/ui/dsn_configuration_window.h index 90286b9..b903414 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/system/ui/dsn_configuration_window.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/system/ui/dsn_configuration_window.h @@ -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 http://git-wip-us.apache.org/repos/asf/ignite/blob/394019ee/modules/platforms/cpp/odbc/os/linux/src/system/socket_client.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/os/linux/src/system/socket_client.cpp b/modules/platforms/cpp/odbc/os/linux/src/system/socket_client.cpp deleted file mode 100644 index a6d6151..0000000 --- a/modules/platforms/cpp/odbc/os/linux/src/system/socket_client.cpp +++ /dev/null @@ -1,360 +0,0 @@ -/* - * 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 <sys/socket.h> -#include <sys/types.h> -#include <netinet/tcp.h> -#include <netdb.h> -#include <unistd.h> -#include <fcntl.h> - -#include <cstring> - -#include <sstream> - -#include "ignite/odbc/system/socket_client.h" -#include "ignite/odbc/utility.h" -#include "ignite/odbc/log.h" - -#define SOCKET_ERROR (-1) - -namespace -{ - /** - * Get last socket error message. - * @param error Error code. - * @return Last socket error message string. - */ - std::string GetSocketErrorMessage(int error) - { - std::stringstream res; - - res << "error_code=" << error; - - if (error == 0) - return res.str(); - - char buffer[1024] = ""; - - if (!strerror_r(error, buffer, sizeof(buffer))) - res << ", msg=" << buffer; - - return res.str(); - } - - /** - * Get last socket error message. - * @return Last socket error message string. - */ - std::string GetLastSocketErrorMessage() - { - int lastError = errno; - - return GetSocketErrorMessage(lastError); - } -} - -namespace ignite -{ - namespace odbc - { - namespace tcp - { - - SocketClient::SocketClient() : - socketHandle(SOCKET_ERROR), - blocking(true) - { - // No-op. - } - - SocketClient::~SocketClient() - { - Close(); - } - - bool SocketClient::Connect(const char* hostname, uint16_t port, diagnostic::Diagnosable& diag) - { - LOG_MSG("Host: " << hostname << ", port: " << port); - - addrinfo hints; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - std::stringstream converter; - converter << port; - - // Resolve the server address and port - addrinfo *result = NULL; - int res = getaddrinfo(hostname, converter.str().c_str(), &hints, &result); - - if (res != 0) - { - LOG_MSG("Address resolving failed: " << gai_strerror(res)); - - diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not resolve host address."); - - return false; - } - - // Attempt to connect to an address until one succeeds - for (addrinfo *it = result; it != NULL; it = it->ai_next) - { - LOG_MSG("Addr: " << (it->ai_addr->sa_data[2] & 0xFF) << "." - << (it->ai_addr->sa_data[3] & 0xFF) << "." - << (it->ai_addr->sa_data[4] & 0xFF) << "." - << (it->ai_addr->sa_data[5] & 0xFF)); - - // Create a SOCKET for connecting to server - socketHandle = socket(it->ai_family, it->ai_socktype, it->ai_protocol); - - if (socketHandle == SOCKET_ERROR) - { - LOG_MSG("Socket creation failed: " << GetLastSocketErrorMessage()); - - diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not create new socket."); - - return false; - } - - diag.GetDiagnosticRecords().Reset(); - - TrySetOptions(diag); - - // Connect to server. - res = connect(socketHandle, it->ai_addr, static_cast<int>(it->ai_addrlen)); - if (SOCKET_ERROR == res) - { - int lastError = errno; - - if (lastError != EWOULDBLOCK && lastError != EINPROGRESS) - { - LOG_MSG("Connection failed: " << GetSocketErrorMessage(lastError)); - - Close(); - - continue; - } - - res = WaitOnSocket(CONNECT_TIMEOUT, false); - - if (res < 0 || res == WaitResult::TIMEOUT) - { - LOG_MSG("Connection timeout expired: " << GetSocketErrorMessage(-res)); - - Close(); - - continue; - } - } - break; - } - - freeaddrinfo(result); - - return socketHandle != SOCKET_ERROR; - } - - void SocketClient::Close() - { - if (socketHandle != SOCKET_ERROR) - { - close(socketHandle); - - socketHandle = SOCKET_ERROR; - } - } - - int SocketClient::Send(const int8_t* data, size_t size, int32_t timeout) - { - if (!blocking) - { - int res = WaitOnSocket(timeout, false); - - if (res < 0 || res == WaitResult::TIMEOUT) - return res; - } - - 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) - { - if (!blocking) - { - int res = WaitOnSocket(timeout, true); - - if (res < 0 || res == WaitResult::TIMEOUT) - return res; - } - - return recv(socketHandle, reinterpret_cast<char*>(buffer), static_cast<int>(size), 0); - } - - void SocketClient::TrySetOptions(diagnostic::Diagnosable& diag) - { - int trueOpt = 1; - int bufSizeOpt = BUFFER_SIZE; - int idleOpt = KEEP_ALIVE_IDLE_TIME; - int idleRetryOpt = KEEP_ALIVE_PROBES_PERIOD; - - int res = setsockopt(socketHandle, SOL_SOCKET, SO_SNDBUF, - reinterpret_cast<char*>(&bufSizeOpt), sizeof(bufSizeOpt)); - - if (SOCKET_ERROR == res) - { - LOG_MSG("TCP socket send buffer size setup failed: " << GetLastSocketErrorMessage()); - - diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, - "Can not set up TCP socket send buffer size"); - } - - res = setsockopt(socketHandle, SOL_SOCKET, SO_RCVBUF, - reinterpret_cast<char*>(&bufSizeOpt), sizeof(bufSizeOpt)); - - if (SOCKET_ERROR == res) - { - LOG_MSG("TCP socket receive buffer size setup failed: " << GetLastSocketErrorMessage()); - - diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, - "Can not set up TCP socket receive buffer size"); - } - - res = setsockopt(socketHandle, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast<char*>(&trueOpt), sizeof(trueOpt)); - - if (SOCKET_ERROR == res) - { - LOG_MSG("TCP no-delay mode setup failed: " << GetLastSocketErrorMessage()); - - diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, - "Can not set up TCP no-delay mode"); - } - - res = setsockopt(socketHandle, SOL_SOCKET, SO_OOBINLINE, - reinterpret_cast<char*>(&trueOpt), sizeof(trueOpt)); - - if (SOCKET_ERROR == res) - { - LOG_MSG("TCP out-of-bound data inlining setup failed: " << GetLastSocketErrorMessage()); - - diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, - "Can not set up TCP out-of-bound data inlining"); - } - - blocking = false; - - int flags; - if (((flags = fcntl(socketHandle, F_GETFL, 0)) < 0) || - (fcntl(socketHandle, F_SETFL, flags | O_NONBLOCK) < 0)) - { - blocking = true; - LOG_MSG("Non-blocking mode setup failed: " << GetLastSocketErrorMessage()); - - diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, - "Can not set up non-blocking mode. Timeouts are not available."); - } - - res = setsockopt(socketHandle, SOL_SOCKET, SO_KEEPALIVE, - reinterpret_cast<char*>(&trueOpt), sizeof(trueOpt)); - - if (SOCKET_ERROR == res) - { - LOG_MSG("TCP keep-alive mode setup failed: " << GetLastSocketErrorMessage()); - - diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, - "Can not set up TCP keep-alive mode"); - - // There is no sense in configuring keep alive params if we faileed to set up keep alive mode. - return; - } - - res = setsockopt(socketHandle, IPPROTO_TCP, TCP_KEEPIDLE, - reinterpret_cast<char*>(&idleOpt), sizeof(idleOpt)); - - if (SOCKET_ERROR == res) - { - LOG_MSG("TCP keep-alive idle timeout setup failed: " << GetLastSocketErrorMessage()); - - diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, - "Can not set up TCP keep-alive idle timeout"); - } - - res = setsockopt(socketHandle, IPPROTO_TCP, TCP_KEEPINTVL, - reinterpret_cast<char*>(&idleRetryOpt), sizeof(idleRetryOpt)); - - if (SOCKET_ERROR == res) - { - LOG_MSG("TCP keep-alive probes period setup failed: " << GetLastSocketErrorMessage()); - - diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED, - "Can not set up TCP keep-alive probes period"); - } - - } - - int SocketClient::WaitOnSocket(int32_t timeout, bool rd) - { - int ready = 0; - int lastError = 0; - - fd_set fds; - - do { - struct timeval tv = { 0 }; - tv.tv_sec = timeout; - - FD_ZERO(&fds); - FD_SET(socketHandle, &fds); - - fd_set* readFds = 0; - fd_set* writeFds = 0; - - if (rd) - readFds = &fds; - else - writeFds = &fds; - - ready = select(static_cast<int>((socketHandle) + 1), - readFds, writeFds, NULL, (timeout == 0 ? NULL : &tv)); - - if (ready == SOCKET_ERROR) - lastError = errno; - - } while (ready == SOCKET_ERROR && lastError == EINTR); - - if (ready == SOCKET_ERROR) - return -lastError; - - socklen_t size = sizeof(lastError); - int res = getsockopt(socketHandle, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&lastError), &size); - - if (res != SOCKET_ERROR && lastError != 0) - return -lastError; - - if (ready == 0) - return WaitResult::TIMEOUT; - - return WaitResult::SUCCESS; - } - } - } -} -
