/* * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2.0, as * published by the Free Software Foundation. * * This program is also distributed with certain software (including * but not limited to OpenSSL) that is licensed under separate terms, * as designated in a particular file or component or in included license * documentation. The authors of MySQL hereby grant you an * additional permission to link the program and your derivative works * with the separately licensed software that they have included with * MySQL. * * Without limiting anything contained in the foregoing, this file, * which is part of MySQL Connector/C++, is also subject to the * Universal FOSS Exception, version 1.0, a copy of which can be found at * http://oss.oracle.com/licenses/universal-foss-exception. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License, version 2.0, for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MYSQLX_COMMON_SETTINGS_H #define MYSQLX_COMMON_SETTINGS_H /* Classes and code handling session settings. They are used to process session creation options, check their consistency and present the settings in the form expected by CDK. Known session options and their values are defined in mysql_common_constants.h header as SESSION_OPTION_LIST() and accompanying macros. */ #include "../common_constants.h" #include "value.h" #include #include #include #include namespace cdk { namespace ds { class Multi_source; }} namespace mysqlx { namespace common { /* Class for storing session configuration settings. */ class PUBLIC_API Settings_impl { public: /* Enumerations with available session options and their values. */ #define SETTINGS_OPT_ENUM_str(X,N) X = N, #define SETTINGS_OPT_ENUM_num(X,N) X = N, #define SETTINGS_OPT_ENUM_any(X,N) X = N, enum class Option_impl { SESSION_OPTION_LIST(SETTINGS_OPT_ENUM) LAST }; /* Enumerations with available client options and their values. */ #define CLIENT_OPT_ENUM_str(X,N) X = N, #define CLIENT_OPT_ENUM_bool(X,N) X = N, #define CLIENT_OPT_ENUM_num(X,N) X = N, #define CLIENT_OPT_ENUM_any(X,N) X = N, #define CLIENT_OPT_ENUM_end(X,N) X = N, enum class Client_option_impl { CLIENT_OPTION_LIST(CLIENT_OPT_ENUM) }; static const char* option_name(Option_impl opt); static const char* option_name(Client_option_impl opt); #define SETTINGS_VAL_ENUM(X,N) X = N, enum class SSL_mode { SSL_MODE_LIST(SETTINGS_VAL_ENUM) LAST }; static const char* ssl_mode_name(SSL_mode mode); enum class Auth_method { AUTH_METHOD_LIST(SETTINGS_VAL_ENUM) LAST }; static const char* auth_method_name(Auth_method method); protected: using Value = common::Value; using opt_val_t = std::pair; // TODO: use multimap instead? using option_list_t = std::vector; using iterator = option_list_t::const_iterator; using client_option_list_t = std::map; using client_iterator = option_list_t::const_iterator; public: /* Examine settings stored in this object. */ bool has_option(Option_impl) const; const Value& get(Option_impl) const; bool has_option(Client_option_impl) const; const Value& get(Client_option_impl) const; // Iterating over options stored in this object. iterator begin() const { return m_data.m_options.cbegin(); } iterator end() const { return m_data.m_options.cend(); } /* Clear individual or all settings. */ void clear(); void erase(Option_impl); void erase(Client_option_impl); /* Session options include connection options that specify data source (one or many) for which given session is created. This method initializes CDK Multi_source object to describe the data source(s) based on the connection options. */ void get_data_source(cdk::ds::Multi_source&); // Set options based on URI void set_from_uri(const std::string &); // Set Client options based on JSON object void set_client_opts(const std::string &); // Set Client options from othe Settings object void set_client_opts(const Settings_impl &); /* Public API has no methods to directly set individual options. Instead, to change session settings implementation should create a Setter object and use its methods to do the changes. A Settings_impl::Setter object provides "transactional" semantics for changing session options -- only consistent option changes modify the original Settings_impl object. Note: This Setter class is defined in "implementation" header common/settings.h. The public API leaves it undefined. */ class Setter; protected: struct PUBLIC_API Data { DLL_WARNINGS_PUSH option_list_t m_options; client_option_list_t m_client_options; DLL_WARNINGS_POP unsigned m_host_cnt = 0; bool m_user_priorities = false; bool m_ssl_ca = false; SSL_mode m_ssl_mode = SSL_mode::LAST; bool m_tcpip = false; // set to true if TCPIP connection was specified bool m_sock = false; // set to true if socket connection was specified void erase(Option_impl); void erase(Client_option_impl); }; Data m_data; }; #define SETTINGS_OPT_NAME_str(X,N) case N: return #X; #define SETTINGS_OPT_NAME_num(X,N) case N: return #X; #define SETTINGS_OPT_NAME_any(X,N) case N: return #X; inline const char* Settings_impl::option_name(Option_impl opt) { switch (unsigned(opt)) { SESSION_OPTION_LIST(SETTINGS_OPT_NAME) default: return nullptr; } } #define CLIENT_OPT_NAME_str(X,N) case N: return #X; #define CLIENT_OPT_NAME_bool(X,N) case N: return #X; #define CLIENT_OPT_NAME_num(X,N) case N: return #X; #define CLIENT_OPT_NAME_any(X,N) case N: return #X; #define CLIENT_OPT_NAME_end(X,N) case N: throw_error("Unexpected Option"); return #X; inline const char* Settings_impl::option_name(Client_option_impl opt) { switch (unsigned(opt)) { CLIENT_OPTION_LIST(CLIENT_OPT_NAME) default: return nullptr; } } #define SETTINGS_VAL_NAME(X,N) case N: return #X; inline const char* Settings_impl::ssl_mode_name(SSL_mode mode) { switch (unsigned(mode)) { SSL_MODE_LIST(SETTINGS_VAL_NAME) default: return nullptr; } } inline const char* Settings_impl::auth_method_name(Auth_method method) { switch (unsigned(method)) { SSL_MODE_LIST(SETTINGS_VAL_NAME) default: return nullptr; } } /* Note: For options that can repeat, returns the last value. */ inline const common::Value& Settings_impl::get(Option_impl opt) const { using std::find_if; auto it = find_if(m_data.m_options.crbegin(), m_data.m_options.crend(), [opt](opt_val_t el) -> bool { return el.first == opt; } ); static Value null_value; if (it == m_data.m_options.crend()) return null_value; return it->second; } inline const common::Value& Settings_impl::get(Client_option_impl opt) const { static Value null_value; auto it = m_data.m_client_options.find(opt); if (it == m_data.m_client_options.cend()) return null_value; return it->second; } inline bool Settings_impl::has_option(Option_impl opt) const { return m_data.m_options.cend() != find_if(m_data.m_options.cbegin(), m_data.m_options.cend(), [opt](opt_val_t el) -> bool { return el.first == opt; } ); } inline bool Settings_impl::has_option(Client_option_impl opt) const { return m_data.m_client_options.find(opt) != m_data.m_client_options.cend(); } inline void Settings_impl::erase(Option_impl opt) { m_data.erase(opt); } inline void Settings_impl::erase(Client_option_impl opt) { m_data.erase(opt); } /* Note: Removes all occurrences of the given option. Also updates the context used for checking option consistency. */ inline void Settings_impl::Data::erase(Option_impl opt) { remove_from(m_options, [opt](opt_val_t el) -> bool { return el.first == opt; } ); /* TODO: removing HOST from multi-host settings can leave "orphaned" PORT/PRIORITY settings. Do we correctly detect that? */ switch (opt) { case Option_impl::HOST: m_host_cnt = 0; FALLTHROUGH; case Option_impl::PORT: if (0 == m_host_cnt) m_tcpip = false; break; case Option_impl::SOCKET: m_sock = false; break; case Option_impl::PRIORITY: m_user_priorities = false; break; case Option_impl::SSL_CA: m_ssl_ca = false; break; case Option_impl::SSL_MODE: m_ssl_mode = SSL_mode::LAST; break; default: break; } } inline void Settings_impl::Data::erase(Client_option_impl opt) { m_client_options.erase(opt); } } // common namespace } // mysqlx namespace #endif