Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

dsg
Dan Lake 2011-04-28 16:15:04 -07:00
commit c7fa637f0d
122 changed files with 1570 additions and 4469 deletions

View File

@ -1,34 +1,36 @@
The following people have contributed to OpenSim (Thank you
for your effort!)
Add your name in here if you have committed to OpenSim
= Current OpenSim Developers (in very rough order of appearance) =
These folks represent the current core team for OpenSim, and are the
people that make the day to day of OpenSim happen.
* justincc
* chi11ken (Genkii)
* dahlia
* Melanie Thielker
* Diva (Crista Lopes, University of California, Irvine)
* Dan Lake (Intel)
* Marck
* Mic Bowman (Intel)
* BlueWall (James Hughes)
= Core Developers Following the White Rabbit =
Core developers who have temporarily (we hope) gone chasing the white rabbit.
They are in all similar to the active core developers, except that they haven't
been that active lately, so their voting rights are awaiting their come back.
* MW (Tribal Media AB)
* Adam Frisby (DeepThink Pty Ltd)
* MingChen (DeepThink Pty Ltd)
* lbsa71 (Tribal Media AB)
* Sean Dague / sdague (IBM)
* Tedd
* justincc
* Teravus (w3z)
* Johan Berntsson (3Di)
* Ckrinke (Charles Krinke)
* chi11ken (Genkii)
* adjohn (Genkii)
* Dr Scofield aka Dirk Husemann (IBM Research - Zurich)
* dahlia
* mikem (3Di)
* Melanie Thielker
* Homer_Horwitz
* idb (Ian Brown)
* Diva (Crista Lopes, University of California, Irvine)
* nlin (3Di)
* Arthur Rodrigo S Valadares (IBM)
* BlueWall (James Hughes)
* John Hurliman
= Past Open Sim Developers =
These folks are alumns of the OpenSim core group, but are now
@ -44,6 +46,12 @@ where we are today.
* Dalien
* Darok
* Alondria
* Sean Dague / sdague (IBM)
* Tedd
* MingChen (DeepThink Pty Ltd)
* adjohn (Genkii)
* idb (Ian Brown)
* Johan Berntsson (3Di)
= Additional OpenSim Contributors =
@ -102,6 +110,7 @@ what it is today.
* Misterblue (Intel)
* Mircea Kitsune
* mpallari
* MrMonkE
* nornalbion
* Omar Vera Ustariz (IBM)
* openlifegrid.com

File diff suppressed because it is too large Load Diff

View File

@ -1,131 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Timers;
using log4net;
using MXP;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Client.MXP.PacketHandler;
using OpenSim.Region.Framework.Interfaces;
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 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private MXPPacketServer m_server;
private IConfigSource m_config;
private int m_port = 1253;
private Timer m_ticker;
private readonly Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
private bool m_shutdown;
public void Initialise(Scene scene, IConfigSource source)
{
if (!m_scenes.ContainsKey(scene.RegionInfo.RegionID))
m_scenes.Add(scene.RegionInfo.RegionID, scene);
m_config = source;
}
public void PostInitialise()
{
if (m_config.Configs["MXP"] != null)
{
IConfig con = m_config.Configs["MXP"];
if (!con.GetBoolean("Enabled", false))
return;
m_port = con.GetInt("Port", m_port);
m_server = new MXPPacketServer(m_port, m_scenes,m_config.Configs["StandAlone"].GetBoolean("accounts_authenticate",true));
m_ticker = new Timer(100);
m_ticker.AutoReset = false;
m_ticker.Elapsed += ticker_Elapsed;
lock (m_ticker)
m_ticker.Start();
m_log.Info("[MXP ClientStack] MXP Enabled and Listening");
}
}
void ticker_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
m_server.Process();
}
catch (Exception ex)
{
m_log.Error("[MXP ClientStack]: Unhandled exception in process loop: " + ex.ToString() + " :" + ex.StackTrace.ToString());
}
if (!m_shutdown)
{
lock (m_ticker)
m_ticker.Start();
}
}
public void Close()
{
m_shutdown = true;
if (m_ticker != null)
{
lock (m_ticker)
m_ticker.Stop();
}
}
public string Name
{
get { return "MXP ClientStack Module"; }
}
public bool IsSharedModule
{
get { return true; }
}
}
}

View File

@ -1,42 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenSim.Client.MXP
{
public static class MXPUtil
{
public static string GenerateMXPURL(string server, int port, UUID bubbleID, Vector3 location)
{
return string.Format("mxp://{0}:{1}/{2}/{3}", server, port, bubbleID.Guid, location);
}
}
}

View File

