Compare commits

...

474 Commits

Author SHA1 Message Date
Justin Clark-Casey (justincc)
56e245e5e9 minor: Tidy up disabled logging on AssetTransactionModule for future use. Make it clear that transaction parameter to HandleUDPUploadRequest is an ID. 2013-02-20 22:24:20 +00:00
Justin Clark-Casey (justincc)
89362dbc4e minor: remove some mono compile warnings in XEngine.cs 2013-02-20 22:24:13 +00:00
Melanie
2f6ddc68b0 Prevent items being destroyed by rename operations. Renaming of a wearable also
sends an asset transaciton but it is empty. So we can't ignore name data
when a transaction is present and can't treat every transaction as valid.

Conflicts:

	OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
2013-02-20 22:23:54 +00:00
Justin Clark-Casey (justincc)
25b539e593 Fix issue where the "set terrain texture" console command did not tell the viewers that textures had updated (hence they did not display the changes).
Addresses http://opensimulator.org/mantis/view.php?id=6513
2013-02-20 22:23:46 +00:00
Talun
25a9ad1722 Mantis 6343: Turn a prim to flexy to OFF don't work llSetPrimParams
Correction so that scripts can turn Flexi off as well as on.
2013-02-20 22:23:30 +00:00
Justin Clark-Casey (justincc)
d3bbfcc97b minor: Fix full scene part console report to show proper Light* names rather than all wrongly FlexiDrag 2013-02-20 22:22:32 +00:00
Justin Clark-Casey (justincc)
c3cbba7778 minor: Call down to base OpenSimTestCase.SetUp() in NPCModuleTests to disable any enabled logging from previous tests 2013-02-20 22:22:26 +00:00
Justin Clark-Casey (justincc)
648932458a Disable json tests for now - I see this is failing on jenkins because mono 2.4.3 doesn't have Funcs >5 params, though mono 2.6 onwards does.
Standardize logging in JsonStoreScriptModule and some minor code formatting.
2013-02-20 22:21:50 +00:00
Justin Clark-Casey (justincc)
f1b978cdf0 See if getting the registering JsonReadNotecard with MethodInfo works around an apparent issue with registering methods with more than 5 parameters on mono 2.4.3 2013-02-20 22:21:44 +00:00
Justin Clark-Casey (justincc)
cb26e8a6c6 Increase logging by enabling during test setup rather than during individual tests of for JsonStore 2013-02-20 22:21:38 +00:00
Justin Clark-Casey (justincc)
7b8dc102d2 Enable logging in new json store tests to find out why they fail on jenkins but not locally. 2013-02-20 22:21:33 +00:00
Justin Clark-Casey (justincc)
cf04e09521 Add JsonTestPath() regression test 2013-02-20 22:21:25 +00:00
Justin Clark-Casey (justincc)
3f50de6445 Add regression test for JsonSetValue() 2013-02-20 22:21:20 +00:00
Justin Clark-Casey (justincc)
18659dfaea minor: remove mono compiler warning in SceneCommandsModule 2013-02-20 22:21:03 +00:00
Justin Clark-Casey (justincc)
ba175ee50b Add basic JsonGetValue() regression test. 2013-02-20 22:20:09 +00:00
Justin Clark-Casey (justincc)
995976c6db Add basic JsonCreateStore() regression test 2013-02-20 22:17:49 +00:00
Melanie
cfc9270bae Update ScriptModuleComms name space to CoreModules 2013-02-20 22:12:59 +00:00
Melanie
b2b6fd6aad Add a method to query all registered script constants to allow non-XEngine
script engines to use them.
2013-02-20 22:12:52 +00:00
Mic Bowman
96454ddee2 Moving ScriptModuleComms into the CoreModules tree. 2013-02-20 22:12:41 +00:00
Justin Clark-Casey (justincc)
4a0b9c411e Fix issue where lsl -> c# generation in co-operative termination mode did not correctly handle single statement versions of for, while and do-while loops.
Add regression tests to validate the fix.
This problem will not affect the default abort termination mode.
2013-01-30 03:59:22 +00:00
Justin Clark-Casey (justincc)
e67b84613d Fix build break where implicit animation console output code crept back into AnimationsCommandModule but it doesn't exist in this branch 2013-01-24 03:09:49 +00:00
Justin Clark-Casey (justincc)
d4f9982936 Remove unnecessary System.Linq reference from Compiler.cs
Hopefully will fix windows build via compile.bat
2013-01-24 03:05:11 +00:00
Justin Clark-Casey (justincc)
873ce644d3 Disable the not very useful infinite recursion co-op termination tests for now as they appear to cause failures with testing in jenkins.
These tests are not very useful anyway as they never actually get a chance to try termination before the script runs out of stack
2013-01-24 03:04:27 +00:00
Justin Clark-Casey (justincc)
1f8e43dd93 Fix mono 2.4.3 build break by using CreateInstanceAndUnwrap 9 method call deprecated in later .net versions 2013-01-24 03:04:19 +00:00
Justin Clark-Casey (justincc)
7bfd369b24 Add information on ScriptStopStrategy to [XEngine] in OpenSimDefaults.ini and OpenSim.ini.example. Default remains abort.
This setting controls whether scripts are stopped by aborting their threads externally (abort) or by co-operative checks from the compiled script (co-op)
co-op should be more stable but this option is experimental.
If moving from co-op to abort, existing script DLLs will need to be recompiled.
This currently can only be done manually, either by setting DeleteScriptsOnStartup = true for one run
or by deleting the script DLL* files in bin/ScriptEngines/<region-id>/
One can move from co-op back to abort without recompilation, but reverting back to co-op again will need script recompile
2013-01-24 03:04:09 +00:00
Justin Clark-Casey (justincc)
1da5a1ab21 Pass narrower WaitHandle rather than EventWaitHandle as co-op termination wait handle to script APIs.
APIs don't need to reference any methods on EventWaitHandle
2013-01-24 03:03:59 +00:00
Justin Clark-Casey (justincc)
af30d9b07e Improve logging by making it clearer which script is failing if an assembly fails to load.
Moves the noise co-op start/stop debug log messages to only display if xengine debug level >= 1
Logs which stop strategy is being used (abort or co-op)
Adjusts some other logging to remove not very useful stuff
2013-01-24 03:03:52 +00:00
Justin Clark-Casey (justincc)
b2c893a7be If ScriptStopStrategy hasn't been set to co-op in [XEngine] config, then continue to generate C# that is functionality identical to historical generation
This is to eliminate disruption until co-op termination has been well-tested.
In non co-op mode, XEngine will continue to load DLLs of the existing Script class and the new XEngineScript class.
Moving to co-op mode still requires existing script DLL deletion to force recompilation, either manually or by setting DeleteScriptsOnStartup = true for one run.
This change also means that scripts which fail to initialize do not still show up as running scripts.
2013-01-24 03:03:36 +00:00
Justin Clark-Casey (justincc)
3f80ac23b6 Add co-op termination regression test for infinite recursive manual call on event function.
Such code would normally terminate quickly with a stack overflow exception anyway.
2013-01-24 03:03:28 +00:00
Justin Clark-Casey (justincc)
701109c8c9 Set script delay factor to 0 in co-op termination tests
This is to ensure loops aren't actually terminating from a wait on an LSL function.
This was not the case with any of the existing tests.
2013-01-24 03:03:21 +00:00
Justin Clark-Casey (justincc)
5cbda393cd Add regression test for co-op termination on infinite user function call regression.
Such a script would probably run out of stack pretty quickly anyway.
2013-01-24 03:03:10 +00:00
Justin Clark-Casey (justincc)
98d0440c42 Add regression test for co-op stop of an infinite jump loop
Also fixes bug in do-while test
Improves detection of failure due to invalid script in test
Sets up xengine anew for each test rather than once for the while testsuite to improve isolation between tests.
Stop listening for chat after the first 'script is running' chat is received to reduce test run time.
2013-01-24 03:03:04 +00:00
Justin Clark-Casey (justincc)
8148d7e204 Add do-while co-op termination test
Minor changes to scripts in other tests.
2013-01-24 03:02:54 +00:00
Justin Clark-Casey (justincc)
b43a6b0199 Add single and comound while loop co-op termination test 2013-01-24 03:02:47 +00:00
Justin Clark-Casey (justincc)
d01943fa40 Fix bug in generating termination checks in compound statement for loop.
Add regression test for this case.
2013-01-24 03:02:39 +00:00
Justin Clark-Casey (justincc)
b6daf4d4c6 factor out common code in existing co-op termination regression tests 2013-01-24 03:02:33 +00:00
Justin Clark-Casey (justincc)
4495ecd158 Increase WaitForEventCompletionOnScriptStop to 120 secs to show that the co-op setting is active in its regression tests. 2013-01-24 03:02:24 +00:00
Justin Clark-Casey (justincc)
85df66db51 minor: comment out Console.WriteLine debugging message in XEngine 2013-01-24 03:02:17 +00:00
Justin Clark-Casey (justincc)
3024d0e61c Add regression test TestStopOnLongForLoop() 2013-01-24 03:02:11 +00:00
Justin Clark-Casey (justincc)
5ac0447e0f refactor: rename XEngineTest to more descriptive XEngineBasicTests 2013-01-24 03:02:04 +00:00
Oren Hurvitz
bb42862639 Assign the SmartThreadPool name in the constructor
This is required because some threads are created in the constructor, so assigning the name afterwards would be too late.
2013-01-24 03:01:26 +00:00
Justin Clark-Casey (justincc)
39b8f339ce Fix use of scene debug commands when region is set to root or a specific region where there is more than one region on the simulator. 2013-01-24 03:01:02 +00:00
Justin Clark-Casey (justincc)
af99e5e74a Add "debug set set animations true|false" region console command.
Setting this logs extra information about animation add/remove, such as uuid and animation name
Unfortunately cannot be done per client yet
2013-01-24 03:00:39 +00:00
Justin Clark-Casey (justincc)
f79800246a Implement non-wait co-operative termination of scripts for XEngine in addition to termination on wait.
This involves inserting opensim_reserved_CheckForCoopTermination() calls in lsl -> c# translation at any place where the script could be in a loop with no wait calls.
These places are for, while, do-while, label, user function call and manual event function call.
Call goes through to an XEngineScriptBase which extends ScriptBase.
IEngine is extended to supply necessary engine-specific parent class references and constructor parameters to Compiler.
Unfortunately, since XEngineScriptBase has to be passed WaitHandle in its constructor, older compiled scripts will fail to load with an error on the OpenSim console.
Such scripts will need to be recompiled, either by removing all *.dll files from the bin/ScriptEngines/<region-id> or by setting DeleteScriptsOnStartup = true in [XEngine] for one run.
Automatic recompilation may be implemented in a later commit.
This feature should not yet be used, default remains termination with Thread.Abort() which will work as normal once scripts are recompiled.
2013-01-24 03:00:18 +00:00
Melanie
4c1b1d89eb Complete removal of the now unused state queue 2013-01-24 02:04:41 +00:00
Diva Canto
a473482413 Changed a couple of debug messages at the request of osgrid. 2013-01-24 02:04:33 +00:00
Justin Clark-Casey (justincc)
535ec23646 Implement co-operative script termination if termination comes during a script wait event (llSleep(), etc.)
This makes use of EventWaitHandles since various web references indicate that Thread.Interrupt() can also cause runtime instability.
If co-op termination is enabled, then termination sets the wait handle instead of waiting for a timeout before possibly aborting the thread.
This allows the script to cleanly terminate if it's in a llSleep/LL function delay or the next time it enters such a wait without any timeout period.
Co-op termination is not yet testable since checking for termination request within loops that never trigger a wait is not yet implemented.
This commit, unlike 1b5c41c, passes the wait handle as an extra parameter through IScript.Initialize() instead of passing IScriptInstance itself.
2013-01-24 02:03:49 +00:00
Justin Clark-Casey (justincc)
245d6435e3 Revert "Implement co-operative script termination if termination comes during a script wait event (llSleep(), etc.)"
Doing this as a favour to Melanie.  This will be back with passing the wait handles directly to the api.

This reverts commit 1b5c41c14a.
2013-01-24 02:00:13 +00:00
Justin Clark-Casey (justincc)
8728d4ce6a Implement co-operative script termination if termination comes during a script wait event (llSleep(), etc.)
This makes use of EventWaitHandles since various web references indicate that Thread.Interrupt() can also cause runtime instability.
If co-op termination is enabled, then termination sets the wait handle instead of waiting for a timeout before possibly aborting the thread.
This allows the script to cleanly terminate if it's in a llSleep/LL function delay or the next time it enters such a wait without any timeout period.
Co-op termination is not yet testable since checking for termination request within loops that never trigger a wait is not yet implemented.
2013-01-24 02:00:04 +00:00
Justin Clark-Casey (justincc)
44901f0b31 Instead of passing separate engine, part and item components to script APIs, pass down IScriptInstance instead.
This is to allow the future co-operative script thread terminate feature to detect and act upon termination requests.
This splits the assembly and state loading out from the ScriptInstance() constructor to a separate Load() method
in order to facilititate continued script logic regression testing.
2013-01-24 01:59:42 +00:00
Justin Clark-Casey (justincc)
5054a07be2 Print full stacktrace from plugin loading failure to help determine what went wrong, rather than a possibly unhelpful simple exception message. 2013-01-24 01:35:08 +00:00
Justin Clark-Casey (justincc)
2f1cc6a06a refactor: Simplify ScriptInstance by retaining reference to SceneObjectPart instead of sometimes but not always looking it up. 2013-01-24 01:34:58 +00:00
Robert Adams
ff7693a14b Fix exception reporting in SceneObjectPart so it logs what the exception is rather than just saying it happened. 2013-01-24 01:34:35 +00:00
Justin Clark-Casey (justincc)
e89f93c78c Implement a workaround solution for saving manual script state changes by the user before logout instead of wrongly removing the script early.
This workaround relies on the fact that a closing client goes inactive before the attachments derez calls happen.
This reverts the change to remove scripts too early instead of stopping them, since the the two step stop then remove is necessary to execute the detach event.
2013-01-24 01:34:05 +00:00
Justin Clark-Casey (justincc)
d51aee876d Save attachments on detach/exit if a contained script state has been changed.
This involves making Attachments module listen for start/stop script changes.
It also involves removing the script from the region on detach in the same manner as every other DeleteSceneObject() call rather than simply stopping it
This is necessary tue to the bad assymetry of start and stop script triggers but it appears to be the correct behaviour anyway, as detached objects are completely gone from the sim.
Not just in a state where their scripts have been stopped.
2013-01-24 01:30:37 +00:00
Justin Clark-Casey (justincc)
3ad03d41e6 Fix a regression in the last few scene commands changes where setting these via the viewer estate dialog stopped working.
Forgot to register the new interface.
Also removes some code which got included by adpating an existing module.
2013-01-24 01:30:21 +00:00
Justin Clark-Casey (justincc)
69104f38f9 Add "debug scene get" console command to list current scene options 2013-01-24 01:29:49 +00:00
Justin Clark-Casey (justincc)
c6bb0d9662 Move scene debug commands into separate module. Command changes from "debug scene <key> <value>" to "debug scene set <key> <value>" to accomodate future settings 2013-01-24 01:29:40 +00:00
Justin Clark-Casey (justincc)
73717f2ce7 refactor: route the final scene backup through the same code that handles periodic backup
This is rather than making unnecessary duplicate checks that the SOG later performs again.
2013-01-24 01:29:29 +00:00
Justin Clark-Casey (justincc)
03bc92d112 minor: Capitalize GroupsModule command category 2013-01-24 01:29:12 +00:00
Justin Clark-Casey (justincc)
fd015c1ed7 minor: add missing newline to "debug scene" console command 2013-01-24 01:29:03 +00:00
Justin Clark-Casey (justincc)
8e548e4c8a Remove unimplemented "debug teleport" console command 2013-01-24 01:28:55 +00:00
Justin Clark-Casey (justincc)
44adf909b0 Add "debug scene pbackup true|false" console command. This enables or disable periodic scene backup. For debug purposes.
If false, scene is still saved on shutdown.
2013-01-24 01:28:47 +00:00
Justin Clark-Casey (justincc)
d43863af78 On baked texture save, replace any HG ID with an ordinary asset ID so the HGAssetBroker doesn't try to save back to the avatar's originating region 2013-01-24 01:28:29 +00:00
Justin Clark-Casey (justincc)
83c70dc914 revert accidental change to MemoryWatchdog stat calculation in previous b1b4687 2013-01-24 01:28:16 +00:00
Justin Clark-Casey (justincc)
10c1b15f12 Add "show script timers" command to show script timers. For debug purposes.
Also, "show sensors" changes to "show script sensors".
2013-01-24 01:28:05 +00:00
Justin Clark-Casey (justincc)
be5c6658bb Add "show sensors" command to show script sensor information for debug purposes. 2013-01-24 01:27:58 +00:00
Justin Clark-Casey (justincc)
f0a936832b minor: Remove unnecessary commented out code from last commit c28a2f05 and fix up code comment 2013-01-24 01:27:49 +00:00
Justin Clark-Casey (justincc)
ce5c2ee506 minor: make spacing consistent in console help output 2013-01-24 01:27:32 +00:00
Justin Clark-Casey (justincc)
bd33953c60 minor: Fix command match of "debug script" command to "debug scripts" to match other scripts commands (and it's own short help text) 2013-01-24 01:27:20 +00:00
Justin Clark-Casey (justincc)
ab22de03b8 minor: Allow "script *" console commands to take multiple script item ids 2013-01-24 01:27:13 +00:00
Melanie
61af272956 Add the new UpdateAgentInformation cap to make maturity on more recent viewers
work.
2013-01-24 01:27:06 +00:00
Justin Clark-Casey (justincc)
e43ddcd5ea minor: Rename BUILDING.txt to BUILDING.md in distbin distribution nant target 2013-01-24 01:26:48 +00:00
Justin Clark-Casey (justincc)
4041cb54f3 refactor: simplify llGetNumberOfPrims() to return prim count + sitting avatar count rather than independently inspecting every scene presence 2013-01-24 01:26:05 +00:00
Justin Clark-Casey (justincc)
87b4f335af minor: Add some doc to the extremely unhelpful 'fudge....' comment as to why we're deselecting the prim in code before scheduling an update on attachment 2013-01-24 01:25:28 +00:00
SignpostMarv
f9bb9191cf Improving documentation of AttachToAvatar and GetLine methods in LSL_Api.cs based on doxygen error output 2013-01-24 01:24:26 +00:00
SignpostMarv
4ab7697f00 updating documentation in SampleMoneyModule based on doxygen error log output; changing an xml-style hint to a uri-style hint in the class summary, improving documentation of Initialise method and removing a superfluous parameter, improving documentating of ClientClosed method and documenting an omitted parameter 2013-01-24 01:24:16 +00:00
SignpostMarv
d1ba3ea60d updating config properties added during upgrade process, adding error log file to doxygen config, adding doxygen output directory & error log to .gitignore 2013-01-24 01:24:04 +00:00
SignpostMarv
e597b33926 ran doxygen -s -u to upgrade the doxygen config file 2013-01-24 01:23:58 +00:00
Justin Clark-Casey (justincc)
3bb3a8f39b Change nant distbin target to also remove ThirdParty/ source code when making binary distribution 2013-01-24 01:23:51 +00:00
Justin Clark-Casey (justincc)
561626fe1b minor: Change channel digger replacement message in TerrainModule to Info from Warn.
This is to stop this unnecessarily triggering log analysis code which reports warn and error level statements.
2013-01-24 01:23:43 +00:00
Oren Hurvitz
86519bd407 Added locking in NullRegionData.
This prevents errors when one thread iterates over the regions (e.g., from RegenerateMaptileAndReregister()) while another thread is adding a region.
2013-01-24 01:22:54 +00:00
Justin Clark-Casey (justincc)
35a1949fb8 Fix indenting on ConsoleDisplayTable, align indenting on "show animations" console command 2013-01-24 01:22:46 +00:00
Justin Clark-Casey (justincc)
586a331a95 minor: minor code and log formatting fixes to recent changes in LandManagementModule 2013-01-24 01:22:34 +00:00
Justin Clark-Casey (justincc)
9b0f784c63 minor: Allow objects to be added directly to a row on a ConsoleDisplayTable rather than having to ToString() them first 2013-01-24 01:22:09 +00:00
Oren Hurvitz
ac0f5e75bd Implemented Return Objects when it's invoked from the Top Colliders or Top Scripts dialogs 2013-01-24 01:22:01 +00:00
Justin Clark-Casey (justincc)
f283ff5949 Add "show animations" console command for debug purposes.
This shows the current animation sequence and default anims for avatars.
2013-01-24 01:21:52 +00:00
Justin Clark-Casey (justincc)
04ee863c33 If an NPC is unowned, then always auto-grant permissions requested via llRequestPermissions()
This is consistent with all other OSSL NPC functions that allow unowned avatars to be manipulated.
Aims to address http://opensimulator.org/mantis/view.php?id=6483
2013-01-24 01:21:42 +00:00
Oren Hurvitz
16349c1368 Fixed bugs when getting the root folder.
1. The error checking for the case where there's no "My Inventory" folder was
incorrect: it checked the wrong variable.
2. If GetSystemFolderForType() is called to get AssetType.RootFolder then
it should return the root folder immediately; not look for another root
folder below it.
2013-01-24 01:21:30 +00:00
Justin Clark-Casey (justincc)
7caf21c8a8 minor: Assign names to the different SmartThreadPools for debugging purposes.
A different approach to the patch in http://opensimulator.org/mantis/view.php?id=6462
that doesn't involve further forking of SmartThreadPool
2013-01-24 01:21:17 +00:00
Justin Clark-Casey (justincc)
c98d215242 refactor: call Util.InitThreadPool() if we are initializing an uninitialized pool on first use rather than constructing it ourselves.
No functional change.
2013-01-24 01:21:09 +00:00
Justin Clark-Casey (justincc)
76cfab35a5 Clarify that AllowLightShareFunctions setting is false, which is the default in OpenSimDefaults.ini and the code. 2013-01-24 01:20:43 +00:00
Justin Clark-Casey (justincc)
2e02f49fd9 minor: If the physics module tells us that an object has gone out of bounds, more helpfully log the name, id, position and region of that object. 2013-01-24 01:19:00 +00:00
Justin Clark-Casey (justincc)
548deb9153 minor: Add commented out log lines to ScenePresenceAnimator for future debug use (such as logging anim pack contents sent to clients) 2013-01-24 01:18:39 +00:00
Justin Clark-Casey (justincc)
150c4faa79 Fix issue where calling llVolumeDetect(FALSE) would not remove phantom flag, causing subsequent issues if physics was re-enabled.
Added regression tests
Addresses http://opensimulator.org/mantis/view.php?id=6365
2013-01-24 01:18:25 +00:00
nebadon
6693ef8288 fix openjpeg on 64 bit OSX we were pointing to a file taht did not
exist.
2013-01-24 00:50:22 +00:00
Justin Clark-Casey (justincc)
ba93e36fce On XEngine.ProcessEventHandler(), instead of creating a new CultureInfo on every call use the single one set by Culture.SetCurrentCulture()
This is slightly different in that SetCurrentCulture() does not use overridden settings if the system culture matches en-US but some settings there have been changed.
This is what we want - we do not want to use any system overriden settings.
2013-01-24 00:44:22 +00:00
Justin Clark-Casey (justincc)
9ab580d1ea Extend default 1 second wait for event completion to other thread script reset (as called by llResetOtherScript()).
As with script stop (via llDie()) aborting other scripts event threads, llResetOtherScript() can also abort any current event thread on another script.
On mono 2.6, 2.10 and possibly later this may cause locking problems in certain code areas.
This commit reuses the recently introduced [XEngine] WaitForEventCompletionOnScriptStop to make this a 1 sec timeout, rather than 0 secs.
2012-12-17 22:53:40 +00:00
Justin Clark-Casey (justincc)
7deb2d9646 minor: add some more detail to the logging if an LLClientView fails to process a packet 2012-12-14 00:00:23 +00:00
Justin Clark-Casey (justincc)
c77728ebf8 Add WaitForEventCompletionOnScriptStop [XEngine] config param to OpenSimDefaults.ini to allow change of the wait time for an event to complete on script removal before aborting its thread
Default is 1000, as has previously been the case.
This parameter exists for further debug work concerning mono 2.10 crashes that may be related to locks not being removed on Thread.Abort
2012-12-14 00:00:16 +00:00
Justin Clark-Casey (justincc)
83487bfbec Log situations where workitem event threads are aborted on stop request because they failed to complete event processing within the given timeout.
This is for bug hunting purposes where thread aborts may be causing dangling lock issues and subsequent vm crashes on mono (with ReaderWriterLockSlim, etc.)
2012-12-14 00:00:01 +00:00
Justin Clark-Casey (justincc)
e6f475735f Add "debug script log" command to allow setting a numeric debug level on individual IScriptInstances for debugging purposes.
Current, state changes and event fires can be logged for individual scripts.
See command help for more details.
2012-12-13 23:59:53 +00:00
Justin Clark-Casey (justincc)
48486b137a Add asset id to "show script" and "show scripts" command output to make it easier to extract and inspect the script's asset via "dump asset" 2012-12-13 23:59:44 +00:00
Justin Clark-Casey (justincc)
4490020197 Use a thread abort safe version of OpenMetaverse.DoubleDictionary with the aim of avoiding OpenSimulator problems due to script thread aborts.
When an object is removed, its scripts are stopped and then the thread running them is aborted if stop takes too long.
However, it appears that aborting a thread at just the wrong moment when it is obtaining a ReaderWriterLockSlim lock can leave this lock in an inconsistent state.
One symptom of this is that mono leaps to 100% cpu and a vm thread dump reveals lots of threads waiting for a ReaderWriterLockSlim lock without any thread actually holding it.
This is probably the same problem as encountered originally in commit 12cebb12
This commit looks to plaster this problem by putting lock obtaining methods inside finally blocks which should be uninterruptible by thread aborts.
2012-12-12 00:40:16 +00:00
Justin Clark-Casey (justincc)
770caad0ad minor: change method doc on GetTextureHandler.TryParseRange(), mainly to trigger another build 2012-12-12 00:39:39 +00:00
Justin Clark-Casey (justincc)
13e29ae3f7 Allow GetTexture calls with no second value in the range header (e.g. just 5333-)
It looks like the latest Kokua is doing this.
As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, leaving off the second value is legal
This indicates the caller wants the rest of the entity.
2012-12-12 00:39:29 +00:00
Justin Clark-Casey (justincc)
b52ac8c5d1 Remove very probably unused PrimitiveBaseShape(bool) constructor to reduce code complexity 2012-12-12 00:22:56 +00:00
Justin Clark-Casey (justincc)
97a907ad84 Don't pointlessly set ExtraParams = byte[1] in PrimitiveBaseShape since this is ignored by the ExtraParams properly anyway 2012-12-12 00:22:47 +00:00
Justin Clark-Casey (justincc)
7ced077821 In BaseHttpServer.HandleRequest(), use Culture.SetCurrentCulture() rather than creating a new CultureInfo separately 2012-12-12 00:22:24 +00:00
Justin Clark-Casey (justincc)
fdbd448cc7 In XEngine.DoOnRezScript() use Culture.SetCurrentCulture() instead of constructing a new CultureInfo separately 2012-12-12 00:22:15 +00:00
Justin Clark-Casey (justincc)
d8c88f4894 Instead of printing script errors out to console, put to debug log so that we also get timestamps.
This commit also adds script name, part name, uuid, etc. for later identification.
This information has been sent to console since 2009 but may be turned down if it proves too noisy.
However, I still currently need it to investigate some region problems probably triggered by scripting.
2012-12-06 00:31:15 +00:00
Justin Clark-Casey (justincc)
d558bbfa35 minor: Fix more compiler warnings in CoreModules tests by properly overriding OpenSimTestCase.SetUp() 2012-12-06 00:30:45 +00:00
Justin Clark-Casey (justincc)
992dc1c2c7 Add engine-wide events queued and events processed numbers to output of "xengine status" console command. For debugging purposes. 2012-12-06 00:30:38 +00:00
Justin Clark-Casey (justincc)
ce1d3e9c96 Remove some mono warnings in script tests, chiefly where SetUp() wasn't properly calling to OpenSimTestCase.SetUp() 2012-12-06 00:30:30 +00:00
Justin Clark-Casey (justincc)
a8a712e1f8 Add IScriptInstance.EventsQueued to match EventsProcessed instead of asking callers to lock and directly inspect the EventQueue 2012-12-06 00:30:18 +00:00
Justin Clark-Casey (justincc)
5a71cbe530 For now, sort "show scripts" output in descending order sorted by events processed.
For debug purposes - should later add options to allow different sorting or show only highest 10, etc.
2012-12-06 00:30:11 +00:00
Justin Clark-Casey (justincc)
c2bdb36c11 Add IScriptInstance.EventsProcessed stat so that we can record this information and display in "show scripts" for debug purposes 2012-12-06 00:30:04 +00:00
Justin Clark-Casey (justincc)
6d03a5d01b minor: tidy up spacing at bottom of MundaneFrameworkTests 2012-12-06 00:29:49 +00:00
Justin Clark-Casey (justincc)
ad75cb2682 minor: also comment out the debug log message which reports searching for child agents in simulator scenes for now. 2012-12-06 00:29:15 +00:00
Justin Clark-Casey (justincc)
f46478f1df minor: Comment out "Delivering IM to..." messages for now. 2012-12-06 00:29:07 +00:00
Justin Clark-Casey (justincc)
7c811c39c8 Fix problem where restarting the currently selected region would stop various console commands (e.g. "show users") from working.
This was because the "currently selected" scene reference was being left as the dead scene instead of the restarted Scene object.
2012-12-06 00:26:42 +00:00
Justin Clark-Casey (justincc)
e18d6c0956 Show many more primitive properties on console command "show part name/id/pos" 2012-11-28 03:47:11 +00:00
Justin Clark-Casey (justincc)
a7af8345a5 Fix database service unit test failures by temporarily reverting BasicDataServiceTest extending OpenSimTestCase.
Mono 2.4.3 doesn't like this when running nunit, with nunit throwing
AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true.
and similar.  Mono 2.10.8.1 does not have this issue.
So will wait until min version of mono bumps before restoring.
2012-11-28 03:46:58 +00:00
Justin Clark-Casey (justincc)
b5ecc31096 Combine TestDeleteSceneObjectAsync() with TestDeRezSceneObject() as they are functionally identical.
Move TestDeleteSceneObjectAsync() and TestDeleteSceneObjectAsyncToUserInventory() from SceneObjectBasicTests -> SceneObjectDeRezTests
2012-11-28 03:46:49 +00:00
Justin Clark-Casey (justincc)
3a297c7fe6 Fix regression TestDeleteSceneObjectAsyncToUserInventory by adding a BasicInventoryAccessModule() and re-enable in test suite. 2012-11-28 03:46:41 +00:00
Justin Clark-Casey (justincc)
c3243ce0ce Consistenly make NUnit test cases inherit from OpenSimTestCase which automatically turns off any logging enabled between tests 2012-11-28 03:46:33 +00:00
Justin Clark-Casey (justincc)
ace552ecc5 Make "show threads" and "thread abort" console commands available on all servers 2012-11-28 03:46:10 +00:00
Justin Clark-Casey (justincc)
1d75570c59 Make "force gc" console command available across all servers 2012-11-28 03:46:04 +00:00
Justin Clark-Casey (justincc)
70ccc63b83 Make "show version" console command available across all servers 2012-11-28 03:45:56 +00:00
Justin Clark-Casey (justincc)
31373ee099 Delete unused BaseHttpServer.HandleAgentRequest() 2012-11-28 03:45:50 +00:00
Justin Clark-Casey (justincc)
afaf7b5b94 Enable further client stack packet pooling by default by setting RecycleBaseUDPPackets = true by default.
This reduces base memory churn of every client connection, improving the garbage collection situation.
The effect is a significant portion of base load (an avatar standing still on a completely blank island)
but will probably still be swallowed up by other memory use on active regions.
Tests have shown no noticeable impact on speed of processing incoming packets, though setting remains
in case a switch back is needed.
2012-11-28 03:45:43 +00:00
Justin Clark-Casey (justincc)
6d0f66ae87 minor: Make note in log if scene was restarted due to an unrecoverable physics error 2012-11-28 03:45:15 +00:00
Justin Clark-Casey (justincc)
207233335e Add AllowRegionRestartFromClient setting to [EstateManagement] section of OpenSim.ini.
Setting this to false will block all restart requests from the viewer even if they are otherwise legitimate.
One use is to block region restarts if necessary whilst restart functionality remains buggy or triggers bugs in modules,
though these should be fixed as soon as practicable.
Default is true, as has been the case historically.
2012-11-28 03:44:44 +00:00
Justin Clark-Casey (justincc)
e9fbfd0905 Remove the redundant BypassPermissions() checks in EstateManagmentModule.
This is repeated in the PermissionsModule and checking it earlier does not allow a force override of the bypass value
2012-11-28 03:40:59 +00:00
Justin Clark-Casey (justincc)
c35f974637 minor: Add some console feedback on region restart and log who requested a region restart if done from the viewer. 2012-11-28 03:40:52 +00:00
Justin Clark-Casey (justincc)
a4007cbe71 Add regression test for checking scene close when SceneManager is asked to close 2012-11-28 03:39:31 +00:00
Justin Clark-Casey (justincc)
d70e0b1189 Add "help all" console command which will list all commands alphabetically in a single list 2012-11-28 03:39:20 +00:00
Justin Clark-Casey (justincc)
a9ce40a722 Factor out command script code.
This also allows comments in command scripts (lines starting with ;, # or //) to be used across all servers
2012-11-28 03:39:05 +00:00
Justin Clark-Casey (justincc)
8d207fd8e6 Make "config show/set/get/save" console commands available on all servers 2012-11-28 03:38:41 +00:00
Justin Clark-Casey (justincc)
2487adf0b1 Factor out common pid file creation and removal code.
Log path at which pid file is created or reason for failure to create.
2012-11-28 03:28:27 +00:00
Justin Clark-Casey (justincc)
4aa725f60b Add "get log level" command - this returns the current server session console logging level.
This supersedes getting information by calling "set log level" without a 4th argument, which is confusing.
2012-11-28 03:28:19 +00:00
Justin Clark-Casey (justincc)
0686a2fba9 Remove unused BaseOpenSimServer.ShowHelp() 2012-11-28 03:28:13 +00:00
Justin Clark-Casey (justincc)
b6305011db Make "set log level" command available across all servers 2012-11-28 03:28:06 +00:00
Justin Clark-Casey (justincc)
9cdf5199df Make "show info" command available across all servers
This helpfully lists version information, startup location and console log level
2012-11-28 03:27:59 +00:00
Justin Clark-Casey (justincc)
632dad337b Factor out common registration of "show uptime" command 2012-11-28 03:27:52 +00:00
Justin Clark-Casey (justincc)
08234d0097 factor out common HandleShow code for "show uptime" 2012-11-28 03:27:43 +00:00
Justin Clark-Casey (justincc)
d68ba391fc refactor: Factor out copy/pasted server uptime report code 2012-11-28 03:27:36 +00:00
Justin Clark-Casey (justincc)
603a140eb7 If an asset POST does not contain well-formed XML, return a 400 (Bad Request) HTTP status rather than simply dropping the request. 2012-11-28 03:27:30 +00:00
Justin Clark-Casey (justincc)
fd31f05cf0 Add regression test for a good request made to the asset service post handler.
Adds new OpenSim.Server.Handlers.Tests.dll to test suite
2012-11-28 03:27:15 +00:00
Justin Clark-Casey (justincc)
a8152c57b3 If GetAgents() is called with an empty userIDs array then don't bother with a useless potentially network call on the scene presence service connector.
This also eliminates the "[PRESENCE HANDLER]: GetAgents called without required uuids argument"
which has started to pop up in the logs when a call is made with an empty uuid array as occasionally happens.
2012-11-28 03:27:08 +00:00
Justin Clark-Casey (justincc)
4753d14a19 refactor: Move common presence connector code into BasePresenceServiceConnector 2012-11-28 03:26:50 +00:00
Justin Clark-Casey (justincc)
ee5e61d448 minor: If logging full incoming HTTP data, don't deceptively print ... at the end of the body. 2012-11-28 03:21:42 +00:00
Justin Clark-Casey (justincc)
41b76c4b9e Remove old InventoryService, which has for a long time been replaced by XInventoryService. 2012-11-28 03:21:31 +00:00
Justin Clark-Casey (justincc)
314de0fc49 Remove unnecessary ability to directly set InventoryItemBase.CreatorIdAsUuid
This was necessary historically but hasn't been for many years.
Can still get CreatorIdAsUuid, which is really just a UUID cached version of the string CreatorId
2012-11-28 03:21:23 +00:00
Justin Clark-Casey (justincc)
93f7e4fb9d Do not allow invariants to change on calls to XInventoryService.UpdateItem()
This is to help track down http://opensimulator.org/mantis/view.php?id=6359 where creator IDs on items and rezzed objects have been reported to sometimes change.
This should never happen - a particular item should never change creators (if an item is given then a new item (with new id) is created).
Invariants are inventory type, asset type, folder (changed only on MoveItems()), CreatorIdentification and Owner.
If caller attempts to change an invariant, warning is logged but other properties are still changed.
If you see this warning, reporting on Mantis 6359 would be very welcome with the exact operation being done at the time.
2012-11-28 03:21:15 +00:00
Justin Clark-Casey (justincc)
f8adf4de2f Add basic XInventoryServicesTests.TestAddItem() regression test. 2012-11-28 03:21:06 +00:00
Justin Clark-Casey (justincc)
08f0274b5a refactor: Move stat classes out of StatManager and into their own files for clarity. 2012-11-28 03:20:59 +00:00
Justin Clark-Casey (justincc)
94748aab84 Add a first draft mechanism for the IncomingPacketsProcessedStat to show the delta over time.
The chief motivation for this is to be able to tell whether there's any impact on incoming packet processing from enabling extra packet pooling.
2012-11-28 03:20:50 +00:00
Justin Clark-Casey (justincc)
468d1cf03e refactor: move common inventory folder version update code to parent class in mysql, mssql and sqlite database plugins 2012-11-28 03:20:28 +00:00
Justin Clark-Casey (justincc)
e8e6bc0c6a Improve inventory folder version updating for mssql database plugin.
I am not in a position to test this so the updates have been done blind.
If it needs any fixing will probably require patches.
2012-11-28 03:07:05 +00:00
Justin Clark-Casey (justincc)
c7b9d460e0 Fix build break from 1aa0271 by adding System.Core to prebuild.xml 2012-11-28 03:06:57 +00:00
Justin Clark-Casey (justincc)
e263368656 Implement folder version updating for the sqlite inventory plugin 2012-11-28 03:06:51 +00:00
Justin Clark-Casey (justincc)
4b6a9d107d Handle Map block requests on a separate thread rather than the main packet handling thread.
This prevents a slow grid information network call from holding up the main packet handling thread.
There's no obvious race condition reason for not doing this asynchronously.
2012-11-28 03:06:43 +00:00
Justin Clark-Casey (justincc)
ee5454fd4a Do HandleMapLayerRequest on its own thread rather than on the main inbound udp packet handling thread.
There's no obvious race condition reason for doing this on the main packet handling thread.
2012-11-28 03:06:35 +00:00
Justin Clark-Casey (justincc)
38d2d6a20c Following on from 4f982596, launch map name requests on an async thread from LLClientView directly.
This releases the inbound packet handling thread marginally quicker and is more consistent with the other async packet handling
2012-11-28 03:06:28 +00:00
Justin Clark-Casey (justincc)
7e493b9665 Make PacketPool class stats pull stats instead of push stats so they can be lifted up into LLUDPServer and be distiguished by scene name 2012-11-28 03:06:19 +00:00
Justin Clark-Casey (justincc)
b7c1a37676 Add IncomingPacketsProcessedCount stat for diagnostics.
Also puts some packet processing counts in a container named after the scene so that stats can be collected from more than one scene.
2012-11-28 03:06:12 +00:00
Justin Clark-Casey (justincc)
4fe042aa7f More consistently dispose of SqliteCommand in OpenSim.Data.SQLite where possible.
Not doing SQLiteInventoryStore since this is no longer used and should disappear in the future.
2012-11-28 03:06:00 +00:00
Justin Clark-Casey (justincc)
a83218fd08 If no ISimulationDataStore or IEstateDataStore implementations could be loaded then halt with informative message rather than a later NRE.
Halt already occurs if the relevant config sections are not present.
So it also makes sense to halt if the implementations themselves cannot be loaded.
2012-11-28 03:05:49 +00:00
Justin Clark-Casey (justincc)
221af2da70 minor: Add some explanative method doc to SceneHelpers.SetupSceneModules() 2012-11-28 03:05:16 +00:00
Diva Canto
c6c6ac0a3e Fix Unit tests -- the module contract was not being honored in the set up of scenes. 2012-11-28 03:04:02 +00:00
Justin Clark-Casey (justincc)
a5fdfd6343 Uncomment SceneObjectBasicTests.TestDeleteSceneObjectAsyncToUserInventory() and make it compile again
Not currently in test suite since not yet working.
Also add method doc to Scene.DeRezObjects()
2012-11-28 03:03:26 +00:00
Diva Canto
72e0c77f91 Minor improvement in the MapSearchModule. Stop blocking the client thread if the search takes too long. 2012-11-28 03:03:18 +00:00
Justin Clark-Casey (justincc)
862f595e5d Replace the 64 bit macosx version of libopenjpeg-dotnet.dylib with a 32-bit version from libopenmetaverse commit 3731ee4
This is because macosx mono is 32-bit and this can't p/invoke 64-bit binaries.
However, the reverse is also true.
If OpenSimulator stops working for you then please complain!  Long term alternative is probably to build a fat binary with both architectures.
2012-11-28 03:00:03 +00:00
Justin Clark-Casey (justincc)
db045e69f9 Also add the additional ScriptException constructor necessary to get [Serializable] to work. 2012-11-28 02:59:53 +00:00
Justin Clark-Casey (justincc)
6a54cb871b Mark ScriptException as [Serializable] for when it has to cross AppDomains 2012-11-28 02:59:47 +00:00
Justin Clark-Casey (justincc)
3619a83b28 Handle UUIDGroupName and ObjectGroup viewer UDP requests asynchronously rather than synchronously.
This is to avoid the entire scene loop being held up when the group service is slow to respond.
There's no obvious reason for these queries to be sync rather than async.
2012-11-28 02:59:39 +00:00
Justin Clark-Casey (justincc)
e3927d2868 Make "show object part" command correctly display script status.
Uses new IEntityInventory.TryGetScriptInstanceRunning()
Makes it clearer that TaskInventoryItem.ScriptRunning cannot be used as it is temporary and not updated.
2012-11-28 02:59:30 +00:00
Justin Clark-Casey (justincc)
fe503de17a Only create a new list to check if objects have reached targets if there actually are any targets. 2012-11-28 02:59:13 +00:00
SignpostMarv
5498a64a9f fixing poorly-formatted xml doc string for Util.IsInsideBox 2012-11-28 02:58:37 +00:00
SignpostMarv
3148a231db refactoring llGetPos() to take advantage of implicit converter 2012-11-28 02:58:22 +00:00
Justin Clark-Casey (justincc)
bffdf20721 Fix memory leak where removing an NPC did not remove its circuits.
This was because we were removing by circuitcode where NPCs have no code.
Now removing by agent ID instead.
This commit also fixes the "show circuits" console command to work properly where the circuit has no associated IP address.
2012-11-28 02:57:13 +00:00
Justin Clark-Casey (justincc)
a4b64d4854 Add "force gc" region console command which manually invokes garbage collection.
For debugging purposes.
2012-11-28 02:57:02 +00:00
Melanie
fe195e0a9c Deep copy the collection of at_target objects so it can't be modified while
it's being iterated
2012-11-28 02:56:53 +00:00
Justin Clark-Casey (justincc)
9d70f48207 minor: Fix verbose IAR save message to make it a bit clearer that item data is being saved at that point, not asset data. 2012-11-28 02:56:44 +00:00
Justin Clark-Casey (justincc)
d83df8c1cf Fix "save iar" hanging permanently if the asset request phase times out.
Unlike "save oar", this was happening on the same thread as the original request.
The timeout happens on another so the original thread is never aborted.
On "save oar" this leaves the thread hanging (still bad) but on "save iar" it left the console thread hanging.
Temporary fix is to make "save iar" do asset request on a separate thread, like "save oar".
Longer term fix will be to restructure asset save to use a ManualResetEvent rather than a separate timeout timer.
2012-11-28 02:56:34 +00:00
Justin Clark-Casey (justincc)
c7c6c12146 minor: Make the error thrown logged when a simulator in grid mode is trying to set estate owner to a user that doesn't exist a little more obvious. 2012-11-28 02:56:22 +00:00
SignpostMarv
e83a4c24ee Formatting and casing correction in WorldCommModule, trailing new line in OSSL to get git diff to not complain 2012-11-28 02:56:09 +00:00
Justin Clark-Casey (justincc)
a1669be6c3 minor: Add comment as to why we are pulcking plain old ints out of the LSL_List when converting values from LSL for modInvoke() 2012-11-28 02:55:58 +00:00
SignpostMarv
e36799f515 system ints can end up in LSL lists, which can cause counter-intuitive unknown list element type errors in ConvertFromLSL (via modInvoke) 2012-11-28 02:55:36 +00:00
Justin Clark-Casey (justincc)
186fe5f7b0 Comment out InventoryTransferModule.NeedSceneCacheClear() and invocations since the call itself does nothing and the return value is ignored by all callers.
This is a very old method (+4 years) so is probably confusing code cruft.
2012-11-28 02:55:26 +00:00
Justin Clark-Casey (justincc)
27206eccef minor: if a scene is already shutting down on Scene.Close(), warn and exit instead of attempting to run another shutdown concurrently.
Thanks to Oren Hurvitz for this change.
2012-11-28 02:55:15 +00:00
Oren Hurvitz
62c0d60d3e Changed "course" to "coarse" in several places 2012-11-28 02:55:08 +00:00
Oren Hurvitz
c39342df3e Changed duplicate Asset ID's to unique ID's in CollisionSoundsAssetSet.xml 2012-11-28 02:55:00 +00:00
Justin Clark-Casey (justincc)
458a103529 In Scene.Close(), dispose of the physics scene after base.Close() since script events can still access Physics scene until the script engine shuts down (triggered off base.Close())
XEngine listeners to EventManager.OnShutdown which is triggered from base.Close().
Possibly it could listen for the earlier OnSceneShuttingDown instead, but the easier solution right now is to relocate disposal of the physics scene.
This bug has existed since c150320 (Thu Jul 26 15:27:18 2012) and was in 0.7.4
2012-11-28 02:54:52 +00:00
Justin Clark-Casey (justincc)
c22a37e7a6 Fix script error messages not showing up in viewer 3 and associated viewers.
Viewer 3 will discard such a message if the chat message owner does not match the avatar.
We were filling the ownerID with the primID, so this never matched, hence viewer 3 did not see any script error messages.
This commit fills the ownerID in with the prim ownerID so the script owner will receive script error messages.
This does not affect viewer 1 and associated viewers which continue to process script errors as normal.
2012-11-28 02:54:31 +00:00
Justin Clark-Casey (justincc)
01a8a65d75 Get osNpcCreate() and osNpcLoadAppearance() to generate a script error if appearance notecard does not exist, rather than returning UUID.Zero or silently failing. 2012-11-28 02:54:25 +00:00
Justin Clark-Casey (justincc)
28ced402d8 When scripts generate expected exceptions (e.g. due to checked bad parameter) throw ScriptException instead of just a plain old exception.
This is to make it easier to distinguish these exceptions from unexpected OpenSimulator problems internally and in regression tests.
No functional changes.
2012-11-28 02:54:17 +00:00
Justin Clark-Casey (justincc)
95e35fe84a Make osNpcCreate() return UUID.Zero instead of throwing an exception if notecard name is invalid. Make osNpcLoadAppearance() fail silently in same circumstance rather than throwing exception. 2012-11-28 02:54:05 +00:00
Justin Clark-Casey (justincc)
3692ff2bdb Add TestOsNpcLoadAppearance() 2012-11-28 02:53:55 +00:00
Justin Clark-Casey (justincc)
7235a5fed4 Move npc creation tests involving appearance from OSSL_ApiAppearanceTest to OSSL_ApiNpcTests
This is a more intuitive location.
2012-11-28 02:53:46 +00:00
Justin Clark-Casey (justincc)
614e5b52b8 Allow "show object", "show part", "dump object" and "delete object" to accept a local ID as well as a UUID.
This means that the sub-commands are now id rather than uuid, e.g. show object id
2012-11-28 02:53:39 +00:00
Justin Clark-Casey (justincc)
35ab31fb5f Add "dump object uuid" console command. This allows any object in the scene to be serialized and dumped to XML for debug purposes. 2012-11-28 02:53:15 +00:00
Justin Clark-Casey (justincc)
636994eea6 minor: Move co-ordinate related help to object commands to common ConsoleUtil.CoordHelp 2012-11-28 02:53:06 +00:00
Justin Clark-Casey (justincc)
146ac5ceda Make it possible to turn the base UDP object packet pools on and off whilst running via the "debug lludp pool <on|off>" console command. For debug purposes.
This does not currently apply to the higher LLUDP packetpool.
2012-11-28 02:52:53 +00:00
Justin Clark-Casey (justincc)
5413bfec30 Add object count stats for new IncomingPacket and UDPPacketBuffer pools if they are enabled. Add count stats for existing LLUDP pool.
This introduces a pull stat type in addition to the push stat type.
A pull stat takes a method on construction which knows how to update the stat on request.
In this way, special interfaces for pull stat collection are not necessary.
2012-11-28 02:52:46 +00:00
Justin Clark-Casey (justincc)
f39c2cd714 minor: Get content type handler logger to log "unset" for the content type instead of blank if no content type was set. 2012-11-28 02:52:40 +00:00
Justin Clark-Casey (justincc)
e0ef2bdf81 minor: Use LogIncomingToContentTypeHandler() method for incoming HTTP data where this wasn't already used.
This allows log level 5 (log sample or large part of incoming post data) to operate and removes copy/paste.
2012-11-28 02:52:29 +00:00
PixelTomsen
efc09e8022 SQLite DB: some values of land data will be not saved / loaded
http://opensimulator.org/mantis/view.php?id=6370

Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2012-11-28 02:52:17 +00:00
Justin Clark-Casey (justincc)
1790355f3e minor: Rename assetCache constructor param in UUIDGatherer to assetService which is what it is. 2012-11-28 02:51:42 +00:00
Justin Clark-Casey (justincc)
d0d004c6ff Add method doc for IPresenceService 2012-11-28 02:51:36 +00:00
Justin Clark-Casey (justincc)
ee4abb681e Improve efficiency of friends notification by only make one PresenceService call for all friends rather than one for each friend.
However, large groups could still take a very long time since we still need to message each avatar on different simulators.
2012-11-28 02:51:24 +00:00
Justin Clark-Casey (justincc)
9e3605d952 Fix build break from commit e469879 2012-11-28 02:51:11 +00:00
Justin Clark-Casey (justincc)
0df4927710 Add "debug groups verbose <true|false>" region console command
This allows one to turn on super-verbose groups debug logging on and off whilst the region is in operation.
2012-11-28 02:51:01 +00:00
Justin Clark-Casey (justincc)
9d4415429d minor: Increase attachment name field from 36 to 50 chars in "attachments show" report 2012-11-28 02:50:47 +00:00
SignpostMarv
c86ac36876 altering documentation for llGetLinkName, as the current documentation is rather lengthy for a "summary". 2012-11-28 02:50:23 +00:00
SignpostMarv
4a4d800523 ensuring that operand order in llGetLinkName is internally consistent 2012-11-28 02:49:44 +00:00
Justin Clark-Casey (justincc)
01c148bbce minor: comment out currently unused logger in DynamicTextureModule 2012-11-28 02:49:28 +00:00
Justin Clark-Casey (justincc)
1cbe4363a3 Make "show part" console commands print out information about each item the part contains 2012-11-28 02:49:21 +00:00
Justin Clark-Casey (justincc)
c0254d914f minor: Convert ad-hoc list building in ObjectCommandsModule to use ConsoleDisplayList 2012-11-28 02:49:10 +00:00
Justin Clark-Casey (justincc)
53112f1e80 Add local and UUID to information output of "show object" and "show part" region console commands 2012-11-28 02:49:02 +00:00
Justin Clark-Casey (justincc)
0f312c58ca Add --full option to "show object name/uuid/pos" to show info on all parts of an object, not just whole object summary information. 2012-11-28 02:48:54 +00:00
Justin Clark-Casey (justincc)
2ca520c1eb Add number of inventory items to information displayed via "show part" console command 2012-11-28 02:48:47 +00:00
Justin Clark-Casey (justincc)
c9b7ac2ae5 minor: Remove event method doc from LLClientView that I forgot in the last commit (1de80c) 2012-11-28 02:47:47 +00:00
Justin Clark-Casey (justincc)
6e2ffd7050 minor: move recent OnAgentUpdate/OnPreAgentUpdate event doc up into IClientAPI from LLClientView 2012-11-28 02:47:40 +00:00
Justin Clark-Casey (justincc)
8726748e22 Reuse the same AgentUpdateArgs object for each AgentUpdate UDP packet (of which there are 10 a second) rather than constructing a new one every time.
We can do this because AgentUpdate packets are handled synchronously.
2012-11-28 02:47:31 +00:00
Justin Clark-Casey (justincc)
73c2db9e8f Explicitly return only the incoming AgentUpdate packet as this is the only one we pool atm, rather than attempting to return all incoming packets. 2012-11-28 02:47:24 +00:00
Justin Clark-Casey (justincc)
c1cab3e752 If RecycleBaseUDPPackets = true, also pool IncomingPackets to reduce memory churn 2012-11-28 02:47:15 +00:00
Justin Clark-Casey (justincc)
713fdda7f8 minor: Make BasicCircuitTests.SetUp() call overriden base method instead of ignoring it. 2012-11-28 02:47:08 +00:00
Justin Clark-Casey (justincc)
baa599e5b0 Add LastMemoryChurn stat using existing data so we can more quickly tell how memory churn changes rather than waiting for the average to move. 2012-11-28 02:47:01 +00:00
Justin Clark-Casey (justincc)
014c533ebe Add optional pool for the UDPPacketBuffer objects that handle all incoming UDP data.
Even when an avatar is standing still, it's sending in a constant stream of AgentUpdate packets that the client creates new UDPPacketBuffer objects to handle.
This option pools those objects.  This reduces memory churn.
Currently off by default.  Works but the scope can be expanded.
2012-11-28 02:46:53 +00:00
Justin Clark-Casey (justincc)
53d87510ce Make it possible to separate start and stop lludp packet processing from the console for debug processes.
This is controlled via the "debug lludp start <in|out|all>" and "debug lludp stop <in|out|all>" region console commands.
The command "debug lludp status" will show current status.
2012-11-28 02:46:46 +00:00
Justin Clark-Casey (justincc)
43aa74d139 minor: Comment out log message on every FRIENDS SIM CONNECTOR request for now. 2012-11-28 02:46:39 +00:00
Justin Clark-Casey (justincc)
ada9238907 minor: Add missing newlines and spacing to help for "debug eq" console command 2012-11-28 02:46:23 +00:00
Justin Clark-Casey (justincc)
4d98cdf829 minor: Add/correct some doc messages associated with entity teleport.
I believe UseCircuitCode is sent on EnableSimulator EQ message, rather than EstablishAgentCommunication
At least with LL 3.3.4, EstablishAgentCommunication appears unnecessary in the teleport context -
viewer still requests it though possibly only after TeleportFinish().  However, we will continue to send it.
2012-11-28 02:46:16 +00:00
Justin Clark-Casey (justincc)
547043047e minor: comment out "Registered seed capability" message for "Received SEED caps request" message for now.
I think this is more useful right now since it tells us if the viewer requested a seed caps at all in various scenarios (such as when teleporting to a new region).
2012-11-28 02:46:10 +00:00
Justin Clark-Casey (justincc)
9d3b68411a minor: Fix and elaborate on log information printed when an unrecognized estate method is received from the client. 2012-11-28 02:45:11 +00:00
Justin Clark-Casey (justincc)
470f8d3c04 Get rid of accidental scene start left in ScenePresenceAutopilotTests 2012-11-28 02:44:53 +00:00
Justin Clark-Casey (justincc)
da00b57d4b Fix problems with regression tests by allowing invoke of Update() with a finite number of frames even if the scene isn't active. 2012-11-28 02:44:45 +00:00
Justin Clark-Casey (justincc)
caedac67e0 Get Watchdog to log thread removal 2012-11-28 02:44:38 +00:00
Justin Clark-Casey (justincc)
2b5dc4eba4 Add "active true|false" to "debug scene" console command.
This allows the scene update and maintenance loops to be started and stopped for debug purposes.
2012-11-28 02:44:30 +00:00
Justin Clark-Casey (justincc)
39b8d01e71 minor: Use && instead of & when deciding whether to print Improve/ObjectUpdate packet out messages when debug is turned on.
Practical effect is probably none.
2012-11-28 02:44:23 +00:00
Justin Clark-Casey (justincc)
fca3154982 minor: Fix bug in categorization of blocks reused stat from packetpool 2012-11-28 02:44:17 +00:00
Justin Clark-Casey (justincc)
cef158c42d Remove now unnecessary OpenSim.Framework.Console reference from Monitoring.
Properly resolve circular reference which no longer appeared in Mono build as there were no using statements for it.
2012-11-28 02:44:10 +00:00
Justin Clark-Casey (justincc)
177c3bcfe6 Add AgentUpdate to PacketPool. This is the most common inbound packet from viewers. 2012-11-28 02:44:02 +00:00
Justin Clark-Casey (justincc)
35766f2c3a minor: Comment out "Client requested range for texture ... but" message. This is not useful during normal operation. 2012-11-28 02:43:55 +00:00
Justin Clark-Casey (justincc)
e175cf543c Fix percentage stats to multiply by 100. Adjust container name for packetpool stats. 2012-11-28 02:43:48 +00:00
Justin Clark-Casey (justincc)
96b0d1276e Enable reuse of data blocks for ImprovedTerseObjectUpdate using existing Packetpool code. 2012-11-28 02:43:42 +00:00
Justin Clark-Casey (justincc)
301546289e Fix build break by moving OpenSim.Framework.Console back below HttpServer in the build order.
Luckily, it turns out Framework.Monitoring doesn't need to reference Console directly.
2012-11-28 02:43:32 +00:00
Justin Clark-Casey (justincc)
813778b39e Fix packetpool for ImprovedTerseObjectUpdate packets.
These were neither being returned or in many places reused.
Getting packets from a pool rather than deallocating and reallocating reduces memory churn which in turn reduces garbage collection time and frequency.
2012-11-28 02:43:23 +00:00
Justin Clark-Casey (justincc)
6c3eceb197 Extend "show stats" command to "show stats [list|all|<category name>]"
This allows different categories of stats to be shown, with options to list categories or show all stats.
Currently categories are scene and simulator and only a very few stats are currently registered via this mechanism.
This commit also adds percentage stats for packets and blocks reused from the packet pool.
2012-11-28 02:43:11 +00:00
Justin Clark-Casey (justincc)
0afc43eed7 Assign endVector before control leaves ObjectCommandsModule.TryParseVectorRange() in order to fix mono 2.4.3 compile failure.
This doesn't fail the compile on mono 2.10.8.
2012-11-28 02:42:56 +00:00
Justin Clark-Casey (justincc)
6eb260d4eb Add "delete object pos <start-coord> to <end-coord>" console command.
This allows one to delete objects within a certain volume.
See help on console for more details.
2012-11-28 02:42:44 +00:00
Justin Clark-Casey (justincc)
63f1efc414 minor: Add method doc to EventManager.OnNewClient, OnClientLogin, ClientClosed, OnRemovePresence that any long-running operations should be launched on a thread separate to the event thread. 2012-11-28 02:42:02 +00:00
Justin Clark-Casey (justincc)
e685f7ab68 Lock on AgentCircuitData during Scene.AddClient() and RemoveClient() to prevent an inactive connection being left behind if the user closes the viewer whilst the connection is being established.
This should remove the need to run the console command "kick user --force" when these connections are left around.
2012-11-28 02:41:55 +00:00
Justin Clark-Casey (justincc)
ac8f420adb minor: elaborate method doc on Scene.NewUserConnection() 2012-11-28 02:41:42 +00:00
SignpostMarv
fa16f132e3 string format arguments in wrong order 2012-11-28 02:36:16 +00:00
Justin Clark-Casey (justincc)
7a5782c3e3 Get rid of some unnecessary casts in RemoteAdminPlugin.
This was stopping http://code.google.com/p/opensimtools/wiki/RemoteAdminPHPClass from working with some methods (e.g. create_user).
However, this casting has been around for at least 2 years so I'm puzzled that it worked in the first place, though it probably is extremely old sample code.
2012-11-28 02:35:28 +00:00
Justin Clark-Casey (justincc)
cf98691a3d Merge branch '0.7.4-post-fixes' into 0.7.4-extended
Conflicts:
	OpenSim/Data/MySQL/MySQLXInventoryData.cs
2012-11-15 02:52:37 +00:00
Justin Clark-Casey (justincc)
09aa87ba26 Fix SceneObjectUndoRedoTests.TestNoUndoOnObjectsNotInScene by not looking up ParentGroup scale limits if part is not in a sog 2012-11-15 02:38:57 +00:00
Justin Clark-Casey (justincc)
38fb0430bf Replace old Prebuild.exe accidentally added back in f977291 with one built without <copy> nant target generation and on mono 2.4.3 2012-11-15 02:16:03 +00:00
Justin Clark-Casey (justincc)
ec82e2fde8 Replace previously updated Prebuild.exe with one built directly with mono 2.4.3 2012-11-15 02:15:53 +00:00
Justin Clark-Casey (justincc)
fba2864cbc Stop Prebuild from generating <copy> statements which unnecessarily copy files into bin/Debug or bin/Release
nant_0.91~alpha2+dfsg-3_all.deb in Ubuntu 12.04 and earlier actually ignored these due to a bug
However, nant 0.92~rc1+dfsg-2 in Ubuntu 12.10 fixes this bug (possibly https://github.com/nant/nant/pull/39).
Which makes nant time-consumingly copy these files when the aren't actually used.
Tested removal of <copy> on both nant 0.91 and nant 0.92
Will be submitting this patch to prebuild project for comment though I suspect there's nobody there to pay attention.
2012-11-15 02:15:28 +00:00
Justin Clark-Casey (justincc)
60c6d3e108 Add [AssetService] AllowRemoteDeleteAllTypes (default false).
This allows a closed grid to delete asset types other than maptile remotely.
Only operational if AllowRemoteDelete = true also.
Defaults to false - do not enable if anybody other than you can make asset service requests.
2012-11-15 02:09:31 +00:00
Justin Clark-Casey (justincc)
92f9750ded Move check to allow only deletion of maptiles up to AssetServerDeleteHandler from AssetService.
This allows us to use a common check for both AssetService and XAssetService.
It also allows future console commands to delete an asset.
As before, deletion of maptile assets is not allowed remotely unless this is explicitly configured.
2012-11-15 02:09:20 +00:00
Justin Clark-Casey (justincc)
23106bce76 Merge branch '0.7.4-post-fixes' into 0.7.4-extended 2012-11-14 02:51:44 +00:00
Justin Clark-Casey (justincc)
15acba1972 minor: Adjust method doc on IXInventoryData MoveItem() and MoveFolder() to make it clear we're moving to an existing folder. 2012-11-14 01:53:32 +00:00
Justin Clark-Casey (justincc)
909d4dca82 Update parent inventory folder version numbers when folders are moved/created/deleted to match version numbers cached by viewers.
This is done in the way that one would expect (e.g. moving a folder increments version number on both source and destination parent folders).
This should hopefully improve viewer reuse of its cached inventory information.
Currently MySQL only but will be implement for SQLite/MSSQL if there are no issues.
2012-11-14 01:53:23 +00:00
Justin Clark-Casey (justincc)
5676f1d037 Update folder version numbers when moving items and making the Delete(string[], string[]) call (not just string, string).
This is to stop viewer inventory cache version numbers becoming out of sync with grid stored numbers when viewer performs these actions.
If there are no problems with these changes, they will be propogated to SQLite (and MSSQL if that's simple enough).
May also need to do the same on folder store/create/delete and maybe propogate version increments up the folder hierarchy, but that requires investigation.
2012-11-14 01:52:53 +00:00
Justin Clark-Casey (justincc)
d864d76254 Increment version number of a folder when an object it contains is deleted.
Not doing this was allowing the viewer inventory cache to become out of sync if an item was directly deleted.
2012-11-14 01:52:44 +00:00
Justin Clark-Casey (justincc)
9ff4d38cc9 Update folder version numbers when moving items and making the Delete(string[], string[]) call (not just string, string).
This is to stop viewer inventory cache version numbers becoming out of sync with grid stored numbers when viewer performs these actions.
If there are no problems with these changes, they will be propogated to SQLite (and MSSQL if that's simple enough).
May also need to do the same on folder store/create/delete and maybe propogate version increments up the folder hierarchy, but that requires investigation.
2012-11-08 21:16:49 +00:00
Justin Clark-Casey (justincc)
8dadbf706d Increment version number of a folder when an object it contains is deleted.
Not doing this was allowing the viewer inventory cache to become out of sync if an item was directly deleted.
2012-11-08 21:16:42 +00:00
Justin Clark-Casey (justincc)
ff968cbe43 refactor: Rename UserSessioNID -> UserSession in WebStatsModule since this is what it actually represents 2012-10-11 00:22:37 +01:00
Justin Clark-Casey (justincc)
582540657f Make UserSessionID a class rather than a struct, so that later updates to value suceed (rather than having to pull the data out and reinsert back into the Dictionary).
Fixes http://opensimulator.org/mantis/view.php?id=6338
2012-10-11 00:22:30 +01:00
Justin Clark-Casey (justincc)
05eeee6ee8 Add MaxPrimsUndo config setting to [Startup] section of OpenSim.ini.
This controls how many undo steps the simulator will store for each prim.
Default is now 20 rather than 5 as it briefly was.
The default number could be increased through this is a memory tradeoff which will scale with the number of prims in the sim and level of activity.
2012-10-11 00:22:23 +01:00
Justin Clark-Casey (justincc)
cd6f3b147d Don't store undo states if a scene object is manipulated when it is not in a scene.
Adds regression test for this.
2012-10-11 00:22:16 +01:00
Justin Clark-Casey (justincc)
86f519ba57 refactor: Change control structures in SOP.StoreUndoState() to reduce nesting. 2012-10-11 00:22:10 +01:00
Justin Clark-Casey (justincc)
febc6bae30 Make it possible to rescale SOGs when they are not in a scene. 2012-10-11 00:22:03 +01:00
Justin Clark-Casey (justincc)
48f818bf07 Enforce existing 5 action hardcoded undo limit.
This was present in the code but not enforced, which led to a memory leak over time as part properties were changed, whether by viewer, script or another source.
This commit enforces that limit, which will soon become configurable.
Regression test for undo limit added
Should help with http://opensimulator.org/mantis/view.php?id=6279
2012-10-11 00:21:56 +01:00
Justin Clark-Casey (justincc)
c2d21bb8cc Add basic undo/redo regression tests. 2012-10-11 00:21:49 +01:00
Justin Clark-Casey (justincc)
39fe1ba028 Fix very recently introduced race condition where a CreateNewItem outracing an UploadAsset request could throw an exception because m_asset did not yet exist.
This was accidentally introduced in 4fc0cfb
This commit also consistently removes the AssetXferUploader when the transaction completes, no matter if it completed on asset upload or item operation.
The amount of data being retained was small, since this was clothing/bodypart metadata in the asset rather than textures themselves.
2012-10-11 00:21:39 +01:00
Justin Clark-Casey (justincc)
7112e860dc Comment out old m_storeLocal from AssetXferUploader.
This was only used if none of new item, update item or update task item had been set.
But since all transactions go through these paths this old code is redundant.
2012-10-11 00:21:30 +01:00
Justin Clark-Casey (justincc)
4606137882 Insert transaction ID into AssetXferUploader constructor rather than at UploadAsset() to prevent item creation failure when NewInventoryItem thread reachs the object first.
This was preventing the previous race condition fix in 4fc0cfb from actually working.
This commit also removes some of the pointless transaction id checks - these conditions are already being enforced in AgentAssetsTransactions.
2012-10-11 00:21:22 +01:00
Justin Clark-Casey (justincc)
8eab6b7701 Move UDP update task item code to AssetXferUploader to match existing create user item and update user item mechanisms
This is done for consistency and to allow removal or some access methods that increase code complexity.
However, this path has not been used for a long time, not even by LL 1.23 - viewers use caps http upload for this instead
2012-10-11 00:21:16 +01:00
Justin Clark-Casey (justincc)
71cd68eec1 Fix occasional race condition failure when creating new clothing/body parts in the viewer or updating existing assets.
On creating these items, the viewer sends a UDP AssetUploadRequest followed by a CreateInventoryItem.
It was possible for the CreateInventoryItem/UpdateInventoryItem to occasionally outrace the AssetUploadRequest and fail to find an initialized Xfer object, at which point the item create would fail.
So instead we always set up a Xfer object on either the asset or inventory item update request.
This does not introduce a new race because code already exists to delay the item operation until the asset is uploaded if necessary (but this only worked if the xfer object already existed)
2012-10-11 00:21:08 +01:00
Justin Clark-Casey (justincc)
168c3b78f4 Fix llListFindList() returning no match when there is a match with a script constant component in the source list.
Adds regression test for this case.
Based on http://opensimulator.org/mantis/view.php?id=6156
Thanks SignpostMarv.
2012-10-11 00:21:01 +01:00
Justin Clark-Casey (justincc)
d175e49e15 refactor: Rename UserSessioNID -> UserSession in WebStatsModule since this is what it actually represents 2012-10-10 23:55:51 +01:00
Justin Clark-Casey (justincc)
79624d762e Make UserSessionID a class rather than a struct, so that later updates to value suceed (rather than having to pull the data out and reinsert back into the Dictionary).
Fixes http://opensimulator.org/mantis/view.php?id=6338
2012-10-10 23:55:39 +01:00
Justin Clark-Casey (justincc)
3ec9eec257 Fix bug in implementation of "show part pos" that would not filter probably.
Also refactors more of ObjectCommandsModule to remove duplicate code
2012-10-10 23:55:18 +01:00
Justin Clark-Casey (justincc)
e5ac4a72b7 Add "show part pos" console command to match "show object pos" 2012-10-10 23:55:12 +01:00
Justin Clark-Casey (justincc)
470ea6cf70 refactor: eliminate some now duplicate code in ObjectCommandsModule 2012-10-10 23:55:06 +01:00
Justin Clark-Casey (justincc)
45dc7ac7d1 Add Vector3.Zero return on TryParseConsoleVector() which fails on mono 2.4.3 but not mono 2.10.9 2012-10-10 23:54:58 +01:00
Justin Clark-Casey (justincc)
2905eaa8ff Add missing ConsoleUtil from last commit 2012-10-10 23:54:51 +01:00
Justin Clark-Casey (justincc)
deb068050b Add "show object pos <start-coord> to <end-coord>" command to simulator console.
This allows you to display details of all objects in a given bounding box.
Values parts of the co-ord can be left out as appropriate (e.g. to get all objects between the ground and z=30.
See "help show object pos" for more details.
2012-10-10 23:54:44 +01:00
Justin Clark-Casey (justincc)
8f803c5a7d Finally fix build break by allowing UserManagementModule (which constructs a packet directly) to reference OpenSim.Region.ClientStack.LindenUDP.
This time I actually properly did a clean build
2012-10-10 23:54:36 +01:00
Justin Clark-Casey (justincc)
601c7998eb Print number of objects found with "show object name" and "show part name" simulator console commands 2012-10-10 23:54:27 +01:00
Justin Clark-Casey (justincc)
5a686d40de Forgot to actually remove the packetpool set code from scene. 2012-10-10 23:54:19 +01:00
Justin Clark-Casey (justincc)
57837a1e81 Read PacketPool config in LLUDPServer with other config params rather than in Scene.
This is to resolve previous build break.
This unnecessarily but harmlessly reads and sets the parameter multiple times - scene was doing the same thing.
2012-10-10 23:54:13 +01:00
Justin Clark-Casey (justincc)
5162ebd2cc refactor: Move OpenSim.Framework.PacketPool to OpenSim.Region.Clientstack.Linden.UDP
This is to allow it to use OpenSim.Framework.Monitoring in the future.
This is also a better location since the packet pool is linden udp specific
2012-10-10 23:54:04 +01:00
Justin Clark-Casey (justincc)
1f869ab36d Output monitor data in response to console command on MainConsole.Instance rather than m_log
This should really be happening for all console commands (though many don't).
However, things might get difficult if both a console command and other code invoke the same paths.
2012-10-10 23:53:29 +01:00
Justin Clark-Casey (justincc)
e912e52e15 Add generic PercentageStat.
Not yet used.
2012-10-10 23:53:21 +01:00
Justin Clark-Casey (justincc)
14b0c03d5b Add experimental "slow frames" stat, available in "show stats" and via the monitoring module.
This increments a SlowFrames counter if a frame takes over 120% of maximum time.
This commit also introduces a generic OpenSim.Framework.Monitoring.Stat which is available to any code that wants to register a statistic.
This is more granualar than asking objects to create their own reports.
At some point this will supersede earlier IMonitor and IAlert facilities in MonitoringModule which are only available to scene code.
2012-10-10 23:52:59 +01:00
Justin Clark-Casey (justincc)
8414ec9429 Fix bug where debug http level 6 could not be specified. Also converts newlines at this level to '\n' to enable them to be logged. 2012-10-10 23:51:20 +01:00
Justin Clark-Casey (justincc)
ac03b1b82f Add MaxPrimsUndo config setting to [Startup] section of OpenSim.ini.
This controls how many undo steps the simulator will store for each prim.
Default is now 20 rather than 5 as it briefly was.
The default number could be increased through this is a memory tradeoff which will scale with the number of prims in the sim and level of activity.
2012-10-10 23:49:30 +01:00
Justin Clark-Casey (justincc)
d5c999553e Don't store undo states if a scene object is manipulated when it is not in a scene.
Adds regression test for this.
2012-10-10 23:47:34 +01:00
Justin Clark-Casey (justincc)
371df42d3f refactor: Change control structures in SOP.StoreUndoState() to reduce nesting. 2012-10-10 23:47:15 +01:00
Justin Clark-Casey (justincc)
a4a0396850 Make it possible to rescale SOGs when they are not in a scene. 2012-10-10 23:46:58 +01:00
Justin Clark-Casey (justincc)
83ad75b997 Enforce existing 5 action hardcoded undo limit.
This was present in the code but not enforced, which led to a memory leak over time as part properties were changed, whether by viewer, script or another source.
This commit enforces that limit, which will soon become configurable.
Regression test for undo limit added
Should help with http://opensimulator.org/mantis/view.php?id=6279
2012-10-10 23:39:14 +01:00
Justin Clark-Casey (justincc)
3f45d4ba9d Add basic undo/redo regression tests. 2012-10-10 23:39:02 +01:00
Justin Clark-Casey (justincc)
2fa8bc201a Fix very recently introduced race condition where a CreateNewItem outracing an UploadAsset request could throw an exception because m_asset did not yet exist.
This was accidentally introduced in 4fc0cfb
This commit also consistently removes the AssetXferUploader when the transaction completes, no matter if it completed on asset upload or item operation.
The amount of data being retained was small, since this was clothing/bodypart metadata in the asset rather than textures themselves.
2012-10-10 23:38:39 +01:00
Justin Clark-Casey (justincc)
e6b99ec849 Comment out old m_storeLocal from AssetXferUploader.
This was only used if none of new item, update item or update task item had been set.
But since all transactions go through these paths this old code is redundant.
2012-10-10 23:38:26 +01:00
Justin Clark-Casey (justincc)
e5c665384c Insert transaction ID into AssetXferUploader constructor rather than at UploadAsset() to prevent item creation failure when NewInventoryItem thread reachs the object first.
This was preventing the previous race condition fix in 4fc0cfb from actually working.
This commit also removes some of the pointless transaction id checks - these conditions are already being enforced in AgentAssetsTransactions.
2012-10-10 23:37:59 +01:00
Justin Clark-Casey (justincc)
5bb1273b3d Move UDP update task item code to AssetXferUploader to match existing create user item and update user item mechanisms
This is done for consistency and to allow removal or some access methods that increase code complexity.
However, this path has not been used for a long time, not even by LL 1.23 - viewers use caps http upload for this instead
2012-10-10 23:37:52 +01:00
Justin Clark-Casey (justincc)
5629f5141e Fix occasional race condition failure when creating new clothing/body parts in the viewer or updating existing assets.
On creating these items, the viewer sends a UDP AssetUploadRequest followed by a CreateInventoryItem.
It was possible for the CreateInventoryItem/UpdateInventoryItem to occasionally outrace the AssetUploadRequest and fail to find an initialized Xfer object, at which point the item create would fail.
So instead we always set up a Xfer object on either the asset or inventory item update request.
This does not introduce a new race because code already exists to delay the item operation until the asset is uploaded if necessary (but this only worked if the xfer object already existed)
2012-10-10 23:37:29 +01:00
SignpostMarv
15aef01b34 Documenting object-related events 2012-10-10 23:37:14 +01:00
SignpostMarv
67a010298f Documenting LSL script-related events 2012-10-10 23:37:05 +01:00
SignpostMarv
7c398a532b Documenting non-LSL script-related events 2012-10-10 23:36:43 +01:00
Justin Clark-Casey (justincc)
eefd39a0d5 Fix llListFindList() returning no match when there is a match with a script constant component in the source list.
Adds regression test for this case.
Based on http://opensimulator.org/mantis/view.php?id=6156
Thanks SignpostMarv.
2012-10-10 23:36:10 +01:00
Justin Clark-Casey (justincc)
176b1c85c0 minor: Make slow outgoing request log messages consistent with other log messages 2012-10-10 23:35:45 +01:00
Justin Clark-Casey (justincc)
2da6cfde80 Rename UuidGather.m_assetCache to m_assetService. If HGUuidGatherer hasn't been instantiated with an assetServerURL then call down to overriden UuidGatherer.GetAsset() instead of calling m_assetService.GetAsset() itself - these two codepaths are now identical. 2012-10-10 23:35:35 +01:00
Justin Clark-Casey (justincc)
8068c083f6 Simplify UuidGatherer by performing asset fetch synchronously rather than using the async call but waiting for completion anyway! 2012-10-10 23:35:27 +01:00
Justin Clark-Casey (justincc)
bbe04aab95 Lock GDI+ portion og VectorRenderModule.GetDrawStringSize() to prevent concurrent thread use provoking mono crashes.
Same rationale as commit 13690582.
2012-09-28 02:38:51 +01:00
Justin Clark-Casey (justincc)
d31a951d94 Lock GDI+ portion og VectorRenderModule.GetDrawStringSize() to prevent concurrent thread use provoking mono crashes.
Same rationale as commit 13690582.
2012-09-28 02:37:50 +01:00
Justin Clark-Casey (justincc)
c27a158961 Don't fail to create an IRC nick if nick randomization is disabled in the IRC module.
Patch from http://opensimulator.org/mantis/view.php?id=6293
Thanks Starflower.
2012-09-28 00:12:54 +01:00
SignpostMarv
068e97cf0e Documentation of teleport-related events 2012-09-28 00:12:48 +01:00
SignpostMarv
aa45d831f3 minor tweaks to existing comments for IDE goodness 2012-09-28 00:12:40 +01:00
SignpostMarv
eff8448154 Documentation of agent-related events 2012-09-28 00:12:32 +01:00
SignpostMarv
badd7f1578 Documentation of object-related events 2012-09-28 00:12:24 +01:00
SignpostMarv
e12cb7bca9 Documentation of OnPluginConsole 2012-09-28 00:12:17 +01:00
Justin Clark-Casey (justincc)
23fe2a2103 Make ResendAppearanceUpdates = true by default in [Appearance] in OpenSimDefaults.ini.
This resends appearance uuids to avatars in the scene once a minute.
I have seen this help in the past resolve grey appearance problems where viewers have for unknown reasons sometimes ignored the packet.
The overhead is very small since only the UUIDs are sent - the viewer then requests the texture only if it does not have it cached.
This setting will not help with cloudy avatars which are usually due to the viewer not uploading baked texture data or uploading something that isn't valid JPEG2000
2012-09-27 23:55:15 +01:00
Justin Clark-Casey (justincc)
e684e426af Add openmetaverse_data from libopenmetaverse to allow testing of texture baking via bot rather than just throwing out errors 2012-09-27 23:54:59 +01:00
Justin Clark-Casey (justincc)
e65959b6f7 Add basic asset connector tests to check behaviour for normal, local and temporary assets.
Make AssetServiceConnector return more useful data on failure, such as what DLL it was trying to load
Allow LocalAssetServiceConnector.GetData() to work without a cache present, as works for the other lasc Get* methods.
2012-09-27 23:54:40 +01:00
Justin Clark-Casey (justincc)
8041af6d18 For FlotsamAssetCache, always update access times of cached scene assets before looking for files to expire.
This is to resolve a problem where an asset marked as local but not temporary but still used in the scene would be removed.
The timed expiry scan no longer tries to refetch assets from the scene that are not currently in the cache - this is not helpful since it just drags a lot of data into the cache that may never be referenced.
This removes the DeepScanBeforePurge option since setting this to false will introduce the above problem.  This previously had a default of true.
2012-09-27 23:54:32 +01:00
SignpostMarv
56873b319b Documentation of parcel-related events
Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2012-09-27 23:54:13 +01:00
SignpostMarv
b315fab771 correcting a typo that causes c# express to complain about xml comment containing invalid xml
Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2012-09-27 23:54:05 +01:00
Justin Clark-Casey (justincc)
05342ed677 minor: Comment out friends notification log spam for now. 2012-09-27 23:53:47 +01:00
SignpostMarv
487bf31e06 documentation (OnSceneObjectPartCopy) 2012-09-27 23:53:20 +01:00
SignpostMarv
6f3b2ea632 documentation (OnRemovePresence) 2012-09-27 23:53:12 +01:00
SignpostMarv
307fdeff78 documentation (OnNewPresence) 2012-09-27 23:53:00 +01:00
SignpostMarv
8df3edcc30 documentation (OnClientConnect) 2012-09-27 23:52:51 +01:00
SignpostMarv
a43e282efa documentation (OnBackup) 2012-09-27 23:52:34 +01:00
SignpostMarv
7374690957 documentation (OnTerrainTick) 2012-09-27 23:52:26 +01:00
SignpostMarv
0c69575670 documentation (OnTerrainTainted) 2012-09-27 23:52:19 +01:00
SignpostMarv
148cad1976 documentation (OnClientMovement) 2012-09-27 23:52:08 +01:00
SignpostMarv
7db4e00b14 Documenting some of the events on OpenSim.Region.Framework.Scenes.EventManager (OnFrame) 2012-09-27 23:51:15 +01:00
BlueWall
a00f745eba Add file to .gitignore
Add OpenSim.userprefs which is created by Monodevelop to .gitignore
2012-09-27 23:50:53 +01:00
SignpostMarv
9ae335fafc adding documentation to script invokation methods 2012-09-27 23:49:06 +01:00
Justin Clark-Casey (justincc)
6bd7639d66 Also do other MySQL region settings related calls under m_dbLock, in common with other calls. 2012-09-27 23:48:51 +01:00
Justin Clark-Casey (justincc)
c336309234 Do Windlight storage and removal calls in MySQL under m_dbLock, as is done with all the other database calls. 2012-09-27 23:48:45 +01:00
SignpostMarv
41d217321d fixing bug where last element in list is ignored 2012-09-27 23:48:27 +01:00
Justin Clark-Casey (justincc)
2226dd1efb Revert "refactoring to allow Scene.GetLandData to accept Vector3 as an argument. Note that the prior work on LSL_Vector implicit operators means one does not need to explicitly cast a LSL_Vector to Vector3"
This reverts commit f8612b0d1b.
2012-09-27 23:29:47 +01:00
Justin Clark-Casey (justincc)
44699b07e4 Comment out the long unused afaik HTTP agent handlers.
As far as I know, this was only used by the IBM Rest modules, much of which has been commented out for a very long time now.  Other similar code uses HTTP or stream handlers instead.
So commenting this out to reduce code complexity and the need to make this facility consistent with the others where it may not be used anyway.
If this facility is actually being used then please notify me or uncomment it if you are core.
2012-09-27 23:24:40 +01:00
Justin Clark-Casey (justincc)
6739f0752b Add request number counting to incoming HTTP requests in the same way that this was already being done for outgoing HTTP requests.
This allows us to associate debug logging messages with the right request.
It also allows us to put a request number on 'long request' logging even if other debug logging is not enabled, which gives us some idea of whether every request is suffering this problem or only some.
This is a separate internal number not associated with any incoming number in the opensim-request-id header, this will be clarified when logging of this incoming request number is re-enabled.
This commit also adds port number to HTTP IN logging to allow us to distinguish between different request numbers on different ports.
2012-09-27 23:24:32 +01:00
Justin Clark-Casey (justincc)
1ebde81d6a Insert a new log level 4 for HTTP IN and HTTP OUT that will log how long the request took.
This is only printed if debug http level >= 4 and the request didn't take more than the time considered 'long', in which case the existing log message is printed.
This displaces the previous log levels 4 and 5 which are now 5 and 6 respectively.
2012-09-27 23:24:22 +01:00
Justin Clark-Casey (justincc)
195625b5e7 Add ability to turn on/off logging of outgoing HTTP requests flowing through WebUtil.
This is for debugging purposes.
This is controlled via the "debug http" command which can already log incoming requests.
This now gains a mandatory parameter of in, out or all to control what is logged.
Log messages are also shortened and labelled and HTTP IN or HTTP OUT to be consistent with existing UDP PACKET IN and PACKET OUT messages.
2012-09-27 23:24:14 +01:00
Justin Clark-Casey (justincc)
951c2702ff Don't fail to create an IRC nick if nick randomization is disabled in the IRC module.
Patch from http://opensimulator.org/mantis/view.php?id=6293
Thanks Starflower.
2012-09-27 23:24:08 +01:00
SignpostMarv
02b90df6ff Documentation of teleport-related events 2012-09-27 23:24:01 +01:00
SignpostMarv
f7c01c8e90 minor tweaks to existing comments for IDE goodness 2012-09-27 23:23:55 +01:00
SignpostMarv
e8c964efaf Documentation of agent-related events 2012-09-27 23:23:49 +01:00
SignpostMarv
74baab6f0f Documentation of object-related events 2012-09-27 23:23:39 +01:00
SignpostMarv
bff0ea2fc3 Documentation of OnPluginConsole 2012-09-27 23:23:33 +01:00
Justin Clark-Casey (justincc)
e474c19c40 Make ResendAppearanceUpdates = true by default in [Appearance] in OpenSimDefaults.ini.
This resends appearance uuids to avatars in the scene once a minute.
I have seen this help in the past resolve grey appearance problems where viewers have for unknown reasons sometimes ignored the packet.
The overhead is very small since only the UUIDs are sent - the viewer then requests the texture only if it does not have it cached.
This setting will not help with cloudy avatars which are usually due to the viewer not uploading baked texture data or uploading something that isn't valid JPEG2000
2012-09-27 23:23:27 +01:00
Justin Clark-Casey (justincc)
a2a81f1bb7 Update libopenjpeg libraries used by libopenmetaverse back up to 1.5, this time using lkalif's linux libraries built against a much earlier libc (2.7) 2012-09-27 23:23:18 +01:00
Justin Clark-Casey (justincc)
c291284629 Downgrade libopenjpeg back to 1.3 from 1.5.
This is because libopenjpeg 1.5 appears to require a minimum of glibc 2.14, whereas at least one fairly recent distro (openSUSE 11.4 from 2011-03-10) only has glibc
Further investigation pending.
2012-09-27 23:23:11 +01:00
Justin Clark-Casey (justincc)
7f7ad71def Add openmetaverse_data from libopenmetaverse to allow testing of texture baking via bot rather than just throwing out errors 2012-09-27 23:23:05 +01:00
justincc
7dfc0f30cc Update libopenmetaverse components to commit f5cecaa
Among other things this allows pCampbot to work under Windows since libopenmateverse now ships the same log4net.dll (publicly signed) as OpenSimulator
This also updates the libopenmetaverse embedded libopenjpeg from 1.3 to 1.5.
DLL naming and mapping for non-Windows libopenjpeg changes to remove version number to make future udpates easier and bring it into line with names of other shipped DLLs.
libopenjpeg updates have been made for OSX, Windows (32 and 64 bit) and Linux (32 and 64 bit).  Please report any issues.
2012-09-27 23:22:57 +01:00
Justin Clark-Casey (justincc)
c14e67a8bb Add basic asset connector tests to check behaviour for normal, local and temporary assets.
Make AssetServiceConnector return more useful data on failure, such as what DLL it was trying to load
Allow LocalAssetServiceConnector.GetData() to work without a cache present, as works for the other lasc Get* methods.
2012-09-27 23:21:19 +01:00
Justin Clark-Casey (justincc)
75b7e6009a For FlotsamAssetCache, always update access times of cached scene assets before looking for files to expire.
This is to resolve a problem where an asset marked as local but not temporary but still used in the scene would be removed.
The timed expiry scan no longer tries to refetch assets from the scene that are not currently in the cache - this is not helpful since it just drags a lot of data into the cache that may never be referenced.
This removes the DeepScanBeforePurge option since setting this to false will introduce the above problem.  This previously had a default of true.
2012-09-27 23:21:12 +01:00
Justin Clark-Casey (justincc)
63df56d613 Don't store the unnecessary VERSIONMIN. VERSIONMAX, METHOD or UserID (present as column PrincipalID) parameters in the Avatars table.
These are used to invoke avatar service calls but are not in themselves persistable avatar data.
2012-09-27 23:20:42 +01:00
SignpostMarv
f2e1f3e659 Documentation of parcel-related events
Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2012-09-27 23:20:28 +01:00
SignpostMarv
b1b7d3b004 correcting a typo that causes c# express to complain about xml comment containing invalid xml
Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2012-09-27 23:20:21 +01:00
Justin Clark-Casey (justincc)
f2c12d4fba Fix usage statement on "debug http" console command since max level is now 5 rather than 3 2012-09-27 23:20:10 +01:00
Justin Clark-Casey (justincc)
3a60c9c8c8 Fix bug in logging sample input at debug http level 4.
Also converts newlines to "\n" text.
2012-09-27 23:20:04 +01:00
Justin Clark-Casey (justincc)
44cd864205 minor: Comment out friends notification log spam for now. 2012-09-27 23:19:53 +01:00
SignpostMarv
f70d7013a5 Documentation of economy-related EventManager events 2012-09-27 23:19:41 +01:00
Mic Bowman
ac1e902d59 Allow an incoming identifier to be specified for a JsonStore. 2012-09-27 23:18:37 +01:00
Justin Clark-Casey (justincc)
b67bdee3cf Make "show http-handlers" command available for ROBUST instances as well as the simulator executable. 2012-09-27 23:18:08 +01:00
Justin Clark-Casey (justincc)
83d4fa98f0 Add levels 4 and 5 to "debug http" console command that will log a sample of incoming request data and the entire incoming data respectively.
See "help debug http" for more details.
2012-09-27 23:17:59 +01:00
SignpostMarv
70a968b342 documentation (OnSceneObjectPartCopy) 2012-09-27 23:17:53 +01:00
SignpostMarv
8e576f7511 documentation (OnRemovePresence) 2012-09-27 23:17:44 +01:00
SignpostMarv
4526424436 documentation (OnNewPresence) 2012-09-27 23:17:38 +01:00
SignpostMarv
fd43620e87 documentation (OnClientConnect) 2012-09-27 23:17:32 +01:00
SignpostMarv
56b8d331cb documentation (OnBackup) 2012-09-27 23:17:24 +01:00
SignpostMarv
14bfba8b3b documentation (OnTerrainTick) 2012-09-27 23:17:17 +01:00
SignpostMarv
af8d3ae790 documentation (OnTerrainTainted) 2012-09-27 23:17:11 +01:00
SignpostMarv
e6bb7e99be documentation (OnClientMovement) 2012-09-27 23:17:05 +01:00
SignpostMarv
97c56adb9d Documenting some of the events on OpenSim.Region.Framework.Scenes.EventManager (OnFrame) 2012-09-27 23:16:59 +01:00
SignpostMarv
f8612b0d1b refactoring to allow Scene.GetLandData to accept Vector3 as an argument. Note that the prior work on LSL_Vector implicit operators means one does not need to explicitly cast a LSL_Vector to Vector3 2012-09-27 23:16:35 +01:00
SignpostMarv
a2a46a18ae 4096 is used in various places as the maximum height of a region, refactoring to be a constant 2012-09-27 23:16:25 +01:00
Justin Clark-Casey (justincc)
1cf888b71f Add missing DynamicTexture.cs file from last commit 2012-09-27 23:15:49 +01:00
Justin Clark-Casey (justincc)
0109603cdc If reusing dynamic textures, do not reuse small data length textures that fall below current viewer discard level 2 thresholds.
Viewer LL 3.3.4 and before sometimes fail to properly redisplay dynamic textures that have a small data length compared to pixel size when pulled from cache.
This appears to happen when the data length is smaller than the estimate discard level 2 size the viewer uses when making this GetTexture request.
This commit works around this by always regenerating dynamic textures that fall below this threshold rather than reusing them if ReuseDynamicTextures = true
This can be controlled by the [Textures] ReuseDynamicLowDataTextures config setting which defaults to false.
2012-09-27 23:15:43 +01:00
SignpostMarv
c7c750d127 adding utility method for getting SceneObjectGroup from scene
Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2012-09-27 23:15:30 +01:00
SignpostMarv
b738b50cd6 adding utility method for getting SceneObjectPart from scene
Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2012-09-27 23:15:23 +01:00
SignpostMarv
351daf90f1 pasting in show uptime code
Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2012-09-27 23:15:07 +01:00
BlueWall
19d9acf63a Add file to .gitignore
Add OpenSim.userprefs which is created by Monodevelop to .gitignore
2012-09-27 23:14:52 +01:00
Justin Clark-Casey (justincc)
eb40d3b6fc If the GetTexture capability receives a request for a range of data beyond that of an otherwise valid asset, return HTTP PartialContent rather than RequestedRangeNotSatisfiable.
This is because recent viewers (3.2.1, 3.3.4) and probably earlier ones using the http GetTexture capability will sometimes make such invalid range requests.
This appears to happen if the viewer's estimate of texture sizes at discard levels > 0 (chiefly 2) exceeds the total texture size.
I believe this does not normally happen but can occur for dynamic textures with are large but mainly blank.
If this happens, returning a RequestedRangeNotSatisfiable will cause the viewer to not render the texture at the final resolution.
However, returning a PartialContent (or OK) even with 0 data will allow the viewer to render the final texture.
2012-09-27 23:14:39 +01:00
BlueWall
f5da23d9db Fix Windows build
Add reference to fix Windows build: no windows here to test, please report any issues back to IRC #opensim-dev ASAP
2012-09-27 23:13:56 +01:00
SignpostMarv
b412bce095 adding documentation to script invokation methods 2012-09-27 23:13:11 +01:00
Justin Clark-Casey (justincc)
0b57ddd753 Also do other MySQL region settings related calls under m_dbLock, in common with other calls. 2012-09-27 23:12:58 +01:00
Justin Clark-Casey (justincc)
d0a6d82a23 Do Windlight storage and removal calls in MySQL under m_dbLock, as is done with all the other database calls. 2012-09-27 23:12:48 +01:00
Justin Clark-Casey (justincc)
ba2792bd1f Make ReuseDynamicTextures an experimental config setting in [Textures]. Default is false, as before.
If true, this setting reuses dynamically generated textures (i.e. created through osSetDynamicTextureData() and similar OSSL functions) where possible rather than always regenerating them.
This results in much quicker updates viewer-side but may bloat the asset cache (though this is fixable).
Also, sometimes issue have been seen where dynamic textures do not transfer to the viewer properly (permanently blurry).
If this happens and that flag is set then they are not regenerated, the viewer has to clear cache or wait for 24 hours before all cached uuids are invalidated.
CUrrently experimental.  Default is false, as before.
2012-09-27 23:12:39 +01:00
Justin Clark-Casey (justincc)
3f8c09e006 If the compile-time DynamicTextureModule.ReuseTextures flag is set, check metadata still exists for any reused asset in case some other process has removed it from the cache. 2012-09-27 23:12:32 +01:00
SignpostMarv
8f39268761 fixing bug where last element in list is ignored 2012-09-27 23:12:24 +01:00
Justin Clark-Casey (justincc)
cd8c8d78a9 Renaming existing 'torture' tests to 'performance' tests instead, since this better matches what they really do.
nant target name changes to test-perf instead of torture, to match test-stress
still not run by default
2012-09-27 23:11:55 +01:00
Justin Clark-Casey (justincc)
980678846d Add VectorRenderModuleStressTests that contains a long running test that generates thousands of vector textures concurrently.
Intended for use if there are future issues with mono crashes whilst generate dynamic textures.
This test is triggered via a new test-stress nant target.
Not run by default.
2012-09-27 23:11:44 +01:00
Justin Clark-Casey (justincc)
9a92d8d57e Add experimental DynamicTextureModule.ReuseTextures flag, currently only configurable on compile.
Disabled (status quo) by default.
This flag makes the dynamic texture module reuse cache previously dynamically generated textures given the same input commands and extra params for 24 hours.
This occurs as long as those commands would always generate the same texture (e.g. they do not contain commands to fetch data from the web).
This makes texture changing faster as a viewer-cached texture uuid is sent and may reduce simulator load in regions with generation of lots of dynamic textures.
A downside is that this stops expiry of old temporary dynamic textures from the cache,
Another downside is that a jpeg2000 generation that partially failed is currently not regenerated until restart or after 24 hours.
2012-09-27 23:11:10 +01:00
Justin Clark-Casey (justincc)
b155c601d7 Add IDynamicTextureManager.ConvertData() to match AsyncConvertData(). Remove mismatching ConvertStream() where there is no AsyncConvertStream and neither IDynamicTextureManager implementer implements this method. 2012-09-27 23:11:04 +01:00
Justin Clark-Casey (justincc)
536f2c085a minor: Simplify return of vector render module name and some very minor removal of unncessary syntax clutter 2012-09-27 23:10:08 +01:00
SignpostMarv
2602d4f16e refactoring using List.ConvertAll<string> 2012-09-27 23:05:50 +01:00
SignpostMarv
174addc426 adding a clip method to handle Vector3 objects to enable a minor amount of refactoring 2012-09-27 23:00:01 +01:00
Justin Clark-Casey (justincc)
849053681e Change flavour to Extended 2012-09-27 00:57:34 +01:00
Justin Clark-Casey (justincc)
a8d8ea7990 Flip release type to post fixes 2012-09-01 00:01:01 +01:00
Justin Clark-Casey (justincc)
10e6493f9f Set flavour to release. 2012-08-31 21:39:51 +01:00
Melanie
8c4f911935 Replace SendBannedUserList with Avination's version. Untested in core. Not even test compiled. 2012-08-31 16:35:36 +01:00
Justin Clark-Casey (justincc)
62bc85b5c7 Fix regression introduced in a0d178b2 (Sat Aug 25 02:00:17 2012) where folders with asset type of 'Folder' and 'Unknown' were accidentally treated as system folders.
This prevented more than one additional ordinary folder from being created in the base "My Inventory" user folder.
Added regression test for this case.
Switched tests to use XInventoryService with mostly implemented TestXInventoryDataPlugin rather than InventoryService
Disabled TestLoadIarV0_1SameNameCreator() since this has not been working for a very long time (ever since XInventoryService) started being used
since it doesnt' preserve creator data in the same way as InventoryService did and so effectively lost the OSPAs.
However, nobody noticed/complained about this issue and OSPAs have been superseded by HG like creator information via the --home save oar/iar switch.
2012-08-31 16:29:57 +01:00
SignpostMarv
76eba917f9 copying documentation from http://opensimulator.org/wiki/Threat_level 2012-08-31 16:29:46 +01:00
SignpostMarv
84a046eaf5 adding some files to .gitignore that get generated when debugging in c# express with OpenSim.32BitLaunch as the startup project 2012-08-31 16:29:40 +01:00
Justin Clark-Casey (justincc)
8d1d314f49 Add VectorRenderModule.TestRepeatSameDrawDifferentExtraParams() 2012-08-31 16:29:22 +01:00
Justin Clark-Casey (justincc)
9395f12584 Add VectorRenderModuleTests.TestRepeatDrawContainingImage() 2012-08-31 16:29:16 +01:00
Justin Clark-Casey (justincc)
b97f58d597 Add VectorRenderModuleTests.TestRepeatDraw() 2012-08-31 16:29:09 +01:00
Justin Clark-Casey (justincc)
30c36a3960 Following on from f8a89a79, do not allow more than one 'type' folder (e.g. calling cards) to be created in the base "My Inventory" user folder.
This is to accomodate situations where viewers will create more than one 'type' subfolder (e.g. calling cards)
But at the same time to prevent multiple such 'system' folders (those in the base "My Inventory" user folder).
This also makes GetFolderForType() only return a folder in the base "My Inventory" folder, if such a type folder exists
2012-08-31 16:28:20 +01:00
Justin Clark-Casey (justincc)
206eccc2b6 Allow multiple calling card type inventory folders to be created.
Modern viewers want to create Friends and All folders of this type inside the root Calling Cards folder.
2012-08-31 16:28:13 +01:00
Justin Clark-Casey (justincc)
2358a623e3 minor: Fix bad log message for failure to create an inventory folder 2012-08-31 16:28:04 +01:00
Justin Clark-Casey (justincc)
87850bd6dc Log initial script startup info notice when xengine actually starts to do this for debugging purposes, rather than before it actually starts to do this. 2012-08-31 16:27:54 +01:00
Justin Clark-Casey (justincc)
d80eda202f Extend "Restarting scripts in attachments" debug log message to show actual name of user and the region they are in 2012-08-24 22:57:18 +01:00
Justin Clark-Casey (justincc)
3edfa585ec If a connecting scene presence is replacing an existing scene presence then bypass close checks. 2012-08-24 22:43:14 +01:00
Justin Clark-Casey (justincc)
fa13a6a8da Bump version number to 0.7.4-rc2 2012-08-24 22:07:58 +01:00
Justin Clark-Casey (justincc)
9d5e7c89d9 Pass the "attachToBackup" bool given to SceneGraph.AddNewSceneObject() down into the 3-parameter AddNewSceneObject() method instead of always hardcoding true.
This doesn't affect any core OpenSimulator code since all callers were passing true anyway
But it allows region modules to create objects that are never persisted.
2012-08-24 21:53:57 +01:00
SignpostMarv
590bf0bcc0 adding sqlite journal files to .gitignore 2012-08-24 21:53:46 +01:00
Justin Clark-Casey (justincc)
b199a2dea3 If a script state save fails for some reason on shutdown/region removal, get xengine to spit out some useful information and continue to save other script states 2012-08-24 21:53:22 +01:00
Justin Clark-Casey (justincc)
f1d4b8d83e Add an [HGAssetService] section to SQLiteStandalone.ini with the same connection string as [AssetService].
This is necessary because commit 8131a24 (Tue Mar 27 10:08:13 2012) started passing the config section name rather than hardcoding "AssetService"
This meant that the HG external-facing asset service tried to read ConnectionString from [HGAssetService] rather than [AssetService].
On SQLite, not finding this meant that it fell back to [DatabaseService], which is set for OpenSim.db rather than Asset.db.
Therefore, all external asset requests returned null.
Solution taken here is to create an [HGAssetService] section with the same ConnectionString as [AssetService].
This bug does not affect normal MySQL/MSSQL config since they use the [DatabaseService] connection string anyway.
Addresses http://opensimulator.org/mantis/view.php?id=6200, many thanks to DanBanner for identifying the exact problem commit which was very helpful.
This was a regression from OpenSimulator 0.7.3.1 which did not contain this bug.
2012-08-24 21:53:12 +01:00
Justin Clark-Casey (justincc)
0088661356 Lock disposal of separate gdi+ objects under different threads since this prevents malloc heap corruption seen under Ubuntu 10.04.1 and 11.04 - probably a libcairo issue
In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously,
the native malloc heap can become corrupted, possibly due to a double free().  This may be due to
bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX.  These problems were
seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1.  They go away if disposal is perfomed
under lock.
2012-08-24 21:53:01 +01:00
Justin Clark-Casey (justincc)
1a7e3cabc0 Fix bug in SoundModule.PlayAttachedSound() where every sound update to an avatar would base its gain calculation on the previous avatar's gain, instead of the original input gain
This is similar to commit d89faa which fixed the same kind of bug in TriggerSound()
2012-08-24 21:52:51 +01:00
Justin Clark-Casey (justincc)
132d701b3e Tighten up OpenSim.Framework.Cache locking to avoid race conditions.
This is to resolve a reported issue in http://opensimulator.org/mantis/view.php?id=6232
Here, the land management module is using OpenSim.Framework.Cache (the only code to currently do so apart from the non-default CoreAssetCache).
2012-08-24 21:52:30 +01:00
Justin Clark-Casey (justincc)
3b97241716 Add --force flag to "kick user" console command to allow bypassing of recent race condition checks.
This is to allow a second attempt to remove an avatar even if "show connections" shows them as already inactive (i.e. close has already been attempted once).
You should only attempt --force if a normal kick fails.
This is partly for diagnostics as we have seen some connections occasionally remain on lbsa plaza even if they are registered as inactive.
This is not a permanent solution and may not work anyway - the ultimate solution is to stop this problem from happening in the first place.
2012-08-24 21:52:21 +01:00
Melanie
f82d090df3 Fix llDialog responses so that they can be heard throughout the region. This now conforms to the behaviour in SL. 2012-08-24 21:52:12 +01:00
Justin Clark-Casey (justincc)
7399d3e953 When reporting a thread timeout, create a copy of the info rather than passing the original ThreadWatchdogInfo structure.
This is to avoid the possibility of misleading reporting if a watchdog update outraces an alarm.
Should address any remaining issues from http://opensimulator.org/mantis/view.php?id=6012
2012-08-24 21:51:03 +01:00
Justin Clark-Casey (justincc)
cab546ecee Add information to ThreadStackSize about possibly increasing if suffering StackOverflowExceptions during script conversion/compilation (e.g. on Windows 64-bit) 2012-08-24 21:50:49 +01:00
Justin Clark-Casey (justincc)
7dc1c7d841 minor: Make xengine debug message on script load a scripting loading message instead.
This is more useful if compilation fails due to an uncatchable exception since we know what was being compiled.
2012-08-24 21:50:40 +01:00
Robert Adams
fbff51f387 Correct an exception report in SceneObjectPart so it outputs the stack. 2012-08-24 21:50:03 +01:00
SignpostMarv
b714fb0c39 Implementing PRIM_LINK_TARGET in a non-recursive fashion 2012-08-24 21:49:44 +01:00
Justin Clark-Casey (justincc)
f37038013d Don't enable the thread watchdog until all regions are ready.
This is to avoid false positives when the machine is under heavy load whilst starting up.
2012-08-24 21:49:36 +01:00
SignpostMarv
5e98e2b7c7 adding ATTACH_*_PEC constants 2012-08-24 21:49:27 +01:00
Justin Clark-Casey (justincc)
35f8f3ff79 minor: Add Gryc Ueusp to CREDITS for commit 884edac amongst others, by request. 2012-08-24 21:48:59 +01:00
Justin Clark-Casey (justincc)
7ec8e7e025 Prevent race conditions when one thread removes an NPC SP before another thread has retreived it after checking whether the NPC exists. 2012-08-24 21:48:48 +01:00
Melanie
c6efebdd8c Release http-in URLs when llResetScript is called 2012-08-24 21:48:15 +01:00
Justin Clark-Casey (justincc)
760047abc5 Flip version to 0.7.4-rc1 2012-08-03 23:58:34 +01:00
Justin Clark-Casey (justincc)
374ebab574 Strip experimental tag from --publish option of "save oar" region console command 2012-08-03 23:54:17 +01:00
Justin Clark-Casey (justincc)
fb91ca6f1d Fix old regression that stopped saving parcel owner data in OARs.
This was working in 0.7.2 but was accidentally removed from 0.7.3.
The --publish option for "save oar" will now save oars stripped of parcel owner information as well as scene object info.
Please use the --publish option if you want to publish oars that may be later loaded by others to the same grid from which they were saved.
2012-08-03 23:49:34 +01:00
Justin Clark-Casey (justincc)
2724cf685e Fix build break. 2012-08-03 23:13:19 +01:00
Robert Adams
8730dc9d6a Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2012-08-03 15:10:55 -07:00
Robert Adams
d5cd60131f BulletSim: update DLLs and SOs 2012-08-03 15:10:00 -07:00
Robert Adams
e7ad6ed3a3 BulletSim: pass collision subscription information to the C++ code so collisions on objects that don't care are not reported up. 2012-08-03 15:09:56 -07:00
Robert Adams
ea36d4a4cf BulletSim: Add AddObjectForce to BulletSim API.
Add interface 2 enhancements to BSCharacter.
Modify AddForce and SetForce to use the new Bullet interface.
More DetailLog statements for character.
2012-08-03 15:09:52 -07:00
Justin Clark-Casey (justincc)
0e3b08fa5b Update settings loading in AvatarFactoryModule which should have been in last commit 205f2326 2012-08-03 23:09:47 +01:00
Justin Clark-Casey (justincc)
205f2326dc Consolidate PersistBakedTextures, DelayBeforeAppearanceSend and DelayBeforeAppearanceSave into [Appearance] section from [Startup] config section so that all appearance settings are in the same place and not in the startup bucket.
All these settings are in OpenSimDefaults.ini only.  If you are using them then please adjust your OpenSim.ini
2012-08-03 23:02:39 +01:00
Justin Clark-Casey (justincc)
5914270ff1 Restore SOG constructor chaining removed in recent 513b77b. This is not a functional change. 2012-08-03 22:15:06 +01:00
Justin Clark-Casey (justincc)
faffe2f2f9 Fix the recent windows compile error by putting newFont for case "R" in VectorRenderModule inside its own context, rather than disposing of the old font before using it as a prototype for the new. 2012-08-03 22:03:04 +01:00
Justin Clark-Casey (justincc)
8327e048b9 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2012-08-03 21:56:48 +01:00
Justin Clark-Casey (justincc)
789e88d8bd Move previously unadvertised SendPeriodicAppearanceUpdates setting from [Startup] to [Appearance] config section.
Add description and default of false (as before) to OpenSimDefaults.ini
If set to true, this config switch will resend avatar appearance information (a small amount of UUID data, not the baked textures themselves) to other avatars in the sim every 60 seconds.
For me, this has helped with situations where avatars appear persistently grey - the LL viewer sometimes did not appear to request assets the first time the appearance data was sent.
However, this switch will not help with other appearance failure situations (e.g. failure to bake assets).
This setting is experimental but will not have any significant impact on the simulator if turned to true.
2012-08-03 21:36:00 +01:00
SignpostMarv
5181bdae0a attempting to fix a build issue
Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2012-08-03 16:14:01 -04:00
Justin Clark-Casey (justincc)
513b77b78d refactor: rename SOG.RezzingObjectID to SOG.FromPartID to match FromFolderID, FromItemID and to reflect that it's a SOP ID rather than a SOG ID. 2012-08-03 02:26:54 +01:00
Justin Clark-Casey (justincc)
08ec18f8a3 Don't bothre setting RezzingObjectID to UUID.Zero in SOG constructor - this is already its default value as it's a struct. 2012-08-03 02:08:04 +01:00
SignpostMarv
cd9fd77e2c ImprovedTerseObjectUpdate packet does not support shape updates, thus scheduling terse updates will not (and does not) update shape information in the viewer 2012-08-03 01:55:46 +01:00
Oren Hurvitz
0588f27d18 Fixed a rare bug that caused Save OAR to fail because it thought it had timed-out
The bug manifested as follows: a large world was saved. All the assets were found. But for some unknown reason, the timeout timer was restarted. So after 1 minute it closed the Archive Writer, because it didn't receive any more assets during that minute. That caused the OAR to become corrupted because ArchiveWriteRequestExecution.Save() was still running.
2012-08-03 01:12:46 +01:00
Kevin Cozens
72075e68c7 Save membership fee to the database when a group is created. 2012-08-03 00:44:03 +01:00
Robert Adams
8b04e8a297 BulletSim: Debugging log statements added. Reduced size of updata buffer trying to find a corrupted memory problem. Update DLL and SO. 2012-08-02 16:30:23 -07:00
Justin Clark-Casey (justincc)
293d0cc629 minor: Comment out "Deleting asset" log messages for now 2012-08-03 00:25:22 +01:00
Justin Clark-Casey (justincc)
0cd698d82b Delete old blank SOGSpamTest 2012-08-03 00:23:03 +01:00
Justin Clark-Casey (justincc)
eeef9d7e99 Properly dispose of all GDI+ entities used in VectorRenderModule for dynamic textures.
The convention is that if an object implements IDiposable() the code must explicitly call Dispose() or call it via the using statement.
This may be particularly important for GDI+ objects since they encapsulate native code entities.
2012-08-03 00:00:54 +01:00
Justin Clark-Casey (justincc)
0dfccfc1d9 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2012-08-02 23:54:32 +01:00
Melanie
68406ab8f9 Initialize the Rezzing object to UUID.Zero 2012-08-02 22:34:46 +01:00
Justin Clark-Casey (justincc)
86b005de1d Add simple draw test for the VectorRenderModule 2012-08-02 22:14:09 +01:00
SignpostMarv
cd2c5843a8 reduced-complexity implementation of function to get rezzing object key
Signed-off-by: Melanie <melanie@t-data.com>
2012-08-02 22:12:36 +01:00
376 changed files with 26734 additions and 7132 deletions

8
.gitignore vendored
View File

@@ -26,9 +26,14 @@
bin/Debug/*.dll
bin/*.dll.mdb
bin/*.db
bin/*.db-journal
bin/addin-db-*
bin/*.dll
bin/OpenSim.vshost.exe.config
bin/OpenSim.32BitLaunch.vshost.exe.config
bin/OpenSim.32BitLaunch.log
UpgradeLog.XML
_UpgradeReport_Files/
bin/ScriptEngines/*-*-*-*-*
bin/ScriptEngines/*.dll
bin/ScriptEngines/*/*.dll
@@ -61,6 +66,7 @@ Examples/*.dll
OpenSim.build
OpenSim.sln
OpenSim.suo
OpenSim.userprefs
Prebuild/Prebuild.build
Prebuild/Prebuild.sln
TestResult.xml
@@ -89,3 +95,5 @@ OpenSim/Region/ScriptEngine/test-results/
OpenSim/Tests/Common/test-results/
OpenSim/Tests/test-results/
test-results/
doc/html
doc/doxygen.error.log

View File

@@ -43,10 +43,11 @@
<delete dir="${distbindir}/Prebuild"/>
<delete dir="${distbindir}/%temp%"/>
<delete dir="${distbindir}/.nant"/>
<delete dir="${distbindir}/ThirdParty"/>
<delete>
<fileset basedir="${distbindir}">
<include name="compile.bat"/>
<include name="BUILDING.txt"/>
<include name="BUILDING.md"/>
<include name="Makefile"/>
<include name="nant-color"/>
<include name="OpenSim.*"/>
@@ -132,17 +133,38 @@
</exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.capabilities.handlers.tests)==0}" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.server.handlers.tests">
<arg value="./bin/OpenSim.Server.Handlers.Tests.dll" />
</exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.server.handlers.tests)==0}" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.services.inventoryservice.tests">
<arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" />
</exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.services.inventoryservice.tests)==0}" />
<delete dir="%temp%"/>
</target>
<target name="torture" depends="build, find-nunit">
<target name="test-stress" depends="build, find-nunit">
<setenv name="MONO_THREADS_PER_CPU" value="100" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.torture">
<arg value="./bin/OpenSim.Tests.Torture.dll" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.stress">
<arg value="./bin/OpenSim.Tests.Stress.dll" />
</exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests.torture)==0}" />
<fail message="Failures reported in stress tests." unless="${int::parse(testresult.opensim.tests.stress)==0}" />
<delete dir="%temp%"/>
</target>
<target name="test-perf" depends="build, find-nunit">
<setenv name="MONO_THREADS_PER_CPU" value="100" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.performance">
<arg value="./bin/OpenSim.Tests.Performance.dll" />
</exec>
<fail message="Failures reported in performance tests." unless="${int::parse(testresult.opensim.tests.performance)==0}" />
<delete dir="%temp%"/>
</target>
@@ -224,6 +246,16 @@
<arg value="-xml=test-results/OpenSim.Capabilities.Handlers.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.server.handlers.tests">
<arg value="./bin/OpenSim.Server.Handlers.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Server.Handlers.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.services.inventoryservice.tests">
<arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Services.InventoryService.Tests.dll-Results.xml" />
</exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.servers.tests)==0}" />
@@ -234,6 +266,7 @@
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.framework.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.data.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.capabilities.handlers.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.services.inventoryservice.tests)==0}" />
</target>
<target name="doxygen">

View File

@@ -91,6 +91,7 @@ what it is today.
* Fly-Man
* Flyte Xevious
* Garmin Kawaguichi
* Gryc Ueusp
* Imaze Rhiano
* Intimidated
* Jeremy Bongio (IBM)

View File

@@ -572,7 +572,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
region.ExternalHostName = (string) requestData["external_address"];
bool persist = Convert.ToBoolean((string) requestData["persist"]);
bool persist = Convert.ToBoolean(requestData["persist"]);
if (persist)
{
// default place for region configuration files is in the
@@ -982,8 +982,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
string lastName = (string) requestData["user_lastname"];
string password = (string) requestData["user_password"];
uint regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]);
uint regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]);
uint regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
uint regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
string email = ""; // empty string for email
if (requestData.Contains("user_email"))
@@ -1180,9 +1180,9 @@ namespace OpenSim.ApplicationPlugins.RemoteController
if (requestData.ContainsKey("user_password")) password = (string) requestData["user_password"];
if (requestData.ContainsKey("start_region_x"))
regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]);
regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
if (requestData.ContainsKey("start_region_y"))
regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]);
regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
// if (requestData.ContainsKey("start_lookat_x"))
// ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]);
@@ -2381,7 +2381,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
destinationItem.Description = item.Description;
destinationItem.InvType = item.InvType;
destinationItem.CreatorId = item.CreatorId;
destinationItem.CreatorIdAsUuid = item.CreatorIdAsUuid;
destinationItem.CreatorData = item.CreatorData;
destinationItem.NextPermissions = item.NextPermissions;
destinationItem.CurrentPermissions = item.CurrentPermissions;
@@ -2436,7 +2435,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
destinationItem.Description = item.Description;
destinationItem.InvType = item.InvType;
destinationItem.CreatorId = item.CreatorId;
destinationItem.CreatorIdAsUuid = item.CreatorIdAsUuid;
destinationItem.CreatorData = item.CreatorData;
destinationItem.NextPermissions = item.NextPermissions;
destinationItem.CurrentPermissions = item.CurrentPermissions;
@@ -2549,7 +2547,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
destinationItem.Description = item.Description;
destinationItem.InvType = item.InvType;
destinationItem.CreatorId = item.CreatorId;
destinationItem.CreatorIdAsUuid = item.CreatorIdAsUuid;
destinationItem.CreatorData = item.CreatorData;
destinationItem.NextPermissions = item.NextPermissions;
destinationItem.CurrentPermissions = item.CurrentPermissions;
@@ -2855,7 +2852,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
inventoryItem.Description = GetStringAttribute(item,"desc","");
inventoryItem.InvType = GetIntegerAttribute(item,"invtype",-1);
inventoryItem.CreatorId = GetStringAttribute(item,"creatorid","");
inventoryItem.CreatorIdAsUuid = (UUID)GetStringAttribute(item,"creatoruuid","");
inventoryItem.CreatorData = GetStringAttribute(item, "creatordata", "");
inventoryItem.NextPermissions = GetUnsignedAttribute(perms, "next", 0x7fffffff);
inventoryItem.CurrentPermissions = GetUnsignedAttribute(perms,"current",0x7fffffff);

View File

@@ -312,14 +312,16 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
// Now that everything is setup we can proceed to
// add THIS agent to the HTTP server's handler list
if (!AddAgentHandler(Rest.Name,this))
{
Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
foreach (IRest handler in handlers)
{
handler.Close();
}
}
// FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
// have to be handled through the AddHttpHandler interface.
// if (!AddAgentHandler(Rest.Name,this))
// {
// Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
// foreach (IRest handler in handlers)
// {
// handler.Close();
// }
// }
}
catch (Exception e)
@@ -342,11 +344,13 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
try
{
RemoveAgentHandler(Rest.Name, this);
}
catch (KeyNotFoundException){}
// FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
// have to be handled through the AddHttpHandler interface.
// try
// {
// RemoveAgentHandler(Rest.Name, this);
// }
// catch (KeyNotFoundException){}
foreach (IRest handler in handlers)
{

View File

@@ -297,7 +297,9 @@ namespace OpenSim.ApplicationPlugins.Rest
{
if (!IsEnabled) return false;
_agents.Add(agentName, handler);
return _httpd.AddAgentHandler(agentName, handler);
// return _httpd.AddAgentHandler(agentName, handler);
return false;
}
/// <summary>
@@ -316,7 +318,7 @@ namespace OpenSim.ApplicationPlugins.Rest
if (_agents[agentName] == handler)
{
_agents.Remove(agentName);
return _httpd.RemoveAgentHandler(agentName, handler);
// return _httpd.RemoveAgentHandler(agentName, handler);
}
return false;
}
@@ -358,10 +360,10 @@ namespace OpenSim.ApplicationPlugins.Rest
_httpd.RemoveStreamHandler(h.HttpMethod, h.Path);
}
_handlers = null;
foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents)
{
_httpd.RemoveAgentHandler(h.Key, h.Value);
}
// foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents)
// {
// _httpd.RemoveAgentHandler(h.Key, h.Value);
// }
_agents = null;
}

View File

@@ -163,7 +163,7 @@ namespace OpenSim.Capabilities.Handlers
if (texture == null)
{
//m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
// m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
// Fetch locally or remotely. Misses return a 404
texture = m_assetService.Get(textureID.ToString());
@@ -197,7 +197,7 @@ namespace OpenSim.Capabilities.Handlers
}
else // it was on the cache
{
//m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
// m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
WriteTextureData(httpRequest, httpResponse, texture, format);
return true;
}
@@ -219,25 +219,54 @@ namespace OpenSim.Capabilities.Handlers
int start, end;
if (TryParseRange(range, out start, out end))
{
// Before clamping start make sure we can satisfy it in order to avoid
// sending back the last byte instead of an error status
if (start >= texture.Data.Length)
{
response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
// m_log.DebugFormat(
// "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}",
// texture.ID, start, texture.Data.Length);
// Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back
// Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations
// of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously
// received a very small texture may attempt to fetch bytes from the server past the
// range of data that it received originally. Whether this happens appears to depend on whether
// the viewer's estimation of how large a request it needs to make for certain discard levels
// (http://wiki.secondlife.com/wiki/Image_System#Discard_Level_and_Mip_Mapping), chiefly discard
// level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable
// here will cause the viewer to treat the texture as bad and never display the full resolution
// However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length));
// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
response.ContentType = texture.Metadata.ContentType;
}
else
{
// Handle the case where no second range value was given. This is equivalent to requesting
// the rest of the entity.
if (end == -1)
end = int.MaxValue;
end = Utils.Clamp(end, 0, texture.Data.Length - 1);
start = Utils.Clamp(start, 0, end);
int len = end - start + 1;
//m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
// Always return PartialContent, even if the range covered the entire data length
// We were accidentally sending back 404 before in this situation
// https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the
// entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this.
//
// We also do not want to send back OK even if the whole range was satisfiable since this causes
// HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality.
// if (end > maxEnd)
// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
// else
response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
response.ContentLength = len;
@@ -275,15 +304,43 @@ namespace OpenSim.Capabilities.Handlers
// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
}
/// <summary>
/// Parse a range header.
/// </summary>
/// <remarks>
/// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
/// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
/// Where there is no value, -1 is returned.
/// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
/// for start.</remarks>
/// <returns></returns>
/// <param name='header'></param>
/// <param name='start'>Start of the range. Undefined if this was not a number.</param>
/// <param name='end'>End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number.</param>
private bool TryParseRange(string header, out int start, out int end)
{
start = end = 0;
if (header.StartsWith("bytes="))
{
string[] rangeValues = header.Substring(6).Split('-');
if (rangeValues.Length == 2)
{
if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end))
if (!Int32.TryParse(rangeValues[0], out start))
return false;
string rawEnd = rangeValues[1];
if (rawEnd == "")
{
end = -1;
return true;
}
else if (Int32.TryParse(rawEnd, out end))
{
return true;
}
}
}

View File

@@ -42,7 +42,7 @@ using OpenSim.Tests.Common.Mock;
namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
{
[TestFixture]
public class GetTextureHandlerTests
public class GetTextureHandlerTests : OpenSimTestCase
{
[Test]
public void TestTextureNotFound()

View File

@@ -40,6 +40,11 @@ namespace OpenSim.Data
public UUID folderID;
public UUID agentID;
public UUID parentFolderID;
public XInventoryFolder Clone()
{
return (XInventoryFolder)MemberwiseClone();
}
}
public class XInventoryItem
@@ -64,6 +69,11 @@ namespace OpenSim.Data
public UUID avatarID;
public UUID parentFolderID;
public int inventoryGroupPermissions;
public XInventoryItem Clone()
{
return (XInventoryItem)MemberwiseClone();
}
}
public interface IXInventoryData
@@ -106,7 +116,22 @@ namespace OpenSim.Data
/// <returns>true if the delete was successful, false if it was not</returns>
bool DeleteItems(string[] fields, string[] vals);
bool MoveItem(string id, string newParent);
/// <summary>
/// Move an item to another folder.
/// </summary>
/// <returns>/returns>
/// <param name='id'>UUID of the item</param>
/// <param name='newParent'>UUID of the new parent folder.</param>
bool MoveItem(string id, string newParentFolderID);
/// <summary>
/// Move a folder to another folder.
/// </summary>
/// <returns>/returns>
/// <param name='id'>UUID of the item</param>
/// <param name='newParent'>UUID of the new parent folder.</param>
bool MoveFolder(string id, string newParentFolderID);
XInventoryItem[] GetActiveGestures(UUID principalID);
int GetAssetPermissions(UUID principalID, UUID assetID);
}

View File

@@ -43,12 +43,12 @@ namespace OpenSim.Data.MSSQL
// private static readonly ILog m_log = LogManager.GetLogger(
// MethodBase.GetCurrentMethod().DeclaringType);
private MSSQLGenericTableHandler<XInventoryFolder> m_Folders;
private MSSQLFolderHandler m_Folders;
private MSSQLItemHandler m_Items;
public MSSQLXInventoryData(string conn, string realm)
{
m_Folders = new MSSQLGenericTableHandler<XInventoryFolder>(
m_Folders = new MSSQLFolderHandler(
conn, "inventoryfolders", "InventoryStore");
m_Items = new MSSQLItemHandler(
conn, "inventoryitems", String.Empty);
@@ -85,6 +85,7 @@ namespace OpenSim.Data.MSSQL
{
return m_Folders.Delete(field, val);
}
public bool DeleteFolders(string[] fields, string[] vals)
{
return m_Folders.Delete(fields, vals);
@@ -94,15 +95,22 @@ namespace OpenSim.Data.MSSQL
{
return m_Items.Delete(field, val);
}
public bool DeleteItems(string[] fields, string[] vals)
{
return m_Items.Delete(fields, vals);
}
public bool MoveItem(string id, string newParent)
{
return m_Items.MoveItem(id, newParent);
}
public bool MoveFolder(string id, string newParent)
{
return m_Folders.MoveFolder(id, newParent);
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
return m_Items.GetActiveGestures(principalID);
@@ -114,7 +122,7 @@ namespace OpenSim.Data.MSSQL
}
}
public class MSSQLItemHandler : MSSQLGenericTableHandler<XInventoryItem>
public class MSSQLItemHandler : MSSQLInventoryHandler<XInventoryItem>
{
public MSSQLItemHandler(string c, string t, string m) :
base(c, t, m)
@@ -123,70 +131,163 @@ namespace OpenSim.Data.MSSQL
public bool MoveItem(string id, string newParent)
{
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
using (SqlCommand cmd = new SqlCommand())
{
XInventoryItem[] retrievedItems = Get(new string[] { "inventoryID" }, new string[] { id });
if (retrievedItems.Length == 0)
return false;
cmd.CommandText = String.Format("update {0} set parentFolderID = @ParentFolderID where inventoryID = @InventoryID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("@ParentFolderID", newParent));
cmd.Parameters.Add(m_database.CreateParameter("@InventoryID", id));
cmd.Connection = conn;
conn.Open();
return cmd.ExecuteNonQuery() == 0 ? false : true;
UUID oldParent = retrievedItems[0].parentFolderID;
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = String.Format("update {0} set parentFolderID = @ParentFolderID where inventoryID = @InventoryID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("@ParentFolderID", newParent));
cmd.Parameters.Add(m_database.CreateParameter("@InventoryID", id));
cmd.Connection = conn;
conn.Open();
if (cmd.ExecuteNonQuery() == 0)
return false;
}
}
IncrementFolderVersion(oldParent);
IncrementFolderVersion(newParent);
return true;
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = String.Format("select * from inventoryitems where avatarId = @uuid and assetType = @type and flags = 1", m_Realm);
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = String.Format("select * from inventoryitems where avatarId = @uuid and assetType = @type and flags = 1", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("@uuid", principalID.ToString()));
cmd.Parameters.Add(m_database.CreateParameter("@type", (int)AssetType.Gesture));
cmd.Connection = conn;
conn.Open();
return DoQuery(cmd);
cmd.Parameters.Add(m_database.CreateParameter("@uuid", principalID.ToString()));
cmd.Parameters.Add(m_database.CreateParameter("@type", (int)AssetType.Gesture));
cmd.Connection = conn;
conn.Open();
return DoQuery(cmd);
}
}
}
public int GetAssetPermissions(UUID principalID, UUID assetID)
{
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = String.Format("select bit_or(inventoryCurrentPermissions) as inventoryCurrentPermissions from inventoryitems where avatarID = @PrincipalID and assetID = @AssetID group by assetID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("@PrincipalID", principalID.ToString()));
cmd.Parameters.Add(m_database.CreateParameter("@AssetID", assetID.ToString()));
cmd.Connection = conn;
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
using (SqlCommand cmd = new SqlCommand())
{
int perms = 0;
if (reader.Read())
cmd.CommandText = String.Format("select bit_or(inventoryCurrentPermissions) as inventoryCurrentPermissions from inventoryitems where avatarID = @PrincipalID and assetID = @AssetID group by assetID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("@PrincipalID", principalID.ToString()));
cmd.Parameters.Add(m_database.CreateParameter("@AssetID", assetID.ToString()));
cmd.Connection = conn;
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
perms = Convert.ToInt32(reader["inventoryCurrentPermissions"]);
int perms = 0;
if (reader.Read())
{
perms = Convert.ToInt32(reader["inventoryCurrentPermissions"]);
}
return perms;
}
return perms;
}
}
}
public override bool Store(XInventoryItem item)
{
if (!base.Store(item))
return false;
string sql = "update inventoryfolders set version=version+1 where folderID = @folderID";
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
conn.Open();
cmd.Parameters.AddWithValue("@folderID", item.parentFolderID.ToString());
IncrementFolderVersion(item.parentFolderID);
return true;
}
}
public class MSSQLFolderHandler : MSSQLInventoryHandler<XInventoryFolder>
{
public MSSQLFolderHandler(string c, string t, string m) :
base(c, t, m)
{
}
public bool MoveFolder(string id, string newParentFolderID)
{
XInventoryFolder[] folders = Get(new string[] { "folderID" }, new string[] { id });
if (folders.Length == 0)
return false;
UUID oldParentFolderUUID = folders[0].parentFolderID;
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = String.Format("update {0} set parentFolderID = @ParentFolderID where folderID = @folderID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("@ParentFolderID", newParentFolderID));
cmd.Parameters.Add(m_database.CreateParameter("@folderID", id));
cmd.Connection = conn;
conn.Open();
if (cmd.ExecuteNonQuery() == 0)
return false;
}
}
IncrementFolderVersion(oldParentFolderUUID);
IncrementFolderVersion(newParentFolderID);
return true;
}
public override bool Store(XInventoryFolder folder)
{
if (!base.Store(folder))
return false;
IncrementFolderVersion(folder.parentFolderID);
return true;
}
}
public class MSSQLInventoryHandler<T> : MSSQLGenericTableHandler<T> where T: class, new()
{
public MSSQLInventoryHandler(string c, string t, string m) : base(c, t, m) {}
protected bool IncrementFolderVersion(UUID folderID)
{
return IncrementFolderVersion(folderID.ToString());
}
protected bool IncrementFolderVersion(string folderID)
{
// m_log.DebugFormat("[MYSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID);
// Util.PrintCallStack();
string sql = "update inventoryfolders set version=version+1 where folderID = ?folderID";
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
{
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
conn.Open();
cmd.Parameters.AddWithValue("@folderID", folderID);
try
{
cmd.ExecuteNonQuery();
@@ -194,9 +295,11 @@ namespace OpenSim.Data.MSSQL
catch (Exception)
{
return false;
}
}
}
}
return true;
}
}
}
}

View File

@@ -219,6 +219,8 @@ namespace OpenSim.Data.MySQL
public virtual bool Store(T row)
{
// m_log.DebugFormat("[MYSQL GENERIC TABLE HANDLER]: Store(T row) invoked");
using (MySqlCommand cmd = new MySqlCommand())
{
string query = "";
@@ -273,6 +275,10 @@ namespace OpenSim.Data.MySQL
public virtual bool Delete(string[] fields, string[] keys)
{
// m_log.DebugFormat(
// "[MYSQL GENERIC TABLE HANDLER]: Delete(string[] fields, string[] keys) invoked with {0}:{1}",
// string.Join(",", fields), string.Join(",", keys));
if (fields.Length != keys.Length)
return false;

View File

@@ -719,95 +719,99 @@ namespace OpenSim.Data.MySQL
RegionLightShareData nWP = new RegionLightShareData();
nWP.OnSave += StoreRegionWindlightSettings;
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
lock (m_dbLock)
{
dbcon.Open();
string command = "select * from `regionwindlight` where region_id = ?regionID";
using (MySqlCommand cmd = new MySqlCommand(command))
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
cmd.Connection = dbcon;
cmd.Parameters.AddWithValue("?regionID", regionUUID.ToString());
IDataReader result = ExecuteReader(cmd);
if (!result.Read())
dbcon.Open();
string command = "select * from `regionwindlight` where region_id = ?regionID";
using (MySqlCommand cmd = new MySqlCommand(command))
{
//No result, so store our default windlight profile and return it
nWP.regionID = regionUUID;
StoreRegionWindlightSettings(nWP);
return nWP;
}
else
{
nWP.regionID = DBGuid.FromDB(result["region_id"]);
nWP.waterColor.X = Convert.ToSingle(result["water_color_r"]);
nWP.waterColor.Y = Convert.ToSingle(result["water_color_g"]);
nWP.waterColor.Z = Convert.ToSingle(result["water_color_b"]);
nWP.waterFogDensityExponent = Convert.ToSingle(result["water_fog_density_exponent"]);
nWP.underwaterFogModifier = Convert.ToSingle(result["underwater_fog_modifier"]);
nWP.reflectionWaveletScale.X = Convert.ToSingle(result["reflection_wavelet_scale_1"]);
nWP.reflectionWaveletScale.Y = Convert.ToSingle(result["reflection_wavelet_scale_2"]);
nWP.reflectionWaveletScale.Z = Convert.ToSingle(result["reflection_wavelet_scale_3"]);
nWP.fresnelScale = Convert.ToSingle(result["fresnel_scale"]);
nWP.fresnelOffset = Convert.ToSingle(result["fresnel_offset"]);
nWP.refractScaleAbove = Convert.ToSingle(result["refract_scale_above"]);
nWP.refractScaleBelow = Convert.ToSingle(result["refract_scale_below"]);
nWP.blurMultiplier = Convert.ToSingle(result["blur_multiplier"]);
nWP.bigWaveDirection.X = Convert.ToSingle(result["big_wave_direction_x"]);
nWP.bigWaveDirection.Y = Convert.ToSingle(result["big_wave_direction_y"]);
nWP.littleWaveDirection.X = Convert.ToSingle(result["little_wave_direction_x"]);
nWP.littleWaveDirection.Y = Convert.ToSingle(result["little_wave_direction_y"]);
UUID.TryParse(result["normal_map_texture"].ToString(), out nWP.normalMapTexture);
nWP.horizon.X = Convert.ToSingle(result["horizon_r"]);
nWP.horizon.Y = Convert.ToSingle(result["horizon_g"]);
nWP.horizon.Z = Convert.ToSingle(result["horizon_b"]);
nWP.horizon.W = Convert.ToSingle(result["horizon_i"]);
nWP.hazeHorizon = Convert.ToSingle(result["haze_horizon"]);
nWP.blueDensity.X = Convert.ToSingle(result["blue_density_r"]);
nWP.blueDensity.Y = Convert.ToSingle(result["blue_density_g"]);
nWP.blueDensity.Z = Convert.ToSingle(result["blue_density_b"]);
nWP.blueDensity.W = Convert.ToSingle(result["blue_density_i"]);
nWP.hazeDensity = Convert.ToSingle(result["haze_density"]);
nWP.densityMultiplier = Convert.ToSingle(result["density_multiplier"]);
nWP.distanceMultiplier = Convert.ToSingle(result["distance_multiplier"]);
nWP.maxAltitude = Convert.ToUInt16(result["max_altitude"]);
nWP.sunMoonColor.X = Convert.ToSingle(result["sun_moon_color_r"]);
nWP.sunMoonColor.Y = Convert.ToSingle(result["sun_moon_color_g"]);
nWP.sunMoonColor.Z = Convert.ToSingle(result["sun_moon_color_b"]);
nWP.sunMoonColor.W = Convert.ToSingle(result["sun_moon_color_i"]);
nWP.sunMoonPosition = Convert.ToSingle(result["sun_moon_position"]);
nWP.ambient.X = Convert.ToSingle(result["ambient_r"]);
nWP.ambient.Y = Convert.ToSingle(result["ambient_g"]);
nWP.ambient.Z = Convert.ToSingle(result["ambient_b"]);
nWP.ambient.W = Convert.ToSingle(result["ambient_i"]);
nWP.eastAngle = Convert.ToSingle(result["east_angle"]);
nWP.sunGlowFocus = Convert.ToSingle(result["sun_glow_focus"]);
nWP.sunGlowSize = Convert.ToSingle(result["sun_glow_size"]);
nWP.sceneGamma = Convert.ToSingle(result["scene_gamma"]);
nWP.starBrightness = Convert.ToSingle(result["star_brightness"]);
nWP.cloudColor.X = Convert.ToSingle(result["cloud_color_r"]);
nWP.cloudColor.Y = Convert.ToSingle(result["cloud_color_g"]);
nWP.cloudColor.Z = Convert.ToSingle(result["cloud_color_b"]);
nWP.cloudColor.W = Convert.ToSingle(result["cloud_color_i"]);
nWP.cloudXYDensity.X = Convert.ToSingle(result["cloud_x"]);
nWP.cloudXYDensity.Y = Convert.ToSingle(result["cloud_y"]);
nWP.cloudXYDensity.Z = Convert.ToSingle(result["cloud_density"]);
nWP.cloudCoverage = Convert.ToSingle(result["cloud_coverage"]);
nWP.cloudScale = Convert.ToSingle(result["cloud_scale"]);
nWP.cloudDetailXYDensity.X = Convert.ToSingle(result["cloud_detail_x"]);
nWP.cloudDetailXYDensity.Y = Convert.ToSingle(result["cloud_detail_y"]);
nWP.cloudDetailXYDensity.Z = Convert.ToSingle(result["cloud_detail_density"]);
nWP.cloudScrollX = Convert.ToSingle(result["cloud_scroll_x"]);
nWP.cloudScrollXLock = Convert.ToBoolean(result["cloud_scroll_x_lock"]);
nWP.cloudScrollY = Convert.ToSingle(result["cloud_scroll_y"]);
nWP.cloudScrollYLock = Convert.ToBoolean(result["cloud_scroll_y_lock"]);
nWP.drawClassicClouds = Convert.ToBoolean(result["draw_classic_clouds"]);
nWP.valid = true;
cmd.Connection = dbcon;
cmd.Parameters.AddWithValue("?regionID", regionUUID.ToString());
IDataReader result = ExecuteReader(cmd);
if (!result.Read())
{
//No result, so store our default windlight profile and return it
nWP.regionID = regionUUID;
StoreRegionWindlightSettings(nWP);
return nWP;
}
else
{
nWP.regionID = DBGuid.FromDB(result["region_id"]);
nWP.waterColor.X = Convert.ToSingle(result["water_color_r"]);
nWP.waterColor.Y = Convert.ToSingle(result["water_color_g"]);
nWP.waterColor.Z = Convert.ToSingle(result["water_color_b"]);
nWP.waterFogDensityExponent = Convert.ToSingle(result["water_fog_density_exponent"]);
nWP.underwaterFogModifier = Convert.ToSingle(result["underwater_fog_modifier"]);
nWP.reflectionWaveletScale.X = Convert.ToSingle(result["reflection_wavelet_scale_1"]);
nWP.reflectionWaveletScale.Y = Convert.ToSingle(result["reflection_wavelet_scale_2"]);
nWP.reflectionWaveletScale.Z = Convert.ToSingle(result["reflection_wavelet_scale_3"]);
nWP.fresnelScale = Convert.ToSingle(result["fresnel_scale"]);
nWP.fresnelOffset = Convert.ToSingle(result["fresnel_offset"]);
nWP.refractScaleAbove = Convert.ToSingle(result["refract_scale_above"]);
nWP.refractScaleBelow = Convert.ToSingle(result["refract_scale_below"]);
nWP.blurMultiplier = Convert.ToSingle(result["blur_multiplier"]);
nWP.bigWaveDirection.X = Convert.ToSingle(result["big_wave_direction_x"]);
nWP.bigWaveDirection.Y = Convert.ToSingle(result["big_wave_direction_y"]);
nWP.littleWaveDirection.X = Convert.ToSingle(result["little_wave_direction_x"]);
nWP.littleWaveDirection.Y = Convert.ToSingle(result["little_wave_direction_y"]);
UUID.TryParse(result["normal_map_texture"].ToString(), out nWP.normalMapTexture);
nWP.horizon.X = Convert.ToSingle(result["horizon_r"]);
nWP.horizon.Y = Convert.ToSingle(result["horizon_g"]);
nWP.horizon.Z = Convert.ToSingle(result["horizon_b"]);
nWP.horizon.W = Convert.ToSingle(result["horizon_i"]);
nWP.hazeHorizon = Convert.ToSingle(result["haze_horizon"]);
nWP.blueDensity.X = Convert.ToSingle(result["blue_density_r"]);
nWP.blueDensity.Y = Convert.ToSingle(result["blue_density_g"]);
nWP.blueDensity.Z = Convert.ToSingle(result["blue_density_b"]);
nWP.blueDensity.W = Convert.ToSingle(result["blue_density_i"]);
nWP.hazeDensity = Convert.ToSingle(result["haze_density"]);
nWP.densityMultiplier = Convert.ToSingle(result["density_multiplier"]);
nWP.distanceMultiplier = Convert.ToSingle(result["distance_multiplier"]);
nWP.maxAltitude = Convert.ToUInt16(result["max_altitude"]);
nWP.sunMoonColor.X = Convert.ToSingle(result["sun_moon_color_r"]);
nWP.sunMoonColor.Y = Convert.ToSingle(result["sun_moon_color_g"]);
nWP.sunMoonColor.Z = Convert.ToSingle(result["sun_moon_color_b"]);
nWP.sunMoonColor.W = Convert.ToSingle(result["sun_moon_color_i"]);
nWP.sunMoonPosition = Convert.ToSingle(result["sun_moon_position"]);
nWP.ambient.X = Convert.ToSingle(result["ambient_r"]);
nWP.ambient.Y = Convert.ToSingle(result["ambient_g"]);
nWP.ambient.Z = Convert.ToSingle(result["ambient_b"]);
nWP.ambient.W = Convert.ToSingle(result["ambient_i"]);
nWP.eastAngle = Convert.ToSingle(result["east_angle"]);
nWP.sunGlowFocus = Convert.ToSingle(result["sun_glow_focus"]);
nWP.sunGlowSize = Convert.ToSingle(result["sun_glow_size"]);
nWP.sceneGamma = Convert.ToSingle(result["scene_gamma"]);
nWP.starBrightness = Convert.ToSingle(result["star_brightness"]);
nWP.cloudColor.X = Convert.ToSingle(result["cloud_color_r"]);
nWP.cloudColor.Y = Convert.ToSingle(result["cloud_color_g"]);
nWP.cloudColor.Z = Convert.ToSingle(result["cloud_color_b"]);
nWP.cloudColor.W = Convert.ToSingle(result["cloud_color_i"]);
nWP.cloudXYDensity.X = Convert.ToSingle(result["cloud_x"]);
nWP.cloudXYDensity.Y = Convert.ToSingle(result["cloud_y"]);
nWP.cloudXYDensity.Z = Convert.ToSingle(result["cloud_density"]);
nWP.cloudCoverage = Convert.ToSingle(result["cloud_coverage"]);
nWP.cloudScale = Convert.ToSingle(result["cloud_scale"]);
nWP.cloudDetailXYDensity.X = Convert.ToSingle(result["cloud_detail_x"]);
nWP.cloudDetailXYDensity.Y = Convert.ToSingle(result["cloud_detail_y"]);
nWP.cloudDetailXYDensity.Z = Convert.ToSingle(result["cloud_detail_density"]);
nWP.cloudScrollX = Convert.ToSingle(result["cloud_scroll_x"]);
nWP.cloudScrollXLock = Convert.ToBoolean(result["cloud_scroll_x_lock"]);
nWP.cloudScrollY = Convert.ToSingle(result["cloud_scroll_y"]);
nWP.cloudScrollYLock = Convert.ToBoolean(result["cloud_scroll_y_lock"]);
nWP.drawClassicClouds = Convert.ToBoolean(result["draw_classic_clouds"]);
nWP.valid = true;
}
}
}
}
return nWP;
}
@@ -853,118 +857,124 @@ namespace OpenSim.Data.MySQL
public void StoreRegionWindlightSettings(RegionLightShareData wl)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
lock (m_dbLock)
{
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
cmd.CommandText = "REPLACE INTO `regionwindlight` (`region_id`, `water_color_r`, `water_color_g`, ";
cmd.CommandText += "`water_color_b`, `water_fog_density_exponent`, `underwater_fog_modifier`, ";
cmd.CommandText += "`reflection_wavelet_scale_1`, `reflection_wavelet_scale_2`, `reflection_wavelet_scale_3`, ";
cmd.CommandText += "`fresnel_scale`, `fresnel_offset`, `refract_scale_above`, `refract_scale_below`, ";
cmd.CommandText += "`blur_multiplier`, `big_wave_direction_x`, `big_wave_direction_y`, `little_wave_direction_x`, ";
cmd.CommandText += "`little_wave_direction_y`, `normal_map_texture`, `horizon_r`, `horizon_g`, `horizon_b`, ";
cmd.CommandText += "`horizon_i`, `haze_horizon`, `blue_density_r`, `blue_density_g`, `blue_density_b`, ";
cmd.CommandText += "`blue_density_i`, `haze_density`, `density_multiplier`, `distance_multiplier`, `max_altitude`, ";
cmd.CommandText += "`sun_moon_color_r`, `sun_moon_color_g`, `sun_moon_color_b`, `sun_moon_color_i`, `sun_moon_position`, ";
cmd.CommandText += "`ambient_r`, `ambient_g`, `ambient_b`, `ambient_i`, `east_angle`, `sun_glow_focus`, `sun_glow_size`, ";
cmd.CommandText += "`scene_gamma`, `star_brightness`, `cloud_color_r`, `cloud_color_g`, `cloud_color_b`, `cloud_color_i`, ";
cmd.CommandText += "`cloud_x`, `cloud_y`, `cloud_density`, `cloud_coverage`, `cloud_scale`, `cloud_detail_x`, ";
cmd.CommandText += "`cloud_detail_y`, `cloud_detail_density`, `cloud_scroll_x`, `cloud_scroll_x_lock`, `cloud_scroll_y`, ";
cmd.CommandText += "`cloud_scroll_y_lock`, `draw_classic_clouds`) VALUES (?region_id, ?water_color_r, ";
cmd.CommandText += "?water_color_g, ?water_color_b, ?water_fog_density_exponent, ?underwater_fog_modifier, ?reflection_wavelet_scale_1, ";
cmd.CommandText += "?reflection_wavelet_scale_2, ?reflection_wavelet_scale_3, ?fresnel_scale, ?fresnel_offset, ?refract_scale_above, ";
cmd.CommandText += "?refract_scale_below, ?blur_multiplier, ?big_wave_direction_x, ?big_wave_direction_y, ?little_wave_direction_x, ";
cmd.CommandText += "?little_wave_direction_y, ?normal_map_texture, ?horizon_r, ?horizon_g, ?horizon_b, ?horizon_i, ?haze_horizon, ";
cmd.CommandText += "?blue_density_r, ?blue_density_g, ?blue_density_b, ?blue_density_i, ?haze_density, ?density_multiplier, ";
cmd.CommandText += "?distance_multiplier, ?max_altitude, ?sun_moon_color_r, ?sun_moon_color_g, ?sun_moon_color_b, ";
cmd.CommandText += "?sun_moon_color_i, ?sun_moon_position, ?ambient_r, ?ambient_g, ?ambient_b, ?ambient_i, ?east_angle, ";
cmd.CommandText += "?sun_glow_focus, ?sun_glow_size, ?scene_gamma, ?star_brightness, ?cloud_color_r, ?cloud_color_g, ";
cmd.CommandText += "?cloud_color_b, ?cloud_color_i, ?cloud_x, ?cloud_y, ?cloud_density, ?cloud_coverage, ?cloud_scale, ";
cmd.CommandText += "?cloud_detail_x, ?cloud_detail_y, ?cloud_detail_density, ?cloud_scroll_x, ?cloud_scroll_x_lock, ";
cmd.CommandText += "?cloud_scroll_y, ?cloud_scroll_y_lock, ?draw_classic_clouds)";
cmd.Parameters.AddWithValue("region_id", wl.regionID);
cmd.Parameters.AddWithValue("water_color_r", wl.waterColor.X);
cmd.Parameters.AddWithValue("water_color_g", wl.waterColor.Y);
cmd.Parameters.AddWithValue("water_color_b", wl.waterColor.Z);
cmd.Parameters.AddWithValue("water_fog_density_exponent", wl.waterFogDensityExponent);
cmd.Parameters.AddWithValue("underwater_fog_modifier", wl.underwaterFogModifier);
cmd.Parameters.AddWithValue("reflection_wavelet_scale_1", wl.reflectionWaveletScale.X);
cmd.Parameters.AddWithValue("reflection_wavelet_scale_2", wl.reflectionWaveletScale.Y);
cmd.Parameters.AddWithValue("reflection_wavelet_scale_3", wl.reflectionWaveletScale.Z);
cmd.Parameters.AddWithValue("fresnel_scale", wl.fresnelScale);
cmd.Parameters.AddWithValue("fresnel_offset", wl.fresnelOffset);
cmd.Parameters.AddWithValue("refract_scale_above", wl.refractScaleAbove);
cmd.Parameters.AddWithValue("refract_scale_below", wl.refractScaleBelow);
cmd.Parameters.AddWithValue("blur_multiplier", wl.blurMultiplier);
cmd.Parameters.AddWithValue("big_wave_direction_x", wl.bigWaveDirection.X);
cmd.Parameters.AddWithValue("big_wave_direction_y", wl.bigWaveDirection.Y);
cmd.Parameters.AddWithValue("little_wave_direction_x", wl.littleWaveDirection.X);
cmd.Parameters.AddWithValue("little_wave_direction_y", wl.littleWaveDirection.Y);
cmd.Parameters.AddWithValue("normal_map_texture", wl.normalMapTexture);
cmd.Parameters.AddWithValue("horizon_r", wl.horizon.X);
cmd.Parameters.AddWithValue("horizon_g", wl.horizon.Y);
cmd.Parameters.AddWithValue("horizon_b", wl.horizon.Z);
cmd.Parameters.AddWithValue("horizon_i", wl.horizon.W);
cmd.Parameters.AddWithValue("haze_horizon", wl.hazeHorizon);
cmd.Parameters.AddWithValue("blue_density_r", wl.blueDensity.X);
cmd.Parameters.AddWithValue("blue_density_g", wl.blueDensity.Y);
cmd.Parameters.AddWithValue("blue_density_b", wl.blueDensity.Z);
cmd.Parameters.AddWithValue("blue_density_i", wl.blueDensity.W);
cmd.Parameters.AddWithValue("haze_density", wl.hazeDensity);
cmd.Parameters.AddWithValue("density_multiplier", wl.densityMultiplier);
cmd.Parameters.AddWithValue("distance_multiplier", wl.distanceMultiplier);
cmd.Parameters.AddWithValue("max_altitude", wl.maxAltitude);
cmd.Parameters.AddWithValue("sun_moon_color_r", wl.sunMoonColor.X);
cmd.Parameters.AddWithValue("sun_moon_color_g", wl.sunMoonColor.Y);
cmd.Parameters.AddWithValue("sun_moon_color_b", wl.sunMoonColor.Z);
cmd.Parameters.AddWithValue("sun_moon_color_i", wl.sunMoonColor.W);
cmd.Parameters.AddWithValue("sun_moon_position", wl.sunMoonPosition);
cmd.Parameters.AddWithValue("ambient_r", wl.ambient.X);
cmd.Parameters.AddWithValue("ambient_g", wl.ambient.Y);
cmd.Parameters.AddWithValue("ambient_b", wl.ambient.Z);
cmd.Parameters.AddWithValue("ambient_i", wl.ambient.W);
cmd.Parameters.AddWithValue("east_angle", wl.eastAngle);
cmd.Parameters.AddWithValue("sun_glow_focus", wl.sunGlowFocus);
cmd.Parameters.AddWithValue("sun_glow_size", wl.sunGlowSize);
cmd.Parameters.AddWithValue("scene_gamma", wl.sceneGamma);
cmd.Parameters.AddWithValue("star_brightness", wl.starBrightness);
cmd.Parameters.AddWithValue("cloud_color_r", wl.cloudColor.X);
cmd.Parameters.AddWithValue("cloud_color_g", wl.cloudColor.Y);
cmd.Parameters.AddWithValue("cloud_color_b", wl.cloudColor.Z);
cmd.Parameters.AddWithValue("cloud_color_i", wl.cloudColor.W);
cmd.Parameters.AddWithValue("cloud_x", wl.cloudXYDensity.X);
cmd.Parameters.AddWithValue("cloud_y", wl.cloudXYDensity.Y);
cmd.Parameters.AddWithValue("cloud_density", wl.cloudXYDensity.Z);
cmd.Parameters.AddWithValue("cloud_coverage", wl.cloudCoverage);
cmd.Parameters.AddWithValue("cloud_scale", wl.cloudScale);
cmd.Parameters.AddWithValue("cloud_detail_x", wl.cloudDetailXYDensity.X);
cmd.Parameters.AddWithValue("cloud_detail_y", wl.cloudDetailXYDensity.Y);
cmd.Parameters.AddWithValue("cloud_detail_density", wl.cloudDetailXYDensity.Z);
cmd.Parameters.AddWithValue("cloud_scroll_x", wl.cloudScrollX);
cmd.Parameters.AddWithValue("cloud_scroll_x_lock", wl.cloudScrollXLock);
cmd.Parameters.AddWithValue("cloud_scroll_y", wl.cloudScrollY);
cmd.Parameters.AddWithValue("cloud_scroll_y_lock", wl.cloudScrollYLock);
cmd.Parameters.AddWithValue("draw_classic_clouds", wl.drawClassicClouds);
ExecuteNonQuery(cmd);
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
{
cmd.CommandText = "REPLACE INTO `regionwindlight` (`region_id`, `water_color_r`, `water_color_g`, ";
cmd.CommandText += "`water_color_b`, `water_fog_density_exponent`, `underwater_fog_modifier`, ";
cmd.CommandText += "`reflection_wavelet_scale_1`, `reflection_wavelet_scale_2`, `reflection_wavelet_scale_3`, ";
cmd.CommandText += "`fresnel_scale`, `fresnel_offset`, `refract_scale_above`, `refract_scale_below`, ";
cmd.CommandText += "`blur_multiplier`, `big_wave_direction_x`, `big_wave_direction_y`, `little_wave_direction_x`, ";
cmd.CommandText += "`little_wave_direction_y`, `normal_map_texture`, `horizon_r`, `horizon_g`, `horizon_b`, ";
cmd.CommandText += "`horizon_i`, `haze_horizon`, `blue_density_r`, `blue_density_g`, `blue_density_b`, ";
cmd.CommandText += "`blue_density_i`, `haze_density`, `density_multiplier`, `distance_multiplier`, `max_altitude`, ";
cmd.CommandText += "`sun_moon_color_r`, `sun_moon_color_g`, `sun_moon_color_b`, `sun_moon_color_i`, `sun_moon_position`, ";
cmd.CommandText += "`ambient_r`, `ambient_g`, `ambient_b`, `ambient_i`, `east_angle`, `sun_glow_focus`, `sun_glow_size`, ";
cmd.CommandText += "`scene_gamma`, `star_brightness`, `cloud_color_r`, `cloud_color_g`, `cloud_color_b`, `cloud_color_i`, ";
cmd.CommandText += "`cloud_x`, `cloud_y`, `cloud_density`, `cloud_coverage`, `cloud_scale`, `cloud_detail_x`, ";
cmd.CommandText += "`cloud_detail_y`, `cloud_detail_density`, `cloud_scroll_x`, `cloud_scroll_x_lock`, `cloud_scroll_y`, ";
cmd.CommandText += "`cloud_scroll_y_lock`, `draw_classic_clouds`) VALUES (?region_id, ?water_color_r, ";
cmd.CommandText += "?water_color_g, ?water_color_b, ?water_fog_density_exponent, ?underwater_fog_modifier, ?reflection_wavelet_scale_1, ";
cmd.CommandText += "?reflection_wavelet_scale_2, ?reflection_wavelet_scale_3, ?fresnel_scale, ?fresnel_offset, ?refract_scale_above, ";
cmd.CommandText += "?refract_scale_below, ?blur_multiplier, ?big_wave_direction_x, ?big_wave_direction_y, ?little_wave_direction_x, ";
cmd.CommandText += "?little_wave_direction_y, ?normal_map_texture, ?horizon_r, ?horizon_g, ?horizon_b, ?horizon_i, ?haze_horizon, ";
cmd.CommandText += "?blue_density_r, ?blue_density_g, ?blue_density_b, ?blue_density_i, ?haze_density, ?density_multiplier, ";
cmd.CommandText += "?distance_multiplier, ?max_altitude, ?sun_moon_color_r, ?sun_moon_color_g, ?sun_moon_color_b, ";
cmd.CommandText += "?sun_moon_color_i, ?sun_moon_position, ?ambient_r, ?ambient_g, ?ambient_b, ?ambient_i, ?east_angle, ";
cmd.CommandText += "?sun_glow_focus, ?sun_glow_size, ?scene_gamma, ?star_brightness, ?cloud_color_r, ?cloud_color_g, ";
cmd.CommandText += "?cloud_color_b, ?cloud_color_i, ?cloud_x, ?cloud_y, ?cloud_density, ?cloud_coverage, ?cloud_scale, ";
cmd.CommandText += "?cloud_detail_x, ?cloud_detail_y, ?cloud_detail_density, ?cloud_scroll_x, ?cloud_scroll_x_lock, ";
cmd.CommandText += "?cloud_scroll_y, ?cloud_scroll_y_lock, ?draw_classic_clouds)";
cmd.Parameters.AddWithValue("region_id", wl.regionID);
cmd.Parameters.AddWithValue("water_color_r", wl.waterColor.X);
cmd.Parameters.AddWithValue("water_color_g", wl.waterColor.Y);
cmd.Parameters.AddWithValue("water_color_b", wl.waterColor.Z);
cmd.Parameters.AddWithValue("water_fog_density_exponent", wl.waterFogDensityExponent);
cmd.Parameters.AddWithValue("underwater_fog_modifier", wl.underwaterFogModifier);
cmd.Parameters.AddWithValue("reflection_wavelet_scale_1", wl.reflectionWaveletScale.X);
cmd.Parameters.AddWithValue("reflection_wavelet_scale_2", wl.reflectionWaveletScale.Y);
cmd.Parameters.AddWithValue("reflection_wavelet_scale_3", wl.reflectionWaveletScale.Z);
cmd.Parameters.AddWithValue("fresnel_scale", wl.fresnelScale);
cmd.Parameters.AddWithValue("fresnel_offset", wl.fresnelOffset);
cmd.Parameters.AddWithValue("refract_scale_above", wl.refractScaleAbove);
cmd.Parameters.AddWithValue("refract_scale_below", wl.refractScaleBelow);
cmd.Parameters.AddWithValue("blur_multiplier", wl.blurMultiplier);
cmd.Parameters.AddWithValue("big_wave_direction_x", wl.bigWaveDirection.X);
cmd.Parameters.AddWithValue("big_wave_direction_y", wl.bigWaveDirection.Y);
cmd.Parameters.AddWithValue("little_wave_direction_x", wl.littleWaveDirection.X);
cmd.Parameters.AddWithValue("little_wave_direction_y", wl.littleWaveDirection.Y);
cmd.Parameters.AddWithValue("normal_map_texture", wl.normalMapTexture);
cmd.Parameters.AddWithValue("horizon_r", wl.horizon.X);
cmd.Parameters.AddWithValue("horizon_g", wl.horizon.Y);
cmd.Parameters.AddWithValue("horizon_b", wl.horizon.Z);
cmd.Parameters.AddWithValue("horizon_i", wl.horizon.W);
cmd.Parameters.AddWithValue("haze_horizon", wl.hazeHorizon);
cmd.Parameters.AddWithValue("blue_density_r", wl.blueDensity.X);
cmd.Parameters.AddWithValue("blue_density_g", wl.blueDensity.Y);
cmd.Parameters.AddWithValue("blue_density_b", wl.blueDensity.Z);
cmd.Parameters.AddWithValue("blue_density_i", wl.blueDensity.W);
cmd.Parameters.AddWithValue("haze_density", wl.hazeDensity);
cmd.Parameters.AddWithValue("density_multiplier", wl.densityMultiplier);
cmd.Parameters.AddWithValue("distance_multiplier", wl.distanceMultiplier);
cmd.Parameters.AddWithValue("max_altitude", wl.maxAltitude);
cmd.Parameters.AddWithValue("sun_moon_color_r", wl.sunMoonColor.X);
cmd.Parameters.AddWithValue("sun_moon_color_g", wl.sunMoonColor.Y);
cmd.Parameters.AddWithValue("sun_moon_color_b", wl.sunMoonColor.Z);
cmd.Parameters.AddWithValue("sun_moon_color_i", wl.sunMoonColor.W);
cmd.Parameters.AddWithValue("sun_moon_position", wl.sunMoonPosition);
cmd.Parameters.AddWithValue("ambient_r", wl.ambient.X);
cmd.Parameters.AddWithValue("ambient_g", wl.ambient.Y);
cmd.Parameters.AddWithValue("ambient_b", wl.ambient.Z);
cmd.Parameters.AddWithValue("ambient_i", wl.ambient.W);
cmd.Parameters.AddWithValue("east_angle", wl.eastAngle);
cmd.Parameters.AddWithValue("sun_glow_focus", wl.sunGlowFocus);
cmd.Parameters.AddWithValue("sun_glow_size", wl.sunGlowSize);
cmd.Parameters.AddWithValue("scene_gamma", wl.sceneGamma);
cmd.Parameters.AddWithValue("star_brightness", wl.starBrightness);
cmd.Parameters.AddWithValue("cloud_color_r", wl.cloudColor.X);
cmd.Parameters.AddWithValue("cloud_color_g", wl.cloudColor.Y);
cmd.Parameters.AddWithValue("cloud_color_b", wl.cloudColor.Z);
cmd.Parameters.AddWithValue("cloud_color_i", wl.cloudColor.W);
cmd.Parameters.AddWithValue("cloud_x", wl.cloudXYDensity.X);
cmd.Parameters.AddWithValue("cloud_y", wl.cloudXYDensity.Y);
cmd.Parameters.AddWithValue("cloud_density", wl.cloudXYDensity.Z);
cmd.Parameters.AddWithValue("cloud_coverage", wl.cloudCoverage);
cmd.Parameters.AddWithValue("cloud_scale", wl.cloudScale);
cmd.Parameters.AddWithValue("cloud_detail_x", wl.cloudDetailXYDensity.X);
cmd.Parameters.AddWithValue("cloud_detail_y", wl.cloudDetailXYDensity.Y);
cmd.Parameters.AddWithValue("cloud_detail_density", wl.cloudDetailXYDensity.Z);
cmd.Parameters.AddWithValue("cloud_scroll_x", wl.cloudScrollX);
cmd.Parameters.AddWithValue("cloud_scroll_x_lock", wl.cloudScrollXLock);
cmd.Parameters.AddWithValue("cloud_scroll_y", wl.cloudScrollY);
cmd.Parameters.AddWithValue("cloud_scroll_y_lock", wl.cloudScrollYLock);
cmd.Parameters.AddWithValue("draw_classic_clouds", wl.drawClassicClouds);
ExecuteNonQuery(cmd);
}
}
}
}
public void RemoveRegionWindlightSettings(UUID regionID)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
lock (m_dbLock)
{
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
cmd.CommandText = "delete from `regionwindlight` where `region_id`=?regionID";
cmd.Parameters.AddWithValue("?regionID", regionID.ToString());
ExecuteNonQuery(cmd);
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
{
cmd.CommandText = "delete from `regionwindlight` where `region_id`=?regionID";
cmd.Parameters.AddWithValue("?regionID", regionID.ToString());
ExecuteNonQuery(cmd);
}
}
}
}
@@ -972,26 +982,29 @@ namespace OpenSim.Data.MySQL
#region RegionEnvironmentSettings
public string LoadRegionEnvironmentSettings(UUID regionUUID)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
lock (m_dbLock)
{
dbcon.Open();
string command = "select * from `regionenvironment` where region_id = ?region_id";
using (MySqlCommand cmd = new MySqlCommand(command))
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
cmd.Connection = dbcon;
cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString());
IDataReader result = ExecuteReader(cmd);
if (!result.Read())
dbcon.Open();
string command = "select * from `regionenvironment` where region_id = ?region_id";
using (MySqlCommand cmd = new MySqlCommand(command))
{
return String.Empty;
}
else
{
return Convert.ToString(result["llsd_settings"]);
cmd.Connection = dbcon;
cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString());
IDataReader result = ExecuteReader(cmd);
if (!result.Read())
{
return String.Empty;
}
else
{
return Convert.ToString(result["llsd_settings"]);
}
}
}
}
@@ -999,33 +1012,39 @@ namespace OpenSim.Data.MySQL
public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
lock (m_dbLock)
{
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
cmd.CommandText = "REPLACE INTO `regionenvironment` (`region_id`, `llsd_settings`) VALUES (?region_id, ?llsd_settings)";
cmd.Parameters.AddWithValue("region_id", regionUUID);
cmd.Parameters.AddWithValue("llsd_settings", settings);
ExecuteNonQuery(cmd);
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
{
cmd.CommandText = "REPLACE INTO `regionenvironment` (`region_id`, `llsd_settings`) VALUES (?region_id, ?llsd_settings)";
cmd.Parameters.AddWithValue("region_id", regionUUID);
cmd.Parameters.AddWithValue("llsd_settings", settings);
ExecuteNonQuery(cmd);
}
}
}
}
public void RemoveRegionEnvironmentSettings(UUID regionUUID)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
lock (m_dbLock)
{
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
cmd.CommandText = "delete from `regionenvironment` where region_id = ?region_id";
cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString());
ExecuteNonQuery(cmd);
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
{
cmd.CommandText = "delete from `regionenvironment` where region_id = ?region_id";
cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString());
ExecuteNonQuery(cmd);
}
}
}
}

View File

@@ -26,9 +26,10 @@
*/
using System;
using System.Data;
using System.Reflection;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using log4net;
using MySql.Data.MySqlClient;
using OpenMetaverse;
@@ -41,12 +42,12 @@ namespace OpenSim.Data.MySQL
/// </summary>
public class MySQLXInventoryData : IXInventoryData
{
private MySQLGenericTableHandler<XInventoryFolder> m_Folders;
private MySqlFolderHandler m_Folders;
private MySqlItemHandler m_Items;
public MySQLXInventoryData(string conn, string realm)
{
m_Folders = new MySQLGenericTableHandler<XInventoryFolder>(
m_Folders = new MySqlFolderHandler(
conn, "inventoryfolders", "InventoryStore");
m_Items = new MySqlItemHandler(
conn, "inventoryitems", String.Empty);
@@ -105,6 +106,11 @@ namespace OpenSim.Data.MySQL
return m_Items.MoveItem(id, newParent);
}
public bool MoveFolder(string id, string newParent)
{
return m_Folders.MoveFolder(id, newParent);
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
return m_Items.GetActiveGestures(principalID);
@@ -116,24 +122,71 @@ namespace OpenSim.Data.MySQL
}
}
public class MySqlItemHandler : MySQLGenericTableHandler<XInventoryItem>
public class MySqlItemHandler : MySqlInventoryHandler<XInventoryItem>
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public MySqlItemHandler(string c, string t, string m) :
base(c, t, m)
{
}
public override bool Delete(string field, string val)
{
XInventoryItem[] retrievedItems = Get(new string[] { field }, new string[] { val });
if (retrievedItems.Length == 0)
return false;
if (!base.Delete(field, val))
return false;
// Don't increment folder version here since Delete(string, string) calls Delete(string[], string[])
// IncrementFolderVersion(retrievedItems[0].parentFolderID);
return true;
}
public override bool Delete(string[] fields, string[] vals)
{
XInventoryItem[] retrievedItems = Get(fields, vals);
if (retrievedItems.Length == 0)
return false;
if (!base.Delete(fields, vals))
return false;
HashSet<UUID> deletedItemFolderUUIDs = new HashSet<UUID>();
Array.ForEach<XInventoryItem>(retrievedItems, i => deletedItemFolderUUIDs.Add(i.parentFolderID));
foreach (UUID deletedItemFolderUUID in deletedItemFolderUUIDs)
IncrementFolderVersion(deletedItemFolderUUID);
return true;
}
public bool MoveItem(string id, string newParent)
{
XInventoryItem[] retrievedItems = Get(new string[] { "inventoryID" }, new string[] { id });
if (retrievedItems.Length == 0)
return false;
UUID oldParent = retrievedItems[0].parentFolderID;
using (MySqlCommand cmd = new MySqlCommand())
{
cmd.CommandText = String.Format("update {0} set parentFolderID = ?ParentFolderID where inventoryID = ?InventoryID", m_Realm);
cmd.Parameters.AddWithValue("?ParentFolderID", newParent);
cmd.Parameters.AddWithValue("?InventoryID", id);
return ExecuteNonQuery(cmd) == 0 ? false : true;
if (ExecuteNonQuery(cmd) == 0)
return false;
}
IncrementFolderVersion(oldParent);
IncrementFolderVersion(newParent);
return true;
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
@@ -184,6 +237,73 @@ namespace OpenSim.Data.MySQL
if (!base.Store(item))
return false;
IncrementFolderVersion(item.parentFolderID);
return true;
}
}
public class MySqlFolderHandler : MySqlInventoryHandler<XInventoryFolder>
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public MySqlFolderHandler(string c, string t, string m) :
base(c, t, m)
{
}
public bool MoveFolder(string id, string newParentFolderID)
{
XInventoryFolder[] folders = Get(new string[] { "folderID" }, new string[] { id });
if (folders.Length == 0)
return false;
UUID oldParentFolderUUID = folders[0].parentFolderID;
using (MySqlCommand cmd = new MySqlCommand())
{
cmd.CommandText
= String.Format(
"update {0} set parentFolderID = ?ParentFolderID where folderID = ?folderID", m_Realm);
cmd.Parameters.AddWithValue("?ParentFolderID", newParentFolderID);
cmd.Parameters.AddWithValue("?folderID", id);
if (ExecuteNonQuery(cmd) == 0)
return false;
}
IncrementFolderVersion(oldParentFolderUUID);
IncrementFolderVersion(newParentFolderID);
return true;
}
public override bool Store(XInventoryFolder folder)
{
if (!base.Store(folder))
return false;
IncrementFolderVersion(folder.parentFolderID);
return true;
}
}
public class MySqlInventoryHandler<T> : MySQLGenericTableHandler<T> where T: class, new()
{
public MySqlInventoryHandler(string c, string t, string m) : base(c, t, m) {}
protected bool IncrementFolderVersion(UUID folderID)
{
return IncrementFolderVersion(folderID.ToString());
}
protected bool IncrementFolderVersion(string folderID)
{
// m_log.DebugFormat("[MYSQL FOLDER HANDLER]: Incrementing version on folder {0}", folderID);
// Util.PrintCallStack();
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
@@ -193,7 +313,7 @@ namespace OpenSim.Data.MySQL
cmd.Connection = dbcon;
cmd.CommandText = String.Format("update inventoryfolders set version=version+1 where folderID = ?folderID");
cmd.Parameters.AddWithValue("?folderID", item.parentFolderID.ToString());
cmd.Parameters.AddWithValue("?folderID", folderID);
try
{
@@ -205,9 +325,11 @@ namespace OpenSim.Data.MySQL
}
cmd.Dispose();
}
dbcon.Close();
}
return true;
}
}
}
}

View File

@@ -112,11 +112,14 @@ namespace OpenSim.Data.Null
// Find region data
List<RegionData> ret = new List<RegionData>();
foreach (RegionData r in m_regionData.Values)
lock (m_regionData)
{
// m_log.DebugFormat("[NULL REGION DATA]: comparing {0} to {1}", cleanName, r.RegionName.ToLower());
foreach (RegionData r in m_regionData.Values)
{
// m_log.DebugFormat("[NULL REGION DATA]: comparing {0} to {1}", cleanName, r.RegionName.ToLower());
if (queryMatch(r.RegionName.ToLower()))
ret.Add(r);
}
}
if (ret.Count > 0)
@@ -132,10 +135,13 @@ namespace OpenSim.Data.Null
List<RegionData> ret = new List<RegionData>();
foreach (RegionData r in m_regionData.Values)
lock (m_regionData)
{
if (r.posX == posX && r.posY == posY)
ret.Add(r);
foreach (RegionData r in m_regionData.Values)
{
if (r.posX == posX && r.posY == posY)
ret.Add(r);
}
}
if (ret.Count > 0)
@@ -149,8 +155,11 @@ namespace OpenSim.Data.Null
if (m_useStaticInstance && Instance != this)
return Instance.Get(regionID, scopeID);
if (m_regionData.ContainsKey(regionID))
return m_regionData[regionID];
lock (m_regionData)
{
if (m_regionData.ContainsKey(regionID))
return m_regionData[regionID];
}
return null;
}
@@ -162,10 +171,13 @@ namespace OpenSim.Data.Null
List<RegionData> ret = new List<RegionData>();
foreach (RegionData r in m_regionData.Values)
lock (m_regionData)
{
if (r.posX >= startX && r.posX <= endX && r.posY >= startY && r.posY <= endY)
ret.Add(r);
foreach (RegionData r in m_regionData.Values)
{
if (r.posX >= startX && r.posX <= endX && r.posY >= startY && r.posY <= endY)
ret.Add(r);
}
}
return ret;
@@ -179,7 +191,10 @@ namespace OpenSim.Data.Null
// m_log.DebugFormat(
// "[NULL REGION DATA]: Storing region {0} {1}, scope {2}", data.RegionName, data.RegionID, data.ScopeID);
m_regionData[data.RegionID] = data;
lock (m_regionData)
{
m_regionData[data.RegionID] = data;
}
return true;
}
@@ -189,10 +204,13 @@ namespace OpenSim.Data.Null
if (m_useStaticInstance && Instance != this)
return Instance.SetDataItem(regionID, item, value);
if (!m_regionData.ContainsKey(regionID))
return false;
lock (m_regionData)
{
if (!m_regionData.ContainsKey(regionID))
return false;
m_regionData[regionID].Data[item] = value;
m_regionData[regionID].Data[item] = value;
}
return true;
}
@@ -204,10 +222,13 @@ namespace OpenSim.Data.Null
// m_log.DebugFormat("[NULL REGION DATA]: Deleting region {0}", regionID);
if (!m_regionData.ContainsKey(regionID))
return false;
lock (m_regionData)
{
if (!m_regionData.ContainsKey(regionID))
return false;
m_regionData.Remove(regionID);
m_regionData.Remove(regionID);
}
return true;
}
@@ -237,10 +258,13 @@ namespace OpenSim.Data.Null
List<RegionData> ret = new List<RegionData>();
foreach (RegionData r in m_regionData.Values)
lock (m_regionData)
{
if ((Convert.ToInt32(r.Data["flags"]) & regionFlags) != 0)
ret.Add(r);
foreach (RegionData r in m_regionData.Values)
{
if ((Convert.ToInt32(r.Data["flags"]) & regionFlags) != 0)
ret.Add(r);
}
}
return ret;

View File

@@ -202,7 +202,8 @@ namespace OpenSim.Data.SQLite
/// <returns>True if exist, or false.</returns>
override public bool ExistsAsset(UUID uuid)
{
lock (this) {
lock (this)
{
using (SqliteCommand cmd = new SqliteCommand(SelectAssetSQL, m_conn))
{
cmd.Parameters.Add(new SqliteParameter(":UUID", uuid.ToString()));
@@ -353,12 +354,13 @@ namespace OpenSim.Data.SQLite
{
lock (this)
{
using (SqliteCommand cmd = new SqliteCommand(DeleteAssetSQL, m_conn))
{
cmd.Parameters.Add(new SqliteParameter(":UUID", uuid.ToString()));
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = new SqliteCommand(DeleteAssetSQL, m_conn))
{
cmd.Parameters.Add(new SqliteParameter(":UUID", uuid.ToString()));
cmd.ExecuteNonQuery();
}
}
return true;
}

View File

@@ -82,11 +82,14 @@ namespace OpenSim.Data.SQLite
{
AuthenticationData ret = new AuthenticationData();
ret.Data = new Dictionary<string, object>();
IDataReader result;
SqliteCommand cmd = new SqliteCommand("select * from `" + m_Realm + "` where UUID = :PrincipalID");
cmd.Parameters.Add(new SqliteParameter(":PrincipalID", principalID.ToString()));
using (SqliteCommand cmd = new SqliteCommand("select * from `" + m_Realm + "` where UUID = :PrincipalID"))
{
cmd.Parameters.Add(new SqliteParameter(":PrincipalID", principalID.ToString()));
IDataReader result = ExecuteReader(cmd, m_Connection);
result = ExecuteReader(cmd, m_Connection);
}
try
{
@@ -121,10 +124,6 @@ namespace OpenSim.Data.SQLite
catch
{
}
finally
{
//CloseCommand(cmd);
}
return null;
}
@@ -140,84 +139,81 @@ namespace OpenSim.Data.SQLite
foreach (object o in data.Data.Values)
values[i++] = o.ToString();
SqliteCommand cmd = new SqliteCommand();
if (Get(data.PrincipalID) != null)
using (SqliteCommand cmd = new SqliteCommand())
{
string update = "update `" + m_Realm + "` set ";
bool first = true;
foreach (string field in fields)
if (Get(data.PrincipalID) != null)
{
if (!first)
update += ", ";
update += "`" + field + "` = :" + field;
cmd.Parameters.Add(new SqliteParameter(":" + field, data.Data[field]));
first = false;
}
update += " where UUID = :UUID";
cmd.Parameters.Add(new SqliteParameter(":UUID", data.PrincipalID.ToString()));
cmd.CommandText = update;
try
{
if (ExecuteNonQuery(cmd, m_Connection) < 1)
string update = "update `" + m_Realm + "` set ";
bool first = true;
foreach (string field in fields)
{
if (!first)
update += ", ";
update += "`" + field + "` = :" + field;
cmd.Parameters.Add(new SqliteParameter(":" + field, data.Data[field]));
first = false;
}
update += " where UUID = :UUID";
cmd.Parameters.Add(new SqliteParameter(":UUID", data.PrincipalID.ToString()));
cmd.CommandText = update;
try
{
if (ExecuteNonQuery(cmd, m_Connection) < 1)
{
//CloseCommand(cmd);
return false;
}
}
catch (Exception e)
{
m_log.Error("[SQLITE]: Exception storing authentication data", e);
//CloseCommand(cmd);
return false;
}
}
catch (Exception e)
else
{
m_log.Error("[SQLITE]: Exception storing authentication data", e);
//CloseCommand(cmd);
return false;
}
}
string insert = "insert into `" + m_Realm + "` (`UUID`, `" +
String.Join("`, `", fields) +
"`) values (:UUID, :" + String.Join(", :", fields) + ")";
else
{
string insert = "insert into `" + m_Realm + "` (`UUID`, `" +
String.Join("`, `", fields) +
"`) values (:UUID, :" + String.Join(", :", fields) + ")";
cmd.Parameters.Add(new SqliteParameter(":UUID", data.PrincipalID.ToString()));
foreach (string field in fields)
cmd.Parameters.Add(new SqliteParameter(":" + field, data.Data[field]));
cmd.Parameters.Add(new SqliteParameter(":UUID", data.PrincipalID.ToString()));
foreach (string field in fields)
cmd.Parameters.Add(new SqliteParameter(":" + field, data.Data[field]));
cmd.CommandText = insert;
cmd.CommandText = insert;
try
{
if (ExecuteNonQuery(cmd, m_Connection) < 1)
try
{
//CloseCommand(cmd);
if (ExecuteNonQuery(cmd, m_Connection) < 1)
{
return false;
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return false;
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
//CloseCommand(cmd);
return false;
}
}
//CloseCommand(cmd);
return true;
}
public bool SetDataItem(UUID principalID, string item, string value)
{
SqliteCommand cmd = new SqliteCommand("update `" + m_Realm +
"` set `" + item + "` = " + value + " where UUID = '" + principalID.ToString() + "'");
if (ExecuteNonQuery(cmd, m_Connection) > 0)
return true;
using (SqliteCommand cmd = new SqliteCommand("update `" + m_Realm +
"` set `" + item + "` = " + value + " where UUID = '" + principalID.ToString() + "'"))
{
if (ExecuteNonQuery(cmd, m_Connection) > 0)
return true;
}
return false;
}
@@ -227,16 +223,13 @@ namespace OpenSim.Data.SQLite
if (System.Environment.TickCount - m_LastExpire > 30000)
DoExpire();
SqliteCommand cmd = new SqliteCommand("insert into tokens (UUID, token, validity) values ('" + principalID.ToString() +
"', '" + token + "', datetime('now', 'localtime', '+" + lifetime.ToString() + " minutes'))");
if (ExecuteNonQuery(cmd, m_Connection) > 0)
using (SqliteCommand cmd = new SqliteCommand("insert into tokens (UUID, token, validity) values ('" + principalID.ToString() +
"', '" + token + "', datetime('now', 'localtime', '+" + lifetime.ToString() + " minutes'))"))
{
cmd.Dispose();
return true;
if (ExecuteNonQuery(cmd, m_Connection) > 0)
return true;
}
cmd.Dispose();
return false;
}
@@ -245,28 +238,22 @@ namespace OpenSim.Data.SQLite
if (System.Environment.TickCount - m_LastExpire > 30000)
DoExpire();
SqliteCommand cmd = new SqliteCommand("update tokens set validity = datetime('now', 'localtime', '+" + lifetime.ToString() +
" minutes') where UUID = '" + principalID.ToString() + "' and token = '" + token + "' and validity > datetime('now', 'localtime')");
if (ExecuteNonQuery(cmd, m_Connection) > 0)
using (SqliteCommand cmd = new SqliteCommand("update tokens set validity = datetime('now', 'localtime', '+" + lifetime.ToString() +
" minutes') where UUID = '" + principalID.ToString() + "' and token = '" + token + "' and validity > datetime('now', 'localtime')"))
{
cmd.Dispose();
return true;
if (ExecuteNonQuery(cmd, m_Connection) > 0)
return true;
}
cmd.Dispose();
return false;
}
private void DoExpire()
{
SqliteCommand cmd = new SqliteCommand("delete from tokens where validity < datetime('now', 'localtime')");
ExecuteNonQuery(cmd, m_Connection);
cmd.Dispose();
using (SqliteCommand cmd = new SqliteCommand("delete from tokens where validity < datetime('now', 'localtime')"))
ExecuteNonQuery(cmd, m_Connection);
m_LastExpire = System.Environment.TickCount;
}
}
}
}

View File

@@ -56,23 +56,17 @@ namespace OpenSim.Data.SQLite
public bool Delete(UUID principalID, string name)
{
SqliteCommand cmd = new SqliteCommand();
cmd.CommandText = String.Format("delete from {0} where `PrincipalID` = :PrincipalID and `Name` = :Name", m_Realm);
cmd.Parameters.AddWithValue(":PrincipalID", principalID.ToString());
cmd.Parameters.AddWithValue(":Name", name);
try
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.CommandText = String.Format("delete from {0} where `PrincipalID` = :PrincipalID and `Name` = :Name", m_Realm);
cmd.Parameters.AddWithValue(":PrincipalID", principalID.ToString());
cmd.Parameters.AddWithValue(":Name", name);
if (ExecuteNonQuery(cmd, m_Connection) > 0)
return true;
}
return false;
}
finally
{
//CloseCommand(cmd);
}
return false;
}
}
}
}

View File

@@ -104,12 +104,13 @@ namespace OpenSim.Data.SQLite
{
string sql = "select estate_settings."+String.Join(",estate_settings.", FieldList)+" from estate_map left join estate_settings on estate_map.EstateID = estate_settings.EstateID where estate_settings.EstateID is not null and RegionID = :RegionID";
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":RegionID", regionID.ToString());
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":RegionID", regionID.ToString());
return DoLoad(cmd, regionID, create);
return DoLoad(cmd, regionID, create);
}
}
private EstateSettings DoLoad(SqliteCommand cmd, UUID regionID, bool create)
@@ -186,38 +187,40 @@ namespace OpenSim.Data.SQLite
{
List<string> names = new List<string>(FieldList);
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
IDataReader r = null;
names.Remove("EstateID");
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
names.Remove("EstateID");
string sql = "insert into estate_settings ("+String.Join(",", names.ToArray())+") values ( :"+String.Join(", :", names.ToArray())+")";
string sql = "insert into estate_settings ("+String.Join(",", names.ToArray())+") values ( :"+String.Join(", :", names.ToArray())+")";
cmd.CommandText = sql;
cmd.Parameters.Clear();
cmd.CommandText = sql;
cmd.Parameters.Clear();
foreach (string name in FieldList)
{
if (m_FieldMap[name].GetValue(es) is bool)
foreach (string name in FieldList)
{
if ((bool)m_FieldMap[name].GetValue(es))
cmd.Parameters.AddWithValue(":"+name, "1");
if (m_FieldMap[name].GetValue(es) is bool)
{
if ((bool)m_FieldMap[name].GetValue(es))
cmd.Parameters.AddWithValue(":"+name, "1");
else
cmd.Parameters.AddWithValue(":"+name, "0");
}
else
cmd.Parameters.AddWithValue(":"+name, "0");
}
else
{
cmd.Parameters.AddWithValue(":"+name, m_FieldMap[name].GetValue(es).ToString());
{
cmd.Parameters.AddWithValue(":"+name, m_FieldMap[name].GetValue(es).ToString());
}
}
cmd.ExecuteNonQuery();
cmd.CommandText = "select LAST_INSERT_ROWID() as id";
cmd.Parameters.Clear();
r = cmd.ExecuteReader();
}
cmd.ExecuteNonQuery();
cmd.CommandText = "select LAST_INSERT_ROWID() as id";
cmd.Parameters.Clear();
r = cmd.ExecuteReader();
r.Read();
es.EstateID = Convert.ToUInt32(r["id"]);
@@ -239,26 +242,27 @@ namespace OpenSim.Data.SQLite
string sql = "update estate_settings set "+String.Join(", ", terms.ToArray())+" where EstateID = :EstateID";
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
cmd.CommandText = sql;
foreach (string name in FieldList)
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
if (m_FieldMap[name].GetValue(es) is bool)
{
if ((bool)m_FieldMap[name].GetValue(es))
cmd.Parameters.AddWithValue(":"+name, "1");
else
cmd.Parameters.AddWithValue(":"+name, "0");
}
else
{
cmd.Parameters.AddWithValue(":"+name, m_FieldMap[name].GetValue(es).ToString());
}
}
cmd.CommandText = sql;
cmd.ExecuteNonQuery();
foreach (string name in FieldList)
{
if (m_FieldMap[name].GetValue(es) is bool)
{
if ((bool)m_FieldMap[name].GetValue(es))
cmd.Parameters.AddWithValue(":"+name, "1");
else
cmd.Parameters.AddWithValue(":"+name, "0");
}
else
{
cmd.Parameters.AddWithValue(":"+name, m_FieldMap[name].GetValue(es).ToString());
}
}
cmd.ExecuteNonQuery();
}
SaveBanList(es);
SaveUUIDList(es.EstateID, "estate_managers", es.EstateManagers);
@@ -270,12 +274,15 @@ namespace OpenSim.Data.SQLite
{
es.ClearBans();
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
IDataReader r;
cmd.CommandText = "select bannedUUID from estateban where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", es.EstateID);
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = "select bannedUUID from estateban where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", es.EstateID);
IDataReader r = cmd.ExecuteReader();
r = cmd.ExecuteReader();
}
while (r.Read())
{
@@ -294,60 +301,64 @@ namespace OpenSim.Data.SQLite
private void SaveBanList(EstateSettings es)
{
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
cmd.CommandText = "delete from estateban where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", es.EstateID.ToString());
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
cmd.CommandText = "insert into estateban (EstateID, bannedUUID, bannedIp, bannedIpHostMask, bannedNameMask) values ( :EstateID, :bannedUUID, '', '', '' )";
foreach (EstateBan b in es.EstateBans)
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = "delete from estateban where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", es.EstateID.ToString());
cmd.Parameters.AddWithValue(":bannedUUID", b.BannedUserID.ToString());
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
cmd.CommandText = "insert into estateban (EstateID, bannedUUID, bannedIp, bannedIpHostMask, bannedNameMask) values ( :EstateID, :bannedUUID, '', '', '' )";
foreach (EstateBan b in es.EstateBans)
{
cmd.Parameters.AddWithValue(":EstateID", es.EstateID.ToString());
cmd.Parameters.AddWithValue(":bannedUUID", b.BannedUserID.ToString());
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
}
}
void SaveUUIDList(uint EstateID, string table, UUID[] data)
{
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
cmd.CommandText = "delete from "+table+" where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", EstateID.ToString());
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
cmd.CommandText = "insert into "+table+" (EstateID, uuid) values ( :EstateID, :uuid )";
foreach (UUID uuid in data)
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = "delete from "+table+" where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", EstateID.ToString());
cmd.Parameters.AddWithValue(":uuid", uuid.ToString());
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
cmd.CommandText = "insert into "+table+" (EstateID, uuid) values ( :EstateID, :uuid )";
foreach (UUID uuid in data)
{
cmd.Parameters.AddWithValue(":EstateID", EstateID.ToString());
cmd.Parameters.AddWithValue(":uuid", uuid.ToString());
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
}
}
UUID[] LoadUUIDList(uint EstateID, string table)
{
List<UUID> uuids = new List<UUID>();
IDataReader r;
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = "select uuid from "+table+" where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", EstateID);
cmd.CommandText = "select uuid from "+table+" where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", EstateID);
IDataReader r = cmd.ExecuteReader();
r = cmd.ExecuteReader();
}
while (r.Read())
{
@@ -367,12 +378,13 @@ namespace OpenSim.Data.SQLite
{
string sql = "select estate_settings."+String.Join(",estate_settings.", FieldList)+" from estate_settings where estate_settings.EstateID = :EstateID";
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateID", estateID.ToString());
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateID", estateID.ToString());
return DoLoad(cmd, UUID.Zero, false);
return DoLoad(cmd, UUID.Zero, false);
}
}
public List<EstateSettings> LoadEstateSettingsAll()
@@ -391,13 +403,15 @@ namespace OpenSim.Data.SQLite
List<int> result = new List<int>();
string sql = "select EstateID from estate_settings where estate_settings.EstateName = :EstateName";
IDataReader r;
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateName", search);
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateName", search);
IDataReader r = cmd.ExecuteReader();
r = cmd.ExecuteReader();
}
while (r.Read())
{
@@ -413,12 +427,14 @@ namespace OpenSim.Data.SQLite
List<int> result = new List<int>();
string sql = "select EstateID from estate_settings";
IDataReader r;
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.CommandText = sql;
IDataReader r = cmd.ExecuteReader();
r = cmd.ExecuteReader();
}
while (r.Read())
{
@@ -434,13 +450,15 @@ namespace OpenSim.Data.SQLite
List<int> result = new List<int>();
string sql = "select EstateID from estate_settings where estate_settings.EstateOwner = :EstateOwner";
IDataReader r;
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateOwner", ownerID);
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateOwner", ownerID);
IDataReader r = cmd.ExecuteReader();
r = cmd.ExecuteReader();
}
while (r.Read())
{

View File

@@ -90,12 +90,5 @@ namespace OpenSim.Data.SQLite
return cmd.ExecuteReader();
}
}
protected void CloseCommand(SqliteCommand cmd)
{
cmd.Connection.Close();
cmd.Connection.Dispose();
cmd.Dispose();
}
}
}
}

View File

@@ -53,13 +53,13 @@ namespace OpenSim.Data.SQLite
public FriendsData[] GetFriends(string userID)
{
SqliteCommand cmd = new SqliteCommand();
cmd.CommandText = String.Format("select a.*,case when b.Flags is null then -1 else b.Flags end as TheirFlags from {0} as a left join {0} as b on a.PrincipalID = b.Friend and a.Friend = b.PrincipalID where a.PrincipalID = :PrincipalID", m_Realm);
cmd.Parameters.AddWithValue(":PrincipalID", userID.ToString());
return DoQuery(cmd);
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.CommandText = String.Format("select a.*,case when b.Flags is null then -1 else b.Flags end as TheirFlags from {0} as a left join {0} as b on a.PrincipalID = b.Friend and a.Friend = b.PrincipalID where a.PrincipalID = :PrincipalID", m_Realm);
cmd.Parameters.AddWithValue(":PrincipalID", userID.ToString());
return DoQuery(cmd);
}
}
public bool Delete(UUID principalID, string friend)
@@ -69,13 +69,14 @@ namespace OpenSim.Data.SQLite
public bool Delete(string principalID, string friend)
{
SqliteCommand cmd = new SqliteCommand();
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.CommandText = String.Format("delete from {0} where PrincipalID = :PrincipalID and Friend = :Friend", m_Realm);
cmd.Parameters.AddWithValue(":PrincipalID", principalID.ToString());
cmd.Parameters.AddWithValue(":Friend", friend);
cmd.CommandText = String.Format("delete from {0} where PrincipalID = :PrincipalID and Friend = :Friend", m_Realm);
cmd.Parameters.AddWithValue(":PrincipalID", principalID.ToString());
cmd.Parameters.AddWithValue(":Friend", friend);
ExecuteNonQuery(cmd, m_Connection);
ExecuteNonQuery(cmd, m_Connection);
}
return true;
}

View File

@@ -120,34 +120,35 @@ namespace OpenSim.Data.SQLite
}
}
public T[] Get(string field, string key)
public virtual T[] Get(string field, string key)
{
return Get(new string[] { field }, new string[] { key });
}
public T[] Get(string[] fields, string[] keys)
public virtual T[] Get(string[] fields, string[] keys)
{
if (fields.Length != keys.Length)
return new T[0];
List<string> terms = new List<string>();
SqliteCommand cmd = new SqliteCommand();
for (int i = 0 ; i < fields.Length ; i++)
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.Parameters.Add(new SqliteParameter(":" + fields[i], keys[i]));
terms.Add("`" + fields[i] + "` = :" + fields[i]);
for (int i = 0 ; i < fields.Length ; i++)
{
cmd.Parameters.Add(new SqliteParameter(":" + fields[i], keys[i]));
terms.Add("`" + fields[i] + "` = :" + fields[i]);
}
string where = String.Join(" and ", terms.ToArray());
string query = String.Format("select * from {0} where {1}",
m_Realm, where);
cmd.CommandText = query;
return DoQuery(cmd);
}
string where = String.Join(" and ", terms.ToArray());
string query = String.Format("select * from {0} where {1}",
m_Realm, where);
cmd.CommandText = query;
return DoQuery(cmd);
}
protected T[] DoQuery(SqliteCommand cmd)
@@ -212,53 +213,55 @@ namespace OpenSim.Data.SQLite
return result.ToArray();
}
public T[] Get(string where)
public virtual T[] Get(string where)
{
SqliteCommand cmd = new SqliteCommand();
using (SqliteCommand cmd = new SqliteCommand())
{
string query = String.Format("select * from {0} where {1}",
m_Realm, where);
string query = String.Format("select * from {0} where {1}",
m_Realm, where);
cmd.CommandText = query;
cmd.CommandText = query;
return DoQuery(cmd);
return DoQuery(cmd);
}
}
public bool Store(T row)
public virtual bool Store(T row)
{
SqliteCommand cmd = new SqliteCommand();
string query = "";
List<String> names = new List<String>();
List<String> values = new List<String>();
foreach (FieldInfo fi in m_Fields.Values)
using (SqliteCommand cmd = new SqliteCommand())
{
names.Add(fi.Name);
values.Add(":" + fi.Name);
cmd.Parameters.Add(new SqliteParameter(":" + fi.Name, fi.GetValue(row).ToString()));
}
string query = "";
List<String> names = new List<String>();
List<String> values = new List<String>();
if (m_DataField != null)
{
Dictionary<string, string> data =
(Dictionary<string, string>)m_DataField.GetValue(row);
foreach (KeyValuePair<string, string> kvp in data)
foreach (FieldInfo fi in m_Fields.Values)
{
names.Add(kvp.Key);
values.Add(":" + kvp.Key);
cmd.Parameters.Add(new SqliteParameter(":" + kvp.Key, kvp.Value));
names.Add(fi.Name);
values.Add(":" + fi.Name);
cmd.Parameters.Add(new SqliteParameter(":" + fi.Name, fi.GetValue(row).ToString()));
}
if (m_DataField != null)
{
Dictionary<string, string> data =
(Dictionary<string, string>)m_DataField.GetValue(row);
foreach (KeyValuePair<string, string> kvp in data)
{
names.Add(kvp.Key);
values.Add(":" + kvp.Key);
cmd.Parameters.Add(new SqliteParameter(":" + kvp.Key, kvp.Value));
}
}
query = String.Format("replace into {0} (`", m_Realm) + String.Join("`,`", names.ToArray()) + "`) values (" + String.Join(",", values.ToArray()) + ")";
cmd.CommandText = query;
if (ExecuteNonQuery(cmd, m_Connection) > 0)
return true;
}
query = String.Format("replace into {0} (`", m_Realm) + String.Join("`,`", names.ToArray()) + "`) values (" + String.Join(",", values.ToArray()) + ")";
cmd.CommandText = query;
if (ExecuteNonQuery(cmd, m_Connection) > 0)
return true;
return false;
}
@@ -267,28 +270,29 @@ namespace OpenSim.Data.SQLite
return Delete(new string[] { field }, new string[] { key });
}
public bool Delete(string[] fields, string[] keys)
public virtual bool Delete(string[] fields, string[] keys)
{
if (fields.Length != keys.Length)
return false;
List<string> terms = new List<string>();
SqliteCommand cmd = new SqliteCommand();
for (int i = 0 ; i < fields.Length ; i++)
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.Parameters.Add(new SqliteParameter(":" + fields[i], keys[i]));
terms.Add("`" + fields[i] + "` = :" + fields[i]);
for (int i = 0 ; i < fields.Length ; i++)
{
cmd.Parameters.Add(new SqliteParameter(":" + fields[i], keys[i]));
terms.Add("`" + fields[i] + "` = :" + fields[i]);
}
string where = String.Join(" and ", terms.ToArray());
string query = String.Format("delete from {0} where {1}", m_Realm, where);
cmd.CommandText = query;
return ExecuteNonQuery(cmd, m_Connection) > 0;
}
string where = String.Join(" and ", terms.ToArray());
string query = String.Format("delete from {0} where {1}", m_Realm, where);
cmd.CommandText = query;
return ExecuteNonQuery(cmd, m_Connection) > 0;
}
}
}

View File

@@ -1366,6 +1366,12 @@ namespace OpenSim.Data.SQLite
createCol(land, "UserLookAtZ", typeof(Double));
createCol(land, "AuthbuyerID", typeof(String));
createCol(land, "OtherCleanTime", typeof(Int32));
createCol(land, "MediaType", typeof(String));
createCol(land, "MediaDescription", typeof(String));
createCol(land, "MediaSize", typeof(String));
createCol(land, "MediaLoop", typeof(Boolean));
createCol(land, "ObscureMedia", typeof(Boolean));
createCol(land, "ObscureMusic", typeof(Boolean));
land.PrimaryKey = new DataColumn[] { land.Columns["UUID"] };
@@ -1781,9 +1787,15 @@ namespace OpenSim.Data.SQLite
newData.PassHours = Convert.ToSingle(row["PassHours"]);
newData.PassPrice = Convert.ToInt32(row["PassPrice"]);
newData.SnapshotID = (UUID)(String)row["SnapshotUUID"];
newData.MediaType = (String)row["MediaType"];
newData.MediaDescription = (String)row["MediaDescription"];
newData.MediaWidth = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[0]);
newData.MediaHeight = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[1]);
newData.MediaLoop = Convert.ToBoolean(row["MediaLoop"]);
newData.ObscureMedia = Convert.ToBoolean(row["ObscureMedia"]);
newData.ObscureMusic = Convert.ToBoolean(row["ObscureMusic"]);
try
{
newData.UserLocation =
new Vector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]),
Convert.ToSingle(row["UserLocationZ"]));
@@ -2197,10 +2209,10 @@ namespace OpenSim.Data.SQLite
row["OtherCleanTime"] = land.OtherCleanTime;
row["MediaType"] = land.MediaType;
row["MediaDescription"] = land.MediaDescription;
row["MediaSize"] = land.MediaWidth.ToString() + "," + land.MediaHeight.ToString();
row["MediaLoop"] = land.MediaLoop.ToString();
row["ObscureMusic"] = land.ObscureMusic.ToString();
row["ObscureMedia"] = land.ObscureMedia.ToString();
row["MediaSize"] = String.Format("{0},{1}", land.MediaWidth, land.MediaHeight);
row["MediaLoop"] = land.MediaLoop;
row["ObscureMusic"] = land.ObscureMusic;
row["ObscureMedia"] = land.ObscureMedia;
}
/// <summary>

View File

@@ -66,20 +66,21 @@ namespace OpenSim.Data.SQLite
if (words.Length > 2)
return new UserAccountData[0];
SqliteCommand cmd = new SqliteCommand();
if (words.Length == 1)
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.CommandText = String.Format("select * from {0} where (ScopeID='{1}' or ScopeID='00000000-0000-0000-0000-000000000000') and (FirstName like '{2}%' or LastName like '{2}%')",
m_Realm, scopeID.ToString(), words[0]);
}
else
{
cmd.CommandText = String.Format("select * from {0} where (ScopeID='{1}' or ScopeID='00000000-0000-0000-0000-000000000000') and (FirstName like '{2}%' or LastName like '{3}%')",
m_Realm, scopeID.ToString(), words[0], words[1]);
}
if (words.Length == 1)
{
cmd.CommandText = String.Format("select * from {0} where (ScopeID='{1}' or ScopeID='00000000-0000-0000-0000-000000000000') and (FirstName like '{2}%' or LastName like '{2}%')",
m_Realm, scopeID.ToString(), words[0]);
}
else
{
cmd.CommandText = String.Format("select * from {0} where (ScopeID='{1}' or ScopeID='00000000-0000-0000-0000-000000000000') and (FirstName like '{2}%' or LastName like '{3}%')",
m_Realm, scopeID.ToString(), words[0], words[1]);
}
return DoQuery(cmd);
return DoQuery(cmd);
}
}
}
}

View File

@@ -47,7 +47,7 @@ namespace OpenSim.Data.SQLite
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private SQLiteGenericTableHandler<XInventoryFolder> m_Folders;
private SqliteFolderHandler m_Folders;
private SqliteItemHandler m_Items;
public SQLiteXInventoryData(string conn, string realm)
@@ -55,7 +55,7 @@ namespace OpenSim.Data.SQLite
if (Util.IsWindows())
Util.LoadArchSpecificWindowsDll("sqlite3.dll");
m_Folders = new SQLiteGenericTableHandler<XInventoryFolder>(
m_Folders = new SqliteFolderHandler(
conn, "inventoryfolders", "XInventoryStore");
m_Items = new SqliteItemHandler(
conn, "inventoryitems", String.Empty);
@@ -114,6 +114,11 @@ namespace OpenSim.Data.SQLite
return m_Items.MoveItem(id, newParent);
}
public bool MoveFolder(string id, string newParent)
{
return m_Folders.MoveFolder(id, newParent);
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
return m_Items.GetActiveGestures(principalID);
@@ -125,44 +130,106 @@ namespace OpenSim.Data.SQLite
}
}
public class SqliteItemHandler : SQLiteGenericTableHandler<XInventoryItem>
public class SqliteItemHandler : SqliteInventoryHandler<XInventoryItem>
{
public SqliteItemHandler(string c, string t, string m) :
base(c, t, m)
{
}
public override bool Store(XInventoryItem item)
{
if (!base.Store(item))
return false;
IncrementFolderVersion(item.parentFolderID);
return true;
}
public override bool Delete(string field, string val)
{
XInventoryItem[] retrievedItems = Get(new string[] { field }, new string[] { val });
if (retrievedItems.Length == 0)
return false;
if (!base.Delete(field, val))
return false;
// Don't increment folder version here since Delete(string, string) calls Delete(string[], string[])
// IncrementFolderVersion(retrievedItems[0].parentFolderID);
return true;
}
public override bool Delete(string[] fields, string[] vals)
{
XInventoryItem[] retrievedItems = Get(fields, vals);
if (retrievedItems.Length == 0)
return false;
if (!base.Delete(fields, vals))
return false;
HashSet<UUID> deletedItemFolderUUIDs = new HashSet<UUID>();
Array.ForEach<XInventoryItem>(retrievedItems, i => deletedItemFolderUUIDs.Add(i.parentFolderID));
foreach (UUID deletedItemFolderUUID in deletedItemFolderUUIDs)
IncrementFolderVersion(deletedItemFolderUUID);
return true;
}
public bool MoveItem(string id, string newParent)
{
SqliteCommand cmd = new SqliteCommand();
XInventoryItem[] retrievedItems = Get(new string[] { "inventoryID" }, new string[] { id });
if (retrievedItems.Length == 0)
return false;
cmd.CommandText = String.Format("update {0} set parentFolderID = :ParentFolderID where inventoryID = :InventoryID", m_Realm);
cmd.Parameters.Add(new SqliteParameter(":ParentFolderID", newParent));
cmd.Parameters.Add(new SqliteParameter(":InventoryID", id));
UUID oldParent = retrievedItems[0].parentFolderID;
return ExecuteNonQuery(cmd, m_Connection) == 0 ? false : true;
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.CommandText = String.Format("update {0} set parentFolderID = :ParentFolderID where inventoryID = :InventoryID", m_Realm);
cmd.Parameters.Add(new SqliteParameter(":ParentFolderID", newParent));
cmd.Parameters.Add(new SqliteParameter(":InventoryID", id));
if (ExecuteNonQuery(cmd, m_Connection) == 0)
return false;
}
IncrementFolderVersion(oldParent);
IncrementFolderVersion(newParent);
return true;
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
SqliteCommand cmd = new SqliteCommand();
cmd.CommandText = String.Format("select * from inventoryitems where avatarId = :uuid and assetType = :type and flags = 1", m_Realm);
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.CommandText = String.Format("select * from inventoryitems where avatarId = :uuid and assetType = :type and flags = 1", m_Realm);
cmd.Parameters.Add(new SqliteParameter(":uuid", principalID.ToString()));
cmd.Parameters.Add(new SqliteParameter(":type", (int)AssetType.Gesture));
cmd.Parameters.Add(new SqliteParameter(":uuid", principalID.ToString()));
cmd.Parameters.Add(new SqliteParameter(":type", (int)AssetType.Gesture));
return DoQuery(cmd);
return DoQuery(cmd);
}
}
public int GetAssetPermissions(UUID principalID, UUID assetID)
{
SqliteCommand cmd = new SqliteCommand();
IDataReader reader;
cmd.CommandText = String.Format("select inventoryCurrentPermissions from inventoryitems where avatarID = :PrincipalID and assetID = :AssetID", m_Realm);
cmd.Parameters.Add(new SqliteParameter(":PrincipalID", principalID.ToString()));
cmd.Parameters.Add(new SqliteParameter(":AssetID", assetID.ToString()));
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.CommandText = String.Format("select inventoryCurrentPermissions from inventoryitems where avatarID = :PrincipalID and assetID = :AssetID", m_Realm);
cmd.Parameters.Add(new SqliteParameter(":PrincipalID", principalID.ToString()));
cmd.Parameters.Add(new SqliteParameter(":AssetID", assetID.ToString()));
IDataReader reader = ExecuteReader(cmd, m_Connection);
reader = ExecuteReader(cmd, m_Connection);
}
int perms = 0;
@@ -177,4 +244,81 @@ namespace OpenSim.Data.SQLite
return perms;
}
}
}
public class SqliteFolderHandler : SqliteInventoryHandler<XInventoryFolder>
{
public SqliteFolderHandler(string c, string t, string m) :
base(c, t, m)
{
}
public override bool Store(XInventoryFolder folder)
{
if (!base.Store(folder))
return false;
IncrementFolderVersion(folder.parentFolderID);
return true;
}
public bool MoveFolder(string id, string newParentFolderID)
{
XInventoryFolder[] folders = Get(new string[] { "folderID" }, new string[] { id });
if (folders.Length == 0)
return false;
UUID oldParentFolderUUID = folders[0].parentFolderID;
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.CommandText = String.Format("update {0} set parentFolderID = :ParentFolderID where folderID = :FolderID", m_Realm);
cmd.Parameters.Add(new SqliteParameter(":ParentFolderID", newParentFolderID));
cmd.Parameters.Add(new SqliteParameter(":FolderID", id));
if (ExecuteNonQuery(cmd, m_Connection) == 0)
return false;
}
IncrementFolderVersion(oldParentFolderUUID);
IncrementFolderVersion(newParentFolderID);
return true;
}
}
public class SqliteInventoryHandler<T> : SQLiteGenericTableHandler<T> where T: class, new()
{
public SqliteInventoryHandler(string c, string t, string m) : base(c, t, m) {}
protected bool IncrementFolderVersion(UUID folderID)
{
return IncrementFolderVersion(folderID.ToString());
}
protected bool IncrementFolderVersion(string folderID)
{
// m_log.DebugFormat("[MYSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID);
// Util.PrintCallStack();
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.CommandText = "update inventoryfolders set version=version+1 where folderID = ?folderID";
cmd.Parameters.Add(new SqliteParameter(":folderID", folderID));
try
{
cmd.ExecuteNonQuery();
}
catch (Exception)
{
return false;
}
}
return true;
}
}
}

View File

@@ -49,7 +49,7 @@ using OpenSim.Data.SQLite;
namespace OpenSim.Data.Tests
{
[TestFixture(Description = "Asset store tests (SQLite)")]
public class SQLiteAssetTests : AssetTests<SqliteConnection, SQLiteAssetData>
public class SQLiteAssetTests : AssetTests<SqliteConnection, SQLiteAssetData>
{
}

View File

@@ -33,6 +33,7 @@ using NUnit.Framework;
using NUnit.Framework.Constraints;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Tests.Common;
using log4net;
using System.Data;
using System.Data.Common;
@@ -43,6 +44,12 @@ namespace OpenSim.Data.Tests
/// <summary>This is a base class for testing any Data service for any DBMS.
/// Requires NUnit 2.5 or better (to support the generics).
/// </summary>
/// <remarks>
/// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with
/// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true.
/// and similar on EstateTests, InventoryTests and RegionTests.
/// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts.
/// </remarks>
/// <typeparam name="TConn"></typeparam>
/// <typeparam name="TService"></typeparam>
public class BasicDataServiceTest<TConn, TService>

View File

@@ -36,6 +36,7 @@ using NUnit.Framework;
using NUnit.Framework.Constraints;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Tests.Common;
namespace OpenSim.Data.Tests
{
@@ -254,7 +255,7 @@ namespace OpenSim.Data.Tests
}
[TestFixture]
public class PropertyCompareConstraintTest
public class PropertyCompareConstraintTest : OpenSimTestCase
{
public class HasInt
{

View File

@@ -34,6 +34,7 @@ using System.Text;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Tests.Common;
namespace OpenSim.Data.Tests
{
@@ -158,7 +159,7 @@ namespace OpenSim.Data.Tests
}
[TestFixture]
public class PropertyScramblerTests
public class PropertyScramblerTests : OpenSimTestCase
{
[Test]
public void TestScramble()

View File

@@ -330,6 +330,9 @@ namespace OpenSim.Framework
SetVisualParams(visualParams);
}
/// <summary>
/// Set avatar height by a calculation based on their visual parameters.
/// </summary>
public virtual void SetHeight()
{
// Start with shortest possible female avatar height

View File

@@ -199,7 +199,14 @@ namespace OpenSim.Framework
//
public class Cache
{
/// <summary>
/// Must only be accessed under lock.
/// </summary>
private List<CacheItemBase> m_Index = new List<CacheItemBase>();
/// <summary>
/// Must only be accessed under m_Index lock.
/// </summary>
private Dictionary<string, CacheItemBase> m_Lookup =
new Dictionary<string, CacheItemBase>();
@@ -320,19 +327,19 @@ namespace OpenSim.Framework
{
if (m_Lookup.ContainsKey(index))
item = m_Lookup[index];
}
if (item == null)
{
if (item == null)
{
Expire(true);
return null;
}
item.hits++;
item.lastUsed = DateTime.Now;
Expire(true);
return null;
}
item.hits++;
item.lastUsed = DateTime.Now;
Expire(true);
return item;
}
@@ -385,7 +392,10 @@ namespace OpenSim.Framework
//
public Object Find(Predicate<CacheItemBase> d)
{
CacheItemBase item = m_Index.Find(d);
CacheItemBase item;
lock (m_Index)
item = m_Index.Find(d);
if (item == null)
return null;
@@ -419,12 +429,12 @@ namespace OpenSim.Framework
public virtual void Store(string index, Object data, Type container,
Object[] parameters)
{
Expire(false);
CacheItemBase item;
lock (m_Index)
{
Expire(false);
if (m_Index.Contains(new CacheItemBase(index)))
{
if ((m_Flags & CacheFlags.AllowUpdate) != 0)
@@ -450,9 +460,17 @@ namespace OpenSim.Framework
m_Index.Add(item);
m_Lookup[index] = item;
}
item.Store(data);
}
/// <summary>
/// Expire items as appropriate.
/// </summary>
/// <remarks>
/// Callers must lock m_Index.
/// </remarks>
/// <param name='getting'></param>
protected virtual void Expire(bool getting)
{
if (getting && (m_Strategy == CacheStrategy.Aggressive))
@@ -475,12 +493,10 @@ namespace OpenSim.Framework
switch (m_Strategy)
{
case CacheStrategy.Aggressive:
if (Count < Size)
return;
case CacheStrategy.Aggressive:
if (Count < Size)
return;
lock (m_Index)
{
m_Index.Sort(new SortLRU());
m_Index.Reverse();
@@ -490,7 +506,7 @@ namespace OpenSim.Framework
ExpireDelegate doExpire = OnExpire;
if (doExpire != null)
if (doExpire != null)
{
List<CacheItemBase> candidates =
m_Index.GetRange(target, Count - target);
@@ -513,27 +529,34 @@ namespace OpenSim.Framework
foreach (CacheItemBase item in m_Index)
m_Lookup[item.uuid] = item;
}
}
break;
default:
break;
break;
default:
break;
}
}
public void Invalidate(string uuid)
{
if (!m_Lookup.ContainsKey(uuid))
return;
lock (m_Index)
{
if (!m_Lookup.ContainsKey(uuid))
return;
CacheItemBase item = m_Lookup[uuid];
m_Lookup.Remove(uuid);
m_Index.Remove(item);
CacheItemBase item = m_Lookup[uuid];
m_Lookup.Remove(uuid);
m_Index.Remove(item);
}
}
public void Clear()
{
m_Index.Clear();
m_Lookup.Clear();
lock (m_Index)
{
m_Index.Clear();
m_Lookup.Clear();
}
}
}
}
}

View File

@@ -33,7 +33,8 @@ namespace OpenSim.Framework.Client
{
event ChatMessage OnChatFromClient;
void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, byte source,
byte audible);
void SendChatMessage(
string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source,
byte audible);
}
}
}

View File

@@ -83,7 +83,8 @@ namespace OpenSim.Framework.Console
= "To enter an argument that contains spaces, surround the argument with double quotes.\nFor example, show object name \"My long object name\"\n";
public const string ItemHelpText
= "For more information, type 'help <item>' where <item> is one of the following:";
= @"For more information, type 'help all' to get a list of all commands,
or type help <item>' where <item> is one of the following:";
/// <value>
/// Commands organized by keyword in a tree
@@ -109,19 +110,48 @@ namespace OpenSim.Framework.Console
// Remove initial help keyword
helpParts.RemoveAt(0);
help.Add(""); // Will become a newline.
// General help
if (helpParts.Count == 0)
{
help.Add(""); // Will become a newline.
help.Add(GeneralHelpText);
help.Add(ItemHelpText);
help.AddRange(CollectModulesHelp(tree));
}
else if (helpParts.Count == 1 && helpParts[0] == "all")
{
help.AddRange(CollectAllCommandsHelp());
}
else
{
help.AddRange(CollectHelp(helpParts));
}
help.Add(""); // Will become a newline.
return help;
}
/// <summary>
/// Collects the help from all commands and return in alphabetical order.
/// </summary>
/// <returns></returns>
private List<string> CollectAllCommandsHelp()
{
List<string> help = new List<string>();
lock (m_modulesCommands)
{
foreach (List<CommandInfo> commands in m_modulesCommands.Values)
{
var ourHelpText = commands.ConvertAll(c => string.Format("{0} - {1}", c.help_text, c.long_help));
help.AddRange(ourHelpText);
}
}
help.Sort();
return help;
}
@@ -167,14 +197,11 @@ namespace OpenSim.Framework.Console
string descriptiveHelp = commandInfo.descriptive_help;
// If we do have some descriptive help then insert a spacing line before and after for readability.
// If we do have some descriptive help then insert a spacing line before for readability.
if (descriptiveHelp != string.Empty)
help.Add(string.Empty);
help.Add(commandInfo.descriptive_help);
if (descriptiveHelp != string.Empty)
help.Add(string.Empty);
}
else
{
@@ -702,7 +729,7 @@ namespace OpenSim.Framework.Console
/// </summary>
public void Prompt()
{
string line = ReadLine(m_defaultPrompt + "# ", true, true);
string line = ReadLine(DefaultPrompt + "# ", true, true);
if (line != String.Empty)
Output("Invalid command");

View File

@@ -43,15 +43,7 @@ namespace OpenSim.Framework.Console
public object ConsoleScene { get; set; }
/// <summary>
/// The default prompt text.
/// </summary>
public string DefaultPrompt
{
set { m_defaultPrompt = value; }
get { return m_defaultPrompt; }
}
protected string m_defaultPrompt;
public string DefaultPrompt { get; set; }
public ConsoleBase(string defaultPrompt)
{

View File

@@ -56,7 +56,7 @@ namespace OpenSim.Framework.Console
public List<ConsoleDisplayTableRow> Rows { get; private set; }
/// <summary>
/// Number of spaces to indent the table.
/// Number of spaces to indent the whole table.
/// </summary>
public int Indent { get; set; }
@@ -84,7 +84,7 @@ namespace OpenSim.Framework.Console
Columns.Add(new ConsoleDisplayTableColumn(name, width));
}
public void AddRow(params string[] cells)
public void AddRow(params object[] cells)
{
Rows.Add(new ConsoleDisplayTableRow(cells));
}
@@ -113,7 +113,8 @@ namespace OpenSim.Framework.Console
for (int i = 0; i < Columns.Count; i++)
{
formatSb.Append(' ', TableSpacing);
if (i != 0)
formatSb.Append(' ', TableSpacing);
// Can only do left formatting for now
formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width);
@@ -139,16 +140,16 @@ namespace OpenSim.Framework.Console
public struct ConsoleDisplayTableRow
{
public List<string> Cells { get; private set; }
public List<object> Cells { get; private set; }
public ConsoleDisplayTableRow(List<string> cells) : this()
public ConsoleDisplayTableRow(List<object> cells) : this()
{
Cells = cells;
}
public ConsoleDisplayTableRow(params string[] cells) : this()
public ConsoleDisplayTableRow(params object[] cells) : this()
{
Cells = new List<string>(cells);
Cells = new List<object>(cells);
}
}
}

View File

@@ -0,0 +1,229 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using log4net;
using OpenMetaverse;
namespace OpenSim.Framework.Console
{
public class ConsoleUtil
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public const int LocalIdNotFound = 0;
/// <summary>
/// Used by modules to display stock co-ordinate help, though possibly this should be under some general section
/// rather than in each help summary.
/// </summary>
public const string CoordHelp
= @"Each component of the coord is comma separated. There must be no spaces between the commas.
If you don't care about the z component you can simply omit it.
If you don't care about the x or y components then you can leave them blank (though a comma is still required)
If you want to specify the maxmimum value of a component then you can use ~ instead of a number
If you want to specify the minimum value of a component then you can use -~ instead of a number
e.g.
delete object pos 20,20,20 to 40,40,40
delete object pos 20,20 to 40,40
delete object pos ,20,20 to ,40,40
delete object pos ,,30 to ,,~
delete object pos ,,-~ to ,,30";
public const string MinRawConsoleVectorValue = "-~";
public const string MaxRawConsoleVectorValue = "~";
public const string VectorSeparator = ",";
public static char[] VectorSeparatorChars = VectorSeparator.ToCharArray();
/// <summary>
/// Try to parse a console UUID from the console.
/// </summary>
/// <remarks>
/// Will complain to the console if parsing fails.
/// </remarks>
/// <returns></returns>
/// <param name='console'>If null then no complaint is printed.</param>
/// <param name='rawUuid'></param>
/// <param name='uuid'></param>
public static bool TryParseConsoleUuid(ICommandConsole console, string rawUuid, out UUID uuid)
{
if (!UUID.TryParse(rawUuid, out uuid))
{
if (console != null)
console.OutputFormat("ERROR: {0} is not a valid uuid", rawUuid);
return false;
}
return true;
}
public static bool TryParseConsoleLocalId(ICommandConsole console, string rawLocalId, out uint localId)
{
if (!uint.TryParse(rawLocalId, out localId))
{
if (console != null)
console.OutputFormat("ERROR: {0} is not a valid local id", localId);
return false;
}
if (localId == 0)
{
if (console != null)
console.OutputFormat("ERROR: {0} is not a valid local id - it must be greater than 0", localId);
return false;
}
return true;
}
/// <summary>
/// Tries to parse the input as either a UUID or a local ID.
/// </summary>
/// <returns>true if parsing succeeded, false otherwise.</returns>
/// <param name='console'></param>
/// <param name='rawId'></param>
/// <param name='uuid'></param>
/// <param name='localId'>
/// Will be set to ConsoleUtil.LocalIdNotFound if parsing result was a UUID or no parse succeeded.
/// </param>
public static bool TryParseConsoleId(ICommandConsole console, string rawId, out UUID uuid, out uint localId)
{
if (TryParseConsoleUuid(null, rawId, out uuid))
{
localId = LocalIdNotFound;
return true;
}
if (TryParseConsoleLocalId(null, rawId, out localId))
{
return true;
}
if (console != null)
console.OutputFormat("ERROR: {0} is not a valid UUID or local id", rawId);
return false;
}
/// <summary>
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
/// </summary>
/// <param name='console'>Can be null if no console is available.</param>
/// <param name='rawConsoleVector'>/param>
/// <param name='vector'></param>
/// <returns></returns>
public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
{
if (!int.TryParse(rawConsoleInt, out i))
{
if (console != null)
console.OutputFormat("ERROR: {0} is not a valid integer", rawConsoleInt);
return false;
}
return true;
}
/// <summary>
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
/// </summary>
/// <param name='rawConsoleVector'>/param>
/// <param name='vector'></param>
/// <returns></returns>
public static bool TryParseConsoleMinVector(string rawConsoleVector, out Vector3 vector)
{
return TryParseConsoleVector(rawConsoleVector, c => float.MinValue.ToString(), out vector);
}
/// <summary>
/// Convert a maximum vector input from the console to an OpenMetaverse.Vector3
/// </summary>
/// <param name='rawConsoleVector'>/param>
/// <param name='vector'></param>
/// <returns></returns>
public static bool TryParseConsoleMaxVector(string rawConsoleVector, out Vector3 vector)
{
return TryParseConsoleVector(rawConsoleVector, c => float.MaxValue.ToString(), out vector);
}
/// <summary>
/// Convert a vector input from the console to an OpenMetaverse.Vector3
/// </summary>
/// <param name='rawConsoleVector'>
/// A string in the form <x>,<y>,<z> where there is no space between values.
/// Any component can be missing (e.g. ,,40). blankComponentFunc is invoked to replace the blank with a suitable value
/// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40,30 or 40)
/// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
/// Other than that, component values must be numeric.
/// </param>
/// <param name='blankComponentFunc'></param>
/// <param name='vector'></param>
/// <returns></returns>
public static bool TryParseConsoleVector(
string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector)
{
List<string> components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
if (components.Count < 1 || components.Count > 3)
{
vector = Vector3.Zero;
return false;
}
for (int i = components.Count; i < 3; i++)
components.Add("");
List<string> semiDigestedComponents
= components.ConvertAll<string>(
c =>
{
if (c == "")
return blankComponentFunc.Invoke(c);
else if (c == MaxRawConsoleVectorValue)
return float.MaxValue.ToString();
else if (c == MinRawConsoleVectorValue)
return float.MinValue.ToString();
else
return c;
});
string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
// m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
return Vector3.TryParse(semiDigestedConsoleVector, out vector);
}
}
}

View File

@@ -44,13 +44,18 @@ namespace OpenSim.Framework.Console
public ICommands Commands { get { return m_commands; } }
public string DefaultPrompt { get; set; }
public void Prompt() {}
public void RunCommand(string cmd) {}
public string ReadLine(string p, bool isCommand, bool e) { return ""; }
public object ConsoleScene { get { return null; } }
public object ConsoleScene {
get { return null; }
set {}
}
public void Output(string text, string level) {}
public void Output(string text) {}
@@ -76,4 +81,4 @@ namespace OpenSim.Framework.Console
public string[] Resolve(string[] cmd) { return null; }
public XmlElement GetXml(XmlDocument doc) { return null; }
}
}
}

View File

@@ -31,6 +31,7 @@ namespace OpenSim.Framework
public class Constants
{
public const uint RegionSize = 256;
public const uint RegionHeight = 4096;
public const byte TerrainPatchSize = 16;
public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f";

View File

@@ -0,0 +1,508 @@
/*
* Copyright (c) 2008, openmetaverse.org, http://opensimulator.org/
* All rights reserved.
*
* - Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Neither the name of the openmetaverse.org nor the names
* of its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Threading;
using System.Collections.Generic;
namespace OpenSim.Framework
{
/// <summary>
/// A double dictionary that is thread abort safe.
/// </summary>
/// <remarks>
/// This adapts OpenMetaverse.DoubleDictionary to be thread-abort safe by acquiring ReaderWriterLockSlim within
/// a finally section (which can't be interrupted by Thread.Abort()).
/// </remarks>
public class DoubleDictionaryThreadAbortSafe<TKey1, TKey2, TValue>
{
Dictionary<TKey1, TValue> Dictionary1;
Dictionary<TKey2, TValue> Dictionary2;
ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
public DoubleDictionaryThreadAbortSafe()
{
Dictionary1 = new Dictionary<TKey1,TValue>();
Dictionary2 = new Dictionary<TKey2,TValue>();
}
public DoubleDictionaryThreadAbortSafe(int capacity)
{
Dictionary1 = new Dictionary<TKey1, TValue>(capacity);
Dictionary2 = new Dictionary<TKey2, TValue>(capacity);
}
public void Add(TKey1 key1, TKey2 key2, TValue value)
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterWriteLock();
gotLock = true;
}
if (Dictionary1.ContainsKey(key1))
{
if (!Dictionary2.ContainsKey(key2))
throw new ArgumentException("key1 exists in the dictionary but not key2");
}
else if (Dictionary2.ContainsKey(key2))
{
if (!Dictionary1.ContainsKey(key1))
throw new ArgumentException("key2 exists in the dictionary but not key1");
}
Dictionary1[key1] = value;
Dictionary2[key2] = value;
}
finally
{
if (gotLock)
rwLock.ExitWriteLock();
}
}
public bool Remove(TKey1 key1, TKey2 key2)
{
bool success;
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterWriteLock();
gotLock = true;
}
Dictionary1.Remove(key1);
success = Dictionary2.Remove(key2);
}
finally
{
if (gotLock)
rwLock.ExitWriteLock();
}
return success;
}
public bool Remove(TKey1 key1)
{
bool found = false;
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterWriteLock();
gotLock = true;
}
// This is an O(n) operation!
TValue value;
if (Dictionary1.TryGetValue(key1, out value))
{
foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
{
if (kvp.Value.Equals(value))
{
Dictionary1.Remove(key1);
Dictionary2.Remove(kvp.Key);
found = true;
break;
}
}
}
}
finally
{
if (gotLock)
rwLock.ExitWriteLock();
}
return found;
}
public bool Remove(TKey2 key2)
{
bool found = false;
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterWriteLock();
gotLock = true;
}
// This is an O(n) operation!
TValue value;
if (Dictionary2.TryGetValue(key2, out value))
{
foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
{
if (kvp.Value.Equals(value))
{
Dictionary2.Remove(key2);
Dictionary1.Remove(kvp.Key);
found = true;
break;
}
}
}
}
finally
{
if (gotLock)
rwLock.ExitWriteLock();
}
return found;
}
public void Clear()
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterWriteLock();
gotLock = true;
}
Dictionary1.Clear();
Dictionary2.Clear();
}
finally
{
if (gotLock)
rwLock.ExitWriteLock();
}
}
public int Count
{
get { return Dictionary1.Count; }
}
public bool ContainsKey(TKey1 key)
{
return Dictionary1.ContainsKey(key);
}
public bool ContainsKey(TKey2 key)
{
return Dictionary2.ContainsKey(key);
}
public bool TryGetValue(TKey1 key, out TValue value)
{
bool success;
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
success = Dictionary1.TryGetValue(key, out value);
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
return success;
}
public bool TryGetValue(TKey2 key, out TValue value)
{
bool success;
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
success = Dictionary2.TryGetValue(key, out value);
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
return success;
}
public void ForEach(Action<TValue> action)
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
foreach (TValue value in Dictionary1.Values)
action(value);
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
}
public void ForEach(Action<KeyValuePair<TKey1, TValue>> action)
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
foreach (KeyValuePair<TKey1, TValue> entry in Dictionary1)
action(entry);
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
}
public void ForEach(Action<KeyValuePair<TKey2, TValue>> action)
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
foreach (KeyValuePair<TKey2, TValue> entry in Dictionary2)
action(entry);
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
}
public TValue FindValue(Predicate<TValue> predicate)
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
foreach (TValue value in Dictionary1.Values)
{
if (predicate(value))
return value;
}
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
return default(TValue);
}
public IList<TValue> FindAll(Predicate<TValue> predicate)
{
IList<TValue> list = new List<TValue>();
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
foreach (TValue value in Dictionary1.Values)
{
if (predicate(value))
list.Add(value);
}
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
return list;
}
public int RemoveAll(Predicate<TValue> predicate)
{
IList<TKey1> list = new List<TKey1>();
bool gotUpgradeableLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterUpgradeableReadLock();
gotUpgradeableLock = true;
}
foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
{
if (predicate(kvp.Value))
list.Add(kvp.Key);
}
IList<TKey2> list2 = new List<TKey2>(list.Count);
foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
{
if (predicate(kvp.Value))
list2.Add(kvp.Key);
}
bool gotWriteLock = false;
try
{
try {}
finally
{
rwLock.EnterUpgradeableReadLock();
gotWriteLock = true;
}
for (int i = 0; i < list.Count; i++)
Dictionary1.Remove(list[i]);
for (int i = 0; i < list2.Count; i++)
Dictionary2.Remove(list2[i]);
}
finally
{
if (gotWriteLock)
rwLock.ExitWriteLock();
}
}
finally
{
if (gotUpgradeableLock)
rwLock.ExitUpgradeableReadLock();
}
return list.Count;
}
}
}

View File

@@ -805,8 +805,23 @@ namespace OpenSim.Framework
event Action<IClientAPI> OnRegionHandShakeReply;
event GenericCall1 OnRequestWearables;
event Action<IClientAPI, bool> OnCompleteMovementToRegion;
/// <summary>
/// Called when an AgentUpdate message is received and before OnAgentUpdate.
/// </summary>
/// <remarks>
/// Listeners must not retain a reference to AgentUpdateArgs since this object may be reused for subsequent AgentUpdates.
/// </remarks>
event UpdateAgent OnPreAgentUpdate;
/// <summary>
/// Called when an AgentUpdate message is received and after OnPreAgentUpdate.
/// </summary>
/// <remarks>
/// Listeners must not retain a reference to AgentUpdateArgs since this object may be reused for subsequent AgentUpdates.
/// </remarks>
event UpdateAgent OnAgentUpdate;
event AgentRequestSit OnAgentRequestSit;
event AgentSit OnAgentSit;
event AvatarPickerRequest OnAvatarPickerRequest;
@@ -1033,7 +1048,21 @@ namespace OpenSim.Framework
void InPacket(object NewPack);
void ProcessInPacket(Packet NewPack);
/// <summary>
/// Close this client
/// </summary>
void Close();
/// <summary>
/// Close this client
/// </summary>
/// <param name='force'>
/// If true, attempts the close without checking active status. You do not want to try this except as a last
/// ditch attempt where Active == false but the ScenePresence still exists.
/// </param>
void Close(bool force);
void Kick(string message);
/// <summary>
@@ -1070,8 +1099,20 @@ namespace OpenSim.Framework
void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, byte source,
byte audible);
/// <summary>
/// Send chat to the viewer.
/// </summary>
/// <param name='message'></param>
/// <param name='type'></param>
/// <param name='fromPos'></param>
/// <param name='fromName'></param>
/// <param name='fromAgentID'></param>
/// <param name='ownerID'></param>
/// <param name='source'></param>
/// <param name='audible'></param>
void SendChatMessage(
string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source,
byte audible);
void SendInstantMessage(GridInstantMessage im);

View File

@@ -78,6 +78,11 @@ namespace OpenSim.Framework
{
ICommands Commands { get; }
/// <summary>
/// The default prompt text.
/// </summary>
string DefaultPrompt { get; set; }
/// <summary>
/// Display a command prompt on the console and wait for user input
/// </summary>
@@ -87,4 +92,4 @@ namespace OpenSim.Framework
string ReadLine(string p, bool isCommand, bool e);
}
}
}

View File

@@ -32,7 +32,7 @@ namespace OpenSim.Framework
{
public interface IConsole
{
object ConsoleScene { get; }
object ConsoleScene { get; set; }
void Output(string text, string level);
void Output(string text);

View File

@@ -73,33 +73,27 @@ namespace OpenSim.Framework
{
}
public InventoryFolderBase(UUID id)
public InventoryFolderBase(UUID id) : this()
{
ID = id;
}
public InventoryFolderBase(UUID id, UUID owner)
public InventoryFolderBase(UUID id, UUID owner) : this(id)
{
ID = id;
Owner = owner;
}
public InventoryFolderBase(UUID id, string name, UUID owner, UUID parent)
public InventoryFolderBase(UUID id, string name, UUID owner, UUID parent) : this(id, owner)
{
ID = id;
Name = name;
Owner = owner;
ParentID = parent;
}
public InventoryFolderBase(UUID id, string name, UUID owner, short type, UUID parent, ushort version)
public InventoryFolderBase(
UUID id, string name, UUID owner, short type, UUID parent, ushort version) : this(id, name, owner, parent)
{
ID = id;
Name = name;
Owner = owner;
Type = type;
ParentID = parent;
Version = version;
}
}
}
}

View File

@@ -87,16 +87,7 @@ namespace OpenSim.Framework
protected string m_creatorId;
/// <value>
/// The UUID for the creator. This may be different from the canonical CreatorId. This property is used
/// for communication with the client over the Second Life protocol, since that protocol can only understand
/// UUIDs. As this is a basic framework class, this means that both the string creator id and the uuid
/// reference have to be settable separately
///
/// Database plugins don't need to set this, it will be set by
/// upstream code (or set by the get accessor if left unset).
///
/// XXX: An alternative to having a separate uuid property would be to hash the CreatorId appropriately
/// every time there was communication with a UUID-only client. This may be much more expensive.
/// The CreatorId expressed as a UUID.tely
/// </value>
public UUID CreatorIdAsUuid
{
@@ -109,20 +100,18 @@ namespace OpenSim.Framework
return m_creatorIdAsUuid;
}
set
{
m_creatorIdAsUuid = value;
}
}
protected UUID m_creatorIdAsUuid = UUID.Zero;
protected string m_creatorData = string.Empty;
/// <summary>
/// Extended creator information of the form <profile url>;<name>
/// </summary>
public string CreatorData // = <profile url>;<name>
{
get { return m_creatorData; }
set { m_creatorData = value; }
}
protected string m_creatorData = string.Empty;
/// <summary>
/// Used by the DB layer to retrieve / store the entire user identification.
@@ -162,7 +151,6 @@ namespace OpenSim.Framework
name = parts[2];
m_creatorData += ';' + name;
}
}
}

View File

@@ -49,7 +49,11 @@ namespace OpenSim.Framework.Monitoring
Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0));
sb.AppendFormat(
"OpenSim object memory churn : {0} MB/s\n",
"OpenSim last object memory churn : {0} MB/s\n",
Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3));
sb.AppendFormat(
"OpenSim average object memory churn : {0} MB/s\n",
Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3));
sb.AppendFormat(

View File

@@ -60,13 +60,21 @@ namespace OpenSim.Framework.Monitoring
private static bool m_enabled;
/// <summary>
/// Average memory churn in bytes per millisecond.
/// Last memory churn in bytes per millisecond.
/// </summary>
public static double AverageMemoryChurn
{
get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; }
}
/// <summary>
/// Average memory churn in bytes per millisecond.
/// </summary>
public static double LastMemoryChurn
{
get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; }
}
/// <summary>
/// Maximum number of statistical samples.
/// </summary>

View File

@@ -355,10 +355,25 @@ Asset service request failures: {3}" + Environment.NewLine,
sb.Append(Environment.NewLine);
sb.Append(
string.Format(
"{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}",
"{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}\n\n",
inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
sb.Append(Environment.NewLine);
Dictionary<string, Dictionary<string, Stat>> sceneStats;
if (StatsManager.TryGetStats("scene", out sceneStats))
{
foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats)
{
foreach (Stat stat in kvp.Value.Values)
{
if (stat.Verbosity == StatVerbosity.Info)
{
sb.AppendFormat("{0} ({1}): {2}{3}\n", stat.Name, stat.Container, stat.Value, stat.UnitName);
}
}
}
}
/*
sb.Append(Environment.NewLine);

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenSim.Framework.Monitoring
{
public class PercentageStat : Stat
{
public long Antecedent { get; set; }
public long Consequent { get; set; }
public override double Value
{
get
{
// Asking for an update here means that the updater cannot access this value without infinite recursion.
// XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being
// called by the pull action and just return the value.
if (StatType == StatType.Pull)
PullAction(this);
long c = Consequent;
// Avoid any chance of a multi-threaded divide-by-zero
if (c == 0)
return 0;
return (double)Antecedent / c * 100;
}
set
{
throw new InvalidOperationException("Cannot set value on a PercentageStat");
}
}
public PercentageStat(
string shortName,
string name,
string description,
string category,
string container,
StatType type,
Action<Stat> pullAction,
StatVerbosity verbosity)
: base(shortName, name, description, "%", category, container, type, pullAction, verbosity) {}
public override string ToConsoleString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat(
"{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})",
Category, Container, ShortName, Value, UnitName, Antecedent, Consequent);
AppendMeasuresOfInterest(sb);
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,238 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenSim.Framework.Monitoring
{
/// <summary>
/// Holds individual statistic details
/// </summary>
public class Stat
{
/// <summary>
/// Category of this stat (e.g. cache, scene, etc).
/// </summary>
public string Category { get; private set; }
/// <summary>
/// Containing name for this stat.
/// FIXME: In the case of a scene, this is currently the scene name (though this leaves
/// us with a to-be-resolved problem of non-unique region names).
/// </summary>
/// <value>
/// The container.
/// </value>
public string Container { get; private set; }
public StatType StatType { get; private set; }
public MeasuresOfInterest MeasuresOfInterest { get; private set; }
/// <summary>
/// Action used to update this stat when the value is requested if it's a pull type.
/// </summary>
public Action<Stat> PullAction { get; private set; }
public StatVerbosity Verbosity { get; private set; }
public string ShortName { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
public virtual string UnitName { get; private set; }
public virtual double Value
{
get
{
// Asking for an update here means that the updater cannot access this value without infinite recursion.
// XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being
// called by the pull action and just return the value.
if (StatType == StatType.Pull)
PullAction(this);
return m_value;
}
set
{
m_value = value;
}
}
private double m_value;
/// <summary>
/// Historical samples for calculating measures of interest average.
/// </summary>
/// <remarks>
/// Will be null if no measures of interest require samples.
/// </remarks>
private static Queue<double> m_samples;
/// <summary>
/// Maximum number of statistical samples.
/// </summary>
/// <remarks>
/// At the moment this corresponds to 1 minute since the sampling rate is every 2.5 seconds as triggered from
/// the main Watchdog.
/// </remarks>
private static int m_maxSamples = 24;
public Stat(
string shortName,
string name,
string description,
string unitName,
string category,
string container,
StatType type,
Action<Stat> pullAction,
StatVerbosity verbosity)
: this(
shortName,
name,
description,
unitName,
category,
container,
type,
MeasuresOfInterest.None,
pullAction,
verbosity)
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
/// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
/// <param name='description'>Description of stat</param>
/// <param name='unitName'>
/// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
/// e.g. " frames"
/// </param>
/// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
/// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
/// <param name='type'>Push or pull</param>
/// <param name='pullAction'>Pull stats need an action to update the stat on request. Push stats should set null here.</param>
/// <param name='moi'>Measures of interest</param>
/// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
public Stat(
string shortName,
string name,
string description,
string unitName,
string category,
string container,
StatType type,
MeasuresOfInterest moi,
Action<Stat> pullAction,
StatVerbosity verbosity)
{
if (StatsManager.SubCommands.Contains(category))
throw new Exception(
string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
ShortName = shortName;
Name = name;
Description = description;
UnitName = unitName;
Category = category;
Container = container;
StatType = type;
if (StatType == StatType.Push && pullAction != null)
throw new Exception("A push stat cannot have a pull action");
else
PullAction = pullAction;
MeasuresOfInterest = moi;
if ((moi & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime)
m_samples = new Queue<double>(m_maxSamples);
Verbosity = verbosity;
}
/// <summary>
/// Record a value in the sample set.
/// </summary>
/// <remarks>
/// Do not call this if MeasuresOfInterest.None
/// </remarks>
public void RecordValue()
{
double newValue = Value;
lock (m_samples)
{
if (m_samples.Count >= m_maxSamples)
m_samples.Dequeue();
m_samples.Enqueue(newValue);
}
}
public virtual string ToConsoleString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
AppendMeasuresOfInterest(sb);
return sb.ToString();
}
protected void AppendMeasuresOfInterest(StringBuilder sb)
{
if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime)
== MeasuresOfInterest.AverageChangeOverTime)
{
double totalChange = 0;
double? lastSample = null;
lock (m_samples)
{
foreach (double s in m_samples)
{
if (lastSample != null)
totalChange += s - (double)lastSample;
lastSample = s;
}
}
int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName);
}
}
}
}

View File

@@ -25,6 +25,10 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenSim.Framework.Monitoring
{
/// <summary>
@@ -32,6 +36,24 @@ namespace OpenSim.Framework.Monitoring
/// </summary>
public class StatsManager
{
// Subcommand used to list other stats.
public const string AllSubCommand = "all";
// Subcommand used to list other stats.
public const string ListSubCommand = "list";
// All subcommands
public static HashSet<string> SubCommands = new HashSet<string> { AllSubCommand, ListSubCommand };
/// <summary>
/// Registered stats categorized by category/container/shortname
/// </summary>
/// <remarks>
/// Do not add or remove directly from this dictionary.
/// </remarks>
public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
= new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
private static AssetStatsCollector assetStats;
private static UserStatsCollector userStats;
private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
@@ -40,6 +62,75 @@ namespace OpenSim.Framework.Monitoring
public static UserStatsCollector UserStats { get { return userStats; } }
public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
public static void RegisterConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"General",
false,
"show stats",
"show stats [list|all|<category>]",
"Show statistical information for this server",
"If no final argument is specified then legacy statistics information is currently shown.\n"
+ "If list is specified then statistic categories are shown.\n"
+ "If all is specified then all registered statistics are shown.\n"
+ "If a category name is specified then only statistics from that category are shown.\n"
+ "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
HandleShowStatsCommand);
}
public static void HandleShowStatsCommand(string module, string[] cmd)
{
ICommandConsole con = MainConsole.Instance;
if (cmd.Length > 2)
{
var categoryName = cmd[2];
if (categoryName == AllSubCommand)
{
foreach (var category in RegisteredStats.Values)
{
OutputCategoryStatsToConsole(con, category);
}
}
else if (categoryName == ListSubCommand)
{
con.Output("Statistic categories available are:");
foreach (string category in RegisteredStats.Keys)
con.OutputFormat(" {0}", category);
}
else
{
Dictionary<string, Dictionary<string, Stat>> category;
if (!RegisteredStats.TryGetValue(categoryName, out category))
{
con.OutputFormat("No such category as {0}", categoryName);
}
else
{
OutputCategoryStatsToConsole(con, category);
}
}
}
else
{
// Legacy
con.Output(SimExtraStats.Report());
}
}
private static void OutputCategoryStatsToConsole(
ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category)
{
foreach (var container in category.Values)
{
foreach (Stat stat in container.Values)
{
con.Output(stat.ToConsoleString());
}
}
}
/// <summary>
/// Start collecting statistics related to assets.
/// Should only be called once.
@@ -61,5 +152,153 @@ namespace OpenSim.Framework.Monitoring
return userStats;
}
/// <summary>
/// Registers a statistic.
/// </summary>
/// <param name='stat'></param>
/// <returns></returns>
public static bool RegisterStat(Stat stat)
{
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
Dictionary<string, Stat> container = null, newContainer;
lock (RegisteredStats)
{
// Stat name is not unique across category/container/shortname key.
// XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM.
if (TryGetStat(stat, out category, out container))
return false;
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
// This means that we don't need to lock or copy them on iteration, which will be a much more
// common operation after startup.
if (container != null)
newContainer = new Dictionary<string, Stat>(container);
else
newContainer = new Dictionary<string, Stat>();
if (category != null)
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
else
newCategory = new Dictionary<string, Dictionary<string, Stat>>();
newContainer[stat.ShortName] = stat;
newCategory[stat.Container] = newContainer;
RegisteredStats[stat.Category] = newCategory;
}
return true;
}
/// <summary>
/// Deregister a statistic
/// </summary>>
/// <param name='stat'></param>
/// <returns></returns
public static bool DeregisterStat(Stat stat)
{
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
Dictionary<string, Stat> container = null, newContainer;
lock (RegisteredStats)
{
if (!TryGetStat(stat, out category, out container))
return false;
newContainer = new Dictionary<string, Stat>(container);
newContainer.Remove(stat.ShortName);
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
newCategory.Remove(stat.Container);
newCategory[stat.Container] = newContainer;
RegisteredStats[stat.Category] = newCategory;
return true;
}
}
public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
{
return RegisteredStats.TryGetValue(category, out stats);
}
public static bool TryGetStat(
Stat stat,
out Dictionary<string, Dictionary<string, Stat>> category,
out Dictionary<string, Stat> container)
{
category = null;
container = null;
lock (RegisteredStats)
{
if (RegisteredStats.TryGetValue(stat.Category, out category))
{
if (category.TryGetValue(stat.Container, out container))
{
if (container.ContainsKey(stat.ShortName))
return true;
}
}
}
return false;
}
public static void RecordStats()
{
lock (RegisteredStats)
{
foreach (Dictionary<string, Dictionary<string, Stat>> category in RegisteredStats.Values)
{
foreach (Dictionary<string, Stat> container in category.Values)
{
foreach (Stat stat in container.Values)
{
if (stat.MeasuresOfInterest != MeasuresOfInterest.None)
stat.RecordValue();
}
}
}
}
}
}
/// <summary>
/// Stat type.
/// </summary>
/// <remarks>
/// A push stat is one which is continually updated and so it's value can simply by read.
/// A pull stat is one where reading the value triggers a collection method - the stat is not continually updated.
/// </remarks>
public enum StatType
{
Push,
Pull
}
/// <summary>
/// Measures of interest for this stat.
/// </summary>
[Flags]
public enum MeasuresOfInterest
{
None,
AverageChangeOverTime
}
/// <summary>
/// Verbosity of stat.
/// </summary>
/// <remarks>
/// Info will always be displayed.
/// </remarks>
public enum StatVerbosity
{
Debug,
Info
}
}

View File

@@ -39,7 +39,7 @@ namespace OpenSim.Framework.Monitoring
public static class Watchdog
{
/// <summary>Timer interval in milliseconds for the watchdog timer</summary>
const double WATCHDOG_INTERVAL_MS = 2500.0d;
public const double WATCHDOG_INTERVAL_MS = 2500.0d;
/// <summary>Default timeout in milliseconds before a thread is considered dead</summary>
public const int DEFAULT_WATCHDOG_TIMEOUT_MS = 5000;
@@ -89,6 +89,17 @@ namespace OpenSim.Framework.Monitoring
FirstTick = Environment.TickCount & Int32.MaxValue;
LastTick = FirstTick;
}
public ThreadWatchdogInfo(ThreadWatchdogInfo previousTwi)
{
Thread = previousTwi.Thread;
FirstTick = previousTwi.FirstTick;
LastTick = previousTwi.LastTick;
Timeout = previousTwi.Timeout;
IsTimedOut = previousTwi.IsTimedOut;
AlarmIfTimeout = previousTwi.AlarmIfTimeout;
AlarmMethod = previousTwi.AlarmMethod;
}
}
/// <summary>
@@ -97,6 +108,32 @@ namespace OpenSim.Framework.Monitoring
/// /summary>
public static event Action<ThreadWatchdogInfo> OnWatchdogTimeout;
/// <summary>
/// Is this watchdog active?
/// </summary>
public static bool Enabled
{
get { return m_enabled; }
set
{
// m_log.DebugFormat("[MEMORY WATCHDOG]: Setting MemoryWatchdog.Enabled to {0}", value);
if (value == m_enabled)
return;
m_enabled = value;
if (m_enabled)
{
// Set now so we don't get alerted on the first run
LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue;
}
m_watchdogTimer.Enabled = m_enabled;
}
}
private static bool m_enabled;
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static Dictionary<int, ThreadWatchdogInfo> m_threads;
private static System.Timers.Timer m_watchdogTimer;
@@ -115,11 +152,6 @@ namespace OpenSim.Framework.Monitoring
m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS);
m_watchdogTimer.AutoReset = false;
m_watchdogTimer.Elapsed += WatchdogTimerElapsed;
// Set now so we don't get alerted on the first run
LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue;
m_watchdogTimer.Start();
}
/// <summary>
@@ -199,7 +231,25 @@ namespace OpenSim.Framework.Monitoring
private static bool RemoveThread(int threadID)
{
lock (m_threads)
return m_threads.Remove(threadID);
{
ThreadWatchdogInfo twi;
if (m_threads.TryGetValue(threadID, out twi))
{
m_log.DebugFormat(
"[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
m_threads.Remove(threadID);
return true;
}
else
{
m_log.WarnFormat(
"[WATCHDOG]: Requested to remove thread with ID {0} but this is not being monitored", threadID);
return false;
}
}
}
public static bool AbortThread(int threadID)
@@ -314,7 +364,9 @@ namespace OpenSim.Framework.Monitoring
if (callbackInfos == null)
callbackInfos = new List<ThreadWatchdogInfo>();
callbackInfos.Add(threadInfo);
// Send a copy of the watchdog info to prevent race conditions where the watchdog
// thread updates the monitoring info after an alarm has been sent out.
callbackInfos.Add(new ThreadWatchdogInfo(threadInfo));
}
}
}
@@ -328,6 +380,8 @@ namespace OpenSim.Framework.Monitoring
if (MemoryWatchdog.Enabled)
MemoryWatchdog.Update();
StatsManager.RecordStats();
m_watchdogTimer.Start();
}
}

91
OpenSim/Framework/Pool.cs Normal file
View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
namespace OpenSim.Framework
{
/// <summary>
/// Naive pool implementation.
/// </summary>
/// <remarks>
/// Currently assumes that objects are in a useable state when returned.
/// </remarks>
public class Pool<T>
{
/// <summary>
/// Number of objects in the pool.
/// </summary>
public int Count
{
get
{
lock (m_pool)
return m_pool.Count;
}
}
private Stack<T> m_pool;
/// <summary>
/// Maximum pool size. Beyond this, any returned objects are not pooled.
/// </summary>
private int m_maxPoolSize;
private Func<T> m_createFunction;
public Pool(Func<T> createFunction, int maxSize)
{
m_maxPoolSize = maxSize;
m_createFunction = createFunction;
m_pool = new Stack<T>(m_maxPoolSize);
}
public T GetObject()
{
lock (m_pool)
{
if (m_pool.Count > 0)
return m_pool.Pop();
else
return m_createFunction();
}
}
public void ReturnObject(T obj)
{
lock (m_pool)
{
if (m_pool.Count >= m_maxPoolSize)
return;
else
m_pool.Push(obj);
}
}
}
}

View File

@@ -192,18 +192,7 @@ namespace OpenSim.Framework
public PrimitiveBaseShape()
{
PCode = (byte) PCodeEnum.Primitive;
ExtraParams = new byte[1];
m_textureEntry = DEFAULT_TEXTURE;
}
public PrimitiveBaseShape(bool noShape)
{
if (noShape)
return;
PCode = (byte)PCodeEnum.Primitive;
ExtraParams = new byte[1];
m_textureEntry = DEFAULT_TEXTURE;
}
@@ -216,7 +205,6 @@ namespace OpenSim.Framework
// m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID);
PCode = (byte)prim.PrimData.PCode;
ExtraParams = new byte[1];
State = prim.PrimData.State;
PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
@@ -248,7 +236,10 @@ namespace OpenSim.Framework
SculptTexture = prim.Sculpt.SculptTexture;
SculptType = (byte)prim.Sculpt.Type;
}
else SculptType = (byte)OpenMetaverse.SculptType.None;
else
{
SculptType = (byte)OpenMetaverse.SculptType.None;
}
}
[XmlIgnore]
@@ -340,9 +331,9 @@ namespace OpenSim.Framework
_scale = new Vector3(side, side, side);
}
public void SetHeigth(float heigth)
public void SetHeigth(float height)
{
_scale.Z = heigth;
_scale.Z = height;
}
public void SetRadius(float radius)

View File

@@ -93,6 +93,8 @@ namespace OpenSim.Framework.Serialization.External
"MediaURL", (ld, xtr) => ld.MediaURL = xtr.ReadElementString("MediaURL"));
m_ldProcessors.Add(
"MusicURL", (ld, xtr) => ld.MusicURL = xtr.ReadElementString("MusicURL"));
m_ldProcessors.Add(
"OwnerID", (ld, xtr) => ld.OwnerID = UUID.Parse(xtr.ReadElementString("OwnerID")));
m_ldProcessors.Add(
"ParcelAccessList", ProcessParcelAccessList);
@@ -186,7 +188,16 @@ namespace OpenSim.Framework.Serialization.External
return landData;
}
public static string Serialize(LandData landData)
/// <summary>
/// Serialize land data
/// </summary>
/// <param name='landData'></param>
/// <param name='options'>
/// Serialization options.
/// Can be null if there are no options.
/// "wipe-owners" will write UUID.Zero rather than the ownerID so that a later reload loads all parcels with the estate owner as the owner
/// </param>
public static string Serialize(LandData landData, Dictionary<string, object> options)
{
StringWriter sw = new StringWriter();
XmlTextWriter xtw = new XmlTextWriter(sw);
@@ -215,7 +226,14 @@ namespace OpenSim.Framework.Serialization.External
xtw.WriteElementString("MediaID", landData.MediaID.ToString());
xtw.WriteElementString("MediaURL", landData.MediaURL);
xtw.WriteElementString("MusicURL", landData.MusicURL);
xtw.WriteElementString("OwnerID", landData.OwnerID.ToString());
UUID ownerIdToWrite;
if (options != null && options.ContainsKey("wipe-owners"))
ownerIdToWrite = UUID.Zero;
else
ownerIdToWrite = landData.OwnerID;
xtw.WriteElementString("OwnerID", ownerIdToWrite.ToString());
xtw.WriteStartElement("ParcelAccessList");
foreach (LandAccessEntry pal in landData.ParcelAccessList)

View File

@@ -65,9 +65,14 @@ namespace OpenSim.Framework.Serialization
UserAccount account = userService.GetUserAccount(UUID.Zero, userId);
if (account != null)
{
return MakeOspa(account.FirstName, account.LastName);
}
// else
// {
// m_log.WarnFormat("[OSP RESOLVER]: No user account for {0}", userId);
// System.Console.WriteLine("[OSP RESOLVER]: No user account for {0}", userId);
// }
return null;
}
@@ -79,10 +84,13 @@ namespace OpenSim.Framework.Serialization
/// <returns></returns>
public static string MakeOspa(string firstName, string lastName)
{
// m_log.DebugFormat("[OSP RESOLVER]: Making OSPA for {0} {1}", firstName, lastName);
string ospa
= OSPA_PREFIX + OSPA_NAME_KEY + OSPA_PAIR_SEPARATOR + firstName + OSPA_NAME_VALUE_SEPARATOR + lastName;
// m_log.DebugFormat("[OSP RESOLVER]: Made OSPA {0} for {1} {2}", ospa, firstName, lastName);
// System.Console.WriteLine("[OSP RESOLVER]: Made OSPA {0} for {1} {2}", ospa, firstName, lastName);
return
OSPA_PREFIX + OSPA_NAME_KEY + OSPA_PAIR_SEPARATOR + firstName + OSPA_NAME_VALUE_SEPARATOR + lastName;
return ospa;
}
/// <summary>

View File

@@ -37,27 +37,28 @@ using OpenSim.Tests.Common;
namespace OpenSim.Framework.Serialization.Tests
{
[TestFixture]
public class LandDataSerializerTest
public class LandDataSerializerTest : OpenSimTestCase
{
private LandData land;
private LandData landWithParcelAccessList;
private static string preSerialized = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n<LandData>\n <Area>128</Area>\n <AuctionID>0</AuctionID>\n <AuthBuyerID>00000000-0000-0000-0000-000000000000</AuthBuyerID>\n <Category>10</Category>\n <ClaimDate>0</ClaimDate>\n <ClaimPrice>0</ClaimPrice>\n <GlobalID>54ff9641-dd40-4a2c-b1f1-47dd3af24e50</GlobalID>\n <GroupID>d740204e-bbbf-44aa-949d-02c7d739f6a5</GroupID>\n <IsGroupOwned>False</IsGroupOwned>\n <Bitmap>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</Bitmap>\n <Description>land data to test LandDataSerializer</Description>\n <Flags>536870944</Flags>\n <LandingType>2</LandingType>\n <Name>LandDataSerializerTest Land</Name>\n <Status>0</Status>\n <LocalID>0</LocalID>\n <MediaAutoScale>1</MediaAutoScale>\n <MediaID>d4452578-2f25-4b97-a81b-819af559cfd7</MediaID>\n <MediaURL>http://videos.opensimulator.org/bumblebee.mp4</MediaURL>\n <MusicURL />\n <OwnerID>1b8eedf9-6d15-448b-8015-24286f1756bf</OwnerID>\n <ParcelAccessList />\n <PassHours>0</PassHours>\n <PassPrice>0</PassPrice>\n <SalePrice>0</SalePrice>\n <SnapshotID>00000000-0000-0000-0000-000000000000</SnapshotID>\n <UserLocation>&lt;0, 0, 0&gt;</UserLocation>\n <UserLookAt>&lt;0, 0, 0&gt;</UserLookAt>\n <Dwell>0</Dwell>\n <OtherCleanTime>0</OtherCleanTime>\n</LandData>";
private static string preSerializedWithParcelAccessList = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n<LandData>\n <Area>128</Area>\n <AuctionID>0</AuctionID>\n <AuthBuyerID>00000000-0000-0000-0000-000000000000</AuthBuyerID>\n <Category>10</Category>\n <ClaimDate>0</ClaimDate>\n <ClaimPrice>0</ClaimPrice>\n <GlobalID>54ff9641-dd40-4a2c-b1f1-47dd3af24e50</GlobalID>\n <GroupID>d740204e-bbbf-44aa-949d-02c7d739f6a5</GroupID>\n <IsGroupOwned>False</IsGroupOwned>\n <Bitmap>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</Bitmap>\n <Description>land data to test LandDataSerializer</Description>\n <Flags>536870944</Flags>\n <LandingType>2</LandingType>\n <Name>LandDataSerializerTest Land</Name>\n <Status>0</Status>\n <LocalID>0</LocalID>\n <MediaAutoScale>1</MediaAutoScale>\n <MediaID>d4452578-2f25-4b97-a81b-819af559cfd7</MediaID>\n <MediaURL>http://videos.opensimulator.org/bumblebee.mp4</MediaURL>\n <MusicURL />\n <OwnerID>1b8eedf9-6d15-448b-8015-24286f1756bf</OwnerID>\n <ParcelAccessList>\n <ParcelAccessEntry>\n <AgentID>62d65d45-c91a-4f77-862c-46557d978b6c</AgentID>\n <Time>0</Time>\n <AccessList>2</AccessList>\n </ParcelAccessEntry>\n <ParcelAccessEntry>\n <AgentID>ec2a8d18-2378-4fe0-8b68-2a31b57c481e</AgentID>\n <Time>0</Time>\n <AccessList>1</AccessList>\n </ParcelAccessEntry>\n </ParcelAccessList>\n <PassHours>0</PassHours>\n <PassPrice>0</PassPrice>\n <SalePrice>0</SalePrice>\n <SnapshotID>00000000-0000-0000-0000-000000000000</SnapshotID>\n <UserLocation>&lt;0, 0, 0&gt;</UserLocation>\n <UserLookAt>&lt;0, 0, 0&gt;</UserLookAt>\n <Dwell>0</Dwell>\n <OtherCleanTime>0</OtherCleanTime>\n</LandData>";
// private static string preSerialized = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n<LandData>\n <Area>128</Area>\n <AuctionID>0</AuctionID>\n <AuthBuyerID>00000000-0000-0000-0000-000000000000</AuthBuyerID>\n <Category>10</Category>\n <ClaimDate>0</ClaimDate>\n <ClaimPrice>0</ClaimPrice>\n <GlobalID>54ff9641-dd40-4a2c-b1f1-47dd3af24e50</GlobalID>\n <GroupID>d740204e-bbbf-44aa-949d-02c7d739f6a5</GroupID>\n <IsGroupOwned>False</IsGroupOwned>\n <Bitmap>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</Bitmap>\n <Description>land data to test LandDataSerializer</Description>\n <Flags>536870944</Flags>\n <LandingType>2</LandingType>\n <Name>LandDataSerializerTest Land</Name>\n <Status>0</Status>\n <LocalID>0</LocalID>\n <MediaAutoScale>1</MediaAutoScale>\n <MediaID>d4452578-2f25-4b97-a81b-819af559cfd7</MediaID>\n <MediaURL>http://videos.opensimulator.org/bumblebee.mp4</MediaURL>\n <MusicURL />\n <OwnerID>1b8eedf9-6d15-448b-8015-24286f1756bf</OwnerID>\n <ParcelAccessList />\n <PassHours>0</PassHours>\n <PassPrice>0</PassPrice>\n <SalePrice>0</SalePrice>\n <SnapshotID>00000000-0000-0000-0000-000000000000</SnapshotID>\n <UserLocation>&lt;0, 0, 0&gt;</UserLocation>\n <UserLookAt>&lt;0, 0, 0&gt;</UserLookAt>\n <Dwell>0</Dwell>\n <OtherCleanTime>0</OtherCleanTime>\n</LandData>";
private static string preSerializedWithParcelAccessList
= "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n<LandData>\n <Area>128</Area>\n <AuctionID>0</AuctionID>\n <AuthBuyerID>00000000-0000-0000-0000-000000000000</AuthBuyerID>\n <Category>10</Category>\n <ClaimDate>0</ClaimDate>\n <ClaimPrice>0</ClaimPrice>\n <GlobalID>54ff9641-dd40-4a2c-b1f1-47dd3af24e50</GlobalID>\n <GroupID>d740204e-bbbf-44aa-949d-02c7d739f6a5</GroupID>\n <IsGroupOwned>False</IsGroupOwned>\n <Bitmap>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</Bitmap>\n <Description>land data to test LandDataSerializer</Description>\n <Flags>536870944</Flags>\n <LandingType>2</LandingType>\n <Name>LandDataSerializerTest Land</Name>\n <Status>0</Status>\n <LocalID>0</LocalID>\n <MediaAutoScale>1</MediaAutoScale>\n <MediaID>d4452578-2f25-4b97-a81b-819af559cfd7</MediaID>\n <MediaURL>http://videos.opensimulator.org/bumblebee.mp4</MediaURL>\n <MusicURL />\n <OwnerID>1b8eedf9-6d15-448b-8015-24286f1756bf</OwnerID>\n <ParcelAccessList>\n <ParcelAccessEntry>\n <AgentID>62d65d45-c91a-4f77-862c-46557d978b6c</AgentID>\n <Time>0</Time>\n <AccessList>2</AccessList>\n </ParcelAccessEntry>\n <ParcelAccessEntry>\n <AgentID>ec2a8d18-2378-4fe0-8b68-2a31b57c481e</AgentID>\n <Time>0</Time>\n <AccessList>1</AccessList>\n </ParcelAccessEntry>\n </ParcelAccessList>\n <PassHours>0</PassHours>\n <PassPrice>0</PassPrice>\n <SalePrice>0</SalePrice>\n <SnapshotID>00000000-0000-0000-0000-000000000000</SnapshotID>\n <UserLocation>&lt;0, 0, 0&gt;</UserLocation>\n <UserLookAt>&lt;0, 0, 0&gt;</UserLookAt>\n <Dwell>0</Dwell>\n <OtherCleanTime>0</OtherCleanTime>\n</LandData>";
[SetUp]
public void setup()
{
// setup LandData object
this.land = new LandData();
this.land.AABBMax = new Vector3(0, 0, 0);
this.land.AABBMin = new Vector3(128, 128, 128);
this.land.AABBMax = new Vector3(1, 2, 3);
this.land.AABBMin = new Vector3(129, 130, 131);
this.land.Area = 128;
this.land.AuctionID = 0;
this.land.AuthBuyerID = new UUID();
this.land.AuctionID = 4;
this.land.AuthBuyerID = new UUID("7176df0c-6c50-45db-8a37-5e78be56a0cd");
this.land.Category = ParcelCategory.Residential;
this.land.ClaimDate = 0;
this.land.ClaimPrice = 0;
this.land.ClaimDate = 1;
this.land.ClaimPrice = 2;
this.land.GlobalID = new UUID("54ff9641-dd40-4a2c-b1f1-47dd3af24e50");
this.land.GroupID = new UUID("d740204e-bbbf-44aa-949d-02c7d739f6a5");
this.land.Description = "land data to test LandDataSerializer";
@@ -65,7 +66,7 @@ namespace OpenSim.Framework.Serialization.Tests
this.land.LandingType = (byte)LandingType.Direct;
this.land.Name = "LandDataSerializerTest Land";
this.land.Status = ParcelStatus.Leased;
this.land.LocalID = 0;
this.land.LocalID = 1;
this.land.MediaAutoScale = (byte)0x01;
this.land.MediaID = new UUID("d4452578-2f25-4b97-a81b-819af559cfd7");
this.land.MediaURL = "http://videos.opensimulator.org/bumblebee.mp4";
@@ -90,26 +91,26 @@ namespace OpenSim.Framework.Serialization.Tests
/// <summary>
/// Test the LandDataSerializer.Serialize() method
/// </summary>
[Test]
public void LandDataSerializerSerializeTest()
{
TestHelpers.InMethod();
string serialized = LandDataSerializer.Serialize(this.land).Replace("\r\n", "\n");
Assert.That(serialized.Length > 0, "Serialize(LandData) returned empty string");
// adding a simple boolean variable because resharper nUnit integration doesn't like this
// XML data in the Assert.That statement. Not sure why.
bool result = (serialized == preSerialized);
Assert.That(result, "result of Serialize LandData does not match expected result");
string serializedWithParcelAccessList = LandDataSerializer.Serialize(this.landWithParcelAccessList).Replace("\r\n", "\n");
Assert.That(serializedWithParcelAccessList.Length > 0,
"Serialize(LandData) returned empty string for LandData object with ParcelAccessList");
result = (serializedWithParcelAccessList == preSerializedWithParcelAccessList);
Assert.That(result,
"result of Serialize(LandData) does not match expected result (pre-serialized with parcel access list");
}
// [Test]
// public void LandDataSerializerSerializeTest()
// {
// TestHelpers.InMethod();
//
// string serialized = LandDataSerializer.Serialize(this.land).Replace("\r\n", "\n");
// Assert.That(serialized.Length > 0, "Serialize(LandData) returned empty string");
//
// // adding a simple boolean variable because resharper nUnit integration doesn't like this
// // XML data in the Assert.That statement. Not sure why.
// bool result = (serialized == preSerialized);
// Assert.That(result, "result of Serialize LandData does not match expected result");
//
// string serializedWithParcelAccessList = LandDataSerializer.Serialize(this.landWithParcelAccessList).Replace("\r\n", "\n");
// Assert.That(serializedWithParcelAccessList.Length > 0,
// "Serialize(LandData) returned empty string for LandData object with ParcelAccessList");
// result = (serializedWithParcelAccessList == preSerializedWithParcelAccessList);
// Assert.That(result,
// "result of Serialize(LandData) does not match expected result (pre-serialized with parcel access list");
// }
/// <summary>
/// Test the LandDataSerializer.Deserialize() method
@@ -120,10 +121,28 @@ namespace OpenSim.Framework.Serialization.Tests
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
LandData ld = LandDataSerializer.Deserialize(LandDataSerializerTest.preSerialized);
Assert.That(ld != null, "Deserialize(string) returned null");
Assert.That(ld.GlobalID == this.land.GlobalID, "Reified LandData.GlobalID != original LandData.GlobalID");
Assert.That(ld.Name == this.land.Name, "Reified LandData.Name != original LandData.Name");
LandData ld = LandDataSerializer.Deserialize(LandDataSerializer.Serialize(this.land, null));
Assert.That(ld, Is.Not.Null, "Deserialize(string) returned null");
// Assert.That(ld.AABBMax, Is.EqualTo(land.AABBMax));
// Assert.That(ld.AABBMin, Is.EqualTo(land.AABBMin));
Assert.That(ld.Area, Is.EqualTo(land.Area));
Assert.That(ld.AuctionID, Is.EqualTo(land.AuctionID));
Assert.That(ld.AuthBuyerID, Is.EqualTo(land.AuthBuyerID));
Assert.That(ld.Category, Is.EqualTo(land.Category));
Assert.That(ld.ClaimDate, Is.EqualTo(land.ClaimDate));
Assert.That(ld.ClaimPrice, Is.EqualTo(land.ClaimPrice));
Assert.That(ld.GlobalID, Is.EqualTo(land.GlobalID), "Reified LandData.GlobalID != original LandData.GlobalID");
Assert.That(ld.GroupID, Is.EqualTo(land.GroupID));
Assert.That(ld.Description, Is.EqualTo(land.Description));
Assert.That(ld.Flags, Is.EqualTo(land.Flags));
Assert.That(ld.LandingType, Is.EqualTo(land.LandingType));
Assert.That(ld.Name, Is.EqualTo(land.Name), "Reified LandData.Name != original LandData.Name");
Assert.That(ld.Status, Is.EqualTo(land.Status));
Assert.That(ld.LocalID, Is.EqualTo(land.LocalID));
Assert.That(ld.MediaAutoScale, Is.EqualTo(land.MediaAutoScale));
Assert.That(ld.MediaID, Is.EqualTo(land.MediaID));
Assert.That(ld.MediaURL, Is.EqualTo(land.MediaURL));
Assert.That(ld.OwnerID, Is.EqualTo(land.OwnerID));
}
[Test]

View File

@@ -37,7 +37,7 @@ using OpenSim.Tests.Common;
namespace OpenSim.Framework.Serialization.Tests
{
[TestFixture]
public class RegionSettingsSerializerTests
public class RegionSettingsSerializerTests : OpenSimTestCase
{
private string m_serializedRs = @"<?xml version=""1.0"" encoding=""utf-16""?>
<RegionSettings>

View File

@@ -27,7 +27,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
@@ -38,6 +37,8 @@ using log4net;
using log4net.Appender;
using log4net.Core;
using log4net.Repository;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Monitoring;
@@ -45,16 +46,12 @@ using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using Timer=System.Timers.Timer;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace OpenSim.Framework.Servers
{
/// <summary>
/// Common base for the main OpenSimServers (user, grid, inventory, region, etc)
/// </summary>
public abstract class BaseOpenSimServer
public abstract class BaseOpenSimServer : ServerBase
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -63,27 +60,6 @@ namespace OpenSim.Framework.Servers
/// server.
/// </summary>
private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000);
protected CommandConsole m_console;
protected OpenSimAppender m_consoleAppender;
protected IAppender m_logFileAppender = null;
/// <summary>
/// Time at which this server was started
/// </summary>
protected DateTime m_startuptime;
/// <summary>
/// Record the initial startup directory for info purposes
/// </summary>
protected string m_startupDirectory = Environment.CurrentDirectory;
/// <summary>
/// Server version information. Usually VersionInfo + information about git commit, operating system, etc.
/// </summary>
protected string m_version;
protected string m_pidFile = String.Empty;
/// <summary>
/// Random uuid for private data
@@ -96,35 +72,13 @@ namespace OpenSim.Framework.Servers
get { return m_httpServer; }
}
/// <summary>
/// Holds the non-viewer statistics collection object for this service/server
/// </summary>
protected IStatsCollector m_stats;
public BaseOpenSimServer()
public BaseOpenSimServer() : base()
{
m_startuptime = DateTime.Now;
m_version = VersionInfo.Version;
// Random uuid for private data
m_osSecret = UUID.Random().ToString();
m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics);
m_periodicDiagnosticsTimer.Enabled = true;
// This thread will go on to become the console listening thread
Thread.CurrentThread.Name = "ConsoleThread";
ILoggerRepository repository = LogManager.GetRepository();
IAppender[] appenders = repository.GetAppenders();
foreach (IAppender appender in appenders)
{
if (appender.Name == "LogFileAppender")
{
m_logFileAppender = appender;
}
}
}
/// <summary>
@@ -132,76 +86,18 @@ namespace OpenSim.Framework.Servers
/// </summary>
protected virtual void StartupSpecific()
{
if (m_console != null)
{
ILoggerRepository repository = LogManager.GetRepository();
IAppender[] appenders = repository.GetAppenders();
if (m_console == null)
return;
foreach (IAppender appender in appenders)
{
if (appender.Name == "Console")
{
m_consoleAppender = (OpenSimAppender)appender;
break;
}
}
RegisterCommonCommands();
m_console.Commands.AddCommand("General", false, "quit",
"quit",
"Quit the application", HandleQuit);
if (null == m_consoleAppender)
{
Notice("No appender named Console found (see the log4net config file for this executable)!");
}
else
{
m_consoleAppender.Console = m_console;
// If there is no threshold set then the threshold is effectively everything.
if (null == m_consoleAppender.Threshold)
m_consoleAppender.Threshold = Level.All;
Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold));
}
m_console.Commands.AddCommand("General", false, "quit",
"quit",
"Quit the application", HandleQuit);
m_console.Commands.AddCommand("General", false, "shutdown",
"shutdown",
"Quit the application", HandleQuit);
m_console.Commands.AddCommand("General", false, "set log level",
"set log level <level>",
"Set the console logging level", HandleLogLevel);
m_console.Commands.AddCommand("General", false, "show info",
"show info",
"Show general information about the server", HandleShow);
m_console.Commands.AddCommand("General", false, "show stats",
"show stats",
"Show statistics", HandleShow);
m_console.Commands.AddCommand("General", false, "show threads",
"show threads",
"Show thread status", HandleShow);
m_console.Commands.AddCommand("General", false, "show uptime",
"show uptime",
"Show server uptime", HandleShow);
m_console.Commands.AddCommand("General", false, "show version",
"show version",
"Show server version", HandleShow);
m_console.Commands.AddCommand("General", false, "threads abort",
"threads abort <thread-id>",
"Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
m_console.Commands.AddCommand("General", false, "threads show",
"threads show",
"Show thread status. Synonym for \"show threads\"",
(string module, string[] args) => Notice(GetThreadsReport()));
}
m_console.Commands.AddCommand("General", false, "shutdown",
"shutdown",
"Quit the application", HandleQuit);
}
/// <summary>
@@ -226,87 +122,19 @@ namespace OpenSim.Framework.Servers
{
StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n");
sb.Append(GetUptimeReport());
if (m_stats != null)
{
sb.Append(m_stats.Report());
}
sb.Append(StatsManager.SimExtraStats.Report());
sb.Append(Environment.NewLine);
sb.Append(GetThreadsReport());
m_log.Debug(sb);
}
/// <summary>
/// Get a report about the registered threads in this server.
/// </summary>
protected string GetThreadsReport()
{
// This should be a constant field.
string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}";
StringBuilder sb = new StringBuilder();
Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo();
sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine);
int timeNow = Environment.TickCount & Int32.MaxValue;
sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE");
sb.Append(Environment.NewLine);
foreach (Watchdog.ThreadWatchdogInfo twi in threads)
{
Thread t = twi.Thread;
sb.AppendFormat(
reportFormat,
t.ManagedThreadId,
t.Name,
timeNow - twi.LastTick,
timeNow - twi.FirstTick,
t.Priority,
t.ThreadState);
sb.Append("\n");
}
sb.Append("\n");
// For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting
// zero active threads.
int totalThreads = Process.GetCurrentProcess().Threads.Count;
if (totalThreads > 0)
sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
sb.Append("Main threadpool (excluding script engine pools)\n");
sb.Append(Util.GetThreadPoolReport());
return sb.ToString();
}
/// <summary>
/// Return a report about the uptime of this server
/// </summary>
/// <returns></returns>
protected string GetUptimeReport()
{
StringBuilder sb = new StringBuilder(String.Format("Time now is {0}\n", DateTime.Now));
sb.Append(String.Format("Server has been running since {0}, {1}\n", m_startuptime.DayOfWeek, m_startuptime));
sb.Append(String.Format("That is an elapsed time of {0}\n", DateTime.Now - m_startuptime));
return sb.ToString();
}
/// <summary>
/// Performs initialisation of the scene, such as loading configuration from disk.
/// </summary>
public virtual void Startup()
{
m_log.Info("[STARTUP]: Beginning startup processing");
EnhanceVersionInformation();
m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine);
// clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
@@ -341,271 +169,11 @@ namespace OpenSim.Framework.Servers
private void HandleQuit(string module, string[] args)
{
Shutdown();
}
private void HandleLogLevel(string module, string[] cmd)
{
if (null == m_consoleAppender)
{
Notice("No appender named Console found (see the log4net config file for this executable)!");
return;
}
if (cmd.Length > 3)
{
string rawLevel = cmd[3];
ILoggerRepository repository = LogManager.GetRepository();
Level consoleLevel = repository.LevelMap[rawLevel];
if (consoleLevel != null)
m_consoleAppender.Threshold = consoleLevel;
else
Notice(
String.Format(
"{0} is not a valid logging level. Valid logging levels are ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF",
rawLevel));
}
Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold));
}
/// <summary>
/// Show help information
/// </summary>
/// <param name="helpArgs"></param>
protected virtual void ShowHelp(string[] helpArgs)
{
Notice("");
if (helpArgs.Length == 0)
{
Notice("set log level [level] - change the console logging level only. For example, off or debug.");
Notice("show info - show server information (e.g. startup path).");
if (m_stats != null)
Notice("show stats - show statistical information for this server");
Notice("show threads - list tracked threads");
Notice("show uptime - show server startup time and uptime.");
Notice("show version - show server version.");
Notice("");
return;
}
}
public virtual void HandleShow(string module, string[] cmd)
{
List<string> args = new List<string>(cmd);
args.RemoveAt(0);
string[] showParams = args.ToArray();
switch (showParams[0])
{
case "info":
ShowInfo();
break;
case "stats":
if (m_stats != null)
Notice(m_stats.Report());
break;
case "threads":
Notice(GetThreadsReport());
break;
case "uptime":
Notice(GetUptimeReport());
break;
case "version":
Notice(GetVersionText());
break;
}
}
public virtual void HandleThreadsAbort(string module, string[] cmd)
{
if (cmd.Length != 3)
{
MainConsole.Instance.Output("Usage: threads abort <thread-id>");
return;
}
int threadId;
if (!int.TryParse(cmd[2], out threadId))
{
MainConsole.Instance.Output("ERROR: Thread id must be an integer");
return;
}
if (Watchdog.AbortThread(threadId))
MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId);
else
MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId);
}
protected void ShowInfo()
{
Notice(GetVersionText());
Notice("Startup directory: " + m_startupDirectory);
if (null != m_consoleAppender)
Notice(String.Format("Console log level: {0}", m_consoleAppender.Threshold));
}
protected string GetVersionText()
{
return String.Format("Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion);
}
/// <summary>
/// Console output is only possible if a console has been established.
/// That is something that cannot be determined within this class. So
/// all attempts to use the console MUST be verified.
/// </summary>
/// <param name="msg"></param>
protected void Notice(string msg)
{
if (m_console != null)
{
m_console.Output(msg);
}
}
/// <summary>
/// Console output is only possible if a console has been established.
/// That is something that cannot be determined within this class. So
/// all attempts to use the console MUST be verified.
/// </summary>
/// <param name="format"></param>
/// <param name="components"></param>
protected void Notice(string format, params string[] components)
{
if (m_console != null)
m_console.OutputFormat(format, components);
}
/// <summary>
/// Enhance the version string with extra information if it's available.
/// </summary>
protected void EnhanceVersionInformation()
{
string buildVersion = string.Empty;
// The subversion information is deprecated and will be removed at a later date
// Add subversion revision information if available
// Try file "svn_revision" in the current directory first, then the .svn info.
// This allows to make the revision available in simulators not running from the source tree.
// FIXME: Making an assumption about the directory we're currently in - we do this all over the place
// elsewhere as well
string gitDir = "../.git/";
string gitRefPointerPath = gitDir + "HEAD";
string svnRevisionFileName = "svn_revision";
string svnFileName = ".svn/entries";
string manualVersionFileName = ".version";
string inputLine;
int strcmp;
if (File.Exists(manualVersionFileName))
{
using (StreamReader CommitFile = File.OpenText(manualVersionFileName))
buildVersion = CommitFile.ReadLine();
m_version += buildVersion ?? "";
}
else if (File.Exists(gitRefPointerPath))
{
// m_log.DebugFormat("[OPENSIM]: Found {0}", gitRefPointerPath);
string rawPointer = "";
using (StreamReader pointerFile = File.OpenText(gitRefPointerPath))
rawPointer = pointerFile.ReadLine();
// m_log.DebugFormat("[OPENSIM]: rawPointer [{0}]", rawPointer);
Match m = Regex.Match(rawPointer, "^ref: (.+)$");
if (m.Success)
{
// m_log.DebugFormat("[OPENSIM]: Matched [{0}]", m.Groups[1].Value);
string gitRef = m.Groups[1].Value;
string gitRefPath = gitDir + gitRef;
if (File.Exists(gitRefPath))
{
// m_log.DebugFormat("[OPENSIM]: Found gitRefPath [{0}]", gitRefPath);
using (StreamReader refFile = File.OpenText(gitRefPath))
{
string gitHash = refFile.ReadLine();
m_version += gitHash.Substring(0, 7);
}
}
}
}
else
{
// Remove the else logic when subversion mirror is no longer used
if (File.Exists(svnRevisionFileName))
{
StreamReader RevisionFile = File.OpenText(svnRevisionFileName);
buildVersion = RevisionFile.ReadLine();
buildVersion.Trim();
RevisionFile.Close();
}
if (string.IsNullOrEmpty(buildVersion) && File.Exists(svnFileName))
{
StreamReader EntriesFile = File.OpenText(svnFileName);
inputLine = EntriesFile.ReadLine();
while (inputLine != null)
{
// using the dir svn revision at the top of entries file
strcmp = String.Compare(inputLine, "dir");
if (strcmp == 0)
{
buildVersion = EntriesFile.ReadLine();
break;
}
else
{
inputLine = EntriesFile.ReadLine();
}
}
EntriesFile.Close();
}
m_version += string.IsNullOrEmpty(buildVersion) ? " " : ("." + buildVersion + " ").Substring(0, 6);
}
}
protected void CreatePIDFile(string path)
{
try
{
string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
FileStream fs = File.Create(path);
Byte[] buf = Encoding.ASCII.GetBytes(pidstring);
fs.Write(buf, 0, buf.Length);
fs.Close();
m_pidFile = path;
}
catch (Exception)
{
}
}
}
public string osSecret {
// Secret uuid for the simulator
get { return m_osSecret; }
get { return m_osSecret; }
}
public string StatReport(IOSHttpRequest httpRequest)
@@ -613,27 +181,12 @@ namespace OpenSim.Framework.Servers
// If we catch a request for "callback", wrap the response in the value for jsonp
if (httpRequest.Query.ContainsKey("callback"))
{
return httpRequest.Query["callback"].ToString() + "(" + m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
return httpRequest.Query["callback"].ToString() + "(" + StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
}
else
{
return m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
}
}
protected void RemovePIDFile()
{
if (m_pidFile != String.Empty)
{
try
{
File.Delete(m_pidFile);
m_pidFile = String.Empty;
}
catch (Exception)
{
}
return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
}
}
}
}
}

View File

@@ -54,8 +54,23 @@ namespace OpenSim.Framework.Servers.HttpServer
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
/// <summary>
/// Gets or sets the debug level.
/// </summary>
/// <value>
/// See MainServer.DebugLevel.
/// </value>
public int DebugLevel { get; set; }
/// <summary>
/// Request number for diagnostic purposes.
/// </summary>
/// <remarks>
/// This is an internal number. In some debug situations an external number may also be supplied in the
/// opensim-request-id header but we are not currently logging this.
/// </remarks>
public int RequestNumber { get; private set; }
private volatile int NotSocketErrors = 0;
public volatile bool HTTPDRunning = false;
@@ -67,7 +82,7 @@ namespace OpenSim.Framework.Servers.HttpServer
protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>();
protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>();
protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
// protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
new Dictionary<string, PollServiceEventArgs>();
@@ -245,29 +260,29 @@ namespace OpenSim.Framework.Servers.HttpServer
return new List<string>(m_pollHandlers.Keys);
}
// Note that the agent string is provided simply to differentiate
// the handlers - it is NOT required to be an actual agent header
// value.
public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
{
lock (m_agentHandlers)
{
if (!m_agentHandlers.ContainsKey(agent))
{
m_agentHandlers.Add(agent, handler);
return true;
}
}
//must already have a handler for that path so return false
return false;
}
public List<string> GetAgentHandlerKeys()
{
lock (m_agentHandlers)
return new List<string>(m_agentHandlers.Keys);
}
// // Note that the agent string is provided simply to differentiate
// // the handlers - it is NOT required to be an actual agent header
// // value.
// public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
// {
// lock (m_agentHandlers)
// {
// if (!m_agentHandlers.ContainsKey(agent))
// {
// m_agentHandlers.Add(agent, handler);
// return true;
// }
// }
//
// //must already have a handler for that path so return false
// return false;
// }
//
// public List<string> GetAgentHandlerKeys()
// {
// lock (m_agentHandlers)
// return new List<string>(m_agentHandlers.Keys);
// }
public bool AddLLSDHandler(string path, LLSDMethod handler)
{
@@ -296,6 +311,8 @@ namespace OpenSim.Framework.Servers.HttpServer
private void OnRequest(object source, RequestEventArgs args)
{
RequestNumber++;
try
{
IHttpClientContext context = (IHttpClientContext)source;
@@ -405,7 +422,6 @@ namespace OpenSim.Framework.Servers.HttpServer
string requestMethod = request.HttpMethod;
string uriString = request.RawUrl;
// string reqnum = "unknown";
int requestStartTick = Environment.TickCount;
// Will be adjusted later on.
@@ -420,24 +436,24 @@ namespace OpenSim.Framework.Servers.HttpServer
// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]);
//m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
Culture.SetCurrentCulture();
// This is the REST agent interface. We require an agent to properly identify
// itself. If the REST handler recognizes the prefix it will attempt to
// satisfy the request. If it is not recognizable, and no damage has occurred
// the request can be passed through to the other handlers. This is a low
// probability event; if a request is matched it is normally expected to be
// handled
IHttpAgentHandler agentHandler;
if (TryGetAgentHandler(request, response, out agentHandler))
{
if (HandleAgentRequest(agentHandler, request, response))
{
requestEndTick = Environment.TickCount;
return;
}
}
// // This is the REST agent interface. We require an agent to properly identify
// // itself. If the REST handler recognizes the prefix it will attempt to
// // satisfy the request. If it is not recognizable, and no damage has occurred
// // the request can be passed through to the other handlers. This is a low
// // probability event; if a request is matched it is normally expected to be
// // handled
// IHttpAgentHandler agentHandler;
//
// if (TryGetAgentHandler(request, response, out agentHandler))
// {
// if (HandleAgentRequest(agentHandler, request, response))
// {
// requestEndTick = Environment.TickCount;
// return;
// }
// }
//response.KeepAlive = true;
response.SendChunked = false;
@@ -449,9 +465,7 @@ namespace OpenSim.Framework.Servers.HttpServer
if (TryGetStreamHandler(handlerKey, out requestHandler))
{
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found stream handler for {0} {1} {2} {3}",
request.HttpMethod, request.Url.PathAndQuery, requestHandler.Name, requestHandler.Description);
LogIncomingToStreamHandler(request, requestHandler);
response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
@@ -528,11 +542,8 @@ namespace OpenSim.Framework.Servers.HttpServer
{
case null:
case "text/html":
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
LogIncomingToContentTypeHandler(request);
buffer = HandleHTTPRequest(request, response);
break;
@@ -540,11 +551,8 @@ namespace OpenSim.Framework.Servers.HttpServer
case "application/llsd+xml":
case "application/xml+llsd":
case "application/llsd+json":
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
LogIncomingToContentTypeHandler(request);
buffer = HandleLLSDRequests(request, response);
break;
@@ -563,9 +571,7 @@ namespace OpenSim.Framework.Servers.HttpServer
if (DoWeHaveALLSDHandler(request.RawUrl))
{
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
LogIncomingToContentTypeHandler(request);
buffer = HandleLLSDRequests(request, response);
}
@@ -573,18 +579,14 @@ namespace OpenSim.Framework.Servers.HttpServer
else if (DoWeHaveAHTTPHandler(request.RawUrl))
{
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
LogIncomingToContentTypeHandler(request);
buffer = HandleHTTPRequest(request, response);
}
else
{
if (DebugLevel >= 3)
m_log.DebugFormat(
"[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}",
request.HttpMethod, request.Url.PathAndQuery);
LogIncomingToXmlRpcHandler(request);
// generic login request.
buffer = HandleXmlRpcRequests(request, response);
@@ -643,14 +645,93 @@ namespace OpenSim.Framework.Servers.HttpServer
if (tickdiff > 3000)
{
m_log.InfoFormat(
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms",
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
RequestNumber,
requestMethod,
uriString,
requestHandler != null ? requestHandler.Name : "",
requestHandler != null ? requestHandler.Description : "",
request.RemoteIPEndPoint.ToString(),
request.RemoteIPEndPoint,
tickdiff);
}
else if (DebugLevel >= 4)
{
m_log.DebugFormat(
"[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms",
RequestNumber,
Port,
tickdiff);
}
}
}
private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler)
{
m_log.DebugFormat(
"[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}",
RequestNumber,
Port,
request.HttpMethod,
request.Url.PathAndQuery,
requestHandler.Name,
requestHandler.Description,
request.RemoteIPEndPoint);
if (DebugLevel >= 5)
LogIncomingInDetail(request);
}
private void LogIncomingToContentTypeHandler(OSHttpRequest request)
{
m_log.DebugFormat(
"[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
RequestNumber,
Port,
(request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType,
request.HttpMethod,
request.Url.PathAndQuery,
request.RemoteIPEndPoint);
if (DebugLevel >= 5)
LogIncomingInDetail(request);
}
private void LogIncomingToXmlRpcHandler(OSHttpRequest request)
{
m_log.DebugFormat(
"[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}",
RequestNumber,
Port,
request.HttpMethod,
request.Url.PathAndQuery,
request.RemoteIPEndPoint);
if (DebugLevel >= 5)
LogIncomingInDetail(request);
}
private void LogIncomingInDetail(OSHttpRequest request)
{
using (StreamReader reader = new StreamReader(Util.Copy(request.InputStream), Encoding.UTF8))
{
string output;
if (DebugLevel == 5)
{
const int sampleLength = 80;
char[] sampleChars = new char[sampleLength + 3];
reader.Read(sampleChars, 0, sampleLength);
sampleChars[80] = '.';
sampleChars[81] = '.';
sampleChars[82] = '.';
output = new string(sampleChars);
}
else
{
output = reader.ReadToEnd();
}
m_log.DebugFormat("[BASE HTTP SERVER]: {0}", output.Replace("\n", @"\n"));
}
}
@@ -746,24 +827,24 @@ namespace OpenSim.Framework.Servers.HttpServer
}
}
private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler)
{
agentHandler = null;
lock (m_agentHandlers)
{
foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
{
if (handler.Match(request, response))
{
agentHandler = handler;
return true;
}
}
}
return false;
}
// private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler)
// {
// agentHandler = null;
//
// lock (m_agentHandlers)
// {
// foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
// {
// if (handler.Match(request, response))
// {
// agentHandler = handler;
// return true;
// }
// }
// }
//
// return false;
// }
/// <summary>
/// Try all the registered xmlrpc handlers when an xmlrpc request is received.
@@ -1201,59 +1282,6 @@ namespace OpenSim.Framework.Servers.HttpServer
map["login"] = OSD.FromString("false");
return map;
}
/// <summary>
/// A specific agent handler was provided. Such a handler is expecetd to have an
/// intimate, and highly specific relationship with the client. Consequently,
/// nothing is done here.
/// </summary>
/// <param name="handler"></param>
/// <param name="request"></param>
/// <param name="response"></param>
private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response)
{
// In the case of REST, then handler is responsible for ALL aspects of
// the request/response handling. Nothing is done here, not even encoding.
try
{
return handler.Handle(request, response);
}
catch (Exception e)
{
// If the handler did in fact close the stream, then this will blow
// chunks. So that that doesn't disturb anybody we throw away any
// and all exceptions raised. We've done our best to release the
// client.
try
{
m_log.Warn("[HTTP-AGENT]: Error - " + e.Message);
response.SendChunked = false;
response.KeepAlive = true;
response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError;
//response.OutputStream.Close();
try
{
response.Send();
//response.FreeContext();
}
catch (SocketException f)
{
// This has to be here to prevent a Linux/Mono crash
m_log.Warn(
String.Format("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux. ", f.Message), f);
}
}
catch(Exception)
{
}
}
// Indicate that the request has been "handled"
return true;
}
public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
{
@@ -1688,21 +1716,21 @@ namespace OpenSim.Framework.Servers.HttpServer
m_pollHandlers.Remove(path);
}
public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
{
lock (m_agentHandlers)
{
IHttpAgentHandler foundHandler;
if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
{
m_agentHandlers.Remove(agent);
return true;
}
}
return false;
}
// public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
// {
// lock (m_agentHandlers)
// {
// IHttpAgentHandler foundHandler;
//
// if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
// {
// m_agentHandlers.Remove(agent);
// return true;
// }
// }
//
// return false;
// }
public void RemoveXmlRPCHandler(string method)
{

View File

@@ -41,10 +41,10 @@ namespace OpenSim.Framework.Servers.HttpServer
uint Port { get; }
bool UseSSL { get; }
// Note that the agent string is provided simply to differentiate
// the handlers - it is NOT required to be an actual agent header
// value.
bool AddAgentHandler(string agent, IHttpAgentHandler handler);
// // Note that the agent string is provided simply to differentiate
// // the handlers - it is NOT required to be an actual agent header
// // value.
// bool AddAgentHandler(string agent, IHttpAgentHandler handler);
/// <summary>
/// Add a handler for an HTTP request.
@@ -106,13 +106,13 @@ namespace OpenSim.Framework.Servers.HttpServer
bool SetDefaultLLSDHandler(DefaultLLSDMethod handler);
/// <summary>
/// Remove the agent if it is registered.
/// </summary>
/// <param name="agent"></param>
/// <param name="handler"></param>
/// <returns></returns>
bool RemoveAgentHandler(string agent, IHttpAgentHandler handler);
// /// <summary>
// /// Remove the agent if it is registered.
// /// </summary>
// /// <param name="agent"></param>
// /// <param name="handler"></param>
// /// <returns></returns>
// bool RemoveAgentHandler(string agent, IHttpAgentHandler handler);
/// <summary>
/// Remove an HTTP handler

View File

@@ -29,6 +29,7 @@ using System;
using System.Collections.Generic;
using System.Reflection;
using System.Net;
using System.Text;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Console;
@@ -47,9 +48,12 @@ namespace OpenSim.Framework.Servers
/// Control the printing of certain debug messages.
/// </summary>
/// <remarks>
/// If DebugLevel >= 1, then short warnings are logged when receiving bad input data.
/// If DebugLevel >= 2, then long warnings are logged when receiving bad input data.
/// If DebugLevel >= 3, then short notices about all incoming non-poll HTTP requests are logged.
/// If DebugLevel >= 1 then short warnings are logged when receiving bad input data.
/// If DebugLevel >= 2 then long warnings are logged when receiving bad input data.
/// If DebugLevel >= 3 then short notices about all incoming non-poll HTTP requests are logged.
/// If DebugLevel >= 4 then the time taken to fulfill the request is logged.
/// If DebugLevel >= 5 then the start of the body of incoming non-poll HTTP requests will be logged.
/// If DebugLevel >= 6 then the entire body of incoming non-poll HTTP requests will be logged.
/// </remarks>
public static int DebugLevel
{
@@ -101,17 +105,28 @@ namespace OpenSim.Framework.Servers
get { return new Dictionary<uint, BaseHttpServer>(m_Servers); }
}
public static void RegisterHttpConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"Debug", false, "debug http", "debug http [<level>]",
"Turn on inbound non-poll http request debugging.",
"If level <= 0, then no extra logging is done.\n"
+ "If level >= 1, then short warnings are logged when receiving bad input data.\n"
+ "If level >= 2, then long warnings are logged when receiving bad input data.\n"
+ "If level >= 3, then short notices about all incoming non-poll HTTP requests are logged.\n"
+ "If no level is specified then the current level is returned.",
"Comms", false, "show http-handlers",
"show http-handlers",
"Show all registered http handlers", HandleShowHttpHandlersCommand);
console.Commands.AddCommand(
"Debug", false, "debug http", "debug http <in|out|all> [<level>]",
"Turn on http request logging.",
"If in or all and\n"
+ " level <= 0 then no extra logging is done.\n"
+ " level >= 1 then short warnings are logged when receiving bad input data.\n"
+ " level >= 2 then long warnings are logged when receiving bad input data.\n"
+ " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n"
+ " level >= 4 then the time taken to fulfill the request is logged.\n"
+ " level >= 5 then a sample from the beginning of the incoming data is logged.\n"
+ " level >= 6 then the entire incoming data is logged.\n"
+ " no level is specified then the current level is returned.\n\n"
+ "If out or all and\n"
+ " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n"
+ " level >= 4 then the time taken to fulfill the request is logged.\n",
HandleDebugHttpCommand);
}
@@ -119,25 +134,120 @@ namespace OpenSim.Framework.Servers
/// Turn on some debugging values for OpenSim.
/// </summary>
/// <param name="args"></param>
private static void HandleDebugHttpCommand(string module, string[] args)
private static void HandleDebugHttpCommand(string module, string[] cmdparams)
{
if (args.Length == 3)
if (cmdparams.Length < 3)
{
int newDebug;
if (int.TryParse(args[2], out newDebug))
{
MainServer.DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug);
}
MainConsole.Instance.Output("Usage: debug http <in|out|all> 0..6");
return;
}
else if (args.Length == 2)
bool inReqs = false;
bool outReqs = false;
bool allReqs = false;
string subCommand = cmdparams[2];
if (subCommand.ToLower() == "in")
{
MainConsole.Instance.OutputFormat("Current debug http level is {0}", MainServer.DebugLevel);
inReqs = true;
}
else if (subCommand.ToLower() == "out")
{
outReqs = true;
}
else if (subCommand.ToLower() == "all")
{
allReqs = true;
}
else
{
MainConsole.Instance.Output("Usage: debug http 0..3");
MainConsole.Instance.Output("You must specify in, out or all");
return;
}
if (cmdparams.Length >= 4)
{
string rawNewDebug = cmdparams[3];
int newDebug;
if (!int.TryParse(rawNewDebug, out newDebug))
{
MainConsole.Instance.OutputFormat("{0} is not a valid debug level", rawNewDebug);
return;
}
if (newDebug < 0 || newDebug > 6)
{
MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0..6", newDebug);
return;
}
if (allReqs || inReqs)
{
MainServer.DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("IN debug level set to {0}", newDebug);
}
if (allReqs || outReqs)
{
WebUtil.DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("OUT debug level set to {0}", newDebug);
}
}
else
{
if (allReqs || inReqs)
MainConsole.Instance.OutputFormat("Current IN debug level is {0}", MainServer.DebugLevel);
if (allReqs || outReqs)
MainConsole.Instance.OutputFormat("Current OUT debug level is {0}", WebUtil.DebugLevel);
}
}
private static void HandleShowHttpHandlersCommand(string module, string[] args)
{
if (args.Length != 2)
{
MainConsole.Instance.Output("Usage: show http-handlers");
return;
}
StringBuilder handlers = new StringBuilder();
lock (m_Servers)
{
foreach (BaseHttpServer httpServer in m_Servers.Values)
{
handlers.AppendFormat(
"Registered HTTP Handlers for server at {0}:{1}\n", httpServer.ListenIPAddress, httpServer.Port);
handlers.AppendFormat("* XMLRPC:\n");
foreach (String s in httpServer.GetXmlRpcHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* HTTP:\n");
List<String> poll = httpServer.GetPollServiceHandlerKeys();
foreach (String s in httpServer.GetHTTPHandlerKeys())
handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
// handlers.AppendFormat("* Agent:\n");
// foreach (String s in httpServer.GetAgentHandlerKeys())
// handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* LLSD:\n");
foreach (String s in httpServer.GetLLSDHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* StreamHandlers ({0}):\n", httpServer.GetStreamHandlerKeys().Count);
foreach (String s in httpServer.GetStreamHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.Append("\n");
}
}
MainConsole.Instance.Output(handlers.ToString());
}
/// <summary>

View File

@@ -0,0 +1,677 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using log4net;
using log4net.Appender;
using log4net.Core;
using log4net.Repository;
using Nini.Config;
using OpenSim.Framework.Console;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Framework.Servers
{
public class ServerBase
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public IConfigSource Config { get; protected set; }
/// <summary>
/// Console to be used for any command line output. Can be null, in which case there should be no output.
/// </summary>
protected ICommandConsole m_console;
protected OpenSimAppender m_consoleAppender;
protected FileAppender m_logFileAppender;
protected DateTime m_startuptime;
protected string m_startupDirectory = Environment.CurrentDirectory;
protected string m_pidFile = String.Empty;
/// <summary>
/// Server version information. Usually VersionInfo + information about git commit, operating system, etc.
/// </summary>
protected string m_version;
public ServerBase()
{
m_startuptime = DateTime.Now;
m_version = VersionInfo.Version;
EnhanceVersionInformation();
}
protected void CreatePIDFile(string path)
{
try
{
string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
using (FileStream fs = File.Create(path))
{
Byte[] buf = Encoding.ASCII.GetBytes(pidstring);
fs.Write(buf, 0, buf.Length);
}
m_pidFile = path;
m_log.InfoFormat("[SERVER BASE]: Created pid file {0}", m_pidFile);
}
catch (Exception e)
{
m_log.Warn(string.Format("[SERVER BASE]: Could not create PID file at {0} ", path), e);
}
}
protected void RemovePIDFile()
{
if (m_pidFile != String.Empty)
{
try
{
File.Delete(m_pidFile);
}
catch (Exception e)
{
m_log.Error(string.Format("[SERVER BASE]: Error whilst removing {0} ", m_pidFile), e);
}
m_pidFile = String.Empty;
}
}
public void RegisterCommonAppenders(IConfig startupConfig)
{
ILoggerRepository repository = LogManager.GetRepository();
IAppender[] appenders = repository.GetAppenders();
foreach (IAppender appender in appenders)
{
if (appender.Name == "Console")
{
m_consoleAppender = (OpenSimAppender)appender;
}
else if (appender.Name == "LogFileAppender")
{
m_logFileAppender = (FileAppender)appender;
}
}
if (null == m_consoleAppender)
{
Notice("No appender named Console found (see the log4net config file for this executable)!");
}
else
{
// FIXME: This should be done through an interface rather than casting.
m_consoleAppender.Console = (ConsoleBase)m_console;
// If there is no threshold set then the threshold is effectively everything.
if (null == m_consoleAppender.Threshold)
m_consoleAppender.Threshold = Level.All;
Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold));
}
if (m_logFileAppender != null && startupConfig != null)
{
string cfgFileName = startupConfig.GetString("LogFile", null);
if (cfgFileName != null)
{
m_logFileAppender.File = cfgFileName;
m_logFileAppender.ActivateOptions();
}
m_log.InfoFormat("[SERVER BASE]: Logging started to file {0}", m_logFileAppender.File);
}
}
/// <summary>
/// Register common commands once m_console has been set if it is going to be set
/// </summary>
public void RegisterCommonCommands()
{
if (m_console == null)
return;
m_console.Commands.AddCommand(
"General", false, "show info", "show info", "Show general information about the server", HandleShow);
m_console.Commands.AddCommand(
"General", false, "show version", "show version", "Show server version", HandleShow);
m_console.Commands.AddCommand(
"General", false, "show uptime", "show uptime", "Show server uptime", HandleShow);
m_console.Commands.AddCommand(
"General", false, "get log level", "get log level", "Get the current console logging level",
(mod, cmd) => ShowLogLevel());
m_console.Commands.AddCommand(
"General", false, "set log level", "set log level <level>",
"Set the console logging level for this session.", HandleSetLogLevel);
m_console.Commands.AddCommand(
"General", false, "config set",
"config set <section> <key> <value>",
"Set a config option. In most cases this is not useful since changed parameters are not dynamically reloaded. Neither do changed parameters persist - you will have to change a config file manually and restart.", HandleConfig);
m_console.Commands.AddCommand(
"General", false, "config get",
"config get [<section>] [<key>]",
"Synonym for config show",
HandleConfig);
m_console.Commands.AddCommand(
"General", false, "config show",
"config show [<section>] [<key>]",
"Show config information",
"If neither section nor field are specified, then the whole current configuration is printed." + Environment.NewLine
+ "If a section is given but not a field, then all fields in that section are printed.",
HandleConfig);
m_console.Commands.AddCommand(
"General", false, "config save",
"config save <path>",
"Save current configuration to a file at the given path", HandleConfig);
m_console.Commands.AddCommand(
"General", false, "command-script",
"command-script <script>",
"Run a command script from file", HandleScript);
m_console.Commands.AddCommand(
"General", false, "show threads",
"show threads",
"Show thread status", HandleShow);
m_console.Commands.AddCommand(
"General", false, "threads abort",
"threads abort <thread-id>",
"Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
m_console.Commands.AddCommand(
"General", false, "threads show",
"threads show",
"Show thread status. Synonym for \"show threads\"",
(string module, string[] args) => Notice(GetThreadsReport()));
m_console.Commands.AddCommand(
"General", false, "force gc",
"force gc",
"Manually invoke runtime garbage collection. For debugging purposes",
HandleForceGc);
}
private void HandleForceGc(string module, string[] args)
{
Notice("Manually invoking runtime garbage collection");
GC.Collect();
}
public virtual void HandleShow(string module, string[] cmd)
{
List<string> args = new List<string>(cmd);
args.RemoveAt(0);
string[] showParams = args.ToArray();
switch (showParams[0])
{
case "info":
ShowInfo();
break;
case "version":
Notice(GetVersionText());
break;
case "uptime":
Notice(GetUptimeReport());
break;
case "threads":
Notice(GetThreadsReport());
break;
}
}
/// <summary>
/// Change and load configuration file data.
/// </summary>
/// <param name="module"></param>
/// <param name="cmd"></param>
private void HandleConfig(string module, string[] cmd)
{
List<string> args = new List<string>(cmd);
args.RemoveAt(0);
string[] cmdparams = args.ToArray();
if (cmdparams.Length > 0)
{
string firstParam = cmdparams[0].ToLower();
switch (firstParam)
{
case "set":
if (cmdparams.Length < 4)
{
Notice("Syntax: config set <section> <key> <value>");
Notice("Example: config set ScriptEngine.DotNetEngine NumberOfScriptThreads 5");
}
else
{
IConfig c;
IConfigSource source = new IniConfigSource();
c = source.AddConfig(cmdparams[1]);
if (c != null)
{
string _value = String.Join(" ", cmdparams, 3, cmdparams.Length - 3);
c.Set(cmdparams[2], _value);
Config.Merge(source);
Notice("In section [{0}], set {1} = {2}", c.Name, cmdparams[2], _value);
}
}
break;
case "get":
case "show":
if (cmdparams.Length == 1)
{
foreach (IConfig config in Config.Configs)
{
Notice("[{0}]", config.Name);
string[] keys = config.GetKeys();
foreach (string key in keys)
Notice(" {0} = {1}", key, config.GetString(key));
}
}
else if (cmdparams.Length == 2 || cmdparams.Length == 3)
{
IConfig config = Config.Configs[cmdparams[1]];
if (config == null)
{
Notice("Section \"{0}\" does not exist.",cmdparams[1]);
break;
}
else
{
if (cmdparams.Length == 2)
{
Notice("[{0}]", config.Name);
foreach (string key in config.GetKeys())
Notice(" {0} = {1}", key, config.GetString(key));
}
else
{
Notice(
"config get {0} {1} : {2}",
cmdparams[1], cmdparams[2], config.GetString(cmdparams[2]));
}
}
}
else
{
Notice("Syntax: config {0} [<section>] [<key>]", firstParam);
Notice("Example: config {0} ScriptEngine.DotNetEngine NumberOfScriptThreads", firstParam);
}
break;
case "save":
if (cmdparams.Length < 2)
{
Notice("Syntax: config save <path>");
return;
}
string path = cmdparams[1];
Notice("Saving configuration file: {0}", path);
if (Config is IniConfigSource)
{
IniConfigSource iniCon = (IniConfigSource)Config;
iniCon.Save(path);
}
else if (Config is XmlConfigSource)
{
XmlConfigSource xmlCon = (XmlConfigSource)Config;
xmlCon.Save(path);
}
break;
}
}
}
private void HandleSetLogLevel(string module, string[] cmd)
{
if (cmd.Length != 4)
{
Notice("Usage: set log level <level>");
return;
}
if (null == m_consoleAppender)
{
Notice("No appender named Console found (see the log4net config file for this executable)!");
return;
}
string rawLevel = cmd[3];
ILoggerRepository repository = LogManager.GetRepository();
Level consoleLevel = repository.LevelMap[rawLevel];
if (consoleLevel != null)
m_consoleAppender.Threshold = consoleLevel;
else
Notice(
"{0} is not a valid logging level. Valid logging levels are ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF",
rawLevel);
ShowLogLevel();
}
private void ShowLogLevel()
{
Notice("Console log level is {0}", m_consoleAppender.Threshold);
}
protected virtual void HandleScript(string module, string[] parms)
{
if (parms.Length != 2)
{
Notice("Usage: command-script <path-to-script");
return;
}
RunCommandScript(parms[1]);
}
/// <summary>
/// Run an optional startup list of commands
/// </summary>
/// <param name="fileName"></param>
protected void RunCommandScript(string fileName)
{
if (m_console == null)
return;
if (File.Exists(fileName))
{
m_log.Info("[SERVER BASE]: Running " + fileName);
using (StreamReader readFile = File.OpenText(fileName))
{
string currentCommand;
while ((currentCommand = readFile.ReadLine()) != null)
{
currentCommand = currentCommand.Trim();
if (!(currentCommand == ""
|| currentCommand.StartsWith(";")
|| currentCommand.StartsWith("//")
|| currentCommand.StartsWith("#")))
{
m_log.Info("[SERVER BASE]: Running '" + currentCommand + "'");
m_console.RunCommand(currentCommand);
}
}
}
}
}
/// <summary>
/// Return a report about the uptime of this server
/// </summary>
/// <returns></returns>
protected string GetUptimeReport()
{
StringBuilder sb = new StringBuilder(String.Format("Time now is {0}\n", DateTime.Now));
sb.Append(String.Format("Server has been running since {0}, {1}\n", m_startuptime.DayOfWeek, m_startuptime));
sb.Append(String.Format("That is an elapsed time of {0}\n", DateTime.Now - m_startuptime));
return sb.ToString();
}
protected void ShowInfo()
{
Notice(GetVersionText());
Notice("Startup directory: " + m_startupDirectory);
if (null != m_consoleAppender)
Notice(String.Format("Console log level: {0}", m_consoleAppender.Threshold));
}
/// <summary>
/// Enhance the version string with extra information if it's available.
/// </summary>
protected void EnhanceVersionInformation()
{
string buildVersion = string.Empty;
// The subversion information is deprecated and will be removed at a later date
// Add subversion revision information if available
// Try file "svn_revision" in the current directory first, then the .svn info.
// This allows to make the revision available in simulators not running from the source tree.
// FIXME: Making an assumption about the directory we're currently in - we do this all over the place
// elsewhere as well
string gitDir = "../.git/";
string gitRefPointerPath = gitDir + "HEAD";
string svnRevisionFileName = "svn_revision";
string svnFileName = ".svn/entries";
string manualVersionFileName = ".version";
string inputLine;
int strcmp;
if (File.Exists(manualVersionFileName))
{
using (StreamReader CommitFile = File.OpenText(manualVersionFileName))
buildVersion = CommitFile.ReadLine();
m_version += buildVersion ?? "";
}
else if (File.Exists(gitRefPointerPath))
{
// m_log.DebugFormat("[SERVER BASE]: Found {0}", gitRefPointerPath);
string rawPointer = "";
using (StreamReader pointerFile = File.OpenText(gitRefPointerPath))
rawPointer = pointerFile.ReadLine();
// m_log.DebugFormat("[SERVER BASE]: rawPointer [{0}]", rawPointer);
Match m = Regex.Match(rawPointer, "^ref: (.+)$");
if (m.Success)
{
// m_log.DebugFormat("[SERVER BASE]: Matched [{0}]", m.Groups[1].Value);
string gitRef = m.Groups[1].Value;
string gitRefPath = gitDir + gitRef;
if (File.Exists(gitRefPath))
{
// m_log.DebugFormat("[SERVER BASE]: Found gitRefPath [{0}]", gitRefPath);
using (StreamReader refFile = File.OpenText(gitRefPath))
{
string gitHash = refFile.ReadLine();
m_version += gitHash.Substring(0, 7);
}
}
}
}
else
{
// Remove the else logic when subversion mirror is no longer used
if (File.Exists(svnRevisionFileName))
{
StreamReader RevisionFile = File.OpenText(svnRevisionFileName);
buildVersion = RevisionFile.ReadLine();
buildVersion.Trim();
RevisionFile.Close();
}
if (string.IsNullOrEmpty(buildVersion) && File.Exists(svnFileName))
{
StreamReader EntriesFile = File.OpenText(svnFileName);
inputLine = EntriesFile.ReadLine();
while (inputLine != null)
{
// using the dir svn revision at the top of entries file
strcmp = String.Compare(inputLine, "dir");
if (strcmp == 0)
{
buildVersion = EntriesFile.ReadLine();
break;
}
else
{
inputLine = EntriesFile.ReadLine();
}
}
EntriesFile.Close();
}
m_version += string.IsNullOrEmpty(buildVersion) ? " " : ("." + buildVersion + " ").Substring(0, 6);
}
}
protected string GetVersionText()
{
return String.Format("Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion);
}
/// <summary>
/// Get a report about the registered threads in this server.
/// </summary>
protected string GetThreadsReport()
{
// This should be a constant field.
string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}";
StringBuilder sb = new StringBuilder();
Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo();
sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine);
int timeNow = Environment.TickCount & Int32.MaxValue;
sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE");
sb.Append(Environment.NewLine);
foreach (Watchdog.ThreadWatchdogInfo twi in threads)
{
Thread t = twi.Thread;
sb.AppendFormat(
reportFormat,
t.ManagedThreadId,
t.Name,
timeNow - twi.LastTick,
timeNow - twi.FirstTick,
t.Priority,
t.ThreadState);
sb.Append("\n");
}
sb.Append("\n");
// For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting
// zero active threads.
int totalThreads = Process.GetCurrentProcess().Threads.Count;
if (totalThreads > 0)
sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
sb.Append("Main threadpool (excluding script engine pools)\n");
sb.Append(Util.GetThreadPoolReport());
return sb.ToString();
}
public virtual void HandleThreadsAbort(string module, string[] cmd)
{
if (cmd.Length != 3)
{
MainConsole.Instance.Output("Usage: threads abort <thread-id>");
return;
}
int threadId;
if (!int.TryParse(cmd[2], out threadId))
{
MainConsole.Instance.Output("ERROR: Thread id must be an integer");
return;
}
if (Watchdog.AbortThread(threadId))
MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId);
else
MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId);
}
/// <summary>
/// Console output is only possible if a console has been established.
/// That is something that cannot be determined within this class. So
/// all attempts to use the console MUST be verified.
/// </summary>
/// <param name="msg"></param>
protected void Notice(string msg)
{
if (m_console != null)
{
m_console.Output(msg);
}
}
/// <summary>
/// Console output is only possible if a console has been established.
/// That is something that cannot be determined within this class. So
/// all attempts to use the console MUST be verified.
/// </summary>
/// <param name="format"></param>
/// <param name="components"></param>
protected void Notice(string format, params object[] components)
{
if (m_console != null)
m_console.OutputFormat(format, components);
}
}
}

View File

@@ -35,11 +35,12 @@ using HttpServer;
using HttpServer.FormDecoders;
using NUnit.Framework;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Tests.Common;
namespace OpenSim.Framework.Servers.Tests
{
[TestFixture]
public class OSHttpTests
public class OSHttpTests : OpenSimTestCase
{
// we need an IHttpClientContext for our tests
public class TestHttpClientContext: IHttpClientContext

View File

@@ -29,11 +29,12 @@ using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using OpenSim.Tests.Common;
namespace OpenSim.Framework.Servers.Tests
{
[TestFixture]
public class VersionInfoTests
public class VersionInfoTests : OpenSimTestCase
{
[Test]
public void TestVersionLength()

View File

@@ -30,7 +30,7 @@ namespace OpenSim
public class VersionInfo
{
private const string VERSION_NUMBER = "0.7.4";
private const Flavour VERSION_FLAVOUR = Flavour.Dev;
private const Flavour VERSION_FLAVOUR = Flavour.Extended;
public enum Flavour
{

View File

@@ -35,10 +35,12 @@ using OpenMetaverse;
namespace OpenSim.Framework
{
/// <summary>
/// A dictionary for task inventory.
/// A dictionary containing task inventory items. Indexed by item UUID.
/// </summary>
/// <remarks>
/// This class is not thread safe. Callers must synchronize on Dictionary methods or Clone() this object before
/// iterating over it.
/// </remarks>
public class TaskInventoryDictionary : Dictionary<UUID, TaskInventoryItem>,
ICloneable, IXmlSerializable
{

View File

@@ -73,9 +73,6 @@ namespace OpenSim.Framework
private bool _ownerChanged = false;
// This used ONLY during copy. It can't be relied on at other times!
private bool _scriptRunning = true;
public UUID AssetID {
get {
return _assetID;
@@ -353,14 +350,13 @@ namespace OpenSim.Framework
}
}
public bool ScriptRunning {
get {
return _scriptRunning;
}
set {
_scriptRunning = value;
}
}
/// <summary>
/// This used ONLY during copy. It can't be relied on at other times!
/// </summary>
/// <remarks>
/// For true script running status, use IEntityInventory.TryGetScriptInstanceRunning() for now.
/// </remarks>
public bool ScriptRunning { get; set; }
// See ICloneable
@@ -388,6 +384,7 @@ namespace OpenSim.Framework
public TaskInventoryItem()
{
ScriptRunning = true;
CreationDate = (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
}
}

View File

@@ -24,16 +24,17 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using NUnit.Framework;
using OpenSim.Tests.Common;
namespace OpenSim.Framework.Tests
{
[TestFixture]
public class AgentCircuitDataTest
public class AgentCircuitDataTest : OpenSimTestCase
{
private UUID AgentId;
private AvatarAppearance AvAppearance;

View File

@@ -38,7 +38,7 @@ using Animation = OpenSim.Framework.Animation;
namespace OpenSim.Framework.Tests
{
[TestFixture]
public class AnimationTests
public class AnimationTests : OpenSimTestCase
{
private Animation anim1 = null;
private Animation anim2 = null;

View File

@@ -30,11 +30,12 @@ using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Tests.Common;
namespace OpenSim.Framework.Tests
{
[TestFixture]
public class AssetBaseTest
public class AssetBaseTest : OpenSimTestCase
{
[Test]
public void TestContainsReferences()

View File

@@ -28,11 +28,12 @@
using System;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Tests.Common;
namespace OpenSim.Framework.Tests
{
[TestFixture]
public class CacheTests
public class CacheTests : OpenSimTestCase
{
private Cache cache;
private UUID cacheItemUUID;

View File

@@ -26,11 +26,12 @@
*/
using NUnit.Framework;
using OpenSim.Tests.Common;
namespace OpenSim.Framework.Tests
{
[TestFixture]
public class LocationTest
public class LocationTest : OpenSimTestCase
{
[Test]
public void locationRegionHandleRegionHandle()

View File

@@ -32,11 +32,12 @@ using OpenMetaverse.StructuredData;
using System;
using System.Globalization;
using System.Threading;
using OpenSim.Tests.Common;
namespace OpenSim.Framework.Tests
{
[TestFixture]
public class MundaneFrameworkTests
public class MundaneFrameworkTests : OpenSimTestCase
{
private bool m_RegionSettingsOnSaveEventFired;
private bool m_RegionLightShareDataOnSaveEventFired;
@@ -302,10 +303,6 @@ namespace OpenSim.Framework.Tests
Culture.SetCurrentCulture();
Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US");
}
}
}
}
}

View File

@@ -31,11 +31,12 @@ using NUnit.Framework;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Tests.Common;
namespace OpenSim.Framework.Tests
{
[TestFixture]
public class PrimeNumberHelperTests
public class PrimeNumberHelperTests : OpenSimTestCase
{
[Test]
public void TestGetPrime()

View File

@@ -33,7 +33,7 @@ using OpenSim.Tests.Common;
namespace OpenSim.Framework.Tests
{
[TestFixture]
public class UtilTests
public class UtilTests : OpenSimTestCase
{
[Test]
public void VectorOperationTests()

View File

@@ -47,9 +47,6 @@ namespace OpenSim.Framework
Texture = 5,
/// <summary>Non-texture assets</summary>
Asset = 6,
/// <summary>Avatar and primitive data</summary>
/// <remarks>This is a sub-category of Task</remarks>
State = 7,
}
[Flags]
@@ -61,6 +58,5 @@ namespace OpenSim.Framework
Task = 1 << 3,
Texture = 1 << 4,
Asset = 1 << 5,
State = 1 << 6,
}
}

View File

@@ -533,6 +533,19 @@ namespace OpenSim.Framework
return (x + y - (min >> 1) - (min >> 2) + (min >> 4));
}
/// <summary>
/// Determines whether a point is inside a bounding box.
/// </summary>
/// <param name='v'></param>
/// <param name='min'></param>
/// <param name='max'></param>
/// <returns></returns>
public static bool IsInsideBox(Vector3 v, Vector3 min, Vector3 max)
{
return v.X >= min.X & v.Y >= min.Y && v.Z >= min.Z
&& v.X <= max.X && v.Y <= max.Y && v.Z <= max.Z;
}
/// <summary>
/// Are the co-ordinates of the new region visible from the old region?
/// </summary>
@@ -850,6 +863,12 @@ namespace OpenSim.Framework
return Math.Min(Math.Max(x, min), max);
}
public static Vector3 Clip(Vector3 vec, float min, float max)
{
return new Vector3(Clip(vec.X, min, max), Clip(vec.Y, min, max),
Clip(vec.Z, min, max));
}
/// <summary>
/// Convert an UUID to a raw uuid string. Right now this is a string without hyphens.
/// </summary>
@@ -1001,6 +1020,38 @@ namespace OpenSim.Framework
}
}
/// <summary>
/// Copy data from one stream to another, leaving the read position of both streams at the beginning.
/// </summary>
/// <param name='inputStream'>
/// Input stream. Must be seekable.
/// </param>
/// <exception cref='ArgumentException'>
/// Thrown if the input stream is not seekable.
/// </exception>
public static Stream Copy(Stream inputStream)
{
if (!inputStream.CanSeek)
throw new ArgumentException("Util.Copy(Stream inputStream) must receive an inputStream that can seek");
const int readSize = 256;
byte[] buffer = new byte[readSize];
MemoryStream ms = new MemoryStream();
int count = inputStream.Read(buffer, 0, readSize);
while (count > 0)
{
ms.Write(buffer, 0, count);
count = inputStream.Read(buffer, 0, readSize);
}
ms.Position = 0;
inputStream.Position = 0;
return ms;
}
public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args)
{
return SendXmlRpcCommand(url, methodName, args);
@@ -1588,7 +1639,13 @@ namespace OpenSim.Framework
if (m_ThreadPool != null)
throw new InvalidOperationException("SmartThreadPool is already initialized");
m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2);
STPStartInfo startInfo = new STPStartInfo();
startInfo.ThreadPoolName = "Util";
startInfo.IdleTimeout = 2000;
startInfo.MaxWorkerThreads = maxThreads;
startInfo.MinWorkerThreads = 2;
m_ThreadPool = new SmartThreadPool(startInfo);
}
public static int FireAndForgetCount()
@@ -1661,7 +1718,7 @@ namespace OpenSim.Framework
break;
case FireAndForgetMethod.SmartThreadPool:
if (m_ThreadPool == null)
m_ThreadPool = new SmartThreadPool(2000, 15, 2);
InitThreadPool(15);
m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj });
break;
case FireAndForgetMethod.Thread:
@@ -1690,12 +1747,16 @@ namespace OpenSim.Framework
StringBuilder sb = new StringBuilder();
if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
{
threadPoolUsed = "SmartThreadPool";
maxThreads = m_ThreadPool.MaxThreads;
minThreads = m_ThreadPool.MinThreads;
inUseThreads = m_ThreadPool.InUseThreads;
allocatedThreads = m_ThreadPool.ActiveThreads;
waitingCallbacks = m_ThreadPool.WaitingCallbacks;
// ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
if (m_ThreadPool != null)
{
threadPoolUsed = "SmartThreadPool";
maxThreads = m_ThreadPool.MaxThreads;
minThreads = m_ThreadPool.MinThreads;
inUseThreads = m_ThreadPool.InUseThreads;
allocatedThreads = m_ThreadPool.ActiveThreads;
waitingCallbacks = m_ThreadPool.WaitingCallbacks;
}
}
else if (
FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem

View File

@@ -53,10 +53,18 @@ namespace OpenSim.Framework
LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Control the printing of certain debug messages.
/// </summary>
/// <remarks>
/// If DebugLevel >= 3 then short notices about outgoing HTTP requests are logged.
/// </remarks>
public static int DebugLevel { get; set; }
/// <summary>
/// Request number for diagnostic purposes.
/// </summary>
public static int RequestNumber = 0;
public static int RequestNumber { get; internal set; }
/// <summary>
/// this is the header field used to communicate the local request id
@@ -146,7 +154,11 @@ namespace OpenSim.Framework
private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed)
{
int reqnum = RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} ServiceOSD {1} {2} (timeout {3}, compressed {4})",
reqnum, method, url, timeout, compressed);
string errorMessage = "unknown error";
int tickstart = Util.EnvironmentTickCount();
@@ -229,7 +241,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > LongCallTime)
m_log.InfoFormat(
"[OSD REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
"[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum,
method,
url,
@@ -238,10 +250,14 @@ namespace OpenSim.Framework
strBuffer != null
? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer)
: "");
else if (DebugLevel >= 4)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
}
m_log.DebugFormat(
"[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage);
"[WEB UTIL]: ServiceOSD request {0} {1} {2} FAILED: {3}", reqnum, url, method, errorMessage);
return ErrorResponseMap(errorMessage);
}
@@ -317,7 +333,11 @@ namespace OpenSim.Framework
{
int reqnum = RequestNumber++;
string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown";
// m_log.DebugFormat("[WEB UTIL]: <{0}> start form request for {1}, method {2}",reqnum,url,method);
if (DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} ServiceForm {1} {2} (timeout {3})",
reqnum, method, url, timeout);
string errorMessage = "unknown error";
int tickstart = Util.EnvironmentTickCount();
@@ -380,7 +400,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > LongCallTime)
m_log.InfoFormat(
"[SERVICE FORM]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
"[WEB UTIL]: Slow ServiceForm request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum,
method,
url,
@@ -389,9 +409,13 @@ namespace OpenSim.Framework
queryString != null
? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString
: "");
else if (DebugLevel >= 4)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
}
m_log.WarnFormat("[SERVICE FORM]: <{0}> form request to {1} failed: {2}", reqnum, url, errorMessage);
m_log.WarnFormat("[WEB UTIL]: ServiceForm request {0} {1} {2} failed: {2}", reqnum, method, url, errorMessage);
return ErrorResponseMap(errorMessage);
}
@@ -643,7 +667,6 @@ namespace OpenSim.Framework
/// <returns></returns>
public static string[] GetPreferredImageTypes(string accept)
{
if (accept == null || accept == string.Empty)
return new string[0];
@@ -695,13 +718,15 @@ namespace OpenSim.Framework
string requestUrl, TRequest obj, Action<TResponse> action)
{
int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} AsynchronousRequestObject {1} {2}",
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount();
int tickdata = 0;
// m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl);
Type type = typeof(TRequest);
WebRequest request = WebRequest.Create(requestUrl);
@@ -854,7 +879,7 @@ namespace OpenSim.Framework
}
m_log.InfoFormat(
"[ASYNC REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
"[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum,
verb,
requestUrl,
@@ -862,6 +887,12 @@ namespace OpenSim.Framework
tickdata,
originalRequest);
}
else if (WebUtil.DebugLevel >= 4)
{
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
}
}
}
@@ -882,7 +913,11 @@ namespace OpenSim.Framework
public static string MakeRequest(string verb, string requestUrl, string obj)
{
int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} SynchronousRestForms {1} {2}",
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount();
int tickdata = 0;
@@ -967,13 +1002,17 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > WebUtil.LongCallTime)
m_log.InfoFormat(
"[FORMS]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
"[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum,
verb,
requestUrl,
tickdiff,
tickdata,
obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
else if (WebUtil.DebugLevel >= 4)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
return respstring;
}
@@ -998,7 +1037,11 @@ namespace OpenSim.Framework
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj)
{
int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} SynchronousRestObject {1} {2}",
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount();
int tickdata = 0;
@@ -1111,7 +1154,7 @@ namespace OpenSim.Framework
}
m_log.InfoFormat(
"[SynchronousRestObjectRequester]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
"[SynchronousRestObjectRequester]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum,
verb,
requestUrl,
@@ -1119,6 +1162,12 @@ namespace OpenSim.Framework
tickdata,
originalRequest);
}
else if (WebUtil.DebugLevel >= 4)
{
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
}
return deserial;
}

View File

@@ -188,7 +188,6 @@ namespace OpenSim
// Make sure command line options take precedence
m_config.Source.Merge(argvSource);
IConfig enVars = m_config.Source.Configs["Environment"];
if( enVars != null )

View File

@@ -35,6 +35,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Timers;
using log4net;
using NDesk.Options;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
@@ -81,8 +82,8 @@ namespace OpenSim
{
base.ReadExtraConfigSettings();
IConfig startupConfig = m_config.Source.Configs["Startup"];
IConfig networkConfig = m_config.Source.Configs["Network"];
IConfig startupConfig = Config.Configs["Startup"];
IConfig networkConfig = Config.Configs["Network"];
int stpMaxThreads = 15;
@@ -105,22 +106,6 @@ namespace OpenSim
m_timeInterval = startupConfig.GetInt("timer_Interval", 1200);
}
if (m_logFileAppender != null)
{
if (m_logFileAppender is log4net.Appender.FileAppender)
{
log4net.Appender.FileAppender appender =
(log4net.Appender.FileAppender)m_logFileAppender;
string fileName = startupConfig.GetString("LogFile", String.Empty);
if (fileName != String.Empty)
{
appender.File = fileName;
appender.ActivateOptions();
}
m_log.InfoFormat("[LOGGING]: Logging started to file {0}", appender.File);
}
}
string asyncCallMethodStr = startupConfig.GetString("async_call_method", String.Empty);
FireAndForgetMethod asyncCallMethod;
if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse<FireAndForgetMethod>(asyncCallMethodStr, out asyncCallMethod))
@@ -163,7 +148,7 @@ namespace OpenSim
break;
case "rest":
m_console = new RemoteConsole("Region");
((RemoteConsole)m_console).ReadConfig(m_config.Source);
((RemoteConsole)m_console).ReadConfig(Config);
break;
default:
m_console = new LocalConsole("Region");
@@ -173,6 +158,7 @@ namespace OpenSim
MainConsole.Instance = m_console;
RegisterCommonAppenders(Config.Configs["Startup"]);
RegisterConsoleCommands();
base.StartupSpecific();
@@ -250,12 +236,6 @@ namespace OpenSim
+ "If an avatar name is given then only packets from that avatar are logged",
Debug);
m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
m_console.Commands.AddCommand("Debug", false, "debug scene",
"debug scene <scripting> <collisions> <physics>",
"Turn on scene debugging", Debug);
m_console.Commands.AddCommand("General", false, "change region",
"change region <region name>",
"Change current console region", ChangeSelectedRegion);
@@ -294,14 +274,13 @@ namespace OpenSim
"save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [<OAR path>]",
"Save a region's data to an OAR archive.",
// "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine
"-h|--home=<url> adds the url of the profile service to the saved user information." + Environment.NewLine
+ "--noassets stops assets being saved to the OAR." + Environment.NewLine
+ "--publish saves an OAR stripped of owner and last owner information." + Environment.NewLine
+ " on reload, the estate owner will be the owner of all objects" + Environment.NewLine
+ " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published" + Environment.NewLine
+ " this option is EXPERIMENTAL" + Environment.NewLine
+ "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR." + Environment.NewLine
+ " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer" + Environment.NewLine
"-h|--home=<url> adds the url of the profile service to the saved user information.\n"
+ "--noassets stops assets being saved to the OAR.\n"
+ "--publish saves an OAR stripped of owner and last owner information.\n"
+ " on reload, the estate owner will be the owner of all objects\n"
+ " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n"
+ "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n"
+ " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n"
+ "The OAR path must be a filesystem path."
+ " If this is not given then the oar is saved to region.oar in the current directory.",
SaveOar);
@@ -311,8 +290,11 @@ namespace OpenSim
"Change the scale of a named prim", HandleEditScale);
m_console.Commands.AddCommand("Users", false, "kick user",
"kick user <first> <last> [message]",
"Kick a user off the simulator", KickUserCommand);
"kick user <first> <last> [--force] [message]",
"Kick a user off the simulator",
"The --force option will kick the user without any checks to see whether it's already in the process of closing\n"
+ "Only use this option if you are sure the avatar is inactive and a normal kick user operation does not removed them",
KickUserCommand);
m_console.Commands.AddCommand("Users", false, "show users",
"show users [full]",
@@ -329,10 +311,6 @@ namespace OpenSim
"show circuits",
"Show agent circuit data", HandleShow);
m_console.Commands.AddCommand("Comms", false, "show http-handlers",
"show http-handlers",
"Show all registered http handlers", HandleShow);
m_console.Commands.AddCommand("Comms", false, "show pending-objects",
"show pending-objects",
"Show # of objects on the pending queues of all scene viewers", HandleShow);
@@ -366,26 +344,6 @@ namespace OpenSim
"restart",
"Restart all sims in this instance", RunCommand);
m_console.Commands.AddCommand("General", false, "config set",
"config set <section> <key> <value>",
"Set a config option. In most cases this is not useful since changed parameters are not dynamically reloaded. Neither do changed parameters persist - you will have to change a config file manually and restart.", HandleConfig);
m_console.Commands.AddCommand("General", false, "config get",
"config get [<section>] [<key>]",
"Synonym for config show",
HandleConfig);
m_console.Commands.AddCommand("General", false, "config show",
"config show [<section>] [<key>]",
"Show config information",
"If neither section nor field are specified, then the whole current configuration is printed." + Environment.NewLine
+ "If a section is given but not a field, then all fields in that section are printed.",
HandleConfig);
m_console.Commands.AddCommand("General", false, "config save",
"config save <path>",
"Save current configuration to a file at the given path", HandleConfig);
m_console.Commands.AddCommand("General", false, "command-script",
"command-script <script>",
"Run a command script from file", RunCommand);
@@ -454,11 +412,17 @@ namespace OpenSim
/// <param name="cmdparams">name of avatar to kick</param>
private void KickUserCommand(string module, string[] cmdparams)
{
if (cmdparams.Length < 4)
bool force = false;
OptionSet options = new OptionSet().Add("f|force", delegate (string v) { force = v != null; });
List<string> mainParams = options.Parse(cmdparams);
if (mainParams.Count < 4)
return;
string alert = null;
if (cmdparams.Length > 4)
if (mainParams.Count > 4)
alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4));
IList agents = SceneManager.GetCurrentSceneAvatars();
@@ -467,8 +431,8 @@ namespace OpenSim
{
RegionInfo regionInfo = presence.Scene.RegionInfo;
if (presence.Firstname.ToLower().Contains(cmdparams[2].ToLower()) &&
presence.Lastname.ToLower().Contains(cmdparams[3].ToLower()))
if (presence.Firstname.ToLower().Contains(mainParams[2].ToLower()) &&
presence.Lastname.ToLower().Contains(mainParams[3].ToLower()))
{
MainConsole.Instance.Output(
String.Format(
@@ -481,42 +445,13 @@ namespace OpenSim
else
presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n");
presence.Scene.IncomingCloseAgent(presence.UUID);
presence.Scene.IncomingCloseAgent(presence.UUID, force);
}
}
MainConsole.Instance.Output("");
}
/// <summary>
/// Run an optional startup list of commands
/// </summary>
/// <param name="fileName"></param>
private void RunCommandScript(string fileName)
{
if (File.Exists(fileName))
{
m_log.Info("[COMMANDFILE]: Running " + fileName);
using (StreamReader readFile = File.OpenText(fileName))
{
string currentCommand;
while ((currentCommand = readFile.ReadLine()) != null)
{
currentCommand = currentCommand.Trim();
if (!(currentCommand == ""
|| currentCommand.StartsWith(";")
|| currentCommand.StartsWith("//")
|| currentCommand.StartsWith("#")))
{
m_log.Info("[COMMANDFILE]: Running '" + currentCommand + "'");
m_console.RunCommand(currentCommand);
}
}
}
}
}
/// <summary>
/// Opens a file and uses it as input to the console command parser.
/// </summary>
@@ -621,111 +556,9 @@ namespace OpenSim
bool changed = PopulateRegionEstateInfo(regInfo);
IScene scene;
CreateRegion(regInfo, true, out scene);
if (changed)
regInfo.EstateSettings.Save();
}
/// <summary>
/// Change and load configuration file data.
/// </summary>
/// <param name="module"></param>
/// <param name="cmd"></param>
private void HandleConfig(string module, string[] cmd)
{
List<string> args = new List<string>(cmd);
args.RemoveAt(0);
string[] cmdparams = args.ToArray();
if (cmdparams.Length > 0)
{
string firstParam = cmdparams[0].ToLower();
switch (firstParam)
{
case "set":
if (cmdparams.Length < 4)
{
Notice("Syntax: config set <section> <key> <value>");
Notice("Example: config set ScriptEngine.DotNetEngine NumberOfScriptThreads 5");
}
else
{
IConfig c;
IConfigSource source = new IniConfigSource();
c = source.AddConfig(cmdparams[1]);
if (c != null)
{
string _value = String.Join(" ", cmdparams, 3, cmdparams.Length - 3);
c.Set(cmdparams[2], _value);
m_config.Source.Merge(source);
Notice("In section [{0}], set {1} = {2}", c.Name, cmdparams[2], _value);
}
}
break;
case "get":
case "show":
if (cmdparams.Length == 1)
{
foreach (IConfig config in m_config.Source.Configs)
{
Notice("[{0}]", config.Name);
string[] keys = config.GetKeys();
foreach (string key in keys)
Notice(" {0} = {1}", key, config.GetString(key));
}
}
else if (cmdparams.Length == 2 || cmdparams.Length == 3)
{
IConfig config = m_config.Source.Configs[cmdparams[1]];
if (config == null)
{
Notice("Section \"{0}\" does not exist.",cmdparams[1]);
break;
}
else
{
if (cmdparams.Length == 2)
{
Notice("[{0}]", config.Name);
foreach (string key in config.GetKeys())
Notice(" {0} = {1}", key, config.GetString(key));
}
else
{
Notice(
"config get {0} {1} : {2}",
cmdparams[1], cmdparams[2], config.GetString(cmdparams[2]));
}
}
}
else
{
Notice("Syntax: config {0} [<section>] [<key>]", firstParam);
Notice("Example: config {0} ScriptEngine.DotNetEngine NumberOfScriptThreads", firstParam);
}
break;
case "save":
if (cmdparams.Length < 2)
{
Notice("Syntax: config save <path>");
return;
}
if (Application.iniFilePath == cmdparams[1])
{
Notice("Path can not be " + Application.iniFilePath);
return;
}
Notice("Saving configuration file: " + cmdparams[1]);
m_config.Save(cmdparams[1]);
break;
}
}
regInfo.EstateSettings.Save();
}
/// <summary>
@@ -794,13 +627,6 @@ namespace OpenSim
switch (command)
{
case "command-script":
if (cmdparams.Length > 0)
{
RunCommandScript(cmdparams[0]);
}
break;
case "backup":
MainConsole.Instance.Output("Triggering save of pending object updates to persistent store");
SceneManager.BackupCurrentScene();
@@ -844,12 +670,20 @@ namespace OpenSim
if (!SceneManager.TrySetCurrentScene(newRegionName))
MainConsole.Instance.Output(String.Format("Couldn't select region {0}", newRegionName));
else
RefreshPrompt();
}
else
{
MainConsole.Instance.Output("Usage: change region <region name>");
}
}
/// <summary>
/// Refreshs prompt with the current selection details.
/// </summary>
private void RefreshPrompt()
{
string regionName = (SceneManager.CurrentScene == null ? "root" : SceneManager.CurrentScene.RegionInfo.RegionName);
MainConsole.Instance.Output(String.Format("Currently selected region is {0}", regionName));
@@ -871,6 +705,18 @@ namespace OpenSim
m_console.ConsoleScene = SceneManager.CurrentScene;
}
protected override void HandleRestartRegion(RegionInfo whichRegion)
{
base.HandleRestartRegion(whichRegion);
// Where we are restarting multiple scenes at once, a previous call to RefreshPrompt may have set the
// m_console.ConsoleScene to null (indicating all scenes).
if (m_console.ConsoleScene != null && whichRegion.RegionName == ((Scene)m_console.ConsoleScene).Name)
SceneManager.TrySetCurrentScene(whichRegion.RegionName);
RefreshPrompt();
}
/// <summary>
/// Turn on some debugging values for OpenSim.
/// </summary>
@@ -904,30 +750,6 @@ namespace OpenSim
break;
case "scene":
if (args.Length == 4)
{
if (SceneManager.CurrentScene == null)
{
MainConsole.Instance.Output("Please use 'change region <regioname>' first");
}
else
{
string key = args[2];
string value = args[3];
SceneManager.CurrentScene.SetSceneCoreDebug(
new Dictionary<string, string>() { { key, value } });
MainConsole.Instance.OutputFormat("Set debug scene {0} = {1}", key, value);
}
}
else
{
MainConsole.Instance.Output("Usage: debug scene scripting|collisions|physics|teleport true|false");
}
break;
default:
MainConsole.Instance.Output("Unknown debug command");
break;
@@ -1003,33 +825,6 @@ namespace OpenSim
HandleShowCircuits();
break;
case "http-handlers":
System.Text.StringBuilder handlers = new System.Text.StringBuilder("Registered HTTP Handlers:\n");
handlers.AppendFormat("* XMLRPC:\n");
foreach (String s in HttpServer.GetXmlRpcHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* HTTP:\n");
List<String> poll = HttpServer.GetPollServiceHandlerKeys();
foreach (String s in HttpServer.GetHTTPHandlerKeys())
handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
handlers.AppendFormat("* Agent:\n");
foreach (String s in HttpServer.GetAgentHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* LLSD:\n");
foreach (String s in HttpServer.GetLLSDHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* StreamHandlers ({0}):\n", HttpServer.GetStreamHandlerKeys().Count);
foreach (String s in HttpServer.GetStreamHandlerKeys())
handlers.AppendFormat("\t{0}\n", s);
MainConsole.Instance.Output(handlers.ToString());
break;
case "modules":
MainConsole.Instance.Output("The currently loaded shared modules are:");
foreach (IRegionModule module in m_moduleLoader.GetLoadedSharedModules)
@@ -1124,7 +919,7 @@ namespace OpenSim
aCircuit.Name,
aCircuit.child ? "child" : "root",
aCircuit.circuitcode.ToString(),
aCircuit.IPAddress.ToString(),
aCircuit.IPAddress != null ? aCircuit.IPAddress.ToString() : "not set",
aCircuit.Viewer);
});

View File

@@ -100,13 +100,7 @@ namespace OpenSim
/// <value>
/// The config information passed into the OpenSimulator region server.
/// </value>
public OpenSimConfigSource ConfigSource
{
get { return m_config; }
set { m_config = value; }
}
protected OpenSimConfigSource m_config;
public OpenSimConfigSource ConfigSource { get; private set; }
public List<IClientNetworkServer> ClientServers
{
@@ -154,13 +148,14 @@ namespace OpenSim
protected virtual void LoadConfigSettings(IConfigSource configSource)
{
m_configLoader = new ConfigurationLoader();
m_config = m_configLoader.LoadConfigSettings(configSource, envConfigSource, out m_configSettings, out m_networkServersInfo);
ConfigSource = m_configLoader.LoadConfigSettings(configSource, envConfigSource, out m_configSettings, out m_networkServersInfo);
Config = ConfigSource.Source;
ReadExtraConfigSettings();
}
protected virtual void ReadExtraConfigSettings()
{
IConfig networkConfig = m_config.Source.Configs["Network"];
IConfig networkConfig = Config.Configs["Network"];
if (networkConfig != null)
{
proxyUrl = networkConfig.GetString("proxy_url", "");
@@ -193,7 +188,7 @@ namespace OpenSim
/// </summary>
protected override void StartupSpecific()
{
IConfig startupConfig = m_config.Source.Configs["Startup"];
IConfig startupConfig = Config.Configs["Startup"];
if (startupConfig != null)
{
string pidFile = startupConfig.GetString("PIDFile", String.Empty);
@@ -204,29 +199,41 @@ namespace OpenSim
}
// Load the simulation data service
IConfig simDataConfig = m_config.Source.Configs["SimulationDataStore"];
IConfig simDataConfig = Config.Configs["SimulationDataStore"];
if (simDataConfig == null)
throw new Exception("Configuration file is missing the [SimulationDataStore] section. Have you copied OpenSim.ini.example to OpenSim.ini to reference config-include/ files?");
string module = simDataConfig.GetString("LocalServiceModule", String.Empty);
if (String.IsNullOrEmpty(module))
throw new Exception("Configuration file is missing the LocalServiceModule parameter in the [SimulationDataStore] section.");
m_simulationDataService = ServerUtils.LoadPlugin<ISimulationDataService>(module, new object[] { m_config.Source });
m_simulationDataService = ServerUtils.LoadPlugin<ISimulationDataService>(module, new object[] { Config });
if (m_simulationDataService == null)
throw new Exception(
string.Format(
"Could not load an ISimulationDataService implementation from {0}, as configured in the LocalServiceModule parameter of the [SimulationDataStore] config section.",
module));
// Load the estate data service
IConfig estateDataConfig = m_config.Source.Configs["EstateDataStore"];
IConfig estateDataConfig = Config.Configs["EstateDataStore"];
if (estateDataConfig == null)
throw new Exception("Configuration file is missing the [EstateDataStore] section. Have you copied OpenSim.ini.example to OpenSim.ini to reference config-include/ files?");
module = estateDataConfig.GetString("LocalServiceModule", String.Empty);
if (String.IsNullOrEmpty(module))
throw new Exception("Configuration file is missing the LocalServiceModule parameter in the [EstateDataStore] section");
m_estateDataService = ServerUtils.LoadPlugin<IEstateDataService>(module, new object[] { m_config.Source });
m_estateDataService = ServerUtils.LoadPlugin<IEstateDataService>(module, new object[] { Config });
if (m_estateDataService == null)
throw new Exception(
string.Format(
"Could not load an IEstateDataService implementation from {0}, as configured in the LocalServiceModule parameter of the [EstateDataStore] config section.",
module));
base.StartupSpecific();
m_stats = StatsManager.SimExtraStats;
// Create a ModuleLoader instance
m_moduleLoader = new ModuleLoader(m_config.Source);
m_moduleLoader = new ModuleLoader(Config);
LoadPlugins();
foreach (IApplicationPlugin plugin in m_plugins)
@@ -234,51 +241,51 @@ namespace OpenSim
plugin.PostInitialise();
}
AddPluginCommands();
}
protected virtual void AddPluginCommands()
{
// If console exists add plugin commands.
if (m_console != null)
{
List<string> topics = GetHelpTopics();
StatsManager.RegisterConsoleCommands(m_console);
AddPluginCommands(m_console);
}
}
foreach (string topic in topics)
protected virtual void AddPluginCommands(ICommandConsole console)
{
List<string> topics = GetHelpTopics();
foreach (string topic in topics)
{
string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
// This is a hack to allow the user to enter the help command in upper or lowercase. This will go
// away at some point.
console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
ICommander commander = null;
Scene s = SceneManager.CurrentOrFirstScene;
if (s != null && s.GetCommanders() != null)
{
string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
if (s.GetCommanders().ContainsKey(topic))
commander = s.GetCommanders()[topic];
}
// This is a hack to allow the user to enter the help command in upper or lowercase. This will go
// away at some point.
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
if (commander == null)
continue;
ICommander commander = null;
Scene s = SceneManager.CurrentOrFirstScene;
if (s != null && s.GetCommanders() != null)
{
if (s.GetCommanders().ContainsKey(topic))
commander = s.GetCommanders()[topic];
}
if (commander == null)
continue;
foreach (string command in commander.Commands.Keys)
{
m_console.Commands.AddCommand(capitalizedTopic, false,
topic + " " + command,
topic + " " + commander.Commands[command].ShortHelp(),
String.Empty, HandleCommanderCommand);
}
foreach (string command in commander.Commands.Keys)
{
console.Commands.AddCommand(capitalizedTopic, false,
topic + " " + command,
topic + " " + commander.Commands[command].ShortHelp(),
String.Empty, HandleCommanderCommand);
}
}
}
@@ -303,10 +310,15 @@ namespace OpenSim
// Called from base.StartUp()
m_httpServerPort = m_networkServersInfo.HttpListenerPort;
SceneManager.OnRestartSim += handleRestartRegion;
SceneManager.OnRestartSim += HandleRestartRegion;
// Only start the memory watchdog once all regions are ready
SceneManager.OnRegionsReadyStatusChange += sm => MemoryWatchdog.Enabled = sm.AllRegionsReady;
// Only enable the watchdogs when all regions are ready. Otherwise we get false positives when cpu is
// heavily used during initial startup.
//
// FIXME: It's also possible that region ready status should be flipped during an OAR load since this
// also makes heavy use of the CPU.
SceneManager.OnRegionsReadyStatusChange
+= sm => { MemoryWatchdog.Enabled = sm.AllRegionsReady; Watchdog.Enabled = sm.AllRegionsReady; };
}
/// <summary>
@@ -363,7 +375,7 @@ namespace OpenSim
}
IClientNetworkServer clientServer;
Scene scene = SetupScene(regionInfo, proxyOffset, m_config.Source, out clientServer);
Scene scene = SetupScene(regionInfo, proxyOffset, Config, out clientServer);
m_log.Info("[MODULES]: Loading Region's modules (old style)");
@@ -458,10 +470,10 @@ namespace OpenSim
string estateOwnerPassword = null;
string rawEstateOwnerUuid = null;
if (m_config.Source.Configs[ESTATE_SECTION_NAME] != null)
if (Config.Configs[ESTATE_SECTION_NAME] != null)
{
string defaultEstateOwnerName
= m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerName", "").Trim();
= Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerName", "").Trim();
string[] ownerNames = defaultEstateOwnerName.Split(' ');
if (ownerNames.Length >= 2)
@@ -471,9 +483,9 @@ namespace OpenSim
}
// Info to be used only on Standalone Mode
rawEstateOwnerUuid = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerUUID", null);
estateOwnerEMail = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerEMail", null);
estateOwnerPassword = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerPassword", null);
rawEstateOwnerUuid = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerUUID", null);
estateOwnerEMail = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerEMail", null);
estateOwnerPassword = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerPassword", null);
}
MainConsole.Instance.OutputFormat("Estate {0} has no owner set.", regionInfo.EstateSettings.EstateName);
@@ -540,7 +552,7 @@ namespace OpenSim
if (account == null)
{
m_log.ErrorFormat(
"[OPENSIM]: Unable to store account. If this simulator is connected to a grid, you must create the estate owner account first.");
"[OPENSIM]: Unable to store account. If this simulator is connected to a grid, you must create the estate owner account first at the grid level.");
}
else
{
@@ -720,7 +732,7 @@ namespace OpenSim
return new Scene(
regionInfo, circuitManager, sceneGridService,
simDataService, estateDataService, m_moduleLoader, false,
m_config.Source, m_version);
Config, m_version);
}
protected void ShutdownClientServer(RegionInfo whichRegion)
@@ -747,9 +759,11 @@ namespace OpenSim
}
}
public void handleRestartRegion(RegionInfo whichRegion)
protected virtual void HandleRestartRegion(RegionInfo whichRegion)
{
m_log.Info("[OPENSIM]: Got restart signal from SceneManager");
m_log.InfoFormat(
"[OPENSIM]: Got restart signal from SceneManager for region {0} ({1},{2})",
whichRegion.RegionName, whichRegion.RegionLocX, whichRegion.RegionLocY);
ShutdownClientServer(whichRegion);
IScene scene;
@@ -761,7 +775,7 @@ namespace OpenSim
protected override PhysicsScene GetPhysicsScene(string osSceneIdentifier)
{
return GetPhysicsScene(
m_configSettings.PhysicsEngine, m_configSettings.MeshEngineName, m_config.Source, osSceneIdentifier);
m_configSettings.PhysicsEngine, m_configSettings.MeshEngineName, Config, osSceneIdentifier);
}
/// <summary>
@@ -895,7 +909,6 @@ namespace OpenSim
m_log.Info("[SHUTDOWN]: Closing all threads");
m_log.Info("[SHUTDOWN]: Killing listener thread");
m_log.Info("[SHUTDOWN]: Killing clients");
// TODO: implement this
m_log.Info("[SHUTDOWN]: Closing console and terminating");
try
@@ -904,7 +917,7 @@ namespace OpenSim
}
catch (Exception e)
{
m_log.ErrorFormat("[SHUTDOWN]: Ignoring failure during shutdown - {0}", e);
m_log.Error("[SHUTDOWN]: Ignoring failure during shutdown - ", e);
}
}
@@ -998,9 +1011,9 @@ namespace OpenSim
string defaultEstateName = null;
if (m_config.Source.Configs[ESTATE_SECTION_NAME] != null)
if (Config.Configs[ESTATE_SECTION_NAME] != null)
{
defaultEstateName = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateName", null);
defaultEstateName = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateName", null);
if (defaultEstateName != null)
{
@@ -1083,28 +1096,14 @@ namespace OpenSim
MainConsole.Instance.Output("Joining the estate failed. Please try again.");
}
}
}
}
return true; // need to update the database
}
return true; // need to update the database
}
}
public class OpenSimConfigSource
{
public IConfigSource Source;
public void Save(string path)
{
if (Source is IniConfigSource)
{
IniConfigSource iniCon = (IniConfigSource) Source;
iniCon.Save(path);
}
else if (Source is XmlConfigSource)
{
XmlConfigSource xmlCon = (XmlConfigSource) Source;
xmlCon.Save(path);
}
}
}
}

View File

@@ -96,8 +96,8 @@ namespace OpenSim.Region.ClientStack.Linden
// private static readonly string m_fetchInventoryPath = "0006/";
private static readonly string m_copyFromNotecardPath = "0007/";
// private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
private static readonly string m_UpdateAgentInformationPath = "0500/";
// These are callbacks which will be setup by the scene so that we can update scene data when we
// receive capability calls
public NewInventoryItem AddNewInventoryItem = null;
@@ -123,9 +123,14 @@ namespace OpenSim.Region.ClientStack.Linden
IConfig sconfig = config.Configs["Startup"];
if (sconfig != null)
{
m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
m_levelUpload = sconfig.GetInt("LevelUpload", 0);
}
IConfig appearanceConfig = config.Configs["Appearance"];
if (appearanceConfig != null)
{
m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
}
}
m_assetService = m_Scene.AssetService;
@@ -158,8 +163,8 @@ namespace OpenSim.Region.ClientStack.Linden
m_HostCapsObj.RegisterHandler(
"SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null));
m_log.DebugFormat(
"[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
// m_log.DebugFormat(
// "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
//m_capsHandlers["MapLayer"] =
// new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
@@ -199,6 +204,8 @@ namespace OpenSim.Region.ClientStack.Linden
m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
m_HostCapsObj.RegisterHandler(
"CopyInventoryFromNotecard",
@@ -249,11 +256,12 @@ namespace OpenSim.Region.ClientStack.Linden
public string SeedCapRequest(string request, string path, string param,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
// m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName);
m_log.DebugFormat(
"[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
{
m_log.DebugFormat(
m_log.WarnFormat(
"[CAPS]: Unauthorized CAPS client {0} from {1}",
m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint);
@@ -849,6 +857,22 @@ namespace OpenSim.Region.ClientStack.Linden
response["int_response_code"] = 200;
return LLSDHelpers.SerialiseLLSDReply(response);
}
public string UpdateAgentInformation(string request, string path,
string param, IOSHttpRequest httpRequest,
IOSHttpResponse httpResponse)
{
OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
OSDMap resp = new OSDMap();
OSDMap accessPrefs = new OSDMap();
accessPrefs["max"] = "A";
resp["access_prefs"] = accessPrefs;
string response = OSDParser.SerializeLLSDXmlString(resp);
return response;
}
}
public class AssetUploader

View File

@@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden
//scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack);
scene.EventManager.OnNewClient += OnNewClient;
// scene.EventManager.OnNewClient += OnNewClient;
// TODO: Leaving these open, or closing them when we
// become a child is incorrect. It messes up TP in a big
@@ -102,6 +102,7 @@ namespace OpenSim.Region.ClientStack.Linden
// circuit is there.
scene.EventManager.OnClientClosed += ClientClosed;
scene.EventManager.OnMakeChildAgent += MakeChildAgent;
scene.EventManager.OnRegisterCaps += OnRegisterCaps;
@@ -110,10 +111,10 @@ namespace OpenSim.Region.ClientStack.Linden
false,
"debug eq",
"debug eq [0|1|2]",
"Turn on event queue debugging"
+ "<= 0 - turns off all event queue logging"
+ ">= 1 - turns on outgoing event logging"
+ ">= 2 - turns on poll notification",
"Turn on event queue debugging\n"
+ " <= 0 - turns off all event queue logging\n"
+ " >= 1 - turns on outgoing event logging\n"
+ " >= 2 - turns on poll notification",
HandleDebugEq);
}
else
@@ -226,16 +227,6 @@ namespace OpenSim.Region.ClientStack.Linden
#endregion
private void OnNewClient(IClientAPI client)
{
//client.OnLogout += ClientClosed;
}
// private void ClientClosed(IClientAPI client)
// {
// ClientClosed(client.AgentId);
// }
private void ClientClosed(UUID agentID, Scene scene)
{
// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);

View File

@@ -44,7 +44,7 @@ using OpenSim.Tests.Common.Mock;
namespace OpenSim.Region.ClientStack.Linden.Tests
{
[TestFixture]
public class EventQueueTests
public class EventQueueTests : OpenSimTestCase
{
private TestScene m_scene;
@@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
UUID spId = TestHelpers.ParseTail(0x1);
SceneHelpers.AddScenePresence(m_scene, spId);
m_scene.IncomingCloseAgent(spId);
m_scene.IncomingCloseAgent(spId, false);
// TODO: Add more assertions for the other aspects of event queues
Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));

View File

@@ -66,9 +66,9 @@ namespace OpenSim.Region.ClientStack.Linden
public void Initialise(IConfigSource source)
{
IConfig sconfig = source.Configs["Startup"];
if (sconfig != null)
m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
IConfig appearanceConfig = source.Configs["Appearance"];
if (appearanceConfig != null)
m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
}
public void AddRegion(Scene s)

View File

@@ -45,7 +45,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public Packet Packet;
/// <summary>
/// Default constructor
/// No arg constructor.
/// </summary>
public IncomingPacket() {}
/// <summary>
/// Constructor
/// </summary>
/// <param name="client">Reference to the client this packet came from</param>
/// <param name="packet">Packet data</param>

View File

@@ -346,7 +346,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private int m_moneyBalance;
private int m_animationSequenceNumber = 1;
private bool m_SendLogoutPacketWhenClosing = true;
private AgentUpdateArgs lastarg;
/// <summary>
/// We retain a single AgentUpdateArgs so that we can constantly reuse it rather than construct a new one for
/// every single incoming AgentUpdate. Every client sends 10 AgentUpdate UDP messages per second, even if it
/// is doing absolutely nothing.
/// </summary>
/// <remarks>
/// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
/// cannot retain a reference to it outside of that method.
/// </remarks>
private AgentUpdateArgs m_lastAgentUpdateArgs;
protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -487,16 +497,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Client Methods
/// <summary>
/// Close down the client view
/// </summary>
public void Close()
{
Close(false);
}
public void Close(bool force)
{
// We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
// a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
lock (CloseSyncLock)
{
if (!IsActive)
// We still perform a force close inside the sync lock since this is intended to attempt close where
// there is some unidentified connection problem, not where we have issues due to deadlock
if (!IsActive && !force)
return;
IsActive = false;
@@ -802,8 +816,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(mov, ThrottleOutPacketType.Unknown);
}
public void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName,
UUID fromAgentID, byte source, byte audible)
public void SendChatMessage(
string message, byte type, Vector3 fromPos, string fromName,
UUID fromAgentID, UUID ownerID, byte source, byte audible)
{
ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator);
reply.ChatData.Audible = audible;
@@ -812,7 +827,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
reply.ChatData.SourceType = source;
reply.ChatData.Position = fromPos;
reply.ChatData.FromName = Util.StringToBytes256(fromName);
reply.ChatData.OwnerID = fromAgentID;
reply.ChatData.OwnerID = ownerID;
reply.ChatData.SourceID = fromAgentID;
OutPacket(reply, ThrottleOutPacketType.Task);
@@ -1572,7 +1587,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null)
{
OutPacket(kill, ThrottleOutPacketType.State);
OutPacket(kill, ThrottleOutPacketType.Task);
}
else
{
@@ -3917,7 +3932,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -3962,7 +3979,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4447,37 +4467,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (bl[i].BannedUserID == UUID.Zero)
continue;
BannedUsers.Add(bl[i].BannedUserID);
if (BannedUsers.Count >= 50 || (i == (bl.Length - 1) && BannedUsers.Count > 0))
{
EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
packet.AgentData.TransactionID = UUID.Random();
packet.AgentData.AgentID = AgentId;
packet.AgentData.SessionID = SessionId;
packet.MethodData.Invoice = invoice;
packet.MethodData.Method = Utils.StringToBytes("setaccess");
EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + BannedUsers.Count];
int j;
for (j = 0; j < (6 + BannedUsers.Count); j++)
{
returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock();
}
j = 0;
returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++;
returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++;
returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
returnblock[j].Parameter = Utils.StringToBytes(BannedUsers.Count.ToString()); j++;
returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
foreach (UUID banned in BannedUsers)
{
returnblock[j].Parameter = banned.GetBytes(); j++;
}
packet.ParamList = returnblock;
packet.Header.Reliable = true;
OutPacket(packet, ThrottleOutPacketType.Task);
BannedUsers.Clear();
}
}
EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
packet.AgentData.TransactionID = UUID.Random();
packet.AgentData.AgentID = AgentId;
packet.AgentData.SessionID = SessionId;
packet.MethodData.Invoice = invoice;
packet.MethodData.Method = Utils.StringToBytes("setaccess");
EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + BannedUsers.Count];
for (int i = 0; i < (6 + BannedUsers.Count); i++)
{
returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock();
}
int j = 0;
returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++;
returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++;
returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
returnblock[j].Parameter = Utils.StringToBytes(BannedUsers.Count.ToString()); j++;
returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
foreach (UUID banned in BannedUsers)
{
returnblock[j].Parameter = banned.GetBytes(); j++;
}
packet.ParamList = returnblock;
packet.Header.Reliable = false;
OutPacket(packet, ThrottleOutPacketType.Task);
}
public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args)
@@ -4947,7 +4974,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock();
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
= PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
block.Data = data;
if (textureEntry != null && textureEntry.Length > 0)
@@ -5179,14 +5208,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected virtual void RegisterLocalPacketHandlers()
{
AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout);
// If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
// for each AgentUpdate packet.
AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false);
AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest, false);
AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest, false);
AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest);
AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest);
AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage);
AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest);
AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer);
@@ -5286,9 +5319,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
AddLocalPacketHandler(PacketType.RemoveTaskInventory, HandleRemoveTaskInventory);
AddLocalPacketHandler(PacketType.MoveTaskInventory, HandleMoveTaskInventory);
AddLocalPacketHandler(PacketType.RezScript, HandleRezScript);
AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest, false);
AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest, false);
AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest, false);
AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest);
AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest);
AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest);
AddLocalPacketHandler(PacketType.TeleportLandmarkRequest, HandleTeleportLandmarkRequest);
AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
@@ -5406,80 +5439,83 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Scene/Avatar
private bool HandleAgentUpdate(IClientAPI sener, Packet Pack)
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
{
if (OnAgentUpdate != null)
{
bool update = false;
AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack;
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
#region Packet Session and User Check
if (agenUpdate.AgentData.SessionID != SessionId || agenUpdate.AgentData.AgentID != AgentId)
if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
{
PacketPool.Instance.ReturnPacket(packet);
return false;
}
#endregion
AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData;
bool update = false;
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
// We can only check when we have something to check
// against.
if (lastarg != null)
if (m_lastAgentUpdateArgs != null)
{
// These should be ordered from most-likely to
// least likely to change. I've made an initial
// guess at that.
update =
(
(x.BodyRotation != lastarg.BodyRotation) ||
(x.CameraAtAxis != lastarg.CameraAtAxis) ||
(x.CameraCenter != lastarg.CameraCenter) ||
(x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
(x.CameraUpAxis != lastarg.CameraUpAxis) ||
(x.ControlFlags != lastarg.ControlFlags) ||
(x.Far != lastarg.Far) ||
(x.Flags != lastarg.Flags) ||
(x.State != lastarg.State) ||
(x.HeadRotation != lastarg.HeadRotation) ||
(x.SessionID != lastarg.SessionID) ||
(x.AgentID != lastarg.AgentID)
(x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
(x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
(x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
(x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
(x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
(x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
(x.Far != m_lastAgentUpdateArgs.Far) ||
(x.Flags != m_lastAgentUpdateArgs.Flags) ||
(x.State != m_lastAgentUpdateArgs.State) ||
(x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
(x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
(x.AgentID != m_lastAgentUpdateArgs.AgentID)
);
}
else
{
m_lastAgentUpdateArgs = new AgentUpdateArgs();
update = true;
}
// These should be ordered from most-likely to
// least likely to change. I've made an initial
// guess at that.
if (update)
{
// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name);
AgentUpdateArgs arg = new AgentUpdateArgs();
arg.AgentID = x.AgentID;
arg.BodyRotation = x.BodyRotation;
arg.CameraAtAxis = x.CameraAtAxis;
arg.CameraCenter = x.CameraCenter;
arg.CameraLeftAxis = x.CameraLeftAxis;
arg.CameraUpAxis = x.CameraUpAxis;
arg.ControlFlags = x.ControlFlags;
arg.Far = x.Far;
arg.Flags = x.Flags;
arg.HeadRotation = x.HeadRotation;
arg.SessionID = x.SessionID;
arg.State = x.State;
m_lastAgentUpdateArgs.AgentID = x.AgentID;
m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation;
m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
m_lastAgentUpdateArgs.Far = x.Far;
m_lastAgentUpdateArgs.Flags = x.Flags;
m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
m_lastAgentUpdateArgs.SessionID = x.SessionID;
m_lastAgentUpdateArgs.State = x.State;
UpdateAgent handlerAgentUpdate = OnAgentUpdate;
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
lastarg = arg; // save this set of arguments for nexttime
if (handlerPreAgentUpdate != null)
OnPreAgentUpdate(this, arg);
OnPreAgentUpdate(this, m_lastAgentUpdateArgs);
if (handlerAgentUpdate != null)
OnAgentUpdate(this, arg);
OnAgentUpdate(this, m_lastAgentUpdateArgs);
handlerAgentUpdate = null;
handlerPreAgentUpdate = null;
}
}
PacketPool.Instance.ReturnPacket(packet);
return true;
}
@@ -5810,7 +5846,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
args.Channel = ch;
args.From = String.Empty;
args.Message = Utils.BytesToString(msg);
args.Type = ChatTypeEnum.Shout;
args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
args.Position = new Vector3();
args.Scene = Scene;
args.Sender = this;
@@ -9043,7 +9079,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
#endregion
switch (Utils.BytesToString(messagePacket.MethodData.Method))
string method = Utils.BytesToString(messagePacket.MethodData.Method);
switch (method)
{
case "getinfo":
if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
@@ -9359,7 +9397,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return true;
default:
m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket);
m_log.WarnFormat(
"[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}",
method, Name, Scene.Name);
for (int i = 0; i < messagePacket.ParamList.Length; i++)
{
EstateOwnerMessagePacket.ParamListBlock block = messagePacket.ParamList[i];
string data = (string)Utils.BytesToString(block.Parameter);
m_log.DebugFormat("[LLCLIENTVIEW]: Param {0}={1}", i, data);
}
return true;
}
@@ -11745,7 +11793,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
logPacket = false;
if (DebugPacketLevel <= 50
& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
&& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
logPacket = false;
if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
@@ -11814,13 +11862,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (logPacket)
m_log.DebugFormat(
"[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}",
Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type);
Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name, packet.Type);
}
if (!ProcessPacketMethod(packet))
m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
PacketPool.Instance.ReturnPacket(packet);
m_log.WarnFormat(
"[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.",
packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name);
}
private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
@@ -11989,7 +12037,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
Kick(reason);
Thread.Sleep(1000);
Close();
Disconnect();
}
public void Disconnect()
@@ -12273,7 +12321,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];

View File

@@ -278,7 +278,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public string GetStats()
{
return string.Format(
"{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7} {12,7}",
"{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}",
Util.EnvironmentTickCountSubtract(TickLastPacketReceived),
PacketsReceived,
PacketsSent,
@@ -290,8 +290,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_packetOutboxes[(int)ThrottleOutPacketType.Cloud].Count,
m_packetOutboxes[(int)ThrottleOutPacketType.Task].Count,
m_packetOutboxes[(int)ThrottleOutPacketType.Texture].Count,
m_packetOutboxes[(int)ThrottleOutPacketType.Asset].Count,
m_packetOutboxes[(int)ThrottleOutPacketType.State].Count);
m_packetOutboxes[(int)ThrottleOutPacketType.Asset].Count);
}
public void SendPacketStats()
@@ -337,8 +336,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
// State is a subcategory of task that we allocate a percentage to
int state = 0;
// Make sure none of the throttles are set below our packet MTU,
// otherwise a throttle could become permanently clogged
@@ -375,9 +372,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
bucket.RequestedDripRate = task;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.State];
bucket.RequestedDripRate = state;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
bucket.RequestedDripRate = texture;
@@ -678,9 +672,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
Texture = 5,
/// <summary>Non-texture assets</summary>
Asset = 6,
/// <summary>Avatar and primitive data</summary>
/// <remarks>This is a sub-category of Task</remarks>
State = 7,
*/
switch (category)
@@ -697,11 +688,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return ThrottleOutPacketTypeFlags.Texture;
case ThrottleOutPacketType.Asset:
return ThrottleOutPacketTypeFlags.Asset;
case ThrottleOutPacketType.State:
return ThrottleOutPacketTypeFlags.State;
default:
return 0;
}
}
}
}
}

View File

@@ -37,6 +37,7 @@ using log4net;
using Nini.Config;
using OpenMetaverse.Packets;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Scenes;
using OpenMetaverse;
@@ -69,6 +70,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public void AddScene(IScene scene)
{
m_udpServer.AddScene(scene);
StatsManager.RegisterStat(
new Stat(
"IncomingPacketsProcessedCount",
"Number of inbound UDP packets processed",
"Number of inbound UDP packets processed",
"",
"clientstack",
scene.Name,
StatType.Pull,
MeasuresOfInterest.AverageChangeOverTime,
stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
StatVerbosity.Debug));
}
public bool HandlesRegion(Location x)
@@ -100,9 +114,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>The measured resolution of Environment.TickCount</summary>
public readonly float TickCountResolution;
/// <summary>Number of prim updates to put on the queue each time the
/// OnQueueEmpty event is triggered for updates</summary>
public readonly int PrimUpdatesPerCallback;
/// <summary>Number of texture packets to put on the queue each time the
/// OnQueueEmpty event is triggered for textures</summary>
public readonly int TextureSendLimit;
@@ -111,6 +127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
//PacketEventDictionary packetEvents = new PacketEventDictionary();
/// <summary>Incoming packets that are awaiting handling</summary>
private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
/// <summary></summary>
//private UDPClientCollection m_clients = new UDPClientCollection();
/// <summary>Bandwidth throttle for this UDP server</summary>
@@ -121,28 +138,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>Manages authentication for agent circuits</summary>
private AgentCircuitManager m_circuitManager;
/// <summary>Reference to the scene this UDP server is attached to</summary>
protected Scene m_scene;
/// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
private Location m_location;
/// <summary>The size of the receive buffer for the UDP socket. This value
/// is passed up to the operating system and used in the system networking
/// stack. Use zero to leave this value as the default</summary>
private int m_recvBufferSize;
/// <summary>Flag to process packets asynchronously or synchronously</summary>
private bool m_asyncPacketHandling;
/// <summary>Tracks whether or not a packet was sent each round so we know
/// whether or not to sleep</summary>
private bool m_packetSent;
/// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
private int m_elapsedMSSinceLastStatReport = 0;
/// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
private int m_tickLastOutgoingPacketHandler;
/// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
private int m_elapsedMSOutgoingPacketHandler;
/// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
private int m_elapsed100MSOutgoingPacketHandler;
/// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
private int m_elapsed500MSOutgoingPacketHandler;
@@ -155,6 +181,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>Flag to signal when clients should send pings</summary>
protected bool m_sendPing;
private Pool<IncomingPacket> m_incomingPacketPool;
/// <summary>
/// Stat for number of packets in the main pool awaiting use.
/// </summary>
private Stat m_poolCountStat;
/// <summary>
/// Stat for number of packets in the inbound packet pool awaiting use.
/// </summary>
private Stat m_incomingPacketPoolStat;
private int m_defaultRTO = 0;
private int m_maxRTO = 0;
private int m_ackTimeout = 0;
@@ -175,7 +213,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </summary>
private IClientAPI m_currentIncomingClient;
public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
public LLUDPServer(
IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
IConfigSource configSource, AgentCircuitManager circuitManager)
: base(listenIP, (int)port)
{
#region Environment.TickCount Measurement
@@ -197,6 +237,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_circuitManager = circuitManager;
int sceneThrottleBps = 0;
bool usePools = false;
IConfig config = configSource.Configs["ClientStack.LindenUDP"];
if (config != null)
@@ -222,6 +263,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_pausedAckTimeout = 1000 * 300; // 5 minutes
}
// FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
// However, there is no harm in temporarily doing it multiple times.
IConfig packetConfig = configSource.Configs["PacketPool"];
if (packetConfig != null)
{
PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
usePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", usePools);
}
#region BinaryStats
config = configSource.Configs["Statistics.Binary"];
m_shouldCollectStats = false;
@@ -249,20 +300,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_throttle = new TokenBucket(null, sceneThrottleBps);
ThrottleRates = new ThrottleRates(configSource);
if (usePools)
EnablePools();
}
public void Start()
{
if (m_scene == null)
throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference");
StartInbound();
StartOutbound();
m_elapsedMSSinceLastStatReport = Environment.TickCount;
}
private void StartInbound()
{
m_log.InfoFormat(
"[LLUDPSERVER]: Starting the LLUDP server in {0} mode",
m_asyncPacketHandling ? "asynchronous" : "synchronous");
"[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
base.Start(m_recvBufferSize, m_asyncPacketHandling);
base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
// Start the packet processing threads
// This thread will process the packets received that are placed on the packetInbox
Watchdog.StartThread(
IncomingPacketHandler,
string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
@@ -271,6 +330,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
true,
GetWatchdogIncomingAlarmData,
Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
}
private new void StartOutbound()
{
m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
base.StartOutbound();
Watchdog.StartThread(
OutgoingPacketHandler,
@@ -280,8 +346,90 @@ namespace OpenSim.Region.ClientStack.LindenUDP
true,
GetWatchdogOutgoingAlarmData,
Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
}
m_elapsedMSSinceLastStatReport = Environment.TickCount;
public void Stop()
{
m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
base.StopOutbound();
base.StopInbound();
}
protected override bool EnablePools()
{
if (!UsePools)
{
base.EnablePools();
m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
return true;
}
return false;
}
protected override bool DisablePools()
{
if (UsePools)
{
base.DisablePools();
StatsManager.DeregisterStat(m_incomingPacketPoolStat);
// We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
return true;
}
return false;
}
/// <summary>
/// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene
/// stats.
/// </summary>
private void EnablePoolStats()
{
m_poolCountStat
= new Stat(
"UDPPacketBufferPoolCount",
"Objects within the UDPPacketBuffer pool",
"The number of objects currently stored within the UDPPacketBuffer pool",
"",
"clientstack",
m_scene.Name,
StatType.Pull,
stat => stat.Value = Pool.Count,
StatVerbosity.Debug);
StatsManager.RegisterStat(m_poolCountStat);
m_incomingPacketPoolStat
= new Stat(
"IncomingPacketPoolCount",
"Objects within incoming packet pool",
"The number of objects currently stored within the incoming packet pool",
"",
"clientstack",
m_scene.Name,
StatType.Pull,
stat => stat.Value = m_incomingPacketPool.Count,
StatVerbosity.Debug);
StatsManager.RegisterStat(m_incomingPacketPoolStat);
}
/// <summary>
/// Disables pool stats.
/// </summary>
private void DisablePoolStats()
{
StatsManager.DeregisterStat(m_poolCountStat);
m_poolCountStat = null;
StatsManager.DeregisterStat(m_incomingPacketPoolStat);
m_incomingPacketPoolStat = null;
}
/// <summary>
@@ -306,12 +454,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
}
public new void Stop()
{
m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
base.Stop();
}
public void AddScene(IScene scene)
{
if (m_scene != null)
@@ -328,6 +470,182 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_scene = (Scene)scene;
m_location = new Location(m_scene.RegionInfo.RegionHandle);
// XXX: These stats are also pool stats but we register them separately since they are currently not
// turned on and off by EnablePools()/DisablePools()
StatsManager.RegisterStat(
new PercentageStat(
"PacketsReused",
"Packets reused",
"Number of packets reused out of all requests to the packet pool",
"clientstack",
m_scene.Name,
StatType.Pull,
stat =>
{ PercentageStat pstat = (PercentageStat)stat;
pstat.Consequent = PacketPool.Instance.PacketsRequested;
pstat.Antecedent = PacketPool.Instance.PacketsReused; },
StatVerbosity.Debug));
StatsManager.RegisterStat(
new PercentageStat(
"PacketDataBlocksReused",
"Packet data blocks reused",
"Number of data blocks reused out of all requests to the packet pool",
"clientstack",
m_scene.Name,
StatType.Pull,
stat =>
{ PercentageStat pstat = (PercentageStat)stat;
pstat.Consequent = PacketPool.Instance.BlocksRequested;
pstat.Antecedent = PacketPool.Instance.BlocksReused; },
StatVerbosity.Debug));
StatsManager.RegisterStat(
new Stat(
"PacketsPoolCount",
"Objects within the packet pool",
"The number of objects currently stored within the packet pool",
"",
"clientstack",
m_scene.Name,
StatType.Pull,
stat => stat.Value = PacketPool.Instance.PacketsPooled,
StatVerbosity.Debug));
StatsManager.RegisterStat(
new Stat(
"PacketDataBlocksPoolCount",
"Objects within the packet data block pool",
"The number of objects currently stored within the packet data block pool",
"",
"clientstack",
m_scene.Name,
StatType.Pull,
stat => stat.Value = PacketPool.Instance.BlocksPooled,
StatVerbosity.Debug));
// We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by
// scene name
if (UsePools)
EnablePoolStats();
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug lludp start",
"debug lludp start <in|out|all>",
"Control LLUDP packet processing.",
"No effect if packet processing has already started.\n"
+ "in - start inbound processing.\n"
+ "out - start outbound processing.\n"
+ "all - start in and outbound processing.\n",
HandleStartCommand);
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug lludp stop",
"debug lludp stop <in|out|all>",
"Stop LLUDP packet processing.",
"No effect if packet processing has already stopped.\n"
+ "in - stop inbound processing.\n"
+ "out - stop outbound processing.\n"
+ "all - stop in and outbound processing.\n",
HandleStopCommand);
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug lludp pool",
"debug lludp pool <on|off>",
"Turn object pooling within the lludp component on or off.",
HandlePoolCommand);
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug lludp status",
"debug lludp status",
"Return status of LLUDP packet processing.",
HandleStatusCommand);
}
private void HandleStartCommand(string module, string[] args)
{
if (args.Length != 4)
{
MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
return;
}
string subCommand = args[3];
if (subCommand == "in" || subCommand == "all")
StartInbound();
if (subCommand == "out" || subCommand == "all")
StartOutbound();
}
private void HandleStopCommand(string module, string[] args)
{
if (args.Length != 4)
{
MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
return;
}
string subCommand = args[3];
if (subCommand == "in" || subCommand == "all")
StopInbound();
if (subCommand == "out" || subCommand == "all")
StopOutbound();
}
private void HandlePoolCommand(string module, string[] args)
{
if (args.Length != 4)
{
MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
return;
}
string enabled = args[3];
if (enabled == "on")
{
if (EnablePools())
{
EnablePoolStats();
MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_scene.Name);
}
}
else if (enabled == "off")
{
if (DisablePools())
{
DisablePoolStats();
MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_scene.Name);
}
}
else
{
MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
}
}
private void HandleStatusCommand(string module, string[] args)
{
MainConsole.Instance.OutputFormat(
"IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
MainConsole.Instance.OutputFormat(
"OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
}
public bool HandlesRegion(Location x)
@@ -411,6 +729,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
byte[] data = packet.ToBytes();
SendPacketData(udpClient, data, packet.Type, category, method);
}
PacketPool.Instance.ReturnPacket(packet);
}
/// <summary>
@@ -695,7 +1015,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
LLUDPClient udpClient = null;
Packet packet = null;
int packetEnd = buffer.DataLength - 1;
IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
#region Decoding
@@ -705,7 +1025,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
return; // Drop undersizd packet
return; // Drop undersized packet
}
int headerLen = 7;
@@ -728,7 +1048,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
try
{
packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
// // Only allocate a buffer for zerodecoding if the packet is zerocoded
// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
// If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
// assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
// bytes are copied out).
packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
// Only allocate a buffer for zerodecoding if the packet is zerocoded
((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
}
@@ -743,11 +1069,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return; // Drop short packet
}
catch(Exception e)
catch (Exception e)
{
if (m_malformedCount < 100)
m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
m_malformedCount++;
if ((m_malformedCount % 100000) == 0)
m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
}
@@ -768,7 +1096,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// UseCircuitCode handling
if (packet.Type == PacketType.UseCircuitCode)
{
object[] array = new object[] { buffer, packet };
// We need to copy the endpoint so that it doesn't get changed when another thread reuses the
// buffer.
object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
Util.FireAndForget(HandleUseCircuitCode, array);
@@ -777,7 +1107,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Determine which agent this packet came from
IClientAPI client;
if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView))
if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
{
//m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
return;
@@ -801,6 +1131,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Handle appended ACKs
if (packet.Header.AppendedAcks && packet.Header.AckList != null)
{
// m_log.DebugFormat(
// "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
// packet.Header.AckList.Length, client.Name, m_scene.Name);
for (int i = 0; i < packet.Header.AckList.Length; i++)
udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
}
@@ -810,6 +1144,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
PacketAckPacket ackPacket = (PacketAckPacket)packet;
// m_log.DebugFormat(
// "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
// ackPacket.Packets.Length, client.Name, m_scene.Name);
for (int i = 0; i < ackPacket.Packets.Length; i++)
udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
@@ -823,6 +1161,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (packet.Header.Reliable)
{
// m_log.DebugFormat(
// "[LLUDPSERVER]: Adding ack request for {0} {1} from {2} in {3}",
// packet.Type, packet.Header.Sequence, client.Name, m_scene.Name);
udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
// This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
@@ -869,6 +1211,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (packet.Type == PacketType.StartPingCheck)
{
// m_log.DebugFormat("[LLUDPSERVER]: Handling ping from {0} in {1}", client.Name, m_scene.Name);
// We don't need to do anything else with ping checks
StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
CompletePing(udpClient, startPing.PingID.PingID);
@@ -888,8 +1232,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#endregion Ping Check Handling
IncomingPacket incomingPacket;
// Inbox insertion
packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet));
if (UsePools)
{
incomingPacket = m_incomingPacketPool.GetObject();
incomingPacket.Client = (LLClientView)client;
incomingPacket.Packet = packet;
}
else
{
incomingPacket = new IncomingPacket((LLClientView)client, packet);
}
packetInbox.Enqueue(incomingPacket);
}
#region BinaryStats
@@ -975,21 +1332,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private void HandleUseCircuitCode(object o)
{
IPEndPoint remoteEndPoint = null;
IPEndPoint endPoint = null;
IClientAPI client = null;
try
{
// DateTime startTime = DateTime.Now;
object[] array = (object[])o;
UDPPacketBuffer buffer = (UDPPacketBuffer)array[0];
endPoint = (IPEndPoint)array[0];
UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
m_log.DebugFormat(
"[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint);
remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
AuthenticateResponse sessionInfo;
if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1000,13 +1355,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
uccp.CircuitCode.Code,
uccp.CircuitCode.ID,
uccp.CircuitCode.SessionID,
remoteEndPoint,
endPoint,
sessionInfo);
// Send ack straight away to let the viewer know that the connection is active.
// The client will be null if it already exists (e.g. if on a region crossing the client sends a use
// circuit code to the existing child agent. This is not particularly obvious.
SendAckImmediate(remoteEndPoint, uccp.Header.Sequence);
SendAckImmediate(endPoint, uccp.Header.Sequence);
// We only want to send initial data to new clients, not ones which are being converted from child to root.
if (client != null)
@@ -1017,7 +1372,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Don't create clients for unauthorized requesters.
m_log.WarnFormat(
"[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint);
uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
}
// m_log.DebugFormat(
@@ -1029,7 +1384,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
m_log.ErrorFormat(
"[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a",
endPoint != null ? endPoint.ToString() : "n/a",
client != null ? client.Name : "unknown",
client != null ? client.AgentId.ToString() : "unknown",
e.Message,
@@ -1094,20 +1449,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
IClientAPI client = null;
// In priciple there shouldn't be more than one thread here, ever.
// But in case that happens, we need to synchronize this piece of code
// because it's too important
lock (this)
// We currently synchronize this code across the whole scene to avoid issues such as
// http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
// consistently, this lock could probably be removed.
lock (this)
{
if (!m_scene.TryGetClient(agentID, out client))
{
LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
client.OnLogout += LogoutHandler;
((LLClientView)client).DisableFacelights = m_disableFacelights;
client.Start();
}
}
@@ -1146,7 +1501,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// on to en-US to avoid number parsing issues
Culture.SetCurrentCulture();
while (base.IsRunning)
while (IsRunningInbound)
{
try
{
@@ -1161,7 +1516,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
if (packetInbox.Dequeue(100, ref incomingPacket))
{
ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket);
if (UsePools)
m_incomingPacketPool.ReturnObject(incomingPacket);
}
}
catch (Exception ex)
{
@@ -1188,7 +1548,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Action generic every round
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
while (base.IsRunning)
while (base.IsRunningOutbound)
{
try
{
@@ -1315,6 +1675,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private int npacksSent = 0;
private int npackNotSent = 0;
/// <summary>
/// Number of inbound packets processed since startup.
/// </summary>
public long IncomingPacketsProcessed { get; private set; }
private void MonitoredClientOutgoingPacketHandler(IClientAPI client)
{
nticks++;
@@ -1374,7 +1739,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
npacksSent++;
}
else
{
npackNotSent++;
}
watch2.Stop();
avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks);
@@ -1382,7 +1749,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
else
{
m_log.WarnFormat("[LLUDPSERVER]: Client is not connected");
}
}
}
catch (Exception ex)
@@ -1446,6 +1815,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
"[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
packet.Type, client.Name, m_scene.RegionInfo.RegionName);
}
IncomingPacketsProcessed++;
}
protected void LogoutHandler(IClientAPI client)

View File

@@ -30,6 +30,8 @@ using System.Net;
using System.Net.Sockets;
using System.Threading;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
namespace OpenMetaverse
{
@@ -58,17 +60,29 @@ namespace OpenMetaverse
/// <summary>Flag to process packets asynchronously or synchronously</summary>
private bool m_asyncPacketHandling;
/// <summary>The all important shutdown flag</summary>
private volatile bool m_shutdownFlag = true;
/// <summary>
/// Are we to use object pool(s) to reduce memory churn when receiving data?
/// </summary>
public bool UsePools { get; protected set; }
/// <summary>Returns true if the server is currently listening, otherwise false</summary>
public bool IsRunning { get { return !m_shutdownFlag; } }
/// <summary>
/// Pool to use for handling data. May be null if UsePools = false;
/// </summary>
protected OpenSim.Framework.Pool<UDPPacketBuffer> Pool { get; private set; }
/// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
public bool IsRunningInbound { get; private set; }
/// <summary>Returns true if the server is currently sending outbound packets, otherwise false</summary>
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
public bool IsRunningOutbound { get; private set; }
/// <summary>
/// Default constructor
/// </summary>
/// <param name="bindAddress">Local IP address to bind the server to</param>
/// <param name="port">Port to listening for incoming UDP packets on</param>
/// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
public OpenSimUDPBase(IPAddress bindAddress, int port)
{
m_localBindAddress = bindAddress;
@@ -76,7 +90,7 @@ namespace OpenMetaverse
}
/// <summary>
/// Start the UDP server
/// Start inbound UDP packet handling.
/// </summary>
/// <param name="recvBufferSize">The size of the receive buffer for
/// the UDP socket. This value is passed up to the operating system
@@ -91,11 +105,11 @@ namespace OpenMetaverse
/// manner (not throwing an exception when the remote side resets the
/// connection). This call is ignored on Mono where the flag is not
/// necessary</remarks>
public void Start(int recvBufferSize, bool asyncPacketHandling)
public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
{
m_asyncPacketHandling = asyncPacketHandling;
if (m_shutdownFlag)
if (!IsRunningInbound)
{
const int SIO_UDP_CONNRESET = -1744830452;
@@ -127,8 +141,7 @@ namespace OpenMetaverse
m_udpSocket.Bind(ipep);
// we're not shutting down, we're starting up
m_shutdownFlag = false;
IsRunningInbound = true;
// kick off an async receive. The Start() method will return, the
// actual receives will occur asynchronously and will be caught in
@@ -138,28 +151,69 @@ namespace OpenMetaverse
}
/// <summary>
/// Stops the UDP server
/// Start outbound UDP packet handling.
/// </summary>
public void Stop()
public void StartOutbound()
{
if (!m_shutdownFlag)
IsRunningOutbound = true;
}
public void StopInbound()
{
if (IsRunningInbound)
{
// wait indefinitely for a writer lock. Once this is called, the .NET runtime
// will deny any more reader locks, in effect blocking all other send/receive
// threads. Once we have the lock, we set shutdownFlag to inform the other
// threads. Once we have the lock, we set IsRunningInbound = false to inform the other
// threads that the socket is closed.
m_shutdownFlag = true;
IsRunningInbound = false;
m_udpSocket.Close();
}
}
public void StopOutbound()
{
IsRunningOutbound = false;
}
protected virtual bool EnablePools()
{
if (!UsePools)
{
Pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
UsePools = true;
return true;
}
return false;
}
protected virtual bool DisablePools()
{
if (UsePools)
{
UsePools = false;
// We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
return true;
}
return false;
}
private void AsyncBeginReceive()
{
// allocate a packet buffer
//WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut();
UDPPacketBuffer buf = new UDPPacketBuffer();
UDPPacketBuffer buf;
if (!m_shutdownFlag)
if (UsePools)
buf = Pool.GetObject();
else
buf = new UDPPacketBuffer();
if (IsRunningInbound)
{
try
{
@@ -212,7 +266,7 @@ namespace OpenMetaverse
{
// Asynchronous receive operations will complete here through the call
// to AsyncBeginReceive
if (!m_shutdownFlag)
if (IsRunningInbound)
{
// Asynchronous mode will start another receive before the
// callback for this packet is even fired. Very parallel :-)
@@ -221,8 +275,6 @@ namespace OpenMetaverse
// get the buffer that was created in AsyncBeginReceive
// this is the received data
//WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
//UDPPacketBuffer buffer = wrappedBuffer.Instance;
UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
try
@@ -239,7 +291,8 @@ namespace OpenMetaverse
catch (ObjectDisposedException) { }
finally
{
//wrappedBuffer.Dispose();
if (UsePools)
Pool.ReturnObject(buffer);
// Synchronous mode waits until the packet callback completes
// before starting the receive to fetch another packet
@@ -252,7 +305,7 @@ namespace OpenMetaverse
public void AsyncBeginSend(UDPPacketBuffer buf)
{
if (!m_shutdownFlag)
if (IsRunningOutbound)
{
try
{
@@ -281,4 +334,4 @@ namespace OpenMetaverse
catch (ObjectDisposedException) { }
}
}
}
}

View File

@@ -31,63 +31,114 @@ using System.Reflection;
using OpenMetaverse;
using OpenMetaverse.Packets;
using log4net;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Framework
namespace OpenSim.Region.ClientStack.LindenUDP
{
public sealed class PacketPool
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly PacketPool instance = new PacketPool();
private bool packetPoolEnabled = true;
private bool dataBlockPoolEnabled = true;
/// <summary>
/// Pool of packets available for reuse.
/// </summary>
private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
private static Dictionary<Type, Stack<Object>> DataBlocks =
new Dictionary<Type, Stack<Object>>();
static PacketPool()
{
}
private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
public static PacketPool Instance
{
get { return instance; }
}
public bool RecyclePackets
public bool RecyclePackets { get; set; }
public bool RecycleDataBlocks { get; set; }
/// <summary>
/// The number of packets pooled
/// </summary>
public int PacketsPooled
{
set { packetPoolEnabled = value; }
get { return packetPoolEnabled; }
get
{
lock (pool)
return pool.Count;
}
}
public bool RecycleDataBlocks
/// <summary>
/// The number of blocks pooled.
/// </summary>
public int BlocksPooled
{
set { dataBlockPoolEnabled = value; }
get { return dataBlockPoolEnabled; }
get
{
lock (DataBlocks)
return DataBlocks.Count;
}
}
/// <summary>
/// Number of packets requested.
/// </summary>
public long PacketsRequested { get; private set; }
/// <summary>
/// Number of packets reused.
/// </summary>
public long PacketsReused { get; private set; }
/// <summary>
/// Number of packet blocks requested.
/// </summary>
public long BlocksRequested { get; private set; }
/// <summary>
/// Number of packet blocks reused.
/// </summary>
public long BlocksReused { get; private set; }
private PacketPool()
{
// defaults
RecyclePackets = true;
RecycleDataBlocks = true;
}
/// <summary>
/// Gets a packet of the given type.
/// </summary>
/// <param name='type'></param>
/// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
public Packet GetPacket(PacketType type)
{
PacketsRequested++;
Packet packet;
if (!packetPoolEnabled)
if (!RecyclePackets)
return Packet.BuildPacket(type);
lock (pool)
{
if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
{
// m_log.DebugFormat("[PACKETPOOL]: Building {0} packet", type);
// Creating a new packet if we cannot reuse an old package
packet = Packet.BuildPacket(type);
}
else
{
// m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
// Recycle old packages
packet = (pool[type]).Pop();
PacketsReused++;
packet = pool[type].Pop();
}
}
@@ -136,7 +187,7 @@ namespace OpenSim.Framework
{
PacketType type = GetType(bytes);
Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
int i = 0;
Packet packet = GetPacket(type);
@@ -154,7 +205,7 @@ namespace OpenSim.Framework
/// <param name="packet"></param>
public void ReturnPacket(Packet packet)
{
if (dataBlockPoolEnabled)
if (RecycleDataBlocks)
{
switch (packet.Type)
{
@@ -178,11 +229,12 @@ namespace OpenSim.Framework
}
}
if (packetPoolEnabled)
if (RecyclePackets)
{
switch (packet.Type)
{
// List pooling packets here
case PacketType.AgentUpdate:
case PacketType.PacketAck:
case PacketType.ObjectUpdate:
case PacketType.ImprovedTerseObjectUpdate:
@@ -197,7 +249,9 @@ namespace OpenSim.Framework
if ((pool[type]).Count < 50)
{
(pool[type]).Push(packet);
// m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
pool[type].Push(packet);
}
}
break;
@@ -209,16 +263,21 @@ namespace OpenSim.Framework
}
}
public static T GetDataBlock<T>() where T: new()
public T GetDataBlock<T>() where T: new()
{
lock (DataBlocks)
{
BlocksRequested++;
Stack<Object> s;
if (DataBlocks.TryGetValue(typeof(T), out s))
{
if (s.Count > 0)
{
BlocksReused++;
return (T)s.Pop();
}
}
else
{
@@ -229,7 +288,7 @@ namespace OpenSim.Framework
}
}
public static void ReturnDataBlock<T>(T block) where T: new()
public void ReturnDataBlock<T>(T block) where T: new()
{
if (block == null)
return;
@@ -244,4 +303,4 @@ namespace OpenSim.Framework
}
}
}
}
}

View File

@@ -43,7 +43,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
/// This will contain basic tests for the LindenUDP client stack
/// </summary>
[TestFixture]
public class BasicCircuitTests
public class BasicCircuitTests : OpenSimTestCase
{
private Scene m_scene;
private TestLLUDPServer m_udpServer;
@@ -65,8 +65,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
}
[SetUp]
public void SetUp()
public override void SetUp()
{
base.SetUp();
m_scene = new SceneHelpers().SetupScene();
}
@@ -143,7 +144,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
public void TestAddClient()
{
TestHelpers.InMethod();
// XmlConfigurator.Configure();
// TestHelpers.EnableLogging();
AddUdpServer();

View File

@@ -43,7 +43,7 @@ using OpenSim.Tests.Common.Mock;
namespace OpenSim.Region.ClientStack.LindenUDP.Tests
{
[TestFixture]
public class LLImageManagerTests
public class LLImageManagerTests : OpenSimTestCase
{
private AssetBase m_testImageAsset;
private Scene scene;

View File

@@ -39,7 +39,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
/// Tests for the LL packet handler
/// </summary>
[TestFixture]
public class PacketHandlerTests
public class PacketHandlerTests : OpenSimTestCase
{
// [Test]
// /// <summary>

View File

@@ -57,39 +57,36 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
/// <summary>
/// Return a xfer uploader if one does not already exist.
/// Return the xfer uploader for the given transaction.
/// </summary>
/// <remarks>
/// If an uploader does not already exist for this transaction then it is created, otherwise the existing
/// uploader is returned.
/// </remarks>
/// <param name="transactionID"></param>
/// <param name="assetID">
/// We must transfer the new asset ID into the uploader on creation, otherwise
/// we can see race conditions with other threads which can retrieve an item before it is updated with the new
/// asset id.
/// </param>
/// <returns>
/// The xfer uploader requested. Null if one is already in existence.
/// FIXME: This is a bizarre thing to do, and is probably meant to signal an error condition if multiple
/// transfers are made. Needs to be corrected.
/// </returns>
public AssetXferUploader RequestXferUploader(UUID transactionID, UUID assetID)
/// <returns>The asset xfer uploader</returns>
public AssetXferUploader RequestXferUploader(UUID transactionID)
{
AssetXferUploader uploader;
lock (XferUploaders)
{
if (!XferUploaders.ContainsKey(transactionID))
{
AssetXferUploader uploader = new AssetXferUploader(this, m_Scene, assetID, m_dumpAssetsToFile);
uploader = new AssetXferUploader(this, m_Scene, transactionID, m_dumpAssetsToFile);
// m_log.DebugFormat(
// "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID);
XferUploaders.Add(transactionID, uploader);
return uploader;
}
else
{
uploader = XferUploaders[transactionID];
}
}
m_log.WarnFormat("[AGENT ASSETS TRANSACTIONS]: Ignoring request for asset xfer uploader {0} since it already exists", transactionID);
return null;
return uploader;
}
public void HandleXfer(ulong xferID, uint packetID, byte[] data)
@@ -151,115 +148,28 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask)
{
AssetXferUploader uploader = null;
AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders)
{
if (XferUploaders.ContainsKey(transactionID))
uploader = XferUploaders[transactionID];
}
if (uploader != null)
uploader.RequestCreateInventoryItem(
remoteClient, transactionID, folderID,
callbackID, description, name, invType, type,
wearableType, nextOwnerMask);
else
m_log.ErrorFormat(
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to create inventory item {1} from {2}",
transactionID, name, remoteClient.Name);
}
/// <summary>
/// Get an uploaded asset. If the data is successfully retrieved,
/// the transaction will be removed.
/// </summary>
/// <param name="transactionID"></param>
/// <returns>The asset if the upload has completed, null if it has not.</returns>
private AssetBase GetTransactionAsset(UUID transactionID)
{
lock (XferUploaders)
{
if (XferUploaders.ContainsKey(transactionID))
{
AssetXferUploader uploader = XferUploaders[transactionID];
AssetBase asset = uploader.GetAssetData();
RemoveXferUploader(transactionID);
return asset;
}
}
return null;
uploader.RequestCreateInventoryItem(
remoteClient, folderID, callbackID,
description, name, invType, type, wearableType, nextOwnerMask);
}
public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient,
SceneObjectPart part, UUID transactionID,
TaskInventoryItem item)
{
AssetXferUploader uploader = null;
AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders)
{
if (XferUploaders.ContainsKey(transactionID))
uploader = XferUploaders[transactionID];
}
if (uploader != null)
{
AssetBase asset = GetTransactionAsset(transactionID);
// Only legacy viewers use this, and they prefer CAPS, which
// we have, so this really never runs.
// Allow it, but only for "safe" types.
if ((InventoryType)item.InvType != InventoryType.Notecard &&
(InventoryType)item.InvType != InventoryType.LSL)
return;
if (asset != null)
{
// m_log.DebugFormat(
// "[AGENT ASSETS TRANSACTIONS]: Updating item {0} in {1} for transaction {2}",
// item.Name, part.Name, transactionID);
asset.FullID = UUID.Random();
asset.Name = item.Name;
asset.Description = item.Description;
asset.Type = (sbyte)item.Type;
item.AssetID = asset.FullID;
m_Scene.AssetService.Store(asset);
}
}
else
{
m_log.ErrorFormat(
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update task inventory item {1} in {2}",
transactionID, item.Name, part.Name);
}
uploader.RequestUpdateTaskInventoryItem(remoteClient, item);
}
public void RequestUpdateInventoryItem(IClientAPI remoteClient,
UUID transactionID, InventoryItemBase item)
{
AssetXferUploader uploader = null;
AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders)
{
if (XferUploaders.ContainsKey(transactionID))
uploader = XferUploaders[transactionID];
}
if (uploader != null)
{
uploader.RequestUpdateInventoryItem(remoteClient, transactionID, item);
}
else
{
m_log.ErrorFormat(
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update inventory item {1} for {2}",
transactionID, item.Name, remoteClient.Name);
}
uploader.RequestUpdateInventoryItem(remoteClient, item);
}
}
}
}

View File

@@ -214,9 +214,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
public void HandleTaskItemUpdateFromTransaction(
IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
{
m_log.DebugFormat(
"[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
// m_log.DebugFormat(
// "[ASSET TRANSACTION MODULE]: Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
// item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
AgentAssetTransactions transactions =
GetUserTransactions(remoteClient.AgentId);
@@ -230,15 +230,17 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
/// </summary>
/// <param name="remoteClient"></param>
/// <param name="assetID"></param>
/// <param name="transaction"></param>
/// <param name="transactionID"></param>
/// <param name="type"></param>
/// <param name="data"></param></param>
/// <param name="tempFile"></param>
public void HandleUDPUploadRequest(IClientAPI remoteClient,
UUID assetID, UUID transaction, sbyte type, byte[] data,
UUID assetID, UUID transactionID, sbyte type, byte[] data,
bool storeLocal, bool tempFile)
{
// m_log.Debug("HandleUDPUploadRequest - assetID: " + assetID.ToString() + " transaction: " + transaction.ToString() + " type: " + type.ToString() + " storelocal: " + storeLocal + " tempFile: " + tempFile);
// m_log.DebugFormat(
// "[ASSET TRANSACTION MODULE]: HandleUDPUploadRequest - assetID: {0}, transaction {1}, type {2}, storeLocal {3}, tempFile {4}, data.Length {5}",
// assetID, transactionID, type, storeLocal, tempFile, data.Length);
if (((AssetType)type == AssetType.Texture ||
(AssetType)type == AssetType.Sound ||
@@ -274,13 +276,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
AssetXferUploader uploader = transactions.RequestXferUploader(transaction, assetID);
if (uploader != null)
{
uploader.Initialise(remoteClient, assetID, transaction, type,
data, storeLocal, tempFile);
}
AssetXferUploader uploader = transactions.RequestXferUploader(transactionID);
uploader.StartUpload(remoteClient, assetID, transactionID, type, data, storeLocal, tempFile);
}
/// <summary>

View File

@@ -40,39 +40,75 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Upload state.
/// </summary>
/// <remarks>
/// New -> Uploading -> Complete
/// </remarks>
private enum UploadState
{
New,
Uploading,
Complete
}
/// <summary>
/// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we
/// are performing a delayed update.
/// </summary>
AgentAssetTransactions m_transactions;
private UploadState m_uploadState = UploadState.New;
private AssetBase m_asset;
private UUID InventFolder = UUID.Zero;
private sbyte invType = 0;
private bool m_createItem = false;
private uint m_createItemCallback = 0;
private bool m_updateItem = false;
private bool m_createItem;
private uint m_createItemCallback;
private bool m_updateItem;
private InventoryItemBase m_updateItemData;
private bool m_updateTaskItem;
private TaskInventoryItem m_updateTaskItemData;
private string m_description = String.Empty;
private bool m_dumpAssetToFile;
private bool m_finished = false;
private string m_name = String.Empty;
private bool m_storeLocal;
// private bool m_storeLocal;
private uint nextPerm = 0;
private IClientAPI ourClient;
private UUID TransactionID = UUID.Zero;
private UUID m_transactionID;
private sbyte type = 0;
private byte wearableType = 0;
public ulong XferID;
private Scene m_Scene;
public AssetXferUploader(AgentAssetTransactions transactions, Scene scene, UUID assetID, bool dumpAssetToFile)
/// <summary>
/// AssetXferUploader constructor
/// </summary>
/// <param name='transactions'>/param>
/// <param name='scene'></param>
/// <param name='transactionID'></param>
/// <param name='dumpAssetToFile'>
/// If true then when the asset is uploaded it is dumped to a file with the format
/// String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat",
/// now.Year, now.Month, now.Day, now.Hour, now.Minute,
/// now.Second, m_asset.Name, m_asset.Type);
/// for debugging purposes.
/// </param>
public AssetXferUploader(
AgentAssetTransactions transactions, Scene scene, UUID transactionID, bool dumpAssetToFile)
{
m_asset = new AssetBase();
m_transactions = transactions;
m_transactionID = transactionID;
m_Scene = scene;
m_asset = new AssetBase() { FullID = assetID };
m_dumpAssetToFile = dumpAssetToFile;
}
@@ -118,30 +154,50 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
/// <summary>
/// Initialise asset transfer from the client
/// Start asset transfer from the client
/// </summary>
/// <param name="xferID"></param>
/// <param name="packetID"></param>
/// <param name="data"></param>
public void Initialise(IClientAPI remoteClient, UUID assetID,
UUID transaction, sbyte type, byte[] data, bool storeLocal,
bool tempFile)
/// <param name="remoteClient"></param>
/// <param name="assetID"></param>
/// <param name="transaction"></param>
/// <param name="type"></param>
/// <param name="data">
/// Optional data. If present then the asset is created immediately with this data
/// rather than requesting an upload from the client. The data must be longer than 2 bytes.
/// </param>
/// <param name="storeLocal"></param>
/// <param name="tempFile"></param>
public void StartUpload(
IClientAPI remoteClient, UUID assetID, UUID transaction, sbyte type, byte[] data, bool storeLocal,
bool tempFile)
{
// m_log.DebugFormat(
// "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}",
// remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length);
lock (this)
{
if (m_uploadState != UploadState.New)
{
m_log.WarnFormat(
"[ASSET XFER UPLOADER]: Tried to start upload of asset {0}, transaction {1} for {2} but this is already in state {3}. Aborting.",
assetID, transaction, remoteClient.Name, m_uploadState);
return;
}
m_uploadState = UploadState.Uploading;
}
ourClient = remoteClient;
m_asset.Name = "blank";
m_asset.Description = "empty";
m_asset.FullID = assetID;
m_asset.Type = type;
m_asset.CreatorID = remoteClient.AgentId.ToString();
m_asset.Data = data;
m_asset.Local = storeLocal;
m_asset.Temporary = tempFile;
TransactionID = transaction;
m_storeLocal = storeLocal;
// m_storeLocal = storeLocal;
if (m_asset.Data.Length > 2)
{
@@ -166,36 +222,35 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
protected void SendCompleteMessage()
{
ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true,
m_asset.FullID);
// We must lock in order to avoid a race with a separate thread dealing with an inventory item or create
// message from other client UDP.
lock (this)
{
m_finished = true;
m_uploadState = UploadState.Complete;
ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID);
if (m_createItem)
{
DoCreateItem(m_createItemCallback);
CompleteCreateItem(m_createItemCallback);
}
else if (m_updateItem)
{
StoreAssetForItemUpdate(m_updateItemData);
// Remove ourselves from the list of transactions if completion was delayed until the transaction
// was complete.
// TODO: Should probably do the same for create item.
m_transactions.RemoveXferUploader(TransactionID);
CompleteItemUpdate(m_updateItemData);
}
else if (m_storeLocal)
else if (m_updateTaskItem)
{
m_Scene.AssetService.Store(m_asset);
CompleteTaskItemUpdate(m_updateTaskItemData);
}
// else if (m_storeLocal)
// {
// m_Scene.AssetService.Store(m_asset);
// }
}
m_log.DebugFormat(
"[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}",
m_asset.FullID, TransactionID);
m_asset.FullID, m_transactionID);
if (m_dumpAssetToFile)
{
@@ -223,40 +278,37 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
public void RequestCreateInventoryItem(IClientAPI remoteClient,
UUID transactionID, UUID folderID, uint callbackID,
UUID folderID, uint callbackID,
string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask)
{
if (TransactionID == transactionID)
{
InventFolder = folderID;
m_name = name;
m_description = description;
this.type = type;
this.invType = invType;
this.wearableType = wearableType;
nextPerm = nextOwnerMask;
m_asset.Name = name;
m_asset.Description = description;
m_asset.Type = type;
InventFolder = folderID;
m_name = name;
m_description = description;
this.type = type;
this.invType = invType;
this.wearableType = wearableType;
nextPerm = nextOwnerMask;
m_asset.Name = name;
m_asset.Description = description;
m_asset.Type = type;
// We must lock to avoid a race with a separate thread uploading the asset.
lock (this)
// We must lock to avoid a race with a separate thread uploading the asset.
lock (this)
{
if (m_uploadState == UploadState.Complete)
{
if (m_finished)
{
DoCreateItem(callbackID);
}
else
{
m_createItem = true; //set flag so the inventory item is created when upload is complete
m_createItemCallback = callbackID;
}
CompleteCreateItem(callbackID);
}
else
{
m_createItem = true; //set flag so the inventory item is created when upload is complete
m_createItemCallback = callbackID;
}
}
}
public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item)
public void RequestUpdateInventoryItem(IClientAPI remoteClient, InventoryItemBase item)
{
// We must lock to avoid a race with a separate thread uploading the asset.
lock (this)
@@ -269,11 +321,12 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
// to avoid a race condition when the appearance module retrieves the item to set the asset id in
// the AvatarAppearance structure.
item.AssetID = m_asset.FullID;
m_Scene.InventoryService.UpdateItem(item);
if (item.AssetID != UUID.Zero)
m_Scene.InventoryService.UpdateItem(item);
if (m_finished)
if (m_uploadState == UploadState.Complete)
{
StoreAssetForItemUpdate(item);
CompleteItemUpdate(item);
}
else
{
@@ -287,20 +340,59 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
}
public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, TaskInventoryItem taskItem)
{
// We must lock to avoid a race with a separate thread uploading the asset.
lock (this)
{
m_asset.Name = taskItem.Name;
m_asset.Description = taskItem.Description;
m_asset.Type = (sbyte)taskItem.Type;
taskItem.AssetID = m_asset.FullID;
if (m_uploadState == UploadState.Complete)
{
CompleteTaskItemUpdate(taskItem);
}
else
{
m_updateTaskItem = true;
m_updateTaskItemData = taskItem;
}
}
}
/// <summary>
/// Store the asset for the given item.
/// Store the asset for the given item when it has been uploaded.
/// </summary>
/// <param name="item"></param>
private void StoreAssetForItemUpdate(InventoryItemBase item)
private void CompleteItemUpdate(InventoryItemBase item)
{
// m_log.DebugFormat(
// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}",
// m_asset.FullID, item.Name, ourClient.Name);
m_Scene.AssetService.Store(m_asset);
m_transactions.RemoveXferUploader(m_transactionID);
}
private void DoCreateItem(uint callbackID)
/// <summary>
/// Store the asset for the given task item when it has been uploaded.
/// </summary>
/// <param name="taskItem"></param>
private void CompleteTaskItemUpdate(TaskInventoryItem taskItem)
{
// m_log.DebugFormat(
// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier task item update for {1} for {2}",
// m_asset.FullID, taskItem.Name, ourClient.Name);
m_Scene.AssetService.Store(m_asset);
m_transactions.RemoveXferUploader(m_transactionID);
}
private void CompleteCreateItem(uint callbackID)
{
m_Scene.AssetService.Store(m_asset);
@@ -326,20 +418,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
ourClient.SendInventoryItemCreateUpdate(item, callbackID);
else
ourClient.SendAlertMessage("Unable to create inventory item");
}
/// <summary>
/// Get the asset data uploaded in this transfer.
/// </summary>
/// <returns>null if the asset has not finished uploading</returns>
public AssetBase GetAssetData()
{
if (m_finished)
{
return m_asset;
}
return null;
m_transactions.RemoveXferUploader(m_transactionID);
}
}
}
}

View File

@@ -107,8 +107,6 @@ namespace Flotsam.RegionModules.AssetCache
private IAssetService m_AssetService;
private List<Scene> m_Scenes = new List<Scene>();
private bool m_DeepScanBeforePurge;
public FlotsamAssetCache()
{
m_InvalidChars.AddRange(Path.GetInvalidPathChars());
@@ -170,8 +168,6 @@ namespace Flotsam.RegionModules.AssetCache
m_CacheDirectoryTierLen = assetConfig.GetInt("CacheDirectoryTierLength", m_CacheDirectoryTierLen);
m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", m_CacheWarnAt);
m_DeepScanBeforePurge = assetConfig.GetBoolean("DeepScanBeforePurge", m_DeepScanBeforePurge);
}
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory);
@@ -506,13 +502,10 @@ namespace Flotsam.RegionModules.AssetCache
// Purge all files last accessed prior to this point
DateTime purgeLine = DateTime.Now - m_FileExpiration;
// An optional deep scan at this point will ensure assets present in scenes,
// or referenced by objects in the scene, but not recently accessed
// are not purged.
if (m_DeepScanBeforePurge)
{
CacheScenes();
}
// An asset cache may contain local non-temporary assets that are not in the asset service. Therefore,
// before cleaning up expired files we must scan the objects in the scene to make sure that we retain
// such local assets if they have not been recently accessed.
TouchAllSceneAssets(false);
foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
{
@@ -705,11 +698,14 @@ namespace Flotsam.RegionModules.AssetCache
/// <summary>
/// Iterates through all Scenes, doing a deep scan through assets
/// to cache all assets present in the scene or referenced by assets
/// in the scene
/// to update the access time of all assets present in the scene or referenced by assets
/// in the scene.
/// </summary>
/// <returns></returns>
private int CacheScenes()
/// <param name="storeUncached">
/// If true, then assets scanned which are not found in cache are added to the cache.
/// </param>
/// <returns>Number of distinct asset references found in the scene.</returns>
private int TouchAllSceneAssets(bool storeUncached)
{
UuidGatherer gatherer = new UuidGatherer(m_AssetService);
@@ -732,7 +728,7 @@ namespace Flotsam.RegionModules.AssetCache
{
File.SetLastAccessTime(filename, DateTime.Now);
}
else
else if (storeUncached)
{
m_AssetService.Get(assetID.ToString());
}
@@ -860,13 +856,14 @@ namespace Flotsam.RegionModules.AssetCache
break;
case "assets":
m_log.Info("[FLOTSAM ASSET CACHE]: Caching all assets, in all scenes.");
m_log.Info("[FLOTSAM ASSET CACHE]: Ensuring assets are cached for all scenes.");
Util.FireAndForget(delegate {
int assetsCached = CacheScenes();
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached);
int assetReferenceTotal = TouchAllSceneAssets(true);
m_log.InfoFormat(
"[FLOTSAM ASSET CACHE]: Completed check with {0} assets.",
assetReferenceTotal);
});
break;

View File

@@ -48,14 +48,16 @@ namespace OpenSim.Region.CoreModules.Asset.Tests
/// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness.
/// </summary>
[TestFixture]
public class FlotsamAssetCacheTests
public class FlotsamAssetCacheTests : OpenSimTestCase
{
protected TestScene m_scene;
protected FlotsamAssetCache m_cache;
[SetUp]
public void SetUp()
public override void SetUp()
{
base.SetUp();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");

View File

@@ -75,10 +75,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
m_scene.RegisterModuleInterface<IAttachmentsModule>(this);
if (Enabled)
{
m_scene.EventManager.OnNewClient += SubscribeToClientEvents;
m_scene.EventManager.OnStartScript += (localID, itemID) => HandleScriptStateChange(localID, true);
m_scene.EventManager.OnStopScript += (localID, itemID) => HandleScriptStateChange(localID, false);
}
// TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI
}
/// <summary>
/// Listen for client triggered running state changes so that we can persist the script's object if necessary.
/// </summary>
/// <param name='localID'></param>
/// <param name='itemID'></param>
private void HandleScriptStateChange(uint localID, bool started)
{
SceneObjectGroup sog = m_scene.GetGroupByPrim(localID);
if (sog != null && sog.IsAttachment)
{
if (!started)
{
// FIXME: This is a convoluted way for working out whether the script state has changed to stop
// because it has been manually stopped or because the stop was called in UpdateDetachedObject() below
// This needs to be handled in a less tangled way.
ScenePresence sp = m_scene.GetScenePresence(sog.AttachedAvatar);
if (sp.ControllingClient.IsActive)
sog.HasGroupChanged = true;
}
else
{
sog.HasGroupChanged = true;
}
}
}
public void RemoveRegion(Scene scene)
{
@@ -531,9 +561,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (grp.HasGroupChanged)
{
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
// grp.UUID, grp.AttachmentPoint);
m_log.DebugFormat(
"[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
grp.UUID, grp.AttachmentPoint);
string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, scriptedState);
@@ -637,7 +667,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
});
}
so.IsSelected = false; // fudge....
// Fudge below is an extremely unhelpful comment. It's probably here so that the scheduled full update
// will succeed, as that will not update if an attachment is selected.
so.IsSelected = false; // fudge....
so.ScheduleGroupForFullUpdate();
}

View File

@@ -461,7 +461,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
scene.IncomingCloseAgent(presence.UUID);
scene.IncomingCloseAgent(presence.UUID, false);
// Check that we can't retrieve this attachment from the scene.
Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
@@ -641,4 +641,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
// Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects");
// }
}
}
}

Some files were not shown because too many files have changed in this diff Show More