diff options
Diffstat (limited to 'OpenSim/Region/Environment')
-rw-r--r-- | OpenSim/Region/Environment/Interfaces/IWorldComm.cs | 15 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Interfaces/IXMLRPC.cs | 14 | ||||
-rw-r--r-- | OpenSim/Region/Environment/ModuleLoader.cs | 8 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Modules/WorldCommModule.cs | 481 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Modules/XMLRPCModule.cs | 360 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Scenes/Scene.cs | 4 |
6 files changed, 881 insertions, 1 deletions
diff --git a/OpenSim/Region/Environment/Interfaces/IWorldComm.cs b/OpenSim/Region/Environment/Interfaces/IWorldComm.cs new file mode 100644 index 0000000..23bdbb6 --- /dev/null +++ b/OpenSim/Region/Environment/Interfaces/IWorldComm.cs | |||
@@ -0,0 +1,15 @@ | |||
1 | using libsecondlife; | ||
2 | using OpenSim.Region.Environment.Modules; | ||
3 | |||
4 | namespace OpenSim.Region.Environment.Interfaces | ||
5 | { | ||
6 | public interface IWorldComm | ||
7 | { | ||
8 | int Listen(uint LocalID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg); | ||
9 | void DeliverMessage(string sourceItemID, int type, int channel, string name, string msg); | ||
10 | bool HasMessages(); | ||
11 | ListenerInfo GetNextMessage(); | ||
12 | void ListenControl(int handle, int active); | ||
13 | void ListenRemove(int handle); | ||
14 | } | ||
15 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Environment/Interfaces/IXMLRPC.cs b/OpenSim/Region/Environment/Interfaces/IXMLRPC.cs new file mode 100644 index 0000000..dc44a8f --- /dev/null +++ b/OpenSim/Region/Environment/Interfaces/IXMLRPC.cs | |||
@@ -0,0 +1,14 @@ | |||
1 | using libsecondlife; | ||
2 | using OpenSim.Region.Environment.Modules; | ||
3 | |||
4 | namespace OpenSim.Region.Environment.Interfaces | ||
5 | { | ||
6 | public interface IXMLRPC | ||
7 | { | ||
8 | LLUUID OpenXMLRPCChannel(uint localID, LLUUID itemID); | ||
9 | void CloseXMLRPCChannel(LLUUID channelKey); | ||
10 | bool hasRequests(); | ||
11 | RPCRequestInfo GetNextRequest(); | ||
12 | void RemoteDataReply(string channel, string message_id, string sdata, int idata); | ||
13 | } | ||
14 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Environment/ModuleLoader.cs b/OpenSim/Region/Environment/ModuleLoader.cs index ce2a843..43c1aae 100644 --- a/OpenSim/Region/Environment/ModuleLoader.cs +++ b/OpenSim/Region/Environment/ModuleLoader.cs | |||
@@ -34,6 +34,12 @@ namespace OpenSim.Region.Environment | |||
34 | module = new AvatarProfilesModule(); | 34 | module = new AvatarProfilesModule(); |
35 | InitialiseModule(module, scene); | 35 | InitialiseModule(module, scene); |
36 | 36 | ||
37 | module = new XMLRPCModule(); | ||
38 | InitialiseModule(module, scene); | ||
39 | |||
40 | module = new WorldCommModule(); | ||
41 | InitialiseModule(module, scene); | ||
42 | |||
37 | LoadRegionModule("OpenSim.Region.ExtensionsScriptModule.dll", "ExtensionsScriptingModule", scene); | 43 | LoadRegionModule("OpenSim.Region.ExtensionsScriptModule.dll", "ExtensionsScriptingModule", scene); |
38 | 44 | ||
39 | string lslPath = Path.Combine("ScriptEngines", "OpenSim.Region.ScriptEngine.DotNetEngine.dll"); | 45 | string lslPath = Path.Combine("ScriptEngines", "OpenSim.Region.ScriptEngine.DotNetEngine.dll"); |
@@ -153,4 +159,4 @@ namespace OpenSim.Region.Environment | |||
153 | LoadedAssemblys.Clear(); | 159 | LoadedAssemblys.Clear(); |
154 | } | 160 | } |
155 | } | 161 | } |
156 | } \ No newline at end of file | 162 | } |
diff --git a/OpenSim/Region/Environment/Modules/WorldCommModule.cs b/OpenSim/Region/Environment/Modules/WorldCommModule.cs new file mode 100644 index 0000000..c2ec699 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/WorldCommModule.cs | |||
@@ -0,0 +1,481 @@ | |||
1 | using System; | ||
2 | using System.IO; | ||
3 | using System.Net.Sockets; | ||
4 | using System.Text; | ||
5 | using System.Threading; | ||
6 | using libsecondlife; | ||
7 | using OpenSim.Framework.Interfaces; | ||
8 | using OpenSim.Framework.Utilities; | ||
9 | using OpenSim.Region.Environment.Interfaces; | ||
10 | using OpenSim.Region.Environment.Scenes; | ||
11 | using OpenSim.Framework.Servers; | ||
12 | using Nwc.XmlRpc; | ||
13 | using System.Collections; | ||
14 | using System.Collections.Generic; | ||
15 | |||
16 | /***************************************************** | ||
17 | * | ||
18 | * WorldCommModule | ||
19 | * | ||
20 | * | ||
21 | * Holding place for world comms - basically llListen | ||
22 | * function implementation. | ||
23 | * | ||
24 | * lLListen(integer channel, string name, key id, string msg) | ||
25 | * The name, id, and msg arguments specify the filtering | ||
26 | * criteria. You can pass the empty string | ||
27 | * (or NULL_KEY for id) for these to set a completely | ||
28 | * open filter; this causes the listen() event handler to be | ||
29 | * invoked for all chat on the channel. To listen only | ||
30 | * for chat spoken by a specific object or avatar, | ||
31 | * specify the name and/or id arguments. To listen | ||
32 | * only for a specific command, specify the | ||
33 | * (case-sensitive) msg argument. If msg is not empty, | ||
34 | * listener will only hear strings which are exactly equal | ||
35 | * to msg. You can also use all the arguments to establish | ||
36 | * the most restrictive filtering criteria. | ||
37 | * | ||
38 | * It might be useful for each listener to maintain a message | ||
39 | * digest, with a list of recent messages by UUID. This can | ||
40 | * be used to prevent in-world repeater loops. However, the | ||
41 | * linden functions do not have this capability, so for now | ||
42 | * thats the way it works. | ||
43 | * | ||
44 | * **************************************************/ | ||
45 | namespace OpenSim.Region.Environment.Modules | ||
46 | { | ||
47 | public class WorldCommModule : IRegionModule, IWorldComm | ||
48 | { | ||
49 | private Scene m_scene; | ||
50 | private object CommListLock = new object(); | ||
51 | private string m_name = "WorldCommModule"; | ||
52 | private ListenerManager m_listenerManager; | ||
53 | private Queue<ListenerInfo> m_pending; | ||
54 | |||
55 | public WorldCommModule() | ||
56 | { | ||
57 | } | ||
58 | |||
59 | public void Initialise(Scene scene) | ||
60 | { | ||
61 | |||
62 | m_scene = scene; | ||
63 | m_scene.RegisterModuleInterface<IWorldComm>(this); | ||
64 | m_listenerManager = new ListenerManager(); | ||
65 | m_pending = new Queue<ListenerInfo>(); | ||
66 | m_scene.EventManager.OnNewClient += NewClient; | ||
67 | |||
68 | } | ||
69 | |||
70 | public void PostInitialise() | ||
71 | { | ||
72 | } | ||
73 | |||
74 | public void CloseDown() | ||
75 | { | ||
76 | } | ||
77 | |||
78 | public string GetName() | ||
79 | { | ||
80 | return m_name; | ||
81 | } | ||
82 | |||
83 | public bool IsSharedModule() | ||
84 | { | ||
85 | return false; | ||
86 | } | ||
87 | |||
88 | public void NewClient(IClientAPI client) | ||
89 | { | ||
90 | client.OnChatFromViewer += DeliverClientMessage; | ||
91 | } | ||
92 | |||
93 | private void DeliverClientMessage(byte[] message, byte type, int channel, LLVector3 fromPos, string fromName, | ||
94 | LLUUID fromAgentID) | ||
95 | { | ||
96 | ASCIIEncoding ae = new ASCIIEncoding(); | ||
97 | |||
98 | DeliverMessage(fromAgentID.ToString(), type, channel, fromName, ae.GetString(message)); | ||
99 | |||
100 | } | ||
101 | |||
102 | public int Listen(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) | ||
103 | { | ||
104 | return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg); | ||
105 | } | ||
106 | |||
107 | public void ListenControl(int handle, int active) | ||
108 | { | ||
109 | if ( active == 1 ) | ||
110 | m_listenerManager.Activate(handle); | ||
111 | else if ( active == 0 ) | ||
112 | m_listenerManager.Dectivate(handle); | ||
113 | |||
114 | } | ||
115 | |||
116 | public void ListenRemove(int handle) | ||
117 | { | ||
118 | m_listenerManager.Remove(handle); | ||
119 | } | ||
120 | |||
121 | // This method scans nearby objects and determines if they are listeners, | ||
122 | // and if so if this message fits the filter. If it does, then | ||
123 | // enqueue the message for delivery to the objects listen event handler. | ||
124 | // Objects that do an llSay have their messages delivered here, and for | ||
125 | // nearby avatards, the SimChat function is used. | ||
126 | public void DeliverMessage(string sourceItemID, int type, int channel, string name, string msg) | ||
127 | { | ||
128 | |||
129 | SceneObjectPart source = null; | ||
130 | ScenePresence avatar = null; | ||
131 | |||
132 | source = m_scene.GetSceneObjectPart(new LLUUID(sourceItemID)); | ||
133 | if (source == null) | ||
134 | { | ||
135 | avatar = m_scene.GetScenePresence(new LLUUID(sourceItemID)); | ||
136 | } | ||
137 | if( (avatar != null) || (source != null) ) | ||
138 | { | ||
139 | // Loop through the objects in the scene | ||
140 | // If they are in proximity, then if they are | ||
141 | // listeners, if so add them to the pending queue | ||
142 | |||
143 | foreach (LLUUID eb in m_scene.Entities.Keys) | ||
144 | { | ||
145 | EntityBase sPart; | ||
146 | |||
147 | m_scene.Entities.TryGetValue(eb, out sPart); | ||
148 | |||
149 | // Dont process if this message is from itself! | ||
150 | if (eb.ToString().Equals(sourceItemID) || | ||
151 | sPart.UUID.ToString().Equals(sourceItemID) ) | ||
152 | continue; | ||
153 | |||
154 | double dis = 0; | ||
155 | |||
156 | if (source != null) | ||
157 | dis = sPart.AbsolutePosition.GetDistanceTo(source.AbsolutePosition); | ||
158 | else | ||
159 | dis = sPart.AbsolutePosition.GetDistanceTo(avatar.AbsolutePosition); | ||
160 | |||
161 | switch (type) | ||
162 | { | ||
163 | case 0: // Whisper | ||
164 | |||
165 | if ((dis < 10) && (dis > -10)) | ||
166 | { | ||
167 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
168 | sourceItemID, sPart.UUID, channel, name, msg | ||
169 | ); | ||
170 | if (isListener != null) | ||
171 | { | ||
172 | m_pending.Enqueue(isListener); | ||
173 | } | ||
174 | |||
175 | } | ||
176 | break; | ||
177 | |||
178 | case 1: // Say | ||
179 | |||
180 | if ((dis < 30) && (dis > -30)) | ||
181 | { | ||
182 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
183 | sourceItemID, sPart.UUID, channel, name, msg | ||
184 | ); | ||
185 | if (isListener != null) | ||
186 | { | ||
187 | m_pending.Enqueue(isListener); | ||
188 | } | ||
189 | |||
190 | } | ||
191 | break; | ||
192 | |||
193 | case 2: // Shout | ||
194 | if ((dis < 100) && (dis > -100)) | ||
195 | { | ||
196 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
197 | sourceItemID, sPart.UUID, channel, name, msg | ||
198 | ); | ||
199 | if (isListener != null) | ||
200 | { | ||
201 | m_pending.Enqueue(isListener); | ||
202 | } | ||
203 | |||
204 | } | ||
205 | break; | ||
206 | |||
207 | case 0xff: // Broadcast | ||
208 | ListenerInfo isListen = m_listenerManager.IsListenerMatch(sourceItemID, eb, channel, name, msg); | ||
209 | if (isListen != null) | ||
210 | { | ||
211 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
212 | sourceItemID, sPart.UUID, channel, name, msg | ||
213 | ); | ||
214 | if (isListener != null) | ||
215 | { | ||
216 | m_pending.Enqueue(isListener); | ||
217 | } | ||
218 | } | ||
219 | break; | ||
220 | } | ||
221 | }; | ||
222 | |||
223 | } | ||
224 | |||
225 | } | ||
226 | |||
227 | public bool HasMessages() | ||
228 | { | ||
229 | return (m_pending.Count > 0); | ||
230 | } | ||
231 | |||
232 | public ListenerInfo GetNextMessage() | ||
233 | { | ||
234 | |||
235 | ListenerInfo li = null; | ||
236 | |||
237 | lock (CommListLock) | ||
238 | { | ||
239 | li = m_pending.Dequeue(); | ||
240 | } | ||
241 | |||
242 | return li; | ||
243 | |||
244 | } | ||
245 | |||
246 | } | ||
247 | |||
248 | // hostID: the ID of the ScenePart | ||
249 | // itemID: the ID of the script host engine | ||
250 | // localID: local ID of host engine | ||
251 | public class ListenerManager | ||
252 | { | ||
253 | private Dictionary<int, ListenerInfo> m_listeners; | ||
254 | private object ListenersLock = new object(); | ||
255 | private int m_MaxListeners = 100; | ||
256 | |||
257 | public ListenerManager() | ||
258 | { | ||
259 | m_listeners = new Dictionary<int, ListenerInfo>(); | ||
260 | } | ||
261 | |||
262 | public int AddListener(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) | ||
263 | { | ||
264 | |||
265 | if ( m_listeners.Count < m_MaxListeners ) | ||
266 | { | ||
267 | ListenerInfo isListener = IsListenerMatch(LLUUID.Zero.ToString(), itemID, channel, name, msg); | ||
268 | |||
269 | if(isListener == null) | ||
270 | { | ||
271 | int newHandle = GetNewHandle(); | ||
272 | |||
273 | if (newHandle > -1) | ||
274 | { | ||
275 | |||
276 | ListenerInfo li = new ListenerInfo(localID, newHandle, itemID, hostID, channel, name, id, msg); | ||
277 | |||
278 | lock (ListenersLock) | ||
279 | { | ||
280 | m_listeners.Add(newHandle, li); | ||
281 | } | ||
282 | |||
283 | return newHandle; | ||
284 | } | ||
285 | |||
286 | } | ||
287 | |||
288 | } | ||
289 | |||
290 | return -1; | ||
291 | |||
292 | } | ||
293 | |||
294 | public void Remove(int handle) | ||
295 | { | ||
296 | m_listeners.Remove(handle); | ||
297 | } | ||
298 | |||
299 | private int GetNewHandle() | ||
300 | { | ||
301 | |||
302 | for (int i = 0; i < int.MaxValue - 1; i++) | ||
303 | { | ||
304 | if (!m_listeners.ContainsKey(i)) | ||
305 | return i; | ||
306 | } | ||
307 | |||
308 | return -1; | ||
309 | |||
310 | } | ||
311 | |||
312 | public bool IsListener(LLUUID hostID) | ||
313 | { | ||
314 | |||
315 | foreach (ListenerInfo li in m_listeners.Values) | ||
316 | { | ||
317 | if (li.GetHostID().Equals(hostID)) | ||
318 | return true; | ||
319 | } | ||
320 | |||
321 | return false; | ||
322 | |||
323 | } | ||
324 | |||
325 | public void Activate(int handle) | ||
326 | { | ||
327 | |||
328 | ListenerInfo li; | ||
329 | |||
330 | if( m_listeners.TryGetValue(handle, out li) ) | ||
331 | { | ||
332 | li.Activate(); | ||
333 | } | ||
334 | } | ||
335 | |||
336 | public void Dectivate(int handle) | ||
337 | { | ||
338 | |||
339 | ListenerInfo li; | ||
340 | |||
341 | if( m_listeners.TryGetValue(handle, out li) ) | ||
342 | { | ||
343 | li.Deactivate(); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | // Theres probably a more clever and efficient way to | ||
348 | // do this, maybe with regex. | ||
349 | public ListenerInfo IsListenerMatch(string sourceItemID, LLUUID listenerKey, int channel, string name, string msg) | ||
350 | { | ||
351 | |||
352 | bool isMatch = true; | ||
353 | |||
354 | foreach (ListenerInfo li in m_listeners.Values) | ||
355 | { | ||
356 | if (li.GetHostID().Equals(listenerKey)) | ||
357 | { | ||
358 | if ( li.IsActive() ) | ||
359 | { | ||
360 | if ( channel == li.GetChannel() ) | ||
361 | { | ||
362 | if ( (li.GetID().ToString().Length > 0) && | ||
363 | (!li.GetID().Equals(LLUUID.Zero)) ) | ||
364 | { | ||
365 | if (!li.GetID().ToString().Equals(sourceItemID)) | ||
366 | { | ||
367 | isMatch = false; | ||
368 | } | ||
369 | } | ||
370 | if ( isMatch && (li.GetName().Length > 0) ) | ||
371 | { | ||
372 | if ( li.GetName().Equals(name) ) | ||
373 | { | ||
374 | isMatch = false; | ||
375 | } | ||
376 | } | ||
377 | if ( isMatch ) | ||
378 | { | ||
379 | return new ListenerInfo( | ||
380 | li.GetLocalID(), li.GetHandle(), li.GetItemID(), li.GetHostID(), | ||
381 | li.GetChannel(), name, li.GetID(), msg, new LLUUID(sourceItemID) | ||
382 | ); | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | return null; | ||
389 | } | ||
390 | |||
391 | } | ||
392 | |||
393 | public class ListenerInfo | ||
394 | { | ||
395 | |||
396 | private LLUUID m_itemID; // ID of the host script engine | ||
397 | private LLUUID m_hostID; // ID of the host/scene part | ||
398 | private LLUUID m_sourceItemID; // ID of the scenePart or avatar source of the message | ||
399 | private int m_channel; // Channel | ||
400 | private int m_handle; // Assigned handle of this listener | ||
401 | private uint m_localID; // Local ID from script engine | ||
402 | private string m_name; // Object name to filter messages from | ||
403 | private LLUUID m_id; // ID to filter messages from | ||
404 | private string m_message; // The message | ||
405 | private bool m_active; // Listener is active or not | ||
406 | |||
407 | public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message) | ||
408 | { | ||
409 | Initialise(localID, handle, ItemID, hostID, channel, name, id, message); | ||
410 | } | ||
411 | |||
412 | public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message, LLUUID sourceItemID) | ||
413 | { | ||
414 | Initialise(localID, handle, ItemID, hostID, channel, name, id, message); | ||
415 | m_sourceItemID = sourceItemID; | ||
416 | } | ||
417 | |||
418 | private void Initialise(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message) | ||
419 | { | ||
420 | m_handle = handle; | ||
421 | m_channel = channel; | ||
422 | m_itemID = ItemID; | ||
423 | m_hostID = hostID; | ||
424 | m_name = name; | ||
425 | m_id = id; | ||
426 | m_message = message; | ||
427 | m_active = true; | ||
428 | m_localID = localID; | ||
429 | } | ||
430 | public LLUUID GetItemID() | ||
431 | { | ||
432 | return m_itemID; | ||
433 | } | ||
434 | public LLUUID GetHostID() | ||
435 | { | ||
436 | return m_hostID; | ||
437 | } | ||
438 | public LLUUID GetSourceItemID() | ||
439 | { | ||
440 | return m_sourceItemID; | ||
441 | } | ||
442 | public int GetChannel() | ||
443 | { | ||
444 | return m_channel; | ||
445 | } | ||
446 | public uint GetLocalID() | ||
447 | { | ||
448 | return m_localID; | ||
449 | } | ||
450 | public int GetHandle() | ||
451 | { | ||
452 | return m_handle; | ||
453 | } | ||
454 | public string GetMessage() | ||
455 | { | ||
456 | return m_message; | ||
457 | } | ||
458 | public string GetName() | ||
459 | { | ||
460 | return m_name; | ||
461 | } | ||
462 | public bool IsActive() | ||
463 | { | ||
464 | return m_active; | ||
465 | } | ||
466 | public void Deactivate() | ||
467 | { | ||
468 | m_active = false; | ||
469 | } | ||
470 | public void Activate() | ||
471 | { | ||
472 | m_active = true; | ||
473 | } | ||
474 | public LLUUID GetID() | ||
475 | { | ||
476 | return m_id; | ||
477 | } | ||
478 | |||
479 | } | ||
480 | |||
481 | } | ||
diff --git a/OpenSim/Region/Environment/Modules/XMLRPCModule.cs b/OpenSim/Region/Environment/Modules/XMLRPCModule.cs new file mode 100644 index 0000000..50ed776 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/XMLRPCModule.cs | |||
@@ -0,0 +1,360 @@ | |||
1 | using System; | ||
2 | using System.IO; | ||
3 | using System.Net.Sockets; | ||
4 | using System.Threading; | ||
5 | using libsecondlife; | ||
6 | using OpenSim.Framework.Interfaces; | ||
7 | using OpenSim.Framework.Utilities; | ||
8 | using OpenSim.Region.Environment.Interfaces; | ||
9 | using OpenSim.Region.Environment.Scenes; | ||
10 | using OpenSim.Framework.Servers; | ||
11 | using Nwc.XmlRpc; | ||
12 | using System.Collections; | ||
13 | using System.Collections.Generic; | ||
14 | |||
15 | /***************************************************** | ||
16 | * | ||
17 | * XMLRPCModule | ||
18 | * | ||
19 | * Module for accepting incoming communications from | ||
20 | * external XMLRPC client and calling a remote data | ||
21 | * procedure for a registered data channel/prim. | ||
22 | * | ||
23 | * | ||
24 | * 1. On module load, open a listener port | ||
25 | * 2. Attach an XMLRPC handler | ||
26 | * 3. When a request is received: | ||
27 | * 3.1 Parse into components: channel key, int, string | ||
28 | * 3.2 Look up registered channel listeners | ||
29 | * 3.3 Call the channel (prim) remote data method | ||
30 | * 3.4 Capture the response (llRemoteDataReply) | ||
31 | * 3.5 Return response to client caller | ||
32 | * 3.6 If no response from llRemoteDataReply within | ||
33 | * RemoteReplyScriptTimeout, generate script timeout fault | ||
34 | * | ||
35 | * Prims in script must: | ||
36 | * 1. Open a remote data channel | ||
37 | * 1.1 Generate a channel ID | ||
38 | * 1.2 Register primid,channelid pair with module | ||
39 | * 2. Implement the remote data procedure handler | ||
40 | * | ||
41 | * llOpenRemoteDataChannel | ||
42 | * llRemoteDataReply | ||
43 | * remote_data(integer type, key channel, key messageid, string sender, integer ival, string sval) | ||
44 | * llCloseRemoteDataChannel | ||
45 | * | ||
46 | * **************************************************/ | ||
47 | namespace OpenSim.Region.Environment.Modules | ||
48 | { | ||
49 | public class XMLRPCModule : IRegionModule, IXMLRPC | ||
50 | { | ||
51 | private Scene m_scene; | ||
52 | private Queue<RPCRequestInfo> rpcQueue = new Queue<RPCRequestInfo>(); | ||
53 | private object XMLRPCListLock = new object(); | ||
54 | private string m_name = "XMLRPCModule"; | ||
55 | private int RemoteReplyScriptWait = 100; | ||
56 | private int RemoteReplyScriptTimeout = 300; | ||
57 | |||
58 | // <channel id, RPCChannelInfo> | ||
59 | private Dictionary<LLUUID, RPCChannelInfo> m_openChannels; | ||
60 | |||
61 | // <channel id, RPCRequestInfo> | ||
62 | private Dictionary<LLUUID, RPCRequestInfo> m_pendingResponse; | ||
63 | |||
64 | public XMLRPCModule() | ||
65 | { | ||
66 | } | ||
67 | |||
68 | public void Initialise(Scene scene) | ||
69 | { | ||
70 | m_scene = scene; | ||
71 | |||
72 | m_scene.RegisterModuleInterface<IXMLRPC>(this); | ||
73 | |||
74 | m_openChannels = new Dictionary<LLUUID, RPCChannelInfo>(); | ||
75 | m_pendingResponse = new Dictionary<LLUUID, RPCRequestInfo>(); | ||
76 | |||
77 | // Start http server | ||
78 | // Attach xmlrpc handlers | ||
79 | BaseHttpServer httpServer = new BaseHttpServer(20800); | ||
80 | httpServer.AddXmlRPCHandler("llRemoteData", this.XmlRpcRemoteData); | ||
81 | httpServer.Start(); | ||
82 | } | ||
83 | |||
84 | public void PostInitialise() | ||
85 | { | ||
86 | } | ||
87 | |||
88 | public void CloseDown() | ||
89 | { | ||
90 | } | ||
91 | |||
92 | public string GetName() | ||
93 | { | ||
94 | return m_name; | ||
95 | } | ||
96 | |||
97 | public bool IsSharedModule() | ||
98 | { | ||
99 | return false; | ||
100 | } | ||
101 | |||
102 | /********************************************** | ||
103 | * OpenXMLRPCChannel | ||
104 | * | ||
105 | * Generate a LLUUID channel key and add it and | ||
106 | * the prim id to dictionary <channelUUID, primUUID> | ||
107 | * | ||
108 | * First check if there is a channel assigned for | ||
109 | * this itemID. If there is, then someone called | ||
110 | * llOpenRemoteDataChannel twice. Just return the | ||
111 | * original channel. Other option is to delete the | ||
112 | * current channel and assign a new one. | ||
113 | * | ||
114 | * ********************************************/ | ||
115 | public LLUUID OpenXMLRPCChannel(uint localID, LLUUID itemID) | ||
116 | { | ||
117 | LLUUID channel = null; | ||
118 | |||
119 | //Is a dupe? | ||
120 | foreach (RPCChannelInfo ci in m_openChannels.Values) | ||
121 | { | ||
122 | if (ci.GetItemID().Equals(itemID)) | ||
123 | { | ||
124 | // return the original channel ID for this item | ||
125 | channel = ci.GetChannelID(); | ||
126 | break; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | if ( (channel == null) || (channel.Equals(LLUUID.Zero)) ) | ||
131 | { | ||
132 | channel = LLUUID.Random(); | ||
133 | RPCChannelInfo rpcChanInfo = new RPCChannelInfo(localID, itemID, channel); | ||
134 | lock (XMLRPCListLock) | ||
135 | { | ||
136 | m_openChannels.Add(channel, rpcChanInfo); | ||
137 | } | ||
138 | |||
139 | } | ||
140 | |||
141 | return channel; | ||
142 | } | ||
143 | |||
144 | /********************************************** | ||
145 | * Remote Data Reply | ||
146 | * | ||
147 | * Response to RPC message | ||
148 | * | ||
149 | *********************************************/ | ||
150 | public void RemoteDataReply(string channel, string message_id, string sdata, int idata) | ||
151 | { | ||
152 | RPCRequestInfo rpcInfo; | ||
153 | LLUUID message_key = new LLUUID(message_id); | ||
154 | |||
155 | if (m_pendingResponse.TryGetValue(message_key, out rpcInfo)) | ||
156 | { | ||
157 | rpcInfo.SetRetval(sdata); | ||
158 | rpcInfo.SetProcessed(true); | ||
159 | |||
160 | lock (XMLRPCListLock) | ||
161 | { | ||
162 | m_pendingResponse.Remove(message_key); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | } | ||
167 | |||
168 | /********************************************** | ||
169 | * CloseXMLRPCChannel | ||
170 | * | ||
171 | * Remove channel from dictionary | ||
172 | * | ||
173 | *********************************************/ | ||
174 | public void CloseXMLRPCChannel(LLUUID channelKey) | ||
175 | { | ||
176 | if(m_openChannels.ContainsKey(channelKey)) | ||
177 | m_openChannels.Remove(channelKey); | ||
178 | } | ||
179 | |||
180 | |||
181 | public XmlRpcResponse XmlRpcRemoteData(XmlRpcRequest request) | ||
182 | { | ||
183 | |||
184 | XmlRpcResponse response = new XmlRpcResponse(); | ||
185 | |||
186 | Hashtable requestData = (Hashtable)request.Params[0]; | ||
187 | bool GoodXML = (requestData.Contains("Channel") && requestData.Contains("IntValue") && requestData.Contains("StringValue")); | ||
188 | |||
189 | if (GoodXML) | ||
190 | { | ||
191 | LLUUID channel = new LLUUID((string)requestData["Channel"]); | ||
192 | RPCChannelInfo rpcChanInfo; | ||
193 | if (m_openChannels.TryGetValue(channel, out rpcChanInfo)) | ||
194 | { | ||
195 | string intVal = (string)requestData["IntValue"]; | ||
196 | string strVal = (string)requestData["StringValue"]; | ||
197 | |||
198 | RPCRequestInfo rpcInfo; | ||
199 | |||
200 | lock (XMLRPCListLock) | ||
201 | { | ||
202 | rpcInfo = new RPCRequestInfo(rpcChanInfo.GetLocalID(), rpcChanInfo.GetItemID(), channel, strVal, intVal); | ||
203 | rpcQueue.Enqueue(rpcInfo); | ||
204 | } | ||
205 | |||
206 | int timeoutCtr = 0; | ||
207 | |||
208 | while(!rpcInfo.IsProcessed() && (timeoutCtr < RemoteReplyScriptTimeout)) | ||
209 | { | ||
210 | Thread.Sleep(RemoteReplyScriptWait); | ||
211 | timeoutCtr += RemoteReplyScriptWait; | ||
212 | } | ||
213 | if (rpcInfo.IsProcessed()) | ||
214 | { | ||
215 | response.Value = rpcInfo.GetRetval(); | ||
216 | rpcInfo = null; | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | response.SetFault(-1, "Script timeout"); | ||
221 | lock (XMLRPCListLock) | ||
222 | { | ||
223 | m_pendingResponse.Remove(rpcInfo.GetMessageID()); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | } | ||
228 | else | ||
229 | { | ||
230 | response.SetFault(-1, "Invalid channel"); | ||
231 | } | ||
232 | |||
233 | } | ||
234 | |||
235 | return response; | ||
236 | } | ||
237 | |||
238 | public bool hasRequests() | ||
239 | { | ||
240 | return (rpcQueue.Count > 0); | ||
241 | } | ||
242 | |||
243 | public RPCRequestInfo GetNextRequest() | ||
244 | { | ||
245 | lock (XMLRPCListLock) | ||
246 | { | ||
247 | RPCRequestInfo rpcInfo = rpcQueue.Dequeue(); | ||
248 | m_pendingResponse.Add(rpcInfo.GetMessageID(), rpcInfo); | ||
249 | return rpcInfo; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | } | ||
254 | |||
255 | /************************************************************** | ||
256 | * | ||
257 | * Class RPCRequestInfo | ||
258 | * | ||
259 | * Holds details about incoming requests until they are picked | ||
260 | * from the queue by LSLLongCmdHandler | ||
261 | * ***********************************************************/ | ||
262 | public class RPCRequestInfo | ||
263 | { | ||
264 | private string m_StrVal; | ||
265 | private string m_IntVal; | ||
266 | private bool m_processed; | ||
267 | private string m_resp; | ||
268 | private uint m_localID; | ||
269 | private LLUUID m_ItemID; | ||
270 | private LLUUID m_MessageID; | ||
271 | private LLUUID m_ChannelKey; | ||
272 | |||
273 | public RPCRequestInfo(uint localID, LLUUID itemID, LLUUID channelKey, string strVal, string intVal) | ||
274 | { | ||
275 | m_localID = localID; | ||
276 | m_StrVal = strVal; | ||
277 | m_IntVal = intVal; | ||
278 | m_ItemID = itemID; | ||
279 | m_ChannelKey = channelKey; | ||
280 | m_MessageID = LLUUID.Random(); | ||
281 | m_processed = false; | ||
282 | m_resp = ""; | ||
283 | } | ||
284 | |||
285 | public bool IsProcessed() | ||
286 | { | ||
287 | return m_processed; | ||
288 | } | ||
289 | public LLUUID GetChannelKey() | ||
290 | { | ||
291 | return m_ChannelKey; | ||
292 | } | ||
293 | |||
294 | public void SetProcessed(bool processed) | ||
295 | { | ||
296 | m_processed = processed; | ||
297 | } | ||
298 | public void SetRetval(string resp) | ||
299 | { | ||
300 | m_resp = resp; | ||
301 | } | ||
302 | public string GetRetval() | ||
303 | { | ||
304 | return m_resp; | ||
305 | } | ||
306 | public uint GetLocalID() | ||
307 | { | ||
308 | return m_localID; | ||
309 | } | ||
310 | public LLUUID GetItemID() | ||
311 | { | ||
312 | return m_ItemID; | ||
313 | } | ||
314 | public string GetStrVal() | ||
315 | { | ||
316 | return m_StrVal; | ||
317 | } | ||
318 | public int GetIntValue() | ||
319 | { | ||
320 | return int.Parse(m_IntVal); | ||
321 | } | ||
322 | public LLUUID GetMessageID() | ||
323 | { | ||
324 | return m_MessageID; | ||
325 | } | ||
326 | |||
327 | |||
328 | } | ||
329 | |||
330 | public class RPCChannelInfo | ||
331 | { | ||
332 | private LLUUID m_itemID; | ||
333 | private uint m_localID; | ||
334 | private LLUUID m_ChannelKey; | ||
335 | |||
336 | public RPCChannelInfo(uint localID, LLUUID itemID, LLUUID channelID) | ||
337 | { | ||
338 | m_ChannelKey = channelID; | ||
339 | m_localID = localID; | ||
340 | m_itemID = itemID; | ||
341 | } | ||
342 | |||
343 | public LLUUID GetItemID() | ||
344 | { | ||
345 | return m_itemID; | ||
346 | } | ||
347 | |||
348 | public LLUUID GetChannelID() | ||
349 | { | ||
350 | return m_ChannelKey; | ||
351 | } | ||
352 | |||
353 | public uint GetLocalID() | ||
354 | { | ||
355 | return m_localID; | ||
356 | } | ||
357 | |||
358 | } | ||
359 | |||
360 | } | ||
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 579ec90..9e19a26 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs | |||
@@ -91,6 +91,8 @@ namespace OpenSim.Region.Environment.Scenes | |||
91 | 91 | ||
92 | private IHttpRequests m_httpRequestModule = null; | 92 | private IHttpRequests m_httpRequestModule = null; |
93 | private ISimChat m_simChatModule = null; | 93 | private ISimChat m_simChatModule = null; |
94 | private IXMLRPC m_xmlrpcModule = null; | ||
95 | private IWorldComm m_worldCommModule = null; | ||
94 | 96 | ||
95 | 97 | ||
96 | // Central Update Loop | 98 | // Central Update Loop |
@@ -210,6 +212,8 @@ namespace OpenSim.Region.Environment.Scenes | |||
210 | { | 212 | { |
211 | m_simChatModule = RequestModuleInterface<ISimChat>(); | 213 | m_simChatModule = RequestModuleInterface<ISimChat>(); |
212 | m_httpRequestModule = RequestModuleInterface<IHttpRequests>(); | 214 | m_httpRequestModule = RequestModuleInterface<IHttpRequests>(); |
215 | m_xmlrpcModule = RequestModuleInterface<IXMLRPC>(); | ||
216 | m_worldCommModule = RequestModuleInterface<IWorldComm>(); | ||
213 | 217 | ||
214 | XferManager = RequestModuleInterface<IXfer>(); | 218 | XferManager = RequestModuleInterface<IXfer>(); |
215 | } | 219 | } |