From 937a2e6dcae6c4369ee6952a2697ae31aaba4903 Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Sun, 22 Feb 2009 08:48:55 +0000 Subject: * Adds initial support for the MXP Virtual Worlds protocol (http://www.bubblecloud.org) * Handled via the MXPModule.cs located in OpenSim.Client.MXP namespace. * Also implements MXPClientView and MXPPacketServer for IClientAPI compatibility. * No changes were required to Core to implement this - the thing is self contained in OpenSim.Client.MXP.dll. * Includes reference implementation of MXP as MXP.dll - this is under the Apache 2.0 license. * Requires OpenSim.ini setting to enable. "[MXP] \n Enabled=true \n Port=1253" * May break. Highly untested. --- .../Client/MXP/PacketHandler/MXPPacketServer.cs | 367 +++++++++++++++++++++ 1 file changed, 367 insertions(+) create mode 100644 OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs (limited to 'OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs') diff --git a/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs b/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs new file mode 100644 index 0000000..b35ab9c --- /dev/null +++ b/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs @@ -0,0 +1,367 @@ +/* This file borrows heavily from MXPServer.cs - the reference MXPServer + * See http://www.bubblecloud.org for a copy of the original file and + * implementation details. */ +using System; +using System.Collections.Generic; +using System.Reflection; +using log4net; +using MXP; +using MXP.Messages; +using OpenMetaverse; +using OpenSim.Client.MXP.ClientStack; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Client.MXP.PacketHandler +{ + class MXPPacketServer + { + internal static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private readonly List Clients = new List(); + private readonly Dictionary Scenes; + + #region Fields + + private readonly Transmitter transmitter; + + private readonly IList sessions = new List(); + private readonly IList sessionsToRemove = new List(); + + private readonly String cloudUrl; + private readonly String programName; + private readonly byte programMajorVersion; + private readonly byte programMinorVersion; + + #endregion + + #region Constructors + + public MXPPacketServer(string cloudUrl, int port, Dictionary scenes) + { + this.cloudUrl = cloudUrl; + + Scenes = scenes; + + programMinorVersion = 63; + programMajorVersion = 0; + programName = "OpenSimulator"; + + transmitter = new Transmitter(port); + } + + #endregion + + #region Properties + + /// + /// Number of sessions pending. (Process() accepts pending sessions). + /// + public int PendingSessionCount + { + get + { + return transmitter.PendingSessionCount; + } + } + /// + /// Number of connected sessions. + /// + public int SessionCount + { + get + { + return sessions.Count; + } + } + /// + /// Property reflecting whether client transmitter threads are alive. + /// + public bool IsTransmitterAlive + { + get + { + return transmitter != null && transmitter.IsAlive; + } + } + /// + /// Number of packets sent. + /// + public ulong PacketsSent + { + get + { + return transmitter != null ? transmitter.PacketsSent : 0; + } + } + /// + /// Number of packets received. + /// + public ulong PacketsReceived + { + get + { + return transmitter != null ? transmitter.PacketsReceived : 0; + } + } + /// + /// Bytes client has received so far. + /// + public ulong BytesReceived + { + get + { + return transmitter != null ? transmitter.BytesReceived : 0; + } + } + /// + /// Bytes client has sent so far. + /// + public ulong BytesSent + { + get + { + return transmitter != null ? transmitter.BytesSent : 0; + } + } + /// + /// Number of bytes received (bytes per second) during past second. + /// + public double ReceiveRate + { + get + { + return transmitter != null ? transmitter.ReceiveRate : 0; + } + } + /// + /// Number of bytes sent (bytes per second) during past second. + /// + public double SendRate + { + get + { + return transmitter != null ? transmitter.SendRate : 0; + } + } + + #endregion + + #region Session Management + + public void Disconnect(Session session) + { + if (session.IsConnected) + { + Message message = MessageFactory.Current.ReserveMessage(typeof(LeaveRequestMessage)); + session.Send(message); + MessageFactory.Current.ReleaseMessage(message); + } + else + { + throw new Exception("Not connected."); + } + } + + #endregion + + + #region Processing + + public void PrintDebugInformation() + { + m_log.Info("[MXP ClientStack] Statistics report"); + m_log.Info("Pending Sessions: " + PendingSessionCount); + m_log.Info("Sessions: " + SessionCount + " (Clients: " + Clients.Count + " )"); + m_log.Info("Transmitter Alive?: " + IsTransmitterAlive); + m_log.Info("Packets Sent/Recieved: " + PacketsSent + " / " + PacketsReceived); + m_log.Info("Bytes Sent/Recieved: " + BytesSent + " / " + BytesReceived); + m_log.Info("Send/Recieve Rate (bps): " + SendRate + " / " + ReceiveRate); + } + + public void Process() + { + ProcessMessages(); + Clean(); + } + + public void Clean() + { + foreach (MXPClientView clientView in Clients) + { + if (clientView.Session.SessionState == SessionState.Disconnected) + { + sessionsToRemove.Add(clientView); + } + } + + foreach (MXPClientView clientView in sessionsToRemove) + { + clientView.Scene.RemoveClient(clientView.AgentId); + Clients.Remove(clientView); + sessions.Remove(clientView.Session); + } + + sessionsToRemove.Clear(); + } + + public bool AuthoriseUser(string participantName, string pass, UUID scene) + { + if (Scenes.ContainsKey(scene)) + return true; + + return false; + } + + public void ProcessMessages() + { + if (transmitter.PendingSessionCount > 0) + { + sessions.Add(transmitter.AcceptPendingSession()); + } + + foreach (MXPClientView clientView in Clients) + { + + int messagesProcessedCount = 0; + Session session = clientView.Session; + + while (session.AvailableMessages > 0) + { + + Message message = session.Receive(); + + if (message.GetType() == typeof(JoinRequestMessage)) + { + + JoinRequestMessage joinRequestMessage = (JoinRequestMessage)message; + + bool authorized = AuthoriseUser(joinRequestMessage.ParticipantName, + joinRequestMessage.ParticipantPassphrase, + new UUID(joinRequestMessage.BubbleId)); + + if (authorized) + { + Scene target = Scenes[new UUID(joinRequestMessage.BubbleId)]; + + UUID mxpSessionID = UUID.Random(); + + m_log.Info("[MXP ClientStack] Session join request success: " + session.SessionId + " (" + (session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port + ")"); + + AcceptConnection(session, joinRequestMessage, mxpSessionID); + + MXPClientView client = new MXPClientView(session, mxpSessionID, target, + joinRequestMessage.ParticipantName); + Clients.Add(client); + + target.AddNewClient(client); + } + else + { + m_log.Info("[MXP ClientStack] Session join request failure: " + session.SessionId + " (" + (session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port + ")"); + + DeclineConnection(session, joinRequestMessage); + } + + } + if (message.GetType() == typeof(LeaveRequestMessage)) + { + + LeaveResponseMessage leaveResponseMessage = (LeaveResponseMessage)MessageFactory.Current.ReserveMessage( + typeof(LeaveResponseMessage)); + + m_log.Info("[MXP ClientStack] Session leave request: " + session.SessionId + " (" + (session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port + ")"); + + leaveResponseMessage.RequestMessageId = message.MessageId; + leaveResponseMessage.FailureCode = 0; + session.Send(leaveResponseMessage); + + if (session.SessionState != SessionState.Disconnected) + { + session.SetStateDisconnected(); + } + + m_log.Info("[MXP ClientStack] Removing Client from Scene"); + clientView.Scene.RemoveClient(clientView.AgentId); + } + if (message.GetType() == typeof(LeaveResponseMessage)) + { + + LeaveResponseMessage leaveResponseMessage = (LeaveResponseMessage)message; + + m_log.Info("[MXP ClientStack] Session leave response: " + session.SessionId + " (" + (session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port + ")"); + + if (leaveResponseMessage.FailureCode == 0) + { + session.SetStateDisconnected(); + } + + m_log.Info("[MXP ClientStack] Removing Client from Scene"); + clientView.Scene.RemoveClient(clientView.AgentId); + } + else + { + clientView.ProcessMXPPacket(message); + } + + MessageFactory.Current.ReleaseMessage(message); + messagesProcessedCount++; + if (messagesProcessedCount > 1000) + { + break; + } + } + } + } + + private void AcceptConnection(Session session, JoinRequestMessage joinRequestMessage, UUID mxpSessionID) + { + JoinResponseMessage joinResponseMessage = (JoinResponseMessage)MessageFactory.Current.ReserveMessage( + typeof(JoinResponseMessage)); + + joinResponseMessage.RequestMessageId = joinRequestMessage.MessageId; + joinResponseMessage.FailureCode = 0; + + joinResponseMessage.ParticipantId = mxpSessionID.Guid; + joinResponseMessage.CloudUrl = cloudUrl; + + joinResponseMessage.BubbleName = Scenes[new UUID(joinRequestMessage.BubbleId)].RegionInfo.RegionName; + + joinResponseMessage.BubbleRealTime = 0; + joinResponseMessage.ProgramName = programName; + joinResponseMessage.ProgramMajorVersion = programMajorVersion; + joinResponseMessage.ProgramMinorVersion = programMinorVersion; + joinResponseMessage.ProtocolMajorVersion = MxpConstants.ProtocolMajorVersion; + joinResponseMessage.ProtocolMinorVersion = MxpConstants.ProtocolMinorVersion; + + session.Send(joinResponseMessage); + + session.SetStateConnected(); + } + + private void DeclineConnection(Session session, Message joinRequestMessage) + { + JoinResponseMessage joinResponseMessage = (JoinResponseMessage)MessageFactory.Current.ReserveMessage(typeof(JoinResponseMessage)); + + joinResponseMessage.RequestMessageId = joinRequestMessage.MessageId; + joinResponseMessage.FailureCode = 1; + + joinResponseMessage.CloudUrl = cloudUrl; + + joinResponseMessage.BubbleName = "Declined OpenSim Region"; // Dont reveal anything about the sim in the disconnect notice + + joinResponseMessage.BubbleRealTime = 0; + joinResponseMessage.ProgramName = programName; + joinResponseMessage.ProgramMajorVersion = programMajorVersion; + joinResponseMessage.ProgramMinorVersion = programMinorVersion; + joinResponseMessage.ProtocolMajorVersion = MxpConstants.ProtocolMajorVersion; + joinResponseMessage.ProtocolMinorVersion = MxpConstants.ProtocolMinorVersion; + + session.Send(joinResponseMessage); + + session.SetStateDisconnected(); + } + + #endregion + + } +} -- cgit v1.1