opensim – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | eva | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ |
||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
||
4 | * |
||
5 | * Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that the following conditions are met: |
||
7 | * * Redistributions of source code must retain the above copyright |
||
8 | * notice, this list of conditions and the following disclaimer. |
||
9 | * * Redistributions in binary form must reproduce the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer in the |
||
11 | * documentation and/or other materials provided with the distribution. |
||
12 | * * Neither the name of the OpenSimulator Project nor the |
||
13 | * names of its contributors may be used to endorse or promote products |
||
14 | * derived from this software without specific prior written permission. |
||
15 | * |
||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
26 | */ |
||
27 | |||
28 | using System; |
||
29 | using System.Collections.Generic; |
||
30 | using System.IO; |
||
31 | using System.Net; |
||
32 | using System.Reflection; |
||
33 | using System.Text; |
||
34 | using System.Collections; |
||
35 | |||
36 | using OpenSim.Framework; |
||
37 | using OpenSim.Services.Interfaces; |
||
38 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
||
39 | |||
40 | using OpenMetaverse; |
||
41 | using OpenMetaverse.StructuredData; |
||
42 | using log4net; |
||
43 | using Nini.Config; |
||
44 | |||
45 | namespace OpenSim.Services.Connectors.Simulation |
||
46 | { |
||
47 | public class SimulationServiceConnector : ISimulationService |
||
48 | { |
||
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
50 | |||
51 | // we use this dictionary to track the pending updateagent requests, maps URI --> position update |
||
52 | private Dictionary<string,AgentPosition> m_updateAgentQueue = new Dictionary<string,AgentPosition>(); |
||
53 | |||
54 | //private GridRegion m_Region; |
||
55 | |||
56 | public SimulationServiceConnector() |
||
57 | { |
||
58 | } |
||
59 | |||
60 | public SimulationServiceConnector(IConfigSource config) |
||
61 | { |
||
62 | //m_Region = region; |
||
63 | } |
||
64 | |||
65 | public IScene GetScene(UUID regionId) |
||
66 | { |
||
67 | return null; |
||
68 | } |
||
69 | |||
70 | public ISimulationService GetInnerService() |
||
71 | { |
||
72 | return null; |
||
73 | } |
||
74 | |||
75 | #region Agents |
||
76 | |||
77 | protected virtual string AgentPath() |
||
78 | { |
||
79 | return "agent/"; |
||
80 | } |
||
81 | |||
82 | protected virtual void PackData(OSDMap args, AgentCircuitData aCircuit, GridRegion destination, uint flags) |
||
83 | { |
||
84 | args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); |
||
85 | args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); |
||
86 | args["destination_name"] = OSD.FromString(destination.RegionName); |
||
87 | args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); |
||
88 | args["teleport_flags"] = OSD.FromString(flags.ToString()); |
||
89 | } |
||
90 | |||
91 | public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string reason) |
||
92 | { |
||
93 | string tmp = String.Empty; |
||
94 | return CreateAgent(destination, aCircuit, flags, out tmp, out reason); |
||
95 | } |
||
96 | |||
97 | public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string myipaddress, out string reason) |
||
98 | { |
||
99 | m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: Creating agent at {0}", destination.ServerURI); |
||
100 | reason = String.Empty; |
||
101 | myipaddress = String.Empty; |
||
102 | |||
103 | if (destination == null) |
||
104 | { |
||
105 | m_log.Debug("[REMOTE SIMULATION CONNECTOR]: Given destination is null"); |
||
106 | return false; |
||
107 | } |
||
108 | |||
109 | string uri = destination.ServerURI + AgentPath() + aCircuit.AgentID + "/"; |
||
110 | |||
111 | try |
||
112 | { |
||
113 | OSDMap args = aCircuit.PackAgentCircuitData(); |
||
114 | PackData(args, aCircuit, destination, flags); |
||
115 | |||
116 | OSDMap result = WebUtil.PostToServiceCompressed(uri, args, 30000); |
||
117 | bool success = result["success"].AsBoolean(); |
||
118 | if (success && result.ContainsKey("_Result")) |
||
119 | { |
||
120 | OSDMap data = (OSDMap)result["_Result"]; |
||
121 | |||
122 | reason = data["reason"].AsString(); |
||
123 | success = data["success"].AsBoolean(); |
||
124 | myipaddress = data["your_ip"].AsString(); |
||
125 | return success; |
||
126 | } |
||
127 | |||
128 | // Try the old version, uncompressed |
||
129 | result = WebUtil.PostToService(uri, args, 30000); |
||
130 | |||
131 | if (result["Success"].AsBoolean()) |
||
132 | { |
||
133 | if (result.ContainsKey("_Result")) |
||
134 | { |
||
135 | OSDMap data = (OSDMap)result["_Result"]; |
||
136 | |||
137 | reason = data["reason"].AsString(); |
||
138 | success = data["success"].AsBoolean(); |
||
139 | myipaddress = data["your_ip"].AsString(); |
||
140 | m_log.WarnFormat( |
||
141 | "[REMOTE SIMULATION CONNECTOR]: Remote simulator {0} did not accept compressed transfer, suggest updating it.", destination.RegionName); |
||
142 | return success; |
||
143 | } |
||
144 | } |
||
145 | |||
146 | m_log.WarnFormat( |
||
147 | "[REMOTE SIMULATION CONNECTOR]: Failed to create agent {0} {1} at remote simulator {2}", |
||
148 | aCircuit.firstname, aCircuit.lastname, destination.RegionName); |
||
149 | reason = result["Message"] != null ? result["Message"].AsString() : "error"; |
||
150 | return false; |
||
151 | } |
||
152 | catch (Exception e) |
||
153 | { |
||
154 | m_log.Warn("[REMOTE SIMULATION CONNECTOR]: CreateAgent failed with exception: " + e.ToString()); |
||
155 | reason = e.Message; |
||
156 | } |
||
157 | |||
158 | return false; |
||
159 | } |
||
160 | |||
161 | /// <summary> |
||
162 | /// Send complete data about an agent in this region to a neighbor |
||
163 | /// </summary> |
||
164 | public bool UpdateAgent(GridRegion destination, AgentData data) |
||
165 | { |
||
166 | return UpdateAgent(destination, (IAgentData)data, 200000); // yes, 200 seconds |
||
167 | } |
||
168 | |||
169 | private ExpiringCache<string, bool> _failedSims = new ExpiringCache<string, bool>(); |
||
170 | /// <summary> |
||
171 | /// Send updated position information about an agent in this region to a neighbor |
||
172 | /// This operation may be called very frequently if an avatar is moving about in |
||
173 | /// the region. |
||
174 | /// </summary> |
||
175 | public bool UpdateAgent(GridRegion destination, AgentPosition data) |
||
176 | { |
||
177 | bool v = true; |
||
178 | if (_failedSims.TryGetValue(destination.ServerURI, out v)) |
||
179 | return false; |
||
180 | |||
181 | // The basic idea of this code is that the first thread that needs to |
||
182 | // send an update for a specific avatar becomes the worker for any subsequent |
||
183 | // requests until there are no more outstanding requests. Further, only send the most |
||
184 | // recent update; this *should* never be needed but some requests get |
||
185 | // slowed down and once that happens the problem with service end point |
||
186 | // limits kicks in and nothing proceeds |
||
187 | string uri = destination.ServerURI + AgentPath() + data.AgentID + "/"; |
||
188 | lock (m_updateAgentQueue) |
||
189 | { |
||
190 | if (m_updateAgentQueue.ContainsKey(uri)) |
||
191 | { |
||
192 | // Another thread is already handling |
||
193 | // updates for this simulator, just update |
||
194 | // the position and return, overwrites are |
||
195 | // not a problem since we only care about the |
||
196 | // last update anyway |
||
197 | m_updateAgentQueue[uri] = data; |
||
198 | return true; |
||
199 | } |
||
200 | |||
201 | // Otherwise update the reference and start processing |
||
202 | m_updateAgentQueue[uri] = data; |
||
203 | } |
||
204 | |||
205 | AgentPosition pos = null; |
||
206 | bool success = true; |
||
207 | while (success) |
||
208 | { |
||
209 | lock (m_updateAgentQueue) |
||
210 | { |
||
211 | // save the position |
||
212 | AgentPosition lastpos = pos; |
||
213 | |||
214 | pos = m_updateAgentQueue[uri]; |
||
215 | |||
216 | // this is true if no one put a new |
||
217 | // update in the map since the last |
||
218 | // one we processed, if thats the |
||
219 | // case then we are done |
||
220 | if (pos == lastpos) |
||
221 | { |
||
222 | m_updateAgentQueue.Remove(uri); |
||
223 | return true; |
||
224 | } |
||
225 | } |
||
226 | |||
227 | success = UpdateAgent(destination, (IAgentData)pos, 10000); |
||
228 | } |
||
229 | // we get here iff success == false |
||
230 | // blacklist sim for 2 minutes |
||
231 | lock (m_updateAgentQueue) |
||
232 | { |
||
233 | _failedSims.AddOrUpdate(destination.ServerURI, true, 120); |
||
234 | m_updateAgentQueue.Remove(uri); |
||
235 | } |
||
236 | return false; |
||
237 | } |
||
238 | |||
239 | /// <summary> |
||
240 | /// This is the worker function to send AgentData to a neighbor region |
||
241 | /// </summary> |
||
242 | private bool UpdateAgent(GridRegion destination, IAgentData cAgentData, int timeout) |
||
243 | { |
||
244 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: UpdateAgent in {0}", destination.ServerURI); |
||
245 | |||
246 | // Eventually, we want to use a caps url instead of the agentID |
||
247 | string uri = destination.ServerURI + AgentPath() + cAgentData.AgentID + "/"; |
||
248 | |||
249 | try |
||
250 | { |
||
251 | OSDMap args = cAgentData.Pack(); |
||
252 | |||
253 | args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); |
||
254 | args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); |
||
255 | args["destination_name"] = OSD.FromString(destination.RegionName); |
||
256 | args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); |
||
257 | |||
258 | OSDMap result = WebUtil.PutToServiceCompressed(uri, args, timeout); |
||
259 | if (result["Success"].AsBoolean()) |
||
260 | return true; |
||
261 | |||
262 | result = WebUtil.PutToService(uri, args, timeout); |
||
263 | |||
264 | return result["Success"].AsBoolean(); |
||
265 | } |
||
266 | catch (Exception e) |
||
267 | { |
||
268 | m_log.Warn("[REMOTE SIMULATION CONNECTOR]: UpdateAgent failed with exception: " + e.ToString()); |
||
269 | } |
||
270 | |||
271 | return false; |
||
272 | } |
||
273 | |||
274 | |||
275 | /// <summary> |
||
276 | /// </summary> |
||
277 | public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason) |
||
278 | { |
||
279 | reason = "Failed to contact destination"; |
||
280 | version = "Unknown"; |
||
281 | |||
282 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: QueryAccess start, position={0}", position); |
||
283 | |||
284 | IPEndPoint ext = destination.ExternalEndPoint; |
||
285 | if (ext == null) return false; |
||
286 | |||
287 | // Eventually, we want to use a caps url instead of the agentID |
||
288 | string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/"; |
||
289 | |||
290 | OSDMap request = new OSDMap(); |
||
291 | request.Add("position", OSD.FromString(position.ToString())); |
||
292 | |||
293 | try |
||
294 | { |
||
295 | OSDMap result = WebUtil.ServiceOSDRequest(uri, request, "QUERYACCESS", 30000, false); |
||
296 | bool success = result["success"].AsBoolean(); |
||
297 | if (result.ContainsKey("_Result")) |
||
298 | { |
||
299 | OSDMap data = (OSDMap)result["_Result"]; |
||
300 | |||
301 | // FIXME: If there is a _Result map then it's the success key here that indicates the true success |
||
302 | // or failure, not the sibling result node. |
||
303 | success = data["success"]; |
||
304 | |||
305 | reason = data["reason"].AsString(); |
||
306 | if (data["version"] != null && data["version"].AsString() != string.Empty) |
||
307 | version = data["version"].AsString(); |
||
308 | |||
309 | m_log.DebugFormat( |
||
310 | "[REMOTE SIMULATION CONNECTOR]: QueryAccess to {0} returned {1}, reason {2}, version {3} ({4})", |
||
311 | uri, success, reason, version, data["version"].AsString()); |
||
312 | } |
||
313 | |||
314 | if (!success) |
||
315 | { |
||
316 | // If we don't check this then OpenSimulator 0.7.3.1 and some period before will never see the |
||
317 | // actual failure message |
||
318 | if (!result.ContainsKey("_Result")) |
||
319 | { |
||
320 | if (result.ContainsKey("Message")) |
||
321 | { |
||
322 | string message = result["Message"].AsString(); |
||
323 | if (message == "Service request failed: [MethodNotAllowed] MethodNotAllowed") // Old style region |
||
324 | { |
||
325 | m_log.Info("[REMOTE SIMULATION CONNECTOR]: The above web util error was caused by a TP to a sim that doesn't support QUERYACCESS and can be ignored"); |
||
326 | return true; |
||
327 | } |
||
328 | |||
329 | reason = result["Message"]; |
||
330 | } |
||
331 | else |
||
332 | { |
||
333 | reason = "Communications failure"; |
||
334 | } |
||
335 | } |
||
336 | |||
337 | return false; |
||
338 | } |
||
339 | |||
340 | return success; |
||
341 | } |
||
342 | catch (Exception e) |
||
343 | { |
||
344 | m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] QueryAcesss failed with exception; {0}",e.ToString()); |
||
345 | } |
||
346 | |||
347 | return false; |
||
348 | } |
||
349 | |||
350 | /// <summary> |
||
351 | /// </summary> |
||
352 | public bool ReleaseAgent(UUID origin, UUID id, string uri) |
||
353 | { |
||
354 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: ReleaseAgent start"); |
||
355 | |||
356 | try |
||
357 | { |
||
358 | WebUtil.ServiceOSDRequest(uri, null, "DELETE", 10000, false); |
||
359 | } |
||
360 | catch (Exception e) |
||
361 | { |
||
362 | m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] ReleaseAgent failed with exception; {0}",e.ToString()); |
||
363 | } |
||
364 | |||
365 | return true; |
||
366 | } |
||
367 | |||
368 | /// <summary> |
||
369 | /// </summary> |
||
370 | public bool CloseAgent(GridRegion destination, UUID id, string auth_code) |
||
371 | { |
||
372 | string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/?auth=" + auth_code; |
||
373 | m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CloseAgent {0}", uri); |
||
374 | |||
375 | try |
||
376 | { |
||
377 | WebUtil.ServiceOSDRequest(uri, null, "DELETE", 10000, false); |
||
378 | } |
||
379 | catch (Exception e) |
||
380 | { |
||
381 | m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] CloseAgent failed with exception; {0}",e.ToString()); |
||
382 | } |
||
383 | |||
384 | return true; |
||
385 | } |
||
386 | |||
387 | #endregion Agents |
||
388 | |||
389 | #region Objects |
||
390 | |||
391 | protected virtual string ObjectPath() |
||
392 | { |
||
393 | return "object/"; |
||
394 | } |
||
395 | |||
396 | /// <summary> |
||
397 | /// |
||
398 | /// </summary> |
||
399 | public bool CreateObject(GridRegion destination, Vector3 newPosition, ISceneObject sog, bool isLocalCall) |
||
400 | { |
||
401 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CreateObject start"); |
||
402 | |||
403 | string uri = destination.ServerURI + ObjectPath() + sog.UUID + "/"; |
||
404 | |||
405 | try |
||
406 | { |
||
407 | OSDMap args = new OSDMap(2); |
||
408 | |||
409 | args["sog"] = OSD.FromString(sog.ToXml2()); |
||
410 | args["extra"] = OSD.FromString(sog.ExtraToXmlString()); |
||
411 | args["modified"] = OSD.FromBoolean(sog.HasGroupChanged); |
||
412 | args["new_position"] = newPosition.ToString(); |
||
413 | |||
414 | string state = sog.GetStateSnapshot(); |
||
415 | if (state.Length > 0) |
||
416 | args["state"] = OSD.FromString(state); |
||
417 | |||
418 | // Add the input general arguments |
||
419 | args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); |
||
420 | args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); |
||
421 | args["destination_name"] = OSD.FromString(destination.RegionName); |
||
422 | args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); |
||
423 | |||
424 | WebUtil.PostToService(uri, args, 40000); |
||
425 | } |
||
426 | catch (Exception e) |
||
427 | { |
||
428 | m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] CreateObject failed with exception; {0}",e.ToString()); |
||
429 | } |
||
430 | |||
431 | return true; |
||
432 | } |
||
433 | |||
434 | /// <summary> |
||
435 | /// |
||
436 | /// </summary> |
||
437 | public bool CreateObject(GridRegion destination, UUID userID, UUID itemID) |
||
438 | { |
||
439 | // TODO, not that urgent |
||
440 | return false; |
||
441 | } |
||
442 | |||
443 | #endregion Objects |
||
444 | } |
||
445 | } |