@ -1,561 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* 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 System.Threading;
using log4net;
using MXP;
using MXP.Messages;
using OpenMetaverse;
using OpenSim.Client.MXP.ClientStack;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Framework.Communications;
using OpenSim.Services.Interfaces;
using System.Security.Cryptography;
namespace OpenSim.Client.MXP.PacketHandler
{
public class MXPPacketServer
{
internal static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
#region Fields
private readonly List<MXPClientView> m_clients = new List<MXPClientView>();
private readonly Dictionary<UUID, Scene> m_scenes;
private readonly Transmitter m_transmitter;
// private readonly Thread m_clientThread;
private readonly IList<Session> m_sessions = new List<Session>();
private readonly IList<Session> m_sessionsToClient = new List<Session>();
private readonly IList<MXPClientView> m_sessionsToRemove = new List<MXPClientView>();
private readonly int m_port;
// private readonly bool m_accountsAuthenticate;
private readonly String m_programName;
private readonly byte m_programMajorVersion;
private readonly byte m_programMinorVersion;
#endregion
#region Constructors
public MXPPacketServer(int port, Dictionary<UUID, Scene> scenes, bool accountsAuthenticate)
{
m_port = port;
// m_accountsAuthenticate = accountsAuthenticate;
m_scenes = scenes;
m_programMinorVersion = 63;
m_programMajorVersion = 0;
m_programName = "OpenSimulator";
m_transmitter = new Transmitter(port);
StartListener();
}
public void StartListener()
{
m_log.Info("[MXP ClientStack] Transmitter starting on UDP server port: " + m_port);
m_transmitter.Startup();
m_log.Info("[MXP ClientStack] Transmitter started. MXP version: "+MxpConstants.ProtocolMajorVersion+"."+MxpConstants.ProtocolMinorVersion+" Source Revision: "+MxpConstants.ProtocolSourceRevision);
}
#endregion
#region Properties
/// <summary>
/// Number of sessions pending. (Process() accepts pending sessions).
/// </summary>
public int PendingSessionCount
{
get
{
return m_transmitter.PendingSessionCount;
}
}
/// <summary>
/// Number of connected sessions.
/// </summary>
public int SessionCount
{
get
{
return m_sessions.Count;
}
}
/// <summary>
/// Property reflecting whether client transmitter threads are alive.
/// </summary>
public bool IsTransmitterAlive
{
get
{
return m_transmitter != null && m_transmitter.IsAlive;
}
}
/// <summary>
/// Number of packets sent.
/// </summary>
public ulong PacketsSent
{
get
{
return m_transmitter != null ? m_transmitter.PacketsSent : 0;
}
}
/// <summary>
/// Number of packets received.
/// </summary>
public ulong PacketsReceived
{
get
{
return m_transmitter != null ? m_transmitter.PacketsReceived : 0;
}
}
/// <summary>
/// Bytes client has received so far.
/// </summary>
public ulong BytesReceived
{
get
{
return m_transmitter != null ? m_transmitter.BytesReceived : 0;
}
}
/// <summary>
/// Bytes client has sent so far.
/// </summary>
public ulong BytesSent
{
get
{
return m_transmitter != null ? m_transmitter.BytesSent : 0;
}
}
/// <summary>
/// Number of bytes received (bytes per second) during past second.
/// </summary>
public double ReceiveRate
{
get
{
return m_transmitter != null ? m_transmitter.ReceiveRate : 0;
}
}
/// <summary>
/// Number of bytes sent (bytes per second) during past second.
/// </summary>
public double SendRate
{
get
{
return m_transmitter != null ? m_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 Process()
{
ProcessMessages();
Clean();
}
public void Clean()
{
foreach (MXPClientView clientView in m_clients)
{
if (clientView.Session.SessionState == SessionState.Disconnected)
{
m_sessionsToRemove.Add(clientView);
}
}
foreach (MXPClientView clientView in m_sessionsToRemove)
{
clientView.Scene.RemoveClient(clientView.AgentId);
clientView.OnClean();
m_clients.Remove(clientView);
m_sessions.Remove(clientView.Session);
}
m_sessionsToRemove.Clear();
}
public void ProcessMessages()
{
if (m_transmitter.PendingSessionCount > 0)
{
Session tmp = m_transmitter.AcceptPendingSession();
m_sessions.Add(tmp);
m_sessionsToClient.Add(tmp);
}
List<Session> tmpRemove = new List<Session>();
foreach (Session session in m_sessionsToClient)
{
while (session.AvailableMessages > 0)
{
Message message = session.Receive();
if (message.GetType() == typeof (JoinRequestMessage))
{
JoinRequestMessage joinRequestMessage = (JoinRequestMessage) message;
m_log.Info("[MXP ClientStack]: Session join request: " + session.SessionId + " (" +
(session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" +
session.RemoteEndPoint.Port + ")");
try
{
if (joinRequestMessage.BubbleId == Guid.Empty)
{
foreach (Scene scene in m_scenes.Values)
{
if (scene.RegionInfo.RegionName == joinRequestMessage.BubbleName)
{
m_log.Info("[MXP ClientStack]: Resolved region by name: " + joinRequestMessage.BubbleName + " (" + scene.RegionInfo.RegionID + ")");
joinRequestMessage.BubbleId = scene.RegionInfo.RegionID.Guid;
}
}
}
if (joinRequestMessage.BubbleId == Guid.Empty)
{
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;
}
UUID userId = UUID.Zero;
UserAccount account = null;
bool authorized = regionExists ? AuthoriseUser(joinRequestMessage.ParticipantName,
joinRequestMessage.ParticipantPassphrase,
new UUID(joinRequestMessage.BubbleId), out account)
: false;
if (authorized)
{
Scene scene = m_scenes[sceneId];
UUID mxpSessionID = UUID.Random();
string reason;
m_log.Debug("[MXP ClientStack]: Session join request success: " + session.SessionId + " (" +
(session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" +
session.RemoteEndPoint.Port + ")");
m_log.Debug("[MXP ClientStack]: Attaching UserAgent to UserProfile...");
UUID secureSession = UUID.Zero;
AttachUserAgentToUserProfile(account, session, mxpSessionID, sceneId, out secureSession);
m_log.Debug("[MXP ClientStack]: Attached UserAgent to UserProfile.");
m_log.Debug("[MXP ClientStack]: Preparing Scene to Connection...");
if (!PrepareSceneForConnection(mxpSessionID, secureSession, sceneId, account, out reason))
{
m_log.DebugFormat("[MXP ClientStack]: Scene refused connection: {0}", reason);
DeclineConnection(session, joinRequestMessage);
tmpRemove.Add(session);
continue;
}
m_log.Debug("[MXP ClientStack]: Prepared Scene to Connection.");
m_log.Debug("[MXP ClientStack]: Accepting connection...");
AcceptConnection(session, joinRequestMessage, mxpSessionID, userId);
m_log.Info("[MXP ClientStack]: Accepted connection.");
m_log.Debug("[MXP ClientStack]: Creating ClientView....");
MXPClientView client = new MXPClientView(session, mxpSessionID, userId, scene, account.FirstName, account.LastName);
m_clients.Add(client);
m_log.Debug("[MXP ClientStack]: Created ClientView.");
client.MXPSendSynchronizationBegin(m_scenes[new UUID(joinRequestMessage.BubbleId)].SceneContents.GetTotalObjectsCount());
m_log.Debug("[MXP ClientStack]: Starting ClientView...");
try
{
client.Start();
m_log.Debug("[MXP ClientStack]: Started ClientView.");
}
catch (Exception e)
{
m_log.Error(e);
}
m_log.Debug("[MXP ClientStack]: Connected");
}
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);
}
}
catch (Exception e)
{
m_log.Error("[MXP ClientStack]: Session join request failure: " + session.SessionId + " (" +
(session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" +
session.RemoteEndPoint.Port + "): "+e.ToString()+" :"+e.StackTrace.ToString());
}
tmpRemove.Add(session);
}
}
}
foreach (Session session in tmpRemove)
{
m_sessionsToClient.Remove(session);
}
foreach (MXPClientView clientView in m_clients)
{
int messagesProcessedCount = 0;
Session session = clientView.Session;
while (session.AvailableMessages > 0)
{
Message message = session.Receive();
if (message.GetType() == typeof(LeaveRequestMessage))
{
LeaveResponseMessage leaveResponseMessage = (LeaveResponseMessage)MessageFactory.Current.ReserveMessage(
typeof(LeaveResponseMessage));
m_log.Debug("[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.Debug("[MXP ClientStack]: Removing Client from Scene");
//clientView.Scene.RemoveClient(clientView.AgentId);
}
if (message.GetType() == typeof(LeaveResponseMessage))
{
LeaveResponseMessage leaveResponseMessage = (LeaveResponseMessage)message;
m_log.Debug("[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.Debug("[MXP ClientStack]: Removing Client from Scene");
//clientView.Scene.RemoveClient(clientView.AgentId);
}
else
{
clientView.MXPPRocessMessage(message);
}
MessageFactory.Current.ReleaseMessage(message);
messagesProcessedCount++;
if (messagesProcessedCount > 1000)
{
break;
}
}
}
}
private void AcceptConnection(Session session, JoinRequestMessage joinRequestMessage, UUID mxpSessionID, UUID userId)
{
JoinResponseMessage joinResponseMessage = (JoinResponseMessage)MessageFactory.Current.ReserveMessage(
typeof(JoinResponseMessage));
joinResponseMessage.RequestMessageId = joinRequestMessage.MessageId;
joinResponseMessage.FailureCode = MxpResponseCodes.SUCCESS;
joinResponseMessage.BubbleId = joinRequestMessage.BubbleId;
joinResponseMessage.ParticipantId = userId.Guid;
joinResponseMessage.AvatarId = userId.Guid;
joinResponseMessage.BubbleAssetCacheUrl = "http://" +
NetworkUtil.GetHostFor(session.RemoteEndPoint.Address,
m_scenes[
new UUID(joinRequestMessage.BubbleId)].
RegionInfo.
ExternalHostName) + ":" +
m_scenes[new UUID(joinRequestMessage.BubbleId)].RegionInfo.
HttpPort + "/assets/";
joinResponseMessage.BubbleName = m_scenes[new UUID(joinRequestMessage.BubbleId)].RegionInfo.RegionName;
joinResponseMessage.BubbleRange = 128;
joinResponseMessage.BubblePerceptionRange = 128 + 256;
joinResponseMessage.BubbleRealTime = 0;
joinResponseMessage.ProgramName = m_programName;
joinResponseMessage.ProgramMajorVersion = m_programMajorVersion;
joinResponseMessage.ProgramMinorVersion = m_programMinorVersion;
joinResponseMessage.ProtocolMajorVersion = MxpConstants.ProtocolMajorVersion;
joinResponseMessage.ProtocolMinorVersion = MxpConstants.ProtocolMinorVersion;
joinResponseMessage.ProtocolSourceRevision = MxpConstants.ProtocolSourceRevision;
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 = MxpResponseCodes.UNAUTHORIZED_OPERATION;
joinResponseMessage.ProgramName = m_programName;
joinResponseMessage.ProgramMajorVersion = m_programMajorVersion;
joinResponseMessage.ProgramMinorVersion = m_programMinorVersion;
joinResponseMessage.ProtocolMajorVersion = MxpConstants.ProtocolMajorVersion;
joinResponseMessage.ProtocolMinorVersion = MxpConstants.ProtocolMinorVersion;
joinResponseMessage.ProtocolSourceRevision = MxpConstants.ProtocolSourceRevision;
session.Send(joinResponseMessage);
session.SetStateDisconnected();
}
public bool AuthoriseUser(string participantName, string password, UUID sceneId, out UserAccount account)
{
string firstName = "";
string lastName = "";
account = null;
string[] nameParts = participantName.Split(' ');
if (nameParts.Length != 2)
{
m_log.Error("[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];
account = m_scenes[sceneId].UserAccountService.GetUserAccount(m_scenes[sceneId].RegionInfo.ScopeID, firstName, lastName);
if (account != null)
return (m_scenes[sceneId].AuthenticationService.Authenticate(account.PrincipalID, password, 1) != string.Empty);
return false;
}
private void AttachUserAgentToUserProfile(UserAccount account, Session session, UUID sessionId, UUID sceneId, out UUID secureSessionId)
{
secureSessionId = UUID.Random();
Scene scene = m_scenes[sceneId];
scene.PresenceService.LoginAgent(account.PrincipalID.ToString(), sessionId, secureSessionId);
}
private bool PrepareSceneForConnection(UUID sessionId, UUID secureSessionId, UUID sceneId, UserAccount account, out string reason)
{
Scene scene = m_scenes[sceneId];
AgentCircuitData agent = new AgentCircuitData();
agent.AgentID = account.PrincipalID;
agent.firstname = account.FirstName;
agent.lastname = account.LastName;
agent.SessionID = sessionId;
agent.SecureSessionID = 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 = scene.AvatarService.GetAppearance(account.PrincipalID);
if (agent.Appearance == null)
{
m_log.WarnFormat("[INTER]: Appearance not found for {0} {1}. Creating default.", agent.firstname, agent.lastname);
agent.Appearance = new AvatarAppearance();
}
return scene.NewUserConnection(agent, 0, out reason);
}
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
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,133 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Client.VWoHTTP.ClientStack;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Client.VWoHTTP
{
class VWoHTTPModule : IRegionModule, IHttpAgentHandler
{
private bool m_disabled = true;
private IHttpServer m_httpd;
private readonly List<Scene> m_scenes = new List<Scene>();
private Dictionary<UUID, VWHClientView> m_clients = new Dictionary<UUID, VWHClientView>();
#region Implementation of IRegionModule
public void Initialise(Scene scene, IConfigSource source)
{
if (m_disabled)
return;
m_scenes.Add(scene);
m_httpd = MainServer.Instance;
}
public void PostInitialise()
{
if (m_disabled)
return;
m_httpd.AddAgentHandler("vwohttp", this);
}
public void Close()
{
if (m_disabled)
return;
m_httpd.RemoveAgentHandler("vwohttp", this);
}
public string Name
{
get { return "VWoHTTP ClientStack"; }
}
public bool IsSharedModule
{
get { return true; }
}
#endregion
#region Implementation of IHttpAgentHandler
public bool Handle(OSHttpRequest req, OSHttpResponse resp)
{
string[] urlparts = req.Url.AbsolutePath.Split(new char[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
if (urlparts.Length < 2)
return false;
if (urlparts[1] == "connect")
{
UUID sessID = UUID.Random();
VWHClientView client = new VWHClientView(sessID, UUID.Random(), "VWoHTTPClient", m_scenes[0]);
m_clients.Add(sessID, client);
return true;
}
else
{
if (urlparts.Length < 3)
return false;
UUID sessionID;
if (!UUID.TryParse(urlparts[1], out sessionID))
return false;
if (!m_clients.ContainsKey(sessionID))
return false;
return m_clients[sessionID].ProcessInMsg(req, resp);
}
}
public bool Match(OSHttpRequest req, OSHttpResponse resp)
{
return req.Url.ToString().Contains("vwohttp");
}
#endregion
}
}

View File

@ -57,14 +57,14 @@ namespace OpenSim.Data.MSSQL
{
m_Realm = realm;
m_ConnectionString = connectionString;
if (storeName != String.Empty)
{
Assembly assem = GetType().Assembly;
m_ConnectionString = connectionString;
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
{
conn.Open();
Migration m = new Migration(conn, assem, storeName);
Migration m = new Migration(conn, GetType().Assembly, storeName);
m.Update();
}

View File

@ -61,7 +61,8 @@ namespace OpenSim.Data.MSSQL
}
catch
{
// Something went wrong, so we're version 0
// Return -1 to indicate table does not exist
return -1;
}
}
return version;

View File

@ -492,12 +492,11 @@ ELSE
using (SqlConnection conn = new SqlConnection(m_connectionString))
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
conn.Open();
foreach (TaskInventoryItem taskItem in items)
{
cmd.Parameters.AddRange(CreatePrimInventoryParameters(taskItem));
conn.Open();
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
}
@ -1154,9 +1153,9 @@ VALUES
PrimitiveBaseShape baseShape = new PrimitiveBaseShape();
baseShape.Scale = new Vector3(
Convert.ToSingle(shapeRow["ScaleX"]),
Convert.ToSingle(shapeRow["ScaleY"]),
Convert.ToSingle(shapeRow["ScaleZ"]));
(float)Convert.ToDouble(shapeRow["ScaleX"]),
(float)Convert.ToDouble(shapeRow["ScaleY"]),
(float)Convert.ToDouble(shapeRow["ScaleZ"]));
// paths
baseShape.PCode = Convert.ToByte(shapeRow["PCode"]);
@ -1194,7 +1193,10 @@ VALUES
}
if (!(shapeRow["Media"] is System.DBNull) )
{
baseShape.Media = PrimitiveBaseShape.MediaList.FromXml((string)shapeRow["Media"]);
}
return baseShape;
}
@ -1573,7 +1575,16 @@ VALUES
parameters.Add(_Database.CreateParameter("Texture", s.TextureEntry));
parameters.Add(_Database.CreateParameter("ExtraParams", s.ExtraParams));
parameters.Add(_Database.CreateParameter("State", s.State));
parameters.Add(_Database.CreateParameter("Media", null == s.Media ? null : s.Media.ToXml()));
if(null == s.Media )
{
parameters.Add(_Database.CreateParameter("Media", DBNull.Value));
}
else
{
parameters.Add(_Database.CreateParameter("Media", s.Media.ToXml()));
}
return parameters.ToArray();
}

View File

@ -22,7 +22,11 @@ COMMIT
BEGIN TRANSACTION
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[users]') AND type in (N'U'))
INSERT INTO auth (UUID, passwordHash, passwordSalt, webLoginKey, accountType) SELECT [UUID] AS UUID, [passwordHash] AS passwordHash, [passwordSalt] AS passwordSalt, [webLoginKey] AS webLoginKey, 'UserAccount' as [accountType] FROM users;
COMMIT

View File

@ -13,5 +13,28 @@ PRIMARY KEY CLUSTERED
) ON [PRIMARY]
COMMIT
:VERSION 2
BEGIN TRANSACTION
CREATE TABLE dbo.Tmp_Avatars
(
PrincipalID uniqueidentifier NOT NULL,
[Name] varchar(32) NOT NULL,
Value text NOT NULL DEFAULT '',
) ON [PRIMARY]
TEXTIMAGE_ON [PRIMARY]
IF EXISTS(SELECT * FROM dbo.Avatars)
EXEC('INSERT INTO dbo.Tmp_Avatars (PrincipalID, Name, Value)
SELECT PrincipalID, CONVERT(text, Name), Value FROM dbo.Avatars WITH (HOLDLOCK TABLOCKX)')
DROP TABLE dbo.Avatars
EXECUTE sp_rename N'dbo.Tmp_Avatars', N'Avatars', 'OBJECT'
COMMIT

View File

@ -15,6 +15,8 @@ COMMIT
BEGIN TRANSACTION
INSERT INTO Friends (PrincipalID, Friend, Flags, Offered) SELECT [ownerID], [friendID], [friendPerms], 0 FROM userfriends;
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[userfriends]') AND type in (N'U'))
INSERT INTO Friends (PrincipalID, Friend, Flags, Offered)
SELECT [ownerID], [friendID], [friendPerms], 0 FROM userfriends;
COMMIT

View File

@ -222,4 +222,17 @@ ALTER TABLE [regions] ADD [Token] varchar(255) NOT NULL DEFAULT 0;
COMMIT
:VERSION 8
BEGIN TRANSACTION
ALTER TABLE regions ALTER COLUMN regionName VarChar(128)
DROP INDEX IX_regions_name ON dbo.regions
ALTER TABLE regions ALTER COLUMN regionName VarChar(128) null
CREATE NONCLUSTERED INDEX IX_regions_name ON dbo.regions
(
regionName
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
COMMIT

View File

@ -238,7 +238,10 @@ alter table inventoryitems
COMMIT
:VERSION 8
ALTER TABLE inventoryitems
ADD CONSTRAINT DF_inventoryitems_creatorID
DEFAULT '00000000-0000-0000-0000-000000000000' FOR creatorID
:GO

View File

@ -7,14 +7,7 @@ CREATE TABLE [Presence] (
[RegionID] uniqueidentifier NOT NULL,
[SessionID] uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
[SecureSessionID] uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
[Online] char(5) NOT NULL DEFAULT 'false',
[Login] char(16) NOT NULL DEFAULT '0',
[Logout] char(16) NOT NULL DEFAULT '0',
[Position] char(64) NOT NULL DEFAULT '<0,0,0>',
[LookAt] char(64) NOT NULL DEFAULT '<0,0,0>',
[HomeRegionID] uniqueidentifier NOT NULL,
[HomePosition] CHAR(64) NOT NULL DEFAULT '<0,0,0>',
[HomeLookAt] CHAR(64) NOT NULL DEFAULT '<0,0,0>',
)
ON [PRIMARY]
@ -28,3 +21,11 @@ CREATE UNIQUE INDEX SessionID ON Presence(SessionID);
CREATE INDEX UserID ON Presence(UserID);
COMMIT
:VERSION 2
BEGIN TRANSACTION
ALTER TABLE Presence ADD LastSeen DateTime
COMMIT

View File

@ -1,4 +1,3 @@
:VERSION 1
CREATE TABLE [dbo].[prims](
@ -926,11 +925,121 @@ ALTER TABLE regionsettings ADD loaded_creation_datetime int NOT NULL default 0
COMMIT
:VERSION 24
-- Added post 0.7
BEGIN TRANSACTION
ALTER TABLE prims ADD COLUMN MediaURL varchar(255)
ALTER TABLE primshapes ADD COLUMN Media TEXT
ALTER TABLE prims ADD MediaURL varchar(255)
ALTER TABLE primshapes ADD Media TEXT NULL
COMMIT
:VERSION 25
BEGIN TRANSACTION
CREATE TABLE "regionwindlight" (
"region_id" varchar(36) NOT NULL DEFAULT '000000-0000-0000-0000-000000000000',
"water_color_r" [float] NOT NULL DEFAULT '4.000000',
"water_color_g" [float] NOT NULL DEFAULT '38.000000',
"water_color_b" [float] NOT NULL DEFAULT '64.000000',
"water_fog_density_exponent" [float] NOT NULL DEFAULT '4.0',
"underwater_fog_modifier" [float] NOT NULL DEFAULT '0.25',
"reflection_wavelet_scale_1" [float] NOT NULL DEFAULT '2.0',
"reflection_wavelet_scale_2" [float] NOT NULL DEFAULT '2.0',
"reflection_wavelet_scale_3" [float] NOT NULL DEFAULT '2.0',
"fresnel_scale" [float] NOT NULL DEFAULT '0.40',
"fresnel_offset" [float] NOT NULL DEFAULT '0.50',
"refract_scale_above" [float] NOT NULL DEFAULT '0.03',
"refract_scale_below" [float] NOT NULL DEFAULT '0.20',
"blur_multiplier" [float] NOT NULL DEFAULT '0.040',
"big_wave_direction_x" [float] NOT NULL DEFAULT '1.05',
"big_wave_direction_y" [float] NOT NULL DEFAULT '-0.42',
"little_wave_direction_x" [float] NOT NULL DEFAULT '1.11',
"little_wave_direction_y" [float] NOT NULL DEFAULT '-1.16',
"normal_map_texture" varchar(36) NOT NULL DEFAULT '822ded49-9a6c-f61c-cb89-6df54f42cdf4',
"horizon_r" [float] NOT NULL DEFAULT '0.25',
"horizon_g" [float] NOT NULL DEFAULT '0.25',
"horizon_b" [float] NOT NULL DEFAULT '0.32',
"horizon_i" [float] NOT NULL DEFAULT '0.32',
"haze_horizon" [float] NOT NULL DEFAULT '0.19',
"blue_density_r" [float] NOT NULL DEFAULT '0.12',
"blue_density_g" [float] NOT NULL DEFAULT '0.22',
"blue_density_b" [float] NOT NULL DEFAULT '0.38',
"blue_density_i" [float] NOT NULL DEFAULT '0.38',
"haze_density" [float] NOT NULL DEFAULT '0.70',
"density_multiplier" [float] NOT NULL DEFAULT '0.18',
"distance_multiplier" [float] NOT NULL DEFAULT '0.8',
"max_altitude" int NOT NULL DEFAULT '1605',
"sun_moon_color_r" [float] NOT NULL DEFAULT '0.24',
"sun_moon_color_g" [float] NOT NULL DEFAULT '0.26',
"sun_moon_color_b" [float] NOT NULL DEFAULT '0.30',
"sun_moon_color_i" [float] NOT NULL DEFAULT '0.30',
"sun_moon_position" [float] NOT NULL DEFAULT '0.317',
"ambient_r" [float] NOT NULL DEFAULT '0.35',
"ambient_g" [float] NOT NULL DEFAULT '0.35',
"ambient_b" [float] NOT NULL DEFAULT '0.35',
"ambient_i" [float] NOT NULL DEFAULT '0.35',
"east_angle" [float] NOT NULL DEFAULT '0.00',
"sun_glow_focus" [float] NOT NULL DEFAULT '0.10',
"sun_glow_size" [float] NOT NULL DEFAULT '1.75',
"scene_gamma" [float] NOT NULL DEFAULT '1.00',
"star_brightness" [float] NOT NULL DEFAULT '0.00',
"cloud_color_r" [float] NOT NULL DEFAULT '0.41',
"cloud_color_g" [float] NOT NULL DEFAULT '0.41',
"cloud_color_b" [float] NOT NULL DEFAULT '0.41',
"cloud_color_i" [float] NOT NULL DEFAULT '0.41',
"cloud_x" [float] NOT NULL DEFAULT '1.00',
"cloud_y" [float] NOT NULL DEFAULT '0.53',
"cloud_density" [float] NOT NULL DEFAULT '1.00',
"cloud_coverage" [float] NOT NULL DEFAULT '0.27',
"cloud_scale" [float] NOT NULL DEFAULT '0.42',
"cloud_detail_x" [float] NOT NULL DEFAULT '1.00',
"cloud_detail_y" [float] NOT NULL DEFAULT '0.53',
"cloud_detail_density" [float] NOT NULL DEFAULT '0.12',
"cloud_scroll_x" [float] NOT NULL DEFAULT '0.20',
"cloud_scroll_x_lock" tinyint NOT NULL DEFAULT '0',
"cloud_scroll_y" [float] NOT NULL DEFAULT '0.01',
"cloud_scroll_y_lock" tinyint NOT NULL DEFAULT '0',
"draw_classic_clouds" tinyint NOT NULL DEFAULT '1',
PRIMARY KEY ("region_id")
)
COMMIT TRANSACTION
:VERSION 26
BEGIN TRANSACTION
ALTER TABLE regionsettings ADD map_tile_ID CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'
COMMIT
:VERSION 27 #---------------------
BEGIN TRANSACTION
ALTER TABLE land ADD MediaType VARCHAR(32) NOT NULL DEFAULT 'none/none'
ALTER TABLE land ADD MediaDescription VARCHAR(255) NOT NULL DEFAULT ''
ALTER TABLE land ADD MediaSize VARCHAR(16) NOT NULL DEFAULT '0,0'
ALTER TABLE land ADD MediaLoop bit NOT NULL DEFAULT 0
ALTER TABLE land ADD ObscureMusic bit NOT NULL DEFAULT 0
ALTER TABLE land ADD ObscureMedia bit NOT NULL DEFAULT 0
COMMIT
:VERSION 28 #---------------------
BEGIN TRANSACTION
ALTER TABLE prims
ADD CONSTRAINT DF_prims_CreatorID
DEFAULT '00000000-0000-0000-0000-000000000000'
FOR CreatorID
ALTER TABLE prims ALTER COLUMN CreatorID uniqueidentifier NOT NULL
ALTER TABLE primitems
ADD CONSTRAINT DF_primitems_CreatorID
DEFAULT '00000000-0000-0000-0000-000000000000'
FOR CreatorID
ALTER TABLE primitems ALTER COLUMN CreatorID uniqueidentifier NOT NULL
COMMIT

View File

@ -19,7 +19,7 @@ CREATE TABLE [UserAccounts] (
:VERSION 2
BEGIN TRANSACTION
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[users]') AND type in (N'U'))
INSERT INTO UserAccounts (PrincipalID, ScopeID, FirstName, LastName, Email, ServiceURLs, Created) SELECT [UUID] AS PrincipalID, '00000000-0000-0000-0000-000000000000' AS ScopeID,
username AS FirstName,
lastname AS LastName,

View File

@ -592,9 +592,7 @@ namespace OpenSim.Framework.Console
string line = ReadLine(m_defaultPrompt + "# ", true, true);
if (line != String.Empty)
{
m_log.Info("[CONSOLE] Invalid command");
}
Output("Invalid command");
}
public void RunCommand(string cmd)

View File

@ -572,34 +572,69 @@ namespace OpenSim.Framework
public class IEntityUpdate
{
public ISceneEntity Entity;
public uint Flags;
private ISceneEntity m_entity;
private uint m_flags;
private int m_updateTime;
public ISceneEntity Entity
{
get { return m_entity; }
}
public uint Flags
{
get { return m_flags; }
}
public int UpdateTime
{
get { return m_updateTime; }
}
public virtual void Update(IEntityUpdate update)
{
this.Flags |= update.Flags;
m_flags |= update.Flags;
// Use the older of the updates as the updateTime
if (Util.EnvironmentTickCountCompare(UpdateTime, update.UpdateTime) > 0)
m_updateTime = update.UpdateTime;
}
public IEntityUpdate(ISceneEntity entity, uint flags)
{
Entity = entity;
Flags = flags;
}
m_entity = entity;
m_flags = flags;
m_updateTime = Util.EnvironmentTickCount();
}
public IEntityUpdate(ISceneEntity entity, uint flags, Int32 updateTime)
{
m_entity = entity;
m_flags = flags;
m_updateTime = updateTime;
}
}
public class EntityUpdate : IEntityUpdate
{
// public ISceneEntity Entity;
// public PrimUpdateFlags Flags;
public float TimeDilation;
private float m_timeDilation;
public float TimeDilation
{
get { return m_timeDilation; }
}
public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation)
: base(entity, (uint)flags)
{
//Entity = entity;
// Flags = flags;
TimeDilation = timedilation;
m_timeDilation = timedilation;
}
public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation, Int32 updateTime)
: base(entity,(uint)flags,updateTime)
{
m_timeDilation = timedilation;
}
}

View File

@ -34,50 +34,81 @@ using OpenSim.Framework;
using OpenSim.Framework.Client;
using log4net;
namespace OpenSim.Region.ClientStack.LindenUDP
namespace OpenSim.Framework
{
public class PriorityQueue
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
// Heap[0] for self updates
// Heap[1..12] for entity updates
/// <summary>
/// Total number of queues (priorities) available
/// </summary>
public const uint NumberOfQueues = 12;
internal const uint m_numberOfQueues = 12;
/// <summary>
/// Number of queuest (priorities) that are processed immediately
/// </summary.
public const uint NumberOfImmediateQueues = 2;
private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[m_numberOfQueues];
private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[NumberOfQueues];
private Dictionary<uint, LookupItem> m_lookupTable;
// internal state used to ensure the deqeues are spread across the priority
// queues "fairly". queuecounts is the amount to pull from each queue in
// each pass. weighted towards the higher priority queues
private uint m_nextQueue = 0;
private uint m_countFromQueue = 0;
private uint[] m_queueCounts = { 8, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1 };
// next request is a counter of the number of updates queued, it provides
// a total ordering on the updates coming through the queue and is more
// lightweight (and more discriminating) than tick count
private UInt64 m_nextRequest = 0;
/// <summary>
/// Lock for enqueue and dequeue operations on the priority queue
/// </summary>
private object m_syncRoot = new object();
public object SyncRoot {
get { return this.m_syncRoot; }
}
internal PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { }
#region constructor
public PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { }
internal PriorityQueue(int capacity)
public PriorityQueue(int capacity)
{
m_lookupTable = new Dictionary<uint, LookupItem>(capacity);
for (int i = 0; i < m_heaps.Length; ++i)
m_heaps[i] = new MinHeap<MinHeapItem>(capacity);
}
internal int Count
m_nextQueue = NumberOfImmediateQueues;
m_countFromQueue = m_queueCounts[m_nextQueue];
}
#endregion Constructor
#region PublicMethods
/// <summary>
/// Return the number of items in the queues
/// </summary>
public int Count
{
get
{
int count = 0;
for (int i = 0; i < m_heaps.Length; ++i)
count += m_heaps[i].Count;
return count;
}
}
/// <summary>
/// Enqueue an item into the specified priority queue
/// </summary>
public bool Enqueue(uint pqueue, IEntityUpdate value)
{
LookupItem lookup;
@ -91,7 +122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
lookup.Heap.Remove(lookup.Handle);
}
pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1);
pqueue = Util.Clamp<uint>(pqueue, 0, NumberOfQueues - 1);
lookup.Heap = m_heaps[pqueue];
lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle);
m_lookupTable[localid] = lookup;
@ -99,20 +130,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return true;
}
internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
/// <summary>
/// Remove an item from one of the queues. Specifically, it removes the
/// oldest item from the next queue in order to provide fair access to
/// all of the queues
/// </summary>
public bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
{
for (int i = 0; i < m_numberOfQueues; ++i)
// If there is anything in priority queue 0, return it first no
// matter what else. Breaks fairness. But very useful.
for (int iq = 0; iq < NumberOfImmediateQueues; iq++)
{
// To get the fair queing, we cycle through each of the
// queues when finding an element to dequeue, this code
// assumes that the distribution of updates in the queues
// is polynomial, probably quadractic (eg distance of PI * R^2)
uint h = (uint)((m_nextQueue + i) % m_numberOfQueues);
if (m_heaps[h].Count > 0)
if (m_heaps[iq].Count > 0)
{
m_nextQueue = (uint)((h + 1) % m_numberOfQueues);
MinHeapItem item = m_heaps[iq].RemoveMin();
m_lookupTable.Remove(item.Value.Entity.LocalId);
timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
value = item.Value;
MinHeapItem item = m_heaps[h].RemoveMin();
return true;
}
}
// To get the fair queing, we cycle through each of the
// queues when finding an element to dequeue.
// We pull (NumberOfQueues - QueueIndex) items from each queue in order
// to give lower numbered queues a higher priority and higher percentage
// of the bandwidth.
// Check for more items to be pulled from the current queue
if (m_heaps[m_nextQueue].Count > 0 && m_countFromQueue > 0)
{
m_countFromQueue--;
MinHeapItem item = m_heaps[m_nextQueue].RemoveMin();
m_lookupTable.Remove(item.Value.Entity.LocalId);
timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
value = item.Value;
return true;
}
// Find the next non-immediate queue with updates in it
for (int i = 0; i < NumberOfQueues; ++i)
{
m_nextQueue = (uint)((m_nextQueue + 1) % NumberOfQueues);
m_countFromQueue = m_queueCounts[m_nextQueue];
// if this is one of the immediate queues, just skip it
if (m_nextQueue < NumberOfImmediateQueues)
continue;
if (m_heaps[m_nextQueue].Count > 0)
{
m_countFromQueue--;
MinHeapItem item = m_heaps[m_nextQueue].RemoveMin();
m_lookupTable.Remove(item.Value.Entity.LocalId);
timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
value = item.Value;
@ -126,7 +199,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return false;
}
internal void Reprioritize(UpdatePriorityHandler handler)
/// <summary>
/// Reapply the prioritization function to each of the updates currently
/// stored in the priority queues.
/// </summary
public void Reprioritize(UpdatePriorityHandler handler)
{
MinHeapItem item;
foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values))
@ -140,7 +217,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
// unless the priority queue has changed, there is no need to modify
// the entry
pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1);
pqueue = Util.Clamp<uint>(pqueue, 0, NumberOfQueues - 1);
if (pqueue != item.PriorityQueue)
{
lookup.Heap.Remove(lookup.Handle);
@ -161,17 +238,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
/// <summary>
/// </summary>
public override string ToString()
{
string s = "";
for (int i = 0; i < m_numberOfQueues; i++)
{
if (s != "") s += ",";
s += m_heaps[i].Count.ToString();
}
for (int i = 0; i < NumberOfQueues; i++)
s += String.Format("{0,7} ",m_heaps[i].Count);
return s;
}
#endregion PublicMethods
#region MinHeapItem
private struct MinHeapItem : IComparable<MinHeapItem>
{

View File

@ -369,6 +369,7 @@ namespace OpenSim.Framework
private int m_physPrimMax = 0;
private bool m_clampPrimSize = false;
private int m_objectCapacity = 0;
private int m_agentCapacity = 0;
private string m_regionType = String.Empty;
private RegionLightShareData m_windlight = new RegionLightShareData();
protected uint m_httpPort;
@ -547,6 +548,11 @@ namespace OpenSim.Framework
get { return m_objectCapacity; }
}
public int AgentCapacity
{
get { return m_agentCapacity; }
}
public byte AccessLevel
{
get { return (byte)Util.ConvertMaturityToAccessLevel((uint)RegionSettings.Maturity); }
@ -821,6 +827,8 @@ namespace OpenSim.Framework
m_objectCapacity = config.GetInt("MaxPrims", 15000);
m_agentCapacity = config.GetInt("MaxAgents", 100);
// Multi-tenancy
//
@ -857,6 +865,9 @@ namespace OpenSim.Framework
if (m_objectCapacity != 0)
config.Set("MaxPrims", m_objectCapacity);
if (m_agentCapacity != 0)
config.Set("MaxAgents", m_agentCapacity);
if (ScopeID != UUID.Zero)
config.Set("ScopeID", ScopeID.ToString());
@ -943,6 +954,9 @@ namespace OpenSim.Framework
configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
"Max objects this sim will hold", m_objectCapacity.ToString(), true);
configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
"Max avatars this sim will hold", m_agentCapacity.ToString(), true);
configMember.addConfigurationOption("scope_id", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
"Scope ID for this region", ScopeID.ToString(), true);
@ -1055,6 +1069,9 @@ namespace OpenSim.Framework
case "object_capacity":
m_objectCapacity = (int)configuration_result;
break;
case "agent_capacity":
m_agentCapacity = (int)configuration_result;
break;
case "scope_id":
ScopeID = (UUID)configuration_result;
break;

View File

@ -29,7 +29,7 @@ namespace OpenSim
{
public class VersionInfo
{
private const string VERSION_NUMBER = "0.7.1";
private const string VERSION_NUMBER = "0.7.2";
private const Flavour VERSION_FLAVOUR = Flavour.Dev;
public enum Flavour

View File

@ -1537,6 +1537,23 @@ namespace OpenSim.Framework
return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1);
}
// Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount
// Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount().
// A positive return value indicates A occured later than B
public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB)
{
// A, B and TC are all between 0 and 0x3fffffff
int tc = EnvironmentTickCount();
if (tc - tcA >= 0)
tcA += EnvironmentTickCountMask + 1;
if (tc - tcB >= 0)
tcB += EnvironmentTickCountMask + 1;
return tcA - tcB;
}
/// <summary>
/// Prints the call stack at any given point. Useful for debugging.
/// </summary>

View File

@ -384,6 +384,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } }
public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
/// <summary>
/// Entity update queues
/// </summary>
public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } }
/// <summary>
/// First name of the agent/avatar represented by the client
/// </summary>
@ -3561,6 +3566,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
}
/// <summary>
/// Requeue an EntityUpdate when it was not acknowledged by the client.
/// We will update the priority and put it in the correct queue, merging update flags
/// with any other updates that may be queued for the same entity.
/// The original update time is used for the merged update.
/// </summary>
private void ResendPrimUpdate(EntityUpdate update)
{
// If the update exists in priority queue, it will be updated.
// If it does not exist then it will be added with the current (rather than its original) priority
uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
lock (m_entityUpdates.SyncRoot)
m_entityUpdates.Enqueue(priority, update);
}
/// <summary>
/// Requeue a list of EntityUpdates when they were not acknowledged by the client.
/// We will update the priority and put it in the correct queue, merging update flags
/// with any other updates that may be queued for the same entity.
/// The original update time is used for the merged update.
/// </summary>
private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket)
{
// m_log.WarnFormat("[CLIENT] resending prim update {0}",updates[0].UpdateTime);
// Remove the update packet from the list of packets waiting for acknowledgement
// because we are requeuing the list of updates. They will be resent in new packets
// with the most recent state and priority.
m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
// Count this as a resent packet since we are going to requeue all of the updates contained in it
Interlocked.Increment(ref m_udpClient.PacketsResent);
foreach (EntityUpdate update in updates)
ResendPrimUpdate(update);
}
private void ProcessEntityUpdates(int maxUpdates)
{
OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@ -3568,6 +3611,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
// Check to see if this is a flush
if (maxUpdates <= 0)
{
@ -3688,24 +3736,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (update.Entity is ScenePresence)
{
objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
objectUpdates.Value.Add(update);
}
else
{
objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
objectUpdates.Value.Add(update);
}
}
else if (!canUseImproved)
{
compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
compressedUpdates.Value.Add(update);
}
else
{
if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
{
// Self updates go into a special list
terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
terseAgentUpdates.Value.Add(update);
}
else
{
// Everything else goes here
terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
terseUpdates.Value.Add(update);
}
}
#endregion Block Construction
@ -3713,10 +3770,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Packet Sending
//const float TIME_DILATION = 1.0f;
ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
if (terseAgentUpdateBlocks.IsValueCreated)
@ -3730,9 +3783,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < blocks.Count; i++)
packet.ObjectData[i] = blocks[i];
OutPacket(packet, ThrottleOutPacketType.Unknown, true);
// If any of the packets created from this call go unacknowledged, all of the updates will be resent
OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); });
}
if (objectUpdateBlocks.IsValueCreated)
@ -3746,8 +3798,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < blocks.Count; i++)
packet.ObjectData[i] = blocks[i];
OutPacket(packet, ThrottleOutPacketType.Task, true);
// If any of the packets created from this call go unacknowledged, all of the updates will be resent
OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
}
if (compressedUpdateBlocks.IsValueCreated)
@ -3761,8 +3813,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < blocks.Count; i++)
packet.ObjectData[i] = blocks[i];
OutPacket(packet, ThrottleOutPacketType.Task, true);
// If any of the packets created from this call go unacknowledged, all of the updates will be resent
OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
}
if (terseUpdateBlocks.IsValueCreated)
@ -3776,8 +3828,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < blocks.Count; i++)
packet.ObjectData[i] = blocks[i];
OutPacket(packet, ThrottleOutPacketType.Task, true);
// If any of the packets created from this call go unacknowledged, all of the updates will be resent
OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
}
}
@ -3969,7 +4021,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
SendObjectProps = SendObjectProps || update.SendObjectProps;
Flags |= update.Flags;
// other properties may need to be updated by base class
base.Update(update);
}
}
@ -3980,6 +4033,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false));
}
private void ResendPropertyUpdate(ObjectPropertyUpdate update)
{
uint priority = 0;
lock (m_entityProps.SyncRoot)
m_entityProps.Enqueue(priority, update);
}
private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates, OutgoingPacket oPacket)
{
// m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime);
// Remove the update packet from the list of packets waiting for acknowledgement
// because we are requeuing the list of updates. They will be resent in new packets
// with the most recent state.
m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
// Count this as a resent packet since we are going to requeue all of the updates contained in it
Interlocked.Increment(ref m_udpClient.PacketsResent);
foreach (ObjectPropertyUpdate update in updates)
ResendPropertyUpdate(update);
}
public void SendObjectPropertiesReply(ISceneEntity entity)
{
uint priority = 0; // time based ordering only
@ -3995,6 +4071,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks =
new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>();
OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates =
new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates =
new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
IEntityUpdate iupdate;
Int32 timeinqueue; // this is just debugging code & can be dropped later
@ -4013,6 +4095,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
SceneObjectPart sop = (SceneObjectPart)update.Entity;
ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
objectFamilyBlocks.Value.Add(objPropDB);
familyUpdates.Value.Add(update);
}
}
@ -4023,6 +4106,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
SceneObjectPart sop = (SceneObjectPart)update.Entity;
ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
objectPropertiesBlocks.Value.Add(objPropDB);
propertyUpdates.Value.Add(update);
}
}
@ -4030,12 +4114,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
Int32 ppcnt = 0;
Int32 pbcnt = 0;
// Int32 ppcnt = 0;
// Int32 pbcnt = 0;
if (objectPropertiesBlocks.IsValueCreated)
{
List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value;
List<ObjectPropertyUpdate> updates = propertyUpdates.Value;
ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count];
@ -4043,28 +4128,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
packet.ObjectData[i] = blocks[i];
packet.Header.Zerocoded = true;
OutPacket(packet, ThrottleOutPacketType.Task, true);
pbcnt += blocks.Count;
ppcnt++;
// Pass in the delegate so that if this packet needs to be resent, we send the current properties
// of the object rather than the properties when the packet was created
OutPacket(packet, ThrottleOutPacketType.Task, true,
delegate(OutgoingPacket oPacket)
{
ResendPropertyUpdates(updates, oPacket);
});
// pbcnt += blocks.Count;
// ppcnt++;
}
Int32 fpcnt = 0;
Int32 fbcnt = 0;
// Int32 fpcnt = 0;
// Int32 fbcnt = 0;
if (objectFamilyBlocks.IsValueCreated)
{
List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value;
// ObjectPropertiesFamilyPacket objPropFamilyPack =
// (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
//
// objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count];
// for (int i = 0; i < blocks.Count; i++)
// objPropFamilyPack.ObjectData[i] = blocks[i];
//
// OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true);
// one packet per object block... uggh...
for (int i = 0; i < blocks.Count; i++)
{
@ -4073,10 +4156,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
packet.ObjectData = blocks[i];
packet.Header.Zerocoded = true;
OutPacket(packet, ThrottleOutPacketType.Task);
fpcnt++;
fbcnt++;
// Pass in the delegate so that if this packet needs to be resent, we send the current properties
// of the object rather than the properties when the packet was created
List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
updates.Add(familyUpdates.Value[i]);
OutPacket(packet, ThrottleOutPacketType.Task, true,
delegate(OutgoingPacket oPacket)
{
ResendPropertyUpdates(updates, oPacket);
});
// fpcnt++;
// fbcnt++;
}
}
@ -4764,7 +4856,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
data.RelativePosition.ToBytes(objectData, 0);
data.Velocity.ToBytes(objectData, 12);
data.Acceleration.ToBytes(objectData, 24);
try
{
data.RotationOffset.ToBytes(objectData, 36);
}
catch (Exception e)
{
m_log.Warn("[LLClientView]: exception converting quaternion to bytes, using Quaternion.Identity. Exception: " + e.ToString());
OpenMetaverse.Quaternion.Identity.ToBytes(objectData, 36);
}
data.AngularVelocity.ToBytes(objectData, 48);
ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@ -11328,7 +11428,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <returns></returns>
public byte[] GetThrottlesPacked(float multiplier)
{
return m_udpClient.GetThrottlesPacked();
return m_udpClient.GetThrottlesPacked(multiplier);
}
/// <summary>
@ -11362,6 +11462,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// packets (the default), or false to disable splitting if the calling code
/// handles splitting manually</param>
protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting)
{
OutPacket(packet, throttlePacketType, doAutomaticSplitting, null);
}
/// <summary>
/// This is the starting point for sending a simulator packet out to the client
/// </summary>
/// <param name="packet">Packet to send</param>
/// <param name="throttlePacketType">Throttling category for the packet</param>
/// <param name="doAutomaticSplitting">True to automatically split oversized
/// packets (the default), or false to disable splitting if the calling code
/// handles splitting manually</param>
/// <param name="method">The method to be called in the event this packet is reliable
/// and unacknowledged. The server will provide normal resend capability if you do not
/// provide your own method.</param>
protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
{
if (m_debugPacketLevel > 0)
{
@ -11388,7 +11504,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type);
}
m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting);
m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
}
public bool AddMoney(int debit)

