settings.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License, version 2.0, as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is also distributed with certain software (including
  9. * but not limited to OpenSSL) that is licensed under separate terms,
  10. * as designated in a particular file or component or in included license
  11. * documentation. The authors of MySQL hereby grant you an
  12. * additional permission to link the program and your derivative works
  13. * with the separately licensed software that they have included with
  14. * MySQL.
  15. *
  16. * Without limiting anything contained in the foregoing, this file,
  17. * which is part of MySQL Connector/C++, is also subject to the
  18. * Universal FOSS Exception, version 1.0, a copy of which can be found at
  19. * http://oss.oracle.com/licenses/universal-foss-exception.
  20. *
  21. * This program is distributed in the hope that it will be useful, but
  22. * WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  24. * See the GNU General Public License, version 2.0, for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software Foundation, Inc.,
  28. * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  29. */
  30. #ifndef MYSQLX_COMMON_SETTINGS_H
  31. #define MYSQLX_COMMON_SETTINGS_H
  32. /*
  33. Classes and code handling session settings. They are used to process session
  34. creation options, check their consistency and present the settings in the
  35. form expected by CDK.
  36. Known session options and their values are defined
  37. in mysql_common_constants.h header as SESSION_OPTION_LIST() and accompanying
  38. macros.
  39. */
  40. #include "../common_constants.h"
  41. #include "value.h"
  42. #include <vector>
  43. #include <map>
  44. #include <bitset>
  45. #include <sstream>
  46. namespace cdk {
  47. namespace ds {
  48. class Multi_source;
  49. }}
  50. namespace mysqlx {
  51. namespace common {
  52. /*
  53. Class for storing session configuration settings.
  54. */
  55. class PUBLIC_API Settings_impl
  56. {
  57. public:
  58. /*
  59. Enumerations with available session options and their values.
  60. */
  61. #define SETTINGS_OPT_ENUM_str(X,N) X = N,
  62. #define SETTINGS_OPT_ENUM_num(X,N) X = N,
  63. #define SETTINGS_OPT_ENUM_any(X,N) X = N,
  64. enum class Option_impl {
  65. SESSION_OPTION_LIST(SETTINGS_OPT_ENUM)
  66. LAST
  67. };
  68. /*
  69. Enumerations with available client options and their values.
  70. */
  71. #define CLIENT_OPT_ENUM_str(X,N) X = N,
  72. #define CLIENT_OPT_ENUM_bool(X,N) X = N,
  73. #define CLIENT_OPT_ENUM_num(X,N) X = N,
  74. #define CLIENT_OPT_ENUM_any(X,N) X = N,
  75. #define CLIENT_OPT_ENUM_end(X,N) X = N,
  76. enum class Client_option_impl {
  77. CLIENT_OPTION_LIST(CLIENT_OPT_ENUM)
  78. };
  79. static const char* option_name(Option_impl opt);
  80. static const char* option_name(Client_option_impl opt);
  81. #define SETTINGS_VAL_ENUM(X,N) X = N,
  82. enum class SSL_mode {
  83. SSL_MODE_LIST(SETTINGS_VAL_ENUM)
  84. LAST
  85. };
  86. static const char* ssl_mode_name(SSL_mode mode);
  87. enum class Auth_method {
  88. AUTH_METHOD_LIST(SETTINGS_VAL_ENUM)
  89. LAST
  90. };
  91. static const char* auth_method_name(Auth_method method);
  92. protected:
  93. using Value = common::Value;
  94. using opt_val_t = std::pair<Option_impl, Value>;
  95. // TODO: use multimap instead?
  96. using option_list_t = std::vector<opt_val_t>;
  97. using iterator = option_list_t::const_iterator;
  98. using client_option_list_t = std::map<Client_option_impl, Value>;
  99. using client_iterator = option_list_t::const_iterator;
  100. public:
  101. /*
  102. Examine settings stored in this object.
  103. */
  104. bool has_option(Option_impl) const;
  105. const Value& get(Option_impl) const;
  106. bool has_option(Client_option_impl) const;
  107. const Value& get(Client_option_impl) const;
  108. // Iterating over options stored in this object.
  109. iterator begin() const
  110. {
  111. return m_data.m_options.cbegin();
  112. }
  113. iterator end() const
  114. {
  115. return m_data.m_options.cend();
  116. }
  117. /*
  118. Clear individual or all settings.
  119. */
  120. void clear();
  121. void erase(Option_impl);
  122. void erase(Client_option_impl);
  123. /*
  124. Session options include connection options that specify data source
  125. (one or many) for which given session is created. This method initializes
  126. CDK Multi_source object to describe the data source(s) based on the
  127. connection options.
  128. */
  129. void get_data_source(cdk::ds::Multi_source&);
  130. // Set options based on URI
  131. void set_from_uri(const std::string &);
  132. // Set Client options based on JSON object
  133. void set_client_opts(const std::string &);
  134. // Set Client options from othe Settings object
  135. void set_client_opts(const Settings_impl &);
  136. /*
  137. Public API has no methods to directly set individual options. Instead,
  138. to change session settings implementation should create a Setter object
  139. and use its methods to do the changes. A Settings_impl::Setter object
  140. provides "transactional" semantics for changing session options -- only
  141. consistent option changes modify the original Settings_impl object.
  142. Note: This Setter class is defined in "implementation" header
  143. common/settings.h. The public API leaves it undefined.
  144. */
  145. class Setter;
  146. protected:
  147. struct PUBLIC_API Data
  148. {
  149. DLL_WARNINGS_PUSH
  150. option_list_t m_options;
  151. client_option_list_t m_client_options;
  152. DLL_WARNINGS_POP
  153. unsigned m_host_cnt = 0;
  154. bool m_user_priorities = false;
  155. bool m_ssl_ca = false;
  156. SSL_mode m_ssl_mode = SSL_mode::LAST;
  157. bool m_tcpip = false; // set to true if TCPIP connection was specified
  158. bool m_sock = false; // set to true if socket connection was specified
  159. void erase(Option_impl);
  160. void erase(Client_option_impl);
  161. };
  162. Data m_data;
  163. };
  164. #define SETTINGS_OPT_NAME_str(X,N) case N: return #X;
  165. #define SETTINGS_OPT_NAME_num(X,N) case N: return #X;
  166. #define SETTINGS_OPT_NAME_any(X,N) case N: return #X;
  167. inline
  168. const char* Settings_impl::option_name(Option_impl opt)
  169. {
  170. switch (unsigned(opt))
  171. {
  172. SESSION_OPTION_LIST(SETTINGS_OPT_NAME)
  173. default:
  174. return nullptr;
  175. }
  176. }
  177. #define CLIENT_OPT_NAME_str(X,N) case N: return #X;
  178. #define CLIENT_OPT_NAME_bool(X,N) case N: return #X;
  179. #define CLIENT_OPT_NAME_num(X,N) case N: return #X;
  180. #define CLIENT_OPT_NAME_any(X,N) case N: return #X;
  181. #define CLIENT_OPT_NAME_end(X,N) case N: throw_error("Unexpected Option"); return #X;
  182. inline
  183. const char* Settings_impl::option_name(Client_option_impl opt)
  184. {
  185. switch (unsigned(opt))
  186. {
  187. CLIENT_OPTION_LIST(CLIENT_OPT_NAME)
  188. default:
  189. return nullptr;
  190. }
  191. }
  192. #define SETTINGS_VAL_NAME(X,N) case N: return #X;
  193. inline
  194. const char* Settings_impl::ssl_mode_name(SSL_mode mode)
  195. {
  196. switch (unsigned(mode))
  197. {
  198. SSL_MODE_LIST(SETTINGS_VAL_NAME)
  199. default:
  200. return nullptr;
  201. }
  202. }
  203. inline
  204. const char* Settings_impl::auth_method_name(Auth_method method)
  205. {
  206. switch (unsigned(method))
  207. {
  208. SSL_MODE_LIST(SETTINGS_VAL_NAME)
  209. default:
  210. return nullptr;
  211. }
  212. }
  213. /*
  214. Note: For options that can repeat, returns the last value.
  215. */
  216. inline
  217. const common::Value& Settings_impl::get(Option_impl opt) const
  218. {
  219. using std::find_if;
  220. auto it = find_if(m_data.m_options.crbegin(), m_data.m_options.crend(),
  221. [opt](opt_val_t el) -> bool { return el.first == opt; }
  222. );
  223. static Value null_value;
  224. if (it == m_data.m_options.crend())
  225. return null_value;
  226. return it->second;
  227. }
  228. inline
  229. const common::Value& Settings_impl::get(Client_option_impl opt) const
  230. {
  231. static Value null_value;
  232. auto it = m_data.m_client_options.find(opt);
  233. if (it == m_data.m_client_options.cend())
  234. return null_value;
  235. return it->second;
  236. }
  237. inline
  238. bool Settings_impl::has_option(Option_impl opt) const
  239. {
  240. return m_data.m_options.cend() !=
  241. find_if(m_data.m_options.cbegin(), m_data.m_options.cend(),
  242. [opt](opt_val_t el) -> bool { return el.first == opt; }
  243. );
  244. }
  245. inline
  246. bool Settings_impl::has_option(Client_option_impl opt) const
  247. {
  248. return m_data.m_client_options.find(opt) != m_data.m_client_options.cend();
  249. }
  250. inline
  251. void Settings_impl::erase(Option_impl opt)
  252. {
  253. m_data.erase(opt);
  254. }
  255. inline
  256. void Settings_impl::erase(Client_option_impl opt)
  257. {
  258. m_data.erase(opt);
  259. }
  260. /*
  261. Note: Removes all occurrences of the given option. Also updates the context
  262. used for checking option consistency.
  263. */
  264. inline
  265. void Settings_impl::Data::erase(Option_impl opt)
  266. {
  267. remove_from(m_options,
  268. [opt](opt_val_t el) -> bool
  269. {
  270. return el.first == opt;
  271. }
  272. );
  273. /*
  274. TODO: removing HOST from multi-host settings can leave "orphaned"
  275. PORT/PRIORITY settings. Do we correctly detect that?
  276. */
  277. switch (opt)
  278. {
  279. case Option_impl::HOST:
  280. m_host_cnt = 0;
  281. FALLTHROUGH;
  282. case Option_impl::PORT:
  283. if (0 == m_host_cnt)
  284. m_tcpip = false;
  285. break;
  286. case Option_impl::SOCKET:
  287. m_sock = false;
  288. break;
  289. case Option_impl::PRIORITY:
  290. m_user_priorities = false;
  291. break;
  292. case Option_impl::SSL_CA:
  293. m_ssl_ca = false;
  294. break;
  295. case Option_impl::SSL_MODE:
  296. m_ssl_mode = SSL_mode::LAST;
  297. break;
  298. default:
  299. break;
  300. }
  301. }
  302. inline
  303. void Settings_impl::Data::erase(Client_option_impl opt)
  304. {
  305. m_client_options.erase(opt);
  306. }
  307. } // common namespace
  308. } // mysqlx namespace
  309. #endif