~jan-kneschke/mysql-proxy/packet-tracking-assertions

« back to all changes in this revision

Viewing changes to tags/mysql-proxy-0.6.0/src/mysql-proxy.c

  • Committer: Kay Roepke
  • Author(s): Jan Kneschke
  • Date: 2008-01-23 22:00:28 UTC
  • Revision ID: kay@mysql.com-20080123220028-hq2xqb69apa75fnx
first round on mysql-shell based on the proxy code

this is mostly a verification if the proxy-code is flexible enough to handle 
all three scenarios of: client, server and forwarding (proxy)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2007 MySQL AB
 
2
 
 
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.
 
6
 
 
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.
 
11
 
 
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 */ 
 
15
 
 
16
#define SVN_REVISION "$Rev$"
 
17
 
 
18
#ifdef HAVE_CONFIG_H
 
19
#include "config.h"
 
20
#endif
 
21
 
 
22
#include <sys/types.h>
 
23
#include <sys/stat.h>
 
24
 
 
25
#ifdef HAVE_SIGNAL_H
 
26
#include <signal.h>
 
27
#endif
 
28
#include <string.h>
 
29
#include <stdlib.h>
 
30
#include <stdio.h>
 
31
#include <fcntl.h>
 
32
#include <errno.h>
 
33
 
 
34
#ifdef _WIN32
 
35
#include <process.h> /* getpid() */
 
36
#include <io.h>      /* open() */
 
37
#else
 
38
#include <unistd.h>
 
39
#endif
 
40
 
 
41
#include <glib.h>
 
42
 
 
43
#ifdef HAVE_LUA_H
 
44
#include <lua.h>
 
45
#endif
 
46
 
 
47
#include "network-mysqld.h"
 
48
#include "network-mysqld-proto.h"
 
49
#include "sys-pedantic.h"
 
50
 
 
51
/**
 
52
 * signal handlers have to be volatile
 
53
 */
 
54
#ifdef _WIN32
 
55
volatile int agent_shutdown = 0;
 
56
#define STDERR_FILENO 2
 
57
#else
 
58
volatile sig_atomic_t agent_shutdown = 0;
 
59
#endif
 
60
 
 
61
#ifndef _WIN32
 
62
static void signal_handler(int sig) {
 
63
        switch (sig) {
 
64
        case SIGINT: agent_shutdown = 1; break;
 
65
        case SIGTERM: agent_shutdown = 1; break;
 
66
        }
 
67
}
 
68
#endif
 
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);
 
72
}
 
73
 
 
74
int help_select(GPtrArray *fields, GPtrArray *rows, gpointer user_data) {
 
75
        /**
 
76
         * show the available commands 
 
77
         */
 
78
        network_mysqld *srv = user_data;
 
79
        MYSQL_FIELD *field;
 
80
        GPtrArray *row;
 
81
 
 
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;
 
87
        field->length = 50;
 
88
 
 
89
        g_ptr_array_add(fields, field);
 
90
 
 
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;
 
95
        field->length = 80;
 
96
 
 
97
        g_ptr_array_add(fields, field);
 
98
 
 
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);
 
103
 
 
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);
 
108
 
 
109
    /*
 
110
     * Add new command descriptions above this comment
 
111
     *
 
112
     * */
 
113
 
 
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);
 
118
 
 
119
        return 0;
 
120
}
 
121
 
 
122
int config_select(GPtrArray *fields, GPtrArray *rows, gpointer user_data) {
 
123
        /**
 
124
         * show the current configuration 
 
125
         */
 
126
        network_mysqld *srv = user_data;
 
127
        MYSQL_FIELD *field;
 
128
        GPtrArray *row;
 
129
        gsize i;
 
130
 
 
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;
 
136
        field->length = 32;
 
137
 
 
138
        g_ptr_array_add(fields, field);
 
139
 
 
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;
 
144
        field->length = 32;
 
145
 
 
146
        g_ptr_array_add(fields, field);
 
147
 
 
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);
 
153
 
 
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);
 
159
 
 
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); \
 
166
        }
 
167
 
 
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);
 
174
 
 
175
        return 0;
 
176
}
 
