1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
namespace Xmpp {
private class SrvTargetInfo {
public string host { get; set; }
public uint16 port { get; set; }
public string service { get; set; }
public uint16 priority { get; set; }
}
public class XmppStreamResult {
public TlsXmppStream? stream { get; set; }
public TlsCertificateFlags? tls_errors { get; set; }
public IOStreamError? io_error { get; set; }
}
public async XmppStreamResult establish_stream(Jid bare_jid, Gee.List<XmppStreamModule> modules, string? log_options, owned TlsXmppStream.OnInvalidCert on_invalid_cert) {
Jid remote = bare_jid.domain_jid;
//Lookup xmpp-client and xmpps-client SRV records
GLib.List<SrvTargetInfo>? targets = new GLib.List<SrvTargetInfo>();
GLibFixes.Resolver resolver = GLibFixes.Resolver.get_default();
try {
GLib.List<SrvTarget> xmpp_services = yield resolver.lookup_service_async("xmpp-client", "tcp", remote.to_string(), null);
foreach (SrvTarget service in xmpp_services) {
targets.append(new SrvTargetInfo() { host=service.get_hostname(), port=service.get_port(), service="xmpp-client", priority=service.get_priority()});
}
} catch (Error e) {
debug("Got no xmpp-client DNS records for %s: %s", remote.to_string(), e.message);
}
try {
GLib.List<SrvTarget> xmpp_services = yield resolver.lookup_service_async("xmpps-client", "tcp", remote.to_string(), null);
foreach (SrvTarget service in xmpp_services) {
targets.append(new SrvTargetInfo() { host=service.get_hostname(), port=service.get_port(), service="xmpps-client", priority=service.get_priority()});
}
} catch (Error e) {
debug("Got no xmpps-client DNS records for %s: %s", remote.to_string(), e.message);
}
targets.sort((a, b) => {
return a.priority - b.priority;
});
// Add fallback connection
bool should_add_fallback = true;
foreach (SrvTargetInfo target in targets) {
if (target.service == "xmpp-client" && target.port == 5222 && target.host == remote.to_string()) {
should_add_fallback = false;
}
}
if (should_add_fallback) {
targets.append(new SrvTargetInfo() { host=remote.to_string(), port=5222, service="xmpp-client", priority=uint16.MAX});
}
// Try all connection options from lowest to highest priority
TlsXmppStream? stream = null;
TlsCertificateFlags? tls_errors = null;
IOStreamError? io_error = null;
foreach (SrvTargetInfo target in targets) {
try {
if (target.service == "xmpp-client") {
stream = new StartTlsXmppStream(remote, target.host, target.port, (owned)on_invalid_cert);
} else {
stream = new DirectTlsXmppStream(remote, target.host, target.port, (owned)on_invalid_cert);
}
stream.log = new XmppLog(bare_jid.to_string(), log_options);
foreach (XmppStreamModule module in modules) {
stream.add_module(module);
}
yield stream.connect();
return new XmppStreamResult() { stream=stream };
} catch (IOStreamError e) {
warning("Could not establish XMPP session with %s:%i: %s", target.host, target.port, e.message);
if (stream != null) {
if (stream.errors != null) {
tls_errors = stream.errors;
}
io_error = e;
stream.detach_modules();
}
}
}
return new XmppStreamResult() { io_error=io_error, tls_errors=tls_errors };
}
}
|