aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework')
-rw-r--r--OpenSim/Framework/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Communications/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Console/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Console/CommandConsole.cs10
-rw-r--r--OpenSim/Framework/Console/ConsoleDisplayTable.cs15
-rw-r--r--OpenSim/Framework/Console/ConsoleUtil.cs28
-rw-r--r--OpenSim/Framework/DAMap.cs273
-rw-r--r--OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs508
-rw-r--r--OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/PluginManager.cs563
-rw-r--r--OpenSim/Framework/PrimitiveBaseShape.cs32
-rw-r--r--OpenSim/Framework/RegionInfo.cs27
-rw-r--r--OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Serialization/ArchiveConstants.cs5
-rw-r--r--OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs2
-rw-r--r--OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs2
-rw-r--r--OpenSim/Framework/Servers/BaseOpenSimServer.cs122
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs230
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs12
-rw-r--r--OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs34
-rw-r--r--OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs150
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs16
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs1085
-rw-r--r--OpenSim/Framework/Servers/MainServer.cs4
-rw-r--r--OpenSim/Framework/Servers/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Servers/ServerBase.cs111
-rw-r--r--OpenSim/Framework/Servers/Tests/OSHttpTests.cs8
-rw-r--r--OpenSim/Framework/Servers/Tests/VersionInfoTests.cs3
-rw-r--r--OpenSim/Framework/Servers/VersionInfo.cs2
-rw-r--r--OpenSim/Framework/Tests/AgentCircuitDataTest.cs5
-rw-r--r--OpenSim/Framework/Tests/AnimationTests.cs2
-rw-r--r--OpenSim/Framework/Tests/AssetBaseTest.cs3
-rw-r--r--OpenSim/Framework/Tests/CacheTests.cs3
-rw-r--r--OpenSim/Framework/Tests/LocationTest.cs3
-rw-r--r--OpenSim/Framework/Tests/MundaneFrameworkTests.cs11
-rw-r--r--OpenSim/Framework/Tests/PrimeNumberHelperTests.cs3
-rw-r--r--OpenSim/Framework/Tests/UtilTest.cs2
-rw-r--r--OpenSim/Framework/Util.cs80
44 files changed, 3119 insertions, 259 deletions
diff --git a/OpenSim/Framework/AssemblyInfo.cs b/OpenSim/Framework/AssemblyInfo.cs
index 02986d5..b3db56c 100644
--- a/OpenSim/Framework/AssemblyInfo.cs
+++ b/OpenSim/Framework/AssemblyInfo.cs
@@ -59,5 +59,5 @@ using System.Runtime.InteropServices;
59// Revision 59// Revision
60// 60//
61 61
62[assembly : AssemblyVersion("0.7.5.*")] 62[assembly : AssemblyVersion("0.7.6.*")]
63[assembly : AssemblyFileVersion("0.6.5.0")] \ No newline at end of file 63[assembly : AssemblyFileVersion("0.6.5.0")] \ No newline at end of file
diff --git a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs
index 0498ed4..077244d 100644
--- a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/AssetLoader/Filesystem/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.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
index 6d1c03a..cf575ac 100644
--- a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
61// You can specify all the values or you can default the Revision and Build Numbers 61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below: 62// by using the '*' as shown below:
63 63
64[assembly : AssemblyVersion("0.7.5.*")] 64[assembly : AssemblyVersion("0.7.6.*")]
65[assembly : AssemblyFileVersion("0.6.5.0")] 65[assembly : AssemblyFileVersion("0.6.5.0")]
diff --git a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs
index 0674656..c3b6227 100644
--- a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Configuration/HTTP/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.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs
index 1095b23..b0d2d67 100644
--- a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Configuration/XML/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.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Console/AssemblyInfo.cs b/OpenSim/Framework/Console/AssemblyInfo.cs
index 37c7304..c618454 100644
--- a/OpenSim/Framework/Console/AssemblyInfo.cs
+++ b/OpenSim/Framework/Console/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.5.*")] 58[assembly : AssemblyVersion("0.7.6.*")]
diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs
index d703d78..9490013 100644
--- a/OpenSim/Framework/Console/CommandConsole.cs
+++ b/OpenSim/Framework/Console/CommandConsole.cs
@@ -110,10 +110,11 @@ namespace OpenSim.Framework.Console
110 // Remove initial help keyword 110 // Remove initial help keyword
111 helpParts.RemoveAt(0); 111 helpParts.RemoveAt(0);
112 112
113 help.Add(""); // Will become a newline.
114
113 // General help 115 // General help
114 if (helpParts.Count == 0) 116 if (helpParts.Count == 0)
115 { 117 {
116 help.Add(""); // Will become a newline.
117 help.Add(GeneralHelpText); 118 help.Add(GeneralHelpText);
118 help.AddRange(CollectAllCommandsHelp()); 119 help.AddRange(CollectAllCommandsHelp());
119 } 120 }
@@ -129,6 +130,8 @@ namespace OpenSim.Framework.Console
129 help.AddRange(CollectHelp(helpParts)); 130 help.AddRange(CollectHelp(helpParts));
130 } 131 }
131 132
133 help.Add(""); // Will become a newline.
134
132 return help; 135 return help;
133 } 136 }
134 137
@@ -199,14 +202,11 @@ namespace OpenSim.Framework.Console
199 202
200 string descriptiveHelp = commandInfo.descriptive_help; 203 string descriptiveHelp = commandInfo.descriptive_help;
201 204
202 // If we do have some descriptive help then insert a spacing line before and after for readability. 205 // If we do have some descriptive help then insert a spacing line before for readability.
203 if (descriptiveHelp != string.Empty) 206 if (descriptiveHelp != string.Empty)
204 help.Add(string.Empty); 207 help.Add(string.Empty);
205 208
206 help.Add(commandInfo.descriptive_help); 209 help.Add(commandInfo.descriptive_help);
207
208 if (descriptiveHelp != string.Empty)
209 help.Add(string.Empty);
210 } 210 }
211 else 211 else
212 { 212 {
diff --git a/OpenSim/Framework/Console/ConsoleDisplayTable.cs b/OpenSim/Framework/Console/ConsoleDisplayTable.cs
index c620dfe..711a337 100644
--- a/OpenSim/Framework/Console/ConsoleDisplayTable.cs
+++ b/OpenSim/Framework/Console/ConsoleDisplayTable.cs
@@ -56,7 +56,7 @@ namespace OpenSim.Framework.Console
56 public List<ConsoleDisplayTableRow> Rows { get; private set; } 56 public List<ConsoleDisplayTableRow> Rows { get; private set; }
57 57
58 /// <summary> 58 /// <summary>
59 /// Number of spaces to indent the table. 59 /// Number of spaces to indent the whole table.
60 /// </summary> 60 /// </summary>
61 public int Indent { get; set; } 61 public int Indent { get; set; }
62 62
@@ -84,7 +84,7 @@ namespace OpenSim.Framework.Console
84 Columns.Add(new ConsoleDisplayTableColumn(name, width)); 84 Columns.Add(new ConsoleDisplayTableColumn(name, width));
85 } 85 }
86 86
87 public void AddRow(params string[] cells) 87 public void AddRow(params object[] cells)
88 { 88 {
89 Rows.Add(new ConsoleDisplayTableRow(cells)); 89 Rows.Add(new ConsoleDisplayTableRow(cells));
90 } 90 }
@@ -113,7 +113,8 @@ namespace OpenSim.Framework.Console
113 113
114 for (int i = 0; i < Columns.Count; i++) 114 for (int i = 0; i < Columns.Count; i++)
115 { 115 {
116 formatSb.Append(' ', TableSpacing); 116 if (i != 0)
117 formatSb.Append(' ', TableSpacing);
117 118
118 // Can only do left formatting for now 119 // Can only do left formatting for now
119 formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width); 120 formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width);
@@ -139,16 +140,16 @@ namespace OpenSim.Framework.Console
139 140
140 public struct ConsoleDisplayTableRow 141 public struct ConsoleDisplayTableRow
141 { 142 {
142 public List<string> Cells { get; private set; } 143 public List<object> Cells { get; private set; }
143 144
144 public ConsoleDisplayTableRow(List<string> cells) : this() 145 public ConsoleDisplayTableRow(List<object> cells) : this()
145 { 146 {
146 Cells = cells; 147 Cells = cells;
147 } 148 }
148 149
149 public ConsoleDisplayTableRow(params string[] cells) : this() 150 public ConsoleDisplayTableRow(params object[] cells) : this()
150 { 151 {
151 Cells = new List<string>(cells); 152 Cells = new List<object>(cells);
152 } 153 }
153 } 154 }
154} \ No newline at end of file 155} \ No newline at end of file
diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs
index 16a63e0..dff956a 100644
--- a/OpenSim/Framework/Console/ConsoleUtil.cs
+++ b/OpenSim/Framework/Console/ConsoleUtil.cs
@@ -97,7 +97,7 @@ namespace OpenSim.Framework.Console
97 if (!UUID.TryParse(rawUuid, out uuid)) 97 if (!UUID.TryParse(rawUuid, out uuid))
98 { 98 {
99 if (console != null) 99 if (console != null)
100 console.OutputFormat("{0} is not a valid uuid", rawUuid); 100 console.OutputFormat("ERROR: {0} is not a valid uuid", rawUuid);
101 101
102 return false; 102 return false;
103 } 103 }
@@ -110,7 +110,7 @@ namespace OpenSim.Framework.Console
110 if (!uint.TryParse(rawLocalId, out localId)) 110 if (!uint.TryParse(rawLocalId, out localId))
111 { 111 {
112 if (console != null) 112 if (console != null)
113 console.OutputFormat("{0} is not a valid local id", localId); 113 console.OutputFormat("ERROR: {0} is not a valid local id", localId);
114 114
115 return false; 115 return false;
116 } 116 }
@@ -118,7 +118,7 @@ namespace OpenSim.Framework.Console
118 if (localId == 0) 118 if (localId == 0)
119 { 119 {
120 if (console != null) 120 if (console != null)
121 console.OutputFormat("{0} is not a valid local id - it must be greater than 0", localId); 121 console.OutputFormat("ERROR: {0} is not a valid local id - it must be greater than 0", localId);
122 122
123 return false; 123 return false;
124 } 124 }
@@ -150,10 +150,30 @@ namespace OpenSim.Framework.Console
150 } 150 }
151 151
152 if (console != null) 152 if (console != null)
153 console.OutputFormat("{0} is not a valid UUID or local id", rawId); 153 console.OutputFormat("ERROR: {0} is not a valid UUID or local id", rawId);
154 154
155 return false; 155 return false;
156 } 156 }
157
158 /// <summary>
159 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
160 /// </summary>
161 /// <param name='console'>Can be null if no console is available.</param>
162 /// <param name='rawConsoleVector'>/param>
163 /// <param name='vector'></param>
164 /// <returns></returns>
165 public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
166 {
167 if (!int.TryParse(rawConsoleInt, out i))
168 {
169 if (console != null)
170 console.OutputFormat("ERROR: {0} is not a valid integer", rawConsoleInt);
171
172 return false;
173 }
174
175 return true;
176 }
157 177
158 /// <summary> 178 /// <summary>
159 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 179 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs
new file mode 100644
index 0000000..64cea77
--- /dev/null
+++ b/OpenSim/Framework/DAMap.cs
@@ -0,0 +1,273 @@
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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Text;
33using System.Xml;
34using System.Xml.Schema;
35using System.Xml.Serialization;
36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38
39namespace OpenSim.Framework
40{
41 /// <summary>
42 /// This class stores and retrieves dynamic attributes.
43 /// </summary>
44 /// <remarks>
45 /// Modules that want to use dynamic attributes need to do so in a private data store
46 /// which is accessed using a unique name. DAMap provides access to the data stores,
47 /// each of which is an OSDMap. Modules are free to store any type of data they want
48 /// within their data store. However, avoid storing large amounts of data because that
49 /// would slow down database access.
50 /// </remarks>
51 public class DAMap : IDictionary<string, OSDMap>, IXmlSerializable
52 {
53 private static readonly int MIN_STORE_NAME_LENGTH = 4;
54
55 protected OSDMap m_map;
56
57 public DAMap() { m_map = new OSDMap(); }
58
59 public XmlSchema GetSchema() { return null; }
60
61 public static DAMap FromXml(string rawXml)
62 {
63 DAMap map = new DAMap();
64 map.ReadXml(rawXml);
65 return map;
66 }
67
68 public void ReadXml(string rawXml)
69 {
70 // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml);
71
72 lock (this)
73 m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml);
74 }
75
76 // WARNING: this is temporary for experimentation only, it will be removed!!!!
77 public OSDMap TopLevelMap
78 {
79 get { return m_map; }
80 set { m_map = value; }
81 }
82
83
84 public void ReadXml(XmlReader reader)
85 {
86 ReadXml(reader.ReadInnerXml());
87 }
88
89 public string ToXml()
90 {
91 lock (this)
92 return OSDParser.SerializeLLSDXmlString(m_map);
93 }
94
95 public void WriteXml(XmlWriter writer)
96 {
97 writer.WriteRaw(ToXml());
98 }
99
100 public void CopyFrom(DAMap other)
101 {
102 // Deep copy
103
104 string data = null;
105 lock (other)
106 {
107 if (other.Count > 0)
108 {
109 data = OSDParser.SerializeLLSDXmlString(other.m_map);
110 }
111 }
112
113 lock (this)
114 {
115 if (data == null)
116 Clear();
117 else
118 m_map = (OSDMap)OSDParser.DeserializeLLSDXml(data);
119 }
120 }
121
122 /// <summary>
123 /// Returns the number of data stores.
124 /// </summary>
125 public int Count { get { lock (this) { return m_map.Count; } } }
126
127 public bool IsReadOnly { get { return false; } }
128
129 /// <summary>
130 /// Returns the names of the data stores.
131 /// </summary>
132 public ICollection<string> Keys { get { lock (this) { return m_map.Keys; } } }
133
134 /// <summary>
135 /// Returns all the data stores.
136 /// </summary>
137 public ICollection<OSDMap> Values
138 {
139 get
140 {
141 lock (this)
142 {
143 List<OSDMap> stores = new List<OSDMap>(m_map.Count);
144 foreach (OSD llsd in m_map.Values)
145 stores.Add((OSDMap)llsd);
146 return stores;
147 }
148 }
149 }
150
151 /// <summary>
152 /// Gets or sets one data store.
153 /// </summary>
154 /// <param name="key">Store name</param>
155 /// <returns></returns>
156 public OSDMap this[string key]
157 {
158 get
159 {
160 OSD llsd;
161
162 lock (this)
163 {
164 if (m_map.TryGetValue(key, out llsd))
165 return (OSDMap)llsd;
166 else
167 return null;
168 }
169 }
170
171 set
172 {
173 ValidateKey(key);
174 lock (this)
175 m_map[key] = value;
176 }
177 }
178
179 /// <summary>
180 /// Validate the key used for storing separate data stores.
181 /// </summary>
182 /// <param name='key'></param>
183 private static void ValidateKey(string key)
184 {
185 if (key.Length < MIN_STORE_NAME_LENGTH)
186 throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH);
187 }
188
189 public bool ContainsKey(string key)
190 {
191 lock (this)
192 return m_map.ContainsKey(key);
193 }
194
195 public void Add(string key, OSDMap store)
196 {
197 ValidateKey(key);
198 lock (this)
199 m_map.Add(key, store);
200 }
201
202 public void Add(KeyValuePair<string, OSDMap> kvp)
203 {
204 ValidateKey(kvp.Key);
205 lock (this)
206 m_map.Add(kvp.Key, kvp.Value);
207 }
208
209 public bool Remove(string key)
210 {
211 lock (this)
212 return m_map.Remove(key);
213 }
214
215 public bool TryGetValue(string key, out OSDMap store)
216 {
217 lock (this)
218 {
219 OSD llsd;
220 if (m_map.TryGetValue(key, out llsd))
221 {
222 store = (OSDMap)llsd;
223 return true;
224 }
225 else
226 {
227 store = null;
228 return false;
229 }
230 }
231 }
232
233 public void Clear()
234 {
235 lock (this)
236 m_map.Clear();
237 }
238
239 public bool Contains(KeyValuePair<string, OSDMap> kvp)
240 {
241 lock (this)
242 return m_map.ContainsKey(kvp.Key);
243 }
244
245 public void CopyTo(KeyValuePair<string, OSDMap>[] array, int index)
246 {
247 throw new NotImplementedException();
248 }
249
250 public bool Remove(KeyValuePair<string, OSDMap> kvp)
251 {
252 lock (this)
253 return m_map.Remove(kvp.Key);
254 }
255
256 public System.Collections.IDictionaryEnumerator GetEnumerator()
257 {
258 lock (this)
259 return m_map.GetEnumerator();
260 }
261
262 IEnumerator<KeyValuePair<string, OSDMap>> IEnumerable<KeyValuePair<string, OSDMap>>.GetEnumerator()
263 {
264 return null;
265 }
266
267 IEnumerator IEnumerable.GetEnumerator()
268 {
269 lock (this)
270 return m_map.GetEnumerator();
271 }
272 }
273} \ No newline at end of file
diff --git a/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs
new file mode 100644
index 0000000..9056548
--- /dev/null
+++ b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs
@@ -0,0 +1,508 @@
1/*
2 * Copyright (c) 2008, openmetaverse.org, http://opensimulator.org/
3 * All rights reserved.
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 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27using System;
28using System.Threading;
29using System.Collections.Generic;
30
31namespace OpenSim.Framework
32{
33 /// <summary>
34 /// A double dictionary that is thread abort safe.
35 /// </summary>
36 /// <remarks>
37 /// This adapts OpenMetaverse.DoubleDictionary to be thread-abort safe by acquiring ReaderWriterLockSlim within
38 /// a finally section (which can't be interrupted by Thread.Abort()).
39 /// </remarks>
40 public class DoubleDictionaryThreadAbortSafe<TKey1, TKey2, TValue>
41 {
42 Dictionary<TKey1, TValue> Dictionary1;
43 Dictionary<TKey2, TValue> Dictionary2;
44 ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
45
46 public DoubleDictionaryThreadAbortSafe()
47 {
48 Dictionary1 = new Dictionary<TKey1,TValue>();
49 Dictionary2 = new Dictionary<TKey2,TValue>();
50 }
51
52 public DoubleDictionaryThreadAbortSafe(int capacity)
53 {
54 Dictionary1 = new Dictionary<TKey1, TValue>(capacity);
55 Dictionary2 = new Dictionary<TKey2, TValue>(capacity);
56 }
57
58 public void Add(TKey1 key1, TKey2 key2, TValue value)
59 {
60 bool gotLock = false;
61
62 try
63 {
64 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
65 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
66 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
67 try {}
68 finally
69 {
70 rwLock.EnterWriteLock();
71 gotLock = true;
72 }
73
74 if (Dictionary1.ContainsKey(key1))
75 {
76 if (!Dictionary2.ContainsKey(key2))
77 throw new ArgumentException("key1 exists in the dictionary but not key2");
78 }
79 else if (Dictionary2.ContainsKey(key2))
80 {
81 if (!Dictionary1.ContainsKey(key1))
82 throw new ArgumentException("key2 exists in the dictionary but not key1");
83 }
84
85 Dictionary1[key1] = value;
86 Dictionary2[key2] = value;
87 }
88 finally
89 {
90 if (gotLock)
91 rwLock.ExitWriteLock();
92 }
93 }
94
95 public bool Remove(TKey1 key1, TKey2 key2)
96 {
97 bool success;
98 bool gotLock = false;
99
100 try
101 {
102 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
103 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
104 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
105 try {}
106 finally
107 {
108 rwLock.EnterWriteLock();
109 gotLock = true;
110 }
111
112 Dictionary1.Remove(key1);
113 success = Dictionary2.Remove(key2);
114 }
115 finally
116 {
117 if (gotLock)
118 rwLock.ExitWriteLock();
119 }
120
121 return success;
122 }
123
124 public bool Remove(TKey1 key1)
125 {
126 bool found = false;
127 bool gotLock = false;
128
129 try
130 {
131 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
132 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
133 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
134 try {}
135 finally
136 {
137 rwLock.EnterWriteLock();
138 gotLock = true;
139 }
140
141 // This is an O(n) operation!
142 TValue value;
143 if (Dictionary1.TryGetValue(key1, out value))
144 {
145 foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
146 {
147 if (kvp.Value.Equals(value))
148 {
149 Dictionary1.Remove(key1);
150 Dictionary2.Remove(kvp.Key);
151 found = true;
152 break;
153 }
154 }
155 }
156 }
157 finally
158 {
159 if (gotLock)
160 rwLock.ExitWriteLock();
161 }
162
163 return found;
164 }
165
166 public bool Remove(TKey2 key2)
167 {
168 bool found = false;
169 bool gotLock = false;
170
171 try
172 {
173 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
174 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
175 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
176 try {}
177 finally
178 {
179 rwLock.EnterWriteLock();
180 gotLock = true;
181 }
182
183 // This is an O(n) operation!
184 TValue value;
185 if (Dictionary2.TryGetValue(key2, out value))
186 {
187 foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
188 {
189 if (kvp.Value.Equals(value))
190 {
191 Dictionary2.Remove(key2);
192 Dictionary1.Remove(kvp.Key);
193 found = true;
194 break;
195 }
196 }
197 }
198 }
199 finally
200 {
201 if (gotLock)
202 rwLock.ExitWriteLock();
203 }
204
205 return found;
206 }
207
208 public void Clear()
209 {
210 bool gotLock = false;
211
212 try
213 {
214 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
215 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
216 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
217 try {}
218 finally
219 {
220 rwLock.EnterWriteLock();
221 gotLock = true;
222 }
223
224 Dictionary1.Clear();
225 Dictionary2.Clear();
226 }
227 finally
228 {
229 if (gotLock)
230 rwLock.ExitWriteLock();
231 }
232 }
233
234 public int Count
235 {
236 get { return Dictionary1.Count; }
237 }
238
239 public bool ContainsKey(TKey1 key)
240 {
241 return Dictionary1.ContainsKey(key);
242 }
243
244 public bool ContainsKey(TKey2 key)
245 {
246 return Dictionary2.ContainsKey(key);
247 }
248
249 public bool TryGetValue(TKey1 key, out TValue value)
250 {
251 bool success;
252 bool gotLock = false;
253
254 try
255 {
256 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
257 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
258 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
259 try {}
260 finally
261 {
262 rwLock.EnterReadLock();
263 gotLock = true;
264 }
265
266 success = Dictionary1.TryGetValue(key, out value);
267 }
268 finally
269 {
270 if (gotLock)
271 rwLock.ExitReadLock();
272 }
273
274 return success;
275 }
276
277 public bool TryGetValue(TKey2 key, out TValue value)
278 {
279 bool success;
280 bool gotLock = false;
281
282 try
283 {
284 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
285 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
286 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
287 try {}
288 finally
289 {
290 rwLock.EnterReadLock();
291 gotLock = true;
292 }
293
294 success = Dictionary2.TryGetValue(key, out value);
295 }
296 finally
297 {
298 if (gotLock)
299 rwLock.ExitReadLock();
300 }
301
302 return success;
303 }
304
305 public void ForEach(Action<TValue> action)
306 {
307 bool gotLock = false;
308
309 try
310 {
311 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
312 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
313 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
314 try {}
315 finally
316 {
317 rwLock.EnterReadLock();
318 gotLock = true;
319 }
320
321 foreach (TValue value in Dictionary1.Values)
322 action(value);
323 }
324 finally
325 {
326 if (gotLock)
327 rwLock.ExitReadLock();
328 }
329 }
330
331 public void ForEach(Action<KeyValuePair<TKey1, TValue>> action)
332 {
333 bool gotLock = false;
334
335 try
336 {
337 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
338 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
339 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
340 try {}
341 finally
342 {
343 rwLock.EnterReadLock();
344 gotLock = true;
345 }
346
347 foreach (KeyValuePair<TKey1, TValue> entry in Dictionary1)
348 action(entry);
349 }
350 finally
351 {
352 if (gotLock)
353 rwLock.ExitReadLock();
354 }
355 }
356
357 public void ForEach(Action<KeyValuePair<TKey2, TValue>> action)
358 {
359 bool gotLock = false;
360
361 try
362 {
363 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
364 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
365 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
366 try {}
367 finally
368 {
369 rwLock.EnterReadLock();
370 gotLock = true;
371 }
372
373 foreach (KeyValuePair<TKey2, TValue> entry in Dictionary2)
374 action(entry);
375 }
376 finally
377 {
378 if (gotLock)
379 rwLock.ExitReadLock();
380 }
381 }
382
383 public TValue FindValue(Predicate<TValue> predicate)
384 {
385 bool gotLock = false;
386
387 try
388 {
389 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
390 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
391 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
392 try {}
393 finally
394 {
395 rwLock.EnterReadLock();
396 gotLock = true;
397 }
398
399 foreach (TValue value in Dictionary1.Values)
400 {
401 if (predicate(value))
402 return value;
403 }
404 }
405 finally
406 {
407 if (gotLock)
408 rwLock.ExitReadLock();
409 }
410
411 return default(TValue);
412 }
413
414 public IList<TValue> FindAll(Predicate<TValue> predicate)
415 {
416 IList<TValue> list = new List<TValue>();
417 bool gotLock = false;
418
419 try
420 {
421 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
422 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
423 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
424 try {}
425 finally
426 {
427 rwLock.EnterReadLock();
428 gotLock = true;
429 }
430
431 foreach (TValue value in Dictionary1.Values)
432 {
433 if (predicate(value))
434 list.Add(value);
435 }
436 }
437 finally
438 {
439 if (gotLock)
440 rwLock.ExitReadLock();
441 }
442
443 return list;
444 }
445
446 public int RemoveAll(Predicate<TValue> predicate)
447 {
448 IList<TKey1> list = new List<TKey1>();
449 bool gotUpgradeableLock = false;
450
451 try
452 {
453 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
454 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
455 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
456 try {}
457 finally
458 {
459 rwLock.EnterUpgradeableReadLock();
460 gotUpgradeableLock = true;
461 }
462
463 foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
464 {
465 if (predicate(kvp.Value))
466 list.Add(kvp.Key);
467 }
468
469 IList<TKey2> list2 = new List<TKey2>(list.Count);
470 foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
471 {
472 if (predicate(kvp.Value))
473 list2.Add(kvp.Key);
474 }
475
476 bool gotWriteLock = false;
477
478 try
479 {
480 try {}
481 finally
482 {
483 rwLock.EnterUpgradeableReadLock();
484 gotWriteLock = true;
485 }
486
487 for (int i = 0; i < list.Count; i++)
488 Dictionary1.Remove(list[i]);
489
490 for (int i = 0; i < list2.Count; i++)
491 Dictionary2.Remove(list2[i]);
492 }
493 finally
494 {
495 if (gotWriteLock)
496 rwLock.ExitWriteLock();
497 }
498 }
499 finally
500 {
501 if (gotUpgradeableLock)
502 rwLock.ExitUpgradeableReadLock();
503 }
504
505 return list.Count;
506 }
507 }
508} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs
index 1f2bb40..bb83db1 100644
--- a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Monitoring/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.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/PluginManager.cs b/OpenSim/Framework/PluginManager.cs
new file mode 100644
index 0000000..00263f5
--- /dev/null
+++ b/OpenSim/Framework/PluginManager.cs
@@ -0,0 +1,563 @@
1
2/*
3 * Copyright (c) Contributors, http://opensimulator.org/
4 * See CONTRIBUTORS.TXT for a full list of copyright holders.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the OpenSimulator Project nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29
30using System;
31using System.Text;
32using System.Linq;
33using System.Collections;
34using System.Collections.Generic;
35using System.Collections.ObjectModel;
36using Mono.Addins;
37using Mono.Addins.Setup;
38using Mono.Addins.Description;
39using OpenSim.Framework;
40
41
42namespace OpenSim.Framework
43{
44 /// <summary>
45 /// Manager for registries and plugins
46 /// </summary>
47 public class PluginManager : SetupService
48 {
49 public AddinRegistry PluginRegistry;
50
51 public PluginManager(AddinRegistry registry): base (registry)
52 {
53 PluginRegistry = registry;
54
55 }
56
57 /// <summary>
58 /// Installs the plugin.
59 /// </summary>
60 /// <returns>
61 /// The plugin.
62 /// </returns>
63 /// <param name='args'>
64 /// Arguments.
65 /// </param>
66 public bool InstallPlugin(int ndx, out Dictionary<string, object> result)
67 {
68 Dictionary<string, object> res = new Dictionary<string, object>();
69
70 PackageCollection pack = new PackageCollection();
71 PackageCollection toUninstall;
72 DependencyCollection unresolved;
73
74 IProgressStatus ps = new ConsoleProgressStatus(false);
75
76 AddinRepositoryEntry[] available = GetSortedAvailbleAddins();
77
78 if (ndx > (available.Length - 1))
79 {
80 MainConsole.Instance.Output("Selection out of range");
81 result = res;
82 return false;
83 }
84
85 AddinRepositoryEntry aentry = available[ndx];
86
87 Package p = Package.FromRepository(aentry);
88 pack.Add(p);
89
90 ResolveDependencies(ps, pack, out toUninstall, out unresolved);
91
92 // Attempt to install the plugin disabled
93 if (Install(ps, pack) == true)
94 {
95 MainConsole.Instance.Output("Ignore the following error...");
96 PluginRegistry.Update(ps);
97 Addin addin = PluginRegistry.GetAddin(aentry.Addin.Id);
98 PluginRegistry.DisableAddin(addin.Id);
99 addin.Enabled = false;
100
101 MainConsole.Instance.Output("Installation Success");
102 ListInstalledAddins(out res);
103 result = res;
104 return true;
105 }
106 else
107 {
108 MainConsole.Instance.Output("Installation Failed");
109 result = res;
110 return false;
111 }
112 }
113
114 // Remove plugin
115 /// <summary>
116 /// Uns the install.
117 /// </summary>
118 /// <param name='args'>
119 /// Arguments.
120 /// </param>
121 public void UnInstall(int ndx)
122 {
123 Addin[] addins = GetSortedAddinList("RobustPlugin");
124
125 if (ndx > (addins.Length -1))
126 {
127 MainConsole.Instance.Output("Selection out of range");
128 return;
129 }
130
131 Addin addin = addins[ndx];
132 MainConsole.Instance.OutputFormat("Uninstalling plugin {0}", addin.Id);
133 AddinManager.Registry.DisableAddin(addin.Id);
134 addin.Enabled = false;
135 IProgressStatus ps = new ConsoleProgressStatus(false);
136 Uninstall(ps, addin.Id);
137 MainConsole.Instance.Output("Uninstall Success - restart to complete operation");
138 return;
139 }
140
141 /// <summary>
142 /// Checks the installed.
143 /// </summary>
144 /// <returns>
145 /// The installed.
146 /// </returns>
147 public string CheckInstalled()
148 {
149 return "CheckInstall";
150 }
151
152 /// <summary>
153 /// Lists the installed addins.
154 /// </summary>
155 /// <param name='result'>
156 /// Result.
157 /// </param>
158 public void ListInstalledAddins(out Dictionary<string, object> result)
159 {
160 Dictionary<string, object> res = new Dictionary<string, object>();
161
162 Addin[] addins = GetSortedAddinList("RobustPlugin");
163 if(addins.Count() < 1)
164 {
165 MainConsole.Instance.Output("Error!");
166 }
167 int count = 0;
168 foreach (Addin addin in addins)
169 {
170 Dictionary<string, object> r = new Dictionary<string, object>();
171 r["enabled"] = addin.Enabled == true ? true : false;
172 r["name"] = addin.LocalId;
173 r["version"] = addin.Version;
174
175 res.Add(count.ToString(), r);
176
177 count++;
178 }
179 result = res;
180 return;
181 }
182
183 // List compatible plugins in registered repositories
184 /// <summary>
185 /// Lists the available.
186 /// </summary>
187 /// <param name='result'>
188 /// Result.
189 /// </param>
190 public void ListAvailable(out Dictionary<string, object> result)
191 {
192 Dictionary<string, object> res = new Dictionary<string, object>();
193
194 AddinRepositoryEntry[] addins = GetSortedAvailbleAddins();
195
196 int count = 0;
197 foreach (AddinRepositoryEntry addin in addins)
198 {
199 Dictionary<string, object> r = new Dictionary<string, object>();
200 r["name"] = addin.Addin.Name;
201 r["version"] = addin.Addin.Version;
202 r["repository"] = addin.RepositoryName;
203
204 res.Add(count.ToString(), r);
205 count++;
206 }
207 result = res;
208 return;
209 }
210
211 // List available updates ** 1
212 /// <summary>
213 /// Lists the updates.
214 /// </summary>
215 public void ListUpdates()
216 {
217 IProgressStatus ps = new ConsoleProgressStatus(true);
218 Console.WriteLine ("Looking for updates...");
219 Repositories.UpdateAllRepositories (ps);
220 Console.WriteLine ("Available add-in updates:");
221 bool found = false;
222 AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates();
223
224 foreach (AddinRepositoryEntry entry in entries)
225 {
226 Console.WriteLine(String.Format("{0}",entry.Addin.Id));
227 }
228 }
229
230 // Sync to repositories
231 /// <summary>
232 /// Update this instance.
233 /// </summary>
234 public string Update()
235 {
236 IProgressStatus ps = new ConsoleProgressStatus(true);
237 Repositories.UpdateAllRepositories(ps);
238 return "Update";
239 }
240
241 // Register a repository
242 /// <summary>
243 /// Register a repository with our server.
244 /// </summary>
245 /// <returns>
246 /// result of the action
247 /// </returns>
248 /// <param name='repo'>
249 /// The URL of the repository we want to add
250 /// </param>
251 public bool AddRepository(string repo)
252 {
253 Repositories.RegisterRepository(null, repo, true);
254 PluginRegistry.Rebuild(null);
255
256 return true;
257 }
258
259 /// <summary>
260 /// Gets the repository.
261 /// </summary>
262 public void GetRepository()
263 {
264 Repositories.UpdateAllRepositories(new ConsoleProgressStatus(false));
265 }
266
267 // Remove a repository from the list
268 /// <summary>
269 /// Removes the repository.
270 /// </summary>
271 /// <param name='args'>
272 /// Arguments.
273 /// </param>
274 public void RemoveRepository(string[] args)
275 {
276 AddinRepository[] reps = Repositories.GetRepositories();
277 Array.Sort(reps, (r1,r2) => r1.Title.CompareTo(r2.Title));
278 if (reps.Length == 0)
279 {
280 MainConsole.Instance.Output("No repositories have been registered.");
281 return;
282 }
283
284 int n = Convert.ToInt16(args[2]);
285 if (n > (reps.Length -1))
286 {
287 MainConsole.Instance.Output("Selection out of range");
288 return;
289 }
290
291 AddinRepository rep = reps[n];
292 Repositories.RemoveRepository(rep.Url);
293 return;
294 }
295
296 // Enable repository
297 /// <summary>
298 /// Enables the repository.
299 /// </summary>
300 /// <param name='args'>
301 /// Arguments.
302 /// </param>
303 public void EnableRepository(string[] args)
304 {
305 AddinRepository[] reps = Repositories.GetRepositories();
306 Array.Sort(reps, (r1,r2) => r1.Title.CompareTo(r2.Title));
307 if (reps.Length == 0)
308 {
309 MainConsole.Instance.Output("No repositories have been registered.");
310 return;
311 }
312
313 int n = Convert.ToInt16(args[2]);
314 if (n > (reps.Length -1))
315 {
316 MainConsole.Instance.Output("Selection out of range");
317 return;
318 }
319
320 AddinRepository rep = reps[n];
321 Repositories.SetRepositoryEnabled(rep.Url, true);
322 return;
323 }
324
325 // Disable a repository
326 /// <summary>
327 /// Disables the repository.
328 /// </summary>
329 /// <param name='args'>
330 /// Arguments.
331 /// </param>
332 public void DisableRepository(string[] args)
333 {
334 AddinRepository[] reps = Repositories.GetRepositories();
335 Array.Sort(reps, (r1,r2) => r1.Title.CompareTo(r2.Title));
336 if (reps.Length == 0)
337 {
338 MainConsole.Instance.Output("No repositories have been registered.");
339 return;
340 }
341
342 int n = Convert.ToInt16(args[2]);
343 if (n > (reps.Length -1))
344 {
345 MainConsole.Instance.Output("Selection out of range");
346 return;
347 }
348
349 AddinRepository rep = reps[n];
350 Repositories.SetRepositoryEnabled(rep.Url, false);
351 return;
352 }
353
354 // List registered repositories
355 /// <summary>
356 /// Lists the repositories.
357 /// </summary>
358 /// <param name='result'>
359 /// Result.
360 /// </param>
361 public void ListRepositories(out Dictionary<string, object> result)
362 {
363 Dictionary<string, object> res = new Dictionary<string, object>();
364 result = res;
365
366 AddinRepository[] reps = GetSortedAddinRepo();
367 if (reps.Length == 0)
368 {
369 MainConsole.Instance.Output("No repositories have been registered.");
370 return;
371 }
372
373 int count = 0;
374 foreach (AddinRepository rep in reps)
375 {
376 Dictionary<string, object> r = new Dictionary<string, object>();
377 r["enabled"] = rep.Enabled == true ? true : false;
378 r["name"] = rep.Name;
379 r["url"] = rep.Url;
380
381 res.Add(count.ToString(), r);
382 count++;
383 }
384 return;
385 }
386
387 /// <summary>
388 /// Updates the registry.
389 /// </summary>
390 public void UpdateRegistry()
391 {
392 PluginRegistry.Update();
393 }
394
395 // Show plugin info
396 /// <summary>
397 /// Addins the info.
398 /// </summary>
399 /// <returns>
400 /// The info.
401 /// </returns>
402 /// <param name='args'>
403 /// Arguments.
404 /// </param>
405 public bool AddinInfo(int ndx, out Dictionary<string, object> result)
406 {
407 Dictionary<string, object> res = new Dictionary<string, object>();
408 result = res;
409
410 Addin[] addins = GetSortedAddinList("RobustPlugin");
411
412 if (ndx > (addins.Length - 1))
413 {
414 MainConsole.Instance.Output("Selection out of range");
415 return false;
416 }
417 // author category description
418 Addin addin = addins[ndx];
419
420 res["author"] = addin.Description.Author;
421 res["category"] = addin.Description.Category;
422 res["description"] = addin.Description.Description;
423 res["name"] = addin.Name;
424 res["url"] = addin.Description.Url;
425 res["file_name"] = addin.Description.FileName;
426
427 result = res;
428 return true;
429 }
430
431 // Disable a plugin
432 /// <summary>
433 /// Disables the plugin.
434 /// </summary>
435 /// <param name='args'>
436 /// Arguments.
437 /// </param>
438 public void DisablePlugin(string[] args)
439 {
440 Addin[] addins = GetSortedAddinList("RobustPlugin");
441
442 int n = Convert.ToInt16(args[2]);
443 if (n > (addins.Length -1))
444 {
445 MainConsole.Instance.Output("Selection out of range");
446 return;
447 }
448
449 Addin addin = addins[n];
450 AddinManager.Registry.DisableAddin(addin.Id);
451 addin.Enabled = false;
452 return;
453 }
454
455 // Enable plugin
456 /// <summary>
457 /// Enables the plugin.
458 /// </summary>
459 /// <param name='args'>
460 /// Arguments.
461 /// </param>
462 public void EnablePlugin(string[] args)
463 {
464 Addin[] addins = GetSortedAddinList("RobustPlugin");
465
466 int n = Convert.ToInt16(args[2]);
467 if (n > (addins.Length -1))
468 {
469 MainConsole.Instance.Output("Selection out of range");
470 return;
471 }
472
473 Addin addin = addins[n];
474
475 addin.Enabled = true;
476 AddinManager.Registry.EnableAddin(addin.Id);
477 // AddinManager.Registry.Update();
478 if(PluginRegistry.IsAddinEnabled(addin.Id))
479 {
480 ConsoleProgressStatus ps = new ConsoleProgressStatus(false);
481 if (!AddinManager.AddinEngine.IsAddinLoaded(addin.Id))
482 {
483 MainConsole.Instance.Output("Ignore the following error...");
484 AddinManager.Registry.Rebuild(ps);
485 AddinManager.AddinEngine.LoadAddin(ps, addin.Id);
486 }
487 }
488 else
489 {
490 MainConsole.Instance.OutputFormat("Not Enabled in this domain {0}", addin.Name);
491 }
492 return;
493 }
494
495
496
497 #region Util
498 private void Testing()
499 {
500 Addin[] list = Registry.GetAddins();
501
502 var addins = list.Where( a => a.Description.Category == "RobustPlugin");
503
504 foreach (Addin addin in addins)
505 {
506 MainConsole.Instance.OutputFormat("Addin {0}", addin.Name);
507 }
508 }
509
510 // These will let us deal with numbered lists instead
511 // of needing to type in the full ids
512 private AddinRepositoryEntry[] GetSortedAvailbleAddins()
513 {
514 ArrayList list = new ArrayList();
515 list.AddRange(Repositories.GetAvailableAddins());
516
517 AddinRepositoryEntry[] addins = list.ToArray(typeof(AddinRepositoryEntry)) as AddinRepositoryEntry[];
518
519 Array.Sort(addins,(r1,r2) => r1.Addin.Id.CompareTo(r2.Addin.Id));
520
521 return addins;
522 }
523
524 private AddinRepository[] GetSortedAddinRepo()
525 {
526 ArrayList list = new ArrayList();
527 list.AddRange(Repositories.GetRepositories());
528
529 AddinRepository[] repos = list.ToArray(typeof(AddinRepository)) as AddinRepository[];
530 Array.Sort (repos,(r1,r2) => r1.Name.CompareTo(r2.Name));
531
532 return repos;
533 }
534
535 private Addin[] GetSortedAddinList(string category)
536 {
537
538 ArrayList xlist = new ArrayList();
539 ArrayList list = new ArrayList();
540 try
541 {
542 list.AddRange(PluginRegistry.GetAddins());
543 }
544 catch(Exception e)
545 {
546 Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[];
547 return x;
548 }
549
550 foreach (Addin addin in list)
551 {
552 if (addin.Description.Category == category)
553 xlist.Add(addin);
554 }
555
556 Addin[] addins = xlist.ToArray(typeof(Addin)) as Addin[];
557 Array.Sort(addins,(r1,r2) => r1.Id.CompareTo(r2.Id));
558
559 return addins;
560 }
561 #endregion Util
562 }
563}
diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs
index fcc9873..df928dc 100644
--- a/OpenSim/Framework/PrimitiveBaseShape.cs
+++ b/OpenSim/Framework/PrimitiveBaseShape.cs
@@ -192,18 +192,7 @@ namespace OpenSim.Framework
192 192
193 public PrimitiveBaseShape() 193 public PrimitiveBaseShape()
194 { 194 {
195 PCode = (byte) PCodeEnum.Primitive;
196 ExtraParams = new byte[1];
197 m_textureEntry = DEFAULT_TEXTURE;
198 }
199
200 public PrimitiveBaseShape(bool noShape)
201 {
202 if (noShape)
203 return;
204
205 PCode = (byte)PCodeEnum.Primitive; 195 PCode = (byte)PCodeEnum.Primitive;
206 ExtraParams = new byte[1];
207 m_textureEntry = DEFAULT_TEXTURE; 196 m_textureEntry = DEFAULT_TEXTURE;
208 } 197 }
209 198
@@ -216,7 +205,6 @@ namespace OpenSim.Framework
216// m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID); 205// m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID);
217 206
218 PCode = (byte)prim.PrimData.PCode; 207 PCode = (byte)prim.PrimData.PCode;
219 ExtraParams = new byte[1];
220 208
221 State = prim.PrimData.State; 209 State = prim.PrimData.State;
222 PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin); 210 PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
@@ -248,7 +236,10 @@ namespace OpenSim.Framework
248 SculptTexture = prim.Sculpt.SculptTexture; 236 SculptTexture = prim.Sculpt.SculptTexture;
249 SculptType = (byte)prim.Sculpt.Type; 237 SculptType = (byte)prim.Sculpt.Type;
250 } 238 }
251 else SculptType = (byte)OpenMetaverse.SculptType.None; 239 else
240 {
241 SculptType = (byte)OpenMetaverse.SculptType.None;
242 }
252 } 243 }
253 244
254 [XmlIgnore] 245 [XmlIgnore]
@@ -340,9 +331,9 @@ namespace OpenSim.Framework
340 _scale = new Vector3(side, side, side); 331 _scale = new Vector3(side, side, side);
341 } 332 }
342 333
343 public void SetHeigth(float heigth) 334 public void SetHeigth(float height)
344 { 335 {
345 _scale.Z = heigth; 336 _scale.Z = height;
346 } 337 }
347 338
348 public void SetRadius(float radius) 339 public void SetRadius(float radius)
@@ -631,6 +622,8 @@ namespace OpenSim.Framework
631 } 622 }
632 } 623 }
633 624
625 // This is only used at runtime. For sculpties this holds the texture data, and for meshes
626 // the mesh data.
634 public byte[] SculptData 627 public byte[] SculptData
635 { 628 {
636 get 629 get
@@ -1184,14 +1177,13 @@ namespace OpenSim.Framework
1184 1177
1185 public void ReadSculptData(byte[] data, int pos) 1178 public void ReadSculptData(byte[] data, int pos)
1186 { 1179 {
1187 byte[] SculptTextureUUID = new byte[16]; 1180 UUID SculptUUID;
1188 UUID SculptUUID = UUID.Zero; 1181 byte SculptTypel;
1189 byte SculptTypel = data[16+pos];
1190 1182
1191 if (data.Length+pos >= 17) 1183 if (data.Length-pos >= 17)
1192 { 1184 {
1193 _sculptEntry = true; 1185 _sculptEntry = true;
1194 SculptTextureUUID = new byte[16]; 1186 byte[] SculptTextureUUID = new byte[16];
1195 SculptTypel = data[16 + pos]; 1187 SculptTypel = data[16 + pos];
1196 Array.Copy(data, pos, SculptTextureUUID,0, 16); 1188 Array.Copy(data, pos, SculptTextureUUID,0, 16);
1197 SculptUUID = new UUID(SculptTextureUUID, 0); 1189 SculptUUID = new UUID(SculptTextureUUID, 0);
diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs
index e7bed6a..6dde62f 100644
--- a/OpenSim/Framework/RegionInfo.cs
+++ b/OpenSim/Framework/RegionInfo.cs
@@ -145,6 +145,7 @@ namespace OpenSim.Framework
145 public UUID RegionID = UUID.Zero; 145 public UUID RegionID = UUID.Zero;
146 public string RemotingAddress; 146 public string RemotingAddress;
147 public UUID ScopeID = UUID.Zero; 147 public UUID ScopeID = UUID.Zero;
148 private UUID m_maptileStaticUUID = UUID.Zero;
148 149
149 private Dictionary<String, String> m_otherSettings = new Dictionary<string, string>(); 150 private Dictionary<String, String> m_otherSettings = new Dictionary<string, string>();
150 151
@@ -340,6 +341,11 @@ namespace OpenSim.Framework
340 get { return m_regionType; } 341 get { return m_regionType; }
341 } 342 }
342 343
344 public UUID MaptileStaticUUID
345 {
346 get { return m_maptileStaticUUID; }
347 }
348
343 /// <summary> 349 /// <summary>
344 /// The port by which http communication occurs with the region (most noticeably, CAPS communication) 350 /// The port by which http communication occurs with the region (most noticeably, CAPS communication)
345 /// </summary> 351 /// </summary>
@@ -643,7 +649,7 @@ namespace OpenSim.Framework
643 m_regionType = config.GetString("RegionType", String.Empty); 649 m_regionType = config.GetString("RegionType", String.Empty);
644 allKeys.Remove("RegionType"); 650 allKeys.Remove("RegionType");
645 651
646 #region Prim stuff 652 #region Prim and map stuff
647 653
648 m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0); 654 m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0);
649 allKeys.Remove("NonPhysicalPrimMin"); 655 allKeys.Remove("NonPhysicalPrimMin");
@@ -665,6 +671,13 @@ namespace OpenSim.Framework
665 671
666 m_linksetCapacity = config.GetInt("LinksetPrims", 0); 672 m_linksetCapacity = config.GetInt("LinksetPrims", 0);
667 allKeys.Remove("LinksetPrims"); 673 allKeys.Remove("LinksetPrims");
674
675 allKeys.Remove("MaptileStaticUUID");
676 string mapTileStaticUUID = config.GetString("MaptileStaticUUID", UUID.Zero.ToString());
677 if (UUID.TryParse(mapTileStaticUUID.Trim(), out m_maptileStaticUUID))
678 {
679 config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString());
680 }
668 681
669 #endregion 682 #endregion
670 683
@@ -734,6 +747,9 @@ namespace OpenSim.Framework
734 747
735 if (RegionType != String.Empty) 748 if (RegionType != String.Empty)
736 config.Set("RegionType", RegionType); 749 config.Set("RegionType", RegionType);
750
751 if (m_maptileStaticUUID != UUID.Zero)
752 config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString());
737 } 753 }
738 754
739 public bool ignoreIncomingConfiguration(string configuration_key, object configuration_result) 755 public bool ignoreIncomingConfiguration(string configuration_key, object configuration_result)
@@ -832,6 +848,9 @@ namespace OpenSim.Framework
832 848
833 configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING, 849 configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING,
834 "Free form string describing the type of region", String.Empty, true); 850 "Free form string describing the type of region", String.Empty, true);
851
852 configMember.addConfigurationOption("region_static_maptile", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
853 "UUID of a texture to use as the map for this region", m_maptileStaticUUID.ToString(), true);
835 } 854 }
836 855
837 public void loadConfigurationOptions() 856 public void loadConfigurationOptions()
@@ -885,6 +904,9 @@ namespace OpenSim.Framework
885 904
886 configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING, 905 configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING,
887 "Region Type", String.Empty, true); 906 "Region Type", String.Empty, true);
907
908 configMember.addConfigurationOption("region_static_maptile", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
909 "UUID of a texture to use as the map for this region", String.Empty, true);
888 } 910 }
889 911
890 public bool handleIncomingConfiguration(string configuration_key, object configuration_result) 912 public bool handleIncomingConfiguration(string configuration_key, object configuration_result)
@@ -957,6 +979,9 @@ namespace OpenSim.Framework
957 case "region_type": 979 case "region_type":
958 m_regionType = (string)configuration_result; 980 m_regionType = (string)configuration_result;
959 break; 981 break;
982 case "region_static_maptile":
983 m_maptileStaticUUID = (UUID)configuration_result;
984 break;
960 } 985 }
961 986
962 return true; 987 return true;
diff --git a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs
index d670f2f..f836350 100644
--- a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/RegionLoader/Filesystem/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.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs
index 7309a12..72fa679 100644
--- a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/RegionLoader/Web/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.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs
index 48f1c4f..0c12787 100644
--- a/OpenSim/Framework/Serialization/ArchiveConstants.cs
+++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs
@@ -154,6 +154,11 @@ namespace OpenSim.Framework.Serialization
154 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder; 154 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder;
155 } 155 }
156 156
157 public static string CreateOarLandDataPath(LandData ld)
158 {
159 return string.Format("{0}{1}.xml", ArchiveConstants.LANDDATA_PATH, ld.GlobalID);
160 }
161
157 /// <summary> 162 /// <summary>
158 /// Create the filename used to store an object in an OpenSim Archive. 163 /// Create the filename used to store an object in an OpenSim Archive.
159 /// </summary> 164 /// </summary>
diff --git a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs
index 11efa4b..7a122da 100644
--- a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Serialization/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.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs b/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs
index 8b9756b..ea100ee 100644
--- a/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs
+++ b/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs
@@ -37,7 +37,7 @@ using OpenSim.Tests.Common;
37namespace OpenSim.Framework.Serialization.Tests 37namespace OpenSim.Framework.Serialization.Tests
38{ 38{
39 [TestFixture] 39 [TestFixture]
40 public class LandDataSerializerTest 40 public class LandDataSerializerTest : OpenSimTestCase
41 { 41 {
42 private LandData land; 42 private LandData land;
43 private LandData landWithParcelAccessList; 43 private LandData landWithParcelAccessList;
diff --git a/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs b/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs
index 09b6f6d..142726b 100644
--- a/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs
+++ b/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs
@@ -37,7 +37,7 @@ using OpenSim.Tests.Common;
37namespace OpenSim.Framework.Serialization.Tests 37namespace OpenSim.Framework.Serialization.Tests
38{ 38{
39 [TestFixture] 39 [TestFixture]
40 public class RegionSettingsSerializerTests 40 public class RegionSettingsSerializerTests : OpenSimTestCase
41 { 41 {
42 private string m_serializedRs = @"<?xml version=""1.0"" encoding=""utf-16""?> 42 private string m_serializedRs = @"<?xml version=""1.0"" encoding=""utf-16""?>
43<RegionSettings> 43<RegionSettings>
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
index 2c21800..cb47cbf 100644
--- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -27,7 +27,6 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Diagnostics;
31using System.IO; 30using System.IO;
32using System.Reflection; 31using System.Reflection;
33using System.Text; 32using System.Text;
@@ -99,34 +98,6 @@ namespace OpenSim.Framework.Servers
99 m_console.Commands.AddCommand("General", false, "shutdown", 98 m_console.Commands.AddCommand("General", false, "shutdown",
100 "shutdown", 99 "shutdown",
101 "Quit the application", HandleQuit); 100 "Quit the application", HandleQuit);
102
103 m_console.Commands.AddCommand("General", false, "show threads",
104 "show threads",
105 "Show thread status", HandleShow);
106
107 m_console.Commands.AddCommand("General", false, "show version",
108 "show version",
109 "Show server version", HandleShow);
110
111 m_console.Commands.AddCommand("General", false, "threads abort",
112 "threads abort <thread-id>",
113 "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
114
115 m_console.Commands.AddCommand("General", false, "threads show",
116 "threads show",
117 "Show thread status. Synonym for \"show threads\"",
118 (string module, string[] args) => Notice(GetThreadsReport()));
119
120 m_console.Commands.AddCommand("General", false, "force gc",
121 "force gc",
122 "Manually invoke runtime garbage collection. For debugging purposes",
123 HandleForceGc);
124 }
125
126 private void HandleForceGc(string module, string[] args)
127 {
128 MainConsole.Instance.Output("Manually invoking runtime garbage collection");
129 GC.Collect();
130 } 101 }
131 102
132 /// <summary> 103 /// <summary>
@@ -159,54 +130,6 @@ namespace OpenSim.Framework.Servers
159 } 130 }
160 131
161 /// <summary> 132 /// <summary>
162 /// Get a report about the registered threads in this server.
163 /// </summary>
164 protected string GetThreadsReport()
165 {
166 // This should be a constant field.
167 string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}";
168
169 StringBuilder sb = new StringBuilder();
170 Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo();
171
172 sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine);
173
174 int timeNow = Environment.TickCount & Int32.MaxValue;
175
176 sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE");
177 sb.Append(Environment.NewLine);
178
179 foreach (Watchdog.ThreadWatchdogInfo twi in threads)
180 {
181 Thread t = twi.Thread;
182
183 sb.AppendFormat(
184 reportFormat,
185 t.ManagedThreadId,
186 t.Name,
187 timeNow - twi.LastTick,
188 timeNow - twi.FirstTick,
189 t.Priority,
190 t.ThreadState);
191
192 sb.Append("\n");
193 }
194
195 sb.Append("\n");
196
197 // For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting
198 // zero active threads.
199 int totalThreads = Process.GetCurrentProcess().Threads.Count;
200 if (totalThreads > 0)
201 sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
202
203 sb.Append("Main threadpool (excluding script engine pools)\n");
204 sb.Append(Util.GetThreadPoolReport());
205
206 return sb.ToString();
207 }
208
209 /// <summary>
210 /// Performs initialisation of the scene, such as loading configuration from disk. 133 /// Performs initialisation of the scene, such as loading configuration from disk.
211 /// </summary> 134 /// </summary>
212 public virtual void Startup() 135 public virtual void Startup()
@@ -246,50 +169,7 @@ namespace OpenSim.Framework.Servers
246 private void HandleQuit(string module, string[] args) 169 private void HandleQuit(string module, string[] args)
247 { 170 {
248 Shutdown(); 171 Shutdown();
249 } 172 }
250
251 public override void HandleShow(string module, string[] cmd)
252 {
253 base.HandleShow(module, cmd);
254
255 List<string> args = new List<string>(cmd);
256
257 args.RemoveAt(0);
258
259 string[] showParams = args.ToArray();
260
261 switch (showParams[0])
262 {
263 case "threads":
264 Notice(GetThreadsReport());
265 break;
266
267 case "version":
268 Notice(GetVersionText());
269 break;
270 }
271 }
272
273 public virtual void HandleThreadsAbort(string module, string[] cmd)
274 {
275 if (cmd.Length != 3)
276 {
277 MainConsole.Instance.Output("Usage: threads abort <thread-id>");
278 return;
279 }
280
281 int threadId;
282 if (!int.TryParse(cmd[2], out threadId))
283 {
284 MainConsole.Instance.Output("ERROR: Thread id must be an integer");
285 return;
286 }
287
288 if (Watchdog.AbortThread(threadId))
289 MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId);
290 else
291 MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId);
292 }
293 173
294 public string osSecret { 174 public string osSecret {
295 // Secret uuid for the simulator 175 // Secret uuid for the simulator
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 77fce9e..27af009 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -54,6 +54,16 @@ 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>
59 /// 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
61 /// start the connection and optionally provide an origin authentication method.
62 /// </summary>
63 /// <param name="servicepath"></param>
64 /// <param name="handler"></param>
65 public delegate void WebSocketRequestDelegate(string servicepath, WebSocketHttpServerHandler handler);
66
57 /// <summary> 67 /// <summary>
58 /// Gets or sets the debug level. 68 /// Gets or sets the debug level.
59 /// </summary> 69 /// </summary>
@@ -77,6 +87,7 @@ namespace OpenSim.Framework.Servers.HttpServer
77 // protected HttpListener m_httpListener; 87 // protected HttpListener m_httpListener;
78 protected CoolHTTPListener m_httpListener2; 88 protected CoolHTTPListener m_httpListener2;
79 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); 89 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
90 protected Dictionary<string, JsonRPCMethod> jsonRpcHandlers = new Dictionary<string, JsonRPCMethod>();
80 protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>(); 91 protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>();
81 protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ 92 protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/
82 protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); 93 protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
@@ -86,6 +97,9 @@ namespace OpenSim.Framework.Servers.HttpServer
86 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = 97 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
87 new Dictionary<string, PollServiceEventArgs>(); 98 new Dictionary<string, PollServiceEventArgs>();
88 99
100 protected Dictionary<string, WebSocketRequestDelegate> m_WebSocketHandlers =
101 new Dictionary<string, WebSocketRequestDelegate>();
102
89 protected uint m_port; 103 protected uint m_port;
90 protected uint m_sslport; 104 protected uint m_sslport;
91 protected bool m_ssl; 105 protected bool m_ssl;
@@ -169,6 +183,22 @@ namespace OpenSim.Framework.Servers.HttpServer
169 } 183 }
170 } 184 }
171 185
186 public void AddWebSocketHandler(string servicepath, WebSocketRequestDelegate handler)
187 {
188 lock (m_WebSocketHandlers)
189 {
190 if (!m_WebSocketHandlers.ContainsKey(servicepath))
191 m_WebSocketHandlers.Add(servicepath, handler);
192 }
193 }
194
195 public void RemoveWebSocketHandler(string servicepath)
196 {
197 lock (m_WebSocketHandlers)
198 if (m_WebSocketHandlers.ContainsKey(servicepath))
199 m_WebSocketHandlers.Remove(servicepath);
200 }
201
172 public List<string> GetStreamHandlerKeys() 202 public List<string> GetStreamHandlerKeys()
173 { 203 {
174 lock (m_streamHandlers) 204 lock (m_streamHandlers)
@@ -217,6 +247,37 @@ namespace OpenSim.Framework.Servers.HttpServer
217 return new List<string>(m_rpcHandlers.Keys); 247 return new List<string>(m_rpcHandlers.Keys);
218 } 248 }
219 249
250 // JsonRPC
251 public bool AddJsonRPCHandler(string method, JsonRPCMethod handler)
252 {
253 lock(jsonRpcHandlers)
254 {
255 jsonRpcHandlers.Add(method, handler);
256 }
257 return true;
258 }
259
260 public JsonRPCMethod GetJsonRPCHandler(string method)
261 {
262 lock (jsonRpcHandlers)
263 {
264 if (jsonRpcHandlers.ContainsKey(method))
265 {
266 return jsonRpcHandlers[method];
267 }
268 else
269 {
270 return null;
271 }
272 }
273 }
274
275 public List<string> GetJsonRpcHandlerKeys()
276 {
277 lock (jsonRpcHandlers)
278 return new List<string>(jsonRpcHandlers.Keys);
279 }
280
220 public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) 281 public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler)
221 { 282 {
222 //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); 283 //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName);
@@ -378,9 +439,24 @@ namespace OpenSim.Framework.Servers.HttpServer
378 439
379 public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) 440 public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
380 { 441 {
442
381 OSHttpRequest req = new OSHttpRequest(context, request); 443 OSHttpRequest req = new OSHttpRequest(context, request);
444 WebSocketRequestDelegate dWebSocketRequestDelegate = null;
445 lock (m_WebSocketHandlers)
446 {
447 if (m_WebSocketHandlers.ContainsKey(req.RawUrl))
448 dWebSocketRequestDelegate = m_WebSocketHandlers[req.RawUrl];
449 }
450 if (dWebSocketRequestDelegate != null)
451 {
452 dWebSocketRequestDelegate(req.Url.AbsolutePath, new WebSocketHttpServerHandler(req, context, 8192));
453 return;
454 }
455
382 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); 456 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
457
383 HandleRequest(req, resp); 458 HandleRequest(req, resp);
459
384 460
385 // !!!HACK ALERT!!! 461 // !!!HACK ALERT!!!
386 // There seems to be a bug in the underlying http code that makes subsequent requests 462 // There seems to be a bug in the underlying http code that makes subsequent requests
@@ -437,7 +513,7 @@ namespace OpenSim.Framework.Servers.HttpServer
437// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); 513// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]);
438 //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); 514 //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
439 515
440 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); 516 Culture.SetCurrentCulture();
441 517
442// // This is the REST agent interface. We require an agent to properly identify 518// // This is the REST agent interface. We require an agent to properly identify
443// // itself. If the REST handler recognizes the prefix it will attempt to 519// // itself. If the REST handler recognizes the prefix it will attempt to
@@ -469,7 +545,7 @@ namespace OpenSim.Framework.Servers.HttpServer
469 LogIncomingToStreamHandler(request, requestHandler); 545 LogIncomingToStreamHandler(request, requestHandler);
470 546
471 response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. 547 response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
472 548
473 if (requestHandler is IStreamedRequestHandler) 549 if (requestHandler is IStreamedRequestHandler)
474 { 550 {
475 IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; 551 IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler;
@@ -557,10 +633,18 @@ namespace OpenSim.Framework.Servers.HttpServer
557 633
558 buffer = HandleLLSDRequests(request, response); 634 buffer = HandleLLSDRequests(request, response);
559 break; 635 break;
636
637 case "application/json-rpc":
638 if (DebugLevel >= 3)
639 LogIncomingToContentTypeHandler(request);
640
641 buffer = HandleJsonRpcRequests(request, response);
642 break;
560 643
561 case "text/xml": 644 case "text/xml":
562 case "application/xml": 645 case "application/xml":
563 case "application/json": 646 case "application/json":
647
564 default: 648 default:
565 //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); 649 //m_log.Info("[Debug BASE HTTP SERVER]: in default handler");
566 // Point of note.. the DoWeHaveA methods check for an EXACT path 650 // Point of note.. the DoWeHaveA methods check for an EXACT path
@@ -986,6 +1070,93 @@ namespace OpenSim.Framework.Servers.HttpServer
986 return buffer; 1070 return buffer;
987 } 1071 }
988 1072
1073 // JsonRpc (v2.0 only)
1074 // Batch requests not yet supported
1075 private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response)
1076 {
1077 Stream requestStream = request.InputStream;
1078 JsonRpcResponse jsonRpcResponse = new JsonRpcResponse();
1079 OSDMap jsonRpcRequest = null;
1080
1081 try
1082 {
1083 jsonRpcRequest = (OSDMap)OSDParser.DeserializeJson(requestStream);
1084 }
1085 catch (LitJson.JsonException e)
1086 {
1087 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1088 jsonRpcResponse.Error.Message = e.Message;
1089 }
1090
1091 requestStream.Close();
1092
1093 if (jsonRpcRequest != null)
1094 {
1095 if (jsonRpcRequest.ContainsKey("jsonrpc") || jsonRpcRequest["jsonrpc"].AsString() == "2.0")
1096 {
1097 jsonRpcResponse.JsonRpc = "2.0";
1098
1099 // If we have no id, then it's a "notification"
1100 if (jsonRpcRequest.ContainsKey("id"))
1101 {
1102 jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
1103 }
1104
1105 string methodname = jsonRpcRequest["method"];
1106 JsonRPCMethod method;
1107
1108 if (jsonRpcHandlers.ContainsKey(methodname))
1109 {
1110 lock(jsonRpcHandlers)
1111 {
1112 jsonRpcHandlers.TryGetValue(methodname, out method);
1113 }
1114 bool res = false;
1115 try
1116 {
1117 res = method(jsonRpcRequest, ref jsonRpcResponse);
1118 if(!res)
1119 {
1120 // The handler sent back an unspecified error
1121 if(jsonRpcResponse.Error.Code == 0)
1122 {
1123 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1124 }
1125 }
1126 }
1127 catch (Exception e)
1128 {
1129 string ErrorMessage = string.Format("[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}", methodname, e.Message);
1130 m_log.Error(ErrorMessage);
1131 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1132 jsonRpcResponse.Error.Message = ErrorMessage;
1133 }
1134 }
1135 else // Error no hanlder defined for requested method
1136 {
1137 jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1138 jsonRpcResponse.Error.Message = string.Format ("No handler defined for {0}", methodname);
1139 }
1140 }
1141 else // not json-rpc 2.0 could be v1
1142 {
1143 jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1144 jsonRpcResponse.Error.Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification";
1145
1146 if (jsonRpcRequest.ContainsKey("id"))
1147 jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
1148 }
1149 }
1150
1151 response.KeepAlive = true;
1152 string responseData = string.Empty;
1153
1154 responseData = jsonRpcResponse.Serialize();
1155
1156 byte[] buffer = Encoding.UTF8.GetBytes(responseData);
1157 return buffer;
1158 }
1159
989 private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) 1160 private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response)
990 { 1161 {
991 //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); 1162 //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request");
@@ -1283,59 +1454,6 @@ namespace OpenSim.Framework.Servers.HttpServer
1283 map["login"] = OSD.FromString("false"); 1454 map["login"] = OSD.FromString("false");
1284 return map; 1455 return map;
1285 } 1456 }
1286 /// <summary>
1287 /// A specific agent handler was provided. Such a handler is expecetd to have an
1288 /// intimate, and highly specific relationship with the client. Consequently,
1289 /// nothing is done here.
1290 /// </summary>
1291 /// <param name="handler"></param>
1292 /// <param name="request"></param>
1293 /// <param name="response"></param>
1294
1295 private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response)
1296 {
1297 // In the case of REST, then handler is responsible for ALL aspects of
1298 // the request/response handling. Nothing is done here, not even encoding.
1299
1300 try
1301 {
1302 return handler.Handle(request, response);
1303 }
1304 catch (Exception e)
1305 {
1306 // If the handler did in fact close the stream, then this will blow
1307 // chunks. So that that doesn't disturb anybody we throw away any
1308 // and all exceptions raised. We've done our best to release the
1309 // client.
1310 try
1311 {
1312 m_log.Warn("[HTTP-AGENT]: Error - " + e.Message);
1313 response.SendChunked = false;
1314 response.KeepAlive = true;
1315 response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError;
1316 //response.OutputStream.Close();
1317 try
1318 {
1319 response.Send();
1320 //response.FreeContext();
1321 }
1322 catch (SocketException f)
1323 {
1324 // This has to be here to prevent a Linux/Mono crash
1325 m_log.Warn(
1326 String.Format("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux. ", f.Message), f);
1327 }
1328 }
1329 catch(Exception)
1330 {
1331 }
1332 }
1333
1334 // Indicate that the request has been "handled"
1335
1336 return true;
1337
1338 }
1339 1457
1340 public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) 1458 public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
1341 { 1459 {
@@ -1775,6 +1893,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1775 HTTPDRunning = false; 1893 HTTPDRunning = false;
1776 try 1894 try
1777 { 1895 {
1896// m_PollServiceManager.Stop();
1897
1778 m_httpListener2.ExceptionThrown -= httpServerException; 1898 m_httpListener2.ExceptionThrown -= httpServerException;
1779 //m_httpListener2.DisconnectHandler = null; 1899 //m_httpListener2.DisconnectHandler = null;
1780 1900
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
index 0bd3aae..71ca3ff 100644
--- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
@@ -97,6 +97,18 @@ namespace OpenSim.Framework.Servers.HttpServer
97 bool AddXmlRPCHandler(string method, XmlRpcMethod handler); 97 bool AddXmlRPCHandler(string method, XmlRpcMethod handler);
98 bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive); 98 bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive);
99 99
100 bool AddJsonRPCHandler(string method, JsonRPCMethod handler);
101
102 /// <summary>
103 /// Websocket HTTP server handlers.
104 /// </summary>
105 /// <param name="servicepath"></param>
106 /// <param name="handler"></param>
107 void AddWebSocketHandler(string servicepath, BaseHttpServer.WebSocketRequestDelegate handler);
108
109
110 void RemoveWebSocketHandler(string servicepath);
111
100 /// <summary> 112 /// <summary>
101 /// Gets the XML RPC handler for given method name 113 /// Gets the XML RPC handler for given method name
102 /// </summary> 114 /// </summary>
diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
new file mode 100644
index 0000000..5bab508
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
@@ -0,0 +1,34 @@
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
28using System.Net;
29using OpenMetaverse.StructuredData;
30
31namespace OpenSim.Framework.Servers.HttpServer
32{
33 public delegate bool JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response);
34}
diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs b/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs
new file mode 100644
index 0000000..2c50587
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs
@@ -0,0 +1,150 @@
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 */
27using System;
28using System.Net;
29using OpenMetaverse.StructuredData;
30
31namespace OpenSim.Framework.Servers.HttpServer
32{
33 public sealed class ErrorCode
34 {
35 private ErrorCode() {}
36
37 public const int ParseError = -32700;
38 public const int InvalidRequest = -32600;
39 public const int MethodNotFound = -32601;
40 public const int InvalidParams = -32602;
41 public const int InternalError = -32604;
42
43 }
44
45 public class JsonRpcError
46 {
47 internal OSDMap Error = new OSDMap();
48
49 public int Code
50 {
51 get
52 {
53 if (Error.ContainsKey("code"))
54 return Error["code"].AsInteger();
55 else
56 return 0;
57 }
58 set
59 {
60 Error["code"] = OSD.FromInteger(value);
61 }
62 }
63
64 public string Message
65 {
66 get
67 {
68 if (Error.ContainsKey("message"))
69 return Error["message"].AsString();
70 else
71 return null;
72 }
73 set
74 {
75 Error["message"] = OSD.FromString(value);
76 }
77 }
78
79 public OSD Data
80 {
81 get; set;
82 }
83 }
84
85 public class JsonRpcResponse
86 {
87 public string JsonRpc
88 {
89 get
90 {
91 return Reply["jsonrpc"].AsString();
92 }
93 set
94 {
95 Reply["jsonrpc"] = OSD.FromString(value);
96 }
97 }
98
99 public string Id
100 {
101 get
102 {
103 return Reply["id"].AsString();
104 }
105 set
106 {
107 Reply["id"] = OSD.FromString(value);
108 }
109 }
110
111 public OSD Result
112 {
113 get; set;
114 }
115
116 public JsonRpcError Error
117 {
118 get; set;
119 }
120
121 public OSDMap Reply = new OSDMap();
122
123 public JsonRpcResponse()
124 {
125 Error = new JsonRpcError();
126 }
127
128 public string Serialize()
129 {
130 if (Result != null)
131 Reply["result"] = Result;
132
133 if (Error.Code != 0)
134 {
135 Reply["error"] = (OSD)Error.Error;
136 }
137
138 string result = string.Empty;
139 try
140 {
141 result = OSDParser.SerializeJsonString(Reply);
142 }
143 catch
144 {
145
146 }
147 return result;
148 }
149 }
150}
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index 4be8bf4..07bd48a 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -50,19 +50,26 @@ namespace OpenSim.Framework.Servers.HttpServer
50 private uint m_WorkerThreadCount = 0; 50 private uint m_WorkerThreadCount = 0;
51 private Thread[] m_workerThreads; 51 private Thread[] m_workerThreads;
52 private PollServiceWorkerThread[] m_PollServiceWorkerThreads; 52 private PollServiceWorkerThread[] m_PollServiceWorkerThreads;
53 private bool m_running = true; 53 private volatile bool m_running = true;
54 private int m_pollTimeout;
54 55
55 public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) 56 public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout)
56 { 57 {
57 m_server = pSrv; 58 m_server = pSrv;
58 m_WorkerThreadCount = pWorkerThreadCount; 59 m_WorkerThreadCount = pWorkerThreadCount;
60 m_pollTimeout = pTimeout;
61 }
62
63 public void Start()
64 {
65 m_running = true;
59 m_workerThreads = new Thread[m_WorkerThreadCount]; 66 m_workerThreads = new Thread[m_WorkerThreadCount];
60 m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount]; 67 m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
61 68
62 //startup worker threads 69 //startup worker threads
63 for (uint i = 0; i < m_WorkerThreadCount; i++) 70 for (uint i = 0; i < m_WorkerThreadCount; i++)
64 { 71 {
65 m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, pTimeout); 72 m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, m_pollTimeout);
66 m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent; 73 m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent;
67 74
68 m_workerThreads[i] 75 m_workerThreads[i]
@@ -141,8 +148,10 @@ namespace OpenSim.Framework.Servers.HttpServer
141 148
142 } 149 }
143 150
144 ~PollServiceRequestManager() 151 public void Stop()
145 { 152 {
153 m_running = false;
154
146 foreach (object o in m_requests) 155 foreach (object o in m_requests)
147 { 156 {
148 PollServiceHttpRequest req = (PollServiceHttpRequest) o; 157 PollServiceHttpRequest req = (PollServiceHttpRequest) o;
@@ -157,7 +166,6 @@ namespace OpenSim.Framework.Servers.HttpServer
157 { 166 {
158 t.Abort(); 167 t.Abort();
159 } 168 }
160 m_running = false;
161 } 169 }
162 } 170 }
163} 171}
diff --git a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs
index 02ecc25..386be2d 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.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
new file mode 100644
index 0000000..cfb1605
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
@@ -0,0 +1,1085 @@
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
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Security.Cryptography;
32using System.Text;
33using HttpServer;
34
35namespace OpenSim.Framework.Servers.HttpServer
36{
37 // Sealed class. If you're going to unseal it, implement IDisposable.
38 /// <summary>
39 /// This class implements websockets. It grabs the network context from C#Webserver and utilizes it directly as a tcp streaming service
40 /// </summary>
41 public sealed class WebSocketHttpServerHandler : BaseRequestHandler
42 {
43
44 private class WebSocketState
45 {
46 public List<byte> ReceivedBytes;
47 public int ExpectedBytes;
48 public WebsocketFrameHeader Header;
49 public bool FrameComplete;
50 public WebSocketFrame ContinuationFrame;
51 }
52
53 /// <summary>
54 /// Binary Data will trigger this event
55 /// </summary>
56 public event DataDelegate OnData;
57
58 /// <summary>
59 /// Textual Data will trigger this event
60 /// </summary>
61 public event TextDelegate OnText;
62
63 /// <summary>
64 /// A ping request form the other side will trigger this event.
65 /// This class responds to the ping automatically. You shouldn't send a pong.
66 /// it's informational.
67 /// </summary>
68 public event PingDelegate OnPing;
69
70 /// <summary>
71 /// This is a response to a ping you sent.
72 /// </summary>
73 public event PongDelegate OnPong;
74
75 /// <summary>
76 /// This is a regular HTTP Request... This may be removed in the future.
77 /// </summary>
78 public event RegularHttpRequestDelegate OnRegularHttpRequest;
79
80 /// <summary>
81 /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired
82 /// </summary>
83 public event UpgradeCompletedDelegate OnUpgradeCompleted;
84
85 /// <summary>
86 /// If the upgrade failed, this will be fired
87 /// </summary>
88 public event UpgradeFailedDelegate OnUpgradeFailed;
89
90 /// <summary>
91 /// When the websocket is closed, this will be fired.
92 /// </summary>
93 public event CloseDelegate OnClose;
94
95 /// <summary>
96 /// Set this delegate to allow your module to validate the origin of the
97 /// Websocket request. Primary line of defense against cross site scripting
98 /// </summary>
99 public ValidateHandshake HandshakeValidateMethodOverride = null;
100
101 private OSHttpRequest _request;
102 private HTTPNetworkContext _networkContext;
103 private IHttpClientContext _clientContext;
104
105 private int _pingtime = 0;
106 private byte[] _buffer;
107 private int _bufferPosition;
108 private int _bufferLength;
109 private bool _closing;
110 private bool _upgraded;
111
112 private const string HandshakeAcceptText =
113 "HTTP/1.1 101 Switching Protocols\r\n" +
114 "upgrade: websocket\r\n" +
115 "Connection: Upgrade\r\n" +
116 "sec-websocket-accept: {0}\r\n\r\n";// +
117 //"{1}";
118
119 private const string HandshakeDeclineText =
120 "HTTP/1.1 {0} {1}\r\n" +
121 "Connection: close\r\n\r\n";
122
123 /// <summary>
124 /// Mysterious constant defined in RFC6455 to append to the client provided security key
125 /// </summary>
126 private const string WebsocketHandshakeAcceptHashConstant = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
127
128 public WebSocketHttpServerHandler(OSHttpRequest preq, IHttpClientContext pContext, int bufferlen)
129 : base(preq.HttpMethod, preq.Url.OriginalString)
130 {
131 _request = preq;
132 _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing();
133 _clientContext = pContext;
134 _bufferLength = bufferlen;
135 _buffer = new byte[_bufferLength];
136 }
137
138 // Sealed class implments destructor and an internal dispose method. complies with C# unmanaged resource best practices.
139 ~WebSocketHttpServerHandler()
140 {
141 Dispose();
142
143 }
144
145 /// <summary>
146 /// Sets the length of the stream buffer
147 /// </summary>
148 /// <param name="pChunk">Byte length.</param>
149 public void SetChunksize(int pChunk)
150 {
151 if (!_upgraded)
152 {
153 _buffer = new byte[pChunk];
154 }
155 else
156 {
157 throw new InvalidOperationException("You must set the chunksize before the connection is upgraded");
158 }
159 }
160
161 /// <summary>
162 /// This is the famous nagle.
163 /// </summary>
164 public bool NoDelay_TCP_Nagle
165 {
166 get
167 {
168 if (_networkContext != null && _networkContext.Socket != null)
169 {
170 return _networkContext.Socket.NoDelay;
171 }
172 else
173 {
174 throw new InvalidOperationException("The socket has been shutdown");
175 }
176 }
177 set
178 {
179 if (_networkContext != null && _networkContext.Socket != null)
180 _networkContext.Socket.NoDelay = value;
181 else
182 {
183 throw new InvalidOperationException("The socket has been shutdown");
184 }
185 }
186 }
187
188 /// <summary>
189 /// This triggers the websocket to start the upgrade process...
190 /// This is a Generalized Networking 'common sense' helper method. Some people expect to call Start() instead
191 /// of the more context appropriate HandshakeAndUpgrade()
192 /// </summary>
193 public void Start()
194 {
195 HandshakeAndUpgrade();
196 }
197
198 /// <summary>
199 /// This triggers the websocket start the upgrade process
200 /// </summary>
201 public void HandshakeAndUpgrade()
202 {
203 string webOrigin = string.Empty;
204 string websocketKey = string.Empty;
205 string acceptKey = string.Empty;
206 string accepthost = string.Empty;
207 if (!string.IsNullOrEmpty(_request.Headers["origin"]))
208 webOrigin = _request.Headers["origin"];
209
210 if (!string.IsNullOrEmpty(_request.Headers["sec-websocket-key"]))
211 websocketKey = _request.Headers["sec-websocket-key"];
212
213 if (!string.IsNullOrEmpty(_request.Headers["host"]))
214 accepthost = _request.Headers["host"];
215
216 if (string.IsNullOrEmpty(_request.Headers["upgrade"]))
217 {
218 FailUpgrade(OSHttpStatusCode.ClientErrorBadRequest, "no upgrade request submitted");
219 }
220
221 string connectionheader = _request.Headers["upgrade"];
222 if (connectionheader.ToLower() != "websocket")
223 {
224 FailUpgrade(OSHttpStatusCode.ClientErrorBadRequest, "no connection upgrade request submitted");
225 }
226
227 // If the object consumer provided a method to validate the origin, we should call it and give the client a success or fail.
228 // If not.. we should accept any. The assumption here is that there would be no Websocket handlers registered in baseHTTPServer unless
229 // Something asked for it...
230 if (HandshakeValidateMethodOverride != null)
231 {
232 if (HandshakeValidateMethodOverride(webOrigin, websocketKey, accepthost))
233 {
234 acceptKey = GenerateAcceptKey(websocketKey);
235 string rawaccept = string.Format(HandshakeAcceptText, acceptKey);
236 SendUpgradeSuccess(rawaccept);
237
238 }
239 else
240 {
241 FailUpgrade(OSHttpStatusCode.ClientErrorForbidden, "Origin Validation Failed");
242 }
243 }
244 else
245 {
246 acceptKey = GenerateAcceptKey(websocketKey);
247 string rawaccept = string.Format(HandshakeAcceptText, acceptKey);
248 SendUpgradeSuccess(rawaccept);
249 }
250 }
251
252 /// <summary>
253 /// Generates a handshake response key string based on the client's
254 /// provided key to prove to the client that we're allowing the Websocket
255 /// upgrade of our own free will and we were not coerced into doing it.
256 /// </summary>
257 /// <param name="key">Client provided security key</param>
258 /// <returns></returns>
259 private static string GenerateAcceptKey(string key)
260 {
261 if (string.IsNullOrEmpty(key))
262 return string.Empty;
263
264 string acceptkey = key + WebsocketHandshakeAcceptHashConstant;
265
266 SHA1 hashobj = SHA1.Create();
267 string ret = Convert.ToBase64String(hashobj.ComputeHash(Encoding.UTF8.GetBytes(acceptkey)));
268 hashobj.Clear();
269
270 return ret;
271 }
272
273 /// <summary>
274 /// Informs the otherside that we accepted their upgrade request
275 /// </summary>
276 /// <param name="pHandshakeResponse">The HTTP 1.1 101 response that says Yay \o/ </param>
277 private void SendUpgradeSuccess(string pHandshakeResponse)
278 {
279 // Create a new websocket state so we can keep track of data in between network reads.
280 WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true};
281
282 byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse);
283 try
284 {
285
286 // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream.
287 _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState);
288
289 // Write the upgrade handshake success message
290 _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length);
291 _networkContext.Stream.Flush();
292 _upgraded = true;
293 UpgradeCompletedDelegate d = OnUpgradeCompleted;
294 if (d != null)
295 d(this, new UpgradeCompletedEventArgs());
296 }
297 catch (IOException fail)
298 {
299 Close(string.Empty);
300 }
301 catch (ObjectDisposedException fail)
302 {
303 Close(string.Empty);
304 }
305
306 }
307
308 /// <summary>
309 /// The server has decided not to allow the upgrade to a websocket for some reason. The Http 1.1 response that says Nay >:(
310 /// </summary>
311 /// <param name="pCode">HTTP Status reflecting the reason why</param>
312 /// <param name="pMessage">Textual reason for the upgrade fail</param>
313 private void FailUpgrade(OSHttpStatusCode pCode, string pMessage )
314 {
315 string handshakeResponse = string.Format(HandshakeDeclineText, (int)pCode, pMessage.Replace("\n", string.Empty).Replace("\r", string.Empty));
316 byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(handshakeResponse);
317 _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length);
318 _networkContext.Stream.Flush();
319 _networkContext.Stream.Dispose();
320
321 UpgradeFailedDelegate d = OnUpgradeFailed;
322 if (d != null)
323 d(this,new UpgradeFailedEventArgs());
324 }
325
326
327 /// <summary>
328 /// This is our ugly Async OnReceive event handler.
329 /// This chunks the input stream based on the length of the provided buffer and processes out
330 /// as many frames as it can. It then moves the unprocessed data to the beginning of the buffer.
331 /// </summary>
332 /// <param name="ar">Our Async State from beginread</param>
333 private void OnReceive(IAsyncResult ar)
334 {
335 WebSocketState _socketState = ar.AsyncState as WebSocketState;
336 try
337 {
338 int bytesRead = _networkContext.Stream.EndRead(ar);
339 if (bytesRead == 0)
340 {
341 // Do Disconnect
342 _networkContext.Stream.Dispose();
343 _networkContext = null;
344 return;
345 }
346 _bufferPosition += bytesRead;
347
348 if (_bufferPosition > _bufferLength)
349 {
350 // Message too big for chunksize.. not sure how this happened...
351 //Close(string.Empty);
352 }
353
354 int offset = 0;
355 bool headerread = true;
356 int headerforwardposition = 0;
357 while (headerread && offset < bytesRead)
358 {
359 if (_socketState.FrameComplete)
360 {
361 WebsocketFrameHeader pheader = WebsocketFrameHeader.ZeroHeader;
362
363 headerread = WebSocketReader.TryReadHeader(_buffer, offset, _bufferPosition - offset, out pheader,
364 out headerforwardposition);
365 offset += headerforwardposition;
366
367 if (headerread)
368 {
369 _socketState.FrameComplete = false;
370
371 if (pheader.PayloadLen > 0)
372 {
373 if ((int) pheader.PayloadLen > _bufferPosition - offset)
374 {
375 byte[] writebytes = new byte[_bufferPosition - offset];
376
377 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition - offset);
378 _socketState.ExpectedBytes = (int) pheader.PayloadLen;
379 _socketState.ReceivedBytes.AddRange(writebytes);
380 _socketState.Header = pheader; // We need to add the header so that we can unmask it
381 offset += (int) _bufferPosition - offset;
382 }
383 else
384 {
385 byte[] writebytes = new byte[pheader.PayloadLen];
386 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) pheader.PayloadLen);
387 WebSocketReader.Mask(pheader.Mask, writebytes);
388 pheader.IsMasked = false;
389 _socketState.FrameComplete = true;
390 _socketState.ReceivedBytes.AddRange(writebytes);
391 _socketState.Header = pheader;
392 offset += (int) pheader.PayloadLen;
393 }
394 }
395 else
396 {
397 pheader.Mask = 0;
398 _socketState.FrameComplete = true;
399 _socketState.Header = pheader;
400 }
401
402
403
404 if (_socketState.FrameComplete)
405 {
406 ProcessFrame(_socketState);
407 _socketState.Header.SetDefault();
408 _socketState.ReceivedBytes.Clear();
409 _socketState.ExpectedBytes = 0;
410
411 }
412
413 }
414 }
415 else
416 {
417 WebsocketFrameHeader frameHeader = _socketState.Header;
418 int bytesleft = _socketState.ExpectedBytes - _socketState.ReceivedBytes.Count;
419
420 if (bytesleft > _bufferPosition)
421 {
422 byte[] writebytes = new byte[_bufferPosition];
423
424 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition);
425 _socketState.ReceivedBytes.AddRange(writebytes);
426 _socketState.Header = frameHeader; // We need to add the header so that we can unmask it
427 offset += (int) _bufferPosition;
428 }
429 else
430 {
431 byte[] writebytes = new byte[_bufferPosition];
432 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition);
433 _socketState.FrameComplete = true;
434 _socketState.ReceivedBytes.AddRange(writebytes);
435 _socketState.Header = frameHeader;
436 offset += (int) _bufferPosition;
437 }
438 if (_socketState.FrameComplete)
439 {
440 ProcessFrame(_socketState);
441 _socketState.Header.SetDefault();
442 _socketState.ReceivedBytes.Clear();
443 _socketState.ExpectedBytes = 0;
444 // do some processing
445 }
446
447 }
448 }
449 if (offset > 0)
450 {
451 // If the buffer is maxed out.. we can just move the cursor. Nothing to move to the beginning.
452 if (offset <_buffer.Length)
453 Buffer.BlockCopy(_buffer, offset, _buffer, 0, _bufferPosition - offset);
454 _bufferPosition -= offset;
455 }
456 if (_networkContext.Stream != null && _networkContext.Stream.CanRead && !_closing)
457 {
458 _networkContext.Stream.BeginRead(_buffer, _bufferPosition, _bufferLength - _bufferPosition, OnReceive,
459 _socketState);
460 }
461 else
462 {
463 // We can't read the stream anymore...
464 }
465
466 }
467 catch (IOException fail)
468 {
469 Close(string.Empty);
470 }
471 catch (ObjectDisposedException fail)
472 {
473 Close(string.Empty);
474 }
475 }
476
477 /// <summary>
478 /// Sends a string to the other side
479 /// </summary>
480 /// <param name="message">the string message that is to be sent</param>
481 public void SendMessage(string message)
482 {
483 byte[] messagedata = Encoding.UTF8.GetBytes(message);
484 WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata };
485 textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text;
486 textMessageFrame.Header.IsEnd = true;
487 SendSocket(textMessageFrame.ToBytes());
488
489 }
490
491 public void SendData(byte[] data)
492 {
493 WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data};
494 dataMessageFrame.Header.IsEnd = true;
495 dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary;
496 SendSocket(dataMessageFrame.ToBytes());
497
498 }
499
500 /// <summary>
501 /// Writes raw bytes to the websocket. Unframed data will cause disconnection
502 /// </summary>
503 /// <param name="data"></param>
504 private void SendSocket(byte[] data)
505 {
506 if (!_closing)
507 {
508 try
509 {
510
511 _networkContext.Stream.Write(data, 0, data.Length);
512 }
513 catch (IOException)
514 {
515
516 }
517 }
518 }
519
520 /// <summary>
521 /// Sends a Ping check to the other side. The other side SHOULD respond as soon as possible with a pong frame. This interleaves with incoming fragmented frames.
522 /// </summary>
523 public void SendPingCheck()
524 {
525 WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] };
526 pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping;
527 pingFrame.Header.IsEnd = true;
528 _pingtime = Util.EnvironmentTickCount();
529 SendSocket(pingFrame.ToBytes());
530 }
531
532 /// <summary>
533 /// Closes the websocket connection. Sends a close message to the other side if it hasn't already done so.
534 /// </summary>
535 /// <param name="message"></param>
536 public void Close(string message)
537 {
538 if (_networkContext.Stream != null)
539 {
540 if (_networkContext.Stream.CanWrite)
541 {
542 byte[] messagedata = Encoding.UTF8.GetBytes(message);
543 WebSocketFrame closeResponseFrame = new WebSocketFrame()
544 {
545 Header = WebsocketFrameHeader.HeaderDefault(),
546 WebSocketPayload = messagedata
547 };
548 closeResponseFrame.Header.Opcode = WebSocketReader.OpCode.Close;
549 closeResponseFrame.Header.PayloadLen = (ulong) messagedata.Length;
550 closeResponseFrame.Header.IsEnd = true;
551 SendSocket(closeResponseFrame.ToBytes());
552 }
553 }
554 CloseDelegate closeD = OnClose;
555 if (closeD != null)
556 {
557 closeD(this, new CloseEventArgs());
558 }
559
560 _closing = true;
561 }
562
563 /// <summary>
564 /// Processes a websocket frame and triggers consumer events
565 /// </summary>
566 /// <param name="psocketState">We need to modify the websocket state here depending on the frame</param>
567 private void ProcessFrame(WebSocketState psocketState)
568 {
569 if (psocketState.Header.IsMasked)
570 {
571 byte[] unmask = psocketState.ReceivedBytes.ToArray();
572 WebSocketReader.Mask(psocketState.Header.Mask, unmask);
573 psocketState.ReceivedBytes = new List<byte>(unmask);
574 }
575
576 switch (psocketState.Header.Opcode)
577 {
578 case WebSocketReader.OpCode.Ping:
579 PingDelegate pingD = OnPing;
580 if (pingD != null)
581 {
582 pingD(this, new PingEventArgs());
583 }
584
585 WebSocketFrame pongFrame = new WebSocketFrame(){Header = WebsocketFrameHeader.HeaderDefault(),WebSocketPayload = new byte[0]};
586 pongFrame.Header.Opcode = WebSocketReader.OpCode.Pong;
587 pongFrame.Header.IsEnd = true;
588 SendSocket(pongFrame.ToBytes());
589 break;
590 case WebSocketReader.OpCode.Pong:
591
592 PongDelegate pongD = OnPong;
593 if (pongD != null)
594 {
595 pongD(this, new PongEventArgs(){PingResponseMS = Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(),_pingtime)});
596 }
597 break;
598 case WebSocketReader.OpCode.Binary:
599 if (!psocketState.Header.IsEnd) // Not done, so we need to store this and wait for the end frame.
600 {
601 psocketState.ContinuationFrame = new WebSocketFrame
602 {
603 Header = psocketState.Header,
604 WebSocketPayload =
605 psocketState.ReceivedBytes.ToArray()
606 };
607 }
608 else
609 {
610 // Send Done Event!
611 DataDelegate dataD = OnData;
612 if (dataD != null)
613 {
614 dataD(this,new WebsocketDataEventArgs(){Data = psocketState.ReceivedBytes.ToArray()});
615 }
616 }
617 break;
618 case WebSocketReader.OpCode.Text:
619 if (!psocketState.Header.IsEnd) // Not done, so we need to store this and wait for the end frame.
620 {
621 psocketState.ContinuationFrame = new WebSocketFrame
622 {
623 Header = psocketState.Header,
624 WebSocketPayload =
625 psocketState.ReceivedBytes.ToArray()
626 };
627 }
628 else
629 {
630 TextDelegate textD = OnText;
631 if (textD != null)
632 {
633 textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(psocketState.ReceivedBytes.ToArray()) });
634 }
635
636 // Send Done Event!
637 }
638 break;
639 case WebSocketReader.OpCode.Continue: // Continuation. Multiple frames worth of data for one message. Only valid when not using Control Opcodes
640 //Console.WriteLine("currhead " + psocketState.Header.IsEnd);
641 //Console.WriteLine("Continuation! " + psocketState.ContinuationFrame.Header.IsEnd);
642 byte[] combineddata = new byte[psocketState.ReceivedBytes.Count+psocketState.ContinuationFrame.WebSocketPayload.Length];
643 byte[] newdata = psocketState.ReceivedBytes.ToArray();
644 Buffer.BlockCopy(psocketState.ContinuationFrame.WebSocketPayload, 0, combineddata, 0, psocketState.ContinuationFrame.WebSocketPayload.Length);
645 Buffer.BlockCopy(newdata, 0, combineddata,
646 psocketState.ContinuationFrame.WebSocketPayload.Length, newdata.Length);
647 psocketState.ContinuationFrame.WebSocketPayload = combineddata;
648 psocketState.Header.PayloadLen = (ulong)combineddata.Length;
649 if (psocketState.Header.IsEnd)
650 {
651 if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Text)
652 {
653 // Send Done event
654 TextDelegate textD = OnText;
655 if (textD != null)
656 {
657 textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(combineddata) });
658 }
659 }
660 else if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Binary)
661 {
662 // Send Done event
663 DataDelegate dataD = OnData;
664 if (dataD != null)
665 {
666 dataD(this, new WebsocketDataEventArgs() { Data = combineddata });
667 }
668 }
669 else
670 {
671 // protocol violation
672 }
673 psocketState.ContinuationFrame = null;
674 }
675 break;
676 case WebSocketReader.OpCode.Close:
677 Close(string.Empty);
678
679 break;
680
681 }
682 psocketState.Header.SetDefault();
683 psocketState.ReceivedBytes.Clear();
684 psocketState.ExpectedBytes = 0;
685 }
686 public void Dispose()
687 {
688 if (_networkContext != null && _networkContext.Stream != null)
689 {
690 if (_networkContext.Stream.CanWrite)
691 _networkContext.Stream.Flush();
692 _networkContext.Stream.Close();
693 _networkContext.Stream.Dispose();
694 _networkContext.Stream = null;
695 }
696
697 if (_request != null && _request.InputStream != null)
698 {
699 _request.InputStream.Close();
700 _request.InputStream.Dispose();
701 _request = null;
702 }
703
704 if (_clientContext != null)
705 {
706 _clientContext.Close();
707 _clientContext = null;
708 }
709 }
710 }
711
712 /// <summary>
713 /// Reads a byte stream and returns Websocket frames.
714 /// </summary>
715 public class WebSocketReader
716 {
717 /// <summary>
718 /// Bit to determine if the frame read on the stream is the last frame in a sequence of fragmented frames
719 /// </summary>
720 private const byte EndBit = 0x80;
721
722 /// <summary>
723 /// These are the Frame Opcodes
724 /// </summary>
725 public enum OpCode
726 {
727 // Data Opcodes
728 Continue = 0x0,
729 Text = 0x1,
730 Binary = 0x2,
731
732 // Control flow Opcodes
733 Close = 0x8,
734 Ping = 0x9,
735 Pong = 0xA
736 }
737
738 /// <summary>
739 /// Masks and Unmasks data using the frame mask. Mask is applied per octal
740 /// Note: Frames from clients MUST be masked
741 /// Note: Frames from servers MUST NOT be masked
742 /// </summary>
743 /// <param name="pMask">Int representing 32 bytes of mask data. Mask is applied per octal</param>
744 /// <param name="pBuffer"></param>
745 public static void Mask(int pMask, byte[] pBuffer)
746 {
747 byte[] maskKey = BitConverter.GetBytes(pMask);
748 int currentMaskIndex = 0;
749 for (int i = 0; i < pBuffer.Length; i++)
750 {
751 pBuffer[i] = (byte)(pBuffer[i] ^ maskKey[currentMaskIndex]);
752 if (currentMaskIndex == 3)
753 {
754 currentMaskIndex = 0;
755 }
756 else
757 {
758 currentMaskIndex++;
759
760 }
761
762 }
763 }
764
765 /// <summary>
766 /// Attempts to read a header off the provided buffer. Returns true, exports a WebSocketFrameheader,
767 /// and an int to move the buffer forward when it reads a header. False when it can't read a header
768 /// </summary>
769 /// <param name="pBuffer">Bytes read from the stream</param>
770 /// <param name="pOffset">Starting place in the stream to begin trying to read from</param>
771 /// <param name="length">Lenth in the stream to try and read from. Provided for cases where the
772 /// buffer's length is larger then the data in it</param>
773 /// <param name="oHeader">Outputs the read WebSocket frame header</param>
774 /// <param name="moveBuffer">Informs the calling stream to move the buffer forward</param>
775 /// <returns>True if it got a header, False if it didn't get a header</returns>
776 public static bool TryReadHeader(byte[] pBuffer, int pOffset, int length, out WebsocketFrameHeader oHeader,
777 out int moveBuffer)
778 {
779 oHeader = WebsocketFrameHeader.ZeroHeader;
780 int minumheadersize = 2;
781 if (length > pBuffer.Length - pOffset)
782 throw new ArgumentOutOfRangeException("The Length specified was larger the byte array supplied");
783 if (length < minumheadersize)
784 {
785 moveBuffer = 0;
786 return false;
787 }
788
789 byte nibble1 = (byte)(pBuffer[pOffset] & 0xF0); //FIN/RSV1/RSV2/RSV3
790 byte nibble2 = (byte)(pBuffer[pOffset] & 0x0F); // Opcode block
791
792 oHeader = new WebsocketFrameHeader();
793 oHeader.SetDefault();
794
795 if ((nibble1 & WebSocketReader.EndBit) == WebSocketReader.EndBit)
796 {
797 oHeader.IsEnd = true;
798 }
799 else
800 {
801 oHeader.IsEnd = false;
802 }
803 //Opcode
804 oHeader.Opcode = (WebSocketReader.OpCode)nibble2;
805 //Mask
806 oHeader.IsMasked = Convert.ToBoolean((pBuffer[pOffset + 1] & 0x80) >> 7);
807
808 // Payload length
809 oHeader.PayloadLen = (byte)(pBuffer[pOffset + 1] & 0x7F);
810
811 int index = 2; // LargerPayload length starts at byte 3
812
813 switch (oHeader.PayloadLen)
814 {
815 case 126:
816 minumheadersize += 2;
817 if (length < minumheadersize)
818 {
819 moveBuffer = 0;
820 return false;
821 }
822 Array.Reverse(pBuffer, pOffset + index, 2); // two bytes
823 oHeader.PayloadLen = BitConverter.ToUInt16(pBuffer, pOffset + index);
824 index += 2;
825 break;
826 case 127: // we got more this is a bigger frame
827 // 8 bytes - uint64 - most significant bit 0 network byte order
828 minumheadersize += 8;
829 if (length < minumheadersize)
830 {
831 moveBuffer = 0;
832 return false;
833 }
834 Array.Reverse(pBuffer, pOffset + index, 8);
835 oHeader.PayloadLen = BitConverter.ToUInt64(pBuffer, pOffset + index);
836 index += 8;
837 break;
838
839 }
840 //oHeader.PayloadLeft = oHeader.PayloadLen; // Start the count in case it's chunked over the network. This is different then frame fragmentation
841 if (oHeader.IsMasked)
842 {
843 minumheadersize += 4;
844 if (length < minumheadersize)
845 {
846 moveBuffer = 0;
847 return false;
848 }
849 oHeader.Mask = BitConverter.ToInt32(pBuffer, pOffset + index);
850 index += 4;
851 }
852 moveBuffer = index;
853 return true;
854
855 }
856 }
857
858 /// <summary>
859 /// RFC6455 Websocket Frame
860 /// </summary>
861 public class WebSocketFrame
862 {
863 /*
864 * RFC6455
865nib 0 1 2 3 4 5 6 7
866byt 0 1 2 3
867dec 0 1 2 3
868 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
869 +-+-+-+-+-------+-+-------------+-------------------------------+
870 |F|R|R|R| opcode|M| Payload len | Extended payload length |
871 |I|S|S|S| (4) |A| (7) | (16/64) +
872 |N|V|V|V| |S| | (if payload len==126/127) |
873 | |1|2|3| |K| | +
874 +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
875 | Extended payload length continued, if payload len == 127 |
876 + - - - - - - - - - - - - - - - +-------------------------------+
877 | |Masking-key, if MASK set to 1 |
878 +-------------------------------+-------------------------------+
879 | Masking-key (continued) | Payload Data |
880 +-------------------------------- - - - - - - - - - - - - - - - +
881 : Payload Data continued ... :
882 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
883 | Payload Data continued ... |
884 +---------------------------------------------------------------+
885
886 * When reading these, the frames are possibly fragmented and interleaved with control frames
887 * the fragmented frames are not interleaved with data frames. Just control frames
888 */
889 public static readonly WebSocketFrame DefaultFrame = new WebSocketFrame(){Header = new WebsocketFrameHeader(),WebSocketPayload = new byte[0]};
890 public WebsocketFrameHeader Header;
891 public byte[] WebSocketPayload;
892
893 public byte[] ToBytes()
894 {
895 Header.PayloadLen = (ulong)WebSocketPayload.Length;
896 return Header.ToBytes(WebSocketPayload);
897 }
898
899 }
900
901 public struct WebsocketFrameHeader
902 {
903 //public byte CurrentMaskIndex;
904 /// <summary>
905 /// The last frame in a sequence of fragmented frames or the one and only frame for this message.
906 /// </summary>
907 public bool IsEnd;
908
909 /// <summary>
910 /// Returns whether the payload data is masked or not. Data from Clients MUST be masked, Data from Servers MUST NOT be masked
911 /// </summary>
912 public bool IsMasked;
913
914 /// <summary>
915 /// A set of cryptologically sound random bytes XoR-ed against the payload octally. Looped
916 /// </summary>
917 public int Mask;
918 /*
919byt 0 1 2 3
920 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
921 +---------------+---------------+---------------+---------------+
922 | Octal 1 | Octal 2 | Octal 3 | Octal 4 |
923 +---------------+---------------+---------------+---------------+
924*/
925
926
927 public WebSocketReader.OpCode Opcode;
928
929 public UInt64 PayloadLen;
930 //public UInt64 PayloadLeft;
931 // Payload is X + Y
932 //public UInt64 ExtensionDataLength;
933 //public UInt64 ApplicationDataLength;
934 public static readonly WebsocketFrameHeader ZeroHeader = WebsocketFrameHeader.HeaderDefault();
935
936 public void SetDefault()
937 {
938
939 //CurrentMaskIndex = 0;
940 IsEnd = true;
941 IsMasked = true;
942 Mask = 0;
943 Opcode = WebSocketReader.OpCode.Close;
944 // PayloadLeft = 0;
945 PayloadLen = 0;
946 // ExtensionDataLength = 0;
947 // ApplicationDataLength = 0;
948
949 }
950
951 /// <summary>
952 /// Returns a byte array representing the Frame header
953 /// </summary>
954 /// <param name="payload">This is the frame data payload. The header describes the size of the payload.
955 /// If payload is null, a Zero sized payload is assumed</param>
956 /// <returns>Returns a byte array representing the frame header</returns>
957 public byte[] ToBytes(byte[] payload)
958 {
959 List<byte> result = new List<byte>();
960
961 // Squeeze in our opcode and our ending bit.
962 result.Add((byte)((byte)Opcode | (IsEnd?0x80:0x00) ));
963
964 // Again with the three different byte interpretations of size..
965
966 //bytesize
967 if (PayloadLen <= 125)
968 {
969 result.Add((byte) PayloadLen);
970 } //Uint16
971 else if (PayloadLen <= ushort.MaxValue)
972 {
973 result.Add(126);
974 byte[] payloadLengthByte = BitConverter.GetBytes(Convert.ToUInt16(PayloadLen));
975 Array.Reverse(payloadLengthByte);
976 result.AddRange(payloadLengthByte);
977 } //UInt64
978 else
979 {
980 result.Add(127);
981 byte[] payloadLengthByte = BitConverter.GetBytes(PayloadLen);
982 Array.Reverse(payloadLengthByte);
983 result.AddRange(payloadLengthByte);
984 }
985
986 // Only add a payload if it's not null
987 if (payload != null)
988 {
989 result.AddRange(payload);
990 }
991 return result.ToArray();
992 }
993
994 /// <summary>
995 /// A Helper method to define the defaults
996 /// </summary>
997 /// <returns></returns>
998
999 public static WebsocketFrameHeader HeaderDefault()
1000 {
1001 return new WebsocketFrameHeader
1002 {
1003 //CurrentMaskIndex = 0,
1004 IsEnd = false,
1005 IsMasked = true,
1006 Mask = 0,
1007 Opcode = WebSocketReader.OpCode.Close,
1008 //PayloadLeft = 0,
1009 PayloadLen = 0,
1010 // ExtensionDataLength = 0,
1011 // ApplicationDataLength = 0
1012 };
1013 }
1014 }
1015
1016 public delegate void DataDelegate(object sender, WebsocketDataEventArgs data);
1017
1018 public delegate void TextDelegate(object sender, WebsocketTextEventArgs text);
1019
1020 public delegate void PingDelegate(object sender, PingEventArgs pingdata);
1021
1022 public delegate void PongDelegate(object sender, PongEventArgs pongdata);
1023
1024 public delegate void RegularHttpRequestDelegate(object sender, RegularHttpRequestEvnetArgs request);
1025
1026 public delegate void UpgradeCompletedDelegate(object sender, UpgradeCompletedEventArgs completeddata);
1027
1028 public delegate void UpgradeFailedDelegate(object sender, UpgradeFailedEventArgs faileddata);
1029
1030 public delegate void CloseDelegate(object sender, CloseEventArgs closedata);
1031
1032 public delegate bool ValidateHandshake(string pWebOrigin, string pWebSocketKey, string pHost);
1033
1034
1035 public class WebsocketDataEventArgs : EventArgs
1036 {
1037 public byte[] Data;
1038 }
1039
1040 public class WebsocketTextEventArgs : EventArgs
1041 {
1042 public string Data;
1043 }
1044
1045 public class PingEventArgs : EventArgs
1046 {
1047 /// <summary>
1048 /// The ping event can arbitrarily contain data
1049 /// </summary>
1050 public byte[] Data;
1051 }
1052
1053 public class PongEventArgs : EventArgs
1054 {
1055 /// <summary>
1056 /// The pong event can arbitrarily contain data
1057 /// </summary>
1058 public byte[] Data;
1059
1060 public int PingResponseMS;
1061
1062 }
1063
1064 public class RegularHttpRequestEvnetArgs : EventArgs
1065 {
1066
1067 }
1068
1069 public class UpgradeCompletedEventArgs : EventArgs
1070 {
1071
1072 }
1073
1074 public class UpgradeFailedEventArgs : EventArgs
1075 {
1076
1077 }
1078
1079 public class CloseEventArgs : EventArgs
1080 {
1081
1082 }
1083
1084
1085}
diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs
index ae7d515..293887f 100644
--- a/OpenSim/Framework/Servers/MainServer.cs
+++ b/OpenSim/Framework/Servers/MainServer.cs
@@ -230,6 +230,10 @@ namespace OpenSim.Framework.Servers
230 List<String> poll = httpServer.GetPollServiceHandlerKeys(); 230 List<String> poll = httpServer.GetPollServiceHandlerKeys();
231 foreach (String s in httpServer.GetHTTPHandlerKeys()) 231 foreach (String s in httpServer.GetHTTPHandlerKeys())
232 handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty)); 232 handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
233
234 handlers.AppendFormat("* JSONRPC:\n");
235 foreach (String s in httpServer.GetJsonRpcHandlerKeys())
236 handlers.AppendFormat("\t{0}\n", s);
233 237
234// handlers.AppendFormat("* Agent:\n"); 238// handlers.AppendFormat("* Agent:\n");
235// foreach (String s in httpServer.GetAgentHandlerKeys()) 239// foreach (String s in httpServer.GetAgentHandlerKeys())
diff --git a/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs
index 021f63c..792c62e 100644
--- a/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Servers/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.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs
index 9eb2281..65ccd10 100644
--- a/OpenSim/Framework/Servers/ServerBase.cs
+++ b/OpenSim/Framework/Servers/ServerBase.cs
@@ -27,16 +27,19 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Diagnostics;
30using System.IO; 31using System.IO;
31using System.Reflection; 32using System.Reflection;
32using System.Text; 33using System.Text;
33using System.Text.RegularExpressions; 34using System.Text.RegularExpressions;
35using System.Threading;
34using log4net; 36using log4net;
35using log4net.Appender; 37using log4net.Appender;
36using log4net.Core; 38using log4net.Core;
37using log4net.Repository; 39using log4net.Repository;
38using Nini.Config; 40using Nini.Config;
39using OpenSim.Framework.Console; 41using OpenSim.Framework.Console;
42using OpenSim.Framework.Monitoring;
40 43
41namespace OpenSim.Framework.Servers 44namespace OpenSim.Framework.Servers
42{ 45{
@@ -168,6 +171,9 @@ namespace OpenSim.Framework.Servers
168 "General", false, "show info", "show info", "Show general information about the server", HandleShow); 171 "General", false, "show info", "show info", "Show general information about the server", HandleShow);
169 172
170 m_console.Commands.AddCommand( 173 m_console.Commands.AddCommand(
174 "General", false, "show version", "show version", "Show server version", HandleShow);
175
176 m_console.Commands.AddCommand(
171 "General", false, "show uptime", "show uptime", "Show server uptime", HandleShow); 177 "General", false, "show uptime", "show uptime", "Show server uptime", HandleShow);
172 178
173 m_console.Commands.AddCommand( 179 m_console.Commands.AddCommand(
@@ -206,6 +212,34 @@ namespace OpenSim.Framework.Servers
206 "General", false, "command-script", 212 "General", false, "command-script",
207 "command-script <script>", 213 "command-script <script>",
208 "Run a command script from file", HandleScript); 214 "Run a command script from file", HandleScript);
215
216 m_console.Commands.AddCommand(
217 "General", false, "show threads",
218 "show threads",
219 "Show thread status", HandleShow);
220
221 m_console.Commands.AddCommand(
222 "General", false, "threads abort",
223 "threads abort <thread-id>",
224 "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
225
226 m_console.Commands.AddCommand(
227 "General", false, "threads show",
228 "threads show",
229 "Show thread status. Synonym for \"show threads\"",
230 (string module, string[] args) => Notice(GetThreadsReport()));
231
232 m_console.Commands.AddCommand(
233 "General", false, "force gc",
234 "force gc",
235 "Manually invoke runtime garbage collection. For debugging purposes",
236 HandleForceGc);
237 }
238
239 private void HandleForceGc(string module, string[] args)
240 {
241 Notice("Manually invoking runtime garbage collection");
242 GC.Collect();
209 } 243 }
210 244
211 public virtual void HandleShow(string module, string[] cmd) 245 public virtual void HandleShow(string module, string[] cmd)
@@ -222,9 +256,17 @@ namespace OpenSim.Framework.Servers
222 ShowInfo(); 256 ShowInfo();
223 break; 257 break;
224 258
259 case "version":
260 Notice(GetVersionText());
261 break;
262
225 case "uptime": 263 case "uptime":
226 Notice(GetUptimeReport()); 264 Notice(GetUptimeReport());
227 break; 265 break;
266
267 case "threads":
268 Notice(GetThreadsReport());
269 break;
228 } 270 }
229 } 271 }
230 272
@@ -537,6 +579,75 @@ namespace OpenSim.Framework.Servers
537 } 579 }
538 580
539 /// <summary> 581 /// <summary>
582 /// Get a report about the registered threads in this server.
583 /// </summary>
584 protected string GetThreadsReport()
585 {
586 // This should be a constant field.
587 string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}";
588
589 StringBuilder sb = new StringBuilder();
590 Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo();
591
592 sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine);
593
594 int timeNow = Environment.TickCount & Int32.MaxValue;
595
596 sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE");
597 sb.Append(Environment.NewLine);
598
599 foreach (Watchdog.ThreadWatchdogInfo twi in threads)
600 {
601 Thread t = twi.Thread;
602
603 sb.AppendFormat(
604 reportFormat,
605 t.ManagedThreadId,
606 t.Name,
607 timeNow - twi.LastTick,
608 timeNow - twi.FirstTick,
609 t.Priority,
610 t.ThreadState);
611
612 sb.Append("\n");
613 }
614
615 sb.Append("\n");
616
617 // For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting
618 // zero active threads.
619 int totalThreads = Process.GetCurrentProcess().Threads.Count;
620 if (totalThreads > 0)
621 sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
622
623 sb.Append("Main threadpool (excluding script engine pools)\n");
624 sb.Append(Util.GetThreadPoolReport());
625
626 return sb.ToString();
627 }
628
629 public virtual void HandleThreadsAbort(string module, string[] cmd)
630 {
631 if (cmd.Length != 3)
632 {
633 MainConsole.Instance.Output("Usage: threads abort <thread-id>");
634 return;
635 }
636
637 int threadId;
638 if (!int.TryParse(cmd[2], out threadId))
639 {
640 MainConsole.Instance.Output("ERROR: Thread id must be an integer");
641 return;
642 }
643
644 if (Watchdog.AbortThread(threadId))
645 MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId);
646 else
647 MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId);
648 }
649
650 /// <summary>
540 /// Console output is only possible if a console has been established. 651 /// Console output is only possible if a console has been established.
541 /// That is something that cannot be determined within this class. So 652 /// That is something that cannot be determined within this class. So
542 /// all attempts to use the console MUST be verified. 653 /// all attempts to use the console MUST be verified.
diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
index 4c2f586..deae45c 100644
--- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
+++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
@@ -35,11 +35,12 @@ using HttpServer;
35using HttpServer.FormDecoders; 35using HttpServer.FormDecoders;
36using NUnit.Framework; 36using NUnit.Framework;
37using OpenSim.Framework.Servers.HttpServer; 37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Tests.Common;
38 39
39namespace OpenSim.Framework.Servers.Tests 40namespace OpenSim.Framework.Servers.Tests
40{ 41{
41 [TestFixture] 42 [TestFixture]
42 public class OSHttpTests 43 public class OSHttpTests : OpenSimTestCase
43 { 44 {
44 // we need an IHttpClientContext for our tests 45 // we need an IHttpClientContext for our tests
45 public class TestHttpClientContext: IHttpClientContext 46 public class TestHttpClientContext: IHttpClientContext
@@ -69,6 +70,11 @@ namespace OpenSim.Framework.Servers.Tests
69 public void Close() { } 70 public void Close() { }
70 public bool EndWhenDone { get { return false;} set { return;}} 71 public bool EndWhenDone { get { return false;} set { return;}}
71 72
73 public HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing()
74 {
75 return new HTTPNetworkContext();
76 }
77
72 public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { }; 78 public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { };
73 /// <summary> 79 /// <summary>
74 /// A request have been received in the context. 80 /// A request have been received in the context.
diff --git a/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs b/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs
index 49e5061..480f2bb 100644
--- a/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs
+++ b/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs
@@ -29,11 +29,12 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31using NUnit.Framework; 31using NUnit.Framework;
32using OpenSim.Tests.Common;
32 33
33namespace OpenSim.Framework.Servers.Tests 34namespace OpenSim.Framework.Servers.Tests
34{ 35{
35 [TestFixture] 36 [TestFixture]
36 public class VersionInfoTests 37 public class VersionInfoTests : OpenSimTestCase
37 { 38 {
38 [Test] 39 [Test]
39 public void TestVersionLength() 40 public void TestVersionLength()
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs
index bb094ed..737c14d 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.5CM"; 32 private const string VERSION_NUMBER = "0.7.6CM";
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
diff --git a/OpenSim/Framework/Tests/AgentCircuitDataTest.cs b/OpenSim/Framework/Tests/AgentCircuitDataTest.cs
index 0dce414..95e9439 100644
--- a/OpenSim/Framework/Tests/AgentCircuitDataTest.cs
+++ b/OpenSim/Framework/Tests/AgentCircuitDataTest.cs
@@ -24,16 +24,17 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27
27using System.Collections.Generic; 28using System.Collections.Generic;
28using OpenMetaverse; 29using OpenMetaverse;
29using OpenMetaverse.StructuredData; 30using OpenMetaverse.StructuredData;
30using NUnit.Framework; 31using NUnit.Framework;
31 32using OpenSim.Tests.Common;
32 33
33namespace OpenSim.Framework.Tests 34namespace OpenSim.Framework.Tests
34{ 35{
35 [TestFixture] 36 [TestFixture]
36 public class AgentCircuitDataTest 37 public class AgentCircuitDataTest : OpenSimTestCase
37 { 38 {
38 private UUID AgentId; 39 private UUID AgentId;
39 private AvatarAppearance AvAppearance; 40 private AvatarAppearance AvAppearance;
diff --git a/OpenSim/Framework/Tests/AnimationTests.cs b/OpenSim/Framework/Tests/AnimationTests.cs
index 967a355..f3be81b 100644
--- a/OpenSim/Framework/Tests/AnimationTests.cs
+++ b/OpenSim/Framework/Tests/AnimationTests.cs
@@ -38,7 +38,7 @@ using Animation = OpenSim.Framework.Animation;
38namespace OpenSim.Framework.Tests 38namespace OpenSim.Framework.Tests
39{ 39{
40 [TestFixture] 40 [TestFixture]
41 public class AnimationTests 41 public class AnimationTests : OpenSimTestCase
42 { 42 {
43 private Animation anim1 = null; 43 private Animation anim1 = null;
44 private Animation anim2 = null; 44 private Animation anim2 = null;
diff --git a/OpenSim/Framework/Tests/AssetBaseTest.cs b/OpenSim/Framework/Tests/AssetBaseTest.cs
index 6db1aa0..25d2393 100644
--- a/OpenSim/Framework/Tests/AssetBaseTest.cs
+++ b/OpenSim/Framework/Tests/AssetBaseTest.cs
@@ -30,11 +30,12 @@ using System.Collections.Generic;
30using System.Text; 30using System.Text;
31using NUnit.Framework; 31using NUnit.Framework;
32using OpenMetaverse; 32using OpenMetaverse;
33using OpenSim.Tests.Common;
33 34
34namespace OpenSim.Framework.Tests 35namespace OpenSim.Framework.Tests
35{ 36{
36 [TestFixture] 37 [TestFixture]
37 public class AssetBaseTest 38 public class AssetBaseTest : OpenSimTestCase
38 { 39 {
39 [Test] 40 [Test]
40 public void TestContainsReferences() 41 public void TestContainsReferences()
diff --git a/OpenSim/Framework/Tests/CacheTests.cs b/OpenSim/Framework/Tests/CacheTests.cs
index c3613e6..c709860 100644
--- a/OpenSim/Framework/Tests/CacheTests.cs
+++ b/OpenSim/Framework/Tests/CacheTests.cs
@@ -28,11 +28,12 @@
28using System; 28using System;
29using NUnit.Framework; 29using NUnit.Framework;
30using OpenMetaverse; 30using OpenMetaverse;
31using OpenSim.Tests.Common;
31 32
32namespace OpenSim.Framework.Tests 33namespace OpenSim.Framework.Tests
33{ 34{
34 [TestFixture] 35 [TestFixture]
35 public class CacheTests 36 public class CacheTests : OpenSimTestCase
36 { 37 {
37 private Cache cache; 38 private Cache cache;
38 private UUID cacheItemUUID; 39 private UUID cacheItemUUID;
diff --git a/OpenSim/Framework/Tests/LocationTest.cs b/OpenSim/Framework/Tests/LocationTest.cs
index 2707afa..a56ecb4 100644
--- a/OpenSim/Framework/Tests/LocationTest.cs
+++ b/OpenSim/Framework/Tests/LocationTest.cs
@@ -26,11 +26,12 @@
26 */ 26 */
27 27
28using NUnit.Framework; 28using NUnit.Framework;
29using OpenSim.Tests.Common;
29 30
30namespace OpenSim.Framework.Tests 31namespace OpenSim.Framework.Tests
31{ 32{
32 [TestFixture] 33 [TestFixture]
33 public class LocationTest 34 public class LocationTest : OpenSimTestCase
34 { 35 {
35 [Test] 36 [Test]
36 public void locationRegionHandleRegionHandle() 37 public void locationRegionHandleRegionHandle()
diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
index 6fde488..0fbdaf3 100644
--- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
+++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
@@ -32,11 +32,12 @@ using OpenMetaverse.StructuredData;
32using System; 32using System;
33using System.Globalization; 33using System.Globalization;
34using System.Threading; 34using System.Threading;
35using OpenSim.Tests.Common;
35 36
36namespace OpenSim.Framework.Tests 37namespace OpenSim.Framework.Tests
37{ 38{
38 [TestFixture] 39 [TestFixture]
39 public class MundaneFrameworkTests 40 public class MundaneFrameworkTests : OpenSimTestCase
40 { 41 {
41 private bool m_RegionSettingsOnSaveEventFired; 42 private bool m_RegionSettingsOnSaveEventFired;
42 private bool m_RegionLightShareDataOnSaveEventFired; 43 private bool m_RegionLightShareDataOnSaveEventFired;
@@ -302,10 +303,6 @@ namespace OpenSim.Framework.Tests
302 Culture.SetCurrentCulture(); 303 Culture.SetCurrentCulture();
303 Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US"); 304 Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US");
304 305
305 } 306 }
306
307
308
309 } 307 }
310} 308} \ No newline at end of file
311
diff --git a/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs b/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs
index 36bc6e7..82e13e5 100644
--- a/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs
+++ b/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs
@@ -31,11 +31,12 @@ using NUnit.Framework;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenMetaverse.StructuredData; 32using OpenMetaverse.StructuredData;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Tests.Common;
34 35
35namespace OpenSim.Framework.Tests 36namespace OpenSim.Framework.Tests
36{ 37{
37 [TestFixture] 38 [TestFixture]
38 public class PrimeNumberHelperTests 39 public class PrimeNumberHelperTests : OpenSimTestCase
39 { 40 {
40 [Test] 41 [Test]
41 public void TestGetPrime() 42 public void TestGetPrime()
diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs
index f0d2a3f..11ca068 100644
--- a/OpenSim/Framework/Tests/UtilTest.cs
+++ b/OpenSim/Framework/Tests/UtilTest.cs
@@ -33,7 +33,7 @@ using OpenSim.Tests.Common;
33namespace OpenSim.Framework.Tests 33namespace OpenSim.Framework.Tests
34{ 34{
35 [TestFixture] 35 [TestFixture]
36 public class UtilTests 36 public class UtilTests : OpenSimTestCase
37 { 37 {
38 [Test] 38 [Test]
39 public void VectorOperationTests() 39 public void VectorOperationTests()
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 48f3f8b..0545365 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -45,6 +45,7 @@ using System.Text.RegularExpressions;
45using System.Xml; 45using System.Xml;
46using System.Threading; 46using System.Threading;
47using log4net; 47using log4net;
48using log4net.Appender;
48using Nini.Config; 49using Nini.Config;
49using Nwc.XmlRpc; 50using Nwc.XmlRpc;
50using OpenMetaverse; 51using OpenMetaverse;
@@ -299,6 +300,25 @@ namespace OpenSim.Framework
299 x; 300 x;
300 } 301 }
301 302
303 // Clamp the maximum magnitude of a vector
304 public static Vector3 ClampV(Vector3 x, float max)
305 {
306 Vector3 ret = x;
307 float lenSq = x.LengthSquared();
308 if (lenSq > (max * max))
309 {
310 x = x / x.Length() * max;
311 }
312 return x;
313 }
314
315 // Inclusive, within range test (true if equal to the endpoints)
316 public static bool InRange<T>(T x, T min, T max)
317 where T : IComparable<T>
318 {
319 return x.CompareTo(max) <= 0 && x.CompareTo(min) >= 0;
320 }
321
302 public static uint GetNextXferID() 322 public static uint GetNextXferID()
303 { 323 {
304 uint id = 0; 324 uint id = 0;
@@ -809,9 +829,22 @@ namespace OpenSim.Framework
809 return "."; 829 return ".";
810 } 830 }
811 831
832 public static string logFile()
833 {
834 foreach (IAppender appender in LogManager.GetRepository().GetAppenders())
835 {
836 if (appender is FileAppender)
837 {
838 return ((FileAppender)appender).File;
839 }
840 }
841
842 return "./OpenSim.log";
843 }
844
812 public static string logDir() 845 public static string logDir()
813 { 846 {
814 return "."; 847 return Path.GetDirectoryName(logFile());
815 } 848 }
816 849
817 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html 850 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html
@@ -1651,7 +1684,13 @@ namespace OpenSim.Framework
1651 if (m_ThreadPool != null) 1684 if (m_ThreadPool != null)
1652 throw new InvalidOperationException("SmartThreadPool is already initialized"); 1685 throw new InvalidOperationException("SmartThreadPool is already initialized");
1653 1686
1654 m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); 1687 STPStartInfo startInfo = new STPStartInfo();
1688 startInfo.ThreadPoolName = "Util";
1689 startInfo.IdleTimeout = 2000;
1690 startInfo.MaxWorkerThreads = maxThreads;
1691 startInfo.MinWorkerThreads = 2;
1692
1693 m_ThreadPool = new SmartThreadPool(startInfo);
1655 } 1694 }
1656 1695
1657 public static int FireAndForgetCount() 1696 public static int FireAndForgetCount()
@@ -1724,7 +1763,7 @@ namespace OpenSim.Framework
1724 break; 1763 break;
1725 case FireAndForgetMethod.SmartThreadPool: 1764 case FireAndForgetMethod.SmartThreadPool:
1726 if (m_ThreadPool == null) 1765 if (m_ThreadPool == null)
1727 m_ThreadPool = new SmartThreadPool(2000, 15, 2); 1766 InitThreadPool(15);
1728 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); 1767 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj });
1729 break; 1768 break;
1730 case FireAndForgetMethod.Thread: 1769 case FireAndForgetMethod.Thread:
@@ -1753,12 +1792,16 @@ namespace OpenSim.Framework
1753 StringBuilder sb = new StringBuilder(); 1792 StringBuilder sb = new StringBuilder();
1754 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) 1793 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
1755 { 1794 {
1756 threadPoolUsed = "SmartThreadPool"; 1795 // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
1757 maxThreads = m_ThreadPool.MaxThreads; 1796 if (m_ThreadPool != null)
1758 minThreads = m_ThreadPool.MinThreads; 1797 {
1759 inUseThreads = m_ThreadPool.InUseThreads; 1798 threadPoolUsed = "SmartThreadPool";
1760 allocatedThreads = m_ThreadPool.ActiveThreads; 1799 maxThreads = m_ThreadPool.MaxThreads;
1761 waitingCallbacks = m_ThreadPool.WaitingCallbacks; 1800 minThreads = m_ThreadPool.MinThreads;
1801 inUseThreads = m_ThreadPool.InUseThreads;
1802 allocatedThreads = m_ThreadPool.ActiveThreads;
1803 waitingCallbacks = m_ThreadPool.WaitingCallbacks;
1804 }
1762 } 1805 }
1763 else if ( 1806 else if (
1764 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem 1807 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem
@@ -1863,6 +1906,12 @@ namespace OpenSim.Framework
1863 /// </summary> 1906 /// </summary>
1864 public static void PrintCallStack() 1907 public static void PrintCallStack()
1865 { 1908 {
1909 PrintCallStack(m_log.DebugFormat);
1910 }
1911
1912 public delegate void DebugPrinter(string msg, params Object[] parm);
1913 public static void PrintCallStack(DebugPrinter printer)
1914 {
1866 StackTrace stackTrace = new StackTrace(true); // get call stack 1915 StackTrace stackTrace = new StackTrace(true); // get call stack
1867 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) 1916 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
1868 1917
@@ -1870,7 +1919,7 @@ namespace OpenSim.Framework
1870 foreach (StackFrame stackFrame in stackFrames) 1919 foreach (StackFrame stackFrame in stackFrames)
1871 { 1920 {
1872 MethodBase mb = stackFrame.GetMethod(); 1921 MethodBase mb = stackFrame.GetMethod();
1873 m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name 1922 printer("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name
1874 } 1923 }
1875 } 1924 }
1876 1925
@@ -2096,6 +2145,17 @@ namespace OpenSim.Framework
2096 return firstName + "." + lastName + " " + "@" + uri.Authority; 2145 return firstName + "." + lastName + " " + "@" + uri.Authority;
2097 } 2146 }
2098 #endregion 2147 #endregion
2148
2149 /// <summary>
2150 /// Escapes the special characters used in "LIKE".
2151 /// </summary>
2152 /// <remarks>
2153 /// For example: EscapeForLike("foo_bar%baz") = "foo\_bar\%baz"
2154 /// </remarks>
2155 public static string EscapeForLike(string str)
2156 {
2157 return str.Replace("_", "\\_").Replace("%", "\\%");
2158 }
2099 } 2159 }
2100 2160
2101 public class DoubleQueue<T> where T:class 2161 public class DoubleQueue<T> where T:class