Merge branch 'ubitwork' of ssh://3dhosting.de/var/git/careminster into ubitwork

avinationmerge
ubit 2012-09-17 14:35:01 +02:00
commit 434704fa99
18 changed files with 434 additions and 216 deletions

View File

@ -47,36 +47,36 @@ using Caps = OpenSim.Framework.Capabilities.Caps;
namespace OpenSim.Capabilities.Handlers namespace OpenSim.Capabilities.Handlers
{ {
public class GetTextureHandler : BaseStreamHandler public class GetTextureHandler
{ {
private static readonly ILog m_log = private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IAssetService m_assetService; private IAssetService m_assetService;
public const string DefaultFormat = "x-j2c"; public const string DefaultFormat = "x-j2c";
// TODO: Change this to a config option public GetTextureHandler(IAssetService assService)
const string REDIRECT_URL = null;
public GetTextureHandler(string path, IAssetService assService, string name, string description)
: base("GET", path, name, description)
{ {
m_assetService = assService; m_assetService = assService;
} }
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) public Hashtable Handle(Hashtable request)
{ {
// Try to parse the texture ID from the request URL Hashtable ret = new Hashtable();
NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
string textureStr = query.GetOne("texture_id"); ret["content_type"] = "text/plain";
string format = query.GetOne("format"); ret["keepalive"] = false;
ret["reusecontext"] = false;
string textureStr = (string)request["texture_id"];
string format = (string)request["format"];
//m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr); //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr);
if (m_assetService == null) if (m_assetService == null)
{ {
m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service");
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
} }
UUID textureID; UUID textureID;
@ -91,30 +91,30 @@ namespace OpenSim.Capabilities.Handlers
} }
else else
{ {
formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); formats = new string[1] { DefaultFormat }; // default
if (((Hashtable)request["headers"])["Accept"] != null)
formats = WebUtil.GetPreferredImageTypes((string)((Hashtable)request["headers"])["Accept"]);
if (formats.Length == 0) if (formats.Length == 0)
formats = new string[1] { DefaultFormat }; // default formats = new string[1] { DefaultFormat }; // default
} }
// OK, we have an array with preferred formats, possibly with only one entry // OK, we have an array with preferred formats, possibly with only one entry
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
foreach (string f in formats) foreach (string f in formats)
{ {
if (FetchTexture(httpRequest, httpResponse, textureID, f)) if (FetchTexture(request, ret, textureID, f))
break; break;
} }
} }
else else
{ {
m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + (string)request["uri"]);
} }
// m_log.DebugFormat( // m_log.DebugFormat(
// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", // "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}",
// textureID, httpResponse.StatusCode, httpResponse.ContentLength); // textureID, httpResponse.StatusCode, httpResponse.ContentLength);
return ret;
return null;
} }
/// <summary> /// <summary>
@ -125,7 +125,7 @@ namespace OpenSim.Capabilities.Handlers
/// <param name="textureID"></param> /// <param name="textureID"></param>
/// <param name="format"></param> /// <param name="format"></param>
/// <returns>False for "caller try another codec"; true otherwise</returns> /// <returns>False for "caller try another codec"; true otherwise</returns>
private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format) private bool FetchTexture(Hashtable request, Hashtable response, UUID textureID, string format)
{ {
// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); // m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format);
AssetBase texture; AssetBase texture;
@ -134,30 +134,6 @@ namespace OpenSim.Capabilities.Handlers
if (format != DefaultFormat) if (format != DefaultFormat)
fullID = fullID + "-" + format; fullID = fullID + "-" + format;
if (!String.IsNullOrEmpty(REDIRECT_URL))
{
// Only try to fetch locally cached textures. Misses are redirected
texture = m_assetService.GetCached(fullID);
if (texture != null)
{
if (texture.Type != (sbyte)AssetType.Texture)
{
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
return true;
}
WriteTextureData(httpRequest, httpResponse, texture, format);
}
else
{
string textureUrl = REDIRECT_URL + textureID.ToString();
m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl);
httpResponse.RedirectLocation = textureUrl;
return true;
}
}
else // no redirect
{
// try the cache // try the cache
texture = m_assetService.GetCached(fullID); texture = m_assetService.GetCached(fullID);
@ -171,13 +147,11 @@ namespace OpenSim.Capabilities.Handlers
if (texture != null) if (texture != null)
{ {
if (texture.Type != (sbyte)AssetType.Texture) if (texture.Type != (sbyte)AssetType.Texture)
{
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
return true; return true;
}
if (format == DefaultFormat) if (format == DefaultFormat)
{ {
WriteTextureData(httpRequest, httpResponse, texture, format); WriteTextureData(request, response, texture, format);
return true; return true;
} }
else else
@ -190,7 +164,7 @@ namespace OpenSim.Capabilities.Handlers
newTexture.Flags = AssetFlags.Collectable; newTexture.Flags = AssetFlags.Collectable;
newTexture.Temporary = true; newTexture.Temporary = true;
m_assetService.Store(newTexture); m_assetService.Store(newTexture);
WriteTextureData(httpRequest, httpResponse, newTexture, format); WriteTextureData(request, response, newTexture, format);
return true; return true;
} }
} }
@ -198,20 +172,23 @@ namespace OpenSim.Capabilities.Handlers
else // it was on the cache else // it was on the cache
{ {
//m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
WriteTextureData(httpRequest, httpResponse, texture, format); WriteTextureData(request, response, texture, format);
return true; return true;
} }
}
// not found // not found
// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); // m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
return true; return true;
} }
private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) private void WriteTextureData(Hashtable request, Hashtable response, AssetBase texture, string format)
{ {
string range = request.Headers.GetOne("Range"); Hashtable headers = new Hashtable();
response["headers"] = headers;
string range = String.Empty;
if (((Hashtable)request["headers"])["Range"] != null)
range = (string)((Hashtable)request["headers"])["Range"];
if (!String.IsNullOrEmpty(range)) // JP2's only if (!String.IsNullOrEmpty(range)) // JP2's only
{ {
@ -226,7 +203,7 @@ namespace OpenSim.Capabilities.Handlers
{ {
// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; // response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
// viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters
response.StatusCode = (int)System.Net.HttpStatusCode.NotFound; response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
} }
else else
{ {
@ -240,31 +217,33 @@ namespace OpenSim.Capabilities.Handlers
// We were accidentally sending back 404 before in this situation // We were accidentally sending back 404 before in this situation
// https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the
// entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this. // entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this.
response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; response["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent;
response["content-type"] = texture.Metadata.ContentType;
headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length);
response.ContentLength = len; byte[] d = new byte[len];
response.ContentType = texture.Metadata.ContentType; Array.Copy(texture.Data, start, d, 0, len);
response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); response["bin_response_data"] = d;
// response.Body.Write(texture.Data, start, len);
response.Body.Write(texture.Data, start, len);
} }
} }
else else
{ {
m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range);
response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; response["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest;
} }
} }
else // JP2's or other formats else // JP2's or other formats
{ {
// Full content request // Full content request
response.StatusCode = (int)System.Net.HttpStatusCode.OK; response["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
response.ContentLength = texture.Data.Length;
if (format == DefaultFormat) if (format == DefaultFormat)
response.ContentType = texture.Metadata.ContentType; response["content_type"] = texture.Metadata.ContentType;
else else
response.ContentType = "image/" + format; response["content_type"] = "image/" + format;
response.Body.Write(texture.Data, 0, texture.Data.Length);
response["bin_response_data"] = texture.Data;
// response.Body.Write(texture.Data, 0, texture.Data.Length);
} }
// if (response.StatusCode < 200 || response.StatusCode > 299) // if (response.StatusCode < 200 || response.StatusCode > 299)

View File

@ -33,6 +33,7 @@ using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Server.Handlers.Base; using OpenSim.Server.Handlers.Base;
using OpenMetaverse; using OpenMetaverse;
/*
namespace OpenSim.Capabilities.Handlers namespace OpenSim.Capabilities.Handlers
{ {
public class GetTextureServerConnector : ServiceConnector public class GetTextureServerConnector : ServiceConnector
@ -63,7 +64,8 @@ namespace OpenSim.Capabilities.Handlers
throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName));
server.AddStreamHandler( server.AddStreamHandler(
new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService, "GetTexture", null)); new GetTextureHandler("/CAPS/GetTexture/", m_AssetService, "GetTexture", null));
} }
} }
} }
*/

View File

@ -39,6 +39,7 @@ using OpenSim.Region.Framework.Scenes;
using OpenSim.Tests.Common; using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock; using OpenSim.Tests.Common.Mock;
/*
namespace OpenSim.Capabilities.Handlers.GetTexture.Tests namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
{ {
[TestFixture] [TestFixture]
@ -61,3 +62,4 @@ namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
} }
} }
} }
*/

View File

@ -640,7 +640,7 @@ namespace OpenSim.Framework.Servers.HttpServer
// Every month or so this will wrap and give bad numbers, not really a problem // Every month or so this will wrap and give bad numbers, not really a problem
// since its just for reporting // since its just for reporting
int tickdiff = requestEndTick - requestStartTick; int tickdiff = requestEndTick - requestStartTick;
if (tickdiff > 3000) if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture"))
{ {
m_log.InfoFormat( m_log.InfoFormat(
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms", "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms",
@ -1449,7 +1449,8 @@ namespace OpenSim.Framework.Servers.HttpServer
internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response)
{ {
int responsecode; int responsecode;
string responseString; string responseString = String.Empty;
byte[] responseData = null;
string contentType; string contentType;
if (responsedata == null) if (responsedata == null)
@ -1465,8 +1466,13 @@ namespace OpenSim.Framework.Servers.HttpServer
{ {
//m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response");
responsecode = (int)responsedata["int_response_code"]; responsecode = (int)responsedata["int_response_code"];
if (responsedata["bin_response_data"] != null)
responseData = (byte[])responsedata["bin_response_data"];
else
responseString = (string)responsedata["str_response_string"]; responseString = (string)responsedata["str_response_string"];
contentType = (string)responsedata["content_type"]; contentType = (string)responsedata["content_type"];
if (responseString == null)
responseString = String.Empty;
} }
catch catch
{ {
@ -1520,8 +1526,22 @@ namespace OpenSim.Framework.Servers.HttpServer
response.AddHeader("Content-Type", contentType); response.AddHeader("Content-Type", contentType);
if (responsedata.ContainsKey("headers"))
{
Hashtable headerdata = (Hashtable)responsedata["headers"];
foreach (string header in headerdata.Keys)
response.AddHeader(header, (string)headerdata[header]);
}
byte[] buffer; byte[] buffer;
if (responseData != null)
{
buffer = responseData;
}
else
{
if (!(contentType.Contains("image") if (!(contentType.Contains("image")
|| contentType.Contains("x-shockwave-flash") || contentType.Contains("x-shockwave-flash")
|| contentType.Contains("application/x-oar") || contentType.Contains("application/x-oar")
@ -1539,6 +1559,7 @@ namespace OpenSim.Framework.Servers.HttpServer
response.SendChunked = false; response.SendChunked = false;
response.ContentLength64 = buffer.Length; response.ContentLength64 = buffer.Length;
response.ContentEncoding = Encoding.UTF8; response.ContentEncoding = Encoding.UTF8;
}
return buffer; return buffer;
} }

View File

@ -52,7 +52,8 @@ namespace OpenSim.Framework.Servers.HttpServer
{ {
Normal = 0, Normal = 0,
LslHttp = 1, LslHttp = 1,
Inventory = 2 Inventory = 2,
Texture = 3
} }
public PollServiceEventArgs( public PollServiceEventArgs(

View File

@ -231,8 +231,7 @@ namespace OpenSim.Framework.Servers.HttpServer
{ {
if (m_running) if (m_running)
{ {
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LslHttp || if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal)
req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Inventory)
{ {
m_requests.Enqueue(req); m_requests.Enqueue(req);
} }

View File

@ -694,6 +694,13 @@ namespace OpenSim.Framework
// //
public static void MakeRequest<TRequest, TResponse>(string verb, public static void MakeRequest<TRequest, TResponse>(string verb,
string requestUrl, TRequest obj, Action<TResponse> action) string requestUrl, TRequest obj, Action<TResponse> action)
{
MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, action, 0);
}
public static void MakeRequest<TRequest, TResponse>(string verb,
string requestUrl, TRequest obj, Action<TResponse> action,
int maxConnections)
{ {
int reqnum = WebUtil.RequestNumber++; int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
@ -706,6 +713,10 @@ namespace OpenSim.Framework
Type type = typeof(TRequest); Type type = typeof(TRequest);
WebRequest request = WebRequest.Create(requestUrl); WebRequest request = WebRequest.Create(requestUrl);
HttpWebRequest ht = (HttpWebRequest)request;
if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
ht.ServicePoint.ConnectionLimit = maxConnections;
WebResponse response = null; WebResponse response = null;
TResponse deserial = default(TResponse); TResponse deserial = default(TResponse);
XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
@ -1002,6 +1013,11 @@ namespace OpenSim.Framework
} }
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout) public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout)
{
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0);
}
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections)
{ {
int reqnum = WebUtil.RequestNumber++; int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
@ -1013,6 +1029,10 @@ namespace OpenSim.Framework
TResponse deserial = default(TResponse); TResponse deserial = default(TResponse);
WebRequest request = WebRequest.Create(requestUrl); WebRequest request = WebRequest.Create(requestUrl);
HttpWebRequest ht = (HttpWebRequest)request;
if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
ht.ServicePoint.ConnectionLimit = maxConnections;
request.Method = verb; request.Method = verb;
if (pTimeout != 0) if (pTimeout != 0)
request.Timeout = pTimeout * 1000; request.Timeout = pTimeout * 1000;

View File

@ -74,7 +74,7 @@ namespace OpenSim
AppDomain.CurrentDomain.UnhandledException += AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
ServicePointManager.DefaultConnectionLimit = 6; ServicePointManager.DefaultConnectionLimit = 12;
// Add the arguments supplied when running the application to the configuration // Add the arguments supplied when running the application to the configuration
ArgvConfigSource configSource = new ArgvConfigSource(args); ArgvConfigSource configSource = new ArgvConfigSource(args);

View File

@ -26,6 +26,7 @@
*/ */
using System; using System;
using System.Timers;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -466,6 +467,8 @@ namespace OpenSim.Region.ClientStack.Linden
if (llsdRequest.asset_type == "mesh") if (llsdRequest.asset_type == "mesh")
{ {
cost += 20; // Constant for now to test showing a price
if (llsdRequest.asset_resources == null) if (llsdRequest.asset_resources == null)
{ {
client.SendAgentAlertMessage("Unable to upload asset. missing information.", false); client.SendAgentAlertMessage("Unable to upload asset. missing information.", false);
@ -479,7 +482,7 @@ namespace OpenSim.Region.ClientStack.Linden
uint textures_cost = (uint)llsdRequest.asset_resources.texture_list.Array.Count; uint textures_cost = (uint)llsdRequest.asset_resources.texture_list.Array.Count;
textures_cost *= (uint)mm.UploadCharge; textures_cost *= (uint)mm.UploadCharge;
cost = textures_cost; cost += textures_cost;
} }
else else
{ {
@ -1092,6 +1095,9 @@ namespace OpenSim.Region.ClientStack.Linden
public class AssetUploader public class AssetUploader
{ {
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public event UpLoadedAsset OnUpLoad; public event UpLoadedAsset OnUpLoad;
private UpLoadedAsset handlerUpLoad = null; private UpLoadedAsset handlerUpLoad = null;
@ -1106,6 +1112,7 @@ namespace OpenSim.Region.ClientStack.Linden
private string m_invType = String.Empty; private string m_invType = String.Empty;
private string m_assetType = String.Empty; private string m_assetType = String.Empty;
private Timer m_timeoutTimer = new Timer();
public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
UUID parentFolderID, string invType, string assetType, string path, UUID parentFolderID, string invType, string assetType, string path,
@ -1121,6 +1128,11 @@ namespace OpenSim.Region.ClientStack.Linden
m_assetType = assetType; m_assetType = assetType;
m_invType = invType; m_invType = invType;
m_dumpAssetsToFile = dumpAssetsToFile; m_dumpAssetsToFile = dumpAssetsToFile;
m_timeoutTimer.Elapsed += TimedOut;
m_timeoutTimer.Interval = 120000;
m_timeoutTimer.AutoReset = false;
m_timeoutTimer.Start();
} }
/// <summary> /// <summary>
@ -1142,6 +1154,7 @@ namespace OpenSim.Region.ClientStack.Linden
res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
httpListener.RemoveStreamHandler("POST", uploaderPath); httpListener.RemoveStreamHandler("POST", uploaderPath);
m_timeoutTimer.Stop();
// TODO: probably make this a better set of extensions here // TODO: probably make this a better set of extensions here
string extension = ".jp2"; string extension = ".jp2";
@ -1163,6 +1176,12 @@ namespace OpenSim.Region.ClientStack.Linden
return res; return res;
} }
private void TimedOut(object sender, ElapsedEventArgs args)
{
m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
httpListener.RemoveStreamHandler("POST", uploaderPath);
}
///Left this in and commented in case there are unforseen issues ///Left this in and commented in case there are unforseen issues
//private void SaveAssetToFile(string filename, byte[] data) //private void SaveAssetToFile(string filename, byte[] data)
//{ //{

View File

@ -27,18 +27,13 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Specialized; using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection; using System.Reflection;
using System.IO; using System.Threading;
using System.Web;
using log4net; using log4net;
using Nini.Config; using Nini.Config;
using Mono.Addins; using Mono.Addins;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Imaging;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Servers; using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer; using OpenSim.Framework.Servers.HttpServer;
@ -47,64 +42,73 @@ using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
using Caps = OpenSim.Framework.Capabilities.Caps; using Caps = OpenSim.Framework.Capabilities.Caps;
using OpenSim.Capabilities.Handlers; using OpenSim.Capabilities.Handlers;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Region.ClientStack.Linden namespace OpenSim.Region.ClientStack.Linden
{ {
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] /// <summary>
/// This module implements both WebFetchTextureDescendents and FetchTextureDescendents2 capabilities.
/// </summary>
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
public class GetTextureModule : INonSharedRegionModule public class GetTextureModule : INonSharedRegionModule
{ {
// private static readonly ILog m_log = private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene; private Scene m_scene;
private IAssetService m_assetService;
private bool m_Enabled = false; private static GetTextureHandler m_getTextureHandler;
// TODO: Change this to a config option private IAssetService m_assetService = null;
const string REDIRECT_URL = null;
private string m_URL; private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
private static Thread[] m_workerThreads = null;
private static OpenMetaverse.BlockingQueue<PollServiceTextureEventArgs> m_queue =
new OpenMetaverse.BlockingQueue<PollServiceTextureEventArgs>();
#region ISharedRegionModule Members #region ISharedRegionModule Members
public void Initialise(IConfigSource source) public void Initialise(IConfigSource source)
{ {
IConfig config = source.Configs["ClientStack.LindenCaps"];
if (config == null)
return;
m_URL = config.GetString("Cap_GetTexture", string.Empty);
// Cap doesn't exist
if (m_URL != string.Empty)
m_Enabled = true;
} }
public void AddRegion(Scene s) public void AddRegion(Scene s)
{ {
if (!m_Enabled)
return;
m_scene = s; m_scene = s;
m_assetService = s.AssetService;
} }
public void RemoveRegion(Scene s) public void RemoveRegion(Scene s)
{ {
if (!m_Enabled)
return;
m_scene.EventManager.OnRegisterCaps -= RegisterCaps; m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
m_scene = null; m_scene = null;
} }
public void RegionLoaded(Scene s) public void RegionLoaded(Scene s)
{ {
if (!m_Enabled) // We'll reuse the same handler for all requests.
return; m_getTextureHandler = new GetTextureHandler(m_assetService);
m_assetService = m_scene.RequestModuleInterface<IAssetService>();
m_scene.EventManager.OnRegisterCaps += RegisterCaps; m_scene.EventManager.OnRegisterCaps += RegisterCaps;
m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
if (m_workerThreads == null)
{
m_workerThreads = new Thread[4];
for (uint i = 0; i < 4; i++)
{
m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
String.Format("TextureWorkerThread{0}", i),
ThreadPriority.Normal,
false,
true,
null,
int.MaxValue);
}
}
} }
public void PostInitialise() public void PostInitialise()
@ -122,24 +126,155 @@ namespace OpenSim.Region.ClientStack.Linden
#endregion #endregion
public void RegisterCaps(UUID agentID, Caps caps) ~GetTextureModule()
{ {
UUID capID = UUID.Random(); foreach (Thread t in m_workerThreads)
t.Abort();
//caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
if (m_URL == "localhost")
{
// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
caps.RegisterHandler(
"GetTexture",
new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString()));
} }
else
private class PollServiceTextureEventArgs : PollServiceEventArgs
{ {
// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); private List<Hashtable> requests =
caps.RegisterHandler("GetTexture", m_URL); new List<Hashtable>();
private Dictionary<UUID, Hashtable> responses =
new Dictionary<UUID, Hashtable>();
private Scene m_scene;
public PollServiceTextureEventArgs(UUID pId, Scene scene) :
base(null, null, null, null, pId, 30000)
{
m_scene = scene;
HasEvents = (x, y) => { return this.responses.ContainsKey(x); };
GetEvents = (x, y, s) =>
{
try
{
return this.responses[x];
}
finally
{
responses.Remove(x);
}
};
Request = (x, y) =>
{
y["RequestID"] = x.ToString();
lock (this.requests)
this.requests.Add(y);
m_queue.Enqueue(this);
};
NoEvents = (x, y) =>
{
lock (this.requests)
{
Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
requests.Remove(request);
}
Hashtable response = new Hashtable();
response["int_response_code"] = 500;
response["str_response_string"] = "Script timeout";
response["content_type"] = "text/plain";
response["keepalive"] = false;
response["reusecontext"] = false;
return response;
};
}
public void Process()
{
Hashtable response;
Hashtable request = null;
try
{
lock (this.requests)
{
request = requests[0];
requests.RemoveAt(0);
}
}
catch
{
return;
}
UUID requestID = new UUID(request["RequestID"].ToString());
// If the avatar is gone, don't bother to get the texture
if (m_scene.GetScenePresence(Id) == null)
{
response = new Hashtable();
response["int_response_code"] = 500;
response["str_response_string"] = "Script timeout";
response["content_type"] = "text/plain";
response["keepalive"] = false;
response["reusecontext"] = false;
responses[requestID] = response;
return;
}
response = m_getTextureHandler.Handle(request);
responses[requestID] = response;
}
}
private void RegisterCaps(UUID agentID, Caps caps)
{
string capUrl = "/CAPS/" + UUID.Random() + "/";
// Register this as a poll service
// absurd large timeout to tune later to make a bit less than viewer
PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
args.Type = PollServiceEventArgs.EventType.Texture;
MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
string hostName = m_scene.RegionInfo.ExternalHostName;
uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
string protocol = "http";
if (MainServer.Instance.UseSSL)
{
hostName = MainServer.Instance.SSLCommonName;
port = MainServer.Instance.SSLPort;
protocol = "https";
}
caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
m_capsDict[agentID] = capUrl;
}
private void DeregisterCaps(UUID agentID, Caps caps)
{
string capUrl;
if (m_capsDict.TryGetValue(agentID, out capUrl))
{
MainServer.Instance.RemoveHTTPHandler("", capUrl);
m_capsDict.Remove(agentID);
}
}
private void DoTextureRequests()
{
while (true)
{
PollServiceTextureEventArgs args = m_queue.Dequeue();
args.Process();
}
} }
} }
} }
}

View File

@ -256,7 +256,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
if (sp.IsChildAgent) if (sp.IsChildAgent)
return; return;
sp.ControllingClient.Kick(reason); sp.ControllingClient.Kick(reason);
sp.Scene.IncomingCloseAgent(sp.UUID); sp.MakeChildAgent();
sp.ControllingClient.Close();
} }
private void OnIncomingInstantMessage(GridInstantMessage msg) private void OnIncomingInstantMessage(GridInstantMessage msg)

View File

@ -648,7 +648,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// //
// This sleep can be increased if necessary. However, whilst it's active, // This sleep can be increased if necessary. However, whilst it's active,
// an agent cannot teleport back to this region if it has teleported away. // an agent cannot teleport back to this region if it has teleported away.
Thread.Sleep(2000); Thread.Sleep(3000);
sp.Scene.IncomingCloseAgent(sp.UUID); sp.Scene.IncomingCloseAgent(sp.UUID);
} }

View File

@ -218,7 +218,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
id, m_mod.Scene.RegionInfo.RegionName, currentState)); id, m_mod.Scene.RegionInfo.RegionName, currentState));
} }
int count = 200; int count = 400;
// There should be no race condition here since no other code should be removing the agent transfer or // There should be no race condition here since no other code should be removing the agent transfer or
// changing the state to another other than Transferring => ReceivedAtDestination. // changing the state to another other than Transferring => ReceivedAtDestination.