177
 
 
178
int connections_select(GPtrArray *fields, GPtrArray *rows, gpointer user_data) {
 
179
        network_mysqld *srv = user_data;
 
180
        /**
 
181
         * show the current configuration 
 
182
         *
 
183
         * TODO: move to the proxy-module
 
184
         */
 
185
        MYSQL_FIELD *field;
 
186
        gsize i;
 
187
 
 
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;
 
192
        field->length = 32;
 
193
        g_ptr_array_add(fields, field);
 
194
 
 
195
        field = network_mysqld_proto_field_init();
 
196
        field->name = g_strdup("type");
 
197
        field->type = FIELD_TYPE_STRING;
 
198
        field->length = 32;
 
199
        g_ptr_array_add(fields, field);
 
200
 
 
201
        field = network_mysqld_proto_field_init();
 
202
        field->name = g_strdup("state");
 
203
        field->type = FIELD_TYPE_STRING;
 
204
        field->length = 32;
 
205
        g_ptr_array_add(fields, field);
 
206
 
 
207
        field = network_mysqld_proto_field_init();
 
208
        field->name = g_strdup("db");
 
209
        field->type = FIELD_TYPE_STRING;
 
210
        field->length = 64;
 
211
        g_ptr_array_add(fields, field);
 
212
 
 
213
        for (i = 0; i < srv->cons->len; i++) {
 
214
                GPtrArray *row;
 
215
                network_mysqld_con *rcon = srv->cons->pdata[i];
 
216
 
 
217
                if (!rcon) continue;
 
218
                if (rcon->is_listen_socket) continue;
 
219
 
 
220
                row = g_ptr_array_new();
 
221
 
 
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"));
 
226
                        break;
 
227
                case NETWORK_TYPE_PROXY:
 
228
                        g_ptr_array_add(row, g_strdup("proxy"));
 
229
                        break;
 
230
                }
 
231
 
 
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 : ""));
 
234
        
 
235
                g_ptr_array_add(rows, row);
 
236
        }
 
237
 
 
238
        return 0;
 
239
}
 
240
 
 
241
#ifndef _WIN32
 
242
/**
 
243
 * start the agent in the background 
 
244
 * 
 
245
 * UNIX-version
 
246
 */
 
247
static void daemonize(void) {
 
248
#ifdef SIGTTOU
 
249
        signal(SIGTTOU, SIG_IGN);
 
250
#endif
 
251
#ifdef SIGTTIN
 
252
        signal(SIGTTIN, SIG_IGN);
 
253
#endif
 
254
#ifdef SIGTSTP
 
255
        signal(SIGTSTP, SIG_IGN);
 
256
#endif
 
257
        if (fork() != 0) exit(0);
 
258
        
 
259
        if (setsid() == -1) exit(0);
 
260
 
 
261
        signal(SIGHUP, SIG_IGN);
 
262
 
 
263
        if (fork() != 0) exit(0);
 
264
        
 
265
        chdir("/");
 
266
        
 
267
        umask(0);
 
268
}
 
269
#endif
 
270
 
 
271
 
 
272
#define GETTEXT_PACKAGE "mysql-proxy"
 
273
 
 
274
int main(int argc, char **argv) {
 
275
        network_mysqld *srv;
 
276
        network_mysqld_table *table;
 
277
        
 
278
        /* read the command-line options */
 
279
        GOptionContext *option_ctx;
 
280
        GOptionGroup *option_grp;
 
281
        GError *gerr = NULL;
 
282
        int i;
 
283
        int exit_code = 0;
 
284
        int print_version = 0;
 
285
        int daemon_mode = 0;
 
286
        int start_proxy = 1;
 
287
        const gchar *check_str = NULL;
 
288
 
 
289
        GOptionEntry admin_entries[] = 
 
290
        {
 
291
                { "admin-address",            0, 0, G_OPTION_ARG_STRING, NULL, "listening address:port of internal admin-server (default: :4041)", "<host:port>" },
 
292
                
 
293
                { NULL,                       0, 0, G_OPTION_ARG_NONE,   NULL, NULL, NULL }
 
294
        };
 
295
 
 
296
        GOptionEntry proxy_entries[] = 
 
297
        {
 
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>" },
 
302
                
 
303
                { "proxy-skip-profiling",     0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, NULL, "disables profiling of queries (default: enabled)", NULL },
 
304
 
 
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>" },
 
307
                
 
308
                { "no-proxy",                 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, NULL, "Don't start proxy-server", NULL },
 
309
                
 
310
                { NULL,                       0, 0, G_OPTION_ARG_NONE,   NULL, NULL, NULL }
 
311
        };
 
312
 
 
313
        GOptionEntry main_entries[] = 
 
314
        {
 
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>" },
 
318
                
 
319
                { NULL,                       0, 0, G_OPTION_ARG_NONE,   NULL, NULL, NULL }
 
320
        };
 
321
 
 
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);
 
