/** * accept a connection * * event handler for listening connections * * @param srv a listening socket * */ network_socket *network_socket_accept(network_socket *srv) { network_socket *client; g_return_val_if_fail(srv, NULL); g_return_val_if_fail(srv->socket_type == SOCK_STREAM, NULL); /* accept() only works on stream sockets */ client = network_socket_new(); if (-1 == (client->fd = accept4(srv->fd, &client->src->addr.common, &(client->src->len), SOCK_NONBLOCK))) { network_socket_free(client); return NULL; } if (network_address_refresh_name(client->src)) { network_socket_free(client); return NULL; } /* the listening side may be INADDR_ANY, let's get which address the client really connected to */ if (-1 == getsockname(client->fd, &client->dst->addr.common, &(client->dst->len))) { network_address_reset(client->dst); } else if (network_address_refresh_name(client->dst)) { network_address_reset(client->dst); } return client; }
/** * init the plugin with the parsed config */ static int network_mysqld_admin_plugin_apply_config(chassis *chas, chassis_plugin_config *config) { network_mysqld_con *con; network_socket *listen_sock; if (!config->address) config->address = g_strdup(":4041"); if (!config->admin_username) { g_critical("%s: --admin-username needs to be set", G_STRLOC); return -1; } if (!config->admin_password) { g_critical("%s: --admin-password needs to be set", G_STRLOC); return -1; } if (!config->lua_script) { g_critical("%s: --admin-lua-script needs to be set, <install-dir>/lib/mysql-proxy/lua/admin.lua may be a good value", G_STRLOC); return -1; } /** * create a connection handle for the listen socket */ con = network_mysqld_con_new(); network_mysqld_add_connection(chas, con); con->config = config; config->listen_con = con; listen_sock = network_socket_new(); con->server = listen_sock; /* set the plugin hooks as we want to apply them to the new connections too later */ network_mysqld_server_connection_init(con); /* FIXME: network_socket_set_address() */ if (0 != network_address_set_address(listen_sock->dst, config->address)) { return -1; } /* FIXME: network_socket_bind() */ if (0 != network_socket_bind(listen_sock)) { return -1; } /** * call network_mysqld_con_accept() with this connection when we are done */ event_set(&(listen_sock->event), listen_sock->fd, EV_READ|EV_PERSIST, network_mysqld_con_accept, con); event_base_set(chas->event_base, &(listen_sock->event)); event_add(&(listen_sock->event), NULL); return 0; }
/** * init the plugin with the parsed config */ static int network_mysqld_master_plugin_apply_config(chassis *chas, chassis_plugin_config *config) { network_mysqld_con *con; network_socket *listen_sock; if (!config->address) config->address = g_strdup(":4041"); if (!config->master_username) config->master_username = g_strdup("root"); if (!config->master_password) config->master_password = g_strdup("secret"); /** * create a connection handle for the listen socket */ con = network_mysqld_con_new(); network_mysqld_add_connection(chas, con); con->config = config; config->listen_con = con; listen_sock = network_socket_new(); con->server = listen_sock; /* set the plugin hooks as we want to apply them to the new connections too later */ network_mysqld_server_connection_init(con); /* FIXME: network_socket_set_address() */ if (0 != network_address_set_address(listen_sock->dst, config->address)) { return -1; } /* FIXME: network_socket_bind() */ if (0 != network_socket_bind(listen_sock)) { return -1; } /** * call network_mysqld_con_accept() with this connection when we are done */ event_set(&(listen_sock->event), listen_sock->fd, EV_READ|EV_PERSIST, network_mysqld_con_accept, con); event_base_set(chas->event_base, &(listen_sock->event)); event_add(&(listen_sock->event), NULL); return 0; }
network_socket *network_socket_init() { return network_socket_new(); }
network_socket *self_connect(network_mysqld_con *con, network_backend_t *backend, GHashTable *pwd_table) { /*make sure that the max conn for the backend is no more than the config number *when max_conn_for_a_backend is no more than 0, there is no limitation for max connection for a backend; * */ if (con->srv->max_conn_for_a_backend > 0 && backend->connected_clients >= con->srv->max_conn_for_a_backend) { g_critical("%s.%d: self_connect:%08x's connected_clients is %d, which are too many!",__FILE__, __LINE__, backend, backend->connected_clients); return NULL; } //1. connect DB network_socket *sock = network_socket_new(); network_address_copy(sock->dst, backend->addr); if (-1 == (sock->fd = socket(sock->dst->addr.common.sa_family, sock->socket_type, 0))) { g_critical("%s.%d: socket(%s) failed: %s (%d)", __FILE__, __LINE__, sock->dst->name->str, g_strerror(errno), errno); network_socket_free(sock); return NULL; } if (-1 == (connect(sock->fd, &sock->dst->addr.common, sock->dst->len))) { g_message("%s.%d: connecting to backend (%s) failed, marking it as down for ...", __FILE__, __LINE__, sock->dst->name->str); network_socket_free(sock); if (backend->state != BACKEND_STATE_OFFLINE) backend->state = BACKEND_STATE_DOWN; return NULL; } //2. read handshake,重点是获取20个字节的随机串 off_t to_read = NET_HEADER_SIZE; guint offset = 0; guchar header[NET_HEADER_SIZE]; while (to_read > 0) { gssize len = recv(sock->fd, header + offset, to_read, 0); if (len == -1 || len == 0) { network_socket_free(sock); return NULL; } offset += len; to_read -= len; } to_read = header[0] + (header[1] << 8) + (header[2] << 16); offset = 0; GString *data = g_string_sized_new(to_read); while (to_read > 0) { gssize len = recv(sock->fd, data->str + offset, to_read, 0); if (len == -1 || len == 0) { network_socket_free(sock); g_string_free(data, TRUE); return NULL; } offset += len; to_read -= len; } data->len = offset; network_packet packet; packet.data = data; packet.offset = 0; network_mysqld_auth_challenge *challenge = network_mysqld_auth_challenge_new(); network_mysqld_proto_get_auth_challenge(&packet, challenge); //3. 生成response GString *response = g_string_sized_new(20); GString *hashed_password = g_hash_table_lookup(pwd_table, con->client->response->username->str); if (hashed_password) { network_mysqld_proto_password_scramble(response, S(challenge->challenge), S(hashed_password)); } else { network_socket_free(sock); g_string_free(data, TRUE); network_mysqld_auth_challenge_free(challenge); g_string_free(response, TRUE); return NULL; } //4. send auth off_t to_write = 58 + con->client->response->username->len; offset = 0; g_string_truncate(data, 0); char tmp[] = {to_write - 4, 0, 0, 1, 0x85, 0xa6, 3, 0, 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; g_string_append_len(data, tmp, 36); g_string_append_len(data, con->client->response->username->str, con->client->response->username->len); g_string_append_len(data, "\0\x14", 2); g_string_append_len(data, response->str, 20); g_string_free(response, TRUE); while (to_write > 0) { gssize len = send(sock->fd, data->str + offset, to_write, 0); if (len == -1) { network_socket_free(sock); g_string_free(data, TRUE); network_mysqld_auth_challenge_free(challenge); return NULL; } offset += len; to_write -= len; } //5. read auth result to_read = NET_HEADER_SIZE; offset = 0; while (to_read > 0) { gssize len = recv(sock->fd, header + offset, to_read, 0); if (len == -1 || len == 0) { network_socket_free(sock); g_string_free(data, TRUE); network_mysqld_auth_challenge_free(challenge); return NULL; } offset += len; to_read -= len; } to_read = header[0] + (header[1] << 8) + (header[2] << 16); offset = 0; g_string_truncate(data, 0); g_string_set_size(data, to_read); while (to_read > 0) { gssize len = recv(sock->fd, data->str + offset, to_read, 0); if (len == -1 || len == 0) { network_socket_free(sock); g_string_free(data, TRUE); network_mysqld_auth_challenge_free(challenge); return NULL; } offset += len; to_read -= len; } data->len = offset; if (data->str[0] != MYSQLD_PACKET_OK) { network_socket_free(sock); g_string_free(data, TRUE); network_mysqld_auth_challenge_free(challenge); return NULL; } g_string_free(data, TRUE); //6. set non-block network_socket_set_non_blocking(sock); network_socket_connect_setopts(sock); //此句是否需要?是否应该放在第1步末尾? sock->challenge = challenge; sock->response = network_mysqld_auth_response_copy(con->client->response); g_atomic_int_inc(&backend->connected_clients); return sock; }
/** * 测试zabbix没有启动的情况 * @return */ void test_admin_backend_mange_Add(void) { /** 初始化内存变量*/ network_backend_t *b = NULL; chassis *srv1 = g_new0(chassis, 1); srv1->priv = g_new0(chassis_private, 1); srv1->priv->backends = network_backends_new(); srv1->xml_filename = "test_config.xml"; network_backends_add(srv1->priv->backends, "X.X.X.X:3306#2#UP", BACKEND_TYPE_RW); b = network_backends_get(srv1->priv->backends, 0); g_mutex_init(&(b->mutex[0])); g_mutex_init(&(b->mutex[1])); network_backends_add(srv1->priv->backends, "X.X.X.X:3306#3#UP", BACKEND_TYPE_RO); b = network_backends_get(srv1->priv->backends, 1); g_mutex_init(&(b->mutex[0])); g_mutex_init(&(b->mutex[1])); network_mysqld_con *con = network_mysqld_con_new(); con->client = network_socket_new(); con->srv = srv1; con->srv->detect_threads = g_ptr_array_new(); //network_mysqld_add_connection(srv1, con); gchar *cmd = g_strdup("addBackend --backend=X.X.X.X:3306"); g_assert_cmpint(COMMAND_PROCESS_ERROR, ==, admin_command_process(con, cmd)); g_free(cmd); cmd = NULL; cmd = g_strdup("addBackend"); g_assert_cmpint(COMMAND_PROCESS_ERROR, ==, admin_command_process(con, cmd)); g_free(cmd); cmd = NULL; g_assert(COMMAND_NO_QUERY_SPECIFIED == admin_command_process(con, NULL)); cmd = g_strdup("addBackend --backend=X.X.X.X:3307"); g_assert(COMMAND_PROCESS_ERROR == admin_command_process(con, cmd)); g_free(cmd); cmd = NULL; cmd = g_strdup("addBackend --backend=X.X.X.X:3307#1#up --bktype=rw"); g_assert(COMMAND_PROCESS_ERROR == admin_command_process(con, cmd)); g_free(cmd); cmd = NULL; cmd = g_strdup("addBackend --backend=X.X.X.X:3307 --bktype=ro"); g_assert(COMMAND_PROCESS_SUCCESS == admin_command_process(con, cmd)); network_backend_t *backend = network_backends_get_by_name(srv1->priv->backends, "X.X.X.X:3307"); g_assert(backend); g_free(cmd); cmd = NULL; cmd = g_strdup("addBackend --backend=192.1968.x.xx:3308"); g_assert(COMMAND_PROCESS_ERROR == admin_command_process(con, cmd)); g_free(cmd); cmd = NULL; cmd = g_strdup("addBackend --backends=X.X.X.X:3308"); g_assert(COMMAND_PROCESS_ERROR == admin_command_process(con, cmd)); g_free(cmd); cmd = NULL; cmd = g_strdup("addBackend --backend=X.X.X.X:103307"); g_assert(COMMAND_PROCESS_ERROR == admin_command_process(con, cmd)); g_free(cmd); cmd = NULL; cmd = g_strdup("addBackends --backend=X.X.X.X:3308"); g_assert(COMMAND_NOT_SUPPORT == admin_command_process(con, cmd)); g_free(cmd); cmd = NULL; // g_ptr_array_free(con->srv->detect_threads, TRUE); // con->srv->detect_threads = NULL; //network_mysqld_con_free(con); //con = NULL; //network_backends_free(srv1->priv->backends); //srv1->priv->backends = NULL; //g_free(srv1->priv); //srv1->priv = NULL; //g_free(srv1); //srv1 = NULL; }