View File

@ -135,7 +135,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private int m_nextOnQueueEmpty = 1;
/// <summary>Throttle bucket for this agent's connection</summary>
private readonly TokenBucket m_throttleClient;
private readonly AdaptiveTokenBucket m_throttleClient;
public AdaptiveTokenBucket FlowThrottle
{
get { return m_throttleClient; }
}
/// <summary>Throttle bucket for this agent's connection</summary>
private readonly TokenBucket m_throttleCategory;
/// <summary>Throttle buckets for each packet category</summary>
@ -176,9 +181,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_maxRTO = maxRTO;
// Create a token bucket throttle for this client that has the scene token bucket as a parent
m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit);
m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled);
// Create a token bucket throttle for the total categary with the client bucket as a throttle
m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit);
m_throttleCategory = new TokenBucket(m_throttleClient, 0);
// Create an array of token buckets for this clients different throttle categories
m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
@ -189,7 +194,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Initialize the packet outboxes, where packets sit while they are waiting for tokens
m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
// Initialize the token buckets that control the throttling for each category
m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type));
m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type));
}
// Default the retransmission timeout to three seconds
@ -223,26 +228,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <returns>Information about the client connection</returns>
public ClientInfo GetClientInfo()
{
///<mic>
TokenBucket tb;
tb = m_throttleClient.Parent;
m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT");
tb = m_throttleClient;
m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT");
tb = m_throttleCategory;
m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY");
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
{
tb = m_throttleCategories[i];
m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET");
}
///</mic>
// TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
// of pending and needed ACKs for every client every time some method wants information about
// this connection is a recipe for poor performance
@ -254,12 +239,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
// info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle +
info.taskThrottle + info.assetThrottle + info.textureThrottle;
info.totalThrottle = (int)m_throttleCategory.DripRate;
return info;
}
@ -346,8 +329,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
// State is a subcategory of task that we allocate a percentage to
int state = 0;
// int state = (int)((float)task * STATE_TASK_PERCENTAGE);
// task -= state;
// Make sure none of the throttles are set below our packet MTU,
// otherwise a throttle could become permanently clogged
@ -358,19 +339,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
task = Math.Max(task, LLUDPServer.MTU);
texture = Math.Max(texture, LLUDPServer.MTU);
asset = Math.Max(asset, LLUDPServer.MTU);
state = Math.Max(state, LLUDPServer.MTU);
int total = resend + land + wind + cloud + task + texture + asset + state;
//m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, State={8}, Total={9}",
// AgentID, resend, land, wind, cloud, task, texture, asset, state, total);
//int total = resend + land + wind + cloud + task + texture + asset;
//m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
// AgentID, resend, land, wind, cloud, task, texture, asset, total);
// Update the token buckets with new throttle values
TokenBucket bucket;
bucket = m_throttleCategory;
bucket.RequestedDripRate = total;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
bucket.RequestedDripRate = resend;
@ -399,22 +375,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_packedThrottles = null;
}
public byte[] GetThrottlesPacked()
public byte[] GetThrottlesPacked(float multiplier)
{
byte[] data = m_packedThrottles;
if (data == null)
{
float rate;
data = new byte[7 * 4];
int i = 0;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4;
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4;
// multiply by 8 to convert bytes back to bits
rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier;
Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier;
Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier;
Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier;
Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier;
Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier;
Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier;
Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
m_packedThrottles = data;
}

View File

@ -297,7 +297,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
delegate(IClientAPI client)
{
if (client is LLClientView)
SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
}
);
}
@ -309,7 +309,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
delegate(IClientAPI client)
{
if (client is LLClientView)
SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
}
);
}
@ -322,7 +322,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <param name="packet"></param>
/// <param name="category"></param>
/// <param name="allowSplitting"></param>
public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
{
// CoarseLocationUpdate packets cannot be split in an automated way
if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
@ -339,13 +339,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < packetCount; i++)
{
byte[] data = datas[i];
SendPacketData(udpClient, data, packet.Type, category);
SendPacketData(udpClient, data, packet.Type, category, method);
}
}
else
{
byte[] data = packet.ToBytes();
SendPacketData(udpClient, data, packet.Type, category);
SendPacketData(udpClient, data, packet.Type, category, method);
}
}
@ -356,7 +356,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <param name="data"></param>
/// <param name="type"></param>
/// <param name="category"></param>
public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category)
public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
{
int dataLength = data.Length;
bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
@ -411,7 +411,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Queue or Send
OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category);
OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
// If we were not provided a method for handling unacked, use the UDPServer default method
outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
// If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
// continue to display the deleted object until relog. Therefore, we need to always queue a kill object
@ -445,7 +447,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
packet.Header.Reliable = false;
packet.Packets = blocks.ToArray();
SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true);
SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null);
}
}
@ -458,17 +460,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
pc.PingID.OldestUnacked = 0;
SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false);
SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
}
public void CompletePing(LLUDPClient udpClient, byte pingID)
{
CompletePingCheckPacket completePing = new CompletePingCheckPacket();
completePing.PingID.PingID = pingID;
SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false);
SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
}
public void ResendUnacked(LLUDPClient udpClient)
public void HandleUnacked(LLUDPClient udpClient)
{
if (!udpClient.IsConnected)
return;
@ -488,16 +490,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (expiredPackets != null)
{
//m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
//m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
// Exponential backoff of the retransmission timeout
udpClient.BackoffRTO();
for (int i = 0; i < expiredPackets.Count; ++i)
expiredPackets[i].UnackedMethod(expiredPackets[i]);
}
}
// Resend packets
for (int i = 0; i < expiredPackets.Count; i++)
public void ResendUnacked(OutgoingPacket outgoingPacket)
{
OutgoingPacket outgoingPacket = expiredPackets[i];
//m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
// outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
@ -512,8 +514,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false))
SendPacketFinal(outgoingPacket);
}
}
}
public void Flush(LLUDPClient udpClient)
{
@ -672,7 +672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (packet.Header.AppendedAcks && packet.Header.AckList != null)
{
for (int i = 0; i < packet.Header.AckList.Length; i++)
udpClient.NeedAcks.Remove(packet.Header.AckList[i], now, packet.Header.Resent);
udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
}
// Handle PacketAck packets
@ -681,7 +681,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
PacketAckPacket ackPacket = (PacketAckPacket)packet;
for (int i = 0; i < ackPacket.Packets.Length; i++)
udpClient.NeedAcks.Remove(ackPacket.Packets[i].ID, now, packet.Header.Resent);
udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
// We don't need to do anything else with PacketAck packets
return;
@ -1096,7 +1096,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (udpClient.IsConnected)
{
if (m_resendUnacked)
ResendUnacked(udpClient);
HandleUnacked(udpClient);
if (m_sendAcks)
SendAcks(udpClient);
@ -1152,7 +1152,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
nticksUnack++;
watch2.Start();
ResendUnacked(udpClient);
HandleUnacked(udpClient);
watch2.Stop();
avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);

View File

@ -31,6 +31,8 @@ using OpenMetaverse;
namespace OpenSim.Region.ClientStack.LindenUDP
{
public delegate void UnackedPacketMethod(OutgoingPacket oPacket);
/// <summary>
/// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is
/// destined for, along with the serialized packet data, sequence number
@ -52,6 +54,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public int TickCount;
/// <summary>Category this packet belongs to</summary>
public ThrottleOutPacketType Category;
/// <summary>The delegate to be called if this packet is determined to be unacknowledged</summary>
public UnackedPacketMethod UnackedMethod;
/// <summary>
/// Default constructor
@ -60,11 +64,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <param name="buffer">Serialized packet data. If the flags or sequence number
/// need to be updated, they will be injected directly into this binary buffer</param>
/// <param name="category">Throttling category for this packet</param>
public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category)
public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method)
{
Client = client;
Buffer = buffer;
Category = category;
UnackedMethod = method;
}
}
}

