aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Data/MySQL/MySQLSimulationData.cs4
-rw-r--r--OpenSim/Framework/DAMap.cs7
-rw-r--r--OpenSim/Framework/IClientAPI.cs4
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs46
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs10
-rw-r--r--OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs1085
-rw-r--r--OpenSim/Framework/Servers/Tests/OSHttpTests.cs5
-rw-r--r--OpenSim/Framework/Util.cs16
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs35
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs8
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs20
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs59
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEventQueue.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs25
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs5
-rw-r--r--OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs174
-rwxr-xr-xOpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs19
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs61
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs5
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs36
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs1
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs41
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs28
-rwxr-xr-xOpenSim/Region/Physics/Manager/IPhysicsParameters.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs2
-rw-r--r--OpenSim/Region/UserStatistics/WebStatsModule.cs2
-rw-r--r--OpenSim/Tests/Common/Mock/MockScriptEngine.cs2
-rw-r--r--OpenSim/Tests/Common/Mock/TestClient.cs5
30 files changed, 1651 insertions, 75 deletions
diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs
index 41174f4..1b02b4f 100644
--- a/OpenSim/Data/MySQL/MySQLSimulationData.cs
+++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs
@@ -1311,7 +1311,7 @@ namespace OpenSim.Data.MySQL
1311 prim.Density = (float)(double)row["Density"]; 1311 prim.Density = (float)(double)row["Density"];
1312 prim.GravityModifier = (float)(double)row["GravityModifier"]; 1312 prim.GravityModifier = (float)(double)row["GravityModifier"];
1313 prim.Friction = (float)(double)row["Friction"]; 1313 prim.Friction = (float)(double)row["Friction"];
1314 prim.Bounciness = (float)(double)row["Restitution"]; 1314 prim.Restitution = (float)(double)row["Restitution"];
1315 1315
1316 return prim; 1316 return prim;
1317 } 1317 }
@@ -1663,7 +1663,7 @@ namespace OpenSim.Data.MySQL
1663 cmd.Parameters.AddWithValue("Density", (double)prim.Density); 1663 cmd.Parameters.AddWithValue("Density", (double)prim.Density);
1664 cmd.Parameters.AddWithValue("GravityModifier", (double)prim.GravityModifier); 1664 cmd.Parameters.AddWithValue("GravityModifier", (double)prim.GravityModifier);
1665 cmd.Parameters.AddWithValue("Friction", (double)prim.Friction); 1665 cmd.Parameters.AddWithValue("Friction", (double)prim.Friction);
1666 cmd.Parameters.AddWithValue("Restitution", (double)prim.Bounciness); 1666 cmd.Parameters.AddWithValue("Restitution", (double)prim.Restitution);
1667 1667
1668 if (prim.DynAttrs.Count > 0) 1668 if (prim.DynAttrs.Count > 0)
1669 cmd.Parameters.AddWithValue("DynAttrs", prim.DynAttrs.ToXml()); 1669 cmd.Parameters.AddWithValue("DynAttrs", prim.DynAttrs.ToXml());
diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs
index 7d7738a..64cea77 100644
--- a/OpenSim/Framework/DAMap.cs
+++ b/OpenSim/Framework/DAMap.cs
@@ -176,6 +176,10 @@ namespace OpenSim.Framework
176 } 176 }
177 } 177 }
178 178
179 /// <summary>
180 /// Validate the key used for storing separate data stores.
181 /// </summary>
182 /// <param name='key'></param>
179 private static void ValidateKey(string key) 183 private static void ValidateKey(string key)
180 { 184 {
181 if (key.Length < MIN_STORE_NAME_LENGTH) 185 if (key.Length < MIN_STORE_NAME_LENGTH)
@@ -196,7 +200,8 @@ namespace OpenSim.Framework
196 } 200 }
197 201
198 public void Add(KeyValuePair<string, OSDMap> kvp) 202 public void Add(KeyValuePair<string, OSDMap> kvp)
199 { 203 {
204 ValidateKey(kvp.Key);
200 lock (this) 205 lock (this)
201 m_map.Add(kvp.Key, kvp.Value); 206 m_map.Add(kvp.Key, kvp.Value);
202 } 207 }
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 87433cc..f6b7689 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -124,7 +124,7 @@ namespace OpenSim.Framework
124 public delegate void ObjectDrop(uint localID, IClientAPI remoteClient); 124 public delegate void ObjectDrop(uint localID, IClientAPI remoteClient);
125 125
126 public delegate void UpdatePrimFlags( 126 public delegate void UpdatePrimFlags(
127 uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, IClientAPI remoteClient); 127 uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient);
128 128
129 public delegate void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient); 129 public delegate void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient);
130 130
@@ -1356,6 +1356,8 @@ namespace OpenSim.Framework
1356 1356
1357 void SendObjectPropertiesReply(ISceneEntity Entity); 1357 void SendObjectPropertiesReply(ISceneEntity Entity);
1358 1358
1359 void SendPartPhysicsProprieties(ISceneEntity Entity);
1360
1359 void SendAgentOffline(UUID[] agentIDs); 1361 void SendAgentOffline(UUID[] agentIDs);
1360 1362
1361 void SendAgentOnline(UUID[] agentIDs); 1363 void SendAgentOnline(UUID[] agentIDs);
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index b24336d..70c531c 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>
@@ -87,6 +97,9 @@ namespace OpenSim.Framework.Servers.HttpServer
87 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = 97 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
88 new Dictionary<string, PollServiceEventArgs>(); 98 new Dictionary<string, PollServiceEventArgs>();
89 99
100 protected Dictionary<string, WebSocketRequestDelegate> m_WebSocketHandlers =
101 new Dictionary<string, WebSocketRequestDelegate>();
102
90 protected uint m_port; 103 protected uint m_port;
91 protected uint m_sslport; 104 protected uint m_sslport;
92 protected bool m_ssl; 105 protected bool m_ssl;
@@ -170,6 +183,22 @@ namespace OpenSim.Framework.Servers.HttpServer
170 } 183 }
171 } 184 }
172 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
173 public List<string> GetStreamHandlerKeys() 202 public List<string> GetStreamHandlerKeys()
174 { 203 {
175 lock (m_streamHandlers) 204 lock (m_streamHandlers)
@@ -409,9 +438,24 @@ namespace OpenSim.Framework.Servers.HttpServer
409 438
410 public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) 439 public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
411 { 440 {
441
412 OSHttpRequest req = new OSHttpRequest(context, request); 442 OSHttpRequest req = new OSHttpRequest(context, request);
443 WebSocketRequestDelegate dWebSocketRequestDelegate = null;
444 lock (m_WebSocketHandlers)
445 {
446 if (m_WebSocketHandlers.ContainsKey(req.RawUrl))
447 dWebSocketRequestDelegate = m_WebSocketHandlers[req.RawUrl];
448 }
449 if (dWebSocketRequestDelegate != null)
450 {
451 dWebSocketRequestDelegate(req.Url.AbsolutePath, new WebSocketHttpServerHandler(req, context, 8192));
452 return;
453 }
454
413 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); 455 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
456
414 HandleRequest(req, resp); 457 HandleRequest(req, resp);
458
415 459
416 // !!!HACK ALERT!!! 460 // !!!HACK ALERT!!!
417 // There seems to be a bug in the underlying http code that makes subsequent requests 461 // There seems to be a bug in the underlying http code that makes subsequent requests
@@ -500,7 +544,7 @@ namespace OpenSim.Framework.Servers.HttpServer
500 LogIncomingToStreamHandler(request, requestHandler); 544 LogIncomingToStreamHandler(request, requestHandler);
501 545
502 response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. 546 response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
503 547
504 if (requestHandler is IStreamedRequestHandler) 548 if (requestHandler is IStreamedRequestHandler)
505 { 549 {
506 IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; 550 IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler;
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
index 13b5dd3..71ca3ff 100644
--- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
@@ -98,7 +98,17 @@ namespace OpenSim.Framework.Servers.HttpServer
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); 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
101 109
110 void RemoveWebSocketHandler(string servicepath);
111
102 /// <summary> 112 /// <summary>
103 /// Gets the XML RPC handler for given method name 113 /// Gets the XML RPC handler for given method name
104 /// </summary> 114 /// </summary>
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/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
index 3412e0f..5b912b4 100644
--- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
+++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
@@ -70,6 +70,11 @@ namespace OpenSim.Framework.Servers.Tests
70 public void Close() { } 70 public void Close() { }
71 public bool EndWhenDone { get { return false;} set { return;}} 71 public bool EndWhenDone { get { return false;} set { return;}}
72 72
73 public HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing()
74 {
75 return new HTTPNetworkContext();
76 }
77
73 public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { }; 78 public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { };
74 /// <summary> 79 /// <summary>
75 /// A request have been received in the context. 80 /// A request have been received in the context.
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 9b1e97d..d9148fb 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;
@@ -816,9 +817,22 @@ namespace OpenSim.Framework
816 return "."; 817 return ".";
817 } 818 }
818 819
820 public static string logFile()
821 {
822 foreach (IAppender appender in LogManager.GetRepository().GetAppenders())
823 {
824 if (appender is FileAppender)
825 {
826 return ((FileAppender)appender).File;
827 }
828 }
829
830 return "./OpenSim.log";
831 }
832
819 public static string logDir() 833 public static string logDir()
820 { 834 {
821 return "."; 835 return Path.GetDirectoryName(logFile());
822 } 836 }
823 837
824 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html 838 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 568e216..1af61db 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -96,6 +96,8 @@ namespace OpenSim.Region.ClientStack.Linden
96 // private static readonly string m_fetchInventoryPath = "0006/"; 96 // private static readonly string m_fetchInventoryPath = "0006/";
97 private static readonly string m_copyFromNotecardPath = "0007/"; 97 private static readonly string m_copyFromNotecardPath = "0007/";
98 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. 98 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
99 private static readonly string m_getObjectPhysicsDataPath = "0101/";
100 /* 0102 - 0103 RESERVED */
99 private static readonly string m_UpdateAgentInformationPath = "0500/"; 101 private static readonly string m_UpdateAgentInformationPath = "0500/";
100 102
101 // These are callbacks which will be setup by the scene so that we can update scene data when we 103 // These are callbacks which will be setup by the scene so that we can update scene data when we
@@ -204,6 +206,8 @@ namespace OpenSim.Region.ClientStack.Linden
204 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); 206 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
205 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); 207 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
206 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 208 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
209 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData);
210 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
207 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); 211 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
208 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 212 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
209 213
@@ -873,6 +877,37 @@ namespace OpenSim.Region.ClientStack.Linden
873 return LLSDHelpers.SerialiseLLSDReply(response); 877 return LLSDHelpers.SerialiseLLSDReply(response);
874 } 878 }
875 879
880 public string GetObjectPhysicsData(string request, string path,
881 string param, IOSHttpRequest httpRequest,
882 IOSHttpResponse httpResponse)
883 {
884 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
885 OSDMap resp = new OSDMap();
886 OSDArray object_ids = (OSDArray)req["object_ids"];
887
888 for (int i = 0 ; i < object_ids.Count ; i++)
889 {
890 UUID uuid = object_ids[i].AsUUID();
891
892 SceneObjectPart obj = m_Scene.GetSceneObjectPart(uuid);
893 if (obj != null)
894 {
895 OSDMap object_data = new OSDMap();
896
897 object_data["PhysicsShapeType"] = obj.PhysicsShapeType;
898 object_data["Density"] = obj.Density;
899 object_data["Friction"] = obj.Friction;
900 object_data["Restitution"] = obj.Restitution;
901 object_data["GravityMultiplier"] = obj.GravityModifier;
902
903 resp[uuid.ToString()] = object_data;
904 }
905 }
906
907 string response = OSDParser.SerializeLLSDXmlString(resp);
908 return response;
909 }
910
876 public string UpdateAgentInformation(string request, string path, 911 public string UpdateAgentInformation(string request, string path,
877 string param, IOSHttpRequest httpRequest, 912 string param, IOSHttpRequest httpRequest,
878 IOSHttpResponse httpResponse) 913 IOSHttpResponse httpResponse)
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index 4d2c0f2..3cc3950 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -807,5 +807,13 @@ namespace OpenSim.Region.ClientStack.Linden
807 { 807 {
808 return EventQueueHelper.BuildEvent(eventName, eventBody); 808 return EventQueueHelper.BuildEvent(eventName, eventBody);
809 } 809 }
810
811 public void partPhysicsProperties(uint localID, byte physhapetype,
812 float density, float friction, float bounce, float gravmod,UUID avatarID)
813 {
814 OSD item = EventQueueHelper.partPhysicsProperties(localID, physhapetype,
815 density, friction, bounce, gravmod);
816 Enqueue(item, avatarID);
817 }
810 } 818 }
811} 819}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index 3f49aba..dab727f 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -395,5 +395,25 @@ namespace OpenSim.Region.ClientStack.Linden
395 return message; 395 return message;
396 } 396 }
397 397
398 public static OSD partPhysicsProperties(uint localID, byte physhapetype,
399 float density, float friction, float bounce, float gravmod)
400 {
401
402 OSDMap physinfo = new OSDMap(6);
403 physinfo["LocalID"] = localID;
404 physinfo["Density"] = density;
405 physinfo["Friction"] = friction;
406 physinfo["GravityMultiplier"] = gravmod;
407 physinfo["Restitution"] = bounce;
408 physinfo["PhysicsShapeType"] = (int)physhapetype;
409
410 OSDArray array = new OSDArray(1);
411 array.Add(physinfo);
412
413 OSDMap llsdBody = new OSDMap(1);
414 llsdBody.Add("ObjectData", array);
415
416 return BuildEvent("ObjectPhysicsProperties", llsdBody);
417 }
398 } 418 }
399} 419}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 88b64f5..bd4a2d1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -2627,6 +2627,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2627 } 2627 }
2628 } 2628 }
2629 2629
2630 public void SendPartPhysicsProprieties(ISceneEntity entity)
2631 {
2632 SceneObjectPart part = (SceneObjectPart)entity;
2633 if (part != null && AgentId != UUID.Zero)
2634 {
2635 try
2636 {
2637 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
2638 if (eq != null)
2639 {
2640 uint localid = part.LocalId;
2641 byte physshapetype = part.PhysicsShapeType;
2642 float density = part.Density;
2643 float friction = part.Friction;
2644 float bounce = part.Restitution;
2645 float gravmod = part.GravityModifier;
2646 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2647 }
2648 }
2649 catch (Exception ex)
2650 {
2651 m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString());
2652 }
2653 part.UpdatePhysRequired = false;
2654 }
2655 }
2656
2657
2630 2658
2631 public void SendGroupNameReply(UUID groupLLUID, string GroupName) 2659 public void SendGroupNameReply(UUID groupLLUID, string GroupName)
2632 { 2660 {
@@ -7035,10 +7063,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7035 // 46,47,48 are special positions within the packet 7063 // 46,47,48 are special positions within the packet
7036 // This may change so perhaps we need a better way 7064 // This may change so perhaps we need a better way
7037 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?) 7065 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)
7038 bool UsePhysics = (data[46] != 0) ? true : false; 7066 /*
7039 bool IsTemporary = (data[47] != 0) ? true : false; 7067 bool UsePhysics = (data[46] != 0) ? true : false;
7040 bool IsPhantom = (data[48] != 0) ? true : false; 7068 bool IsTemporary = (data[47] != 0) ? true : false;
7041 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this); 7069 bool IsPhantom = (data[48] != 0) ? true : false;
7070 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this);
7071 */
7072 bool UsePhysics = flags.AgentData.UsePhysics;
7073 bool IsPhantom = flags.AgentData.IsPhantom;
7074 bool IsTemporary = flags.AgentData.IsTemporary;
7075 ObjectFlagUpdatePacket.ExtraPhysicsBlock[] blocks = flags.ExtraPhysics;
7076 ExtraPhysicsData physdata = new ExtraPhysicsData();
7077
7078 if (blocks == null || blocks.Length == 0)
7079 {
7080 physdata.PhysShapeType = PhysShapeType.invalid;
7081 }
7082 else
7083 {
7084 ObjectFlagUpdatePacket.ExtraPhysicsBlock phsblock = blocks[0];
7085 physdata.PhysShapeType = (PhysShapeType)phsblock.PhysicsShapeType;
7086 physdata.Bounce = phsblock.Restitution;
7087 physdata.Density = phsblock.Density;
7088 physdata.Friction = phsblock.Friction;
7089 physdata.GravitationModifier = phsblock.GravityMultiplier;
7090 }
7091
7092 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
7042 } 7093 }
7043 return true; 7094 return true;
7044 } 7095 }
diff --git a/OpenSim/Region/Framework/Interfaces/IEventQueue.cs b/OpenSim/Region/Framework/Interfaces/IEventQueue.cs
index bfa5d17..5512642 100644
--- a/OpenSim/Region/Framework/Interfaces/IEventQueue.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEventQueue.cs
@@ -59,5 +59,7 @@ namespace OpenSim.Region.Framework.Interfaces
59 void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID); 59 void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID);
60 OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono); 60 OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono);
61 OSD BuildEvent(string eventName, OSD eventBody); 61 OSD BuildEvent(string eventName, OSD eventBody);
62 void partPhysicsProperties(uint localID, byte physhapetype, float density, float friction, float bounce, float gravmod, UUID avatarID);
63
62 } 64 }
63} 65}
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index a4383fd..a84f6d3 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -1408,7 +1408,7 @@ namespace OpenSim.Region.Framework.Scenes
1408 /// <param name="SetPhantom"></param> 1408 /// <param name="SetPhantom"></param>
1409 /// <param name="remoteClient"></param> 1409 /// <param name="remoteClient"></param>
1410 protected internal void UpdatePrimFlags( 1410 protected internal void UpdatePrimFlags(
1411 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, IClientAPI remoteClient) 1411 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
1412 { 1412 {
1413 SceneObjectGroup group = GetGroupByPrim(localID); 1413 SceneObjectGroup group = GetGroupByPrim(localID);
1414 if (group != null) 1414 if (group != null)
@@ -1416,7 +1416,28 @@ namespace OpenSim.Region.Framework.Scenes
1416 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1416 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1417 { 1417 {
1418 // VolumeDetect can't be set via UI and will always be off when a change is made there 1418 // VolumeDetect can't be set via UI and will always be off when a change is made there
1419 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, false); 1419 // now only change volume dtc if phantom off
1420
1421 if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data
1422 {
1423 bool vdtc;
1424 if (SetPhantom) // if phantom keep volumedtc
1425 vdtc = group.RootPart.VolumeDetectActive;
1426 else // else turn it off
1427 vdtc = false;
1428
1429 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc);
1430 }
1431 else
1432 {
1433 SceneObjectPart part = GetSceneObjectPart(localID);
1434 if (part != null)
1435 {
1436 part.UpdateExtraPhysics(PhysData);
1437 if (part.UpdatePhysRequired)
1438 remoteClient.SendPartPhysicsProprieties(part);
1439 }
1440 }
1420 } 1441 }
1421 } 1442 }
1422 } 1443 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 55b5462..cd40b29 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -1042,6 +1042,7 @@ namespace OpenSim.Region.Framework.Scenes
1042 } 1042 }
1043 1043
1044 public UpdateRequired UpdateFlag { get; set; } 1044 public UpdateRequired UpdateFlag { get; set; }
1045 public bool UpdatePhysRequired { get; set; }
1045 1046
1046 /// <summary> 1047 /// <summary>
1047 /// Used for media on a prim. 1048 /// Used for media on a prim.
@@ -1390,7 +1391,7 @@ namespace OpenSim.Region.Framework.Scenes
1390 public float Density { get; set; } 1391 public float Density { get; set; }
1391 public float GravityModifier { get; set; } 1392 public float GravityModifier { get; set; }
1392 public float Friction { get; set; } 1393 public float Friction { get; set; }
1393 public float Bounciness { get; set; } 1394 public float Restitution { get; set; }
1394 1395
1395 #endregion Public Properties with only Get 1396 #endregion Public Properties with only Get
1396 1397
@@ -3964,8 +3965,8 @@ namespace OpenSim.Region.Framework.Scenes
3964 GravityModifier = physdata.GravitationModifier; 3965 GravityModifier = physdata.GravitationModifier;
3965 if(Friction != physdata.Friction) 3966 if(Friction != physdata.Friction)
3966 Friction = physdata.Friction; 3967 Friction = physdata.Friction;
3967 if(Bounciness != physdata.Bounce) 3968 if(Restitution != physdata.Bounce)
3968 Bounciness = physdata.Bounce; 3969 Restitution = physdata.Bounce;
3969 } 3970 }
3970 /// <summary> 3971 /// <summary>
3971 /// Update the flags on this prim. This covers properties such as phantom, physics and temporary. 3972 /// Update the flags on this prim. This covers properties such as phantom, physics and temporary.
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index 78229fe..39420a6 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -618,7 +618,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
618 618
619 private static void ProcessBounce(SceneObjectPart obj, XmlTextReader reader) 619 private static void ProcessBounce(SceneObjectPart obj, XmlTextReader reader)
620 { 620 {
621 obj.Bounciness = reader.ReadElementContentAsFloat("Bounce", String.Empty); 621 obj.Restitution = reader.ReadElementContentAsFloat("Bounce", String.Empty);
622 } 622 }
623 623
624 private static void ProcessGravityModifier(SceneObjectPart obj, XmlTextReader reader) 624 private static void ProcessGravityModifier(SceneObjectPart obj, XmlTextReader reader)
@@ -1295,8 +1295,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1295 writer.WriteElementString("Density", sop.Density.ToString().ToLower()); 1295 writer.WriteElementString("Density", sop.Density.ToString().ToLower());
1296 if (sop.Friction != 0.6f) 1296 if (sop.Friction != 0.6f)
1297 writer.WriteElementString("Friction", sop.Friction.ToString().ToLower()); 1297 writer.WriteElementString("Friction", sop.Friction.ToString().ToLower());
1298 if (sop.Bounciness != 0.5f) 1298 if (sop.Restitution != 0.5f)
1299 writer.WriteElementString("Bounce", sop.Bounciness.ToString().ToLower()); 1299 writer.WriteElementString("Bounce", sop.Restitution.ToString().ToLower());
1300 if (sop.GravityModifier != 1.0f) 1300 if (sop.GravityModifier != 1.0f)
1301 writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString().ToLower()); 1301 writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString().ToLower());
1302 1302
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 781539a..0ac56fa 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -1678,5 +1678,10 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
1678 public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data) 1678 public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data)
1679 { 1679 {
1680 } 1680 }
1681
1682 public void SendPartPhysicsProprieties(ISceneEntity entity)
1683 {
1684 }
1685
1681 } 1686 }
1682} 1687}
diff --git a/OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs b/OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs
new file mode 100644
index 0000000..112ba4e
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs
@@ -0,0 +1,174 @@
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.Reflection;
31using OpenSim.Framework.Servers;
32using Mono.Addins;
33using log4net;
34using Nini.Config;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38using OpenSim.Framework.Servers.HttpServer;
39
40
41namespace OpenSim.Region.OptionalModules.WebSocketEchoModule
42{
43
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebSocketEchoModule")]
45 public class WebSocketEchoModule : ISharedRegionModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private bool enabled;
49 public string Name { get { return "WebSocketEchoModule"; } }
50
51 public Type ReplaceableInterface { get { return null; } }
52
53
54 private HashSet<WebSocketHttpServerHandler> _activeHandlers = new HashSet<WebSocketHttpServerHandler>();
55
56 public void Initialise(IConfigSource pConfig)
57 {
58 enabled =(pConfig.Configs["WebSocketEcho"] != null);
59 if (enabled)
60 m_log.DebugFormat("[WebSocketEchoModule]: INITIALIZED MODULE");
61 }
62
63 /// <summary>
64 /// This method sets up the callback to WebSocketHandlerCallback below when a HTTPRequest comes in for /echo
65 /// </summary>
66 public void PostInitialise()
67 {
68 if (enabled)
69 MainServer.Instance.AddWebSocketHandler("/echo", WebSocketHandlerCallback);
70 }
71
72 // This gets called by BaseHttpServer and gives us an opportunity to set things on the WebSocket handler before we turn it on
73 public void WebSocketHandlerCallback(string path, WebSocketHttpServerHandler handler)
74 {
75 SubscribeToEvents(handler);
76 handler.SetChunksize(8192);
77 handler.NoDelay_TCP_Nagle = true;
78 handler.HandshakeAndUpgrade();
79 }
80
81 //These are our normal events
82 public void SubscribeToEvents(WebSocketHttpServerHandler handler)
83 {
84 handler.OnClose += HandlerOnOnClose;
85 handler.OnText += HandlerOnOnText;
86 handler.OnUpgradeCompleted += HandlerOnOnUpgradeCompleted;
87 handler.OnData += HandlerOnOnData;
88 handler.OnPong += HandlerOnOnPong;
89 }
90
91 public void UnSubscribeToEvents(WebSocketHttpServerHandler handler)
92 {
93 handler.OnClose -= HandlerOnOnClose;
94 handler.OnText -= HandlerOnOnText;
95 handler.OnUpgradeCompleted -= HandlerOnOnUpgradeCompleted;
96 handler.OnData -= HandlerOnOnData;
97 handler.OnPong -= HandlerOnOnPong;
98 }
99
100 private void HandlerOnOnPong(object sender, PongEventArgs pongdata)
101 {
102 m_log.Info("[WebSocketEchoModule]: Got a pong.. ping time: " + pongdata.PingResponseMS);
103 }
104
105 private void HandlerOnOnData(object sender, WebsocketDataEventArgs data)
106 {
107 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
108 obj.SendData(data.Data);
109 m_log.Info("[WebSocketEchoModule]: We received a bunch of ugly non-printable bytes");
110 obj.SendPingCheck();
111 }
112
113
114 private void HandlerOnOnUpgradeCompleted(object sender, UpgradeCompletedEventArgs completeddata)
115 {
116 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
117 _activeHandlers.Add(obj);
118 }
119
120 private void HandlerOnOnText(object sender, WebsocketTextEventArgs text)
121 {
122 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
123 obj.SendMessage(text.Data);
124 m_log.Info("[WebSocketEchoModule]: We received this: " + text.Data);
125 }
126
127 // Remove the references to our handler
128 private void HandlerOnOnClose(object sender, CloseEventArgs closedata)
129 {
130 WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler;
131 UnSubscribeToEvents(obj);
132
133 lock (_activeHandlers)
134 _activeHandlers.Remove(obj);
135 obj.Dispose();
136 }
137
138 // Shutting down.. so shut down all sockets.
139 // Note.. this should be done outside of an ienumerable if you're also hook to the close event.
140 public void Close()
141 {
142 if (!enabled)
143 return;
144
145 // We convert this to a for loop so we're not in in an IEnumerable when the close
146 //call triggers an event which then removes item from _activeHandlers that we're enumerating
147 WebSocketHttpServerHandler[] items = new WebSocketHttpServerHandler[_activeHandlers.Count];
148 _activeHandlers.CopyTo(items);
149
150 for (int i = 0; i < items.Length; i++)
151 {
152 items[i].Close(string.Empty);
153 items[i].Dispose();
154 }
155 _activeHandlers.Clear();
156 MainServer.Instance.RemoveWebSocketHandler("/echo");
157 }
158
159 public void AddRegion(Scene scene)
160 {
161 m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName);
162 }
163
164 public void RemoveRegion(Scene scene)
165 {
166 m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
167 }
168
169 public void RegionLoaded(Scene scene)
170 {
171 m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} LOADED", scene.RegionInfo.RegionName);
172 }
173 }
174} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
index 40f7fbc..3083a33 100755
--- a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
+++ b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
@@ -146,7 +146,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
146 { 146 {
147 foreach (PhysParameterEntry ppe in physScene.GetParameterList()) 147 foreach (PhysParameterEntry ppe in physScene.GetParameterList())
148 { 148 {
149 float val = 0.0f; 149 string val = string.Empty;
150 if (physScene.GetPhysicsParameter(ppe.name, out val)) 150 if (physScene.GetPhysicsParameter(ppe.name, out val))
151 { 151 {
152 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, val); 152 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, val);
@@ -159,7 +159,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
159 } 159 }
160 else 160 else
161 { 161 {
162 float val = 0.0f; 162 string val = string.Empty;
163 if (physScene.GetPhysicsParameter(parm, out val)) 163 if (physScene.GetPhysicsParameter(parm, out val))
164 { 164 {
165 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, parm, val); 165 WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, parm, val);
@@ -185,21 +185,12 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
185 return; 185 return;
186 } 186 }
187 string parm = "xxx"; 187 string parm = "xxx";
188 float val = 0f; 188 string valparm = String.Empty;
189 uint localID = (uint)PhysParameterEntry.APPLY_TO_NONE; // set default value 189 uint localID = (uint)PhysParameterEntry.APPLY_TO_NONE; // set default value
190 try 190 try
191 { 191 {
192 parm = cmdparms[2]; 192 parm = cmdparms[2];
193 string valparm = cmdparms[3].ToLower(); 193 valparm = cmdparms[3].ToLower();
194 if (valparm == "true")
195 val = PhysParameterEntry.NUMERIC_TRUE;
196 else
197 {
198 if (valparm == "false")
199 val = PhysParameterEntry.NUMERIC_FALSE;
200 else
201 val = float.Parse(valparm, Culture.NumberFormatInfo);
202 }
203 if (cmdparms.Length > 4) 194 if (cmdparms.Length > 4)
204 { 195 {
205 if (cmdparms[4].ToLower() == "all") 196 if (cmdparms[4].ToLower() == "all")
@@ -224,7 +215,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
224 IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters; 215 IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters;
225 if (physScene != null) 216 if (physScene != null)
226 { 217 {
227 if (!physScene.SetPhysicsParameter(parm, val, localID)) 218 if (!physScene.SetPhysicsParameter(parm, valparm, localID))
228 { 219 {
229 WriteError("Failed set of parameter '{0}' for region '{1}'", parm, scene.RegionInfo.RegionName); 220 WriteError("Failed set of parameter '{0}' for region '{1}'", parm, scene.RegionInfo.RegionName);
230 } 221 }
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
index eddae38..aea94ea 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
@@ -54,6 +54,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
54 private MockScriptEngine m_engine; 54 private MockScriptEngine m_engine;
55 private ScriptModuleCommsModule m_smcm; 55 private ScriptModuleCommsModule m_smcm;
56 56
57 [TestFixtureSetUp]
58 public void FixtureInit()
59 {
60 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
61 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
62 }
63
64 [TestFixtureTearDown]
65 public void TearDown()
66 {
67 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
68 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
69 // tests really shouldn't).
70 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
71 }
72
57 [SetUp] 73 [SetUp]
58 public override void SetUp() 74 public override void SetUp()
59 { 75 {
@@ -85,7 +101,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
85 101
86 private object InvokeOp(string name, params object[] args) 102 private object InvokeOp(string name, params object[] args)
87 { 103 {
88 return m_smcm.InvokeOperation(UUID.Zero, UUID.Zero, name, args); 104 return InvokeOpOnHost(name, UUID.Zero, args);
105 }
106
107 private object InvokeOpOnHost(string name, UUID hostId, params object[] args)
108 {
109 return m_smcm.InvokeOperation(hostId, UUID.Zero, name, args);
89 } 110 }
90 111
91 [Test] 112 [Test]
@@ -193,6 +214,44 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
193 Assert.That(value, Is.EqualTo("Times")); 214 Assert.That(value, Is.EqualTo("Times"));
194 } 215 }
195 216
217 /// <summary>
218 /// Test for reading and writing json to a notecard
219 /// </summary>
220 /// <remarks>
221 /// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching
222 /// it via the MockScriptEngine or perhaps by a dummy script instance.
223 /// </remarks>
224 [Test]
225 public void TestJsonWriteReadNotecard()
226 {
227 TestHelpers.InMethod();
228 TestHelpers.EnableLogging();
229
230 string notecardName = "nc1";
231
232 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1));
233 m_scene.AddSceneObject(so);
234
235 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }");
236
237 // Write notecard
238 UUID writeNotecardRequestId = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "/", notecardName);
239 Assert.That(writeNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
240
241 TaskInventoryItem nc1Item = so.RootPart.Inventory.GetInventoryItem(notecardName);
242 Assert.That(nc1Item, Is.Not.Null);
243
244 // TODO: Should probably independently check the contents.
245
246 // Read notecard
247 UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }");
248 UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName);
249 Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
250
251 string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
252 Assert.That(value, Is.EqualTo("World"));
253 }
254
196 public object DummyTestMethod(object o1, object o2, object o3, object o4, object o5) { return null; } 255 public object DummyTestMethod(object o1, object o2, object o3, object o4, object o5) { return null; }
197 } 256 }
198} \ No newline at end of file 257} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index 5ea2bcd..6bd27f0 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -1234,5 +1234,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC
1234 public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data) 1234 public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data)
1235 { 1235 {
1236 } 1236 }
1237
1238 public void SendPartPhysicsProprieties(ISceneEntity entity)
1239 {
1240 }
1241
1237 } 1242 }
1238} 1243}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 306928a..601c78c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -220,7 +220,7 @@ public static class BSParam
220 (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); }, 220 (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); },
221 (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ), 221 (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ),
222 new ParameterDefn("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", 222 new ParameterDefn("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes",
223 ConfigurationParameters.numericFalse, 223 ConfigurationParameters.numericTrue,
224 (s,cf,p,v) => { ShouldRemoveZeroWidthTriangles = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, 224 (s,cf,p,v) => { ShouldRemoveZeroWidthTriangles = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
225 (s) => { return BSParam.NumericBool(ShouldRemoveZeroWidthTriangles); }, 225 (s) => { return BSParam.NumericBool(ShouldRemoveZeroWidthTriangles); },
226 (s,p,l,v) => { ShouldRemoveZeroWidthTriangles = BSParam.BoolNumeric(v); } ), 226 (s,p,l,v) => { ShouldRemoveZeroWidthTriangles = BSParam.BoolNumeric(v); } ),
@@ -641,24 +641,6 @@ public static class BSParam
641 return (b == ConfigurationParameters.numericTrue ? true : false); 641 return (b == ConfigurationParameters.numericTrue ? true : false);
642 } 642 }
643 643
644 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v)
645 {
646 BSScene physScene = pPhysScene;
647 physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate()
648 {
649 physScene.PE.ResetBroadphasePool(physScene.World);
650 });
651 }
652
653 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
654 {
655 BSScene physScene = pPhysScene;
656 physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate()
657 {
658 physScene.PE.ResetConstraintSolver(physScene.World);
659 });
660 }
661
662 // Search through the parameter definitions and return the matching 644 // Search through the parameter definitions and return the matching
663 // ParameterDefn structure. 645 // ParameterDefn structure.
664 // Case does not matter as names are compared after converting to lower case. 646 // Case does not matter as names are compared after converting to lower case.
@@ -722,6 +704,22 @@ public static class BSParam
722 } 704 }
723 } 705 }
724 706
707 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v)
708 {
709 BSScene physScene = pPhysScene;
710 physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate()
711 {
712 physScene.PE.ResetBroadphasePool(physScene.World);
713 });
714 }
725 715
716 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
717 {
718 BSScene physScene = pPhysScene;
719 physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate()
720 {
721 physScene.PE.ResetConstraintSolver(physScene.World);
722 });
723 }
726} 724}
727} 725}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 823402b..ec25aa9 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -75,6 +75,7 @@ public abstract class BSPhysObject : PhysicsActor
75 PhysicsScene = parentScene; 75 PhysicsScene = parentScene;
76 LocalID = localID; 76 LocalID = localID;
77 PhysObjectName = name; 77 PhysObjectName = name;
78 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
78 TypeName = typeName; 79 TypeName = typeName;
79 80
80 // We don't have any physical representation yet. 81 // We don't have any physical representation yet.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 6cd72f2..f8a0c1e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -876,14 +876,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
876 // will use the next time since it's pinned and shared memory. 876 // will use the next time since it's pinned and shared memory.
877 // Some of the values require calling into the physics engine to get the new 877 // Some of the values require calling into the physics engine to get the new
878 // value activated ('terrainFriction' for instance). 878 // value activated ('terrainFriction' for instance).
879 public bool SetPhysicsParameter(string parm, float val, uint localID) 879 public bool SetPhysicsParameter(string parm, string val, uint localID)
880 { 880 {
881 bool ret = false; 881 bool ret = false;
882
883 float valf = 0f;
884 if (val.ToLower() == "true")
885 {
886 valf = PhysParameterEntry.NUMERIC_TRUE;
887 }
888 else
889 {
890 if (val.ToLower() == "false")
891 {
892 valf = PhysParameterEntry.NUMERIC_FALSE;
893 }
894 else
895 {
896 try
897 {
898 valf = float.Parse(val);
899 }
900 catch
901 {
902 valf = 0f;
903 }
904 }
905 }
906
882 BSParam.ParameterDefn theParam; 907 BSParam.ParameterDefn theParam;
883 if (BSParam.TryGetParameter(parm, out theParam)) 908 if (BSParam.TryGetParameter(parm, out theParam))
884 { 909 {
885 // Set the value in the C# code 910 // Set the value in the C# code
886 theParam.setter(this, parm, localID, val); 911 theParam.setter(this, parm, localID, valf);
887 912
888 // Optionally set the parameter in the unmanaged code 913 // Optionally set the parameter in the unmanaged code
889 if (theParam.onObject != null) 914 if (theParam.onObject != null)
@@ -898,16 +923,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
898 case PhysParameterEntry.APPLY_TO_NONE: 923 case PhysParameterEntry.APPLY_TO_NONE:
899 // This will cause a call into the physical world if some operation is specified (SetOnObject). 924 // This will cause a call into the physical world if some operation is specified (SetOnObject).
900 objectIDs.Add(TERRAIN_ID); 925 objectIDs.Add(TERRAIN_ID);
901 TaintedUpdateParameter(parm, objectIDs, val); 926 TaintedUpdateParameter(parm, objectIDs, valf);
902 break; 927 break;
903 case PhysParameterEntry.APPLY_TO_ALL: 928 case PhysParameterEntry.APPLY_TO_ALL:
904 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); 929 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
905 TaintedUpdateParameter(parm, objectIDs, val); 930 TaintedUpdateParameter(parm, objectIDs, valf);
906 break; 931 break;
907 default: 932 default:
908 // setting only one localID 933 // setting only one localID
909 objectIDs.Add(localID); 934 objectIDs.Add(localID);
910 TaintedUpdateParameter(parm, objectIDs, val); 935 TaintedUpdateParameter(parm, objectIDs, valf);
911 break; 936 break;
912 } 937 }
913 } 938 }
@@ -942,14 +967,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
942 967
943 // Get parameter. 968 // Get parameter.
944 // Return 'false' if not able to get the parameter. 969 // Return 'false' if not able to get the parameter.
945 public bool GetPhysicsParameter(string parm, out float value) 970 public bool GetPhysicsParameter(string parm, out string value)
946 { 971 {
947 float val = 0f; 972 string val = String.Empty;
948 bool ret = false; 973 bool ret = false;
949 BSParam.ParameterDefn theParam; 974 BSParam.ParameterDefn theParam;
950 if (BSParam.TryGetParameter(parm, out theParam)) 975 if (BSParam.TryGetParameter(parm, out theParam))
951 { 976 {
952 val = theParam.getter(this); 977 val = theParam.getter(this).ToString();
953 ret = true; 978 ret = true;
954 } 979 }
955 value = val; 980 value = val;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index fe0f984..15747c9 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -608,7 +608,7 @@ public sealed class BSShapeCollection : IDisposable
608 // Since we're recreating new, get rid of the reference to the previous shape 608 // Since we're recreating new, get rid of the reference to the previous shape
609 DereferenceShape(prim.PhysShape, shapeCallback); 609 DereferenceShape(prim.PhysShape, shapeCallback);
610 610
611 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); 611 newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod);
612 // Take evasive action if the mesh was not constructed. 612 // Take evasive action if the mesh was not constructed.
613 newShape = VerifyMeshCreated(newShape, prim); 613 newShape = VerifyMeshCreated(newShape, prim);
614 614
@@ -619,7 +619,7 @@ public sealed class BSShapeCollection : IDisposable
619 return true; // 'true' means a new shape has been added to this prim 619 return true; // 'true' means a new shape has been added to this prim
620 } 620 }
621 621
622 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 622 private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
623 { 623 {
624 BulletShape newShape = new BulletShape(); 624 BulletShape newShape = new BulletShape();
625 625
@@ -631,7 +631,7 @@ public sealed class BSShapeCollection : IDisposable
631 } 631 }
632 else 632 else
633 { 633 {
634 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, 634 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
635 false, // say it is not physical so a bounding box is not built 635 false, // say it is not physical so a bounding box is not built
636 false // do not cache the mesh and do not use previously built versions 636 false // do not cache the mesh and do not use previously built versions
637 ); 637 );
@@ -651,18 +651,20 @@ public sealed class BSShapeCollection : IDisposable
651 realIndicesIndex = 0; 651 realIndicesIndex = 0;
652 for (int tri = 0; tri < indices.Length; tri += 3) 652 for (int tri = 0; tri < indices.Length; tri += 3)
653 { 653 {
654 // Compute displacements into vertex array for each vertex of the triangle
654 int v1 = indices[tri + 0] * 3; 655 int v1 = indices[tri + 0] * 3;
655 int v2 = indices[tri + 1] * 3; 656 int v2 = indices[tri + 1] * 3;
656 int v3 = indices[tri + 2] * 3; 657 int v3 = indices[tri + 2] * 3;
657 if (!((verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] 658 // Check to see if any two of the vertices are the same
659 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
658 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] 660 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
659 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) 661 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
660 || (verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] 662 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
661 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] 663 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
662 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) 664 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
663 || (verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] 665 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
664 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] 666 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
665 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2])) 667 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
666 ) 668 )
667 { 669 {
668 // None of the vertices of the triangles are the same. This is a good triangle; 670 // None of the vertices of the triangles are the same. This is a good triangle;
@@ -676,8 +678,16 @@ public sealed class BSShapeCollection : IDisposable
676 DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", 678 DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}",
677 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); 679 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
678 680
679 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, 681 if (realIndicesIndex != 0)
680 realIndicesIndex, indices, verticesAsFloats.Length/3, verticesAsFloats); 682 {
683 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
684 realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
685 }
686 else
687 {
688 PhysicsScene.Logger.ErrorFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
689 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
690 }
681 } 691 }
682 } 692 }
683 newShape.shapeKey = newMeshKey; 693 newShape.shapeKey = newMeshKey;
diff --git a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs
index b8676ba..31a397c 100755
--- a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs
+++ b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs
@@ -60,14 +60,14 @@ namespace OpenSim.Region.Physics.Manager
60 60
61 // Set parameter on a specific or all instances. 61 // Set parameter on a specific or all instances.
62 // Return 'false' if not able to set the parameter. 62 // Return 'false' if not able to set the parameter.
63 bool SetPhysicsParameter(string parm, float value, uint localID); 63 bool SetPhysicsParameter(string parm, string value, uint localID);
64 64
65 // Get parameter. 65 // Get parameter.
66 // Return 'false' if not able to get the parameter. 66 // Return 'false' if not able to get the parameter.
67 bool GetPhysicsParameter(string parm, out float value); 67 bool GetPhysicsParameter(string parm, out string value);
68 68
69 // Get parameter from a particular object 69 // Get parameter from a particular object
70 // TODO: 70 // TODO:
71 // bool GetPhysicsParameter(string parm, out float value, uint localID); 71 // bool GetPhysicsParameter(string parm, out string value, uint localID);
72 } 72 }
73} 73}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 64052ae..be6ac0a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -7602,7 +7602,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7602 7602
7603 ExtraPhysicsData physdata = new ExtraPhysicsData(); 7603 ExtraPhysicsData physdata = new ExtraPhysicsData();
7604 physdata.Density = part.Density; 7604 physdata.Density = part.Density;
7605 physdata.Bounce = part.Bounciness; 7605 physdata.Bounce = part.Restitution;
7606 physdata.GravitationModifier = part.GravityModifier; 7606 physdata.GravitationModifier = part.GravityModifier;
7607 physdata.PhysShapeType = (PhysShapeType)shape_type; 7607 physdata.PhysShapeType = (PhysShapeType)shape_type;
7608 7608
diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs
index 438ef48..b98b762 100644
--- a/OpenSim/Region/UserStatistics/WebStatsModule.cs
+++ b/OpenSim/Region/UserStatistics/WebStatsModule.cs
@@ -420,7 +420,7 @@ namespace OpenSim.Region.UserStatistics
420 Encoding encoding = Encoding.ASCII; 420 Encoding encoding = Encoding.ASCII;
421 int sizeOfChar = encoding.GetByteCount("\n"); 421 int sizeOfChar = encoding.GetByteCount("\n");
422 byte[] buffer = encoding.GetBytes("\n"); 422 byte[] buffer = encoding.GetBytes("\n");
423 string logfile = Util.logDir() + "/" + "OpenSim.log"; 423 string logfile = Util.logFile();
424 FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 424 FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
425 Int64 tokenCount = 0; 425 Int64 tokenCount = 0;
426 Int64 endPosition = fs.Length / sizeOfChar; 426 Int64 endPosition = fs.Length / sizeOfChar;
diff --git a/OpenSim/Tests/Common/Mock/MockScriptEngine.cs b/OpenSim/Tests/Common/Mock/MockScriptEngine.cs
index 51f2712..78bab5b 100644
--- a/OpenSim/Tests/Common/Mock/MockScriptEngine.cs
+++ b/OpenSim/Tests/Common/Mock/MockScriptEngine.cs
@@ -85,7 +85,7 @@ namespace OpenSim.Tests.Common
85 85
86 public bool PostScriptEvent(UUID itemID, string name, object[] args) 86 public bool PostScriptEvent(UUID itemID, string name, object[] args)
87 { 87 {
88 throw new System.NotImplementedException (); 88 return false;
89 } 89 }
90 90
91 public bool PostObjectEvent(UUID itemID, string name, object[] args) 91 public bool PostObjectEvent(UUID itemID, string name, object[] args)
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index dde37ab..182f4d9 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -1276,5 +1276,10 @@ namespace OpenSim.Tests.Common.Mock
1276 public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data) 1276 public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data)
1277 { 1277 {
1278 } 1278 }
1279
1280 public void SendPartPhysicsProprieties(ISceneEntity entity)
1281 {
1282 }
1283
1279 } 1284 }
1280} 1285}