network_socket *network_socket_new() { network_socket *s; s = g_new0(network_socket, 1); s->send_queue = network_queue_new(); s->recv_queue = network_queue_new(); s->recv_queue_raw = network_queue_new(); s->default_db = g_string_new(NULL); s->charset = g_string_new(NULL); s->charset_client = g_string_new(NULL); s->charset_connection = g_string_new(NULL); s->charset_results = g_string_new(NULL); s->sql_mode = g_string_new(NULL); s->fd = -1; s->socket_type = SOCK_STREAM; /* let's default to TCP */ s->packet_id_is_reset = TRUE; s->src = network_address_new(); s->dst = network_address_new(); s->last_visit_time = time(0); return s; }
void t_network_address_new() { network_address *addr; addr = network_address_new(); network_address_free(addr); }
void t_network_address_set() { network_address *addr; addr = network_address_new(); g_assert_cmpint(network_address_set_address(addr, "127.0.0.1:3306"), ==, 0); g_assert_cmpint(network_address_set_address(addr, "127.0.0.1"), ==, 0); g_log_set_always_fatal(G_LOG_FATAL_MASK); /* shouldn't crash. * * we can't test if it works as we can't know if the host has setup IPv6 */ network_address_set_address(addr, "[::1]"); network_address_set_address(addr, "[::1]:3306"); /* should fail */ g_assert_cmpint(network_address_set_address(addr, "500.0.0.1"), ==, -1); g_assert_cmpint(network_address_set_address(addr, "127.0.0.1:"), ==, -1); g_assert_cmpint(network_address_set_address(addr, "[::1]:"), ==, -1); g_assert_cmpint(network_address_set_address(addr, "127.0.0.1:65536"), ==, -1); g_assert_cmpint(network_address_set_address(addr, "127.0.0.1:-1"), ==, -1); network_address_free(addr); }
static void t_network_address_tostring_unix() { #ifndef _WIN32 network_address *addr; char buf[255]; gsize buf_len = sizeof(buf); GError *gerr = NULL; addr = network_address_new(); g_assert_cmpint(network_address_set_address(addr, "/foobar"), ==, 0); buf_len = sizeof(buf); /* should be large enough */ g_assert_cmpstr(network_address_tostring(addr, buf, &buf_len, NULL), ==, "/foobar"); g_assert_cmpint(7 + 1, ==, buf_len); buf_len = 3; /* too small */ g_assert(NULL == network_address_tostring(addr, buf, &buf_len, &gerr)); g_assert_cmpint(NETWORK_ADDRESS_ERROR, ==, gerr->domain); g_assert_cmpint(NETWORK_ADDRESS_ERROR_DST_TOO_SMALL, ==, gerr->code); g_clear_error(&gerr); network_address_free(addr); #endif }
static void t_network_address_tostring_ipv6() { #ifdef AF_INET6 network_address *addr; char buf[255]; gsize buf_len = sizeof(buf); GError *gerr = NULL; addr = network_address_new(); if (0 != network_address_set_address(addr, "[::1]")) { /* skip test, if resolving ::1 fails */ network_address_free(addr); return; } buf_len = sizeof(buf); /* should be large enough */ g_assert_cmpstr(network_address_tostring(addr, buf, &buf_len, NULL), ==, "::1"); g_assert_cmpint(3 + 1, ==, buf_len); buf_len = 3; /* too small */ g_assert(NULL == network_address_tostring(addr, buf, &buf_len, &gerr)); g_assert_cmpint(NETWORK_ADDRESS_ERROR, ==, gerr->domain); g_assert_cmpint(NETWORK_ADDRESS_ERROR_DST_TOO_SMALL, ==, gerr->code); g_clear_error(&gerr); network_address_free(addr); #endif }
network_address *network_address_copy(network_address *dst, network_address *src) { if (!dst) dst = network_address_new(); dst->len = src->len; dst->addr = src->addr; g_string_assign_len(dst->name, S(src->name)); return dst; }
network_backend_t *network_backend_new() { network_backend_t *b; b = g_new0(network_backend_t, 1); b->pool = network_connection_pool_new(); b->uuid = g_string_new(NULL); b->addr = network_address_new(); return b; }
network_backend_t *network_backend_new(guint event_thread_count) { network_backend_t *b = g_new0(network_backend_t, 1); b->pools = g_ptr_array_new(); guint i; for (i = 0; i <= event_thread_count; ++i) { network_connection_pool* pool = network_connection_pool_new(); g_ptr_array_add(b->pools, pool); } b->uuid = g_string_new(NULL); b->addr = network_address_new(); return b; }
void t_network_address_set() { network_address *addr; addr = network_address_new(); g_assert_cmpint(network_address_set_address(addr, "127.0.0.1:3306"), ==, 0); g_assert_cmpint(network_address_set_address(addr, "127.0.0.1"), ==, 0); g_log_set_always_fatal(G_LOG_FATAL_MASK); /* should fail */ g_assert_cmpint(network_address_set_address(addr, "500.0.0.1"), ==, -1); g_assert_cmpint(network_address_set_address(addr, "127.0.0.1:"), ==, -1); g_assert_cmpint(network_address_set_address(addr, "127.0.0.1:65536"), ==, -1); g_assert_cmpint(network_address_set_address(addr, "127.0.0.1:-1"), ==, -1); network_address_free(addr); }
/** * test if we decode the port number correctly */ void t_network_address_resolve() { network_address *addr; g_test_bug("43313"); addr = network_address_new(); network_address_set_address(addr, "127.0.0.1:3306"); /* _set_address() should set the port number */ g_assert_cmpint(ntohs(addr->addr.ipv4.sin_port), ==, 3306); /* reset the name to see that _refresh_name() updates to the right value */ g_string_truncate(addr->name, 0); network_address_refresh_name(addr); g_assert_cmpstr(addr->name->str, ==, "127.0.0.1:3306"); network_address_free(addr); }
/** * test if we convert addr->string correctly for IPv6 */ void t_network_address_resolve_ipv6() { network_address *addr; addr = network_address_new(); if (0 != network_address_set_address(addr, "[::1]")) { /* skip test, if resolving ::1 fails */ network_address_free(addr); return; } /* _set_address() should set the port number */ /* reset the name to see that _refresh_name() updates to the right value */ g_string_truncate(addr->name, 0); network_address_refresh_name(addr); g_assert_cmpstr(addr->name->str, ==, "[::1]:3306"); network_address_free(addr); }
/** * connect a socket * * the con->dst->addr has to be set before * * @param con a socket * @return NETWORK_SOCKET_SUCCESS on connected, NETWORK_SOCKET_ERROR on error * * @see network_address_set_address() */ network_socket_retval_t network_socket_bind(network_socket * con) { /* * HPUX: int setsockopt(int s, int level, int optname, const void *optval, int optlen); * all others: int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); */ #define SETSOCKOPT_OPTVAL_CAST (void *) g_return_val_if_fail(con->fd < 0, NETWORK_SOCKET_ERROR); /* socket is already bound */ g_return_val_if_fail((con->socket_type == SOCK_DGRAM) || (con->socket_type == SOCK_STREAM), NETWORK_SOCKET_ERROR); if (con->socket_type == SOCK_STREAM) { g_return_val_if_fail(con->dst, NETWORK_SOCKET_ERROR); g_return_val_if_fail(con->dst->name->len > 0, NETWORK_SOCKET_ERROR); if (-1 == (con->fd = socket(con->dst->addr.common.sa_family, con->socket_type, 0))) { g_critical("%s: socket(%s) failed: %s (%d)", G_STRLOC, con->dst->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } if (con->dst->addr.common.sa_family == AF_INET || con->dst->addr.common.sa_family == AF_INET6) { /* TCP_NODELAY is int on unix */ /* SO_REUSEADDR is int on unix */ int val; val = 1; if (0 != setsockopt(con->fd, IPPROTO_TCP, TCP_NODELAY, SETSOCKOPT_OPTVAL_CAST &val, sizeof(val))) { g_critical("%s: setsockopt(%s, IPPROTO_TCP, TCP_NODELAY) failed: %s (%d)", G_STRLOC, con->dst->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } if (0 != setsockopt(con->fd, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_CAST &val, sizeof(val))) { g_critical("%s: setsockopt(%s, SOL_SOCKET, SO_REUSEADDR) failed: %s (%d)", G_STRLOC, con->dst->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } } if (con->dst->addr.common.sa_family == AF_INET6) { #ifdef IPV6_V6ONLY /* disable dual-stack IPv4-over-IPv6 sockets * * ... if it is supported: * - Linux * - Mac OS X * - FreeBSD * - Solaris 10 and later * * no supported on: * - Solaris 9 and earlier */ /* IPV6_V6ONLY is int on unix */ int val; val = 0; if (0 != setsockopt(con->fd, IPPROTO_IPV6, IPV6_V6ONLY, SETSOCKOPT_OPTVAL_CAST &val, sizeof(val))) { g_critical("%s: setsockopt(%s, IPPROTO_IPV6, IPV6_V6ONLY) failed: %s (%d)", G_STRLOC, con->dst->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } #endif } if (-1 == bind(con->fd, &con->dst->addr.common, con->dst->len)) { gchar *address_copy; /* binding failed so the address/socket is already being used * let's check if we can connect to it so we check if is being used * by some app */ if (-1 == connect(con->fd, &con->dst->addr.common, con->dst->len)) { g_debug("%s.%d: connect(%s) failed: %s (%d)", __FILE__, __LINE__, con->dst->name->str, g_strerror(errno), errno); /* we can't connect to the socket so no one is listening on it. We need * to unlink it (delete the name from the file system) to be able to * re-use it. * network_address_free does the unlink, but to re-use it we need * to store the pathname associated with the socket before unlink it and * create a new socket with it. */ address_copy = g_strdup(con->dst->name->str); con->dst->can_unlink_socket = TRUE; network_address_free(con->dst); con->dst = network_address_new(); network_address_set_address(con->dst, address_copy); /* we can now free the address copy */ g_free(address_copy); g_debug("%s: retrying to bind(%s)", G_STRLOC, con->dst->name->str); /* let's bind again with the new socket */ if (-1 == bind(con->fd, &con->dst->addr.common, con->dst->len)) { g_critical("%s: bind(%s) failed: %s (%d)", G_STRLOC, con->dst->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } } else { g_critical("%s: bind(%s) failed: %s (%d)", G_STRLOC, con->dst->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } } if (con->dst->addr.common.sa_family == AF_INET && con->dst->addr.ipv4.sin_port == 0) { struct sockaddr_in a; socklen_t a_len = sizeof(a); if (0 != getsockname(con->fd, (struct sockaddr *)&a, &a_len)) { g_critical("%s: getsockname(%s) failed: %s (%d)", G_STRLOC, con->dst->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } con->dst->addr.ipv4.sin_port = a.sin_port; } else if (con->dst->addr.common.sa_family == AF_INET6 && con->dst->addr.ipv6.sin6_port == 0) { struct sockaddr_in6 a; socklen_t a_len = sizeof(a); if (0 != getsockname(con->fd, (struct sockaddr *)&a, &a_len)) { g_critical("%s: getsockname(%s) failed: %s (%d)", G_STRLOC, con->dst->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } con->dst->addr.ipv6.sin6_port = a.sin6_port; } if (-1 == listen(con->fd, 128)) { g_critical("%s: listen(%s, 128) failed: %s (%d)", G_STRLOC, con->dst->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } } else { /* UDP sockets bind the ->src address */ g_return_val_if_fail(con->src, NETWORK_SOCKET_ERROR); g_return_val_if_fail(con->src->name->len > 0, NETWORK_SOCKET_ERROR); if (-1 == (con->fd = socket(con->src->addr.common.sa_family, con->socket_type, 0))) { g_critical("%s: socket(%s) failed: %s (%d)", G_STRLOC, con->src->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } if (-1 == bind(con->fd, &con->src->addr.common, con->src->len)) { g_critical("%s: bind(%s) failed: %s (%d)", G_STRLOC, con->src->name->str, g_strerror(errno), errno); return NETWORK_SOCKET_ERROR; } } con->dst->can_unlink_socket = TRUE; return NETWORK_SOCKET_SUCCESS; }
static gint admin_reload_backends( network_mysqld_con* con, GPtrArray* backend_addr_str_array, gint fail_flag ) { chassis* srv; network_backends_t* backends; GPtrArray* cons; gchar* s; gchar* new_backend_addr; guint i; //gchar ip_address[MAX_IP_PORT_STRING_LEN + 1]; admin_network_addr_t* addr; GPtrArray* addr_array; gint ret = EC_ADMIN_RELOAD_SUCCESS; gboolean all_same_flag = 1; guint server_cnt = 0; guint client_cnt = 0; srv = con->srv; backends = srv->priv->backends; cons = srv->priv->cons; //for test if (fail_flag == 1000) { admin_print_all_backend_cons(con->srv); return EC_ADMIN_RELOAD_SUCCESS; } if (backend_addr_str_array->len != backends->backends->len) { g_critical("%s: Number of refresh backends num is not matched, new backends :%d, orignal backends : %d", G_STRLOC, backend_addr_str_array->len , backends->backends->len); return EC_ADMIN_RELOAD_FAIL; } if (fail_flag != 0 && fail_flag != 1) { g_critical("%s: Fail flag of refresh backends must be 0 or 1, but the flag is %d", G_STRLOC, fail_flag); return EC_ADMIN_RELOAD_FAIL; } addr_array = g_ptr_array_new(); /* 1. 测试DR连通性 */ for (i = 0; i < backend_addr_str_array->len; ++i) { new_backend_addr = g_ptr_array_index(backend_addr_str_array, i); addr = g_new0(admin_network_addr_t, 1); g_ptr_array_add(addr_array, addr); s = strchr(new_backend_addr, ':'); if (NULL != s) { gint len; char * port_err = NULL; network_backend_t* backend; backend = g_ptr_array_index(backends->backends, i); //check whether all backends are same //to do check backend:127.0.0.1:3306, addr:ip:3306? if (all_same_flag && g_strcasecmp(new_backend_addr, backend->addr->name->str) != 0 || backend->state == BACKEND_STATE_DOWN) { all_same_flag = 0; } len = s - new_backend_addr; if (len <= MAX_IP_PORT_STRING_LEN) { memcpy(addr->ip_address, new_backend_addr, len); addr->ip_address[len] = '\0'; addr->port = strtoul(s + 1, &port_err, 10); } if (len > MAX_IP_PORT_STRING_LEN || *(s + 1) == '\0') { g_critical("%s: Reload IP-address has to be in the form [<ip>][:<port>], is '%s'. No port number", G_STRLOC, new_backend_addr); ret = EC_ADMIN_RELOAD_FAIL; } else if (*port_err != '\0') { g_critical("%s: Reload IP-address has to be in the form [<ip>][:<port>], is '%s'. Failed to parse the port at '%s'", G_STRLOC, new_backend_addr, port_err); ret = EC_ADMIN_RELOAD_FAIL; } else { addr->addr = network_address_new(); if (network_address_set_address_ip(addr->addr, addr->ip_address, addr->port)) { g_critical("%s: Reload IP-address %s : %d error", G_STRLOC, addr->ip_address, addr->port); ret = EC_ADMIN_RELOAD_FAIL; } //ping the ip address and port; //ret = network_address_set_address_ip(addr, ip_address, port); //to do } } else ret = EC_ADMIN_RELOAD_FAIL; if (EC_ADMIN_RELOAD_FAIL == ret) { g_ptr_array_free_all(addr_array, admin_network_addr_free); return ret; } } //backends are same if (all_same_flag) { g_ptr_array_free_all(addr_array, admin_network_addr_free); return EC_ADMIN_RELOAD_SUCCESS; } /* 2. 置当前所有backends为down */ g_mutex_lock(backends->backends_mutex); for (i = 0; i < backends->backends->len; ++i) { network_backend_t* backend; backend = g_ptr_array_index(backends->backends, i); backend->state = BACKEND_STATE_DOWN; } g_mutex_unlock(backends->backends_mutex); /* 3. 当前backend为新地址 */ g_mutex_lock(backends->backends_mutex); for (i = 0; i < backends->backends->len; ++i) { network_backend_t* backend; backend = g_ptr_array_index(backends->backends, i); addr = g_ptr_array_index(addr_array, i); network_address_copy(backend->addr, addr->addr); // backend->addr->name->len = 0; /* network refresh name */ // // if (network_address_set_address_ip(backend->addr, addr->ip_address, addr->port)) // { // g_critical("%s: Reload IP-address %s : %d error" // G_STRLOC, addr->ip_address, addr->port); // ret = EC_ADMIN_RELOAD_FAIL; // // break; // } } g_mutex_unlock(backends->backends_mutex); /* 4. 关闭proxy当前所有连接 */ g_mutex_lock(srv->priv->cons_mutex); for (i = 0; i < cons->len; ++i) { con = g_ptr_array_index(cons, i); //区分了是否为backends的连接 if (con->server && con->server->backend_idx != -1) { //g_assert(con->server->fd != -1); if (con->server->fd != -1) { //closesocket(con->server->fd); con->server->fd_bak = con->server->fd; /* 后端连接暂不关闭,让其正常处理正在进行的事件 */ con->server->fd = -1; con->server->disconnect_flag = 1; server_cnt++; } //g_assert(con->client && con->client->fd != -1); if (con->client && con->client->fd != -1) { // int c_fd = con->client->fd; // con->client->fd = -1; // closesocket(c_fd); /* 需主动关闭前端fd,防止前端一直等待,但会导致con资源没有释放 */ client_cnt++; } /* 以上操作可能产生一种情况:客户端请求已在DB执行成功,但前端认为连接已断开 */ switch(con->state) { case CON_STATE_CLOSE_CLIENT: case CON_STATE_CLOSE_SERVER: case CON_STATE_SEND_ERROR: case CON_STATE_ERROR: break; case CON_STATE_INIT: case CON_STATE_CONNECT_SERVER: case CON_STATE_READ_HANDSHAKE: case CON_STATE_SEND_HANDSHAKE: case CON_STATE_READ_AUTH: case CON_STATE_SEND_AUTH: case CON_STATE_READ_AUTH_RESULT: case CON_STATE_SEND_AUTH_RESULT: case CON_STATE_READ_AUTH_OLD_PASSWORD: case CON_STATE_SEND_AUTH_OLD_PASSWORD: break; case CON_STATE_READ_QUERY: case CON_STATE_SEND_QUERY: break; case CON_STATE_READ_QUERY_RESULT: case CON_STATE_SEND_QUERY_RESULT: // //需要主动关闭连接 // if (fail_flag == 1) // { // if (con->client->fd != -1) // { // closesocket(con->client->fd); // con->client->fd = -1; // } // } break; case CON_STATE_READ_LOCAL_INFILE_DATA: case CON_STATE_SEND_LOCAL_INFILE_DATA: case CON_STATE_READ_LOCAL_INFILE_RESULT: case CON_STATE_SEND_LOCAL_INFILE_RESULT: break; } } } g_message("%s reload backends: connection count %d, close server count %d, close client count %d", G_STRLOC, srv->priv->cons->len, server_cnt, client_cnt); g_mutex_unlock(srv->priv->cons_mutex); if (ret != EC_ADMIN_RELOAD_SUCCESS) goto destroy_end; /* 5. 再把后端状态置为unknown,接收新连接 */ g_mutex_lock(backends->backends_mutex); for (i = 0; i < backends->backends->len; ++i) { network_backend_t* backend; backend = g_ptr_array_index(backends->backends, i); backend->state = BACKEND_STATE_UNKNOWN; } g_mutex_unlock(backends->backends_mutex); /* 6. 刷新配置 */ ret = admin_configure_flush_to_file(srv); destroy_end: g_ptr_array_free_all(addr_array, admin_network_addr_free); return ret; }