aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Scripting/XMLRPC
diff options
context:
space:
mode:
authorAdam Frisby2008-04-30 21:16:36 +0000
committerAdam Frisby2008-04-30 21:16:36 +0000
commitf5c312bc3c2567449c7268a54a08a54119f58d53 (patch)
tree424668a4bbec6873ebc5b8256f3671db102f5e9c /OpenSim/Region/Environment/Modules/Scripting/XMLRPC
parent* Adds the AuthbuyerID field to sqlite and makes use of it. (diff)
downloadopensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.zip
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.gz
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.bz2
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.xz
* Refactored Environment/Modules directory - modules now reside in their own directory with any associated module-specific classes.
* Each module directory is currently inside one of the following category folders: Agent (Anything relating to do with Client<->Server communications.), Avatar (Anything to do with the avatar or presence inworld), Framework (Classes modules can use), Grid (Grid traffic, new OGS2 grid comms), Scripting (Scripting functions, etc), World (The enrivonment/scene, IE Sun/Tree modules.) * This should be moved into a seperate project file.
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Scripting/XMLRPC')
-rw-r--r--OpenSim/Region/Environment/Modules/Scripting/XMLRPC/XMLRPCModule.cs672
1 files changed, 672 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/Scripting/XMLRPC/XMLRPCModule.cs b/OpenSim/Region/Environment/Modules/Scripting/XMLRPC/XMLRPCModule.cs
new file mode 100644
index 0000000..1139b4b
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Scripting/XMLRPC/XMLRPCModule.cs
@@ -0,0 +1,672 @@
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 OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using System.Reflection;
33using System.Threading;
34using libsecondlife;
35using log4net;
36using Nini.Config;
37using Nwc.XmlRpc;
38using OpenSim.Framework;
39using OpenSim.Framework.Servers;
40using OpenSim.Region.Environment.Interfaces;
41using OpenSim.Region.Environment.Scenes;
42
43/*****************************************************
44 *
45 * XMLRPCModule
46 *
47 * Module for accepting incoming communications from
48 * external XMLRPC client and calling a remote data
49 * procedure for a registered data channel/prim.
50 *
51 *
52 * 1. On module load, open a listener port
53 * 2. Attach an XMLRPC handler
54 * 3. When a request is received:
55 * 3.1 Parse into components: channel key, int, string
56 * 3.2 Look up registered channel listeners
57 * 3.3 Call the channel (prim) remote data method
58 * 3.4 Capture the response (llRemoteDataReply)
59 * 3.5 Return response to client caller
60 * 3.6 If no response from llRemoteDataReply within
61 * RemoteReplyScriptTimeout, generate script timeout fault
62 *
63 * Prims in script must:
64 * 1. Open a remote data channel
65 * 1.1 Generate a channel ID
66 * 1.2 Register primid,channelid pair with module
67 * 2. Implement the remote data procedure handler
68 *
69 * llOpenRemoteDataChannel
70 * llRemoteDataReply
71 * remote_data(integer type, key channel, key messageid, string sender, integer ival, string sval)
72 * llCloseRemoteDataChannel
73 *
74 * **************************************************/
75
76namespace OpenSim.Region.Environment.Modules.Scripting.XMLRPC
77{
78 public class XMLRPCModule : IRegionModule, IXMLRPC
79 {
80 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
81
82 private object XMLRPCListLock = new object();
83 private string m_name = "XMLRPCModule";
84 private int RemoteReplyScriptWait = 300;
85 private int RemoteReplyScriptTimeout = 9000;
86 private int m_remoteDataPort = 0;
87 private List<Scene> m_scenes = new List<Scene>();
88
89 // <channel id, RPCChannelInfo>
90 private Dictionary<LLUUID, RPCChannelInfo> m_openChannels;
91
92 private Dictionary<LLUUID, RPCRequestInfo> m_rpcPending;
93 private Dictionary<LLUUID, RPCRequestInfo> m_rpcPendingResponses;
94
95 private Dictionary<LLUUID, SendRemoteDataRequest> m_pendingSRDResponses;
96
97 public void Initialise(Scene scene, IConfigSource config)
98 {
99 try
100 {
101 m_remoteDataPort = config.Configs["Network"].GetInt("remoteDataPort", m_remoteDataPort);
102 }
103 catch (Exception)
104 {
105 }
106
107 if (!m_scenes.Contains(scene))
108 {
109 m_scenes.Add(scene);
110
111 scene.RegisterModuleInterface<IXMLRPC>(this);
112 }
113 }
114
115 public void PostInitialise()
116 {
117 if (IsEnabled())
118 {
119 m_openChannels = new Dictionary<LLUUID, RPCChannelInfo>();
120 m_rpcPending = new Dictionary<LLUUID, RPCRequestInfo>();
121 m_rpcPendingResponses = new Dictionary<LLUUID, RPCRequestInfo>();
122 m_pendingSRDResponses = new Dictionary<LLUUID, SendRemoteDataRequest>();
123
124 // Start http server
125 // Attach xmlrpc handlers
126 m_log.Info("[REMOTE_DATA]: " +
127 "Starting XMLRPC Server on port " + m_remoteDataPort + " for llRemoteData commands.");
128 BaseHttpServer httpServer = new BaseHttpServer((uint)m_remoteDataPort);
129 httpServer.AddXmlRPCHandler("llRemoteData", XmlRpcRemoteData);
130 httpServer.Start();
131 }
132 }
133
134 public void Close()
135 {
136 }
137
138 public string Name
139 {
140 get { return m_name; }
141 }
142
143 public bool IsSharedModule
144 {
145 get { return true; }
146 }
147
148 public bool IsEnabled()
149 {
150 return (m_remoteDataPort > 0);
151 }
152
153 /**********************************************
154 * OpenXMLRPCChannel
155 *
156 * Generate a LLUUID channel key and add it and
157 * the prim id to dictionary <channelUUID, primUUID>
158 *
159 * First check if there is a channel assigned for
160 * this itemID. If there is, then someone called
161 * llOpenRemoteDataChannel twice. Just return the
162 * original channel. Other option is to delete the
163 * current channel and assign a new one.
164 *
165 * ********************************************/
166
167 public LLUUID OpenXMLRPCChannel(uint localID, LLUUID itemID)
168 {
169 LLUUID channel = new LLUUID();
170
171 //Is a dupe?
172 foreach (RPCChannelInfo ci in m_openChannels.Values)
173 {
174 if (ci.GetItemID().Equals(itemID))
175 {
176 // return the original channel ID for this item
177 channel = ci.GetChannelID();
178 break;
179 }
180 }
181
182 if (channel == LLUUID.Zero)
183 {
184 channel = LLUUID.Random();
185 RPCChannelInfo rpcChanInfo = new RPCChannelInfo(localID, itemID, channel);
186 lock (XMLRPCListLock)
187 {
188 m_openChannels.Add(channel, rpcChanInfo);
189 }
190 }
191
192 return channel;
193 }
194
195 // Delete channels based on itemID
196 // for when a script is deleted
197 public void DeleteChannels(LLUUID itemID)
198 {
199
200 if (m_openChannels != null)
201 {
202 ArrayList tmp = new ArrayList();
203
204 lock (XMLRPCListLock)
205 {
206 foreach (RPCChannelInfo li in m_openChannels.Values)
207 {
208 if (li.GetItemID().Equals(itemID))
209 {
210 tmp.Add(itemID);
211 }
212 }
213
214 IEnumerator tmpEnumerator = tmp.GetEnumerator();
215 while ( tmpEnumerator.MoveNext() )
216 m_openChannels.Remove((LLUUID)tmpEnumerator.Current);
217 }
218
219 }
220
221 }
222
223 /**********************************************
224 * Remote Data Reply
225 *
226 * Response to RPC message
227 *
228 *********************************************/
229
230 public void RemoteDataReply(string channel, string message_id, string sdata, int idata)
231 {
232 RPCRequestInfo rpcInfo;
233 LLUUID message_key = new LLUUID(message_id);
234
235 if (m_rpcPendingResponses.TryGetValue(message_key, out rpcInfo))
236 {
237 rpcInfo.SetStrRetval(sdata);
238 rpcInfo.SetIntRetval(idata);
239 rpcInfo.SetProcessed(true);
240 m_rpcPendingResponses.Remove(message_key);
241 }
242 }
243
244 /**********************************************
245 * CloseXMLRPCChannel
246 *
247 * Remove channel from dictionary
248 *
249 *********************************************/
250
251 public void CloseXMLRPCChannel(LLUUID channelKey)
252 {
253 if (m_openChannels.ContainsKey(channelKey))
254 m_openChannels.Remove(channelKey);
255 }
256
257
258 public XmlRpcResponse XmlRpcRemoteData(XmlRpcRequest request)
259 {
260 XmlRpcResponse response = new XmlRpcResponse();
261
262 Hashtable requestData = (Hashtable)request.Params[0];
263 bool GoodXML = (requestData.Contains("Channel") && requestData.Contains("IntValue") &&
264 requestData.Contains("StringValue"));
265
266 if (GoodXML)
267 {
268 LLUUID channel = new LLUUID((string)requestData["Channel"]);
269 RPCChannelInfo rpcChanInfo;
270 if (m_openChannels.TryGetValue(channel, out rpcChanInfo))
271 {
272 string intVal = (string)requestData["IntValue"];
273 string strVal = (string)requestData["StringValue"];
274
275 RPCRequestInfo rpcInfo;
276
277 lock (XMLRPCListLock)
278 {
279 rpcInfo =
280 new RPCRequestInfo(rpcChanInfo.GetLocalID(), rpcChanInfo.GetItemID(), channel, strVal,
281 intVal);
282 m_rpcPending.Add(rpcInfo.GetMessageID(), rpcInfo);
283 }
284
285 int timeoutCtr = 0;
286
287 while (!rpcInfo.IsProcessed() && (timeoutCtr < RemoteReplyScriptTimeout))
288 {
289 Thread.Sleep(RemoteReplyScriptWait);
290 timeoutCtr += RemoteReplyScriptWait;
291 }
292 if (rpcInfo.IsProcessed())
293 {
294 Hashtable param = new Hashtable();
295 param["StringValue"] = rpcInfo.GetStrRetval();
296 param["IntValue"] = Convert.ToString(rpcInfo.GetIntRetval());
297
298 ArrayList parameters = new ArrayList();
299 parameters.Add(param);
300
301 response.Value = parameters;
302 rpcInfo = null;
303 }
304 else
305 {
306 response.SetFault(-1, "Script timeout");
307 rpcInfo = null;
308 }
309 }
310 else
311 {
312 response.SetFault(-1, "Invalid channel");
313 }
314 }
315
316 return response;
317 }
318
319 public bool hasRequests()
320 {
321 lock (XMLRPCListLock)
322 {
323 if (m_rpcPending != null)
324 return (m_rpcPending.Count > 0);
325 else
326 return false;
327 }
328 }
329
330 public RPCRequestInfo GetNextCompletedRequest()
331 {
332 if (m_rpcPending != null)
333 {
334 lock (XMLRPCListLock)
335 {
336 foreach (LLUUID luid in m_rpcPending.Keys)
337 {
338 RPCRequestInfo tmpReq;
339
340 if (m_rpcPending.TryGetValue(luid, out tmpReq))
341 {
342
343 if (!tmpReq.IsProcessed()) return tmpReq;
344 }
345 }
346 }
347 }
348 return null;
349 }
350
351 public void RemoveCompletedRequest(LLUUID id)
352 {
353 lock (XMLRPCListLock)
354 {
355 RPCRequestInfo tmp;
356 if (m_rpcPending.TryGetValue(id, out tmp))
357 {
358 m_rpcPending.Remove(id);
359 m_rpcPendingResponses.Add(id, tmp);
360 }
361 else
362 {
363 Console.WriteLine("UNABLE TO REMOVE COMPLETED REQUEST");
364 }
365 }
366 }
367
368 public LLUUID SendRemoteData(uint localID, LLUUID itemID, string channel, string dest, int idata, string sdata)
369 {
370
371 SendRemoteDataRequest req = new SendRemoteDataRequest(
372 localID, itemID, channel, dest, idata, sdata
373 );
374 m_pendingSRDResponses.Add(req.GetReqID(), req);
375 return req.process();
376
377 }
378
379 public SendRemoteDataRequest GetNextCompletedSRDRequest()
380 {
381 if (m_pendingSRDResponses != null)
382 {
383 lock (XMLRPCListLock)
384 {
385 foreach (LLUUID luid in m_pendingSRDResponses.Keys)
386 {
387 SendRemoteDataRequest tmpReq;
388
389 if (m_pendingSRDResponses.TryGetValue(luid, out tmpReq))
390 {
391 if (tmpReq.finished)
392 return tmpReq;
393 }
394 }
395 }
396 }
397 return null;
398 }
399
400 public void RemoveCompletedSRDRequest(LLUUID id)
401 {
402 lock (XMLRPCListLock)
403 {
404 SendRemoteDataRequest tmpReq;
405 if (m_pendingSRDResponses.TryGetValue(id, out tmpReq))
406 {
407 m_pendingSRDResponses.Remove(id);
408 }
409 }
410 }
411
412 public void CancelSRDRequests(LLUUID itemID)
413 {
414 if (m_pendingSRDResponses != null)
415 {
416 lock (XMLRPCListLock)
417 {
418 foreach (SendRemoteDataRequest li in m_pendingSRDResponses.Values)
419 {
420 if (li.m_itemID.Equals(itemID))
421 m_pendingSRDResponses.Remove(li.GetReqID());
422 }
423 }
424 }
425 }
426 }
427
428 public class RPCRequestInfo
429 {
430 private string m_StrVal;
431 private string m_IntVal;
432 private bool m_processed;
433 private string m_respStr;
434 private int m_respInt;
435 private uint m_localID;
436 private LLUUID m_ItemID;
437 private LLUUID m_MessageID;
438 private LLUUID m_ChannelKey;
439
440 public RPCRequestInfo(uint localID, LLUUID itemID, LLUUID channelKey, string strVal, string intVal)
441 {
442 m_localID = localID;
443 m_StrVal = strVal;
444 m_IntVal = intVal;
445 m_ItemID = itemID;
446 m_ChannelKey = channelKey;
447 m_MessageID = LLUUID.Random();
448 m_processed = false;
449 m_respStr = String.Empty;
450 m_respInt = 0;
451 }
452
453 public bool IsProcessed()
454 {
455 return m_processed;
456 }
457
458 public LLUUID GetChannelKey()
459 {
460 return m_ChannelKey;
461 }
462
463 public void SetProcessed(bool processed)
464 {
465 m_processed = processed;
466 }
467
468 public void SetStrRetval(string resp)
469 {
470 m_respStr = resp;
471 }
472
473 public string GetStrRetval()
474 {
475 return m_respStr;
476 }
477 public void SetIntRetval(int resp)
478 {
479 m_respInt = resp;
480 }
481
482 public int GetIntRetval()
483 {
484 return m_respInt;
485 }
486 public uint GetLocalID()
487 {
488 return m_localID;
489 }
490
491 public LLUUID GetItemID()
492 {
493 return m_ItemID;
494 }
495
496 public string GetStrVal()
497 {
498 return m_StrVal;
499 }
500
501 public int GetIntValue()
502 {
503 return int.Parse(m_IntVal);
504 }
505
506 public LLUUID GetMessageID()
507 {
508 return m_MessageID;
509 }
510 }
511
512 public class RPCChannelInfo
513 {
514 private LLUUID m_itemID;
515 private uint m_localID;
516 private LLUUID m_ChannelKey;
517
518 public RPCChannelInfo(uint localID, LLUUID itemID, LLUUID channelID)
519 {
520 m_ChannelKey = channelID;
521 m_localID = localID;
522 m_itemID = itemID;
523 }
524
525 public LLUUID GetItemID()
526 {
527 return m_itemID;
528 }
529
530 public LLUUID GetChannelID()
531 {
532 return m_ChannelKey;
533 }
534
535 public uint GetLocalID()
536 {
537 return m_localID;
538 }
539
540 }
541
542 public class SendRemoteDataRequest
543 {
544
545 public LLUUID reqID;
546 public string destURL;
547 public string channel;
548 public string sdata;
549 public int idata;
550 public bool finished;
551 public string response_sdata;
552 public int response_idata;
553 public XmlRpcRequest request;
554 private Thread httpThread;
555 public LLUUID m_itemID;
556 public uint m_localID;
557 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
558
559 public SendRemoteDataRequest(uint localID, LLUUID itemID, string channel, string dest, int idata, string sdata)
560 {
561
562 this.channel = channel;
563 this.destURL = dest;
564 this.idata = idata;
565 this.sdata = sdata;
566 m_itemID = itemID;
567 m_localID = localID;
568
569 reqID = LLUUID.Random();
570
571 }
572
573 public LLUUID process()
574 {
575 httpThread = new Thread(SendRequest);
576 httpThread.Name = "HttpRequestThread";
577 httpThread.Priority = ThreadPriority.BelowNormal;
578 httpThread.IsBackground = true;
579 finished = false;
580 httpThread.Start();
581 ThreadTracker.Add(httpThread);
582
583 return reqID;
584
585 }
586
587 /*
588 * TODO: More work on the response codes. Right now
589 * returning 200 for success or 499 for exception
590 */
591
592 public void SendRequest()
593 {
594 Hashtable param = new Hashtable();
595
596 // Check if channel is an LLUUID
597 // if not, use as method name
598 LLUUID parseUID;
599 string mName = "llRemoteData";
600 if( (channel != null) && (channel != "") )
601 if( !LLUUID.TryParse(channel, out parseUID) )
602 mName = channel;
603 else
604 param["Channel"] = channel;
605
606 param["StringValue"] = sdata;
607 param["IntValue"] = Convert.ToString(idata);
608
609 ArrayList parameters = new ArrayList();
610 parameters.Add(param);
611 XmlRpcRequest req = new XmlRpcRequest(mName, parameters);
612 try
613 {
614 XmlRpcResponse resp = req.Send(destURL, 30000);
615 if (resp != null)
616 {
617 Hashtable respParms;
618 if(resp.Value.GetType().Equals(Type.GetType("System.Collections.Hashtable"))) {
619 respParms = (Hashtable)resp.Value;
620 }
621 else {
622 ArrayList respData = (ArrayList)resp.Value;
623 respParms = (Hashtable)respData[0];
624 }
625 if (respParms != null)
626 {
627 if (respParms.Contains("StringValue"))
628 {
629 sdata = (string)respParms["StringValue"];
630 }
631 if (respParms.Contains("IntValue"))
632 {
633 idata = Convert.ToInt32((string)respParms["IntValue"]);
634 }
635 if (respParms.Contains("faultString"))
636 {
637 sdata = (string)respParms["faultString"];
638 }
639 if (respParms.Contains("faultCode"))
640 {
641 idata = Convert.ToInt32(respParms["faultCode"]);
642 }
643 }
644 }
645 }
646 catch (WebException we)
647 {
648 sdata = we.Message;
649 m_log.Warn("[SendRemoteDataRequest]: Request failed");
650 m_log.Warn(we.StackTrace);
651 }
652
653 finished = true;
654 }
655
656 public void Stop()
657 {
658 try
659 {
660 httpThread.Abort();
661 }
662 catch (Exception)
663 {
664 }
665 }
666
667 public LLUUID GetReqID()
668 {
669 return reqID;
670 }
671 }
672} \ No newline at end of file