Diff

plugins/mod_net_multiplex.lua @ 10465:09697a673015

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.
author Kim Alvefur <zash@zash.se>
date Fri, 29 Nov 2019 23:27:51 +0100
parent 9465:876171084ea3
child 10466:276f62d14437
line wrap: on
line diff
--- 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;
 });