View File

@ -52,29 +52,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public int Texture;
/// <summary>Drip rate for asset packets</summary>
public int Asset;
/// <summary>Drip rate for state packets</summary>
public int State;
/// <summary>Drip rate for the parent token bucket</summary>
public int Total;
/// <summary>Maximum burst rate for resent packets</summary>
public int ResendLimit;
/// <summary>Maximum burst rate for land packets</summary>
public int LandLimit;
/// <summary>Maximum burst rate for wind packets</summary>
public int WindLimit;
/// <summary>Maximum burst rate for cloud packets</summary>
public int CloudLimit;
/// <summary>Maximum burst rate for task (state and transaction) packets</summary>
public int TaskLimit;
/// <summary>Maximum burst rate for texture packets</summary>
public int TextureLimit;
/// <summary>Maximum burst rate for asset packets</summary>
public int AssetLimit;
/// <summary>Maximum burst rate for state packets</summary>
public int StateLimit;
/// <summary>Burst rate for the parent token bucket</summary>
public int TotalLimit;
/// <summary>Flag used to enable adaptive throttles</summary>
public bool AdaptiveThrottlesEnabled;
/// <summary>
/// Default constructor
@ -86,26 +69,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
Resend = throttleConfig.GetInt("resend_default", 12500);
Land = throttleConfig.GetInt("land_default", 1000);
Wind = throttleConfig.GetInt("wind_default", 1000);
Cloud = throttleConfig.GetInt("cloud_default", 1000);
Task = throttleConfig.GetInt("task_default", 1000);
Texture = throttleConfig.GetInt("texture_default", 1000);
Asset = throttleConfig.GetInt("asset_default", 1000);
State = throttleConfig.GetInt("state_default", 1000);
ResendLimit = throttleConfig.GetInt("resend_limit", 18750);
LandLimit = throttleConfig.GetInt("land_limit", 29750);
WindLimit = throttleConfig.GetInt("wind_limit", 18750);
CloudLimit = throttleConfig.GetInt("cloud_limit", 18750);
TaskLimit = throttleConfig.GetInt("task_limit", 18750);
TextureLimit = throttleConfig.GetInt("texture_limit", 55750);
AssetLimit = throttleConfig.GetInt("asset_limit", 27500);
StateLimit = throttleConfig.GetInt("state_limit", 37000);
Resend = throttleConfig.GetInt("resend_default", 6625);
Land = throttleConfig.GetInt("land_default", 9125);
Wind = throttleConfig.GetInt("wind_default", 1750);
Cloud = throttleConfig.GetInt("cloud_default", 1750);
Task = throttleConfig.GetInt("task_default", 18500);
Texture = throttleConfig.GetInt("texture_default", 18500);
Asset = throttleConfig.GetInt("asset_default", 10500);
Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
TotalLimit = Total;
AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
}
catch (Exception) { }
}
@ -128,34 +102,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return Texture;
case ThrottleOutPacketType.Asset:
return Asset;
case ThrottleOutPacketType.State:
return State;
case ThrottleOutPacketType.Unknown:
default:
return 0;
}
}
public int GetLimit(ThrottleOutPacketType type)
{
switch (type)
{
case ThrottleOutPacketType.Resend:
return ResendLimit;
case ThrottleOutPacketType.Land:
return LandLimit;
case ThrottleOutPacketType.Wind:
return WindLimit;
case ThrottleOutPacketType.Cloud:
return CloudLimit;
case ThrottleOutPacketType.Task:
return TaskLimit;
case ThrottleOutPacketType.Texture:
return TextureLimit;
case ThrottleOutPacketType.Asset:
return AssetLimit;
case ThrottleOutPacketType.State:
return StateLimit;
case ThrottleOutPacketType.Unknown:
default:
return 0;

View File

@ -29,6 +29,8 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using OpenSim.Framework;
using log4net;
namespace OpenSim.Region.ClientStack.LindenUDP
@ -48,31 +50,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// Number of ticks (ms) per quantum, drip rate and max burst
/// are defined over this interval.
/// </summary>
private const Int32 m_ticksPerQuantum = 1000;
protected const Int32 m_ticksPerQuantum = 1000;
/// <summary>
/// This is the number of quantums worth of packets that can
/// be accommodated during a burst
/// </summary>
private const Double m_quantumsPerBurst = 1.5;
protected const Double m_quantumsPerBurst = 1.5;
/// <summary>
/// </summary>
private const Int32 m_minimumDripRate = 1400;
protected const Int32 m_minimumDripRate = 1400;
/// <summary>Time of the last drip, in system ticks</summary>
private Int32 m_lastDrip;
protected Int32 m_lastDrip;
/// <summary>
/// The number of bytes that can be sent at this moment. This is the
/// current number of tokens in the bucket
/// </summary>
private Int64 m_tokenCount;
protected Int64 m_tokenCount;
/// <summary>
/// Map of children buckets and their requested maximum burst rate
/// </summary>
private Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
#region Properties
@ -81,7 +83,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// parent. The parent bucket will limit the aggregate bandwidth of all
/// of its children buckets
/// </summary>
private TokenBucket m_parent;
protected TokenBucket m_parent;
public TokenBucket Parent
{
get { return m_parent; }
@ -93,7 +95,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// of tokens that can accumulate in the bucket at any one time. This
/// also sets the total request for leaf nodes
/// </summary>
private Int64 m_burstRate;
protected Int64 m_burstRate;
public Int64 RequestedBurstRate
{
get { return m_burstRate; }
@ -118,8 +120,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <remarks>Tokens are added to the bucket any time
/// <seealso cref="RemoveTokens"/> is called, at the granularity of
/// the system tick interval (typically around 15-22ms)</remarks>
private Int64 m_dripRate;
public Int64 RequestedDripRate
protected Int64 m_dripRate;
public virtual Int64 RequestedDripRate
{
get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
set {
@ -131,7 +133,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
public Int64 DripRate
public virtual Int64 DripRate
{
get {
if (m_parent == null)
@ -149,7 +151,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// The current total of the requested maximum burst rates of
/// this bucket's children buckets.
/// </summary>
private Int64 m_totalDripRequest;
protected Int64 m_totalDripRequest;
public Int64 TotalDripRequest
{
get { return m_totalDripRequest; }
@ -177,7 +179,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
RequestedDripRate = dripRate;
// TotalDripRequest = dripRate; // this will be overwritten when a child node registers
// MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
m_lastDrip = Environment.TickCount & Int32.MaxValue;
m_lastDrip = Util.EnvironmentTickCount();
}
#endregion Constructor
@ -189,7 +191,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// hierarchy. However, if any of the parents is over-booked, then
/// the modifier will be less than 1.
/// </summary>
private double DripRateModifier()
protected double DripRateModifier()
{
Int64 driprate = DripRate;
return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
@ -197,7 +199,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>
/// </summary>
private double BurstRateModifier()
protected double BurstRateModifier()
{
// for now... burst rate is always m_quantumsPerBurst (constant)
// larger than drip rate so the ratio of burst requests is the
@ -210,6 +212,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// changes up the hierarchy.
/// </summary>
public void RegisterRequest(TokenBucket child, Int64 request)
{
lock (m_children)
{
m_children[child] = request;
// m_totalDripRequest = m_children.Values.Sum();
@ -217,6 +221,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_totalDripRequest = 0;
foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
m_totalDripRequest += cref.Value;
}
// Pass the new values up to the parent
if (m_parent != null)
@ -228,6 +233,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// changes up the hierarchy.
/// </summary>
public void UnregisterRequest(TokenBucket child)
{
lock (m_children)
{
m_children.Remove(child);
// m_totalDripRequest = m_children.Values.Sum();
@ -235,6 +242,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_totalDripRequest = 0;
foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
m_totalDripRequest += cref.Value;
}
// Pass the new values up to the parent
if (m_parent != null)
@ -268,7 +277,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// Deposit tokens into the bucket from a child bucket that did
/// not use all of its available tokens
/// </summary>
private void Deposit(Int64 count)
protected void Deposit(Int64 count)
{
m_tokenCount += count;
@ -285,7 +294,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// call to Drip
/// </summary>
/// <returns>True if tokens were added to the bucket, otherwise false</returns>
private void Drip()
protected void Drip()
{
// This should never happen... means we are a leaf node and were created
// with no drip rate...
@ -297,10 +306,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Determine the interval over which we are adding tokens, never add
// more than a single quantum of tokens
Int32 now = Environment.TickCount & Int32.MaxValue;
Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum);
m_lastDrip = now;
Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum);
m_lastDrip = Util.EnvironmentTickCount();
// This can be 0 in the very unusual case that the timer wrapped
// It can be 0 if we try add tokens at a sub-tick rate
@ -310,4 +317,77 @@ namespace OpenSim.Region.ClientStack.LindenUDP
Deposit(deltaMS * DripRate / m_ticksPerQuantum);
}
}
public class AdaptiveTokenBucket : TokenBucket
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// The minimum rate for flow control. Minimum drip rate is one
/// packet per second. Open the throttle to 15 packets per second
/// or about 160kbps.
/// </summary>
protected const Int64 m_minimumFlow = m_minimumDripRate * 15;
// <summary>
// The maximum rate for flow control. Drip rate can never be
// greater than this.
// </summary>
protected Int64 m_maxDripRate = 0;
protected Int64 MaxDripRate
{
get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
}
private bool m_enabled = false;
// <summary>
//
// </summary>
public virtual Int64 AdjustedDripRate
{
get { return m_dripRate; }
set {
m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate);
m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
if (m_parent != null)
m_parent.RegisterRequest(this,m_dripRate);
}
}
// <summary>
//
// </summary>
public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate)
{
m_enabled = enabled;
if (m_enabled)
{
// m_log.DebugFormat("[TOKENBUCKET] Adaptive throttle enabled");
MaxDripRate = maxDripRate;
AdjustedDripRate = m_minimumFlow;
}
}
// <summary>
//
// </summary>
public void ExpirePackets(Int32 count)
{
// m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
if (m_enabled)
AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count));
}
// <summary>
//
// </summary>
public void AcknowledgePackets(Int32 count)
{
if (m_enabled)
AdjustedDripRate = AdjustedDripRate + count;
}
}
}

View File

@ -65,7 +65,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>Holds packets that need to be added to the unacknowledged list</summary>
private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>();
/// <summary>Holds information about pending acknowledgements</summary>
private LocklessQueue<PendingAck> m_pendingRemoves = new LocklessQueue<PendingAck>();
private LocklessQueue<PendingAck> m_pendingAcknowledgements = new LocklessQueue<PendingAck>();
/// <summary>Holds information about pending removals</summary>
private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>();
/// <summary>
/// Add an unacked packet to the collection
@ -83,15 +85,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>
/// Marks a packet as acknowledged
/// This method is used when an acknowledgement is received from the network for a previously
/// sent packet. Effects of removal this way are to update unacked byte count, adjust RTT
/// and increase throttle to the coresponding client.
/// </summary>
/// <param name="sequenceNumber">Sequence number of the packet to
/// acknowledge</param>
/// <param name="currentTime">Current value of Environment.TickCount</param>
/// <remarks>This does not immediately acknowledge the packet, it only
/// queues the ack so it can be handled in a thread-safe way later</remarks>
public void Remove(uint sequenceNumber, int currentTime, bool fromResend)
public void Acknowledge(uint sequenceNumber, int currentTime, bool fromResend)
{
m_pendingRemoves.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend));
m_pendingAcknowledgements.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend));
}
/// <summary>
/// Marks a packet as no longer needing acknowledgement without a received acknowledgement.
/// This method is called when a packet expires and we no longer need an acknowledgement.
/// When some reliable packet types expire, they are handled in a way other than simply
/// resending them. The only effect of removal this way is to update unacked byte count.
/// </summary>
/// <param name="sequenceNumber">Sequence number of the packet to
/// acknowledge</param>
/// <remarks>The does not immediately remove the packet, it only queues the removal
/// so it can be handled in a thread safe way later</remarks>
public void Remove(uint sequenceNumber)
{
m_pendingRemoves.Enqueue(sequenceNumber);
}
/// <summary>
@ -130,6 +150,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// is actually sent out again
packet.TickCount = 0;
// As with other network applications, assume that an expired packet is
// an indication of some network problem, slow transmission
packet.Client.FlowThrottle.ExpirePackets(1);
expiredPackets.Add(packet);
}
}
@ -147,29 +171,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_packets[pendingAdd.SequenceNumber] = pendingAdd;
// Process all the pending removes, including updating statistics and round-trip times
PendingAck pendingRemove;
OutgoingPacket ackedPacket;
while (m_pendingRemoves.TryDequeue(out pendingRemove))
PendingAck pendingAcknowledgement;
while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement))
{
if (m_packets.TryGetValue(pendingRemove.SequenceNumber, out ackedPacket))
OutgoingPacket ackedPacket;
if (m_packets.TryGetValue(pendingAcknowledgement.SequenceNumber, out ackedPacket))
{
if (ackedPacket != null)
{
m_packets.Remove(pendingRemove.SequenceNumber);
m_packets.Remove(pendingAcknowledgement.SequenceNumber);
// As with other network applications, assume that an acknowledged packet is an
// indication that the network can handle a little more load, speed up the transmission
ackedPacket.Client.FlowThrottle.AcknowledgePackets(ackedPacket.Buffer.DataLength);
// Update stats
Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
if (!pendingRemove.FromResend)
if (!pendingAcknowledgement.FromResend)
{
// Calculate the round-trip time for this packet and its ACK
int rtt = pendingRemove.RemoveTime - ackedPacket.TickCount;
int rtt = pendingAcknowledgement.RemoveTime - ackedPacket.TickCount;
if (rtt > 0)
ackedPacket.Client.UpdateRoundTrip(rtt);
}
}
}
}
uint pendingRemove;
while(m_pendingRemoves.TryDequeue(out pendingRemove))
{
OutgoingPacket removedPacket;
if (m_packets.TryGetValue(pendingRemove, out removedPacket))
{
if (removedPacket != null)
{
m_packets.Remove(pendingRemove);
// Update stats
Interlocked.Add(ref removedPacket.Client.UnackedBytes, -removedPacket.Buffer.DataLength);
}
}
}
}
}
}

