2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
9 local configmanager
= require
"core.configmanager";
10 local modulemanager
= require
"core.modulemanager";
11 local events_new
= require
"util.events".new
;
12 local disco_items
= require
"util.multitable".new();
15 local log = require
"util.logger".init("hostmanager");
17 local hosts
= prosody
.hosts
;
18 local prosody_events
= prosody
.events
;
19 if not _G
.prosody
.incoming_s2s
then
20 require
"core.s2smanager";
22 local incoming_s2s
= _G
.prosody
.incoming_s2s
;
23 local core_route_stanza
= _G
.prosody
.core_route_stanza
;
25 local pairs
, rawget = pairs
, rawget;
26 local tostring, type = tostring, type;
27 local setmetatable
= setmetatable
;
33 function host_mt
:__tostring()
34 if self
.type == "component" then
35 local typ
= configmanager
.get(self
.host
, "component_module");
36 if typ
== "component" then
37 return ("Component %q"):format(self
.host
);
39 return ("Component %q %q"):format(self
.host
, typ
);
40 elseif self
.type == "local" then
41 return ("VirtualHost %q"):format(self
.host
);
45 local hosts_loaded_once
;
47 local activate
, deactivate
;
49 local function load_enabled_hosts(config
)
50 local defined_hosts
= config
or configmanager
.getconfig();
51 local activated_any_host
;
53 for host
, host_config
in pairs(defined_hosts
) do
54 if host
~= "*" and host_config
.enabled
~= false then
55 if not host_config
.component_module
then
56 activated_any_host
= true;
58 activate(host
, host_config
);
62 if not activated_any_host
then
63 log("error", "No active VirtualHost entries in the config file. This may cause unexpected behaviour as no modules will be loaded.");
66 prosody_events
.fire_event("hosts-activated", defined_hosts
);
67 hosts_loaded_once
= true;
70 prosody_events
.add_handler("server-starting", load_enabled_hosts
);
72 local function host_send(stanza
)
73 core_route_stanza(nil, stanza
);
76 function activate(host
, host_config
)
77 if rawget(hosts
, host
) then return nil, "The host "..host
.." is already activated"; end
78 host_config
= host_config
or configmanager
.getconfig()[host
];
79 if not host_config
then return nil, "Couldn't find the host "..tostring(host
).." defined in the current config"; end
80 local host_session
= {
83 events
= events_new();
87 function host_session
:close(reason
)
88 log("debug", "Attempt to close host session %s with reason: %s", self
.host
, reason
);
90 setmetatable(host_session
, host_mt
);
91 if not host_config
.component_module
then -- host
92 host_session
.type = "local";
93 host_session
.sessions
= {};
95 host_session
.type = "component";
97 hosts
[host
] = host_session
;
98 if not host_config
.disco_hidden
and not host
:match("[@/]") then
99 disco_items
:set(host
:match("%.(.*)") or "*", host
, host_config
.name
or true);
101 for option_name
in pairs(host_config
) do
102 if option_name
:match("_ports$") or option_name
:match("_interface$") then
103 log("warn", "%s: Option '%s' has no effect for virtual hosts - put it in the server-wide section instead", host
, option_name
);
107 log((hosts_loaded_once
and "info") or "debug", "Activated host: %s", host
);
108 prosody_events
.fire_event("host-activated", host
);
112 function deactivate(host
, reason
)
113 local host_session
= hosts
[host
];
114 if not host_session
then return nil, "The host "..tostring(host
).." is not activated"; end
115 log("info", "Deactivating host: %s", host
);
116 prosody_events
.fire_event("host-deactivating", { host
= host
, host_session
= host_session
, reason
= reason
});
118 if type(reason
) ~= "table" then
119 reason
= { condition
= "host-gone", text
= tostring(reason
or "This server has stopped serving "..host
) };
122 -- Disconnect local users, s2s connections
123 -- TODO: These should move to mod_c2s and mod_s2s (how do they know they're being unloaded and not reloaded?)
124 if host_session
.sessions
then
125 for username
, user
in pairs(host_session
.sessions
) do
126 for resource
, session
in pairs(user
.sessions
) do
127 log("debug", "Closing connection for %s@%s/%s", username
, host
, resource
);
128 session
:close(reason
);
132 if host_session
.s2sout
then
133 for remotehost
, session
in pairs(host_session
.s2sout
) do
134 if session
.close
then
135 log("debug", "Closing outgoing connection to %s", remotehost
);
136 if session
.srv_hosts
then session
.srv_hosts
= nil; end
137 session
:close(reason
);
141 for remote_session
in pairs(incoming_s2s
) do
142 if remote_session
.to_host
== host
then
143 log("debug", "Closing incoming connection from %s", remote_session
.from_host
or "<unknown>");
144 remote_session
:close(reason
);
148 -- TODO: This should be done in modulemanager
149 if host_session
.modules
then
150 for module
in pairs(host_session
.modules
) do
151 modulemanager
.unload(host
, module
);
156 if not host
:match("[@/]") then
157 disco_items
:remove(host
:match("%.(.*)") or "*", host
);
159 prosody_events
.fire_event("host-deactivated", host
);
160 log("info", "Deactivated host: %s", host
);
164 local function get_children(host
)
165 return disco_items
:get(host
) or NULL
;
170 deactivate
= deactivate
;
171 get_children
= get_children
;