diff options
Diffstat (limited to '')
21 files changed, 905 insertions, 141 deletions
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 6c04c69..3055865 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs | |||
@@ -59,7 +59,7 @@ namespace OpenSim.Framework.Servers | |||
59 | /// This will control a periodic log printout of the current 'show stats' (if they are active) for this | 59 | /// This will control a periodic log printout of the current 'show stats' (if they are active) for this |
60 | /// server. | 60 | /// server. |
61 | /// </summary> | 61 | /// </summary> |
62 | private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); | 62 | // private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); |
63 | 63 | ||
64 | /// <summary> | 64 | /// <summary> |
65 | /// Random uuid for private data | 65 | /// Random uuid for private data |
@@ -77,8 +77,8 @@ namespace OpenSim.Framework.Servers | |||
77 | // Random uuid for private data | 77 | // Random uuid for private data |
78 | m_osSecret = UUID.Random().ToString(); | 78 | m_osSecret = UUID.Random().ToString(); |
79 | 79 | ||
80 | m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); | 80 | // m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); |
81 | m_periodicDiagnosticsTimer.Enabled = true; | 81 | // m_periodicDiagnosticsTimer.Enabled = true; |
82 | } | 82 | } |
83 | 83 | ||
84 | /// <summary> | 84 | /// <summary> |
@@ -86,26 +86,23 @@ namespace OpenSim.Framework.Servers | |||
86 | /// </summary> | 86 | /// </summary> |
87 | protected virtual void StartupSpecific() | 87 | protected virtual void StartupSpecific() |
88 | { | 88 | { |
89 | if (m_console == null) | 89 | StatsManager.SimExtraStats = new SimExtraStatsCollector(); |
90 | return; | ||
91 | |||
92 | RegisterCommonCommands(); | 90 | RegisterCommonCommands(); |
93 | 91 | RegisterCommonComponents(Config); | |
94 | m_console.Commands.AddCommand("General", false, "quit", | 92 | } |
95 | "quit", | 93 | |
96 | "Quit the application", HandleQuit); | 94 | protected override void ShutdownSpecific() |
95 | { | ||
96 | m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); | ||
97 | |||
98 | RemovePIDFile(); | ||
97 | 99 | ||
98 | m_console.Commands.AddCommand("General", false, "shutdown", | 100 | base.ShutdownSpecific(); |
99 | "shutdown", | 101 | |
100 | "Quit the application", HandleQuit); | 102 | Environment.Exit(0); |
101 | } | 103 | } |
102 | 104 | ||
103 | /// <summary> | 105 | /// <summary> |
104 | /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing | ||
105 | /// </summary> | ||
106 | public virtual void ShutdownSpecific() {} | ||
107 | |||
108 | /// <summary> | ||
109 | /// Provides a list of help topics that are available. Overriding classes should append their topics to the | 106 | /// Provides a list of help topics that are available. Overriding classes should append their topics to the |
110 | /// information returned when the base method is called. | 107 | /// information returned when the base method is called. |
111 | /// </summary> | 108 | /// </summary> |
@@ -148,30 +145,13 @@ namespace OpenSim.Framework.Servers | |||
148 | 145 | ||
149 | TimeSpan timeTaken = DateTime.Now - m_startuptime; | 146 | TimeSpan timeTaken = DateTime.Now - m_startuptime; |
150 | 147 | ||
151 | m_log.InfoFormat( | 148 | // MainConsole.Instance.OutputFormat( |
152 | "[STARTUP]: Non-script portion of startup took {0}m {1}s. PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED.", | 149 | // "PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED. Non-script portion of startup took {0}m {1}s.", |
153 | timeTaken.Minutes, timeTaken.Seconds); | 150 | // timeTaken.Minutes, timeTaken.Seconds); |
154 | } | 151 | } |
155 | 152 | ||
156 | /// <summary> | 153 | public string osSecret |
157 | /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing | ||
158 | /// </summary> | ||
159 | public virtual void Shutdown() | ||
160 | { | 154 | { |
161 | ShutdownSpecific(); | ||
162 | |||
163 | m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); | ||
164 | RemovePIDFile(); | ||
165 | |||
166 | Environment.Exit(0); | ||
167 | } | ||
168 | |||
169 | private void HandleQuit(string module, string[] args) | ||
170 | { | ||
171 | Shutdown(); | ||
172 | } | ||
173 | |||
174 | public string osSecret { | ||
175 | // Secret uuid for the simulator | 155 | // Secret uuid for the simulator |
176 | get { return m_osSecret; } | 156 | get { return m_osSecret; } |
177 | } | 157 | } |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 97035e3..7841f47 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | |||
@@ -54,7 +54,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
55 | private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); | 55 | private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); |
56 | 56 | ||
57 | |||
58 | /// <summary> | 57 | /// <summary> |
59 | /// This is a pending websocket request before it got an sucessful upgrade response. | 58 | /// This is a pending websocket request before it got an sucessful upgrade response. |
60 | /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to | 59 | /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to |
@@ -81,6 +80,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
81 | /// </remarks> | 80 | /// </remarks> |
82 | public int RequestNumber { get; private set; } | 81 | public int RequestNumber { get; private set; } |
83 | 82 | ||
83 | /// <summary> | ||
84 | /// Statistic for holding number of requests processed. | ||
85 | /// </summary> | ||
86 | private Stat m_requestsProcessedStat; | ||
87 | |||
84 | private volatile int NotSocketErrors = 0; | 88 | private volatile int NotSocketErrors = 0; |
85 | public volatile bool HTTPDRunning = false; | 89 | public volatile bool HTTPDRunning = false; |
86 | 90 | ||
@@ -383,6 +387,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
383 | 387 | ||
384 | if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) | 388 | if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) |
385 | { | 389 | { |
390 | psEvArgs.RequestsReceived++; | ||
391 | |||
386 | PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); | 392 | PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); |
387 | 393 | ||
388 | if (psEvArgs.Request != null) | 394 | if (psEvArgs.Request != null) |
@@ -437,9 +443,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
437 | } | 443 | } |
438 | } | 444 | } |
439 | 445 | ||
440 | public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) | 446 | private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) |
441 | { | 447 | { |
442 | |||
443 | OSHttpRequest req = new OSHttpRequest(context, request); | 448 | OSHttpRequest req = new OSHttpRequest(context, request); |
444 | WebSocketRequestDelegate dWebSocketRequestDelegate = null; | 449 | WebSocketRequestDelegate dWebSocketRequestDelegate = null; |
445 | lock (m_WebSocketHandlers) | 450 | lock (m_WebSocketHandlers) |
@@ -454,9 +459,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
454 | } | 459 | } |
455 | 460 | ||
456 | OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); | 461 | OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); |
457 | 462 | resp.ReuseContext = true; | |
458 | HandleRequest(req, resp); | 463 | HandleRequest(req, resp); |
459 | |||
460 | 464 | ||
461 | // !!!HACK ALERT!!! | 465 | // !!!HACK ALERT!!! |
462 | // There seems to be a bug in the underlying http code that makes subsequent requests | 466 | // There seems to be a bug in the underlying http code that makes subsequent requests |
@@ -687,7 +691,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
687 | 691 | ||
688 | if (buffer != null) | 692 | if (buffer != null) |
689 | { | 693 | { |
690 | if (!response.SendChunked) | 694 | if (!response.SendChunked && response.ContentLength64 <= 0) |
691 | response.ContentLength64 = buffer.LongLength; | 695 | response.ContentLength64 = buffer.LongLength; |
692 | 696 | ||
693 | response.OutputStream.Write(buffer, 0, buffer.Length); | 697 | response.OutputStream.Write(buffer, 0, buffer.Length); |
@@ -782,7 +786,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
782 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", | 786 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", |
783 | RequestNumber, | 787 | RequestNumber, |
784 | Port, | 788 | Port, |
785 | (request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType, | 789 | string.IsNullOrEmpty(request.ContentType) ? "not set" : request.ContentType, |
786 | request.HttpMethod, | 790 | request.HttpMethod, |
787 | request.Url.PathAndQuery, | 791 | request.Url.PathAndQuery, |
788 | request.RemoteIPEndPoint); | 792 | request.RemoteIPEndPoint); |
@@ -1053,7 +1057,21 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1053 | } | 1057 | } |
1054 | 1058 | ||
1055 | response.ContentType = "text/xml"; | 1059 | response.ContentType = "text/xml"; |
1056 | responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); | 1060 | using (MemoryStream outs = new MemoryStream()) |
1061 | { | ||
1062 | using (XmlTextWriter writer = new XmlTextWriter(outs, Encoding.UTF8)) | ||
1063 | { | ||
1064 | writer.Formatting = Formatting.None; | ||
1065 | XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse); | ||
1066 | writer.Flush(); | ||
1067 | outs.Flush(); | ||
1068 | outs.Position = 0; | ||
1069 | using (StreamReader sr = new StreamReader(outs)) | ||
1070 | { | ||
1071 | responseString = sr.ReadToEnd(); | ||
1072 | } | ||
1073 | } | ||
1074 | } | ||
1057 | } | 1075 | } |
1058 | else | 1076 | else |
1059 | { | 1077 | { |
@@ -1850,8 +1868,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1850 | m_httpListener2.Start(64); | 1868 | m_httpListener2.Start(64); |
1851 | 1869 | ||
1852 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events | 1870 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events |
1853 | // m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); | ||
1854 | m_PollServiceManager = new PollServiceRequestManager(this, 4, 25000); | 1871 | m_PollServiceManager = new PollServiceRequestManager(this, 4, 25000); |
1872 | m_PollServiceManager.Start(); | ||
1855 | HTTPDRunning = true; | 1873 | HTTPDRunning = true; |
1856 | 1874 | ||
1857 | //HttpListenerContext context; | 1875 | //HttpListenerContext context; |
@@ -1870,6 +1888,21 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1870 | // useful without inbound HTTP. | 1888 | // useful without inbound HTTP. |
1871 | throw e; | 1889 | throw e; |
1872 | } | 1890 | } |
1891 | |||
1892 | m_requestsProcessedStat | ||
1893 | = new Stat( | ||
1894 | "HTTPRequestsServed", | ||
1895 | "Number of inbound HTTP requests processed", | ||
1896 | "", | ||
1897 | "requests", | ||
1898 | "httpserver", | ||
1899 | Port.ToString(), | ||
1900 | StatType.Pull, | ||
1901 | MeasuresOfInterest.AverageChangeOverTime, | ||
1902 | stat => stat.Value = RequestNumber, | ||
1903 | StatVerbosity.Debug); | ||
1904 | |||
1905 | StatsManager.RegisterStat(m_requestsProcessedStat); | ||
1873 | } | 1906 | } |
1874 | 1907 | ||
1875 | public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) | 1908 | public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) |
@@ -1902,9 +1935,12 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1902 | public void Stop() | 1935 | public void Stop() |
1903 | { | 1936 | { |
1904 | HTTPDRunning = false; | 1937 | HTTPDRunning = false; |
1938 | |||
1939 | StatsManager.DeregisterStat(m_requestsProcessedStat); | ||
1940 | |||
1905 | try | 1941 | try |
1906 | { | 1942 | { |
1907 | // m_PollServiceManager.Stop(); | 1943 | m_PollServiceManager.Stop(); |
1908 | 1944 | ||
1909 | m_httpListener2.ExceptionThrown -= httpServerException; | 1945 | m_httpListener2.ExceptionThrown -= httpServerException; |
1910 | //m_httpListener2.DisconnectHandler = null; | 1946 | //m_httpListener2.DisconnectHandler = null; |
@@ -1931,6 +1967,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1931 | 1967 | ||
1932 | public void RemoveHTTPHandler(string httpMethod, string path) | 1968 | public void RemoveHTTPHandler(string httpMethod, string path) |
1933 | { | 1969 | { |
1970 | if (path == null) return; // Caps module isn't loaded, tries to remove handler where path = null | ||
1934 | lock (m_HTTPHandlers) | 1971 | lock (m_HTTPHandlers) |
1935 | { | 1972 | { |
1936 | if (httpMethod != null && httpMethod.Length == 0) | 1973 | if (httpMethod != null && httpMethod.Length == 0) |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs new file mode 100644 index 0000000..72b3065 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System.IO; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | /// <summary> | ||
33 | /// Base handler for writing to an output stream | ||
34 | /// </summary> | ||
35 | /// <remarks> | ||
36 | /// Inheriting classes should override ProcessRequest() rather than Handle() | ||
37 | /// </remarks> | ||
38 | public abstract class BaseOutputStreamHandler : BaseRequestHandler, IRequestHandler | ||
39 | { | ||
40 | protected BaseOutputStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} | ||
41 | |||
42 | protected BaseOutputStreamHandler(string httpMethod, string path, string name, string description) | ||
43 | : base(httpMethod, path, name, description) {} | ||
44 | |||
45 | public virtual void Handle( | ||
46 | string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
47 | { | ||
48 | RequestsReceived++; | ||
49 | |||
50 | ProcessRequest(path, request, response, httpRequest, httpResponse); | ||
51 | |||
52 | RequestsHandled++; | ||
53 | } | ||
54 | |||
55 | protected virtual void ProcessRequest( | ||
56 | string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
57 | { | ||
58 | } | ||
59 | } | ||
60 | } \ No newline at end of file | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs index ae7aaf2..bbac699 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs | |||
@@ -31,6 +31,10 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
31 | { | 31 | { |
32 | public abstract class BaseRequestHandler | 32 | public abstract class BaseRequestHandler |
33 | { | 33 | { |
34 | public int RequestsReceived { get; protected set; } | ||
35 | |||
36 | public int RequestsHandled { get; protected set; } | ||
37 | |||
34 | public virtual string ContentType | 38 | public virtual string ContentType |
35 | { | 39 | { |
36 | get { return "application/xml"; } | 40 | get { return "application/xml"; } |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs index 6342983..252cc2a 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs | |||
@@ -29,14 +29,35 @@ using System.IO; | |||
29 | 29 | ||
30 | namespace OpenSim.Framework.Servers.HttpServer | 30 | namespace OpenSim.Framework.Servers.HttpServer |
31 | { | 31 | { |
32 | /// <summary> | ||
33 | /// Base streamed request handler. | ||
34 | /// </summary> | ||
35 | /// <remarks> | ||
36 | /// Inheriting classes should override ProcessRequest() rather than Handle() | ||
37 | /// </remarks> | ||
32 | public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler | 38 | public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler |
33 | { | 39 | { |
34 | public abstract byte[] Handle(string path, Stream request, | ||
35 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse); | ||
36 | |||
37 | protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} | 40 | protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} |
38 | 41 | ||
39 | protected BaseStreamHandler(string httpMethod, string path, string name, string description) | 42 | protected BaseStreamHandler(string httpMethod, string path, string name, string description) |
40 | : base(httpMethod, path, name, description) {} | 43 | : base(httpMethod, path, name, description) {} |
44 | |||
45 | public virtual byte[] Handle( | ||
46 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
47 | { | ||
48 | RequestsReceived++; | ||
49 | |||
50 | byte[] result = ProcessRequest(path, request, httpRequest, httpResponse); | ||
51 | |||
52 | RequestsHandled++; | ||
53 | |||
54 | return result; | ||
55 | } | ||
56 | |||
57 | protected virtual byte[] ProcessRequest( | ||
58 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
59 | { | ||
60 | return null; | ||
61 | } | ||
41 | } | 62 | } |
42 | } \ No newline at end of file | 63 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs new file mode 100644 index 0000000..1b88545 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using OpenSim.Framework; | ||
28 | using System.IO; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | /// <summary> | ||
33 | /// BaseStreamHandlerBasicDOSProtector Base streamed request handler. | ||
34 | /// </summary> | ||
35 | /// <remarks> | ||
36 | /// Inheriting classes should override ProcessRequest() rather than Handle() | ||
37 | /// </remarks> | ||
38 | public abstract class BaseStreamHandlerBasicDOSProtector : BaseRequestHandler, IStreamedRequestHandler | ||
39 | { | ||
40 | |||
41 | private readonly BasicDosProtectorOptions _options; | ||
42 | private readonly BasicDOSProtector _dosProtector; | ||
43 | |||
44 | protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, BasicDosProtectorOptions options) : this(httpMethod, path, null, null, options) {} | ||
45 | |||
46 | protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, string name, string description, BasicDosProtectorOptions options) | ||
47 | : base(httpMethod, path, name, description) | ||
48 | { | ||
49 | _options = options; | ||
50 | _dosProtector = new BasicDOSProtector(_options); | ||
51 | } | ||
52 | |||
53 | public virtual byte[] Handle( | ||
54 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
55 | { | ||
56 | byte[] result; | ||
57 | RequestsReceived++; | ||
58 | string clientstring = GetClientString(httpRequest); | ||
59 | string endpoint = GetRemoteAddr(httpRequest); | ||
60 | if (_dosProtector.Process(clientstring, endpoint)) | ||
61 | result = ProcessRequest(path, request, httpRequest, httpResponse); | ||
62 | else | ||
63 | result = ThrottledRequest(path, request, httpRequest, httpResponse); | ||
64 | if (_options.MaxConcurrentSessions > 0) | ||
65 | _dosProtector.ProcessEnd(clientstring, endpoint); | ||
66 | |||
67 | RequestsHandled++; | ||
68 | |||
69 | return result; | ||
70 | } | ||
71 | |||
72 | protected virtual byte[] ProcessRequest( | ||
73 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
74 | { | ||
75 | return null; | ||
76 | } | ||
77 | |||
78 | protected virtual byte[] ThrottledRequest( | ||
79 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
80 | { | ||
81 | return new byte[0]; | ||
82 | } | ||
83 | |||
84 | |||
85 | private string GetRemoteAddr(IOSHttpRequest httpRequest) | ||
86 | { | ||
87 | string remoteaddr = string.Empty; | ||
88 | if (httpRequest.Headers["remote_addr"] != null) | ||
89 | remoteaddr = httpRequest.Headers["remote_addr"]; | ||
90 | |||
91 | return remoteaddr; | ||
92 | } | ||
93 | |||
94 | private string GetClientString(IOSHttpRequest httpRequest) | ||
95 | { | ||
96 | string clientstring = string.Empty; | ||
97 | |||
98 | if (_options.AllowXForwardedFor && httpRequest.Headers["x-forwarded-for"] != null) | ||
99 | clientstring = httpRequest.Headers["x-forwarded-for"]; | ||
100 | else | ||
101 | clientstring = GetRemoteAddr(httpRequest); | ||
102 | |||
103 | return clientstring; | ||
104 | |||
105 | } | ||
106 | } | ||
107 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs index b94bfb4..1b03f54 100644 --- a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs | |||
@@ -45,7 +45,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
45 | m_method = binaryMethod; | 45 | m_method = binaryMethod; |
46 | } | 46 | } |
47 | 47 | ||
48 | public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 48 | protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
49 | { | 49 | { |
50 | byte[] data = ReadFully(request); | 50 | byte[] data = ReadFully(request); |
51 | string param = GetParam(path); | 51 | string param = GetParam(path); |
diff --git a/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs new file mode 100644 index 0000000..cd4b8ff --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System.Collections; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | public class GenericHTTPDOSProtector | ||
33 | { | ||
34 | private readonly GenericHTTPMethod _normalMethod; | ||
35 | private readonly GenericHTTPMethod _throttledMethod; | ||
36 | |||
37 | private readonly BasicDosProtectorOptions _options; | ||
38 | private readonly BasicDOSProtector _dosProtector; | ||
39 | |||
40 | public GenericHTTPDOSProtector(GenericHTTPMethod normalMethod, GenericHTTPMethod throttledMethod, BasicDosProtectorOptions options) | ||
41 | { | ||
42 | _normalMethod = normalMethod; | ||
43 | _throttledMethod = throttledMethod; | ||
44 | |||
45 | _options = options; | ||
46 | _dosProtector = new BasicDOSProtector(_options); | ||
47 | } | ||
48 | public Hashtable Process(Hashtable request) | ||
49 | { | ||
50 | Hashtable process = null; | ||
51 | string clientstring= GetClientString(request); | ||
52 | string endpoint = GetRemoteAddr(request); | ||
53 | if (_dosProtector.Process(clientstring, endpoint)) | ||
54 | process = _normalMethod(request); | ||
55 | else | ||
56 | process = _throttledMethod(request); | ||
57 | |||
58 | if (_options.MaxConcurrentSessions>0) | ||
59 | _dosProtector.ProcessEnd(clientstring, endpoint); | ||
60 | |||
61 | return process; | ||
62 | } | ||
63 | |||
64 | private string GetRemoteAddr(Hashtable request) | ||
65 | { | ||
66 | string remoteaddr = ""; | ||
67 | if (!request.ContainsKey("headers")) | ||
68 | return remoteaddr; | ||
69 | Hashtable requestinfo = (Hashtable)request["headers"]; | ||
70 | if (!requestinfo.ContainsKey("remote_addr")) | ||
71 | return remoteaddr; | ||
72 | object remote_addrobj = requestinfo["remote_addr"]; | ||
73 | if (remote_addrobj != null) | ||
74 | { | ||
75 | if (!string.IsNullOrEmpty(remote_addrobj.ToString())) | ||
76 | { | ||
77 | remoteaddr = remote_addrobj.ToString(); | ||
78 | } | ||
79 | |||
80 | } | ||
81 | return remoteaddr; | ||
82 | } | ||
83 | |||
84 | private string GetClientString(Hashtable request) | ||
85 | { | ||
86 | string clientstring = ""; | ||
87 | if (!request.ContainsKey("headers")) | ||
88 | return clientstring; | ||
89 | |||
90 | Hashtable requestinfo = (Hashtable)request["headers"]; | ||
91 | if (_options.AllowXForwardedFor && requestinfo.ContainsKey("x-forwarded-for")) | ||
92 | { | ||
93 | object str = requestinfo["x-forwarded-for"]; | ||
94 | if (str != null) | ||
95 | { | ||
96 | if (!string.IsNullOrEmpty(str.ToString())) | ||
97 | { | ||
98 | return str.ToString(); | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | if (!requestinfo.ContainsKey("remote_addr")) | ||
103 | return clientstring; | ||
104 | |||
105 | object remote_addrobj = requestinfo["remote_addr"]; | ||
106 | if (remote_addrobj != null) | ||
107 | { | ||
108 | if (!string.IsNullOrEmpty(remote_addrobj.ToString())) | ||
109 | { | ||
110 | clientstring = remote_addrobj.ToString(); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | return clientstring; | ||
115 | |||
116 | } | ||
117 | |||
118 | } | ||
119 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs index cb5cce5..b8541cb 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs | |||
@@ -32,7 +32,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
32 | { | 32 | { |
33 | public interface IRequestHandler | 33 | public interface IRequestHandler |
34 | { | 34 | { |
35 | |||
36 | /// <summary> | 35 | /// <summary> |
37 | /// Name for this handler. | 36 | /// Name for this handler. |
38 | /// </summary> | 37 | /// </summary> |
@@ -59,6 +58,19 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
59 | 58 | ||
60 | // Return path | 59 | // Return path |
61 | string Path { get; } | 60 | string Path { get; } |
61 | |||
62 | /// <summary> | ||
63 | /// Number of requests received by this handler | ||
64 | /// </summary> | ||
65 | int RequestsReceived { get; } | ||
66 | |||
67 | /// <summary> | ||
68 | /// Number of requests handled. | ||
69 | /// </summary> | ||
70 | /// <remarks> | ||
71 | /// Should be equal to RequestsReceived unless requested are being handled slowly or there is deadlock. | ||
72 | /// </remarks> | ||
73 | int RequestsHandled { get; } | ||
62 | } | 74 | } |
63 | 75 | ||
64 | public interface IStreamedRequestHandler : IRequestHandler | 76 | public interface IStreamedRequestHandler : IRequestHandler |
@@ -69,7 +81,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
69 | 81 | ||
70 | public interface IStreamHandler : IRequestHandler | 82 | public interface IStreamHandler : IRequestHandler |
71 | { | 83 | { |
72 | // Handle request stream, return byte array | ||
73 | void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse); | 84 | void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse); |
74 | } | 85 | } |
75 | 86 | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index c19ac32..3fd3bf7 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs | |||
@@ -50,25 +50,39 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
50 | 50 | ||
51 | public enum EventType : int | 51 | public enum EventType : int |
52 | { | 52 | { |
53 | Normal = 0, | 53 | LongPoll = 0, |
54 | LslHttp = 1, | 54 | LslHttp = 1, |
55 | Inventory = 2, | 55 | Inventory = 2, |
56 | Texture = 3, | 56 | Texture = 3, |
57 | Mesh = 4 | 57 | Mesh = 4 |
58 | } | 58 | } |
59 | 59 | ||
60 | public string Url { get; set; } | ||
61 | |||
62 | /// <summary> | ||
63 | /// Number of requests received for this poll service. | ||
64 | /// </summary> | ||
65 | public int RequestsReceived { get; set; } | ||
66 | |||
67 | /// <summary> | ||
68 | /// Number of requests handled by this poll service. | ||
69 | /// </summary> | ||
70 | public int RequestsHandled { get; set; } | ||
71 | |||
60 | public PollServiceEventArgs( | 72 | public PollServiceEventArgs( |
61 | RequestMethod pRequest, | 73 | RequestMethod pRequest, |
74 | string pUrl, | ||
62 | HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, | 75 | HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, |
63 | UUID pId, int pTimeOutms) | 76 | UUID pId, int pTimeOutms) |
64 | { | 77 | { |
65 | Request = pRequest; | 78 | Request = pRequest; |
79 | Url = pUrl; | ||
66 | HasEvents = pHasEvents; | 80 | HasEvents = pHasEvents; |
67 | GetEvents = pGetEvents; | 81 | GetEvents = pGetEvents; |
68 | NoEvents = pNoEvents; | 82 | NoEvents = pNoEvents; |
69 | Id = pId; | 83 | Id = pId; |
70 | TimeOutms = pTimeOutms; | 84 | TimeOutms = pTimeOutms; |
71 | Type = EventType.Normal; | 85 | Type = EventType.LongPoll; |
72 | } | 86 | } |
73 | } | 87 | } |
74 | } | 88 | } |
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 723530a..6aa9479 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs | |||
@@ -26,13 +26,19 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
29 | using HttpServer; | 32 | using HttpServer; |
33 | using log4net; | ||
30 | using OpenMetaverse; | 34 | using OpenMetaverse; |
31 | 35 | ||
32 | namespace OpenSim.Framework.Servers.HttpServer | 36 | namespace OpenSim.Framework.Servers.HttpServer |
33 | { | 37 | { |
34 | public class PollServiceHttpRequest | 38 | public class PollServiceHttpRequest |
35 | { | 39 | { |
40 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
41 | |||
36 | public readonly PollServiceEventArgs PollServiceArgs; | 42 | public readonly PollServiceEventArgs PollServiceArgs; |
37 | public readonly IHttpClientContext HttpContext; | 43 | public readonly IHttpClientContext HttpContext; |
38 | public readonly IHttpRequest Request; | 44 | public readonly IHttpRequest Request; |
@@ -48,5 +54,44 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
48 | RequestTime = System.Environment.TickCount; | 54 | RequestTime = System.Environment.TickCount; |
49 | RequestID = UUID.Random(); | 55 | RequestID = UUID.Random(); |
50 | } | 56 | } |
57 | |||
58 | internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata) | ||
59 | { | ||
60 | OSHttpResponse response | ||
61 | = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); | ||
62 | |||
63 | byte[] buffer = server.DoHTTPGruntWork(responsedata, response); | ||
64 | |||
65 | response.SendChunked = false; | ||
66 | response.ContentLength64 = buffer.Length; | ||
67 | response.ContentEncoding = Encoding.UTF8; | ||
68 | |||
69 | try | ||
70 | { | ||
71 | response.OutputStream.Write(buffer, 0, buffer.Length); | ||
72 | } | ||
73 | catch (Exception ex) | ||
74 | { | ||
75 | m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); | ||
76 | } | ||
77 | finally | ||
78 | { | ||
79 | //response.OutputStream.Close(); | ||
80 | try | ||
81 | { | ||
82 | response.OutputStream.Flush(); | ||
83 | response.Send(); | ||
84 | |||
85 | //if (!response.KeepAlive && response.ReuseContext) | ||
86 | // response.FreeContext(); | ||
87 | } | ||
88 | catch (Exception e) | ||
89 | { | ||
90 | m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); | ||
91 | } | ||
92 | |||
93 | PollServiceArgs.RequestsHandled++; | ||
94 | } | ||
95 | } | ||
51 | } | 96 | } |
52 | } \ No newline at end of file | 97 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 5406f00..4058229 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | |||
@@ -64,14 +64,17 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
64 | m_server = pSrv; | 64 | m_server = pSrv; |
65 | m_WorkerThreadCount = pWorkerThreadCount; | 65 | m_WorkerThreadCount = pWorkerThreadCount; |
66 | m_workerThreads = new Thread[m_WorkerThreadCount]; | 66 | m_workerThreads = new Thread[m_WorkerThreadCount]; |
67 | } | ||
67 | 68 | ||
69 | public void Start() | ||
70 | { | ||
68 | //startup worker threads | 71 | //startup worker threads |
69 | for (uint i = 0; i < m_WorkerThreadCount; i++) | 72 | for (uint i = 0; i < m_WorkerThreadCount; i++) |
70 | { | 73 | { |
71 | m_workerThreads[i] | 74 | m_workerThreads[i] |
72 | = Watchdog.StartThread( | 75 | = Watchdog.StartThread( |
73 | PoolWorkerJob, | 76 | PoolWorkerJob, |
74 | String.Format("PollServiceWorkerThread{0}", i), | 77 | string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port), |
75 | ThreadPriority.Normal, | 78 | ThreadPriority.Normal, |
76 | false, | 79 | false, |
77 | false, | 80 | false, |
@@ -81,7 +84,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
81 | 84 | ||
82 | m_retrysThread = Watchdog.StartThread( | 85 | m_retrysThread = Watchdog.StartThread( |
83 | this.CheckRetries, | 86 | this.CheckRetries, |
84 | "PollServiceWatcherThread", | 87 | string.Format("PollServiceWatcherThread:{0}", m_server.Port), |
85 | ThreadPriority.Normal, | 88 | ThreadPriority.Normal, |
86 | false, | 89 | false, |
87 | true, | 90 | true, |
@@ -89,7 +92,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
89 | 1000 * 60 * 10); | 92 | 1000 * 60 * 10); |
90 | } | 93 | } |
91 | 94 | ||
92 | |||
93 | private void ReQueueEvent(PollServiceHttpRequest req) | 95 | private void ReQueueEvent(PollServiceHttpRequest req) |
94 | { | 96 | { |
95 | if (m_running) | 97 | if (m_running) |
@@ -103,7 +105,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
103 | { | 105 | { |
104 | if (m_running) | 106 | if (m_running) |
105 | { | 107 | { |
106 | if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal) | 108 | if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.LongPoll) |
107 | { | 109 | { |
108 | m_requests.Enqueue(req); | 110 | m_requests.Enqueue(req); |
109 | } | 111 | } |
@@ -140,19 +142,19 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
140 | } | 142 | } |
141 | } | 143 | } |
142 | 144 | ||
143 | ~PollServiceRequestManager() | 145 | public void Stop() |
144 | { | 146 | { |
145 | m_running = false; | 147 | m_running = false; |
146 | Thread.Sleep(1000); // let the world move | 148 | Thread.Sleep(1000); // let the world move |
147 | 149 | ||
148 | foreach (Thread t in m_workerThreads) | 150 | foreach (Thread t in m_workerThreads) |
149 | Watchdog.AbortThread(t.ManagedThreadId); | 151 | Watchdog.AbortThread(t.ManagedThreadId); |
150 | 152 | ||
151 | try | 153 | try |
152 | { | 154 | { |
153 | foreach (PollServiceHttpRequest req in m_retryRequests) | 155 | foreach (PollServiceHttpRequest req in m_retryRequests) |
154 | { | 156 | { |
155 | DoHTTPGruntWork(m_server,req, | 157 | req.DoHTTPGruntWork(m_server, |
156 | req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); | 158 | req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); |
157 | } | 159 | } |
158 | } | 160 | } |
@@ -174,7 +176,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
174 | try | 176 | try |
175 | { | 177 | { |
176 | wreq = m_requests.Dequeue(0); | 178 | wreq = m_requests.Dequeue(0); |
177 | DoHTTPGruntWork(m_server,wreq, | 179 | wreq.DoHTTPGruntWork(m_server, |
178 | wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id)); | 180 | wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id)); |
179 | } | 181 | } |
180 | catch | 182 | catch |
@@ -202,14 +204,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
202 | { | 204 | { |
203 | Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); | 205 | Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); |
204 | 206 | ||
205 | if (responsedata == null) | 207 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue |
206 | continue; | ||
207 | |||
208 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue | ||
209 | { | 208 | { |
210 | try | 209 | try |
211 | { | 210 | { |
212 | DoHTTPGruntWork(m_server, req, responsedata); | 211 | req.DoHTTPGruntWork(m_server, responsedata); |
213 | } | 212 | } |
214 | catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream | 213 | catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream |
215 | { | 214 | { |
@@ -222,7 +221,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
222 | { | 221 | { |
223 | try | 222 | try |
224 | { | 223 | { |
225 | DoHTTPGruntWork(m_server, req, responsedata); | 224 | req.DoHTTPGruntWork(m_server, responsedata); |
226 | } | 225 | } |
227 | catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream | 226 | catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream |
228 | { | 227 | { |
@@ -237,7 +236,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
237 | { | 236 | { |
238 | if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) | 237 | if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) |
239 | { | 238 | { |
240 | DoHTTPGruntWork(m_server, req, | 239 | req.DoHTTPGruntWork(m_server, |
241 | req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); | 240 | req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); |
242 | } | 241 | } |
243 | else | 242 | else |
@@ -254,41 +253,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
254 | } | 253 | } |
255 | } | 254 | } |
256 | 255 | ||
257 | // DoHTTPGruntWork changed, not sending response | ||
258 | // do the same work around as core | ||
259 | |||
260 | internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata) | ||
261 | { | ||
262 | OSHttpResponse response | ||
263 | = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext); | ||
264 | |||
265 | byte[] buffer = server.DoHTTPGruntWork(responsedata, response); | ||
266 | |||
267 | response.SendChunked = false; | ||
268 | response.ContentLength64 = buffer.Length; | ||
269 | response.ContentEncoding = Encoding.UTF8; | ||
270 | |||
271 | try | ||
272 | { | ||
273 | response.OutputStream.Write(buffer, 0, buffer.Length); | ||
274 | } | ||
275 | catch (Exception ex) | ||
276 | { | ||
277 | m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); | ||
278 | } | ||
279 | finally | ||
280 | { | ||
281 | try | ||
282 | { | ||
283 | response.OutputStream.Flush(); | ||
284 | response.Send(); | ||
285 | } | ||
286 | catch (Exception e) | ||
287 | { | ||
288 | m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | } | 256 | } |
293 | } | 257 | } |
294 | 258 | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs index 8e592c1..f409667 100644 --- a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs index 07082a8..bd55657 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs | |||
@@ -33,7 +33,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
33 | { | 33 | { |
34 | public delegate TResponse RestDeserialiseMethod<TRequest, TResponse>(TRequest request); | 34 | public delegate TResponse RestDeserialiseMethod<TRequest, TResponse>(TRequest request); |
35 | 35 | ||
36 | public class RestDeserialiseHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler | 36 | public class RestDeserialiseHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler |
37 | where TRequest : new() | 37 | where TRequest : new() |
38 | { | 38 | { |
39 | private RestDeserialiseMethod<TRequest, TResponse> m_method; | 39 | private RestDeserialiseMethod<TRequest, TResponse> m_method; |
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
48 | m_method = method; | 48 | m_method = method; |
49 | } | 49 | } |
50 | 50 | ||
51 | public void Handle(string path, Stream request, Stream responseStream, | 51 | protected override void ProcessRequest(string path, Stream request, Stream responseStream, |
52 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 52 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
53 | { | 53 | { |
54 | TRequest deserial; | 54 | TRequest deserial; |
diff --git a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs index edcd134..83c9848 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs | |||
@@ -183,7 +183,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
183 | 183 | ||
184 | public delegate bool CheckIdentityMethod(string sid, string aid); | 184 | public delegate bool CheckIdentityMethod(string sid, string aid); |
185 | 185 | ||
186 | public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler | 186 | public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler |
187 | where TRequest : new() | 187 | where TRequest : new() |
188 | { | 188 | { |
189 | private static readonly ILog m_log | 189 | private static readonly ILog m_log |
@@ -201,7 +201,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
201 | m_method = method; | 201 | m_method = method; |
202 | } | 202 | } |
203 | 203 | ||
204 | public void Handle(string path, Stream request, Stream responseStream, | 204 | protected override void ProcessRequest(string path, Stream request, Stream responseStream, |
205 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 205 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
206 | { | 206 | { |
207 | RestSessionObject<TRequest> deserial = default(RestSessionObject<TRequest>); | 207 | RestSessionObject<TRequest> deserial = default(RestSessionObject<TRequest>); |
@@ -237,7 +237,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
237 | 237 | ||
238 | public delegate bool CheckTrustedSourceMethod(IPEndPoint peer); | 238 | public delegate bool CheckTrustedSourceMethod(IPEndPoint peer); |
239 | 239 | ||
240 | public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler | 240 | public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler |
241 | where TRequest : new() | 241 | where TRequest : new() |
242 | { | 242 | { |
243 | private static readonly ILog m_log | 243 | private static readonly ILog m_log |
@@ -260,7 +260,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
260 | m_method = method; | 260 | m_method = method; |
261 | } | 261 | } |
262 | 262 | ||
263 | public void Handle(string path, Stream request, Stream responseStream, | 263 | protected override void ProcessRequest(string path, Stream request, Stream responseStream, |
264 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 264 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
265 | { | 265 | { |
266 | TRequest deserial = default(TRequest); | 266 | TRequest deserial = default(TRequest); |
@@ -292,6 +292,5 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
292 | serializer.Serialize(xmlWriter, response); | 292 | serializer.Serialize(xmlWriter, response); |
293 | } | 293 | } |
294 | } | 294 | } |
295 | } | 295 | } |
296 | 296 | } \ No newline at end of file | |
297 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs index 1f17fee..0305dee 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs | |||
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
48 | m_restMethod = restMethod; | 48 | m_restMethod = restMethod; |
49 | } | 49 | } |
50 | 50 | ||
51 | public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 51 | protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
52 | { | 52 | { |
53 | Encoding encoding = Encoding.UTF8; | 53 | Encoding encoding = Encoding.UTF8; |
54 | StreamReader streamReader = new StreamReader(request, encoding); | 54 | StreamReader streamReader = new StreamReader(request, encoding); |
diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs index ee96b47..c2925e3 100644 --- a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs | |||
@@ -28,8 +28,10 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.IO; | 30 | using System.IO; |
31 | using System.Net; | ||
31 | using System.Security.Cryptography; | 32 | using System.Security.Cryptography; |
32 | using System.Text; | 33 | using System.Text; |
34 | using System.Threading; | ||
33 | using HttpServer; | 35 | using HttpServer; |
34 | 36 | ||
35 | namespace OpenSim.Framework.Servers.HttpServer | 37 | namespace OpenSim.Framework.Servers.HttpServer |
@@ -75,7 +77,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
75 | /// <summary> | 77 | /// <summary> |
76 | /// This is a regular HTTP Request... This may be removed in the future. | 78 | /// This is a regular HTTP Request... This may be removed in the future. |
77 | /// </summary> | 79 | /// </summary> |
78 | public event RegularHttpRequestDelegate OnRegularHttpRequest; | 80 | // public event RegularHttpRequestDelegate OnRegularHttpRequest; |
79 | 81 | ||
80 | /// <summary> | 82 | /// <summary> |
81 | /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired | 83 | /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired |
@@ -98,6 +100,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
98 | /// </summary> | 100 | /// </summary> |
99 | public ValidateHandshake HandshakeValidateMethodOverride = null; | 101 | public ValidateHandshake HandshakeValidateMethodOverride = null; |
100 | 102 | ||
103 | private ManualResetEvent _receiveDone = new ManualResetEvent(false); | ||
104 | |||
101 | private OSHttpRequest _request; | 105 | private OSHttpRequest _request; |
102 | private HTTPNetworkContext _networkContext; | 106 | private HTTPNetworkContext _networkContext; |
103 | private IHttpClientContext _clientContext; | 107 | private IHttpClientContext _clientContext; |
@@ -109,6 +113,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
109 | private bool _closing; | 113 | private bool _closing; |
110 | private bool _upgraded; | 114 | private bool _upgraded; |
111 | private int _maxPayloadBytes = 41943040; | 115 | private int _maxPayloadBytes = 41943040; |
116 | private int _initialMsgTimeout = 0; | ||
117 | private int _defaultReadTimeout = 10000; | ||
112 | 118 | ||
113 | private const string HandshakeAcceptText = | 119 | private const string HandshakeAcceptText = |
114 | "HTTP/1.1 101 Switching Protocols\r\n" + | 120 | "HTTP/1.1 101 Switching Protocols\r\n" + |
@@ -131,6 +137,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
131 | { | 137 | { |
132 | _request = preq; | 138 | _request = preq; |
133 | _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing(); | 139 | _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing(); |
140 | _networkContext.Stream.ReadTimeout = _defaultReadTimeout; | ||
134 | _clientContext = pContext; | 141 | _clientContext = pContext; |
135 | _bufferLength = bufferlen; | 142 | _bufferLength = bufferlen; |
136 | _buffer = new byte[_bufferLength]; | 143 | _buffer = new byte[_bufferLength]; |
@@ -206,6 +213,16 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
206 | } | 213 | } |
207 | 214 | ||
208 | /// <summary> | 215 | /// <summary> |
216 | /// Set this to the maximum amount of milliseconds to wait for the first complete message to be sent or received on the websocket after upgrading | ||
217 | /// Default, it waits forever. Use this when your Websocket consuming code opens a connection and waits for a message from the other side to avoid a Denial of Service vector. | ||
218 | /// </summary> | ||
219 | public int InitialMsgTimeout | ||
220 | { | ||
221 | get { return _initialMsgTimeout; } | ||
222 | set { _initialMsgTimeout = value; } | ||
223 | } | ||
224 | |||
225 | /// <summary> | ||
209 | /// This triggers the websocket start the upgrade process | 226 | /// This triggers the websocket start the upgrade process |
210 | /// </summary> | 227 | /// </summary> |
211 | public void HandshakeAndUpgrade() | 228 | public void HandshakeAndUpgrade() |
@@ -245,6 +262,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
245 | string rawaccept = string.Format(HandshakeAcceptText, acceptKey); | 262 | string rawaccept = string.Format(HandshakeAcceptText, acceptKey); |
246 | SendUpgradeSuccess(rawaccept); | 263 | SendUpgradeSuccess(rawaccept); |
247 | 264 | ||
265 | |||
248 | } | 266 | } |
249 | else | 267 | else |
250 | { | 268 | { |
@@ -258,6 +276,10 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
258 | SendUpgradeSuccess(rawaccept); | 276 | SendUpgradeSuccess(rawaccept); |
259 | } | 277 | } |
260 | } | 278 | } |
279 | public IPEndPoint GetRemoteIPEndpoint() | ||
280 | { | ||
281 | return _request.RemoteIPEndPoint; | ||
282 | } | ||
261 | 283 | ||
262 | /// <summary> | 284 | /// <summary> |
263 | /// Generates a handshake response key string based on the client's | 285 | /// Generates a handshake response key string based on the client's |
@@ -290,9 +312,16 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
290 | WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true}; | 312 | WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true}; |
291 | 313 | ||
292 | byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse); | 314 | byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse); |
315 | |||
316 | |||
317 | |||
318 | |||
293 | try | 319 | try |
294 | { | 320 | { |
295 | 321 | if (_initialMsgTimeout > 0) | |
322 | { | ||
323 | _receiveDone.Reset(); | ||
324 | } | ||
296 | // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream. | 325 | // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream. |
297 | _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState); | 326 | _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState); |
298 | 327 | ||
@@ -303,16 +332,20 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
303 | UpgradeCompletedDelegate d = OnUpgradeCompleted; | 332 | UpgradeCompletedDelegate d = OnUpgradeCompleted; |
304 | if (d != null) | 333 | if (d != null) |
305 | d(this, new UpgradeCompletedEventArgs()); | 334 | d(this, new UpgradeCompletedEventArgs()); |
335 | if (_initialMsgTimeout > 0) | ||
336 | { | ||
337 | if (!_receiveDone.WaitOne(TimeSpan.FromMilliseconds(_initialMsgTimeout))) | ||
338 | Close(string.Empty); | ||
339 | } | ||
306 | } | 340 | } |
307 | catch (IOException fail) | 341 | catch (IOException) |
308 | { | 342 | { |
309 | Close(string.Empty); | 343 | Close(string.Empty); |
310 | } | 344 | } |
311 | catch (ObjectDisposedException fail) | 345 | catch (ObjectDisposedException) |
312 | { | 346 | { |
313 | Close(string.Empty); | 347 | Close(string.Empty); |
314 | } | 348 | } |
315 | |||
316 | } | 349 | } |
317 | 350 | ||
318 | /// <summary> | 351 | /// <summary> |
@@ -414,8 +447,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
414 | _socketState.Header = pheader; | 447 | _socketState.Header = pheader; |
415 | } | 448 | } |
416 | 449 | ||
417 | |||
418 | |||
419 | if (_socketState.FrameComplete) | 450 | if (_socketState.FrameComplete) |
420 | { | 451 | { |
421 | ProcessFrame(_socketState); | 452 | ProcessFrame(_socketState); |
@@ -424,7 +455,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
424 | _socketState.ExpectedBytes = 0; | 455 | _socketState.ExpectedBytes = 0; |
425 | 456 | ||
426 | } | 457 | } |
427 | |||
428 | } | 458 | } |
429 | } | 459 | } |
430 | else | 460 | else |
@@ -457,8 +487,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
457 | _socketState.ReceivedBytes.Clear(); | 487 | _socketState.ReceivedBytes.Clear(); |
458 | _socketState.ExpectedBytes = 0; | 488 | _socketState.ExpectedBytes = 0; |
459 | // do some processing | 489 | // do some processing |
460 | } | 490 | } |
461 | |||
462 | } | 491 | } |
463 | } | 492 | } |
464 | if (offset > 0) | 493 | if (offset > 0) |
@@ -477,13 +506,12 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
477 | { | 506 | { |
478 | // We can't read the stream anymore... | 507 | // We can't read the stream anymore... |
479 | } | 508 | } |
480 | |||
481 | } | 509 | } |
482 | catch (IOException fail) | 510 | catch (IOException) |
483 | { | 511 | { |
484 | Close(string.Empty); | 512 | Close(string.Empty); |
485 | } | 513 | } |
486 | catch (ObjectDisposedException fail) | 514 | catch (ObjectDisposedException) |
487 | { | 515 | { |
488 | Close(string.Empty); | 516 | Close(string.Empty); |
489 | } | 517 | } |
@@ -495,6 +523,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
495 | /// <param name="message">the string message that is to be sent</param> | 523 | /// <param name="message">the string message that is to be sent</param> |
496 | public void SendMessage(string message) | 524 | public void SendMessage(string message) |
497 | { | 525 | { |
526 | if (_initialMsgTimeout > 0) | ||
527 | { | ||
528 | _receiveDone.Set(); | ||
529 | _initialMsgTimeout = 0; | ||
530 | } | ||
498 | byte[] messagedata = Encoding.UTF8.GetBytes(message); | 531 | byte[] messagedata = Encoding.UTF8.GetBytes(message); |
499 | WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata }; | 532 | WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata }; |
500 | textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text; | 533 | textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text; |
@@ -505,6 +538,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
505 | 538 | ||
506 | public void SendData(byte[] data) | 539 | public void SendData(byte[] data) |
507 | { | 540 | { |
541 | if (_initialMsgTimeout > 0) | ||
542 | { | ||
543 | _receiveDone.Set(); | ||
544 | _initialMsgTimeout = 0; | ||
545 | } | ||
508 | WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data}; | 546 | WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data}; |
509 | dataMessageFrame.Header.IsEnd = true; | 547 | dataMessageFrame.Header.IsEnd = true; |
510 | dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary; | 548 | dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary; |
@@ -537,6 +575,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
537 | /// </summary> | 575 | /// </summary> |
538 | public void SendPingCheck() | 576 | public void SendPingCheck() |
539 | { | 577 | { |
578 | if (_initialMsgTimeout > 0) | ||
579 | { | ||
580 | _receiveDone.Set(); | ||
581 | _initialMsgTimeout = 0; | ||
582 | } | ||
540 | WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] }; | 583 | WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] }; |
541 | pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping; | 584 | pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping; |
542 | pingFrame.Header.IsEnd = true; | 585 | pingFrame.Header.IsEnd = true; |
@@ -550,6 +593,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
550 | /// <param name="message"></param> | 593 | /// <param name="message"></param> |
551 | public void Close(string message) | 594 | public void Close(string message) |
552 | { | 595 | { |
596 | if (_initialMsgTimeout > 0) | ||
597 | { | ||
598 | _receiveDone.Set(); | ||
599 | _initialMsgTimeout = 0; | ||
600 | } | ||
553 | if (_networkContext == null) | 601 | if (_networkContext == null) |
554 | return; | 602 | return; |
555 | if (_networkContext.Stream != null) | 603 | if (_networkContext.Stream != null) |
@@ -589,7 +637,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
589 | WebSocketReader.Mask(psocketState.Header.Mask, unmask); | 637 | WebSocketReader.Mask(psocketState.Header.Mask, unmask); |
590 | psocketState.ReceivedBytes = new List<byte>(unmask); | 638 | psocketState.ReceivedBytes = new List<byte>(unmask); |
591 | } | 639 | } |
592 | 640 | if (psocketState.Header.Opcode != WebSocketReader.OpCode.Continue && _initialMsgTimeout > 0) | |
641 | { | ||
642 | _receiveDone.Set(); | ||
643 | _initialMsgTimeout = 0; | ||
644 | } | ||
593 | switch (psocketState.Header.Opcode) | 645 | switch (psocketState.Header.Opcode) |
594 | { | 646 | { |
595 | case WebSocketReader.OpCode.Ping: | 647 | case WebSocketReader.OpCode.Ping: |
@@ -702,6 +754,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
702 | } | 754 | } |
703 | public void Dispose() | 755 | public void Dispose() |
704 | { | 756 | { |
757 | if (_initialMsgTimeout > 0) | ||
758 | { | ||
759 | _receiveDone.Set(); | ||
760 | _initialMsgTimeout = 0; | ||
761 | } | ||
705 | if (_networkContext != null && _networkContext.Stream != null) | 762 | if (_networkContext != null && _networkContext.Stream != null) |
706 | { | 763 | { |
707 | if (_networkContext.Stream.CanWrite) | 764 | if (_networkContext.Stream.CanWrite) |
diff --git a/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs new file mode 100644 index 0000000..f212208 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System.Net; | ||
29 | using Nwc.XmlRpc; | ||
30 | using OpenSim.Framework; | ||
31 | |||
32 | |||
33 | namespace OpenSim.Framework.Servers.HttpServer | ||
34 | { | ||
35 | public class XmlRpcBasicDOSProtector | ||
36 | { | ||
37 | private readonly XmlRpcMethod _normalMethod; | ||
38 | private readonly XmlRpcMethod _throttledMethod; | ||
39 | |||
40 | private readonly BasicDosProtectorOptions _options; | ||
41 | private readonly BasicDOSProtector _dosProtector; | ||
42 | |||
43 | public XmlRpcBasicDOSProtector(XmlRpcMethod normalMethod, XmlRpcMethod throttledMethod,BasicDosProtectorOptions options) | ||
44 | { | ||
45 | _normalMethod = normalMethod; | ||
46 | _throttledMethod = throttledMethod; | ||
47 | |||
48 | _options = options; | ||
49 | _dosProtector = new BasicDOSProtector(_options); | ||
50 | |||
51 | } | ||
52 | public XmlRpcResponse Process(XmlRpcRequest request, IPEndPoint client) | ||
53 | { | ||
54 | |||
55 | XmlRpcResponse resp = null; | ||
56 | string clientstring = GetClientString(request, client); | ||
57 | string endpoint = GetEndPoint(request, client); | ||
58 | if (_dosProtector.Process(clientstring, endpoint)) | ||
59 | resp = _normalMethod(request, client); | ||
60 | else | ||
61 | resp = _throttledMethod(request, client); | ||
62 | if (_options.MaxConcurrentSessions > 0) | ||
63 | _dosProtector.ProcessEnd(clientstring, endpoint); | ||
64 | return resp; | ||
65 | } | ||
66 | |||
67 | private string GetClientString(XmlRpcRequest request, IPEndPoint client) | ||
68 | { | ||
69 | string clientstring; | ||
70 | if (_options.AllowXForwardedFor && request.Params.Count > 3) | ||
71 | { | ||
72 | object headerstr = request.Params[3]; | ||
73 | if (headerstr != null && !string.IsNullOrEmpty(headerstr.ToString())) | ||
74 | clientstring = request.Params[3].ToString(); | ||
75 | else | ||
76 | clientstring = client.Address.ToString(); | ||
77 | } | ||
78 | else | ||
79 | clientstring = client.Address.ToString(); | ||
80 | return clientstring; | ||
81 | } | ||
82 | |||
83 | private string GetEndPoint(XmlRpcRequest request, IPEndPoint client) | ||
84 | { | ||
85 | return client.Address.ToString(); | ||
86 | } | ||
87 | |||
88 | } | ||
89 | |||
90 | |||
91 | } | ||
diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs index cfd34bb..57931d4 100644 --- a/OpenSim/Framework/Servers/MainServer.cs +++ b/OpenSim/Framework/Servers/MainServer.cs | |||
@@ -121,12 +121,14 @@ namespace OpenSim.Framework.Servers | |||
121 | + " level >= 2 then long warnings are logged when receiving bad input data.\n" | 121 | + " level >= 2 then long warnings are logged when receiving bad input data.\n" |
122 | + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n" | 122 | + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n" |
123 | + " level >= 4 then the time taken to fulfill the request is logged.\n" | 123 | + " level >= 4 then the time taken to fulfill the request is logged.\n" |
124 | + " level >= 5 then a sample from the beginning of the incoming data is logged.\n" | 124 | + " level >= 5 then a sample from the beginning of the data is logged.\n" |
125 | + " level >= 6 then the entire incoming data is logged.\n" | 125 | + " level >= 6 then the entire data is logged.\n" |
126 | + " no level is specified then the current level is returned.\n\n" | 126 | + " no level is specified then the current level is returned.\n\n" |
127 | + "If out or all and\n" | 127 | + "If out or all and\n" |
128 | + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n" | 128 | + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n" |
129 | + " level >= 4 then the time taken to fulfill the request is logged.\n", | 129 | + " level >= 4 then the time taken to fulfill the request is logged.\n" |
130 | + " level >= 5 then a sample from the beginning of the data is logged.\n" | ||
131 | + " level >= 6 then the entire data is logged.\n", | ||
130 | HandleDebugHttpCommand); | 132 | HandleDebugHttpCommand); |
131 | } | 133 | } |
132 | 134 | ||
@@ -283,7 +285,12 @@ namespace OpenSim.Framework.Servers | |||
283 | public static bool RemoveHttpServer(uint port) | 285 | public static bool RemoveHttpServer(uint port) |
284 | { | 286 | { |
285 | lock (m_Servers) | 287 | lock (m_Servers) |
288 | { | ||
289 | if (instance != null && instance.Port == port) | ||
290 | instance = null; | ||
291 | |||
286 | return m_Servers.Remove(port); | 292 | return m_Servers.Remove(port); |
293 | } | ||
287 | } | 294 | } |
288 | 295 | ||
289 | /// <summary> | 296 | /// <summary> |
diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 1ff8aca..7108314 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs | |||
@@ -62,6 +62,8 @@ namespace OpenSim.Framework.Servers | |||
62 | 62 | ||
63 | protected string m_pidFile = String.Empty; | 63 | protected string m_pidFile = String.Empty; |
64 | 64 | ||
65 | protected ServerStatsCollector m_serverStatsCollector; | ||
66 | |||
65 | /// <summary> | 67 | /// <summary> |
66 | /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. | 68 | /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. |
67 | /// </summary> | 69 | /// </summary> |
@@ -76,6 +78,11 @@ namespace OpenSim.Framework.Servers | |||
76 | 78 | ||
77 | protected void CreatePIDFile(string path) | 79 | protected void CreatePIDFile(string path) |
78 | { | 80 | { |
81 | if (File.Exists(path)) | ||
82 | m_log.ErrorFormat( | ||
83 | "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.", | ||
84 | path); | ||
85 | |||
79 | try | 86 | try |
80 | { | 87 | { |
81 | string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); | 88 | string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); |
@@ -239,7 +246,7 @@ namespace OpenSim.Framework.Servers | |||
239 | "Show thread status", HandleShow); | 246 | "Show thread status", HandleShow); |
240 | 247 | ||
241 | m_console.Commands.AddCommand( | 248 | m_console.Commands.AddCommand( |
242 | "General", false, "threads abort", | 249 | "Debug", false, "threads abort", |
243 | "threads abort <thread-id>", | 250 | "threads abort <thread-id>", |
244 | "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); | 251 | "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); |
245 | 252 | ||
@@ -249,11 +256,180 @@ namespace OpenSim.Framework.Servers | |||
249 | "Show thread status. Synonym for \"show threads\"", | 256 | "Show thread status. Synonym for \"show threads\"", |
250 | (string module, string[] args) => Notice(GetThreadsReport())); | 257 | (string module, string[] args) => Notice(GetThreadsReport())); |
251 | 258 | ||
259 | m_console.Commands.AddCommand ( | ||
260 | "Debug", false, "debug comms set", | ||
261 | "debug comms set serialosdreq true|false", | ||
262 | "Set comms parameters. For debug purposes.", | ||
263 | HandleDebugCommsSet); | ||
264 | |||
265 | m_console.Commands.AddCommand ( | ||
266 | "Debug", false, "debug comms status", | ||
267 | "debug comms status", | ||
268 | "Show current debug comms parameters.", | ||
269 | HandleDebugCommsStatus); | ||
270 | |||
271 | m_console.Commands.AddCommand ( | ||
272 | "Debug", false, "debug threadpool set", | ||
273 | "debug threadpool set worker|iocp min|max <n>", | ||
274 | "Set threadpool parameters. For debug purposes.", | ||
275 | HandleDebugThreadpoolSet); | ||
276 | |||
277 | m_console.Commands.AddCommand ( | ||
278 | "Debug", false, "debug threadpool status", | ||
279 | "debug threadpool status", | ||
280 | "Show current debug threadpool parameters.", | ||
281 | HandleDebugThreadpoolStatus); | ||
282 | |||
252 | m_console.Commands.AddCommand( | 283 | m_console.Commands.AddCommand( |
253 | "General", false, "force gc", | 284 | "Debug", false, "force gc", |
254 | "force gc", | 285 | "force gc", |
255 | "Manually invoke runtime garbage collection. For debugging purposes", | 286 | "Manually invoke runtime garbage collection. For debugging purposes", |
256 | HandleForceGc); | 287 | HandleForceGc); |
288 | |||
289 | m_console.Commands.AddCommand( | ||
290 | "General", false, "quit", | ||
291 | "quit", | ||
292 | "Quit the application", (mod, args) => Shutdown()); | ||
293 | |||
294 | m_console.Commands.AddCommand( | ||
295 | "General", false, "shutdown", | ||
296 | "shutdown", | ||
297 | "Quit the application", (mod, args) => Shutdown()); | ||
298 | |||
299 | ChecksManager.RegisterConsoleCommands(m_console); | ||
300 | StatsManager.RegisterConsoleCommands(m_console); | ||
301 | } | ||
302 | |||
303 | public void RegisterCommonComponents(IConfigSource configSource) | ||
304 | { | ||
305 | IConfig networkConfig = configSource.Configs["Network"]; | ||
306 | |||
307 | if (networkConfig != null) | ||
308 | { | ||
309 | WebUtil.SerializeOSDRequestsPerEndpoint = networkConfig.GetBoolean("SerializeOSDRequests", false); | ||
310 | } | ||
311 | |||
312 | m_serverStatsCollector = new ServerStatsCollector(); | ||
313 | m_serverStatsCollector.Initialise(configSource); | ||
314 | m_serverStatsCollector.Start(); | ||
315 | } | ||
316 | |||
317 | private void HandleDebugCommsStatus(string module, string[] args) | ||
318 | { | ||
319 | Notice("serialosdreq is {0}", WebUtil.SerializeOSDRequestsPerEndpoint); | ||
320 | } | ||
321 | |||
322 | private void HandleDebugCommsSet(string module, string[] args) | ||
323 | { | ||
324 | if (args.Length != 5) | ||
325 | { | ||
326 | Notice("Usage: debug comms set serialosdreq true|false"); | ||
327 | return; | ||
328 | } | ||
329 | |||
330 | if (args[3] != "serialosdreq") | ||
331 | { | ||
332 | Notice("Usage: debug comms set serialosdreq true|false"); | ||
333 | return; | ||
334 | } | ||
335 | |||
336 | bool setSerializeOsdRequests; | ||
337 | |||
338 | if (!ConsoleUtil.TryParseConsoleBool(m_console, args[4], out setSerializeOsdRequests)) | ||
339 | return; | ||
340 | |||
341 | WebUtil.SerializeOSDRequestsPerEndpoint = setSerializeOsdRequests; | ||
342 | |||
343 | Notice("serialosdreq is now {0}", setSerializeOsdRequests); | ||
344 | } | ||
345 | |||
346 | private void HandleDebugThreadpoolStatus(string module, string[] args) | ||
347 | { | ||
348 | int workerThreads, iocpThreads; | ||
349 | |||
350 | ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); | ||
351 | Notice("Min worker threads: {0}", workerThreads); | ||
352 | Notice("Min IOCP threads: {0}", iocpThreads); | ||
353 | |||
354 | ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); | ||
355 | Notice("Max worker threads: {0}", workerThreads); | ||
356 | Notice("Max IOCP threads: {0}", iocpThreads); | ||
357 | |||
358 | ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); | ||
359 | Notice("Available worker threads: {0}", workerThreads); | ||
360 | Notice("Available IOCP threads: {0}", iocpThreads); | ||
361 | } | ||
362 | |||
363 | private void HandleDebugThreadpoolSet(string module, string[] args) | ||
364 | { | ||
365 | if (args.Length != 6) | ||
366 | { | ||
367 | Notice("Usage: debug threadpool set worker|iocp min|max <n>"); | ||
368 | return; | ||
369 | } | ||
370 | |||
371 | int newThreads; | ||
372 | |||
373 | if (!ConsoleUtil.TryParseConsoleInt(m_console, args[5], out newThreads)) | ||
374 | return; | ||
375 | |||
376 | string poolType = args[3]; | ||
377 | string bound = args[4]; | ||
378 | |||
379 | bool fail = false; | ||
380 | int workerThreads, iocpThreads; | ||
381 | |||
382 | if (poolType == "worker") | ||
383 | { | ||
384 | if (bound == "min") | ||
385 | { | ||
386 | ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); | ||
387 | |||
388 | if (!ThreadPool.SetMinThreads(newThreads, iocpThreads)) | ||
389 | fail = true; | ||
390 | } | ||
391 | else | ||
392 | { | ||
393 | ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); | ||
394 | |||
395 | if (!ThreadPool.SetMaxThreads(newThreads, iocpThreads)) | ||
396 | fail = true; | ||
397 | } | ||
398 | } | ||
399 | else | ||
400 | { | ||
401 | if (bound == "min") | ||
402 | { | ||
403 | ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); | ||
404 | |||
405 | if (!ThreadPool.SetMinThreads(workerThreads, newThreads)) | ||
406 | fail = true; | ||
407 | } | ||
408 | else | ||
409 | { | ||
410 | ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); | ||
411 | |||
412 | if (!ThreadPool.SetMaxThreads(workerThreads, newThreads)) | ||
413 | fail = true; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | if (fail) | ||
418 | { | ||
419 | Notice("ERROR: Could not set {0} {1} threads to {2}", poolType, bound, newThreads); | ||
420 | } | ||
421 | else | ||
422 | { | ||
423 | int minWorkerThreads, maxWorkerThreads, minIocpThreads, maxIocpThreads; | ||
424 | |||
425 | ThreadPool.GetMinThreads(out minWorkerThreads, out minIocpThreads); | ||
426 | ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxIocpThreads); | ||
427 | |||
428 | Notice("Min worker threads now {0}", minWorkerThreads); | ||
429 | Notice("Min IOCP threads now {0}", minIocpThreads); | ||
430 | Notice("Max worker threads now {0}", maxWorkerThreads); | ||
431 | Notice("Max IOCP threads now {0}", maxIocpThreads); | ||
432 | } | ||
257 | } | 433 | } |
258 | 434 | ||
259 | private void HandleForceGc(string module, string[] args) | 435 | private void HandleForceGc(string module, string[] args) |
@@ -641,7 +817,68 @@ namespace OpenSim.Framework.Servers | |||
641 | sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); | 817 | sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); |
642 | 818 | ||
643 | sb.Append("Main threadpool (excluding script engine pools)\n"); | 819 | sb.Append("Main threadpool (excluding script engine pools)\n"); |
644 | sb.Append(Util.GetThreadPoolReport()); | 820 | sb.Append(GetThreadPoolReport()); |
821 | |||
822 | return sb.ToString(); | ||
823 | } | ||
824 | |||
825 | /// <summary> | ||
826 | /// Get a thread pool report. | ||
827 | /// </summary> | ||
828 | /// <returns></returns> | ||
829 | public static string GetThreadPoolReport() | ||
830 | { | ||
831 | string threadPoolUsed = null; | ||
832 | int maxThreads = 0; | ||
833 | int minThreads = 0; | ||
834 | int allocatedThreads = 0; | ||
835 | int inUseThreads = 0; | ||
836 | int waitingCallbacks = 0; | ||
837 | int completionPortThreads = 0; | ||
838 | |||
839 | StringBuilder sb = new StringBuilder(); | ||
840 | if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) | ||
841 | { | ||
842 | STPInfo stpi = Util.GetSmartThreadPoolInfo(); | ||
843 | |||
844 | // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. | ||
845 | if (stpi != null) | ||
846 | { | ||
847 | threadPoolUsed = "SmartThreadPool"; | ||
848 | maxThreads = stpi.MaxThreads; | ||
849 | minThreads = stpi.MinThreads; | ||
850 | inUseThreads = stpi.InUseThreads; | ||
851 | allocatedThreads = stpi.ActiveThreads; | ||
852 | waitingCallbacks = stpi.WaitingCallbacks; | ||
853 | } | ||
854 | } | ||
855 | else if ( | ||
856 | Util.FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem | ||
857 | || Util.FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) | ||
858 | { | ||
859 | threadPoolUsed = "BuiltInThreadPool"; | ||
860 | ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); | ||
861 | ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); | ||
862 | int availableThreads; | ||
863 | ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); | ||
864 | inUseThreads = maxThreads - availableThreads; | ||
865 | allocatedThreads = -1; | ||
866 | waitingCallbacks = -1; | ||
867 | } | ||
868 | |||
869 | if (threadPoolUsed != null) | ||
870 | { | ||
871 | sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); | ||
872 | sb.AppendFormat("Max threads : {0}\n", maxThreads); | ||
873 | sb.AppendFormat("Min threads : {0}\n", minThreads); | ||
874 | sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); | ||
875 | sb.AppendFormat("In use threads : {0}\n", inUseThreads); | ||
876 | sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); | ||
877 | } | ||
878 | else | ||
879 | { | ||
880 | sb.AppendFormat("Thread pool not used\n"); | ||
881 | } | ||
645 | 882 | ||
646 | return sb.ToString(); | 883 | return sb.ToString(); |
647 | } | 884 | } |
@@ -693,5 +930,16 @@ namespace OpenSim.Framework.Servers | |||
693 | if (m_console != null) | 930 | if (m_console != null) |
694 | m_console.OutputFormat(format, components); | 931 | m_console.OutputFormat(format, components); |
695 | } | 932 | } |
933 | |||
934 | public virtual void Shutdown() | ||
935 | { | ||
936 | m_serverStatsCollector.Close(); | ||
937 | ShutdownSpecific(); | ||
938 | } | ||
939 | |||
940 | /// <summary> | ||
941 | /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing | ||
942 | /// </summary> | ||
943 | protected virtual void ShutdownSpecific() {} | ||
696 | } | 944 | } |
697 | } | 945 | } |
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs index 737c14d..33b1366 100644 --- a/OpenSim/Framework/Servers/VersionInfo.cs +++ b/OpenSim/Framework/Servers/VersionInfo.cs | |||
@@ -29,7 +29,7 @@ namespace OpenSim | |||
29 | { | 29 | { |
30 | public class VersionInfo | 30 | public class VersionInfo |
31 | { | 31 | { |
32 | private const string VERSION_NUMBER = "0.7.6CM"; | 32 | private const string VERSION_NUMBER = "0.8.0CM"; |
33 | private const Flavour VERSION_FLAVOUR = Flavour.Dev; | 33 | private const Flavour VERSION_FLAVOUR = Flavour.Dev; |
34 | 34 | ||
35 | public enum Flavour | 35 | public enum Flavour |