View File

@ -41,8 +41,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
/// </summary>
public class AgentAssetTransactions
{
// private static readonly ILog m_log = LogManager.GetLogger(
// MethodBase.GetCurrentMethod().DeclaringType);
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// Fields
private bool m_dumpAssetsToFile;
@ -149,6 +148,10 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
if (asset != null)
{
// m_log.DebugFormat(
// "[AGENT ASSETS TRANSACTIONS]: Updating item {0} in {1} for transaction {2}",
// item.Name, part.Name, transactionID);
asset.FullID = UUID.Random();
asset.Name = item.Name;
asset.Description = item.Description;
@ -156,8 +159,6 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
item.AssetID = asset.FullID;
m_Scene.AssetService.Store(asset);
part.Inventory.UpdateInventoryItem(item);
}
}
}

View File

@ -70,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets
if (meshConfig == null)
return;
m_enabled = meshConfig.GetBoolean("ColladaMesh", true);
m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
}
public void AddRegion(Scene pScene)

View File

@ -72,7 +72,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets
if (meshConfig == null)
return;
m_enabled = meshConfig.GetBoolean("ColladaMesh", true);
m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
}
public void AddRegion(Scene pScene)

View File

@ -182,9 +182,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
public InventoryCollection GetFolderContent(UUID userID, UUID folderID)
{
InventoryCollection invCol = m_InventoryService.GetFolderContent(userID, folderID);
Util.FireAndForget(delegate
{
if (UserManager != null)
foreach (InventoryItemBase item in invCol.Items)
UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData);
});
return invCol;
}

View File

@ -46,10 +46,22 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private bool m_Enabled = false;
private bool m_Initialized = false;
// private Scene m_Scene;
private Scene m_Scene;
private XInventoryServicesConnector m_RemoteConnector;
private IUserManagement m_UserManager;
private IUserManagement UserManager
{
get
{
if (m_UserManager == null)
{
m_UserManager = m_Scene.RequestModuleInterface<IUserManagement>();
}
return m_UserManager;
}
}
public Type ReplaceableInterface
{
get { return null; }
@ -114,12 +126,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
if (!m_Enabled)
return;
if (!m_Initialized)
{
m_Initialized = true;
}
scene.RegisterModuleInterface<IInventoryService>(this);
if (m_Scene == null)
m_Scene = scene;
}
public void RemoveRegion(Scene scene)
@ -173,7 +183,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
public InventoryCollection GetFolderContent(UUID userID, UUID folderID)
{
return m_RemoteConnector.GetFolderContent(userID, folderID);
InventoryCollection invCol = m_RemoteConnector.GetFolderContent(userID, folderID);
Util.FireAndForget(delegate
{
if (UserManager != null)
foreach (InventoryItemBase item in invCol.Items)
UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData);
});
return invCol;
}
public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)

