1 /*
2 * mod_mariadb for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2019, Andrey Volk <andywolk@gmail.com>
4 *
5 * Version: MPL 1.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is ported from FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18 *
19 * The Initial Developer of the Original Code is
20 * Anthony Minessale II <anthm@freeswitch.org>
21 * Portions created by the Initial Developer are Copyright (C)
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 * Andrey Volk <andywolk@gmail.com>
26 *
27 * mariadb_dsn.cpp -- Connection string parser for MariaDB FreeSWITCH module
28 *
29 */
30 #include <switch.h>
31 #include "mariadb_dsn.hpp"
32 
33 #include <string>
34 #include <iterator>
35 #include <vector>
36 #include <unordered_map>
37 #include <regex>
38 #include <algorithm>
39 #include <sstream>
40 
41 class mariadb_dsn {
42 
43 	std::string _host = "localhost";
44 	std::string _user;
45 	std::string _passwd;
46 	std::string _db;
47 	int _port = 3306;
48 	std::string _unix_socket;
49 	std::string _character_set;
50 	unsigned long _clientflag;
51 
52 public:
53 
54 	template<typename Out>
split(const std::string & s,char delim,Out result)55 	void split(const std::string &s, char delim, Out result) {
56 		std::stringstream ss(s);
57 		std::string item;
58 		while (std::getline(ss, item, delim)) {
59 			*(result++) = item;
60 		}
61 	}
62 
split(const std::string & s,char delim)63 	std::vector<std::string> split(const std::string &s, char delim) {
64 		std::vector<std::string> elems;
65 		split(s, delim, std::back_inserter(elems));
66 		return elems;
67 	}
68 
mariadb_dsn(MYSQL * mysql,const char * dsn,unsigned long clientflag)69 	mariadb_dsn(MYSQL *mysql, const char *dsn, unsigned long clientflag)
70 	{
71 		_clientflag = clientflag;
72 
73 		if (dsn) {
74 			std::vector<std::string> params = split(std::string(dsn), ';');
75 
76 			for (auto &param : params) {
77 				std::vector<std::string> pair = split(param, '=');
78 				if (pair.size() >= 2) {
79 					std::string key = std::regex_replace(pair[0], std::regex("^ +| +$|( ) +"), "$1");
80 					std::transform(key.begin(), key.end(), key.begin(), ::tolower);
81 					std::string value = pair[1];
82 
83 					if ("server" == key || "host" == key) {
84 						_host = value;
85 					} else if ("uid" == key || "user" == key || "username" == key) {
86 						_user = value;
87 					} else if ("pwd" == key || "passwd" == key || "password" == key) {
88 						_passwd = value;
89 					} else if ("database" == key || "db" == key) {
90 						_db = value;
91 					} else if ("port" == key) {
92 						_port = std::stoi(value);
93 					} else if ("option" == key || "options" == key) {
94 						unsigned long option;
95 						std::stringstream(value) >> option;
96 						_clientflag |= option;
97 					} else if ("charset" == key) {
98 						std::string charset = std::regex_replace(value, std::regex("^ +| +$|( ) +"), "$1");
99 						int err = mysql_optionsv(mysql, MYSQL_SET_CHARSET_NAME, (void *)charset.c_str());
100 						if (err) {
101 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mysql_optionsv returned an error [MYSQL_SET_CHARSET_NAME=%s]: %s\n", charset.c_str(), mysql_error(mysql));
102 						}
103 					}
104 				}
105 			}
106 
107 		}
108 	}
109 
host() const110 	const char* host() const
111 	{
112 		return _host.c_str();
113 	}
114 
user() const115 	const char* user() const
116 	{
117 		return _user.c_str();
118 	}
119 
passwd() const120 	const char* passwd() const
121 	{
122 		return _passwd.c_str();
123 	}
124 
db() const125 	const char* db() const
126 	{
127 		return _db.c_str();
128 	}
129 
port() const130 	const int port() const
131 	{
132 		return _port;
133 	}
134 
unix_socket() const135 	const char* unix_socket() const
136 	{
137 		return ("" == _unix_socket) ? NULL : _unix_socket.c_str();
138 	}
139 
clientflag()140 	unsigned long clientflag()
141 	{
142 		return _clientflag;
143 	}
144 };
145 
mysql_dsn_connect(MYSQL * mysql,const char * connection_string,unsigned long clientflag)146 MYSQL* STDCALL mysql_dsn_connect(MYSQL *mysql, const char *connection_string, unsigned long clientflag)
147 {
148 	mariadb_dsn dsn(mysql, connection_string, clientflag);
149 	return mysql_real_connect(mysql, dsn.host(), dsn.user(), dsn.passwd(), dsn.db(), dsn.port(), dsn.unix_socket(), dsn.clientflag());
150 }
151 
152 /* For Emacs:
153  * Local Variables:
154  * mode:c
155  * indent-tabs-mode:t
156  * tab-width:4
157  * c-basic-offset:4
158  * End:
159  * For VIM:
160  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
161  */
162