View File

@ -4274,7 +4274,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name='agentID'></param> /// <param name='agentID'></param>
protected virtual ScenePresence WaitGetScenePresence(UUID agentID) protected virtual ScenePresence WaitGetScenePresence(UUID agentID)
{ {
int ntimes = 20; int ntimes = 30;
ScenePresence sp = null; ScenePresence sp = null;
while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0)) while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0))
Thread.Sleep(1000); Thread.Sleep(1000);
@ -4326,7 +4326,7 @@ namespace OpenSim.Region.Framework.Scenes
ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); ScenePresence presence = m_sceneGraph.GetScenePresence(agentID);
if (presence != null) if (presence != null)
{ {
presence.ControllingClient.Close(); presence.ControllingClient.Close(false);
return true; return true;
} }

View File

@ -902,7 +902,7 @@ namespace OpenSim.Region.Physics.OdePlugin
axis.X = (axis.X > 0) ? 1f : 0f; axis.X = (axis.X > 0) ? 1f : 0f;
axis.Y = (axis.Y > 0) ? 1f : 0f; axis.Y = (axis.Y > 0) ? 1f : 0f;
axis.Z = (axis.Z > 0) ? 1f : 0f; axis.Z = (axis.Z > 0) ? 1f : 0f;
m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z); // m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
AddChange(changes.AngLock, axis); AddChange(changes.AngLock, axis);
} }
else else