View File

@ -125,7 +125,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
else
Scene.RegionInfo.RegionSettings.AllowLandResell = true;
if((byte)maxAgents <= Scene.RegionInfo.AgentCapacity)
Scene.RegionInfo.RegionSettings.AgentLimit = (byte) maxAgents;
else
Scene.RegionInfo.RegionSettings.AgentLimit = Scene.RegionInfo.AgentCapacity;
Scene.RegionInfo.RegionSettings.ObjectBonus = objectBonusFactor;

View File

@ -119,16 +119,40 @@ namespace OpenSim.Region.Framework.Scenes
private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity)
{
// And anything attached to this avatar gets top priority as well
if (entity is SceneObjectPart)
{
SceneObjectPart sop = (SceneObjectPart)entity;
if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
return 1;
}
return PriorityQueue.NumberOfImmediateQueues; // first queue past the immediate queues
}
private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
{
// And anything attached to this avatar gets top priority as well
if (entity is SceneObjectPart)
{
SceneObjectPart sop = (SceneObjectPart)entity;
if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
return 1;
}
return ComputeDistancePriority(client,entity,false);
}
private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
{
// And anything attached to this avatar gets top priority as well
if (entity is SceneObjectPart)
{
SceneObjectPart sop = (SceneObjectPart)entity;
if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
return 1;
}
return ComputeDistancePriority(client,entity,true);
}
@ -141,18 +165,20 @@ namespace OpenSim.Region.Framework.Scenes
{
if (!presence.IsChildAgent)
{
// All avatars other than our own go into pqueue 1
if (entity is ScenePresence)
return 1;
if (entity is SceneObjectPart)
{
// Attachments are high priority,
if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
return 1;
// Non physical prims are lower priority than physical prims
PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
if (physActor == null || !physActor.IsPhysical)
pqueue++;
// Attachments are high priority,
// MIC: shouldn't these already be in the highest priority queue already
// since their root position is same as the avatars?
if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
pqueue = 1;
}
}
}
@ -172,7 +198,7 @@ namespace OpenSim.Region.Framework.Scenes
// m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId);
// throw new InvalidOperationException("Prioritization agent not defined");
return Int32.MaxValue;
return PriorityQueue.NumberOfQueues - 1;
}
// Use group position for child prims, since we are putting child prims in
@ -197,8 +223,10 @@ namespace OpenSim.Region.Framework.Scenes
// And convert the distance to a priority queue, this computation gives queues
// at 10, 20, 40, 80, 160, 320, 640, and 1280m
uint pqueue = 1;
for (int i = 0; i < 8; i++)
uint pqueue = PriorityQueue.NumberOfImmediateQueues;
uint queues = PriorityQueue.NumberOfQueues - PriorityQueue.NumberOfImmediateQueues;
for (int i = 0; i < queues - 1; i++)
{
if (distance < 10 * Math.Pow(2.0,i))
break;

View File

@ -1430,6 +1430,10 @@ namespace OpenSim.Region.Framework.Scenes
}
else // Updating existing item with new perms etc
{
// m_log.DebugFormat(
// "[PRIM INVENTORY]: Updating item {0} in {1} for UpdateTaskInventory()",
// currentItem.Name, part.Name);
IAgentAssetTransactions agentTransactions = this.RequestModuleInterface<IAgentAssetTransactions>();
if (agentTransactions != null)
{
@ -2039,6 +2043,12 @@ namespace OpenSim.Region.Framework.Scenes
if (rot != null)
group.UpdateGroupRotationR((Quaternion)rot);
// TODO: This needs to be refactored with the similar code in
// SceneGraph.AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, Vector3 pos, Quaternion rot, Vector3 vel)
// possibly by allowing this method to take a null rotation.
if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical && vel != Vector3.Zero)
group.RootPart.ApplyImpulse((vel * group.GetMass()), false);
// We can only call this after adding the scene object, since the scene object references the scene
// to find out if scripts should be activated at all.
group.CreateScriptInstances(param, true, DefaultScriptEngine, 3);

View File

@ -3665,6 +3665,15 @@ namespace OpenSim.Region.Framework.Scenes
return false;
}
int num = m_sceneGraph.GetNumberOfScenePresences();
if (num >= RegionInfo.RegionSettings.AgentLimit)
{
if (!Permissions.IsAdministrator(cAgentData.AgentID))
return false;
}
ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID);
if (childAgentUpdate != null)
@ -4966,6 +4975,17 @@ namespace OpenSim.Region.Framework.Scenes
// child agent creation, thereby emulating the SL behavior.
public bool QueryAccess(UUID agentID, Vector3 position, out string reason)
{
int num = m_sceneGraph.GetNumberOfScenePresences();
if (num >= RegionInfo.RegionSettings.AgentLimit)
{
if (!Permissions.IsAdministrator(agentID))
{
reason = "The region is full";
return false;
}
}
reason = String.Empty;
return true;
}

View File

@ -800,6 +800,11 @@ namespace OpenSim.Region.Framework.Scenes
return m_scenePresenceArray;
}
public int GetNumberOfScenePresences()
{
return m_scenePresenceArray.Count;
}
/// <summary>
/// Request a scene presence by UUID. Fast, indexed lookup.
/// </summary>

View File

@ -81,16 +81,20 @@ namespace OpenSim.Region.Framework.Scenes
}
/// <summary>
/// Add an inventory item to a prim in this group.
/// Add an inventory item from a user's inventory to a prim in this scene object.
/// </summary>
/// <param name="remoteClient"></param>
/// <param name="localID"></param>
/// <param name="item"></param>
/// <param name="remoteClient">The client adding the item.</param>
/// <param name="localID">The local ID of the part receiving the add.</param>
/// <param name="item">The user inventory item being added.</param>
/// <param name="copyItemID">The item UUID that should be used by the new item.</param>
/// <returns></returns>
public bool AddInventoryItem(IClientAPI remoteClient, uint localID,
InventoryItemBase item, UUID copyItemID)
{
// m_log.DebugFormat(
// "[PRIM INVENTORY]: Adding inventory item {0} from {1} to part with local ID {2}",
// item.Name, remoteClient.Name, localID);
UUID newItemId = (copyItemID != UUID.Zero) ? copyItemID : item.ID;
SceneObjectPart part = GetChildPart(localID);
@ -134,6 +138,11 @@ namespace OpenSim.Region.Framework.Scenes
}
taskItem.Flags = item.Flags;
// m_log.DebugFormat(
// "[PRIM INVENTORY]: Flags are 0x{0:X} for item {1} added to part {2} by {3}",
// taskItem.Flags, taskItem.Name, localID, remoteClient.Name);
// TODO: These are pending addition of those fields to TaskInventoryItem
// taskItem.SalePrice = item.SalePrice;
// taskItem.SaleType = item.SaleType;

View File

@ -693,8 +693,9 @@ namespace OpenSim.Region.Framework.Scenes
{
TaskInventoryItem it = GetInventoryItem(item.ItemID);
if (it != null)
{
// m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name);
item.ParentID = m_part.UUID;
item.ParentPartID = m_part.UUID;
@ -714,11 +715,13 @@ namespace OpenSim.Region.Framework.Scenes
if (fireScriptEvents)
m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
if (considerChanged)
{
HasInventoryChanged = true;
m_part.ParentGroup.HasGroupChanged = true;
}
return true;
}
else

View File

@ -2340,12 +2340,14 @@ namespace OpenSim.Region.Framework.Scenes
#region Update Client(s)
/// <summary>
/// Sends a location update to the client connected to this scenePresence
/// </summary>
/// <param name="remoteClient"></param>
public void SendTerseUpdateToClient(IClientAPI remoteClient)
{
// If the client is inactive, it's getting its updates from another
// server.
if (remoteClient.IsActive)
@ -2367,17 +2369,32 @@ namespace OpenSim.Region.Framework.Scenes
}
}
// vars to support reduced update frequency when velocity is unchanged
private Vector3 lastVelocitySentToAllClients = Vector3.Zero;
private int lastTerseUpdateToAllClientsTick = Util.EnvironmentTickCount();
/// <summary>
/// Send a location/velocity/accelleration update to all agents in scene
/// </summary>
public void SendTerseUpdateToAllClients()
{
m_perfMonMS = Util.EnvironmentTickCount();
int currentTick = Util.EnvironmentTickCount();
// decrease update frequency when avatar is moving but velocity is not changing
if (m_velocity.Length() < 0.01f
|| Vector3.Distance(lastVelocitySentToAllClients, m_velocity) > 0.01f
|| currentTick - lastTerseUpdateToAllClientsTick > 1500)
{
m_perfMonMS = currentTick;
lastVelocitySentToAllClients = m_velocity;
lastTerseUpdateToAllClientsTick = currentTick;
m_scene.ForEachClient(SendTerseUpdateToClient);
m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
}
}
public void SendCoarseLocations(List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
{
@ -2632,18 +2649,17 @@ namespace OpenSim.Region.Framework.Scenes
cadu.GroupAccess = 0;
cadu.Position = AbsolutePosition;
cadu.regionHandle = m_rootRegionHandle;
float multiplier = 1;
int innacurateNeighbors = m_scene.GetInaccurateNeighborCount();
if (innacurateNeighbors != 0)
{
multiplier = 1f / (float)innacurateNeighbors;
}
if (multiplier <= 0f)
{
multiplier = 0.25f;
}
//m_log.Info("[NeighborThrottle]: " + m_scene.GetInaccurateNeighborCount().ToString() + " - m: " + multiplier.ToString());
// Throttles
float multiplier = 1;
int childRegions = m_knownChildRegions.Count;
if (childRegions != 0)
multiplier = 1f / childRegions;
// Minimum throttle for a child region is 1/4 of the root region throttle
if (multiplier <= 0.25f)
multiplier = 0.25f;
cadu.throttles = ControllingClient.GetThrottlesPacked(multiplier);
cadu.Velocity = Velocity;
@ -3039,16 +3055,14 @@ namespace OpenSim.Region.Framework.Scenes
// Throttles
float multiplier = 1;
int innacurateNeighbors = m_scene.GetInaccurateNeighborCount();
if (innacurateNeighbors != 0)
{
multiplier = 1f / innacurateNeighbors;
}
if (multiplier <= 0f)
{
int childRegions = m_knownChildRegions.Count;
if (childRegions != 0)
multiplier = 1f / childRegions;
// Minimum throttle for a child region is 1/4 of the root region throttle
if (multiplier <= 0.25f)
multiplier = 0.25f;
}
//m_log.Info("[NeighborThrottle]: " + m_scene.GetInaccurateNeighborCount().ToString() + " - m: " + multiplier.ToString());
cAgent.Throttles = ControllingClient.GetThrottlesPacked(multiplier);
cAgent.HeadRotation = m_headrotation;
@ -3271,10 +3285,7 @@ namespace OpenSim.Region.Framework.Scenes
m_updateflag = true;
// The magic constant 0.95f seems to make walking feel less jerky,
// probably because it hackishly accounts for the overall latency of
// these Velocity updates -- Diva
Velocity = force * .95F;
Velocity = force;
m_forceToApply = null;
}

View File

@ -116,6 +116,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
using (StringReader sr = new StringReader(xml))
{
using (XmlTextReader reader = new XmlTextReader(sr))
{
try
{
reader.Read();
if (reader.Name != "CoalescedObject")
@ -141,6 +143,15 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
reader.ReadEndElement(); // CoalescedObject
}
catch (Exception e)
{
m_log.ErrorFormat(
"[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed with {0} {1}",
e.Message, e.StackTrace);
return false;
}
}
}
return true;

View File

@ -298,12 +298,22 @@ namespace OpenSim.Region.Framework.Scenes
if (null != objectAsset)
{
string xml = Utils.BytesToString(objectAsset.Data);
CoalescedSceneObjects coa;
if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa))
{
foreach (SceneObjectGroup sog in coa.Objects)
GatherAssetUuids(sog, assetUuids);
}
else
{
SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml);
if (null != sog)
GatherAssetUuids(sog, assetUuids);
}
}
}
/// <summary>
/// Get the asset uuid associated with a gesture

View File

@ -81,6 +81,14 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
lock (m_scenes)
m_scenes[scene.RegionInfo.RegionID] = scene;
scene.AddCommand(
this, "show pqueues",
"show pqueues [full]",
"Show priority queue data for each client",
"Without the 'full' option, only root agents are shown."
+ " With the 'full' option child agents are also shown.",
ShowPQueuesReport);
scene.AddCommand(
this, "show queues",
"show queues [full]",
@ -119,6 +127,11 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
}
protected void ShowPQueuesReport(string module, string[] cmd)
{
MainConsole.Instance.Output(GetPQueuesReport(cmd));
}
protected void ShowQueuesReport(string module, string[] cmd)
{
MainConsole.Instance.Output(GetQueuesReport(cmd));
@ -155,6 +168,80 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
"");
}
/// <summary>
/// Generate UDP Queue data report for each client
/// </summary>
/// <param name="showParams"></param>
/// <returns></returns>
protected string GetPQueuesReport(string[] showParams)
{
bool showChildren = false;
string pname = "";
if (showParams.Length > 2 && showParams[2] == "full")
showChildren = true;
else if (showParams.Length > 3)
pname = showParams[2] + " " + showParams[3];
StringBuilder report = new StringBuilder();
int columnPadding = 2;
int maxNameLength = 18;
int maxRegionNameLength = 14;
int maxTypeLength = 4;
int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding;
report.Append(GetColumnEntry("User", maxNameLength, columnPadding));
report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding));
report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
report.AppendFormat(
"{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7} {10,7} {11,7}\n",
"Pri 0",
"Pri 1",
"Pri 2",
"Pri 3",
"Pri 4",
"Pri 5",
"Pri 6",
"Pri 7",
"Pri 8",
"Pri 9",
"Pri 10",
"Pri 11");
lock (m_scenes)
{
foreach (Scene scene in m_scenes.Values)
{
scene.ForEachClient(
delegate(IClientAPI client)
{
if (client is LLClientView)
{
bool isChild = scene.PresenceChildStatus(client.AgentId);
if (isChild && !showChildren)
return;
string name = client.Name;
if (pname != "" && name != pname)
return;
string regionName = scene.RegionInfo.RegionName;
report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
report.AppendLine(((LLClientView)client).EntityUpdateQueue.ToString());
}
});
}
}
return report.ToString();
}
/// <summary>
/// Generate UDP Queue data report for each client
/// </summary>
@ -163,9 +250,12 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
protected string GetQueuesReport(string[] showParams)
{
bool showChildren = false;
string pname = "";
if (showParams.Length > 2 && showParams[2] == "full")
showChildren = true;
else if (showParams.Length > 3)
pname = showParams[2] + " " + showParams[3];
StringBuilder report = new StringBuilder();
@ -224,6 +314,9 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
return;
string name = client.Name;
if (pname != "" && name != pname)
return;
string regionName = scene.RegionInfo.RegionName;
report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
@ -249,9 +342,12 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
protected string GetThrottlesReport(string[] showParams)
{
bool showChildren = false;
string pname = "";
if (showParams.Length > 2 && showParams[2] == "full")
showChildren = true;
else if (showParams.Length > 3)
pname = showParams[2] + " " + showParams[3];
StringBuilder report = new StringBuilder();
@ -314,6 +410,9 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
return;
string name = client.Name;
if (pname != "" && name != pname)
return;
string regionName = scene.RegionInfo.RegionName;
LLUDPClient llUdpClient = llClient.UDPClient;
@ -352,7 +451,7 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
int maxRegionNameLength = 14;
int maxTypeLength = 4;
string name = "SERVER AGENT LIMITS";
string name = "SERVER AGENT RATES";
report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
report.Append(GetColumnEntry("-", maxRegionNameLength, columnPadding));
@ -362,13 +461,13 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
report.AppendFormat(
"{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}",
(throttleRates.Total * 8) / 1000,
(throttleRates.ResendLimit * 8) / 1000,
(throttleRates.LandLimit * 8) / 1000,
(throttleRates.WindLimit * 8) / 1000,
(throttleRates.CloudLimit * 8) / 1000,
(throttleRates.TaskLimit * 8) / 1000,
(throttleRates.TextureLimit * 8) / 1000,
(throttleRates.AssetLimit * 8) / 1000);
(throttleRates.Resend * 8) / 1000,
(throttleRates.Land * 8) / 1000,
(throttleRates.Wind * 8) / 1000,
(throttleRates.Cloud * 8) / 1000,
(throttleRates.Task * 8) / 1000,
(throttleRates.Texture * 8) / 1000,
(throttleRates.Asset * 8) / 1000);
return report.ToString();
}

