feat: Adds docs, config and scripts around the visitor mode. (#12658)
* feat: Moves handle of vnode from conferenceIQ stanza error to result. * feat: Handles redirected to visitor node event. * feat: Adds README and configurations. * squash: Drop comment. * copy edits * image fix * fix background for dark mode * fix the background * feat: Update s2soutinjection. * Update README commands formatting. * Update doc/extra-large-conference/README.md Co-authored-by: Saúl Ibarra Corretgé <saghul@jitsi.org> * squash: Creates a generateVisitorConfig helper. * squash: Moves the folder from doc. * squash: Update example. * squash: Drop config. * squash: Rename var to look like template. * squash: Fix plugins path. * squash: Fix sort order of import. * squash: Fix lint errors. Co-authored-by: scott boone <scott.e.boone@gmail.com> Co-authored-by: Scott Boone <scott.boone@8x8.com> Co-authored-by: Saúl Ibarra Corretgé <saghul@jitsi.org>
This commit is contained in:
parent
3445c513ba
commit
9fbbe05d6c
|
@ -47,6 +47,7 @@ import {
|
|||
dataChannelClosed,
|
||||
dataChannelOpened,
|
||||
e2eRttChanged,
|
||||
generateVisitorConfig,
|
||||
getConferenceOptions,
|
||||
kickedOut,
|
||||
lockStateChanged,
|
||||
|
@ -277,7 +278,8 @@ class ConferenceConnector {
|
|||
/**
|
||||
*
|
||||
*/
|
||||
constructor(resolve, reject) {
|
||||
constructor(resolve, reject, conference) {
|
||||
this._conference = conference;
|
||||
this._resolve = resolve;
|
||||
this._reject = reject;
|
||||
this.reconnectTimeout = null;
|
||||
|
@ -336,6 +338,26 @@ class ConferenceConnector {
|
|||
break;
|
||||
}
|
||||
|
||||
case JitsiConferenceErrors.REDIRECTED: {
|
||||
generateVisitorConfig(APP.store.getState(), params);
|
||||
|
||||
connection.disconnect().then(() => {
|
||||
connect(this._conference.roomName).then(con => {
|
||||
const localTracks = getLocalTracks(APP.store.getState()['features/base/tracks']);
|
||||
|
||||
const jitsiTracks = localTracks.map(t => t.jitsiTrack);
|
||||
|
||||
// visitors connect muted
|
||||
jitsiTracks.forEach(t => t.mute());
|
||||
|
||||
// TODO disable option to unmute audio or video
|
||||
this._conference.startConference(con, jitsiTracks);
|
||||
});
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case JitsiConferenceErrors.GRACEFUL_SHUTDOWN:
|
||||
APP.UI.notifyGracefulShutdown();
|
||||
break;
|
||||
|
@ -732,7 +754,7 @@ export default {
|
|||
// XXX The API will take care of disconnecting from the XMPP
|
||||
// server (and, thus, leaving the room) on unload.
|
||||
return new Promise((resolve, reject) => {
|
||||
new ConferenceConnector(resolve, reject).connect();
|
||||
new ConferenceConnector(resolve, reject, this).connect();
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1349,7 +1371,7 @@ export default {
|
|||
this._createRoom(localTracks);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
new ConferenceConnector(resolve, reject).connect();
|
||||
new ConferenceConnector(resolve, reject, this).connect();
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -15,6 +15,17 @@ upstream jvb1 {
|
|||
server 127.0.0.1:9090;
|
||||
keepalive 2;
|
||||
}
|
||||
map $arg_vnode $prosody_node {
|
||||
default prosody;
|
||||
v1 v1;
|
||||
v2 v2;
|
||||
v3 v3;
|
||||
v4 v4;
|
||||
v5 v5;
|
||||
v6 v6;
|
||||
v7 v7;
|
||||
v8 v8;
|
||||
}
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
@ -95,7 +106,7 @@ server {
|
|||
|
||||
# BOSH
|
||||
location = /http-bind {
|
||||
proxy_pass http://prosody/http-bind?prefix=$prefix&$args;
|
||||
proxy_pass http://$prosody_node/http-bind?prefix=$prefix&$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header Host $http_host;
|
||||
|
@ -104,7 +115,7 @@ server {
|
|||
|
||||
# xmpp websockets
|
||||
location = /xmpp-websocket {
|
||||
proxy_pass http://prosody/xmpp-websocket?prefix=$prefix&$args;
|
||||
proxy_pass http://$prosody_node/xmpp-websocket?prefix=$prefix&$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
|
|
@ -252,6 +252,34 @@ export function getConferenceOptions(stateful: IStateful) {
|
|||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object aggregating the conference options.
|
||||
*
|
||||
* @param {IStateful} stateful - The redux store state.
|
||||
* @param {Array<string>} params - The received parameters.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function generateVisitorConfig(stateful: IStateful, params: Array<string>) {
|
||||
const [ vnode, focusJid ] = params;
|
||||
|
||||
const config = toState(stateful)['features/base/config'];
|
||||
|
||||
if (!config || !config.hosts) {
|
||||
logger.warn('Wrong configuration, missing hosts.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const oldDomain = config.hosts.domain;
|
||||
|
||||
config.hosts.domain = `${vnode}.meet.jitsi`;
|
||||
config.hosts.muc = config.hosts.muc.replace(oldDomain, config.hosts.domain);
|
||||
config.hosts.visitorFocus = focusJid;
|
||||
|
||||
config.bosh += `?vnode=${vnode}`;
|
||||
config.websocket += `?vnode=${vnode}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UTC timestamp when the first participant joined the conference.
|
||||
*
|
||||
|
|
|
@ -339,6 +339,7 @@ export interface IConfig {
|
|||
domain: string;
|
||||
focus?: string;
|
||||
muc: string;
|
||||
visitorFocus: string;
|
||||
};
|
||||
iAmRecorder?: boolean;
|
||||
iAmSipGateway?: boolean;
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
WARNING: This is still a Work In Progress
|
||||
|
||||
The final implementation may diverge. Currently, only the participants after a
|
||||
configured threshold will be just viewers (visitors) and there is no promotion
|
||||
mechanism to become a main participant yet.
|
||||
|
||||
TODO:
|
||||
* Merge messaging between visitor nodes and main conference
|
||||
* Polls
|
||||
* Raise hand to be promoted to enter the main conference
|
||||
* Make sure it works with tenants.
|
||||
|
||||
|
||||
# Low-latency conference streaming to very large audiences
|
||||
|
||||
To have a low-latency conference with a very large audience, the media and
|
||||
signaling load must be spread beyond what can be handled by a typical Jitsi
|
||||
installation. A call with 10k participants requires around 50 bridges on decent
|
||||
vms (8+ cores). The main participants of a conference with a very large
|
||||
audience will share a main prosody, like with normal conferences, and
|
||||
additional prosody vms are needed to support signaling to the audience.
|
||||
|
||||
In the example configuration we use a 16 core machine. Eight of the cores are
|
||||
used for the main prosody and other services (nginx, jicofo, etc) and the other
|
||||
eight cores are used to run prosody services for visitors, i.e., "visitor
|
||||
prosodies".
|
||||
|
||||
We consider 2000 participants per visitor node a safe value. So eight visitor
|
||||
prosodies will be enough for one 10k participants meeting.
|
||||
|
||||
<img src="imgs/visitors-prosody.svg" alt="diagram of a central prosody connected to several visitor prosodies" width="500"/>
|
||||
|
||||
# Configuration
|
||||
Use the `pre-configure.sh` script to configure your system, passing it the
|
||||
number of visitor prosodies to set up.
|
||||
`./pre-configure.sh 8`
|
||||
|
||||
The script will add for each visitor prosody:
|
||||
- folders in `/etc/`
|
||||
- a systemd unit file in `/lib/systemd/system/`
|
||||
- a user for jicofo
|
||||
- a config entry in jicofo.conf
|
||||
|
||||
Setting up configuration for the main prosody is a manual process:
|
||||
- Add to the enabled modules list in the general part (e.g. [here](https://github.com/bjc/prosody/blob/76bf6d511f851c7cde8a81257afaaae0fb7a4160/prosody.cfg.lua.dist#L33)):
|
||||
```
|
||||
"s2s_bidi";
|
||||
"certs_s2soutinjection";
|
||||
"s2soutinjection";
|
||||
"s2s_whitelist";
|
||||
```
|
||||
|
||||
- Add the following config also in the general part (matching the number of prosodies you generated config for):
|
||||
```
|
||||
-- targets must be IPs, not hostnames
|
||||
s2s_connect_overrides = {
|
||||
["conference.v1.meet.jitsi"] = { "127.0.0.1", 52691 };
|
||||
["conference.v2.meet.jitsi"] = { "127.0.0.1", 52692 };
|
||||
["conference.v3.meet.jitsi"] = { "127.0.0.1", 52693 };
|
||||
["conference.v4.meet.jitsi"] = { "127.0.0.1", 52694 };
|
||||
["conference.v5.meet.jitsi"] = { "127.0.0.1", 52695 };
|
||||
["conference.v6.meet.jitsi"] = { "127.0.0.1", 52696 };
|
||||
["conference.v7.meet.jitsi"] = { "127.0.0.1", 52697 };
|
||||
["conference.v8.meet.jitsi"] = { "127.0.0.1", 52698 };
|
||||
}
|
||||
-- allowed list of server-2-server connections
|
||||
s2s_whitelist = {
|
||||
"conference.v1.meet.jitsi", "conference.v2.meet.jitsi", "conference.v3.meet.jitsi", "conference.v4.meet.jitsi",
|
||||
"conference.v5.meet.jitsi", "conference.v6.meet.jitsi", "conference.v7.meet.jitsi", "conference.v8.meet.jitsi"
|
||||
};
|
||||
```
|
||||
|
||||
- Make sure s2s is not in modules_disabled
|
||||
- Enable `"xxl_conference";` module under the main virtual host (e.g. [here](https://github.com/jitsi/jitsi-meet/blob/f42772ec5bcc87ff6de17423d36df9bcad6e770d/doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example#L57))
|
||||
|
||||
After configuring you can set the maximum number of main participants, before
|
||||
redirecting to visitors.
|
||||
```
|
||||
hocon -f /etc/jitsi/jicofo/jicofo.conf set "jicofo.visitors.max-participants" 30
|
||||
```
|
||||
Now restart prosody and jicofo
|
||||
```
|
||||
service prosody restart
|
||||
service jicofo restart
|
||||
```
|
||||
|
||||
Now after the main 30 participants join, the rest will be visitors using the
|
||||
visitor nodes.
|
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 198 KiB |
|
@ -0,0 +1,51 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=`dirname "$0"`
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
NUMBER_OF_INSTANCES=$1
|
||||
|
||||
if ! [[ $NUMBER_OF_INSTANCES =~ ^[0-9]+([.][0-9]+)?$ ]] ; then
|
||||
echo "error: Not a number param" >&2;
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Will configure $NUMBER_OF_INSTANCES number of visitor prosodies"
|
||||
set -e
|
||||
set -x
|
||||
|
||||
# Configure prosody instances
|
||||
for (( i=1 ; i<=${NUMBER_OF_INSTANCES} ; i++ ));
|
||||
do
|
||||
cp prosody-v.service.template /lib/systemd/system/prosody-v${i}.service
|
||||
sed -i "s/vX/v${i}/g" /lib/systemd/system/prosody-v${i}.service
|
||||
mkdir /etc/prosody-v${i}
|
||||
ln -s /etc/prosody/certs /etc/prosody-v${i}/certs
|
||||
cp prosody.cfg.lua.visitor.template /etc/prosody-v${i}/prosody.cfg.lua
|
||||
sed -i "s/vX/v${i}/g" /etc/prosody-v${i}/prosody.cfg.lua
|
||||
done
|
||||
|
||||
# Configure jicofo
|
||||
HOCON_CONFIG="/etc/jitsi/jicofo/jicofo.conf"
|
||||
hocon -f $HOCON_CONFIG set "jicofo.bridge.selection-strategy" "VisitorSelectionStrategy"
|
||||
hocon -f $HOCON_CONFIG set "jicofo.bridge.visitor-selection-strategy" "RegionBasedBridgeSelectionStrategy"
|
||||
hocon -f $HOCON_CONFIG set "jicofo.bridge.topology-strategy" "VisitorTopologyStrategy"
|
||||
|
||||
PASS=$(hocon -f $HOCON_CONFIG get "jicofo.xmpp.client.password")
|
||||
for (( i=1 ; i<=${NUMBER_OF_INSTANCES} ; i++ ));
|
||||
do
|
||||
prosodyctl --config /etc/prosody-v${i}/prosody.cfg.lua register focus auth.meet.jitsi $PASS
|
||||
hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.enabled" true
|
||||
hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.conference-service" "conference.v${i}.meet.jitsi"
|
||||
hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.hostname" 127.0.0.1
|
||||
hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.port" 5222${i}
|
||||
hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.domain" "auth.meet.jitsi"
|
||||
hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.password" "${PASS}"
|
||||
hocon -f $HOCON_CONFIG set "jicofo.xmpp.visitors.v${i}.disable-certificate-verification" true
|
||||
done
|
||||
|
||||
for (( i=1 ; i<=${NUMBER_OF_INSTANCES} ; i++ ));
|
||||
do
|
||||
service prosody-v${i} restart
|
||||
done
|
||||
service jicofo restart
|
|
@ -0,0 +1,46 @@
|
|||
[Unit]
|
||||
### see man systemd.unit
|
||||
Description=Prosody vX (visitor vX) JVB XMPP Server
|
||||
Documentation=https://prosody.im/doc
|
||||
|
||||
Requires=network-online.target
|
||||
After=network-online.target network.target mariadb.service mysql.service postgresql.service
|
||||
Before=biboumi.service
|
||||
|
||||
[Service]
|
||||
### see man systemd.service
|
||||
Type=simple
|
||||
|
||||
# Start by executing the main executable
|
||||
# Note: -F option requires Prosody 0.11.5 or later
|
||||
ExecStart=/usr/bin/prosody --config /etc/prosody-vX/prosody.cfg.lua -F
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
Restart=on-abnormal
|
||||
|
||||
### see man systemd.exec
|
||||
User=prosody
|
||||
Group=prosody
|
||||
UMask=0027
|
||||
|
||||
RuntimeDirectory=prosody-vX
|
||||
ConfigurationDirectory=prosody-vX
|
||||
StateDirectory=prosody-vX
|
||||
StateDirectoryMode=0750
|
||||
LogsDirectory=prosody-vX
|
||||
WorkingDirectory=~
|
||||
|
||||
# Set stdin to /dev/null since Prosody does not need it
|
||||
StandardInput=null
|
||||
|
||||
# Direct stdout/-err to journald for use with log = "*stdout"
|
||||
StandardOutput=journal
|
||||
StandardError=inherit
|
||||
|
||||
# Allow binding low ports
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
|
||||
[Install]
|
||||
### see man systemd.unit
|
||||
WantedBy=multi-user.target
|
||||
|
||||
# vim: filetype=systemd
|
|
@ -0,0 +1,121 @@
|
|||
---------- Server-wide settings ----------
|
||||
s2s_ports = { 52691 };
|
||||
c2s_ports = { 52221 }
|
||||
http_ports = { 52801 }
|
||||
https_ports = { 52811 }
|
||||
|
||||
daemonize = true;
|
||||
|
||||
-- we use a common jid for jicofo
|
||||
admins = {
|
||||
'focus@auth.meet.jitsi'
|
||||
}
|
||||
|
||||
-- Enable use of native prosody 0.11 support for epoll over select
|
||||
network_backend = 'epoll';
|
||||
network_settings = {
|
||||
tcp_backlog = 511;
|
||||
}
|
||||
|
||||
modules_enabled = {
|
||||
'saslauth';
|
||||
'tls';
|
||||
'disco';
|
||||
'posix';
|
||||
|
||||
'secure_interfaces';
|
||||
|
||||
-- jitsi
|
||||
'websocket';
|
||||
'bosh';
|
||||
's2s_bidi';
|
||||
's2s_whitelist';
|
||||
};
|
||||
|
||||
s2s_whitelist = {};
|
||||
|
||||
external_service_secret = '__turnSecret__';
|
||||
|
||||
external_services = {
|
||||
{ type = 'stun', host = 'jitmeet.example.com', port = 3478 },
|
||||
{ type = 'turn', host = 'jitmeet.example.com', port = 3478, transport = 'udp', secret = true, ttl = 86400, algorithm = 'turn' },
|
||||
{ type = 'turns', host = 'jitmeet.example.com', port = 5349, transport = 'tcp', secret = true, ttl = 86400, algorithm = 'turn' }
|
||||
};
|
||||
|
||||
muc_mapper_domain_base = 'vX.meet.jitsi';
|
||||
|
||||
-- https://prosody.im/doc/modules/mod_smacks
|
||||
smacks_max_unacked_stanzas = 5;
|
||||
smacks_hibernation_time = 60;
|
||||
-- this is dropped in 0.12
|
||||
smacks_max_hibernated_sessions = 1;
|
||||
smacks_max_old_sessions = 1;
|
||||
|
||||
unlimited_jids = { 'focus@auth.meet.jitsi' }
|
||||
limits = {
|
||||
c2s = {
|
||||
rate = '512kb/s';
|
||||
};
|
||||
}
|
||||
|
||||
modules_disabled = {
|
||||
'offline';
|
||||
'pubsub';
|
||||
'register';
|
||||
};
|
||||
|
||||
allow_registration = false;
|
||||
authentication = 'internal_hashed'
|
||||
storage = 'internal'
|
||||
log = {
|
||||
-- Log files (change 'info' to 'debug' for debug logs):
|
||||
info = '/var/log/prosody-vX/prosody.log';
|
||||
error = '/var/log/prosody-vX/prosody.err';
|
||||
}
|
||||
|
||||
consider_websocket_secure = true;
|
||||
consider_bosh_secure = true;
|
||||
bosh_max_inactivity = 60;
|
||||
|
||||
plugin_paths = { '/usr/share/jitsi-meet/prosody-plugins/' }
|
||||
|
||||
----------- Virtual hosts -----------
|
||||
VirtualHost 'vX.meet.jitsi'
|
||||
authentication = 'jitsi-anonymous'
|
||||
ssl = {
|
||||
key = '/etc/prosody/certs/jitmeet.example.com.key';
|
||||
certificate = '/etc/prosody/certs/jitmeet.example.com.crt';
|
||||
}
|
||||
modules_enabled = {
|
||||
'bosh';
|
||||
'ping';
|
||||
'external_services';
|
||||
'smacks';
|
||||
'jiconop';
|
||||
}
|
||||
main_muc = 'conference.vX.meet.jitsi';
|
||||
|
||||
VirtualHost 'auth.meet.jitsi'
|
||||
modules_enabled = {
|
||||
'limits_exception';
|
||||
'ping';
|
||||
}
|
||||
authentication = 'internal_hashed'
|
||||
|
||||
Component 'conference.vX.meet.jitsi' 'muc'
|
||||
storage = 'memory'
|
||||
muc_room_cache_size = 10000
|
||||
restrict_room_creation = true
|
||||
modules_enabled = {
|
||||
'muc_hide_all';
|
||||
'muc_domain_mapper';
|
||||
'muc_meeting_id';
|
||||
'fmuc';
|
||||
}
|
||||
muc_room_default_presence_broadcast = {
|
||||
visitor = false;
|
||||
participant = true;
|
||||
moderator = true;
|
||||
};
|
||||
muc_room_locking = false
|
||||
muc_room_default_public_jids = true
|
|
@ -1,16 +0,0 @@
|
|||
-- validates all certificates, global module
|
||||
-- Warning: use this only for testing purposes as it will accept all kind of certificates for s2s connections
|
||||
-- you can use https://modules.prosody.im/mod_s2s_whitelist.html for whitelisting only certain destinations
|
||||
module:set_global();
|
||||
|
||||
function attach(event)
|
||||
local session = event.session;
|
||||
|
||||
session.cert_chain_status = 'valid';
|
||||
session.cert_identity_status = 'valid';
|
||||
|
||||
return true;
|
||||
end
|
||||
module:wrap_event('s2s-check-certificate', function (handlers, event_name, event_data)
|
||||
return attach(event_data);
|
||||
end);
|
|
@ -0,0 +1,19 @@
|
|||
-- global module
|
||||
-- validates certificates for all hosts used for s2soutinjection
|
||||
module:set_global();
|
||||
|
||||
local s2s_overrides = module:get_option("s2s_connect_overrides");
|
||||
|
||||
function attach(event)
|
||||
local session = event.session;
|
||||
|
||||
if s2s_overrides and s2s_overrides[event.host] then
|
||||
session.cert_chain_status = 'valid';
|
||||
session.cert_identity_status = 'valid';
|
||||
|
||||
return true;
|
||||
end
|
||||
end
|
||||
module:wrap_event('s2s-check-certificate', function (handlers, event_name, event_data)
|
||||
return attach(event_data);
|
||||
end);
|
|
@ -7,12 +7,6 @@
|
|||
--- };
|
||||
--- Enable in global modules: 's2s_bidi'
|
||||
--- Make sure 's2s' is not in modules_disabled
|
||||
--- TODO: Do we need the /etc/hosts changes? We can drop it for https://modules.prosody.im/mod_s2soutinjection.html
|
||||
--- In /etc/hosts add:
|
||||
--- vmmain-ip-address focus.domain.com
|
||||
--- vmmain-ip-address conference.domain.com
|
||||
--- vmmain-ip-address domain.com
|
||||
--- Open port 5269 on the provider side and on the firewall of the machine, so the core node can access this visitor one
|
||||
local jid = require 'util.jid';
|
||||
local st = require 'util.stanza';
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
-- Using version https://hg.prosody.im/prosody-modules/file/c1a8ce147885/mod_s2s_whitelist/mod_s2s_whitelist.lua
|
||||
local st = require "util.stanza";
|
||||
|
||||
local whitelist = module:get_option_inherited_set("s2s_whitelist", {});
|
||||
|
||||
module:hook("route/remote", function (event)
|
||||
if not whitelist:contains(event.to_host) then
|
||||
module:send(st.error_reply(event.stanza, "cancel", "not-allowed", "Communication with this domain is restricted"));
|
||||
return true;
|
||||
end
|
||||
end, 100);
|
||||
|
||||
module:hook("s2s-stream-features", function (event)
|
||||
if not whitelist:contains(event.origin.from_host) then
|
||||
event.origin:close({
|
||||
condition = "policy-violation";
|
||||
text = "Communication with this domain is restricted";
|
||||
});
|
||||
end
|
||||
end, 1000);
|
|
@ -0,0 +1,90 @@
|
|||
-- Using version https://hg.prosody.im/prosody-modules/file/4fb922aa0ace/mod_s2soutinjection/mod_s2soutinjection.lua
|
||||
local st = require"util.stanza";
|
||||
local new_outgoing = require"core.s2smanager".new_outgoing;
|
||||
local bounce_sendq = module:depends"s2s".route_to_new_session.bounce_sendq;
|
||||
local initialize_filters = require "util.filters".initialize;
|
||||
|
||||
local portmanager = require "core.portmanager";
|
||||
|
||||
local addclient = require "net.server".addclient;
|
||||
|
||||
module:depends("s2s");
|
||||
|
||||
local sessions = module:shared("sessions");
|
||||
|
||||
local injected = module:get_option("s2s_connect_overrides");
|
||||
|
||||
-- The proxy_listener handles connection while still connecting to the proxy,
|
||||
-- then it hands them over to the normal listener (in mod_s2s)
|
||||
local proxy_listener = { default_port = nil, default_mode = "*a", default_interface = "*" };
|
||||
|
||||
function proxy_listener.onconnect(conn)
|
||||
local session = sessions[conn];
|
||||
|
||||
-- Now the real s2s listener can take over the connection.
|
||||
local listener = portmanager.get_service("s2s").listener;
|
||||
|
||||
local log = session.log;
|
||||
|
||||
local filter = initialize_filters(session);
|
||||
|
||||
session.version = 1;
|
||||
|
||||
session.sends2s = function (t)
|
||||
log("debug", "sending (s2s over proxy): %s", (t.top_tag and t:top_tag()) or t:match("^[^>]*>?"));
|
||||
if t.name then
|
||||
t = filter("stanzas/out", t);
|
||||
end
|
||||
if t then
|
||||
t = filter("bytes/out", tostring(t));
|
||||
if t then
|
||||
return conn:write(tostring(t));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
session.open_stream = function ()
|
||||
session.sends2s(st.stanza("stream:stream", {
|
||||
xmlns='jabber:server', ["xmlns:db"]='jabber:server:dialback',
|
||||
["xmlns:stream"]='http://etherx.jabber.org/streams',
|
||||
from=session.from_host, to=session.to_host, version='1.0', ["xml:lang"]='en'}):top_tag());
|
||||
end
|
||||
|
||||
conn.setlistener(conn, listener);
|
||||
|
||||
listener.register_outgoing(conn, session);
|
||||
|
||||
listener.onconnect(conn);
|
||||
end
|
||||
|
||||
function proxy_listener.register_outgoing(conn, session)
|
||||
session.direction = "outgoing";
|
||||
sessions[conn] = session;
|
||||
end
|
||||
|
||||
function proxy_listener.ondisconnect(conn, err)
|
||||
sessions[conn] = nil;
|
||||
end
|
||||
|
||||
module:hook("route/remote", function(event)
|
||||
local from_host, to_host, stanza = event.from_host, event.to_host, event.stanza;
|
||||
local inject = injected and injected[to_host];
|
||||
if not inject then return end
|
||||
module:log("debug", "opening a new outgoing connection for this stanza");
|
||||
local host_session = new_outgoing(from_host, to_host);
|
||||
|
||||
-- Store in buffer
|
||||
host_session.bounce_sendq = bounce_sendq;
|
||||
host_session.sendq = { {tostring(stanza), stanza.attr.type ~= "error" and stanza.attr.type ~= "result" and st.reply(stanza)} };
|
||||
host_session.log("debug", "stanza [%s] queued until connection complete", tostring(stanza.name));
|
||||
|
||||
local host, port = inject[1] or inject, tonumber(inject[2]) or 5269;
|
||||
|
||||
local conn = addclient(host, port, proxy_listener, "*a");
|
||||
|
||||
proxy_listener.register_outgoing(conn, host_session);
|
||||
|
||||
host_session.conn = conn;
|
||||
return true;
|
||||
end, -2);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
-- Using version https://hg.prosody.im/prosody-modules/file/6c806a99f802/mod_secure_interfaces/mod_secure_interfaces.lua
|
||||
local secure_interfaces = module:get_option_set("secure_interfaces", { "127.0.0.1", "::1" });
|
||||
|
||||
module:hook("stream-features", function (event)
|
||||
local session = event.origin;
|
||||
if session.type ~= "c2s_unauthed" then return; end
|
||||
local socket = session.conn:socket();
|
||||
if not socket.getsockname then
|
||||
module:log("debug", "Unable to determine local address of incoming connection");
|
||||
return;
|
||||
end
|
||||
local localip = socket:getsockname();
|
||||
if secure_interfaces:contains(localip) then
|
||||
module:log("debug", "Marking session from %s to %s as secure", session.ip or "[?]", localip);
|
||||
session.secure = true;
|
||||
session.conn.starttls = false;
|
||||
else
|
||||
module:log("debug", "Not marking session from %s to %s as secure", session.ip or "[?]", localip);
|
||||
end
|
||||
end, 2500);
|
|
@ -56,29 +56,23 @@ local visitors_nodes = {};
|
|||
--- Jicofo is connected to the room when sending this error
|
||||
module:log('info', 'Hook to iq/host');
|
||||
module:hook('iq/full', function(event)
|
||||
local session, stanza = event.origin, event.stanza;
|
||||
local stanza = event.stanza;
|
||||
|
||||
if stanza.name ~= 'iq' or stanza.attr.type ~= 'error' or stanza.attr.from ~= focus_component_host then
|
||||
if stanza.name ~= 'iq' or stanza.attr.type ~= 'result' or stanza.attr.from ~= focus_component_host then
|
||||
return; -- not IQ from jicofo. Ignore this event.
|
||||
end
|
||||
|
||||
local error = stanza:get_child('error');
|
||||
if error == nil then
|
||||
return; -- not Conference IQ error. Ignore.
|
||||
end
|
||||
|
||||
local redirect = error:get_child('redirect', 'urn:ietf:params:xml:ns:xmpp-stanzas');
|
||||
local redirect_host = error:get_child_text('url', 'http://jitsi.org/jitmeet');
|
||||
|
||||
if not redirect or not redirect_host then
|
||||
local conference = stanza:get_child('conference', 'http://jitsi.org/protocol/focus');
|
||||
if not conference then
|
||||
return;
|
||||
end
|
||||
|
||||
-- let's send participants if any from the room to the visitors room
|
||||
-- TODO fix room name extract, make sure it works wit tenants
|
||||
local main_room = error:get_child_text('main-room', 'http://jitsi.org/jitmeet');
|
||||
local main_room = conference.attr.room;
|
||||
local vnode = conference.attr.vnode;
|
||||
|
||||
if not main_room then
|
||||
if not main_room or not vnode then
|
||||
return;
|
||||
end
|
||||
|
||||
|
@ -88,7 +82,7 @@ module:hook('iq/full', function(event)
|
|||
return; -- room does not exists. Continue with normal flow
|
||||
end
|
||||
|
||||
local conference_service = muc_domain_prefix..'.'..redirect_host;
|
||||
local conference_service = muc_domain_prefix..'.'..vnode..'.meet.jitsi';
|
||||
|
||||
if visitors_nodes[room.jid] and
|
||||
visitors_nodes[room.jid].nodes and
|
||||
|
|
Loading…
Reference in New Issue