diff --git a/CMakeLists.txt b/CMakeLists.txt index 56baa2cc0..7725349f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,8 @@ # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11) -CMAKE_POLICY(VERSION 2.8.11) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) +CMAKE_POLICY(VERSION 2.8.12) cmake_policy(SET CMP0022 NEW) # @@ -93,7 +93,8 @@ SET(CMAKE_CXX_EXTENSIONS no) # if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" - AND NOT DEFINED ENV{MACOSX_DEPLOYMENT_TARGET}) + AND NOT DEFINED ENV{MACOSX_DEPLOYMENT_TARGET} + AND NOT CMAKE_SYSTEM_NAME MATCHES "Linux") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") endif() @@ -150,6 +151,18 @@ if(WIN32 AND NOT UNREACHABLE_CODE_WARNINGS) endif() +if(WIN32) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") +endif() + + +# +# Gcov support (Linux only) +# + +include(gcov) +#message("WITH_COVERAGE: ${WITH_COVERAGE}") + #message("flags: ${CMAKE_C_FLAGS}") #message("c++ flags: ${CMAKE_CXX_FLAGS}") #foreach(TYPE DEBUG RELEASE RELWITHDEBINFO MINSIZEREL) @@ -241,8 +254,22 @@ SETUP_BOOST() SET(WITH_CDK_DOC 0) OPTION(WITH_CDK_TESTS "cdk tests" OFF) -set(WITH_SSL OFF) set(WITH_PIC ${CMAKE_POSITION_INDEPENDENT_CODE}) + + +if(NOT DEFINED WITH_SSL) +SET(WITH_SSL "bundled" CACHE STRING "") +endif() + +IF(WITH_SSL) + IF(WITH_SSL STREQUAL "bundled") + ADD_DEFINITIONS(-DWITH_SSL_YASSL) + ENDIF() + ADD_DEFINITIONS(-DWITH_SSL) +ENDIF() + + + ADD_SUBDIRECTORY(cdk) INCLUDE_DIRECTORIES(${CDK_INCLUDE_DIR}) INCLUDE_DIRECTORIES(cdk/parser) diff --git a/README.txt b/README.txt index 04545932f..fd2d5d8a9 100644 --- a/README.txt +++ b/README.txt @@ -7,7 +7,7 @@ copy of the software is released under the version 2 of the GNU General Public License. MySQL Connector/C++ is brought to you by Oracle. -Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. License information can be found in the COPYING file. diff --git a/cdk/CMakeLists.txt b/cdk/CMakeLists.txt index f6a77d91e..0f424cc44 100644 --- a/cdk/CMakeLists.txt +++ b/cdk/CMakeLists.txt @@ -53,6 +53,28 @@ LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) include(libutils) +# +# Infrastructure for defining code configuration settings +# (the ADD_CONFIG() macro for declaring contents of config.h). +# + +INCLUDE(config) + + +# +# Detect endianess +# + +if(NOT DEFINED CDK_BIG_ENDIAN) + + INCLUDE(TestBigEndian) + TEST_BIG_ENDIAN(CDK_BIG_ENDIAN) + +endif() + +message(STATUS "BIG_ENDIAN: ${BIG_ENDIAN}") +add_config(CDK_BIG_ENDIAN ${CDK_BIG_ENDIAN}) + # # Configure static runtime library on Windows if requested # @@ -74,7 +96,7 @@ endforeach(LANG) ENDIF() # -# Postion independent code support. +# Position independent code support. # option(WITH_PIC "Generate position independet code (PIC)" OFF) @@ -83,6 +105,11 @@ if(WITH_PIC) set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif() +# +# Gcov support (Linux only). +# + +include(gcov) # # Disable 64-bit warnings until we have dealt with them @@ -108,19 +135,6 @@ if(DISABLE_WARNINGS) endif() -#message("flags: ${CMAKE_C_FLAGS}") -#message("c++ flags: ${CMAKE_CXX_FLAGS}") -#foreach(TYPE DEBUG RELEASE RELWITHDEBINFO MINSIZEREL) -# message("${TYPE} flags: ${CMAKE_C_FLAGS_${TYPE}}") -# message("c++ ${TYPE} flags: ${CMAKE_CXX_FLAGS_${TYPE}}") -#endforeach() - -# -# Infrastructure for defining code configuration settings -# (the ADD_CONFIG() macro for declaring contents of config.h). -# - -INCLUDE(config) # # We want CDK code to compile both under C++ and C++11 compiler. @@ -169,14 +183,23 @@ INCLUDE(protobuf) # if(NOT DEFINED WITH_SSL) -SET(WITH_SSL "bundled" CACHE STRING "") +SET(WITH_SSL "bundled" CACHE STRING "TODO: Document me!") endif() + message("WITH_SSL: ${WITH_SSL}") IF(WITH_SSL) IF(WITH_SSL STREQUAL "bundled") ADD_DEFINITIONS(-DWITH_SSL_YASSL) + if(CDK_BIG_ENDIAN) + ADD_DEFINITIONS(-DWORDS_BIGENDIAN) + endif() ADD_SUBDIRECTORY(extra/yassl) + ELSE() + MESSAGE(WARNING "WITH_SSL option set to unrecognized value '${WITH_SSL}'" + " - will be ignored. Currently the only value allowed is" + " 'bundled', which uses the bundled YaSSL library to implement" + " TLS connections.") ENDIF() ADD_DEFINITIONS(-DWITH_SSL) ENDIF() @@ -237,6 +260,26 @@ if(WITH_TESTS) endif() +# +# Deal with broken optimization in gcc 4.8. +# +# We observed very strange behaviour of exceptions when compiling +# fully optimized code wtih gcc 4.8. Downgrade optimization to -O1 +# in this case. To get trully optimized code use gcc 4.9+ or clang. +# + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") +if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9") + foreach(LANG C CXX) + foreach(TYPE RELEASE RELWITHDEBINFO) + string(REPLACE "-O3" "-O1" CMAKE_${LANG}_FLAGS_${TYPE} "${CMAKE_${LANG}_FLAGS_${TYPE}}") + string(REPLACE "-O2" "-O1" CMAKE_${LANG}_FLAGS_${TYPE} "${CMAKE_${LANG}_FLAGS_${TYPE}}") + endforeach(TYPE) + endforeach(LANG) +endif() +endif() + + # # Set higher warning level on Windows to catch non-portable # code. @@ -302,6 +345,13 @@ ENDIF() endforeach(LANG) +#message("flags: ${CMAKE_C_FLAGS}") +#message("c++ flags: ${CMAKE_CXX_FLAGS}") +#foreach(TYPE DEBUG RELEASE RELWITHDEBINFO MINSIZEREL) +# message("${TYPE} flags: ${CMAKE_C_FLAGS_${TYPE}}") +# message("c++ ${TYPE} flags: ${CMAKE_CXX_FLAGS_${TYPE}}") +#endforeach() + # # Parser library @@ -360,6 +410,6 @@ ENDIF() IF(cdk_stand_alone) ADD_EXECUTABLE(try try.cc) TARGET_LINK_LIBRARIES(try cdk) - ADD_GCOV(try) + #ADD_COVERAGE(try) ENDIF() diff --git a/cdk/cmake/config.cmake b/cdk/cmake/config.cmake index 9bcf74853..055e7c364 100644 --- a/cdk/cmake/config.cmake +++ b/cdk/cmake/config.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. # # The MySQL Connector/C++ is licensed under the terms of the GPLv2 # , like most @@ -36,21 +36,27 @@ # set(CONFIG_VARS "" CACHE INTERNAL "configuration settings" FORCE) +set(CONFIG_VARS_VAL "" CACHE INTERNAL "configuration settings" FORCE) -macro(ADD_CONFIG var) - #message("- adding configuration setting: ${var}") - list(APPEND CONFIG_VARS ${var}) - list(REMOVE_DUPLICATES CONFIG_VARS) - set(CONFIG_VARS ${CONFIG_VARS} CACHE INERNAL "configuration settings" FORCE) +function(ADD_CONFIG var) + #message("- adding configuration setting: ${var} (${ARGN})") - # set variable to the value if given + if(DEFINED ARGV1) + + set(${var} ${ARGV1}) + list(APPEND CONFIG_VARS_VAL ${var}) + list(REMOVE_DUPLICATES CONFIG_VARS_VAL) + set(CONFIG_VARS_VAL ${CONFIG_VARS_VAL} CACHE INERNAL "configuration settings" FORCE) + + else() + + list(APPEND CONFIG_VARS ${var}) + list(REMOVE_DUPLICATES CONFIG_VARS) + set(CONFIG_VARS ${CONFIG_VARS} CACHE INERNAL "configuration settings" FORCE) - if(ARGN) - set(${var} ${ARGN}) - list(GET ${var} 0 ${var}) endif() -endmacro(ADD_CONFIG) +endfunction(ADD_CONFIG) # # Call this macro to write a configuration header containing defines @@ -71,6 +77,13 @@ macro(WRITE_CONFIG_HEADER path) else() set(DEFINE "/* #undef ${var} */") endif() + #message("writing to config.h: ${DEFINE}") + set(GENERATED_CONFIG_DEFS "${GENERATED_CONFIG_DEFS}\n${DEFINE}") + endforeach() + + foreach(var ${CONFIG_VARS_VAL}) + set(DEFINE "#define ${var} ${${var}}") + #message("writing to config.h: ${DEFINE}") set(GENERATED_CONFIG_DEFS "${GENERATED_CONFIG_DEFS}\n${DEFINE}") endforeach() diff --git a/cdk/cmake/gcov.cmake b/cdk/cmake/gcov.cmake new file mode 100644 index 000000000..ed11a2281 --- /dev/null +++ b/cdk/cmake/gcov.cmake @@ -0,0 +1,66 @@ +# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. +# +# This code is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FLOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +if (NOT DEFINED WITH_COVERAGE) + # use ENABLE_GCOV here to make it compatible with server conventions + option(WITH_COVERAGE "Enable gcov (debug, Linux builds only)" ${ENABLE_GCOV}) +endif() + +if (WITH_COVERAGE AND NOT BUILD_STATIC) + message(WARNING "To get good coverage results use static build of the" + " connector (BUILD_STATIC)") +endif() + + +macro(ADD_COVERAGE target) + + if(CMAKE_COMPILER_IS_GNUCXX AND WITH_COVERAGE) + + message(STATUS "Enabling gcc coverage support for target: ${target}") + + # Note: we use set_property(... APPEND ...) to not override other sttings + # for the target. + + set_property(TARGET ${target} APPEND + PROPERTY COMPILE_DEFINITIONS_DEBUG WITH_COVERAGE + ) + + # Note: COMPILE_OPTIONS property does not have per build configuration + # variant. Generator expression is used instead. + + set_property(TARGET ${target} APPEND + PROPERTY COMPILE_OPTIONS + $<$:-O0;-fprofile-arcs;-ftest-coverage> + ) + + set_property(TARGET ${target} APPEND + PROPERTY LINK_FLAGS_DEBUG -fprofile-arcs -ftest-coverage + ) + + set_property(TARGET ${target} APPEND + PROPERTY INTERFACE_LINK_LIBRARIES gcov + ) + + endif() + +endmacro(ADD_COVERAGE) diff --git a/cdk/cmake/testing.cmake b/cdk/cmake/testing.cmake index 1dc7f47ad..70b2150ea 100644 --- a/cdk/cmake/testing.cmake +++ b/cdk/cmake/testing.cmake @@ -54,6 +54,7 @@ IF(NOT DEFINED WITH_COVERAGE) OPTION(WITH_COVERAGE "Enable coverage support for gcc" OFF) ENDIF() + # # Note: On Windows the runtime type must match the one used by gtest. # @@ -72,19 +73,6 @@ IF(WITH_TESTS) ENDIF() -MACRO(ADD_GCOV target) -IF (WITH_TESTS) - IF(WITH_COVERAGE) - MESSAGE(STATUS "Enabling coverage support for gcc") - - SET_TARGET_PROPERTIES(${target} PROPERTIES COMPILE_FLAGS "-g -O0 -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Woverloaded-virtual -Wwrite-strings -fprofile-arcs -ftest-coverage ") - SET_TARGET_PROPERTIES(${target} PROPERTIES LINK_FLAGS "-fprofile-arcs -ftest-coverage") - - ENDIF(WITH_COVERAGE) -ENDIF (WITH_TESTS) - -ENDMACRO(ADD_GCOV) - MACRO(SETUP_TESTING) IF(WITH_TESTS) INCLUDE(CTest) @@ -273,7 +261,6 @@ IF(WITH_TESTS) ) TARGET_LINK_LIBRARIES(${target_run_unit_tests} gtest) - ADD_GCOV(${target_run_unit_tests}) #ADD_BOOST(${target_run_unit_tests}) # diff --git a/cdk/core/CMakeLists.txt b/cdk/core/CMakeLists.txt index 27f3d80eb..6286b1cac 100644 --- a/cdk/core/CMakeLists.txt +++ b/cdk/core/CMakeLists.txt @@ -48,6 +48,8 @@ add_library_ex(cdk STATIC session.cc codec.cc ${cdk_libs} ) +add_coverage(cdk) + #MESSAGE("cdk depends on: ${target_mysqlx} ${target_parser}") EXPORT(TARGETS cdk diff --git a/cdk/core/codec.cc b/cdk/core/codec.cc index 142336118..088f4802b 100644 --- a/cdk/core/codec.cc +++ b/cdk/core/codec.cc @@ -60,36 +60,50 @@ size_t cdk::Codec::to_bytes(const std::string &str, bytes raw) return len; } -size_t Codec::measure(const string &) +size_t Codec::measure(const string &str) { - //TODO: CS - return 0; + return get_codec().measure(str); } size_t Codec::from_bytes(bytes raw, string &str) { - //TODO: CS - //TODO: detect utf8 encoding //TODO: padding - foundation::Codec utf8; - // using string object, no need to have NULL char terminator - // remove NULL char terminator if present - return utf8.from_bytes(bytes(raw.begin(), - ( raw.size() > 0 && *(raw.end()-1) == '\0') ? - raw.end()-1 : - raw.end()), - str); + /* + Note: xprotocol adds 0x00 byte at the end of bytes encoding + a string to distinguisht the empty string from the null value. + When decoding, we strip the extra 0x00 byte at the end, if present. + */ + + return get_codec().from_bytes(bytes(raw.begin(), + ( raw.size() > 0 && *(raw.end()-1) == '\0') ? + raw.end()-1 : + raw.end()), + str); } -size_t Codec::to_bytes(const string& str,bytes raw) +size_t Codec::to_bytes(const string& str, bytes raw) { - //TODO: CS - //TODO: detect utf8 encoding - foundation::Codec utf8; - return utf8.to_bytes(str, raw); + return get_codec().to_bytes(str, raw); +} + + +foundation::api::String_codec* Format::codec() const +{ + /* + TODO: This implementation uses ASCII codec for all non utf8 strings, + which works only for simple strings. Correctly handle all MySQL + character encodings. + */ + + static foundation::String_codec utf8; + static foundation::String_codec ascii; + + return Charset::utf8 == charset() ? + (foundation::api::String_codec*)&utf8 + : (foundation::api::String_codec*)&ascii; } diff --git a/cdk/core/session.cc b/cdk/core/session.cc index 4280098d9..97ecc75eb 100644 --- a/cdk/core/session.cc +++ b/cdk/core/session.cc @@ -30,7 +30,7 @@ namespace cdk { -Session::Session(ds::TCPIP &ds, const ds::Options &options) +Session::Session(ds::TCPIP &ds, const ds::TCPIP::Options &options) : m_session(NULL) , m_connection(NULL) , m_trans(false) @@ -49,11 +49,12 @@ Session::Session(ds::TCPIP &ds, const ds::Options &options) rethrow_error(); } + #ifdef WITH_SSL + if (options.get_tls().use_tls()) + { using foundation::connection::TLS; - if (options.use_tls()) - { // Negotiate TLS capabilities. cdk::protocol::mysqlx::Protocol proto(*connection); @@ -79,16 +80,15 @@ Session::Session(ds::TCPIP &ds, const ds::Options &options) } prc; proto.rcv_Reply(prc).wait(); - - // - TLS* tls = new TLS(connection); + + TLS* tls = new TLS(connection, options.get_tls()); tls->connect(); m_connection = tls; m_session = new mysqlx::Session(*tls, options); } else -#endif // WITH_SSL +#endif { m_connection = connection; m_session = new mysqlx::Session(*connection, options); diff --git a/cdk/core/tests/CMakeLists.txt b/cdk/core/tests/CMakeLists.txt index e2aecaf69..a3e48add3 100644 --- a/cdk/core/tests/CMakeLists.txt +++ b/cdk/core/tests/CMakeLists.txt @@ -24,6 +24,6 @@ IF (WITH_TESTS) ADD_DEFINITIONS(-DDEFAULT_PORT=33060) -ADD_NG_TEST(cdk-t session-t.cc session_crud-t.cc) +ADD_NG_TEST(cdk-t session-t.cc session_crud-t.cc result-t.cc) ENDIF() diff --git a/cdk/core/tests/result-t.cc b/cdk/core/tests/result-t.cc new file mode 100644 index 000000000..26c7ff98e --- /dev/null +++ b/cdk/core/tests/result-t.cc @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * + * This code is licensed under the terms of the GPLv2 + * , like most + * MySQL Connectors. There are special exceptions to the terms and + * conditions of the GPLv2 as it is applied to this software, see the + * FLOSS License Exception + * . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "test.h" +#include "session_test.h" + +#include +#include + + +using ::std::cout; +using ::std::endl; +using namespace ::cdk; + +class Result + : public cdk::test::Core_test + , public cdk::test::Row_processor +{ +public: + + scoped_ptr m_sess; + + virtual void SetUp() + { + Core_test::SetUp(); + + if (!has_xplugin()) + return; + + m_sess.reset(new Session(this)); + if (!m_sess->is_valid()) + FAIL() << "could not create session"; + } + + Session& get_sess() + { + return *m_sess; + } + + void do_sql(const string &query) + { + Reply r; + r = m_sess->sql(query); + r.wait(); + if (0 < r.entry_count()) + r.get_error().rethrow (); + } +}; + + +using ::std::cout; +using ::std::endl; +using namespace ::cdk; +using namespace ::cdk::test; + + +class Result_cs : public Result +{ +public: + + Table_ref t; + + Result_cs() + : t("t1", "test") + {} + + string expected_string; + + void process_field_val(col_count_t pos, bytes data, + const cdk::string &val) + { + std::cout << val; + if (!expected_string.empty()) + EXPECT_EQ(expected_string, val); + } + + /* + Check that we correctly retreive non-ascii strings if stored using + utf8 encoding. + */ + + void check1(const char *cs, const string &val) + { + cout << "Testing " << cs << " string stored as utf8" << endl; + create_table("utf8"); + insert_string(val); + Reply select(get_sess().table_select(t)); + Cursor c(select); + set_meta_data(c); + expected_string = val; + c.get_rows(*this); + c.wait(); + } + + /* + Check that non-utf8 strings which use non-ascii characters trigger + string conversion errors (as, at the moment, we do not support encodings + other than utf8) + */ + + void check2(const char *cs, const string &val) + { + cout << "Testing " << cs << " string (expected conversion error)" << endl; + create_table(cs); + insert_string(val); + Reply select(get_sess().table_select(t)); + Cursor c(select); + set_meta_data(c); + EXPECT_THROW({ c.get_rows(*this); c.wait(); }, cdk::Error); + cout << endl; + } + + /* + Check that non-utf8 strings which consist only of ascii characters are + handled correctly. + */ + + void check3(const char *cs) + { + cout << "Testing ascii string stored as " << cs << endl; + expected_string = "I can eat glass{}, [].!"; + create_table(cs); + insert_string(expected_string); + Reply select(get_sess().table_select(t)); + Cursor c(select); + set_meta_data(c); + c.get_rows(*this); + c.wait(); + } + + void create_table(const char *cs) + { + create_table(t, cs); + } + + void create_table(const Table_ref &t, const char *cs) + { + do_sql( + string(L"drop table if exists ") + + L"`" + t.schema()->name() + L"`.`" + t.name() + L"`"); + do_sql( + string(L"create table ") + + L"`" + t.schema()->name() + L"`.`" + t.name() + L"`" + + L"(c text character set " + string(cs) + L")" + ); + } + + void insert_string(const string &val) + { + insert_string(t, val); + } + + void insert_string(const Table_ref &t, const string &val) + { + do_sql( + string(L"insert into ") + + L"`" + t.schema()->name() + L"`.`" + t.name() + L"`" + + L" values ('" + val + L"')" + ); + } + +}; + + +// Note: samples taken from foundation codec_t test. + +#define SAMPLES(X) \ + X (polish, "latin2", L"Mog\u0119 je\u015B\u0107 szk\u0142o", \ + "\x4D\x6F\x67\xC4\x99\x20\x6A\x65\xC5\x9B\xC4\x87\x20\x73\x7A\x6B\xC5\x82\x6F") \ + X (japaneese, "ujis", L"\u79C1\u306F\u30AC\u30E9\u30B9\u3092\u98DF\u3079\u3089\u308C\u307E\u3059\u3002\u305D\u308C\u306F\u79C1\u3092\u50B7\u3064\u3051\u307E\u305B\u3093\u3002", \ + "\xE7\xA7\x81\xE3\x81\xAF\xE3\x82\xAC\xE3\x83\xA9\xE3\x82\xB9\xE3\x82\x92\xE9\xA3\x9F\xE3\x81\xB9\xE3\x82\x89\xE3\x82\x8C\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82\xE3\x81\x9D\xE3\x82\x8C\xE3\x81\xAF\xE7\xA7\x81\xE3\x82\x92\xE5\x82\xB7\xE3\x81\xA4\xE3\x81\x91\xE3\x81\xBE\xE3\x81\x9B\xE3\x82\x93\xE3\x80\x82") \ + X (ukrainian, "koi8u", L"\u042F \u043C\u043E\u0436\u0443 \u0457\u0441\u0442\u0438 \u0441\u043A\u043B\u043E, \u0456 \u0432\u043E\u043D\u043E \u043C\u0435\u043D\u0456 \u043D\u0435 \u0437\u0430\u0448\u043A\u043E\u0434\u0438\u0442\u044C", \ + "\xD0\xAF\x20\xD0\xBC\xD0\xBE\xD0\xB6\xD1\x83\x20\xD1\x97\xD1\x81\xD1\x82\xD0\xB8\x20\xD1\x81\xD0\xBA\xD0\xBB\xD0\xBE\x2C\x20\xD1\x96\x20\xD0\xB2\xD0\xBE\xD0\xBD\xD0\xBE\x20\xD0\xBC\xD0\xB5\xD0\xBD\xD1\x96\x20\xD0\xBD\xD0\xB5\x20\xD0\xB7\xD0\xB0\xD1\x88\xD0\xBA\xD0\xBE\xD0\xB4\xD0\xB8\xD1\x82\xD1\x8C") \ + X (portuguese, "latin1", L"Posso comer vidro, n\u00E3o me faz mal", \ + "\x50\x6F\x73\x73\x6F\x20\x63\x6F\x6D\x65\x72\x20\x76\x69\x64\x72\x6F\x2C\x20\x6E\xC3\xA3\x6F\x20\x6D\x65\x20\x66\x61\x7A\x20\x6D\x61\x6C") + + +TEST_F(Result_cs, strings) +{ + SKIP_IF_NO_XPLUGIN; + + try + { + cout << "== CHECK 1 ==" << endl; + +#define CHECK1(NAME,CS,WIDE,UTF) check1(CS,WIDE); + + SAMPLES(CHECK1) + + cout <list_el()->member(m_path[pos]); + + prc.list_end(); + } + }; @@ -840,7 +846,7 @@ CRUD_TEST_BEGIN(find) Expr criteria(criteria_str); - Reply find(sess.coll_find(coll, &criteria, NULL)); + Reply find(sess.coll_find(coll, NULL, &criteria, NULL)); Cursor c(find); set_meta_data(c); @@ -863,7 +869,7 @@ CRUD_TEST_BEGIN(find) Expr criteria(criteria_str); - Reply find(sess.coll_find(coll, &criteria, NULL)); + Reply find(sess.coll_find(coll, NULL, &criteria, NULL)); Cursor c(find); set_meta_data(c); @@ -1048,7 +1054,7 @@ CRUD_TEST_BEGIN(update) // Show data after update. - Reply find(sess.coll_find(coll, &which)); + Reply find(sess.coll_find(coll, NULL, &which)); Cursor c(find); set_meta_data(c); c.get_rows(*this); @@ -1082,7 +1088,7 @@ CRUD_TEST_BEGIN(update) // Show data after update. - Reply find(sess.coll_find(coll, &which)); + Reply find(sess.coll_find(coll, NULL, &which)); Cursor c(find); set_meta_data(c); c.get_rows(*this); @@ -1167,7 +1173,7 @@ CRUD_TEST_BEGIN(parameters) param_values; { - Reply find(sess.coll_find(coll, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); + Reply find(sess.coll_find(coll, NULL, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); Cursor c(find); set_meta_data(c); @@ -1199,7 +1205,7 @@ CRUD_TEST_BEGIN(parameters) } { - Reply find(sess.coll_find(coll, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); + Reply find(sess.coll_find(coll, NULL, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); Cursor c(find); set_meta_data(c); @@ -1220,7 +1226,7 @@ CRUD_TEST_BEGIN(parameters) } { - Reply find(sess.coll_find(coll, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); + Reply find(sess.coll_find(coll, NULL, &expr, NULL, NULL, NULL, NULL, NULL, ¶m_values)); Cursor c(find); set_meta_data(c); @@ -1281,6 +1287,7 @@ CRUD_TEST_BEGIN(projections) Reply find( sess.coll_find(coll, + NULL, // view spec NULL, // where &projection, NULL, // sort @@ -1354,7 +1361,7 @@ CRUD_TEST_BEGIN(projections) } projection; - Reply find(sess.table_select(coll, &criteria, &projection)); + Reply find(sess.table_select(coll, NULL, &criteria, &projection)); Cursor c(find); set_meta_data(c); @@ -1441,7 +1448,7 @@ CRUD_TEST_BEGIN(insert) { TExpr cond("id IS NULL AND extra IS NULL"); - Reply check(sess.table_select(tbl, &cond)); + Reply check(sess.table_select(tbl, NULL, &cond)); Cursor c(check); set_meta_data(c); c.get_rows(*this); @@ -1465,7 +1472,7 @@ CRUD_TEST_BEGIN(group_by) Note: By default sql_mode ONLY_FULL_GROUP_BY is enabled. This result in errors from queries generated by xplugin (select list refers to fields not listed in GROUP BY clause). - See: https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by + See: https://dev.mysql.com/doc/refman/en/sql-mode.html#sqlmode_only_full_group_by */ Reply set_mode(sess.sql("set sql_mode=''")); set_mode.wait(); @@ -1534,6 +1541,7 @@ CRUD_TEST_BEGIN(group_by) Reply find( sess.coll_find(coll, + NULL, // view spec NULL, // where &projection, NULL, // sort @@ -1598,6 +1606,7 @@ CRUD_TEST_BEGIN(group_by) Reply find( sess.table_select(tbl, + NULL, // view spec NULL, // where &projection, NULL, // sort @@ -1620,3 +1629,201 @@ CRUD_TEST_BEGIN(group_by) cout <<"Done!" <process_if(prc.columns()); + if (opts) + opts->process_if(prc.options()); + } + } + view; + + cout << "Creating collection view..." << endl; + + // Drop the view first, if it already exists. + + { + Reply drop(sess.view_drop(view.v)); + drop.wait(); + if (0 < drop.entry_count()) + drop.get_error().rethrow(); + } + + { + struct : public View_spec::Options + { + void process(Processor &prc) const + { + prc.security(View_security::DEFINER); + prc.check(View_check::LOCAL); + } + } + view_opts; + + view.opts = &view_opts; + + struct : public Expression::Document + { + void process(Processor &prc) const + { + Path name_path("name"); + Path age_path("age"); + Expr double_age("2*age"); + Safe_prc sprc(prc); + + prc.doc_begin(); + + sprc->key_val("name_proj")->scalar()->ref(name_path); + double_age.process_if(sprc->key_val("age_proj")); + sprc->key_val("extra.orig_age")->scalar()->ref(age_path); + sprc->key_val("extra.val")->scalar()->val()->str("bar"); + + prc.doc_end(); + } + } + projection; + + Expr cond("name LIKE 'ba%'"); + + Reply create(sess.coll_find(coll, &view, &cond, &projection)); + create.wait(); + if (0 < create.entry_count()) + create.get_error().rethrow(); + } + + cout << "View created, querying it..." << endl; + + { + Reply select(sess.coll_find(view.v)); + select.wait(); + + cout << "Got reply..." << endl; + + Cursor c(select); + + set_meta_data(c); + c.get_rows(*this); + c.wait(); + } + + + cout << "Creating table view..." << endl; + + // Drop the view first. + + { + Reply drop(sess.view_drop(view.v, false)); + drop.wait(); + if (0 < drop.entry_count()) + drop.get_error().rethrow(); + } + + { + struct : public View_spec::Options + { + void process(Processor &prc) const + { + prc.security(View_security::INVOKER); + prc.algorithm(View_algorithm::UNDEFINED); + } + } + view_opts; + + view.opts = &view_opts; + + struct : public Projection + { + void process(Processor &prc) const + { + Processor::Element_prc *ep; + + prc.list_begin(); + + if ((ep = prc.list_el())) + { + TExpr proj(L"name"); + proj.process_if(ep->expr()); + // no alias + } + + if ((ep = prc.list_el())) + { + TExpr proj(L"2 * age"); + proj.process_if(ep->expr()); + ep->alias(L"double age"); + } + + prc.list_end(); + } + } + projection; + + struct : public cdk::String_list + { + void process(Processor &prc) const + { + prc.list_begin(); + safe_prc(prc)->list_el()->val("view_name"); + safe_prc(prc)->list_el()->val("view_age"); + prc.list_end(); + } + } + columns; + + view.columns = &columns; + + TExpr cond("name LIKE 'ba%'"); + + Reply create(sess.table_select(tbl, &view, &cond, &projection)); + create.wait(); + if (0 < create.entry_count()) + create.get_error().rethrow(); + } + + cout << "View created, querying it..." << endl; + + { + Reply select(sess.table_select(view.v)); + select.wait(); + + cout << "Got reply..." << endl; + + Cursor c(select); + + EXPECT_EQ(L"view_name", c.col_info(0).name()); + EXPECT_EQ(L"view_age", c.col_info(1).name()); + + set_meta_data(c); + c.get_rows(*this); + c.wait(); + } + + + cout <<"Done!" <, like most -# MySQL Connectors. There are special exceptions to the terms and -# conditions of the GPLv2 as it is applied to this software, see the -# FLOSS License Exception -# . -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published -# by the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - .. uuid_doc documentation master file, created by sphinx-quickstart on Fri Feb 6 18:39:23 2015. You can adapt this file completely to your liking, but it should at least @@ -44,37 +22,36 @@ UUID has the following structure: .. uml:: - object TIME_LOW - object TIME_MID + object NODE + object CLOCK_SEQ object TIME_HI_VER - object PROCESS_ID - object HW_MAC_ADDR + object TIME_MID + object TIME_LOW - TIME_LOW : 32-bit - TIME_MID : 16-bit + NODE : 48-bit + CLOCK_SEQ : 16-bit TIME_HI_VER : 16-bit - PROCESS_ID : 16-bit - HW_MAC_ADDR : 48-bit + TIME_MID : 16-bit + TIME_LOW : 32-bit - TIME_LOW -down-> TIME_MID - TIME_MID -down-> TIME_HI_VER - TIME_HI_VER -down-> PROCESS_ID - PROCESS_ID -down-> HW_MAC_ADDR + NODE -down-> CLOCK_SEQ + CLOCK_SEQ -down-> TIME_HI_VER + TIME_HI_VER -down-> TIME_MID + TIME_MID -down-> TIME_LOW - note right of TIME_LOW - represents the lower 32 bits of system timestamp - in order not to generate the same value the lower bits - can be "borrowed" from the future when two UUIDs generate - within the clock granularity - - this protects against generating similar values within - the same process + note right of NODE + 6 bytes randomly generated using a user-provided seed. + The same node values are used within a process. + Changing the random generator seed causes generating of + new node. end note - note right of TIME_MID - represents the medium 16 bits of system timestamp - this component changes when TIME_LOW reaches its maximum + note right of CLOCK_SEQ + randomly generated 16-bit value also containing the + UUID variant. This value changes on setting a new seed + for the generator or if two time values within the same + process have same time values. end note note right of TIME_HI_VER @@ -85,23 +62,19 @@ UUID has the following structure: timestamp >> 48 | UUID_VERSION end note - note right of PROCESS_ID - represents the lower 16 bits of the current Process ID - to make sure the duplicate values would not be generated if - two independent processes running on the same host - getting UUID at the same time + note right of TIME_MID + represents the medium 16 bits of system timestamp + this component changes when TIME_LOW reaches its maximum end note - note right of HW_MAC_ADDR - 6 bytes from Hardware MAC address of the network adapter - this component eliminates the possibility of duplication on - two or more UUIDs generated on separate hosts at the same - moment of time + note right of TIME_LOW + represents the lower 32 bits of system timestamp + in order not to generate the same value the lower bits + can be "borrowed" from the future when two UUIDs generate + within the clock granularity - If MAC address could not be obtained this value is generated - randomly depending on time, the number of bytes sent, - Query ID (number), query performance frequency and - query performance offset + this protects against generating similar values within + the same process end note How to use UUID generator @@ -114,6 +87,8 @@ To start using the ``UUID`` generator the client code has to use the header: #include +The classes and declarations for the ``UUID`` generator are inside ``uuid`` name space. + The header file contains the definitions for ``uuid_type`` as: .. code-block:: c @@ -122,47 +97,45 @@ The header file contains the definitions for ``uuid_type`` as: typedef unsigned char uuid_type[UUID_LENGTH_BIN]; -UUID functions --------------- +UUID structures +--------------- .. |vspace| raw:: latex \vspace{5mm} -* ``init_uuid(unsigned long seed)`` - initialization function, which should - be called only once before using the generator. The parameter `unsigned long seed` is - used to generate the 6-byte `Hardware MAC address` if it could not be obtained. - The seed can be a random value, system time, the query number, number of sent bytes, etc. +* ``Uuid`` - a static structure with automatically called constructor and destructor + initializing/freeing mutexes etc. The user code is not supposed to create instances of + this structure. |vspace| + +* ``Uuid::set_seed(uint16_t seed)`` - Setting the seed for the UUID generator. + The seed has to be set before generator can be used. Otherwise it throws + an exception. -* ``generate_uuid(uuid_type& uuid)`` - generator returning the result into `uuid` parameter. +* ``Uuid::set_seed_from_time_pid()`` - Converience function for setting the seed + for the UUID generator using the current machine time and the process id. + +* ``Uuid::generate_uuid(uuid_type& uuid)`` - generator returning the result into `uuid` parameter. Could be called many times, sequentially or concurrently from different threads. - Requires `init_uuid()` function to be called before the first use of `generate_uuid`. -|vspace| - -* ``end_uuid()`` - should be called when the application exists or when UUID generator is - not needed. Destroys the mutexes used for synchronizing in concurrent threads. Usage example ------------- .. code-block:: c - /* Initialize the UUID generator and create mutexes */ - unsigned long seed = ; - init_uuid(seed); +#include "uuid_gen.h" ... + uuid::uuid_type uuid; /* Use the generator. The result formatted and converted to text could look as: - bf17975b-4e44-d011-4c6b00268312fb20 + 4c6b00268312fb20-4e44-d011-bf17975b */ - generate_uuid(uuid); - ... - /* Destroy mutexes */ - end_uuid(); + uuid::set_seed(set_seed((uint16_t)(time(0) ^ process_id)); + uuid::generate_uuid(uuid); Contents: diff --git a/cdk/extra/uuid/include/uuid_gen.h b/cdk/extra/uuid/include/uuid_gen.h index 96a585db4..b67db67b6 100644 --- a/cdk/extra/uuid/include/uuid_gen.h +++ b/cdk/extra/uuid/include/uuid_gen.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,14 +15,27 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef UUID_GEN_INCLUDED -#define UUID_GEN_INCLUDED +#ifndef _UUID_GEN_H_ +#define _UUID_GEN_H_ + +#include #define UUID_LENGTH_BIN 16 + +namespace uuid { + typedef unsigned char uuid_type[UUID_LENGTH_BIN]; -void init_uuid(unsigned long); -void end_uuid(); +/* The seed must be set before using the generator. */ +void set_seed(uint16_t seed); + +/* Convenience function, which sets the seed using the time and + process id */ +void set_seed_from_time_pid(); + +/* UUID generator */ void generate_uuid(uuid_type &uuid); +} // namespace uuid + #endif \ No newline at end of file diff --git a/cdk/extra/uuid/src/uuid_gen.cc b/cdk/extra/uuid/src/uuid_gen.cc index ec336529f..beed28a9f 100644 --- a/cdk/extra/uuid/src/uuid_gen.cc +++ b/cdk/extra/uuid/src/uuid_gen.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,31 +15,25 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include "uuid_gen.h" #ifdef _WIN32 -#include -#include #include -#include -#endif - -#include -#include +#include +#else #include -#include +#endif +#include +#include -/* -Begin of MySQL defs and structs -*/ #ifdef _WIN32 typedef CRITICAL_SECTION pthread_mutex_t; typedef DWORD pthread_t; typedef struct thread_attr { - DWORD dwStackSize ; - DWORD dwCreatingFlag ; -} pthread_attr_t ; + DWORD dwStackSize; + DWORD dwCreatingFlag; +} pthread_attr_t; #define pthread_getspecific(A) (TlsGetValue(A)) #define pthread_self() (GetCurrentThreadId()) @@ -52,7 +46,6 @@ typedef struct thread_attr { #else #include -#include #include #include @@ -76,288 +69,50 @@ typedef struct thread_attr { #define likely(x) __builtin_expect((x),1) #define unlikely(x) __builtin_expect((x),0) -typedef unsigned int uint32; -typedef unsigned short uint16; -typedef char my_bool; /* Small bool */ +static pthread_mutex_t LOCK_uuid_generator; -#define UUID_LENGTH_TEXT (8+1+4+1+4+1+4+1+12) - -struct rand_struct { - unsigned long seed1,seed2,max_value; - double max_value_dbl; -}; +/* The seed and the random value are stored in uuid_seed */ +static uint16_t uuid_seed = 0; -static pthread_mutex_t LOCK_uuid_generator, LOCK_sql_rand; +/* Needed for the time counting */ +static unsigned int nanoseq = 0; - -/* -End MySQL defs and structs -*/ - -/* - These values are obtained during the live session, but - here we set them just to non-zero -*/ -static unsigned long uuid_seed= 0; +/* The last used time value is stored here */ +static unsigned long long uuid_time2 = 0; #if defined(_WIN32) -static unsigned long long query_performance_frequency= 0; -static unsigned long long query_performance_offset= 0; +static unsigned long long query_performance_frequency = 0; +static unsigned long long query_performance_offset = 0; #endif +static uint16_t time_seq_global = 0; -static unsigned int nanoseq= 0; -static unsigned long long uuid_time2=0; +/* + The randomly generated node part is stored here. + It is generated only when the seed is changed. + All other times it is just re-used. +*/ +unsigned char node_global[6]; /** number of 100-nanosecond intervals between 1582-10-15 00:00:00.00 and 1970-01-01 00:00:00.00. */ #define UUID_TIME_OFFSET ((unsigned long long) 141427 * 24 * 60 * 60 * \ - 1000 * 1000 * 10) + 1000 * 1000 * 10) #define UUID_MS 10000000 #define UUID_VERSION 0x1000 #define UUID_VARIANT 0x8000 -struct rand_struct sql_rand; -struct rand_struct uuid_rand; - -/** - Getting MAC address -*/ - -#ifdef __FreeBSD__ - -#include -#include -#include // for struct sockaddr -#include -#include -#include - -/* - my_gethwaddr - FreeBSD version - - @brief Retrieve MAC address from network hardware - - @param[out] to MAC address exactly six bytes - - @return Operation status - @retval 0 OK - @retval <>0 FAILED -*/ -my_bool my_gethwaddr(unsigned char *to) -{ - size_t len; - char *buf, *next, *end; - struct if_msghdr *ifm; - struct sockaddr_dl *sdl; - int res=1, mib[6]={CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0}; - char zero_array[ETHER_ADDR_LEN] = {0}; - - if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) - goto err; - if (!(buf = (char*)alloca(len))) - goto err; - if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) - goto err; - - end = buf + len; - - for (next = buf ; res && next < end ; next += ifm->ifm_msglen) - { - ifm = (struct if_msghdr *)next; - if (ifm->ifm_type == RTM_IFINFO) - { - sdl= (struct sockaddr_dl *)(ifm + 1); - std::memcpy(to, LLADDR(sdl), ETHER_ADDR_LEN); - res= std::memcmp(to, zero_array, ETHER_ADDR_LEN) ? 0 : 1; - } - } - -err: - return res; -} - -#elif __linux__ - -#include -#include -#include - -#define MAX_IFS 64 -/* - my_gethwaddr - Linux version - - @brief Retrieve MAC address from network hardware - - @param[out] to MAC address exactly six bytes - - @return Operation status - @retval 0 OK - @retval <>0 FAILED -*/ -my_bool my_gethwaddr(unsigned char *to) -{ - int fd= -1; - int res= 1; - struct ifreq ifr; - struct ifreq ifs[MAX_IFS]; - struct ifreq *ifri= NULL; - struct ifreq *ifend= NULL; - - char zero_array[ETHER_ADDR_LEN] = {0}; - struct ifconf ifc; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) - return 1; - - /* Retrieve interfaces */ - ifc.ifc_len= sizeof(ifs); - ifc.ifc_req= ifs; - if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) - { - close(fd); - return 1; - } - - /* Initialize out parameter */ - std::memcpy(to, zero_array, ETHER_ADDR_LEN); - - /* Calculate first address after array */ - ifend= ifs + (ifc.ifc_len / sizeof(struct ifreq)); - - /* Loop over all interfaces */ - for (ifri= ifc.ifc_req; ifri < ifend; ifri++) - { - if (ifri->ifr_addr.sa_family == AF_INET) - { - /* Reset struct, copy interface name */ - std::memset(&ifr, 0, sizeof(ifr)); - std::strncpy(ifr.ifr_name, ifri->ifr_name, sizeof(ifr.ifr_name)); - - /* Get HW address, break if not 0 */ - if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) - { - std::memcpy(to, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); - if (std::memcmp(to, zero_array, ETHER_ADDR_LEN)) - { - res= 0; - break; - } - } - } - } - close(fd); - return res; -} - -#elif defined(_WIN32) - -/* - The following typedef is for dynamically loading iphlpapi.dll / - GetAdaptersAddresses. Dynamic loading is used because - GetAdaptersAddresses is not available on Windows 2000 which MySQL - still supports. Static linking would cause an unresolved export. -*/ -typedef DWORD (WINAPI *pfnGetAdaptersAddresses)(IN ULONG Family, - IN DWORD Flags,IN PVOID Reserved, - OUT PIP_ADAPTER_ADDRESSES pAdapterAddresses, - IN OUT PULONG pOutBufLen); - -/* - my_gethwaddr - Windows version - - @brief Retrieve MAC address from network hardware - - @param[out] to MAC address exactly six bytes - - @return Operation status - @retval 0 OK - @retval <>0 FAILED -*/ -my_bool my_gethwaddr(unsigned char *to) -{ - PIP_ADAPTER_ADDRESSES pAdapterAddresses; - PIP_ADAPTER_ADDRESSES pCurrAddresses; - IP_ADAPTER_ADDRESSES adapterAddresses; - ULONG address_len; - my_bool return_val= 1; - pfnGetAdaptersAddresses fnGetAdaptersAddresses= - (pfnGetAdaptersAddresses)-1; - - if(fnGetAdaptersAddresses == (pfnGetAdaptersAddresses)-1) - { - /* Get the function from the DLL */ - fnGetAdaptersAddresses= (pfnGetAdaptersAddresses) - GetProcAddress(LoadLibrary("iphlpapi.dll"), - "GetAdaptersAddresses"); - } - if (!fnGetAdaptersAddresses) - return 1; /* failed to get function */ - address_len= sizeof (IP_ADAPTER_ADDRESSES); - - /* Get the required size for the address data. */ - if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, &adapterAddresses, &address_len) - == ERROR_BUFFER_OVERFLOW) - { - pAdapterAddresses= (PIP_ADAPTER_ADDRESSES)malloc(address_len); - if (!pAdapterAddresses) - return 1; /* error, alloc failed */ - } - else - pAdapterAddresses= &adapterAddresses; /* one is enough don't alloc */ - - /* Get the hardware info. */ - if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, pAdapterAddresses, &address_len) - == NO_ERROR) - { - pCurrAddresses= pAdapterAddresses; - - while (pCurrAddresses) - { - /* Look for ethernet cards. */ - if (pCurrAddresses->IfType == IF_TYPE_ETHERNET_CSMACD) - { - /* check for a good address */ - if (pCurrAddresses->PhysicalAddressLength < 6) - continue; /* bad address */ - - /* save 6 bytes of the address in the 'to' parameter */ - memcpy(to, pCurrAddresses->PhysicalAddress, 6); - - /* Network card found, we're done. */ - return_val= 0; - break; - } - pCurrAddresses= pCurrAddresses->Next; - } - } - - /* Clean up memory allocation. */ - if (pAdapterAddresses != &adapterAddresses) - free(pAdapterAddresses); - - return return_val; -} - -#else /* __FreeBSD__ || __linux__ || _WIN32 */ -/* just fail */ -my_bool my_gethwaddr(unsigned char *to __attribute__((unused))) +/* Generate pseudo-random values using Fibonaccy sequence */ +uint16_t rand_fibonacci() { - return 1; -} -#endif - - -double my_rnd(rand_struct *rand_st) -{ - rand_st->seed1= (rand_st->seed1*3+rand_st->seed2) % rand_st->max_value; - rand_st->seed2= (rand_st->seed1+rand_st->seed2+33) % rand_st->max_value; - return (((double) rand_st->seed1) / rand_st->max_value_dbl); + uint16_t bit = ((uuid_seed >> 0) ^ (uuid_seed >> 2) ^ + (uuid_seed >> 3) ^ (uuid_seed >> 5)) & 1; + uuid_seed = (uuid_seed >> 1) | (bit << 15); + return uuid_seed; } @@ -366,7 +121,7 @@ unsigned long long my_getsystime() #ifdef HAVE_CLOCK_GETTIME struct timespec tp; clock_gettime(CLOCK_REALTIME, &tp); - return (unsigned long long)tp.tv_sec*10000000+(unsigned long long)tp.tv_nsec/100; + return (unsigned long long)tp.tv_sec * 10000000 + (unsigned long long)tp.tv_nsec / 100; #elif defined(_WIN32) LARGE_INTEGER t_cnt; if (query_performance_frequency) @@ -374,138 +129,147 @@ unsigned long long my_getsystime() QueryPerformanceCounter(&t_cnt); return ((t_cnt.QuadPart / query_performance_frequency * 10000000) + ((t_cnt.QuadPart % query_performance_frequency) * 10000000 / - query_performance_frequency) + query_performance_offset); + query_performance_frequency) + query_performance_offset); } return 0; #else /* TODO: check for other possibilities for hi-res timestamping */ struct timeval tv; - gettimeofday(&tv,NULL); - return (unsigned long long)tv.tv_sec*10000000+(unsigned long long)tv.tv_usec*10; + gettimeofday(&tv, NULL); + return (unsigned long long)tv.tv_sec * 10000000 + (unsigned long long)tv.tv_usec * 10; #endif } - -unsigned long sql_rnd_with_mutex() +/* Get process id */ +static uint32_t get_proc_id() { - pthread_mutex_lock(&LOCK_sql_rand); - unsigned long tmp=(unsigned long) (my_rnd(&sql_rand) * 0xffffffff); /* make all bits random */ - pthread_mutex_unlock(&LOCK_sql_rand); - return tmp; -} - - -void randominit(struct rand_struct *rand_st, unsigned long seed1, unsigned long seed2) -{ /* For mysql 3.21.# */ -#ifdef HAVE_purify - memset(rand_st, 0, sizeof(*rand_st)); /* Avoid UMC varnings */ -#endif - rand_st->max_value= 0x3FFFFFFFL; - rand_st->max_value_dbl=(double) rand_st->max_value; - rand_st->seed1=seed1%rand_st->max_value ; - rand_st->seed2=seed2%rand_st->max_value; -} - - -static uint16 get_proc_id() -{ - uint16 proc_id= 0; #ifdef _WIN32 - proc_id= (uint16)(GetCurrentProcessId() & 0x0000FFFF); + return (uint32_t)GetCurrentProcessId(); #else - proc_id= (uint16)(getpid() & 0x0000FFFF); + return (uint32_t)getpid(); #endif - return proc_id; } - -void init_uuid(unsigned long seed) +/* Do initialization for UUID generator */ +void init_uuid() { pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&LOCK_sql_rand, MY_MUTEX_INIT_FAST); - uuid_seed= seed; + uuid_seed = 0; #if defined(_WIN32) FILETIME ft; LARGE_INTEGER li, t_cnt; if (QueryPerformanceFrequency((LARGE_INTEGER *)&query_performance_frequency) == 0) - query_performance_frequency= 0; + query_performance_frequency = 0; else { GetSystemTimeAsFileTime(&ft); - li.LowPart= ft.dwLowDateTime; - li.HighPart= ft.dwHighDateTime; - query_performance_offset= li.QuadPart-UUID_TIME_OFFSET; + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + query_performance_offset = li.QuadPart - UUID_TIME_OFFSET; QueryPerformanceCounter(&t_cnt); - query_performance_offset-= (t_cnt.QuadPart / - query_performance_frequency * UUID_MS + - t_cnt.QuadPart % - query_performance_frequency * UUID_MS / - query_performance_frequency); + query_performance_offset -= (t_cnt.QuadPart / + query_performance_frequency * UUID_MS + + t_cnt.QuadPart % + query_performance_frequency * UUID_MS / + query_performance_frequency); } #endif + } -void end_uuid() +void deinit_uuid() { pthread_mutex_destroy(&LOCK_uuid_generator); - pthread_mutex_destroy(&LOCK_sql_rand); } -void generate_uuid(uuid_type &uuid) -{ - struct uuid_internal_st +/* + Instance of this class holds the global UUID generator mutex until + it gets destroyed. An exception-safe way of executing a block of code while + holding the mutex is like follows: + + { + Uuid_guard guard; + // code executed under the guard of the global mutex + } +*/ + +struct Uuid_guard +{ + struct Initializer { - uint32 time_low; - uint16 time_mid; - uint16 time_hi_and_version; - uint16 process_id; - unsigned char hw_mac[6]; + Initializer() { init_uuid(); } + ~Initializer() { deinit_uuid(); } }; - static uuid_internal_st uuid_internal; + Uuid_guard() + { + /* + This static initializer instance gets constructed only once. + It ensures that uuid module is properly initialized before + using the mutex. + */ + static Initializer init; + pthread_mutex_lock(&LOCK_uuid_generator); + } + + ~Uuid_guard() + { + pthread_mutex_unlock(&LOCK_uuid_generator); + } +}; - pthread_mutex_lock(&LOCK_uuid_generator); - /* The thread key address will be used for random number generation */ -#ifdef _WIN32 - static DWORD key; -#else - static pthread_t key; -#endif +/* + Structure of UUID produced by the generator. + It already has its components reversed, but we will + consider the order of components as direct. +*/ +struct uuid_internal_st +{ + unsigned char node[6]; + uint16_t clock_seq; + uint16_t time_hi_and_version; + uint16_t time_mid; + uint32_t time_low; +}; - key= pthread_self(); +/* Random generation of the node part in UUID */ +void generate_node() +{ + uint16_t i = 0; + uint16_t rand_buf[3]; - size_t i; + /* Run a few steps through the sequence */ + i = rand_fibonacci() & 7; + while (i && rand_fibonacci()) --i; - if (!uuid_time2) /* first UUID() call. initializing data */ + for (i = 0; i < 3; i++) { - unsigned long client_start_time= time(0); - randominit(&sql_rand,(unsigned long) client_start_time,(unsigned long) client_start_time/2); - unsigned long tmp=sql_rnd_with_mutex(); - if (my_gethwaddr(uuid_internal.hw_mac)) - { + rand_buf[i] = rand_fibonacci(); + } - /* purecov: begin inspected */ - /* - generating random "hardware addr" - and because specs explicitly specify that it should NOT correlate - with a clock_seq value (initialized random below), we use a separate - randominit() here - */ - randominit(&uuid_rand, tmp + (unsigned long) key, tmp + (unsigned long)uuid_seed); - for (i=0; i < (int)sizeof(uuid_internal.hw_mac); i++) - uuid_internal.hw_mac[i]=(unsigned char)(my_rnd(&uuid_rand)*255); - /* purecov: end */ - } + memcpy(node_global, rand_buf, sizeof(node_global)); + time_seq_global = rand_fibonacci(); +} - uuid_internal.process_id= get_proc_id(); - } - unsigned long long tv= my_getsystime() + UUID_TIME_OFFSET + nanoseq; +namespace uuid +{ + +void generate_uuid(uuid_type &uuid) +{ + if (!uuid_seed) + throw std::logic_error("The seed must be set for random numbers generator"); + + uuid_internal_st uuid_internal; + + Uuid_guard guard; + + unsigned long long tv = my_getsystime() + UUID_TIME_OFFSET + nanoseq; if (likely(tv > uuid_time2)) { @@ -519,9 +283,9 @@ void generate_uuid(uuid_type &uuid) /* -1 so we won't make tv= uuid_time for nanoseq >= (tv - uuid_time) */ - unsigned long delta= std::min(nanoseq, (unsigned long) (tv - uuid_time2 -1)); - tv-= delta; - nanoseq-= delta; + unsigned long delta = std::min(nanoseq, (unsigned long)(tv - uuid_time2 - 1)); + tv -= delta; + nanoseq -= delta; } } else @@ -555,28 +319,37 @@ void generate_uuid(uuid_type &uuid) In either case, we throw away any nanoseq borrowing since it's irrelevant in the new numberspace. */ - uuid_internal.process_id= get_proc_id(); - tv= my_getsystime() + UUID_TIME_OFFSET; - nanoseq= 0; + tv = my_getsystime() + UUID_TIME_OFFSET; + time_seq_global = rand_fibonacci() | UUID_VARIANT; + + nanoseq = 0; } } - uuid_time2=tv; - pthread_mutex_unlock(&LOCK_uuid_generator); + uuid_time2 = tv; - uuid_internal.time_low= (uint32) (tv & 0xFFFFFFFF); - uuid_internal.time_mid= (uint16) ((tv >> 32) & 0xFFFF); - uuid_internal.time_hi_and_version= (uint16) ((tv >> 48) | UUID_VERSION); + uuid_internal.time_low = (uint32_t)(tv & 0xFFFFFFFF); + uuid_internal.time_mid = (uint16_t)((tv >> 32) & 0xFFFF); + uuid_internal.time_hi_and_version = (uint16_t)((tv >> 48) | UUID_VERSION); + uuid_internal.clock_seq = time_seq_global; + memcpy(uuid_internal.node, node_global, sizeof(node_global)); memcpy(uuid, &uuid_internal, sizeof(uuid_internal)); +} - union thread_to_char - { - pthread_t thr; - unsigned char c[sizeof(pthread_t)]; - }t_val; - t_val.thr = key; - for (i = 0; i < sizeof(key); ++i) - uuid[sizeof(uuid) - i - 1] ^= t_val.c[i]; +void set_seed(uint16_t seed) +{ + Uuid_guard guard; + uuid_seed ^= seed; + generate_node(); } + + +void set_seed_from_time_pid() +{ + set_seed((uint16_t)(time(0) ^ get_proc_id())); +} + + +} \ No newline at end of file diff --git a/cdk/extra/uuid/testing/tests_uuid.cc b/cdk/extra/uuid/testing/tests_uuid.cc index 571c48bab..fe9232445 100644 --- a/cdk/extra/uuid/testing/tests_uuid.cc +++ b/cdk/extra/uuid/testing/tests_uuid.cc @@ -32,6 +32,7 @@ */ using namespace std; +using namespace uuid; std::ostream& operator<<(std::ostream &out, unsigned char u) { @@ -44,11 +45,11 @@ std::ostream& operator<<(std::ostream &out, unsigned char u) std::ostream& operator<<(std::ostream &out, const unsigned char id[16]) { - out << id[0] << id[1] << id[2] << id[3]; - out <<"-" << id[4] << id[5]; + out << id[0] << id[1] << id[2] << id[3] << id[4] << id[5]; out <<"-" << id[6] << id[7]; out <<"-" << id[8] << id[9]; - out << id[10] << id[11] << id[12] << id[13] << id[14] << id[15]; + out <<"-" << id[10] << id[11]; + out << id[12] << id[13] << id[14] << id[15]; return out; } @@ -56,24 +57,16 @@ std::ostream& operator<<(std::ostream &out, const unsigned char id[16]) int main(int argc, char **argv) { - init_uuid(365873); + std::cout << "UUID Generator:" << std::endl; - std::cout << "UUID Generator:" << std::endl << "----------------------" << std::endl; - - int iter_number= 100; - - if (argc > 1) - iter_number = std::atoi(argv[1]); - else - std::cout << "Optional number of iterations can be specified in the command line" << std::endl; - - std::cout << "Number of iterations: " << iter_number << std::endl << std::endl; + int iter_number= 20; int i = 0; uuid_type uuid; while(i < iter_number) { + set_seed_from_time_pid(); generate_uuid(uuid); std::cout << "UUID_" << std::setw(4) << std::setfill('0') << ++i << " " << uuid << std::endl; #ifdef _WIN32 @@ -83,7 +76,4 @@ int main(int argc, char **argv) #endif } std::cout << "DONE!" << std::endl; - - end_uuid(); - return 0; } diff --git a/cdk/extra/yassl/CMakeLists.txt b/cdk/extra/yassl/CMakeLists.txt index 0dcbed914..d09eedbe6 100644 --- a/cdk/extra/yassl/CMakeLists.txt +++ b/cdk/extra/yassl/CMakeLists.txt @@ -17,10 +17,9 @@ INCLUDE(install_macros) INCLUDE(msvc) INCLUDE_DIRECTORIES( - ${CMAKE_BINARY_DIR}/include - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/include - ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/mySTL) + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/include + ${CMAKE_CURRENT_SOURCE_DIR}/taocrypt/mySTL) ADD_DEFINITIONS(${SSL_DEFINES}) @@ -49,8 +48,8 @@ CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG) ADD_DEFINITIONS(-DSIZEOF_LONG=${SIZEOF_LONG} -DSIZEOF_LONG_LONG=${SIZEOF_LONG_LONG}) SET(YASSL_SOURCES src/buffer.cpp src/cert_wrapper.cpp src/crypto_wrapper.cpp src/handshake.cpp src/lock.cpp - src/log.cpp src/socket_wrapper.cpp src/ssl.cpp src/timer.cpp src/yassl_error.cpp - src/yassl_imp.cpp src/yassl_int.cpp) + src/log.cpp src/socket_wrapper.cpp src/ssl.cpp src/timer.cpp src/yassl_error.cpp + src/yassl_imp.cpp src/yassl_int.cpp) ADD_LIBRARY(yassl STATIC ${YASSL_SOURCES}) #RESTRICT_SYMBOL_EXPORTS(yassl) @@ -68,4 +67,4 @@ ENDIF() # if(NOT WINDOWS_RUNTIME_MD) # CHANGE_MD_2_MT() # endif() -#endif() \ No newline at end of file +#endif() diff --git a/cdk/extra/yassl/README b/cdk/extra/yassl/README index d245d20ce..32a505438 100644 --- a/cdk/extra/yassl/README +++ b/cdk/extra/yassl/README @@ -2,7 +2,7 @@ yaSSL takes a different approach to certificate verification than OpenSSL does. The default policy for the client is to verify the server, this means that if -you don't load CAs to verify the server you'll get a connect error, unable to +you don't load CAs to verify the server you'll get a connect error, unable to verify. It you want to mimic OpenSSL behavior of not verifying the server and reducing security you can do this by calling: @@ -12,6 +12,66 @@ before calling SSL_new(); *** end Note *** +yaSSL Release notes, version 2.4.2 (9/22/2016) + This release of yaSSL fixes a medium security vulnerability. A fix for + potential AES side channel leaks is included that a local user monitoring + the same CPU core cache could exploit. VM users, hyper-threading users, + and users where potential attackers have access to the CPU cache will need + to update if they utilize AES. + + DSA padding fixes for unusual sizes is included as well. Users with DSA + certficiates should update. + +yaSSL Release notes, version 2.4.0 (5/20/2016) + This release of yaSSL fixes the OpenSSL compatibility function + SSL_CTX_load_verify_locations() when using the path directory to allow + unlimited path sizes. Minor Windows build fixes are included. + No high level security fixes in this version but we always recommend + updating. + + +yaSSL Release notes, version 2.3.9b (2/03/2016) + This release of yaSSL fixes the OpenSSL compatibility function + X509_NAME_get_index_by_NID() to use the actual index of the common name + instead of searching on the format prefix. Thanks for the report from + yashwant.sahu@oracle.com . Anyone using this function should update. + +yaSSL Release notes, version 2.3.9 (12/01/2015) + This release of yaSSL fixes two client side Diffie-Hellman problems. + yaSSL was only handling the cases of zero or one leading zeros for the key + agreement instead of potentially any number. This caused about 1 in 50,000 + connections to fail when using DHE cipher suites. The second problem was + the case where a server would send a public value shorter than the prime + value, causing about 1 in 128 client connections to fail, and also + caused the yaSSL client to read off the end of memory. All client side + DHE cipher suite users should update. + Thanks to Adam Langely (agl@imperialviolet.org) for the detailed report! + +yaSSL Release notes, version 2.3.8 (9/17/2015) + This release of yaSSL fixes a high security vulnerability. All users + SHOULD update. If using yaSSL for TLS on the server side with private + RSA keys allowing ephemeral key exchange you MUST update and regenerate + the RSA private keys. This report is detailed in: + https://people.redhat.com/~fweimer/rsa-crt-leaks.pdf + yaSSL now detects RSA signature faults and returns an error. + +yaSSL Patch notes, version 2.3.7e (6/26/2015) + This release of yaSSL includes a fix for Date less than comparison. + Previously yaSSL would return true on less than comparisons if the Dates + were equal. Reported by Oracle. No security problem, but if a cert was + generated right now, a server started using it in the same second, and a + client tried to verify it in the same second it would report not yet valid. + +yaSSL Patch notes, version 2.3.7d (6/22/2015) + This release of yaSSL includes a fix for input_buffer set_current with + index 0. SSL_peek() at front of waiting data could trigger. Robert + Golebiowski of Oracle identified and suggested a fix, thanks! + +yaSSL Patch notes, version 2.3.7c (6/12/2015) + This release of yaSSL does certificate DATE comparisons to the second + instead of to the minute, helpful when using freshly generated certs. + Though keep in mind that time sync differences could still show up. + yaSSL Patch notes, version 2.3.7b (3/18/2015) This release of yaSSL fixes a potential crash with corrupted private keys. Also detects bad keys earlier for user. @@ -24,7 +84,7 @@ yaSSL Release notes, version 2.3.6 (11/25/2014) This release of yaSSL fixes some valgrind warnings/errors including uninitialized reads and off by one index errors induced from fuzzing - the handshake. These were reported by Oracle. + the handshake. These were reported by Oracle. yaSSL Release notes, version 2.3.5 (9/29/2014) @@ -113,7 +173,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. This release of yaSSL contains bug fixes, the removal of assert() s and a security patch for a buffer overflow possibility in certificate name - processing. + processing. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -141,7 +201,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.9.2 (9/24/08) This release of yaSSL contains bug fixes and improved certificate verify - callback support. + callback support. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -149,7 +209,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.8.8 (5/7/08) - This release of yaSSL contains bug fixes, and better socket handling. + This release of yaSSL contains bug fixes, and better socket handling. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -159,7 +219,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. This release of yaSSL contains bug fixes, and fixes security problems associated with using SSL 2.0 client hellos and improper input handling. - Please upgrade to this version if you are using a previous one. + Please upgrade to this version if you are using a previous one. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -168,7 +228,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.7.5 (10/15/07) This release of yaSSL contains bug fixes, adds MSVC 2005 project support, - GCC 4.2 support, IPV6 support and test, and new test certificates. + GCC 4.2 support, IPV6 support and test, and new test certificates. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -177,7 +237,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. *****************yaSSL Release notes, version 1.7.2 (8/20/07) This release of yaSSL contains bug fixes and adds initial OpenVPN support. - Just configure at this point and beginning of build. + Just configure at this point and beginning of build. See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0 and note in 1.5.8. @@ -208,8 +268,8 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. Since yaSSL now supports zlib, as does libcurl, the libcurl build test can - fail if yaSSL is built with zlib support since the zlib library isn't - passed. You can do two things to fix this: + fail if yaSSL is built with zlib support since the zlib library isn't + passed. You can do two things to fix this: 1) build yaSSL w/o zlib --without-zlib 2) or add flags to curl configure LDFLAGS="-lm -lz" @@ -223,7 +283,7 @@ See libcurl build instructions below under 1.3.0 and note in 1.5.8. SSL_METHOD *TLSv1_1_server_method(void); SSL_METHOD *TLSv1_1_client_method(void); - + or the SSLv23 versions (even though yaSSL doesn't support SSL 2.0 the v23 means to pick the highest of SSL 3.0, TLS 1.0, or TLS 1.1). @@ -260,7 +320,7 @@ See libcurl build instructions below under 1.3.0. 2) follow the instructions in zlib from projects/visualc6/README.txt for how to add the zlib project into the yaSSL workspace noting that you'll need to add configuration support for "Win32 Debug" and - "Win32 Release" in note 3 under "To use:". + "Win32 Release" in note 3 under "To use:". 3) define HAVE_LIBZ when building yaSSL @@ -272,7 +332,7 @@ See libcurl build instructions below under 1.3.0. This release of yaSSL contains bug fixes, portability enhancements, - nonblocking connect and accept, better OpenSSL error mapping, and + nonblocking connect and accept, better OpenSSL error mapping, and certificate caching for session resumption. See normal build instructions below under 1.0.6. @@ -283,7 +343,7 @@ See libcurl build instructions below under 1.3.0. This release of yaSSL contains bug fixes, portability enhancements, - and libcurl 7.15.4 support (any newer versions may not build). + and libcurl 7.15.4 support (any newer versions may not build). See normal build instructions below under 1.0.6. See libcurl build instructions below under 1.3.0. @@ -325,12 +385,12 @@ See normal build instructions below under 1.0.6. --To build for libcurl on Win32: - Simply add the yaSSL project as a dependency to libcurl, add + Simply add the yaSSL project as a dependency to libcurl, add yaSSL-Home\include and yaSSL-Home\include\openssl to the include list, and define USE_SSLEAY and USE_OPENSSL please email todd@yassl.com if you have any questions. - + *******************yaSSL Release notes, version 1.2.2 (03/27/06) @@ -523,8 +583,8 @@ Please see build instructions in release notes 0.3.0. ******************yaSSL Release notes, version 0.4.0 This release of yaSSL contains minor bug fixes, an optional memory tracker, -an echo client and server with input/output redirection for load testing, -and initial session caching support. +an echo client and server with input/output redirection for load testing, +and initial session caching support. Please see build instructions in release notes 0.3.0. @@ -572,7 +632,7 @@ See the notes at the bottom of this page for build instructions. *******************yaSSL Release notes, version 0.2.0 This release of yaSSL contains minor bug fixes and initial alternate crypto -functionality. +functionality. *** Complete Build *** @@ -588,7 +648,7 @@ gzip -cd yassl-update-0.2.0.tar.gz | tar xvf - to update the previous release. -Then issue the make command on linux or rebuild the yaSSL project on Windows. +Then issue the make command on linux or rebuild the yaSSL project on Windows. *******************yaSSL Release notes, version 0.1.0 @@ -648,7 +708,7 @@ Building yassl on linux: use the ./buildall script to build everything. -buildall will configure and build CML, CryptoPP, and yassl. Testing was +buildall will configure and build CML, CryptoPP, and yassl. Testing was preformed with gcc version 3.3.2 on kernel 2.4.22. diff --git a/cdk/extra/yassl/certs/dsa-cert.pem b/cdk/extra/yassl/certs/dsa-cert.pem index 10d533edc..10794cbee 100644 --- a/cdk/extra/yassl/certs/dsa-cert.pem +++ b/cdk/extra/yassl/certs/dsa-cert.pem @@ -1,22 +1,22 @@ -----BEGIN CERTIFICATE----- -MIIDqzCCA2ugAwIBAgIJAMGqrgDU6DyhMAkGByqGSM44BAMwgY4xCzAJBgNVBAYT +MIIDrzCCA2+gAwIBAgIJAK1zRM7YFcNjMAkGByqGSM44BAMwgZAxCzAJBgNVBAYT AlVTMQ8wDQYDVQQIDAZPcmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMRAwDgYDVQQK -DAd3b2xmU1NMMRAwDgYDVQQLDAd0ZXN0aW5nMRYwFAYDVQQDDA13d3cueWFzc2wu -Y29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tMB4XDTEzMDQyMjIw -MDk0NFoXDTE2MDExNzIwMDk0NFowgY4xCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZP -cmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMRAwDgYDVQQKDAd3b2xmU1NMMRAwDgYD -VQQLDAd0ZXN0aW5nMRYwFAYDVQQDDA13d3cueWFzc2wuY29tMR8wHQYJKoZIhvcN -AQkBFhBpbmZvQHdvbGZzc2wuY29tMIIBuDCCASwGByqGSM44BAEwggEfAoGBAL1R -7koy4IrH6sbh6nDEUUPPKgfhxxLCWCVexF2+qzANEr+hC9M002haJXFOfeS9DyoO -WFbL0qMZOuqv+22CaHnoUWl7q3PjJOAI3JH0P54ZyUPuU1909RzgTdIDp5+ikbr7 -KYjnltL73FQVMbjTZQKthIpPn3MjYcF+4jp2W2zFAhUAkcntYND6MGf+eYzIJDN2 -L7SonHUCgYEAklpxErfqznIZjVvqqHFaq+mgAL5J8QrKVmdhYZh/Y8z4jCjoCA8o -TDoFKxf7s2ZzgaPKvglaEKiYqLqic9qY78DYJswzQMLFvjsF4sFZ+pYCBdWPQI4N -PgxCiznK6Ce+JH9ikSBvMvG+tevjr2UpawDIHX3+AWYaZBZwKADAaboDgYUAAoGB -AJ3LY89yHyvQ/TsQ6zlYbovjbk/ogndsMqPdNUvL4RuPTgJP/caaDDa0XJ7ak6A7 -TJ+QheLNwOXoZPYJC4EGFSDAXpYniGhbWIrVTCGe6lmZDfnx40WXS0kk3m/DHaC0 -3ElLAiybxVGxyqoUfbT3Zv1JwftWMuiqHH5uADhdXuXVo1AwTjAdBgNVHQ4EFgQU -IJjk416o4v8qpH9LBtXlR9v8gccwHwYDVR0jBBgwFoAUIJjk416o4v8qpH9LBtXl -R9v8gccwDAYDVR0TBAUwAwEB/zAJBgcqhkjOOAQDAy8AMCwCFCjGKIdOSV12LcTu -k08owGM6YkO1AhQe+K173VuaO/OsDNsxZlKpyH8+1g== +DAd3b2xmU1NMMRAwDgYDVQQLDAd0ZXN0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz +bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMTYwOTIy +MjEyMzA0WhcNMjIwMzE1MjEyMzA0WjCBkDELMAkGA1UEBhMCVVMxDzANBgNVBAgM +Bk9yZWdvbjERMA8GA1UEBwwIUG9ydGxhbmQxEDAOBgNVBAoMB3dvbGZTU0wxEDAO +BgNVBAsMB3Rlc3RpbmcxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG +SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCAbgwggEsBgcqhkjOOAQBMIIBHwKB +gQC9Ue5KMuCKx+rG4epwxFFDzyoH4ccSwlglXsRdvqswDRK/oQvTNNNoWiVxTn3k +vQ8qDlhWy9KjGTrqr/ttgmh56FFpe6tz4yTgCNyR9D+eGclD7lNfdPUc4E3SA6ef +opG6+ymI55bS+9xUFTG402UCrYSKT59zI2HBfuI6dltsxQIVAJHJ7WDQ+jBn/nmM +yCQzdi+0qJx1AoGBAJJacRK36s5yGY1b6qhxWqvpoAC+SfEKylZnYWGYf2PM+Iwo +6AgPKEw6BSsX+7Nmc4Gjyr4JWhComKi6onPamO/A2CbMM0DCxb47BeLBWfqWAgXV +j0CODT4MQos5yugnviR/YpEgbzLxvrXr469lKWsAyB19/gFmGmQWcCgAwGm6A4GF +AAKBgQCdy2PPch8r0P07EOs5WG6L425P6IJ3bDKj3TVLy+Ebj04CT/3Gmgw2tFye +2pOgO0yfkIXizcDl6GT2CQuBBhUgwF6WJ4hoW1iK1UwhnupZmQ358eNFl0tJJN5v +wx2gtNxJSwIsm8VRscqqFH2092b9ScH7VjLoqhx+bgA4XV7l1aNQME4wHQYDVR0O +BBYEFCCY5ONeqOL/KqR/SwbV5Ufb/IHHMB8GA1UdIwQYMBaAFCCY5ONeqOL/KqR/ +SwbV5Ufb/IHHMAwGA1UdEwQFMAMBAf8wCQYHKoZIzjgEAwMvADAsAhQRYSCVN/Ge +agV3mffU3qNZ92fI0QIUPH7Jp+iASI7U1ocaYDc10qXGaGY= -----END CERTIFICATE----- diff --git a/cdk/extra/yassl/include/crypto_wrapper.hpp b/cdk/extra/yassl/include/crypto_wrapper.hpp index db9136c53..84419e342 100644 --- a/cdk/extra/yassl/include/crypto_wrapper.hpp +++ b/cdk/extra/yassl/include/crypto_wrapper.hpp @@ -17,7 +17,7 @@ */ -/* The crypto wrapper header is used to define policies for the cipher +/* The crypto wrapper header is used to define policies for the cipher * components used by SSL. There are 3 policies to consider: * * 1) MAC, the Message Authentication Code used for each Message @@ -174,7 +174,7 @@ class HMAC_RMD : public Digest { }; -// BulkCipher policy should implement encrypt, decrypt, get block size, +// BulkCipher policy should implement encrypt, decrypt, get block size, // and set keys for encrypt and decrypt struct BulkCipher : public virtual_base { virtual void encrypt(byte*, const byte*, unsigned int) = 0; @@ -318,7 +318,7 @@ struct Auth : public virtual_base { // For use with NULL Authentication schemes struct NO_Auth : public Auth { void sign(byte*, const byte*, unsigned int, const RandomPool&) {} - bool verify(const byte*, unsigned int, const byte*, unsigned int) + bool verify(const byte*, unsigned int, const byte*, unsigned int) { return true; } }; @@ -372,11 +372,12 @@ class DiffieHellman { DiffieHellman(const Integer&, const Integer&, const RandomPool&); ~DiffieHellman(); - DiffieHellman(const DiffieHellman&); + DiffieHellman(const DiffieHellman&); DiffieHellman& operator=(const DiffieHellman&); uint get_agreedKeyLength() const; const byte* get_agreedKey() const; + uint get_publicKeyLength() const; const byte* get_publicKey() const; void makeAgreement(const byte*, unsigned int); diff --git a/cdk/extra/yassl/include/openssl/generate_prefix_files.pl b/cdk/extra/yassl/include/openssl/generate_prefix_files.pl old mode 100644 new mode 100755 diff --git a/cdk/extra/yassl/include/openssl/ssl.h b/cdk/extra/yassl/include/openssl/ssl.h index becf7aacd..37654ab71 100644 --- a/cdk/extra/yassl/include/openssl/ssl.h +++ b/cdk/extra/yassl/include/openssl/ssl.h @@ -34,7 +34,7 @@ #include "rsa.h" -#define YASSL_VERSION "2.3.7b" +#define YASSL_VERSION "2.4.2" #if defined(__cplusplus) @@ -335,9 +335,6 @@ enum { /* ssl Constants */ SSL_OP_ALL = 61, SSL_OP_SINGLE_DH_USE = 62, SSL_OP_EPHEMERAL_RSA = 63, - SSL_OP_NO_SSLv2 = 64, - SSL_OP_NO_SSLv3 = 65, - SSL_OP_NO_TLSv1 = 66, SSL_OP_PKCS1_CHECK_1 = 67, SSL_OP_PKCS1_CHECK_2 = 68, SSL_OP_NETSCAPE_CA_DN_BUG = 69, @@ -358,8 +355,12 @@ enum { /* ssl Constants */ SSL_RECEIVED_SHUTDOWN = 94, SSL_CB_ALERT = 95, SSL_CB_READ = 96, - SSL_CB_HANDSHAKE_DONE = 97 + SSL_CB_HANDSHAKE_DONE = 97, + SSL_OP_NO_SSLv2 = 128, + SSL_OP_NO_SSLv3 = 256, + SSL_OP_NO_TLSv1 = 512, + SSL_OP_NO_TLSv1_1 = 1024, }; diff --git a/cdk/extra/yassl/include/yassl_error.hpp b/cdk/extra/yassl/include/yassl_error.hpp index beba7b0b5..d63244dca 100644 --- a/cdk/extra/yassl/include/yassl_error.hpp +++ b/cdk/extra/yassl/include/yassl_error.hpp @@ -53,7 +53,8 @@ enum YasslError { compress_error = 118, decompress_error = 119, pms_version_error = 120, - sanityCipher_error = 121 + sanityCipher_error = 121, + rsaSignFault_error = 122 // !!!! add error message to .cpp !!!! diff --git a/cdk/extra/yassl/include/yassl_int.hpp b/cdk/extra/yassl/include/yassl_int.hpp index 85cbbc966..b360b7775 100644 --- a/cdk/extra/yassl/include/yassl_int.hpp +++ b/cdk/extra/yassl/include/yassl_int.hpp @@ -53,7 +53,6 @@ char* yassl_get_tty_password(const char*); #define get_tty_password yassl_get_tty_password - namespace STL = STL_NAMESPACE; @@ -201,14 +200,19 @@ class sslFactory { class X509_NAME { char* name_; size_t sz_; + int cnPosition_; // start of common name, -1 is none + int cnLen_; // length of above ASN1_STRING entry_; public: - X509_NAME(const char*, size_t sz); + X509_NAME(const char*, size_t sz, int pos, int len); ~X509_NAME(); const char* GetName() const; ASN1_STRING* GetEntry(int i); size_t GetLength() const; + int GetCnPosition() const { return cnPosition_; } + int GetCnLength() const { return cnLen_; } + private: X509_NAME(const X509_NAME&); // hide copy X509_NAME& operator=(const X509_NAME&); // and assign @@ -236,7 +240,7 @@ class X509 { StringHolder afterDate_; // not valid after public: X509(const char* i, size_t, const char* s, size_t, - ASN1_STRING *b, ASN1_STRING *a); + ASN1_STRING *b, ASN1_STRING *a, int, int, int, int); ~X509() {} X509_NAME* GetIssuer(); @@ -488,7 +492,7 @@ class SSL_CTX { void SetUserData(void*); void SetSessionCacheOff(); void SetSessionCacheFlushOff(); - + void SetMethod(SSL_METHOD* meth); void IncrementStats(StatsField); void AddCA(x509* ca); const CertList& GetCA_List() const; diff --git a/cdk/extra/yassl/src/buffer.cpp b/cdk/extra/yassl/src/buffer.cpp index 07325c0e2..e5a996b7f 100644 --- a/cdk/extra/yassl/src/buffer.cpp +++ b/cdk/extra/yassl/src/buffer.cpp @@ -162,7 +162,7 @@ void input_buffer::set_error() void input_buffer::set_current(uint i) { - if (error_ == 0 && i && check(i - 1, size_) == 0) + if (error_ == 0 && check(i ? i - 1 : 0, size_) == 0) current_ = i; else error_ = -1; diff --git a/cdk/extra/yassl/src/cert_wrapper.cpp b/cdk/extra/yassl/src/cert_wrapper.cpp index af94f5bc2..96c8e94fa 100644 --- a/cdk/extra/yassl/src/cert_wrapper.cpp +++ b/cdk/extra/yassl/src/cert_wrapper.cpp @@ -37,14 +37,14 @@ namespace yaSSL { -x509::x509(uint sz) : length_(sz), buffer_(NEW_YS opaque[sz]) +x509::x509(uint sz) : length_(sz), buffer_(NEW_YS opaque[sz]) { } -x509::~x509() -{ - ysArrayDelete(buffer_); +x509::~x509() +{ + ysArrayDelete(buffer_); } @@ -71,20 +71,20 @@ x509& x509::operator=(const x509& that) uint x509::get_length() const -{ - return length_; +{ + return length_; } const opaque* x509::get_buffer() const -{ - return buffer_; +{ + return buffer_; } opaque* x509::use_buffer() -{ - return buffer_; +{ + return buffer_; } @@ -173,7 +173,7 @@ void CertManager::setVerifyCallback(VerifyCallback vc) void CertManager::AddPeerCert(x509* x) -{ +{ peerList_.push_back(x); // take ownership } @@ -203,13 +203,13 @@ int CertManager::CopyCaCert(const x509* x) const x509* CertManager::get_cert() const -{ +{ return list_.front(); } const opaque* CertManager::get_peerKey() const -{ +{ return peerPublicKey_.get_buffer(); } @@ -239,19 +239,19 @@ SignatureAlgorithm CertManager::get_keyType() const uint CertManager::get_peerKeyLength() const -{ +{ return peerPublicKey_.get_size(); } const opaque* CertManager::get_privateKey() const -{ +{ return privateKey_.get_buffer(); } uint CertManager::get_privateKeyLength() const -{ +{ return privateKey_.get_size(); } @@ -304,7 +304,10 @@ int CertManager::Validate() afterDate.type= cert.GetAfterDateType(); afterDate.length= strlen((char *) afterDate.data) + 1; peerX509_ = NEW_YS X509(cert.GetIssuer(), iSz, cert.GetCommonName(), - sSz, &beforeDate, &afterDate); + sSz, &beforeDate, &afterDate, + cert.GetIssuerCnStart(), cert.GetIssuerCnLength(), + cert.GetSubjectCnStart(), cert.GetSubjectCnLength() + ); if (err == TaoCrypt::SIG_OTHER_E && verifyCallback_) { X509_STORE_CTX store; @@ -350,7 +353,9 @@ int CertManager::SetPrivateKey(const x509& key) afterDate.type= cd.GetAfterDateType(); afterDate.length= strlen((char *) afterDate.data) + 1; selfX509_ = NEW_YS X509(cd.GetIssuer(), iSz, cd.GetCommonName(), - sSz, &beforeDate, &afterDate); + sSz, &beforeDate, &afterDate, + cd.GetIssuerCnStart(), cd.GetIssuerCnLength(), + cd.GetSubjectCnStart(), cd.GetSubjectCnLength()); } return 0; } @@ -367,7 +372,9 @@ void CertManager::setPeerX509(X509* x) ASN1_STRING* after = x->GetAfter(); peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(), - subject->GetName(), subject->GetLength(), before, after); + subject->GetName(), subject->GetLength(), before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); } diff --git a/cdk/extra/yassl/src/crypto_wrapper.cpp b/cdk/extra/yassl/src/crypto_wrapper.cpp index 529943645..e9b4586da 100644 --- a/cdk/extra/yassl/src/crypto_wrapper.cpp +++ b/cdk/extra/yassl/src/crypto_wrapper.cpp @@ -58,7 +58,7 @@ MD5::MD5() : pimpl_(NEW_YS MD5Impl) {} MD5::~MD5() { ysDelete(pimpl_); } -MD5::MD5(const MD5& that) : Digest(), pimpl_(NEW_YS +MD5::MD5(const MD5& that) : Digest(), pimpl_(NEW_YS MD5Impl(that.pimpl_->md5_)) {} @@ -223,8 +223,8 @@ struct HMAC_MD5::HMAC_MD5Impl { }; -HMAC_MD5::HMAC_MD5(const byte* secret, unsigned int len) - : pimpl_(NEW_YS HMAC_MD5Impl) +HMAC_MD5::HMAC_MD5(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_MD5Impl) { pimpl_->mac_.SetKey(secret, len); } @@ -273,8 +273,8 @@ struct HMAC_SHA::HMAC_SHAImpl { }; -HMAC_SHA::HMAC_SHA(const byte* secret, unsigned int len) - : pimpl_(NEW_YS HMAC_SHAImpl) +HMAC_SHA::HMAC_SHA(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_SHAImpl) { pimpl_->mac_.SetKey(secret, len); } @@ -324,8 +324,8 @@ struct HMAC_RMD::HMAC_RMDImpl { }; -HMAC_RMD::HMAC_RMD(const byte* secret, unsigned int len) - : pimpl_(NEW_YS HMAC_RMDImpl) +HMAC_RMD::HMAC_RMD(const byte* secret, unsigned int len) + : pimpl_(NEW_YS HMAC_RMDImpl) { pimpl_->mac_.SetKey(secret, len); } @@ -536,7 +536,7 @@ RandomPool::~RandomPool() { ysDelete(pimpl_); } int RandomPool::GetError() const { - return pimpl_->RNG_.GetError(); + return pimpl_->RNG_.GetError(); } void RandomPool::Fill(opaque* dst, uint sz) const @@ -573,10 +573,10 @@ void DSS::DSSImpl::SetPrivate(const byte* key, unsigned int sz) // Set public or private key -DSS::DSS(const byte* key, unsigned int sz, bool publicKey) +DSS::DSS(const byte* key, unsigned int sz, bool publicKey) : pimpl_(NEW_YS DSSImpl) { - if (publicKey) + if (publicKey) pimpl_->SetPublic(key, sz); else pimpl_->SetPrivate(key, sz); @@ -644,10 +644,10 @@ void RSA::RSAImpl::SetPrivate(const byte* key, unsigned int sz) // Set public or private key -RSA::RSA(const byte* key, unsigned int sz, bool publicKey) +RSA::RSA(const byte* key, unsigned int sz, bool publicKey) : pimpl_(NEW_YS RSAImpl) { - if (publicKey) + if (publicKey) pimpl_->SetPublic(key, sz); else pimpl_->SetPrivate(key, sz); @@ -695,7 +695,7 @@ bool RSA::verify(const byte* message, unsigned int sz, const byte* sig, void RSA::encrypt(byte* cipher, const byte* plain, unsigned int sz, const RandomPool& random) { - + TaoCrypt::RSAES_Encryptor enc(pimpl_->publicKey_); enc.Encrypt(plain, sz, cipher, random.pimpl_->RNG_); } @@ -723,7 +723,7 @@ Integer::~Integer() { ysDelete(pimpl_); } -Integer::Integer(const Integer& other) : pimpl_(NEW_YS +Integer::Integer(const Integer& other) : pimpl_(NEW_YS IntegerImpl(other.pimpl_->int_)) {} @@ -748,18 +748,19 @@ struct DiffieHellman::DHImpl { byte* publicKey_; byte* privateKey_; byte* agreedKey_; + uint pubKeyLength_; DHImpl(TaoCrypt::RandomNumberGenerator& r) : ranPool_(r), publicKey_(0), - privateKey_(0), agreedKey_(0) {} - ~DHImpl() - { - ysArrayDelete(agreedKey_); - ysArrayDelete(privateKey_); + privateKey_(0), agreedKey_(0), pubKeyLength_(0) {} + ~DHImpl() + { + ysArrayDelete(agreedKey_); + ysArrayDelete(privateKey_); ysArrayDelete(publicKey_); } DHImpl(const DHImpl& that) : dh_(that.dh_), ranPool_(that.ranPool_), - publicKey_(0), privateKey_(0), agreedKey_(0) + publicKey_(0), privateKey_(0), agreedKey_(0), pubKeyLength_(0) { uint length = dh_.GetByteLength(); AllocKeys(length, length, length); @@ -807,7 +808,7 @@ DiffieHellman::DiffieHellman(const byte* p, unsigned int pSz, const byte* g, using TaoCrypt::Integer; pimpl_->dh_.Initialize(Integer(p, pSz).Ref(), Integer(g, gSz).Ref()); - pimpl_->publicKey_ = NEW_YS opaque[pubSz]; + pimpl_->publicKey_ = NEW_YS opaque[pimpl_->pubKeyLength_ = pubSz]; memcpy(pimpl_->publicKey_, pub, pubSz); } @@ -832,9 +833,9 @@ DiffieHellman::~DiffieHellman() { ysDelete(pimpl_); } // Client side and view, use server that for p and g -DiffieHellman::DiffieHellman(const DiffieHellman& that) +DiffieHellman::DiffieHellman(const DiffieHellman& that) : pimpl_(NEW_YS DHImpl(*that.pimpl_)) -{ +{ pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, pimpl_->publicKey_); } @@ -851,7 +852,7 @@ DiffieHellman& DiffieHellman::operator=(const DiffieHellman& that) void DiffieHellman::makeAgreement(const byte* other, unsigned int otherSz) { - pimpl_->dh_.Agree(pimpl_->agreedKey_, pimpl_->privateKey_, other, otherSz); + pimpl_->dh_.Agree(pimpl_->agreedKey_, pimpl_->privateKey_, other, otherSz); } @@ -866,6 +867,10 @@ const byte* DiffieHellman::get_agreedKey() const return pimpl_->agreedKey_; } +uint DiffieHellman::get_publicKeyLength() const +{ + return pimpl_->pubKeyLength_; +} const byte* DiffieHellman::get_publicKey() const { @@ -954,7 +959,7 @@ x509* PemToDer(FILE* file, CertType type, EncryptedInfo* info) if (fgets(line,sizeof(line), file)) // get blank line begin = ftell(file); } - + } while(fgets(line, sizeof(line), file)) @@ -973,7 +978,7 @@ x509* PemToDer(FILE* file, CertType type, EncryptedInfo* info) size_t bytes = fread(tmp.get_buffer(), end - begin, 1, file); if (bytes != 1) return 0; - + Source der(tmp.get_buffer(), end - begin); Base64Decoder b64Dec(der); diff --git a/cdk/extra/yassl/src/handshake.cpp b/cdk/extra/yassl/src/handshake.cpp index e63d69e9e..212163e6b 100644 --- a/cdk/extra/yassl/src/handshake.cpp +++ b/cdk/extra/yassl/src/handshake.cpp @@ -44,7 +44,7 @@ void buildClientHello(SSL& ssl, ClientHello& hello) memcpy(hello.session_id_, ssl.getSecurity().get_resume().GetID(), ID_LEN); } - else + else hello.id_len_ = 0; hello.suite_len_ = ssl.getSecurity().get_parms().suites_size_; memcpy(hello.cipher_suites_, ssl.getSecurity().get_parms().suites_, @@ -87,7 +87,7 @@ void buildServerHello(SSL& ssl, ServerHello& hello) // add handshake from buffer into md5 and sha hashes, use handshake header void hashHandShake(SSL& ssl, const input_buffer& input, uint sz) { - const opaque* buffer = input.get_buffer() + input.get_current() - + const opaque* buffer = input.get_buffer() + input.get_current() - HANDSHAKE_HEADER; sz += HANDSHAKE_HEADER; ssl.useHashes().use_MD5().update(buffer, sz); @@ -99,7 +99,7 @@ void hashHandShake(SSL& ssl, const input_buffer& input, uint sz) namespace { // Write a plaintext record to buffer -void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, +void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, const Message& msg) { buffer.allocate(RECORD_HEADER + rlHdr.length_); @@ -108,7 +108,7 @@ void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, // Write a plaintext record to buffer -void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, +void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, const HandShakeHeader& hsHdr, const HandShakeBase& shake) { buffer.allocate(RECORD_HEADER + rlHdr.length_); @@ -170,7 +170,7 @@ void buildMD5(SSL& ssl, Finished& fin, const opaque* sender) opaque md5_inner[SIZEOF_SENDER + SECRET_LEN + PAD_MD5]; opaque md5_outer[SECRET_LEN + PAD_MD5 + MD5_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make md5 inner @@ -194,12 +194,12 @@ void buildMD5(SSL& ssl, Finished& fin, const opaque* sender) // calculate SHA hash for finished void buildSHA(SSL& ssl, Finished& fin, const opaque* sender) { - + opaque sha_result[SHA_LEN]; opaque sha_inner[SIZEOF_SENDER + SECRET_LEN + PAD_SHA]; opaque sha_outer[SECRET_LEN + PAD_SHA + SHA_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make sha inner @@ -309,7 +309,7 @@ void cipherFinished(SSL& ssl, Finished& fin, output_buffer& output) uint ivSz = iv.get_size(); output.allocate(sz); output << rlHeader << iv << hsHeader << fin; - + hashHandShake(ssl, output, ssl.isTLSv1_1() ? true : false); opaque digest[SHA_LEN]; // max size if (ssl.isTLS()) @@ -335,7 +335,7 @@ void cipherFinished(SSL& ssl, Finished& fin, output_buffer& output) void buildMessage(SSL& ssl, output_buffer& output, const Message& msg) { uint digestSz = ssl.getCrypto().get_digest().get_digestSize(); - uint sz = RECORD_HEADER + msg.get_length() + digestSz; + uint sz = RECORD_HEADER + msg.get_length() + digestSz; uint pad = 0; uint blockSz = ssl.getCrypto().get_cipher().get_blockSize(); @@ -358,11 +358,11 @@ void buildMessage(SSL& ssl, output_buffer& output, const Message& msg) ssl.getCrypto().get_random().Fill(iv.get_buffer(), blockSz); iv.add_size(blockSz); } - + uint ivSz = iv.get_size(); output.allocate(sz); output << rlHeader << iv << msg; - + opaque digest[SHA_LEN]; // max size if (ssl.isTLS()) TLS_hmac(ssl, digest, output.get_buffer() + RECORD_HEADER + ivSz, @@ -397,7 +397,7 @@ void buildAlert(SSL& ssl, output_buffer& output, const Alert& alert) // build TLS finished message -void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) +void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) { opaque handshake_hash[FINISHED_SZ]; @@ -410,9 +410,9 @@ void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) else side = tls_server; - PRF(fin.set_md5(), TLS_FINISHED_SZ, - ssl.getSecurity().get_connection().master_secret_, SECRET_LEN, - side, FINISHED_LABEL_SZ, + PRF(fin.set_md5(), TLS_FINISHED_SZ, + ssl.getSecurity().get_connection().master_secret_, SECRET_LEN, + side, FINISHED_LABEL_SZ, handshake_hash, FINISHED_SZ); fin.set_length(TLS_FINISHED_SZ); // shorter length for TLS @@ -441,7 +441,7 @@ void p_hash(output_buffer& result, const output_buffer& secret, uint lastTime = times - 1; for (uint i = 0; i < times; i++) { - hmac->update(previous, len); + hmac->update(previous, len); hmac->get_digest(current, seed.get_buffer(), seed.get_size()); if (lastLen && (i == lastTime)) @@ -459,7 +459,7 @@ void p_hash(output_buffer& result, const output_buffer& secret, void get_xor(byte *digest, uint digLen, output_buffer& md5, output_buffer& sha) { - for (uint i = 0; i < digLen; i++) + for (uint i = 0; i < digLen; i++) digest[i] = md5[AUTO] ^ sha[AUTO]; } @@ -471,7 +471,7 @@ void buildMD5_CertVerify(SSL& ssl, byte* digest) opaque md5_inner[SECRET_LEN + PAD_MD5]; opaque md5_outer[SECRET_LEN + PAD_MD5 + MD5_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make md5 inner @@ -497,7 +497,7 @@ void buildSHA_CertVerify(SSL& ssl, byte* digest) opaque sha_inner[SECRET_LEN + PAD_SHA]; opaque sha_outer[SECRET_LEN + PAD_SHA + SHA_LEN]; - const opaque* master_secret = + const opaque* master_secret = ssl.getSecurity().get_connection().master_secret_; // make sha inner @@ -572,7 +572,7 @@ void ProcessOldClientHello(input_buffer& input, SSL& ssl) } int j = 0; - for (uint16 i = 0; i < ch.suite_len_; i += 3) { + for (uint16 i = 0; i < ch.suite_len_; i += 3) { byte first = input[AUTO]; if (first) // sslv2 type input.read(len, SUITE_LEN); // skip @@ -589,13 +589,13 @@ void ProcessOldClientHello(input_buffer& input, SSL& ssl) if (randomLen < RAN_LEN) memset(ch.random_, 0, RAN_LEN - randomLen); input.read(&ch.random_[RAN_LEN - randomLen], randomLen); - + ch.Process(input, ssl); } // Build a finished message, see 7.6.9 -void buildFinished(SSL& ssl, Finished& fin, const opaque* sender) +void buildFinished(SSL& ssl, Finished& fin, const opaque* sender) { // store current states, building requires get_digest which resets state MD5 md5(ssl.getHashes().get_MD5()); @@ -623,7 +623,7 @@ void hmac(SSL& ssl, byte* digest, const byte* buffer, uint sz, { Digest& mac = ssl.useCrypto().use_digest(); opaque inner[SHA_LEN + PAD_MD5 + SEQ_SZ + SIZEOF_ENUM + LENGTH_SZ]; - opaque outer[SHA_LEN + PAD_MD5 + SHA_LEN]; + opaque outer[SHA_LEN + PAD_MD5 + SHA_LEN]; opaque result[SHA_LEN]; // max possible sizes uint digestSz = mac.get_digestSize(); // actual sizes uint padSz = mac.get_padSize(); @@ -676,11 +676,11 @@ void TLS_hmac(SSL& ssl, byte* digest, const byte* buffer, uint sz, hmac.reset(NEW_YS HMAC_RMD(ssl.get_macSecret(verify), RMD_LEN)); else hmac.reset(NEW_YS HMAC_MD5(ssl.get_macSecret(verify), MD5_LEN)); - + hmac->update(seq, SEQ_SZ); // seq_num inner[0] = content; // type - inner[SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.major_; - inner[SIZEOF_ENUM + SIZEOF_ENUM] = + inner[SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.major_; + inner[SIZEOF_ENUM + SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.minor_; // version memcpy(&inner[SIZEOF_ENUM + VERSION_SZ], length, LENGTH_SZ); // length hmac->update(inner, sizeof(inner)); @@ -760,14 +760,16 @@ int DoProcessReply(SSL& ssl) if (read == static_cast(-1)) { ssl.SetError(receive_error); return 0; - } + } else if (read == 0) + return 1; + buffer.add_size(read); uint offset = 0; const MessageFactory& mf = ssl.getFactory().getMessage(); // old style sslv2 client hello? if (ssl.getSecurity().get_parms().entity_ == server_end && - ssl.getStates().getServer() == clientNull) + ssl.getStates().getServer() == clientNull) if (buffer.peek() != handshake) { ProcessOldClientHello(buffer, ssl); if (ssl.GetError()) @@ -814,7 +816,7 @@ int DoProcessReply(SSL& ssl) if (ssl.GetError()) return 0; } - + mySTL::auto_ptr msg(mf.CreateObject(hdr.type_)); if (!msg.get()) { ssl.SetError(factory_error); @@ -835,7 +837,7 @@ int DoProcessReply(SSL& ssl) void processReply(SSL& ssl) { if (ssl.GetError()) return; - + if (DoProcessReply(ssl)) { // didn't complete process if (!ssl.getSocket().IsNonBlocking()) { @@ -934,7 +936,7 @@ void sendChangeCipher(SSL& ssl, BufferOutput buffer) buildHeader(ssl, rlHeader, ccs); mySTL::auto_ptr out(NEW_YS output_buffer); buildOutput(*out.get(), rlHeader, ccs); - + if (buffer == buffered) ssl.addBuffer(out.release()); else @@ -961,7 +963,7 @@ void sendFinished(SSL& ssl, ConnectionEnd side, BufferOutput buffer) GetSessions().add(ssl); // store session if (side == client_end) buildFinished(ssl, ssl.useHashes().use_verify(), server); // server - } + } ssl.useSecurity().use_connection().CleanMaster(); if (buffer == buffered) @@ -1063,7 +1065,7 @@ int receiveData(SSL& ssl, Data& data, bool peek) ssl.SetError(YasslError(SSL_ERROR_WANT_READ)); return SSL_WOULD_BLOCK; } - return data.get_length(); + return data.get_length(); } @@ -1168,6 +1170,8 @@ void sendCertificateVerify(SSL& ssl, BufferOutput buffer) CertificateVerify verify; verify.Build(ssl); + if (ssl.GetError()) return; + RecordLayerHeader rlHeader; HandShakeHeader hsHeader; mySTL::auto_ptr out(NEW_YS output_buffer); diff --git a/cdk/extra/yassl/src/lock.cpp b/cdk/extra/yassl/src/lock.cpp index c74ea1c6b..1ba2450e0 100644 --- a/cdk/extra/yassl/src/lock.cpp +++ b/cdk/extra/yassl/src/lock.cpp @@ -28,7 +28,7 @@ namespace yaSSL { #ifdef MULTI_THREADED #ifdef _WIN32 - + Mutex::Mutex() { InitializeCriticalSection(&cs_); @@ -40,20 +40,20 @@ namespace yaSSL { DeleteCriticalSection(&cs_); } - + Mutex::Lock::Lock(Mutex& lm) : mutex_(lm) { - EnterCriticalSection(&mutex_.cs_); + EnterCriticalSection(&mutex_.cs_); } Mutex::Lock::~Lock() { - LeaveCriticalSection(&mutex_.cs_); + LeaveCriticalSection(&mutex_.cs_); } - + #else // _WIN32 - + Mutex::Mutex() { pthread_mutex_init(&mutex_, 0); @@ -68,15 +68,15 @@ namespace yaSSL { Mutex::Lock::Lock(Mutex& lm) : mutex_(lm) { - pthread_mutex_lock(&mutex_.mutex_); + pthread_mutex_lock(&mutex_.mutex_); } Mutex::Lock::~Lock() { - pthread_mutex_unlock(&mutex_.mutex_); + pthread_mutex_unlock(&mutex_.mutex_); } - + #endif // _WIN32 #endif // MULTI_THREADED diff --git a/cdk/extra/yassl/src/log.cpp b/cdk/extra/yassl/src/log.cpp index c6cb8e6e4..5f034f96c 100644 --- a/cdk/extra/yassl/src/log.cpp +++ b/cdk/extra/yassl/src/log.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -60,6 +60,7 @@ namespace yaSSL { time_t clicks = time(0); char timeStr[32]; + memset(timeStr, 0, sizeof(timeStr)); // get rid of newline strncpy(timeStr, ctime(&clicks), sizeof(timeStr)); unsigned int len = strlen(timeStr); @@ -93,7 +94,7 @@ namespace yaSSL { const char* p = reinterpret_cast(&peeraddr.sin_addr); char msg[MAX_MSG]; char number[16]; - + if (ended) strncpy(msg, "yaSSL conn DONE w/ peer ", 26); else @@ -120,7 +121,7 @@ namespace yaSSL { char number[16]; if (sent) - strncpy(msg, "Sent ", 10); + strncpy(msg, "Sent ", 10); else strncpy(msg, "Received ", 10); sprintf(number, "%u", bytes); diff --git a/cdk/extra/yassl/src/socket_wrapper.cpp b/cdk/extra/yassl/src/socket_wrapper.cpp index a23c1c12e..19e2479c0 100644 --- a/cdk/extra/yassl/src/socket_wrapper.cpp +++ b/cdk/extra/yassl/src/socket_wrapper.cpp @@ -17,8 +17,8 @@ */ -/* The socket wrapper source implements a Socket class that hides the - * differences between Berkely style sockets and Windows sockets, allowing +/* The socket wrapper source implements a Socket class that hides the + * differences between Berkely style sockets and Windows sockets, allowing * transparent TCP access. */ @@ -75,7 +75,7 @@ extern "C" long system_send(void *ptr, const void *buf, size_t count) namespace yaSSL { -Socket::Socket(socket_t s) +Socket::Socket(socket_t s) : socket_(s), wouldBlock_(false), nonBlocking_(false), ptr_(&socket_), send_func_(system_send), recv_func_(system_recv) {} @@ -159,10 +159,10 @@ uint Socket::send(const byte* buf, unsigned int sz, unsigned int& written) while (pos != end) { int sent = send_func_(ptr_, pos, static_cast(end - pos)); if (sent == -1) { - if (get_lastError() == SOCKET_EWOULDBLOCK || + if (get_lastError() == SOCKET_EWOULDBLOCK || get_lastError() == SOCKET_EAGAIN) { wouldBlock_ = true; // would have blocked this time only - nonBlocking_ = true; // nonblocking, win32 only way to tell + nonBlocking_ = true; // nonblocking, win32 only way to tell return 0; } return static_cast(-1); @@ -183,7 +183,7 @@ uint Socket::receive(byte* buf, unsigned int sz) // idea to seperate error from would block by arnetheduck@gmail.com if (recvd == -1) { - if (get_lastError() == SOCKET_EWOULDBLOCK || + if (get_lastError() == SOCKET_EWOULDBLOCK || get_lastError() == SOCKET_EAGAIN) { wouldBlock_ = true; // would have blocked this time only nonBlocking_ = true; // socket nonblocking, win32 only way to tell diff --git a/cdk/extra/yassl/src/ssl.cpp b/cdk/extra/yassl/src/ssl.cpp index acefe8b65..fef2d3cdd 100644 --- a/cdk/extra/yassl/src/ssl.cpp +++ b/cdk/extra/yassl/src/ssl.cpp @@ -112,7 +112,7 @@ int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) ctx->GetUserData()); byte key[AES_256_KEY_SZ]; // max sizes byte iv[AES_IV_SZ]; - + // use file's salt for key derivation, but not real iv TaoCrypt::Source source(info.iv, info.ivSz); TaoCrypt::HexDecoder dec(source); @@ -137,7 +137,7 @@ int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) return SSL_BAD_FILE; } cipher->set_decryptKey(key, info.iv); - mySTL::auto_ptr newx(NEW_YS x509(x->get_length())); + mySTL::auto_ptr newx(NEW_YS x509(x->get_length())); cipher->decrypt(newx->use_buffer(), x->get_buffer(), x->get_length()); ysDelete(x); @@ -161,7 +161,7 @@ int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) TaoCrypt::DSA_PrivateKey dsaKey; dsaKey.Initialize(dsaSource); - if (rsaSource.GetError().What()) { + if (dsaSource.GetError().What()) { // neither worked ret = SSL_FAILURE; } @@ -278,7 +278,7 @@ int SSL_connect(SSL* ssl) ssl->SetError(no_error); if (ssl->GetError() == YasslError(SSL_ERROR_WANT_WRITE)) { - + ssl->SetError(no_error); ssl->SendWriteBuffered(); if (!ssl->GetError()) @@ -301,7 +301,7 @@ int SSL_connect(SSL* ssl) while (ssl->getStates().getClient() < neededState) { if (ssl->GetError()) break; processReply(*ssl); - // if resumption failed, reset needed state + // if resumption failed, reset needed state if (neededState == serverFinishedComplete) if (!ssl->getSecurity().get_resuming()) neededState = serverHelloDoneComplete; @@ -342,7 +342,7 @@ int SSL_connect(SSL* ssl) if (ssl->GetError()) { GetErrors().Add(ssl->GetError()); return SSL_FATAL_ERROR; - } + } return SSL_SUCCESS; default : @@ -370,7 +370,7 @@ int SSL_accept(SSL* ssl) ssl->SetError(no_error); if (ssl->GetError() == YasslError(SSL_ERROR_WANT_WRITE)) { - + ssl->SetError(no_error); ssl->SendWriteBuffered(); if (!ssl->GetError()) @@ -400,7 +400,7 @@ int SSL_accept(SSL* ssl) sendServerHelloDone(*ssl); ssl->flushBuffer(); } - + if (!ssl->GetError()) ssl->useStates().UseAccept() = SERVER_HELLO_DONE; @@ -555,8 +555,8 @@ void SSL_flush_sessions(SSL_CTX *ctx, long /* tm */) const char* SSL_get_cipher_name(SSL* ssl) -{ - return SSL_get_cipher(ssl); +{ + return SSL_get_cipher(ssl); } @@ -598,8 +598,14 @@ const char* SSL_get_version(SSL* ssl) { static const char* version3 = "SSLv3"; static const char* version31 = "TLSv1"; + static const char* version32 = "TLSv1.1"; - return ssl->isTLS() ? version31 : version3; + if (ssl->isTLSv1_1()) + return version32; + else if(ssl->isTLS()) + return version31; + else + return version3; } const char* SSLeay_version(int) @@ -639,7 +645,9 @@ X509* X509_Copy(X509 *x) X509 *newX509 = NEW_YS X509(issuer->GetName(), issuer->GetLength(), subject->GetName(), subject->GetLength(), - before, after); + before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); return newX509; } @@ -707,7 +715,10 @@ X509* PEM_read_X509(FILE *fp, X509 *x, afterDate.length = strlen((char *) afterDate.data) + 1; X509 *thisX509 = NEW_YS X509(cert.GetIssuer(), iSz, cert.GetCommonName(), - sSz, &beforeDate, &afterDate); + sSz, &beforeDate, &afterDate, + cert.GetIssuerCnStart(), cert.GetIssuerCnLength(), + cert.GetSubjectCnStart(), cert.GetSubjectCnLength()); + ysDelete(ptr); return thisX509; @@ -750,7 +761,7 @@ X509_NAME* X509_get_subject_name(X509* x) } -void SSL_load_error_strings() // compatibility only +void SSL_load_error_strings() // compatibility only {} @@ -827,7 +838,6 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, const char* path) { int ret = SSL_FAILURE; - const int HALF_PATH = 128; if (file) ret = read_file(ctx, file, SSL_FILETYPE_PEM, CA); @@ -838,48 +848,76 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, WIN32_FIND_DATA FindFileData; HANDLE hFind; - char name[MAX_PATH + 1]; // directory specification - strncpy(name, path, MAX_PATH - 3); - strncat(name, "\\*", 3); + const int DELIMITER_SZ = 2; + const int DELIMITER_STAR_SZ = 3; + int pathSz = (int)strlen(path); + int nameSz = pathSz + DELIMITER_STAR_SZ + 1; // plus 1 for terminator + char* name = NEW_YS char[nameSz]; // directory specification + memset(name, 0, nameSz); + strncpy(name, path, nameSz - DELIMITER_STAR_SZ - 1); + strncat(name, "\\*", DELIMITER_STAR_SZ); hFind = FindFirstFile(name, &FindFileData); - if (hFind == INVALID_HANDLE_VALUE) return SSL_BAD_PATH; + if (hFind == INVALID_HANDLE_VALUE) { + ysArrayDelete(name); + return SSL_BAD_PATH; + } do { - if (FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) { - strncpy(name, path, MAX_PATH - 2 - HALF_PATH); - strncat(name, "\\", 2); - strncat(name, FindFileData.cFileName, HALF_PATH); + if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + int curSz = (int)strlen(FindFileData.cFileName); + if (pathSz + curSz + DELIMITER_SZ + 1 > nameSz) { + ysArrayDelete(name); + // plus 1 for terminator + nameSz = pathSz + curSz + DELIMITER_SZ + 1; + name = NEW_YS char[nameSz]; + } + memset(name, 0, nameSz); + strncpy(name, path, nameSz - curSz - DELIMITER_SZ - 1); + strncat(name, "\\", DELIMITER_SZ); + strncat(name, FindFileData.cFileName, + nameSz - pathSz - DELIMITER_SZ - 1); ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } } while (ret == SSL_SUCCESS && FindNextFile(hFind, &FindFileData)); + ysArrayDelete(name); FindClose(hFind); #else // _WIN32 - - const int MAX_PATH = 260; - DIR* dir = opendir(path); if (!dir) return SSL_BAD_PATH; struct dirent* entry; struct stat buf; - char name[MAX_PATH + 1]; + const int DELIMITER_SZ = 1; + int pathSz = (int)strlen(path); + int nameSz = pathSz + DELIMITER_SZ + 1; //plus 1 for null terminator + char* name = NEW_YS char[nameSz]; // directory specification while (ret == SSL_SUCCESS && (entry = readdir(dir))) { - strncpy(name, path, MAX_PATH - 1 - HALF_PATH); - strncat(name, "/", 1); - strncat(name, entry->d_name, HALF_PATH); + int curSz = (int)strlen(entry->d_name); + if (pathSz + curSz + DELIMITER_SZ + 1 > nameSz) { + ysArrayDelete(name); + nameSz = pathSz + DELIMITER_SZ + curSz + 1; + name = NEW_YS char[nameSz]; + } + memset(name, 0, nameSz); + strncpy(name, path, nameSz - curSz - 1); + strncat(name, "/", DELIMITER_SZ); + strncat(name, entry->d_name, nameSz - pathSz - DELIMITER_SZ - 1); + if (stat(name, &buf) < 0) { + ysArrayDelete(name); closedir(dir); return SSL_BAD_STAT; } - + if (S_ISREG(buf.st_mode)) ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } + ysArrayDelete(name); closedir(dir); #endif @@ -1015,9 +1053,43 @@ int SSL_get_verify_depth(SSL* ssl) } -long SSL_CTX_set_options(SSL_CTX*, long) +long SSL_CTX_set_options(SSL_CTX* ctx, long options) { - // TDOD: + ProtocolVersion pv= ctx->getMethod()->getVersion(); + bool multi_proto= ctx->getMethod()->multipleProtocol(); + unsigned long ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1; + + do + { + if (options == 0) + break; + // only TLSv1.1 + if ((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 2; + multi_proto= false; + break; + } + // only TLSv1 + ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1; + if((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 1; + multi_proto= false; + break; + } + // TLSv1.1 and TLSv1 + ssl_ctx_mask= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + if((options & ssl_ctx_mask) == ssl_ctx_mask) + { + pv.minor_= 2; + multi_proto= true; + break; + } + }while(0); + + SSL_METHOD *meth= NEW_YS SSL_METHOD(ctx->getMethod()->getSide(), ProtocolVersion(3,pv.minor_), multi_proto); + ctx->SetMethod(meth); return SSL_SUCCESS; } @@ -1055,7 +1127,7 @@ void DH_free(DH* dh) } -// convert positive big-endian num of length sz into retVal, which may need to +// convert positive big-endian num of length sz into retVal, which may need to // be created BIGNUM* BN_bin2bn(const unsigned char* num, int sz, BIGNUM* retVal) { @@ -1404,16 +1476,14 @@ int ASN1_STRING_type(ASN1_STRING *x) int X509_NAME_get_index_by_NID(X509_NAME* name,int nid, int lastpos) { int idx = -1; // not found - const char* start = &name->GetName()[lastpos + 1]; + int cnPos = -1; switch (nid) { case NID_commonName: - const char* found = strstr(start, "/CN="); - if (found) { - found += 4; // advance to str - idx = found - start + lastpos + 1; - } - break; + cnPos = name->GetCnPosition(); + if (lastpos < cnPos) + idx = cnPos; + break; } return idx; @@ -1527,7 +1597,7 @@ int SSL_pending(SSL* ssl) // Just in case there's pending data that hasn't been processed yet... char c; SSL_peek(ssl, &c, 1); - + return ssl->bufferedData(); } @@ -1785,7 +1855,7 @@ unsigned long ERR_get_error() #else snprintf(buf, len, "%s %2d %02d:%02d:%02d %d GMT", #endif - month_names[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min, + month_names[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, t.tm_year + 1900); return buf; } diff --git a/cdk/extra/yassl/src/timer.cpp b/cdk/extra/yassl/src/timer.cpp index a1b9063e1..a8e1a4fa2 100644 --- a/cdk/extra/yassl/src/timer.cpp +++ b/cdk/extra/yassl/src/timer.cpp @@ -37,7 +37,7 @@ namespace yaSSL { { static bool init(false); static LARGE_INTEGER freq; - + if (!init) { QueryPerformanceFrequency(&freq); init = true; @@ -62,7 +62,7 @@ namespace yaSSL { struct timeval tv; gettimeofday(&tv, 0); - return static_cast(tv.tv_sec) + return static_cast(tv.tv_sec) + static_cast(tv.tv_usec) / 1000000; } @@ -72,7 +72,7 @@ namespace yaSSL { struct timeval tv; gettimeofday(&tv, 0); - return tv.tv_sec; + return tv.tv_sec; } diff --git a/cdk/extra/yassl/src/yassl_error.cpp b/cdk/extra/yassl/src/yassl_error.cpp index e5d693673..0b3f9362a 100644 --- a/cdk/extra/yassl/src/yassl_error.cpp +++ b/cdk/extra/yassl/src/yassl_error.cpp @@ -35,8 +35,8 @@ namespace yaSSL { /* may bring back in future -Error::Error(const char* s, YasslError e, Library l) - : mySTL::runtime_error(s), error_(e), lib_(l) +Error::Error(const char* s, YasslError e, Library l) + : mySTL::runtime_error(s), error_(e), lib_(l) { } @@ -59,66 +59,66 @@ void SetErrorString(YasslError error, char* buffer) { using namespace TaoCrypt; const int max = MAX_ERROR_SZ; // shorthand - int localError = error; // errors from a few enums + int localError = error; // errors from a few enums switch (localError) { // yaSSL proper errors case range_error : strncpy(buffer, "buffer index error, out of range", max); - break; + break; case realloc_error : strncpy(buffer, "trying to realloc a fixed buffer", max); - break; + break; - case factory_error : + case factory_error : strncpy(buffer, "unknown factory create request", max); - break; + break; case unknown_cipher : strncpy(buffer, "trying to use an unknown cipher", max); - break; + break; - case prefix_error : + case prefix_error : strncpy(buffer, "bad master secret derivation, prefix too big", max); - break; + break; - case record_layer : + case record_layer : strncpy(buffer, "record layer not ready yet", max); - break; - + break; + case handshake_layer : strncpy(buffer, "handshake layer not ready yet", max); - break; + break; case out_of_order : strncpy(buffer, "handshake message received in wrong order", max); - break; + break; - case bad_input : + case bad_input : strncpy(buffer, "bad cipher suite input", max); - break; + break; case match_error : strncpy(buffer, "unable to match a supported cipher suite", max); - break; + break; - case no_key_file : + case no_key_file : strncpy(buffer, "the server needs a private key file", max); - break; + break; case verify_error : strncpy(buffer, "unable to verify peer checksum", max); - break; + break; case send_error : strncpy(buffer, "socket layer send error", max); - break; + break; case receive_error : strncpy(buffer, "socket layer receive error", max); - break; + break; case certificate_error : strncpy(buffer, "unable to proccess cerificate", max); @@ -148,6 +148,10 @@ void SetErrorString(YasslError error, char* buffer) strncpy(buffer, "sanity check on cipher text size error", max); break; + case rsaSignFault_error: + strncpy(buffer, "rsa signature fault error", max); + break; + // openssl errors case SSL_ERROR_WANT_READ : strncpy(buffer, "the read operation would block", max); diff --git a/cdk/extra/yassl/src/yassl_imp.cpp b/cdk/extra/yassl/src/yassl_imp.cpp index 867811dbb..2802c52cb 100644 --- a/cdk/extra/yassl/src/yassl_imp.cpp +++ b/cdk/extra/yassl/src/yassl_imp.cpp @@ -47,8 +47,8 @@ bool isTLS(ProtocolVersion pv) void hashHandShake(SSL&, const input_buffer&, uint); -ProtocolVersion::ProtocolVersion(uint8 maj, uint8 min) - : major_(maj), minor_(min) +ProtocolVersion::ProtocolVersion(uint8 maj, uint8 min) + : major_(maj), minor_(min) {} @@ -109,15 +109,12 @@ void ClientDiffieHellmanPublic::build(SSL& ssl) uint keyLength = dhClient.get_agreedKeyLength(); // pub and agree same alloc(keyLength, true); - dhClient.makeAgreement(dhServer.get_publicKey(), keyLength); + dhClient.makeAgreement(dhServer.get_publicKey(), + dhServer.get_publicKeyLength()); c16toa(keyLength, Yc_); memcpy(Yc_ + KEY_OFFSET, dhClient.get_publicKey(), keyLength); - // because of encoding first byte might be zero, don't use it for preMaster - if (*dhClient.get_agreedKey() == 0) - ssl.set_preMaster(dhClient.get_agreedKey() + 1, keyLength - 1); - else - ssl.set_preMaster(dhClient.get_agreedKey(), keyLength); + ssl.set_preMaster(dhClient.get_agreedKey(), keyLength); } @@ -134,7 +131,7 @@ void DH_Server::build(SSL& ssl) short sigSz = 0; mySTL::auto_ptr auth; const CertManager& cert = ssl.getCrypto().get_certManager(); - + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { if (cert.get_keyType() != rsa_sa_algo) { ssl.SetError(privateKey_error); @@ -152,7 +149,7 @@ void DH_Server::build(SSL& ssl) cert.get_privateKeyLength(), false)); sigSz += DSS_ENCODED_EXTRA; } - + sigSz += auth->get_signatureLength(); if (!sigSz) { ssl.SetError(privateKey_error); @@ -196,9 +193,16 @@ void DH_Server::build(SSL& ssl) sha.update(tmp.get_buffer(), tmp.get_size()); sha.get_digest(&hash[MD5_LEN]); - if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { auth->sign(signature_, hash, sizeof(hash), ssl.getCrypto().get_random()); + // check for rsa signautre fault + if (!auth->verify(hash, sizeof(hash), signature_, + auth->get_signatureLength())) { + ssl.SetError(rsaSignFault_error); + return; + } + } else { auth->sign(signature_, &hash[MD5_LEN], SHA_LEN, ssl.getCrypto().get_random()); @@ -243,7 +247,7 @@ void EncryptedPreMasterSecret::read(SSL& ssl, input_buffer& input) opaque preMasterSecret[SECRET_LEN]; memset(preMasterSecret, 0, sizeof(preMasterSecret)); - rsa.decrypt(preMasterSecret, secret_, length_, + rsa.decrypt(preMasterSecret, secret_, length_, ssl.getCrypto().get_random()); ProtocolVersion pv = ssl.getSecurity().get_connection().chVersion_; @@ -312,13 +316,9 @@ void ClientDiffieHellmanPublic::read(SSL& ssl, input_buffer& input) ssl.SetError(bad_input); return; } - dh.makeAgreement(Yc_, keyLength); + dh.makeAgreement(Yc_, keyLength); - // because of encoding, first byte might be 0, don't use for preMaster - if (*dh.get_agreedKey() == 0) - ssl.set_preMaster(dh.get_agreedKey() + 1, dh.get_agreedKeyLength() - 1); - else - ssl.set_preMaster(dh.get_agreedKey(), dh.get_agreedKeyLength()); + ssl.set_preMaster(dh.get_agreedKey(), dh.get_agreedKeyLength()); ssl.makeMasterSecret(); } @@ -346,9 +346,9 @@ opaque* ClientDiffieHellmanPublic::get_clientKey() const } -void ClientDiffieHellmanPublic::alloc(int sz, bool offset) +void ClientDiffieHellmanPublic::alloc(int sz, bool offset) { - length_ = sz + (offset ? KEY_OFFSET : 0); + length_ = sz + (offset ? KEY_OFFSET : 0); Yc_ = NEW_YS opaque[length_]; } @@ -444,7 +444,7 @@ void DH_Server::read(SSL& ssl, input_buffer& input) sha.get_digest(&hash[MD5_LEN]); const CertManager& cert = ssl.getCrypto().get_certManager(); - + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { RSA rsa(cert.get_peerKey(), cert.get_peerKeyLength()); if (!rsa.verify(hash, sizeof(hash), signature_, length)) @@ -453,7 +453,7 @@ void DH_Server::read(SSL& ssl, input_buffer& input) else { byte decodedSig[DSS_SIG_SZ]; length = TaoCrypt::DecodeDSA_Signature(decodedSig, signature_, length); - + DSS dss(cert.get_peerKey(), cert.get_peerKeyLength()); if (!dss.verify(&hash[MD5_LEN], SHA_LEN, decodedSig, length)) ssl.SetError(verify_error); @@ -492,7 +492,7 @@ opaque* DH_Server::get_serverKey() const // set available suites -Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, +Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, ProtocolVersion pv, bool haveDH) : entity_(ce) { pending_ = true; // suite not set yet @@ -505,7 +505,7 @@ Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, memcpy(suites_, ciphers.suites_, ciphers.suiteSz_); SetCipherNames(); } - else + else SetSuites(pv, ce == server_end && removeDH_); // defaults } @@ -576,7 +576,7 @@ void Parameters::SetSuites(ProtocolVersion pv, bool removeDH, bool removeRSA, if (!removeRSA) { suites_[i++] = 0x00; - suites_[i++] = SSL_RSA_WITH_RC4_128_SHA; + suites_[i++] = SSL_RSA_WITH_RC4_128_SHA; suites_[i++] = 0x00; suites_[i++] = SSL_RSA_WITH_RC4_128_MD5; @@ -647,7 +647,7 @@ output_buffer& operator<<(output_buffer& output, const RecordLayerHeader& hdr) output[AUTO] = hdr.type_; output[AUTO] = hdr.version_.major_; output[AUTO] = hdr.version_.minor_; - + // length byte tmp[2]; c16toa(hdr.length_, tmp); @@ -679,7 +679,7 @@ input_buffer& operator>>(input_buffer& input, HandShakeHeader& hs) hs.length_[0] = input[AUTO]; hs.length_[1] = input[AUTO]; hs.length_[2] = input[AUTO]; - + return input; } @@ -789,14 +789,14 @@ input_buffer& HandShakeBase::set(input_buffer& in) return in; } - + output_buffer& HandShakeBase::get(output_buffer& out) const { return out; } -void HandShakeBase::Process(input_buffer&, SSL&) +void HandShakeBase::Process(input_buffer&, SSL&) {} @@ -826,7 +826,7 @@ HandShakeType HelloRequest::get_type() const input_buffer& operator>>(input_buffer& input, ChangeCipherSpec& cs) { cs.type_ = CipherChoice(input[AUTO]); - return input; + return input; } // output operator for CipherSpec @@ -837,7 +837,7 @@ output_buffer& operator<<(output_buffer& output, const ChangeCipherSpec& cs) } -ChangeCipherSpec::ChangeCipherSpec() +ChangeCipherSpec::ChangeCipherSpec() : type_(change_cipher_spec_choice) {} @@ -924,7 +924,7 @@ input_buffer& operator>>(input_buffer& input, Alert& a) { a.level_ = AlertLevel(input[AUTO]); a.description_ = AlertDescription(input[AUTO]); - + return input; } @@ -969,7 +969,7 @@ void Alert::Process(input_buffer& input, SSL& ssl) ivExtra = ssl.getCrypto().get_cipher().get_blockSize(); int padSz = ssl.getSecurity().get_parms().encrypt_size_ - ivExtra - aSz - digestSz; - for (int i = 0; i < padSz; i++) + for (int i = 0; i < padSz; i++) fill = input[AUTO]; } @@ -1052,7 +1052,7 @@ output_buffer& operator<<(output_buffer& output, const Data& data) } -// check all bytes for equality +// check all bytes for equality static int constant_compare(const byte* a, const byte* b, int len) { int good = 0; @@ -1095,7 +1095,7 @@ static int pad_check(const byte* input, byte pad, int len) // get number of compression rounds static inline int get_rounds(int pLen, int padLen, int t) { - int roundL1 = 1; // round ups + int roundL1 = 1; // round ups int roundL2 = 1; int L1 = COMPRESS_CONSTANT + pLen - t; @@ -1126,7 +1126,7 @@ static inline void compress_rounds(SSL& ssl, int rounds, const byte* dummy) Digest* digest = NULL; MACAlgorithm ma = ssl.getSecurity().get_parms().mac_algorithm_; - if (ma == sha) + if (ma == sha) digest = NEW_YS SHA; else if (ma == md5) digest = NEW_YS MD5; @@ -1138,7 +1138,7 @@ static inline void compress_rounds(SSL& ssl, int rounds, const byte* dummy) for (int i = 0; i < rounds; i++) digest->update(dummy, COMPRESS_LOWER); - ysDelete(digest); + ysDelete(digest); } } @@ -1217,16 +1217,16 @@ void Data::Process(input_buffer& input, SSL& ssl) } } else { // SSLv3, some don't do this padding right - int sz3 = msgSz - digestSz - pad - 1; + int sz3 = msgSz - digestSz - pad - 1; hmac(ssl, verify, rawData, sz3, application_data, true); if (constant_compare(verify, rawData + sz3, digestSz) != 0) { ssl.SetError(verify_error); return; } - } + } } else { // stream - int streamSz = msgSz - digestSz; + int streamSz = msgSz - digestSz; if (ssl.isTLS()) TLS_hmac(ssl, verify, rawData, streamSz, application_data, true); else @@ -1286,7 +1286,7 @@ output_buffer& operator<<(output_buffer& output, const HandShakeBase& hs) } -Certificate::Certificate(const x509* cert) : cert_(cert) +Certificate::Certificate(const x509* cert) : cert_(cert) { if (cert) set_length(cert_->get_length() + 2 * CERT_HEADER); // list and cert size @@ -1339,7 +1339,7 @@ void Certificate::Process(input_buffer& input, SSL& ssl) } CertManager& cm = ssl.useCrypto().use_certManager(); - + uint32 list_sz; byte tmp[3]; @@ -1356,7 +1356,7 @@ void Certificate::Process(input_buffer& input, SSL& ssl) ssl.SetError(YasslError(bad_input)); return; } - + while (list_sz) { // cert size uint32 cert_sz; @@ -1369,7 +1369,7 @@ void Certificate::Process(input_buffer& input, SSL& ssl) tmp[1] = input[AUTO]; tmp[2] = input[AUTO]; c24to32(tmp, cert_sz); - + if (cert_sz > (uint)MAX_RECORD_SIZE || input.get_remaining() < cert_sz){ ssl.SetError(YasslError(bad_input)); return; @@ -1496,27 +1496,27 @@ opaque* ServerKeyBase::get_serverKey() const // input operator for ServerHello input_buffer& operator>>(input_buffer& input, ServerHello& hello) -{ +{ // Protocol hello.server_version_.major_ = input[AUTO]; hello.server_version_.minor_ = input[AUTO]; - + // Random input.read(hello.random_, RAN_LEN); - + // Session hello.id_len_ = input[AUTO]; if (hello.id_len_ > ID_LEN) { - input.set_error(); + input.set_error(); return input; } if (hello.id_len_) input.read(hello.session_id_, hello.id_len_); - + // Suites hello.cipher_suite_[0] = input[AUTO]; hello.cipher_suite_[1] = input[AUTO]; - + // Compression hello.compression_method_ = CompressionMethod(input[AUTO]); @@ -1711,7 +1711,7 @@ input_buffer& operator>>(input_buffer& input, ClientHello& hello) // Session hello.id_len_ = input[AUTO]; if (hello.id_len_) input.read(hello.session_id_, ID_LEN); - + // Suites byte tmp[2]; uint16 len; @@ -1746,7 +1746,7 @@ input_buffer& operator>>(input_buffer& input, ClientHello& hello) // output operaotr for Client Hello output_buffer& operator<<(output_buffer& output, const ClientHello& hello) -{ +{ // Protocol output[AUTO] = hello.client_version_.major_; output[AUTO] = hello.client_version_.minor_; @@ -1764,7 +1764,7 @@ output_buffer& operator<<(output_buffer& output, const ClientHello& hello) output[AUTO] = tmp[0]; output[AUTO] = tmp[1]; output.write(hello.cipher_suites_, hello.suite_len_); - + // Compression output[AUTO] = hello.comp_len_; output[AUTO] = hello.compression_methods_; @@ -1792,18 +1792,18 @@ void ClientHello::Process(input_buffer& input, SSL& ssl) if (ssl.isTLS() && client_version_.minor_ < 1) { // downgrade to SSLv3 ssl.useSecurity().use_connection().TurnOffTLS(); - + ProtocolVersion pv = ssl.getSecurity().get_connection().version_; bool removeDH = ssl.getSecurity().get_parms().removeDH_; bool removeRSA = false; bool removeDSA = false; - + const CertManager& cm = ssl.getCrypto().get_certManager(); if (cm.get_keyType() == rsa_sa_algo) removeDSA = true; else removeRSA = true; - + // reset w/ SSL suites ssl.useSecurity().use_parms().SetSuites(pv, removeDH, removeRSA, removeDSA); @@ -1945,9 +1945,9 @@ ServerKeyExchange::~ServerKeyExchange() } -void ServerKeyExchange::build(SSL& ssl) -{ - server_key_->build(ssl); +void ServerKeyExchange::build(SSL& ssl) +{ + server_key_->build(ssl); set_length(server_key_->get_length()); } @@ -1982,7 +1982,7 @@ HandShakeType ServerKeyExchange::get_type() const } -// CertificateRequest +// CertificateRequest CertificateRequest::CertificateRequest() : typeTotal_(0) { @@ -2008,7 +2008,7 @@ void CertificateRequest::Build() uint16 authCount = 0; uint16 authSz = 0; - + for (int j = 0; j < authCount; j++) { int sz = REQUEST_HEADER + MIN_DIS_SIZE; DistinguishedName dn; @@ -2017,7 +2017,7 @@ void CertificateRequest::Build() opaque tmp[REQUEST_HEADER]; c16toa(MIN_DIS_SIZE, tmp); memcpy(dn, tmp, sizeof(tmp)); - + // fill w/ junk for now memcpy(dn, tmp, MIN_DIS_SIZE); authSz += sz; @@ -2063,7 +2063,7 @@ input_buffer& operator>>(input_buffer& input, CertificateRequest& request) tmp[0] = input[AUTO]; tmp[1] = input[AUTO]; ato16(tmp, dnSz); - + input.set_current(input.get_current() + dnSz); sz -= dnSz + REQUEST_HEADER; @@ -2128,7 +2128,7 @@ HandShakeType CertificateRequest::get_type() const } -// CertificateVerify +// CertificateVerify CertificateVerify::CertificateVerify() : signature_(0) {} @@ -2159,6 +2159,12 @@ void CertificateVerify::Build(SSL& ssl) memcpy(sig.get(), len, VERIFY_HEADER); rsa.sign(sig.get() + VERIFY_HEADER, hashes_.md5_, sizeof(Hashes), ssl.getCrypto().get_random()); + // check for rsa signautre fault + if (!rsa.verify(hashes_.md5_, sizeof(Hashes), sig.get() + VERIFY_HEADER, + rsa.get_cipherLength())) { + ssl.SetError(rsaSignFault_error); + return; + } } else { // DSA DSS dss(cert.get_privateKey(), cert.get_privateKeyLength(), false); @@ -2246,7 +2252,7 @@ void CertificateVerify::Process(input_buffer& input, SSL& ssl) else { // DSA byte decodedSig[DSS_SIG_SZ]; TaoCrypt::DecodeDSA_Signature(decodedSig, signature_, get_length()); - + DSS dss(cert.get_peerKey(), cert.get_peerKeyLength()); if (!dss.verify(hashVerify.sha_, SHA_LEN, decodedSig, get_length())) ssl.SetError(verify_error); @@ -2307,9 +2313,9 @@ ClientKeyExchange::~ClientKeyExchange() } -void ClientKeyExchange::build(SSL& ssl) -{ - client_key_->build(ssl); +void ClientKeyExchange::build(SSL& ssl) +{ + client_key_->build(ssl); set_length(client_key_->get_length()); } @@ -2348,7 +2354,7 @@ input_buffer& operator>>(input_buffer& input, Finished&) { /* do in process */ - return input; + return input; } // output operator for Finished @@ -2375,7 +2381,7 @@ void Finished::Process(input_buffer& input, SSL& ssl) // verify hashes const Finished& verify = ssl.getHashes().get_verify(); uint finishedSz = ssl.isTLS() ? TLS_FINISHED_SZ : FINISHED_SZ; - + input.read(hashes_.md5_, finishedSz); if (input.get_error()) { ssl.SetError(bad_input); @@ -2415,7 +2421,7 @@ void Finished::Process(input_buffer& input, SSL& ssl) opaque fill; int padSz = ssl.getSecurity().get_parms().encrypt_size_ - ivExtra - HANDSHAKE_HEADER - finishedSz - digestSz; - for (int i = 0; i < padSz; i++) + for (int i = 0; i < padSz; i++) fill = input[AUTO]; if (input.get_error()) { ssl.SetError(bad_input); @@ -2499,14 +2505,14 @@ Connection::Connection(ProtocolVersion v, RandomPool& ran) } -Connection::~Connection() -{ +Connection::~Connection() +{ CleanMaster(); CleanPreMaster(); ysArrayDelete(pre_master_secret_); } -void Connection::AllocPreSecret(uint sz) -{ +void Connection::AllocPreSecret(uint sz) +{ pre_master_secret_ = NEW_YS opaque[pre_secret_len_ = sz]; } @@ -2561,7 +2567,7 @@ HandShakeBase* CreateClientHello() { return NEW_YS ClientHello; } HandShakeBase* CreateServerHello() { return NEW_YS ServerHello; } HandShakeBase* CreateCertificate() { return NEW_YS Certificate; } HandShakeBase* CreateServerKeyExchange() { return NEW_YS ServerKeyExchange;} -HandShakeBase* CreateCertificateRequest() { return NEW_YS +HandShakeBase* CreateCertificateRequest() { return NEW_YS CertificateRequest; } HandShakeBase* CreateServerHelloDone() { return NEW_YS ServerHelloDone; } HandShakeBase* CreateCertificateVerify() { return NEW_YS CertificateVerify;} @@ -2574,9 +2580,9 @@ ServerKeyBase* CreateDHServerKEA() { return NEW_YS DH_Server; } ServerKeyBase* CreateFortezzaServerKEA() { return NEW_YS Fortezza_Server; } // Create functions for client key exchange factory -ClientKeyBase* CreateRSAClient() { return NEW_YS +ClientKeyBase* CreateRSAClient() { return NEW_YS EncryptedPreMasterSecret; } -ClientKeyBase* CreateDHClient() { return NEW_YS +ClientKeyBase* CreateDHClient() { return NEW_YS ClientDiffieHellmanPublic; } ClientKeyBase* CreateFortezzaClient() { return NEW_YS FortezzaKeys; } diff --git a/cdk/extra/yassl/src/yassl_int.cpp b/cdk/extra/yassl/src/yassl_int.cpp index ea321ead9..62334d1be 100644 --- a/cdk/extra/yassl/src/yassl_int.cpp +++ b/cdk/extra/yassl/src/yassl_int.cpp @@ -857,6 +857,19 @@ void SSL::set_random(const opaque* random, ConnectionEnd sender) // store client pre master secret void SSL::set_preMaster(const opaque* pre, uint sz) { + uint i(0); // trim leading zeros + uint fullSz(sz); + + while (i++ < fullSz && *pre == 0) { + sz--; + pre++; + } + + if (sz == 0) { + SetError(bad_input); + return; + } + secure_.use_connection().AllocPreSecret(sz); memcpy(secure_.use_connection().pre_master_secret_, pre, sz); } @@ -974,6 +987,8 @@ void SSL::order_error() // Create and store the master secret see page 32, 6.1 void SSL::makeMasterSecret() { + if (GetError()) return; + if (isTLS()) makeTLSMasterSecret(); else { @@ -1590,7 +1605,9 @@ void SSL_SESSION::CopyX509(X509* x) peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(), subject->GetName(), subject->GetLength(), - before, after); + before, after, + issuer->GetCnPosition(), issuer->GetCnLength(), + subject->GetCnPosition(), subject->GetCnLength()); } @@ -2123,6 +2140,14 @@ void SSL_CTX::SetSessionCacheOff() } +void SSL_CTX::SetMethod(SSL_METHOD* meth) +{ + if(method_) + ysDelete(method_); + method_= meth; +} + + void SSL_CTX::SetSessionCacheFlushOff() { sessionCacheFlushOff_ = true; @@ -2219,7 +2244,7 @@ void SSL_CTX::IncrementStats(StatsField fd) switch (fd) { - case Accept: + case Accept: ++stats_.accept_; break; @@ -2568,8 +2593,8 @@ void Security::set_resuming(bool b) } -X509_NAME::X509_NAME(const char* n, size_t sz) - : name_(0), sz_(sz) +X509_NAME::X509_NAME(const char* n, size_t sz, int pos, int len) + : name_(0), sz_(sz), cnPosition_(pos), cnLen_(len) { if (sz) { name_ = NEW_YS char[sz]; @@ -2599,8 +2624,10 @@ size_t X509_NAME::GetLength() const X509::X509(const char* i, size_t iSz, const char* s, size_t sSz, - ASN1_STRING *b, ASN1_STRING *a) - : issuer_(i, iSz), subject_(s, sSz), + ASN1_STRING *b, ASN1_STRING *a, + int issPos, int issLen, + int subPos, int subLen) + : issuer_(i, iSz, issPos, issLen), subject_(s, sSz, subPos, subLen), beforeDate_((char *) b->data, b->length, b->type), afterDate_((char *) a->data, a->length, a->type) {} @@ -2635,19 +2662,20 @@ ASN1_STRING* X509_NAME::GetEntry(int i) if (i < 0 || i >= int(sz_)) return 0; + if (i != cnPosition_ || cnLen_ <= 0) // only entry currently supported + return 0; + + if (cnLen_ > int(sz_-i)) // make sure there's room in read buffer + return 0; + if (entry_.data) ysArrayDelete(entry_.data); - entry_.data = NEW_YS byte[sz_]; // max size; + entry_.data = NEW_YS byte[cnLen_+1]; // max size; - memcpy(entry_.data, &name_[i], sz_ - i); - if (entry_.data[sz_ -i - 1]) { - entry_.data[sz_ - i] = 0; - entry_.length = int(sz_) - i; - } - else - entry_.length = int(sz_) - i - 1; + memcpy(entry_.data, &name_[i], cnLen_); + entry_.data[cnLen_] = 0; + entry_.length = cnLen_; entry_.type = 0; - return &entry_; } diff --git a/cdk/extra/yassl/taocrypt/include/aes.hpp b/cdk/extra/yassl/taocrypt/include/aes.hpp index 017630331..bccf6e73f 100644 --- a/cdk/extra/yassl/taocrypt/include/aes.hpp +++ b/cdk/extra/yassl/taocrypt/include/aes.hpp @@ -60,6 +60,7 @@ class AES : public Mode_BASE { static const word32 Te[5][256]; static const word32 Td[5][256]; + static const byte CTd4[256]; static const word32* Te0; static const word32* Te1; @@ -80,11 +81,68 @@ class AES : public Mode_BASE { void ProcessAndXorBlock(const byte*, const byte*, byte*) const; + word32 PreFetchTe() const; + word32 PreFetchTd() const; + word32 PreFetchCTd4() const; + AES(const AES&); // hide copy AES& operator=(const AES&); // and assign }; +#if defined(__x86_64__) || defined(_M_X64) || \ + (defined(__ILP32__) && (__ILP32__ >= 1)) + #define TC_CACHE_LINE_SZ 64 +#else + /* default cache line size */ + #define TC_CACHE_LINE_SZ 32 +#endif + +inline word32 AES::PreFetchTe() const +{ + word32 x = 0; + + /* 4 tables of 256 entries */ + for (int i = 0; i < 4; i++) { + /* each entry is 4 bytes */ + for (int j = 0; j < 256; j += TC_CACHE_LINE_SZ/4) { + x &= Te[i][j]; + } + } + + return x; +} + + +inline word32 AES::PreFetchTd() const +{ + word32 x = 0; + + /* 4 tables of 256 entries */ + for (int i = 0; i < 4; i++) { + /* each entry is 4 bytes */ + for (int j = 0; j < 256; j += TC_CACHE_LINE_SZ/4) { + x &= Td[i][j]; + } + } + + return x; +} + + +inline word32 AES::PreFetchCTd4() const +{ + word32 x = 0; + int i; + + for (i = 0; i < 256; i += TC_CACHE_LINE_SZ) { + x &= CTd4[i]; + } + + return x; +} + + typedef BlockCipher AES_ECB_Encryption; typedef BlockCipher AES_ECB_Decryption; diff --git a/cdk/extra/yassl/taocrypt/include/asn.hpp b/cdk/extra/yassl/taocrypt/include/asn.hpp index bc3eebe6b..e029001ba 100644 --- a/cdk/extra/yassl/taocrypt/include/asn.hpp +++ b/cdk/extra/yassl/taocrypt/include/asn.hpp @@ -16,7 +16,7 @@ MA 02110-1301 USA. */ -/* asn.hpp provides ASN1 BER, PublicKey, and x509v3 decoding +/* asn.hpp provides ASN1 BER, PublicKey, and x509v3 decoding */ @@ -109,7 +109,7 @@ enum Constants MIN_DATE_SZ = 13, MAX_DATE_SZ = 16, MAX_ALGO_SZ = 16, - MAX_LENGTH_SZ = 5, + MAX_LENGTH_SZ = 5, MAX_SEQ_SZ = 5, // enum(seq|con) + length(4) MAX_ALGO_SIZE = 9, MAX_DIGEST_SZ = 69, // SHA512 + enum(Bit or Octet) + length(4) @@ -269,7 +269,7 @@ enum KeyType { DSAk = 515, RSAk = 645 }; // sums of algo OID // an x509v Certificate BER Decoder class CertDecoder : public BER_Decoder { public: - enum DateType { BEFORE, AFTER }; + enum DateType { BEFORE, AFTER }; enum NameType { ISSUER, SUBJECT }; enum CertType { CA, USER }; @@ -286,7 +286,10 @@ class CertDecoder : public BER_Decoder { byte GetBeforeDateType() const { return beforeDateType_; } const char* GetAfterDate() const { return afterDate_; } byte GetAfterDateType() const { return afterDateType_; } - + int GetSubjectCnStart() const { return subCnPos_; } + int GetIssuerCnStart() const { return issCnPos_; } + int GetSubjectCnLength() const { return subCnLen_; } + int GetIssuerCnLength() const { return issCnLen_; } void DecodeToKey(); private: PublicKey key_; @@ -295,6 +298,10 @@ class CertDecoder : public BER_Decoder { word32 sigLength_; // length of signature word32 signatureOID_; // sum of algorithm object id word32 keyOID_; // sum of key algo object id + int subCnPos_; // subject common name start, -1 is none + int subCnLen_; // length of above + int issCnPos_; // issuer common name start, -1 is none + int issCnLen_; // length of above byte subjectHash_[SHA_SIZE]; // hash of all Names byte issuerHash_[SHA_SIZE]; // hash of all Names byte* signature_; diff --git a/cdk/extra/yassl/taocrypt/include/block.hpp b/cdk/extra/yassl/taocrypt/include/block.hpp index 4f58c82ff..8242891b0 100644 --- a/cdk/extra/yassl/taocrypt/include/block.hpp +++ b/cdk/extra/yassl/taocrypt/include/block.hpp @@ -125,7 +125,7 @@ class AllocatorWithCleanup : public AllocatorBase template > class Block { public: - explicit Block(word32 s = 0) : sz_(s), buffer_(allocator_.allocate(sz_)) + explicit Block(word32 s = 0) : sz_(s), buffer_(allocator_.allocate(sz_)) { CleanNew(sz_); } Block(const T* buff, word32 s) : sz_(s), buffer_(allocator_.allocate(sz_)) diff --git a/cdk/extra/yassl/taocrypt/include/des.hpp b/cdk/extra/yassl/taocrypt/include/des.hpp index d88e9ef2f..04d1439dd 100644 --- a/cdk/extra/yassl/taocrypt/include/des.hpp +++ b/cdk/extra/yassl/taocrypt/include/des.hpp @@ -48,10 +48,10 @@ class BasicDES { }; -// DES +// DES class DES : public Mode_BASE, public BasicDES { public: - DES(CipherDir DIR, Mode MODE) + DES(CipherDir DIR, Mode MODE) : Mode_BASE(DES_BLOCK_SIZE, DIR, MODE) {} private: @@ -65,7 +65,7 @@ class DES : public Mode_BASE, public BasicDES { // DES_EDE2 class DES_EDE2 : public Mode_BASE { public: - DES_EDE2(CipherDir DIR, Mode MODE) + DES_EDE2(CipherDir DIR, Mode MODE) : Mode_BASE(DES_BLOCK_SIZE, DIR, MODE) {} void SetKey(const byte*, word32, CipherDir dir); diff --git a/cdk/extra/yassl/taocrypt/include/dh.hpp b/cdk/extra/yassl/taocrypt/include/dh.hpp index bdb90ddae..93783f156 100644 --- a/cdk/extra/yassl/taocrypt/include/dh.hpp +++ b/cdk/extra/yassl/taocrypt/include/dh.hpp @@ -40,7 +40,7 @@ class DH { explicit DH(Source&); DH(const DH& that) : p_(that.p_), g_(that.g_) {} - DH& operator=(const DH& that) + DH& operator=(const DH& that) { DH tmp(that); Swap(tmp); @@ -77,7 +77,7 @@ class DH { Integer g_; void GeneratePrivate(RandomNumberGenerator&, byte*); - void GeneratePublic(const byte*, byte*); + void GeneratePublic(const byte*, byte*); }; diff --git a/cdk/extra/yassl/taocrypt/include/dsa.hpp b/cdk/extra/yassl/taocrypt/include/dsa.hpp index d7f81c274..05ae56843 100644 --- a/cdk/extra/yassl/taocrypt/include/dsa.hpp +++ b/cdk/extra/yassl/taocrypt/include/dsa.hpp @@ -43,7 +43,7 @@ class DSA_PublicKey { void Initialize(Source&); void Initialize(const Integer& p, const Integer& q, const Integer& g, const Integer& y); - + const Integer& GetModulus() const; const Integer& GetSubGroupOrder() const; const Integer& GetSubGroupGenerator() const; @@ -55,7 +55,7 @@ class DSA_PublicKey { void SetPublicPart(const Integer&); word32 SignatureLength() const; - + DSA_PublicKey(const DSA_PublicKey&); DSA_PublicKey& operator=(const DSA_PublicKey&); @@ -73,7 +73,7 @@ class DSA_PrivateKey : public DSA_PublicKey { void Initialize(Source&); void Initialize(const Integer& p, const Integer& q, const Integer& g, const Integer& y, const Integer& x); - + const Integer& GetPrivatePart() const; void SetPrivatePart(const Integer&); diff --git a/cdk/extra/yassl/taocrypt/include/error.hpp b/cdk/extra/yassl/taocrypt/include/error.hpp index cb2130d48..a6ab7c72e 100644 --- a/cdk/extra/yassl/taocrypt/include/error.hpp +++ b/cdk/extra/yassl/taocrypt/include/error.hpp @@ -68,7 +68,7 @@ SIG_OTHER_E = 1039, // "bad other signature confirmation" CONTENT_E = 1040, // "bad content processing" PEM_E = 1041 // "bad pem format error" - // add error string to yassl/src/yassl_error.cpp !!! + // add error string to yassl/src/yassl_error.cpp !!! }; diff --git a/cdk/extra/yassl/taocrypt/include/file.hpp b/cdk/extra/yassl/taocrypt/include/file.hpp index 9851a001a..a8d0375e8 100644 --- a/cdk/extra/yassl/taocrypt/include/file.hpp +++ b/cdk/extra/yassl/taocrypt/include/file.hpp @@ -40,13 +40,13 @@ class Source { Source(const byte* b, word32 sz) : buffer_(b, sz), current_(0) {} word32 remaining() { if (GetError().What()) return 0; - else return buffer_.size() - current_; } + else return buffer_.size() - current_; } word32 size() const { return buffer_.size(); } void grow(word32 sz) { buffer_.CleanGrow(sz); } bool IsLeft(word32 sz) { if (remaining() >= sz) return true; else { SetError(CONTENT_E); return false; } } - + const byte* get_buffer() const { return buffer_.get_buffer(); } const byte* get_current() const { return &buffer_[current_]; } word32 get_index() const { return current_; } @@ -82,7 +82,7 @@ class Source { return *this; } - void Swap(Source& other) + void Swap(Source& other) { buffer_.Swap(other.buffer_); STL::swap(current_, other.current_); @@ -97,11 +97,11 @@ class FileSource { public: FileSource(const char* fname, Source& source); ~FileSource(); - + word32 size(bool use_current = false); private: word32 get(Source&); - word32 size_left(); + word32 size_left(); FileSource(const FileSource&); // hide FileSource& operator=(const FileSource&); // hide diff --git a/cdk/extra/yassl/taocrypt/include/hash.hpp b/cdk/extra/yassl/taocrypt/include/hash.hpp index 4d2f7dd35..e1d57ed57 100644 --- a/cdk/extra/yassl/taocrypt/include/hash.hpp +++ b/cdk/extra/yassl/taocrypt/include/hash.hpp @@ -56,7 +56,7 @@ class HASHwithTransform : public HASH { word32 GetBitCountLo() const { return loLen_ << 3; } word32 GetBitCountHi() const { return (loLen_ >> (8*sizeof(loLen_) - 3)) + - (hiLen_ << 3); } + (hiLen_ << 3); } enum { MaxDigestSz = 8, MaxBufferSz = 64 }; protected: typedef word32 HashLengthType; @@ -87,7 +87,7 @@ class HASH64withTransform : public HASH { word32 GetBitCountLo() const { return loLen_ << 3; } word32 GetBitCountHi() const { return (loLen_ >> (8*sizeof(loLen_) - 3)) + - (hiLen_ << 3); } + (hiLen_ << 3); } enum { MaxDigestSz = 8, MaxBufferSz = 128 }; protected: typedef word32 HashLengthType; diff --git a/cdk/extra/yassl/taocrypt/include/hmac.hpp b/cdk/extra/yassl/taocrypt/include/hmac.hpp index 4df081b84..836710db3 100644 --- a/cdk/extra/yassl/taocrypt/include/hmac.hpp +++ b/cdk/extra/yassl/taocrypt/include/hmac.hpp @@ -34,11 +34,11 @@ class HMAC { public: enum { IPAD = 0x36, OPAD = 0x5C }; - HMAC() : ipad_(reinterpret_cast(&ip_)), + HMAC() : ipad_(reinterpret_cast(&ip_)), opad_(reinterpret_cast(&op_)), - innerHash_(reinterpret_cast(&innerH_)) - { - Init(); + innerHash_(reinterpret_cast(&innerH_)) + { + Init(); } void Update(const byte*, word32); void Final(byte*); diff --git a/cdk/extra/yassl/taocrypt/include/integer.hpp b/cdk/extra/yassl/taocrypt/include/integer.hpp index d21219ea1..dab238726 100644 --- a/cdk/extra/yassl/taocrypt/include/integer.hpp +++ b/cdk/extra/yassl/taocrypt/include/integer.hpp @@ -47,7 +47,7 @@ #ifdef TAOCRYPT_X86ASM_AVAILABLE #if defined(__GNUC__) && (__GNUC__ >= 4) - // GCC 4 or greater optimizes too much inline on recursive for bigint, + // GCC 4 or greater optimizes too much inline on recursive for bigint, // -O3 just as fast without asm here anyway #undef TAOCRYPT_X86ASM_AVAILABLE #endif @@ -118,6 +118,10 @@ namespace TaoCrypt { #endif + +#ifdef _WIN32 + #undef max // avoid name clash +#endif // general MAX template inline const T& max(const T& a, const T& b) @@ -147,7 +151,7 @@ class Integer { Signedness s = UNSIGNED); ~Integer() {} - + static const Integer& Zero(); static const Integer& One(); @@ -190,7 +194,7 @@ class Integer { Integer& operator+=(const Integer& t); Integer& operator-=(const Integer& t); Integer& operator*=(const Integer& t) { return *this = Times(t); } - Integer& operator/=(const Integer& t) + Integer& operator/=(const Integer& t) { return *this = DividedBy(t);} Integer& operator%=(const Integer& t) { return *this = Modulo(t); } Integer& operator/=(word t) { return *this = DividedBy(t); } @@ -198,7 +202,7 @@ class Integer { Integer& operator<<=(unsigned int); Integer& operator>>=(unsigned int); - + void Randomize(RandomNumberGenerator &rng, unsigned int bitcount); void Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max); @@ -206,7 +210,7 @@ class Integer { void SetBit(unsigned int n, bool value = 1); void SetByte(unsigned int n, byte value); - void Negate(); + void Negate(); void SetPositive() { sign_ = POSITIVE; } void SetNegative() { if (!!(*this)) sign_ = NEGATIVE; } void Swap(Integer& a); @@ -216,9 +220,9 @@ class Integer { Integer operator-() const; Integer& operator++(); Integer& operator--(); - Integer operator++(int) + Integer operator++(int) { Integer temp = *this; ++*this; return temp; } - Integer operator--(int) + Integer operator--(int) { Integer temp = *this; --*this; return temp; } int Compare(const Integer& a) const; @@ -277,28 +281,28 @@ class Integer { Sign sign_; }; -inline bool operator==(const Integer& a, const Integer& b) +inline bool operator==(const Integer& a, const Integer& b) {return a.Compare(b)==0;} -inline bool operator!=(const Integer& a, const Integer& b) +inline bool operator!=(const Integer& a, const Integer& b) {return a.Compare(b)!=0;} -inline bool operator> (const Integer& a, const Integer& b) +inline bool operator> (const Integer& a, const Integer& b) {return a.Compare(b)> 0;} -inline bool operator>=(const Integer& a, const Integer& b) +inline bool operator>=(const Integer& a, const Integer& b) {return a.Compare(b)>=0;} -inline bool operator< (const Integer& a, const Integer& b) +inline bool operator< (const Integer& a, const Integer& b) {return a.Compare(b)< 0;} -inline bool operator<=(const Integer& a, const Integer& b) +inline bool operator<=(const Integer& a, const Integer& b) {return a.Compare(b)<=0;} -inline Integer operator+(const Integer &a, const Integer &b) +inline Integer operator+(const Integer &a, const Integer &b) {return a.Plus(b);} -inline Integer operator-(const Integer &a, const Integer &b) +inline Integer operator-(const Integer &a, const Integer &b) {return a.Minus(b);} -inline Integer operator*(const Integer &a, const Integer &b) +inline Integer operator*(const Integer &a, const Integer &b) {return a.Times(b);} -inline Integer operator/(const Integer &a, const Integer &b) +inline Integer operator/(const Integer &a, const Integer &b) {return a.DividedBy(b);} -inline Integer operator%(const Integer &a, const Integer &b) +inline Integer operator%(const Integer &a, const Integer &b) {return a.Modulo(b);} inline Integer operator/(const Integer &a, word b) {return a.DividedBy(b);} inline word operator%(const Integer &a, word b) {return a.Modulo(b);} diff --git a/cdk/extra/yassl/taocrypt/include/md5.hpp b/cdk/extra/yassl/taocrypt/include/md5.hpp index fce37bd55..2529d4d57 100644 --- a/cdk/extra/yassl/taocrypt/include/md5.hpp +++ b/cdk/extra/yassl/taocrypt/include/md5.hpp @@ -37,7 +37,7 @@ class MD5 : public HASHwithTransform { public: enum { BLOCK_SIZE = 64, DIGEST_SIZE = 16, PAD_SIZE = 56, TAO_BYTE_ORDER = LittleEndianOrder }; // in Bytes - MD5() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) + MD5() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) { Init(); } ByteOrder getByteOrder() const { return ByteOrder(TAO_BYTE_ORDER); } word32 getBlockSize() const { return BLOCK_SIZE; } diff --git a/cdk/extra/yassl/taocrypt/include/misc.hpp b/cdk/extra/yassl/taocrypt/include/misc.hpp index 18f13e783..6f82ce117 100644 --- a/cdk/extra/yassl/taocrypt/include/misc.hpp +++ b/cdk/extra/yassl/taocrypt/include/misc.hpp @@ -105,21 +105,21 @@ void CleanUp(); #define NEW_TC new class virtual_base {}; - - + + #endif // YASSL_PURE_C #if defined(_MSC_VER) || defined(__BCPLUSPLUS__) - #define INTEL_INTRINSICS - #define FAST_ROTATE + #define INTEL_INTRINSICS + #define FAST_ROTATE #elif defined(__MWERKS__) && TARGET_CPU_PPC - #define PPC_INTRINSICS - #define FAST_ROTATE + #define PPC_INTRINSICS + #define FAST_ROTATE #elif defined(__GNUC__) && defined(__i386__) // GCC does peephole optimizations which should result in using rotate // instructions - #define FAST_ROTATE + #define FAST_ROTATE #endif @@ -163,7 +163,7 @@ void CleanUp(); // Turn on ia32 ASM for Ciphers and Message Digests // Seperate define since these are more complex, use member offsets -// and user may want to turn off while leaving Big Integer optos on +// and user may want to turn off while leaving Big Integer optos on #if defined(TAOCRYPT_X86ASM_AVAILABLE) && !defined(DISABLE_TAO_ASM) #define TAO_ASM #endif @@ -271,7 +271,7 @@ void CleanUp(); template struct CompileAssert { - static char dummy[2*b-1]; + static char dummy[2*b-1]; }; #define TAOCRYPT_COMPILE_ASSERT(assertion) \ @@ -440,7 +440,7 @@ template<> inline word32 rotrFixed(word32 x, word32 y) #ifdef min #undef min -#endif +#endif template @@ -472,14 +472,14 @@ inline word32 ByteReverse(word32 value) inline word64 ByteReverse(word64 value) { #ifdef TAOCRYPT_SLOW_WORD64 - return (word64(ByteReverse(word32(value))) << 32) | + return (word64(ByteReverse(word32(value))) << 32) | ByteReverse(word32(value>>32)); #else - value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | + value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | ((value & W64LIT(0x00FF00FF00FF00FF)) << 8); - value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | + value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | ((value & W64LIT(0x0000FFFF0000FFFF)) << 16); - return rotlFixed(value, 32U); + return rotlFixed(value, 32U); #endif } @@ -512,7 +512,7 @@ inline T ByteReverseIf(T value, ByteOrder order) template inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) { - if (!HostByteOrderIs(order)) + if (!HostByteOrderIs(order)) ByteReverse(out, in, bc); else if (out != in) memcpy(out, in, bc); @@ -520,7 +520,7 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) -// do Asm Reverse is host is Little and x86asm +// do Asm Reverse is host is Little and x86asm #ifdef LITTLE_ENDIAN_ORDER #ifdef TAOCRYPT_X86ASM_AVAILABLE #define LittleReverse AsmReverse @@ -532,7 +532,7 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) #endif -// do Asm Reverse is host is Big and x86asm +// do Asm Reverse is host is Big and x86asm #ifdef BIG_ENDIAN_ORDER #ifdef TAOCRYPT_X86ASM_AVAILABLE #define BigReverse AsmReverse @@ -551,14 +551,14 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) inline word32 AsmReverse(word32 wd) { #ifdef __GNUC__ - __asm__ + __asm__ ( "bswap %1" : "=r"(wd) : "0"(wd) ); #else - __asm + __asm { mov eax, wd bswap eax @@ -568,7 +568,7 @@ inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) return wd; } -#endif +#endif template @@ -699,7 +699,7 @@ inline void PutWord(bool assumeAligned, ByteOrder order, byte* block, T value, if (assumeAligned) { if (xorBlock) - *reinterpret_cast(block) = ByteReverseIf(value, order) + *reinterpret_cast(block) = ByteReverseIf(value, order) ^ *reinterpret_cast(xorBlock); else *reinterpret_cast(block) = ByteReverseIf(value, order); @@ -759,7 +759,7 @@ struct BlockGetAndPut { // function needed because of C++ grammatical ambiguity between // expression-statements and declarations - static inline GetBlock Get(const void *block) + static inline GetBlock Get(const void *block) {return GetBlock(block);} typedef PutBlock Put; }; diff --git a/cdk/extra/yassl/taocrypt/include/modarith.hpp b/cdk/extra/yassl/taocrypt/include/modarith.hpp index 5ac3f67ab..f84436d6d 100644 --- a/cdk/extra/yassl/taocrypt/include/modarith.hpp +++ b/cdk/extra/yassl/taocrypt/include/modarith.hpp @@ -45,8 +45,8 @@ class ModularArithmetic : public AbstractRing modulus(ma.modulus), result((word)0, modulus.reg_.size()) {} const Integer& GetModulus() const {return modulus;} - void SetModulus(const Integer &newModulus) - { + void SetModulus(const Integer &newModulus) + { modulus = newModulus; result.reg_.resize(modulus.reg_.size()); } diff --git a/cdk/extra/yassl/taocrypt/include/modes.hpp b/cdk/extra/yassl/taocrypt/include/modes.hpp index bfe8c6ec5..b9c4f0ec4 100644 --- a/cdk/extra/yassl/taocrypt/include/modes.hpp +++ b/cdk/extra/yassl/taocrypt/include/modes.hpp @@ -38,11 +38,11 @@ class BlockCipher { public: BlockCipher() : cipher_(DIR, MODE) {} - void Process(byte* c, const byte* p, word32 sz) + void Process(byte* c, const byte* p, word32 sz) { cipher_.Process(c, p, sz); } - void SetKey(const byte* k, word32 sz) + void SetKey(const byte* k, word32 sz) { cipher_.SetKey(k, sz, DIR); } - void SetKey(const byte* k, word32 sz, const byte* iv) + void SetKey(const byte* k, word32 sz, const byte* iv) { cipher_.SetKey(k, sz, DIR); cipher_.SetIV(iv); } private: T cipher_; @@ -57,7 +57,7 @@ class Mode_BASE : public virtual_base { public: enum { MaxBlockSz = 16 }; - explicit Mode_BASE(int sz, CipherDir dir, Mode mode) + explicit Mode_BASE(int sz, CipherDir dir, Mode mode) : blockSz_(sz), reg_(reinterpret_cast(r_)), tmp_(reinterpret_cast(t_)), dir_(dir), mode_(mode) {} diff --git a/cdk/extra/yassl/taocrypt/include/rsa.hpp b/cdk/extra/yassl/taocrypt/include/rsa.hpp index ee3e378a6..030970325 100644 --- a/cdk/extra/yassl/taocrypt/include/rsa.hpp +++ b/cdk/extra/yassl/taocrypt/include/rsa.hpp @@ -38,11 +38,11 @@ class PK_Lengths { explicit PK_Lengths(const Integer& i) : image_(i) {} word32 PaddedBlockBitLength() const {return image_.BitCount() - 1;} - word32 PaddedBlockByteLength() const + word32 PaddedBlockByteLength() const {return BitsToBytes(PaddedBlockBitLength());} word32 FixedCiphertextLength() const {return image_.ByteCount();} - word32 FixedMaxPlaintextLength() const + word32 FixedMaxPlaintextLength() const {return SaturatingSubtract(PaddedBlockBitLength() / 8, 10U); } }; @@ -101,7 +101,7 @@ class RSA_PrivateKey : public RSA_PublicKey { explicit RSA_PrivateKey(Source&); void Initialize(const Integer& n, const Integer& e, const Integer& d, - const Integer& p, const Integer& q, const Integer& dp, + const Integer& p, const Integer& q, const Integer& dp, const Integer& dq, const Integer& u) {n_ = n; e_ = e; d_ = d; p_ = p; q_ = q; dp_ = dp; dq_ = dq; u_ = u;} void Initialize(Source&); @@ -113,7 +113,7 @@ class RSA_PrivateKey : public RSA_PublicKey { const Integer& GetPrivateExponent() const {return d_;} const Integer& GetModPrime1PrivateExponent() const {return dp_;} const Integer& GetModPrime2PrivateExponent() const {return dq_;} - const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return u_;} void SetPrime1(const Integer& p) {p_ = p;} @@ -140,7 +140,7 @@ class RSA_BlockType2 { // block type 1 padding class RSA_BlockType1 { public: - void Pad(const byte*, word32, byte*, word32, + void Pad(const byte*, word32, byte*, word32, RandomNumberGenerator&) const; word32 UnPad(const byte*, word32, byte*) const; }; @@ -199,7 +199,7 @@ word32 RSA_Decryptor::Decrypt(const byte* cipher, word32 sz, byte* plain, if (sz != lengths.FixedCiphertextLength()) return 0; - + ByteBlock paddedBlock(lengths.PaddedBlockByteLength()); Integer x = key_.CalculateInverse(rng, Integer(cipher, lengths.FixedCiphertextLength()).Ref()); diff --git a/cdk/extra/yassl/taocrypt/include/runtime.hpp b/cdk/extra/yassl/taocrypt/include/runtime.hpp index b41f20c6d..accd86a37 100644 --- a/cdk/extra/yassl/taocrypt/include/runtime.hpp +++ b/cdk/extra/yassl/taocrypt/include/runtime.hpp @@ -25,6 +25,9 @@ #ifndef yaSSL_NEW_HPP #define yaSSL_NEW_HPP +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #ifdef YASSL_PURE_C diff --git a/cdk/extra/yassl/taocrypt/include/types.hpp b/cdk/extra/yassl/taocrypt/include/types.hpp index ce6ea0809..67ea2609a 100644 --- a/cdk/extra/yassl/taocrypt/include/types.hpp +++ b/cdk/extra/yassl/taocrypt/include/types.hpp @@ -22,6 +22,9 @@ #ifndef TAO_CRYPT_TYPES_HPP #define TAO_CRYPT_TYPES_HPP +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif namespace TaoCrypt { @@ -48,7 +51,7 @@ typedef unsigned int word32; #define WORD64_AVAILABLE typedef unsigned long word64; #define W64LIT(x) x##LL -#elif SIZEOF_LONG_LONG == 8 +#elif SIZEOF_LONG_LONG == 8 #define WORD64_AVAILABLE #define WORD64_IS_DISTINCT_TYPE typedef unsigned long long word64; @@ -63,10 +66,10 @@ typedef unsigned int word32; #endif #endif - + #if defined(HAVE_64_MULTIPLY) && (defined(__ia64__) \ || defined(_ARCH_PPC64) || defined(__mips64) || defined(__x86_64__) \ - || defined(_M_X64) || defined(_M_IA64)) + || defined(_M_X64) || defined(_M_IA64)) // These platforms have 64-bit CPU registers. Unfortunately most C++ compilers // don't allow any way to access the 64-bit by 64-bit multiply instruction // without using assembly, so in order to use word64 as word, the assembly diff --git a/cdk/extra/yassl/taocrypt/src/aes.cpp b/cdk/extra/yassl/taocrypt/src/aes.cpp index ee4c7a6e8..87c8c074b 100644 --- a/cdk/extra/yassl/taocrypt/src/aes.cpp +++ b/cdk/extra/yassl/taocrypt/src/aes.cpp @@ -47,7 +47,7 @@ void AES::Process(byte* out, const byte* in, word32 sz) if (dir_ == ENCRYPTION) AsmEncrypt(in, out, (void*)Te0); else - AsmDecrypt(in, out, (void*)Td0); + AsmDecrypt(in, out, (void*)Td0); out += BLOCK_SIZE; in += BLOCK_SIZE; } @@ -69,7 +69,7 @@ void AES::Process(byte* out, const byte* in, word32 sz) else { while (blocks--) { AsmDecrypt(in, out, (void*)Td0); - + *(word32*)out ^= r_[0]; *(word32*)(out + 4) ^= r_[1]; *(word32*)(out + 8) ^= r_[2]; @@ -94,7 +94,7 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) keylen = 32; else if (keylen != 24) keylen = 24; - + rounds_ = keylen/4 + 6; word32 temp, *rk = key_; @@ -109,10 +109,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[3]; rk[4] = rk[0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; @@ -128,10 +128,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[ 5]; rk[ 6] = rk[ 0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; @@ -149,10 +149,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; @@ -161,10 +161,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) break; temp = rk[11]; rk[12] = rk[ 4] ^ - (Te4[GETBYTE(temp, 3)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 0)] & 0x000000ff); + (Te2[GETBYTE(temp, 3)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 0)] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; @@ -191,25 +191,25 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) for (i = 1; i < rounds_; i++) { rk += 4; rk[0] = - Td0[Te4[GETBYTE(rk[0], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[0], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[0], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[0], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[0], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[0], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[0], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[0], 0)] & 0xff]; rk[1] = - Td0[Te4[GETBYTE(rk[1], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[1], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[1], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[1], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[1], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[1], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[1], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[1], 0)] & 0xff]; rk[2] = - Td0[Te4[GETBYTE(rk[2], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[2], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[2], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[2], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[2], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[2], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[2], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[2], 0)] & 0xff]; rk[3] = - Td0[Te4[GETBYTE(rk[3], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[3], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[3], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[3], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[3], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[3], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[3], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[3], 0)] & 0xff]; } } } @@ -226,7 +226,7 @@ void AES::ProcessAndXorBlock(const byte* in, const byte* xOr, byte* out) const typedef BlockGetAndPut gpBlock; - + void AES::encrypt(const byte* inBlock, const byte* xorBlock, byte* outBlock) const { @@ -243,7 +243,8 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, s1 ^= rk[1]; s2 ^= rk[2]; s3 ^= rk[3]; - + + s0 |= PreFetchTe(); /* * Nr - 1 full rounds: */ @@ -279,7 +280,7 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, if (--r == 0) { break; } - + s0 = Te0[GETBYTE(t0, 3)] ^ Te1[GETBYTE(t1, 2)] ^ @@ -312,28 +313,28 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, */ s0 = - (Te4[GETBYTE(t0, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t1, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t2, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t3, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t0, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t1, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t2, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t3, 0)] & 0x000000ff) ^ rk[0]; s1 = - (Te4[GETBYTE(t1, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t2, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t3, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t0, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t1, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t2, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t3, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t0, 0)] & 0x000000ff) ^ rk[1]; s2 = - (Te4[GETBYTE(t2, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t3, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t0, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t1, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t2, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t3, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t0, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t1, 0)] & 0x000000ff) ^ rk[2]; s3 = - (Te4[GETBYTE(t3, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t0, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t1, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t2, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t3, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t0, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t1, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t2, 0)] & 0x000000ff) ^ rk[3]; @@ -358,6 +359,8 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, s2 ^= rk[2]; s3 ^= rk[3]; + s0 |= PreFetchTd(); + /* * Nr - 1 full rounds: */ @@ -423,29 +426,32 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, * apply last round and * map cipher state to byte array block: */ + + t0 |= PreFetchCTd4(); + s0 = - (Td4[GETBYTE(t0, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t3, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t2, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t1, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t0, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t3, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t2, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t1, 0)]) ^ rk[0]; s1 = - (Td4[GETBYTE(t1, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t0, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t3, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t2, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t1, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t0, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t3, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t2, 0)]) ^ rk[1]; s2 = - (Td4[GETBYTE(t2, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t1, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t0, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t3, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t2, 3)] << 24 ) ^ + ((word32)CTd4[GETBYTE(t1, 2)] << 16 ) ^ + ((word32)CTd4[GETBYTE(t0, 1)] << 8 ) ^ + ((word32)CTd4[GETBYTE(t3, 0)]) ^ rk[2]; s3 = - (Td4[GETBYTE(t3, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t2, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t1, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t0, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t3, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t2, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t1, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t0, 0)]) ^ rk[3]; gpBlock::Put(xorBlock, outBlock)(s0)(s1)(s2)(s3); @@ -466,13 +472,13 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, "movd mm7, ebp;" \ "movd mm4, eax;" \ "mov ebp, edx;" \ - "sub esp, 4;" + "sub esp, 4;" #define EPILOG() \ "add esp, 4;" \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "S" (inBlock), "d" (boxes), "a" (outBlock) \ : "%edi", "memory", "cc" \ @@ -502,13 +508,13 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, AS1( pop ebp ) \ AS1( emms ) \ AS1( ret 12 ) - - + + #endif #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -528,7 +534,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS1( dec edx ) AS2( movd mm6, edi ) // save rk AS2( movd mm5, edx ) // save rounds - + AS2( mov eax, DWORD PTR [esi] ) AS2( mov ebx, DWORD PTR [esi + 4] ) AS2( mov ecx, DWORD PTR [esi + 8] ) @@ -549,17 +555,17 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const #else AS1(1: ) // loop1 #endif - /* Put0 (mm0) = + /* Put0 (mm0) = Te0[get0,rs 24] ^ Te1[get1,rs 16] ^ Te2[get2,rs 8] ^ Te3[get3,rs 0] */ - + AS2( mov esi, eax ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, ebx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -573,7 +579,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( movd mm0, esi ) - /* Put1 (mm1) = + /* Put1 (mm1) = Te0[get1,rs 24] ^ Te1[get2,rs 16] ^ Te2[get3,rs 8] ^ @@ -598,11 +604,11 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( movd mm1, esi ) - /* Put2 (mm2) = + /* Put2 (mm2) = Te0[get2,rs 24] ^ Te1[get3,rs 16] ^ Te2[get0,rs 8] ^ - Te3[get1,rs 0] + Te3[get1,rs 0] */ AS2( mov esi, ecx ) @@ -622,11 +628,11 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( movd mm2, esi ) - /* Put3 (edx) = + /* Put3 (edx) = Te0[get3,rs 24] ^ Te1[get0,rs 16] ^ Te2[get1,rs 8] ^ - Te3[get2,rs 0] + Te3[get2,rs 0] */ AS2( mov esi, edx ) @@ -792,7 +798,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const AS2( and esi, 255 ) AS2( xor edx, esi ) - + // xOr AS2( movd eax, mm0 ) AS2( movd esi, mm6 ) // rk @@ -833,7 +839,7 @@ void AES::AsmEncrypt(const byte* inBlock, byte* outBlock, void* boxes) const #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -844,12 +850,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const #ifdef OLD_GCC_OFFSET AS2( mov edx, DWORD PTR [ecx + 60] ) // rounds - AS2( lea edi, [ecx + 64] ) // rk + AS2( lea edi, [ecx + 64] ) // rk #else AS2( mov edx, DWORD PTR [ecx + 56] ) // rounds - AS2( lea edi, [ecx + 60] ) // rk + AS2( lea edi, [ecx + 60] ) // rk #endif - + AS1( dec edx ) AS2( movd mm6, edi ) // save rk AS2( movd mm5, edx ) // save rounds @@ -879,12 +885,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get0, rs24)] ^ Td1[GETBYTE(get3, rs16)] ^ Td2[GETBYTE(get2, rs 8)] ^ - Td3[GETBYTE(tet1, )] + Td3[GETBYTE(tet1, )] */ AS2( mov esi, eax ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, edx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -902,12 +908,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get1, rs24)] ^ Td1[GETBYTE(get0, rs16)] ^ Td2[GETBYTE(get3, rs 8)] ^ - Td3[GETBYTE(tet2, )] + Td3[GETBYTE(tet2, )] */ AS2( mov esi, ebx ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, eax ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -925,12 +931,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get2, rs24)] ^ Td1[GETBYTE(get1, rs16)] ^ Td2[GETBYTE(get0, rs 8)] ^ - Td3[GETBYTE(tet3, )] + Td3[GETBYTE(tet3, )] */ AS2( mov esi, ecx ) AS2( shr esi, 24 ) AS2( mov esi, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, ebx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -948,12 +954,12 @@ void AES::AsmDecrypt(const byte* inBlock, byte* outBlock, void* boxes) const Td0[GETBYTE(get3, rs24)] ^ Td1[GETBYTE(get2, rs16)] ^ Td2[GETBYTE(get1, rs 8)] ^ - Td3[GETBYTE(tet0, )] + Td3[GETBYTE(tet0, )] */ AS2( mov esi, edx ) AS2( shr esi, 24 ) AS2( mov edx, DWORD PTR [ebp + esi*4] ) - + AS2( mov edi, ecx ) AS2( shr edi, 16 ) AS2( and edi, 255 ) @@ -1826,18 +1832,52 @@ const word32 AES::Td[5][256] = { } }; +const byte AES::CTd4[256] = +{ + 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, + 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, + 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, + 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, + 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, + 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, + 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, + 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, + 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, + 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, + 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, + 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, + 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, + 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, + 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, + 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, + 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, + 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, + 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, + 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, + 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, + 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, + 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, + 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, + 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, + 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, + 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, + 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, + 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, + 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, + 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, + 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, +}; + const word32* AES::Te0 = AES::Te[0]; const word32* AES::Te1 = AES::Te[1]; const word32* AES::Te2 = AES::Te[2]; const word32* AES::Te3 = AES::Te[3]; -const word32* AES::Te4 = AES::Te[4]; const word32* AES::Td0 = AES::Td[0]; const word32* AES::Td1 = AES::Td[1]; const word32* AES::Td2 = AES::Td[2]; const word32* AES::Td3 = AES::Td[3]; -const word32* AES::Td4 = AES::Td[4]; diff --git a/cdk/extra/yassl/taocrypt/src/aestables.cpp b/cdk/extra/yassl/taocrypt/src/aestables.cpp index 60795a549..82e0a9aea 100644 --- a/cdk/extra/yassl/taocrypt/src/aestables.cpp +++ b/cdk/extra/yassl/taocrypt/src/aestables.cpp @@ -28,7 +28,7 @@ namespace TaoCrypt { const word32 AES::rcon_[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; diff --git a/cdk/extra/yassl/taocrypt/src/algebra.cpp b/cdk/extra/yassl/taocrypt/src/algebra.cpp index ace17047a..0f5b76687 100644 --- a/cdk/extra/yassl/taocrypt/src/algebra.cpp +++ b/cdk/extra/yassl/taocrypt/src/algebra.cpp @@ -193,8 +193,8 @@ struct WindowSlider if (windowSize == 0) { unsigned int expLen = exp.BitCount(); - windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : - (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : + windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : + (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : (expLen <= 1434 ? 6 : 7))))); } windowModulus <<= windowSize; @@ -259,7 +259,7 @@ void AbstractGroup::SimultaneousMultiply(Integer *results, const Integer &base, notDone = false; for (i=0; i(tm& a, tm& b) { if (a.tm_year > b.tm_year) @@ -95,7 +95,7 @@ bool operator>(tm& a, tm& b) if (a.tm_year == b.tm_year && a.tm_mon > b.tm_mon) return true; - + if (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && a.tm_mday >b.tm_mday) return true; @@ -108,13 +108,18 @@ bool operator>(tm& a, tm& b) a.tm_min > b.tm_min) return true; + if (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && + a.tm_mday == b.tm_mday && a.tm_hour == b.tm_hour && + a.tm_min == b.tm_min && a.tm_sec > b.tm_sec) + return true; + return false; } bool operator<(tm& a, tm&b) { - return !(a>b); + return (b>a); } @@ -153,7 +158,7 @@ word32 GetLength(Source& source) word32 length = 0; byte b = source.next(); - if (b >= LONG_LENGTH) { + if (b >= LONG_LENGTH) { word32 bytes = b & 0x7F; if (source.IsLeft(bytes) == false) return 0; @@ -180,7 +185,7 @@ word32 SetLength(word32 length, byte* output) output[i++] = length; else { output[i++] = BytePrecision(length) | 0x80; - + for (int j = BytePrecision(length); j; --j) { output[i] = length >> (j - 1) * 8; i++; @@ -244,8 +249,8 @@ Signer::~Signer() Error BER_Decoder::GetError() -{ - return source_.GetError(); +{ + return source_.GetError(); } @@ -256,7 +261,7 @@ Integer& BER_Decoder::GetInteger(Integer& integer) return integer; } - + // Read a Sequence, return length word32 BER_Decoder::GetSequence() { @@ -319,9 +324,9 @@ word32 BER_Decoder::GetExplicitVersion() source_.next(); return GetVersion(); } - else + else source_.prev(); // put back - + return 0; } @@ -364,7 +369,7 @@ void DSA_Private_Decoder::Decode(DSA_PrivateKey& key) // key key.SetPublicPart(GetInteger(Integer().Ref())); - key.SetPrivatePart(GetInteger(Integer().Ref())); + key.SetPrivatePart(GetInteger(Integer().Ref())); } @@ -408,27 +413,27 @@ void RSA_Public_Decoder::ReadHeaderOpenSSL() source_.advance(len); b = source_.next(); - if (b == TAG_NULL) { // could have NULL tag and 0 terminator, may not + if (b == TAG_NULL) { // could have NULL tag and 0 terminator, may not b = source_.next(); if (b != 0) { source_.SetError(EXPECT_0_E); - return; + return; } } else source_.prev(); // put back b = source_.next(); - if (b != BIT_STRING) { + if (b != BIT_STRING) { source_.SetError(BIT_STR_E); - return; + return; } - len = GetLength(source_); + len = GetLength(source_); b = source_.next(); if (b != 0) // could have 0 source_.prev(); // put back - + GetSequence(); } } @@ -482,8 +487,9 @@ void DH_Decoder::Decode(DH& key) CertDecoder::CertDecoder(Source& s, bool decode, SignerList* signers, bool noVerify, CertType ct) - : BER_Decoder(s), certBegin_(0), sigIndex_(0), sigLength_(0), - signature_(0), verify_(!noVerify) + : BER_Decoder(s), certBegin_(0), sigIndex_(0), sigLength_(0), subCnPos_(-1), + subCnLen_(0), issCnPos_(-1), issCnLen_(0), signature_(0), + verify_(!noVerify) { issuer_[0] = 0; subject_[0] = 0; @@ -534,7 +540,7 @@ void CertDecoder::Decode(SignerList* signers, CertType ct) source_.SetError(SIG_OID_E); return; } - + if (ct != CA && verify_ && !ValidateSignature(signers)) source_.SetError(SIG_OTHER_E); } @@ -544,9 +550,9 @@ void CertDecoder::DecodeToKey() { ReadHeader(); signatureOID_ = GetAlgoId(); - GetName(ISSUER); + GetName(ISSUER); GetValidity(); - GetName(SUBJECT); + GetName(SUBJECT); GetKey(); } @@ -556,7 +562,7 @@ void CertDecoder::GetKey() { if (source_.GetError().What()) return; - GetSequence(); + GetSequence(); keyOID_ = GetAlgoId(); if (keyOID_ == RSAk) { @@ -566,7 +572,7 @@ void CertDecoder::GetKey() return; } b = source_.next(); // length, future - b = source_.next(); + b = source_.next(); while(b != 0) b = source_.next(); } @@ -615,7 +621,7 @@ void CertDecoder::AddDSA() return; } b = source_.next(); // length, future - b = source_.next(); + b = source_.next(); while(b != 0) b = source_.next(); @@ -631,7 +637,7 @@ void CertDecoder::AddDSA() if (source_.IsLeft(length) == false) return; - key_.AddToEnd(source_.get_buffer() + idx, length); + key_.AddToEnd(source_.get_buffer() + idx, length); } @@ -642,7 +648,7 @@ word32 CertDecoder::GetAlgoId() word32 length = GetSequence(); if (source_.GetError().What()) return 0; - + byte b = source_.next(); if (b != OBJECT_IDENTIFIER) { source_.SetError(OBJECT_ID_E); @@ -689,7 +695,7 @@ word32 CertDecoder::GetSignature() source_.SetError(CONTENT_E); return 0; } - + b = source_.next(); if (b != 0) { source_.SetError(EXPECT_0_E); @@ -757,7 +763,7 @@ void CertDecoder::GetName(NameType nt) return; if (source_.IsLeft(length) == false) return; length += source_.get_index(); - + char* ptr; char* buf_end; @@ -773,7 +779,7 @@ void CertDecoder::GetName(NameType nt) while (source_.get_index() < length) { GetSet(); if (source_.GetError().What() == SET_E) { - source_.SetError(NO_ERROR_E); // extensions may only have sequence + source_.SetError(NO_ERROR_E); // extensions may only have sequence source_.prev(); } GetSequence(); @@ -794,7 +800,7 @@ void CertDecoder::GetName(NameType nt) // v1 name types if (joint[0] == 0x55 && joint[1] == 0x04) { source_.advance(2); - byte id = source_.next(); + byte id = source_.next(); b = source_.next(); // strType word32 strLen = GetLength(source_); @@ -804,6 +810,13 @@ void CertDecoder::GetName(NameType nt) case COMMON_NAME: if (!(ptr = AddTag(ptr, buf_end, "/CN=", 4, strLen))) return; + if (nt == ISSUER) { + issCnPos_ = (int)(ptr - strLen - issuer_); + issCnLen_ = (int)strLen; + } else { + subCnPos_ = (int)(ptr - strLen - subject_); + subCnLen_ = (int)strLen; + } break; case SUR_NAME: if (!(ptr = AddTag(ptr, buf_end, "/SN=", 4, strLen))) @@ -834,7 +847,7 @@ void CertDecoder::GetName(NameType nt) sha.Update(source_.get_current(), strLen); source_.advance(strLen); } - else { + else { bool email = false; if (joint[0] == 0x2a && joint[1] == 0x86) // email id hdr email = true; @@ -845,7 +858,7 @@ void CertDecoder::GetName(NameType nt) if (email) { if (!(ptr = AddTag(ptr, buf_end, "/emailAddress=", 14, length))) - return; + return; } source_.advance(length); @@ -901,7 +914,7 @@ void CertDecoder::GetDate(DateType dt) memcpy(afterDate_, date, length); afterDate_[length] = 0; afterDateType_= b; - } + } } @@ -955,11 +968,11 @@ bool CertDecoder::ValidateSignature(SignerList* signers) while (first != last) { if ( memcmp(issuerHash_, (*first)->GetHash(), SHA::DIGEST_SIZE) == 0) { - + const PublicKey& iKey = (*first)->GetPublicKey(); Source pub(iKey.GetKey(), iKey.size()); return ConfirmSignature(pub); - } + } ++first; } return false; @@ -1067,7 +1080,7 @@ word32 Signature_Encoder::SetDigest(const byte* d, word32 dSz, byte* output) output[0] = OCTET_STRING; output[1] = dSz; memcpy(&output[2], d, dSz); - + return dSz + 2; } @@ -1145,7 +1158,7 @@ word32 DER_Encoder::SetAlgoID(HashType aOID, byte* output) word32 SetSequence(word32 len, byte* output) { - + output[0] = SEQUENCE | CONSTRUCTED; return SetLength(len, output + 1) + 1; } @@ -1177,7 +1190,7 @@ word32 EncodeDSA_Signature(const Integer& r, const Integer& s, byte* output) byte seqArray[MAX_SEQ_SZ]; word32 seqSz = SetSequence(rLenSz + rSz + sLenSz + sSz, seqArray); - + // seq memcpy(output, seqArray, seqSz); // r @@ -1210,17 +1223,17 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz) } word32 rLen = GetLength(source); if (rLen != 20) { - if (rLen == 21) { // zero at front, eat + while (rLen > 20 && source.remaining() > 0) { // zero's at front, eat source.next(); --rLen; } - else if (rLen == 19) { // add zero to front so 20 bytes + if (rLen < 20) { // add zero's to front so 20 bytes + word32 tmpLen = rLen; + while (tmpLen < 20) { decoded[0] = 0; decoded++; + tmpLen++; } - else { - source.SetError(DSA_SZ_E); - return 0; } } memcpy(decoded, source.get_buffer() + source.get_index(), rLen); @@ -1233,17 +1246,17 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz) } word32 sLen = GetLength(source); if (sLen != 20) { - if (sLen == 21) { - source.next(); // zero at front, eat + while (sLen > 20 && source.remaining() > 0) { + source.next(); // zero's at front, eat --sLen; } - else if (sLen == 19) { - decoded[rLen] = 0; // add zero to front so 20 bytes + if (sLen < 20) { // add zero's to front so 20 bytes + word32 tmpLen = sLen; + while (tmpLen < 20) { + decoded[rLen] = 0; decoded++; + tmpLen++; } - else { - source.SetError(DSA_SZ_E); - return 0; } } memcpy(decoded + rLen, source.get_buffer() + source.get_index(), sLen); @@ -1265,7 +1278,7 @@ int GetCert(Source& source) if (!begin || !end || begin >= end) return -1; - end += strlen(footer); + end += strlen(footer); if (*end == '\r') end++; Source tmp((byte*)begin, end - begin + 1); @@ -1285,7 +1298,7 @@ void PKCS12_Decoder::Decode() // Get AuthSafe GetSequence(); - + // get object id byte obj_id = source_.next(); if (obj_id != OBJECT_IDENTIFIER) { @@ -1299,8 +1312,8 @@ void PKCS12_Decoder::Decode() while (length--) algo_sum += source_.next(); - - + + @@ -1308,7 +1321,7 @@ void PKCS12_Decoder::Decode() // mac digestInfo like certdecoder::getdigest? // macsalt octet string // iter integer - + } diff --git a/cdk/extra/yassl/taocrypt/src/coding.cpp b/cdk/extra/yassl/taocrypt/src/coding.cpp index bc4727cc5..c90d2c85f 100644 --- a/cdk/extra/yassl/taocrypt/src/coding.cpp +++ b/cdk/extra/yassl/taocrypt/src/coding.cpp @@ -37,7 +37,7 @@ const byte hexEncode[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, bad, bad, bad, bad, bad, bad, bad, - 10, 11, 12, 13, 14, 15 + 10, 11, 12, 13, 14, 15 }; // A starts at 0x41 not 0x3A @@ -135,7 +135,7 @@ void Base64Encoder::Encode() word32 i = 0; word32 j = 0; - + while (bytes > 2) { byte b1 = plain_.next(); byte b2 = plain_.next(); @@ -174,10 +174,10 @@ void Base64Encoder::Encode() encoded_[i++] = base64Encode[e2]; encoded_[i++] = (twoBytes) ? base64Encode[e3] : pad; encoded_[i++] = pad; - } + } encoded_[i++] = '\n'; - + if (i == outSz) plain_.reset(encoded_); } @@ -187,7 +187,7 @@ void Base64Encoder::Encode() void Base64Decoder::Decode() { word32 bytes = coded_.size(); - word32 plainSz = bytes - ((bytes + (pemLineSz - 1)) / pemLineSz); + word32 plainSz = bytes - ((bytes + (pemLineSz - 1)) / pemLineSz); const byte maxIdx = (byte)sizeof(base64Decode) + 0x2B - 1; plainSz = ((plainSz * 3) / 4) + 3; decoded_.New(plainSz); @@ -237,7 +237,7 @@ void Base64Decoder::Decode() decoded_[i++] = b3; else break; - + bytes -= 4; if ((++j % 16) == 0) { byte endLine = coded_.next(); @@ -251,7 +251,7 @@ void Base64Decoder::Decode() bytes--; } if (endLine != '\n') { - coded_.SetError(PEM_E); + coded_.SetError(PEM_E); return; } } diff --git a/cdk/extra/yassl/taocrypt/src/des.cpp b/cdk/extra/yassl/taocrypt/src/des.cpp index 53777f082..c1961684c 100644 --- a/cdk/extra/yassl/taocrypt/src/des.cpp +++ b/cdk/extra/yassl/taocrypt/src/des.cpp @@ -257,14 +257,14 @@ void BasicDES::SetKey(const byte* key, word32 /*length*/, CipherDir dir) | ((word32)ks[5] << 8) | ((word32)ks[7]); } - + // reverse key schedule order if (dir == DECRYPTION) for (i = 0; i < 16; i += 2) { STL::swap(k_[i], k_[32 - 2 - i]); STL::swap(k_[i+1], k_[32 - 1 - i]); } - + } static inline void IPERM(word32& left, word32& right) @@ -411,14 +411,14 @@ void DES_EDE3::Process(byte* out, const byte* in, word32 sz) word32 blocks = sz / DES_BLOCK_SIZE; - if (mode_ == CBC) + if (mode_ == CBC) if (dir_ == ENCRYPTION) while (blocks--) { r_[0] ^= *(word32*)in; r_[1] ^= *(word32*)(in + 4); AsmProcess((byte*)r_, (byte*)r_, (void*)Spbox); - + memcpy(out, r_, DES_BLOCK_SIZE); in += DES_BLOCK_SIZE; @@ -427,7 +427,7 @@ void DES_EDE3::Process(byte* out, const byte* in, word32 sz) else while (blocks--) { AsmProcess(in, out, (void*)Spbox); - + *(word32*)out ^= r_[0]; *(word32*)(out + 4) ^= r_[1]; @@ -439,7 +439,7 @@ void DES_EDE3::Process(byte* out, const byte* in, word32 sz) else while (blocks--) { AsmProcess(in, out, (void*)Spbox); - + out += DES_BLOCK_SIZE; in += DES_BLOCK_SIZE; } @@ -641,7 +641,7 @@ void DES_EDE3::ProcessAndXorBlock(const byte* in, const byte* xOr, #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -663,8 +663,8 @@ void DES_EDE3::AsmProcess(const byte* in, byte* out, void* box) const #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "d" (this), "S" (in), "a" (box), "c" (out) \ : "%edi", "memory", "cc" \ @@ -724,7 +724,7 @@ void DES_EDE3::AsmProcess(const byte* in, byte* out, void* box) const DesRound() // 7 DesRound() // 8 - // swap left and right + // swap left and right AS2( xchg eax, ebx ) DesRound() // 1 @@ -765,7 +765,7 @@ void DES_EDE3::AsmProcess(const byte* in, byte* out, void* box) const AS2( mov DWORD PTR [esi], ebx ) // right first AS2( mov DWORD PTR [esi + 4], eax ) - + EPILOG() } diff --git a/cdk/extra/yassl/taocrypt/src/dsa.cpp b/cdk/extra/yassl/taocrypt/src/dsa.cpp index bf116d3e4..a139195a7 100644 --- a/cdk/extra/yassl/taocrypt/src/dsa.cpp +++ b/cdk/extra/yassl/taocrypt/src/dsa.cpp @@ -70,7 +70,7 @@ void DSA_PublicKey::Initialize(const Integer& p, const Integer& q, g_ = g; y_ = y; } - + const Integer& DSA_PublicKey::GetModulus() const { @@ -172,6 +172,7 @@ word32 DSA_Signer::Sign(const byte* sha_digest, byte* sig, const Integer& q = key_.GetSubGroupOrder(); const Integer& g = key_.GetSubGroupGenerator(); const Integer& x = key_.GetPrivatePart(); + byte* tmpPtr = sig; // initial signature output Integer k(rng, 1, q - 1); @@ -187,22 +188,23 @@ word32 DSA_Signer::Sign(const byte* sha_digest, byte* sig, return -1; int rSz = r_.ByteCount(); + int tmpSz = rSz; - if (rSz == 19) { - sig[0] = 0; - sig++; + while (tmpSz++ < SHA::DIGEST_SIZE) { + *sig++ = 0; } - + r_.Encode(sig, rSz); + sig = tmpPtr + SHA::DIGEST_SIZE; // advance sig output to s int sSz = s_.ByteCount(); + tmpSz = sSz; - if (sSz == 19) { - sig[rSz] = 0; - sig++; + while (tmpSz++ < SHA::DIGEST_SIZE) { + *sig++ = 0; } - s_.Encode(sig + rSz, sSz); + s_.Encode(sig, sSz); return 40; } diff --git a/cdk/extra/yassl/taocrypt/src/file.cpp b/cdk/extra/yassl/taocrypt/src/file.cpp index 7c2044bf3..929501f36 100644 --- a/cdk/extra/yassl/taocrypt/src/file.cpp +++ b/cdk/extra/yassl/taocrypt/src/file.cpp @@ -107,7 +107,7 @@ void FileSink::put(Source& source) // swap with other and reset to beginning void Source::reset(ByteBlock& otherBlock) { - buffer_.Swap(otherBlock); + buffer_.Swap(otherBlock); current_ = 0; } diff --git a/cdk/extra/yassl/taocrypt/src/hash.cpp b/cdk/extra/yassl/taocrypt/src/hash.cpp index c176e6a68..c479b7007 100644 --- a/cdk/extra/yassl/taocrypt/src/hash.cpp +++ b/cdk/extra/yassl/taocrypt/src/hash.cpp @@ -92,9 +92,9 @@ void HASHwithTransform::Final(byte* hash) buffLen_ = 0; } memset(&local[buffLen_], 0, padSz - buffLen_); - + ByteReverseIf(local, local, blockSz, order); - + memcpy(&local[padSz], order ? &preHiLen : &preLoLen, sizeof(preLoLen)); memcpy(&local[padSz+4], order ? &preLoLen : &preHiLen, sizeof(preLoLen)); @@ -172,9 +172,9 @@ void HASH64withTransform::Final(byte* hash) buffLen_ = 0; } memset(&local[buffLen_], 0, padSz - buffLen_); - + ByteReverseIf(buffer_, buffer_, padSz, order); - + buffer_[blockSz / sizeof(word64) - 2] = order ? preHiLen : preLoLen; buffer_[blockSz / sizeof(word64) - 1] = order ? preLoLen : preHiLen; diff --git a/cdk/extra/yassl/taocrypt/src/hc128.cpp b/cdk/extra/yassl/taocrypt/src/hc128.cpp index 1d329c87e..df2c3619e 100644 --- a/cdk/extra/yassl/taocrypt/src/hc128.cpp +++ b/cdk/extra/yassl/taocrypt/src/hc128.cpp @@ -60,7 +60,7 @@ namespace TaoCrypt { (T_[(u)]) += tem2+(tem0 ^ tem1); \ (X_[(a)]) = (T_[(u)]); \ (n) = tem3 ^ (T_[(u)]) ; \ -} +} /*one step of HC-128, update Q and generate 32 bits keystream*/ #define step_Q(u,v,a,b,c,d,n){ \ @@ -72,18 +72,18 @@ namespace TaoCrypt { (T_[(u)]) += tem2 + (tem0 ^ tem1); \ (Y_[(a)]) = (T_[(u)]); \ (n) = tem3 ^ (T_[(u)]) ; \ -} +} /*16 steps of HC-128, generate 512 bits keystream*/ -void HC128::GenerateKeystream(word32* keystream) +void HC128::GenerateKeystream(word32* keystream) { word32 cc,dd; cc = counter1024_ & 0x1ff; dd = (cc+16)&0x1ff; - if (counter1024_ < 512) - { + if (counter1024_ < 512) + { counter1024_ = (counter1024_ + 16) & 0x3ff; step_P(cc+0, cc+1, 0, 6, 13,4, keystream[0]); step_P(cc+1, cc+2, 1, 7, 14,5, keystream[1]); @@ -102,9 +102,9 @@ void HC128::GenerateKeystream(word32* keystream) step_P(cc+14,cc+15,14,4, 11,2, keystream[14]); step_P(cc+15,dd+0, 15,5, 12,3, keystream[15]); } - else + else { - counter1024_ = (counter1024_ + 16) & 0x3ff; + counter1024_ = (counter1024_ + 16) & 0x3ff; step_Q(512+cc+0, 512+cc+1, 0, 6, 13,4, keystream[0]); step_Q(512+cc+1, 512+cc+2, 1, 7, 14,5, keystream[1]); step_Q(512+cc+2, 512+cc+3, 2, 8, 15,6, keystream[2]); @@ -138,7 +138,7 @@ void HC128::GenerateKeystream(word32* keystream) h1((X_[(d)]),tem3); \ (T_[(u)]) = ((T_[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ (X_[(a)]) = (T_[(u)]); \ -} +} /*update table Q*/ #define update_Q(u,v,a,b,c,d){ \ @@ -149,7 +149,7 @@ void HC128::GenerateKeystream(word32* keystream) h2((Y_[(d)]),tem3); \ (T_[(u)]) = ((T_[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ (Y_[(a)]) = (T_[(u)]); \ -} +} /*16 steps of HC-128, without generating keystream, */ /*but use the outputs to update P and Q*/ @@ -159,8 +159,8 @@ void HC128::SetupUpdate() /*each time 16 steps*/ cc = counter1024_ & 0x1ff; dd = (cc+16)&0x1ff; - if (counter1024_ < 512) - { + if (counter1024_ < 512) + { counter1024_ = (counter1024_ + 16) & 0x3ff; update_P(cc+0, cc+1, 0, 6, 13, 4); update_P(cc+1, cc+2, 1, 7, 14, 5); @@ -177,9 +177,9 @@ void HC128::SetupUpdate() /*each time 16 steps*/ update_P(cc+12,cc+13,12,2, 9, 0); update_P(cc+13,cc+14,13,3, 10, 1); update_P(cc+14,cc+15,14,4, 11, 2); - update_P(cc+15,dd+0, 15,5, 12, 3); + update_P(cc+15,dd+0, 15,5, 12, 3); } - else + else { counter1024_ = (counter1024_ + 16) & 0x3ff; update_Q(512+cc+0, 512+cc+1, 0, 6, 13, 4); @@ -197,8 +197,8 @@ void HC128::SetupUpdate() /*each time 16 steps*/ update_Q(512+cc+12,512+cc+13,12,2, 9, 0); update_Q(512+cc+13,512+cc+14,13,3, 10, 1); update_Q(512+cc+14,512+cc+15,14,4, 11, 2); - update_Q(512+cc+15,512+dd+0, 15,5, 12, 3); - } + update_Q(512+cc+15,512+dd+0, 15,5, 12, 3); + } } @@ -220,46 +220,46 @@ void HC128::SetupUpdate() /*each time 16 steps*/ void HC128::SetIV(const byte* iv) -{ +{ word32 i; - - for (i = 0; i < (128 >> 5); i++) + + for (i = 0; i < (128 >> 5); i++) iv_[i] = LITTLE32(((word32*)iv)[i]); - + for (; i < 8; i++) iv_[i] = iv_[i-4]; - - /* expand the key and IV into the table T */ - /* (expand the key and IV into the table P and Q) */ - - for (i = 0; i < 8; i++) T_[i] = key_[i]; - for (i = 8; i < 16; i++) T_[i] = iv_[i-8]; - - for (i = 16; i < (256+16); i++) - T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+i; - - for (i = 0; i < 16; i++) T_[i] = T_[256+i]; - - for (i = 16; i < 1024; i++) - T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+256+i; - + + /* expand the key and IV into the table T */ + /* (expand the key and IV into the table P and Q) */ + + for (i = 0; i < 8; i++) T_[i] = key_[i]; + for (i = 8; i < 16; i++) T_[i] = iv_[i-8]; + + for (i = 16; i < (256+16); i++) + T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+i; + + for (i = 0; i < 16; i++) T_[i] = T_[256+i]; + + for (i = 16; i < 1024; i++) + T_[i] = f2(T_[i-2]) + T_[i-7] + f1(T_[i-15]) + T_[i-16]+256+i; + /* initialize counter1024, X and Y */ - counter1024_ = 0; - for (i = 0; i < 16; i++) X_[i] = T_[512-16+i]; + counter1024_ = 0; + for (i = 0; i < 16; i++) X_[i] = T_[512-16+i]; for (i = 0; i < 16; i++) Y_[i] = T_[512+512-16+i]; - + /* run the cipher 1024 steps before generating the output */ - for (i = 0; i < 64; i++) SetupUpdate(); + for (i = 0; i < 64; i++) SetupUpdate(); } void HC128::SetKey(const byte* key, const byte* iv) -{ - word32 i; +{ + word32 i; - /* Key size in bits 128 */ + /* Key size in bits 128 */ for (i = 0; i < (128 >> 5); i++) key_[i] = LITTLE32(((word32*)key)[i]); - + for ( ; i < 8 ; i++) key_[i] = key_[i-4]; SetIV(iv); @@ -273,25 +273,25 @@ void HC128::Process(byte* output, const byte* input, word32 msglen) for ( ; msglen >= 64; msglen -= 64, input += 64, output += 64) { - GenerateKeystream(keystream); + GenerateKeystream(keystream); /* unroll loop */ - ((word32*)output)[0] = ((word32*)input)[0] ^ LITTLE32(keystream[0]); - ((word32*)output)[1] = ((word32*)input)[1] ^ LITTLE32(keystream[1]); - ((word32*)output)[2] = ((word32*)input)[2] ^ LITTLE32(keystream[2]); - ((word32*)output)[3] = ((word32*)input)[3] ^ LITTLE32(keystream[3]); - ((word32*)output)[4] = ((word32*)input)[4] ^ LITTLE32(keystream[4]); - ((word32*)output)[5] = ((word32*)input)[5] ^ LITTLE32(keystream[5]); - ((word32*)output)[6] = ((word32*)input)[6] ^ LITTLE32(keystream[6]); - ((word32*)output)[7] = ((word32*)input)[7] ^ LITTLE32(keystream[7]); - ((word32*)output)[8] = ((word32*)input)[8] ^ LITTLE32(keystream[8]); - ((word32*)output)[9] = ((word32*)input)[9] ^ LITTLE32(keystream[9]); - ((word32*)output)[10] = ((word32*)input)[10] ^ LITTLE32(keystream[10]); - ((word32*)output)[11] = ((word32*)input)[11] ^ LITTLE32(keystream[11]); - ((word32*)output)[12] = ((word32*)input)[12] ^ LITTLE32(keystream[12]); - ((word32*)output)[13] = ((word32*)input)[13] ^ LITTLE32(keystream[13]); - ((word32*)output)[14] = ((word32*)input)[14] ^ LITTLE32(keystream[14]); - ((word32*)output)[15] = ((word32*)input)[15] ^ LITTLE32(keystream[15]); + ((word32*)output)[0] = ((word32*)input)[0] ^ LITTLE32(keystream[0]); + ((word32*)output)[1] = ((word32*)input)[1] ^ LITTLE32(keystream[1]); + ((word32*)output)[2] = ((word32*)input)[2] ^ LITTLE32(keystream[2]); + ((word32*)output)[3] = ((word32*)input)[3] ^ LITTLE32(keystream[3]); + ((word32*)output)[4] = ((word32*)input)[4] ^ LITTLE32(keystream[4]); + ((word32*)output)[5] = ((word32*)input)[5] ^ LITTLE32(keystream[5]); + ((word32*)output)[6] = ((word32*)input)[6] ^ LITTLE32(keystream[6]); + ((word32*)output)[7] = ((word32*)input)[7] ^ LITTLE32(keystream[7]); + ((word32*)output)[8] = ((word32*)input)[8] ^ LITTLE32(keystream[8]); + ((word32*)output)[9] = ((word32*)input)[9] ^ LITTLE32(keystream[9]); + ((word32*)output)[10] = ((word32*)input)[10] ^ LITTLE32(keystream[10]); + ((word32*)output)[11] = ((word32*)input)[11] ^ LITTLE32(keystream[11]); + ((word32*)output)[12] = ((word32*)input)[12] ^ LITTLE32(keystream[12]); + ((word32*)output)[13] = ((word32*)input)[13] ^ LITTLE32(keystream[13]); + ((word32*)output)[14] = ((word32*)input)[14] ^ LITTLE32(keystream[14]); + ((word32*)output)[15] = ((word32*)input)[15] ^ LITTLE32(keystream[15]); } if (msglen > 0) @@ -302,13 +302,13 @@ void HC128::Process(byte* output, const byte* input, word32 msglen) { word32 wordsLeft = msglen / sizeof(word32); if (msglen % sizeof(word32)) wordsLeft++; - + ByteReverse(keystream, keystream, wordsLeft * sizeof(word32)); } #endif for (i = 0; i < msglen; i++) - output[i] = input[i] ^ ((byte*)keystream)[i]; + output[i] = input[i] ^ ((byte*)keystream)[i]; } } diff --git a/cdk/extra/yassl/taocrypt/src/integer.cpp b/cdk/extra/yassl/taocrypt/src/integer.cpp index 478a13cd8..d97376fe4 100644 --- a/cdk/extra/yassl/taocrypt/src/integer.cpp +++ b/cdk/extra/yassl/taocrypt/src/integer.cpp @@ -27,7 +27,7 @@ #endif #if defined(_M_X64) || defined(_M_IA64) - #include + #include #pragma intrinsic(_umul128) #endif @@ -359,7 +359,7 @@ S DivideThreeWordsByTwo(S* A, S B0, S B1, D* dummy_VC6_WorkAround = 0) D p = D::Multiply(B0, Q); D u = (D) A[0] - p.GetLowHalf(); A[0] = u.GetLowHalf(); - u = (D) A[1] - p.GetHighHalf() - u.GetHighHalfAsBorrow() - + u = (D) A[1] - p.GetHighHalf() - u.GetHighHalfAsBorrow() - D::Multiply(B1, Q); A[1] = u.GetLowHalf(); A[2] += u.GetHighHalf(); @@ -389,7 +389,7 @@ inline D DivideFourWordsByTwo(S *T, const D &Al, const D &Ah, const D &B) { S Q[2]; T[0] = Al.GetLowHalf(); - T[1] = Al.GetHighHalf(); + T[1] = Al.GetHighHalf(); T[2] = Ah.GetLowHalf(); T[3] = Ah.GetHighHalf(); Q[1] = DivideThreeWordsByTwo(T+1, B.GetLowHalf(), @@ -1083,7 +1083,7 @@ static PMul s_pMul4, s_pMul8, s_pMul8B; static void SetPentiumFunctionPointers() { if (!IsPentium()) - { + { s_pAdd = &Portable::Add; s_pSub = &Portable::Subtract; } @@ -1099,7 +1099,7 @@ static void SetPentiumFunctionPointers() } #ifdef SSE2_INTRINSICS_AVAILABLE - if (!IsPentium()) + if (!IsPentium()) { s_pMul4 = &Portable::Multiply4; s_pMul8 = &Portable::Multiply8; @@ -1406,7 +1406,7 @@ TAOCRYPT_NAKED word P4Optimized::Subtract(word *C, const word *A, #define MulStartup \ AS2(xor ebp, ebp) \ AS2(xor edi, edi) \ - AS2(xor ebx, ebx) + AS2(xor ebx, ebx) #define MulShiftCarry \ AS2(mov ebp, edx) \ @@ -2160,7 +2160,7 @@ void RecursiveMultiply(word *R, word *T, const word *A, const word *B, } -void RecursiveSquare(word *R, word *T, const word *A, unsigned int N) +void RecursiveSquare(word *R, word *T, const word *A, unsigned int N) { if (LowLevel::SquareRecursionLimit() >= 4 && N==4) LowLevel::Square4(R, A); @@ -2581,7 +2581,7 @@ void Integer::Decode(Source& source) source.prev(); if (source.IsLeft(length) == false) return; - + unsigned int words = (length + WORD_SIZE - 1) / WORD_SIZE; words = RoundupSize(words); if (words > reg_.size()) reg_.CleanNew(words); @@ -2596,7 +2596,7 @@ void Integer::Decode(Source& source) void Integer::Decode(const byte* input, unsigned int inputLen, Signedness s) { unsigned int idx(0); - byte b = 0; + byte b = 0; if (inputLen>0) b = input[idx]; // peek sign_ = ((s==SIGNED) && (b & 0x80)) ? NEGATIVE : POSITIVE; @@ -3174,7 +3174,7 @@ static inline void AtomicDivide(word *Q, const word *A, const word *B) #ifndef NDEBUG if (B[0] || B[1]) { - // multiply quotient and divisor and add remainder, make sure it + // multiply quotient and divisor and add remainder, make sure it // equals dividend word P[4]; Portable::Multiply2(P, Q, B); @@ -3558,7 +3558,7 @@ const Integer& ModularArithmetic::Half(const Integer &a) const const Integer& ModularArithmetic::Add(const Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Add(result.reg_.begin(), a.reg_.begin(), b.reg_.begin(), @@ -3582,7 +3582,7 @@ const Integer& ModularArithmetic::Add(const Integer &a, const Integer &b) const Integer& ModularArithmetic::Accumulate(Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Add(a.reg_.get_buffer(), a.reg_.get_buffer(), @@ -3607,7 +3607,7 @@ Integer& ModularArithmetic::Accumulate(Integer &a, const Integer &b) const const Integer& ModularArithmetic::Subtract(const Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Subtract(result.reg_.begin(), a.reg_.begin(), @@ -3627,7 +3627,7 @@ const Integer& ModularArithmetic::Subtract(const Integer &a, Integer& ModularArithmetic::Reduce(Integer &a, const Integer &b) const { - if (a.reg_.size()==modulus.reg_.size() && + if (a.reg_.size()==modulus.reg_.size() && b.reg_.size()==modulus.reg_.size()) { if (TaoCrypt::Subtract(a.reg_.get_buffer(), a.reg_.get_buffer(), diff --git a/cdk/extra/yassl/taocrypt/src/md2.cpp b/cdk/extra/yassl/taocrypt/src/md2.cpp index 3dfc0d6e7..a2fe0a107 100644 --- a/cdk/extra/yassl/taocrypt/src/md2.cpp +++ b/cdk/extra/yassl/taocrypt/src/md2.cpp @@ -44,7 +44,7 @@ void MD2::Init() void MD2::Update(const byte* data, word32 len) { - static const byte S[256] = + static const byte S[256] = { 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, diff --git a/cdk/extra/yassl/taocrypt/src/md4.cpp b/cdk/extra/yassl/taocrypt/src/md4.cpp index 9364a1c23..9fb789781 100644 --- a/cdk/extra/yassl/taocrypt/src/md4.cpp +++ b/cdk/extra/yassl/taocrypt/src/md4.cpp @@ -29,7 +29,7 @@ namespace STL = STL_NAMESPACE; - + namespace TaoCrypt { @@ -47,8 +47,8 @@ void MD4::Init() MD4::MD4(const MD4& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), - BLOCK_SIZE) -{ + BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -108,7 +108,7 @@ void MD4::Transform() function(C,D,A,B,14,11); function(B,C,D,A,15,19); -#undef function +#undef function #define function(a,b,c,d,k,s) a=rotlFixed(a+G(b,c,d)+buffer_[k]+0x5a827999,s); function(A,B,C,D, 0, 3); function(D,A,B,C, 4, 5); @@ -127,7 +127,7 @@ void MD4::Transform() function(C,D,A,B,11, 9); function(B,C,D,A,15,13); -#undef function +#undef function #define function(a,b,c,d,k,s) a=rotlFixed(a+H(b,c,d)+buffer_[k]+0x6ed9eba1,s); function(A,B,C,D, 0, 3); function(D,A,B,C, 8, 9); diff --git a/cdk/extra/yassl/taocrypt/src/md5.cpp b/cdk/extra/yassl/taocrypt/src/md5.cpp index 45cfa8a33..bdc17c063 100644 --- a/cdk/extra/yassl/taocrypt/src/md5.cpp +++ b/cdk/extra/yassl/taocrypt/src/md5.cpp @@ -48,8 +48,8 @@ void MD5::Init() MD5::MD5(const MD5& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), - BLOCK_SIZE) -{ + BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -91,7 +91,7 @@ void MD5::Update(const byte* data, word32 len) byte* local = reinterpret_cast(buffer_); // remove buffered data if possible - if (buffLen_) { + if (buffLen_) { word32 add = min(len, BLOCK_SIZE - buffLen_); memcpy(&local[buffLen_], data, add); @@ -174,7 +174,7 @@ void MD5::Update(const byte* data, word32 len) // esi already set up, after using set for next round // ebp already set up, set up using next round index - + #define MD5STEP1(w, x, y, z, index, data, s) \ AS2( xor esi, z ) \ AS2( and esi, x ) \ @@ -223,7 +223,7 @@ void MD5::Update(const byte* data, word32 len) #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -242,8 +242,8 @@ void MD5::AsmTransform(const byte* data, word32 times) #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "D" (data), "a" (times) \ : "%esi", "%edx", "memory", "cc" \ @@ -272,7 +272,7 @@ void MD5::AsmTransform(const byte* data, word32 times) AS1( pop ebp ) \ AS1( emms ) \ AS1( ret 8 ) - + #endif @@ -288,16 +288,16 @@ void MD5::AsmTransform(const byte* data, word32 times) AS2( movd mm2, eax ) // store times_ AS2( movd mm1, esi ) // store digest_ - + AS2( mov eax, [esi] ) // a AS2( mov ebx, [esi + 4] ) // b AS2( mov ecx, [esi + 8] ) // c AS2( mov edx, [esi + 12] ) // d - + #ifdef _MSC_VER AS1( loopStart: ) // loopStart #else - AS1( 0: ) // loopStart for some gas (need numeric for jump back + AS1( 0: ) // loopStart for some gas (need numeric for jump back #endif // set up @@ -375,7 +375,7 @@ void MD5::AsmTransform(const byte* data, word32 times) MD5STEP4( edx, eax, ebx, ecx, 2, 0xbd3af235, 10) MD5STEP4( ecx, edx, eax, ebx, 9, 0x2ad7d2bb, 15) MD5STEP4( ebx, ecx, edx, eax, 9, 0xeb86d391, 21) - + AS2( movd esi, mm1 ) // digest_ AS2( add [esi], eax ) // write out @@ -417,7 +417,7 @@ void MD5::Transform() #define MD5STEP(f, w, x, y, z, data, s) \ w = rotlFixed(w + f(x, y, z) + data, s) + x - // Copy context->state[] to working vars + // Copy context->state[] to working vars word32 a = digest_[0]; word32 b = digest_[1]; word32 c = digest_[2]; @@ -490,7 +490,7 @@ void MD5::Transform() MD5STEP(F4, d, a, b, c, buffer_[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, buffer_[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, buffer_[9] + 0xeb86d391, 21); - + // Add the working vars back into digest state[] digest_[0] += a; digest_[1] += b; diff --git a/cdk/extra/yassl/taocrypt/src/misc.cpp b/cdk/extra/yassl/taocrypt/src/misc.cpp index b576d3d59..26c494d74 100644 --- a/cdk/extra/yassl/taocrypt/src/misc.cpp +++ b/cdk/extra/yassl/taocrypt/src/misc.cpp @@ -185,7 +185,7 @@ bool HaveCpuId() { mov eax, 0 cpuid - } + } } __except (1) { diff --git a/cdk/extra/yassl/taocrypt/src/rabbit.cpp b/cdk/extra/yassl/taocrypt/src/rabbit.cpp index 5e32f3834..614e0b425 100644 --- a/cdk/extra/yassl/taocrypt/src/rabbit.cpp +++ b/cdk/extra/yassl/taocrypt/src/rabbit.cpp @@ -89,7 +89,7 @@ void Rabbit::NextState(RabbitCtx which) ctx->c[6] = U32V(ctx->c[6] + 0x4D34D34D + (ctx->c[5] < c_old[5])); ctx->c[7] = U32V(ctx->c[7] + 0xD34D34D3 + (ctx->c[6] < c_old[6])); ctx->carry = (ctx->c[7] < c_old[7]); - + /* Calculate the g-values */ for (i=0;i<8;i++) g[i] = RABBIT_g_func(U32V(ctx->x[i] + ctx->c[i])); @@ -111,7 +111,7 @@ void Rabbit::SetIV(const byte* iv) { /* Temporary variables */ word32 i0, i1, i2, i3, i; - + /* Generate four subvectors */ i0 = LITTLE32(*(word32*)(iv+0)); i2 = LITTLE32(*(word32*)(iv+4)); @@ -189,7 +189,7 @@ void Rabbit::SetKey(const byte* key, const byte* iv) } workCtx_.carry = masterCtx_.carry; - if (iv) SetIV(iv); + if (iv) SetIV(iv); } @@ -238,11 +238,11 @@ void Rabbit::Process(byte* output, const byte* input, word32 msglen) /* Generate 16 bytes of pseudo-random data */ tmp[0] = LITTLE32(workCtx_.x[0] ^ (workCtx_.x[5]>>16) ^ U32V(workCtx_.x[3]<<16)); - tmp[1] = LITTLE32(workCtx_.x[2] ^ + tmp[1] = LITTLE32(workCtx_.x[2] ^ (workCtx_.x[7]>>16) ^ U32V(workCtx_.x[5]<<16)); - tmp[2] = LITTLE32(workCtx_.x[4] ^ + tmp[2] = LITTLE32(workCtx_.x[4] ^ (workCtx_.x[1]>>16) ^ U32V(workCtx_.x[7]<<16)); - tmp[3] = LITTLE32(workCtx_.x[6] ^ + tmp[3] = LITTLE32(workCtx_.x[6] ^ (workCtx_.x[3]>>16) ^ U32V(workCtx_.x[1]<<16)); /* Encrypt/decrypt the data */ diff --git a/cdk/extra/yassl/taocrypt/src/random.cpp b/cdk/extra/yassl/taocrypt/src/random.cpp index 26dae7d19..45df3bdba 100644 --- a/cdk/extra/yassl/taocrypt/src/random.cpp +++ b/cdk/extra/yassl/taocrypt/src/random.cpp @@ -107,7 +107,7 @@ OS_Seed::OS_Seed() } -OS_Seed::~OS_Seed() +OS_Seed::~OS_Seed() { close(fd_); } diff --git a/cdk/extra/yassl/taocrypt/src/ripemd.cpp b/cdk/extra/yassl/taocrypt/src/ripemd.cpp index 5d03dc61c..1c5c6f5d7 100644 --- a/cdk/extra/yassl/taocrypt/src/ripemd.cpp +++ b/cdk/extra/yassl/taocrypt/src/ripemd.cpp @@ -49,8 +49,8 @@ void RIPEMD160::Init() RIPEMD160::RIPEMD160(const RIPEMD160& that) - : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) -{ + : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -93,7 +93,7 @@ void RIPEMD160::Update(const byte* data, word32 len) byte* local = reinterpret_cast(buffer_); // remove buffered data if possible - if (buffLen_) { + if (buffLen_) { word32 add = min(len, BLOCK_SIZE - buffLen_); memcpy(&local[buffLen_], data, add); @@ -131,7 +131,7 @@ void RIPEMD160::Update(const byte* data, word32 len) // for all -#define F(x, y, z) (x ^ y ^ z) +#define F(x, y, z) (x ^ y ^ z) #define G(x, y, z) (z ^ (x & (y^z))) #define H(x, y, z) (z ^ (x | ~y)) #define I(x, y, z) (y ^ (z & (x^y))) @@ -266,7 +266,7 @@ void RIPEMD160::Transform() Subround(J, b2, c2, d2, e2, a2, buffer_[ 3], 12, k5); Subround(J, a2, b2, c2, d2, e2, buffer_[12], 6, k5); - Subround(I, e2, a2, b2, c2, d2, buffer_[ 6], 9, k6); + Subround(I, e2, a2, b2, c2, d2, buffer_[ 6], 9, k6); Subround(I, d2, e2, a2, b2, c2, buffer_[11], 13, k6); Subround(I, c2, d2, e2, a2, b2, buffer_[ 3], 15, k6); Subround(I, b2, c2, d2, e2, a2, buffer_[ 7], 7, k6); @@ -362,7 +362,7 @@ void RIPEMD160::Transform() AS2( and esi, x ) \ AS2( xor esi, z ) - + // H(z ^ (x | ~y)) // place in esi #define ASMH(x, y, z) \ @@ -391,7 +391,7 @@ void RIPEMD160::Transform() // for 160 and 320 -// #define ASMSubround(f, a, b, c, d, e, i, s, k) +// #define ASMSubround(f, a, b, c, d, e, i, s, k) // a += f(b, c, d) + data[i] + k; // a = rotlFixed((word32)a, s) + e; // c = rotlFixed((word32)c, 10U) @@ -506,7 +506,7 @@ void RIPEMD160::Transform() #ifdef _MSC_VER - __declspec(naked) + __declspec(naked) #else __attribute__ ((noinline)) #endif @@ -525,8 +525,8 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "D" (data), "d" (times) \ : "%esi", "%eax", "memory", "cc" \ @@ -555,7 +555,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS1( pop ebp ) \ AS1( emms ) \ AS1( ret 8 ) - + #endif PROLOG() @@ -568,11 +568,11 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS2( sub esp, 24 ) // make room for tmp a1 - e1 AS2( movd mm1, esi ) // store digest_ - + #ifdef _MSC_VER AS1( loopStart: ) // loopStart #else - AS1( 0: ) // loopStart for some gas (need numeric for jump back + AS1( 0: ) // loopStart for some gas (need numeric for jump back #endif AS2( movd mm2, edx ) // store times_ @@ -583,7 +583,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS2( mov edx, [esi + 12] ) // d1 AS2( mov ebp, [esi + 16] ) // e1 - // setup + // setup AS2( mov esi, ecx ) ASMSubroundF( eax, ebx, ecx, edx, ebp, 0, 11) @@ -713,7 +713,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) // setup AS2( mov esi, ebx ) - ASMSubroundI( ebp, eax, ebx, ecx, edx, 6, 9, k6) + ASMSubroundI( ebp, eax, ebx, ecx, edx, 6, 9, k6) ASMSubroundI( edx, ebp, eax, ebx, ecx, 11, 13, k6) ASMSubroundI( ecx, edx, ebp, eax, ebx, 3, 15, k6) ASMSubroundI( ebx, ecx, edx, ebp, eax, 7, 7, k6) @@ -831,7 +831,7 @@ void RIPEMD160::AsmTransform(const byte* data, word32 times) AS1( jnz 0b ) // loopStart #endif - // inline adjust + // inline adjust AS2( add esp, 24 ) // fix room on stack EPILOG() diff --git a/cdk/extra/yassl/taocrypt/src/rsa.cpp b/cdk/extra/yassl/taocrypt/src/rsa.cpp index 73f678e26..be8ca6fec 100644 --- a/cdk/extra/yassl/taocrypt/src/rsa.cpp +++ b/cdk/extra/yassl/taocrypt/src/rsa.cpp @@ -61,7 +61,7 @@ Integer RSA_PrivateKey::CalculateInverse(RandomNumberGenerator& rng, Integer y = ModularRoot(re, dq_, dp_, q_, p_, u_); y = modn.Divide(y, r); // unblind - + return y; } @@ -97,7 +97,7 @@ void RSA_BlockType2::Pad(const byte *input, word32 inputLen, byte *pkcsBlock, rng.GenerateBlock(&pkcsBlock[1], padLen); for (word32 i = 1; i < padLen; i++) if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01; - + pkcsBlock[pkcsBlockLen-inputLen-1] = 0; // separator memcpy(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen); } @@ -200,12 +200,12 @@ word32 RSA_BlockType1::UnPad(const byte* pkcsBlock, word32 pkcsBlockLen, word32 SSL_Decrypt(const RSA_PublicKey& key, const byte* sig, byte* plain) { PK_Lengths lengths(key.GetModulus()); - + ByteBlock paddedBlock(BitsToBytes(lengths.PaddedBlockBitLength())); Integer x = key.ApplyFunction(Integer(sig, lengths.FixedCiphertextLength())); if (x.ByteCount() > paddedBlock.size()) - x = Integer::Zero(); + x = Integer::Zero(); x.Encode(paddedBlock.get_buffer(), paddedBlock.size()); return RSA_BlockType1().UnPad(paddedBlock.get_buffer(), lengths.PaddedBlockBitLength(), plain); diff --git a/cdk/extra/yassl/taocrypt/src/sha.cpp b/cdk/extra/yassl/taocrypt/src/sha.cpp index 4206f7f64..0b2f39ee6 100644 --- a/cdk/extra/yassl/taocrypt/src/sha.cpp +++ b/cdk/extra/yassl/taocrypt/src/sha.cpp @@ -142,8 +142,8 @@ void SHA384::Init() SHA::SHA(const SHA& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), - BLOCK_SIZE) -{ + BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -154,8 +154,8 @@ SHA::SHA(const SHA& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), SHA256::SHA256(const SHA256& that) : HASHwithTransform(DIGEST_SIZE / - sizeof(word32), BLOCK_SIZE) -{ + sizeof(word32), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -166,8 +166,8 @@ SHA256::SHA256(const SHA256& that) : HASHwithTransform(DIGEST_SIZE / SHA224::SHA224(const SHA224& that) : HASHwithTransform(SHA256::DIGEST_SIZE / - sizeof(word32), BLOCK_SIZE) -{ + sizeof(word32), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -177,11 +177,11 @@ SHA224::SHA224(const SHA224& that) : HASHwithTransform(SHA256::DIGEST_SIZE / } -#ifdef WORD64_AVAILABLE +#ifdef WORD64_AVAILABLE SHA512::SHA512(const SHA512& that) : HASH64withTransform(DIGEST_SIZE / - sizeof(word64), BLOCK_SIZE) -{ + sizeof(word64), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -192,8 +192,8 @@ SHA512::SHA512(const SHA512& that) : HASH64withTransform(DIGEST_SIZE / SHA384::SHA384(const SHA384& that) : HASH64withTransform(SHA512::DIGEST_SIZE / - sizeof(word64), BLOCK_SIZE) -{ + sizeof(word64), BLOCK_SIZE) +{ buffLen_ = that.buffLen_; loLen_ = that.loLen_; hiLen_ = that.hiLen_; @@ -326,7 +326,7 @@ void SHA::Update(const byte* data, word32 len) byte* local = reinterpret_cast(buffer_); // remove buffered data if possible - if (buffLen_) { + if (buffLen_) { word32 add = min(len, BLOCK_SIZE - buffLen_); memcpy(&local[buffLen_], data, add); @@ -368,14 +368,14 @@ void SHA::Transform() { word32 W[BLOCK_SIZE / sizeof(word32)]; - // Copy context->state[] to working vars + // Copy context->state[] to working vars word32 a = digest_[0]; word32 b = digest_[1]; word32 c = digest_[2]; word32 d = digest_[3]; word32 e = digest_[4]; - // 4 rounds of 20 operations each. Loop unrolled. + // 4 rounds of 20 operations each. Loop unrolled. R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); @@ -429,7 +429,7 @@ void SHA::Transform() #define h(i) T[(7-i)&7] #define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+(j?blk2(i):blk0(i));\ - d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) + d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) // for SHA256 #define S0(x) (rotrFixed(x,2)^rotrFixed(x,13)^rotrFixed(x,22)) @@ -439,22 +439,22 @@ void SHA::Transform() static const word32 K256[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; @@ -514,46 +514,46 @@ void SHA224::Transform() #ifdef WORD64_AVAILABLE static const word64 K512[80] = { - W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), - W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), - W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), - W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), - W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), - W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), - W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), - W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), - W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), - W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), - W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), - W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), - W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), - W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), - W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), - W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), - W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), - W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), - W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), - W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), - W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), - W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), - W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), - W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), - W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), - W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), - W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), - W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), - W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), - W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), - W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), - W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), - W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), - W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), - W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), - W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), - W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), - W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), - W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), - W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) + W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), + W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), + W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), + W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), + W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), + W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), + W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), + W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), + W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), + W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), + W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), + W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), + W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), + W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), + W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), + W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), + W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), + W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), + W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), + W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), + W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), + W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), + W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), + W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), + W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), + W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), + W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), + W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), + W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), + W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), + W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), + W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), + W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), + W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), + W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), + W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), + W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), + W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), + W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), + W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) }; @@ -582,7 +582,7 @@ static void Transform512(word64* digest_, word64* buffer_) R(12); R(13); R(14); R(15); } - // Add the working vars back into digest + // Add the working vars back into digest digest_[0] += a(0); digest_[1] += b(0); @@ -779,8 +779,8 @@ void SHA::AsmTransform(const byte* data, word32 times) #define EPILOG() \ "pop ebp;" \ "pop ebx;" \ - "emms;" \ - ".att_syntax;" \ + "emms;" \ + ".att_syntax;" \ : \ : "c" (this), "D" (data), "a" (times) \ : "%esi", "%edx", "memory", "cc" \ @@ -808,7 +808,7 @@ void SHA::AsmTransform(const byte* data, word32 times) AS2( mov esp, ebp ) \ AS1( pop ebp ) \ AS1( emms ) \ - AS1( ret 8 ) + AS1( ret 8 ) #endif PROLOG() @@ -829,7 +829,7 @@ void SHA::AsmTransform(const byte* data, word32 times) #ifdef _MSC_VER AS1( loopStart: ) // loopStart #else - AS1( 0: ) // loopStart for some gas (need numeric for jump back + AS1( 0: ) // loopStart for some gas (need numeric for jump back #endif // byte reverse 16 words of input, 4 at a time, put on stack for W[] @@ -1007,12 +1007,12 @@ void SHA::AsmTransform(const byte* data, word32 times) // setup next round AS2( movd ebp, mm2 ) // times - + AS2( mov edi, DWORD PTR [esp + 64] ) // data - + AS2( add edi, 64 ) // next round of data AS2( mov [esp + 64], edi ) // restore - + AS1( dec ebp ) AS2( movd mm2, ebp ) #ifdef _MSC_VER @@ -1021,7 +1021,7 @@ void SHA::AsmTransform(const byte* data, word32 times) AS1( jnz 0b ) // loopStart #endif - // inline adjust + // inline adjust AS2( add esp, 68 ) // fix room on stack EPILOG() diff --git a/cdk/extra/yassl/taocrypt/test/test.cpp b/cdk/extra/yassl/taocrypt/test/test.cpp index a7d5cb3e8..fc1f0e876 100644 --- a/cdk/extra/yassl/taocrypt/test/test.cpp +++ b/cdk/extra/yassl/taocrypt/test/test.cpp @@ -1277,6 +1277,9 @@ int dsa_test() if (!verifier.Verify(digest, decoded)) return -90; + if (!verifier.Verify(digest, signature)) + return -91; + return 0; } diff --git a/cdk/extra/yassl/testsuite/test.hpp b/cdk/extra/yassl/testsuite/test.hpp index 3e15ce814..92d41706c 100644 --- a/cdk/extra/yassl/testsuite/test.hpp +++ b/cdk/extra/yassl/testsuite/test.hpp @@ -22,7 +22,6 @@ #define yaSSL_TEST_HPP #include "runtime.hpp" -#include "openssl/ssl.h" /* openssl compatibility test */ #include "error.hpp" #include #include @@ -56,6 +55,7 @@ #endif #define SOCKET_T int #endif /* _WIN32 */ +#include "openssl/ssl.h" /* openssl compatibility test */ #ifdef _MSC_VER @@ -469,9 +469,24 @@ inline void showPeer(SSL* ssl) if (peer) { char* issuer = X509_NAME_oneline(X509_get_issuer_name(peer), 0, 0); char* subject = X509_NAME_oneline(X509_get_subject_name(peer), 0, 0); + X509_NAME_ENTRY* se = NULL; + ASN1_STRING* sd = NULL; + char* subCN = NULL; + X509_NAME* sub = X509_get_subject_name(peer); + int lastpos = -1; + if (sub) + lastpos = X509_NAME_get_index_by_NID(sub, NID_commonName, lastpos); + if (lastpos >= 0) { + se = X509_NAME_get_entry(sub, lastpos); + if (se) + sd = X509_NAME_ENTRY_get_data(se); + if (sd) + subCN = (char*)ASN1_STRING_data(sd); + } + + printf("peer's cert info:\n issuer : %s\n subject: %s\n" + " subject cn: %s\n", issuer, subject, subCN); - printf("peer's cert info:\n issuer : %s\n subject: %s\n", issuer, - subject); free(subject); free(issuer); } diff --git a/cdk/foundation/CMakeLists.txt b/cdk/foundation/CMakeLists.txt index 9af01e325..e53d3ae91 100644 --- a/cdk/foundation/CMakeLists.txt +++ b/cdk/foundation/CMakeLists.txt @@ -64,7 +64,7 @@ SET(target_foundation ${cdk_target_prefix}foundation CACHE INTERNAL "CDK foundation target") ADD_LIBRARY(${target_foundation} OBJECT ${sources}) -#ADD_BOOST(${target_foundation}) +ADD_COVERAGE(${target_foundation}) IF(WITH_SSL STREQUAL "bundled") lib_interface_link_libraries(${target_foundation} yassl) diff --git a/cdk/foundation/connection_yassl.cc b/cdk/foundation/connection_yassl.cc index e845b2bd4..ad9353aad 100644 --- a/cdk/foundation/connection_yassl.cc +++ b/cdk/foundation/connection_yassl.cc @@ -26,7 +26,6 @@ PUSH_SYS_WARNINGS #include "../extra/yassl/include/openssl/ssl.h" POP_SYS_WARNINGS -#include #include #include #include @@ -34,14 +33,28 @@ POP_SYS_WARNINGS #include "connection_tcpip_base.h" +static const char* tls_ciphers_list="DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" + "AES128-RMD:DES-CBC3-RMD:DHE-RSA-AES256-RMD:" + "DHE-RSA-AES128-RMD:DHE-RSA-DES-CBC3-RMD:" + "AES256-SHA:RC4-SHA:RC4-MD5:DES-CBC3-SHA:" + "DES-CBC-SHA:EDH-RSA-DES-CBC3-SHA:" + "EDH-RSA-DES-CBC-SHA:AES128-SHA:AES256-RMD:"; +static const char* tls_cipher_blocked= "!aNULL:!eNULL:!EXPORT:!LOW:!MD5:!DES:!RC2:!RC4:!PSK:!SSLv3:"; + + +static void throw_yassl_error_msg(const char* msg) +{ + throw cdk::foundation::Error(cdk::foundation::cdkerrc::tls_error, + std::string("yaSSL: ") + msg); +} + static void throw_yassl_error() { char buffer[512]; yaSSL::ERR_error_string_n(yaSSL::ERR_get_error(), buffer, sizeof(buffer)); - throw cdk::foundation::Error(cdk::foundation::cdkerrc::tls_error, - std::string("yaSSL: ") + buffer); + throw_yassl_error_msg(buffer); } @@ -54,10 +67,12 @@ class connection_TLS_impl : public ::cdk::foundation::connection::TCPIP_base::Impl { public: - connection_TLS_impl(cdk::foundation::connection::TCPIP_base* tcpip) + connection_TLS_impl(cdk::foundation::connection::TCPIP_base* tcpip, + cdk::foundation::connection::TLS::Options options) : m_tcpip(tcpip) , m_tls(NULL) , m_tls_ctx(NULL) + , m_options(options) {} ~connection_TLS_impl() @@ -79,6 +94,7 @@ class connection_TLS_impl cdk::foundation::connection::TCPIP_base* m_tcpip; yaSSL::SSL* m_tls; yaSSL::SSL_CTX* m_tls_ctx; + cdk::foundation::connection::TLS::Options m_options; }; @@ -95,7 +111,8 @@ void connection_TLS_impl::do_connect() try { - yaSSL::SSL_METHOD* method = yaSSL::TLSv1_client_method(); + yaSSL::SSL_METHOD* method = yaSSL::TLSv1_1_client_method(); + if (!method) throw_yassl_error(); @@ -103,8 +120,41 @@ void connection_TLS_impl::do_connect() if (!m_tls_ctx) throw_yassl_error(); - // TODO: Server certificate verification. - SSL_CTX_set_verify(m_tls_ctx, yaSSL::SSL_VERIFY_NONE, 0); + + std::string cipher_list; + cipher_list.append(tls_cipher_blocked); + cipher_list.append(tls_ciphers_list); + + SSL_CTX_set_cipher_list(m_tls_ctx, cipher_list.c_str()); + + if (!m_options.get_ca().empty() || + !m_options.get_ca_path().empty()) + { + SSL_CTX_set_verify(m_tls_ctx, yaSSL::SSL_VERIFY_PEER , NULL); + + int errNr = SSL_CTX_load_verify_locations( + m_tls_ctx, + m_options.get_ca().c_str(), + m_options.get_ca_path().empty() + ? NULL : m_options.get_ca_path().c_str()); + + switch(errNr) + { + case yaSSL::SSL_BAD_FILE: + throw_yassl_error_msg("error opening ca file"); + case yaSSL::SSL_BAD_PATH: + throw_yassl_error_msg("bad ca_path"); + case yaSSL::SSL_BAD_STAT: + throw_yassl_error_msg("bad file permissions inside ca_path"); + default: + break; + } + + } + else + { + SSL_CTX_set_verify(m_tls_ctx, yaSSL::SSL_VERIFY_NONE, 0); + } m_tls = yaSSL::SSL_new(m_tls_ctx); if (!m_tls) @@ -116,8 +166,9 @@ void connection_TLS_impl::do_connect() yaSSL::SSL_set_fd(m_tls, static_cast(fd)); - if (yaSSL::SSL_connect(m_tls) != yaSSL::SSL_SUCCESS) + if(yaSSL::SSL_connect(m_tls) != yaSSL::SSL_SUCCESS) throw_yassl_error(); + } catch (...) { @@ -148,8 +199,9 @@ namespace foundation { namespace connection { -TLS::TLS(TCPIP_base* tcpip) - : opaque_impl(NULL, tcpip) +TLS::TLS(TCPIP_base* tcpip, + const TLS::Options &options) + : opaque_impl(NULL, tcpip, options) {} diff --git a/cdk/foundation/string.cc b/cdk/foundation/string.cc index 696f5dc18..59c005f7d 100644 --- a/cdk/foundation/string.cc +++ b/cdk/foundation/string.cc @@ -30,46 +30,6 @@ namespace cdk { namespace foundation { -size_t Codec::to_bytes(const string &in, bytes out) -{ - codecvt_utf8::state_type state; - const char_t *in_next; - char *out_next; - - std::codecvt_base::result res= - m_codec.out(state, &in[0], &in[in.length()], in_next, - (char*)out.begin(), (char*)out.end(), out_next); - - if (std::codecvt_base::ok != res) - THROW("conversion error"); // TODO: report errors - - assert((byte*)out_next >= out.begin()); - return static_cast((byte*)out_next - out.begin()); -} - - -size_t Codec::from_bytes(bytes in, string &out) -{ - codecvt_utf8::state_type state; - const char *in_next; - char_t *out_next; - - out.resize(in.size()+1); - std::codecvt_base::result res= - m_codec.in(state, (char*)in.begin(), (char*)in.end(), in_next, - &out[0], &out[in.size()], out_next); - - if (std::codecvt_base::ok != res) - THROW("conversion error"); // TODO: report errors - - assert(out_next >= &out[0]); - out.resize(static_cast(out_next - &out[0])); - - assert((byte*)in_next >= in.begin()); - return static_cast((byte*)in_next - in.begin()); -} - - string& string::set_utf8(const std::string &str) { Codec codec; @@ -182,3 +142,72 @@ codecvt_utf8::do_in(state_type& state, #endif +namespace cdk { +namespace foundation { + +codecvt_ascii::result +codecvt_ascii::do_out(state_type& state, + const intern_type* from, + const intern_type* from_end, + const intern_type*& from_next, + extern_type* to, + extern_type* to_end, + extern_type*& to_next ) const +{ + from_next = from; + to_next = to; + + while (from_next < from_end) + { + int c = m_ctype.narrow(*from_next, -1); + + if (-1 == c) + return error; + + *to_next = (extern_type)c; + to_next++; + from_next++; + } + + return ok; +} + + +codecvt_ascii::result +codecvt_ascii::do_in(state_type& state, + const extern_type* from, + const extern_type* from_end, + const extern_type*& from_next, + intern_type* to, + intern_type* to_end, + intern_type*& to_next ) const +{ + from_next = from; + to_next = to; + + while (from_next < from_end) + { + unsigned char c = (unsigned char)*from_next; + + /* + Note: In absence of character encoding information, only ASCII + characters can be reliably converted to wide chars by + ctype::widen() method. + */ + if (c > 128) + return error; + + intern_type wc = m_ctype.widen(*from_next); + + if (-1 == wc) + return error; + + *to_next = wc; + to_next++; + from_next++; + } + + return ok; +} + +}} // cdk::foundation diff --git a/cdk/include/mysql/cdk/api/document.h b/cdk/include/mysql/cdk/api/document.h index d3846ab2f..d6bf5ffbe 100644 --- a/cdk/include/mysql/cdk/api/document.h +++ b/cdk/include/mysql/cdk/api/document.h @@ -25,12 +25,12 @@ #ifndef CDK_API_DOCUMENT_H #define CDK_API_DOCUMENT_H -#include "../foundation.h" #include "expression.h" namespace cdk { namespace api { + /** Documents over processor PRC ============================ @@ -165,11 +165,176 @@ class Doc_base : public Expr_base< Doc_processor > }; +/* + Document path specification is a list of items, each to be processed + with Doc_path_processor to describe one element of the path. +*/ + +class Doc_path_processor +{ +public: + + typedef cdk::api::string string; + typedef uint32_t index_t; + + // Path element is name of document field. + + virtual void member(const string &name) =0; + + // Path element "*". + + virtual void any_member() =0; + + // Path element is at given position within an array. + + virtual void index(index_t) =0; + + // Path element "[*]". + + virtual void any_index() =0; + + // Path element "**". + + virtual void any_path() =0; +}; + +typedef Expr_list< Expr_base > Doc_path; + + }} // cdk::api namespace cdk { +class Doc_path_storage + : public api::Doc_path + , public api::Doc_path::Processor + , api::Doc_path_processor +{ +public: + + enum Type { + MEMBER, + MEMBER_ASTERISK, + ARRAY_INDEX, + ARRAY_INDEX_ASTERISK, + DOUBLE_ASTERISK + }; + +protected: + + struct Path_el + { + Type m_type; + string m_name; + uint32_t m_idx; + }; + + std::vector m_path; + +public: + + // Access to path data + + size_t length() const + { + return m_path.size(); + } + + bool is_empty() const + { + return 0 == length(); + } + + const Path_el& get_el(size_t pos) const + { + return m_path.at(pos); + } + + void clear() + { + m_path.clear(); + } + + // Doc_path + + void process(Processor &prc) const + { + prc.list_begin(); + + for (size_t pos = 0; pos < m_path.size(); ++pos) + { + api::Doc_path_processor *eprc = prc.list_el(); + if (eprc) + { + const Path_el &el = m_path[pos]; + switch (el.m_type) + { + case MEMBER: eprc->member(el.m_name); break; + case MEMBER_ASTERISK: eprc->any_member(); break; + case ARRAY_INDEX: eprc->index(el.m_idx); break; + case ARRAY_INDEX_ASTERISK: eprc->any_index(); break; + case DOUBLE_ASTERISK: eprc->any_path(); break; + } + } + } + + prc.list_end(); + } + + + // List_processor + + Path_el *m_el; + + Element_prc* list_el() + { + m_path.push_back(Path_el()); + m_el = &m_path.back(); + return this; + } + +private: + + // Doc_path_processor + + void member(const string &name) + { + assert(m_el); + m_el->m_type = MEMBER; + m_el->m_name = name; + } + + void any_member() + { + assert(m_el); + m_el->m_type = MEMBER_ASTERISK; + } + + void index(index_t pos) + { + assert(m_el); + m_el->m_type = ARRAY_INDEX; + m_el->m_idx = pos; + } + + void any_index() + { + assert(m_el); + m_el->m_type = ARRAY_INDEX_ASTERISK; + } + + void any_path() + { + assert(m_el); + m_el->m_type = DOUBLE_ASTERISK; + } +}; + +} // cdk + + +namespace cdk { template struct Safe_prc< cdk::api::Any_processor > @@ -231,6 +396,40 @@ struct Safe_prc< cdk::api::Doc_processor > }; + +template<> +struct Safe_prc + : Safe_prc_base +{ + typedef Safe_prc_base Base; + using Base::Processor; + typedef Processor::string string; + typedef Processor::index_t index_t; + + Safe_prc(Processor *prc) : Base(prc) + {} + + Safe_prc(Processor &prc) : Base(&prc) + {} + + using Base::m_prc; + + void member(const string &name) + { return m_prc ? m_prc->member(name) : (void)NULL; } + + void any_member() + { return m_prc ? m_prc->any_member() : (void)NULL; } + + void index(index_t ind) + { return m_prc ? m_prc->index(ind) : (void)NULL; } + + void any_index() + { return m_prc ? m_prc->any_index() : (void)NULL; } + + void any_path() + { return m_prc ? m_prc->any_path() : (void)NULL; } +}; + } #endif diff --git a/cdk/include/mysql/cdk/api/expression.h b/cdk/include/mysql/cdk/api/expression.h index 44bdc86f8..258acbc16 100644 --- a/cdk/include/mysql/cdk/api/expression.h +++ b/cdk/include/mysql/cdk/api/expression.h @@ -25,12 +25,16 @@ #ifndef CDK_API_EXPRESSION_H #define CDK_API_EXPRESSION_H +#include "../foundation.h" #include // for NULL #include namespace cdk { namespace api { +using foundation::string; + + /* Expressions =========== diff --git a/cdk/include/mysql/cdk/api/processors.h b/cdk/include/mysql/cdk/api/processors.h index b26315879..b4ca4e430 100644 --- a/cdk/include/mysql/cdk/api/processors.h +++ b/cdk/include/mysql/cdk/api/processors.h @@ -60,7 +60,7 @@ class Row_processor /* - Called before and after processing one filed within a row. The pos + Called before and after processing one field within a row. The pos parameter indicates 0-based position of the field within the row. Method field_begin() returns the amount of space available for storing field data - following field_data() calls should respect this limit. diff --git a/cdk/include/mysql/cdk/api/query.h b/cdk/include/mysql/cdk/api/query.h index 9f9e85270..438d259fa 100644 --- a/cdk/include/mysql/cdk/api/query.h +++ b/cdk/include/mysql/cdk/api/query.h @@ -27,7 +27,9 @@ #ifndef CDK_API_QUERY_H #define CDK_API_QUERY_H +#include "obj_ref.h" #include "expression.h" +#include "document.h" #include "../foundation/types.h" namespace cdk { @@ -35,6 +37,15 @@ namespace api { using foundation::string; +class String_processor +{ +public: + virtual void val(const string&) = 0; +}; + +typedef Expr_list< Expr_base > String_list; + + /* Classes for representing different parts of a query such as LIMIT, ORDER BY etc. @@ -95,7 +106,7 @@ class Order_by /* Projection specification is a list of items. Each item is an expression over - Projection_processor which reports an expression and optional alias. + Projection_processor which reports a projection expression and optional alias. */ template @@ -119,41 +130,86 @@ class Projection {}; - /* - Document path specification is a list of items, each to be processed - with Doc_path_processor to describe one element of the path. + View specifications. + + A view specification can be passed to a session method, such as table_find(), + which sends CRUD query. When view specification is given for a query, then + this query is saved as a new view, or it replaces the query of an existing + view. */ -class Doc_path_processor +template +class View_processor { public: - typedef cdk::api::string string; - typedef uint32_t index_t; + typedef OPTS Options; + typedef String_list::Processor List_processor; + enum op_type { CREATE, UPDATE, REPLACE }; - // Path element is name of document field. + virtual void name(const Table_ref&, op_type type = CREATE) = 0; + virtual typename Options::Processor* options() = 0; + virtual List_processor* columns() + { return NULL; } +}; + + +template +class View_spec : public Expr_base< View_processor > +{ +public: + + typedef OPTS Options; + typedef typename View_processor::op_type op_type; +}; - virtual void member(const string &name) =0; - // Path element "*". +/* + Standard view options: these are aligned with view options defined by + DevAPI. +*/ - virtual void any_member() =0; +struct View_security +{ + enum value { + DEFINER, INVOKER + }; +}; - // Path element is at given position within an array. +struct View_algorithm +{ + enum value { + UNDEFINED, + MERGE, + TEMPTABLE + }; +}; - virtual void index(index_t) =0; +struct View_check +{ + enum value { + LOCAL, + CASCADED + }; +}; - // Path element "[*]". - virtual void any_index() =0; +class View_opt_prc +{ +public: - // Path element "**". + typedef View_security::value View_security_t; + typedef View_algorithm::value View_algorithm_t; + typedef View_check::value View_check_t; - virtual void any_path() =0; + virtual void definer(const string&) = 0; + virtual void security(View_security_t) = 0; + virtual void algorithm(View_algorithm_t) = 0; + virtual void check(View_check_t) = 0; }; -typedef Expr_list< Expr_base > Doc_path; +typedef Expr_base View_options; /* @@ -191,14 +247,14 @@ typedef Expr_list< Expr_base > Columns; namespace cdk { +using api::String_list; + template<> -struct Safe_prc - : Safe_prc_base +struct Safe_prc + : Safe_prc_base { - typedef Safe_prc_base Base; + typedef Safe_prc_base Base; using Base::Processor; - typedef Processor::string string; - typedef Processor::index_t index_t; Safe_prc(Processor *prc) : Base(prc) {} @@ -208,24 +264,13 @@ struct Safe_prc using Base::m_prc; - void member(const string &name) - { return m_prc ? m_prc->member(name) : (void)NULL; } - - void any_member() - { return m_prc ? m_prc->any_member() : (void)NULL; } - - void index(index_t ind) - { return m_prc ? m_prc->index(ind) : (void)NULL; } - - void any_index() - { return m_prc ? m_prc->any_index() : (void)NULL; } - - void any_path() - { return m_prc ? m_prc->any_path() : (void)NULL; } + void val(const string &val) + { + return m_prc ? m_prc->val(val) : (void)NULL; + } }; - template<> struct Safe_prc : Safe_prc_base diff --git a/cdk/include/mysql/cdk/charsets.h b/cdk/include/mysql/cdk/charsets.h new file mode 100644 index 000000000..c1cdb861e --- /dev/null +++ b/cdk/include/mysql/cdk/charsets.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * + * This code is licensed under the terms of the GPLv2 + * , like most + * MySQL Connectors. There are special exceptions to the terms and + * conditions of the GPLv2 as it is applied to this software, see the + * FLOSS License Exception + * . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + Lists of character sets known to CDK string codec (see codec.h). + This is generally kept in sync with character sets known to the MySQL Server. + See: http://dev.mysql.com/doc/refman/en/charset-charsets.html + + Note: currently the codec can only convert utf8 strings. +*/ + + +#ifndef MYSQL_CDK_CHARSETS_H +#define MYSQL_CDK_CHARSETS_H + +#define CDK_CS_LIST(X) \ + X(big5) \ + X(dec8) \ + X(cp850) \ + X(hp8) \ + X(koi8r) \ + X(latin1) \ + X(latin2) \ + X(swe7) \ + X(ascii) \ + X(ujis) \ + X(sjis) \ + X(hebrew) \ + X(tis620) \ + X(euckr) \ + X(koi8u) \ + X(gb2312) \ + X(greek) \ + X(cp1250) \ + X(gbk) \ + X(latin5) \ + X(armscii8) \ + X(utf8) \ + X(ucs2) \ + X(cp866) \ + X(keybcs2) \ + X(macce) \ + X(macroman) \ + X(cp852) \ + X(latin7) \ + X(utf8mb4) \ + X(cp1251) \ + X(utf16) \ + X(utf16le) \ + X(cp1256) \ + X(cp1257) \ + X(utf32) \ + X(binary) \ + X(geostd8) \ + X(cp932) \ + X(eucjpms) \ + X(gb18030) \ + +#endif diff --git a/cdk/include/mysql/cdk/codec.h b/cdk/include/mysql/cdk/codec.h index 47997ed79..b70c60155 100644 --- a/cdk/include/mysql/cdk/codec.h +++ b/cdk/include/mysql/cdk/codec.h @@ -26,7 +26,7 @@ #define CDK_CODEC_H #include "common.h" - +#include "charsets.h" namespace cdk { @@ -141,28 +141,55 @@ class Format : public Format_base }; +/* + String encoding formats (charsets) + ---------------------------------- +*/ + +/* + Constants for the known character set encodings. There is constant + Charset::CS for each charset CS listed in CDK_CD_LIST() macro (see + charsets.h). +*/ + +struct Charset +{ + +#undef CS_ENUM +#undef CS +#define CS_ENUM(CS) CS, + + enum value + { + CDK_CS_LIST(CS_ENUM) + }; +}; + + template<> -class Format : public Format_base +class Format : public Format_base { public: Format(const Format_info &fi) : Format_base(TYPE_STRING, fi) - , m_cs(0), m_width(0), m_kind(STRING) + , m_cs(Charset::value(0)), m_width(0), m_kind(STRING) { fi.get_info(*this); } - charset_id_t charset() const { return m_cs; } + Charset::value charset() const { return m_cs; } uint64_t pad_width() const { return m_width; } bool is_enum() const { return m_kind == ENUM; } bool is_set() const { return m_kind == SET; } + foundation::api::String_codec *codec() const; + protected: - // MySQL collation id that determines character encoding. + // Character set encoding. - charset_id_t m_cs; + Charset::value m_cs; /** If not zero and actual string is shorter than m_width @@ -249,14 +276,22 @@ class Codec : public foundation::api::String_codec , Codec_base { + + foundation::api::String_codec& get_codec() + { + foundation::api::String_codec *codec = m_fmt.codec(); + if (!codec) + throw_error("undefined string conversion"); + return *codec; + } + public: - Codec(const Format_info &fi) : Codec_base(fi) {} + Codec(const Format_info &fi) + : Codec_base(fi) + {} - /** - Return number of bytes required to encode given string (including - the trailing 0x00 - */ + /// Return number of bytes required to encode given string. size_t measure(const string&); size_t from_bytes(bytes raw, string& str); diff --git a/cdk/include/mysql/cdk/common.h b/cdk/include/mysql/cdk/common.h index 91aba6fbb..1fdfaf5c0 100644 --- a/cdk/include/mysql/cdk/common.h +++ b/cdk/include/mysql/cdk/common.h @@ -29,13 +29,10 @@ #include "api/obj_ref.h" #include "api/expression.h" #include "api/document.h" -#include "protocol/mysqlx.h" +#include "api/query.h" -namespace cdk { -using protocol::mysqlx::row_count_t; -using protocol::mysqlx::col_count_t; -using protocol::mysqlx::charset_id_t; +namespace cdk { /* @@ -141,6 +138,14 @@ class Format_info ========== */ +/* + Note: These types are compatible with the X protocol. +*/ + +typedef uint64_t row_count_t; +typedef uint32_t col_count_t; +typedef uint64_t collation_id_t; + class Column_info : public api::Column_ref @@ -151,6 +156,7 @@ class Column_info virtual length_t length() const =0; virtual length_t decimals() const =0; + virtual collation_id_t collation() const = 0; }; @@ -166,6 +172,7 @@ struct Traits }; + typedef api::Meta_data Meta_data; @@ -284,7 +291,7 @@ class Expr_processor; typedef api::Any Expression; typedef api::Expr_list Expr_list; -using cdk::protocol::mysqlx::api::Doc_path; +using api::Doc_path; class Expr_processor { @@ -314,8 +321,11 @@ class Expr_processor virtual Args_prc* op(const char*) =0; virtual Args_prc* call(const Object_ref&) =0; + // TODO: consider changing ref() so that they return doc path processor + virtual void ref(const Column_ref&, const Doc_path*) =0; virtual void ref(const Doc_path&) =0; + virtual void param(const string&) =0; virtual void param(uint16_t) =0; virtual void var(const string&) =0; @@ -502,6 +512,24 @@ class Doc_source {}; +/* + Classes for describing statement parameters + =========================================== +*/ + +typedef cdk::api::Limit Limit; +typedef cdk::api::Order_by Order_by; +typedef cdk::api::Sort_direction Sort_direction; +typedef cdk::api::Doc_base Param_source; + + +using cdk::api::View_security; +using cdk::api::View_algorithm; +using cdk::api::View_check; + +typedef cdk::api::View_options View_options; +typedef cdk::api::View_spec View_spec; + /* Classes for describing update operations ======================================== diff --git a/cdk/include/mysql/cdk/converters.h b/cdk/include/mysql/cdk/converters.h index 50cfe644a..f8c756271 100644 --- a/cdk/include/mysql/cdk/converters.h +++ b/cdk/include/mysql/cdk/converters.h @@ -163,11 +163,25 @@ class Expr_conv_base : m_expr(&expr) {} + Expr_conv_base(const Expr_from *expr) + : m_expr(expr) + {} + void reset(const Expr_from &expr) { m_expr = &expr; } + bool is_valid() const + { + return NULL != m_expr; + } + + const TO* get() const + { + return m_expr ? this : NULL; + } + void process(Prc_to &proc) const { if (!m_expr) diff --git a/cdk/include/mysql/cdk/data_source.h b/cdk/include/mysql/cdk/data_source.h index 70fb39a1c..16150130d 100644 --- a/cdk/include/mysql/cdk/data_source.h +++ b/cdk/include/mysql/cdk/data_source.h @@ -37,28 +37,29 @@ namespace ds { * Generic session options which are valid for any data source. */ + class Options { public: Options() - : m_usr(L"root"), m_has_pwd(false), m_has_db(false), m_use_tls(false) + : m_usr(L"root"), m_has_pwd(false), m_has_db(false) { } Options(const Options &other) : m_usr(other.m_usr) , m_has_pwd(other.m_has_pwd), m_pwd(other.m_pwd) - , m_has_db(false), m_use_tls(other.m_use_tls) + , m_has_db(false) { } Options(const string &usr, const std::string *pwd =NULL) - : m_usr(usr), m_has_pwd(false), m_has_db(false), m_use_tls(false) + : m_usr(usr), m_has_pwd(false), m_has_db(false) { if (pwd) { - m_has_pwd= true; + m_has_pwd = true; m_pwd= *pwd; } } @@ -69,8 +70,6 @@ class Options virtual const std::string* password() const { return m_has_pwd ? &m_pwd : NULL; } - virtual bool use_tls() const { return m_use_tls; } - void set_tls(bool use_tls) { m_use_tls = use_tls; } virtual const string* database() const { @@ -90,8 +89,8 @@ class Options std::string m_pwd; bool m_has_db; - bool m_use_tls; string m_db; + }; @@ -110,7 +109,8 @@ class TCPIP public: - typedef ds::Options Options; + class Options; + TCPIP(const std::string &_host="localhost", unsigned short _port =33060) : m_port(_port), m_host(_host) @@ -125,6 +125,46 @@ class TCPIP virtual const std::string& host() const { return m_host; } }; + +class TCPIP::Options : public ds::Options +{ +public: + + Options() +#ifdef WITH_SSL + : m_tls_options(false) +#endif + {} + + Options(const string &usr, const std::string *pwd =NULL) + : ds::Options(usr, pwd) + #ifdef WITH_SSL + ,m_tls_options(false) + #endif + {} + +#ifdef WITH_SSL + + void set_tls(const cdk::connection::TLS::Options& options) + { + m_tls_options = options; + } + + const cdk::connection::TLS::Options& get_tls() const + { + return m_tls_options; + } + +#endif + +private: + +#ifdef WITH_SSL + cdk::connection::TLS::Options m_tls_options; +#endif + +}; + } // mysqlx namespace mysql { diff --git a/cdk/include/mysql/cdk/foundation.h b/cdk/include/mysql/cdk/foundation.h index 98dfef401..309d5beb8 100644 --- a/cdk/include/mysql/cdk/foundation.h +++ b/cdk/include/mysql/cdk/foundation.h @@ -74,9 +74,11 @@ namespace cdk { namespace connection { using foundation::connection::TCPIP; + using foundation::connection::TLS; using foundation::connection::Error_eos; using foundation::connection::Error_no_connection; using foundation::connection::Error_timeout; + } } // cdk diff --git a/cdk/include/mysql/cdk/foundation/codec.h b/cdk/include/mysql/cdk/foundation/codec.h index af1281a0c..38f503bd7 100644 --- a/cdk/include/mysql/cdk/foundation/codec.h +++ b/cdk/include/mysql/cdk/foundation/codec.h @@ -35,29 +35,32 @@ #include // for std::numeric_limits -/* - TODO: This is probably the only dependency of CDK public headers - on Boost. Remove it... - NOTE: is used in types.h -*/ -PUSH_BOOST_WARNINGS -#include // to detect endianess -POP_BOOST_WARNINGS - namespace cdk { namespace foundation { -#ifdef HAVE_CODECVT_UTF8 -typedef std::codecvt_utf8 codecvt_utf8; -#else - /* Note: the third codecvt template parameter (conversion state type) - probably has to be std::mbstate_t if this codec should work with + probably has to be std::mbstate_t if derived codecs should work with C++ I/O streams (via imbue() method). */ + +#ifdef HAVE_CODECVT_UTF8 + +class codecvt_utf8 : public std::codecvt_utf8 +{ +public: + + size_t measure(const string& str) const + { + THROW("codecvt_utf8: measure() not yet implemented"); + } + +}; + +#else + class codecvt_utf8 : public std::codecvt { result do_out( state_type& state, @@ -75,10 +78,59 @@ class codecvt_utf8 : public std::codecvt intern_type* to, intern_type* to_end, intern_type*& to_next ) const; + +public: + + size_t measure(const string&) const + { + THROW("codecvt_utf8: measure() not yet implemented"); + } + }; #endif + +class codecvt_ascii : public std::codecvt +{ + result do_out( state_type& state, + const intern_type* from, + const intern_type* from_end, + const intern_type*& from_next, + extern_type* to, + extern_type* to_end, + extern_type*& to_next ) const; + + result do_in( state_type& state, + const extern_type* from, + const extern_type* from_end, + const extern_type*& from_next, + intern_type* to, + intern_type* to_end, + intern_type*& to_next ) const; + + /* + Note: At least in VS, dtor of std::ctype<> is protected and for + that reason we can not have direct instance of std::ctype<>. + */ + + struct : public std::ctype< wchar_t > + {} + m_ctype; + +public: + + codecvt_ascii() + {} + + size_t measure(const string& str) const + { + return str.length(); + } + +}; + + }} // cdk::foundation @@ -111,6 +163,7 @@ class String_codec virtual ~String_codec() {} + virtual size_t measure(const string&) =0; virtual size_t from_bytes(bytes, string&) =0; virtual size_t to_bytes(const string&, bytes) =0; }; @@ -118,36 +171,71 @@ class String_codec } // api namespace - -// String utf8 codec - -template<> -class Codec : public api::String_codec +template +class String_codec : public api::String_codec { - codecvt_utf8 m_codec; + VT m_codec; public: + String_codec() + {} + typedef cdk::foundation::char_t char_t; - size_t from_bytes(bytes, string &); - size_t to_bytes(const string&, bytes); -}; + size_t measure(const string &in) + { + return m_codec.measure(in); + } + size_t from_bytes(bytes in, string &out) + { + typename VT::state_type state; + const char *in_next; + char_t *out_next; -#undef BIG_ENDIAN + out.resize(in.size()+1); + std::codecvt_base::result res= + m_codec.in(state, (char*)in.begin(), (char*)in.end(), in_next, + &out[0], &out[in.size()], out_next); -#if BOOST_ENDIAN_BIG_BYTE -#define BIG_ENDIAN 1 -#endif + if (std::codecvt_base::ok != res) + throw_error("string conversion error"); // TODO: report errors -#if BOOST_ENDIAN_LITTLE_BYTE -#define BIG_ENDIAN 0 -#endif + assert(out_next >= &out[0]); + out.resize(static_cast(out_next - &out[0])); + + assert((byte*)in_next >= in.begin()); + return static_cast((byte*)in_next - in.begin()); + } + + + size_t to_bytes(const string &in, bytes out) + { + typename VT::state_type state; + const char_t *in_next; + char *out_next; + + std::codecvt_base::result res= + m_codec.out(state, &in[0], &in[in.length()], in_next, + (char*)out.begin(), (char*)out.end(), out_next); + + if (std::codecvt_base::ok != res) + throw_error("string conversion error"); // TODO: report errors + + assert((byte*)out_next >= out.begin()); + return static_cast((byte*)out_next - out.begin()); + } + +}; + + +// String utf8 codec + +template<> +class Codec : public String_codec +{}; -#ifndef BIG_ENDIAN -#error Endianess could not be determined! -#endif /* @@ -155,13 +243,18 @@ class Codec : public api::String_codec ============= */ +#ifndef CDK_BIG_ENDIAN +#error Unknown endianess! +#endif + + struct Endianess { enum value { BIG, LITTLE, NATIVE = -#if BIG_ENDIAN +#if CDK_BIG_ENDIAN BIG #else LITTLE @@ -336,7 +429,7 @@ static size_t convert(bytes buf, T &val) template<> class Number_codec< -#if BIG_ENDIAN +#if CDK_BIG_ENDIAN Endianess::LITTLE #else Endianess::BIG diff --git a/cdk/include/mysql/cdk/foundation/common.h b/cdk/include/mysql/cdk/foundation/common.h index d7d6441d9..5bbf006ae 100644 --- a/cdk/include/mysql/cdk/foundation/common.h +++ b/cdk/include/mysql/cdk/foundation/common.h @@ -155,8 +155,9 @@ #else #define PUSH_PB_WARNINGS DIAGNOSTIC_PUSH \ - DISABLE_WARNING(-Wshadow) \ - DISABLE_WARNING(-Wunused-parameter) + DISABLE_WARNING(-Wshadow) \ + DISABLE_WARNING(-Wunused-parameter) \ + DISABLE_WARNING(-Wdeprecated-declarations) \ #endif diff --git a/cdk/include/mysql/cdk/foundation/connection_yassl.h b/cdk/include/mysql/cdk/foundation/connection_yassl.h index aacda6737..cd7d764d5 100644 --- a/cdk/include/mysql/cdk/foundation/connection_yassl.h +++ b/cdk/include/mysql/cdk/foundation/connection_yassl.h @@ -26,6 +26,7 @@ #define CDK_FOUNDATION_CONNECTION_YASSL_H #include "connection_tcpip.h" +#include "stream.h" #include "error.h" @@ -39,7 +40,12 @@ class TLS , opaque_impl { public: - TLS(TCPIP_base* tcpip); + + class Options; + + TLS(TCPIP_base* tcpip, + const Options& Opts); + class Read_op; class Read_some_op; @@ -51,6 +57,45 @@ class TLS }; +class TLS::Options +{ +public: + + /* + Note: Normally m_use_tls should be always true: using TLS options object + implies an intent to have TLS connection. A TLS::Options object with + m_use_tls set to false is only used to disable TLS connection inside + TCPIP::Options object. The TCPIP::Options object holds an instance + of TLS::Options. Calling TCPIP::Options::set_tls(false) will alter this + internal TLS::Options instance so that m_use_tls is false and then the + TCPIP::Options object knows that TLS should not be used for the connection. + */ + + Options(bool use_tls = true) + : m_use_tls(use_tls) + {} + + void set_use_tls(bool use_tls) { m_use_tls = use_tls; } + bool use_tls() const { return m_use_tls; } + + void set_key(const string &key) { m_key = key; } + const std::string &get_key() const { return m_key; } + + void set_ca(const string &ca) { m_ca = ca; } + void set_ca_path(const string &ca_path) { m_ca_path = ca_path; } + + const std::string &get_ca() const { return m_ca; } + const std::string &get_ca_path() const { return m_ca_path; } + +protected: + + bool m_use_tls; + std::string m_key; + std::string m_ca; + std::string m_ca_path; +}; + + class TLS::Read_op : public TCPIP_base::IO_op { public: diff --git a/cdk/include/mysql/cdk/mysqlx/common.h b/cdk/include/mysql/cdk/mysqlx/common.h index a3d8b7baa..ffd4d8e3a 100644 --- a/cdk/include/mysql/cdk/mysqlx/common.h +++ b/cdk/include/mysql/cdk/mysqlx/common.h @@ -66,7 +66,7 @@ using protocol::mysqlx::Protocol; using protocol::mysqlx::sql_state_t; using protocol::mysqlx::row_count_t; using protocol::mysqlx::col_count_t; -using protocol::mysqlx::charset_id_t; +using protocol::mysqlx::collation_id_t; using protocol::mysqlx::insert_id_t; typedef api::Async_op Async_op; diff --git a/cdk/include/mysql/cdk/mysqlx/session.h b/cdk/include/mysql/cdk/mysqlx/session.h index 4233a4c24..b18c1d580 100644 --- a/cdk/include/mysql/cdk/mysqlx/session.h +++ b/cdk/include/mysql/cdk/mysqlx/session.h @@ -27,8 +27,9 @@ #include #include +#include + #include "common.h" -#include PUSH_SYS_WARNINGS #include @@ -67,7 +68,7 @@ struct cdk::Format::Access { typedef cdk::Format Format; static void set_width(Format &o, uint64_t width) { o.m_width= width; } - static void set_cs(Format &o, cdk::charset_id_t cs) { o.m_cs= cs; } + static void set_cs(Format &o, Charset::value cs) { o.m_cs= cs; } static void set_kind_set(Format &o) { o.m_kind= Format::SET; } static void set_kind_enum(Format &o) { o.m_kind= Format::ENUM; } }; @@ -101,6 +102,8 @@ class Cursor; template class Obj_ref : public Base { +protected: + string m_name; string m_name_original; bool m_has_name_original; @@ -111,6 +114,12 @@ class Obj_ref : public Base : m_has_name_original(false) {} + Obj_ref(const cdk::api::Ref_base &ref) + : m_name(ref.name()) + , m_name_original(ref.orig_name()) + , m_has_name_original(true) + {} + const string name() const { return m_name; } const string orig_name() const { @@ -121,6 +130,34 @@ class Obj_ref : public Base }; +/* + Determine charset from collation id reported by the protocol. The mapping + is given by COLLATIONS_XXX() lists in collations.h. +*/ + +inline +cdk::Charset::value get_collation_cs(collation_id_t id) +{ + /* + If collation id is 0, that is, there is no collation info in server + reply, we assume utf8. + */ + + if (0 == id) + return cdk::Charset::utf8; + +#undef CS +#define COLL_TO_CS(CS) COLLATIONS_##CS(COLL_TO_CS_CASE) return cdk::Charset::CS; +#define COLL_TO_CS_CASE(CS,ID,COLL,CC) case ID: + + switch (id) + { + CDK_CS_LIST(COLL_TO_CS) + default: + THROW("Unkonwn collation id"); + } +} + class Col_metadata : public Obj_ref @@ -132,7 +169,7 @@ class Col_metadata int m_content_type; length_t m_length; unsigned int m_decimals; - charset_id_t m_cs; + collation_id_t m_cs; uint32_t m_flags; class : public Obj_ref @@ -161,7 +198,10 @@ class Col_metadata return m_has_table ? &m_table : NULL; } - // Encoding format information + /* + Format_info interface + --------------------- + */ bool for_type(Type_info type) const { @@ -195,6 +235,11 @@ class Col_metadata } } + /* + Methods get_info() update a Type_info object to describe the + encoding format used by this column data. + */ + void get_info(Format& fmt) const { switch (m_type) @@ -227,14 +272,14 @@ class Col_metadata void get_info(Format& fmt) const { + Format::Access::set_cs(fmt, get_collation_cs(m_cs)); + /* - Note: Types ENUM and SET are generally treated as - strings, but we set a 'kind' flag in the format description - to be able to distinguish them from plain strings. + Note: Types ENUM and SET are generally treated as + strings, but we set a 'kind' flag in the format description + to be able to distinguish them from plain strings. */ - Format::Access::set_cs(fmt, m_cs); - switch (m_type) { case protocol::mysqlx::col_type::BYTES: @@ -306,6 +351,7 @@ class Col_metadata length_t length() const { return m_length; } length_t decimals() const { return m_decimals; } + collation_id_t collation() const { return m_cs; } friend class Session; friend class Cursor; @@ -316,25 +362,21 @@ typedef std::map Mdata_storage; // --------------------------------------------------------- +/* + Note: other Session implementations might need to translate genric + cdk types to something that is specific to the implementation. +*/ using cdk::Row_source; using cdk::Projection; +using cdk::Limit; +using cdk::Order_by; +using cdk::Sort_direction; +using cdk::Param_source; +using cdk::View_spec; typedef Session Reply_init; -/* - TODO: Make these generic cdk interfaces (defined in cdk/common.h) - that are used by cdk::mysqlx as is (so, the other way around). - - Note: other Session implementations might need to translate genric - cdk interfaces to something that is specific to the implementation. -*/ - -typedef cdk::api::Doc_base Param_source; -typedef cdk::api::Limit Limit; -typedef cdk::api::Order_by Order_by; -typedef cdk::api::Sort_direction Sort_direction; - class Reply; class Cursor; class SessionAuthInterface; @@ -344,7 +386,6 @@ class Session : public api::Diagnostics , public Async_op , private protocol::mysqlx::Auth_processor - , private protocol::mysqlx::Reply_processor , private protocol::mysqlx::Mdata_processor , private protocol::mysqlx::Stmt_processor , private protocol::mysqlx::SessionState_processor @@ -476,6 +517,7 @@ class Session const Limit *lim = NULL, const Param_source *param = NULL); Reply_init &coll_find(const Table_ref&, + const View_spec *view = NULL, const Expression *expr = NULL, const Expression::Document *proj = NULL, const Order_by *order_by = NULL, @@ -489,12 +531,14 @@ class Session const Order_by *order_by = NULL, const Limit* = NULL, const Param_source * = NULL); + Reply_init &table_delete(const Table_ref&, const Expression *expr = NULL, const Order_by *order_by = NULL, const Limit *lim = NULL, const Param_source *param = NULL); Reply_init &table_select(const Table_ref&, + const View_spec *view = NULL, const Expression *expr = NULL, const Projection *proj = NULL, const Order_by *order_by = NULL, @@ -513,6 +557,8 @@ class Session const Limit *lim = NULL, const Param_source *param = NULL); + Reply_init &view_drop(const api::Table_ref&, bool check_existence = false); + /* Async (cdk::api::Async_op) @@ -565,6 +611,7 @@ class Session Mdata_processor (cdk::protocol::mysqlx::Mdata_processor) */ + void ok(string); void col_count(col_count_t nr_cols); void col_type(col_count_t pos, unsigned short type); void col_content_type(col_count_t pos, unsigned short type); @@ -574,7 +621,7 @@ class Session const string &table, const string &original); void col_schema(col_count_t pos, const string &schema, const string &catalog); - void col_charset(col_count_t pos, charset_id_t cs); + void col_collation(col_count_t pos, collation_id_t cs); void col_length(col_count_t pos, uint32_t length); void col_decimals(col_count_t pos, unsigned short decimals); void col_flags(col_count_t, uint32_t); @@ -603,7 +650,7 @@ class Session */ void send_cmd(); - void start_reading_row_set(); + void start_reading_result(); Proto_op* start_reading_row_data(protocol::mysqlx::Row_processor &prc); void start_reading_stmt_reply(); void start_authentication(const char* mechanism,bytes data,bytes response); diff --git a/cdk/include/mysql/cdk/protocol/mysqlx.h b/cdk/include/mysql/cdk/protocol/mysqlx.h index 51dd25323..d88c66a1d 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx.h @@ -37,13 +37,18 @@ #include "../foundation.h" #include "../foundation/opaque_impl.h" #include "../api/query.h" -#include "mysqlx_expr.h" +#include "mysqlx/traits.h" +#include "mysqlx/expr.h" namespace cdk { namespace protocol { namespace mysqlx { +using cdk::foundation::byte; +using cdk::foundation::bytes; +using cdk::foundation::string; + /* Enumerations which define message type codes used by the protocol. @@ -71,7 +76,10 @@ enum ClientMessages_Type { ClientMessages_Type_CRUD_UPDATE = 19, ClientMessages_Type_CRUD_DELETE = 20, ClientMessages_Type_EXPECT_OPEN = 24, - ClientMessages_Type_EXPECT_CLOSE = 25 + ClientMessages_Type_EXPECT_CLOSE = 25, + ClientMessages_Type_CRUD_CREATE_VIEW = 30, + ClientMessages_Type_CRUD_MODIFY_VIEW = 31, + ClientMessages_Type_CRUD_DROP_VIEW = 32 }; enum ServerMessages_Type { @@ -142,6 +150,9 @@ enum ServerMessages_Type { ExpectOpen, EXPECT_OPEN) \ MSG_CLIENT(X, Mysqlx::Crud::Delete, \ ExpectClose, EXPECT_CLOSE) \ + MSG_CLIENT(X, Mysqlx::Crud::CreateView, CreateView, CRUD_CREATE_VIEW) \ + MSG_CLIENT(X, Mysqlx::Crud::ModifyView, ModifyView, CRUD_MODIFY_VIEW) \ + MSG_CLIENT(X, Mysqlx::Crud::DropView, DropView, CRUD_DROP_VIEW) \ \ MSG_SERVER(X, Mysqlx::Ok, \ Ok, OK) \ @@ -403,9 +414,46 @@ typedef cdk::api::Sort_direction Sort_direction; typedef cdk::api::Projection Projection; typedef cdk::api::Columns Columns; +typedef cdk::api::View_options View_options; + } // api namespace +/* + Interfaces which specify parameters for Find and other CRUD operations, + such as Delete or Update, which can work on limited set of rwos/documents. + + Interface Select_spec specifies parameter common to all CRUD operations + which limit set of rows/documents. Interface Find_spec specifies additional + parameters of the Find operation. +*/ + +struct Select_spec +{ +public: + + typedef api::Db_obj Db_obj; + typedef api::Expression Expression; + typedef api::Order_by Order_by; + typedef api::Limit Limit; + + virtual const Db_obj& obj() const = 0; + virtual const Expression* select() const = 0; + virtual const Order_by* order() const = 0; + virtual const Limit* limit() const = 0; +}; + +struct Find_spec : public Select_spec +{ +public: + + typedef api::Projection Projection; + typedef api::Expr_list Expr_list; + + virtual const Projection* project() const = 0; + virtual const Expr_list* group_by() const = 0; + virtual const Expression* having() const = 0; +}; /* @@ -432,43 +480,123 @@ class Protocol Op& snd_AuthenticateContinue(bytes data); Op& snd_Close(); - Op& snd_StmtExecute(const char *ns, const string &stmt, api::Any_list *args); - -// Op& snd_PrepareStmt(stmt_id_t id, const string &stmt); -// Op& snd_PreparedStmtExecute(stmt_id_t id, cursor_id_t cid); -// Op& snd_CursorClose(cursor_id_t cid); -// Op& snd_PreparedStmtClose(stmt_id_t id); - -// Op& snd_CursorFetchRows(cursor_id_t cid, row_count_t limit); -// Op& snd_CursorFetchRows(cursor_id_t cid); - -// Op& snd_CursorFetchMetadata(cursor_id_t cid); - - Op& snd_Find(Data_model, - api::Db_obj&, - api::Expression* = NULL, // select - api::Projection* = NULL, // project - api::Order_by* = NULL, // order - api::Expr_list* = NULL, // group_by - api::Expression* = NULL, // having - api::Limit* = NULL, // limit - api::Args_map * = NULL); - - Op& snd_Insert(Data_model, api::Db_obj&, - const api::Columns*, - Row_source&, - api::Args_map *args = NULL); - Op& snd_Update(Data_model, api::Db_obj&, - api::Expression*, - Update_spec &, - api::Order_by* = NULL, - api::Limit* = NULL, - api::Args_map * = NULL); - Op& snd_Delete(Data_model, api::Db_obj&, - api::Expression* = NULL, - api::Order_by* = NULL, - api::Limit* = NULL, - api::Args_map * = NULL); + + /** + Send protocol command which executes a statement. + + Which statements are understood by the server are defined by the + X Protocol. Currently we use "sql" namespace to execute plain SQL + statements and commands in "admin" namespace for other operations + and queries. + + @param ns namespace used to interpret the statement + @param stmt the statement to be eecuted + @param args optional parameters of the statement + */ + + Op& snd_StmtExecute(const char *ns, const string &stmt, + const api::Any_list *args); + + + /** + Send CRUD Find command. + + This command returns rows from a table or documents from a collection. + Selected data can be transformed using a projection before sending to + the client. + + @param dm determines whether this command fetches rows or documents + + @param spec specifies source of the data, criteria selecting + rows/documents to be returned, optional projection and other parameters + of the commnad (@see Find_spec) + + @param args if expressions used in the specification use named parameters, + this argument map provides values of these parameters + */ + + Op& snd_Find(Data_model dm, const Find_spec &spec, + const api::Args_map *args = NULL); + + /** + Send CRUD Insert command. + + This command inserts rows into a table or documents into a collection + + @param dm determines whether this command inserts rows or documents + + @param obj target table or collection + + @param columns optional specification determining which columns of the + target table should be updated with provided data. + + @param data Object defining rows/documents to be inserted. It is a + sequence of tuples of expressions; each tuple in the sequence defines + values of fields in a single row to be inserted (when inserting documents, + there should be just one field with the document). + + @param args defines values of named parameters, if any are used in the + expressions of the row source object + */ + + Op& snd_Insert(Data_model dm, api::Db_obj &obj, + const api::Columns *columns, + Row_source &data, + const api::Args_map *args = NULL); + + /** + Send CRUD Update command. + + This command updates existing rows in a table or documents in a collection. + In can work on a subset of rows or document defined by a select criteria. + + @param dm determines whether this command updates rows or documents + + @param select defines target table or collection whose data should be + modified and a subset of rows/documents that is affected by the command + + @param update a specification of what modifications should be applied to + each row/document + + @param args defines values of named parameters, if any are used in the + selection criteria or update specification. + */ + + Op& snd_Update(Data_model dm, + const Select_spec &select, + Update_spec &update, + const api::Args_map *args = NULL); + + /** + Send CRUD Delete command. + + This command removes all or selected rows/documents from a table or + collection. + + @param dm determines whether this command removes rows or documents + + @param select defines target table or collection whose data should be + modified and a subset of rows/documents to be deleted + + @param args defines values of named parameters, if any are used in the + selection criteria + */ + + Op& snd_Delete(Data_model dm, const Select_spec &select, + const api::Args_map *args = NULL); + + + Op& snd_CreateView(Data_model dm, const api::Db_obj &obj, + const Find_spec &query, const api::Columns *columns, + bool replace = false, + api::View_options* = NULL, + const api::Args_map *args = NULL); + Op& snd_ModifyView(Data_model dm, const api::Db_obj &obj, + const Find_spec &query, const api::Columns *columns, + api::View_options* = NULL, + const api::Args_map *args = NULL); + Op& snd_DropView(const api::Db_obj &obj, bool if_exists); + Op& rcv_AuthenticateReply(Auth_processor &); Op& rcv_Reply(Reply_processor &); @@ -607,6 +735,7 @@ Protocol_server::Protocol_server(C &conn) static_cast(new Protocol::Stream::Impl(conn))) {} + /* Callback interfaces to be implemented by message processor objects ================================================================== @@ -663,8 +792,9 @@ class Processor_base { public: - typedef foundation::byte byte; - typedef foundation::string string; + typedef protocol::mysqlx::byte byte; + typedef protocol::mysqlx::string string; + typedef protocol::mysqlx::msg_type_t msg_type_t; /* Called when message header is received. The type of the message stored @@ -766,6 +896,8 @@ class Error_processor : public Processor_base { public: + typedef protocol::mysqlx::sql_state_t sql_state_t; + virtual void error(unsigned int /*code*/, short int /*severity*/, sql_state_t /*sql_state*/, const string &/*msg*/) {} @@ -804,6 +936,10 @@ class Stmt_processor : public Error_processor class Row_processor : public Error_processor { public: + + typedef protocol::mysqlx::row_count_t row_count_t; + typedef protocol::mysqlx::col_count_t col_count_t; + virtual bool row_begin(row_count_t /*row*/) { return true; } virtual void row_end(row_count_t /*row*/) {} @@ -824,10 +960,13 @@ class Row_processor : public Error_processor virtual void done(bool /*eod*/, bool /*more*/) {} }; -class Mdata_processor : public Error_processor +class Mdata_processor : public Reply_processor { public: + typedef protocol::mysqlx::col_count_t col_count_t; + typedef protocol::mysqlx::collation_id_t collation_id_t; + virtual void col_count(col_count_t) {} virtual void col_type(col_count_t /*pos*/, unsigned short /*type*/) {} virtual void col_name(col_count_t /*pos*/, @@ -836,7 +975,7 @@ class Mdata_processor : public Error_processor const string &/*table*/, const string &/*original*/) {} virtual void col_schema(col_count_t /*pos*/, const string &/*schema*/, const string &/*catalog*/) {} - virtual void col_charset(col_count_t /*pos*/, charset_id_t /*cs*/) {} + virtual void col_collation(col_count_t /*pos*/, collation_id_t /*cs*/) {} virtual void col_length(col_count_t /*pos*/, uint32_t /*length*/) {} virtual void col_decimals(col_count_t /*pos*/, unsigned short /*decimals*/) {} virtual void col_content_type(col_count_t /*pos*/, unsigned short /*type*/) {} @@ -875,6 +1014,10 @@ class Result_processor class SessionState_processor { public: + + typedef protocol::mysqlx::row_count_t row_count_t; + typedef protocol::mysqlx::insert_id_t insert_id_t; + enum row_stats_t { ROWS_AFFECTED, ROWS_FOUND, ROWS_MATCHED }; enum trx_event_t { COMMIT, ROLLBACK }; @@ -914,7 +1057,10 @@ class Update_processor { public: - typedef api::Expression::Processor Expr_prc; + typedef protocol::mysqlx::string string; + typedef protocol::mysqlx::api::Db_obj Db_obj; + typedef protocol::mysqlx::api::Doc_path Doc_path; + typedef protocol::mysqlx::api::Expression::Processor Expr_prc; virtual void target_name(const string&) = 0; virtual void target_table(const api::Db_obj&) = 0; @@ -975,6 +1121,16 @@ class Db_obj : public api::Db_obj Db_obj(string name, string schema) : m_name(name), m_schema(schema), m_schema_set(true) {} + Db_obj(const api::Db_obj &other) + : m_name(other.get_name()) + , m_schema_set(false) + { + if (!other.get_schema()) + return; + m_schema = *other.get_schema(); + m_schema_set = true; + } + virtual ~Db_obj() {} virtual const string& get_name() const { return m_name; }; @@ -1030,6 +1186,9 @@ class Limit : public api::Limit bool m_offset_set; public: + Limit() : m_row_count(0), m_offset(0), m_offset_set(false) + {} + Limit(row_count_t row_count) : m_row_count(row_count), m_offset(0), m_offset_set(false) {} Limit(row_count_t row_count, row_count_t offset) : m_row_count(row_count), m_offset(offset), diff --git a/cdk/include/mysql/cdk/protocol/mysqlx/collations.h b/cdk/include/mysql/cdk/protocol/mysqlx/collations.h new file mode 100644 index 000000000..e9d2adac6 --- /dev/null +++ b/cdk/include/mysql/cdk/protocol/mysqlx/collations.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * + * This code is licensed under the terms of the GPLv2 + * , like most + * MySQL Connectors. There are special exceptions to the terms and + * conditions of the GPLv2 as it is applied to this software, see the + * FLOSS License Exception + * . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + Lists of collations used by MySQL Server and its protocols. + + Note: it is assumed that each collation's charset is known to CDK and + is listed in CDK_CS_LIST(). +*/ + +#ifndef MYSQL_CDK_PROTOCOL_MYSQLX_COLLATIONS_H +#define MYSQL_CDK_PROTOCOL_MYSQLX_COLLATIONS_H + +/* + Each line X(CS, ID, COLL, CASE) in the expansion of + a COLLATION_XXX() macro declares collation with name COLL for character set + CS. ID is the MySQL id number for the collation. CASE is one of ci, cs or bin + and indicates whether it is case insensitive, sensitive or binary collation, + respectively. +*/ + +#define COLLATIONS_big5(X) \ + X(big5,1,chinese,ci) \ + X(big5,84,bin,bin) \ + +#define COLLATIONS_dec8(X) \ + X(dec8,3,swedish,ci) \ + X(dec8,69,bin,bin) \ + +#define COLLATIONS_cp850(X) \ + X(cp850,4,general,ci) \ + X(cp850,80,bin,bin) \ + +#define COLLATIONS_hp8(X) \ + X(hp8,6,english,ci) \ + X(hp8,72,bin,bin) \ + +#define COLLATIONS_koi8r(X) \ + X(koi8r,7,general,ci) \ + X(koi8r,74,bin,bin) \ + +#define COLLATIONS_latin1(X) \ + X(latin1,5,german1,ci) \ + X(latin1,8,swedish,ci) \ + X(latin1,15,danish,ci) \ + X(latin1,31,german2,ci) \ + X(latin1,47,bin,bin) \ + X(latin1,48,general,ci) \ + X(latin1,49,general,cs) \ + X(latin1,94,spanish,ci) \ + +#define COLLATIONS_latin2(X) \ + X(latin2,2,czech,cs) \ + X(latin2,9,general,ci) \ + X(latin2,21,hungarian,ci) \ + X(latin2,27,croatian,ci) \ + X(latin2,77,bin,bin) \ + +#define COLLATIONS_swe7(X) \ + X(swe7,10,swedish,ci) \ + X(swe7,82,bin,bin) \ + +#define COLLATIONS_ascii(X) \ + X(ascii,11,general,ci) \ + X(ascii,65,bin,bin) \ + +#define COLLATIONS_ujis(X) \ + X(ujis,12,japanese,ci) \ + X(ujis,91,bin,bin) \ + +#define COLLATIONS_sjis(X) \ + X(sjis,13,japanese,ci) \ + X(sjis,88,bin,bin) \ + +#define COLLATIONS_hebrew(X) \ + X(hebrew,16,general,ci) \ + X(hebrew,71,bin,bin) \ + +#define COLLATIONS_tis620(X) \ + X(tis620,18,thai,ci) \ + X(tis620,89,bin,bin) \ + +#define COLLATIONS_euckr(X) \ + X(euckr,19,korean,ci) \ + X(euckr,85,bin,bin) \ + +#define COLLATIONS_koi8u(X) \ + X(koi8u,22,general,ci) \ + X(koi8u,75,bin,bin) \ + +#define COLLATIONS_gb2312(X) \ + X(gb2312,24,chinese,ci) \ + X(gb2312,86,bin,bin) \ + +#define COLLATIONS_greek(X) \ + X(greek,25,general,ci) \ + X(greek,70,bin,bin) \ + +#define COLLATIONS_cp1250(X) \ + X(cp1250,26,general,ci) \ + X(cp1250,34,czech,cs) \ + X(cp1250,44,croatian,ci) \ + X(cp1250,66,bin,bin) \ + X(cp1250,99,polish,ci) \ + +#define COLLATIONS_gbk(X) \ + X(gbk,28,chinese,ci) \ + X(gbk,87,bin,bin) \ + +#define COLLATIONS_latin5(X) \ + X(latin5,30,turkish,ci) \ + X(latin5,78,bin,bin) \ + +#define COLLATIONS_armscii8(X) \ + X(armscii8,32,general,ci) \ + X(armscii8,64,bin,bin) \ + +#define COLLATIONS_utf8(X) \ + X(utf8,33,general,ci) \ + X(utf8,83,bin,bin) \ + X(utf8,192,unicode,ci) \ + X(utf8,193,icelandic,ci) \ + X(utf8,194,latvian,ci) \ + X(utf8,195,romanian,ci) \ + X(utf8,196,slovenian,ci) \ + X(utf8,197,polish,ci) \ + X(utf8,198,estonian,ci) \ + X(utf8,199,spanish,ci) \ + X(utf8,200,swedish,ci) \ + X(utf8,201,turkish,ci) \ + X(utf8,202,czech,ci) \ + X(utf8,203,danish,ci) \ + X(utf8,204,lithuanian,ci) \ + X(utf8,205,slovak,ci) \ + X(utf8,206,spanish2,ci) \ + X(utf8,207,roman,ci) \ + X(utf8,208,persian,ci) \ + X(utf8,209,esperanto,ci) \ + X(utf8,210,hungarian,ci) \ + X(utf8,211,sinhala,ci) \ + X(utf8,212,german2,ci) \ + X(utf8,213,croatian,ci) \ + X(utf8,214,unicode_520,ci) \ + X(utf8,215,vietnamese,ci) \ + X(utf8,223,general_mysql500,ci) \ + +#define COLLATIONS_ucs2(X) \ + X(ucs2,35,general,ci) \ + X(ucs2,90,bin,bin) \ + X(ucs2,128,unicode,ci) \ + X(ucs2,129,icelandic,ci) \ + X(ucs2,130,latvian,ci) \ + X(ucs2,131,romanian,ci) \ + X(ucs2,132,slovenian,ci) \ + X(ucs2,133,polish,ci) \ + X(ucs2,134,estonian,ci) \ + X(ucs2,135,spanish,ci) \ + X(ucs2,136,swedish,ci) \ + X(ucs2,137,turkish,ci) \ + X(ucs2,138,czech,ci) \ + X(ucs2,139,danish,ci) \ + X(ucs2,140,lithuanian,ci) \ + X(ucs2,141,slovak,ci) \ + X(ucs2,142,spanish2,ci) \ + X(ucs2,143,roman,ci) \ + X(ucs2,144,persian,ci) \ + X(ucs2,145,esperanto,ci) \ + X(ucs2,146,hungarian,ci) \ + X(ucs2,147,sinhala,ci) \ + X(ucs2,148,german2,ci) \ + X(ucs2,149,croatian,ci) \ + X(ucs2,150,unicode_520,ci) \ + X(ucs2,151,vietnamese,ci) \ + X(ucs2,159,general_mysql500,ci) \ + +#define COLLATIONS_cp866(X) \ + X(cp866,36,general,ci) \ + X(cp866,68,bin,bin) \ + +#define COLLATIONS_keybcs2(X) \ + X(keybcs2,37,general,ci) \ + X(keybcs2,73,bin,bin) \ + +#define COLLATIONS_macce(X) \ + X(macce,38,general,ci) \ + X(macce,43,bin,bin) \ + +#define COLLATIONS_macroman(X) \ + X(macroman,39,general,ci) \ + X(macroman,53,bin,bin) \ + +#define COLLATIONS_cp852(X) \ + X(cp852,40,general,ci) \ + X(cp852,81,bin,bin) \ + +#define COLLATIONS_latin7(X) \ + X(latin7,20,estonian,cs) \ + X(latin7,41,general,ci) \ + X(latin7,42,general,cs) \ + X(latin7,79,bin,bin) \ + +#define COLLATIONS_utf8mb4(X) \ + X(utf8mb4,45,general,ci) \ + X(utf8mb4,46,bin,bin) \ + X(utf8mb4,224,unicode,ci) \ + X(utf8mb4,225,icelandic,ci) \ + X(utf8mb4,226,latvian,ci) \ + X(utf8mb4,227,romanian,ci) \ + X(utf8mb4,228,slovenian,ci) \ + X(utf8mb4,229,polish,ci) \ + X(utf8mb4,230,estonian,ci) \ + X(utf8mb4,231,spanish,ci) \ + X(utf8mb4,232,swedish,ci) \ + X(utf8mb4,233,turkish,ci) \ + X(utf8mb4,234,czech,ci) \ + X(utf8mb4,235,danish,ci) \ + X(utf8mb4,236,lithuanian,ci) \ + X(utf8mb4,237,slovak,ci) \ + X(utf8mb4,238,spanish2,ci) \ + X(utf8mb4,239,roman,ci) \ + X(utf8mb4,240,persian,ci) \ + X(utf8mb4,241,esperanto,ci) \ + X(utf8mb4,242,hungarian,ci) \ + X(utf8mb4,243,sinhala,ci) \ + X(utf8mb4,244,german2,ci) \ + X(utf8mb4,245,croatian,ci) \ + X(utf8mb4,246,unicode_520,ci) \ + X(utf8mb4,247,vietnamese,ci) \ + +#define COLLATIONS_cp1251(X) \ + X(cp1251,14,bulgarian,ci) \ + X(cp1251,23,ukrainian,ci) \ + X(cp1251,50,bin,bin) \ + X(cp1251,51,general,ci) \ + X(cp1251,52,general,cs) \ + +#define COLLATIONS_utf16(X) \ + X(utf16,54,general,ci) \ + X(utf16,55,bin,bin) \ + X(utf16,101,unicode,ci) \ + X(utf16,102,icelandic,ci) \ + X(utf16,103,latvian,ci) \ + X(utf16,104,romanian,ci) \ + X(utf16,105,slovenian,ci) \ + X(utf16,106,polish,ci) \ + X(utf16,107,estonian,ci) \ + X(utf16,108,spanish,ci) \ + X(utf16,109,swedish,ci) \ + X(utf16,110,turkish,ci) \ + X(utf16,111,czech,ci) \ + X(utf16,112,danish,ci) \ + X(utf16,113,lithuanian,ci) \ + X(utf16,114,slovak,ci) \ + X(utf16,115,spanish2,ci) \ + X(utf16,116,roman,ci) \ + X(utf16,117,persian,ci) \ + X(utf16,118,esperanto,ci) \ + X(utf16,119,hungarian,ci) \ + X(utf16,120,sinhala,ci) \ + X(utf16,121,german2,ci) \ + X(utf16,122,croatian,ci) \ + X(utf16,123,unicode_520,ci) \ + X(utf16,124,vietnamese,ci) \ + +#define COLLATIONS_utf16le(X) \ + X(utf16le,56,general,ci) \ + X(utf16le,62,bin,bin) \ + +#define COLLATIONS_cp1256(X) \ + X(cp1256,57,general,ci) \ + X(cp1256,67,bin,bin) \ + +#define COLLATIONS_cp1257(X) \ + X(cp1257,29,lithuanian,ci) \ + X(cp1257,58,bin,bin) \ + X(cp1257,59,general,ci) \ + +#define COLLATIONS_utf32(X) \ + X(utf32,60,general,ci) \ + X(utf32,61,bin,bin) \ + X(utf32,160,unicode,ci) \ + X(utf32,161,icelandic,ci) \ + X(utf32,162,latvian,ci) \ + X(utf32,163,romanian,ci) \ + X(utf32,164,slovenian,ci) \ + X(utf32,165,polish,ci) \ + X(utf32,166,estonian,ci) \ + X(utf32,167,spanish,ci) \ + X(utf32,168,swedish,ci) \ + X(utf32,169,turkish,ci) \ + X(utf32,170,czech,ci) \ + X(utf32,171,danish,ci) \ + X(utf32,172,lithuanian,ci) \ + X(utf32,173,slovak,ci) \ + X(utf32,174,spanish2,ci) \ + X(utf32,175,roman,ci) \ + X(utf32,176,persian,ci) \ + X(utf32,177,esperanto,ci) \ + X(utf32,178,hungarian,ci) \ + X(utf32,179,sinhala,ci) \ + X(utf32,180,german2,ci) \ + X(utf32,181,croatian,ci) \ + X(utf32,182,unicode_520,ci) \ + X(utf32,183,vietnamese,ci) \ + +#define COLLATIONS_binary(X) \ + X(binary,63,bin,bin) \ + +#define COLLATIONS_geostd8(X) \ + X(geostd8,92,general,ci) \ + X(geostd8,93,bin,bin) \ + +#define COLLATIONS_cp932(X) \ + X(cp932,95,japanese,ci) \ + X(cp932,96,bin,bin) \ + +#define COLLATIONS_eucjpms(X) \ + X(eucjpms,97,japanese,ci) \ + X(eucjpms,98,bin,bin) \ + +#define COLLATIONS_gb18030(X) \ + X(gb18030,248,chinese,ci) \ + X(gb18030,249,bin,bin) \ + X(gb18030,250,unicode_520,ci) \ + + +#endif diff --git a/cdk/include/mysql/cdk/protocol/mysqlx_expr.h b/cdk/include/mysql/cdk/protocol/mysqlx/expr.h similarity index 93% rename from cdk/include/mysql/cdk/protocol/mysqlx_expr.h rename to cdk/include/mysql/cdk/protocol/mysqlx/expr.h index 5eb872bd0..b162f7170 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx_expr.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx/expr.h @@ -54,40 +54,22 @@ */ -#include "../foundation.h" -#include "../api/expression.h" -#include "../api/document.h" - -namespace cdk { -namespace protocol { -namespace mysqlx { - -// These are temporary type declarations -// TODO: remove when the types are defined - -typedef uint32_t stmt_id_t; -typedef uint32_t cursor_id_t; -typedef uint64_t row_count_t; -typedef uint32_t col_count_t; -// Note: protocol uses 64bit numbers for collation ids -typedef uint64_t charset_id_t; -typedef uint64_t insert_id_t; - -typedef int64_t sint64_t; -using ::uint64_t; - -}}} +#include "../../foundation.h" +#include "../../api/expression.h" +#include "../../api/document.h" +#include "traits.h" namespace cdk { namespace protocol { namespace mysqlx { -namespace api { using cdk::foundation::byte; using cdk::foundation::bytes; using cdk::foundation::string; +namespace api { + /* Any value (scalar, document or array) @@ -126,12 +108,12 @@ class Scalar_processor { public: - typedef protocol::mysqlx::charset_id_t charset_id_t; + typedef protocol::mysqlx::collation_id_t collation_id_t; virtual void null() =0; virtual void str(bytes) =0; - virtual void str(charset_id_t, bytes) =0; + virtual void str(collation_id_t, bytes) =0; virtual void num(int64_t) =0; virtual void num(uint64_t) =0; virtual void num(float) =0; @@ -248,7 +230,6 @@ class Doc_path { public: - enum Type { MEMBER = 1, MEMBER_ASTERISK = 2, @@ -281,7 +262,7 @@ struct Safe_prc typedef Safe_prc_base Base; using Base::Processor; - typedef Processor::charset_id_t charset_id_t; + typedef Processor::collation_id_t collation_id_t; Safe_prc(Processor *prc) : Base(prc) {} @@ -298,7 +279,7 @@ struct Safe_prc void str(bytes val) { return m_prc ? m_prc->str(val) : (void)NULL; } - void str(charset_id_t cs, bytes val) + void str(collation_id_t cs, bytes val) { return m_prc ? m_prc->str(cs, val) : (void)NULL; } void num(int64_t val) diff --git a/cdk/include/mysql/cdk/protocol/mysqlx/traits.h b/cdk/include/mysql/cdk/protocol/mysqlx/traits.h new file mode 100644 index 000000000..49c25733d --- /dev/null +++ b/cdk/include/mysql/cdk/protocol/mysqlx/traits.h @@ -0,0 +1,25 @@ + +#ifndef MYSQL_CDK_PROTOCOL_MYSQLX_TRAITS_H +#define MYSQL_CDK_PROTOCOL_MYSQLX_TRAITS_H + +namespace cdk { +namespace protocol { +namespace mysqlx { + +// These are temporary type declarations +// TODO: remove when the types are defined + +typedef uint32_t stmt_id_t; +typedef uint32_t cursor_id_t; +typedef uint64_t row_count_t; +typedef uint32_t col_count_t; +// Note: protocol uses 64bit numbers for collation ids +typedef uint64_t collation_id_t; +typedef uint64_t insert_id_t; + +typedef int64_t sint64_t; +using ::uint64_t; + +}}} + +#endif diff --git a/cdk/include/mysql/cdk/session.h b/cdk/include/mysql/cdk/session.h index 09fa3398d..932bb263e 100644 --- a/cdk/include/mysql/cdk/session.h +++ b/cdk/include/mysql/cdk/session.h @@ -29,15 +29,10 @@ #include "api/transaction.h" #include "data_source.h" #include "reply.h" -#include "mysqlx.h" +#include "common.h" namespace cdk { -using cdk::mysqlx::Param_source; -using cdk::mysqlx::Limit; -using cdk::mysqlx::Order_by; - - /* Session class @@ -63,7 +58,8 @@ class Session /// Create session to a data store represented by `ds` object. - Session(ds::TCPIP &ds, const ds::Options &options = ds::Options()); + Session(ds::TCPIP &ds, + const ds::TCPIP::Options &options = ds::TCPIP::Options()); ~Session(); @@ -75,7 +71,8 @@ class Session void close() { if (m_trans) rollback(); - return m_session->close(); + m_session->close(); + m_connection->close(); } /* @@ -269,6 +266,7 @@ class Session */ Reply_init coll_find(const api::Object_ref &coll, + const View_spec *view = NULL, const Expression *expr = NULL, const Expression::Document *proj = NULL, const Order_by *order_by = NULL, @@ -277,7 +275,7 @@ class Session const Limit *lim = NULL, const Param_source *param = NULL) { - return m_session->coll_find(coll, expr, proj, order_by, + return m_session->coll_find(coll, view, expr, proj, order_by, group_by, having, lim, param); } @@ -320,6 +318,7 @@ class Session */ Reply_init table_select(const api::Table_ref &tab, + const View_spec *view = NULL, const Expression *expr = NULL, const Projection *proj = NULL, const Order_by *order_by = NULL, @@ -328,7 +327,7 @@ class Session const Limit* lim = NULL, const Param_source *param = NULL) { - return m_session->table_select(tab, expr, proj, order_by, + return m_session->table_select(tab, view, expr, proj, order_by, group_by, having, lim, param); } @@ -387,6 +386,16 @@ class Session return m_session->table_update(tab, expr, us, order_by, lim, param); } + + // Views + // ----- + + Reply_init view_drop(const api::Table_ref &view, bool check_existence = false) + { + return m_session->view_drop(view, check_existence); + } + + // Async_op interface public: diff --git a/cdk/mysqlx/CMakeLists.txt b/cdk/mysqlx/CMakeLists.txt index 1647143e9..b05dcbe68 100644 --- a/cdk/mysqlx/CMakeLists.txt +++ b/cdk/mysqlx/CMakeLists.txt @@ -21,8 +21,6 @@ # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -cmake_minimum_required(VERSION 2.8) - SET(target_mysqlx ${cdk_target_prefix}mysqlx CACHE INTERNAL "CDK mysqlx target") # @@ -36,6 +34,7 @@ if(WIN32) endif() ADD_LIBRARY(${target_mysqlx} OBJECT session.cc result.cc auth_mysql41.cc) +ADD_COVERAGE(${target_mysqlx}) #TARGET_LINK_LIBRARIES(${target_mysqlx} ${target_proto_mysqlx}) diff --git a/cdk/mysqlx/converters.h b/cdk/mysqlx/converters.h index 7b127aea5..79384420b 100644 --- a/cdk/mysqlx/converters.h +++ b/cdk/mysqlx/converters.h @@ -26,9 +26,10 @@ #define CDK_MYSQLX_CONVERTERS_H #include -#include +#include #include + namespace cdk { namespace mysqlx { @@ -160,6 +161,53 @@ typedef Expr_conv_base< // ------------------------------------------------------------------------- +struct Doc_path_storage + : public cdk::Doc_path_storage + , public protocol::mysqlx::api::Doc_path +{ + typedef protocol::mysqlx::api::Doc_path Proto_path; + typedef cdk::Doc_path_storage Storage; + + // Proto_path interface + + unsigned length() const + { + size_t len = cdk::Doc_path_storage::length(); + assert(len <= std::numeric_limits::max()); + return (unsigned)len; + } + + Proto_path::Type get_type(unsigned pos) const + { + switch (get_el(pos).m_type) + { + case Storage::MEMBER: return Proto_path::MEMBER; + case Storage::MEMBER_ASTERISK: return Proto_path::MEMBER_ASTERISK; + case Storage::ARRAY_INDEX: return Proto_path::ARRAY_INDEX; + case Storage::ARRAY_INDEX_ASTERISK: return Proto_path::ARRAY_INDEX_ASTERISK; + case Storage::DOUBLE_ASTERISK: return Proto_path::DOUBLE_ASTERISK; + } + + // Quiet compile warning. + assert(false); + return Proto_path::Type(0); + } + + const cdk::string* get_name(unsigned pos) const + { + const Path_el &el = get_el(pos); + return Storage::MEMBER == el.m_type ? &el.m_name : NULL; + } + + const uint32_t* get_index(unsigned pos) const + { + const Path_el &el = get_el(pos); + return Storage::ARRAY_INDEX == el.m_type ? &el.m_idx : NULL; + } + +}; + + struct Expr_prc_converter_base; typedef Any_prc_converter Expr_prc_converter; @@ -204,7 +252,14 @@ struct Expr_prc_converter_base Args_prc* call(const api::Object_ref&); void ref(const api::Column_ref&, const Doc_path*); - void ref(const Doc_path &path) { m_proc->id(path); } + + void ref(const Doc_path &path) + { + Doc_path_storage dp; + path.process(dp); + m_proc->id(dp); + } + void param(const string &name) { m_proc->placeholder(name); } void param(uint16_t pos) { m_proc->placeholder(pos); } void var(const string &name) { m_proc->var(name); } @@ -302,7 +357,11 @@ Expr_prc_converter_base::ref(const api::Column_ref &col, const Doc_path *path) set_db_obj(*col.table()); const protocol::mysqlx::api::Db_obj *table= (col.table() ? this : NULL); if (NULL != path) - m_proc->id(col.name(), table, *path); + { + Doc_path_storage dp; + path->process(dp); + m_proc->id(col.name(), table, dp); + } else m_proc->id(col.name(), table); } diff --git a/cdk/mysqlx/delayed_op.h b/cdk/mysqlx/delayed_op.h index 123a720bc..898db31e4 100644 --- a/cdk/mysqlx/delayed_op.h +++ b/cdk/mysqlx/delayed_op.h @@ -26,9 +26,12 @@ #define CDK_MYSQLX_DELAYED_OP_H #include +#include #include #include "converters.h" +#include + namespace cdk { namespace mysqlx { @@ -109,6 +112,42 @@ class Proto_delayed_op }; +class Crud_op_base + : public Proto_delayed_op + , public protocol::mysqlx::api::Db_obj +{ +protected: + + string m_name; + string m_schema; + bool m_has_schema; + + Crud_op_base(Protocol &proto) + : Proto_delayed_op(proto) + , m_has_schema(false) + {} + + Crud_op_base(Protocol &proto, const api::Object_ref &obj) + : Proto_delayed_op(proto) + { + set(obj); + } + + void set(const api::Object_ref &obj) + { + m_name = obj.name(); + m_has_schema = (NULL != obj.schema()); + if (m_has_schema) + m_schema = obj.schema()->name(); + } + + // Db_obj + + const string& get_name() const { return m_name; } + const string* get_schema() const { return m_has_schema ? &m_schema : NULL; } + +}; + // ------------------------------------------------------------------------- @@ -143,14 +182,11 @@ class SndStmt class SndInsertDocs - : public Proto_delayed_op + : public Crud_op_base , public protocol::mysqlx::Row_source - , public protocol::mysqlx::api::Db_obj { protected: - const string m_schema; - const string m_table; cdk::Doc_source &m_docs; const Param_source *m_param; @@ -170,12 +206,10 @@ class SndInsertDocs public: - SndInsertDocs(Protocol& protocol, - const string &schema, const string &table, + SndInsertDocs(Protocol& protocol, const api::Table_ref &coll, cdk::Doc_source &docs, const Param_source *param) - : Proto_delayed_op(protocol) - , m_schema(schema), m_table(table) + : Crud_op_base(protocol, coll) , m_docs(docs) , m_param(param) {} @@ -201,10 +235,6 @@ class SndInsertDocs return m_docs.next(); } - // Db_obj - - const string& get_name() const { return m_table; } - const string* get_schema() const { return &m_schema; } }; @@ -212,14 +242,11 @@ class SndInsertDocs class SndInsertRows - : public Proto_delayed_op + : public Crud_op_base , public protocol::mysqlx::Row_source - , public protocol::mysqlx::api::Db_obj { protected: - const string m_schema; - const string m_table; Expr_converter m_conv; cdk::Row_source &m_rows; const api::Columns *m_cols; @@ -244,12 +271,11 @@ class SndInsertRows // TODO: Life-time of rows instance... SndInsertRows(Protocol& protocol, - const string &schema, const string &table, + const api::Table_ref &coll, cdk::Row_source &rows, const api::Columns *cols, const Param_source *param) - : Proto_delayed_op(protocol) - , m_schema(schema), m_table(table) + : Crud_op_base(protocol, coll) , m_rows(rows), m_cols(cols), m_param(param) {} @@ -269,10 +295,6 @@ class SndInsertRows return m_rows.next(); } - // Db_obj - - const string& get_name() const { return m_table; } - const string* get_schema() const { return &m_schema; } }; @@ -321,74 +343,98 @@ typedef Expr_conv_base< // ------------------------------------------------------------------------- +/* + Helper base class which implements protocol's Select_spec + (or Find_spec) interface. This is used by CRUD operations + which involve selecting a subset of rows/documents in the + table/colleciton. + + A CRUD operation class which derives from this Select_op_base + can be used as selection criteria specification as required + by protocol object methods. + + Note: This class uses converters to convert selection + parameters from generic cdk types to types required by + the protocol layer. +*/ -class SndDelete - : public Proto_delayed_op - , public Expression - , public protocol::mysqlx::api::Db_obj +template +class Select_op_base + : public Crud_op_base + , public IF { protected: - const string m_schema; - const string m_table; - const Expression *m_expr; - const Limit *m_limit; - const cdk::mysqlx::Order_by *m_order_by; - const Param_source *m_param; + Expr_converter m_expr_conv; + Param_converter m_param_conv; + Order_by_converter m_ord_conv; + const Limit *m_limit; + + + Select_op_base( + Protocol &protocol, + const api::Object_ref &obj, + const cdk::Expression *expr, + const cdk::Order_by *order_by, + const cdk::Limit *lim = NULL, + const cdk::Param_source *param = NULL + ) + : Crud_op_base(protocol, obj) + , m_expr_conv(expr), m_param_conv(param), m_ord_conv(order_by) + , m_limit(lim) + {} - const cdk::protocol::mysqlx::Data_model m_data_model; - Proto_op* start() - { - Expr_converter conv; - Param_converter param_conv; - Order_by_converter ord_conv; + virtual ~Select_op_base() + {} - if (m_order_by) - ord_conv.reset(*m_order_by); - if (m_expr) - conv.reset(*m_expr); + // Select_spec - if (m_param) - param_conv.reset(*m_param); + const protocol::mysqlx::api::Db_obj& obj() const { return *this; } - return &m_protocol.snd_Delete(m_data_model, - *this, - (m_expr ? &conv : NULL), - (m_order_by ? &ord_conv : NULL), - (cdk::protocol::mysqlx::api::Limit*)m_limit, - (m_param ? ¶m_conv : NULL)); + const protocol::mysqlx::api::Expression* select() const + { + return m_expr_conv.get(); } -public: + const protocol::mysqlx::api::Order_by* order() const + { + return m_ord_conv.get(); + } - SndDelete(Protocol& protocol, cdk::protocol::mysqlx::Data_model data_model, - const string &schema, const string &table, - const Expression *expr, - const Order_by *order_by, - const Limit *lim = NULL, - const Param_source *param = NULL) - : Proto_delayed_op(protocol) - , m_schema(schema), m_table(table) - , m_expr(expr), m_limit(lim) - , m_order_by(order_by), m_param(param) - , m_data_model(data_model) - {} + const protocol::mysqlx::api::Limit* limit() const + { + return m_limit; + } + +}; + + +// ------------------------------------------------------------------------- -private: - // Expression +template +class SndDelete + : public Select_op_base<> +{ +protected: - void process(Expression::Processor &ep) const + Proto_op* start() { - m_expr->process(ep); + return &m_protocol.snd_Delete(DM, *this, m_param_conv.get()); } - // Db_obj +public: + + SndDelete(Protocol& protocol, const api::Object_ref &obj, + const cdk::Expression *expr, + const cdk::Order_by *order_by, + const cdk::Limit *lim = NULL, + const cdk::Param_source *param = NULL) + : Select_op_base(protocol, obj, expr, order_by, lim, param) + {} - const string& get_name() const { return m_table; } - const string* get_schema() const { return &m_schema; } }; @@ -506,92 +552,307 @@ struct Find_traits }; +template class SndViewCrud; + + template class SndFind - : public Proto_delayed_op - , public protocol::mysqlx::api::Db_obj + : public Select_op_base { protected: typedef typename Find_traits::Projection Projection; typedef typename Find_traits::Projection_converter Projection_converter; - const string m_schema; - const string m_table; - const Expression *m_expr; - const Limit *m_limit; - const cdk::mysqlx::Order_by *m_order_by; - const Expr_list *m_group_by; - const Expression *m_having; - const Param_source *m_param; - const Projection *m_proj; + Projection_converter m_proj_conv; + Expr_list_converter m_group_by_conv; + Expr_converter m_having_conv; Proto_op* start() { - Expr_converter expr_conv; - Param_converter param_conv; - Order_by_converter ord_conv; - Projection_converter proj_conv; - Expr_converter having_conv; - Expr_list_converter group_by_conv; + return &m_protocol.snd_Find(DM, *this, m_param_conv.get()); + } - if (m_expr) - expr_conv.reset(*m_expr); +public: - if (m_param) - param_conv.reset(*m_param); + SndFind( + Protocol& protocol, const api::Table_ref &coll, + const cdk::Expression *expr = NULL, + const Projection *proj = NULL, + const cdk::Order_by *order_by = NULL, + const cdk::Expr_list *group_by = NULL, + const cdk::Expression *having = NULL, + const cdk::Limit *lim = NULL, + const cdk::Param_source *param = NULL + ) + : Select_op_base(protocol, coll, expr, order_by, lim, param) + , m_proj_conv(proj) + , m_group_by_conv(group_by), m_having_conv(having) + {} - if (m_order_by) - ord_conv.reset(*m_order_by); +private: - if (m_group_by) - group_by_conv.reset(*m_group_by); + const protocol::mysqlx::api::Projection* project() const + { + return m_proj_conv.get(); + } - if (m_having) - having_conv.reset(*m_having); + const protocol::mysqlx::api::Expr_list* group_by() const + { + return m_group_by_conv.get(); + } + + const protocol::mysqlx::api::Expression* having() const + { + return m_having_conv.get(); + } - if (m_proj) - proj_conv.reset(*m_proj); + friend class SndViewCrud; +}; - return &m_protocol.snd_Find(DM, *this, - (m_expr ? &expr_conv : NULL), - (m_proj ? &proj_conv : NULL), - (m_order_by ? &ord_conv : NULL), - (m_group_by ? &group_by_conv : NULL), - (m_having ? &having_conv : NULL), - (cdk::protocol::mysqlx::api::Limit*)m_limit, - (m_param ? ¶m_conv : NULL)); + +// ------------------------------------------------------------------------- + +/* + Conversion from string processor used to process a list of view column names + to callbacks expected by protocol's column info processor. + Basically, each string in a list is reported as column name. Other column + specification parameters, such as alias, are not reported. +*/ + +struct String_to_col_prc_converter + : public Converter< + String_to_col_prc_converter, + cdk::api::String_processor, + cdk::protocol::mysqlx::api::Columns::Processor::Element_prc + > +{ + void val(const string &col) + { + m_proc->name(col); + } + + virtual ~String_to_col_prc_converter() + {} +}; + +typedef List_prc_converter Columns_prc_converter; + + +/* + Delayed operation which sends view create or update request. These request + can include a find message. Whether update or create request should be sent + is determined by the view specification passed when creating this delayed + operation. +*/ + +template +class SndViewCrud + : public Crud_op_base + , public View_spec::Processor + , public cdk::protocol::mysqlx::api::Columns + , public protocol::mysqlx::api::View_options +{ + const View_spec *m_view; + SndFind *m_find; + View_spec::op_type m_type; + bool m_has_cols; + bool m_has_opts; + + // Columns + + void process(cdk::protocol::mysqlx::api::Columns::Processor &prc) const + { + assert(m_view); + + /* + Column names are reported to the protocol layer as column specification + (as used by snd_Insert() for example). We use processor converter to convert + string list processor callbacks to these of Columns specification + processor. + */ + + Columns_prc_converter conv; + conv.reset(prc); + + /* + Process view specification extracting columns information and passing + it to the converter. + */ + + struct : public cdk::View_spec::Processor + { + String_list::Processor *m_prc; + + void name(const Table_ref&, op_type) {} + + Options::Processor* options() + { + return NULL; + } + + List_processor* columns() + { + return m_prc; + } + + } + vprc; + + vprc.m_prc = &conv; + m_view->process(vprc); + } + + protocol::mysqlx::api::Columns* + get_cols() + { + return m_has_cols ? this : NULL; + } + + // View_options + + void process(protocol::mysqlx::api::View_options::Processor &prc) const + { + assert(m_view); + + /* + Process view specification extracting options information and passing + it to the processor. + */ + + struct Opts : public cdk::View_spec::Processor + { + Options::Processor *m_prc; + + void name(const Table_ref&, op_type) + {} + + Options::Processor* options() + { + return m_prc; + } + + List_processor* columns() + { + return NULL; + } + } + vprc; + + vprc.m_prc = &prc; + m_view->process(vprc); + } + + protocol::mysqlx::api::View_options* + get_opts() + { + return m_has_opts ? this : NULL; + } + + const protocol::mysqlx::api::Args_map* + get_args() + { + return m_find->m_param_conv.get(); + } + + + Proto_op* start() + { + switch (m_type) + { + case CREATE: + case REPLACE: + return &m_protocol.snd_CreateView(DM, *this, *m_find, + get_cols(), REPLACE == m_type, + get_opts(), get_args()); + + case UPDATE: + return &m_protocol.snd_ModifyView(DM, *this, *m_find, + get_cols(), get_opts(), + m_find->m_param_conv.get()); + default: + assert(false); + return NULL; // quiet compile warnings + } } public: - SndFind(Protocol& protocol, - const string &schema, const string &table, - const Expression *expr = NULL, - const Projection *proj = NULL, - const cdk::mysqlx::Order_by *order_by = NULL, - const Expr_list *group_by = NULL, - const Expression *having = NULL, - const Limit *lim = NULL, - const Param_source *param = NULL) - : Proto_delayed_op(protocol) - , m_schema(schema), m_table(table) - , m_expr(expr), m_limit(lim), m_order_by(order_by) - , m_group_by(group_by), m_having(having) - , m_param(param), m_proj(proj) - {} + SndViewCrud(const View_spec &view, SndFind *find = NULL) + : Crud_op_base(find->m_protocol) + , m_view(&view), m_find(find), m_type(CREATE) + , m_has_cols(false), m_has_opts(false) + { + /* + Process view specification to extract view name and information which + type of view operation should be sent (m_update member). This also + determines whether columns and options information is present in the + specification. + */ + view.process(*this); + } + + ~SndViewCrud() + { + delete m_find; + } private: - // Db_obj + // View_spec::Processor + + void name(const Table_ref &view, View_spec::op_type type) + { + Crud_op_base::set(view); + m_type = type; + } + + List_processor* columns() + { + m_has_cols = true; + /* + Note: we do not process columns here, it is done above when this + object acts as protocol Columns specification. + */ + return NULL; + } + + Options::Processor* options() + { + m_has_opts = true; + return NULL; + } + +}; + + +class SndDropView + : public Crud_op_base +{ + bool m_check_exists; + + Proto_op* start() + { + return &m_protocol.snd_DropView(*this, m_check_exists); + } + +public: + + SndDropView( + Protocol &protocol, + const api::Object_ref &view, + bool check_exists + ) + : Crud_op_base(protocol, view) + , m_check_exists(check_exists) + {} - const string& get_name() const { return m_table; } - const string* get_schema() const { return &m_schema; } }; // ------------------------------------------------------------------------- + /* Update_converter */ @@ -671,8 +932,7 @@ class Update_prc_converter virtual void remove(const Doc_path *path) { - if (path) - m_proc->target_path(*path); + report_path(path); m_proc->update_op(protocol::mysqlx::update_op::ITEM_REMOVE); } @@ -685,9 +945,7 @@ class Update_prc_converter { Prc_to::Expr_prc *prc; - if (path) - m_proc->target_path(*path); - + report_path(path); if (flags & Update_processor::NO_INSERT) prc = m_proc->update_op(protocol::mysqlx::update_op::ITEM_REPLACE); @@ -700,7 +958,6 @@ class Update_prc_converter prc = m_proc->update_op(path ? protocol::mysqlx::update_op::ITEM_SET : protocol::mysqlx::update_op::SET); - if (!prc) return NULL; @@ -711,8 +968,7 @@ class Update_prc_converter Expr_prc* array_insert(const Doc_path *path) { - if (path) - m_proc->target_path(*path); + report_path(path); Prc_to::Expr_prc *prc = m_proc->update_op(protocol::mysqlx::update_op::ARRAY_INSERT); @@ -726,8 +982,7 @@ class Update_prc_converter Expr_prc* array_append(const Doc_path *path) { - if (path) - m_proc->target_path(*path); + report_path(path); Prc_to::Expr_prc *prc = m_proc->update_op(protocol::mysqlx::update_op::ARRAY_APPEND); @@ -739,6 +994,16 @@ class Update_prc_converter return &m_conv; } + void report_path(const Doc_path *path) + { + if (path) + { + Doc_path_storage dp; + path->process(dp); + if (!dp.is_empty()) + m_proc->target_path(dp); + } + } }; @@ -768,66 +1033,30 @@ class Update_converter template class SndUpdate - : public Proto_delayed_op - , public protocol::mysqlx::api::Db_obj + : public Select_op_base<> { protected: - const string m_schema; - const string m_table; - const Expression *m_expr; - const Update_spec &m_us; - const cdk::mysqlx::Order_by *m_order_by; - const Limit *m_limit; - const Param_source *m_param; + Update_converter m_upd_conv; Proto_op* start() { - Expr_converter conv; - Param_converter param_conv; - Order_by_converter ord_conv; - - if (m_expr) - conv.reset(*m_expr); - - if (m_param) - param_conv.reset(*m_param); - - if (m_order_by) - ord_conv.reset(*m_order_by); - - Update_converter u_conv(DM, m_us); - - return &m_protocol.snd_Update(DM, - *this, - (m_expr ? &conv : NULL), - u_conv, - (m_order_by ? &ord_conv : NULL), - const_cast(m_limit), - (m_param ? ¶m_conv : NULL)); + return &m_protocol.snd_Update(DM, *this, m_upd_conv, m_param_conv.get()); } public: SndUpdate(Protocol& protocol, - const string &schema, const string &table, - const Expression *expr, - const Update_spec &us, - const Order_by *order_by, - const Limit *lim = NULL, - const Param_source *param = NULL) - : Proto_delayed_op(protocol) - , m_schema(schema), m_table(table) - , m_expr(expr), m_us(us), m_order_by(order_by), m_limit(lim), m_param(param) + const api::Table_ref &table, + const cdk::Expression *expr, + const cdk::Update_spec &us, + const cdk::Order_by *order_by, + const cdk::Limit *lim = NULL, + const cdk::Param_source *param = NULL) + : Select_op_base(protocol, table, expr, order_by, lim, param) + , m_upd_conv(DM, us) {} -private: - - - // Db_obj - - const string& get_name() const { return m_table; } - const string* get_schema() const { return &m_schema; } }; diff --git a/cdk/mysqlx/result.cc b/cdk/mysqlx/result.cc index 7520aa000..3fec640a4 100644 --- a/cdk/mysqlx/result.cc +++ b/cdk/mysqlx/result.cc @@ -63,7 +63,7 @@ void Reply::init(Reply_init &init) init.register_reply(this); m_session->send_cmd(); - m_session->start_reading_row_set(); + m_session->start_reading_result(); } @@ -563,7 +563,9 @@ void Cursor::done(bool eod, bool more) if (more) { - m_session.start_reading_row_set(); + // TODO: Normally start_reading_result() accepts OK message from + // server, but here it should not. + m_session.start_reading_result(); } else if (eod) { diff --git a/cdk/mysqlx/session.cc b/cdk/mysqlx/session.cc index 7817e7903..395edd069 100644 --- a/cdk/mysqlx/session.cc +++ b/cdk/mysqlx/session.cc @@ -334,10 +334,12 @@ void Session::rollback() } -Reply_init& Session::coll_add(const Table_ref &coll, Doc_source &docs, const Param_source *param) +Reply_init& Session::coll_add(const Table_ref &coll, + Doc_source &docs, + const Param_source *param) { return set_command( - new SndInsertDocs(m_protocol, coll.schema()->name(), coll.name(), docs, param) + new SndInsertDocs(m_protocol, coll, docs, param) ); } @@ -348,12 +350,14 @@ Reply_init& Session::coll_remove(const Table_ref &coll, const Param_source *param) { return set_command( - new SndDelete(m_protocol, protocol::mysqlx::DOCUMENT, - coll.schema()->name(), coll.name(), expr,order_by, lim, param) + new SndDelete( + m_protocol, coll, expr,order_by, lim, param + ) ); } Reply_init& Session::coll_find(const Table_ref &coll, + const View_spec *view, const Expression *expr, const Expression::Document *proj, const Order_by *order_by, @@ -362,11 +366,16 @@ Reply_init& Session::coll_find(const Table_ref &coll, const Limit *lim, const Param_source *param) { - return set_command( - new SndFind(m_protocol, - coll.schema()->name(), coll.name(), expr, - proj, order_by, group_by, having, lim, param) - ); + SndFind *find + = new SndFind( + m_protocol, coll, expr, proj, order_by, + group_by, having, lim, param + ); + + if (view) + return set_command(new SndViewCrud(*view, find)); + + return set_command(find); } Reply_init& Session::coll_update(const api::Table_ref &coll, @@ -377,14 +386,9 @@ Reply_init& Session::coll_update(const api::Table_ref &coll, const Param_source *param) { return set_command( - new SndUpdate(m_protocol, - coll.schema()->name(), - coll.name(), - expr, - us, - order_by, - lim, - param) + new SndUpdate( + m_protocol, coll, expr, us, order_by, lim, param + ) ); } @@ -392,7 +396,7 @@ Reply_init& Session::table_insert(const Table_ref &coll, Row_source &rows, const api::Columns *cols, const Param_source *param) { return set_command( - new SndInsertRows(m_protocol, coll.schema()->name(), coll.name(), rows, cols, param) + new SndInsertRows(m_protocol, coll, rows, cols, param) ); } @@ -403,13 +407,14 @@ Reply_init& Session::table_delete(const Table_ref &coll, const Param_source *param) { return set_command( - new SndDelete(m_protocol, protocol::mysqlx::TABLE, - coll.schema()->name(), coll.name(), - expr, order_by, lim, param) + new SndDelete( + m_protocol, coll, expr, order_by, lim, param + ) ); } Reply_init& Session::table_select(const Table_ref &coll, + const View_spec *view, const Expression *expr, const Projection *proj, const Order_by *order_by, @@ -418,11 +423,16 @@ Reply_init& Session::table_select(const Table_ref &coll, const Limit *lim, const Param_source *param) { - return set_command( - new SndFind(m_protocol, - coll.schema()->name(), coll.name(), expr, proj, - order_by, group_by, having, lim, param) - ); + SndFind *find + = new SndFind( + m_protocol, coll, expr, proj, order_by, + group_by, having, lim, param + ); + + if (view) + return set_command(new SndViewCrud(*view, find)); + + return set_command(find); } Reply_init& Session::table_update(const api::Table_ref &coll, @@ -433,18 +443,22 @@ Reply_init& Session::table_update(const api::Table_ref &coll, const Param_source *param) { return set_command( - new SndUpdate(m_protocol, - coll.schema()->name(), - coll.name(), - expr, - us, - order_by, - lim, - param) + new SndUpdate( + m_protocol, coll, expr, us, order_by, lim, param + ) ); } +Reply_init& Session::view_drop(const api::Table_ref &view, bool check_existence) +{ + return set_command( + new SndDropView(m_protocol, view, check_existence) + ); +} + + + Reply_init &Session::set_command(Proto_op *cmd) { if (!is_valid()) @@ -551,6 +565,10 @@ void Session::add_diagnostics(Severity::value level, unsigned code, } +void Session::ok(string) +{} + + void Session::col_count(col_count_t nr_cols) { //When all columns metadata arrived... @@ -627,7 +645,7 @@ void Session::col_schema(col_count_t pos, } -void Session::col_charset(col_count_t pos, charset_id_t cs) +void Session::col_collation(col_count_t pos, collation_id_t cs) { if (m_discard) return; @@ -714,7 +732,7 @@ void Session::send_cmd() } -void Session::start_reading_row_set() +void Session::start_reading_result() { m_col_metadata.reset(new Mdata_storage()); m_executed = false; diff --git a/cdk/parser/CMakeLists.txt b/cdk/parser/CMakeLists.txt index 902122345..1bcf1ce8d 100644 --- a/cdk/parser/CMakeLists.txt +++ b/cdk/parser/CMakeLists.txt @@ -32,3 +32,5 @@ add_library(${target_parser} OBJECT json_parser.cc expr_parser.cc uri_parser.cc) + +add_coverage(${target_parser}) diff --git a/cdk/parser/expr_parser.cc b/cdk/parser/expr_parser.cc index 08942117d..11464b6db 100644 --- a/cdk/parser/expr_parser.cc +++ b/cdk/parser/expr_parser.cc @@ -143,8 +143,7 @@ Expression::Processor* ignore_if(Expression::Processor *prc) bool Expr_parser_base::do_parse(It &first, const It &last, Processor *prc) { - Token_op_base::m_first = &first; - Token_op_base::m_last = last; + Token_op_base::set_tokens(first, last); /* if prc is NULL, ignore the parsed expression instead of storing it @@ -372,33 +371,50 @@ Expr_parser_base::parse_function_call(const cdk::api::Table_ref &func, Scalar_pr is rewritten as: columnIdent ::= schemaQualifiedIdent columnIdent1 - columnIdent1 ::= ('.' ident)? ('->' ( columnIdentDocPath | "'" columnIdentDocPath "'" ))? + columnIdent1 ::= ('.' ident)? ('->' ( columnIdentDocPath + | "'" columnIdentDocPath "'" ))? columnIdentDocPath ::= documentField // but require DOLLAR prefix */ -void Expr_parser_base::parse_schema_ident() +/* + Parse a schema-qualified identifier and store it as table/schema + name of m_col_ref member. Schema name is optional. + + If types is not NULL then types of the consumed tokens are stored in this + array. +*/ + +void Expr_parser_base::parse_schema_ident(Token::TokenType (*types)[2]) { + if (types) + { + (*types)[0] = peek_token().get_type(); + // Reset the other entry in case we are not looking at more tokens. + (*types)[1] = Token::TokenType(0); + } const cdk::string &name = get_ident(); + m_col_ref.m_table_ref.set(name); + if (cur_token_type_is(Token::DOT)) { consume_token(Token::DOT); + if (types) + (*types)[1] = peek_token().get_type(); m_col_ref.m_table_ref.set(get_ident(), name); } - else - m_col_ref.m_table_ref.set(name); } -void Expr_parser_base::parse_column_ident() +void Expr_parser_base::parse_column_ident(Path_prc *prc) { parse_schema_ident(); - parse_column_ident1(); + parse_column_ident1(prc); } -void Expr_parser_base::parse_column_ident1() +void Expr_parser_base::parse_column_ident1(Path_prc *prc) { if (cur_token_type_is(Token::DOT)) { @@ -417,9 +433,6 @@ void Expr_parser_base::parse_column_ident1() m_col_ref.set(m_col_ref.table()->name()); } - // Clear Document path - m_path.clear(); - if (cur_token_type_is(Token::ARROW)) { consume_token(Token::ARROW); @@ -432,14 +445,13 @@ void Expr_parser_base::parse_column_ident1() It last = toks.end(); Expr_parser_base path_parser(first, last, m_parser_mode); // TODO: Translate parse errors - path_parser.parse_document_field(true); + path_parser.parse_document_field(prc, true); if (first != last) throw Error("Invalid quotted path component"); - m_path = path_parser.m_path; } else { - parse_document_field(); + parse_document_field(prc, true); } } @@ -450,63 +462,77 @@ void Expr_parser_base::parse_column_ident1() /** + The original grammar was: + documentField ::= ID documentPath? | DOLLAR documentPath + + Which makes "*", "**.foo" or "*.foo" not valid field specifications + while "$[3]" is a valid specification. + + We modify the grammar so that "$[..]" is not valid while "*.." or "**.." + are valid: + + documentField ::= + | DOLLAR documentPathLeadingDot + | documentPath + + The grammar of documentPath was adjusted so that the first + path item can not be an array item ("[n]" or "[*]") and we can request + a leading DOT before member items (see parse_document_path()). + + If prefix is true, only the first form starting with DOLLAR prefix is + accepted. */ -void Doc_path_parser_base::parse_document_field() +void Expr_parser_base::parse_document_field(Path_prc *prc, bool prefix) { - //Clear Doc_path obj - m_path.clear(); - if (cur_token_type_is(Token::DOLLAR)) { consume_token(Token::DOLLAR); - - } else if (!cur_token_type_is(Token::DOT) && - !cur_token_type_is(Token::LSQBRACKET) && - !cur_token_type_is(Token::DOUBLESTAR)) - { - /* - Special case, starting with MEMBER - - On this case, we check if documentPath starts with DOT, LSQBRACKET or - DOUBLESTAR. If not, it is parsed as ID - */ - - parse_docpath_member(); + if (!parse_document_path(prc, true)) // require DOT before members + throw_error("Document path expected"); + return; } - parse_document_path(false); + if (prefix) + throw_error("Expected DOLLAR to start a document path"); + + if (!parse_document_path(prc, false)) + throw_error("Document path expected"); } -/** - documentField ::= ID documentPath? | DOLLAR documentPath - If prefix is true, only second form starting with DOLLAR prefix is - accepted. +/* + Parse a document field path with a given initial member segment. */ -void Expr_parser_base::parse_document_field(bool prefix) +void Expr_parser_base::parse_document_field(const string &first, Path_prc *prc) { - if (cur_token_type_is(Token::ID) && !prefix) - { - return parse_document_path(consume_token(Token::ID)); - } + Safe_prc sprc = prc; - if (cur_token_type_is(Token::DOLLAR)) - { - consume_token(Token::DOLLAR); - return parse_document_path(); - } + sprc->list_begin(); + sprc->list_el()->member(first); + parse_document_path1(prc); + sprc->list_end(); +} +/* + Parse a document field path with given 2 initial member segment. +*/ +void Expr_parser_base::parse_document_field(const string &first, + const string &second, + Path_prc *prc) +{ + Safe_prc sprc = prc; - throw Error( - (boost::format("Expr parser: Expected token type IDENT or DOLLAR in JSON path" - " at token pos %d") % get_token_pos()).str()); + sprc->list_begin(); + sprc->list_el()->member(first); + sprc->list_el()->member(second); + parse_document_path1(prc); + sprc->list_end(); } - /** Original Grammar: @@ -526,92 +552,247 @@ void Expr_parser_base::parse_document_field(bool prefix) ID | STRING1 - This grammar has been re-written to equivalent one + This grammar has few flaws: + + 1. It allows a document path to start with array location, which is not + correct - array locations should be possible only after a path to some + array member. + + 2. It always requires a DOT befre a member element, but in some contexts + we want a document path like "foo.bar.baz" to start without a dot. + + To deal with this the grammar has been changed and require_dot parameter + has been added. Modified grammar: + + documentPath ::= documentPathFirstItem documentPathItem* - documentPath ::= documentPathItem+ + documentPathFirstItem ::= + | DOT? documentPathMember + | DOUBLESTAR documentPathItem ::= - | DOUBLESTAR - | LSQBRACKET documentPathArrayLoc RSQBRACKET - | DOT MUL - | DOT documentPathMember + | DOT documentPathMember + | DOUBLESTAR + | documentPathArray + + documentPathMember ::= + | MUL + | ID + | STRING1 + + docuemntPathArray ::= LSQBRACKET documentPathArrayLoc RSQBRACKET documentPathArrayLoc ::= - | MUL - | INT + | MUL + | INT - documentPathMember ::= - ID - | STRING1 + Parameter require_dot tells if the initial dot is required or not. - A check that DOUBLESTAR is not last element of a path is done separately. + A check that DOUBLESTAR is not last element of a path is done separately. - */ + Returns true if a valid document path was parsed and reported, false if the + current token did not start a valid document path. + + Note: If false is returned then nothing is reported to the processor (not + even an empty list). +*/ -void Doc_path_parser_base::parse_document_path(bool clear) +bool Expr_parser_base::parse_document_path(Path_prc *prc, bool require_dot) { - if (clear) - m_path.clear(); + /* + Below we call methods like parse_docpath_member() which expect a document + path element processor. Our path processor prc is a list processor. So, + before we report the first path element we must call prc->list_begin() and + prc->list_el(). The problem is that when calling parse_docpath_member() + we might not know yet if there is any path to report or not -- only inside + parse_docpath_member() it will become evident. + + The Path_el_reporter wrapper around path processor solves this problem by + deffering the initial list_begin() call and the list_el() calls to the + moment when a path element is reported. If no path elements are reported + then list_begin() or list_el() will not be called. Similar, call to + list_end() will be forwarded to the wrapped processor only if list_begin() + was called before. + */ - while (true) + struct Path_el_reporter + : public Path_prc + , public Path_prc::Element_prc { - if (cur_token_type_is(Token::DOT)) + Safe_prc m_prc; + bool m_started; + + void list_begin() { - consume_token(Token::DOT); - if (cur_token_type_is(Token::MUL)) - { - consume_token(Token::MUL); - m_path.add(Doc_path::MEMBER_ASTERISK); - } - else - { - parse_docpath_member(); - } + if (!m_started) + m_prc->list_begin(); + m_started = true; } - else if (cur_token_type_is(Token::LSQBRACKET)) + + void list_end() { - consume_token(Token::LSQBRACKET); - parse_docpath_array_loc(); - consume_token(Token::RSQBRACKET); + if (m_started) + m_prc->list_end(); } - else if (cur_token_type_is(Token::DOUBLESTAR)) + + Element_prc* list_el() { - consume_token(Token::DOUBLESTAR); - m_path.add(Doc_path::DOUBLE_ASTERISK); + return this; } - else + + // Element_prc + + void member(const string &name) { - break; + list_begin(); + m_prc->list_el()->member(name); + } + + void any_member() + { + list_begin(); + m_prc->list_el()->any_member(); + } + + void index(index_t ind) + { + list_begin(); + m_prc->list_el()->index(ind); } + + void any_index() + { + list_begin(); + m_prc->list_el()->any_index(); + } + + void any_path() + { + list_begin(); + m_prc->list_el()->any_path(); + } + + Path_el_reporter(Path_prc *prc) + : m_prc(prc), m_started(false) + {} } - unsigned int size = m_path.length(); - if (size > 0 && (m_path.get_type(size - 1) == Doc_path::DOUBLE_ASTERISK)) + el_reporter(prc); + + // documentPathFirstItem + + bool double_star = false; + + if (cur_token_type_is(Token::DOUBLESTAR)) { - throw Error((boost::format("Expr parser: JSON path may not end in '**' at %d") % get_token_pos()).str()); + consume_token(Token::DOUBLESTAR); + double_star = true; + el_reporter.any_path(); + } + else + { + if (cur_token_type_is(Token::DOT)) + { + consume_token(Token::DOT); + if (!parse_docpath_member(&el_reporter)) + unexpected_token(peek_token(), "Document path"); + } + else if (require_dot) + { + return false; + } + else + { + if (!parse_docpath_member(&el_reporter)) + return false; + } } -} -void Doc_path_parser_base::parse_document_path(const cdk::string &first) -{ - m_path.clear(); - m_path.add(Doc_path::MEMBER, first); - parse_document_path(false); + // the rest of the path + + bool ret = parse_document_path1(&el_reporter); + + if (!ret && double_star) + throw_error("Document path ending in '**'"); + + el_reporter.list_end(); + + return true; } -void Doc_path_parser_base::parse_document_path(const cdk::string &first, - const cdk::string &second) + +/* + Parse a reminder of a document path after the first item, that is, a possibly + empty sequence of documentPathItem strings. + + The items are reported to the given Path_prc without calling list_begin() or + list_end() (which is assumed to be done by the caller). + + Returns true if at least one path item component was parsed. +*/ + +bool Expr_parser_base::parse_document_path1(Path_prc *prc) { - m_path.clear(); - m_path.add(Doc_path::MEMBER, first); - m_path.add(Doc_path::MEMBER, second); - parse_document_path(false); + Safe_prc sprc = prc; + + /* + These Booleans are used to detect if we are at the beginning of the path + and if there was a "**" component at the end of it. + */ + + bool double_star; + bool last_double_star = false; + bool has_item = false; + + for (double_star = false; true; + last_double_star =double_star, + double_star =false, + has_item = true) + { + if (!tokens_available()) + break; + + const Token &t = peek_token(); + + switch (t.get_type()) + { + case Token::DOT: + consume_token(Token::DOT); + if (!parse_docpath_member(sprc->list_el())) + unexpected_token(peek_token(), + "when looking for a document path element"); + continue; + + case Token::DOUBLESTAR: + consume_token(Token::DOUBLESTAR); + sprc->list_el()->any_path(); + double_star = true; + continue; + + case Token::LSQBRACKET: + consume_token(Token::LSQBRACKET); + parse_docpath_array_loc(sprc->list_el()); + consume_token(Token::RSQBRACKET); + continue; + + default: + break; + } + + break; + } + + if (last_double_star) + throw_error("Document path ending in '**'"); + + return has_item; } /** documentPathMember ::= - ID - | STRING1 + | MUL + | ID + | STRING1 TODO: Does STRING1 differ from plain STRING in any way? @@ -619,27 +800,37 @@ void Doc_path_parser_base::parse_document_path(const cdk::string &first, are otherwise treated by tokenizer as reserved, are treated as normal identifiers. */ -void Doc_path_parser_base::parse_docpath_member() +bool Expr_parser_base::parse_docpath_member(Path_prc::Element_prc *prc) { - const Token &t = get_token(); + const Token &t = peek_token(); switch (t.get_type()) { + case Token::MUL: + if (prc) + prc->any_member(); + break; + case Token::ID: case Token::LSTRING: - - m_path.add(Doc_path::MEMBER, t.get_text()); + if (prc) + prc->member(t.get_text()); break; default: if (t.is_reserved_word()) - m_path.add(Doc_path::MEMBER, t.get_text()); - else - throw Error( - (boost::format("Expr parser: Expected token type IDENT or LSTRING in JSON path" - " at token pos %d") % get_token_pos()).str()); + { + if (prc) + prc->member(t.get_text()); + break; + } + + return false; } + + get_token(); // consume the token + return true; } @@ -648,18 +839,20 @@ void Doc_path_parser_base::parse_docpath_member() MUL | INT */ -void Doc_path_parser_base::parse_docpath_array_loc() +void Expr_parser_base::parse_docpath_array_loc(Path_prc::Element_prc *prc) { if (cur_token_type_is(Token::MUL)) { consume_token(Token::MUL); - m_path.add(Doc_path::ARRAY_INDEX_ASTERISK); + if (prc) + prc->any_index(); } else if (cur_token_type_is(Token::LINTEGER)) { const std::string& value = consume_token(Token::LINTEGER); uint32_t v = boost::lexical_cast(value.c_str(), value.size()); - m_path.add(Doc_path::ARRAY_INDEX, v); + if (prc) + prc->index(v); } else { @@ -675,6 +868,70 @@ void Doc_path_parser_base::parse_docpath_array_loc() // ------------------------------------------------------------------------- +bool column_ref_from_path(cdk::Doc_path &path, parser::Column_ref &column) +{ + struct Path_prc + : public cdk::Doc_path::Processor + , public cdk::Doc_path::Processor::Element_prc + { + unsigned m_len; + parser::Column_ref &m_col; + bool m_ret; + + Element_prc* list_el() + { + return this; + } + + void member(const string &name) + { + switch (m_len++) + { + case 0: m_col.set(name); break; + case 1: m_col.set(name, m_col.name()); break; + case 2: + assert(m_col.table()); + m_col.m_table_ref.set(m_col.name(), m_col.table()->name()); + m_col.set_name(name); + break; + default: + // Too many path elements + m_ret = false; + } + } + + void index(uint32_t) + { + m_ret = false; + } + + void any_member() + { + m_ret = false; + } + + void any_index() + { + m_ret = false; + } + + void any_path() + { + m_ret = false; + } + + Path_prc(parser::Column_ref &col) + : m_len(0), m_col(col), m_ret(true) + {} + } + prc(column); + + path.process(prc); + + return prc.m_ret; +} + + /** atomicExpr ::= placeholder @@ -720,25 +977,25 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) switch (type) { - // jsonDOC + // jsonDOC case Token::LCURLY: return parse(DOC, prc); - // array + // array case Token::LSQBRACKET: return parse(ARR, prc); - // groupedExpr + // groupedExpr case Token::LPAREN: - { - consume_token(Token::LPAREN); - Expression *res = parse(FULL,prc); - consume_token(Token::RPAREN); - return res; - } + { + consume_token(Token::LPAREN); + Expression *res = parse(FULL, prc); + consume_token(Token::RPAREN); + return res; + } default: break; } @@ -764,28 +1021,28 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) switch (type) { - // placeholder + // placeholder case Token::COLON: consume_token(Token::COLON); safe_prc(prc)->scalar()->param(consume_token(Token::ID)); return stored.release(); - // castOp + // castOp case Token::CAST: parse_cast(prc->scalar()); return stored.release(); - // nullary "*" + // nullary "*" case Token::MUL: - { - consume_token(Token::MUL); - safe_prc(prc)->scalar()->op("*"); - // NOTE: arguments processor is ignored as there are no arguments - return stored.release(); - } + { + consume_token(Token::MUL); + safe_prc(prc)->scalar()->op("*"); + // NOTE: arguments processor is ignored as there are no arguments + return stored.release(); + } default: break; } @@ -799,36 +1056,36 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) switch (type) { - case Token::PLUS: - case Token::MINUS: - { - const Token &t = get_token(); - type = peek_token().get_type(); - if (Token::LNUM == type || Token::LINTEGER == type) { - // treat as numeric literal with possibly negated value - neg = (Token::MINUS == t.get_type()); - break; - } - // otherwise report as unary operator - argsp = sprc->op(operator_name(t.get_text()).c_str()); - break; - } + case Token::PLUS: + case Token::MINUS: + { + const Token &t = get_token(); + type = peek_token().get_type(); + if (Token::LNUM == type || Token::LINTEGER == type) { + // treat as numeric literal with possibly negated value + neg = (Token::MINUS == t.get_type()); + break; + } + // otherwise report as unary operator + argsp = sprc->op(operator_name(t.get_text()).c_str()); + break; + } - case Token::BANG: + case Token::BANG: get_token(); argsp = sprc->op(operator_name("!").c_str()); break; - case Token::NOT: + case Token::NOT: get_token(); argsp = sprc->op(operator_name("not").c_str()); break; - case Token::NEG: + case Token::NEG: get_token(); argsp = sprc->op(operator_name("~").c_str()); break; - default: - break; // will continue with literal parsing + default: + break; // will continue with literal parsing } // Report the single argument of the unary operator @@ -845,20 +1102,20 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) switch (peek_token().get_type()) { - case Token::LSTRING: - if (m_strings_as_blobs) - sprc->val()->value(cdk::TYPE_BYTES, Format_info(), - cdk::bytes(get_token().get_text())); - else - sprc->val()->str(get_token().get_text()); - return stored.release(); + case Token::LSTRING: + if (m_strings_as_blobs) + sprc->val()->value(cdk::TYPE_BYTES, Format_info(), + cdk::bytes(get_token().get_text())); + else + sprc->val()->str(get_token().get_text()); + return stored.release(); - case Token::T_NULL: - sprc->val()->null(); - get_token(); - return stored.release(); + case Token::T_NULL: + sprc->val()->null(); + get_token(); + return stored.release(); - case Token::LNUM: + case Token::LNUM: try { double val = boost::lexical_cast(get_token().get_text()); sprc->val()->num(neg ? -val : val); @@ -866,7 +1123,7 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) } RETHROW_BOOST_LEXICAL; - case Token::LINTEGER: + case Token::LINTEGER: try { if (neg) { @@ -901,13 +1158,13 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) } RETHROW_BOOST_LEXICAL; - case Token::TRUE_: - case Token::FALSE_: - sprc->val()->yesno(get_token().get_type() == Token::TRUE_); - return stored.release(); + case Token::TRUE_: + case Token::FALSE_: + sprc->val()->yesno(get_token().get_type() == Token::TRUE_); + return stored.release(); - default: - // will continue with functionCall | columnIdent | documentField parsing + default: + // will continue with functionCall | columnIdent | documentField parsing break; } @@ -916,113 +1173,116 @@ Expression* Expr_parser_base::parse_atomic(Processor *prc) /* functionCall | columnIdent | documentField - In this case the first token can be either ID, QUOTED_ID or DOLLAR: + It is not possible to tell which of these 3 alternatives we have by + looking at the current token. Either functionCall or columnIdent or + documentField can start with something which looks like a schema-qualified + name: "A" or "A.B". + + For that reason we start with a call to parse_schema_indent() which would + parse such a schema-qualified name and store it as table/schema name of + m_col_ref member. + + After this we try to parse a function call and if it fails we try + columnIndent or documentField, depending on the parsing mode. + */ + + Token::TokenType types[2]; + bool schema_ident = false; - functionCall ::= schemaQualifiedIdent ... - columIdent ::= shcemaQualifiedIdent ... - documentField ::= ID .... | DOLLAR ... + m_col_ref.clear(); - schemaQualifiedIdent ::= ident ... - ident ::= ID | QUOTED_ID + /* + Try to parse schema-qualified identifier, storing the types of the tokens + that have been consumed. If parsing fails, we ignore the error because + in this case we will try a document path below. - ID can start either of the three types of atomic expression, DOLLAR - can only start documentField, QUOTED_ID can start either functinCall - or columnIdent. + Note: it is important that parse_schema_ident() stores correct tokens + in m_col_ref even if it fails in the end. */ + try { + parse_schema_ident(&types); + schema_ident = true; + } + catch (const cdk::Error&) + {} - const Token& t = peek_token(); + /* + If parse_schema_ident() succeeded, and we have the result in + m_col_ref.table(), we see if it is not a beginning of a function call. + If parse_function_call() succeeds then we are done. + */ - if (t.get_type() == Token::ID || - t.get_type() == Token::QUOTED_ID || - t.is_reserved_word()) + if (schema_ident) { - /* - Parse schemaQualifiedIdent - the result will be stored - in m_col_ref.table() - */ - - parse_schema_ident(); assert(m_col_ref.table()); - /* - First check if this is a function call. If yes, the call will - be reported to the processor and there is nothing more to do. - */ - if (parse_function_call(*m_col_ref.table(), sprc)) return stored.release(); + } - /* - Otherwise, if we are in TABLE mode, identifier we parsed so far - should be a beginning of columnIdent. We complete parsing it, report - it to the processor and then we are done. - */ + /* + Otherwise we must have either a document path (in DOCUMENT mode) or + a column identifier, possibly followed by a path (in TABLE mode). + */ - if (Parser_mode::TABLE == m_parser_mode) - { - parse_column_ident1(); - sprc->ref(m_col_ref, m_path.is_empty() ? NULL : &m_path); - return stored.release(); - } + cdk::Doc_path_storage path; + if (Parser_mode::TABLE == m_parser_mode) + { /* - Otherwise we are in DOCUMENT mode. In this case the document field - should not start with a quotted identifier (documentField rule only - allows ID, not QUOTED_ID). - */ + If we are in the TABLE mode, and parse_schema_ident() failed above, then + we do not have a valid column identifier which is an error. + */ - if (Token::QUOTED_ID == type) - unexpected_token(get_token(), "atomic expr"); + if (!schema_ident) + unexpected_token(peek_token(), "when looking for a column identifier"); /* - We re-interpret schemaQualifiedIdent parsed above as a beginning of a - document field expression: + Otherwise we complete parsing the column identifier and report it to + the processor. + */ - - if it is of the form A.B, where A is schema name and B is table name, - then A becomes main document field name and B becomes the first - element in the document path; + parse_column_ident1(&path); + sprc->ref(m_col_ref, path.is_empty() ? NULL : &path); + return stored.release(); + } - - if it is a single identifier A (table name) then it becomes the - main field name. + /* + Here we know that we are in DOCUMENT mode and we are expecting a document + path. If parse_schema_ident() called above consumed some tokens, we check + if they were not quotted identifiers. Such identifiers are allowed when + reffering to tables or columns but are invalid in a document path. + */ - The rest of the document path is parsed within parse_document_path() - method. - */ + if (Token::QUOTED_ID == types[0] || Token::QUOTED_ID == types[1]) + throw_error("invalid document path"); - if (m_col_ref.table()->schema()) - parse_document_path(m_col_ref.table()->schema()->name(), - m_col_ref.table()->name()); - else - parse_document_path(m_col_ref.table()->name()); + /* + Now we treat the identifiers "A.B" parsed by parse_schema_ident() and + stored as table/schema name in m_col_ref (if any), as an initail segment + of a document field reference and complete parsing the whole document + field. + */ - /* - Note: the parsed document path will be reported to the processor below - (after switch() statement). - */ + if (m_col_ref.table() && m_col_ref.table()->schema()) + { + parse_document_field( + m_col_ref.table()->schema()->name(), + m_col_ref.table()->name(), + &path + ); } - else if (type == Token::DOLLAR) + else if (m_col_ref.table()) { - /* - DOLLAR starts documentField, which is valid only in DOCUMENT mode. - */ - - if (Parser_mode::DOCUMENT != m_parser_mode) - unexpected_token(get_token(), "atomic expr"); - - parse_document_field(); + parse_document_field(m_col_ref.table()->name(), &path); } else { - - /* - If we see any other token, then we throw exception, since it is unexpected - */ - unexpected_token(t,"atomic expr"); - + parse_document_field(&path); } - sprc->ref(m_path); + sprc->ref(path); return stored.release(); } @@ -1481,10 +1741,10 @@ void Order_parser::process(Processor& prc) const It last = m_tokenizer.end(); /* - * note: passing m_toks.end() directly as constructor argument results - * in "incompatible iterators" exception when comparing iterators (at - * least on win, vs2010). problem with passing temporary object? - */ + note: passing m_toks.end() directly as constructor argument results + in "incompatible iterators" exception when comparing iterators (at + least on win, vs2010). problem with passing temporary object? + */ Stored_any store_expr; @@ -1530,10 +1790,10 @@ void Projection_parser::process(Projection_processor& prc) const It last = m_tokenizer.end(); /* - * note: passing m_toks.end() directly as constructor argument results - * in "incompatible iterators" exception when comparing iterators (at - * least on win, vs2010). problem with passing temporary object? - */ + note: passing m_toks.end() directly as constructor argument results + in "incompatible iterators" exception when comparing iterators (at + least on win, vs2010). problem with passing temporary object? + */ Expr_parser_base parser(first, last, m_mode); parser.process_if(prc.expr()); @@ -1573,10 +1833,10 @@ void Projection_parser::process(Document_processor& prc) const It last = m_tokenizer.end(); /* - * note: passing m_toks.end() directly as constructor argument results - * in "incompatible iterators" exception when comparing iterators (at - * least on win, vs2010). problem with passing temporary object? - */ + note: passing m_toks.end() directly as constructor argument results + in "incompatible iterators" exception when comparing iterators (at + least on win, vs2010). problem with passing temporary object? + */ Stored_any store_expr; diff --git a/cdk/parser/expr_parser.h b/cdk/parser/expr_parser.h index 6828ccdc3..d5e655912 100644 --- a/cdk/parser/expr_parser.h +++ b/cdk/parser/expr_parser.h @@ -28,9 +28,6 @@ #include #include "parser.h" -PUSH_BOOST_WARNINGS -#include -POP_BOOST_WARNINGS PUSH_SYS_WARNINGS #include #include @@ -54,42 +51,44 @@ using cdk::Expression; paths within the parser. */ -struct Column_ref : public cdk::api::Column_ref +struct Table_ref : public cdk::api::Table_ref { - - struct Table_ref : public cdk::api::Table_ref + struct : public cdk::api::Schema_ref { - struct : public cdk::api::Schema_ref - { - cdk::string m_name; + cdk::string m_name; - virtual const cdk::string name() const { return m_name; } + virtual const cdk::string name() const { return m_name; } - } m_schema_ref; + } m_schema_ref; - cdk::string m_name; + cdk::string m_name; - virtual const cdk::string name() const { return m_name; } + virtual const cdk::string name() const { return m_name; } - virtual const cdk::api::Schema_ref* schema() const - { return m_schema_ref.m_name.empty() ? NULL : &m_schema_ref; } + virtual const cdk::api::Schema_ref* schema() const + { return m_schema_ref.m_name.empty() ? NULL : &m_schema_ref; } - void set(const cdk::string &name) - { m_name = name; } + void set(const cdk::string &name) + { m_name = name; } - void set(const cdk::string &name, const cdk::string &schema) - { - m_name = name; - m_schema_ref.m_name = schema; - } + void set(const cdk::string &name, const cdk::string &schema) + { + m_name = name; + m_schema_ref.m_name = schema; + } - void clear() - { - m_name.clear(); - m_schema_ref.m_name.clear(); - } + void clear() + { + m_name.clear(); + m_schema_ref.m_name.clear(); + } - } m_table_ref; +}; + + +struct Column_ref : public cdk::api::Column_ref +{ + Table_ref m_table_ref; cdk::string m_col_name; @@ -146,119 +145,10 @@ struct Column_ref : public cdk::api::Column_ref }; -struct Doc_path : public cdk::Doc_path -{ - // Doc_path - - struct Doc_path_data - { - Doc_path_data(Type doc_type) - : m_doc_type(doc_type) - {} - - Doc_path_data(Type doc_type, const cdk::string& name) - : m_doc_type(doc_type) - , m_name(name) - {} - - Doc_path_data(Type doc_type, uint32_t index) - : m_doc_type(doc_type) - , m_index(index) - {} - - Type m_doc_type; - cdk::string m_name; - uint32_t m_index; - }; - - std::vector m_doc_path; - - virtual ~Doc_path() {} - - unsigned length() const - { - size_t cnt = m_doc_path.size(); - assert(cnt <= std::numeric_limits::max()); - return (unsigned)cnt; - } - - Type get_type(unsigned pos) const { return m_doc_path[pos].m_doc_type; } - - const uint32_t* get_index(unsigned pos) const - { - switch (m_doc_path[pos].m_doc_type) - { - case ARRAY_INDEX: - return &m_doc_path[pos].m_index; - default: - return NULL; - } - } - - const cdk::string* get_name(unsigned pos) const - { - switch (m_doc_path[pos].m_doc_type) - { - case MEMBER: - case MEMBER_ASTERISK: - return &m_doc_path[pos].m_name; - default: - return NULL; - } - } - - - void add(Type type, const cdk::string &name) - { - m_doc_path.push_back(Doc_path_data(type, name)); - } - - void add(Type type, uint32_t index) - { - m_doc_path.push_back(Doc_path_data(type, index)); - } - - void add(Type type) - { - m_doc_path.push_back(Doc_path_data(type)); - } - - - Doc_path& operator=(const cdk::Doc_path &other) - { - for (unsigned pos=0; pos < other.length(); ++pos) - { - switch (other.get_type(pos)) - { - case MEMBER: - add(MEMBER, *other.get_name(pos)); - break; - case ARRAY_INDEX: - add(ARRAY_INDEX, *other.get_index(pos)); - break; - default: - add(other.get_type(pos)); - break; - } - } - return *this; - } - - void clear() - { - m_doc_path.clear(); - } - - bool is_empty() const - { - return m_doc_path.empty(); - } -}; - - /* Trivial Format_info class that is used to report opaque blob values. */ + struct Format_info : public cdk::Format_info { bool for_type(cdk::Type_info ti) const { return cdk::TYPE_BYTES == ti; } @@ -272,171 +162,6 @@ struct Format_info : public cdk::Format_info // ------------------------------------------------------------------------------ -/* - Class that implements token navigation and usage methods - */ - -class Token_op_base -{ - -protected: - - typedef std::set TokSet; - - It *m_first; - It m_last; - - const std::string& consume_token(Token::TokenType type) - { - if (!cur_token_type_is(type)) - unexpected_token(peek_token(), (boost::format("while looking for token %s") - % Token::get_name(type)).str().c_str()); - return get_token().get_text(); - } - - const Token& peek_token() - { - if (!tokens_available()) - throw Error("unexpected end of string"); - return **m_first; - } - - bool cur_token_type_is(Token::TokenType type) - { - return tokens_available() && peek_token().get_type() == type; - } - - bool is_token_type_within_set(TokSet types) - { - return tokens_available() - && types.find(peek_token().get_type()) != types.end(); - } - - unsigned get_token_pos() const - { - // TODO - return 0; - } - - It& cur_pos() const - { - return *m_first; - } - - const It& end_pos() const - { - return m_last; - } - - bool tokens_available() const - { - return cur_pos() != end_pos(); - } - - const Token& get_token() - { - if (!tokens_available()) - throw Error("unexpected end of string"); - const Token &t = peek_token(); - ++(*m_first); - return t; - } - - std::string operator_name(const std::string &name) - { - return Tokenizer::map.operator_names.at(name); - } - - void unexpected_token(const Token&, const char *ctx); - -public: - Token_op_base(It &first, const It &last) - : m_first(&first), m_last(last) - {} -}; - -/* - Class implementing Document Path parsing methods. - */ - - -class Doc_path_parser_base - : public Token_op_base - -{ -protected: - - void parse_document_path(bool clear = true); - void parse_document_path(const cdk::string&); - void parse_document_path(const cdk::string&, const cdk::string&); - - void parse_docpath_member(); - void parse_docpath_array_loc(); - -public: - - Doc_path_parser_base(It &first, const It &last) - : Token_op_base(first, last) - {} - - Doc_path m_path; - - /* - Used to parse documentPath only strings, not as part of an expression. - */ - void parse_document_field(); - -}; - -/* - This class parses Document path using Doc_path_parser_base methods and - act as a cdk::Doc_path object - - Used to parse documentPath only fields, not expressions. - */ - - -class Doc_field_parser - : public cdk::Doc_path -{ - Tokenizer m_tokenizer; - cdk::scoped_ptr m_parser; - - -public: - - Doc_field_parser(const cdk::string &doc_path) - : m_tokenizer(doc_path) - { - m_tokenizer.get_tokens(); - - It begin = m_tokenizer.begin(); - const It end = m_tokenizer.end(); - m_parser.reset(new Doc_path_parser_base(begin, end)); - - m_parser->parse_document_field(); - } - - unsigned length() const - { - return m_parser->m_path.length(); - } - - Type get_type(unsigned pos) const - { - return m_parser->m_path.get_type(pos); - } - const cdk::string* get_name(unsigned pos) const - { - return m_parser->m_path.get_name(pos); - } - - const uint32_t* get_index(unsigned pos) const - { - return m_parser->m_path.get_index(pos); - } - -}; /* Main parser class containing parsing logic. An instance acts @@ -456,14 +181,14 @@ struct Parser_mode class Expr_parser_base - : Doc_path_parser_base - , public Expr_parser + : public Expr_parser { public: typedef Expression::Processor Processor; typedef Expression::Scalar::Processor Scalar_prc; + typedef cdk::api::Doc_path::Processor Path_prc; static Expression::Processor *get_base_prc(Processor *prc) { return prc; } @@ -485,8 +210,7 @@ class Expr_parser_base Expr_parser_base(It &first, const It &last, Parser_mode::value parser_mode, bool strings_as_blobs = false) - : Doc_path_parser_base(first, last) - , Expr_parser(first, last) + : Expr_parser(first, last) , m_parser_mode(parser_mode) , m_strings_as_blobs(strings_as_blobs) { @@ -497,7 +221,6 @@ class Expr_parser_base bool do_parse(It &first, const It &last, Processor *prc); - enum Start { FULL, ATOMIC, MUL, ADD, SHIFT, BIT, COMP, ILRI, AND, OR, CAST_TYPE, COLID_DOCPATH, DOC, ARR}; @@ -535,12 +258,19 @@ class Expr_parser_base void parse_argslist(Expression::List::Processor*, bool strings_as_blobs = false); - void parse_schema_ident(); - void parse_column_ident(); - void parse_column_ident1(); + void parse_schema_ident(Token::TokenType (*types)[2] = NULL); + void parse_column_ident(Path_prc*); + void parse_column_ident1(Path_prc*); const std::string &get_ident(); - void parse_document_field(bool prefix = false); + void parse_document_field(Path_prc*, bool prefix = false); + void parse_document_field(const cdk::string&, Path_prc*); + void parse_document_field(const cdk::string&, const cdk::string&, Path_prc*); + + bool parse_document_path(Path_prc*, bool require_dot=false); + bool parse_document_path1(Path_prc*); + bool parse_docpath_member(Path_prc::Element_prc*); + void parse_docpath_array_loc(Path_prc::Element_prc*); void parse_cast(Scalar_prc*); cdk::string parse_cast_type(); @@ -552,23 +282,15 @@ class Expr_parser_base void parse_doc(Processor::Doc_prc*); void parse_arr(Processor::List_prc*); - - private: Column_ref m_col_ref; - - // Access to the underlying sequence of tokens. - -// It *m_first; -// It m_last; - - friend class Expression_parser; friend class Order_parser; friend class Projection_parser; friend class Table_field_parser; + friend class Doc_field_parser; }; @@ -706,48 +428,79 @@ class Projection_parser class Table_field_parser : public cdk::api::Column_ref + , public cdk::Doc_path { - Tokenizer m_tokenizer; - cdk::scoped_ptr m_table_field; + parser::Column_ref m_col; + cdk::Doc_path_storage m_path; public: Table_field_parser(const cdk::string &table_field) - : m_tokenizer(table_field) { - m_tokenizer.get_tokens(); - - It begin = m_tokenizer.begin(); - const It end = m_tokenizer.end(); - - m_table_field.reset(new Expr_parser_base(begin, - end, - Parser_mode::TABLE)); + Tokenizer toks(table_field); + toks.get_tokens(); - m_table_field->parse_column_ident(); + It begin = toks.begin(); + const It end = toks.end(); + Expr_parser_base parser(begin, end, Parser_mode::TABLE); + parser.parse_column_ident(&m_path); + m_col = parser.m_col_ref; } const cdk::string name() const { - return m_table_field->m_col_ref.name(); + return m_col.name(); } const cdk::api::Table_ref *table() const { - return m_table_field->m_col_ref.table(); + return m_col.table(); } - const Doc_path *path() const + bool has_path() const { - return m_table_field->m_path.length() == 0 ? - NULL : - &(m_table_field->m_path); + return !m_path.is_empty(); + } + + void process(Processor &prc) const + { + m_path.process(prc); } }; +/* + This class acts as cdk::Doc_path object taking path data from a string + containing document field specification (documentField grammar) +*/ + +class Doc_field_parser + : public cdk::Doc_path +{ + Tokenizer m_tokenizer; + cdk::scoped_ptr m_parser; + It m_it; + +public: + + Doc_field_parser(const cdk::string &doc_path) + : m_tokenizer(doc_path) + { + m_tokenizer.get_tokens(); + + m_it = m_tokenizer.begin(); + const It end = m_tokenizer.end(); + m_parser.reset(new Expr_parser_base(m_it, end, Parser_mode::DOCUMENT)); + } + + void process(Processor &prc) const + { + const_cast(m_parser.get())->parse_document_field(&prc); + } +}; + // ------------------------------------------------------------------------------ /* @@ -907,7 +660,7 @@ struct Stored_scalar // Storage for the values parser::Column_ref m_col_ref; - parser::Doc_path m_doc_path; + cdk::Doc_path_storage m_doc_path; std::string m_op_name; cdk::string m_str; @@ -1075,13 +828,13 @@ struct Stored_scalar m_type = COL_REF; m_col_ref = col; if (path) - m_doc_path = *path; + path->process(m_doc_path); } void ref(const Doc_path &path) { m_type = PATH; - m_doc_path = path; + path.process(m_doc_path); } void param(const string &name) diff --git a/cdk/parser/parser.h b/cdk/parser/parser.h index 297b34825..a84088884 100644 --- a/cdk/parser/parser.h +++ b/cdk/parser/parser.h @@ -28,6 +28,11 @@ #include #include "tokenizer.h" +PUSH_BOOST_WARNINGS +#include +POP_BOOST_WARNINGS + + #ifdef _WIN32 /* @@ -53,6 +58,104 @@ namespace parser { typedef Tokenizer::iterator It; using cdk::throw_error; + +/* + Class that implements token navigation and usage methods +*/ + +class Token_op_base +{ + +protected: + + typedef std::set TokSet; + + It *m_first; + It m_last; + + const std::string& consume_token(Token::TokenType type) + { + if (!cur_token_type_is(type)) + unexpected_token(peek_token(), (boost::format("while looking for token %s") + % Token::get_name(type)).str().c_str()); + return get_token().get_text(); + } + + const Token& peek_token() + { + if (!tokens_available()) + throw Error("unexpected end of string"); + return **m_first; + } + + bool cur_token_type_is(Token::TokenType type) + { + return tokens_available() && peek_token().get_type() == type; + } + + bool is_token_type_within_set(TokSet types) + { + return tokens_available() + && types.find(peek_token().get_type()) != types.end(); + } + + unsigned get_token_pos() const + { + // TODO + return 0; + } + + It& cur_pos() + { + assert(m_first); + return *m_first; + } + + const It& cur_pos() const + { + return const_cast(this)->cur_pos(); + } + + const It& end_pos() const + { + return m_last; + } + + bool tokens_available() const + { + return m_first && cur_pos() != end_pos(); + } + + const Token& get_token() + { + if (!tokens_available()) + throw Error("unexpected end of string"); + const Token &t = peek_token(); + ++(*m_first); + return t; + } + + std::string operator_name(const std::string &name) + { + return Tokenizer::map.operator_names.at(name); + } + + void unexpected_token(const Token&, const char *ctx); + +public: + + Token_op_base() + : m_first(NULL) + {} + + void set_tokens(It &first, const It &last) + { + m_first = &first; + m_last = last; + } +}; + + /* Base class for parsers which parse tokens and present result as an expression over processor PRC. @@ -94,12 +197,15 @@ using cdk::throw_error; template class Expr_parser : public cdk::api::Expr_base + , protected Token_op_base { public: Expr_parser(It &first, const It &last) - : m_first(first), m_last(last), m_consumed(false) - {} + : m_consumed(false) + { + set_tokens(first, last); + } void process(PRC &prc) const { @@ -131,7 +237,7 @@ class Expr_parser if (m_consumed) THROW("Expr_praser: second pass"); - if (!do_parse(m_first, m_last, &prc)) + if (!do_parse(cur_pos(), end_pos(), &prc)) return false; m_consumed = true; return true; @@ -153,7 +259,7 @@ class Expr_parser { if (m_consumed) return; - do_consume(m_first, m_last); + do_consume(cur_pos(), end_pos()); m_consumed = true; } @@ -171,10 +277,6 @@ class Expr_parser return true; } -private: - - It &m_first; - const It m_last; protected: diff --git a/cdk/parser/tests/CMakeLists.txt b/cdk/parser/tests/CMakeLists.txt index 6732d6b37..96d57ee89 100644 --- a/cdk/parser/tests/CMakeLists.txt +++ b/cdk/parser/tests/CMakeLists.txt @@ -48,8 +48,6 @@ if(MSVC) target_compile_options(expr_test PRIVATE /W3) endif() -ADD_GCOV(expr_test) - # # Add unit test that runs expr_test using runtests.py script # diff --git a/cdk/parser/tests/parser-t.cc b/cdk/parser/tests/parser-t.cc index e3a9cab11..99dff1933 100644 --- a/cdk/parser/tests/parser-t.cc +++ b/cdk/parser/tests/parser-t.cc @@ -373,6 +373,62 @@ class Expr_printer }; + struct Path_printer + : public cdk::api::Doc_path::Processor + , cdk::api::Doc_path_processor + { + ostream &m_out; + bool m_first; + + Path_printer(ostream &out) + : m_out(out), m_first(true) + {} + + void list_begin() + { + m_first = true; + } + + Element_prc* list_el() + { + return this; + } + + void member(const string &name) + { + if (!m_first) + m_out << "."; + m_first = false; + m_out << name; + } + + void any_member() + { + if (!m_first) + m_out << "."; + m_first = false; + m_out << "*"; + } + + void index(index_t pos) + { + m_first = false; + m_out << "[" << pos << "]"; + } + + void any_index() + { + m_first = false; + m_out << "[*]"; + } + + void any_path() + { + m_first = false; + m_out << "**"; + } + }; + struct Scalar_printer : public Scalar_prc , public Scalar_prc::Args_prc @@ -383,10 +439,12 @@ class Expr_printer cdk::string m_op_name; Val_printer m_val_printer; + Path_printer m_path_printer; Scalar_printer(Expr_printer &parent) : m_parent(parent), m_pb(parent.m_pb) , m_val_printer(parent.m_pb) + , m_path_printer(parent.m_pb.m_out) {} // Table_ref @@ -444,32 +502,8 @@ class Expr_printer virtual void ref(const cdk::Doc_path &path) { - ostream &out = m_pb.out_ind(); - for (unsigned i=0; i < path.length(); ++i) - { - if (i > 0) - out << "."; - switch(path.get_type(i)) - { - case Doc_path::MEMBER: - out << *path.get_name(i); - break; - case Doc_path::MEMBER_ASTERISK: - out << "*"; - break; - case Doc_path::ARRAY_INDEX: - out << "[" << *path.get_index(i) << "]"; - break; - case Doc_path::ARRAY_INDEX_ASTERISK: - out << "[*]"; - break; - case Doc_path::DOUBLE_ASTERISK: - out << "**"; - break; - } - } - - out << endl; + path.process(m_path_printer); + m_pb.m_out << endl; } virtual void ref(const cdk::api::Column_ref &col, const cdk::Doc_path *path) @@ -486,20 +520,8 @@ class Expr_printer if (path) { - out <<"->$"; - for (unsigned i= 0; - i < path->length(); - ++i) - { - switch (path->get_type(i)) - { - case Doc_path::MEMBER: out <<"." << *path->get_name(i); break; - case Doc_path::MEMBER_ASTERISK: out << ".*"; break; - case Doc_path::ARRAY_INDEX: out << "["<< *path->get_index(i) <<"]"; break; - case Doc_path::ARRAY_INDEX_ASTERISK: out << "[*]"; break; - case Doc_path::DOUBLE_ASTERISK: out << "**"; break; - } - } + out <<"->$."; + path->process(m_path_printer); } out < cast(14.01 as decimal(3,2))"}, { parser::Parser_mode::TABLE , L"CHARSET(CHAR(X'65'))"}, { parser::Parser_mode::TABLE , L"CHARSET(CHAR(0x65))"}, - { parser::Parser_mode::TABLE , L"CHARSET(CHAR(X'65' USING utf8))"}, +// { parser::Parser_mode::TABLE , L"CHARSET(CHAR(X'65' USING utf8))"}, // { parser::Parser_mode::TABLE , L"TRIM(BOTH 'x' FROM 'xxxbarxxx')"}, // { parser::Parser_mode::TABLE , L"TRIM(LEADING 'x' FROM 'xxxbarxxx')"}, // { parser::Parser_mode::TABLE , L"TRIM(TRAILING 'xyz' FROM 'barxxyz')"}, @@ -600,7 +622,6 @@ TEST(Parser, expr) { Expr_printer printer(cout, 0); - for (unsigned i=0; i < sizeof(exprs)/sizeof(Expr_Test); i++) { cout <consume_until(host, TokSet(T_AT, T_COLON)); - - if (self->consume_token(T_COLON)) + if (self->next_token_is(T_SQOPEN)) { /* + IPv6 adress found! Will be parsed on rescan + */ + rescan = true; + } + else + { + self->consume_until(host, TokSet(T_AT, T_COLON )); + + if (self->consume_token(T_COLON)) + { + /* We have seen ":" and it still can be user followed by a password or host followed by a port. @@ -306,9 +322,9 @@ void URI_parser::process(Processor &prc) const part, whichever comes first. */ - self->consume_until(port, T_AT); + self->consume_until(port, T_AT); - /* + /* If we see @ now, then it means we were looking at user credentials so far (and they are stored in host and port, respectively). We report them and request re-scanning host/port @@ -319,25 +335,26 @@ void URI_parser::process(Processor &prc) const the corresponding variables. */ - if (self->consume_token(T_AT)) - { - // :@... - prc.user(host); - prc.password(port); - rescan = true; + if (self->consume_token(T_AT)) + { + // :@... + prc.user(host); + prc.password(port); + rescan = true; + } + else + has_port = true; } - else - has_port = true; - } - else if (self->consume_token(T_AT)) - { - /* + else if (self->consume_token(T_AT)) + { + /* No ':' seen but we see '@'. It means user without password and user is stored in host variable. We report it an request re-scanning of host/port info. */ - prc.user(host); - rescan = true; + prc.user(host); + rescan = true; + } } /* @@ -350,7 +367,21 @@ void URI_parser::process(Processor &prc) const { host.clear(); port.clear(); - self->consume_until(host, T_COLON); + + if (self->consume_token(T_SQOPEN)) + { + /* + IPv6 address + */ + host.clear(); + self->consume_until(host, T_SQCLOSE); + if (!self->consume_token(T_SQCLOSE)) + throw Error(this, L"Missing ']' while parsing IPv6 address"); + } + else + { + self->consume_until(host, T_COLON ); + } if (self->consume_token(T_COLON)) { diff --git a/cdk/protobuf/CMakeLists.txt b/cdk/protobuf/CMakeLists.txt index d4cdb7aa3..d59ab5b20 100644 --- a/cdk/protobuf/CMakeLists.txt +++ b/cdk/protobuf/CMakeLists.txt @@ -100,6 +100,16 @@ IF(UNIX) list(APPEND warnings_list "-Wno-return-type") list(APPEND warnings_list "-Wno-unused-function") + if(APPLE) + + # Our version of protobuf uses many constructs (mainly atomic ops) + # which were depracated in OSX 10.12. + # TODO: Upgrade bundled protobuf + + list(APPEND warnings_list -Wno-deprecated-declarations) + + endif() + IF(CMAKE_COMPILER_IS_GNUCXX) list(APPEND warnings_list "-Wno-unused-local-typedefs") list(APPEND warnings_list "-Wno-maybe-uninitialized") diff --git a/cdk/protocol/mysqlx/CMakeLists.txt b/cdk/protocol/mysqlx/CMakeLists.txt index bdbf8cb09..4125f2140 100644 --- a/cdk/protocol/mysqlx/CMakeLists.txt +++ b/cdk/protocol/mysqlx/CMakeLists.txt @@ -96,6 +96,7 @@ SET(target_proto_mysqlx ${cdk_target_prefix}proto_mysqlx ADD_LIBRARY(${target_proto_mysqlx} OBJECT protocol.cc session.cc rset.cc stmt.cc crud.cc ${PB_SRCS}) +ADD_COVERAGE(${target_proto_mysqlx}) source_group(protobuf FILES ${PB_SRCS}) diff --git a/cdk/protocol/mysqlx/builders.h b/cdk/protocol/mysqlx/builders.h index 0bc246633..5e9295a68 100644 --- a/cdk/protocol/mysqlx/builders.h +++ b/cdk/protocol/mysqlx/builders.h @@ -25,7 +25,7 @@ #ifndef PROTOCOL_MYSQLX_BUILDERS_H #define PROTOCOL_MYSQLX_BUILDERS_H -#include +#include PUSH_BOOST_WARNINGS #include @@ -567,7 +567,7 @@ class Scalar_builder_base void null(); void str(bytes val); - void str(charset_id_t cs, bytes val); + void str(collation_id_t cs, bytes val); void num(int64_t val); void num(uint64_t val); void num(float val); @@ -724,7 +724,7 @@ void Scalar_builder_base::str(bytes val) template inline -void Scalar_builder_base::str(charset_id_t cs, bytes val) +void Scalar_builder_base::str(collation_id_t cs, bytes val) { String &str= get_string(); str.set_collation(cs); diff --git a/cdk/protocol/mysqlx/crud.cc b/cdk/protocol/mysqlx/crud.cc index 61e936535..5d769dc79 100644 --- a/cdk/protocol/mysqlx/crud.cc +++ b/cdk/protocol/mysqlx/crud.cc @@ -55,7 +55,7 @@ namespace mysqlx { Helper function template to set a db object for a given message of MSG class */ -template void set_db_obj(api::Db_obj &db_obj, MSG &msg) +template void set_db_obj(const api::Db_obj &db_obj, MSG &msg) { Mysqlx::Crud::Collection *proto_collect = msg.mutable_collection(); @@ -82,7 +82,7 @@ template void set_data_model(Data_model dm, MSG &msg) Helper function template to set `limit` field inside message of type MSG. */ -template void set_limit(api::Limit &lim, MSG &msg) +template void set_limit(const api::Limit &lim, MSG &msg) { Mysqlx::Crud::Limit *proto_lim = msg.mutable_limit(); @@ -100,8 +100,8 @@ template void set_limit(api::Limit &lim, MSG &msg) MSG. */ -template void set_criteria(api::Expression &api_expr, MSG &msg, - Args_conv &conv /*= NULL*/) +template void set_criteria(const api::Expression &api_expr, + MSG &msg, Args_conv &conv) { Mysqlx::Expr::Expr *pb_expr = msg.mutable_criteria(); @@ -110,6 +110,26 @@ template void set_criteria(api::Expression &api_expr, MSG &msg, } +/* + Helper function template to set selection parameters given by a + `Select_spec` object. +*/ + +template +void set_select(const Select_spec &sel, MSG &msg, Args_conv &conv) +{ + set_db_obj(sel.obj(), msg); + + if (sel.select()) + set_criteria(*sel.select(), msg, conv); + + if (sel.order()) + set_order_by(*sel.order(), msg, conv); + + if (sel.limit()) + set_limit(*sel.limit(), msg); +} + // ------------------------------------------------------------------------- /* @@ -219,7 +239,7 @@ struct Ord_msg_traits is stored in a repeated `order` field within the message. */ -template void set_order_by(api::Order_by &order_by, +template void set_order_by(const api::Order_by &order_by, MSG &msg, Args_conv &conv) { @@ -390,7 +410,7 @@ void set_doc_path(Mysqlx::Expr::ColumnIdentifier *p_col_id, /* - Storing Group_by information inside Find protocol command. + Storing Group_by information inside Find protocol command. This command has a repeated `grouping` field of type Mysqlx::Expr::Expr. Below we fill it using a builder created from Array_builer<> template. Such builder process list of @@ -412,59 +432,49 @@ struct Group_by_traits }; -Protocol::Op& -Protocol::snd_Find( - Data_model dm, - api::Db_obj &db_obj, - api::Expression *api_expr, - api::Projection *proj, - api::Order_by *order, - api::Expr_list *group_by, - api::Expression *having, - api::Limit *lim, - api::Args_map *args) +void set_find(Mysqlx::Crud::Find &msg, + Data_model dm, const Find_spec &fs, const api::Args_map *args) { - Mysqlx::Crud::Find find; - Placeholder_conv_imp conv; - set_db_obj(db_obj, find); - set_data_model(dm, find); + set_data_model(dm, msg); if (args) - set_args(*args, find, conv); - - if (api_expr) - set_criteria(*api_expr, find, conv); - - if (lim) - set_limit(*lim, find); + set_args(*args, msg, conv); - if (order) - set_order_by(*order, find, conv); + set_select(fs, msg, conv); - if (proj) + if (fs.project()) { - Array_builder + Array_builder proj_builder; - proj_builder.reset(find, &conv); - proj->process(proj_builder); + proj_builder.reset(msg, &conv); + fs.project()->process(proj_builder); } - if (group_by) + if (fs.group_by()) { Array_builder group_by_builder; - group_by_builder.reset(find, &conv); - group_by->process(group_by_builder); + group_by_builder.reset(msg, &conv); + fs.group_by()->process(group_by_builder); } - if (having) + if (fs.having()) { Expr_builder expr_builder; - expr_builder.reset(*find.mutable_grouping_criteria()); - having->process(expr_builder); + expr_builder.reset(*msg.mutable_grouping_criteria()); + fs.having()->process(expr_builder); } +} + + +Protocol::Op& +Protocol::snd_Find(Data_model dm, const Find_spec &fs, const api::Args_map *args) +{ + Mysqlx::Crud::Find find; + + set_find(find, dm, fs, args); return get_impl().snd_start(find, msg_type::cli_CrudFind); } @@ -531,7 +541,7 @@ Protocol::snd_Insert( api::Db_obj &db_obj, const api::Columns *columns, Row_source &rs, - api::Args_map *args) + const api::Args_map *args) { Mysqlx::Crud::Insert insert; @@ -637,30 +647,19 @@ class Update_builder Protocol::Op& Protocol::snd_Update( Data_model dm, - api::Db_obj &db_obj, - api::Expression *api_expr, + const Select_spec &sel, Update_spec &us, - api::Order_by *order, - api::Limit *lim, - api::Args_map *args) + const api::Args_map *args) { Mysqlx::Crud::Update update; Placeholder_conv_imp conv; - set_db_obj(db_obj, update); set_data_model(dm, update); if (args) set_args(*args, update, conv); - if (api_expr) - set_criteria(*api_expr, update, conv); - - if (order) - set_order_by(*order, update, conv); - - if (lim) - set_limit(*lim, update); + set_select(sel, update, conv); while (us.next()) { @@ -676,34 +675,188 @@ Protocol::Op& Protocol::snd_Update( Protocol::Op& -Protocol::snd_Delete( - Data_model dm, - api::Db_obj &db_obj, - api::Expression *api_expr, - api::Order_by *order_by, - api::Limit *lim, - api::Args_map *args) +Protocol::snd_Delete(Data_model dm, const Select_spec &sel, const api::Args_map *args) { Mysqlx::Crud::Delete del; Placeholder_conv_imp conv; - set_db_obj(db_obj, del); set_data_model(dm, del); if (args) set_args(*args, del, conv); - if (api_expr) - set_criteria(*api_expr, del, conv); + set_select(sel, del, conv); - if (lim) - set_limit(*lim, del); + return get_impl().snd_start(del, msg_type::cli_CrudDelete); +} - if (order_by) - set_order_by(*order_by, del, conv); - return get_impl().snd_start(del, msg_type::cli_CrudDelete); +// ------------------------------------------------------------------------- + + +template +void set_view_columns(MSG &msg, const api::Columns &cols) +{ + struct + : public api::Columns::Processor + , api::Columns::Processor::Element_prc + { + MSG *m_msg; + + // List processor + + void list_begin() {} + void list_end() {} + + Element_prc* list_el() + { + return this; + } + + // Column_processor + + void name(const string &col) + { + m_msg->add_column(col); + } + + virtual void alias(const string&) + { + THROW( + "Unexpected column alias specification when processing view columns" + ); + } + + virtual Path_prc* path() + { + THROW( + "Unexpected path specification when processing view columns" + ); + } + } + prc; + + prc.m_msg = &msg; + cols.process(prc); } +template +void set_view_options(MSG &msg, api::View_options &opts) +{ + struct : public api::View_options::Processor + { + MSG *m_msg; + + void definer(const string &user) + { + m_msg->set_definer(user); + } + + void security(View_security_t security) + { + switch (security) + { + case cdk::api::View_security::DEFINER: + m_msg->set_security(Mysqlx::Crud::DEFINER); + break; + case cdk::api::View_security::INVOKER: + m_msg->set_security(Mysqlx::Crud::INVOKER); + break; + } + } + + void algorithm(View_algorithm_t alg) + { + switch (alg) + { + case cdk::api::View_algorithm::UNDEFINED: + m_msg->set_algorithm(Mysqlx::Crud::UNDEFINED); + break; + case cdk::api::View_algorithm::MERGE: + m_msg->set_algorithm(Mysqlx::Crud::MERGE); + break; + case cdk::api::View_algorithm::TEMPTABLE: + m_msg->set_algorithm(Mysqlx::Crud::TEMPTABLE); + break; + } + } + + void check(View_check_t check) + { + switch (check) + { + case cdk::api::View_check::LOCAL: + m_msg->set_check(Mysqlx::Crud::LOCAL); + break; + case cdk::api::View_check::CASCADED: + m_msg->set_check(Mysqlx::Crud::CASCADED); + break; + } + } + } + prc; + + prc.m_msg = &msg; + opts.process(prc); +} + + +Protocol::Op& +Protocol::snd_CreateView( + Data_model dm, const api::Db_obj &obj, + const Find_spec &query, const api::Columns *cols, + bool replace, + api::View_options *opts, + const api::Args_map *args +) +{ + Mysqlx::Crud::CreateView view; + + set_db_obj(obj, view); + view.set_replace_existing(replace); + + if (cols) + set_view_columns(view, *cols); + + if (opts) + set_view_options(view, *opts); + + set_find(*view.mutable_stmt(), dm, query, args); + return get_impl().snd_start(view, msg_type::cli_CreateView); +} + + +Protocol::Op& +Protocol::snd_ModifyView( + Data_model dm, const api::Db_obj &obj, + const Find_spec &query, const api::Columns *cols, + api::View_options *opts, + const api::Args_map *args +) +{ + Mysqlx::Crud::ModifyView modify; + + set_db_obj(obj, modify); + + if (cols) + set_view_columns(modify, *cols); + + if (opts) + set_view_options(modify, *opts); + + set_find(*modify.mutable_stmt(), dm, query, args); + + return get_impl().snd_start(modify, msg_type::cli_ModifyView); +} + + +Protocol::Op& Protocol::snd_DropView(const api::Db_obj &obj, bool check_exists) +{ + Mysqlx::Crud::DropView drop; + set_db_obj(obj, drop); + drop.set_if_exists(!check_exists); + return get_impl().snd_start(drop, msg_type::cli_DropView); +} + }}} // cdk::protocol::mysqlx diff --git a/cdk/protocol/mysqlx/pb/mysqlx.proto b/cdk/protocol/mysqlx/pb/mysqlx.proto index acf581d29..a0e9a237d 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -73,6 +73,10 @@ message ClientMessages { EXPECT_OPEN = 24; EXPECT_CLOSE = 25; + + CRUD_CREATE_VIEW = 30; + CRUD_MODIFY_VIEW = 31; + CRUD_DROP_VIEW = 32; } } diff --git a/cdk/protocol/mysqlx/pb/mysqlx_connection.proto b/cdk/protocol/mysqlx/pb/mysqlx_connection.proto index ddb4f3864..91484786b 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_connection.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_connection.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/cdk/protocol/mysqlx/pb/mysqlx_crud.proto b/cdk/protocol/mysqlx/pb/mysqlx_crud.proto index 31d5f65ce..e046f2c62 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_crud.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_crud.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -192,3 +192,85 @@ message Delete { repeated Order order = 5; }; + +// ViewAlgorithm defines how MySQL Server processes the view +enum ViewAlgorithm { + UNDEFINED =1; // MySQL chooses which algorithm to use + MERGE = 2; // the text of a statement that refers to the view and the view definition are merged + TEMPTABLE = 3; // the view are retrieved into a temporary table +} + +// ViewSqlSecurity defines the security context in which the view is going to be +// executed, this means that VIEW can be executed with current user permissions or +// with permissions of the uses who defined the VIEW +enum ViewSqlSecurity { + INVOKER = 1; + DEFINER = 2; +} + + +// ViewCheckOption limits the write operations done on a `VIEW` +// (`INSERT`, `UPDATE`, `DELETE`) to rows in which the `WHERE` clause is `TRUE` +enum ViewCheckOption { + LOCAL = 1; // the view WHERE clause is checked, but no underlying views are checked + CASCADED = 2; // the view WHERE clause is checked, then checking recurses to underlying views +} + + +// CreateView create view based on indicated Mysqlx.Crud.Find message +// +// param collection: name of the VIEW object, which should be created +// param definer: user name of the definer, if the value isn't set then the definer is current user +// param algorithm: defines how MySQL Server processes the view +// param security: defines the security context in which the view is going be executed +// param check: limits the write operations done on a VIEW +// param column: defines the list of aliases for column names specified in `stmt` +// param stmt: Mysqlx.Crud.Find message from which the SELECT statement is going to be build +// param replace_existing: if true then suppress error when created view already exists; just replace it + +message CreateView { + required Collection collection = 1; + + optional string definer = 2; + optional ViewAlgorithm algorithm = 3 [default = UNDEFINED]; + optional ViewSqlSecurity security = 4 [default = DEFINER]; + optional ViewCheckOption check = 5; + + repeated string column = 6; + required Find stmt = 7; + optional bool replace_existing = 8 [default = false]; +} + + +// ModifyView modify existing view based on indicated Mysqlx.Crud.Find message +// +// param collection: name of the VIEW object, which should be modified +// param definer: user name of the definer, if the value isn't set then the definer is current user +// param algorithm: defined how MySQL Server processes the view +// param security: defines the security context in which the view is going be executed +// param check: limits the write operations done on a VIEW +// param column: defines the list of aliases for column names specified in `stmt` +// param stmt: Mysqlx.Crud.Find message from which the SELECT statement is going to be build + +message ModifyView { + required Collection collection = 1; + + optional string definer = 2; + optional ViewAlgorithm algorithm = 3; + optional ViewSqlSecurity security = 4; + optional ViewCheckOption check = 5; + + repeated string column = 6; + optional Find stmt = 7; +} + + +// DropView removing existing view +// +// param collection: name of the VIEW object, which should be deleted +// param if_exists: if true then suppress error when deleted view does not exists + +message DropView { + required Collection collection = 1; + optional bool if_exists = 2 [ default = false ]; +} diff --git a/cdk/protocol/mysqlx/pb/mysqlx_datatypes.proto b/cdk/protocol/mysqlx/pb/mysqlx_datatypes.proto index 04a948c89..f4f5ba1f8 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_datatypes.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_datatypes.proto @@ -31,14 +31,14 @@ message Scalar { required bytes value = 1; optional uint64 collation = 2; }; - -// an opaque octet sequence, with an optional content_type -// See ``Mysqlx.Resultset.ColumnMetadata`` for list of known values. -message Octets { - required bytes value = 1; - optional uint32 content_type = 2; -}; - + + // an opaque octet sequence, with an optional content_type + // See ``Mysqlx.Resultset.ColumnMetadata`` for list of known values. + message Octets { + required bytes value = 1; + optional uint32 content_type = 2; + }; + enum Type { V_SINT = 1; V_UINT = 2; diff --git a/cdk/protocol/mysqlx/pb/mysqlx_expect.proto b/cdk/protocol/mysqlx/pb/mysqlx_expect.proto index b7988191a..cd8611384 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_expect.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_expect.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/cdk/protocol/mysqlx/pb/mysqlx_expr.proto b/cdk/protocol/mysqlx/pb/mysqlx_expr.proto index 5a1aa6afd..fb5057878 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_expr.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_expr.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/cdk/protocol/mysqlx/pb/mysqlx_notice.proto b/cdk/protocol/mysqlx/pb/mysqlx_notice.proto index af52ec5c2..bd9104ca2 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_notice.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_notice.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -29,6 +29,7 @@ syntax = "proto2"; // * is sent from the server to the client // * may be global or relate to the current message sequence package Mysqlx.Notice; +option java_package = "com.mysql.cj.mysqlx.protobuf"; import "mysqlx_datatypes.proto"; diff --git a/cdk/protocol/mysqlx/pb/mysqlx_resultset.proto b/cdk/protocol/mysqlx/pb/mysqlx_resultset.proto index 9ecbf889b..bee493760 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_resultset.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_resultset.proto @@ -424,6 +424,16 @@ message FetchDone { // BYTES 0x0001 rightpad // ======= ====== =========== // +// ====== ================ +// value description +// ====== ================ +// 0x0010 NOT_NULL +// 0x0020 PRIMARY_KEY +// 0x0040 UNIQUE_KEY +// 0x0080 MULTIPLE_KEY +// 0x0100 AUTO_INCREMENT +// ====== ================ +// // default: 0 // :param content_type: // a hint about the higher-level encoding of a BYTES field @@ -487,7 +497,8 @@ message ColumnMetaData { // Row in a Resultset // // a row is represented as a list of fields encoded as byte blobs. -// Value of each field is encoded as sequence of bytes using encoding appropriate for the +// Blob of size 0 represents the NULL value. Otherwise, if it contains at least +// one byte, it encodes a non-null value of the field using encoding appropriate for the // type of the value given by ``ColumnMetadata``, as specified // in the :protobuf:msg:`Mysqlx.Resultset::ColumnMetaData` description. // diff --git a/cdk/protocol/mysqlx/pb/mysqlx_session.proto b/cdk/protocol/mysqlx/pb/mysqlx_session.proto index 818a4c788..5a6842433 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_session.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_session.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/cdk/protocol/mysqlx/pb/mysqlx_sql.proto b/cdk/protocol/mysqlx/pb/mysqlx_sql.proto index 05e4d843b..f955757ff 100644 --- a/cdk/protocol/mysqlx/pb/mysqlx_sql.proto +++ b/cdk/protocol/mysqlx/pb/mysqlx_sql.proto @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/cdk/protocol/mysqlx/protocol.cc b/cdk/protocol/mysqlx/protocol.cc index a70187fcc..70a0e1876 100644 --- a/cdk/protocol/mysqlx/protocol.cc +++ b/cdk/protocol/mysqlx/protocol.cc @@ -191,7 +191,7 @@ Protocol::Op& Protocol_impl::snd_start(Message &msg, msg_type_t msg_type) using std::endl; cerr << endl; - cerr << ">>>> Seding message >>>>" << endl; + cerr << ">>>> Sending message >>>>" << endl; cerr << "of type " << msg_type << ": " << msg_type_name(CLIENT, msg_type) << endl; cerr << msg.DebugString(); diff --git a/cdk/protocol/mysqlx/protocol.h b/cdk/protocol/mysqlx/protocol.h index 829088f08..a4695b33f 100644 --- a/cdk/protocol/mysqlx/protocol.h +++ b/cdk/protocol/mysqlx/protocol.h @@ -69,11 +69,11 @@ typedef unsigned short int msg_type_t; #elif defined(HAVE_BYTEORDER_H) #include #define bswap32(X) BSWAP_32(X) -#elif BIG_ENDIAN +#elif CDK_BIG_ENDIAN #error No byte-swap function available on big-endian platform. #endif -#if BIG_ENDIAN +#if CDK_BIG_ENDIAN #define NTOHSIZE(S) do { (S) = bswap32(S); } while(0) #define HTONSIZE(S) do { (S) = bswap32(S); } while(0) #else @@ -528,7 +528,6 @@ class Op_rcv : public Op_base { switch (type) { - // TODO: Notice case msg_type::Error: return EXPECTED; case msg_type::Notice: return EXPECTED; default: return do_next_msg(type); diff --git a/cdk/protocol/mysqlx/rset.cc b/cdk/protocol/mysqlx/rset.cc index 2349c2cb2..b49947d9a 100644 --- a/cdk/protocol/mysqlx/rset.cc +++ b/cdk/protocol/mysqlx/rset.cc @@ -110,7 +110,7 @@ class Rcv_result_base : public Op_rcv } */ - enum { MDATA, ROWS, CLOSE, DONE } m_result_state, m_next_state; + enum { START, MDATA, ROWS, CLOSE, DONE } m_result_state, m_next_state; row_count_t m_rcount; col_count_t m_ccount; @@ -164,7 +164,7 @@ class Rcv_result : public Message_dispatcher Rcv_result_base::Rcv_result_base(Protocol_impl &proto) : Op_rcv(proto) - , m_result_state(MDATA) + , m_result_state(START) , m_rcount(0) , m_ccount(0) { @@ -181,7 +181,7 @@ Rcv_result_base::Rcv_result_base(Protocol_impl &proto) void Rcv_result_base::resume(Mdata_processor &prc) { - if (MDATA != m_result_state) + if (START != m_result_state && MDATA != m_result_state) throw_error("Rcv_result: incorrect resume: attempt to read meta-data"); //TODO: Improve error report m_ccount = 0; m_completed = false; @@ -295,6 +295,18 @@ Op_rcv::Next_msg Rcv_result_base::do_next_msg(msg_type_t type) switch (m_result_state) { + case START: + + if (msg_type::Ok == type) + { + m_next_state = DONE; + m_completed = true; + return EXPECTED; + } + + m_next_state = MDATA; + // fall through to MDATA case + case MDATA: /* @@ -318,6 +330,7 @@ Op_rcv::Next_msg Rcv_result_base::do_next_msg(msg_type_t type) switch (type) { + case msg_type::ColumnMetaData: return EXPECTED; /* @@ -601,7 +614,7 @@ void Rcv_result_base::process_msg_with(Mysqlx::Resultset::ColumnMetaData &col_md col_mdata.has_catalog() ? col_mdata.catalog() : ""); if (col_mdata.has_collation()) - mdata_proc.col_charset(ccount, col_mdata.collation()); + mdata_proc.col_collation(ccount, col_mdata.collation()); if (col_mdata.has_length()) mdata_proc.col_length(ccount, col_mdata.length()); @@ -625,6 +638,13 @@ void Rcv_result_base::process_msg_with(Mysqlx::Resultset::ColumnMetaData &col_md mdata_proc.col_flags(ccount, col_mdata.flags()); } +template<> +void Rcv_result_base::process_msg_with(Mysqlx::Ok &ok, + Mdata_processor &prc) +{ + prc.ok(ok.msg()); +} + template<> void Rcv_result_base::process_msg_with(Mysqlx::Sql::StmtExecuteOk &ok, @@ -656,6 +676,7 @@ void Rcv_result::do_process_msg(msg_type_t type, Message &msg) switch (m_result_state) { + case START: case MDATA: Dispatcher::process_msg_with(type, msg, *static_cast(m_prc)); break; diff --git a/cdk/protocol/mysqlx/stmt.cc b/cdk/protocol/mysqlx/stmt.cc index 7398e11f1..1cfa95ccf 100644 --- a/cdk/protocol/mysqlx/stmt.cc +++ b/cdk/protocol/mysqlx/stmt.cc @@ -72,7 +72,7 @@ struct Arr_msg_traits Protocol::Op& Protocol::snd_StmtExecute(const char *ns, const string &stmt, - api::Any_list *args) + const api::Any_list *args) { Mysqlx::Sql::StmtExecute stmt_exec; diff --git a/cdk/protocol/mysqlx/tests/expr.h b/cdk/protocol/mysqlx/tests/expr.h index fc503aa50..94c8b8d9c 100644 --- a/cdk/protocol/mysqlx/tests/expr.h +++ b/cdk/protocol/mysqlx/tests/expr.h @@ -50,17 +50,11 @@ namespace expr { using std::min; - //using namespace ::std; -//using namespace cdk::foundation; using namespace cdk::protocol::mysqlx; namespace api { using namespace cdk::protocol::mysqlx::api; -} // papi - -//typedef cdk::byte byte; -//typedef cdk::string string; -//typedef foundation::Number_codec Number_codec; +} // api class Scalar_base : public api::Scalar @@ -137,15 +131,16 @@ class Expr_class : public B { return new E(*(E*)this); } }; + class Param_String : public Expr_class { std::string m_val; - charset_id_t m_cs; + collation_id_t m_cs; bool m_has_cs; public: - Param_String(charset_id_t cs, const std::string &val) + Param_String(collation_id_t cs, const std::string &val) : m_val(val), m_cs(cs), m_has_cs(true) {} @@ -272,12 +267,12 @@ List::List(const List &rhs) class String : public Expr_class { std::string m_val; - charset_id_t m_cs; + collation_id_t m_cs; bool m_has_cs; public: - String(charset_id_t cs, const std::string &val) + String(collation_id_t cs, const std::string &val) : m_val(val), m_cs(cs), m_has_cs(true) {} diff --git a/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc b/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc index 6ccc9f887..2abb88a88 100644 --- a/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc +++ b/cdk/protocol/mysqlx/tests/proto_mysqlx_crud-t.cc @@ -174,6 +174,78 @@ class Update }; +/* + Class implementing protocol Find_spec interface, as required by + Protocol methods which send CRUD commands. +*/ + +class Find + : public protocol::mysqlx::Find_spec +{ + protocol::mysqlx::Db_obj m_obj; + const Expression *m_expr; + const Projection *m_proj; + cdk::test::proto::Limit m_lim; + bool m_has_lim; + +public: + + Find(const Db_obj &obj, + const Expression *criteria, row_count_t limit, row_count_t skip = 0) + : m_obj(obj) + , m_expr(criteria), m_proj(NULL) + , m_lim(limit, skip), m_has_lim(true) + {} + + Find(const Db_obj &obj, + const Expression *criteria = NULL, + const Projection *proj = NULL) + : m_obj(obj) + , m_expr(criteria) + , m_proj(proj) + , m_has_lim(false) + {} + +private: + + const Db_obj& obj() const + { + return m_obj; + } + + const Expression* select() const + { + return m_expr; + } + + const Order_by* order() const + { + return NULL; + } + + const Limit* limit() const + { + return m_has_lim ? &m_lim : NULL; + } + + const Projection* project() const + { + return m_proj; + } + + const Expr_list* group_by() const + { + return NULL; + } + + const Expression* having() const + { + return NULL; + } + +}; + + TEST_F(Protocol_mysqlx_xplugin, crud_basic) { SKIP_IF_NO_XPLUGIN; @@ -189,15 +261,10 @@ TEST_F(Protocol_mysqlx_xplugin, crud_basic) Protocol &proto= get_proto(); Db_obj db_obj("crud_basic", "crud_test_db"); - Limit lim1(1, 1); + Find find1(db_obj, NULL, 1, 1); + cout <<"Find" < Number_codec; /* @@ -220,6 +223,13 @@ class Stmt_handler void execute_ok() { cout <<"Statement executed OK" <= 0) @@ -228,6 +238,7 @@ class Stmt_handler cout <<"Rows affected: " < 0); // this method should be called after calling next() @@ -367,8 +354,13 @@ class Op_collection_remove add_where(expr); } + Executable_impl* clone() const override + { + return new Op_collection_remove(*this); + } + - cdk::Reply* send_command() + cdk::Reply* send_command() override { return new cdk::Reply(get_cdk_session().coll_remove( @@ -432,17 +424,22 @@ class Op_collection_find add_where(expr); } + Executable_impl* clone() const override + { + return new Op_collection_find(*this); + } - cdk::Reply* send_command() + cdk::Reply* send_command() override { return new cdk::Reply(get_cdk_session().coll_find( m_coll, + NULL, // view spec get_where(), get_doc_proj(), get_order_by(), - nullptr, // group_by - nullptr, // having + get_group_by(), + get_having(), get_limit(), get_params() )); @@ -531,6 +528,11 @@ class Op_collection_modify add_where(expr); } + Executable_impl* clone() const override + { + return new Op_collection_modify(*this); + } + cdk::Reply* send_command() override { // Do nothing if no update specifications were added @@ -578,7 +580,7 @@ class Op_collection_modify void process(Update_spec::Processor &prc) const override { - Doc_field_parser doc_field((mysqlx::string)m_update_it->m_field); + parser::Doc_field_parser doc_field((mysqlx::string)m_update_it->m_field); switch (m_update_it->m_op) { diff --git a/devapi/impl.h b/devapi/impl.h index 9ee217bea..d93aee965 100644 --- a/devapi/impl.h +++ b/devapi/impl.h @@ -38,6 +38,8 @@ #include #include +#include "../global.h" + namespace mysqlx { @@ -536,7 +538,6 @@ class Op_base : public Impl , public cdk::Limit , public cdk::Param_source - , internal::nocopy { protected: @@ -566,6 +567,14 @@ class Op_base Op_base(Table &tbl) : m_sess(&tbl.getSession()) {} + Op_base(const Op_base& other) + : m_sess (other.m_sess ) + , m_limit (other.m_limit ) + , m_has_limit (other.m_has_limit ) + , m_offset (other.m_offset ) + , m_has_offset (other.m_has_offset) + , m_map (other.m_map ) + {} virtual ~Op_base() {} @@ -616,9 +625,14 @@ class Op_base // Parameters - void add_param(const mysqlx::string &name, Value val) + void add_param(const mysqlx::string &name, Value &&val) { - m_map.emplace(name, std::move(val)); + auto el = m_map.emplace(name, std::move(val)); + //substitute if exists + if (!el.second) + { + el.first->second = std::move(val); + } } void clear_params() @@ -760,10 +774,15 @@ class Op_sort protected: - template - Op_sort(T &x) : Op_base(x) + template ::value + >::type* = nullptr + > + Op_sort(X &x) : Op_base(x) {} + public: cdk::Order_by* get_order_by() @@ -792,9 +811,128 @@ class Op_sort }; +/* + This template adds handling of having specification on top of + Op_sort. + + It implements the `set_having` method required by implementations of + CRUD operations that support having expression. The Expression is stored + internally and transformed to the form expected by CDK: + method `get_having` return pointer to cdk::Expression (as expected + for table/collection having definition) or NULL if no having specification + is given. + + Template parameters are the implementation interface class being + implemented and parser mode for parsing expressions in order + specifications. +*/ + +template +class Op_having + : public Op_sort + , public cdk::Expression +{ + cdk::string m_having; + + void set_having(const mysqlx::string &having) + { + m_having = having; + } + +protected: + + template ::value + >::type* = nullptr + > + Op_having(X &x) : Op_sort(x) + {} + +public: + + cdk::Expression* get_having() + { + return m_having.empty() ? nullptr : this; + } + +private: + + // cdk::Expression processor + + void process(cdk::Expression:: Processor& prc) const + { + parser::Expression_parser expr_parser(PM, m_having); + expr_parser.process(prc); + } +}; + + +/* + This template adds handling of groupBy specification on top of + Op_having. + + It implements the `add_group_by` method required by implementations of + CRUD operations that support groupBy expressions. The Expressions are stored + internally and transformed to the form expected by CDK: + method `get_group_by` return pointer to cdk::Expr_list (as expected + for table/collection groupBy definition) or NULL if no groupBy specification + is given. + + Template parameters are the implementation interface class being + implemented and parser mode for parsing expressions in order + specifications. +*/ + +template +class Op_group_by + : public Op_having + , public cdk::Expr_list +{ + std::vector m_group_by; + + void add_group_by(const mysqlx::string &group_by) + { + m_group_by.push_back(group_by); + } + +protected: + + template ::value + >::type* = nullptr + > + Op_group_by(X &x) : Op_having(x) + {} + +public: + + cdk::Expr_list* get_group_by() + { + return m_group_by.empty() ? nullptr : this; + } + +private: + + void process(cdk::Expr_list::Processor& prc) const + { + prc.list_begin(); + + for (cdk::string el : m_group_by) + { + parser::Expression_parser expr_parser(PM, el); + expr_parser.process_if(prc.list_el()); + } + + prc.list_end(); + } +}; + + /* This template adds handling of projection specifications on top - of Op_order. + of Op_group_by. It implements the `add_proj` method required by implementations of CRUD operations that support projection. Projection specifications @@ -811,7 +949,7 @@ class Op_sort template class Op_projection - : public Op_sort + : public Op_group_by , public cdk::Projection , public cdk::Expression::Document { @@ -821,8 +959,13 @@ class Op_projection protected: - template - Op_projection(X &init) : Op_sort(init) + + template ::value + >::type* = nullptr + > + Op_projection(X &init) : Op_group_by(init) {} public: @@ -941,17 +1084,32 @@ class Op_select : public Base { protected: + mysqlx::string m_where_expr; std::unique_ptr m_expr; - template + template ::value + >::type* = nullptr + > Op_select(X &init) : Base(init) {} + Op_select(const Op_select &other) + : Base(other) + , m_where_expr(other.m_where_expr) + { + if (!m_where_expr.empty()) + m_expr.reset(new parser::Expression_parser(PM, m_where_expr)); + } + public: void add_where(const mysqlx::string &expr) { - m_expr.reset(new parser::Expression_parser(PM, expr)); + m_where_expr = expr; + if (!m_where_expr.empty()) + m_expr.reset(new parser::Expression_parser(PM, m_where_expr)); } cdk::Expression* get_where() const diff --git a/devapi/result.cc b/devapi/result.cc index d11ecf3c7..27cd2c2e3 100644 --- a/devapi/result.cc +++ b/devapi/result.cc @@ -386,6 +386,7 @@ class Column::Impl : public Format_info unsigned long m_length; unsigned short m_decimals; + cdk::collation_id_t m_collation; template Impl(const T &init) : Format_info(init) @@ -405,6 +406,7 @@ class Column::Impl : public Format_info m_schema_name = ci.table()->schema()->name(); } + m_collation = ci.collation(); m_length = ci.length(); assert(ci.decimals() < std::numeric_limits::max()); m_decimals = static_cast(ci.decimals()); @@ -604,11 +606,11 @@ bool Column::isPadded() const #define COLL_SWITCH(CS,ID,COLL,CASE) \ case ID: return Collation::COLL_CONST_NAME(COLL,CASE); -const CollationInfo& collation_from_charset_id(cdk::charset_id_t id) +const CollationInfo& collation_from_id(cdk::collation_id_t id) { switch (id) { - CS_LIST(CS_SWITCH) + CDK_CS_LIST(CS_SWITCH) default: THROW("Unknown collation id"); } @@ -630,8 +632,7 @@ const CollationInfo& Column::getCollation() const case cdk::TYPE_STRING: { - const Format_descr &fd = m_impl->get(); - return collation_from_charset_id(fd.m_format.charset()); + return collation_from_id(m_impl->m_collation); } case cdk::TYPE_INTEGER: @@ -646,6 +647,8 @@ const CollationInfo& Column::getCollation() const CharacterSet Column::getCharacterSet() const { + // TODO: Better use cdk encoding format information + //const Format_descr &fd = m_impl->get(); return getCollation().getCharacterSet(); } @@ -687,7 +690,7 @@ Collation::COLL_CONST_NAME(COLL,CASE) = \ #define COLL_NAME_ci(CS,COLL) #CS "_" #COLL "_ci" #define COLL_NAME_cs(CS,COLL) #CS "_" #COLL "_cs" -CS_LIST(COLL_DEFS) +CDK_CS_LIST(COLL_DEFS) /* @@ -785,15 +788,25 @@ const Row::Impl& Row::get_impl() const col_count_t Row::colCount() const { - const Impl &impl = get_impl(); - col_count_t cnt = (impl.m_mdata ? impl.m_mdata->col_count() : 0); - return impl.m_col_count > cnt ? impl.m_col_count : cnt; + try { + const Impl &impl = get_impl(); + col_count_t cnt = (impl.m_mdata ? impl.m_mdata->col_count() : 0); + return impl.m_col_count > cnt ? impl.m_col_count : cnt; + } + CATCH_AND_WRAP } bytes Row::getBytes(col_count_t pos) const { - return get_impl().get_bytes(pos); + try { + return get_impl().get_bytes(pos); + } + catch (const std::out_of_range&) + { + throw; + } + CATCH_AND_WRAP } @@ -828,68 +841,77 @@ Value& Row::get(mysqlx::col_count_t pos) */ try { - // will throw out_of_range exception if column at `pos` is NULL - bytes data = getBytes(pos); - switch (impl.m_mdata->get_type(pos)) - { - case cdk::TYPE_STRING: return impl.get(pos); - case cdk::TYPE_INTEGER: return impl.get(pos); - case cdk::TYPE_FLOAT: return impl.get(pos); - case cdk::TYPE_DOCUMENT: return impl.get(pos); + try { + // will throw out_of_range exception if column at `pos` is NULL + bytes data = getBytes(pos); - /* - TODO: Other "natural" conversions - TODO: User-defined conversions (also to user-defined types) - */ + switch (impl.m_mdata->get_type(pos)) + { + case cdk::TYPE_STRING: return impl.get(pos); + case cdk::TYPE_INTEGER: return impl.get(pos); + case cdk::TYPE_FLOAT: return impl.get(pos); + case cdk::TYPE_DOCUMENT: return impl.get(pos); - case cdk::TYPE_BYTES: + /* + TODO: Other "natural" conversions + TODO: User-defined conversions (also to user-defined types) + */ - /* - Note: in case of raw bytes, we trim the extra 0x00 byte added - at the end by the protocol (to handle NULL values). - */ + case cdk::TYPE_BYTES: - return set(pos, bytes(data.begin(), data.end() - 1)); + /* + Note: in case of raw bytes, we trim the extra 0x00 byte added + at the end by the protocol (to handle NULL values). + */ - default: + return set(pos, bytes(data.begin(), data.end() - 1)); - /* - For all types for which we do not have a natural conversion - to C++ type, we return raw bytes representing the value as - returned by protocol. - */ + default: - return set(pos, data); + /* + For all types for which we do not have a natural conversion + to C++ type, we return raw bytes representing the value as + returned by protocol. + */ + + return set(pos, data); + } } + catch (std::out_of_range&) + { + // set to NULL + return set(pos, Value()); + } + } - catch (std::out_of_range&) - { - // set to NULL - return set(pos, Value()); - } + CATCH_AND_WRAP } Value& Row::set(col_count_t pos, const Value &val) { - if (!m_impl) - m_impl = std::make_shared(); + try { + if (!m_impl) + m_impl = std::make_shared(); - Impl &impl = get_impl(); + Impl &impl = get_impl(); - impl.m_vals.emplace(pos, val); + impl.m_vals.emplace(pos, val); - if (pos + 1 > impl.m_col_count) - impl.m_col_count = pos + 1; + if (pos + 1 > impl.m_col_count) + impl.m_col_count = pos + 1; - return impl.m_vals.at(pos); + return impl.m_vals.at(pos); + } + CATCH_AND_WRAP } void Row::clear() { - m_impl.reset(); + try { m_impl.reset(); } + CATCH_AND_WRAP } @@ -906,14 +928,22 @@ template<> const Value Row::Impl::convert(cdk::bytes data, Format_descr &fd) const { + /* + String encoding has artificial 0x00 byte appended at the end to + distinguish the empty string from the null value. We skip + the trailing 0x00 byte to get just the raw bytes that encode the string. + */ + + cdk::bytes raw(data.begin(), data.end() - 1); + // If this string value is in fact a SET, then return it as raw bytes. if (fd.m_format.is_set()) - return Value(bytes(data.begin(), data.end())); + return Value(bytes(raw.begin(), raw.end())); auto &codec = fd.m_codec; cdk::string str; - codec.from_bytes(data, str); + codec.from_bytes(raw, str); return Value(std::move(str)); } @@ -1315,10 +1345,14 @@ void mysqlx::internal::BaseResult::init(mysqlx::internal::BaseResult &&init_) m_sess = init_.m_sess; - // first deregister init result, since it registered itself on ctor - // otherwise it would trigger cache, and we are moving Result object - m_sess->deregister_result(&init_); - m_sess->register_result(this); + //On empty results, m_sess is NULL, so don't do anything with it! + if (m_sess) + { + // first deregister init result, since it registered itself on ctor + // otherwise it would trigger cache, and we are moving Result object + m_sess->deregister_result(&init_); + m_sess->register_result(this); + } } diff --git a/devapi/session.cc b/devapi/session.cc index 8aa312660..7482a11d8 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -44,17 +44,25 @@ struct Endpoint struct internal::XSession_base::Options - : public cdk::ds::Options + : public cdk::ds::TCPIP::Options { Options(const string &usr, const std::string *pwd, string schema = string()) - : cdk::ds::Options(usr, pwd) + : cdk::ds::TCPIP::Options(usr, pwd) { if (!schema.empty()) set_database(schema); +#ifdef WITH_SSL + set_tls(true); +#endif } - Options() = default; + Options() + { +#ifdef WITH_SSL + set_tls(true); +#endif + } }; @@ -107,7 +115,7 @@ class internal::XSession_base::Impl , m_sess(m_ds, opt) { if (opt.database()) - m_default_db = *opt.database(); + m_default_db = *opt.database(); if (!m_sess.is_valid()) m_sess.get_error().rethrow(); } @@ -118,12 +126,21 @@ class internal::XSession_base::Impl struct URI_parser : public internal::XSession_base::Access::Options - , public endpoint::TCPIP + , private endpoint::TCPIP , public parser::URI_processor { + +#ifdef WITH_SSL + // tls off by default on URI connection + cdk::connection::TLS::Options m_tls_opt = false; +#endif + URI_parser(const std::string &uri) { parser::parse_conn_str(uri, *this); +#ifdef WITH_SSL + set_tls(m_tls_opt); +#endif } @@ -132,68 +149,158 @@ struct URI_parser return *this; } - void user(const std::string &usr) + void user(const std::string &usr) override { m_usr = usr; } - void password(const std::string &pwd) + void password(const std::string &pwd) override { m_pwd = pwd; m_has_pwd = true; } - void host(const std::string &host) + void host(const std::string &host) override { m_host = host; } - void port(unsigned short port) + void port(unsigned short port) override { m_port = port; } - virtual void path(const std::string &db) + virtual void path(const std::string &db) override { set_database(db); } -}; - -internal::XSession_base::XSession_base(const std::string &url) -{ - URI_parser parser(url); + void key_val(const std::string &key) override + { + if (key == "ssl-enable") + { +#ifdef WITH_SSL + m_tls_opt.set_use_tls(true); +#else + throw_error( + "Can not create TLS session - this connector is built" + " without TLS support." + ); +#endif + } + } - try { - m_impl = new Impl( - static_cast(parser.get_endpoint()), - static_cast(parser) - ); + void key_val(const std::string &key, const std::string &val) override + { + if (key == "ssl-ca") + { +#ifdef WITH_SSL + m_tls_opt.set_use_tls(true); + m_tls_opt.set_ca(val); +#else + throw_error( + "Can not create TLS session - this connector is built" + " without TLS support." + ); +#endif + } else + { + std::stringstream err; + err << "Unexpected key " << key << "=" << val << " on URI"; + throw_error(err.str().c_str()); + } } - CATCH_AND_WRAP -} -internal::XSession_base::XSession_base( - const std::string &host, unsigned port, - const string &user, const char *pwd, - const string &db) +}; + + +internal::XSession_base::XSession_base(SessionSettings settings) { try { - std::string pwd_str; - if (pwd) - pwd_str = pwd; + if (settings.has_option(SessionSettings::URI)) + { + URI_parser parser( + settings[SessionSettings::URI].get() + ); + + m_impl = new Impl( + static_cast(parser.get_endpoint()), + static_cast(parser)); + } + else + { + std::string host = "localhost"; + if (settings.has_option(SessionSettings::HOST)) + host = settings[SessionSettings::HOST].get(); + + unsigned port = DEFAULT_MYSQLX_PORT; - if (port > 65535U) - throw_error("Port value out of range"); + if (settings.has_option(SessionSettings::PORT)) + port = settings[SessionSettings::PORT]; - endpoint::TCPIP ep(host, (uint16_t)port); - Options opt(user, pwd ? &pwd_str : NULL); + if (port > 65535U) + throw_error("Port value out of range"); - if (!db.empty()) - opt.set_database(db); - m_impl = new Impl(ep, opt); + std::string pwd_str; + bool has_pwd = false; + + if (settings.has_option(SessionSettings::PWD) && + settings[SessionSettings::PWD].isNull() == false) + { + has_pwd = true; + pwd_str = settings[SessionSettings::PWD].get(); + } + + endpoint::TCPIP ep( host, (uint16_t)port); + + string user; + + if (settings.has_option(SessionSettings::USER)) + { + user = settings[SessionSettings::USER]; + } + else + { + throw Error("User not defined!"); + } + + Options opt(user, has_pwd ? &pwd_str : NULL); + + if (settings.has_option(SessionSettings::DB)) + opt.set_database( + settings[SessionSettings::DB].get() + ); + + if (settings.has_option(SessionSettings::SSL_ENABLE) || + settings.has_option(SessionSettings::SSL_CA)) + { +#ifdef WITH_SSL + + //ssl_enable by default, unless SSL_ENABLE = false + bool ssl_enable = true; + if (settings.has_option(SessionSettings::SSL_ENABLE)) + ssl_enable = settings[SessionSettings::SSL_ENABLE]; + + cdk::connection::TLS::Options opt_ssl(ssl_enable); + + + if (settings.has_option(SessionSettings::SSL_CA)) + opt_ssl.set_ca(settings[SessionSettings::SSL_CA].get()); + + opt.set_tls(opt_ssl); +#else + throw_error( + "Can not create TLS session - this connector is built" + " without TLS support." + ); +#endif + } + + m_impl = new Impl(ep, opt); + + } } CATCH_AND_WRAP } @@ -311,7 +418,7 @@ void internal::XSession_base::close() NodeSession XSession::bindToDefaultShard() { - return this; + return static_cast(this); } // --------------------------------------------------------------------- @@ -750,6 +857,11 @@ Schema internal::XSession_base::getDefaultSchema() return Schema(*this, m_impl->m_default_db); } +string internal::XSession_base::getDefaultSchemaName() +{ + return m_impl->m_default_db; +} + Schema internal::XSession_base::getSchema(const string &name, bool check) { @@ -1088,12 +1200,18 @@ struct Op_sql : public Op_base } m_params; - void add_param(Value val) + void add_param(Value val) override { m_params.m_values.emplace_back(std::move(val)); } - cdk::Reply* send_command() + Executable_impl* clone() const override + { + return new Op_sql(*this); + } + + + cdk::Reply* send_command() override { return new cdk::Reply( get_cdk_session().sql( diff --git a/devapi/table_crud.cc b/devapi/table_crud.cc index 951b04257..b5edfe3bc 100644 --- a/devapi/table_crud.cc +++ b/devapi/table_crud.cc @@ -30,12 +30,12 @@ #include #include #include +#include #include "impl.h" using namespace mysqlx; -using cdk::string; -using namespace parser; +using parser::Parser_mode; // -------------------------------------------------------------------- @@ -84,6 +84,17 @@ class Op_table_insert , m_table(tbl) {} + Op_table_insert(const Op_table_insert &other) + : Op_sort(other) + , m_table(other.m_table) + , m_rows(other.m_rows) + , m_cols(other.m_cols) + {} + + Executable_impl* clone() const override + { + return new Op_table_insert(*this); + } void add_column(const mysqlx::string &column) override { @@ -208,22 +219,34 @@ class Op_table_select //typedef cdk::string string; Table_ref m_table; + const cdk::View_spec *m_view = nullptr; cdk::Reply* send_command() override { return new cdk::Reply(get_cdk_session().table_select( m_table, + m_view, // view spec get_where(), get_tbl_proj(), get_order_by(), - nullptr, - nullptr, + get_group_by(), + get_having(), get_limit(), get_params() )); } + void set_view(const cdk::View_spec *view) + { + m_view = view; + } + + + Executable_impl* clone() const override + { + return new Op_table_select(*this); + } public: @@ -232,7 +255,10 @@ class Op_table_select , m_table(table) {} + + friend mysqlx::TableSelect; + friend mysqlx::internal::Op_ViewCreateAlter; }; @@ -280,6 +306,11 @@ class Op_table_update SetValues m_set_values; SetValues::const_iterator m_set_it; + Executable_impl* clone() const override + { + return new Op_table_update(*this); + } + void add_set(const mysqlx::string &field, internal::ExprValue &&val) override { m_set_values[field] = std::move(val); @@ -327,7 +358,10 @@ class Op_table_update prc.column(*this); Value_expr val_prc(m_set_it->second, parser::Parser_mode::TABLE); - val_prc.process_if(prc.set(m_table_field->path())); + + val_prc.process_if( + prc.set(m_table_field->has_path() ? m_table_field.get() : NULL) + ); } @@ -343,6 +377,7 @@ class Op_table_update return m_table_field->table(); } + public: Op_table_update(Table &table) @@ -350,6 +385,12 @@ class Op_table_update , m_table(table) {} + Op_table_update(const Op_table_update &other) + : Op_select(other) + , m_table(other.m_table) + , m_set_values(other.m_set_values) + {} + friend mysqlx::TableUpdate; }; @@ -389,6 +430,12 @@ class Op_table_remove Table_ref m_table; + Executable_impl* clone() const override + { + return new Op_table_remove(*this); + } + + cdk::Reply* send_command() override { return @@ -409,6 +456,7 @@ class Op_table_remove {} + friend mysqlx::TableRemove; }; @@ -417,3 +465,264 @@ void TableRemove::prepare(Table &table) { m_impl.reset(new Op_table_remove(table)); } + + +// -------------------------------------------------------------------- + +/* + ViewCreateAlter + =============== +*/ + +namespace mysqlx{ +namespace internal { + +class Op_ViewCreateAlter + : public Op_base + , cdk::View_spec + , Table_ref +{ +public: + typedef cdk::View_spec::op_type op_type; + +private: + + op_type m_op_type; + std::unique_ptr m_table_select; + std::vector m_columns; + + CheckOption m_check_option; + SQLSecurity m_security; + Algorithm m_algorithm; + mysqlx::string m_definer; + + enum view_option { CHECK, SECURITY, ALGORITHM, DEFINER, LAST}; + std::bitset m_opts_mask; + + Executable_impl* clone() const override + { + return new Op_ViewCreateAlter(*this); + } + + Op_ViewCreateAlter(const Op_ViewCreateAlter& other) + : Op_base(other) + , Table_ref(other) + , m_op_type (other.m_op_type ) + , m_columns (other.m_columns ) + , m_check_option (other.m_check_option) + , m_security (other.m_security ) + , m_algorithm (other.m_algorithm ) + , m_definer (other.m_definer ) + , m_opts_mask (other.m_opts_mask ) + { + if (other.m_table_select.get() != NULL) + { + m_table_select.reset(new TableSelect(*other.m_table_select.get())); + static_cast(m_table_select->get_impl())->set_view(this); + } + } + +public: + + Op_ViewCreateAlter(Schema &sch, const mysqlx::string &name, op_type replace) + : Op_base< mysqlx::internal::View_impl >(sch.getSession()) + , Table_ref(sch.getName(), name) + , m_op_type(replace) + {} + + void with_check_option(CheckOption option) override + { + m_check_option = option; + m_opts_mask.set(CHECK); + } + + void defined_as(TableSelect &&select) override + { + m_table_select.reset(new TableSelect(std::move(select))); + static_cast(m_table_select->get_impl())->set_view(this); + } + + void definer(const mysqlx::string &user) override + { + m_definer = user; + m_opts_mask.set(DEFINER); + } + + void security(SQLSecurity security) override + { + m_security = security; + m_opts_mask.set(SECURITY); + } + + void algorithm(Algorithm algorythm) override + { + m_algorithm = algorythm; + m_opts_mask.set(ALGORITHM); + } + + void add_columns(const mysqlx::string &name) override + { + m_columns.push_back(name); + } + + cdk::Reply* send_command() override + { + if (m_table_select.get() == NULL) + throw_error("Unexpected empty TableSelect"); + + cdk::Reply *ret = + static_cast(m_table_select->get_impl())->send_command(); + + return ret; + + } + + /* + cdk::View_spec Processor + */ + + void process( cdk::View_spec::Processor &prc) const override + { + prc.name(*this, m_op_type); + + if (m_columns.size() != 0) + { + auto list_columns = prc.columns(); + if (list_columns) + { + list_columns->list_begin(); + for (auto column : m_columns) + { + list_columns->list_el()->val(column); + } + list_columns->list_end(); + } + } + + auto options = prc.options(); + + if (options) + { + + if (m_opts_mask.test(DEFINER)) + options->definer(m_definer); + + if (m_opts_mask.test(ALGORITHM)) + switch (m_algorithm) + { + case Algorithm::MERGE: + options->algorithm(cdk::api::View_algorithm::MERGE); + break; + case Algorithm::TEMPTABLE: + options->algorithm(cdk::api::View_algorithm::TEMPTABLE); + break; + case Algorithm::UNDEFINED: + options->algorithm(cdk::api::View_algorithm::UNDEFINED); + break; + }; + + if (m_opts_mask.test(CHECK)) + switch(m_check_option) + { + case CheckOption::CASCADED: + options->check(cdk::api::View_check::CASCADED); + break; + case CheckOption::LOCAL: + options->check(cdk::api::View_check::LOCAL); + break; + }; + + if (m_opts_mask.test(SECURITY)) + switch(m_security) + { + case SQLSecurity::DEFINER: + options->security(cdk::api::View_security::DEFINER); + break; + case SQLSecurity::INVOKER: + options->security(cdk::api::View_security::INVOKER); + break; + }; + } + + } +}; + +}} // namespace mysqlx::internal + +namespace mysqlx { + +ViewCreate::ViewCreate(Schema &sch, const string &name, bool replace) +{ + m_impl.reset( + new internal::Op_ViewCreateAlter(sch, + name, + replace ? + internal::Op_ViewCreateAlter::op_type::REPLACE : + internal::Op_ViewCreateAlter::op_type::CREATE ) + ); +} + + + +ViewAlter::ViewAlter(Schema &sch, const string &name) +{ + m_impl.reset( + new internal::Op_ViewCreateAlter(sch, + name, + internal::Op_ViewCreateAlter::op_type::UPDATE) + ); +} + +} // namespace mysqlx + + + +/* + ViewDrop + ======== +*/ + +namespace mysqlx { +namespace internal{ + +class Op_ViewDrop + : public Op_base + , public Table_ref +{ + bool m_checkExistence = true; + +public: + + Op_ViewDrop(Schema &sch, const string &name) + : Op_base(sch.getSession()) + , Table_ref(sch.getName(), name) + {} + + void if_exists() override + { + m_checkExistence = false; + } + + Executable_impl* clone() const override + { + return new Op_ViewDrop(*this); + } + + cdk::Reply* send_command() override + { + return new cdk::Reply(get_cdk_session().view_drop(*this,m_checkExistence)); + } +}; + +} // namespace internal + +ViewDrop::ViewDrop(Schema &sch, const string &name) +{ + m_impl.reset(new internal::Op_ViewDrop(sch, name)); +} + +} // namespace mysqlx + + + +// --------------------------------------------------------------------- diff --git a/devapi/tests/crud-t.cc b/devapi/tests/crud-t.cc index b6d03e528..98a0941a5 100644 --- a/devapi/tests/crud-t.cc +++ b/devapi/tests/crud-t.cc @@ -25,6 +25,7 @@ #include #include #include +#include using std::cout; using std::endl; @@ -33,6 +34,23 @@ using namespace mysqlx; class Crud : public mysqlx::test::Xplugin { public: + + void SetUp() + { + Xplugin::SetUp(); + + /* + Clear sql_mode to work around problems with how + xplugin handles group_by queries (the "only_full_group_by" + mode which is enabled by default). + */ + try { + get_sess().sql("set sql_mode=''").execute(); + } + catch (...) + {} + } + void add_data(Collection &coll); }; @@ -830,6 +848,13 @@ TEST_F(Crud, table) std::vector cols = {"_id"}; + //Inserting empty list + + //Bug #25515964 + //Adding empty list shouldn't do anything + std::list rList; + tbl.insert(cols, "age", string("name")).rows(rList).rows(rList).execute(); + //Using containers (vectors, const char* and string) auto insert = tbl.insert(cols, "age", string("name")); @@ -1838,4 +1863,194 @@ TEST_F(Crud, doc_id) EXPECT_THROW(coll.add("{\"_id\": 127 }").execute(), Error); EXPECT_THROW(coll.add("{\"_id\": 12.7 }").execute(), Error); -} \ No newline at end of file +} + +TEST_F(Crud, group_by_having) +{ + + SKIP_IF_NO_XPLUGIN; + + cout << "Preparing table..." << endl; + + XSession sess(this); + + sess.dropCollection("test", "coll"); + + Collection coll = sess.createSchema("test", true) + .createCollection("coll", true); + + Table tbl = sess.createSchema("test", true).getCollectionAsTable("coll", true); + + coll.remove().execute(); + + std::vector names = {"Foo", "Baz", "Bar"}; + + int i=0; + + for (auto name : names) + { + std::stringstream json; + json <<"{ \"_id\":\""<< i << "\", \"user\":\"" << name << "\", \"age\":" << 20+i << "}"; + coll.add(json.str()).execute(); + ++i; + } + + // Function to check order of operation + auto check_order = [&names] (DocResult &coll_res, RowResult &tbl_res) + { + DbDoc coll_row = coll_res.fetchOne(); + Row tbl_row = tbl_res.fetchOne(); + + for (auto name = names.begin(); + coll_row && tbl_row && name != names.end(); + coll_row = coll_res.fetchOne(), + tbl_row = tbl_res.fetchOne(), + ++name) + { + EXPECT_EQ(*name, static_cast(coll_row["user"])); + EXPECT_EQ(*name, static_cast(tbl_row[0])); + } + + EXPECT_TRUE(coll_row.isNull()); + EXPECT_TRUE(tbl_row.isNull()); + }; + + auto coll_res = coll.find().fields("user AS user", "age as age").execute(); + auto tbl_res = tbl.select("doc->$.user as user","doc->$.age as age").execute(); + + check_order(coll_res, tbl_res); + + cout << "Check with groupBy" << endl; + std::sort(names.begin(), names.end()); + + std::vector fields = {"user"}; + coll_res = coll.find() + .fields("user AS user", "age as age") + .groupBy(fields, "age") + .execute(); + + cout << "and on table" << endl; + tbl_res = tbl.select("doc->$.user as user", "doc->$.age as age") + .groupBy(fields,"age") + .execute(); + + + check_order(coll_res, tbl_res); + + + cout << "Having usage will remove last element of previous groupBy." << endl; + names.pop_back(); + + coll_res = coll.find() + .fields("user AS user", "age as age") + .groupBy(fields,"age") + .having(L"age > 20") + .execute(); + + //and on table + tbl_res = tbl.select("doc->$.user as user", "doc->$.age as age") + .groupBy(fields, "age") + .having(L"age > 20") + .execute(); + + check_order(coll_res, tbl_res); + + cout << "Same test but passing std::string to groupBy" << endl; + + coll_res = coll.find() + .fields("user AS user", "age as age") + .groupBy(fields, std::string("age")) + .having(std::string("age > 20")) + .execute(); + + cout << "and on table" << endl; + tbl_res = tbl.select("doc->$.user as user", "doc->$.age as age") + .groupBy(fields, std::string("age")) + .having(std::string("age > 20")) + .execute(); + + check_order(coll_res, tbl_res); + +} + +TEST_F(Crud, copy_semantics) +{ + SKIP_IF_NO_XPLUGIN; + + cout << "Creating session..." << endl; + + XSession sess(this); + + cout << "Session accepted, creating collection..." << endl; + + Schema sch = sess.getSchema("test"); + Collection coll = sch.createCollection("c1", true); + + add_data(coll); + + + cout << "Fetching documents..." << endl; + + CollectionFind find = coll.find("name like :name and age < :age"); + find.bind("name", "ba%"); + find.bind("age", 3); + + CollectionFind find2 = find; + + DocResult docs = find2.execute(); + + DbDoc doc = docs.fetchOne(); + + unsigned i = 0; + for (; doc; ++i, doc = docs.fetchOne()) + { + cout << "doc#" << i << ": " << doc << endl; + + for (Field fld : doc) + { + cout << " field `" << fld << "`: " << doc[fld] << endl; + } + + string name = doc["name"]; + cout << " name: " << name << endl; + + EXPECT_EQ(string("bar"), (string)doc["name"]); + + cout << " age: " << doc["age"] << endl; + + EXPECT_EQ(2, (int)doc["age"]); + + cout << endl; + } + + EXPECT_EQ(1, i); + + std::map args; + + args["name"] = "ba%"; + args["age"] = 3; + + CollectionRemove remove(coll, "name like :name and age < :age"); + + remove.bind(args); + + CollectionRemove remove2 = remove; + + remove2.execute(); + + { + CollectionFind f(coll, "name like :name and age < :age"); + + CollectionFind find2 = f; + + find2.bind(args); + + docs = find2.execute(); + + doc = docs.fetchOne(); + EXPECT_FALSE((bool)doc); + } + + + cout << "Done!" << endl; +} diff --git a/devapi/tests/ddl-t.cc b/devapi/tests/ddl-t.cc index 7f48e256d..d1909a77b 100644 --- a/devapi/tests/ddl-t.cc +++ b/devapi/tests/ddl-t.cc @@ -109,10 +109,6 @@ TEST_F(Ddl, create_drop) EXPECT_THROW(schema.getTable("tb1", true), mysqlx::Error); EXPECT_THROW(schema.getTable("tb2", true), mysqlx::Error); - // xplugin is not reporting view because view uses deleted table. - // checking this with xplugin team - EXPECT_THROW(schema.getTable("view1", true), mysqlx::Error); - } //Collection tests diff --git a/devapi/tests/session-t.cc b/devapi/tests/session-t.cc index 6a9018bcf..52dc4ae2c 100644 --- a/devapi/tests/session-t.cc +++ b/devapi/tests/session-t.cc @@ -161,6 +161,7 @@ TEST_F(Sess, default_schema) mysqlx::NodeSession s(m_port, m_user, m_password, "test"); EXPECT_EQ(string("test"), s.getDefaultSchema().getName()); + EXPECT_EQ(string("test"), s.getDefaultSchemaName()); SqlResult res = s.sql(L"SELECT DATABASE()").execute(); string db = res.fetchOne()[0]; EXPECT_EQ(string("test"), db); @@ -176,6 +177,7 @@ TEST_F(Sess, default_schema) mysqlx::NodeSession s(url); EXPECT_EQ(string("test"), s.getDefaultSchema().getName()); + EXPECT_EQ(string("test"), s.getDefaultSchemaName()); SqlResult res = s.sql(L"SELECT DATABASE()").execute(); string db = res.fetchOne()[0]; EXPECT_EQ(string("test"), db); @@ -350,3 +352,232 @@ TEST_F(Sess, bind_node_session) cout << "Done!" << endl; } + + +TEST_F(Sess, ssl_session) +{ + + SKIP_IF_NO_XPLUGIN; + + //Test if ssl is enabled using cipher + auto check_ssl_impl = [](mysqlx::XSession &sess, bool enable, int line) + { + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << "Line "<< line << ": " << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_EQ(enable, !cipher.empty()); + }; + +#define check_ssl(x,y) check_ssl_impl(x, y, __LINE__) + + + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, true); + + check_ssl(sess, true); + } + + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER, get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, false); + + check_ssl(sess, false); + } + + //Using URI + + std::stringstream uri; + + uri << "mysqlx://" << get_user(); + + if (get_password() && *get_password()) + uri << ":"<< get_password(); + + uri << "@" << "localhost:" << get_port(); + + //URI without ssl_enable + { + mysqlx::XSession sess(uri.str()); + check_ssl(sess, false); + } + + + { + std::stringstream uri_ssl; + //Enable SSL + uri_ssl << uri.str() << "/?ssl-enable"; + + mysqlx::XSession sess(uri_ssl.str()); + check_ssl(sess, true); + } + + + //using wrong ssl-ca as SessionSettings + { + EXPECT_THROW( + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, true, + SessionSettings::SSL_CA, "unknown") + , mysqlx::Error); + + + } + + //using wrong ssl-ca and ssl-ca-path on URI + { + std::stringstream bad_uri; + bad_uri << uri.str() << "/?ssl-ca=" << "unknown.file"; + + EXPECT_THROW(mysqlx::XSession sess(bad_uri.str()), mysqlx::Error); + } + + string ssl_ca; + string datadir; + + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard() + .sql("show global variables like 'ssl_ca'") + .execute(); + + ssl_ca = res.fetchOne().get(1); + + res = sess.bindToDefaultShard() + .sql("show global variables like 'datadir'") + .execute(); + + datadir = res.fetchOne().get(1); + + } + + std::cout << "ssl-ca:" << ssl_ca + << " datadir:" << datadir + << std::endl; + + if (ssl_ca.find('\\') == string::npos && ssl_ca.find('/') == string::npos) + { //not full path + ssl_ca = datadir + ssl_ca; + } + + uri << "/?ssl-ca=" << ssl_ca; + + { + mysqlx::XSession sess(uri.str()); + check_ssl(sess, true); + } + + //using ssl-enable and ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, true, + SessionSettings::SSL_CA, ssl_ca); + + check_ssl(sess, true); + + } + + //using ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_CA, ssl_ca); + + check_ssl(sess, true); + + } + + //using ssl-ca but ssl-enable = false on SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, false, + SessionSettings::SSL_CA, ssl_ca); + + check_ssl(sess, false); + + } + + //using ssl-enable and ssl-ca as SessionSettings + { + mysqlx::XSession sess(SessionSettings::PORT, get_port(), + SessionSettings::USER,get_user(), + SessionSettings::PWD, get_password() ? get_password() : NULL , + SessionSettings::SSL_ENABLE, true, + SessionSettings::SSL_CA, ssl_ca); + + check_ssl(sess, true); + + } + +} + + +TEST_F(Sess, ipv6) +{ + + SKIP_IF_NO_XPLUGIN; + + { + mysqlx::XSession sess(SessionSettings::HOST, "::1", + SessionSettings::PORT, get_port(), + SessionSettings::USER, get_user(), + SessionSettings::PWD, get_password() ? get_password() : nullptr , + SessionSettings::SSL_ENABLE, false); + } + + //Using URI + + std::stringstream uri; + + uri << "mysqlx://" << get_user(); + + if (get_password() && *get_password()) + uri << ":"<< get_password(); + + uri << "@" << "[::1]:" << get_port(); + + //URI without ssl_enable + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_TRUE(cipher.empty()); + } + + //Enable SSL + uri << "/?ssl-enable"; + { + mysqlx::XSession sess(uri.str()); + + SqlResult res = sess.bindToDefaultShard().sql("SHOW STATUS LIKE 'mysqlx_ssl_cipher'").execute(); + + auto row = res.fetchOne(); + cout << row[0] << ":" << row[1] << endl; + + string cipher = row[1]; + + EXPECT_FALSE(cipher.empty()); + } +} diff --git a/devapi/tests/types-t.cc b/devapi/tests/types-t.cc index a16c1e0a3..e93bc1431 100644 --- a/devapi/tests/types-t.cc +++ b/devapi/tests/types-t.cc @@ -398,27 +398,17 @@ TEST_F(Types, string) sql( "CREATE TABLE test.types(" " c0 VARCHAR(10) COLLATE latin2_general_ci," - " c1 VARCHAR(32) COLLATE utf8_swedish_ci" + " c1 VARCHAR(32) COLLATE utf8_swedish_ci," + " c2 VARCHAR(32) CHARACTER SET latin2" ")" ); Table types = getSchema("test").getTable("types"); - /* - FIXME: For table columns using non utf8 encoding, any non-ascii - characters are returned by xplugin using the column encoding. This - causes errors when reading data because we asssume xplugin - sends strings using utf8 encoding. Check X protocol specs. - - When this is fixed, the first string should use some non-ascii - characters that can be represented in latin2 (str0 can be made - the same as str1). - */ - string str0(L"Foobar"); string str1(L"Mog\u0119 je\u015B\u0107 szk\u0142o"); - types.insert().values(str0, str1).execute(); + types.insert().values(str0, str1, str1).execute(); cout << "Table prepared, querying it..." << endl; @@ -449,10 +439,28 @@ TEST_F(Types, string) EXPECT_EQ(CharacterSet::utf8, c1.getCharacterSet()); EXPECT_EQ(Collation::swedish_ci, c1.getCollation()); + Column c2 = res.getColumn(2); + EXPECT_EQ(Type::STRING, c2.getType()); + cout << "column #2 length: " << c2.getLength() << endl; + cout << "column #2 charset: " << c2.getCharacterSetName() << endl; + cout << "column #2 collation: " << c2.getCollationName() << endl; + + EXPECT_EQ(CharacterSet::latin2, c2.getCharacterSet()); + Row row = res.fetchOne(); EXPECT_EQ(str0, (string)row[0]); EXPECT_EQ(str1, (string)row[1]); + + /* + FIXME: the third colum contains non-utf8 string which uses non-ascii + characters. Currently we do not handle such strings and an error is + thrown on an attempt of converting it to a C++ string. + + Replace with EXPECT_EQ() once we handle all MySQL charsets. + */ + + EXPECT_THROW((string)row[2], Error); } diff --git a/doc/building.txt b/doc/building.txt index 99870c1fe..0ba4ca344 100644 --- a/doc/building.txt +++ b/doc/building.txt @@ -242,7 +242,7 @@ C++ runtime library.