mod_net_multiplex: Add support for using ALPN
authorKim Alvefur <zash@zash.se>
Fri, 29 Nov 2019 23:27:51 +0100
changeset 10469 09697a673015
parent 10468 8d3acf16c404
child 10470 276f62d14437
mod_net_multiplex: Add support for using ALPN Potentially a bit more efficient since it can jump to the selected protocol on connect instead of waiting for some data to look at. Adds a 'protocol' field to net providers for this purpose.
CHANGES
doc/doap.xml
plugins/mod_c2s.lua
plugins/mod_http.lua
plugins/mod_net_multiplex.lua
plugins/mod_s2s/mod_s2s.lua
--- a/CHANGES	Fri Nov 29 23:25:59 2019 +0100
+++ b/CHANGES	Fri Nov 29 23:27:51 2019 +0100
@@ -13,6 +13,7 @@
 -   Bi-directional server-to-server (XEP-0288)
 -   Built-in HTTP server now handles HEAD requests
 -   MUC presence broadcast controls
+-   ALPN support in mod\_net\_multiplex
 
 0.11.0
 ======
--- a/doc/doap.xml	Fri Nov 29 23:25:59 2019 +0100
+++ b/doc/doap.xml	Fri Nov 29 23:27:51 2019 +0100
@@ -51,6 +51,7 @@
     <implements rdf:resource="https://www.rfc-editor.org/info/rfc6121"/>
     <implements rdf:resource="https://www.rfc-editor.org/info/rfc6122"/>
     <implements rdf:resource="https://www.rfc-editor.org/info/rfc6455"/>
+    <implements rdf:resource="https://www.rfc-editor.org/info/rfc7301"/>
     <implements rdf:resource="https://www.rfc-editor.org/info/rfc7395"/>
     <!-- Added in hg:0bbbc9042361 released in 0.6.0 -->
     <implements rdf:resource="https://datatracker.ietf.org/doc/draft-cridland-xmpp-session/"/>
--- a/plugins/mod_c2s.lua	Fri Nov 29 23:25:59 2019 +0100
+++ b/plugins/mod_c2s.lua	Fri Nov 29 23:27:51 2019 +0100
@@ -374,6 +374,7 @@
 	default_port = 5222;
 	encryption = "starttls";
 	multiplex = {
+		protocol = "xmpp-client";
 		pattern = "^<.*:stream.*%sxmlns%s*=%s*(['\"])jabber:client%1.*>";
 	};
 });
--- a/plugins/mod_http.lua	Fri Nov 29 23:25:59 2019 +0100
+++ b/plugins/mod_http.lua	Fri Nov 29 23:27:51 2019 +0100
@@ -242,6 +242,7 @@
 	default_port = 5281;
 	encryption = "ssl";
 	multiplex = {
+		protocol = "http/1.1";
 		pattern = "^[A-Z]";
 	};
 });
--- a/plugins/mod_net_multiplex.lua	Fri Nov 29 23:25:59 2019 +0100
+++ b/plugins/mod_net_multiplex.lua	Fri Nov 29 23:27:51 2019 +0100
@@ -1,22 +1,38 @@
 module:set_global();
 
+local array = require "util.array";
 local max_buffer_len = module:get_option_number("multiplex_buffer_size", 1024);
 
 local portmanager = require "core.portmanager";
 
 local available_services = {};
+local service_by_protocol = {};
+local available_protocols = array();
 
 local function add_service(service)
 	local multiplex_pattern = service.multiplex and service.multiplex.pattern;
+	local protocol_name = service.multiplex and service.multiplex.protocol;
+	if protocol_name then
+		module:log("debug", "Adding multiplex service %q with protocol %q", service.name, protocol_name);
+		service_by_protocol[protocol_name] = service;
+		available_protocols:push(protocol_name);
+	end
 	if multiplex_pattern then
 		module:log("debug", "Adding multiplex service %q with pattern %q", service.name, multiplex_pattern);
 		available_services[service] = multiplex_pattern;
-	else
+	elseif not protocol_name then
 		module:log("debug", "Service %q is not multiplex-capable", service.name);
 	end
+	module:log("info", "available_protocols = %q", available_protocols);
 end
 module:hook("service-added", function (event) add_service(event.service); end);
-module:hook("service-removed", function (event)	available_services[event.service] = nil; end);
+module:hook("service-removed", function (event)
+	available_services[event.service] = nil;
+	if event.service.multiplex and event.service.multiplex.protocol then
+		available_protocols:filter(function (p) return p ~= event.service.multiplex.protocol end);
+		service_by_protocol[event.service.multiplex.protocol] = nil;
+	end
+end);
 
 for _, services in pairs(portmanager.get_registered_services()) do
 	for _, service in ipairs(services) do
@@ -28,7 +44,20 @@
 
 local listener = { default_mode = "*a" };
 
-function listener.onconnect()
+function listener.onconnect(conn)
+	local sock = conn:socket();
+	if sock.getalpn then
+		local selected_proto = sock:getalpn();
+		module:log("debug", "ALPN selected is %s", selected_proto);
+		local service = service_by_protocol[selected_proto];
+		if service then
+			module:log("debug", "Routing incoming connection to %s", service.name);
+			local next_listener = service.listener;
+			conn:setlistener(next_listener);
+			local onconnect = next_listener.onconnect;
+			if onconnect then return onconnect(conn) end
+		end
+	end
 end
 
 function listener.onincoming(conn, data)
@@ -68,5 +97,10 @@
 	name = "multiplex_ssl";
 	config_prefix = "ssl";
 	encryption = "ssl";
+	ssl_config = {
+		alpn = function ()
+			return available_protocols;
+		end;
+	};
 	listener = listener;
 });
--- a/plugins/mod_s2s/mod_s2s.lua	Fri Nov 29 23:25:59 2019 +0100
+++ b/plugins/mod_s2s/mod_s2s.lua	Fri Nov 29 23:27:51 2019 +0100
@@ -796,6 +796,7 @@
 		verify = { "peer", "client_once", };
 	};
 	multiplex = {
+		protocol = "xmpp-server";
 		pattern = "^<.*:stream.*%sxmlns%s*=%s*(['\"])jabber:server%1.*>";
 	};
 });