Exemplo n.º 1
0
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);
}
/*
 * FIXME: 1) remove _set_address, make this function callable with result of same
 *        2) differentiate between reasons for "we didn't add" (now -1 in all cases)
 */
int network_backends_add(network_backends_t *bs, /* const */ gchar *address, backend_type_t type) {
	network_backend_t *new_backend;
	guint i;

	new_backend = network_backend_new();
	new_backend->type = type;

	if (0 != network_address_set_address(new_backend->addr, address)) {
		network_backend_free(new_backend);
		return -1;
	}

	/* check if this backend is already known */
	g_mutex_lock(bs->backends_mutex);
	for (i = 0; i < bs->backends->len; i++) {
		network_backend_t *old_backend = bs->backends->pdata[i];

		if (strleq(S(old_backend->addr->name), S(new_backend->addr->name))) {
			network_backend_free(new_backend);

			g_mutex_unlock(bs->backends_mutex);
			g_critical("backend %s is already known!", address);
			return -1;
		}
	}


	g_ptr_array_add(bs->backends, new_backend);
	g_mutex_unlock(bs->backends_mutex);

	g_message("added %s backend: %s", (type == BACKEND_TYPE_RW) ?
			"read/write" : "read-only", address);

	return 0;
}
Exemplo n.º 3
0
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
}
Exemplo n.º 4
0
/**
 * 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;
}
Exemplo n.º 5
0
/*
 * FIXME: 1) remove _set_address, make this function callable with result of same
 *        2) differentiate between reasons for "we didn't add" (now -1 in all cases)
 */
int network_backends_add(network_backends_t *bs, /* const */ gchar *address, backend_type_t type) {
	network_backend_t *new_backend;
	guint i;

	new_backend = network_backend_new(bs->event_thread_count);
	new_backend->type = type;

	gchar *p = NULL;
	if (type == BACKEND_TYPE_RO) {
		guint weight = 1;
		p = strrchr(address, '@');
		if (p != NULL) {
			*p = '\0';
			weight = atoi(p+1);
		}
		new_backend->weight = weight;
	}

	if (0 != network_address_set_address(new_backend->addr, address)) {
		network_backend_free(new_backend);
		return -1;
	}

	/* check if this backend is already known */
	g_mutex_lock(bs->backends_mutex);	/*remove lock*/
	gint first_slave = -1;
	for (i = 0; i < bs->backends->len; i++) {
		network_backend_t *old_backend = bs->backends->pdata[i];

		if (first_slave == -1 && old_backend->type == BACKEND_TYPE_RO) first_slave = i;

		if (old_backend->type == type && strleq(S(old_backend->addr->name), S(new_backend->addr->name))) {
			network_backend_free(new_backend);

			g_mutex_unlock(bs->backends_mutex);	/*remove lock*/
			g_critical("backend %s is already known!", address);
			return -1;
		}
	}

	g_ptr_array_add(bs->backends, new_backend);
	if (first_slave != -1 && type == BACKEND_TYPE_RW) {
		network_backend_t *temp_backend = bs->backends->pdata[first_slave];
		bs->backends->pdata[first_slave] = bs->backends->pdata[bs->backends->len - 1];
		bs->backends->pdata[bs->backends->len - 1] = temp_backend;
	}
	g_mutex_unlock(bs->backends_mutex);	/*remove lock*/

	g_message("added %s backend: %s", (type == BACKEND_TYPE_RW) ? "read/write" : "read-only", address);

	if (p != NULL) *p = '@';

	return 0;
}
Exemplo n.º 6
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;
}
Exemplo n.º 7
0
/**
 * 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);
}
Exemplo n.º 8
0
/**
 * 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);
}
Exemplo n.º 9
0
/**
 * 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;
}