mirror of
https://github.com/irssi/irssi.git
synced 2026-08-18 16:12:30 +02:00
use GIO resolver
change: rename resolve_prefer_ipv6 -> irssiproxy_prefer_ipv6
This commit is contained in:
parent
d5be7d7756
commit
51f2a4f7fb
18 changed files with 313 additions and 339 deletions
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
%9Examples:%9
|
%9Examples:%9
|
||||||
|
|
||||||
/TOGGLE resolve_prefer_ipv6
|
|
||||||
/TOGGLE channels_rejoin_unavailable ON
|
/TOGGLE channels_rejoin_unavailable ON
|
||||||
|
|
||||||
%9See also:%9 SET
|
%9See also:%9 SET
|
||||||
|
|
|
||||||
|
|
@ -373,9 +373,6 @@
|
||||||
After connected to server, Irssi can automatically change your user
|
After connected to server, Irssi can automatically change your user
|
||||||
mode. You can set it with /SET usermode <mode>, default is +i.
|
mode. You can set it with /SET usermode <mode>, default is +i.
|
||||||
|
|
||||||
/SET resolve_prefer_ipv6 - If ON, prefer IPv6 for hosts that
|
|
||||||
have both v4 and v6 addresses.
|
|
||||||
|
|
||||||
5.5 Automatic reconnecting
|
5.5 Automatic reconnecting
|
||||||
|
|
||||||
If you get disconnected from server, Irssi will try to reconnect
|
If you get disconnected from server, Irssi will try to reconnect
|
||||||
|
|
|
||||||
35
meson.build
35
meson.build
|
|
@ -8,6 +8,7 @@ project('irssi', 'c',
|
||||||
|
|
||||||
glib_internal_version = 'glib-2.74.3' # keep this in sync with subprojects/glib.wrap
|
glib_internal_version = 'glib-2.74.3' # keep this in sync with subprojects/glib.wrap
|
||||||
glib_pcre2_internal_version = 'pcre2-10.40'
|
glib_pcre2_internal_version = 'pcre2-10.40'
|
||||||
|
glib_libffi_internal_version = 'libffi'
|
||||||
cc = meson.get_compiler('c')
|
cc = meson.get_compiler('c')
|
||||||
rootinc = include_directories('.')
|
rootinc = include_directories('.')
|
||||||
dep = []
|
dep = []
|
||||||
|
|
@ -217,11 +218,6 @@ if not glib_dep.found()
|
||||||
prov_lib = cc.find_library('iconv', dirs : '/usr/local/lib')
|
prov_lib = cc.find_library('iconv', dirs : '/usr/local/lib')
|
||||||
glib_internal_usr_local = true
|
glib_internal_usr_local = true
|
||||||
endif
|
endif
|
||||||
if cc.has_function('libiconv_open', dependencies : prov_lib)
|
|
||||||
glib_internal_configure_args += '-Diconv=gnu'
|
|
||||||
else
|
|
||||||
glib_internal_configure_args += '-Diconv=native'
|
|
||||||
endif
|
|
||||||
glib_internal_dependencies += prov_lib
|
glib_internal_dependencies += prov_lib
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
@ -254,7 +250,7 @@ if not glib_dep.found()
|
||||||
glib_internal_configure_t = custom_target('glib-internal-configure',
|
glib_internal_configure_t = custom_target('glib-internal-configure',
|
||||||
command : [ meson_cmd, 'setup', '--prefix=/irssi-glib-internal',
|
command : [ meson_cmd, 'setup', '--prefix=/irssi-glib-internal',
|
||||||
'--buildtype=' + get_option('buildtype'),
|
'--buildtype=' + get_option('buildtype'),
|
||||||
'-Dlibmount=disabled', '-Dselinux=disabled', '-Ddefault_library=static', '-Dforce_fallback_for=pcre2',
|
'-Dlibmount=disabled', '-Dselinux=disabled', '-Ddefault_library=static', '-Dforce_fallback_for=pcre2,libffi',
|
||||||
glib_internal_configure_args,
|
glib_internal_configure_args,
|
||||||
(meson.current_build_dir() / 'build-subprojects' / 'glib'),
|
(meson.current_build_dir() / 'build-subprojects' / 'glib'),
|
||||||
(meson.current_source_dir() / 'subprojects' / glib_internal_version) ],
|
(meson.current_source_dir() / 'subprojects' / glib_internal_version) ],
|
||||||
|
|
@ -263,9 +259,13 @@ if not glib_dep.found()
|
||||||
depends : glib_internal_download_t,)
|
depends : glib_internal_download_t,)
|
||||||
glib_internal_build_t = custom_target('glib-internal-build',
|
glib_internal_build_t = custom_target('glib-internal-build',
|
||||||
command : [ ninja, '-C', meson.current_build_dir() / 'build-subprojects' / 'glib',
|
command : [ ninja, '-C', meson.current_build_dir() / 'build-subprojects' / 'glib',
|
||||||
|
'subprojects' / glib_libffi_internal_version / 'src' / 'libffi.a',
|
||||||
'subprojects' / glib_pcre2_internal_version / 'libpcre2-8.a',
|
'subprojects' / glib_pcre2_internal_version / 'libpcre2-8.a',
|
||||||
'glib' / 'libglib-2.0.a',
|
'glib' / 'libglib-2.0.a',
|
||||||
'gmodule' / 'libgmodule-2.0.a'],
|
'gmodule' / 'libgmodule-2.0.a',
|
||||||
|
'gobject' / 'libgobject-2.0.a',
|
||||||
|
'gio' / 'libgio-2.0.a',
|
||||||
|
],
|
||||||
console : true,
|
console : true,
|
||||||
output : ['glib-internal-build'],
|
output : ['glib-internal-build'],
|
||||||
depends : glib_internal_configure_t,)
|
depends : glib_internal_configure_t,)
|
||||||
|
|
@ -295,11 +295,32 @@ if not glib_dep.found()
|
||||||
],
|
],
|
||||||
link_args : [ meson.current_build_dir() / 'build-subprojects' / 'glib' / 'gmodule' / 'libgmodule-2.0.a' ],
|
link_args : [ meson.current_build_dir() / 'build-subprojects' / 'glib' / 'gmodule' / 'libgmodule-2.0.a' ],
|
||||||
)
|
)
|
||||||
|
gobject_dep = declare_dependency(sources : glib_internal_build_t,
|
||||||
|
compile_args : [
|
||||||
|
'-isystem' + (meson.current_build_dir() / 'build-subprojects' / 'glib'),
|
||||||
|
],
|
||||||
|
link_args : [
|
||||||
|
meson.current_build_dir() / 'build-subprojects' / 'glib' / 'subprojects' / glib_libffi_internal_version / 'src' / 'libffi.a',
|
||||||
|
meson.current_build_dir() / 'build-subprojects' / 'glib' / 'gobject' / 'libgobject-2.0.a'
|
||||||
|
],
|
||||||
|
)
|
||||||
|
gio_dep = declare_dependency(sources : glib_internal_build_t,
|
||||||
|
dependencies : cc.find_library('z'),
|
||||||
|
compile_args : [
|
||||||
|
'-isystem' + (meson.current_source_dir() / 'subprojects' / glib_internal_version / 'gio'),
|
||||||
|
'-isystem' + (meson.current_build_dir() / 'build-subprojects' / 'glib'),
|
||||||
|
],
|
||||||
|
link_args : [ meson.current_build_dir() / 'build-subprojects' / 'glib' / 'gio' / 'libgio-2.0.a' ],
|
||||||
|
)
|
||||||
else
|
else
|
||||||
gmodule_dep = dependency('gmodule-2.0', static : want_static_dependency, include_type : 'system')
|
gmodule_dep = dependency('gmodule-2.0', static : want_static_dependency, include_type : 'system')
|
||||||
|
gobject_dep = dependency('gobject-2.0', static : want_static_dependency, include_type : 'system')
|
||||||
|
gio_dep = dependency('gio-2.0', static : want_static_dependency, include_type : 'system')
|
||||||
endif
|
endif
|
||||||
dep += glib_dep
|
dep += glib_dep
|
||||||
dep += gmodule_dep
|
dep += gmodule_dep
|
||||||
|
dep += gobject_dep
|
||||||
|
dep += gio_dep
|
||||||
|
|
||||||
if glib_internal and want_static_dependency and want_fuzzer
|
if glib_internal and want_static_dependency and want_fuzzer
|
||||||
openssl_proj = subproject('openssl', default_options : ['default_library=static', 'asm=disabled'])
|
openssl_proj = subproject('openssl', default_options : ['default_library=static', 'asm=disabled'])
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
#define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */
|
#define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */
|
||||||
#define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */
|
#define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */
|
||||||
|
|
||||||
#define IRSSI_ABI_VERSION 56
|
#define IRSSI_ABI_VERSION 57
|
||||||
|
|
||||||
#define DEFAULT_SERVER_ADD_PORT 6667
|
#define DEFAULT_SERVER_ADD_PORT 6667
|
||||||
#define DEFAULT_SERVER_ADD_TLS_PORT 6697
|
#define DEFAULT_SERVER_ADD_TLS_PORT 6697
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gmodule.h>
|
#include <gmodule.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
typedef guint64 uoff_t;
|
typedef guint64 uoff_t;
|
||||||
#define PRIuUOFF_T G_GUINT64_FORMAT
|
#define PRIuUOFF_T G_GUINT64_FORMAT
|
||||||
|
|
|
||||||
|
|
@ -101,10 +101,11 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
|
||||||
|
|
||||||
host = g_hash_table_lookup(optlist, "host");
|
host = g_hash_table_lookup(optlist, "host");
|
||||||
if (host != NULL && *host != '\0') {
|
if (host != NULL && *host != '\0') {
|
||||||
IPADDR ip4, ip6;
|
IPADDR ip4 = { 0 };
|
||||||
|
IPADDR ip6 = { 0 };
|
||||||
if (net_gethostbyname(host, &ip4, &ip6) == 0)
|
if (net_gethostbyname_first_ips(host, G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT, &ip4,
|
||||||
server_connect_own_ip_save(conn, &ip4, &ip6);
|
&ip6) == 0)
|
||||||
|
server_connect_own_ip_save(conn, &ip4, &ip6);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_params_free(free_arg);
|
cmd_params_free(free_arg);
|
||||||
|
|
|
||||||
|
|
@ -22,86 +22,54 @@
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include <irssi/src/core/pidwait.h>
|
#include <irssi/src/core/network.h>
|
||||||
#include <irssi/src/core/net-nonblock.h>
|
#include <irssi/src/core/net-nonblock.h>
|
||||||
|
|
||||||
/* nonblocking gethostbyname(), ip (IPADDR) + error (int, 0 = not error) is
|
typedef struct {
|
||||||
written to pipe when found PID of the resolver child is returned */
|
NetGethostbynameContinuationFunc cont;
|
||||||
int net_gethostbyname_nonblock(const char *addr, GIOChannel *pipe, int reverse_lookup)
|
void *cont_data;
|
||||||
{
|
} NET_GETHOSTBYNAME_CALLBACK_DATA;
|
||||||
RESOLVED_IP_REC rec;
|
|
||||||
const char *errorstr;
|
|
||||||
int pid;
|
|
||||||
|
|
||||||
(void) reverse_lookup; /* Kept for API backward compatibility */
|
static void net_gethostbyname_callback(GResolver *resolver, GAsyncResult *result,
|
||||||
|
NET_GETHOSTBYNAME_CALLBACK_DATA *data)
|
||||||
|
{
|
||||||
|
/* GList<GInetAddress> */
|
||||||
|
GList *ailist;
|
||||||
|
GError *error;
|
||||||
|
RESOLVED_IP_REC *iprec;
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
ailist = g_resolver_lookup_by_name_with_flags_finish(resolver, result, &error);
|
||||||
|
iprec = g_new0(RESOLVED_IP_REC, 1);
|
||||||
|
if (error != NULL) {
|
||||||
|
iprec->error = error;
|
||||||
|
} else {
|
||||||
|
iprec->ailist = ailist;
|
||||||
|
}
|
||||||
|
g_object_unref(resolver);
|
||||||
|
resolved_ip_ref(iprec);
|
||||||
|
|
||||||
|
data->cont(iprec, data->cont_data);
|
||||||
|
g_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* nonblocking gethostbyname() */
|
||||||
|
GCancellable *net_gethostbyname_nonblock(const char *addr, GResolverNameLookupFlags flags,
|
||||||
|
NetGethostbynameContinuationFunc cont, void *cont_data)
|
||||||
|
{
|
||||||
|
GResolver *resolver;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
NET_GETHOSTBYNAME_CALLBACK_DATA *data;
|
||||||
|
|
||||||
g_return_val_if_fail(addr != NULL, FALSE);
|
g_return_val_if_fail(addr != NULL, FALSE);
|
||||||
|
|
||||||
pid = fork();
|
resolver = g_resolver_get_default();
|
||||||
if (pid > 0) {
|
cancellable = g_cancellable_new();
|
||||||
/* parent */
|
data = g_new0(NET_GETHOSTBYNAME_CALLBACK_DATA, 1);
|
||||||
pidwait_add(pid);
|
data->cont = cont;
|
||||||
return pid;
|
data->cont_data = cont_data;
|
||||||
}
|
g_resolver_lookup_by_name_with_flags_async(resolver, addr, flags, cancellable,
|
||||||
|
(GAsyncReadyCallback) net_gethostbyname_callback,
|
||||||
if (pid != 0) {
|
data);
|
||||||
/* failed! */
|
return cancellable;
|
||||||
g_warning("net_connect_thread(): fork() failed! "
|
|
||||||
"Using blocking resolving");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* child */
|
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
memset(&rec, 0, sizeof(rec));
|
|
||||||
rec.error = net_gethostbyname(addr, &rec.ip4, &rec.ip6);
|
|
||||||
if (rec.error == 0) {
|
|
||||||
errorstr = NULL;
|
|
||||||
} else {
|
|
||||||
errorstr = net_gethosterror(rec.error);
|
|
||||||
rec.errlen = errorstr == NULL ? 0 : strlen(errorstr)+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
i_io_channel_write_block(pipe, &rec, sizeof(rec));
|
|
||||||
if (rec.errlen != 0)
|
|
||||||
i_io_channel_write_block(pipe, (void *) errorstr, rec.errlen);
|
|
||||||
|
|
||||||
if (pid == 0)
|
|
||||||
_exit(99);
|
|
||||||
|
|
||||||
/* we used blocking lookup */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get the resolved IP address */
|
|
||||||
int net_gethostbyname_return(GIOChannel *pipe, RESOLVED_IP_REC *rec)
|
|
||||||
{
|
|
||||||
rec->error = -1;
|
|
||||||
rec->errorstr = NULL;
|
|
||||||
|
|
||||||
fcntl(g_io_channel_unix_get_fd(pipe), F_SETFL, O_NONBLOCK);
|
|
||||||
|
|
||||||
/* get ip+error */
|
|
||||||
if (i_io_channel_read_block(pipe, rec, sizeof(*rec)) == -1) {
|
|
||||||
rec->errorstr = g_strdup_printf("Host name lookup: %s",
|
|
||||||
g_strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rec->error) {
|
|
||||||
/* read error string, if we can't read everything for some
|
|
||||||
reason, just ignore it. */
|
|
||||||
rec->errorstr = g_malloc0(rec->errlen+1);
|
|
||||||
i_io_channel_read_block(pipe, rec->errorstr, rec->errlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Kill the resolver child */
|
|
||||||
void net_disconnect_nonblock(int pid)
|
|
||||||
{
|
|
||||||
g_return_if_fail(pid > 0);
|
|
||||||
|
|
||||||
kill(pid, SIGKILL);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,10 @@
|
||||||
|
|
||||||
#include <irssi/src/core/network.h>
|
#include <irssi/src/core/network.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef void (*NetGethostbynameContinuationFunc)(RESOLVED_IP_REC *, void *);
|
||||||
IPADDR ip4, ip6; /* resolved ip addresses */
|
|
||||||
int error; /* error, 0 = no error, -1 = error: */
|
|
||||||
int errlen; /* error text length */
|
|
||||||
char *errorstr; /* error string - dynamically allocated, you'll
|
|
||||||
need to free() it yourself unless it's NULL */
|
|
||||||
} RESOLVED_IP_REC;
|
|
||||||
|
|
||||||
/* nonblocking gethostbyname(), PID of the resolver child is returned. */
|
/* nonblocking gethostbyname(), Cancellable of the resolver child is returned. */
|
||||||
int net_gethostbyname_nonblock(const char *addr, GIOChannel *pipe, int reverse_lookup);
|
GCancellable *net_gethostbyname_nonblock(const char *addr, GResolverNameLookupFlags flags,
|
||||||
/* get the resolved IP address. returns -1 if some error occurred with read() */
|
NetGethostbynameContinuationFunc cont, void *cont_data);
|
||||||
int net_gethostbyname_return(GIOChannel *pipe, RESOLVED_IP_REC *rec);
|
|
||||||
|
|
||||||
/* Kill the resolver child */
|
|
||||||
void net_disconnect_nonblock(int pid);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -81,27 +81,6 @@ int i_io_channel_read_block(GIOChannel *channel, void *data, int len)
|
||||||
return received < len ? -1 : 0;
|
return received < len ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPADDR ip4_any = {
|
|
||||||
AF_INET,
|
|
||||||
#if defined(IN6ADDR_ANY_INIT)
|
|
||||||
IN6ADDR_ANY_INIT
|
|
||||||
#else
|
|
||||||
{ INADDR_ANY }
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
int net_ip_compare(IPADDR *ip1, IPADDR *ip2)
|
|
||||||
{
|
|
||||||
if (ip1->family != ip2->family)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (ip1->family == AF_INET6)
|
|
||||||
return memcmp(&ip1->ip, &ip2->ip, sizeof(ip1->ip)) == 0;
|
|
||||||
|
|
||||||
return memcmp(&ip1->ip, &ip2->ip, 4) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void sin_set_ip(union sockaddr_union *so, const IPADDR *ip)
|
static void sin_set_ip(union sockaddr_union *so, const IPADDR *ip)
|
||||||
{
|
{
|
||||||
if (ip == NULL) {
|
if (ip == NULL) {
|
||||||
|
|
@ -392,95 +371,87 @@ int net_getsockname(GIOChannel *handle, IPADDR *addr, int *port)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get IP addresses for host, both IPv4 and IPv6 if possible.
|
void resolved_ip_ref(RESOLVED_IP_REC *iprec)
|
||||||
If ip->family is 0, the address wasn't found.
|
|
||||||
Returns 0 = ok, others = error code for net_gethosterror() */
|
|
||||||
int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6)
|
|
||||||
{
|
{
|
||||||
union sockaddr_union *so;
|
iprec->refcount++;
|
||||||
struct addrinfo hints, *ai, *ailist;
|
}
|
||||||
int ret, count_v4, count_v6, use_v4, use_v6;
|
|
||||||
|
int resolved_ip_unref(RESOLVED_IP_REC *iprec)
|
||||||
|
{
|
||||||
|
if (--iprec->refcount > 0) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_resolver_free_addresses(iprec->ailist);
|
||||||
|
if (iprec->error != NULL) {
|
||||||
|
g_error_free(iprec->error);
|
||||||
|
}
|
||||||
|
g_free(iprec);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get IP addresses for host, both IPv4 and IPv6 if possible. */
|
||||||
|
static RESOLVED_IP_REC *net_gethostbyname(const char *addr, GResolverNameLookupFlags flags)
|
||||||
|
{
|
||||||
|
/* GList<GInetAddress> */
|
||||||
|
GList *ailist;
|
||||||
|
GError *error;
|
||||||
|
GResolver *resolver;
|
||||||
|
RESOLVED_IP_REC *iprec;
|
||||||
|
|
||||||
#ifdef HAVE_CAPSICUM
|
#ifdef HAVE_CAPSICUM
|
||||||
if (capsicum_enabled())
|
if (capsicum_enabled())
|
||||||
return (capsicum_net_gethostbyname(addr, ip4, ip6));
|
return (capsicum_net_gethostbyname(addr, flags));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
g_return_val_if_fail(addr != NULL, -1);
|
g_return_val_if_fail(addr != NULL, NULL);
|
||||||
|
|
||||||
memset(ip4, 0, sizeof(IPADDR));
|
error = NULL;
|
||||||
memset(ip6, 0, sizeof(IPADDR));
|
resolver = g_resolver_get_default();
|
||||||
|
ailist = g_resolver_lookup_by_name_with_flags(resolver, addr, flags, NULL, &error);
|
||||||
memset(&hints, 0, sizeof(struct addrinfo));
|
iprec = g_new0(RESOLVED_IP_REC, 1);
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
if (error != NULL) {
|
||||||
hints.ai_flags = AI_ADDRCONFIG;
|
iprec->error = error;
|
||||||
|
} else {
|
||||||
/* save error to host_error for later use */
|
iprec->ailist = ailist;
|
||||||
ret = getaddrinfo(addr, NULL, &hints, &ailist);
|
|
||||||
if (ret != 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* count IPs */
|
|
||||||
count_v4 = count_v6 = 0;
|
|
||||||
for (ai = ailist; ai != NULL; ai = ai->ai_next) {
|
|
||||||
if (ai->ai_family == AF_INET)
|
|
||||||
count_v4++;
|
|
||||||
else if (ai->ai_family == AF_INET6)
|
|
||||||
count_v6++;
|
|
||||||
}
|
}
|
||||||
|
g_object_unref(resolver);
|
||||||
|
resolved_ip_ref(iprec);
|
||||||
|
|
||||||
if (count_v4 == 0 && count_v6 == 0)
|
return iprec;
|
||||||
return EAI_NONAME; /* shouldn't happen? */
|
|
||||||
|
|
||||||
/* if there are multiple addresses, return random one */
|
|
||||||
use_v4 = count_v4 <= 1 ? 0 : rand() % count_v4;
|
|
||||||
use_v6 = count_v6 <= 1 ? 0 : rand() % count_v6;
|
|
||||||
|
|
||||||
count_v4 = count_v6 = 0;
|
|
||||||
for (ai = ailist; ai != NULL; ai = ai->ai_next) {
|
|
||||||
so = (union sockaddr_union *) ai->ai_addr;
|
|
||||||
|
|
||||||
if (ai->ai_family == AF_INET) {
|
|
||||||
if (use_v4 == count_v4)
|
|
||||||
sin_get_ip(so, ip4);
|
|
||||||
count_v4++;
|
|
||||||
} else if (ai->ai_family == AF_INET6) {
|
|
||||||
if (use_v6 == count_v6)
|
|
||||||
sin_get_ip(so, ip6);
|
|
||||||
count_v6++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
freeaddrinfo(ailist);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get name for host, *name should be g_free()'d unless it's NULL.
|
int net_gethostbyname_first_ips(const char *addr, GResolverNameLookupFlags flags, IPADDR *ip4,
|
||||||
Return values are the same as with net_gethostbyname() */
|
IPADDR *ip6)
|
||||||
int net_gethostbyaddr(IPADDR *ip, char **name)
|
|
||||||
{
|
{
|
||||||
union sockaddr_union so;
|
RESOLVED_IP_REC *iprec;
|
||||||
int host_error;
|
|
||||||
char hostname[NI_MAXHOST];
|
|
||||||
|
|
||||||
g_return_val_if_fail(ip != NULL, -1);
|
iprec = net_gethostbyname(addr, flags);
|
||||||
g_return_val_if_fail(name != NULL, -1);
|
if (iprec->error == NULL) {
|
||||||
|
GList *curr;
|
||||||
|
|
||||||
*name = NULL;
|
for (curr = iprec->ailist; curr->next; curr = curr->next) {
|
||||||
|
unsigned short family;
|
||||||
|
GInetAddress *addr;
|
||||||
|
|
||||||
memset(&so, 0, sizeof(so));
|
addr = curr->data;
|
||||||
sin_set_ip(&so, ip);
|
family = g_inet_address_get_family(addr);
|
||||||
|
if (ip4->family == 0 && family == AF_INET) {
|
||||||
|
ip4->family = AF_INET;
|
||||||
|
memcpy(&ip4->ip, g_inet_address_to_bytes(addr), sizeof(ip4->ip));
|
||||||
|
} else if (ip6->family == 0 && family == AF_INET6) {
|
||||||
|
ip6->family = AF_INET6;
|
||||||
|
memcpy(&ip6->ip, g_inet_address_to_bytes(addr), sizeof(ip6->ip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* save error to host_error for later use */
|
resolved_ip_unref(iprec);
|
||||||
host_error = getnameinfo((struct sockaddr *)&so, sizeof(so),
|
return 0;
|
||||||
hostname, sizeof(hostname),
|
} else {
|
||||||
NULL, 0,
|
resolved_ip_unref(iprec);
|
||||||
NI_NAMEREQD);
|
return -1;
|
||||||
if (host_error != 0)
|
}
|
||||||
return host_error;
|
|
||||||
|
|
||||||
*name = g_strdup(hostname);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int net_ip2host(IPADDR *ip, char *host)
|
int net_ip2host(IPADDR *ip, char *host)
|
||||||
|
|
@ -519,29 +490,6 @@ int net_geterror(GIOChannel *handle)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get error of net_gethostname() */
|
|
||||||
const char *net_gethosterror(int error)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(error != 0, NULL);
|
|
||||||
|
|
||||||
if (error == EAI_SYSTEM) {
|
|
||||||
return strerror(errno);
|
|
||||||
} else {
|
|
||||||
return gai_strerror(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return TRUE if host lookup failed because it didn't exist (ie. not
|
|
||||||
some error with name server) */
|
|
||||||
int net_hosterror_notfound(int error)
|
|
||||||
{
|
|
||||||
#ifdef EAI_NODATA /* NODATA is deprecated */
|
|
||||||
return error != 1 && (error == EAI_NONAME || error == EAI_NODATA);
|
|
||||||
#else
|
|
||||||
return error != 1 && (error == EAI_NONAME);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get name of TCP service */
|
/* Get name of TCP service */
|
||||||
char *net_getservbyport(int port)
|
char *net_getservbyport(int port)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <irssi/src/common.h>
|
||||||
|
|
||||||
#ifndef AF_INET6
|
#ifndef AF_INET6
|
||||||
# ifdef PF_INET6
|
# ifdef PF_INET6
|
||||||
|
|
@ -20,6 +21,13 @@ struct _IPADDR {
|
||||||
struct in6_addr ip;
|
struct in6_addr ip;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int refcount;
|
||||||
|
/* GList<GInetAddress> */
|
||||||
|
GList *ailist; /* needs to be freed */
|
||||||
|
GError *error; /* needs to be freed */
|
||||||
|
} RESOLVED_IP_REC;
|
||||||
|
|
||||||
/* maxmimum string length of IP address */
|
/* maxmimum string length of IP address */
|
||||||
#define MAX_IP_LEN INET6_ADDRSTRLEN
|
#define MAX_IP_LEN INET6_ADDRSTRLEN
|
||||||
|
|
||||||
|
|
@ -29,9 +37,7 @@ extern IPADDR ip4_any;
|
||||||
|
|
||||||
GIOChannel *i_io_channel_new(int handle);
|
GIOChannel *i_io_channel_new(int handle);
|
||||||
|
|
||||||
/* Returns 1 if IPADDRs are the same. */
|
/* OTR */
|
||||||
/* Deprecated since it is unused. It will be deleted in a later release. */
|
|
||||||
int net_ip_compare(IPADDR *ip1, IPADDR *ip2) G_GNUC_DEPRECATED;
|
|
||||||
int i_io_channel_write_block(GIOChannel *channel, void *data, int len);
|
int i_io_channel_write_block(GIOChannel *channel, void *data, int len);
|
||||||
int i_io_channel_read_block(GIOChannel *channel, void *data, int len);
|
int i_io_channel_read_block(GIOChannel *channel, void *data, int len);
|
||||||
|
|
||||||
|
|
@ -60,18 +66,9 @@ int net_receive(GIOChannel *handle, char *buf, int len);
|
||||||
/* Transmit data, return number of bytes sent, -1 = error */
|
/* Transmit data, return number of bytes sent, -1 = error */
|
||||||
int net_transmit(GIOChannel *handle, const char *data, int len);
|
int net_transmit(GIOChannel *handle, const char *data, int len);
|
||||||
|
|
||||||
/* Get IP addresses for host, both IPv4 and IPv6 if possible.
|
/* Get the first IP address for host, both IPv4 and IPv6 if possible. */
|
||||||
If ip->family is 0, the address wasn't found.
|
int net_gethostbyname_first_ips(const char *addr, GResolverNameLookupFlags flags, IPADDR *ip4,
|
||||||
Returns 0 = ok, others = error code for net_gethosterror() */
|
IPADDR *ip6);
|
||||||
int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6);
|
|
||||||
/* 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);
|
|
||||||
/* get error of net_gethostname() */
|
|
||||||
const char *net_gethosterror(int error);
|
|
||||||
/* return TRUE if host lookup failed because it didn't exist (ie. not
|
|
||||||
some error with name server) */
|
|
||||||
int net_hosterror_notfound(int error);
|
|
||||||
|
|
||||||
/* Get socket address/port */
|
/* Get socket address/port */
|
||||||
int net_getsockname(GIOChannel *handle, IPADDR *addr, int *port);
|
int net_getsockname(GIOChannel *handle, IPADDR *addr, int *port);
|
||||||
|
|
@ -90,4 +87,7 @@ char *net_getservbyport(int port);
|
||||||
int is_ipv4_address(const char *host);
|
int is_ipv4_address(const char *host);
|
||||||
int is_ipv6_address(const char *host);
|
int is_ipv6_address(const char *host);
|
||||||
|
|
||||||
|
void resolved_ip_ref(RESOLVED_IP_REC *iprec);
|
||||||
|
int resolved_ip_unref(RESOLVED_IP_REC *iprec);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ unsigned int unix_socket:1; /* Connect using named unix socket */
|
||||||
unsigned int use_tls:1; /* this connection uses TLS */
|
unsigned int use_tls:1; /* this connection uses TLS */
|
||||||
unsigned int tls_verify:1;
|
unsigned int tls_verify:1;
|
||||||
unsigned int no_connect:1; /* don't connect() at all, it's done by plugin */
|
unsigned int no_connect:1; /* don't connect() at all, it's done by plugin */
|
||||||
unsigned short last_failed_family; /* #641: if we failed to connect to ipv6, try ipv4 and vice versa */
|
int last_connected;
|
||||||
|
int last_failed;
|
||||||
|
RESOLVED_IP_REC *resolved_host;
|
||||||
char *channels;
|
char *channels;
|
||||||
char *away_reason;
|
char *away_reason;
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,8 @@ unsigned int no_reconnect:1; /* Don't reconnect to server */
|
||||||
NET_SENDBUF_REC *handle;
|
NET_SENDBUF_REC *handle;
|
||||||
int readtag; /* input tag */
|
int readtag; /* input tag */
|
||||||
|
|
||||||
/* for net_gethostbyname_return() */
|
GCancellable *connect_cancellable;
|
||||||
GIOChannel *connect_pipe[2];
|
|
||||||
int connect_tag;
|
int connect_tag;
|
||||||
int connect_pid;
|
|
||||||
|
|
||||||
RAWLOG_REC *rawlog;
|
RAWLOG_REC *rawlog;
|
||||||
GHashTable *module_data;
|
GHashTable *module_data;
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,10 @@ static int server_reconnect_timeout(void)
|
||||||
if (server->connect_tag != -1) {
|
if (server->connect_tag != -1) {
|
||||||
g_source_remove(server->connect_tag);
|
g_source_remove(server->connect_tag);
|
||||||
server->connect_tag = -1;
|
server->connect_tag = -1;
|
||||||
|
} else if (server->connect_cancellable != NULL) {
|
||||||
|
g_cancellable_cancel(server->connect_cancellable);
|
||||||
|
g_object_unref(server->connect_cancellable);
|
||||||
|
server->connect_cancellable = NULL;
|
||||||
}
|
}
|
||||||
server->connection_lost = TRUE;
|
server->connection_lost = TRUE;
|
||||||
server_connect_failed(server, "Timeout");
|
server_connect_failed(server, "Timeout");
|
||||||
|
|
@ -168,7 +172,8 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info)
|
||||||
server_connect_ref(dest);
|
server_connect_ref(dest);
|
||||||
dest->type = module_get_uniq_id("SERVER CONNECT", 0);
|
dest->type = module_get_uniq_id("SERVER CONNECT", 0);
|
||||||
dest->reconnection = src->reconnection;
|
dest->reconnection = src->reconnection;
|
||||||
dest->last_failed_family = src->last_failed_family;
|
dest->last_connected = src->last_connected;
|
||||||
|
dest->last_failed = src->last_failed;
|
||||||
dest->proxy = g_strdup(src->proxy);
|
dest->proxy = g_strdup(src->proxy);
|
||||||
dest->proxy_port = src->proxy_port;
|
dest->proxy_port = src->proxy_port;
|
||||||
dest->proxy_string = g_strdup(src->proxy_string);
|
dest->proxy_string = g_strdup(src->proxy_string);
|
||||||
|
|
@ -207,6 +212,10 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info)
|
||||||
dest->own_ip6 = g_new(IPADDR, 1);
|
dest->own_ip6 = g_new(IPADDR, 1);
|
||||||
memcpy(dest->own_ip6, src->own_ip6, sizeof(IPADDR));
|
memcpy(dest->own_ip6, src->own_ip6, sizeof(IPADDR));
|
||||||
}
|
}
|
||||||
|
dest->resolved_host = src->resolved_host;
|
||||||
|
if (dest->resolved_host != NULL) {
|
||||||
|
resolved_ip_ref(dest->resolved_host);
|
||||||
|
}
|
||||||
|
|
||||||
dest->channels = g_strdup(src->channels);
|
dest->channels = g_strdup(src->channels);
|
||||||
dest->away_reason = g_strdup(src->away_reason);
|
dest->away_reason = g_strdup(src->away_reason);
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,8 @@ static void save_ips(IPADDR *ip4, IPADDR *ip6,
|
||||||
static void get_source_host_ip(void)
|
static void get_source_host_ip(void)
|
||||||
{
|
{
|
||||||
const char *hostname;
|
const char *hostname;
|
||||||
IPADDR ip4, ip6;
|
IPADDR ip4 = { 0 };
|
||||||
|
IPADDR ip6 = { 0 };
|
||||||
|
|
||||||
if (source_host_ok)
|
if (source_host_ok)
|
||||||
return;
|
return;
|
||||||
|
|
@ -66,7 +67,8 @@ static void get_source_host_ip(void)
|
||||||
/* FIXME: This will block! */
|
/* FIXME: This will block! */
|
||||||
hostname = settings_get_str("hostname");
|
hostname = settings_get_str("hostname");
|
||||||
source_host_ok = *hostname != '\0' &&
|
source_host_ok = *hostname != '\0' &&
|
||||||
net_gethostbyname(hostname, &ip4, &ip6) == 0;
|
net_gethostbyname_first_ips(hostname, G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT,
|
||||||
|
&ip4, &ip6) == 0;
|
||||||
|
|
||||||
if (source_host_ok)
|
if (source_host_ok)
|
||||||
save_ips(&ip4, &ip6, &source_host_ip4, &source_host_ip6);
|
save_ips(&ip4, &ip6, &source_host_ip4, &source_host_ip6);
|
||||||
|
|
@ -79,12 +81,14 @@ static void get_source_host_ip(void)
|
||||||
static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host,
|
static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host,
|
||||||
IPADDR **own_ip4, IPADDR **own_ip6)
|
IPADDR **own_ip4, IPADDR **own_ip6)
|
||||||
{
|
{
|
||||||
IPADDR ip4, ip6;
|
IPADDR ip4 = { 0 };
|
||||||
|
IPADDR ip6 = { 0 };
|
||||||
|
|
||||||
if (*own_ip4 == NULL && *own_ip6 == NULL) {
|
if (*own_ip4 == NULL && *own_ip6 == NULL) {
|
||||||
/* resolve the IP */
|
/* resolve the IP */
|
||||||
if (net_gethostbyname(own_host, &ip4, &ip6) == 0)
|
if (net_gethostbyname_first_ips(own_host, G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT,
|
||||||
save_ips(&ip4, &ip6, own_ip4, own_ip6);
|
&ip4, &ip6) == 0)
|
||||||
|
save_ips(&ip4, &ip6, own_ip4, own_ip6);
|
||||||
}
|
}
|
||||||
|
|
||||||
server_connect_own_ip_save(conn, *own_ip4, *own_ip6);
|
server_connect_own_ip_save(conn, *own_ip4, *own_ip6);
|
||||||
|
|
|
||||||
|
|
@ -51,20 +51,16 @@ void server_connect_failed(SERVER_REC *server, const char *msg)
|
||||||
g_source_remove(server->connect_tag);
|
g_source_remove(server->connect_tag);
|
||||||
server->connect_tag = -1;
|
server->connect_tag = -1;
|
||||||
}
|
}
|
||||||
|
if (server->connect_cancellable != NULL) {
|
||||||
|
g_cancellable_cancel(server->connect_cancellable);
|
||||||
|
g_object_unref(server->connect_cancellable);
|
||||||
|
server->connect_cancellable = NULL;
|
||||||
|
}
|
||||||
if (server->handle != NULL) {
|
if (server->handle != NULL) {
|
||||||
net_sendbuffer_destroy(server->handle, TRUE);
|
net_sendbuffer_destroy(server->handle, TRUE);
|
||||||
server->handle = NULL;
|
server->handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server->connect_pipe[0] != NULL) {
|
|
||||||
g_io_channel_shutdown(server->connect_pipe[0], TRUE, NULL);
|
|
||||||
g_io_channel_unref(server->connect_pipe[0]);
|
|
||||||
g_io_channel_shutdown(server->connect_pipe[1], TRUE, NULL);
|
|
||||||
g_io_channel_unref(server->connect_pipe[1]);
|
|
||||||
server->connect_pipe[0] = NULL;
|
|
||||||
server->connect_pipe[1] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
server_unref(server);
|
server_unref(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,7 +152,7 @@ static void server_connect_callback_init(SERVER_REC *server, GIOChannel *handle)
|
||||||
error = net_geterror(handle);
|
error = net_geterror(handle);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
server->connection_lost = TRUE;
|
server->connection_lost = TRUE;
|
||||||
server->connrec->last_failed_family = server->connrec->chosen_family;
|
server->connrec->last_failed = server->connrec->last_connected;
|
||||||
server_connect_failed(server, g_strerror(error));
|
server_connect_failed(server, g_strerror(error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +173,7 @@ static void server_connect_callback_init_ssl(SERVER_REC *server, GIOChannel *han
|
||||||
error = irssi_ssl_handshake(handle);
|
error = irssi_ssl_handshake(handle);
|
||||||
if (error == -1) {
|
if (error == -1) {
|
||||||
server->connection_lost = TRUE;
|
server->connection_lost = TRUE;
|
||||||
server->connrec->last_failed_family = server->connrec->chosen_family;
|
server->connrec->last_failed = server->connrec->last_connected;
|
||||||
server_connect_failed(server, NULL);
|
server_connect_failed(server, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -259,12 +255,12 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip,
|
||||||
|
|
||||||
server->connection_lost = TRUE;
|
server->connection_lost = TRUE;
|
||||||
if (ip != NULL) {
|
if (ip != NULL) {
|
||||||
server->connrec->last_failed_family = ip->family;
|
server->connrec->last_failed = server->connrec->last_connected;
|
||||||
}
|
}
|
||||||
server_connect_failed(server, errmsg2 ? errmsg2 : errmsg);
|
server_connect_failed(server, errmsg2 ? errmsg2 : errmsg);
|
||||||
g_free(errmsg2);
|
g_free(errmsg2);
|
||||||
} else {
|
} else {
|
||||||
server->connrec->last_failed_family = 0;
|
server->connrec->last_failed = 0;
|
||||||
if (!server->connrec->use_tls)
|
if (!server->connrec->use_tls)
|
||||||
server->handle = net_sendbuffer_create(handle, 0);
|
server->handle = net_sendbuffer_create(handle, 0);
|
||||||
if (server->connrec->use_tls)
|
if (server->connrec->use_tls)
|
||||||
|
|
@ -276,48 +272,47 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_connect_callback_readpipe(SERVER_REC *server)
|
static int server_start_connect_resolve(SERVER_REC *server);
|
||||||
|
|
||||||
|
static void server_connect_use_resolved(SERVER_REC *server)
|
||||||
{
|
{
|
||||||
RESOLVED_IP_REC iprec;
|
IPADDR *ip;
|
||||||
IPADDR *ip;
|
|
||||||
const char *errormsg;
|
const char *errormsg;
|
||||||
|
RESOLVED_IP_REC *iprec = server->connrec->resolved_host;
|
||||||
|
|
||||||
g_source_remove(server->connect_tag);
|
if (iprec->error != NULL) {
|
||||||
server->connect_tag = -1;
|
/* error */
|
||||||
|
|
||||||
net_gethostbyname_return(server->connect_pipe[0], &iprec);
|
|
||||||
|
|
||||||
g_io_channel_shutdown(server->connect_pipe[0], TRUE, NULL);
|
|
||||||
g_io_channel_unref(server->connect_pipe[0]);
|
|
||||||
g_io_channel_shutdown(server->connect_pipe[1], TRUE, NULL);
|
|
||||||
g_io_channel_unref(server->connect_pipe[1]);
|
|
||||||
|
|
||||||
server->connect_pipe[0] = NULL;
|
|
||||||
server->connect_pipe[1] = NULL;
|
|
||||||
|
|
||||||
/* figure out if we should use IPv4 or v6 address */
|
|
||||||
if (iprec.error != 0) {
|
|
||||||
/* error */
|
|
||||||
ip = NULL;
|
ip = NULL;
|
||||||
} else if (server->connrec->family == AF_INET) {
|
|
||||||
/* force IPv4 connection */
|
|
||||||
ip = iprec.ip4.family == 0 ? NULL : &iprec.ip4;
|
|
||||||
} else if (server->connrec->family == AF_INET6) {
|
|
||||||
/* force IPv6 connection */
|
|
||||||
ip = iprec.ip6.family == 0 ? NULL : &iprec.ip6;
|
|
||||||
} else {
|
} else {
|
||||||
/* pick the one that was found. if both were found:
|
GList *curr;
|
||||||
1. disprefer the last one that failed
|
int i;
|
||||||
2. prefer ipv4 over ipv6 unless resolve_prefer_ipv6 is set
|
|
||||||
*/
|
curr = iprec->ailist;
|
||||||
if (iprec.ip4.family == 0 ||
|
i = 0;
|
||||||
(iprec.ip6.family != 0 &&
|
while (i < server->connrec->last_failed) {
|
||||||
(server->connrec->last_failed_family == AF_INET ||
|
if (curr != NULL) {
|
||||||
(settings_get_bool("resolve_prefer_ipv6") &&
|
curr = curr->next;
|
||||||
server->connrec->last_failed_family != AF_INET6)))) {
|
i++;
|
||||||
ip = &iprec.ip6;
|
}
|
||||||
|
/* curr is different now */
|
||||||
|
if (curr == NULL) {
|
||||||
|
resolved_ip_unref(server->connrec->resolved_host);
|
||||||
|
server->connrec->resolved_host = NULL;
|
||||||
|
server->connrec->last_failed = 0;
|
||||||
|
/* retry resolve */
|
||||||
|
server_start_connect_resolve(server);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (curr != NULL) {
|
||||||
|
GInetAddress *addr;
|
||||||
|
addr = curr->data;
|
||||||
|
server->connrec->last_connected = i + 1;
|
||||||
|
ip = g_new0(IPADDR, 1);
|
||||||
|
ip->family = g_inet_address_get_family(addr);
|
||||||
|
memcpy(&ip->ip, g_inet_address_to_bytes(addr), sizeof(ip->ip));
|
||||||
} else {
|
} else {
|
||||||
ip = &iprec.ip4;
|
ip = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,28 +321,63 @@ static void server_connect_callback_readpipe(SERVER_REC *server)
|
||||||
server_real_connect(server, ip, NULL);
|
server_real_connect(server, ip, NULL);
|
||||||
errormsg = NULL;
|
errormsg = NULL;
|
||||||
} else {
|
} else {
|
||||||
if (iprec.error == 0 || net_hosterror_notfound(iprec.error)) {
|
if (iprec->error->code == G_RESOLVER_ERROR_NOT_FOUND) {
|
||||||
/* IP wasn't found for the host, don't try to
|
/* IP wasn't found for the host, don't try to
|
||||||
reconnect back to this server */
|
reconnect back to this server */
|
||||||
server->dns_error = TRUE;
|
server->dns_error = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iprec.error == 0) {
|
errormsg = iprec->error->message;
|
||||||
/* forced IPv4 or IPv6 address but it wasn't found */
|
if (errormsg == NULL)
|
||||||
errormsg = server->connrec->family == AF_INET ?
|
errormsg = "Host lookup failed";
|
||||||
"IPv4 address not found for host" :
|
|
||||||
"IPv6 address not found for host";
|
|
||||||
} else {
|
|
||||||
/* gethostbyname() failed */
|
|
||||||
errormsg = iprec.errorstr != NULL ? iprec.errorstr :
|
|
||||||
"Host lookup failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
server->connection_lost = TRUE;
|
server->connection_lost = TRUE;
|
||||||
|
/* clear the error in resolved_host */
|
||||||
|
server->connrec->resolved_host = NULL;
|
||||||
server_connect_failed(server, errormsg);
|
server_connect_failed(server, errormsg);
|
||||||
}
|
|
||||||
|
|
||||||
g_free(iprec.errorstr);
|
resolved_ip_unref(iprec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void server_connect_callback_resolved(RESOLVED_IP_REC *iprec, SERVER_REC *server)
|
||||||
|
{
|
||||||
|
server->connect_cancellable = NULL;
|
||||||
|
|
||||||
|
if (server->connrec->resolved_host != NULL) {
|
||||||
|
resolved_ip_unref(server->connrec->resolved_host);
|
||||||
|
}
|
||||||
|
server->connrec->resolved_host = iprec;
|
||||||
|
if (iprec->error == NULL && iprec->ailist == NULL) {
|
||||||
|
server->connection_lost = TRUE;
|
||||||
|
server->dns_error = TRUE;
|
||||||
|
server_connect_failed(server, "Host lookup failed");
|
||||||
|
} else {
|
||||||
|
server_connect_use_resolved(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int server_start_connect_resolve(SERVER_REC *server)
|
||||||
|
{
|
||||||
|
const char *connect_address;
|
||||||
|
GResolverNameLookupFlags net_gethostbyname_flags;
|
||||||
|
|
||||||
|
connect_address =
|
||||||
|
server->connrec->proxy != NULL ? server->connrec->proxy : server->connrec->address;
|
||||||
|
net_gethostbyname_flags = G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT;
|
||||||
|
if (server->connrec->family == AF_INET) {
|
||||||
|
net_gethostbyname_flags = G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY;
|
||||||
|
} else if (server->connrec->family == AF_INET6) {
|
||||||
|
net_gethostbyname_flags = G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY;
|
||||||
|
}
|
||||||
|
if (server->connrec->resolved_host == NULL) {
|
||||||
|
server->connect_cancellable = net_gethostbyname_nonblock(
|
||||||
|
connect_address, net_gethostbyname_flags,
|
||||||
|
(NetGethostbynameContinuationFunc) server_connect_callback_resolved, server);
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SERVER_REC *server_connect(SERVER_CONNECT_REC *conn)
|
SERVER_REC *server_connect(SERVER_CONNECT_REC *conn)
|
||||||
|
|
@ -399,9 +429,6 @@ void server_connect_init(SERVER_REC *server)
|
||||||
/* starts connecting to server */
|
/* starts connecting to server */
|
||||||
int server_start_connect(SERVER_REC *server)
|
int server_start_connect(SERVER_REC *server)
|
||||||
{
|
{
|
||||||
const char *connect_address;
|
|
||||||
int fd[2];
|
|
||||||
|
|
||||||
g_return_val_if_fail(server != NULL, FALSE);
|
g_return_val_if_fail(server != NULL, FALSE);
|
||||||
if (!server->connrec->unix_socket && server->connrec->port <= 0)
|
if (!server->connrec->unix_socket && server->connrec->port <= 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
@ -419,30 +446,17 @@ int server_start_connect(SERVER_REC *server)
|
||||||
/* connect with unix socket */
|
/* connect with unix socket */
|
||||||
server_real_connect(server, NULL, server->connrec->address);
|
server_real_connect(server, NULL, server->connrec->address);
|
||||||
} else {
|
} else {
|
||||||
|
int already_resolved;
|
||||||
/* resolve host name */
|
/* resolve host name */
|
||||||
if (pipe(fd) != 0) {
|
already_resolved = server_start_connect_resolve(server);
|
||||||
g_warning("server_connect(): pipe() failed.");
|
|
||||||
g_free(server->tag);
|
|
||||||
g_free(server->nick);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
server->connect_pipe[0] = i_io_channel_new(fd[0]);
|
|
||||||
server->connect_pipe[1] = i_io_channel_new(fd[1]);
|
|
||||||
|
|
||||||
connect_address = server->connrec->proxy != NULL ?
|
|
||||||
server->connrec->proxy : server->connrec->address;
|
|
||||||
server->connect_pid =
|
|
||||||
net_gethostbyname_nonblock(connect_address,
|
|
||||||
server->connect_pipe[1], 0);
|
|
||||||
server->connect_tag =
|
|
||||||
i_input_add(server->connect_pipe[0], I_INPUT_READ,
|
|
||||||
(GInputFunction) server_connect_callback_readpipe, server);
|
|
||||||
|
|
||||||
server->connect_time = time(NULL);
|
server->connect_time = time(NULL);
|
||||||
lookup_servers = g_slist_append(lookup_servers, server);
|
lookup_servers = g_slist_append(lookup_servers, server);
|
||||||
|
|
||||||
signal_emit("server looking", 1, server);
|
signal_emit("server looking", 1, server);
|
||||||
|
if (already_resolved) {
|
||||||
|
server_connect_use_resolved(server);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -481,8 +495,9 @@ void server_disconnect(SERVER_REC *server)
|
||||||
|
|
||||||
if (server->connect_tag != -1) {
|
if (server->connect_tag != -1) {
|
||||||
/* still connecting to server.. */
|
/* still connecting to server.. */
|
||||||
if (server->connect_pid != -1)
|
server_connect_failed(server, NULL);
|
||||||
net_disconnect_nonblock(server->connect_pid);
|
return;
|
||||||
|
} else if (server->connect_cancellable != NULL) {
|
||||||
server_connect_failed(server, NULL);
|
server_connect_failed(server, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -649,6 +664,10 @@ void server_connect_unref(SERVER_CONNECT_REC *conn)
|
||||||
g_free_not_null(conn->own_ip4);
|
g_free_not_null(conn->own_ip4);
|
||||||
g_free_not_null(conn->own_ip6);
|
g_free_not_null(conn->own_ip6);
|
||||||
|
|
||||||
|
if (conn->resolved_host != NULL) {
|
||||||
|
resolved_ip_unref(conn->resolved_host);
|
||||||
|
}
|
||||||
|
|
||||||
g_free_not_null(conn->password);
|
g_free_not_null(conn->password);
|
||||||
g_free_not_null(conn->nick);
|
g_free_not_null(conn->nick);
|
||||||
g_free_not_null(conn->username);
|
g_free_not_null(conn->username);
|
||||||
|
|
@ -769,7 +788,6 @@ static void sig_chat_protocol_deinit(CHAT_PROTOCOL_REC *proto)
|
||||||
|
|
||||||
void servers_init(void)
|
void servers_init(void)
|
||||||
{
|
{
|
||||||
settings_add_bool("server", "resolve_prefer_ipv6", TRUE);
|
|
||||||
lookup_servers = servers = NULL;
|
lookup_servers = servers = NULL;
|
||||||
|
|
||||||
signal_add("chat protocol deinit", (SIGNAL_FUNC) sig_chat_protocol_deinit);
|
signal_add("chat protocol deinit", (SIGNAL_FUNC) sig_chat_protocol_deinit);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#define IRSSI_CORE_SERVERS_H
|
#define IRSSI_CORE_SERVERS_H
|
||||||
|
|
||||||
#include <irssi/src/core/modules.h>
|
#include <irssi/src/core/modules.h>
|
||||||
|
#include <irssi/src/core/network.h>
|
||||||
|
|
||||||
/* Returns SERVER_REC if it's server, NULL if it isn't. */
|
/* Returns SERVER_REC if it's server, NULL if it isn't. */
|
||||||
#define SERVER(server) \
|
#define SERVER(server) \
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ void fe_common_core_init(void)
|
||||||
settings_add_bool("lookandfeel", "use_msgs_window", FALSE);
|
settings_add_bool("lookandfeel", "use_msgs_window", FALSE);
|
||||||
g_get_charset(&str);
|
g_get_charset(&str);
|
||||||
settings_add_str("lookandfeel", "term_charset", str);
|
settings_add_str("lookandfeel", "term_charset", str);
|
||||||
settings_add_str("lookandfeel", "glib_log_domains", "all");
|
settings_add_str("lookandfeel", "glib_log_domains", "all -glib-gio:debug");
|
||||||
themes_init();
|
themes_init();
|
||||||
theme_register(fecommon_core_formats);
|
theme_register(fecommon_core_formats);
|
||||||
|
|
||||||
|
|
@ -258,13 +258,19 @@ void fe_common_core_deinit(void)
|
||||||
g_log_set_default_handler(logger_old, NULL);
|
g_log_set_default_handler(logger_old, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean glib_domain_wanted(const char *domain)
|
static gboolean glib_domain_wanted(const char *domain, const char *level)
|
||||||
{
|
{
|
||||||
const char *domains;
|
const char *domains;
|
||||||
char *c, *cur;
|
char *c, *cur;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int print_it = 0; /* -1 for exclude, 0 for undecided, 1 for include */
|
int print_it = 0; /* -1 for exclude, 0 for undecided, 1 for include */
|
||||||
int incl;
|
int incl;
|
||||||
|
char *domainlevel, *alllevel, *starlevel, *domainstar;
|
||||||
|
|
||||||
|
domainlevel = g_strdup_printf("%s:%s", domain, level);
|
||||||
|
alllevel = g_strdup_printf("all:%s", level);
|
||||||
|
starlevel = g_strdup_printf("*:%s", level);
|
||||||
|
domainstar = g_strdup_printf("%s:*", domain);
|
||||||
|
|
||||||
/* Go through each item in glib_log_domains setting to determine whether
|
/* Go through each item in glib_log_domains setting to determine whether
|
||||||
* or not we want to print message from this domain */
|
* or not we want to print message from this domain */
|
||||||
|
|
@ -287,8 +293,10 @@ static gboolean glib_domain_wanted(const char *domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we got a valid item, process it */
|
/* If we got a valid item, process it */
|
||||||
if (len > 0 && (!strncmp(domain, c, len) || !strncasecmp("all", c, len) ||
|
if (len > 0 && (!strncasecmp(domain, c, len) || !strncasecmp("all", c, len) ||
|
||||||
!strncmp("*", c, len)))
|
!strncmp("*", c, len) || !strncasecmp(domainstar, c, len) ||
|
||||||
|
!strncasecmp(domainlevel, c, len) ||
|
||||||
|
!strncasecmp(alllevel, c, len) || !strncasecmp(starlevel, c, len)))
|
||||||
print_it = incl;
|
print_it = incl;
|
||||||
|
|
||||||
/* Go past any spaces towards the next item */
|
/* Go past any spaces towards the next item */
|
||||||
|
|
@ -300,6 +308,11 @@ static gboolean glib_domain_wanted(const char *domain)
|
||||||
len = 0;
|
len = 0;
|
||||||
} while (*c != '\0' && print_it != -1);
|
} while (*c != '\0' && print_it != -1);
|
||||||
|
|
||||||
|
g_free(domainlevel);
|
||||||
|
g_free(alllevel);
|
||||||
|
g_free(starlevel);
|
||||||
|
g_free(domainstar);
|
||||||
|
|
||||||
return (print_it == 1);
|
return (print_it == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,7 +346,7 @@ static void i_log_func(const char *log_domain, GLogLevelFlags log_level, const c
|
||||||
domain = (log_domain ? log_domain : "default");
|
domain = (log_domain ? log_domain : "default");
|
||||||
|
|
||||||
/* Only print the message if we decided to */
|
/* Only print the message if we decided to */
|
||||||
if (!glib_domain_wanted(domain))
|
if (!glib_domain_wanted(domain, reason))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (windows == NULL)
|
if (windows == NULL)
|
||||||
|
|
|
||||||
|
|
@ -711,16 +711,19 @@ static void add_listen(const char *ircnet, int port, const char *port_or_path)
|
||||||
/* bind to specific host/ip? */
|
/* bind to specific host/ip? */
|
||||||
my_ip = NULL;
|
my_ip = NULL;
|
||||||
if (*settings_get_str("irssiproxy_bind") != '\0') {
|
if (*settings_get_str("irssiproxy_bind") != '\0') {
|
||||||
if (net_gethostbyname(settings_get_str("irssiproxy_bind"),
|
if (net_gethostbyname_first_ips(settings_get_str("irssiproxy_bind"),
|
||||||
&ip4, &ip6) != 0) {
|
G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT, &ip4,
|
||||||
|
&ip6) != 0) {
|
||||||
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
|
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
|
||||||
"Proxy: can not resolve '%s' - aborting",
|
"Proxy: can not resolve '%s' - aborting",
|
||||||
settings_get_str("irssiproxy_bind"));
|
settings_get_str("irssiproxy_bind"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_ip = ip6.family == 0 ? &ip4 : ip4.family == 0 ||
|
my_ip = ip6.family == 0 ? &ip4 :
|
||||||
settings_get_bool("resolve_prefer_ipv6") ? &ip6 : &ip4;
|
ip4.family == 0 || settings_get_bool("irssiproxy_prefer_ipv6") ?
|
||||||
|
&ip6 :
|
||||||
|
&ip4;
|
||||||
}
|
}
|
||||||
handle = net_listen(my_ip, &port);
|
handle = net_listen(my_ip, &port);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ static void irc_proxy_setup_changed(void)
|
||||||
|
|
||||||
void irc_proxy_init(void)
|
void irc_proxy_init(void)
|
||||||
{
|
{
|
||||||
|
settings_add_bool("irssiproxy", "irssiproxy_prefer_ipv6", TRUE);
|
||||||
settings_add_str("irssiproxy", "irssiproxy_ports", "");
|
settings_add_str("irssiproxy", "irssiproxy_ports", "");
|
||||||
settings_add_str("irssiproxy", "irssiproxy_password", "");
|
settings_add_str("irssiproxy", "irssiproxy_password", "");
|
||||||
settings_add_str("irssiproxy", "irssiproxy_bind", "");
|
settings_add_str("irssiproxy", "irssiproxy_bind", "");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue