aboutsummaryrefslogtreecommitdiff
path: root/plugins/ice/src/plugin.vala
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/ice/src/plugin.vala')
-rw-r--r--plugins/ice/src/plugin.vala71
1 files changed, 71 insertions, 0 deletions
diff --git a/plugins/ice/src/plugin.vala b/plugins/ice/src/plugin.vala
new file mode 100644
index 00000000..3ee8a72a
--- /dev/null
+++ b/plugins/ice/src/plugin.vala
@@ -0,0 +1,71 @@
+using Gee;
+using Dino.Entities;
+using Xmpp;
+using Xmpp.Xep;
+
+private extern const size_t NICE_ADDRESS_STRING_LEN;
+
+public class Dino.Plugins.Ice.Plugin : RootInterface, Object {
+ public Dino.Application app;
+
+ public void registered(Dino.Application app) {
+ Nice.debug_enable(true);
+ this.app = app;
+ app.stream_interactor.module_manager.initialize_account_modules.connect((account, list) => {
+ list.add(new Module());
+ });
+ app.stream_interactor.stream_attached_modules.connect((account, stream) => {
+ stream.get_module(Socks5Bytestreams.Module.IDENTITY).set_local_ip_address_handler(get_local_ip_addresses);
+ });
+ app.stream_interactor.stream_negotiated.connect(on_stream_negotiated);
+ }
+
+ private async void on_stream_negotiated(Account account, XmppStream stream) {
+ Module? ice_udp_module = stream.get_module(JingleIceUdp.Module.IDENTITY) as Module;
+ if (ice_udp_module == null) return;
+ Gee.List<Xep.ExternalServiceDiscovery.Service> services = yield ExternalServiceDiscovery.request_services(stream);
+ foreach (Xep.ExternalServiceDiscovery.Service service in services) {
+ if (service.transport == "udp" && (service.ty == "stun" || service.ty == "turn")) {
+ InetAddress ip = yield lookup_ipv4_addess(service.host);
+ if (ip == null) continue;
+
+ if (service.ty == "stun") {
+ debug("Server offers STUN server: %s:%u, resolved to %s", service.host, service.port, ip.to_string());
+ ice_udp_module.stun_ip = ip.to_string();
+ ice_udp_module.stun_port = service.port;
+ } else if (service.ty == "turn") {
+ debug("Server offers TURN server: %s:%u, resolved to %s", service.host, service.port, ip.to_string());
+ ice_udp_module.turn_ip = ip.to_string();
+ ice_udp_module.turn_service = service;
+ }
+ }
+ }
+ if (ice_udp_module.stun_ip == null) {
+ InetAddress ip = yield lookup_ipv4_addess("stun.l.google.com");
+ if (ip == null) return;
+
+ debug("Using fallback STUN server: stun.l.google.com:19302, resolved to %s", ip.to_string());
+
+ ice_udp_module.stun_ip = ip.to_string();
+ ice_udp_module.stun_port = 19302;
+ }
+ }
+
+ public void shutdown() {
+ // Nothing to do
+ }
+
+ private async InetAddress? lookup_ipv4_addess(string host) {
+ try {
+ Resolver resolver = Resolver.get_default();
+ GLib.List<GLib.InetAddress>? ips = yield resolver.lookup_by_name_async(host);
+ foreach (GLib.InetAddress ina in ips) {
+ if (ina.get_family() != SocketFamily.IPV4) continue;
+ return ina;
+ }
+ } catch (Error e) {
+ warning("Failed looking up IP address of %s", host);
+ }
+ return null;
+ }
+} \ No newline at end of file