diff --git a/CMakeLists.txt b/CMakeLists.txt index b8e45c18..b5e9a16f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ PROJECT(mariadb-connector-c C) SET(PACKAGE_STATUS_SUFFIX "alpha") SET(CPACK_PACKAGE_VERSION_MAJOR 3) -SET(CPACK_PACKAGE_VERSION_MINOR 0) +SET(CPACK_PACKAGE_VERSION_MINOR 1) SET(CPACK_PACKAGE_VERSION_PATCH 0) SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") @@ -28,7 +28,7 @@ IF(CMAKE_VERSION VERSION_GREATER "2.9.9") CMAKE_POLICY(SET CMP0045 OLD) ENDIF() -SET(MARIADB_CONNECTOR_C_COPYRIGHT "2013-2015 MariaDB Corporation Ab") +SET(MARIADB_CONNECTOR_C_COPYRIGHT "2013-2016 MariaDB Corporation Ab") ### Options ### IF(NOT WIN32) @@ -37,7 +37,6 @@ ELSE() OPTION(WITH_SIGNCODE "digitally sign files" OFF) OPTION(WITH_RTC "enables run time checks for debug builds" OFF) ENDIF() -OPTION(WITH_REMOTEIO "enables remote io support (requires libcurl)" OFF) OPTION(WITH_EXTERNAL_ZLIB "Enables use of external zlib" OFF) ############### @@ -53,8 +52,25 @@ IF(WITH_RTC) SET(RTC_OPTIONS "/RTC1 /RTCc") ENDIF() +INCLUDE(FindCURL) +IF(CURL_FOUND) + ADD_DEFINITIONS(-DHAVE_CURL=1) +ENDIF() + +IF(NOT WIN32) + INCLUDE(${CMAKE_SOURCE_DIR}/cmake/FindGSSAPI.cmake) + IF(GSSAPI_FOUND) + INCLUDE_DIRECTORIES(${GSSAPI_INCS}) + ENDIF() +ENDIF() + INCLUDE(${CMAKE_SOURCE_DIR}/cmake/plugins.cmake) +IF(AUTH_GSSAPI_PLUGIN_TYPE MATCHES "STATIC") + SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${GSSAPI_LIBS}) +ENDIF() + + IF(WIN32) FILE(REMOVE ${CMAKE_BINARY_DIR}/win/packaging/plugin.conf) INCLUDE(${CMAKE_SOURCE_DIR}/cmake/version_info.cmake) @@ -101,9 +117,9 @@ ENDIF() # various defines for generating include/mysql_version.h SET(PROTOCOL_VERSION 10) # we adapted new password option from PHP's mysqlnd ! -SET(MYSQL_CLIENT_VERSION_MAJOR "5") -SET(MYSQL_CLIENT_VERSION_MINOR "5") -SET(MYSQL_CLIENT_VERSION_PATCH "2") +SET(MYSQL_CLIENT_VERSION_MAJOR "10") +SET(MYSQL_CLIENT_VERSION_MINOR "1") +SET(MYSQL_CLIENT_VERSION_PATCH "7") SET(MYSQL_CLIENT_VERSION "${MYSQL_CLIENT_VERSION_MAJOR}.${MYSQL_CLIENT_VERSION_MINOR}.${MYSQL_CLIENT_VERSION_PATCH}") MATH(EXPR MYSQL_VERSION_ID "${MYSQL_CLIENT_VERSION_MAJOR} * 10000 + ${MYSQL_CLIENT_VERSION_MINOR} * 100 + @@ -133,17 +149,15 @@ ENDIF() IF(UNIX) - SEARCH_LIBRARY(LIBNSL inet_ntoa "nsl_r;nsl") - SEARCH_LIBRARY(LIBBIND bind "bind;socket") - SEARCH_LIBRARY(LIBSOCKET setsockopt "socket") SEARCH_LIBRARY(LIBDL dlopen "dl") SEARCH_LIBRARY(LIBM floor m) - # SEARCH_LIBRARY(LIBICONV iconv iconv) SEARCH_LIBRARY(LIBPTHREAD pthread_getspecific "pthread;pthreads") - SET(EXTRA_LIBS "${LIBNSL}" "${LIBBIND}" "${LIBSOCKET}") FIND_PACKAGE(Threads) SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${LIBNSL} ${LIBBIND} ${LIBICONV} ${LIBSOCKET} ${LIBDL} ${LIBM} ${LIBPTHREAD}) + SET(SYSTEM_LIBS ${LIBNSL} ${LIBBIND} ${LIBICONV} + ${LIBSOCKET} ${LIBDL} ${LIBM} ${LIBPTHREAD}) + MESSAGE(STATUS "SYSTEM_LIBS ${SYSTEM_LIBS}") #remove possible dups from required libraries LIST(LENGTH CMAKE_REQUIRED_LIBRARIES rllength) IF(${rllength} GREATER 0) @@ -178,7 +192,7 @@ INCLUDE(${CMAKE_SOURCE_DIR}/cmake/CheckFunctions.cmake) # check for various types INCLUDE(${CMAKE_SOURCE_DIR}/cmake/CheckTypes.cmake) -IF(NOT WITH_SSL) +IF(NOT WITH_SSL AND NOT WITH_SSL STREQUAL "OFF") IF(WIN32) SET(WITH_SSL "SCHANNEL") ELSE() @@ -245,7 +259,28 @@ ENDIF() IF(WITH_SSL) SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${SSL_LIBRARIES}) ENDIF() +MARK_AS_ADVANCED(SYSTEM_LIBS) +IF(NOT REMOTEIO_PLUGIN_TYPE MATCHES "OFF") + IF(CURL_FOUND) + INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIRS}) + IF(REMOTEIO_PLUGIN_TYPE MATCHES "STATIC") + SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${CURL_LIBRARIES}) + ENDIF() + ADD_DEFINITIONS("-DHAVE_REMOTEIO=1") + ENDIF() +ENDIF() +IF(NOT WIN32) + IF(NOT AUTH_GSSAPI_PLUGIN_TYPE MATCHES "OFF") + INCLUDE(${CMAKE_SOURCE_DIR}/cmake/FindGSSAPI.cmake) + IF(GSSAPI_FOUND) + INCLUDE_DIRECTORIES(${GSSAPI_INCS}) + IF(AUTH_GSSAPI_PLUGIN_TYPE MATCHES "STATIC") + SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${GSSAPI_LIBS}) + ENDIF() + ENDIF() + ENDIF() +ENDIF() ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(libmariadb) ADD_SUBDIRECTORY(plugins) diff --git a/cmake/CheckIncludeFiles.cmake b/cmake/CheckIncludeFiles.cmake index f5dde977..5aaabc8e 100644 --- a/cmake/CheckIncludeFiles.cmake +++ b/cmake/CheckIncludeFiles.cmake @@ -66,3 +66,4 @@ CHECK_INCLUDE_FILES (termio.h HAVE_TERMIO_H) CHECK_INCLUDE_FILES (termios.h HAVE_TERMIOS_H) CHECK_INCLUDE_FILES (unistd.h HAVE_UNISTD_H) CHECK_INCLUDE_FILES (utime.h HAVE_UTIME_H) +CHECK_INCLUDE_FILES (ucontext.h HAVE_UCONTEXT_H) diff --git a/cmake/FindGSSAPI.cmake b/cmake/FindGSSAPI.cmake new file mode 100644 index 00000000..3a1c83cd --- /dev/null +++ b/cmake/FindGSSAPI.cmake @@ -0,0 +1,99 @@ +# - Try to detect the GSSAPI support +# Once done this will define +# +# GSSAPI_FOUND - system supports GSSAPI +# GSSAPI_INCS - the GSSAPI include directory +# GSSAPI_LIBS - the libraries needed to use GSSAPI +# GSSAPI_FLAVOR - the type of API - MIT or HEIMDAL + +# Copyright (c) 2006, Pino Toscano, +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if(GSSAPI_LIBS AND GSSAPI_FLAVOR) + + # in cache already + set(GSSAPI_FOUND TRUE) + +else(GSSAPI_LIBS AND GSSAPI_FLAVOR) + + find_program(KRB5_CONFIG NAMES krb5-config PATHS + /opt/local/bin + /usr/lib/mit/bin/ + ONLY_CMAKE_FIND_ROOT_PATH # this is required when cross compiling with cmake 2.6 and ignored with cmake 2.4, Alex + ) + mark_as_advanced(KRB5_CONFIG) + + #reset vars + set(GSSAPI_INCS) + set(GSSAPI_LIBS) + set(GSSAPI_FLAVOR) + + if(KRB5_CONFIG) + + set(HAVE_KRB5_GSSAPI TRUE) + exec_program(${KRB5_CONFIG} ARGS --libs gssapi RETURN_VALUE _return_VALUE OUTPUT_VARIABLE GSSAPI_LIBS) + if(_return_VALUE) + message(STATUS "GSSAPI configure check failed.") + set(HAVE_KRB5_GSSAPI FALSE) + endif(_return_VALUE) + + exec_program(${KRB5_CONFIG} ARGS --cflags gssapi RETURN_VALUE _return_VALUE OUTPUT_VARIABLE GSSAPI_INCS) + string(REGEX REPLACE "(\r?\n)+$" "" GSSAPI_INCS "${GSSAPI_INCS}") + string(REGEX REPLACE " *-I" ";" GSSAPI_INCS "${GSSAPI_INCS}") + + exec_program(${KRB5_CONFIG} ARGS --vendor RETURN_VALUE _return_VALUE OUTPUT_VARIABLE gssapi_flavor_tmp) + set(GSSAPI_FLAVOR_MIT) + if(gssapi_flavor_tmp MATCHES ".*Massachusetts.*") + set(GSSAPI_FLAVOR "MIT") + else(gssapi_flavor_tmp MATCHES ".*Massachusetts.*") + set(GSSAPI_FLAVOR "HEIMDAL") + endif(gssapi_flavor_tmp MATCHES ".*Massachusetts.*") + + if(NOT HAVE_KRB5_GSSAPI) + if (gssapi_flavor_tmp MATCHES "Sun Microsystems.*") + message(STATUS "Solaris Kerberos does not have GSSAPI; this is normal.") + set(GSSAPI_LIBS) + set(GSSAPI_INCS) + else(gssapi_flavor_tmp MATCHES "Sun Microsystems.*") + message(WARNING "${KRB5_CONFIG} failed unexpectedly.") + endif(gssapi_flavor_tmp MATCHES "Sun Microsystems.*") + endif(NOT HAVE_KRB5_GSSAPI) + + if(GSSAPI_LIBS) # GSSAPI_INCS can be also empty, so don't rely on that + set(GSSAPI_FOUND TRUE CACHE STRING "") + message(STATUS "Found GSSAPI: ${GSSAPI_LIBS}") + + set(GSSAPI_INCS ${GSSAPI_INCS} CACHE STRING "") + set(GSSAPI_LIBS ${GSSAPI_LIBS} CACHE STRING "") + set(GSSAPI_FLAVOR ${GSSAPI_FLAVOR} CACHE STRING "") + + mark_as_advanced(GSSAPI_INCS GSSAPI_LIBS GSSAPI_FLAVOR) + + endif(GSSAPI_LIBS) + + endif(KRB5_CONFIG) + +endif(GSSAPI_LIBS AND GSSAPI_FLAVOR) diff --git a/cmake/FindIconv.cmake b/cmake/FindIconv.cmake index f0768f71..e99a3b2f 100644 --- a/cmake/FindIconv.cmake +++ b/cmake/FindIconv.cmake @@ -15,7 +15,7 @@ ELSE() ENDIF() IF(APPLE) - find_library(ICONV_LIBRARIES NAMES iconv libiconv c PATHS + find_library(ICONV_LIBRARIES NAMES iconv libiconv PATHS /opt/local/lib/ /usr/lib/ NO_CMAKE_SYSTEM_PATH) diff --git a/cmake/plugins.cmake b/cmake/plugins.cmake index a68bd509..2068b1e3 100644 --- a/cmake/plugins.cmake +++ b/cmake/plugins.cmake @@ -2,7 +2,7 @@ MACRO(REGISTER_PLUGIN name source struct type target allow) SET(PLUGIN_TYPE ${${name}}) - IF(NOT PLUGIN_TYPE STREQUAL "OFF") + IF(NOT PLUGIN_TYPE STREQUAL "OFF" AND NOT PLUGIN_TYPE) SET(PLUGIN_TYPE ${type}) ENDIF() IF(PLUGINS) @@ -18,6 +18,7 @@ MACRO(REGISTER_PLUGIN name source struct type target allow) SET(${name}_PLUGIN_SOURCE ${source}) SET(${name}_PLUGIN_CHG ${allow}) SET(PLUGINS ${PLUGINS} "${name}") + ADD_DEFINITIONS(-DHAVE_${name}=1) ENDMACRO() MARK_AS_ADVANCED(PLUGINS) @@ -34,18 +35,31 @@ REGISTER_PLUGIN("AUTH_NATIVE" "${CMAKE_SOURCE_DIR}/plugins/auth/my_auth.c" "nati REGISTER_PLUGIN("AUTH_OLDPASSWORD" "${CMAKE_SOURCE_DIR}/plugins/auth/old_password.c" "old_password_client_plugin" "DYNAMIC" "old_password" 1) REGISTER_PLUGIN("AUTH_DIALOG" "${CMAKE_SOURCE_DIR}/plugins/auth/dialog.c" "auth_dialog_plugin" "DYNAMIC" dialog 1) REGISTER_PLUGIN("AUTH_CLEARTEXT" "${CMAKE_SOURCE_DIR}/plugins/auth/mariadb_clear_text.c" "auth_cleartext_plugin" "DYNAMIC" "mysql_clear_password" 1) +IF(WIN32) + SET(GSSAPI_SOURCES ${CMAKE_SOURCE_DIR}/plugins/auth/auth_gssapi_client.c ${CMAKE_SOURCE_DIR}/plugins/auth/sspi_client.c ${CMAKE_SOURCE_DIR}/plugins/auth/sspi_errmsg.c) + REGISTER_PLUGIN("AUTH_GSSAPI" "${GSSAPI_SOURCES}" "auth_gssapi_plugin" "DYNAMIC" "auth_gssapi_client" 1) +ELSE() + IF(GSSAPI_FOUND) + SET(GSSAPI_SOURCES ${CMAKE_SOURCE_DIR}/plugins/auth/auth_gssapi_client.c ${CMAKE_SOURCE_DIR}/plugins/auth/gssapi_client.c ${CMAKE_SOURCE_DIR}/plugins/auth/gssapi_errmsg.c) + REGISTER_PLUGIN("AUTH_GSSAPI" "${GSSAPI_SOURCES}" "auth_gssapi_plugin" "DYNAMIC" "auth_gssapi_client" 1) + ENDIF() +ENDIF() #Remote_IO IF(CURL_FOUND) - REGISTER_PLUGIN("REMOTEIO" "${CMAKE_SOURCE_DIR}/plugins/io/remote_io.c" "remote_io_plugin" "DYNAMIC" "remote_io" 1) + IF(WIN32) + REGISTER_PLUGIN("REMOTEIO" "${CMAKE_SOURCE_DIR}/plugins/io/remote_io.c" "remote_io_plugin" "DYNAMIC" "remote_io" 1) + ELSE() + REGISTER_PLUGIN("REMOTEIO" "${CMAKE_SOURCE_DIR}/plugins/io/remote_io.c" "remote_io_plugin" "STATIC" "remote_io" 1) + ENDIF() ENDIF() #Trace REGISTER_PLUGIN("TRACE_EXAMPLE" "${CMAKE_SOURCE_DIR}/plugins/trace/trace_example.c" "trace_example_plugin" "DYNAMIC" "trace_example" 1) #Connection -REGISTER_PLUGIN("REPLICATION" "${CMAKE_SOURCE_DIR}/plugins/connection/replication.c" "connection_replication_plugin" "DYNAMIC" "" 1) -REGISTER_PLUGIN("AURORA" "${CMAKE_SOURCE_DIR}/plugins/connection/aurora.c" "connection_aurora_plugin" "DYNAMIC" "" 1) +REGISTER_PLUGIN("REPLICATION" "${CMAKE_SOURCE_DIR}/plugins/connection/replication.c" "connection_replication_plugin" "DYNAMIC" "replication" 1) +REGISTER_PLUGIN("AURORA" "${CMAKE_SOURCE_DIR}/plugins/connection/aurora.c" "connection_aurora_plugin" "DYNAMIC" "aurora" 1) # Allow registration of additional plugins IF(PLUGIN_CONF_FILE) diff --git a/include/config-win.h b/include/config-win.h index 1f433567..cd0b1ddf 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -210,7 +210,9 @@ inline double ulonglong2double(ulonglong value) #define HAVE_PUTENV #define HAVE_SELECT #define HAVE_SETLOCALE +#ifndef HAVE_SOCKET #define HAVE_SOCKET /* Giangi */ +#endif #define HAVE_FLOAT_H #define HAVE_LIMITS_H #define HAVE_STDDEF_H diff --git a/include/ma_common.h b/include/ma_common.h index ff5837f9..a34ac47f 100644 --- a/include/ma_common.h +++ b/include/ma_common.h @@ -56,6 +56,7 @@ struct st_mysql_options_extension { commands in one packet */ char *url; /* for connection handler we need to save URL for reconnect */ my_bool read_only; + char *connection_handler; HASH userdata; }; diff --git a/include/ma_pvio.h b/include/ma_pvio.h index 7ac4be94..4d1a5a45 100644 --- a/include/ma_pvio.h +++ b/include/ma_pvio.h @@ -28,12 +28,6 @@ typedef struct st_ma_pvio_methods PVIO_METHODS; #define IS_MYSQL_ASYNC_ACTIVE(a) \ (IS_MYSQL_ASYNC(a)&& (a)->options.extension->async_context->active) -#ifndef ssl_defined -#define ssl_defined -struct st_ma_pvio_ssl; -typedef struct st_ma_pvio_ssl MARIADB_SSL; -#endif - enum enum_pvio_timeout { PVIO_CONNECT_TIMEOUT= 0, PVIO_READ_TIMEOUT, diff --git a/include/ma_ssl.h b/include/ma_ssl.h index b994f08c..b227ac5e 100644 --- a/include/ma_ssl.h +++ b/include/ma_ssl.h @@ -151,5 +151,6 @@ const char *ma_pvio_ssl_cipher(MARIADB_SSL *cssl); my_bool ma_pvio_ssl_check_fp(MARIADB_SSL *cssl, const char *fp, const char *fp_list); my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio); my_bool ma_pvio_ssl_get_protocol_version(MARIADB_SSL *cssl, struct st_ssl_version *version); +void ma_pvio_ssl_end(); #endif /* _ma_ssl_h_ */ diff --git a/include/my_config.h.in b/include/my_config.h.in index a1181d0b..dc187721 100644 --- a/include/my_config.h.in +++ b/include/my_config.h.in @@ -46,6 +46,7 @@ #cmakedefine HAVE_TERMIOS_H 1 #cmakedefine HAVE_UNISTD_H 1 #cmakedefine HAVE_UTIME_H 1 +#cmakedefine HAVE_UCONTEXT_H 1 /* * function definitions - processed in LibmysqlFunctions.txt diff --git a/include/my_context.h b/include/my_context.h index b66482a4..2cc40d25 100644 --- a/include/my_context.h +++ b/include/my_context.h @@ -31,7 +31,7 @@ #define MY_CONTEXT_USE_X86_64_GCC_ASM #elif defined(__GNUC__) && __GNUC__ >= 3 && defined(__i386__) #define MY_CONTEXT_USE_I386_GCC_ASM -#elif defined(HAVE_UCONTEXT) +#elif defined(HAVE_UCONTEXT_H) #define MY_CONTEXT_USE_UCONTEXT #else #define MY_CONTEXT_DISABLE diff --git a/include/mysql.h b/include/mysql.h index a8d01693..6ffd7a96 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -213,22 +213,25 @@ extern unsigned int mariadb_deinitialize_ssl; MYSQL_DATABASE_DRIVER=7000, MARIADB_OPT_SSL_FP, /* single finger print for server certificate verification */ MARIADB_OPT_SSL_FP_LIST, /* finger print white list for server certificate verification */ - MARIADB_OPT_SSL_PASSWORD, /* password for encrypted certificates */ - MARIADB_OPT_COM_MULTI, + MARIADB_OPT_SSL_PASSPHRASE, /* passphrase for encrypted certificates */ MARIADB_OPT_CONNECTION_READ_ONLY, MYSQL_OPT_CONNECT_ATTRS, /* for mysql_get_optionv */ - MARIADB_OPT_USERDATA + MARIADB_OPT_USERDATA, + MARIADB_OPT_CONNECTION_HANDLER, + MARIADB_OPT_COM_MULTI, }; enum mariadb_value { MARIADB_CHARSET_ID, - MARIADB_CHARSET_INFO, MARIADB_CHARSET_NAME, MARIADB_CLIENT_ERRORS, MARIADB_CLIENT_VERSION, MARIADB_CLIENT_VERSION_ID, MARIADB_CONNECTION_ASYNC_TIMEOUT, MARIADB_CONNECTION_ASYNC_TIMEOUT_MS, + MARIADB_CONNECTION_CHARSET_INFO, + MARIADB_CONNECTION_ERROR, + MARIADB_CONNECTION_ERROR_ID, MARIADB_CONNECTION_HOST, MARIADB_CONNECTION_INFO, MARIADB_CONNECTION_PORT, @@ -239,7 +242,9 @@ extern unsigned int mariadb_deinitialize_ssl; MARIADB_CONNECTION_SERVER_VERSION, MARIADB_CONNECTION_SERVER_VERSION_ID, MARIADB_CONNECTION_SOCKET, + MARIADB_CONNECTION_SQLSTATE, MARIADB_CONNECTION_SSL_CIPHER, + MARIADB_SSL_LIBRARY, MARIADB_CONNECTION_SSL_VERSION, MARIADB_CONNECTION_SSL_VERSION_ID, MARIADB_CONNECTION_TYPE, @@ -281,7 +286,7 @@ struct st_mysql_options { unsigned long max_allowed_packet; my_bool use_ssl; /* if to use SSL or not */ my_bool compress,named_pipe; - my_bool unused_1, unused_2, unused_3, unused_4; + my_bool reconnect, unused_1, unused_2, unused_3; enum mysql_option methods_to_use; char *bind_address; my_bool secure_auth; @@ -318,12 +323,12 @@ struct st_mysql_options { unsigned int warning_count; /* warning count, added in 4.1 protocol */ struct st_mysql_options options; enum mysql_status status; - my_bool free_me; /* If free in mysql_close */ - my_bool reconnect; /* set to 1 if automatic reconnect */ + my_bool free_me; /* If free in mysql_close */ + my_bool unused_1; char scramble_buff[20+ 1]; /* madded after 3.23.58 */ - my_bool unused_1; - void *unused_2, *unused_3, *unused_4, *unused_5; + my_bool unused_2; + void *unused_3, *unused_4, *unused_5, *unused_6; LIST *stmts; const struct st_mysql_methods *methods; void *thd; @@ -438,7 +443,6 @@ const char * STDCALL mysql_character_set_name(MYSQL *mysql); void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs); int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname); -int STDCALL mariadb_flush_multi_command(MYSQL *mysql); my_bool STDCALL mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void *arg, ...); my_bool STDCALL mariadb_get_info(MYSQL *mysql, enum mariadb_value value, void *arg); MYSQL * STDCALL mysql_init(MYSQL *mysql); diff --git a/include/mysql/client_plugin.h b/include/mysql/client_plugin.h index 616de69e..977ef2c4 100644 --- a/include/mysql/client_plugin.h +++ b/include/mysql/client_plugin.h @@ -151,11 +151,11 @@ typedef char *(*mysql_authentication_dialog_ask_t)(struct st_mysql *mysql, #include /* Remote IO plugin */ -struct st_mysql_client_plugin_REMOTEIO +typedef struct st_mysql_client_plugin_REMOTEIO { MYSQL_CLIENT_PLUGIN_HEADER struct st_rio_methods *methods; -}; +} MARIADB_REMOTEIO_PLUGIN; #endif /******** using plugins ************/ diff --git a/libmariadb/CMakeLists.txt b/libmariadb/CMakeLists.txt index 92333cce..26767358 100644 --- a/libmariadb/CMakeLists.txt +++ b/libmariadb/CMakeLists.txt @@ -34,7 +34,6 @@ SET(EXPORT_SYMBOLS mariadb_dyncol_val_double mariadb_dyncol_val_long mariadb_dyncol_val_str - mariadb_flush_multi_command mariadb_get_charset_by_name mariadb_get_charset_by_nr mariadb_get_info @@ -113,7 +112,7 @@ SET(EXPORT_SYMBOLS mysql_list_tables mysql_list_tables_cont mysql_list_tables_start - mysql_load_plugin; + mysql_load_plugin mysql_load_plugin_v mysql_more_results mysql_next_result @@ -403,7 +402,6 @@ ENDIF() ADD_LIBRARY(mariadbclient STATIC ${ariadbclient_RC} $ ${EMPTY_FILE} ${EXPORT_LINK}) TARGET_LINK_LIBRARIES(mariadbclient ${SYSTEM_LIBS}) - ADD_LIBRARY(libmariadb SHARED ${libmariadb_RC} $ ${EMPTY_FILE} ${EXPORT_LINK}) TARGET_LINK_LIBRARIES(libmariadb ${SYSTEM_LIBS}) IF(UNIX) diff --git a/libmariadb/libmariadb.c b/libmariadb/libmariadb.c index ed76d7b4..28760e4f 100644 --- a/libmariadb/libmariadb.c +++ b/libmariadb/libmariadb.c @@ -107,6 +107,10 @@ extern int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row); extern int mthd_stmt_read_all_rows(MYSQL_STMT *stmt); extern void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt); extern unsigned char *mysql_net_store_length(unsigned char *packet, size_t length); +extern void +my_context_install_suspend_resume_hook(struct mysql_async_context *b, + void (*hook)(my_bool, void *), + void *user_data); uint mysql_port=0; my_string mysql_unix_port=0; @@ -132,7 +136,7 @@ struct st_mysql_methods MARIADB_DEFAULT_METHODS; #define native_password_plugin_name "mysql_native_password" #define IS_CONNHDLR_ACTIVE(mysql)\ - ((mysql)->net.conn_hdlr && (mysql)->net.conn_hdlr->active) + (((mysql)->net.conn_hdlr)) static void end_server(MYSQL *mysql); static void mysql_close_memory(MYSQL *mysql); @@ -1169,7 +1173,7 @@ mysql_init(MYSQL *mysql) #ifdef ENABLED_LOCAL_INFILE mysql->options.client_flag|= CLIENT_LOCAL_FILES; #endif - mysql->reconnect= 0; + mysql->options.reconnect= 0; return mysql; } @@ -1304,18 +1308,26 @@ mysql_real_connect(MYSQL *mysql, const char *host, const char *user, uint port, const char *unix_socket,unsigned long client_flag) { char *end; + char *connection_handler= (mysql->options.extension) ? + mysql->options.extension->connection_handler : 0; if (!mysql->methods) mysql->methods= &MARIADB_DEFAULT_METHODS; - if (host && (end= strstr(host, "://"))) + if (connection_handler || + (host && (end= strstr(host, "://")))) { MARIADB_CONNECTION_PLUGIN *plugin; char plugin_name[64]; - bzero(plugin_name, 64); - strncpy(plugin_name, host, MIN(end - host, 63)); - end+= 3; + if (!connection_handler || !connection_handler[0]) + { + bzero(plugin_name, 64); + strncpy(plugin_name, host, MIN(end - host, 63)); + end+= 3; + } + else + strncpy(plugin_name, connection_handler, MIN(63, strlen(connection_handler))); if (!(plugin= (MARIADB_CONNECTION_PLUGIN *)mysql_client_find_plugin(mysql, plugin_name, MARIADB_CLIENT_CONNECTION_PLUGIN))) return NULL; @@ -1332,7 +1344,15 @@ mysql_real_connect(MYSQL *mysql, const char *host, const char *user, mysql->net.conn_hdlr->plugin= plugin; if (plugin && plugin->connect) - return plugin->connect(mysql, end, user, passwd, db, port, unix_socket, client_flag); + { + MYSQL *my= plugin->connect(mysql, end, user, passwd, db, port, unix_socket, client_flag); + if (!my) + { + my_free(mysql->net.conn_hdlr); + mysql->net.conn_hdlr= NULL; + } + return my; + } } return mysql->methods->db_connect(mysql, host, user, passwd, @@ -1678,8 +1698,8 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, char **end= begin + mysql->options.init_command->elements; /* Avoid reconnect in mysql_real_connect */ - my_bool save_reconnect= mysql->reconnect; - mysql->reconnect= 0; + my_bool save_reconnect= mysql->options.reconnect; + mysql->options.reconnect= 0; for (;begin < end; begin++) { @@ -1693,7 +1713,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, mysql_free_result(res); } while (!mysql_next_result(mysql)); } - mysql->reconnect= save_reconnect; + mysql->options.reconnect= save_reconnect; } strmov(mysql->net.sqlstate, "00000"); @@ -1748,13 +1768,13 @@ my_bool STDCALL mysql_reconnect(MYSQL *mysql) DBUG_ENTER("mysql_reconnect"); /* check if connection handler is active */ - if (IS_CONNHDLR_ACTIVE(mysql)) + if (IS_CONNHDLR_ACTIVE(mysql)) { - if (mysql->net.conn_hdlr->plugin && mysql->net.conn_hdlr->plugin->connect) + if (mysql->net.conn_hdlr->plugin && mysql->net.conn_hdlr->plugin->reconnect) DBUG_RETURN(mysql->net.conn_hdlr->plugin->reconnect(mysql)); } - if (!mysql->reconnect || + if (!mysql->options.reconnect || (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) { /* Allow reconnect next time */ @@ -1811,7 +1831,6 @@ my_bool STDCALL mysql_reconnect(MYSQL *mysql) } } - tmp_mysql.reconnect= mysql->reconnect; tmp_mysql.free_me= mysql->free_me; tmp_mysql.stmts= mysql->stmts; mysql->stmts= NULL; @@ -1972,6 +1991,7 @@ static void mysql_close_options(MYSQL *mysql) my_free(mysql->options.extension->ssl_fp_list); my_free(mysql->options.extension->ssl_pw); my_free(mysql->options.extension->url); + my_free(mysql->options.extension->connection_handler); if(hash_inited(&mysql->options.extension->connect_attrs)) hash_free(&mysql->options.extension->connect_attrs); if (hash_inited(&mysql->options.extension->userdata)) @@ -2024,8 +2044,9 @@ void mysql_close_slow_part(MYSQL *mysql) { free_old_query(mysql); mysql->status=MYSQL_STATUS_READY; /* Force command */ - mysql->reconnect=0; - simple_command(mysql, COM_QUIT,NullS,0,1,0); + mysql->options.reconnect=0; + if (mysql->net.pvio && mysql->net.buff) + simple_command(mysql, COM_QUIT,NullS,0,1,0); end_server(mysql); } } @@ -2036,13 +2057,11 @@ mysql_close(MYSQL *mysql) DBUG_ENTER("mysql_close"); if (mysql) /* Some simple safety */ { - - if (IS_CONNHDLR_ACTIVE(mysql)) + if (mysql->net.conn_hdlr) { - void *p= (void *)mysql->net.conn_hdlr; - mysql->net.conn_hdlr->plugin->close(mysql); + MA_CONNECTION_HANDLER *p= mysql->net.conn_hdlr; + p->plugin->close(mysql); my_free(p); - DBUG_VOID_RETURN; } if (mysql->methods) @@ -2160,6 +2179,8 @@ mysql_real_query(MYSQL *mysql, const char *query, size_t length) if (OPT_HAS_EXT_VAL(mysql, multi_command)) is_multi= mysql->options.extension->multi_command; + if (length == -1) + length= strlen(query); free_old_query(mysql); @@ -2566,7 +2587,7 @@ mysql_ping(MYSQL *mysql) rc= simple_command(mysql, COM_PING,0,0,0,0); /* if connection was terminated and reconnect is true, try again */ - if (rc!=0 && mysql->reconnect) + if (rc!=0 && mysql->options.reconnect) rc= simple_command(mysql, COM_PING,0,0,0,0); return rc; } @@ -2704,15 +2725,9 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) mysql->options.charset_name=my_strdup((char *)arg1,MYF(MY_WME)); break; case MYSQL_OPT_RECONNECT: - mysql->reconnect= *(uint *)arg1; + mysql->options.reconnect= *(uint *)arg1; break; case MYSQL_OPT_PROTOCOL: -#ifdef _WIN32 - if (*(uint *)arg1 > MYSQL_PROTOCOL_PIPE) -#else - if (*(uint *)arg1 > MYSQL_PROTOCOL_SOCKET) -#endif - goto end; mysql->options.protocol= *(uint *)arg1; break; case MYSQL_OPT_READ_TIMEOUT: @@ -2722,7 +2737,7 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) mysql->options.write_timeout= *(uint *)arg1; break; case MYSQL_REPORT_DATA_TRUNCATION: - mysql->options.report_data_truncation= *(uint *)arg1; + mysql->options.report_data_truncation= *(my_bool *)arg1; break; case MYSQL_PROGRESS_CALLBACK: if (!mysql->options.extension) @@ -2807,7 +2822,7 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) break; case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: - if (*(uint *)arg1) + if (*(my_bool *)arg1) mysql->options.client_flag |= CLIENT_SSL_VERIFY_SERVER_CERT; else mysql->options.client_flag &= ~CLIENT_SSL_VERIFY_SERVER_CERT; @@ -2865,6 +2880,9 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) mysql->options.extension->connect_attrs_len= 0; } break; + case MARIADB_OPT_CONNECTION_HANDLER: + OPT_SET_EXTENDED_VALUE_STR(&mysql->options, connection_handler, (char *)arg1); + break; case MARIADB_OPT_USERDATA: { void *data= va_arg(ap, void *); @@ -2881,13 +2899,27 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) if (!hash_inited(&mysql->options.extension->userdata)) { if (_hash_init(&mysql->options.extension->userdata, - 0, 0, 0, ma_get_hash_keyval, ma_hash_free, 0) || - !(buffer= (uchar *)my_malloc(strlen(key) + 1 + sizeof(void *), MYF(MY_ZEROFILL)))) + 0, 0, 0, ma_get_hash_keyval, ma_hash_free, 0)) { SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); goto end; } } + /* check if key is already in buffer */ + if (p= (uchar *)hash_search(&mysql->options.extension->userdata, (uchar *)key, + (uint)strlen((char *)key))) + { + p+= strlen(key) + 1; + memcpy(p, &data, sizeof(void *)); + break; + } + + if (!(buffer= (uchar *)my_malloc(strlen(key) + 1 + sizeof(void *), MYF(MY_ZEROFILL)))) + { + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + goto end; + } + p= buffer; strcpy(p, key); p+= strlen(key) + 1; @@ -2972,7 +3004,7 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) case MARIADB_OPT_SSL_FP_LIST: OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_fp_list, (char *)arg1); break; - case MARIADB_OPT_SSL_PASSWORD: + case MARIADB_OPT_SSL_PASSPHRASE: OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_pw, (char *)arg1); break; case MARIADB_OPT_COM_MULTI: @@ -3046,7 +3078,7 @@ mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...) *((char **)arg)= mysql->options.charset_name; break; case MYSQL_OPT_RECONNECT: - *((uint *)arg)= mysql->reconnect; + *((my_bool *)arg)= mysql->options.reconnect; break; case MYSQL_OPT_PROTOCOL: *((uint *)arg)= mysql->options.protocol; @@ -3058,7 +3090,7 @@ mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...) *((uint *)arg)= mysql->options.write_timeout; break; case MYSQL_REPORT_DATA_TRUNCATION: - *((uint *)arg)= mysql->options.report_data_truncation; + *((my_bool *)arg)= mysql->options.report_data_truncation; break; case MYSQL_PROGRESS_CALLBACK: *((void (**)(const MYSQL *, uint, uint, double, const char *, uint))arg)= @@ -3152,13 +3184,12 @@ mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...) case MARIADB_OPT_SSL_FP_LIST: *((char **)arg)= mysql->options.extension ? mysql->options.extension->ssl_fp_list : NULL; break; - case MARIADB_OPT_SSL_PASSWORD: + case MARIADB_OPT_SSL_PASSPHRASE: *((char **)arg)= mysql->options.extension ? mysql->options.extension->ssl_pw : NULL; break; - /* todo case MARIADB_OPT_CONNECTION_READ_ONLY: + *((my_bool *)arg)= mysql->options.extension ? mysql->options.extension->read_only : 0; break; - */ case MARIADB_OPT_USERDATA: /* nysql_get_optionv(mysql, MARIADB_OPT_USERDATA, key, value) */ { @@ -3177,6 +3208,9 @@ mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...) *((void **)data)= NULL; } break; + case MARIADB_OPT_CONNECTION_HANDLER: + *((char **)arg)= mysql->options.extension ? mysql->options.extension->connection_handler : NULL; + break; default: va_end(ap); DBUG_RETURN(-1); @@ -3473,7 +3507,7 @@ int STDCALL mysql_server_init(int argc __attribute__((unused)), return(rc); } -void STDCALL mysql_server_end() +void STDCALL mysql_server_end(void) { if (!mysql_client_init) return; @@ -3483,6 +3517,9 @@ void STDCALL mysql_server_end() list_free(pvio_callback, 0); if (my_init_done) my_end(0); +#ifdef HAVE_SSL + ma_pvio_ssl_end(); +#endif mysql_client_init= 0; my_init_done= 0; } @@ -3571,7 +3608,7 @@ static my_socket mariadb_get_socket(MYSQL *mysql) return sock; } -int STDCALL mariadb_flush_multi_command(MYSQL *mysql) +int mariadb_flush_multi_command(MYSQL *mysql) { int is_multi= 0; int rc; @@ -3625,6 +3662,21 @@ my_bool STDCALL mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void * case MARIADB_NET_BUFFER_LENGTH: *((size_t *)arg)= (size_t)net_buffer_length; break; + case MARIADB_CONNECTION_ERROR_ID: + if (!mysql) + goto error; + *((unsigned int *)arg)= mysql->net.last_errno; + break; + case MARIADB_CONNECTION_ERROR: + if (!mysql) + goto error; + *((char **)arg)= mysql->net.last_error; + break; + case MARIADB_CONNECTION_SQLSTATE: + if (!mysql) + goto error; + *((char **)arg)= mysql->net.sqlstate; + break; case MARIADB_CONNECTION_SSL_VERSION: #ifdef HAVE_SSL if (mysql && mysql->net.pvio && mysql->net.pvio->cssl) @@ -3649,6 +3701,19 @@ my_bool STDCALL mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void * #endif goto error; break; + case MARIADB_SSL_LIBRARY: +#ifdef HAVE_SSL +#ifdef HAVE_GNUTLS + *((char **)arg)= "GNUTLS"; +#elif HAVE_OPENSSL + *((char **)arg)= "OPENSSL"; +#elif HAVE_SCHANNEL + *((char **)arg)= "SCHANNEL"; +#endif +#else + *((char **)arg)= "OFF"; +#endif + break; case MARIADB_CLIENT_VERSION: *((char **)arg)= MYSQL_CLIENT_VERSION; break; @@ -3679,7 +3744,7 @@ my_bool STDCALL mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void * else goto error; break; - case MARIADB_CHARSET_INFO: + case MARIADB_CONNECTION_CHARSET_INFO: if (mysql) mariadb_get_charset_info(mysql, (MY_CHARSET_INFO *)arg); else @@ -3750,7 +3815,7 @@ my_bool STDCALL mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void * goto error; break; case MARIADB_CONNECTION_PVIO_TYPE: - if (mysql && !mysql->net.pvio) + if (mysql && mysql->net.pvio) *((unsigned int *)arg)= (unsigned int)mysql->net.pvio->type; else goto error; diff --git a/libmariadb/ma_pvio.c b/libmariadb/ma_pvio.c index 054ef45d..7d012c66 100644 --- a/libmariadb/ma_pvio.c +++ b/libmariadb/ma_pvio.c @@ -70,6 +70,7 @@ MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo) * Currently we support the following pvio types: * pvio_socket * pvio_namedpipe + * pvio_sharedmed */ char *pvio_plugins[] = {"pvio_socket", "pvio_npipe", "pvio_shmem"}; int type; @@ -488,8 +489,8 @@ my_bool ma_pvio_is_blocking(MARIADB_PVIO *pvio) my_bool ma_pvio_has_data(MARIADB_PVIO *pvio, ssize_t *data_len) { /* check if we still have unread data in cache */ - if (pvio->cache) - if (pvio->cache_pos > pvio->cache) + if (pvio && pvio->cache) + if (pvio->cache_pos > pvio->cache) return test(pvio->cache_pos - pvio->cache); if (pvio && pvio->methods->has_data) return pvio->methods->has_data(pvio, data_len); diff --git a/libmariadb/ma_ssl.c b/libmariadb/ma_ssl.c index 2ea474a8..529979ea 100644 --- a/libmariadb/ma_ssl.c +++ b/libmariadb/ma_ssl.c @@ -78,7 +78,11 @@ MARIADB_SSL *ma_pvio_ssl_init(MYSQL *mysql) my_bool ma_pvio_ssl_connect(MARIADB_SSL *cssl) { - return ma_ssl_connect(cssl); + my_bool rc; + + if ((rc= ma_ssl_connect(cssl))) + ma_ssl_close(cssl); + return rc; } size_t ma_pvio_ssl_read(MARIADB_SSL *cssl, const uchar* buffer, size_t length) @@ -106,6 +110,11 @@ const char *ma_pvio_ssl_cipher(MARIADB_SSL *cssl) return ma_ssl_get_cipher(cssl); } +void ma_pvio_ssl_end() +{ + return ma_ssl_end(); +} + my_bool ma_pvio_ssl_get_protocol_version(MARIADB_SSL *cssl, struct st_ssl_version *version) { return ma_ssl_get_protocol_version(cssl, version); diff --git a/libmariadb/my_context.c b/libmariadb/my_context.c index 545cfe8e..0fda2a73 100644 --- a/libmariadb/my_context.c +++ b/libmariadb/my_context.c @@ -20,6 +20,7 @@ swapcontext(). */ +#include "my_global.h" #include "mysys_priv.h" #include "m_string.h" #include "my_context.h" diff --git a/libmariadb/my_stmt.c b/libmariadb/my_stmt.c index 58a5c951..4894ceb2 100644 --- a/libmariadb/my_stmt.c +++ b/libmariadb/my_stmt.c @@ -1227,6 +1227,9 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, size_t lengt int rc= 1; DBUG_ENTER("mysql_stmt_prepare"); + if (length == -1) + length= strlen(query); + if (!stmt->mysql) { SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); @@ -1374,8 +1377,12 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) stmt->result_cursor= stmt->result.data; stmt->fetch_row_func= stmt_buffered_fetch; - stmt->mysql->status= MYSQL_STATUS_READY; - stmt->state= MYSQL_STMT_USE_OR_STORE_CALLED; + stmt->mysql->status= MYSQL_STATUS_READY; + + if (!stmt->result.rows) + stmt->state= MYSQL_STMT_FETCH_DONE; + else + stmt->state= MYSQL_STMT_USE_OR_STORE_CALLED; /* set affected rows: see bug 2247 */ stmt->upsert_status.affected_rows= stmt->result.rows; @@ -1640,6 +1647,7 @@ static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags) stmt->result.rows= 0; stmt->result_cursor= NULL; stmt->mysql->status= MYSQL_STATUS_READY; + stmt->state= MYSQL_STMT_FETCH_DONE; } /* if there is a pending result set, we will flush it */ diff --git a/libmariadb/net.c b/libmariadb/net.c index 9788906a..49b5ac1f 100644 --- a/libmariadb/net.c +++ b/libmariadb/net.c @@ -195,9 +195,10 @@ static my_bool net_realloc(NET *net, my_bool is_multi, size_t length) /* Remove unwanted characters from connection */ void net_clear(NET *net) { - size_t len; +// size_t len; DBUG_ENTER("net_clear"); - ma_pvio_has_data(net->pvio, &len); +/* if (net->pvio) + ma_pvio_has_data(net->pvio, &len); */ net->compress_pkt_nr= net->pkt_nr=0; /* Ready for new command */ net->write_pos=net->buff; if (net->mbuff) diff --git a/libmariadb/secure/gnutls.c b/libmariadb/secure/gnutls.c index 5b955e1b..534c2592 100644 --- a/libmariadb/secure/gnutls.c +++ b/libmariadb/secure/gnutls.c @@ -35,6 +35,7 @@ pthread_mutex_t LOCK_gnutls_config; static gnutls_certificate_credentials_t GNUTLS_xcred; extern my_bool ma_ssl_initialized; +extern unsigned int mariadb_deinitialize_ssl; static int my_verify_callback(gnutls_session_t ssl); @@ -137,7 +138,8 @@ void ma_ssl_end() gnutls_certificate_free_crls(GNUTLS_xcred); gnutls_certificate_free_ca_names(GNUTLS_xcred); gnutls_certificate_free_credentials(GNUTLS_xcred); - gnutls_global_deinit(); + if (mariadb_deinitialize_ssl) + gnutls_global_deinit(); ma_ssl_initialized= FALSE; } pthread_mutex_unlock(&LOCK_gnutls_config); @@ -204,7 +206,7 @@ void *ma_ssl_init(MYSQL *mysql) goto error; gnutls_session_set_ptr(ssl, (void *)mysql); - ssl_error= gnutls_priority_set_direct(ssl, "NORMAL:-DHE-RSA", &err); + ssl_error= gnutls_priority_set_direct(ssl, "NORMAL", &err); if (ssl_error < 0) goto error; diff --git a/libmariadb/secure/openssl.c b/libmariadb/secure/openssl.c index e659a1a1..f8a844dd 100644 --- a/libmariadb/secure/openssl.c +++ b/libmariadb/secure/openssl.c @@ -41,6 +41,7 @@ #include extern my_bool ma_ssl_initialized; +extern unsigned int mariadb_deinitialize_ssl; static SSL_CTX *SSL_context= NULL; #define MAX_SSL_ERR_LEN 100 @@ -226,14 +227,16 @@ void ma_ssl_end() SSL_CTX_free(SSL_context); SSL_context= NULL; } - ERR_remove_state(0); - EVP_cleanup(); - CRYPTO_cleanup_all_ex_data(); - ERR_free_strings(); - //ENGINE_cleanup(); - CONF_modules_free(); - CONF_modules_unload(1); - sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); + if (mariadb_deinitialize_ssl) + { + ERR_remove_state(0); + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); + CONF_modules_free(); + CONF_modules_unload(1); + sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); + } ma_ssl_initialized= FALSE; } pthread_mutex_unlock(&LOCK_openssl_config); @@ -293,7 +296,12 @@ static int ma_ssl_set_certs(MYSQL *mysql) if (keyfile && keyfile[0]) { if (SSL_CTX_use_PrivateKey_file(SSL_context, keyfile, SSL_FILETYPE_PEM) != 1) - goto error; + { + unsigned long err= ERR_peek_error(); + if (!(ERR_GET_LIB(err) == ERR_LIB_X509 && + ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE)) + goto error; + } } if (OPT_HAS_EXT_VAL(mysql, ssl_pw)) { diff --git a/libmariadb/secure/schannel.c b/libmariadb/secure/schannel.c index 3f84c17f..1f27dd44 100644 --- a/libmariadb/secure/schannel.c +++ b/libmariadb/secure/schannel.c @@ -310,7 +310,6 @@ my_bool ma_ssl_connect(MARIADB_SSL *cssl) return 0; end: - /* todo: cleanup */ if (pRemoteCertContext) CertFreeCertificateContext(pRemoteCertContext); if (rc && sctx->IoBufferSize) @@ -322,6 +321,9 @@ end: CertFreeCertificateContext(sctx->client_cert_ctx); if (sctx->client_crl_ctx) CertFreeCRLContext(sctx->client_crl_ctx); + sctx->client_ca_ctx= 0; + sctx->client_cert_ctx= 0; + sctx->client_crl_ctx= 0; return 1; } diff --git a/mariadb_config/CMakeLists.txt b/mariadb_config/CMakeLists.txt index 69d7c3ac..4c8d973d 100644 --- a/mariadb_config/CMakeLists.txt +++ b/mariadb_config/CMakeLists.txt @@ -1,27 +1,33 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) -# Figure out additional libraries for use with +# Figure out additional libraries for use with -FOREACH (dep ${libmariadb_LIB_DEPENDS}) - STRING(REGEX MATCH "^-l.*$" out "${dep}") - IF(out) - SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} ${dep}") - ENDIF(out) -ENDFOREACH(dep) +FUNCTION(GET_LIB_NAME LIB_NAME LIB_OUT) + STRING(FIND ${LIB_NAME} ".so" IS_SO) + IF(NOT ${IS_SO} STREQUAL "-1") + GET_FILENAME_COMPONENT(LIB_FILE ${LIB_NAME} NAME_WE) + ELSE() + SET(LIB_FILE ${LIB_NAME}) + ENDIF() + SET(LIB_FILE "-l${LIB_FILE}") + STRING(REPLACE "-llib" "-l" LIB_FILE ${LIB_FILE}) + SET(${LIB_OUT} ${LIB_FILE} PARENT_SCOPE) +ENDFUNCTION() + +LIST(LENGTH SYSTEM_LIBS rllength) +IF(${rllength} GREATER 0) + LIST(REMOVE_DUPLICATES SYSTEM_LIBS) +ENDIF() + +FOREACH (LIB_NAME ${SYSTEM_LIBS}) + GET_LIB_NAME(${LIB_NAME} LIB_OUT) + SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} ${LIB_OUT}") +ENDFOREACH() IF(UNIX) - IF(OPENSSL_LIBRARIES) - SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -lssl") - ENDIF() IF(ICONV_EXTERNAL) SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} ${ICONV_LIBRARIES}") ENDIF() - FOREACH(lib ${EXTRA_LIBS}) - SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -l${lib}") - ENDFOREACH() - IF(WITH_SQLITE) - SET(extra_dynamic_LDFLAGS "${extra_dynamic_LDFLAGS} -lsqlite") - ENDIF() ENDIF(UNIX) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mariadb_config.c.in diff --git a/plugins/auth/CMakeLists.txt b/plugins/auth/CMakeLists.txt index f32ba1b2..bf7d0266 100644 --- a/plugins/auth/CMakeLists.txt +++ b/plugins/auth/CMakeLists.txt @@ -1,4 +1,5 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/plugins/auth) INCLUDE(${CMAKE_SOURCE_DIR}/cmake/install_plugins.cmake) IF(WITH_SIGNCODE) @@ -64,3 +65,36 @@ IF(AUTH_CLEARTEXT_PLUGIN_TYPE MATCHES "DYNAMIC") INSTALL_PLUGIN(mysql_clear_password ${CMAKE_BINARY_DIR}/plugins/auth) SIGN_TARGET(mysql_clear_password) ENDIF() + +# SSPI/GSSAPI plugin +IF(WIN32) + SET(USE_SSPI 1) +ENDIF() + +MESSAGE(STATUS "GSSAPI: ${AUTH_GSSAPI_PLUGIN_TYPE}") +IF(${AUTH_GSSAPI_PLUGIN_TYPE} MATCHES "DYNAMIC") + IF(WIN32) + SET_VERSION_INFO("TARGET:auth_gssapi_client" + "FILE_TYPE:VFT_DLL" + "SOURCE_FILE:plugins/auth/auth_gssapi_client.c" + "ORIGINAL_FILE_NAME:auth_gssapi_client.dll" + "FILE_DESCRIPTION:Authentication plugin") + ADD_DEFINITIONS(-DHAVE_AUTH_GSSAPI_DYNAMIC=1) + SET(GSSAPI_SOURCES auth_gssapi_client.c sspi_client.c sspi_errmsg.c ${CMAKE_SOURCE_DIR}/plugins/plugin.def ${gssapi_RC}) + ELSE() + IF(GSSAPI_FOUND) + SET(GSSAPI_SOURCES auth_gssapi_client.c gssapi_client.c gssapi_errmsg.c) + ENDIF() + ENDIF() + IF(GSSAPI_FOUND OR WIN32) + ADD_LIBRARY(auth_gssapi_client SHARED ${GSSAPI_SOURCES}) + IF(WIN32) + TARGET_LINK_LIBRARIES(auth_gssapi_client secur32.lib) + ELSE() + TARGET_LINK_LIBRARIES(auth_gssapi_client ${GSSAPI_LIBS}) + ENDIF() + SET_TARGET_PROPERTIES(auth_gssapi_client PROPERTIES PREFIX "") + INSTALL_PLUGIN(auth_gssapi_client ${CMAKE_BINARY_DIR}/plugins/auth) + SIGN_TARGET(auth_gssapi_client) + ENDIF() +ENDIF() diff --git a/plugins/auth/auth_gssapi_client.c b/plugins/auth/auth_gssapi_client.c new file mode 100644 index 00000000..d0ed3795 --- /dev/null +++ b/plugins/auth/auth_gssapi_client.c @@ -0,0 +1,119 @@ +/* Copyright (c) 2015-2016, Shuang Qiu, Robbie Harwood, +Vladislav Vaintroub & MariaDB Corporation + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + @file + + GSSAPI authentication plugin, client side +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +extern int auth_client(char *principal_name, + char *mech, + MYSQL *mysql, + MYSQL_PLUGIN_VIO *vio); + +static void parse_server_packet(char *packet, size_t packet_len, char *spn, char *mech) +{ + size_t spn_len; + spn_len = strnlen(packet, packet_len); + strncpy(spn, packet, PRINCIPAL_NAME_MAX); + if (spn_len == packet_len - 1) + { + /* Mechanism not included into packet */ + *mech = 0; + } + else + { + strncpy(mech, packet + spn_len + 1, MECH_NAME_MAX); + } +} + +/** + Set client error message. + */ +void log_client_error(MYSQL *mysql, const char *format, ...) +{ + NET *net= &mysql->net; + va_list args; + + net->last_errno= ER_UNKNOWN_ERROR; + va_start(args, format); + vsnprintf(net->last_error, sizeof(net->last_error) - 1, + format, args); + va_end(args); + memcpy(net->sqlstate, "HY000", sizeof(net->sqlstate)); +} + +/** + The main client function of the GSSAPI plugin. + */ +static int gssapi_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) +{ + int packet_len; + unsigned char *packet; + char spn[PRINCIPAL_NAME_MAX + 1]; + char mech[MECH_NAME_MAX + 1]; + + /* read from server for service principal name */ + packet_len= vio->read_packet(vio, &packet); + if (packet_len < 0) + { + return CR_ERROR; + } + parse_server_packet((char *)packet, (size_t)packet_len, spn, mech); + return auth_client(spn, mech, mysql, vio); +} + + +/* register client plugin */ +#ifndef HAVE_AUTH_GSSAPI_DYNAMIC +struct st_mysql_client_plugin_AUTHENTICATION auth_gssapi_plugin= +#else +struct st_mysql_client_plugin_AUTHENTICATION _mysql_client_plugin_declaration_ = +#endif +{ + MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION, + "auth_gssapi_client", + "Shuang Qiu, Robbie Harwood, Vladislav Vaintroub, Georg Richter", + "GSSAPI/SSPI based authentication", + {0, 1, 0}, + "BSD", + NULL, + NULL, + gssapi_auth_client +}; diff --git a/plugins/auth/common.h b/plugins/auth/common.h new file mode 100644 index 00000000..c04241ac --- /dev/null +++ b/plugins/auth/common.h @@ -0,0 +1,4 @@ +/** Maximal length of the target name */ +#define PRINCIPAL_NAME_MAX 256 +/** Maximal length of the mech string */ +#define MECH_NAME_MAX 30 diff --git a/plugins/auth/gssapi_client.c b/plugins/auth/gssapi_client.c new file mode 100644 index 00000000..a05ea158 --- /dev/null +++ b/plugins/auth/gssapi_client.c @@ -0,0 +1,127 @@ +/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood, +Vladislav Vaintroub & MariaDB Corporation + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include "gssapi_errmsg.h" + +extern void log_client_error(MYSQL *mysql,const char *fmt,...); + + +/* This sends the error to the client */ +static void log_error(MYSQL *mysql, OM_uint32 major, OM_uint32 minor, const char *msg) +{ + if (GSS_ERROR(major)) + { + char sysmsg[1024]; + gssapi_errmsg(major, minor, sysmsg, sizeof(sysmsg)); + log_client_error(mysql, + "Client GSSAPI error (major %u, minor %u) : %s - %s", + major, minor, msg, sysmsg); + } + else + { + log_client_error(mysql, "Client GSSAPI error : %s", msg); + } +} + +int auth_client(char *principal_name, char *mech, MYSQL *mysql, MYSQL_PLUGIN_VIO *vio) +{ + + int ret= CR_ERROR; + OM_uint32 major= 0, minor= 0; + gss_ctx_id_t ctxt= GSS_C_NO_CONTEXT; + gss_name_t service_name= GSS_C_NO_NAME; + + if (principal_name && principal_name[0]) + { + /* import principal from plain text */ + gss_buffer_desc principal_name_buf; + principal_name_buf.length= strlen(principal_name); + principal_name_buf.value= (void *) principal_name; + major= gss_import_name(&minor, &principal_name_buf, GSS_C_NT_USER_NAME, &service_name); + if (GSS_ERROR(major)) + { + log_error(mysql, major, minor, "gss_import_name"); + return CR_ERROR; + } + } + + gss_buffer_desc input= {0,0}; + do + { + gss_buffer_desc output= {0,0}; + major= gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &ctxt, service_name, + GSS_C_NO_OID, 0, 0, GSS_C_NO_CHANNEL_BINDINGS, + &input, NULL, &output, NULL, NULL); + if (output.length) + { + /* send credential */ + if(vio->write_packet(vio, (unsigned char *)output.value, output.length)) + { + /* Server error packet contains detailed message. */ + ret= CR_OK_HANDSHAKE_COMPLETE; + gss_release_buffer (&minor, &output); + goto cleanup; + } + } + gss_release_buffer (&minor, &output); + + if (GSS_ERROR(major)) + { + log_error(mysql, major, minor,"gss_init_sec_context"); + goto cleanup; + } + + if (major & GSS_S_CONTINUE_NEEDED) + { + int len= vio->read_packet(vio, (unsigned char **) &input.value); + if (len <= 0) + { + /* Server error packet contains detailed message. */ + ret= CR_OK_HANDSHAKE_COMPLETE; + goto cleanup; + } + input.length= len; + } + } while (major & GSS_S_CONTINUE_NEEDED); + + ret= CR_OK; + +cleanup: + if (service_name != GSS_C_NO_NAME) + gss_release_name(&minor, &service_name); + if (ctxt != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&minor, &ctxt, GSS_C_NO_BUFFER); + + return ret; +} diff --git a/plugins/auth/gssapi_errmsg.c b/plugins/auth/gssapi_errmsg.c new file mode 100644 index 00000000..8ea4cab5 --- /dev/null +++ b/plugins/auth/gssapi_errmsg.c @@ -0,0 +1,75 @@ +/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood, +Vladislav Vaintroub & MariaDB Corporation + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +void gssapi_errmsg(OM_uint32 major, OM_uint32 minor, char *buf, size_t size) +{ + OM_uint32 message_context; + OM_uint32 status_code; + OM_uint32 maj_status; + OM_uint32 min_status; + gss_buffer_desc status_string; + char *p= buf; + char *end= buf + size - 1; + int types[] = {GSS_C_GSS_CODE,GSS_C_MECH_CODE}; + + for(int i= 0; i < 2;i++) + { + message_context= 0; + status_code= types[i] == GSS_C_GSS_CODE?major:minor; + + if(!status_code) + continue; + do + { + maj_status = gss_display_status( + &min_status, + status_code, + types[i], + GSS_C_NO_OID, + &message_context, + &status_string); + + if(maj_status) + break; + + if(p + status_string.length + 2 < end) + { + memcpy(p,status_string.value, status_string.length); + p += status_string.length; + *p++ = '.'; + *p++ = ' '; + } + + gss_release_buffer(&min_status, &status_string); + } + while (message_context != 0); + } + *p= 0; +} diff --git a/plugins/auth/gssapi_errmsg.h b/plugins/auth/gssapi_errmsg.h new file mode 100644 index 00000000..26db8439 --- /dev/null +++ b/plugins/auth/gssapi_errmsg.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood, +Vladislav Vaintroub & MariaDB Corporation + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +extern void gssapi_errmsg(OM_uint32 major, OM_uint32 minor, char *buf, size_t size); diff --git a/plugins/auth/server_plugin.h b/plugins/auth/server_plugin.h new file mode 100644 index 00000000..1348835e --- /dev/null +++ b/plugins/auth/server_plugin.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood, +Vladislav Vaintroub & MariaDB Corporation + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Plugin variables*/ +#include +typedef enum +{ + PLUGIN_MECH_KERBEROS = 0, + PLUGIN_MECH_SPNEGO = 1, + PLUGIN_MECH_DEFAULT = 2 +}PLUGIN_MECH; + +extern unsigned long srv_mech; +extern char *srv_principal_name; +extern char *srv_mech_name; +extern char *srv_keytab_path; +/* + Check, with GSSAPI/SSPI username of logged on user. + + Depending on use_full_name parameter, compare either full name + (principal name like user@real), or local name (first component) +*/ +int plugin_init(); +int plugin_deinit(); + +int auth_server(MYSQL_PLUGIN_VIO *vio, const char *username, size_t username_len, int use_full_name); diff --git a/plugins/auth/sspi_client.c b/plugins/auth/sspi_client.c new file mode 100644 index 00000000..41461297 --- /dev/null +++ b/plugins/auth/sspi_client.c @@ -0,0 +1,183 @@ +/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood, +Vladislav Vaintroub & MariaDB Corporation + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#define SECURITY_WIN32 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sspi_common.h" + +extern void log_client_error(MYSQL *mysql, const char *fmt, ...); +static void log_error(MYSQL *mysql, SECURITY_STATUS err, const char *msg) +{ + if (err) + { + char buf[1024]; + sspi_errmsg(err, buf, sizeof(buf)); + log_client_error(mysql, "SSPI client error 0x%x - %s - %s", err, msg, buf); + } + else + { + log_client_error(mysql, "SSPI client error %s", msg); + } +} + + +/** Client side authentication*/ +int auth_client(char *principal_name, char *mech, MYSQL *mysql, MYSQL_PLUGIN_VIO *vio) +{ + + int ret; + CredHandle cred; + CtxtHandle ctxt; + ULONG attribs = 0; + TimeStamp lifetime; + SECURITY_STATUS sspi_err; + + SecBufferDesc inbuf_desc; + SecBuffer inbuf; + SecBufferDesc outbuf_desc; + SecBuffer outbuf; + PBYTE out = NULL; + + ret= CR_ERROR; + SecInvalidateHandle(&ctxt); + SecInvalidateHandle(&cred); + + if (!mech || strcmp(mech, "Negotiate") != 0) + { + mech= "Kerberos"; + } + + sspi_err = AcquireCredentialsHandle( + NULL, + mech, + SECPKG_CRED_OUTBOUND, + NULL, + NULL, + NULL, + NULL, + &cred, + &lifetime); + + if (SEC_ERROR(sspi_err)) + { + log_error(mysql, sspi_err, "AcquireCredentialsHandle"); + return CR_ERROR; + } + + out = (PBYTE)malloc(SSPI_MAX_TOKEN_SIZE); + if (!out) + { + log_error(mysql, SEC_E_OK, "memory allocation error"); + goto cleanup; + } + + /* Prepare buffers */ + inbuf_desc.ulVersion = SECBUFFER_VERSION; + inbuf_desc.cBuffers = 1; + inbuf_desc.pBuffers = &inbuf; + inbuf.BufferType = SECBUFFER_TOKEN; + inbuf.cbBuffer = 0; + inbuf.pvBuffer = NULL; + + outbuf_desc.ulVersion = SECBUFFER_VERSION; + outbuf_desc.cBuffers = 1; + outbuf_desc.pBuffers = &outbuf; + outbuf.BufferType = SECBUFFER_TOKEN; + outbuf.pvBuffer = out; + + do + { + outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE; + sspi_err= InitializeSecurityContext( + &cred, + SecIsValidHandle(&ctxt) ? &ctxt : NULL, + principal_name, + 0, + 0, + SECURITY_NATIVE_DREP, + inbuf.cbBuffer ? &inbuf_desc : NULL, + 0, + &ctxt, + &outbuf_desc, + &attribs, + &lifetime); + if (SEC_ERROR(sspi_err)) + { + log_error(mysql, sspi_err, "InitializeSecurityContext"); + goto cleanup; + } + if (sspi_err != SEC_E_OK && sspi_err != SEC_I_CONTINUE_NEEDED) + { + log_error(mysql, sspi_err, "Unexpected response from InitializeSecurityContext"); + goto cleanup; + } + + if (outbuf.cbBuffer) + { + /* send credential to server */ + if (vio->write_packet(vio, (unsigned char *)outbuf.pvBuffer, outbuf.cbBuffer)) + { + /* Server error packet contains detailed message. */ + ret= CR_OK_HANDSHAKE_COMPLETE; + goto cleanup; + } + } + + if (sspi_err == SEC_I_CONTINUE_NEEDED) + { + int len= vio->read_packet(vio, (unsigned char **)&inbuf.pvBuffer); + if (len <= 0) + { + /* Server side error is in the last server packet. */ + ret= CR_OK_HANDSHAKE_COMPLETE; + goto cleanup; + } + inbuf.cbBuffer= len; + } + } while (sspi_err == SEC_I_CONTINUE_NEEDED); + + ret= CR_OK; + +cleanup: + + if (SecIsValidHandle(&ctxt)) + DeleteSecurityContext(&ctxt); + if (SecIsValidHandle(&cred)) + FreeCredentialsHandle(&cred); + free(out); + return ret; +} diff --git a/plugins/auth/sspi_common.h b/plugins/auth/sspi_common.h new file mode 100644 index 00000000..34b8a56a --- /dev/null +++ b/plugins/auth/sspi_common.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood, +Vladislav Vaintroub & MariaDB Corporation + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#define SECURITY_WIN32 +#include +#include +#include +#include +#include + +#define SSPI_MAX_TOKEN_SIZE 50000 +#define SEC_ERROR(err) (err < 0) +extern void sspi_errmsg(int err, char *buf, size_t size); \ No newline at end of file diff --git a/plugins/auth/sspi_errmsg.c b/plugins/auth/sspi_errmsg.c new file mode 100644 index 00000000..961ef51f --- /dev/null +++ b/plugins/auth/sspi_errmsg.c @@ -0,0 +1,150 @@ +/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood, +Vladislav Vaintroub & MariaDB Corporation + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#define ERRSYM(x) {x, #x} +static struct { + int error; + const char *sym; +} error_symbols[] = +{ + ERRSYM(SEC_E_OK), + ERRSYM(SEC_E_INSUFFICIENT_MEMORY), + ERRSYM(SEC_E_INVALID_HANDLE), + ERRSYM(SEC_E_UNSUPPORTED_FUNCTION), + ERRSYM(SEC_E_TARGET_UNKNOWN), + ERRSYM(SEC_E_INTERNAL_ERROR), + ERRSYM(SEC_E_SECPKG_NOT_FOUND), + ERRSYM(SEC_E_NOT_OWNER), + ERRSYM(SEC_E_CANNOT_INSTALL), + ERRSYM(SEC_E_INVALID_TOKEN), + ERRSYM(SEC_E_CANNOT_PACK), + ERRSYM(SEC_E_QOP_NOT_SUPPORTED), + ERRSYM(SEC_E_NO_IMPERSONATION), + ERRSYM(SEC_E_LOGON_DENIED), + ERRSYM(SEC_E_UNKNOWN_CREDENTIALS), + ERRSYM(SEC_E_NO_CREDENTIALS), + ERRSYM(SEC_E_MESSAGE_ALTERED), + ERRSYM(SEC_E_OUT_OF_SEQUENCE), + ERRSYM(SEC_E_NO_AUTHENTICATING_AUTHORITY), + ERRSYM(SEC_E_BAD_PKGID), + ERRSYM(SEC_E_CONTEXT_EXPIRED), + ERRSYM(SEC_E_INCOMPLETE_MESSAGE), + ERRSYM(SEC_E_INCOMPLETE_CREDENTIALS), + ERRSYM(SEC_E_BUFFER_TOO_SMALL), + ERRSYM(SEC_E_WRONG_PRINCIPAL), + ERRSYM(SEC_E_TIME_SKEW), + ERRSYM(SEC_E_UNTRUSTED_ROOT), + ERRSYM(SEC_E_ILLEGAL_MESSAGE), + ERRSYM(SEC_E_CERT_UNKNOWN), + ERRSYM(SEC_E_CERT_EXPIRED), + ERRSYM(SEC_E_ENCRYPT_FAILURE), + ERRSYM(SEC_E_DECRYPT_FAILURE), + ERRSYM(SEC_E_ALGORITHM_MISMATCH), + ERRSYM(SEC_E_SECURITY_QOS_FAILED), + ERRSYM(SEC_E_UNFINISHED_CONTEXT_DELETED), + ERRSYM(SEC_E_NO_TGT_REPLY), + ERRSYM(SEC_E_NO_IP_ADDRESSES), + ERRSYM(SEC_E_WRONG_CREDENTIAL_HANDLE), + ERRSYM(SEC_E_CRYPTO_SYSTEM_INVALID), + ERRSYM(SEC_E_MAX_REFERRALS_EXCEEDED), + ERRSYM(SEC_E_MUST_BE_KDC), + ERRSYM(SEC_E_STRONG_CRYPTO_NOT_SUPPORTED), + ERRSYM(SEC_E_TOO_MANY_PRINCIPALS), + ERRSYM(SEC_E_NO_PA_DATA), + ERRSYM(SEC_E_PKINIT_NAME_MISMATCH), + ERRSYM(SEC_E_SMARTCARD_LOGON_REQUIRED), + ERRSYM(SEC_E_SHUTDOWN_IN_PROGRESS), + ERRSYM(SEC_E_KDC_INVALID_REQUEST), + ERRSYM(SEC_E_KDC_UNABLE_TO_REFER), + ERRSYM(SEC_E_KDC_UNKNOWN_ETYPE), + ERRSYM(SEC_E_UNSUPPORTED_PREAUTH), + ERRSYM(SEC_E_DELEGATION_REQUIRED), + ERRSYM(SEC_E_BAD_BINDINGS), + ERRSYM(SEC_E_MULTIPLE_ACCOUNTS), + ERRSYM(SEC_E_NO_KERB_KEY), + ERRSYM(SEC_E_CERT_WRONG_USAGE), + ERRSYM(SEC_E_DOWNGRADE_DETECTED), + ERRSYM(SEC_E_SMARTCARD_CERT_REVOKED), + ERRSYM(SEC_E_ISSUING_CA_UNTRUSTED), + ERRSYM(SEC_E_REVOCATION_OFFLINE_C), + ERRSYM(SEC_E_PKINIT_CLIENT_FAILURE), + ERRSYM(SEC_E_SMARTCARD_CERT_EXPIRED), + ERRSYM(SEC_E_NO_S4U_PROT_SUPPORT), + ERRSYM(SEC_E_CROSSREALM_DELEGATION_FAILURE), + ERRSYM(SEC_E_REVOCATION_OFFLINE_KDC), + ERRSYM(SEC_E_ISSUING_CA_UNTRUSTED_KDC), + ERRSYM(SEC_E_KDC_CERT_EXPIRED), + ERRSYM(SEC_E_KDC_CERT_REVOKED), + ERRSYM(SEC_E_INVALID_PARAMETER), + ERRSYM(SEC_E_DELEGATION_POLICY), + ERRSYM(SEC_E_POLICY_NLTM_ONLY), + ERRSYM(SEC_E_NO_CONTEXT), + ERRSYM(SEC_E_PKU2U_CERT_FAILURE), + ERRSYM(SEC_E_MUTUAL_AUTH_FAILED), + ERRSYM(SEC_E_NO_SPM), + ERRSYM(SEC_E_NOT_SUPPORTED), + {0,0} +}; + +void sspi_errmsg(int err, char *buf, size_t size) +{ + buf[size - 1] = 0; + size_t len; + + for (size_t i= 0; error_symbols[i].sym; i++) + { + if (error_symbols[i].error == err) + { + size_t len= strlen(error_symbols[i].sym); + if (len + 2 < size) + { + memcpy(buf, error_symbols[i].sym, len); + buf[len]= ' '; + buf += len + 1; + size-= len + 1; + } + break; + } + } + + len = FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, + err, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + buf, size, NULL); + + if(len > 0) + { + /* Trim trailing \n\r*/ + char *p; + for(p= buf + len;p > buf && (*p == '\n' || *p=='\r' || *p == 0);p--) + *p= 0; + } +} diff --git a/plugins/connection/CMakeLists.txt b/plugins/connection/CMakeLists.txt index 4ccdd611..f57d08a5 100644 --- a/plugins/connection/CMakeLists.txt +++ b/plugins/connection/CMakeLists.txt @@ -3,6 +3,7 @@ IF(WIN32) ENDIF() SET(CMAKE_SHARED_LIBRARY_PREFIX "") +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) IF(REPLICATION_PLUGIN_TYPE MATCHES "DYNAMIC") IF(WIN32) @@ -20,7 +21,7 @@ IF(REPLICATION_PLUGIN_TYPE MATCHES "DYNAMIC") SET(INSTALL_LIBS replication) ENDIF() -IF(REPLICATION_PLUGIN_TYPE MATCHES "DYNAMIC") +IF(AURORA_PLUGIN_TYPE MATCHES "DYNAMIC") IF(WIN32) SET_VERSION_INFO("TARGET:aurora" "FILE_TYPE:VFT_DLL" diff --git a/plugins/connection/aurora.c b/plugins/connection/aurora.c index 524f4364..32fbfe31 100644 --- a/plugins/connection/aurora.c +++ b/plugins/connection/aurora.c @@ -45,7 +45,6 @@ MYSQL *aurora_connect(MYSQL *mysql, const char *host, const char *user, const ch void aurora_close(MYSQL *mysql); int aurora_command(MYSQL *mysql,enum enum_server_command command, const char *arg, size_t length, my_bool skipp_check, void *opt_arg); -int aurora_set_options(MYSQL *msql, enum mysql_option option, void *arg); my_bool aurora_reconnect(MYSQL *mysql); #define AURORA_MAX_INSTANCES 16 @@ -55,11 +54,6 @@ my_bool aurora_reconnect(MYSQL *mysql); #define AURORA_REPLICA 1 #define AURORA_UNAVAILABLE 2 -#define ENABLE_AURORA(mysql)\ - (mysql)->net.conn_hdlr->active= 1; -#define DISABLE_AURORA(mysql)\ - (mysql)->net.conn_hdlr->active= 0; - #ifndef HAVE_AURORA_DYNAMIC MARIADB_CONNECTION_PLUGIN connection_aurora_plugin = #else @@ -77,7 +71,7 @@ MARIADB_CONNECTION_PLUGIN _mysql_client_plugin_declaration_ = NULL, aurora_connect, aurora_close, - aurora_set_options, + NULL, aurora_command, aurora_reconnect }; @@ -92,16 +86,14 @@ typedef struct st_aurora_instance { } AURORA_INSTANCE; typedef struct st_conn_aurora { - MARIADB_PVIO *pvio[2]; - MYSQL *mysql[2]; - my_bool active[2]; + MYSQL *mysql[2], + save_mysql; char *url; unsigned int num_instances; AURORA_INSTANCE instance[AURORA_MAX_INSTANCES]; char *username, *password, *database; unsigned int port; unsigned long client_flag; - unsigned int last_instance_type; /* Primary or Replica */ char primary_id[100]; } AURORA; @@ -118,20 +110,13 @@ my_bool aurora_switch_connection(MYSQL *mysql, AURORA *aurora, int type) case AURORA_REPLICA: if (aurora->mysql[AURORA_REPLICA]) { - mysql->net.pvio= aurora->pvio[AURORA_REPLICA]; - aurora->pvio[AURORA_REPLICA]->mysql= mysql; - mysql->thread_id= aurora->mysql[AURORA_REPLICA]->thread_id; - aurora->last_instance_type= AURORA_REPLICA; + *mysql= *aurora->mysql[AURORA_REPLICA]; } break; case AURORA_PRIMARY: if (aurora->mysql[AURORA_PRIMARY]) { - if (aurora->mysql[AURORA_REPLICA]) - aurora->mysql[AURORA_REPLICA]->net.pvio->mysql= aurora->mysql[AURORA_REPLICA]; - mysql->net.pvio= aurora->pvio[AURORA_PRIMARY]; - mysql->thread_id= aurora->mysql[AURORA_PRIMARY]->thread_id; - aurora->last_instance_type= AURORA_PRIMARY; + *mysql= *aurora->mysql[AURORA_PRIMARY]; } break; default: @@ -257,17 +242,23 @@ my_bool aurora_parse_url(const char *url, AURORA *aurora) */ int aurora_get_instance_type(MYSQL *mysql) { - int rc; + int rc= -1; + MA_CONNECTION_HANDLER *save_hdlr= mysql->net.conn_hdlr; + char *query= "select variable_value from information_schema.global_variables where variable_name='INNODB_READ_ONLY' AND variable_value='OFF'"; + if (!mysql) + return -1; + + mysql->net.conn_hdlr= 0; if (!mariadb_api->mysql_query(mysql, query)) { - MYSQL_RES *res= mysql_store_result(mysql); + MYSQL_RES *res= mariadb_api->mysql_store_result(mysql); rc= mysql_num_rows(res) ? AURORA_PRIMARY : AURORA_REPLICA; - mysql_free_result(res); - return rc; + mariadb_api->mysql_free_result(res); } - return -1; + mysql->net.conn_hdlr= save_hdlr; + return rc; } /* }}} */ @@ -287,16 +278,18 @@ int aurora_get_instance_type(MYSQL *mysql) my_bool aurora_get_primary_id(MYSQL *mysql, AURORA *aurora) { my_bool rc= 0; + MA_CONNECTION_HANDLER *save_hdlr= mysql->net.conn_hdlr; + mysql->net.conn_hdlr= 0; if (!mariadb_api->mysql_query(mysql, "select server_id from information_schema.replica_host_status " "where session_id = 'MASTER_SESSION_ID'")) { MYSQL_RES *res; MYSQL_ROW row; - if ((res= mysql_store_result(mysql))) + if ((res= mariadb_api->mysql_store_result(mysql))) { - if ((row= mysql_fetch_row(res))) + if ((row= mariadb_api->mysql_fetch_row(res))) { if (row[0]) { @@ -304,9 +297,10 @@ my_bool aurora_get_primary_id(MYSQL *mysql, AURORA *aurora) rc= 1; } } - mysql_free_result(res); + mariadb_api->mysql_free_result(res); } } + mysql->net.conn_hdlr= save_hdlr; return rc; } /* }}} */ @@ -326,7 +320,7 @@ static unsigned int aurora_get_valid_instances(AURORA *aurora, AURORA_INSTANCE * { if (aurora->instance[i].type != AURORA_UNAVAILABLE) { - if (aurora->instance[i].type == AURORA_PRIMARY && aurora->active[AURORA_PRIMARY]) + if (aurora->instance[i].type == AURORA_PRIMARY && aurora->mysql[AURORA_PRIMARY]) continue; instances[valid_instances]= &aurora->instance[i]; valid_instances++; @@ -355,14 +349,14 @@ void aurora_refresh_blacklist(AURORA *aurora) /* {{{ MYSQL *aurora_connect_instance() */ MYSQL *aurora_connect_instance(AURORA *aurora, AURORA_INSTANCE *instance, MYSQL *mysql) { - if (!mysql->methods->db_connect(mysql, + if (!mariadb_api->mysql_real_connect(mysql, instance->host, aurora->username, aurora->password, aurora->database, instance->port ? instance->port : aurora->port, NULL, - aurora->client_flag)) + aurora->client_flag | CLIENT_REMEMBER_OPTIONS)) { /* connection not available */ instance->blacklisted= time(NULL); @@ -386,31 +380,21 @@ MYSQL *aurora_connect_instance(AURORA *aurora, AURORA_INSTANCE *instance, MYSQL return NULL; } if (!aurora->primary_id[0]) - aurora_get_primary_id(mysql, aurora); + if (aurora_get_primary_id(mysql, aurora)) + return NULL; return mysql; } /* }}} */ -/* {{{ void aurora_copy_mysql() */ -void aurora_copy_mysql(MYSQL *from, MYSQL *to) +/* {{{ void aurora_close_internal */ +void aurora_close_internal(MYSQL *mysql) { - /* invalidate statements */ - to->methods->invalidate_stmts(to, "aurora connect/reconnect"); - - from->free_me= to->free_me; - from->reconnect= to->reconnect; - from->net.conn_hdlr= to->net.conn_hdlr; - from->stmts= to->stmts; - to->stmts= NULL; - - memset(&to->options, 0, sizeof(to->options)); - to->free_me= 0; - to->net.conn_hdlr= 0; - mariadb_api->mysql_close(to); - *to= *from; - to->net.pvio= from->net.pvio; - to->net.pvio->mysql= to; - from->net.pvio= NULL; + if (mysql) + { + mysql->net.conn_hdlr= 0; + memset(&mysql->options, 0, sizeof(struct st_mysql_options)); + mariadb_api->mysql_close(mysql); + } } /* }}} */ @@ -420,46 +404,45 @@ my_bool aurora_find_replica(AURORA *aurora) int valid_instances; my_bool replica_found= 0; AURORA_INSTANCE *instance[AURORA_MAX_INSTANCES]; - MYSQL mysql; + MYSQL *mysql; if (aurora->num_instances < 2) return 0; - mariadb_api->mysql_init(&mysql); - mysql.options= aurora->mysql[AURORA_PRIMARY]->options; - - /* don't execute init_command on slave */ - mysql.net.conn_hdlr= aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr; valid_instances= aurora_get_valid_instances(aurora, instance); while (valid_instances && !replica_found) { int random_pick= rand() % valid_instances; - if ((aurora_connect_instance(aurora, instance[random_pick], &mysql))) + mysql= mariadb_api->mysql_init(NULL); + mysql->options= aurora->save_mysql.options; + + /* don't execute init_command on slave */ +// mysql->net.conn_hdlr= aurora->save_mysql.net.conn_hdlr; + if ((aurora_connect_instance(aurora, instance[random_pick], mysql))) { switch (instance[random_pick]->type) { case AURORA_REPLICA: if (!aurora->mysql[AURORA_REPLICA]) - { - aurora->mysql[AURORA_REPLICA]= mysql_init(NULL); - } - aurora_copy_mysql(&mysql, aurora->mysql[AURORA_REPLICA]); - aurora->active[AURORA_REPLICA]= 1; + aurora->mysql[AURORA_REPLICA]= mysql; return 1; break; case AURORA_PRIMARY: - aurora_copy_mysql(&mysql, aurora->mysql[AURORA_PRIMARY]); - aurora->pvio[AURORA_PRIMARY]= aurora->mysql[AURORA_PRIMARY]->net.pvio; - aurora->active[AURORA_PRIMARY]= 1; + if (!aurora->mysql[AURORA_PRIMARY]) + aurora->mysql[AURORA_PRIMARY]= mysql; + else + aurora_close_internal(mysql); continue; break; default: - mysql_close(&mysql); + aurora_close_internal(mysql); return 0; break; } } + else + aurora_close_internal(mysql); valid_instances= aurora_get_valid_instances(aurora, instance); } return 0; @@ -488,101 +471,79 @@ my_bool aurora_find_primary(AURORA *aurora) { unsigned int i; AURORA_INSTANCE *instance= NULL; - MYSQL mysql; + MYSQL *mysql; my_bool check_primary= 1; + /* We try to find a primary: + * by looking 1st if a replica connect provided primary_id already + * by walking through instances */ + if (!aurora->num_instances) return 0; - mariadb_api->mysql_init(&mysql); - mysql.options= aurora->mysql[AURORA_PRIMARY]->options; - mysql.net.conn_hdlr= aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr; - for (i=0; i < aurora->num_instances; i++) { + mysql= mariadb_api->mysql_init(NULL); + mysql->options= aurora->save_mysql.options; + if (check_primary && aurora->primary_id[0]) { if ((instance= aurora_get_primary_id_instance(aurora)) && - aurora_connect_instance(aurora, instance, &mysql) && + aurora_connect_instance(aurora, instance, mysql) && instance->type == AURORA_PRIMARY) { - aurora_copy_mysql(&mysql, aurora->mysql[AURORA_PRIMARY]); - aurora->active[AURORA_PRIMARY]= 1; + aurora->primary_id[0]= 0; + aurora->mysql[AURORA_PRIMARY]= mysql; return 1; } /* primary id connect failed, don't try again */ aurora->primary_id[0]= 0; check_primary= 0; } - if (aurora->instance[i].type != AURORA_UNAVAILABLE) + else if (aurora->instance[i].type != AURORA_UNAVAILABLE) { - if (aurora_connect_instance(aurora, &aurora->instance[i], &mysql) + if (aurora_connect_instance(aurora, &aurora->instance[i], mysql) && aurora->instance[i].type == AURORA_PRIMARY) { - aurora_copy_mysql(&mysql, aurora->mysql[AURORA_PRIMARY]); - aurora->active[AURORA_PRIMARY]= 1; + aurora->mysql[AURORA_PRIMARY]= mysql; return 1; } } + aurora_close_internal(mysql); } return 0; } /* }}} */ -/* {{{ void aurora_close_replica() */ -void aurora_close_replica(MYSQL *mysql, AURORA *aurora) -{ - if (aurora->mysql[AURORA_REPLICA]) - { - aurora->mysql[AURORA_REPLICA]->net.pvio->mysql= aurora->mysql[AURORA_REPLICA]; - aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= 0; - mariadb_api->mysql_close(aurora->mysql[AURORA_REPLICA]); - aurora->pvio[AURORA_REPLICA]= 0; - aurora->mysql[AURORA_REPLICA]= NULL; - } -} -/* }}} */ - /* {{{ MYSQL *aurora_connect */ MYSQL *aurora_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) { AURORA *aurora= NULL; - MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr; - my_bool is_reconnect= 0; + MA_CONNECTION_HANDLER *save_hdlr= mysql->net.conn_hdlr; if (!mariadb_api) mariadb_api= mysql->methods->api; - mariadb_api->mariadb_get_info(mysql, MARIADB_CLIENT_ERRORS, &client_errors); - - if ((aurora= (AURORA *)hdlr->data)) - { - aurora_refresh_blacklist(aurora); - if (aurora->mysql[aurora->last_instance_type]->net.pvio) - { - SET_CLIENT_ERROR(mysql, CR_ALREADY_CONNECTED, SQLSTATE_UNKNOWN, 0); - return NULL; - } - is_reconnect= 1; - } - else + /* we call aurora_connect either from mysql_real_connect or from mysql_reconnect, + * so make sure in case of reconnect we don't allocate aurora twice */ + if (!(aurora= (AURORA *)save_hdlr->data)) { if (!(aurora= (AURORA *)calloc(1, sizeof(AURORA)))) { mysql->methods->set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); return NULL; } + aurora->save_mysql= *mysql; - mysql->net.conn_hdlr->data= (void *)aurora; - - aurora->mysql[AURORA_PRIMARY]= mysql; + save_hdlr->data= (void *)aurora; if (aurora_parse_url(host, aurora)) { goto error; } + /* store login credentials for connect/reconnect */ if (user) aurora->username= strdup(user); if (passwd) @@ -591,51 +552,35 @@ MYSQL *aurora_connect(MYSQL *mysql, const char *host, const char *user, const ch aurora->database= strdup(db); aurora->port= port; aurora->client_flag= client_flag; - aurora->pvio[AURORA_PRIMARY]= aurora->pvio[AURORA_REPLICA]= NULL; - hdlr->data= aurora; } - - /* In case of reconnect, close broken connection first */ - if (is_reconnect) + /* we look for replica first: + if it's a primary we don't need to call find_aurora_primary + if it's a replica we can obtain primary_id */ + if (!aurora->mysql[AURORA_REPLICA]) { - DISABLE_AURORA(mysql); - switch (aurora->last_instance_type) { - case AURORA_REPLICA: - aurora_close_replica(mysql, aurora); - aurora->pvio[AURORA_REPLICA]= NULL; - break; - case AURORA_PRIMARY: - /* pvio will be closed in mysql_reconnect() */ - aurora->pvio[AURORA_PRIMARY]= NULL; - aurora->primary_id[0]= 0; - break; - } - aurora->active[aurora->last_instance_type]= 0; - } - - if (!aurora->active[AURORA_REPLICA]) - { - if (aurora_find_replica(aurora)) - { - aurora->pvio[AURORA_REPLICA]= aurora->mysql[AURORA_REPLICA]->net.pvio; - aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= mysql->net.conn_hdlr; - } + if (!aurora_find_replica(aurora)) + aurora->mysql[AURORA_REPLICA]= NULL; else - aurora->pvio[AURORA_REPLICA]= NULL; + aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= save_hdlr; } - if (!aurora->active[AURORA_PRIMARY]) + if (!aurora->mysql[AURORA_PRIMARY]) { - if (aurora_find_primary(aurora)) - { - aurora->active[AURORA_PRIMARY]= 1; - aurora->pvio[AURORA_PRIMARY]= aurora->mysql[AURORA_PRIMARY]->net.pvio; - } + if (!aurora_find_primary(aurora)) + aurora->mysql[AURORA_PRIMARY]= NULL; + else + aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr= save_hdlr; } - aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); - ENABLE_AURORA(mysql); + if (!aurora->mysql[AURORA_PRIMARY] && !aurora->mysql[AURORA_REPLICA]) + goto error; + + if (aurora->mysql[AURORA_PRIMARY]) + aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); + else + aurora_switch_connection(mysql, aurora, AURORA_REPLICA); + mysql->net.conn_hdlr= save_hdlr; return mysql; error: aurora_close_memory(aurora); @@ -647,28 +592,53 @@ error: my_bool aurora_reconnect(MYSQL *mysql) { AURORA *aurora; - MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr; - my_bool rc= 1; + MA_CONNECTION_HANDLER *save_hdlr= mysql->net.conn_hdlr; + int i; - aurora= (AURORA *)hdlr->data; + /* We can't determine if a new primary was promotoed, or if + * line just dropped - we will close both primary and replica + * connection and establish a new connection via + * aurora_connect */ - DISABLE_AURORA(mysql); - switch (aurora->last_instance_type) + aurora= (AURORA *)save_hdlr->data; + + /* removed blacklisted instances */ + for (i=0; i < aurora->num_instances; i++) + aurora->instance[i].type= AURORA_UNKNOWN; + + if (aurora->mysql[AURORA_PRIMARY]->thread_id == mysql->thread_id) { - case AURORA_REPLICA: - if (!(rc= mariadb_api->mysql_reconnect(aurora->mysql[aurora->last_instance_type]))) - aurora_switch_connection(mysql, aurora, AURORA_REPLICA); - break; - case AURORA_PRIMARY: - if (!(rc= mysql_reconnect(aurora->mysql[aurora->last_instance_type]))) - aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); - break; - default: - /* todo: error message */ - break; + /* don't send COM_QUIT */ + aurora->mysql[AURORA_PRIMARY]->net.pvio= NULL; + aurora_close_internal(aurora->mysql[AURORA_PRIMARY]); + aurora->mysql[AURORA_PRIMARY]= NULL; + aurora_close_internal(aurora->mysql[AURORA_REPLICA]); + aurora->mysql[AURORA_REPLICA]= NULL; } - ENABLE_AURORA(mysql); - return rc; + else if (aurora->mysql[AURORA_REPLICA]->thread_id == mysql->thread_id) + { + /* don't send COM_QUIT */ + aurora->mysql[AURORA_REPLICA]->net.pvio= NULL; + aurora_close_internal(aurora->mysql[AURORA_REPLICA]); + aurora->mysql[AURORA_REPLICA]= NULL; + aurora_close_internal(aurora->mysql[AURORA_PRIMARY]); + aurora->mysql[AURORA_PRIMARY]= NULL; + } + + /* unset connections, so we can connect to primary and replica again */ + aurora->mysql[AURORA_PRIMARY]= aurora->mysql[AURORA_REPLICA]= NULL; + + if (aurora_connect(mysql, NULL, NULL, NULL, NULL, 0, NULL, 0)) + { + if (aurora->mysql[AURORA_PRIMARY]) + *mysql= *aurora->mysql[AURORA_PRIMARY]; + return 0; + } + if (aurora->mysql[AURORA_REPLICA]) + *mysql= *aurora->mysql[AURORA_REPLICA]; + else + *mysql= aurora->save_mysql; + return 1; } /* }}} */ @@ -676,46 +646,34 @@ my_bool aurora_reconnect(MYSQL *mysql) void aurora_close(MYSQL *mysql) { MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr; - AURORA *aurora= (AURORA *)hdlr->data; + AURORA *aurora; + int i; - aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); - - /* if the connection is not active yet, just return */ - if (!aurora->active[1]) + if (!hdlr || !hdlr->data) return; + + aurora= (AURORA *)hdlr->data; + *mysql= aurora->save_mysql; - if (aurora->mysql[AURORA_REPLICA]) + if (!aurora->mysql[AURORA_PRIMARY] && !aurora->mysql[AURORA_REPLICA]) + goto end; + + for (i=0; i < 2; i++) { - /* we got options from primary, so don't free it twice */ - memset(&aurora->mysql[AURORA_REPLICA]->options, 0, sizeof(mysql->options)); - /* connection handler wull be freed in mariadb_api->mysql_close() */ - aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= 0; + if (aurora->mysql[i]) + { + /* Make sure that connection wasn't closed before, e.g. after disconnect */ + if (mysql->thread_id == aurora->mysql[i]->thread_id && !mysql->net.pvio) + aurora->mysql[i]->net.pvio= 0; - mysql_close(aurora->mysql[AURORA_REPLICA]); + aurora_close_internal(aurora->mysql[i]); + aurora->mysql[i]= NULL; + } } - - if (aurora->mysql[AURORA_PRIMARY]) - { - /* connection handler wull be freed in mysql_close() */ - aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr= 0; - - aurora->mysql[AURORA_PRIMARY]->net.pvio= aurora->pvio[AURORA_PRIMARY]; - - mysql_close(aurora->mysql[AURORA_PRIMARY]); - } - - - -/* - if (aurora->mysql[AURORA_PRIMARY]) - { - aurora->mysql[AURORA_PRIMARY]->net.pvio= aurora->pvio[AURORA_PRIMARY]; - aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr= 0; - mysql_close(aurora->mysql[AURORA_PRIMARY]); - } -*/ - /* free masrwe information */ + /* free information */ +end: aurora_close_memory(aurora); + mysql->net.conn_hdlr= hdlr; } /* }}} */ @@ -758,7 +716,8 @@ my_bool is_replica_stmt(MYSQL *mysql, const char *buffer) int aurora_command(MYSQL *mysql,enum enum_server_command command, const char *arg, size_t length, my_bool skipp_check, void *opt_arg) { - AURORA *aurora= (AURORA *)mysql->net.conn_hdlr->data; + MA_CONNECTION_HANDLER *save_hdlr= mysql->net.conn_hdlr; + AURORA *aurora= (AURORA *)save_hdlr->data; /* if we don't have slave or slave became unavailable root traffic to master */ if (!aurora->mysql[AURORA_REPLICA] || !OPT_HAS_EXT_VAL(mysql, read_only)) @@ -766,54 +725,43 @@ int aurora_command(MYSQL *mysql,enum enum_server_command command, const char *ar if (command != COM_INIT_DB) { aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); - return 0; + goto end; } } switch(command) { case COM_INIT_DB: /* we need to change default database on primary and replica */ - if (aurora->mysql[AURORA_REPLICA] && aurora->last_instance_type != AURORA_REPLICA) + if (aurora->mysql[AURORA_REPLICA] && mysql->thread_id == aurora->mysql[AURORA_PRIMARY]->thread_id) { - aurora_switch_connection(mysql, aurora, AURORA_REPLICA); - DISABLE_AURORA(mysql); + aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= 0; mariadb_api->mysql_select_db(aurora->mysql[AURORA_REPLICA], arg); - ENABLE_AURORA(mysql); - aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); + aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= mysql->net.conn_hdlr; } break; case COM_QUERY: case COM_STMT_PREPARE: - if (aurora->mysql[AURORA_REPLICA] && aurora->last_instance_type != AURORA_REPLICA) + if (aurora->mysql[AURORA_REPLICA]) aurora_switch_connection(mysql, aurora, AURORA_REPLICA); break; case COM_STMT_EXECUTE: case COM_STMT_FETCH: - if (aurora->pvio[AURORA_REPLICA]->mysql->stmts && is_replica_stmt(aurora->pvio[AURORA_REPLICA]->mysql, arg)) + if (aurora->mysql[AURORA_REPLICA] && aurora->mysql[AURORA_REPLICA]->stmts && + is_replica_stmt(aurora->mysql[AURORA_REPLICA], arg)) { - if (aurora->last_instance_type != AURORA_REPLICA) - aurora_switch_connection(mysql, aurora, AURORA_REPLICA); + aurora_switch_connection(mysql, aurora, AURORA_REPLICA); } else { - if (aurora->last_instance_type != AURORA_PRIMARY) - aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); + aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); } default: aurora_switch_connection(mysql, aurora, AURORA_PRIMARY); break; } +end: + mysql->net.conn_hdlr= save_hdlr; return 0; } /* }}} */ - -/* {{{ int aurora_set_options() */ -int aurora_set_options(MYSQL *mysql, enum mysql_option option, void *arg) -{ - switch(option) { - default: - return -1; - } -} -/* }}} */ diff --git a/plugins/connection/replication.c b/plugins/connection/replication.c index 9b4d1865..6bb74cef 100644 --- a/plugins/connection/replication.c +++ b/plugins/connection/replication.c @@ -202,8 +202,8 @@ MYSQL *repl_connect(MYSQL *mysql, const char *host, const char *user, const char goto error; /* try to connect to master */ - if (!(mysql->methods->db_connect(mysql, data->host[MARIADB_MASTER], user, passwd, db, - data->port[MARIADB_MASTER] ? data->port[MARIADB_MASTER] : port, unix_socket, clientflag))) + if (!(mariadb_api->mysql_real_connect(mysql, data->host[MARIADB_MASTER], user, passwd, db, + data->port[MARIADB_MASTER] ? data->port[MARIADB_MASTER] : port, unix_socket, clientflag))) goto error; data->pvio[MARIADB_MASTER]= mysql->net.pvio; diff --git a/plugins/io/CMakeLists.txt b/plugins/io/CMakeLists.txt index 2d3d61b8..44850b49 100644 --- a/plugins/io/CMakeLists.txt +++ b/plugins/io/CMakeLists.txt @@ -17,6 +17,7 @@ IF(REMOTEIO_PLUGIN_TYPE MATCHES "DYNAMIC") # remote file plugin INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR}) SET(REMOTE_IO_SOURCES ${remote_io_RC} remote_io.c) + ADD_DEFINITIONS(-DHAVE_REMOTEIO_DYNAMIC=1) ADD_LIBRARY(remote_io SHARED ${REMOTE_IO_SOURCES} ${CMAKE_SOURCE_DIR}/plugins/plugin.def) TARGET_LINK_LIBRARIES(remote_io ${CURL_LIBRARIES}) SET_TARGET_PROPERTIES(remote_io PROPERTIES PREFIX "") diff --git a/plugins/io/remote_io.c b/plugins/io/remote_io.c index dd9be58d..411aa3c5 100644 --- a/plugins/io/remote_io.c +++ b/plugins/io/remote_io.c @@ -1,5 +1,5 @@ /************************************************************************************ - * Copyright (C) 2015 Monty Program AB + * Copyright (C) 2015, 2016 Monty Program AB * Copyright (c) 2003 Simtec Electronics * * Re-implemented by Vincent Sanders with extensive @@ -43,7 +43,6 @@ smb:// */ -#ifdef HAVE_CURL #include #include #include @@ -55,9 +54,12 @@ #include #ifndef WIN32 #include +#else +#pragma comment(lib, "Ws2_32.lib") #endif #include #include +#include /* Internal file structure */ @@ -89,11 +91,10 @@ typedef struct CURLM *multi_handle= NULL; -#ifndef HAVE_REMOTE_IO_DYNAMIC -struct st_mysql_client_plugin remote_io_plugin= -{ +#ifndef HAVE_REMOTEIO_DYNAMIC +MARIADB_REMOTEIO_PLUGIN remote_io_plugin= #else -struct st_mysql_client_plugin _mysql_client_plugin_declare_ = +MARIADB_REMOTEIO_PLUGIN _mysql_client_plugin_declaration_ = #endif { MARIADB_CLIENT_REMOTEIO_PLUGIN, @@ -127,6 +128,7 @@ int ma_rio_deinit(void) multi_handle= NULL; } curl_global_cleanup(); + return 0; } /* }}} */ @@ -439,4 +441,3 @@ char *ma_rio_gets(char *ptr, size_t size, MA_FILE *file) return ptr;/*success */ } -#endif diff --git a/plugins/pvio/pvio_socket.c b/plugins/pvio/pvio_socket.c index 809a6b97..841acfcb 100644 --- a/plugins/pvio/pvio_socket.c +++ b/plugins/pvio/pvio_socket.c @@ -1,5 +1,5 @@ /************************************************************************************ - Copyright (C) 2015 MariaDB Corporation AB, + Copyright (C) 2015,2016 MariaDB Corporation AB, This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -106,7 +106,7 @@ struct st_ma_pvio_methods pvio_socket_methods= { #ifndef HAVE_SOCKET_DYNAMIC MARIADB_PVIO_PLUGIN pvio_socket_plugin= #else -MARIADB_PVIO_PLUGIN _mysql_client_plugin_declare_ +MARIADB_PVIO_PLUGIN _mysql_client_plugin_declaration_ #endif { MARIADB_CLIENT_PVIO_PLUGIN, diff --git a/unittest/libmariadb/CMakeLists.txt b/unittest/libmariadb/CMakeLists.txt index 8c30c728..90e5a1b7 100644 --- a/unittest/libmariadb/CMakeLists.txt +++ b/unittest/libmariadb/CMakeLists.txt @@ -21,11 +21,11 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/unittest/mytap) ADD_DEFINITIONS(-DLIBMARIADB) -SET(API_TESTS "t_aurora" "async" "basic-t" "fetch" "charset" "logs" - "cursor" "errors" "view" "ps" "ps_bugs" - "sp" "result" "connection" "misc" "ps_new" "sqlite3" "thread" - "dyncol" "features-10_2") +SET(API_TESTS "async" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs" + "sp" "result" "connection" "misc" "ps_new" "sqlite3" "thread" "dyncol" "features-10_2") +#exclude following tests from ctests, since we need to run them maually with different credentials +SET(MANUAL_TESTS "t_aurora") # Get finger print from server certificate IF(WITH_SSL) @@ -64,3 +64,8 @@ FOREACH(API_TEST ${API_TESTS}) ADD_TEST(${API_TEST} ${EXECUTABLE_OUTPUT_PATH}/${API_TEST}) SET_TESTS_PROPERTIES(${API_TEST} PROPERTIES TIMEOUT 120) ENDFOREACH(API_TEST) + +FOREACH(API_TEST ${MANUAL_TESTS}) + ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c ${CMAKE_SOURCE_DIR}/libmariadb/getopt.c) + TARGET_LINK_LIBRARIES(${API_TEST} mytap libmariadb) +ENDFOREACH() diff --git a/unittest/libmariadb/basic-t.c b/unittest/libmariadb/basic-t.c index 02dcc294..9a385ffe 100644 --- a/unittest/libmariadb/basic-t.c +++ b/unittest/libmariadb/basic-t.c @@ -35,11 +35,11 @@ static int test_conc75(MYSQL *my) int rc; MYSQL *mysql; int i; + my_bool reconnect= 1; mysql= mysql_init(NULL); - - mysql->reconnect= 1; + mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0| CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS); rc= mysql_query(mysql, "DROP TABLE IF EXISTS a"); @@ -55,7 +55,7 @@ static int test_conc75(MYSQL *my) { ulong thread_id= mysql_thread_id(mysql); /* force reconnect */ - mysql->reconnect= 1; + mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); diag("killing connection"); mysql_kill(my, thread_id); sleep(2); @@ -700,6 +700,10 @@ static int test_reconnect_maxpackage(MYSQL *my) MYSQL_RES *res; MYSQL_ROW row; char *query; + my_bool reconnect= 1; + + SKIP_CONNECTION_HANDLER; + mysql= mysql_init(NULL); SKIP_CONNECTION_HANDLER; mysql= mysql_init(NULL); @@ -707,7 +711,7 @@ static int test_reconnect_maxpackage(MYSQL *my) FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS), mysql_error(mysql)); - mysql->reconnect= 1; + mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); rc= mysql_query(mysql, "SELECT @@max_allowed_packet"); check_mysql_rc(rc, mysql); @@ -753,12 +757,13 @@ static int test_compressed(MYSQL *my) int rc; MYSQL *mysql= mysql_init(NULL); MYSQL_RES *res; + my_bool reconnect= 1; mysql_options(mysql, MYSQL_OPT_COMPRESS, (void *)1); FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS), mysql_error(mysql)); - mysql->reconnect= 1; + mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); rc= mysql_query(mysql, "SHOW VARIABLES"); check_mysql_rc(rc, mysql); diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index 0ce22450..fe1f220b 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -455,16 +455,21 @@ static int test_opt_reconnect(MYSQL *mysql) { my_bool my_true= TRUE; int rc; + my_bool reconnect; + + printf("true: %d\n", TRUE); mysql= mysql_init(NULL); FAIL_IF(!mysql, "not enough memory"); - FAIL_UNLESS(mysql->reconnect == 0, "reconnect != 0"); + mysql_get_option(mysql, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_UNLESS(reconnect == 0, "reconnect != 0"); rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, &my_true); check_mysql_rc(rc, mysql); - FAIL_UNLESS(mysql->reconnect == 1, "reconnect != 1"); + mysql_get_option(mysql, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_UNLESS(reconnect == 1, "reconnect != 1"); if (!(mysql_real_connect(mysql, hostname, username, password, schema, port, @@ -475,14 +480,16 @@ static int test_opt_reconnect(MYSQL *mysql) return FAIL; } - FAIL_UNLESS(mysql->reconnect == 1, "reconnect != 1"); + mysql_get_option(mysql, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_UNLESS(reconnect == 1, "reconnect != 1"); mysql_close(mysql); mysql= mysql_init(NULL); FAIL_IF(!mysql, "not enough memory"); - FAIL_UNLESS(mysql->reconnect == 0, "reconnect != 0"); + mysql_get_option(mysql, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_UNLESS(reconnect == 0, "reconnect != 0"); if (!(mysql_real_connect(mysql, hostname, username, password, schema, port, @@ -493,7 +500,8 @@ static int test_opt_reconnect(MYSQL *mysql) return FAIL; } - FAIL_UNLESS(mysql->reconnect == 0, "reconnect != 0"); + mysql_get_option(mysql, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_UNLESS(reconnect == 0, "reconnect != 0"); mysql_close(mysql); return OK; @@ -538,16 +546,19 @@ static int test_reconnect(MYSQL *mysql) my_bool my_true= TRUE; MYSQL *mysql1; int rc; + my_bool reconnect; mysql1= mysql_init(NULL); FAIL_IF(!mysql1, "not enough memory"); - FAIL_UNLESS(mysql1->reconnect == 0, "reconnect != 0"); + mysql_get_option(mysql1, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_UNLESS(reconnect == 0, "reconnect != 0"); rc= mysql_options(mysql1, MYSQL_OPT_RECONNECT, &my_true); check_mysql_rc(rc, mysql1); - FAIL_UNLESS(mysql1->reconnect == 1, "reconnect != 1"); + mysql_get_option(mysql1, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_UNLESS(reconnect == 1, "reconnect != 1"); if (!(mysql_real_connect(mysql1, hostname, username, password, schema, port, @@ -558,7 +569,8 @@ static int test_reconnect(MYSQL *mysql) return FAIL; } - FAIL_UNLESS(mysql1->reconnect == 1, "reconnect != 1"); + mysql_get_option(mysql1, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_UNLESS(reconnect == 1, "reconnect != 1"); diag("Thread_id before kill: %lu", mysql_thread_id(mysql1)); mysql_kill(mysql, mysql_thread_id(mysql1)); @@ -570,7 +582,8 @@ static int test_reconnect(MYSQL *mysql) check_mysql_rc(rc, mysql1); diag("Thread_id after kill: %lu", mysql_thread_id(mysql1)); - FAIL_UNLESS(mysql1->reconnect == 1, "reconnect != 1"); + mysql_get_option(mysql1, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_UNLESS(reconnect == 1, "reconnect != 1"); mysql_close(mysql1); return OK; } @@ -647,8 +660,10 @@ int test_connection_timeout(MYSQL *my) static int test_conc118(MYSQL *mysql) { int rc; + my_bool reconnect= 1; + + mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); - mysql->reconnect= 1; mysql->options.unused_1= 1; rc= mysql_kill(mysql, mysql_thread_id(mysql)); @@ -745,9 +760,10 @@ static int test_bind_address(MYSQL *my) static int test_get_options(MYSQL *my) { MYSQL *mysql= mysql_init(NULL); - int options_int[]= {MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_LOCAL_INFILE, - MYSQL_OPT_RECONNECT, MYSQL_OPT_PROTOCOL, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT, 0}; - my_bool options_bool[]= {MYSQL_OPT_COMPRESS, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_SECURE_AUTH, + int options_int[]= {MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_LOCAL_INFILE, + MYSQL_OPT_PROTOCOL, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT, 0}; + my_bool options_bool[]= {MYSQL_OPT_RECONNECT, MYSQL_REPORT_DATA_TRUNCATION, + MYSQL_OPT_COMPRESS, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_SECURE_AUTH, #ifdef _WIN32 MYSQL_OPT_NAMED_PIPE, #endif @@ -755,7 +771,7 @@ static int test_get_options(MYSQL *my) int options_char[]= {MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CERT, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER, MYSQL_OPT_BIND, MARIADB_OPT_SSL_FP, MARIADB_OPT_SSL_FP_LIST, - MARIADB_OPT_SSL_PASSWORD, 0}; + MARIADB_OPT_SSL_PASSPHRASE, 0}; char *init_command[3]= {"SET @a:=1", "SET @b:=2", "SET @c:=3"}; int elements= 0; diff --git a/unittest/libmariadb/misc.c b/unittest/libmariadb/misc.c index 1dd9f478..dd156fe8 100644 --- a/unittest/libmariadb/misc.c +++ b/unittest/libmariadb/misc.c @@ -957,6 +957,7 @@ static int test_conc_114(MYSQL *mysql) /* run with valgrind */ static int test_conc117(MYSQL *mysql) { + my_bool reconnect= 1; MYSQL *my= mysql_init(NULL); FAIL_IF(!mysql_real_connect(my, hostname, username, password, schema, port, socketname, 0), mysql_error(my)); @@ -964,7 +965,7 @@ static int test_conc117(MYSQL *mysql) mysql_kill(my, mysql_thread_id(my)); sleep(5); - my->reconnect= 1; + mysql_options(my, MYSQL_OPT_RECONNECT, &reconnect); mysql_query(my, "SET @a:=1"); mysql_close(my); @@ -982,6 +983,7 @@ static int test_remote1(MYSQL *mysql) if (!remote_plugin) { diag("skip - no remote io plugin available"); + diag("error: %s", mysql_error(mysql)); return SKIP; } @@ -1043,7 +1045,7 @@ static int test_get_info(MYSQL *mysql) rc= mariadb_get_infov(mysql, MARIADB_CONNECTION_SERVER_VERSION_ID, &sval); FAIL_IF(rc, "mysql_get_info failed"); diag("server_version_id: %d", sval); - rc= mariadb_get_infov(mysql, MARIADB_CHARSET_INFO, &cs); + rc= mariadb_get_infov(mysql, MARIADB_CONNECTION_CHARSET_INFO, &cs); FAIL_IF(rc, "mysql_get_info failed"); diag("charset name: %s", cs.csname); rc= mariadb_get_infov(mysql, MARIADB_CONNECTION_PVIO_TYPE, &ival); diff --git a/unittest/libmariadb/my_test.h b/unittest/libmariadb/my_test.h index e0db2beb..2897b3a7 100644 --- a/unittest/libmariadb/my_test.h +++ b/unittest/libmariadb/my_test.h @@ -29,6 +29,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include +#ifndef WIN32 +#include +#endif + #ifndef OK # define OK 0 #endif @@ -374,7 +378,6 @@ int check_variable(MYSQL *mysql, char *variable, char *value) */ MYSQL *test_connect(struct my_tests_st *test) { MYSQL *mysql; - char query[255]; int i= 0; int timeout= 10; int truncation_report= 1; @@ -401,32 +404,13 @@ MYSQL *test_connect(struct my_tests_st *test) { } } if (!(mysql_real_connect(mysql, hostname, username, password, - NULL, port, socketname, (test) ? test->connect_flags:0))) + schema, port, socketname, (test) ? test->connect_flags:0))) { diag("Couldn't establish connection to server %s. Error (%d): %s", hostname, mysql_errno(mysql), mysql_error(mysql)); mysql_close(mysql); return(NULL); } - - /* change database or create if it doesn't exist */ - if (mysql_select_db(mysql, schema)) { - diag("Error number: %d", mysql_errno(mysql)); - - if(mysql_errno(mysql) == 1049) { - sprintf(query, "CREATE DATABASE %s", schema); - if (mysql_query(mysql, query)) { - diag("Can't create database %s", schema); - mysql_close(mysql); - return NULL; - } - } else { - diag("Error (%d): %s", mysql_errno(mysql), mysql_error(mysql)); - mysql_close(mysql); - return NULL; - } - } - return(mysql); } @@ -526,6 +510,7 @@ void run_tests(struct my_tests_st *test) { } } if (mysql_default) { + diag("close default"); mysql_close(mysql_default); } mysql_server_end(); diff --git a/unittest/libmariadb/ps.c b/unittest/libmariadb/ps.c index add7a493..3eb74bb9 100644 --- a/unittest/libmariadb/ps.c +++ b/unittest/libmariadb/ps.c @@ -52,12 +52,13 @@ static int test_conc83(MYSQL *my) MYSQL_STMT *stmt; int rc; MYSQL *mysql= mysql_init(NULL); + my_bool reconnect= 1; char *query= "SELECT 1,2,3 FROM DUAL"; stmt= mysql_stmt_init(mysql); - mysql->reconnect= 1; + mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); FAIL_IF(!(mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0)), "mysql_real_connect failed"); @@ -69,7 +70,7 @@ static int test_conc83(MYSQL *my) rc= mysql_ping(mysql); check_mysql_rc(rc, mysql); - rc= mysql_stmt_prepare(stmt, query, strlen(query)); + rc= mysql_stmt_prepare(stmt, query, -1); check_stmt_rc(rc, stmt); diag("Ok"); @@ -77,7 +78,7 @@ static int test_conc83(MYSQL *my) rc= mysql_kill(mysql, mysql_thread_id(mysql)); sleep(2); - rc= mysql_stmt_prepare(stmt, query, strlen(query)); + rc= mysql_stmt_prepare(stmt, query, -1); FAIL_IF(!rc, "Error expected"); mysql_stmt_close(stmt); @@ -97,7 +98,7 @@ static int test_conc60(MYSQL *mysql) rc= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void *)&x); - rc= mysql_stmt_prepare(stmt, query, strlen(query)); + rc= mysql_stmt_prepare(stmt, query, -1); if (rc && mysql_stmt_errno(stmt) == 1146) { diag("Internal test - customer data not available"); mysql_stmt_close(stmt); @@ -4544,9 +4545,9 @@ static int test_stmt_close(MYSQL *mysql) unsigned int count; int rc; char query[MAX_TEST_QUERY_LENGTH]; + my_bool reconnect= 1; - - mysql->reconnect= 1; + mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); /* set AUTOCOMMIT to ON*/ mysql_autocommit(mysql, TRUE); @@ -4644,9 +4645,8 @@ static int test_new_date(MYSQL *mysql) MYSQL_BIND bind[1]; int rc; char buffer[50]; - - - mysql->reconnect= 1; + my_bool reconnect= 1; + mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); /* set AUTOCOMMIT to ON*/ mysql_autocommit(mysql, TRUE); diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index e5204ea4..94b946ea 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -3909,7 +3909,111 @@ static int test_conc141(MYSQL *mysql) return OK; } +static int test_conc154(MYSQL *mysql) +{ + MYSQL_STMT *stmt; + const char *stmtstr= "SELECT * FROM t1"; + int rc; + + /* 1st: empty result set without free_result */ + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "CREATE TABLE t1 (a varchar(20))"); + check_mysql_rc(rc, mysql); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr)); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_store_result(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_store_result(stmt); + check_stmt_rc(rc, stmt); + + mysql_stmt_close(stmt); + + /* 2nd: empty result set with free_result */ + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr)); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_store_result(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_free_result(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_store_result(stmt); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_free_result(stmt); + check_stmt_rc(rc, stmt); + + mysql_stmt_close(stmt); + + /* 3rd: non empty result without free_result */ + rc= mysql_query(mysql, "INSERT INTO t1 VALUES ('test_conc154')"); + check_mysql_rc(rc, mysql); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr)); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_store_result(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_store_result(stmt); + check_stmt_rc(rc, stmt); + + mysql_stmt_close(stmt); + + /* 4th non empty result set with free_result */ + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr)); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_store_result(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_free_result(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_store_result(stmt); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_free_result(stmt); + check_stmt_rc(rc, stmt); + + mysql_stmt_close(stmt); + + return OK; +} + struct my_tests_st my_tests[] = { + {"test_conc154", test_conc154, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, {"test_conc141", test_conc141, TEST_CONNECTION_NEW, 0, NULL , NULL}, {"test_conc67", test_conc67, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, {"test_conc_5", test_conc_5, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, diff --git a/unittest/libmariadb/result.c b/unittest/libmariadb/result.c index 885b70bc..69293b1b 100644 --- a/unittest/libmariadb/result.c +++ b/unittest/libmariadb/result.c @@ -932,6 +932,7 @@ select 1;\ DROP TABLE IF EXISTS test_multi_tab"; uint count, exp_value; uint rows[]= {0, 0, 2, 1, 3, 2, 2, 1, 1, 0, 0, 1, 0}; + my_bool reconnect= 1; /* First test that we get an error for multi statements @@ -950,7 +951,7 @@ DROP TABLE IF EXISTS test_multi_tab"; mysql_close(mysql); mysql= mysql_local; - mysql_local->reconnect= 1; + mysql_options(mysql_local, MYSQL_OPT_RECONNECT, &reconnect); rc= mysql_query(mysql_local, query); check_mysql_rc(rc, mysql); diff --git a/unittest/libmariadb/ssl.c.in b/unittest/libmariadb/ssl.c.in index 6982e41b..516097bf 100644 --- a/unittest/libmariadb/ssl.c.in +++ b/unittest/libmariadb/ssl.c.in @@ -53,18 +53,7 @@ static int check_cipher(MYSQL *mysql) return 1; diag("cipher: %s", cipher); -#ifdef HAVE_GNUTLS - { - return strcmp(cipher, "AES-128-GCM"); - } -#elif HAVE_OPENSSL - if (!strcmp(cipher, "DHE-RSA-AES256-SHA") || - !strcmp(cipher, "DHE-RSA-AES256-GCM-SHA384")) - return 0; -#elif HAVE_SCHANNEL - return strcmp(cipher, "CALG_AES_256"); -#endif - return 1; + return 0; } static int create_ssl_user(const char *ssluser, my_bool is_X509) @@ -90,6 +79,8 @@ static int create_ssl_user(const char *ssluser, my_bool is_X509) rc= mysql_query(mysql, "FLUSH PRIVILEGES"); check_mysql_rc(rc,mysql); + mysql_close(mysql); + return rc; } @@ -388,7 +379,7 @@ static int test_password_protected(MYSQL *my) "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/client-cert.pem", "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem", 0, 0); - mysql_options(mysql, MARIADB_OPT_SSL_PASSWORD, "qwerty"); + mysql_options(mysql, MARIADB_OPT_SSL_PASSPHRASE, "qwerty"); FAIL_IF(!mysql_real_connect(mysql, hostname, ssluser, sslpw, schema, port, socketname, 0), mysql_error(mysql)); @@ -775,7 +766,7 @@ static int test_ssl_fp_list(MYSQL *unused) static int test_ssl_version(MYSQL *mysql) { unsigned int iversion; - char *version; + const char *version, *library; MYSQL *my; if (check_skip_ssl()) @@ -794,6 +785,9 @@ static int test_ssl_version(MYSQL *mysql) mariadb_get_infov(my, MARIADB_CONNECTION_SSL_VERSION, &version); diag("protocol: %s", version); + mariadb_get_infov(my, MARIADB_SSL_LIBRARY, &library); + diag("library: %s", library); + mysql_close(my); return OK; diff --git a/unittest/libmariadb/t_aurora.c b/unittest/libmariadb/t_aurora.c index d9c89c45..0b9c0241 100644 --- a/unittest/libmariadb/t_aurora.c +++ b/unittest/libmariadb/t_aurora.c @@ -2,13 +2,22 @@ */ #include "my_test.h" +#include "ma_pvio.h" -static int aurora1(MYSQL *mysql) +static int aurora1(MYSQL *my) { int rc; my_bool read_only= 1; - char *primary, *replica; + const char *primary, *my_schema; MYSQL_RES *res; + MYSQL *mysql= mysql_init(NULL); + + if (!mysql_real_connect(mysql, hostname, username, password, schema, port, NULL, 0)) + { + diag("Error: %s", mysql_error(mysql)); + mysql_close(mysql); + return FAIL; + } rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); check_mysql_rc(rc, mysql); @@ -19,7 +28,7 @@ static int aurora1(MYSQL *mysql) rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1, 'foo'), (2, 'bar')"); check_mysql_rc(rc, mysql); - primary= mysql->host; + mariadb_get_infov(mysql, MARIADB_CONNECTION_HOST, &primary); diag("primary: %s", primary); mysql_options(mysql, MARIADB_OPT_CONNECTION_READ_ONLY, &read_only); @@ -37,22 +46,108 @@ static int aurora1(MYSQL *mysql) diag("Num_rows: %d", mysql_num_rows(res)); mysql_free_result(res); - replica= mysql->host; - diag("replica: %s", replica); - diag("db: %s", mysql->db); + mariadb_get_infov(mysql, MARIADB_CONNECTION_SCHEMA, &my_schema); + diag("db: %s", my_schema); + + mysql_close(mysql); return OK; } +static int test_wrong_user(MYSQL *my) +{ + MYSQL *mysql= mysql_init(NULL); + + if (mysql_real_connect(mysql, hostname, "wrong_user", NULL, NULL, 0, NULL, 0)) + { + diag("Error expected"); + mysql_close(mysql); + return FAIL; + } + mysql_close(mysql); + return OK; +} + +static int test_reconnect(MYSQL *my) +{ + MYSQL *mysql= mysql_init(NULL); + MYSQL_RES *res; + my_bool read_only= 1; + int rc; + my_bool reconnect= 1; + const char *aurora_host; + + mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); + + if (!mysql_real_connect(mysql, hostname, username, password, schema, port, NULL, 0)) + { + diag("Error: %s", mysql_error(mysql)); + mysql_close(mysql); + return FAIL; + } + + mariadb_get_infov(mysql, MARIADB_CONNECTION_HOST, &aurora_host); + diag("host: %s", aurora_host); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS tx01"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "CREATE TABLE tx01 (a int)"); + check_mysql_rc(rc, mysql); + + /* we force cluster restart and promoting new primary: + * we wait for 50 seconds - however there is no guarantee that + * cluster was restarted already - so this test might fail */ + system("/usr/local/aws/bin/aws rds failover-db-cluster --db-cluster-identifier instance-1-cluster"); + + sleep(50); + diag("Q1"); + rc= mysql_query(mysql, "INSERT INTO tx01 VALUES (1)"); + if (!rc) + diag("error expected!"); + diag("Error: %s", mysql_error(mysql)); + + diag("Q2"); + rc= mysql_query(mysql, "INSERT INTO tx01 VALUES (1)"); + if (rc) + { + diag("no error expected!"); + diag("Error: %s", mysql_error(mysql)); + diag("host: %s", mysql->host); + } + else + { + mariadb_get_infov(mysql, MARIADB_CONNECTION_HOST, &aurora_host); + diag("host: %s", aurora_host); + } + + mysql_options(mysql, MARIADB_OPT_CONNECTION_READ_ONLY, &read_only); + + rc= mysql_query(mysql, "SELECT * from tx01"); + check_mysql_rc(rc, mysql); + + if ((res= mysql_store_result(mysql))) + { + diag("num_rows: %d", mysql_num_rows(res)); + mysql_free_result(res); + } + + mariadb_get_infov(mysql, MARIADB_CONNECTION_HOST, &aurora_host); + diag("host: %s", aurora_host); + + mysql_close(mysql); + return OK; +} + struct my_tests_st my_tests[] = { - {"aurora1", aurora1, TEST_CONNECTION_NEW, 0, NULL, NULL}, + {"aurora1", aurora1, TEST_CONNECTION_NONE, 0, NULL, NULL}, + {"test_wrong_user", test_wrong_user, TEST_CONNECTION_NONE, 0, NULL, NULL}, + {"test_reconnect", test_reconnect, TEST_CONNECTION_NONE, 0, NULL, NULL}, {NULL, NULL, 0, 0, NULL, NULL} }; int main(int argc, char **argv) { - mysql_library_init(0,0,NULL); if (argc > 1) diff --git a/win/packaging/mariadb-connector-c.xml.in b/win/packaging/mariadb-connector-c.xml.in index 4213bbed..38e648e1 100644 --- a/win/packaging/mariadb-connector-c.xml.in +++ b/win/packaging/mariadb-connector-c.xml.in @@ -51,6 +51,7 @@ + @@ -61,6 +62,7 @@ Source="@CLIENT_BIN_DIR@/mariadb_client_plugin_info.exe" /> + @MARIADB_PLUGINS@