Fixed the IRC code so that it deals with regions coming and
going.
0.6.1-post-fixes
Dr Scofield 2008-11-14 10:50:36 +00:00
parent 4e0a424f9f
commit 62317ded9f
4 changed files with 133 additions and 114 deletions

View File

@ -256,6 +256,9 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
// values that, while independent of the IRC connetion, do still distinguish // values that, while independent of the IRC connetion, do still distinguish
// this region's behavior. // this region's behavior.
lock (IRCBridgeModule.m_channels)
{
foreach (ChannelState xcs in IRCBridgeModule.m_channels) foreach (ChannelState xcs in IRCBridgeModule.m_channels)
{ {
if (cs.IsAPerfectMatchFor(xcs)) if (cs.IsAPerfectMatchFor(xcs))
@ -272,6 +275,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
} }
} }
}
// No entry was found, so this is going to be a new entry. // No entry was found, so this is going to be a new entry.
if (cs.irc == null) if (cs.irc == null)
@ -281,6 +286,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
if ((cs.irc = new IRCConnector(cs)) != null) if ((cs.irc = new IRCConnector(cs)) != null)
{ {
IRCBridgeModule.m_channels.Add(cs); IRCBridgeModule.m_channels.Add(cs);
m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}", m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}",
@ -302,11 +308,12 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port); cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
} }
m_log.InfoFormat("[IRC-Channel-{0}] Region {1} connected to channel {2} on server {3}:{4}", m_log.InfoFormat("[IRC-Channel-{0}] Region {1} associated with channel {2} on server {3}:{4}",
cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port); cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
// We're finally ready to commit ourselves // We're finally ready to commit ourselves
return cs; return cs;
} }
@ -443,6 +450,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
// Repeatedly scan the string until all possible // Repeatedly scan the string until all possible
// substitutions have been performed. // substitutions have been performed.
// m_log.DebugFormat("[IRC-Channel] Parse[1]: {0}", result);
while (arg.IsMatch(result)) while (arg.IsMatch(result))
{ {
@ -476,28 +485,26 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
result = result.Replace(vvar, rs.config.GetString(var,var)); result = result.Replace(vvar, rs.config.GetString(var,var));
break; break;
} }
// m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result);
} }
// m_log.DebugFormat("[IRC-Channel] Parse[3]: {0}", result);
return result; return result;
} }
public void Close() public void Close()
{ {
m_log.InfoFormat("[IRC-Channel-{0}] Closing channel <{1}> to server <{2}:{3}>",
m_log.InfoFormat("[IRC-Channel-{0}] Closing channel <{1} to server <{2}:{3}>",
idn, IrcChannel, Server, Port); idn, IrcChannel, Server, Port);
m_log.InfoFormat("[IRC-Channel-{0}] There are {1} active clients", m_log.InfoFormat("[IRC-Channel-{0}] There are {1} active clients",
idn, clientregions.Count); idn, clientregions.Count);
irc.Close(); irc.Close();
} }
public void Open() public void Open()
{ {
m_log.InfoFormat("[IRC-Channel-{0}] Opening channel <{1} to server <{2}:{3}>", m_log.InfoFormat("[IRC-Channel-{0}] Opening channel <{1}> to server <{2}:{3}>",
idn, IrcChannel, Server, Port); idn, IrcChannel, Server, Port);
irc.Open(); irc.Open();
@ -514,16 +521,30 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
Open(); Open();
} }
// Close is called to ensure that the IRC session is terminated if this is the
// only client.
public void Close(RegionState rs) public void Close(RegionState rs)
{ {
RemoveRegion(rs); RemoveRegion(rs);
lock (IRCBridgeModule.m_channels)
{
if (clientregions.Count == 0)
{
Close();
IRCBridgeModule.m_channels.Remove(this);
m_log.InfoFormat("[IRC-Channel-{0}] Region {1} is last user of channel <{2}> to server <{3}:{4}>",
idn, rs.Region, IrcChannel, Server, Port);
m_log.InfoFormat("[IRC-Channel-{0}] Removed", idn);
}
}
} }
// Add a client region to this channel if it is not already known // Add a client region to this channel if it is not already known
public void AddRegion(RegionState rs) public void AddRegion(RegionState rs)
{ {
m_log.InfoFormat("[IRC-Channel-{0}] Adding region {1} to channel <{2} to server <{3}:{4}>", m_log.InfoFormat("[IRC-Channel-{0}] Adding region {1} to channel <{2}> to server <{3}:{4}>",
idn, rs.Region, IrcChannel, Server, Port); idn, rs.Region, IrcChannel, Server, Port);
if (!clientregions.Contains(rs)) if (!clientregions.Contains(rs))
{ {
@ -568,6 +589,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
// Note that this code is responsible for completing some of the // Note that this code is responsible for completing some of the
// settings for the inbound OSChatMessage // settings for the inbound OSChatMessage
lock (IRCBridgeModule.m_channels)
{
foreach (ChannelState cs in IRCBridgeModule.m_channels) foreach (ChannelState cs in IRCBridgeModule.m_channels)
{ {
if ( p_irc == cs.irc) if ( p_irc == cs.irc)
@ -589,7 +612,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
} }
} }
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -49,11 +49,13 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
internal static bool enabled = false; internal static bool enabled = false;
internal static IConfig m_config = null; internal static IConfig m_config = null;
internal static List<RegionState> m_regions = new List<RegionState>();
internal static List<ChannelState> m_channels = new List<ChannelState>(); internal static List<ChannelState> m_channels = new List<ChannelState>();
internal static List<RegionState> m_regions = new List<RegionState>();
internal static string password = String.Empty; internal static string password = String.Empty;
internal RegionState region = null;
#region IRegionModule Members #region IRegionModule Members
public string Name public string Name
@ -63,7 +65,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
public bool IsSharedModule public bool IsSharedModule
{ {
get { return true; } get { return false; }
} }
public void Initialise(Scene scene, IConfigSource config) public void Initialise(Scene scene, IConfigSource config)
@ -110,13 +112,18 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
// Iff the IRC bridge is enabled, then each new region may be // Iff the IRC bridge is enabled, then each new region may be
// connected to IRC. But it should NOT be obligatory (and it // connected to IRC. But it should NOT be obligatory (and it
// is not). // is not).
// We have to do ALL of the startup here because PostInitialize
// is not called when a region gets created in-flight from the
// command line.
if (enabled) if (enabled)
{ {
try try
{ {
m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName); m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName);
m_regions.Add(new RegionState(scene, m_config)); region = new RegionState(scene, m_config);
lock(m_regions) m_regions.Add(region);
region.Open();
} }
catch (Exception e) catch (Exception e)
{ {
@ -131,37 +138,17 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
} }
// Called after all region modules have been loaded. // This module can be called in-flight in which case PostInitialize
// Iff the IRC bridge is enabled, then start all of the // is not called following Initialize. So no use is made of this
// configured channels. The set of channels is a side // call.
// effect of RegionState creation.
public void PostInitialise() public void PostInitialise()
{ {
if (!enabled)
return;
foreach (RegionState region in m_regions)
{
m_log.InfoFormat("[IRC-Bridge] Opening connection for {0}:{1} on IRC server {2}:{3}",
region.Region, region.cs.BaseNickname, region.cs.Server, region.cs.IrcChannel);
try
{
region.Open();
}
catch (Exception e)
{
m_log.ErrorFormat("[IRC-Bridge] Open failed for {0}:{1} on IRC server {2}:{3} : {4}",
region.Region, region.cs.BaseNickname, region.cs.Server, region.cs.IrcChannel,
e.Message);
}
} }
} // Called immediately before the region module is unloaded. Cleanup
// the region.
// Called immediately before the region module is unloaded. Close all
// associated channels.
public void Close() public void Close()
{ {
@ -169,47 +156,14 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
if (!enabled) if (!enabled)
return; return;
// Stop each of the region sessions
foreach (RegionState region in m_regions)
{
m_log.InfoFormat("[IRC-Bridge] Closing connection for {0}:{1} on IRC server {2}:{3}",
region.Region, region.cs.BaseNickname, region.cs.Server, region.cs.IrcChannel);
try
{
region.Close(); region.Close();
} lock(m_regions) m_regions.Remove(region);
catch (Exception e)
{
m_log.ErrorFormat("[IRC-Bridge] Close failed for {0}:{1} on IRC server {2}:{3} : {4}",
region.Region, region.cs.BaseNickname, region.cs.Server, region.cs.IrcChannel,
e.Message);
}
}
// Perform final cleanup of the channels (they now have no active clients)
foreach (ChannelState channel in m_channels)
{
m_log.InfoFormat("[IRC-Bridge] Closing connection for {0} on IRC server {1}:{2}",
channel.BaseNickname, channel.Server, channel.IrcChannel);
try
{
channel.Close();
}
catch (Exception e)
{
m_log.ErrorFormat("[IRC-Bridge] Close failed for {0} on IRC server {1}:{2} : {3}",
channel.BaseNickname, channel.Server, channel.IrcChannel,
e.Message);
}
}
} }
#endregion #endregion
public XmlRpcResponse XmlRpcAdminMethod(XmlRpcRequest request) public static XmlRpcResponse XmlRpcAdminMethod(XmlRpcRequest request)
{ {
m_log.Info("[IRC-Bridge]: XML RPC Admin Entry"); m_log.Info("[IRC-Bridge]: XML RPC Admin Entry");

View File

@ -57,6 +57,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
private const int WD_INTERVAL = 1000; // base watchdog interval private const int WD_INTERVAL = 1000; // base watchdog interval
private static int PING_PERIOD = 15; // WD intervals per PING private static int PING_PERIOD = 15; // WD intervals per PING
private static int ICCD_PERIOD = 10; // WD intervals between Connects private static int ICCD_PERIOD = 10; // WD intervals between Connects
private static int L_TIMEOUT = 10; // Login time out interval
private static int _idk_ = 0; // core connector identifier private static int _idk_ = 0; // core connector identifier
private static int _pdk_ = 0; // ping interval counter private static int _pdk_ = 0; // ping interval counter
@ -118,6 +119,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
} }
private bool m_connected = false; // connection status private bool m_connected = false; // connection status
private bool m_pending = false; // login disposition
private int m_timeout = L_TIMEOUT; // login timeout counter
public bool Connected public bool Connected
{ {
get { return m_connected; } get { return m_connected; }
@ -326,6 +329,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
if (m_connected) return; if (m_connected) return;
m_connected = true; m_connected = true;
m_pending = true;
m_timeout = L_TIMEOUT;
m_tcp = new TcpClient(m_server, (int)m_port); m_tcp = new TcpClient(m_server, (int)m_port);
m_stream = m_tcp.GetStream(); m_stream = m_tcp.GetStream();
@ -349,8 +354,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
m_writer.Flush(); m_writer.Flush();
m_log.InfoFormat("[IRC-Connector-{0}]: {1} has joined {2}", idn, m_nick, m_ircChannel); m_log.InfoFormat("[IRC-Connector-{0}]: {1} has asked to join {2}", idn, m_nick, m_ircChannel);
m_log.InfoFormat("[IRC-Connector-{0}] Connected", idn);
} }
catch (Exception e) catch (Exception e)
@ -358,6 +362,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
m_log.ErrorFormat("[IRC-Connector-{0}] cannot connect {1} to {2}:{3}: {4}", m_log.ErrorFormat("[IRC-Connector-{0}] cannot connect {1} to {2}:{3}: {4}",
idn, m_nick, m_server, m_port, e.Message); idn, m_nick, m_server, m_port, e.Message);
m_connected = false; m_connected = false;
m_pending = false;
} }
} }
@ -396,6 +401,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
try { m_tcp.Close(); } catch (Exception) {} try { m_tcp.Close(); } catch (Exception) {}
m_connected = false; m_connected = false;
m_pending = false;
} }
@ -516,7 +522,12 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
// m_log.Debug(e); // m_log.Debug(e);
} }
// This is potentially circular, but harmless if so.
// The connection is marked as not connected the first time
// through reconnect.
if (m_enabled) Reconnect(); if (m_enabled) Reconnect();
} }
private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)", private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)",
@ -615,7 +626,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
case "003" : // Welcome ... case "003" : // Welcome ...
break; break;
case "004" : // Server information case "004" : // Server information
m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms); m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
commArgs = parms.Split(CS_SPACE); commArgs = parms.Split(CS_SPACE);
c_server = commArgs[1]; c_server = commArgs[1];
m_server = c_server; m_server = c_server;
@ -639,10 +650,10 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
case "366" : // End-of-Name list marker case "366" : // End-of-Name list marker
case "372" : // MOTD body case "372" : // MOTD body
case "375" : // MOTD start case "375" : // MOTD start
m_log.InfoFormat("[IRC-Connector-{0}] {1}", idn, parms.Split(CS_SPACE,2)[1]); m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
break; break;
case "376" : // MOTD end case "376" : // MOTD end
m_log.InfoFormat("[IRC-Connector-{0}] {1}", idn, parms.Split(CS_SPACE,2)[1]); m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
motd = true; motd = true;
break; break;
case "451" : // Not registered case "451" : // Not registered
@ -650,7 +661,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
case "433" : // Nickname in use case "433" : // Nickname in use
// Gen a new name // Gen a new name
m_nick = m_baseNick + Util.RandomClass.Next(1, 99); m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
m_log.ErrorFormat("[IRC-Connector-{0}]: IRC SERVER reports NicknameInUse, trying {1}", idn, m_nick); m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick);
// Retry // Retry
m_writer.WriteLine(String.Format("NICK {0}", m_nick)); m_writer.WriteLine(String.Format("NICK {0}", m_nick));
m_writer.Flush(); m_writer.Flush();
@ -659,43 +670,57 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
m_writer.Flush(); m_writer.Flush();
break; break;
case "479" : // Bad channel name, etc. This will never work, so disable the connection
m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd);
m_enabled = false;
m_connected = false;
m_pending = false;
break;
case "NOTICE" : case "NOTICE" :
m_log.WarnFormat("[IRC-Connector-{0}] {1}", idn, parms.Split(CS_SPACE,2)[1]); m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
break; break;
case "ERROR" : case "ERROR" :
m_log.ErrorFormat("[IRC-Connector-{0}] {1}", idn, parms.Split(CS_SPACE,2)[1]); m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
if (parms.Contains("reconnect too fast")) if (parms.Contains("reconnect too fast"))
ICCD_PERIOD++; ICCD_PERIOD++;
m_pending = false;
Reconnect();
break; break;
case "PING" : case "PING" :
m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms); m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
m_writer.WriteLine(String.Format("PONG {0}", parms)); m_writer.WriteLine(String.Format("PONG {0}", parms));
m_writer.Flush(); m_writer.Flush();
break; break;
case "PONG" : case "PONG" :
break; break;
case "JOIN": case "JOIN":
m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms); if (m_pending)
{
m_log.InfoFormat("[IRC-Connector-{0}] [{1}] Connected", idn, cmd);
m_pending = false;
}
m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
eventIrcJoin(pfx, cmd, parms); eventIrcJoin(pfx, cmd, parms);
break; break;
case "PART": case "PART":
m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms); m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
eventIrcPart(pfx, cmd, parms); eventIrcPart(pfx, cmd, parms);
break; break;
case "MODE": case "MODE":
m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms); m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
eventIrcMode(pfx, cmd, parms); eventIrcMode(pfx, cmd, parms);
break; break;
case "NICK": case "NICK":
m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms); m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
eventIrcNickChange(pfx, cmd, parms); eventIrcNickChange(pfx, cmd, parms);
break; break;
case "KICK": case "KICK":
m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms); m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
eventIrcKick(pfx, cmd, parms); eventIrcKick(pfx, cmd, parms);
break; break;
case "QUIT": case "QUIT":
m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms); m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
eventIrcQuit(pfx, cmd, parms); eventIrcQuit(pfx, cmd, parms);
break; break;
default : default :
@ -813,6 +838,18 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
} }
else else
{ {
if (connector.m_pending)
{
if (connector.m_timeout == 0)
{
m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn);
connector.Reconnect();
}
else
connector.m_timeout--;
}
if (_pdk_ == 0) if (_pdk_ == 0)
{ {
try try
@ -827,6 +864,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
connector.Reconnect(); connector.Reconnect();
} }
} }
} }
} }
} }

View File

@ -123,6 +123,10 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
} }
// Called by IRCBridgeModule.Close immediately prior to unload // Called by IRCBridgeModule.Close immediately prior to unload
// of the module for this region. This happens when the region
// is being removed or the server is terminating. The IRC
// BridgeModule will remove the region from the region list
// when control returns.
public void Close() public void Close()
{ {