View File

@ -118,7 +118,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
if (serviceDll == String.Empty)
{
m_log.Error("[FreeSwitchVoice]: No LocalServiceModule named in section FreeSwitchVoice");
m_log.Error("[FreeSwitchVoice]: No LocalServiceModule named in section FreeSwitchVoice. Not starting.");
return;
}
@ -143,8 +143,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
if (String.IsNullOrEmpty(m_freeSwitchRealm) ||
String.IsNullOrEmpty(m_freeSwitchAPIPrefix))
{
m_log.Error("[FreeSwitchVoice] plugin mis-configured");
m_log.Info("[FreeSwitchVoice] plugin disabled: incomplete configuration");
m_log.Error("[FreeSwitchVoice]: Freeswitch service mis-configured. Not starting.");
return;
}
@ -164,24 +163,24 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
// String.Format("{0}/viv_get_prelogin.php", m_freeSwitchAPIPrefix), FreeSwitchSLVoiceGetPreloginHTTPHandler);
// MainServer.Instance.AddStreamHandler(h);
MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_signin.php", m_freeSwitchAPIPrefix),
FreeSwitchSLVoiceSigninHTTPHandler);
MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_buddy.php", m_freeSwitchAPIPrefix),
FreeSwitchSLVoiceBuddyHTTPHandler);
m_log.InfoFormat("[FreeSwitchVoice] using FreeSwitch server {0}", m_freeSwitchRealm);
MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_watcher.php", m_freeSwitchAPIPrefix),
FreeSwitchSLVoiceWatcherHTTPHandler);
m_log.InfoFormat("[FreeSwitchVoice]: using FreeSwitch server {0}", m_freeSwitchRealm);
m_Enabled = true;
m_log.Info("[FreeSwitchVoice] plugin enabled");
m_log.Info("[FreeSwitchVoice]: plugin enabled");
}
catch (Exception e)
{
m_log.ErrorFormat("[FreeSwitchVoice] plugin initialization failed: {0}", e.Message);
m_log.DebugFormat("[FreeSwitchVoice] plugin initialization failed: {0}", e.ToString());
m_log.ErrorFormat("[FreeSwitchVoice]: plugin initialization failed: {0} {1}", e.Message, e.StackTrace);
return;
}
@ -240,7 +239,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
{
if (m_Enabled)
{
m_log.Info("[FreeSwitchVoice] registering IVoiceModule with the scene");
m_log.Info("[FreeSwitchVoice]: registering IVoiceModule with the scene");
// register the voice interface for this module, so the script engine can call us
scene.RegisterModuleInterface<IVoiceModule>(this);
@ -302,7 +301,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
// </summary>
public void OnRegisterCaps(Scene scene, UUID agentID, Caps caps)
{
m_log.DebugFormat("[FreeSwitchVoice] OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
m_log.DebugFormat(
"[FreeSwitchVoice]: OnRegisterCaps() called with agentID {0} caps {1} in scene {2}",
agentID, caps, scene.RegionInfo.RegionName);
string capsBase = "/CAPS/" + caps.CapsObjectPath;
caps.RegisterHandler("ProvisionVoiceAccountRequest",
@ -344,6 +345,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
public string ProvisionVoiceAccountRequest(Scene scene, string request, string path, string param,
UUID agentID, Caps caps)
{
m_log.DebugFormat(
"[FreeSwitchVoice][PROVISIONVOICE]: ProvisionVoiceAccountRequest() request: {0}, path: {1}, param: {2}", request, path, param);
ScenePresence avatar = scene.GetScenePresence(agentID);
if (avatar == null)
{
@ -357,9 +361,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
try
{
//m_log.DebugFormat("[FreeSwitchVoice][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}",
// request, path, param);
//XmlElement resp;
string agentname = "x" + Convert.ToBase64String(agentID.GetBytes());
string password = "1234";//temp hack//new UUID(Guid.NewGuid()).ToString().Replace('-','Z').Substring(0,16);
@ -390,7 +391,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse);
m_log.DebugFormat("[FreeSwitchVoice][PROVISIONVOICE]: avatar \"{0}\": {1}", avatarName, r);
// m_log.DebugFormat("[FreeSwitchVoice][PROVISIONVOICE]: avatar \"{0}\": {1}", avatarName, r);
return r;
}
@ -416,6 +417,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
public string ParcelVoiceInfoRequest(Scene scene, string request, string path, string param,
UUID agentID, Caps caps)
{
// m_log.DebugFormat(
// "[FreeSwitchVoice][PARCELVOICE]: ParcelVoiceInfoRequest() on {0} for {1}",
// scene.RegionInfo.RegionName, agentID);
ScenePresence avatar = scene.GetScenePresence(agentID);
string avatarName = avatar.Name;
@ -453,8 +458,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
if ((land.Flags & (uint)ParcelFlags.AllowVoiceChat) == 0)
{
m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": voice not enabled for parcel",
scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName);
// m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": voice not enabled for parcel",
// scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName);
channelUri = String.Empty;
}
else
@ -469,8 +474,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
parcelVoiceInfo = new LLSDParcelVoiceInfoResponse(scene.RegionInfo.RegionName, land.LocalID, creds);
string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo);
m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": {4}",
scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, r);
// m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": {4}",
// scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, r);
return r;
}
catch (Exception e)
@ -502,6 +507,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
m_log.DebugFormat("[FreeSwitchVoice][CHATSESSION]: avatar \"{0}\": request: {1}, path: {2}, param: {3}",
avatarName, request, path, param);
return "<llsd>true</llsd>";
}
@ -555,10 +561,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
return response;
}
public Hashtable FreeSwitchSLVoiceGetPreloginHTTPHandler(Hashtable request)
{
m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceGetPreloginHTTPHandler called");
m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceGetPreloginHTTPHandler called");
Hashtable response = new Hashtable();
response["content_type"] = "text/xml";
@ -592,6 +597,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
public Hashtable FreeSwitchSLVoiceBuddyHTTPHandler(Hashtable request)
{
m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceBuddyHTTPHandler called");
Hashtable response = new Hashtable();
response["int_response_code"] = 200;
response["str_response_string"] = string.Empty;
@ -656,15 +663,58 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
resp.Append("</buddies><groups></groups></body></level0></response>");
response["str_response_string"] = resp.ToString();
// Regex normalizeEndLines = new Regex(@"\r\n", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline);
// Regex normalizeEndLines = new Regex(@"(\r\n|\n)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline);
//
// m_log.DebugFormat(
// "[FREESWITCH]: FreeSwitchSLVoiceBuddyHTTPHandler() response {0}",
// normalizeEndLines.Replace((string)response["str_response_string"],""));
return response;
}
public Hashtable FreeSwitchSLVoiceWatcherHTTPHandler(Hashtable request)
{
m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceWatcherHTTPHandler called");
Hashtable response = new Hashtable();
response["int_response_code"] = 200;
response["content-type"] = "text/xml";
Hashtable requestBody = ParseRequestBody((string)request["body"]);
string auth_token = (string)requestBody["auth_token"];
//string[] auth_tokenvals = auth_token.Split(':');
//string username = auth_tokenvals[0];
StringBuilder resp = new StringBuilder();
resp.Append("<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?><response xmlns=\"http://www.vivox.com\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation= \"/xsd/buddy_list.xsd\">");
// FIXME: This is enough of a response to stop viewer 2 complaining about a login failure and get voice to work. If we don't
// give an OK response, then viewer 2 engages in an continuous viv_signin.php, viv_buddy.php, viv_watcher.php loop
// Viewer 1 appeared happy to ignore the lack of reply and still works with this reply.
//
// However, really we need to fill in whatever watcher data should be here (whatever that is).
resp.Append(string.Format(@"<level0>
<status>OK</status>
<cookie_name>lib_session</cookie_name>
<cookie>{0}</cookie>
<auth_token>{0}</auth_token>
<body/></level0></response>", auth_token));
response["str_response_string"] = resp.ToString();
// Regex normalizeEndLines = new Regex(@"(\r\n|\n)", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline);
//
// m_log.DebugFormat(
// "[FREESWITCH]: FreeSwitchSLVoiceWatcherHTTPHandler() response {0}",
// normalizeEndLines.Replace((string)response["str_response_string"],""));
//m_log.DebugFormat("[FREESWITCH]: {0}", normalizeEndLines.Replace((string)response["str_response_string"],""));
return response;
}
public Hashtable FreeSwitchSLVoiceSigninHTTPHandler(Hashtable request)
{
m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceSigninHTTPHandler called");
m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceSigninHTTPHandler called");
// string requestbody = (string)request["body"];
// string uri = (string)request["uri"];
// string contenttype = (string)request["content-type"];
@ -710,6 +760,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
</response>", userid, pos, avatarName);
response["int_response_code"] = 200;
// m_log.DebugFormat("[FreeSwitchVoice]: Sending FreeSwitchSLVoiceSigninHTTPHandler response");
return response;
}
@ -800,11 +853,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
string section = (string) requestBody["section"];
if (section == "directory")
{
string eventCallingFunction = (string)requestBody["Event-Calling-Function"];
m_log.DebugFormat(
"[FreeSwitchVoice]: Received request for config section directory, event calling function '{0}'",
eventCallingFunction);
response = m_FreeswitchService.HandleDirectoryRequest(requestBody);
}
else if (section == "dialplan")
{
m_log.DebugFormat("[FreeSwitchVoice]: Received request for config section dialplan");
response = m_FreeswitchService.HandleDialplanRequest(requestBody);
}
else
m_log.WarnFormat("[FreeSwitchVoice]: section was {0}", section);
m_log.WarnFormat("[FreeSwitchVoice]: Unknown section {0} was requested from config.", section);
return response;
}

View File

@ -84,10 +84,11 @@ namespace OpenSim.Region.Physics.Meshing
public Meshmerizer(IConfigSource config)
{
IConfig start_config = config.Configs["Startup"];
IConfig mesh_config = config.Configs["Mesh"];
decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
useMeshiesPhysicsMesh = start_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
try
{

View File

@ -62,6 +62,8 @@ namespace PrimMesher
bool needsScaling = false;
bool smallMap = bmW * bmH <= lod * lod;
width = bmW;
height = bmH;
while (width * height > numLodPixels)
@ -104,9 +106,14 @@ namespace PrimMesher
{
for (int x = 0; x <= width; x++)
{
int bmY = y < height ? y * 2 : y * 2 - 1;
int bmX = x < width ? x * 2 : x * 2 - 1;
Color c = bm.GetPixel(bmX, bmY);
Color c;
if (smallMap)
c = bm.GetPixel(x < width ? x : x - 1,
y < height ? y : y - 1);
else
c = bm.GetPixel(x < width ? x * 2 : x * 2 - 1,
y < height ? y * 2 : y * 2 - 1);
redBytes[byteNdx] = c.R;
greenBytes[byteNdx] = c.G;

View File

@ -158,6 +158,9 @@ namespace OpenSim.Services.Connectors
public InventoryCollection GetFolderContent(UUID principalID, UUID folderID)
{
InventoryCollection inventory = new InventoryCollection();
inventory.Folders = new List<InventoryFolderBase>();
inventory.Items = new List<InventoryItemBase>();
inventory.UserID = principalID;
try
{
@ -172,11 +175,6 @@ namespace OpenSim.Services.Connectors
if (ret.Count == 0)
return null;
inventory.Folders = new List<InventoryFolderBase>();
inventory.Items = new List<InventoryItemBase>();
inventory.UserID = principalID;
Dictionary<string,object> folders =
(Dictionary<string,object>)ret["FOLDERS"];
Dictionary<string,object> items =

View File

@ -50,13 +50,13 @@ namespace OpenSim.Services.FreeswitchService
public Hashtable HandleDialplanRequest(Hashtable request)
{
m_log.DebugFormat("[FreeSwitchVoice] HandleDialplanRequest called with {0}",request.ToString());
m_log.DebugFormat("[FreeSwitchVoice]: HandleDialplanRequest called with {0}",request.ToString());
Hashtable response = new Hashtable();
foreach (DictionaryEntry item in request)
{
m_log.InfoFormat("[FreeSwitchDirectory] requestBody item {0} {1}",item.Key, item.Value);
// m_log.InfoFormat("[FreeSwitchDirectory]: requestBody item {0} {1}",item.Key, item.Value);
}
string requestcontext = (string) request["Hunt-Context"];
@ -66,7 +66,7 @@ namespace OpenSim.Services.FreeswitchService
if (m_freeSwitchContext != String.Empty && m_freeSwitchContext != requestcontext)
{
m_log.Debug("[FreeSwitchDirectory] returning empty as it's for another context");
m_log.Debug("[FreeSwitchDirectory]: returning empty as it's for another context");
response["str_response_string"] = "";
}
else
@ -116,13 +116,16 @@ namespace OpenSim.Services.FreeswitchService
{
Hashtable response = new Hashtable();
string domain = (string) request["domain"];
if (domain != m_freeSwitchRealm) {
if (domain != m_freeSwitchRealm)
{
response["content_type"] = "text/xml";
response["keepalive"] = false;
response["int_response_code"] = 200;
response["str_response_string"] = "";
} else {
m_log.DebugFormat("[FreeSwitchDirectory] HandleDirectoryRequest called with {0}",request.ToString());
}
else
{
// m_log.DebugFormat("[FreeSwitchDirectory]: HandleDirectoryRequest called with {0}",request.ToString());
// information in the request we might be interested in
@ -143,10 +146,8 @@ namespace OpenSim.Services.FreeswitchService
//domain=9.20.151.43
//ip=9.167.220.137 // this is the correct IP rather than sip_contact_host above when through a vpn or NAT setup
foreach (DictionaryEntry item in request)
{
m_log.InfoFormat("[FreeSwitchDirectory] requestBody item {0} {1}", item.Key, item.Value);
}
// foreach (DictionaryEntry item in request)
// m_log.DebugFormat("[FreeSwitchDirectory]: requestBody item {0} {1}", item.Key, item.Value);
string eventCallingFunction = (string) request["Event-Calling-Function"];
if (eventCallingFunction == null)
@ -173,7 +174,7 @@ namespace OpenSim.Services.FreeswitchService
}
else
{
m_log.ErrorFormat("[FreeSwitchVoice] HandleDirectoryRequest unknown sip_auth_method {0}",sipAuthMethod);
m_log.ErrorFormat("[FreeSwitchVoice]: HandleDirectoryRequest unknown sip_auth_method {0}",sipAuthMethod);
response["int_response_code"] = 404;
response["content_type"] = "text/xml";
response["str_response_string"] = "";
@ -205,7 +206,7 @@ namespace OpenSim.Services.FreeswitchService
}
else
{
m_log.ErrorFormat("[FreeSwitchVoice] HandleDirectoryRequest unknown Event-Calling-Function {0}",eventCallingFunction);
m_log.ErrorFormat("[FreeSwitchVoice]: HandleDirectoryRequest unknown Event-Calling-Function {0}",eventCallingFunction);
response["int_response_code"] = 404;
response["keepalive"] = false;
response["content_type"] = "text/xml";
@ -217,7 +218,7 @@ namespace OpenSim.Services.FreeswitchService
private Hashtable HandleRegister(string Context, string Realm, Hashtable request)
{
m_log.Info("[FreeSwitchDirectory] HandleRegister called");
m_log.Info("[FreeSwitchDirectory]: HandleRegister called");
// TODO the password we return needs to match that sent in the request, this is hard coded for now
string password = "1234";
@ -254,7 +255,7 @@ namespace OpenSim.Services.FreeswitchService
private Hashtable HandleInvite(string Context, string Realm, Hashtable request)
{
m_log.Info("[FreeSwitchDirectory] HandleInvite called");
m_log.Info("[FreeSwitchDirectory]: HandleInvite called");
// TODO the password we return needs to match that sent in the request, this is hard coded for now
string password = "1234";
@ -301,7 +302,7 @@ namespace OpenSim.Services.FreeswitchService
private Hashtable HandleLocateUser(String Realm, Hashtable request)
{
m_log.Info("[FreeSwitchDirectory] HandleLocateUser called");
m_log.Info("[FreeSwitchDirectory]: HandleLocateUser called");
// TODO the password we return needs to match that sent in the request, this is hard coded for now
string domain = (string) request["domain"];
@ -335,7 +336,7 @@ namespace OpenSim.Services.FreeswitchService
private Hashtable HandleConfigSofia(string Context, string Realm, Hashtable request)
{
m_log.Info("[FreeSwitchDirectory] HandleConfigSofia called");
m_log.Info("[FreeSwitchDirectory]: HandleConfigSofia called.");
// TODO the password we return needs to match that sent in the request, this is hard coded for now
string domain = (string) request["domain"];

View File

@ -64,7 +64,7 @@ namespace OpenSim.Services.FreeswitchService
m_freeSwitchDefaultWellKnownIP = freeswitchConfig.GetString("ServerAddress", String.Empty);
if (m_freeSwitchDefaultWellKnownIP == String.Empty)
{
m_log.Error("[FREESWITCH]: No FreeswitchServerAddress given, can't continue");
m_log.Error("[FREESWITCH]: No ServerAddress given, cannot start service.");
return;
}

View File

@ -29,6 +29,7 @@ using System;
using System.Collections.Generic;
using System.Net;
using System.Reflection;
using System.Text.RegularExpressions;
using OpenSim.Framework;
using OpenSim.Services.Interfaces;
@ -57,6 +58,9 @@ namespace OpenSim.Services.HypergridService
private static IUserAgentService m_UserAgentService;
private static ISimulationService m_SimulationService;
protected string m_AllowedClients = string.Empty;
protected string m_DeniedClients = string.Empty;
private static UUID m_ScopeID;
private static bool m_AllowTeleportsToAnyRegion;
private static string m_ExternalName;
@ -104,6 +108,9 @@ namespace OpenSim.Services.HypergridService
else if (simulationService != string.Empty)
m_SimulationService = ServerUtils.LoadPlugin<ISimulationService>(simulationService, args);
m_AllowedClients = serverConfig.GetString("AllowedClients", string.Empty);
m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty);
if (m_GridService == null || m_PresenceService == null || m_SimulationService == null)
throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function.");
@ -181,8 +188,36 @@ namespace OpenSim.Services.HypergridService
string authURL = string.Empty;
if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
authURL = aCircuit.ServiceURLs["HomeURI"].ToString();
m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to login foreign agent {0} {1} @ {2} ({3}) at destination {4}",
aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionName);
m_log.InfoFormat("[GATEKEEPER SERVICE]: Login request for {0} {1} @ {2} ({3}) at {4} using viewer {5}, channel {6}, IP {7}, Mac {8}, Id0 {9}",
aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionName,
aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0);
//
// Check client
//
if (m_AllowedClients != string.Empty)
{
Regex arx = new Regex(m_AllowedClients);
Match am = arx.Match(aCircuit.Viewer);
if (!am.Success)
{
m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", aCircuit.Viewer);
return false;
}
}
if (m_DeniedClients != string.Empty)
{
Regex drx = new Regex(m_DeniedClients);
Match dm = drx.Match(aCircuit.Viewer);
if (dm.Success)
{
m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", aCircuit.Viewer);
return false;
}
}
//
// Authenticate the user

View File

@ -244,7 +244,7 @@ namespace OpenSim.Services.InventoryService
// connector. So we disregard the principal and look
// by ID.
//
m_log.DebugFormat("[XINVENTORY SERVICE]: Fetch contents for folder {0}", folderID.ToString());
//m_log.DebugFormat("[XINVENTORY SERVICE]: Fetch contents for folder {0}", folderID.ToString());
InventoryCollection inventory = new InventoryCollection();
inventory.UserID = principalID;
inventory.Folders = new List<InventoryFolderBase>();

View File

@ -77,7 +77,11 @@ namespace OpenSim.Services.LLLoginService
protected string m_MapTileURL;
protected string m_SearchURL;
protected string m_AllowedClients;
protected string m_DeniedClients;
IConfig m_LoginServerConfig;
IConfig m_ClientsConfig;
public LLLoginService(IConfigSource config, ISimulationService simService, ILibraryService libraryService)
{
@ -106,6 +110,9 @@ namespace OpenSim.Services.LLLoginService
m_MapTileURL = m_LoginServerConfig.GetString("MapTileURL", string.Empty);
m_SearchURL = m_LoginServerConfig.GetString("SearchURL", string.Empty);
m_AllowedClients = m_LoginServerConfig.GetString("AllowedClients", string.Empty);
m_DeniedClients = m_LoginServerConfig.GetString("DeniedClients", string.Empty);
// These are required; the others aren't
if (accountService == string.Empty || authService == string.Empty)
throw new Exception("LoginService is missing service specifications");
@ -215,10 +222,37 @@ namespace OpenSim.Services.LLLoginService
bool success = false;
UUID session = UUID.Random();
m_log.InfoFormat("[LLOGIN SERVICE]: Login request for {0} {1} from {2} with user agent {3} starting in {4}",
firstName, lastName, clientIP.Address.ToString(), clientVersion, startLocation);
m_log.InfoFormat("[LLOGIN SERVICE]: Login request for {0} {1} at {2} using viewer {3}, channel {4}, IP {5}, Mac {6}, Id0 {7}",
firstName, lastName, startLocation, clientVersion, channel, clientIP.Address.ToString(), mac, id0);
try
{
//
// Check client
//
if (m_AllowedClients != string.Empty)
{
Regex arx = new Regex(m_AllowedClients);
Match am = arx.Match(clientVersion);
if (!am.Success)
{
m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: client {0} is not allowed", clientVersion);
return LLFailedLoginResponse.LoginBlockedProblem;
}
}
if (m_DeniedClients != string.Empty)
{
Regex drx = new Regex(m_DeniedClients);
Match dm = drx.Match(clientVersion);
if (dm.Success)
{
m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: client {0} is denied", clientVersion);
return LLFailedLoginResponse.LoginBlockedProblem;
}
}
//
// Get the account and check that it exists
//

View File

@ -37,7 +37,7 @@ Now see the "Configuring OpenSim" section
=== Running OpenSim on Linux ===
================================
You will need Mono >= 2.4.2 to run OpenSim. On some Linux distributions you
You will need Mono >= 2.4.3 to run OpenSim. On some Linux distributions you
may need to install additional packages. See http://opensimulator.org/wiki/Dependencies
for more information.

0
bin/Axiom.MathLib.dll Normal file → Executable file
View File

0
bin/BulletDotNET.dll Normal file → Executable file
View File

0
bin/C5.dll Normal file → Executable file
View File

0
bin/CSJ2K.dll Normal file → Executable file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

0
bin/Community.CsharpSqlite.Sqlite.dll Normal file → Executable file
View File

0
bin/Community.CsharpSqlite.dll Normal file → Executable file
View File

0
bin/CookComputing.XmlRpcV2.dll Normal file → Executable file
View File

0
bin/DotNetOpenId.dll Normal file → Executable file
View File

0
bin/DotNetOpenMail.dll Normal file → Executable file
View File

Binary file not shown.

0
bin/Fadd.Globalization.Yaml.dll Normal file → Executable file
View File

0
bin/Fadd.dll Normal file → Executable file
View File

0
bin/GlynnTucker.Cache.dll Normal file → Executable file
View File

0
bin/Google.ProtocolBuffers.dll Normal file → Executable file
View File

0
bin/HttpServer.dll Normal file → Executable file
View File

0
bin/HttpServer_OpenSim.dll Normal file → Executable file
View File

0
bin/Iesi.Collections.dll Normal file → Executable file
View File

0
bin/Kds.Serialization.dll Normal file → Executable file
View File

Binary file not shown.

0
bin/Modified.XnaDevRu.BulletX.dll Normal file → Executable file
View File

0
bin/Mono.Addins.CecilReflector.dll Normal file → Executable file
View File

0
bin/Mono.Addins.Setup.dll Normal file → Executable file
View File

0
bin/Mono.Addins.dll Normal file → Executable file
View File

0
bin/Mono.Data.Sqlite.dll Normal file → Executable file
View File

0
bin/Mono.Data.SqliteClient.dll Normal file → Executable file
View File

Binary file not shown.

0
bin/MonoXnaCompactMaths.dll Normal file → Executable file
View File

0
bin/MySql.Data.dll Normal file → Executable file
View File

0
bin/NDesk.Options.dll Normal file → Executable file
View File

0
bin/Newtonsoft.Json.Net20.dll Normal file → Executable file
View File

0
bin/Nini.dll Normal file → Executable file
View File

0
bin/Npgsql.dll Normal file → Executable file
View File

0
bin/Ode.NET.dll Normal file → Executable file
View File

0
bin/OpenMetaverse.StructuredData.dll Normal file → Executable file
View File

0
bin/OpenMetaverse.dll Normal file → Executable file
View File

0
bin/OpenMetaverseTypes.dll Normal file → Executable file
View File

View File

@ -621,31 +621,49 @@
;; You need to load a local service for a standalone, and a remote service
;; for a grid region. Use one of the lines below, as appropriate
;; If you're using Freeswitch on a standalone then you will also need to configure the [FreeswitchService] section
; LocalServiceModule = OpenSim.Services.FreeswitchService.dll:FreeswitchService
; LocalServiceModule = OpenSim.Services.Connectors.dll:RemoteFreeswitchConnector
;; If using a remote module, specify the server URL
; FreeswitchServiceURL = http://my.grid.server:8003/fsapi
;; If using a remote connector, specify the server URL
; FreeswitchServiceURL = http://my.grid.server:8004/fsapi
[FreeswitchService]
;; !!!!!!!!!!!!!!!!!!!!!!!!!!!
;; !!!!!!STANDALONE ONLY!!!!!!
;; !!!!!!!!!!!!!!!!!!!!!!!!!!!
;; IP of your FS server
;ServerAddress = 85.25.142.92
;; The IP address of your FreeSWITCH server. The common case is for this to be the same as the server running the OpenSim standalone
;; This has to be set for the FreeSWITCH service to work
;ServerAddress = 127.0.0.1
;; All other options are - well - optional
; Realm = "127.0.0.1"
; SIPProxy = "127.0.0.1:5060"
; EchoServer = "127.0.0.1"
; EchoPort = 50505
; AttemptSTUN = "false"
;; The following configuration parameters are optional
;; By default, this is the same as the ServerAddress
; Realm = 127.0.0.1
;; By default, this is the same as the ServerAddress on port 5060
; SIPProxy = 127.0.0.1:5060
;; Default is 5000ms
; DefaultTimeout = 5000
; Context = "default"
; UserName = "freeswitch"
; Password = "password"
;; The dial plan context. Default is "default"
; Context = default
;; Currently unused
; UserName = freeswitch
;; Currently unused
; Password = password
;; The following parameters are for STUN = Simple Traversal of UDP through NATs
;; See http://wiki.freeswitch.org/wiki/NAT_Traversal
;; stun.freeswitch.org is not guaranteed to be running so use it in
;; production at your own risk
; EchoServer = 127.0.0.1
; EchoPort = 50505
; AttemptSTUN = false
[Groups]
;# {Enabled} {} {Enable groups?} {true false} false

View File

@ -149,12 +149,6 @@
; to false if you have compatibility problems.
;CacheSculptMaps = true
; if you use Meshmerizer and want collisions for meshies, setting this to true
; will cause OpenSim to attempt to decode meshies assets, extract the physics
; mesh, and use it for collisions. This is currently experimental code and enabling
; it may cause unexpected physics problems.
;UseMeshiesPhysicsMesh = false
; Choose one of the physics engines below
; OpenDynamicsEngine is by some distance the most developed physics engine
; basicphysics effectively does not model physics at all, making all objects phantom
@ -368,30 +362,24 @@
;
;client_throttle_max_bps = 196608
; Per-client bytes per second rates for the various throttle categories.
; These are default values that will be overriden by clients
; Adaptive throttling attempts to limit network overload when multiple
; clients login by starting each connection more slowly. Disabled by
; default
;
;resend_default = 12500
;land_default = 1000
;wind_default = 1000
;cloud_default = 1000
;task_default = 1000
;texture_default = 1000
;asset_default = 1000
;state_default = 1000
;enable_adaptive_throttles = true
; Per-client maximum burst rates in bytes per second for the various
; throttle categories. These are default values that will be overriden by
; clients
;
;resend_limit = 18750
;land_limit = 29750
;wind_limit = 18750
;cloud_limit = 18750
;task_limit = 18750
;texture_limit = 55750
;asset_limit = 27500
;state_limit = 37000
; Per-client bytes per second rates for the various throttle categories.
; These are default values that will be overriden by clients. These
; defaults are approximately equivalent to the throttles set by the Imprudence
; viewer when maximum bandwidth is set to 350kbps
;resend_default = 6625
;land_default = 9125
;wind_default = 1750
;cloud_default = 1750
;task_default = 18500
;texture_default = 18500
;asset_default = 10500
; Configures how ObjectUpdates are aggregated. These numbers
; do not literally mean how many updates will be put in each
@ -459,7 +447,13 @@
[Mesh]
; enable / disable Collada mesh support
; default is true
; ColladaMesh = true
; AllowMeshUpload = true
; if you use Meshmerizer and want collisions for meshies, setting this to true
; will cause OpenSim to attempt to decode meshies assets, extract the physics
; mesh, and use it for collisions. This is currently experimental code and enabling
; it may cause unexpected physics problems.
;UseMeshiesPhysicsMesh = false
[ODEPhysicsSettings]

0
bin/PhysX-wrapper.dll Normal file → Executable file
View File

0
bin/PhysX_Wrapper_Dotnet.dll Normal file → Executable file
View File

Some files were not shown because too many files have changed in this diff Show More