View File

@ -443,7 +443,15 @@ namespace OpenSim.Server.Handlers.Simulation
// subclasses can override this // subclasses can override this
protected virtual bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) protected virtual bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason)
{ {
return m_SimulationService.CreateAgent(destination, aCircuit, teleportFlags, out reason); reason = String.Empty;
Util.FireAndForget(x =>
{
string r;
m_SimulationService.CreateAgent(destination, aCircuit, teleportFlags, out r);
});
return true;
} }
} }

View File

@ -27,6 +27,7 @@
using log4net; using log4net;
using System; using System;
using System.Threading;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
@ -50,7 +51,7 @@ namespace OpenSim.Services.Connectors
private IImprovedAssetCache m_Cache = null; private IImprovedAssetCache m_Cache = null;
private int m_retryCounter; private int m_retryCounter;
private Dictionary<int, List<AssetBase>> m_retryQueue = new Dictionary<int, List<AssetBase>>(); private Dictionary<int, List<AssetBase>> m_retryQueue = new Dictionary<int, List<AssetBase>>();
private Timer m_retryTimer; private System.Timers.Timer m_retryTimer;
private delegate void AssetRetrievedEx(AssetBase asset); private delegate void AssetRetrievedEx(AssetBase asset);
// Keeps track of concurrent requests for the same asset, so that it's only loaded once. // Keeps track of concurrent requests for the same asset, so that it's only loaded once.
@ -61,6 +62,8 @@ namespace OpenSim.Services.Connectors
private Dictionary<string, string> m_UriMap = new Dictionary<string, string>(); private Dictionary<string, string> m_UriMap = new Dictionary<string, string>();
private Thread[] m_fetchThreads;
public AssetServicesConnector() public AssetServicesConnector()
{ {
} }
@ -96,7 +99,7 @@ namespace OpenSim.Services.Connectors
} }
m_retryTimer = new Timer(); m_retryTimer = new System.Timers.Timer();
m_retryTimer.Elapsed += new ElapsedEventHandler(retryCheck); m_retryTimer.Elapsed += new ElapsedEventHandler(retryCheck);
m_retryTimer.Interval = 60000; m_retryTimer.Interval = 60000;
@ -112,6 +115,14 @@ namespace OpenSim.Services.Connectors
m_UriMap[prefix] = groupHost; m_UriMap[prefix] = groupHost;
//m_log.DebugFormat("[ASSET]: Using {0} for prefix {1}", groupHost, prefix); //m_log.DebugFormat("[ASSET]: Using {0} for prefix {1}", groupHost, prefix);
} }
m_fetchThreads = new Thread[2];
for (int i = 0 ; i < 2 ; i++)
{
m_fetchThreads[i] = new Thread(AssetRequestProcessor);
m_fetchThreads[i].Start();
}
} }
private string MapServer(string id) private string MapServer(string id)
@ -193,7 +204,7 @@ namespace OpenSim.Services.Connectors
if (asset == null || asset.Data == null || asset.Data.Length == 0) if (asset == null || asset.Data == null || asset.Data.Length == 0)
{ {
asset = SynchronousRestObjectRequester. asset = SynchronousRestObjectRequester.
MakeRequest<int, AssetBase>("GET", uri, 0); MakeRequest<int, AssetBase>("GET", uri, 0, 30);
if (m_Cache != null) if (m_Cache != null)
m_Cache.Cache(asset); m_Cache.Cache(asset);
@ -261,6 +272,66 @@ namespace OpenSim.Services.Connectors
return null; return null;
} }
private class QueuedAssetRequest
{
public string uri;
public string id;
}
private OpenMetaverse.BlockingQueue<QueuedAssetRequest> m_requestQueue =
new OpenMetaverse.BlockingQueue<QueuedAssetRequest>();
private void AssetRequestProcessor()
{
QueuedAssetRequest r;
while (true)
{
r = m_requestQueue.Dequeue();
string uri = r.uri;
string id = r.id;
bool success = false;
try
{
AsynchronousRestObjectRequester.MakeRequest<int, AssetBase>("GET", uri, 0,
delegate(AssetBase a)
{
if (m_Cache != null)
m_Cache.Cache(a);
List<AssetRetrievedEx> handlers;
lock (m_AssetHandlers)
{
handlers = m_AssetHandlers[id];
m_AssetHandlers.Remove(id);
}
foreach (AssetRetrievedEx h in handlers)
h.Invoke(a);
if (handlers != null)
handlers.Clear();
}, 30);
success = true;
}
finally
{
if (!success)
{
List<AssetRetrievedEx> handlers;
lock (m_AssetHandlers)
{
handlers = m_AssetHandlers[id];
m_AssetHandlers.Remove(id);
}
if (handlers != null)
handlers.Clear();
}
}
}
}
public bool Get(string id, Object sender, AssetRetrieved handler) public bool Get(string id, Object sender, AssetRetrieved handler)
{ {
string uri = MapServer(id) + "/assets/" + id; string uri = MapServer(id) + "/assets/" + id;
@ -293,52 +364,11 @@ namespace OpenSim.Services.Connectors
m_AssetHandlers.Add(id, handlers); m_AssetHandlers.Add(id, handlers);
} }
bool success = false; QueuedAssetRequest request = new QueuedAssetRequest();
try request.id = id;
{ request.uri = uri;
AsynchronousRestObjectRequester.MakeRequest<int, AssetBase>("GET", uri, 0,
delegate(AssetBase a)
{
if (m_Cache != null)
m_Cache.Cache(a);
/*
AssetRetrievedEx handlers;
lock (m_AssetHandlers)
{
handlers = m_AssetHandlers[id];
m_AssetHandlers.Remove(id);
}
handlers.Invoke(a); m_requestQueue.Enqueue(request);
*/
List<AssetRetrievedEx> handlers;
lock (m_AssetHandlers)
{
handlers = m_AssetHandlers[id];
m_AssetHandlers.Remove(id);
}
foreach (AssetRetrievedEx h in handlers)
h.Invoke(a);
if (handlers != null)
handlers.Clear();
});
success = true;
}
finally
{
if (!success)
{
List<AssetRetrievedEx> handlers;
lock (m_AssetHandlers)
{
handlers = m_AssetHandlers[id];
m_AssetHandlers.Remove(id);
}
if (handlers != null)
handlers.Clear();
}
}
} }
else else
{ {

View File

@ -1713,6 +1713,7 @@
<Reference name="Nini" path="../../../../../bin/"/> <Reference name="Nini" path="../../../../../bin/"/>
<Reference name="log4net" path="../../../../../bin/"/> <Reference name="log4net" path="../../../../../bin/"/>
<Reference name="Nini" path="../../../../../bin/"/> <Reference name="Nini" path="../../../../../bin/"/>
<Reference name="zlib.net" path="../../../../bin/"/>
<Files> <Files>
<Match pattern="*.cs" recurse="true"> <Match pattern="*.cs" recurse="true">