1
/* Copyright (C) 2007 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#define SVN_REVISION "$Rev$"
22
#include <sys/types.h>
35
#include <process.h> /* getpid() */
36
#include <io.h> /* open() */
47
#include "network-mysqld.h"
48
#include "network-mysqld-proto.h"
49
#include "sys-pedantic.h"
52
* signal handlers have to be volatile
55
volatile int agent_shutdown = 0;
56
#define STDERR_FILENO 2
58
volatile sig_atomic_t agent_shutdown = 0;
62
static void signal_handler(int sig) {
64
case SIGINT: agent_shutdown = 1; break;
65
case SIGTERM: agent_shutdown = 1; break;
69
static void log_func(const gchar *UNUSED_PARAM(log_domain), GLogLevelFlags UNUSED_PARAM(log_level), const gchar *message, gpointer UNUSED_PARAM(user_data)) {
70
write(STDERR_FILENO, message, strlen(message));
71
write(STDERR_FILENO, "\n", 1);
74
int help_select(GPtrArray *fields, GPtrArray *rows, gpointer user_data) {
76
* show the available commands
78
network_mysqld *srv = user_data;
82
field = network_mysqld_proto_field_init();
83
field->name = g_strdup("command");
84
field->org_name = g_strdup("command");
85
field->type = FIELD_TYPE_STRING;
86
field->flags = PRI_KEY_FLAG;
89
g_ptr_array_add(fields, field);
91
field = network_mysqld_proto_field_init();
92
field->name = g_strdup("description");
93
field->org_name = g_strdup("description");
94
field->type = FIELD_TYPE_STRING;
97
g_ptr_array_add(fields, field);
99
row = g_ptr_array_new();
100
g_ptr_array_add(row, g_strdup("select * from proxy_connections"));
101
g_ptr_array_add(row, g_strdup("show information about proxy connections"));
102
g_ptr_array_add(rows, row);
104
row = g_ptr_array_new();
105
g_ptr_array_add(row, g_strdup("select * from proxy_config"));
106
g_ptr_array_add(row, g_strdup("show information about proxy configuration"));
107
g_ptr_array_add(rows, row);
110
* Add new command descriptions above this comment
114
row = g_ptr_array_new();
115
g_ptr_array_add(row, g_strdup("select * from help"));
116
g_ptr_array_add(row, g_strdup("show the available commands"));
117
g_ptr_array_add(rows, row);
122
int config_select(GPtrArray *fields, GPtrArray *rows, gpointer user_data) {
124
* show the current configuration
126
network_mysqld *srv = user_data;
131
field = network_mysqld_proto_field_init();
132
field->name = g_strdup("option");
133
field->org_name = g_strdup("option");
134
field->type = FIELD_TYPE_STRING;
135
field->flags = PRI_KEY_FLAG;
138
g_ptr_array_add(fields, field);
140
field = network_mysqld_proto_field_init();
141
field->name = g_strdup("value");
142
field->org_name = g_strdup("value");
143
field->type = FIELD_TYPE_STRING;
146
g_ptr_array_add(fields, field);
148
#define RESULTSET_ADD(x) \
149
row = g_ptr_array_new(); \
150
g_ptr_array_add(row, g_strdup(#x)); \
151
g_ptr_array_add(row, g_strdup_printf("%d", srv->config.x)); \
152
g_ptr_array_add(rows, row);
154
#define RESULTSET_ADD_STR(x) \
155
row = g_ptr_array_new(); \
156
g_ptr_array_add(row, g_strdup(#x)); \
157
g_ptr_array_add(row, g_strdup(srv->config.x)); \
158
g_ptr_array_add(rows, row);
160
#define RESULTSET_ADD_STR_ARRAY(x) \
161
for (i = 0; srv->config.x[i]; i++) { \
162
row = g_ptr_array_new(); \
163
g_ptr_array_add(row, g_strdup_printf("%s["F_SIZE_T"]", #x, i)); \
164
g_ptr_array_add(row, g_strdup(srv->config.x[i])); \
165
g_ptr_array_add(rows, row); \
168
RESULTSET_ADD_STR(admin.address);
169
RESULTSET_ADD_STR(proxy.address);
170
RESULTSET_ADD_STR(proxy.lua_script);
171
RESULTSET_ADD_STR_ARRAY(proxy.backend_addresses);
172
RESULTSET_ADD(proxy.fix_bug_25371);
173
RESULTSET_ADD(proxy.profiling);
178
int connections_select(GPtrArray *fields, GPtrArray *rows, gpointer user_data) {
179
network_mysqld *srv = user_data;
181
* show the current configuration
183
* TODO: move to the proxy-module
188
field = network_mysqld_proto_field_init();
189
field->name = g_strdup("id");
190
field->type = FIELD_TYPE_LONG;
191
field->flags = PRI_KEY_FLAG;
193
g_ptr_array_add(fields, field);
195
field = network_mysqld_proto_field_init();
196
field->name = g_strdup("type");
197
field->type = FIELD_TYPE_STRING;
199
g_ptr_array_add(fields, field);
201
field = network_mysqld_proto_field_init();
202
field->name = g_strdup("state");
203
field->type = FIELD_TYPE_STRING;
205
g_ptr_array_add(fields, field);
207
field = network_mysqld_proto_field_init();
208
field->name = g_strdup("db");
209
field->type = FIELD_TYPE_STRING;
211
g_ptr_array_add(fields, field);
213
for (i = 0; i < srv->cons->len; i++) {
215
network_mysqld_con *rcon = srv->cons->pdata[i];
218
if (rcon->is_listen_socket) continue;
220
row = g_ptr_array_new();
222
g_ptr_array_add(row, g_strdup_printf(F_SIZE_T, i));
223
switch (rcon->config.network_type) {
224
case NETWORK_TYPE_SERVER:
225
g_ptr_array_add(row, g_strdup("server"));
227
case NETWORK_TYPE_PROXY:
228
g_ptr_array_add(row, g_strdup("proxy"));
232
g_ptr_array_add(row, g_strdup_printf("%d", rcon->state));
233
g_ptr_array_add(row, g_strdup(rcon && rcon->server && rcon->server->default_db->len ? rcon->server->default_db->str : ""));
235
g_ptr_array_add(rows, row);
243
* start the agent in the background
247
static void daemonize(void) {
249
signal(SIGTTOU, SIG_IGN);
252
signal(SIGTTIN, SIG_IGN);
255
signal(SIGTSTP, SIG_IGN);
257
if (fork() != 0) exit(0);
259
if (setsid() == -1) exit(0);
261
signal(SIGHUP, SIG_IGN);
263
if (fork() != 0) exit(0);
272
#define GETTEXT_PACKAGE "mysql-proxy"
274
int main(int argc, char **argv) {
276
network_mysqld_table *table;
278
/* read the command-line options */
279
GOptionContext *option_ctx;
280
GOptionGroup *option_grp;
284
int print_version = 0;
287
const gchar *check_str = NULL;
289
GOptionEntry admin_entries[] =
291
{ "admin-address", 0, 0, G_OPTION_ARG_STRING, NULL, "listening address:port of internal admin-server (default: :4041)", "<host:port>" },
293
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
296
GOptionEntry proxy_entries[] =
298
{ "proxy-address", 0, 0, G_OPTION_ARG_STRING, NULL, "listening address:port of the proxy-server (default: :4040)", "<host:port>" },
299
{ "proxy-read-only-backend-addresses",
300
0, 0, G_OPTION_ARG_STRING_ARRAY, NULL, "address:port of the remote slave-server (default: not set)", "<host:port>" },
301
{ "proxy-backend-addresses", 0, 0, G_OPTION_ARG_STRING_ARRAY, NULL, "address:port of the remote backend-servers (default: 127.0.0.1:3306)", "<host:port>" },
303
{ "proxy-skip-profiling", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, NULL, "disables profiling of queries (default: enabled)", NULL },
305
{ "proxy-fix-bug-25371", 0, 0, G_OPTION_ARG_NONE, NULL, "fix bug #25371 (mysqld > 5.1.12) for older libmysql versions", NULL },
306
{ "proxy-lua-script", 0, 0, G_OPTION_ARG_STRING, NULL, "filename of the lua script (default: not set)", "<file>" },
308
{ "no-proxy", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, NULL, "Don't start proxy-server", NULL },
310
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
313
GOptionEntry main_entries[] =
315
{ "version", 'V', 0, G_OPTION_ARG_NONE, NULL, "Show version", NULL },
316
{ "daemon", 0, 0, G_OPTION_ARG_NONE, NULL, "Start in daemon-mode", NULL },
317
{ "pid-file", 0, 0, G_OPTION_ARG_STRING, NULL, "PID file in case we are started as daemon", "<file>" },
319
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
322
if (!GLIB_CHECK_VERSION(2, 6, 0)) {
323
g_error("the glib header are too old, need at least 2.6.0, got: %d.%d.%d",
324
GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
327
check_str = glib_check_version(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
330
g_error("%s, got: lib=%d.%d.%d, headers=%d.%d.%d",
332
glib_major_version, glib_minor_version, glib_micro_version,
333
GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
336
srv = network_mysqld_init();
337
srv->config.network_type = NETWORK_TYPE_PROXY; /* doesn't matter anymore */
338
srv->config.proxy.fix_bug_25371 = 0; /** double ERR packet on AUTH failures */
339
srv->config.proxy.profiling = 1;
342
admin_entries[i++].arg_data = &(srv->config.admin.address);
345
proxy_entries[i++].arg_data = &(srv->config.proxy.address);
346
proxy_entries[i++].arg_data = &(srv->config.proxy.read_only_backend_addresses);
347
proxy_entries[i++].arg_data = &(srv->config.proxy.backend_addresses);
349
proxy_entries[i++].arg_data = &(srv->config.proxy.profiling);
351
proxy_entries[i++].arg_data = &(srv->config.proxy.fix_bug_25371);
352
proxy_entries[i++].arg_data = &(srv->config.proxy.lua_script);
353
proxy_entries[i++].arg_data = &(start_proxy);
356
main_entries[i++].arg_data = &(print_version);
357
main_entries[i++].arg_data = &(daemon_mode);
358
main_entries[i++].arg_data = &(srv->config.pid_file);
360
g_log_set_default_handler(log_func, NULL);
362
option_ctx = g_option_context_new("- MySQL Proxy");
363
g_option_context_add_main_entries(option_ctx, main_entries, GETTEXT_PACKAGE);
365
option_grp = g_option_group_new("admin", "admin module", "Show options for the admin-module", NULL, NULL);
366
g_option_group_add_entries(option_grp, admin_entries);
367
g_option_context_add_group(option_ctx, option_grp);
369
option_grp = g_option_group_new("proxy", "proxy-module", "Show options for the proxy-module", NULL, NULL);
370
g_option_group_add_entries(option_grp, proxy_entries);
371
g_option_context_add_group(option_ctx, option_grp);
373
if (FALSE == g_option_context_parse(option_ctx, &argc, &argv, &gerr)) {
374
g_critical("%s", gerr->message);
381
g_option_context_free(option_ctx);
383
#if defined(HAVE_LUA_H) && defined(LIBDIR)
385
* if the LUA_PATH is not set, set a good default
387
if (!g_getenv("LUA_PATH")) {
388
g_setenv("LUA_PATH", LUA_PATHSEP LUA_PATHSEP LIBDIR "/?.lua", 1);
393
printf("%s\r\n", PACKAGE_STRING);
398
if (!srv->config.proxy.address) srv->config.proxy.address = g_strdup(":4040");
399
if (!srv->config.proxy.backend_addresses) {
400
srv->config.proxy.backend_addresses = g_new0(char *, 2);
401
srv->config.proxy.backend_addresses[0] = g_strdup("127.0.0.1:3306");
404
if (srv->config.proxy.address) {
405
g_free(srv->config.proxy.address);
406
srv->config.proxy.address = NULL;
410
if (!srv->config.admin.address) srv->config.admin.address = g_strdup(":4041");
413
* If you add a new command, please update help_select() above
416
table = network_mysqld_table_init();
417
table->select = connections_select;
418
table->user_data = srv;
419
g_hash_table_insert(srv->tables, g_strdup("proxy_connections"), table);
421
table = network_mysqld_table_init();
422
table->select = config_select;
423
table->user_data = srv;
424
g_hash_table_insert(srv->tables, g_strdup("proxy_config"), table);
426
table = network_mysqld_table_init();
427
table->select = help_select;
428
table->user_data = srv;
429
g_hash_table_insert(srv->tables, g_strdup("help"), table);
432
signal(SIGINT, signal_handler);
433
signal(SIGTERM, signal_handler);
434
signal(SIGPIPE, SIG_IGN);
440
if (srv->config.pid_file) {
448
if (-1 == (fd = open(srv->config.pid_file, O_WRONLY|O_TRUNC|O_CREAT, 0600))) {
449
g_critical("%s.%d: open(%s) failed: %s",
451
srv->config.pid_file,
456
pid_str = g_strdup_printf("%d", getpid());
458
write(fd, pid_str, strlen(pid_str));
464
network_mysqld_init_libevent(srv);
466
if (network_mysqld_thread(srv)) {
467
/* looks like we failed */
472
network_mysqld_free(srv);