diff --git a/src/core/network.c b/src/core/network.c index 149b047e..274ad06f 100644 --- a/src/core/network.c +++ b/src/core/network.c @@ -47,6 +47,8 @@ union sockaddr_union { # define g_io_channel_new(handle) g_io_channel_unix_new(handle) #endif +static unsigned short default_family = 0; + /* Cygwin need this, don't know others.. */ /*#define BLOCKING_SOCKETS 1*/ @@ -332,8 +334,9 @@ int net_getsockname(GIOChannel *handle, IPADDR *addr, int *port) return 0; } -/* Get IP address for host, returns 0 = ok, - others = error code for net_gethosterror() */ +/* Get IP address for host. family specifies if we should prefer to + IPv4 or IPv6 address (0 = default, AF_INET or AF_INET6). + returns 0 = ok, others = error code for net_gethosterror() */ int net_gethostbyname(const char *addr, IPADDR *ip, int family) { #ifdef HAVE_IPV6 @@ -352,7 +355,7 @@ int net_gethostbyname(const char *addr, IPADDR *ip, int family) memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; - hints.ai_family = family; + hints.ai_family = family != 0 ? family : default_family; /* save error to host_error for later use */ host_error = getaddrinfo(addr, NULL, &hints, &ai); @@ -377,6 +380,13 @@ int net_gethostbyname(const char *addr, IPADDR *ip, int family) return 0; } +/* Set the default address family to use with host resolving + (AF_INET or AF_INET6) */ +void net_host_resolver_set_default_family(unsigned short family) +{ + default_family = family; +} + /* Get name for host, *name should be g_free()'d unless it's NULL. Return values are the same as with net_gethostbyname() */ int net_gethostbyaddr(IPADDR *ip, char **name) diff --git a/src/core/network.h b/src/core/network.h index 810b11c7..1213c8e9 100644 --- a/src/core/network.h +++ b/src/core/network.h @@ -51,9 +51,12 @@ int net_receive(GIOChannel *handle, char *buf, int len); int net_transmit(GIOChannel *handle, const char *data, int len); /* Get IP address for host. family specifies if we should prefer to - IPv4 or IPv6 address (0 = don't care, AF_INET or AF_INET6). + IPv4 or IPv6 address (0 = default, AF_INET or AF_INET6). returns 0 = ok, others = error code for net_gethosterror() */ int net_gethostbyname(const char *addr, IPADDR *ip, int family); +/* Set the default address family to use with host resolving + (AF_INET or AF_INET6) */ +void net_host_resolver_set_default_family(unsigned short family); /* Get name for host, *name should be g_free()'d unless it's NULL. Return values are the same as with net_gethostbyname() */ int net_gethostbyaddr(IPADDR *ip, char **name); diff --git a/src/core/server-setup-rec.h b/src/core/server-setup-rec.h index 56df6106..8fa774ed 100644 --- a/src/core/server-setup-rec.h +++ b/src/core/server-setup-rec.h @@ -3,6 +3,7 @@ int chat_type; /* chat_protocol_lookup(xx) */ char *chatnet; +unsigned short family; /* 0 = default, AF_INET or AF_INET6 */ char *address; int port; char *password; diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c index cc0e83ba..46d7f64a 100644 --- a/src/core/servers-setup.c +++ b/src/core/servers-setup.c @@ -1,7 +1,7 @@ /* servers-setup.c : irssi - Copyright (C) 1999-2000 Timo Sirainen + Copyright (C) 1999-2001 Timo Sirainen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,6 +31,7 @@ GSList *setupservers; +char *old_source_host; int source_host_ok; /* Use source_host_ip .. */ IPADDR *source_host_ip; /* Resolved address */ @@ -133,6 +134,8 @@ static void server_setup_fill_server(SERVER_CONNECT_REC *conn, sserver->last_connect = time(NULL); + if (sserver->family != 0 && conn->family == 0) + conn->family = sserver->family; if (sserver->port > 0 && conn->port <= 0) conn->port = sserver->port; server_setup_fill_reconn(conn, sserver); @@ -307,7 +310,7 @@ static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node) { SERVER_SETUP_REC *rec; CHATNET_REC *chatnetrec; - char *server, *chatnet; + char *server, *chatnet, *family; int port; g_return_val_if_fail(node != NULL, NULL); @@ -343,10 +346,14 @@ static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node) chatnet_create(chatnetrec); } + family = config_node_get_str(node, "family", ""); + rec = CHAT_PROTOCOL(chatnetrec)->create_server_setup(); rec->type = module_get_uniq_id("SERVER SETUP", 0); - rec->chat_type = chatnetrec->chat_type; - rec->chatnet = g_strdup(chatnetrec->name); + rec->chat_type = CHAT_PROTOCOL(chatnetrec)->id; + rec->chatnet = chatnetrec == NULL ? NULL : g_strdup(chatnetrec->name); + rec->family = g_strcasecmp(family, "inet6") == 0 ? AF_INET6 : + (g_strcasecmp(family, "inet") == 0 ? AF_INET : 0); rec->address = g_strdup(server); rec->password = g_strdup(config_node_get_str(node, "password", NULL)); rec->port = port; @@ -379,6 +386,10 @@ static void server_setup_save(SERVER_SETUP_REC *rec) iconfig_node_set_str(node, "password", rec->password); iconfig_node_set_str(node, "own_host", rec->own_host); + iconfig_node_set_str(node, "family", + rec->family == AF_INET6 ? "inet6" : + rec->family == AF_INET ? "inet" : NULL); + if (rec->autoconnect) iconfig_node_set_bool(node, "autoconnect", TRUE); @@ -442,15 +453,26 @@ static void read_servers(void) static void read_settings(void) { - g_free_and_null(source_host_ip); + unsigned short family; - source_host_ok = FALSE; - get_source_host_ip(); + family = settings_get_bool("resolve_prefer_ipv6") ? AF_INET6 : AF_INET; + net_host_resolver_set_default_family(family); + + if (old_source_host == NULL || + strcmp(old_source_host, settings_get_str("hostname")) != 0) { + g_free_not_null(old_source_host); + old_source_host = g_strdup(settings_get_str("hostname")); + + g_free_and_null(source_host_ip); + source_host_ok = FALSE; + get_source_host_ip(); + } } void servers_setup_init(void) { settings_add_str("server", "hostname", ""); + settings_add_bool("server", "resolve_prefer_ipv6", FALSE); settings_add_str("server", "nick", NULL); settings_add_str("server", "user_name", NULL); @@ -463,6 +485,7 @@ void servers_setup_init(void) setupservers = NULL; source_host_ip = NULL; + old_source_host = NULL; read_settings(); signal_add("setup changed", (SIGNAL_FUNC) read_settings); @@ -473,6 +496,7 @@ void servers_setup_init(void) void servers_setup_deinit(void) { g_free_not_null(source_host_ip); + g_free_not_null(old_source_host); while (setupservers != NULL) server_setup_destroy(setupservers->data); diff --git a/src/core/servers.c b/src/core/servers.c index 4b190267..9324a7d5 100644 --- a/src/core/servers.c +++ b/src/core/servers.c @@ -171,6 +171,9 @@ static void server_connect_callback_readpipe(SERVER_REC *server) server->connect_pipe[0] = NULL; server->connect_pipe[1] = NULL; + if (iprec.error == 0) + signal_emit("server connecting", 2, server, &iprec.ip); + conn = server->connrec; handle = iprec.error != 0 ? NULL : net_connect_ip(&iprec.ip, conn->proxy != NULL ? @@ -205,7 +208,6 @@ static void server_connect_callback_readpipe(SERVER_REC *server) g_input_add(handle, G_INPUT_WRITE | G_INPUT_READ, (GInputFunction) server_connect_callback_init, server); - signal_emit("server connecting", 2, server, &iprec.ip); } /* initializes server record but doesn't start connecting */ diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c index 6abc4374..eba6dcf1 100644 --- a/src/fe-common/core/fe-server.c +++ b/src/fe-common/core/fe-server.c @@ -139,6 +139,11 @@ static void cmd_server_add(const char *data) } } + if (g_hash_table_lookup(optlist, "6")) + rec->family = AF_INET6; + else if (g_hash_table_lookup(optlist, "4")) + rec->family = AF_INET; + if (g_hash_table_lookup(optlist, "auto")) rec->autoconnect = TRUE; if (g_hash_table_lookup(optlist, "noauto")) rec->autoconnect = FALSE; @@ -321,7 +326,7 @@ void fe_server_init(void) command_bind("server", NULL, (SIGNAL_FUNC) cmd_server); command_bind("server add", NULL, (SIGNAL_FUNC) cmd_server_add); command_bind("server remove", NULL, (SIGNAL_FUNC) cmd_server_remove); - command_set_options("server add", "auto noauto -host -port"); + command_set_options("server add", "4 6 auto noauto -host -port"); signal_add("server looking", (SIGNAL_FUNC) sig_server_looking); signal_add("server connecting", (SIGNAL_FUNC) sig_server_connecting);