From abc5df12c883ab14bf7926fc047431249ba52cb5 Mon Sep 17 00:00:00 2001 From: Homer Horwitz Date: Sun, 15 Mar 2009 21:34:28 +0000 Subject: [PATCH] This patch improves MXP connect and disconnect functionality. - Avatars are now properly on top of terrain. - ScenePresence is now removed from Scene only once. Fixes Mantis #3302. Thanks tlaukkan. --- .../Client/MXP/ClientStack/MXPClientView.cs | 34 ++- OpenSim/Client/MXP/MXPModule.cs | 20 +- .../MXP/PacketHandler/MXPPacketServer.cs | 267 ++++++++++++------ 3 files changed, 207 insertions(+), 114 deletions(-) diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs index 9052443676..5a7accf9e6 100644 --- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs +++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs @@ -189,8 +189,6 @@ namespace OpenSim.Client.MXP.ClientStack private void MXPProcessModifyRequest(ModifyRequestMessage modifyRequest) { - m_log.Debug("Received modify request for: " + modifyRequest.ObjectFragment.ObjectName); - ObjectFragment objectFragment=modifyRequest.ObjectFragment; if (objectFragment.ObjectId == m_userID.Guid) { @@ -448,7 +446,7 @@ namespace OpenSim.Client.MXP.ClientStack Session.Send(pe); } - public void MXPSentSynchronizationBegin(int objectCount) + public void MXPSendSynchronizationBegin(int objectCount) { m_objectsToSynchronize = objectCount; m_objectsSynchronized = 0; @@ -767,6 +765,15 @@ namespace OpenSim.Client.MXP.ClientStack //throw new System.NotImplementedException(); } + public void OnClean() + { + if (OnLogout != null) + OnLogout(this); + + if (OnConnectionClosed != null) + OnConnectionClosed(this); + } + public void Close(bool ShutdownCircuit) { m_log.Info("[MXP ClientStack] Close Called with SC=" + ShutdownCircuit); @@ -780,16 +787,6 @@ namespace OpenSim.Client.MXP.ClientStack Session.SetStateDisconnected(); } - // Handle OpenSim cleanup - if (ShutdownCircuit) - { - if (OnConnectionClosed != null) - OnConnectionClosed(this); - } - else - { - Scene.RemoveClient(AgentId); - } } public void Kick(string message) @@ -800,6 +797,17 @@ namespace OpenSim.Client.MXP.ClientStack public void Start() { Scene.AddNewClient(this); + + // Mimicking LLClientView which gets always set appearance from client. + OpenSim.Region.Framework.Scenes.Scene scene=(OpenSim.Region.Framework.Scenes.Scene)Scene; + AvatarAppearance appearance; + scene.GetAvatarAppearance(this,out appearance); + List visualParams = new List(); + foreach (byte visualParam in appearance.VisualParams) + { + visualParams.Add(visualParam); + } + OnSetAppearance(appearance.Texture.ToBytes(), visualParams); } public void Stop() diff --git a/OpenSim/Client/MXP/MXPModule.cs b/OpenSim/Client/MXP/MXPModule.cs index 6ec7744799..4eb0058f36 100644 --- a/OpenSim/Client/MXP/MXPModule.cs +++ b/OpenSim/Client/MXP/MXPModule.cs @@ -38,21 +38,20 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Client.MXP { + /** * MXP Client Module which adds MXP support to client / region communication. */ public class MXPModule : IRegionModule { - - private int m_port = 1253; - //private int m_ticks = 0; - private bool m_shutdown = false; + private MXPPacketServer m_server; private IConfigSource m_config; - private readonly Timer m_ticker = new Timer(100); - private readonly Dictionary m_scenes = new Dictionary(); + private int m_port = 1253; - private MXPPacketServer m_server; + private readonly Dictionary m_scenes = new Dictionary(); + private readonly Timer m_ticker = new Timer(100); + private bool m_shutdown = false; public void Initialise(Scene scene, IConfigSource source) { @@ -88,13 +87,6 @@ namespace OpenSim.Client.MXP if (!m_shutdown) m_ticker.Start(); - - // Commenting this at because of the excess flood to log. - // TODO: Add ini file option. - /*if (++ticks % 100 == 0) - { - server.PrintDebugInformation(); - }*/ } public void Close() diff --git a/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs b/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs index ba7bd00ae0..bb049554ef 100644 --- a/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs +++ b/OpenSim/Client/MXP/PacketHandler/MXPPacketServer.cs @@ -40,6 +40,7 @@ using OpenSim.Client.MXP.ClientStack; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; using OpenSim.Framework.Communications; +using System.Security.Cryptography; namespace OpenSim.Client.MXP.PacketHandler { @@ -214,17 +215,6 @@ namespace OpenSim.Client.MXP.PacketHandler #region Processing - public void PrintDebugInformation() - { - m_log.Info("[MXP ClientStack] Statistics report"); - m_log.Info("Pending Sessions: " + PendingSessionCount); - m_log.Info("Sessions: " + SessionCount + " (Clients: " + m_clients.Count + " )"); - m_log.Info("Transmitter Alive?: " + IsTransmitterAlive); - m_log.Info("Packets Sent/Received: " + PacketsSent + " / " + PacketsReceived); - m_log.Info("Bytes Sent/Received: " + BytesSent + " / " + BytesReceived); - m_log.Info("Send/Receive Rate (bps): " + SendRate + " / " + ReceiveRate); - } - public void Process() { ProcessMessages(); @@ -243,7 +233,7 @@ namespace OpenSim.Client.MXP.PacketHandler foreach (MXPClientView clientView in m_sessionsToRemove) { - clientView.Scene.RemoveClient(clientView.AgentId); + clientView.OnClean(); m_clients.Remove(clientView); m_sessions.Remove(clientView.Session); } @@ -251,59 +241,6 @@ namespace OpenSim.Client.MXP.PacketHandler m_sessionsToRemove.Clear(); } - public bool AuthoriseUser(string participantName, string password, UUID sceneId, out UUID userId, out string firstName, out string lastName) - { - userId = UUID.Zero; - firstName = ""; - lastName = ""; - - if (!m_scenes.ContainsKey(sceneId)) - { - m_log.Info("Login failed as region was not found: " + sceneId); - return false; - } - - string[] nameParts=participantName.Split(' '); - if (nameParts.Length != 2) - { - m_log.Info("Login failed as user name is not formed of first and last name separated by space: " + participantName); - return false; - } - firstName = nameParts[0]; - lastName = nameParts[1]; - - UserProfileData userProfile = m_scenes[sceneId].CommsManager.UserService.GetUserProfile(firstName, lastName); - if (userProfile == null && !m_accountsAuthenticate) - { - userId = ((UserManagerBase)m_scenes[sceneId].CommsManager.UserService).AddUser(firstName, lastName, "test", "", 1000, 1000); - } - else - { - if (userProfile == null) - { - m_log.Info("Login failed as user was not found: " + participantName); - return false; - } - userId = userProfile.ID; - } - - if (m_accountsAuthenticate) - { - if (!password.StartsWith("$1$")) - { - password = "$1$" + Util.Md5Hash(password); - } - password = password.Remove(0, 3); //remove $1$ - string s = Util.Md5Hash(password + ":" + userProfile.PasswordSalt); - return (userProfile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase) - || userProfile.PasswordHash.Equals(password, StringComparison.InvariantCultureIgnoreCase)); - } - else - { - return true; - } - } - public void ProcessMessages() { if (m_transmitter.PendingSessionCount > 0) @@ -327,9 +264,9 @@ namespace OpenSim.Client.MXP.PacketHandler JoinRequestMessage joinRequestMessage = (JoinRequestMessage) message; - UUID userId; - string firstName; - string lastName; + m_log.Info("[MXP ClientStack] Session join request: " + session.SessionId + " (" + + (session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" + + session.RemoteEndPoint.Port + ")"); if (joinRequestMessage.BubbleId == Guid.Empty) { @@ -337,7 +274,7 @@ namespace OpenSim.Client.MXP.PacketHandler { if (scene.RegionInfo.RegionName == joinRequestMessage.BubbleName) { - m_log.Info("Resolved region by name: " + joinRequestMessage.BubbleName + " (" + scene.RegionInfo.RegionID+")"); + m_log.Info("[MXP ClientStack] Resolved region by name: " + joinRequestMessage.BubbleName + " (" + scene.RegionInfo.RegionID + ")"); joinRequestMessage.BubbleId = scene.RegionInfo.RegionID.Guid; } } @@ -345,47 +282,71 @@ namespace OpenSim.Client.MXP.PacketHandler if (joinRequestMessage.BubbleId == Guid.Empty) { - m_log.Warn("Failed to resolve region by name: "+joinRequestMessage.BubbleName); + m_log.Warn("[MXP ClientStack] Failed to resolve region by name: " + joinRequestMessage.BubbleName); + } + + UUID sceneId = new UUID(joinRequestMessage.BubbleId); + + bool regionExists = true; + if (!m_scenes.ContainsKey(sceneId)) + { + m_log.Info("[MXP ClientStack] No such region: " + sceneId); + regionExists=false; } - bool authorized = AuthoriseUser(joinRequestMessage.ParticipantName, + UserProfileData user=null; + UUID userId=UUID.Zero; + string firstName=null; + string lastName=null; + bool authorized = regionExists?AuthoriseUser(joinRequestMessage.ParticipantName, joinRequestMessage.ParticipantPassphrase, - new UUID(joinRequestMessage.BubbleId), out userId, out firstName, out lastName); + new UUID(joinRequestMessage.BubbleId), out userId, out firstName, out lastName, out user) + :false; if (authorized) - { - Scene target = m_scenes[new UUID(joinRequestMessage.BubbleId)]; - + { + Scene scene = m_scenes[sceneId]; 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 + ")"); + (session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" + + session.RemoteEndPoint.Port + ")"); - AcceptConnection(session, joinRequestMessage, mxpSessionID,userId); + m_log.Info("[MXP ClientStack] Attaching UserAgent to UserProfile..."); + AttachUserAgentToUserProfile(session, mxpSessionID, sceneId, user); + m_log.Info("[MXP ClientStack] Attached UserAgent to UserProfile."); + m_log.Info("[MXP ClientStack] Preparing Scene to Connection..."); + PrepareSceneForConnection(mxpSessionID, sceneId, user); + m_log.Info("[MXP ClientStack] Prepared Scene to Connection."); + m_log.Info("[MXP ClientStack] Accepting connection..."); + AcceptConnection(session, joinRequestMessage, mxpSessionID, userId); + m_log.Info("[MXP ClientStack] Accepted connection."); - MXPClientView client = new MXPClientView(session, mxpSessionID,userId, target, - firstName, lastName); - m_log.Info("[MXP ClientStack] Created Client"); + m_log.Info("[MXP ClientStack] Creating ClientView...."); + MXPClientView client = new MXPClientView(session, mxpSessionID, userId, scene, firstName, lastName); m_clients.Add(client); + m_log.Info("[MXP ClientStack] Created ClientView."); - m_log.Info("[MXP ClientStack] Adding to Scene"); - target.ClientManager.Add(client.CircuitCode, client); - m_log.Info("[MXP ClientStack] Initialising..."); + m_log.Info("[MXP ClientStack] Adding ClientView to Scene..."); + scene.ClientManager.Add(client.CircuitCode, client); + m_log.Info("[MXP ClientStack] Added ClientView to Scene."); - client.MXPSentSynchronizationBegin(m_scenes[new UUID(joinRequestMessage.BubbleId)].SceneContents.GetTotalObjectsCount()); + + client.MXPSendSynchronizationBegin(m_scenes[new UUID(joinRequestMessage.BubbleId)].SceneContents.GetTotalObjectsCount()); + m_log.Info("[MXP ClientStack] Starting ClientView..."); try { client.Start(); - } catch( Exception e) + m_log.Info("[MXP ClientStack] Started ClientView."); + } + catch (Exception e) { m_log.Info(e); } m_log.Info("[MXP ClientStack] Connected"); - //target.EventManager.TriggerOnNewClient(client); } else { @@ -512,6 +473,138 @@ namespace OpenSim.Client.MXP.PacketHandler session.SetStateDisconnected(); } + public bool AuthoriseUser(string participantName, string password, UUID sceneId, out UUID userId, out string firstName, out string lastName, out UserProfileData userProfile) + { + userId = UUID.Zero; + firstName = ""; + lastName = ""; + userProfile = null; + + string[] nameParts = participantName.Split(' '); + if (nameParts.Length != 2) + { + m_log.Info("[MXP ClientStack] Login failed as user name is not formed of first and last name separated by space: " + participantName); + return false; + } + firstName = nameParts[0]; + lastName = nameParts[1]; + + userProfile = m_scenes[sceneId].CommsManager.UserService.GetUserProfile(firstName, lastName); + if (userProfile == null && !m_accountsAuthenticate) + { + userId = ((UserManagerBase)m_scenes[sceneId].CommsManager.UserService).AddUser(firstName, lastName, "test", "", 1000, 1000); + } + else + { + if (userProfile == null) + { + m_log.Info("Login failed as user was not found: " + participantName); + return false; + } + userId = userProfile.ID; + } + + if (m_accountsAuthenticate) + { + if (!password.StartsWith("$1$")) + { + password = "$1$" + Util.Md5Hash(password); + } + password = password.Remove(0, 3); //remove $1$ + string s = Util.Md5Hash(password + ":" + userProfile.PasswordSalt); + return (userProfile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase) + || userProfile.PasswordHash.Equals(password, StringComparison.InvariantCultureIgnoreCase)); + } + else + { + return true; + } + } + + private void AttachUserAgentToUserProfile(Session session, UUID sessionId, UUID sceneId, UserProfileData userProfile) + { + Scene scene = m_scenes[sceneId]; + CommunicationsManager commsManager = m_scenes[sceneId].CommsManager; + UserManagerBase userService = (UserManagerBase)commsManager.UserService; + + UserAgentData agent = new UserAgentData(); + + // User connection + agent.AgentOnline = true; + agent.AgentIP = session.RemoteEndPoint.Address.ToString(); + agent.AgentPort = (uint)session.RemoteEndPoint.Port; + + agent.SecureSessionID = UUID.Random(); + agent.SessionID = sessionId; + + // Profile UUID + agent.ProfileID = userProfile.ID; + + // Current location/position/alignment + if (userProfile.CurrentAgent != null) + { + agent.Region = userProfile.CurrentAgent.Region; + agent.Handle = userProfile.CurrentAgent.Handle; + agent.Position = userProfile.CurrentAgent.Position; + agent.LookAt = userProfile.CurrentAgent.LookAt; + } + else + { + agent.Region = userProfile.HomeRegionID; + agent.Handle = userProfile.HomeRegion; + agent.Position = userProfile.HomeLocation; + agent.LookAt = userProfile.HomeLookAt; + } + + // What time did the user login? + agent.LoginTime = Util.UnixTimeSinceEpoch(); + agent.LogoutTime = 0; + + userProfile.CurrentAgent = agent; + + userService.CommitAgent(ref userProfile); + } + + private void PrepareSceneForConnection(UUID sessionId, UUID sceneId, UserProfileData userProfile) + { + Scene scene = m_scenes[sceneId]; + CommunicationsManager commsManager = m_scenes[sceneId].CommsManager; + UserManagerBase userService = (UserManagerBase)commsManager.UserService; + + AgentCircuitData agent = new AgentCircuitData(); + agent.AgentID = userProfile.ID; + agent.firstname = userProfile.FirstName; + agent.lastname = userProfile.SurName; + agent.SessionID = sessionId; + agent.SecureSessionID = userProfile.CurrentAgent.SecureSessionID; + agent.circuitcode = sessionId.CRC(); + agent.BaseFolder = UUID.Zero; + agent.InventoryFolder = UUID.Zero; + agent.startpos = new Vector3(0, 0, 0); // TODO Fill in region start position + agent.CapsPath = "http://localhost/"; + agent.Appearance = userService.GetUserAppearance(userProfile.ID); + + if (agent.Appearance == null) + { + m_log.WarnFormat("[INTER]: Appearance not found for {0} {1}. Creating default.", agent.firstname, agent.lastname); + agent.Appearance = new AvatarAppearance(); + } + + scene.NewUserConnection(agent); + + } + + public void PrintDebugInformation() + { + m_log.Info("[MXP ClientStack] Statistics report"); + m_log.Info("Pending Sessions: " + PendingSessionCount); + m_log.Info("Sessions: " + SessionCount + " (Clients: " + m_clients.Count + " )"); + m_log.Info("Transmitter Alive?: " + IsTransmitterAlive); + m_log.Info("Packets Sent/Received: " + PacketsSent + " / " + PacketsReceived); + m_log.Info("Bytes Sent/Received: " + BytesSent + " / " + BytesReceived); + m_log.Info("Send/Receive Rate (bps): " + SendRate + " / " + ReceiveRate); + } + #endregion }