OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
CapabilitiesModule.cs
Go to the documentation of this file.
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 copyrightD
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;
30 using System.Collections.Generic;
31 using System.Linq;
32 using System.Reflection;
33 using System.Text;
34 using log4net;
35 using Nini.Config;
36 using Mono.Addins;
37 using OpenMetaverse;
38 using OpenSim.Framework;
39 using OpenSim.Framework.Console;
40 using OpenSim.Framework.Servers;
41 using OpenSim.Framework.Servers.HttpServer;
42 using OpenSim.Region.Framework.Interfaces;
43 using OpenSim.Region.Framework.Scenes;
45 
46 namespace OpenSim.Region.CoreModules.Framework
47 {
48  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CapabilitiesModule")]
50  {
51  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 
53  private string m_showCapsCommandFormat = " {0,-38} {1,-60}\n";
54 
55  protected Scene m_scene;
56 
60  protected Dictionary<uint, Caps> m_capsObjects = new Dictionary<uint, Caps>();
61 
62  protected Dictionary<UUID, string> m_capsPaths = new Dictionary<UUID, string>();
63 
64  protected Dictionary<UUID, Dictionary<ulong, string>> m_childrenSeeds
65  = new Dictionary<UUID, Dictionary<ulong, string>>();
66 
67  public void Initialise(IConfigSource source)
68  {
69  }
70 
71  public void AddRegion(Scene scene)
72  {
73  m_scene = scene;
74  m_scene.RegisterModuleInterface<ICapabilitiesModule>(this);
75 
76  MainConsole.Instance.Commands.AddCommand(
77  "Comms", false, "show caps list",
78  "show caps list",
79  "Shows list of registered capabilities for users.", HandleShowCapsListCommand);
80 
81  MainConsole.Instance.Commands.AddCommand(
82  "Comms", false, "show caps stats by user",
83  "show caps stats by user [<first-name> <last-name>]",
84  "Shows statistics on capabilities use by user.",
85  "If a user name is given, then prints a detailed breakdown of caps use ordered by number of requests received.",
86  HandleShowCapsStatsByUserCommand);
87 
88  MainConsole.Instance.Commands.AddCommand(
89  "Comms", false, "show caps stats by cap",
90  "show caps stats by cap [<cap-name>]",
91  "Shows statistics on capabilities use by capability.",
92  "If a capability name is given, then prints a detailed breakdown of use by each user.",
93  HandleShowCapsStatsByCapCommand);
94  }
95 
96  public void RegionLoaded(Scene scene)
97  {
98  }
99 
100  public void RemoveRegion(Scene scene)
101  {
102  m_scene.UnregisterModuleInterface<ICapabilitiesModule>(this);
103  }
104 
105  public void PostInitialise()
106  {
107  }
108 
109  public void Close() {}
110 
111  public string Name
112  {
113  get { return "Capabilities Module"; }
114  }
115 
116  public Type ReplaceableInterface
117  {
118  get { return null; }
119  }
120 
121  public void CreateCaps(UUID agentId, uint circuitCode)
122  {
123  int ts = Util.EnvironmentTickCount();
124 /* this as no business here...
125  * must be done elsewhere ( and is )
126  int flags = m_scene.GetUserFlags(agentId);
127 
128  m_log.ErrorFormat("[CreateCaps]: banCheck {0} ", Util.EnvironmentTickCountSubtract(ts));
129 
130  if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags))
131  return;
132 */
133  Caps caps;
134  String capsObjectPath = GetCapsPath(agentId);
135 
136  lock (m_capsObjects)
137  {
138  if (m_capsObjects.ContainsKey(circuitCode))
139  {
140  Caps oldCaps = m_capsObjects[circuitCode];
141 
142 
143  if (capsObjectPath == oldCaps.CapsObjectPath)
144  {
145  m_log.WarnFormat(
146  "[CAPS]: Reusing caps for agent {0} in region {1}. Old caps path {2}, new caps path {3}. ",
147  agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath);
148  return;
149  }
150  else
151  {
152  // not reusing add extra melanie cleanup
153  // Remove tge handlers. They may conflict with the
154  // new object created below
155  oldCaps.DeregisterHandlers();
156 
157  // Better safe ... should not be needed but also
158  // no big deal
159  m_capsObjects.Remove(circuitCode);
160  }
161  }
162 
163 // m_log.DebugFormat(
164 // "[CAPS]: Adding capabilities for agent {0} in {1} with path {2}",
165 // agentId, m_scene.RegionInfo.RegionName, capsObjectPath);
166 
167  caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName,
168  (MainServer.Instance == null) ? 0: MainServer.Instance.Port,
169  capsObjectPath, agentId, m_scene.RegionInfo.RegionName);
170 
171  m_log.DebugFormat("[CreateCaps]: new caps agent {0}, circuit {1}, path {2}, time {3} ",agentId,
172  circuitCode,caps.CapsObjectPath, Util.EnvironmentTickCountSubtract(ts));
173 
174  m_capsObjects[circuitCode] = caps;
175  }
176  m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps);
177 // m_log.ErrorFormat("[CreateCaps]: end {0} ", Util.EnvironmentTickCountSubtract(ts));
178 
179  }
180 
181  public void RemoveCaps(UUID agentId, uint circuitCode)
182  {
183  m_log.DebugFormat("[CAPS]: Remove caps for agent {0} in region {1}", agentId, m_scene.RegionInfo.RegionName);
184  lock (m_childrenSeeds)
185  {
186  if (m_childrenSeeds.ContainsKey(agentId))
187  {
188  m_childrenSeeds.Remove(agentId);
189  }
190  }
191 
192  lock (m_capsObjects)
193  {
194  if (m_capsObjects.ContainsKey(circuitCode))
195  {
196  m_capsObjects[circuitCode].DeregisterHandlers();
197  m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[circuitCode]);
198  m_capsObjects.Remove(circuitCode);
199  }
200  else
201  {
202  foreach (KeyValuePair<uint, Caps> kvp in m_capsObjects)
203  {
204  if (kvp.Value.AgentID == agentId)
205  {
206  kvp.Value.DeregisterHandlers();
207  m_scene.EventManager.TriggerOnDeregisterCaps(agentId, kvp.Value);
208  m_capsObjects.Remove(kvp.Key);
209  return;
210  }
211  }
212  m_log.WarnFormat(
213  "[CAPS]: Received request to remove CAPS handler for root agent {0} in {1}, but no such CAPS handler found!",
214  agentId, m_scene.RegionInfo.RegionName);
215  }
216  }
217  }
218 
219  public Caps GetCapsForUser(uint circuitCode)
220  {
221  lock (m_capsObjects)
222  {
223  if (m_capsObjects.ContainsKey(circuitCode))
224  {
225  return m_capsObjects[circuitCode];
226  }
227  }
228 
229  return null;
230  }
231 
232  public void ActivateCaps(uint circuitCode)
233  {
234  lock (m_capsObjects)
235  {
236  if (m_capsObjects.ContainsKey(circuitCode))
237  {
238  m_capsObjects[circuitCode].Activate();
239  }
240  }
241  }
242 
244  {
245  lock (m_capsPaths)
246  m_capsPaths[agent.AgentID] = agent.CapsPath;
247 
248  lock (m_childrenSeeds)
249  m_childrenSeeds[agent.AgentID]
250  = ((agent.ChildrenCapSeeds == null) ? new Dictionary<ulong, string>() : agent.ChildrenCapSeeds);
251  }
252 
253  public string GetCapsPath(UUID agentId)
254  {
255  lock (m_capsPaths)
256  {
257  if (m_capsPaths.ContainsKey(agentId))
258  {
259  return m_capsPaths[agentId];
260  }
261  }
262 
263  return null;
264  }
265 
266  public Dictionary<ulong, string> GetChildrenSeeds(UUID agentID)
267  {
268  Dictionary<ulong, string> seeds = null;
269 
270  lock (m_childrenSeeds)
271  if (m_childrenSeeds.TryGetValue(agentID, out seeds))
272  return seeds;
273 
274  return new Dictionary<ulong, string>();
275  }
276 
277  public void DropChildSeed(UUID agentID, ulong handle)
278  {
279  Dictionary<ulong, string> seeds;
280 
281  lock (m_childrenSeeds)
282  {
283  if (m_childrenSeeds.TryGetValue(agentID, out seeds))
284  {
285  seeds.Remove(handle);
286  }
287  }
288  }
289 
290  public string GetChildSeed(UUID agentID, ulong handle)
291  {
292  Dictionary<ulong, string> seeds;
293  string returnval;
294 
295  lock (m_childrenSeeds)
296  {
297  if (m_childrenSeeds.TryGetValue(agentID, out seeds))
298  {
299  if (seeds.TryGetValue(handle, out returnval))
300  return returnval;
301  }
302  }
303 
304  return null;
305  }
306 
307  public void SetChildrenSeed(UUID agentID, Dictionary<ulong, string> seeds)
308  {
309  //m_log.DebugFormat(" !!! Setting child seeds in {0} to {1}", m_scene.RegionInfo.RegionName, seeds.Count);
310 
311  lock (m_childrenSeeds)
312  m_childrenSeeds[agentID] = seeds;
313  }
314 
315  public void DumpChildrenSeeds(UUID agentID)
316  {
317  m_log.Info("================ ChildrenSeed "+m_scene.RegionInfo.RegionName+" ================");
318 
319  lock (m_childrenSeeds)
320  {
321  foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID])
322  {
323  uint x, y;
324  Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
325  m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
326  }
327  }
328  }
329 
330  private void HandleShowCapsListCommand(string module, string[] cmdParams)
331  {
333  return;
334 
335  StringBuilder capsReport = new StringBuilder();
336  capsReport.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName);
337 
338  lock (m_capsObjects)
339  {
340  foreach (KeyValuePair<uint, Caps> kvp in m_capsObjects)
341  {
342  capsReport.AppendFormat("** Circuit {0}:\n", kvp.Key);
343  Caps caps = kvp.Value;
344 
345  for (IDictionaryEnumerator kvp2 = caps.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); )
346  {
347  Uri uri = new Uri(kvp2.Value.ToString());
348  capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery);
349  }
350 
351  foreach (KeyValuePair<string, PollServiceEventArgs> kvp2 in caps.GetPollHandlers())
352  capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, kvp2.Value.Url);
353 
354  foreach (KeyValuePair<string, string> kvp3 in caps.ExternalCapsHandlers)
355  capsReport.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value);
356  }
357  }
358 
359  MainConsole.Instance.Output(capsReport.ToString());
360  }
361 
362  private void HandleShowCapsStatsByCapCommand(string module, string[] cmdParams)
363  {
365  return;
366 
367  if (cmdParams.Length != 5 && cmdParams.Length != 6)
368  {
369  MainConsole.Instance.Output("Usage: show caps stats by cap [<cap-name>]");
370  return;
371  }
372 
373  StringBuilder sb = new StringBuilder();
374  sb.AppendFormat("Region {0}:\n", m_scene.Name);
375 
376  if (cmdParams.Length == 5)
377  {
378  BuildSummaryStatsByCapReport(sb);
379  }
380  else if (cmdParams.Length == 6)
381  {
382  BuildDetailedStatsByCapReport(sb, cmdParams[5]);
383  }
384 
385  MainConsole.Instance.Output(sb.ToString());
386  }
387 
388  private void BuildDetailedStatsByCapReport(StringBuilder sb, string capName)
389  {
390  /*
391  sb.AppendFormat("Capability name {0}\n", capName);
392 
393  ConsoleDisplayTable cdt = new ConsoleDisplayTable();
394  cdt.AddColumn("User Name", 34);
395  cdt.AddColumn("Req Received", 12);
396  cdt.AddColumn("Req Handled", 12);
397  cdt.Indent = 2;
398 
399  Dictionary<string, int> receivedStats = new Dictionary<string, int>();
400  Dictionary<string, int> handledStats = new Dictionary<string, int>();
401 
402  m_scene.ForEachScenePresence(
403  sp =>
404  {
405  Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
406 
407  if (caps == null)
408  return;
409 
410  Dictionary<string, IRequestHandler> capsHandlers = caps.CapsHandlers.GetCapsHandlers();
411 
412  IRequestHandler reqHandler;
413  if (capsHandlers.TryGetValue(capName, out reqHandler))
414  {
415  receivedStats[sp.Name] = reqHandler.RequestsReceived;
416  handledStats[sp.Name] = reqHandler.RequestsHandled;
417  }
418  else
419  {
420  PollServiceEventArgs pollHandler = null;
421  if (caps.TryGetPollHandler(capName, out pollHandler))
422  {
423  receivedStats[sp.Name] = pollHandler.RequestsReceived;
424  handledStats[sp.Name] = pollHandler.RequestsHandled;
425  }
426  }
427  }
428  );
429 
430  foreach (KeyValuePair<string, int> kvp in receivedStats.OrderByDescending(kp => kp.Value))
431  {
432  cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]);
433  }
434 
435  sb.Append(cdt.ToString());
436  */
437  }
438 
439  private void BuildSummaryStatsByCapReport(StringBuilder sb)
440  {
441  /*
442  ConsoleDisplayTable cdt = new ConsoleDisplayTable();
443  cdt.AddColumn("Name", 34);
444  cdt.AddColumn("Req Received", 12);
445  cdt.AddColumn("Req Handled", 12);
446  cdt.Indent = 2;
447 
448  Dictionary<string, int> receivedStats = new Dictionary<string, int>();
449  Dictionary<string, int> handledStats = new Dictionary<string, int>();
450 
451  m_scene.ForEachScenePresence(
452  sp =>
453  {
454  Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
455 
456  if (caps == null)
457  return;
458 
459  foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values)
460  {
461  string reqName = reqHandler.Name ?? "";
462 
463  if (!receivedStats.ContainsKey(reqName))
464  {
465  receivedStats[reqName] = reqHandler.RequestsReceived;
466  handledStats[reqName] = reqHandler.RequestsHandled;
467  }
468  else
469  {
470  receivedStats[reqName] += reqHandler.RequestsReceived;
471  handledStats[reqName] += reqHandler.RequestsHandled;
472  }
473  }
474 
475  foreach (KeyValuePair<string, PollServiceEventArgs> kvp in caps.GetPollHandlers())
476  {
477  string name = kvp.Key;
478  PollServiceEventArgs pollHandler = kvp.Value;
479 
480  if (!receivedStats.ContainsKey(name))
481  {
482  receivedStats[name] = pollHandler.RequestsReceived;
483  handledStats[name] = pollHandler.RequestsHandled;
484  }
485  else
486  {
487  receivedStats[name] += pollHandler.RequestsReceived;
488  handledStats[name] += pollHandler.RequestsHandled;
489  }
490  }
491  }
492  );
493 
494  foreach (KeyValuePair<string, int> kvp in receivedStats.OrderByDescending(kp => kp.Value))
495  cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]);
496 
497  sb.Append(cdt.ToString());
498  */
499  }
500 
501  private void HandleShowCapsStatsByUserCommand(string module, string[] cmdParams)
502  {
503  /*
504  if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
505  return;
506 
507  if (cmdParams.Length != 5 && cmdParams.Length != 7)
508  {
509  MainConsole.Instance.Output("Usage: show caps stats by user [<first-name> <last-name>]");
510  return;
511  }
512 
513  StringBuilder sb = new StringBuilder();
514  sb.AppendFormat("Region {0}:\n", m_scene.Name);
515 
516  if (cmdParams.Length == 5)
517  {
518  BuildSummaryStatsByUserReport(sb);
519  }
520  else if (cmdParams.Length == 7)
521  {
522  string firstName = cmdParams[5];
523  string lastName = cmdParams[6];
524 
525  ScenePresence sp = m_scene.GetScenePresence(firstName, lastName);
526 
527  if (sp == null)
528  return;
529 
530  BuildDetailedStatsByUserReport(sb, sp);
531  }
532 
533  MainConsole.Instance.Output(sb.ToString());
534  */
535  }
536 
537  private void BuildDetailedStatsByUserReport(StringBuilder sb, ScenePresence sp)
538  {
539  /*
540  sb.AppendFormat("Avatar name {0}, type {1}\n", sp.Name, sp.IsChildAgent ? "child" : "root");
541 
542  ConsoleDisplayTable cdt = new ConsoleDisplayTable();
543  cdt.AddColumn("Cap Name", 34);
544  cdt.AddColumn("Req Received", 12);
545  cdt.AddColumn("Req Handled", 12);
546  cdt.Indent = 2;
547 
548  Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
549 
550  if (caps == null)
551  return;
552 
553  List<CapTableRow> capRows = new List<CapTableRow>();
554 
555  foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values)
556  capRows.Add(new CapTableRow(reqHandler.Name, reqHandler.RequestsReceived, reqHandler.RequestsHandled));
557 
558  foreach (KeyValuePair<string, PollServiceEventArgs> kvp in caps.GetPollHandlers())
559  capRows.Add(new CapTableRow(kvp.Key, kvp.Value.RequestsReceived, kvp.Value.RequestsHandled));
560 
561  foreach (CapTableRow ctr in capRows.OrderByDescending(ctr => ctr.RequestsReceived))
562  cdt.AddRow(ctr.Name, ctr.RequestsReceived, ctr.RequestsHandled);
563 
564  sb.Append(cdt.ToString());
565  */
566  }
567 
568  private void BuildSummaryStatsByUserReport(StringBuilder sb)
569  {
570  /*
571  ConsoleDisplayTable cdt = new ConsoleDisplayTable();
572  cdt.AddColumn("Name", 32);
573  cdt.AddColumn("Type", 5);
574  cdt.AddColumn("Req Received", 12);
575  cdt.AddColumn("Req Handled", 12);
576  cdt.Indent = 2;
577 
578  m_scene.ForEachScenePresence(
579  sp =>
580  {
581  Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
582 
583  if (caps == null)
584  return;
585 
586  Dictionary<string, IRequestHandler> capsHandlers = caps.CapsHandlers.GetCapsHandlers();
587 
588  int totalRequestsReceived = 0;
589  int totalRequestsHandled = 0;
590 
591  foreach (IRequestHandler reqHandler in capsHandlers.Values)
592  {
593  totalRequestsReceived += reqHandler.RequestsReceived;
594  totalRequestsHandled += reqHandler.RequestsHandled;
595  }
596 
597  Dictionary<string, PollServiceEventArgs> capsPollHandlers = caps.GetPollHandlers();
598 
599  foreach (PollServiceEventArgs handler in capsPollHandlers.Values)
600  {
601  totalRequestsReceived += handler.RequestsReceived;
602  totalRequestsHandled += handler.RequestsHandled;
603  }
604 
605  cdt.AddRow(sp.Name, sp.IsChildAgent ? "child" : "root", totalRequestsReceived, totalRequestsHandled);
606  }
607  );
608 
609  sb.Append(cdt.ToString());
610  */
611  }
612 
613  private class CapTableRow
614  {
615  public string Name { get; set; }
616  public int RequestsReceived { get; set; }
617  public int RequestsHandled { get; set; }
618 
619  public CapTableRow(string name, int requestsReceived, int requestsHandled)
620  {
621  Name = name;
622  RequestsReceived = requestsReceived;
623  RequestsHandled = requestsHandled;
624  }
625  }
626  }
627 }
Caps GetCapsForUser(uint circuitCode)
Will return null if the agent doesn't have a caps handler registered
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
OpenSim.Framework.Capabilities.Caps Caps
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
Circuit data for an agent. Connection information shared between regions that accept UDP connections ...
OpenSim.Framework.Capabilities.Caps Caps
Manager for adding, closing and restarting scenes.
Definition: SceneManager.cs:44
Scene CurrentScene
Scene selected from the console.
Interactive OpenSim region server
Definition: OpenSim.cs:55
void RemoveCaps(UUID agentId, uint circuitCode)
Remove the caps handler for a given agent.
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
static BaseHttpServer Instance
Set the main HTTP server instance.
Definition: MainServer.cs:83
Dictionary< ulong, string > GetChildrenSeeds(UUID agentID)
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void CreateCaps(UUID agentId, uint circuitCode)
Add a caps handler for the given agent. If the CAPS handler already exists for this agent...
void SetChildrenSeed(UUID agentID, Dictionary< ulong, string > seeds)