325
        }
 
326
 
 
327
        check_str = glib_check_version(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
 
328
 
 
329
        if (check_str) {
 
330
                g_error("%s, got: lib=%d.%d.%d, headers=%d.%d.%d", 
 
331
                        check_str,
 
332
                        glib_major_version, glib_minor_version, glib_micro_version,
 
333
                        GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
 
334
        }
 
335
        
 
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;
 
340
 
 
341
        i = 0;
 
342
        admin_entries[i++].arg_data = &(srv->config.admin.address);
 
343
 
 
344
        i = 0;
 
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);
 
348
 
 
349
        proxy_entries[i++].arg_data = &(srv->config.proxy.profiling);
 
350
 
 
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);
 
354
 
 
355
        i = 0;
 
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);
 
359
 
 
360
        g_log_set_default_handler(log_func, NULL);
 
361
 
 
362
        option_ctx = g_option_context_new("- MySQL Proxy");
 
363
        g_option_context_add_main_entries(option_ctx, main_entries, GETTEXT_PACKAGE);
 
364
 
 
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);
 
368
 
 
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);
 
372
        
 
373
        if (FALSE == g_option_context_parse(option_ctx, &argc, &argv, &gerr)) {
 
374
                g_critical("%s", gerr->message);
 
375
                
 
376
                g_error_free(gerr);
 
377
 
 
378
                return -1;
 
379
        }
 
380
 
 
381
        g_option_context_free(option_ctx);
 
382
 
 
383
#if defined(HAVE_LUA_H) && defined(LIBDIR)
 
384
        /**
 
385
         * if the LUA_PATH is not set, set a good default 
 
386
         */
 
387
        if (!g_getenv("LUA_PATH")) {
 
388
                g_setenv("LUA_PATH", LUA_PATHSEP LUA_PATHSEP LIBDIR "/?.lua", 1);
 
389
        }
 
390
#endif
 
391
 
 
392
        if (print_version) {
 
393
                printf("%s\r\n", PACKAGE_STRING);
 
394
                return 0;
 
395
        }
 
396
 
 
397
        if (start_proxy) {
 
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");
 
402
                }
 
403
        } else {
 
404
                if (srv->config.proxy.address) {
 
405
                        g_free(srv->config.proxy.address);
 
406
                        srv->config.proxy.address = NULL;
 
407
                }
 
408
        }
 
409
 
 
410
        if (!srv->config.admin.address) srv->config.admin.address = g_strdup(":4041");
 
411
 
 
412
    /*
 
413
     *  If you add a new command, please update help_select() above
 
414
     *
 
415
     */
 
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);
 
420
 
 
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);
 
425
        
 
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);
 
430
 
 
431
#ifndef _WIN32  
 
432
        signal(SIGINT,  signal_handler);
 
433
        signal(SIGTERM, signal_handler);
 
434
        signal(SIGPIPE, SIG_IGN);
 
435
 
 
436
        if (daemon_mode) {
 
437
                daemonize();
 
438
        }
 
439
#endif
 
440
        if (srv->config.pid_file) {
 
441
                int fd;
 
442
                gchar *pid_str;
 
443
 
 
444
                /**
 
445
                 * write the PID file
 
446
                 */
 
447
 
 
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", 
 
450
                                        __FILE__, __LINE__,
 
451
                                        srv->config.pid_file,
 
452
                                        strerror(errno));
 
453
                        return -1;
 
454
                }
 
455
 
 
456
                pid_str = g_strdup_printf("%d", getpid());
 
457
 
 
458
                write(fd, pid_str, strlen(pid_str));
 
459
                g_free(pid_str);
 
460
 
 
461
                close(fd);
 
462
        }
 
463
 
 
464
        network_mysqld_init_libevent(srv);
 
465
 
 
466
        if (network_mysqld_thread(srv)) {
 
467
                /* looks like we failed */
 
468
 
 
469
                exit_code = -1;
 
470
        }
 
471
 
 
472
        network_mysqld_free(srv);
 
473
 
 
474
        return exit_code;
 
475
}
 
476