Compare commits

..

183 Commits

Author SHA1 Message Date
BlueWall
5eb2526e88 0006270: Warp3D leaks memory on mono based systems
Thanks Hiro Lecker for a patch to reduce memory useage with Warp3D map module
2012-09-06 05:18:08 -04:00
Mic Bowman
641b08aa78 Enables cast from int to float for MOD* functions;
Thanks SignpostMarv!
2012-09-05 09:13:16 -07:00
Justin Clark-Casey (justincc)
15d5f3d09d Bump master code up to 0.7.5 now that 0.7.4 is out. 2012-09-04 00:11:14 +01:00
SignpostMarv
07dbe46ba3 wrapping attachment functions in a region 2012-09-04 00:03:44 +01:00
SignpostMarv
ff867b59cf Implementing functing to send messages directly to attachments 2012-09-04 00:03:44 +01:00
SignpostMarv
d4b8a13a1d refactoring the grunt work of MessageObject into a private method with a UUID argument 2012-09-04 00:03:44 +01:00
SignpostMarv
a858c5daee implementing a function to get the number of attachments worn 2012-09-04 00:03:43 +01:00
SignpostMarv
8d431c6359 formatting 2012-09-04 00:03:43 +01:00
SignpostMarv
663bfbb372 although the attachmentPoint argument is a uint, zero is not a valid attachment point 2012-09-04 00:03:43 +01:00
Melanie
d297eb39e5 Revert "made setting rotation match Second Life"
Second Life seems to have introduced a bug, as we have confirmation that SL
behavior changed recently and changed in contradiction to their stated intention
This appears to be another of the bugs SL is notorious for. Signpost and I have
decided to back this out until SL's intention becomes clear.

This reverts commit f7b88d1c40.
2012-09-03 21:52:12 +01:00
Melanie
29218cdb31 Revert "no need to assign rotation to a variable now"
This reverts commit a3d140b57c.
2012-09-03 21:52:03 +01:00
Melanie
359f9efc76 Revert "formatting"
This reverts commit fb211c64fd.
2012-09-03 21:51:54 +01:00
SignpostMarv
fb211c64fd formatting 2012-09-03 13:55:41 +01:00
SignpostMarv
a3d140b57c no need to assign rotation to a variable now 2012-09-03 13:55:40 +01:00
SignpostMarv
f7b88d1c40 made setting rotation match Second Life 2012-09-03 13:55:40 +01:00
Robert Adams
32b534f324 BulletSim: update the SOs and DLLs 2012-08-31 11:41:39 -07:00
Robert Adams
ffdc798720 BulletSim: Update BulletSimAPI to match the DLL interface.
Major rework of terrain management which finally makes mega-regions work.
Update heightmap of terrain by rebuilding the terrain's body and shape.
    There is a problem with just replacing the shape so this workaround
    will do for the moment but it will need to be resolved for
    mesh and hull switching.
2012-08-31 11:41:33 -07:00
Robert Adams
ae852bb873 BulletSim: clean up some variable naming for consistancy.
Update DLL API for new terrain and shape/body pattern methods.
Terrain creation and modification uses new shape/body pattern.
Move debug logging callback set to initialization call so logging
   is per physics engine.
2012-08-31 11:41:28 -07:00
Robert Adams
d3adf9b2b3 BulletSim: fix line endings. 2012-08-31 11:41:23 -07:00
Robert Adams
7c140570db BulletSim: Changes to terrain storage and management so mega-regions work.
Moved all terrain code out of BSScene and into new BSTerrainManager.
Added logic to manage multiple terrains for mega-regions.
Added new functions to BulletSimAPI to match the library.
Moved all of the terrain creation and setup logic from C++ code to C# code.
    The unused code has not yet been removed from either place. Soon.
Moved checks for avatar above ground and in bounds into BSCharacter.
2012-08-31 11:41:18 -07:00
Robert Adams
7b6987ce83 BulletSim: unify physical objects under BSPhysObjects. Now BSScene and BSLinkset only know of BSPhysObject's and there is only one list to search in BSScene. 2012-08-31 11:41:12 -07:00
Robert Adams
0376b8ddbc BulletSim: add new interface for mesh, hull and terrain creation that will move nearly all of the logic into the C# code. 2012-08-31 11:41:07 -07:00
Mic Bowman
2d2495cc45 Remove the unused Newtonsoft.Json dlls
Also remove the license files
2012-08-31 11:33:53 -07:00
BlueWall
a0eda6eb16 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-08-31 13:09:54 -04:00
SignpostMarv
dac31303b7 Type.Type is RuntimeType 2012-08-31 15:33:15 +01:00
Melanie
edd3577b66 Merge branch 'master' of melanie@opensimulator.org:/var/git/opensim 2012-08-31 14:34:44 +01:00
SignpostMarv
054db94d5d formatting 2012-08-31 14:32:33 +01:00
SignpostMarv
794c5f5a6d adding support for static method script invocations 2012-08-31 14:32:33 +01:00
SignpostMarv
b625579780 moving assignment to new line to make next commit easier to read in diffs 2012-08-31 14:32:33 +01:00
SignpostMarv
7e41559917 using specific type instead of var 2012-08-31 14:32:33 +01:00
SignpostMarv
8cd415c2b0 formatting 2012-08-31 14:32:32 +01:00
SignpostMarv
4c58c1b116 formatting 2012-08-31 14:32:32 +01:00
SignpostMarv
e6f43023b6 adding support for finding static methods 2012-08-31 14:32:32 +01:00
SignpostMarv
bcf944db48 assign binding flags to variable 2012-08-31 14:32:32 +01:00
SignpostMarv
7a9eee8538 no need to assign result to GetMethodInfoFromType 2012-08-31 14:32:32 +01:00
SignpostMarv
05648c2c4a changing to use Type argument instead of object 2012-08-31 14:32:31 +01:00
SignpostMarv
dff746df7b moving code that will be common into private static method 2012-08-31 14:32:31 +01:00
SignpostMarv
973f2e8be5 adding documentation to script invokation methods 2012-08-31 14:32:31 +01:00
SignpostMarv
3c019bea8c Implementing a vastly simpler means of allowing region modules to access GetLinkParts than mantis 6236 2012-08-31 01:19:17 +01:00
Melanie
68814f904e Replace SendBannedUserList with Avination's version. Untested in core. Not even test compiled. 2012-08-31 00:37:27 +01:00
Justin Clark-Casey (justincc)
3bd3f448a2 Also do other MySQL region settings related calls under m_dbLock, in common with other calls. 2012-08-31 00:33:06 +01:00
Justin Clark-Casey (justincc)
7c6e8fab15 Do Windlight storage and removal calls in MySQL under m_dbLock, as is done with all the other database calls. 2012-08-31 00:29:57 +01:00
Justin Clark-Casey (justincc)
3ed0d79b00 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-08-30 22:57:40 +01:00
Justin Clark-Casey (justincc)
d89b974680 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-08-30 22:28:45 +01:00
SignpostMarv
c76c63725b fixing bug where last element in list is ignored 2012-08-30 00:10:28 +01:00
SignpostMarv
6b277394c0 refactoring as the list funcs either skip invalid values or recall ToDoubleList 2012-08-30 00:10:28 +01:00
Justin Clark-Casey (justincc)
adce58b33a 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-08-29 23:19:21 +01:00
Justin Clark-Casey (justincc)
1f88179a65 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2012-08-29 23:16:16 +01:00
Justin Clark-Casey (justincc)
ec726413dd 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-08-29 23:04:00 +01:00
Mic Bowman
3d736d575f This partially implements the LSL function to set the response
type for an HTTP request. Since the "official" LSL function limits
the use of the response type, it is implemented as osSetContentType
with a string for the content mime type and a threat level of high.
With this function you should be able to implement rather functional
media-on-a-prim application with much less difficulty.
2012-08-29 14:56:51 -07:00
SignpostMarv
0c3061f973 implementing rule tracking 2012-08-29 02:10:04 +01:00
SignpostMarv
3bf7bd6359 track originating IScriptApi method for SL-like error messages. Will add rule number tracking in next commit. 2012-08-29 02:10:04 +01:00
Justin Clark-Casey (justincc)
7ea832d47c 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-29 02:01:43 +01:00
Justin Clark-Casey (justincc)
c1cece4b82 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-08-28 23:06:53 +01:00
Justin Clark-Casey (justincc)
aa44df9c04 Add IDynamicTextureManager.ConvertData() to match AsyncConvertData(). Remove mismatching ConvertStream() where there is no AsyncConvertStream and neither IDynamicTextureManager implementer implements this method. 2012-08-28 20:35:17 +01:00
SignpostMarv
1e18f0f26a copying documentation from http://opensimulator.org/wiki/Threat_level 2012-08-28 00:12:35 +01:00
SignpostMarv
8a7fbfb06a adding some files to .gitignore that get generated when debugging in c# express with OpenSim.32BitLaunch as the startup project 2012-08-27 23:48:29 +01:00
SignpostMarv
e916b1399f formatting 2012-08-27 23:39:18 +01:00
SignpostMarv
72c2d13ac6 refactoring to load from self (fixes ChanneDigger being absent) 2012-08-27 23:39:18 +01:00
SignpostMarv
a6d689c529 refactoring to assign the first argument to a variable 2012-08-27 23:39:18 +01:00
Justin Clark-Casey (justincc)
ab9bfe5156 minor: Simplify return of vector render module name and some very minor removal of unncessary syntax clutter 2012-08-27 23:06:37 +01:00
Justin Clark-Casey (justincc)
4e26d039d6 Add VectorRenderModule.TestRepeatSameDrawDifferentExtraParams() 2012-08-27 23:03:21 +01:00
Justin Clark-Casey (justincc)
3082fdd0f6 Add VectorRenderModuleTests.TestRepeatDrawContainingImage() 2012-08-27 22:58:20 +01:00
Justin Clark-Casey (justincc)
e90168c738 Add VectorRenderModuleTests.TestRepeatDraw() 2012-08-27 22:42:40 +01:00
Melanie
a5c6cb2fc9 Merge branch 'master' of melanie@opensimulator.org:/var/git/opensim 2012-08-25 17:34:08 +01:00
Melanie
6ea95a3294 Fix and refactor region registration. Reorder checks to short-curcuit expensive and destructive ones. Properly fix region reservation and authentication.
Make region moves and flags preservation work again as intended. Prevent
failes reservation take-over from damging reservation data.
2012-08-25 17:32:00 +01:00
SignpostMarv
6e86b23012 implementing PRIM_LINK_TARGET on GetPrimParams ala SetPrimParams 2012-08-25 02:30:23 +01:00
SignpostMarv
58714b0aca minor formatting 2012-08-25 02:30:23 +01:00
SignpostMarv
5203665bb2 refactoring to local variable for cleaner code 2012-08-25 02:30:23 +01:00
SignpostMarv
2a2e120470 since we will be making the Get return type the remaining ruleset as with the Set return type, we need to move the original return type to a ref param 2012-08-25 02:30:23 +01:00
SignpostMarv
a8044999fb use SceneObjectPart instead of var 2012-08-25 02:30:23 +01:00
SignpostMarv
3d504261b0 renaming to be similar to equivalent Set command 2012-08-25 02:30:23 +01:00
Justin Clark-Casey (justincc)
a0d178b284 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-25 02:00:17 +01:00
Justin Clark-Casey (justincc)
f8a89a79eb 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-25 01:09:12 +01:00
Justin Clark-Casey (justincc)
e04047152f minor: Fix bad log message for failure to create an inventory folder 2012-08-25 00:49:38 +01:00
Justin Clark-Casey (justincc)
f3a5e3a02b 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-25 00:42:32 +01:00
Justin Clark-Casey (justincc)
ba58331b29 Extend "Restarting scripts in attachments" debug log message to show actual name of user and the region they are in 2012-08-24 22:56:05 +01:00
Justin Clark-Casey (justincc)
476996bee8 If a connecting scene presence is replacing an existing scene presence then bypass close checks. 2012-08-24 22:38:07 +01:00
Justin Clark-Casey (justincc)
01771aca40 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2012-08-24 21:38:46 +01:00
Justin Clark-Casey (justincc)
cd325fdf02 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:36:20 +01:00
SignpostMarv
67477290ad stripping superfluous whitespace
Signed-off-by: Melanie <melanie@t-data.com>
2012-08-24 17:44:35 +01:00
SignpostMarv
582a256646 immediately returning the string.Join operation instead of checking if the list has members 2012-08-24 17:44:14 +01:00
SignpostMarv
d188272462 refactoring using List.ConvertAll<string> 2012-08-24 17:44:14 +01:00
SignpostMarv
632908db9e adding sqlite journal files to .gitignore 2012-08-24 01:26:11 +01:00
Justin Clark-Casey (justincc)
82b23f7cc1 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2012-08-24 01:20:23 +01:00
Justin Clark-Casey (justincc)
a08687aef3 Revert "implementing function to allow scripts to self-replicate as if the owner duplicated them, using the same script delay as llRezObject()"
This reverts commit 2ad9d656b3.

Reverted pending consideration of associated issues.
2012-08-24 01:18:35 +01:00
SignpostMarv
2ad9d656b3 implementing function to allow scripts to self-replicate as if the owner duplicated them, using the same script delay as llRezObject() 2012-08-24 00:21:42 +01:00
Melanie
1747030d19 Merge branch 'master' of melanie@opensimulator.org:/var/git/opensim 2012-08-24 00:16:58 +01:00
Melanie
c557684666 Fix bad child prim permissions that can make objects change perms after rezzing
Port from Avination
2012-08-24 00:15:30 +01:00
TBG Renfold
a3cbda0d74 Removed land checking as suggested by SignpostMarv.
Now whatever remaining health the avatar has is displayed (float).
This will be 100% (100.000000) if no damage has occurred (as what the viewer should really be seeing anyway).

Returns -1.000000 if the avatar is not found.
2012-08-24 00:13:27 +01:00
TBG Renfold
4f3fabae5b Adds osGetHealth.
Returns the amount of health (in an integer) that an avatar has left in the scene.
If an avatar is not found or safe is enabled on a region, -1 is returned.

Example usage:

default
{
    touch_end(integer _t)
    {
        key agentID = llDetectedKey(0);
        osCauseDamage(agentID, 50);
        llSay(0, llKey2Name(agentID) + " has " + (string)osGetHealth(agentID) + "% health left.");
    }
}
2012-08-24 00:13:14 +01:00
Justin Clark-Casey (justincc)
aede42b875 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-23 23:13:53 +01:00
Justin Clark-Casey (justincc)
a533db7e27 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-23 22:30:14 +01:00
SignpostMarv
4820dfd733 this should be an if-else block in case the non-phys min/max are smaller than the physical min/max 2012-08-22 23:55:01 +01:00
Justin Clark-Casey (justincc)
1369058280 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-22 23:04:17 +01:00
Robert Adams
568de9313a BulletSim: update DLLs and SOs to eliminate terrain update crash which manifested itself on Linux. 2012-08-21 20:55:48 -07:00
Justin Clark-Casey (justincc)
219326dd8e Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2012-08-21 22:29:27 +01:00
Justin Clark-Casey (justincc)
9925317239 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-21 22:21:35 +01:00
nebadon
150748392e testing github bot take 2 2012-08-20 15:57:28 -07:00
nebadon
555edc4ef7 testing github commit bot 2012-08-20 15:51:30 -07:00
SignpostMarv
481c00f50a refactoring out SetFaceColor 2012-08-20 23:10:25 +01:00
SignpostMarv
ede3b9ab07 making use of implicit operators and Util.Clip handling of Vector3 2012-08-20 23:10:25 +01:00
SignpostMarv
b863a15a82 single operation for PRIM_COLOR 2012-08-20 23:10:25 +01:00
SignpostMarv
aee4353e9c fix typo 2012-08-20 23:10:25 +01:00
Justin Clark-Casey (justincc)
e6fb458597 no-op change for cia.vc test 2012-08-20 22:18:29 +01:00
Justin Clark-Casey (justincc)
812c498ef4 When loading an OAR, validate any group UUIDs and properly reconstruct parcel access lists.
If a group UUID is present that is not on this simulator then the object or parcel is no longer group owned.
This is a change from previous behaviour where such invalid UUIDs were kept.
This is an adaptation of patch 0002 from http://opensimulator.org/mantis/view.php?id=6105 by Oren Hurvitz of Kitely.
My adaptations are formatting only, apart from the notices about parcel owner IDs not being saved since this has now been fixed.
Thanks Oren.
2012-08-20 22:01:02 +01:00
Justin Clark-Casey (justincc)
970727e57e 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-20 20:55:58 +01:00
Justin Clark-Casey (justincc)
bcbd450fe4 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-20 20:24:54 +01:00
Melanie
9aec62f0ac Fix scripted detach of temp attachments 2012-08-20 15:59:38 +01:00
Melanie
dd0556abc9 Fix llDialog responses so that they can be heard throughout the region. This now conforms to the behaviour in SL. 2012-08-19 22:05:38 +01:00
Melanie
8769e4ee73 Add a reference to OpenMetaverseType.dll to compiled script assemblies. 2012-08-18 19:08:38 +01:00
SignpostMarv
d72d599056 integrating redundant code into operator 2012-08-18 18:30:00 +01:00
SignpostMarv
ca33619e11 Rot2Quaternion is now redundant 2012-08-18 18:30:00 +01:00
SignpostMarv
ffdde05bb7 constructor means not having to manually refer to individual properties 2012-08-18 18:29:59 +01:00
SignpostMarv
fb84ff96a9 implicit operators mean one does not need to instantiate new objects manually 2012-08-18 18:29:59 +01:00
SignpostMarv
52d7af05bc adding missing refactor for LSL_Vector 2012-08-18 18:29:59 +01:00
SignpostMarv
2b0c8bc480 Implementing operators & constructors for Quaternion 2012-08-18 18:29:59 +01:00
Melanie
2a70afeca2 Fix the whitespace formatting error introduced by the last patch 2012-08-18 14:00:10 +01:00
SignpostMarv
5d7751da89 refactoring for Vector3 operator & constructor tweaks 2012-08-18 13:21:55 +01:00
Melanie
9d6fe1224a Merge branch 'master' of melanie@opensimulator.org:/var/git/opensim 2012-08-18 12:57:49 +01:00
Justin Clark-Casey (justincc)
e4e5237086 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-18 00:46:34 +01:00
SignpostMarv
28d0aff2e3 adding null return to fix building 2012-08-17 23:23:03 +01:00
SignpostMarv
7068fddd2f fixing bug that get/set the wrong property for prim types other than sphere & box 2012-08-17 23:23:03 +01:00
SignpostMarv
466d684fbe implemented 2012-08-17 23:23:03 +01:00
SignpostMarv
74f5253a36 attempt to handle InvalidCastException in a manner similar to Second Life 2012-08-17 23:08:24 +01:00
Justin Clark-Casey (justincc)
3ad827174e Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2012-08-17 22:50:54 +01:00
Justin Clark-Casey (justincc)
56da788243 Add information to ThreadStackSize about possibly increasing if suffering StackOverflowExceptions during script conversion/compilation (e.g. on Windows 64-bit) 2012-08-17 22:50:11 +01:00
Robert Adams
7243d4f842 BulletSim: Properly regenerate hulls when objects made physical.
This fixes the problem of non-base shapes (cubes and spheres)
    falling through the terrain.
2012-08-17 14:45:18 -07:00
Justin Clark-Casey (justincc)
f57c1ac386 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2012-08-17 22:31:58 +01:00
Justin Clark-Casey (justincc)
0860a0d856 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-17 22:30:01 +01:00
Robert Adams
03d76e9403 BulletSim: restore most of the Detail logging statements. Will have
no effect on non-logging running.
Capture region name that is passed to the physics engine and use
    it for detail logging file name prefix.
Fix problem with avatars dropping when flying across region boundries.
2012-08-17 13:34:22 -07:00
Robert Adams
5c192b9bab Modify order of code so SOP doesn't set the physics actor flying
property multiple times every time Update is called.
This eliminates zillions of settings which is better for BulletSim.
The should be no functionality change.
2012-08-17 13:34:20 -07:00
Robert Adams
ccc69d66a1 BulletSim: add parameters and functionality to specify the mesh
level of detail for large meshes.
Remove parameter and code for DetailLog (conditional logging into
   regular log file).
2012-08-17 13:34:18 -07:00
Robert Adams
8eda290262 BulletSim: comments and parameter changes in dynamics engine. 2012-08-17 13:34:16 -07:00
Robert Adams
e31e23d68d BulletSim: in BSDynamics, merge 'flags' and 'hoverFlags' as they are defined for the same bits and it makes the code less complicated. 2012-08-17 13:34:14 -07:00
Justin Clark-Casey (justincc)
99e339dd40 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2012-08-17 18:48:35 +01:00
SignpostMarv
e9ea911563 adding a clip method to handle Vector3 objects to enable a minor amount of refactoring 2012-08-17 18:40:49 +01:00
Melanie
9995421df1 Do a proper null check to avoid the overloaded operator == trap 2012-08-16 02:35:03 +01:00
Robert Adams
57a9879669 Correct an exception report in SceneObjectPart so it outputs the stack. 2012-08-15 16:39:00 -07:00
Robert Adams
376441e550 BulletSim: make it so objects in a linkset do not generate collisions with each other. 2012-08-15 16:29:50 -07:00
Robert Adams
ae5db637f2 BulletSim: update DLLs and SOs to fix the problem with avatars jumping around at altitudes less than 25m. 2012-08-15 16:29:46 -07:00
SignpostMarv
ef4122213c enables configurable minimum sizes for physical & non-physical prims 2012-08-15 23:35:23 +01:00
Melanie
e286a95d76 Merge branch 'master' of melanie@opensimulator.org:/var/git/opensim 2012-08-15 22:59:31 +01:00
SignpostMarv
0aa1f1cc3f Implementing PRIM_LINK_TARGET in a non-recursive fashion 2012-08-15 22:58:33 +01:00
Justin Clark-Casey (justincc)
5a1b6fdf06 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-15 22:43:32 +01:00
SignpostMarv
7679384829 adding ATTACH_*_PEC constants 2012-08-15 22:06:20 +01:00
Robert Adams
9f83f4bfa3 BulletSim: update DLLs and SOs 2012-08-15 12:08:29 -07:00
Robert Adams
2b982ab212 BulletSim: add physics logging parameters to OpenSimDefaults.ini. Remove trailing semis from some the of the value definitions. 2012-08-15 12:08:25 -07:00
Robert Adams
dd10cf01e7 BulletSim: add hinge constraint.
Update BulletSimAPI with new constraint related function calls.
Reorganize locking in BS6DofConstraint.
Update BS6DofConstraint to do constraint reset correctly.
Add new 'midpoint' construction of 6Dof constraint.
2012-08-15 12:08:21 -07:00
Robert Adams
9efe7bf7ba BulletSim: add locking to constraintCollection and rename some of the public method variables to reduce confusion between a physics scene and the real scene. 2012-08-15 12:08:17 -07:00
Robert Adams
68f112888b BulletSim: clean up detail logging by adding many more debug log statements and then commenting out most of the additions. 2012-08-15 12:08:13 -07:00
Robert Adams
b05a2fc4ed BulletSim: don't recreate mesh unless it needs it when rebuilding the hull. Make sure the collisionCollection is reallocated each tick to fix race condition of it being cleared while still in use. 2012-08-15 12:08:09 -07:00
Robert Adams
257446889b BulletSim: fix problem of a null reference exception on shutdown if there were linksets in the region. 2012-08-15 12:08:05 -07:00
Robert Adams
77a7758cf5 BulletSim: Refactor BSConstraintCollection to add a new RemoveAndDestroyConstraint(BSConstraint xx) 2012-08-15 12:08:01 -07:00
Robert Adams
c1c1d48af1 BulletSim: add BSConstraint.RecomputConstraintVariables for the recomputation after linksets changed, etc 2012-08-15 12:07:57 -07:00
Robert Adams
6f1f299619 BulletSim: Add the class BSCharacter to the DetailLog output 2012-08-15 12:07:53 -07:00
Robert Adams
11a4b9ec1d BulletSim: rework physics FPS calculation to make a more realistic number. 2012-08-15 12:07:49 -07:00
Melanie
ebbf349c6a Let the temp attachment module add a command to allow attaching without permissions and add support for this (incomplete!) to LSL 2012-08-15 19:37:16 +01:00
Melanie
c27ff70d5c Add support for the extra params to scene and the event manager 2012-08-15 18:58:39 +01:00
Melanie
c7f2debd38 Fix and finish the extra parameters storage system for MySQL 2012-08-15 18:58:32 +01:00
Melanie
dc82ad0f7a Add a skeleton for a name value storage associated with regions 2012-08-15 02:06:22 +01:00
Melanie
f6562e2269 Actually add the module 2012-08-14 22:22:25 +01:00
Melanie
faa710aee1 Allow the use of the region debug console found in recent viewers. This console
will be available to estate owners and managers. If the user using the console
had god privs, they can use "set console on" and "set console off" to switch on
the actual region console. This allows console access from within the viewer.
The region debug console can coexist with any other main console.
2012-08-14 22:22:20 +01:00
Justin Clark-Casey (justincc)
d8125fb1f7 minor: Add Gryc Ueusp to CREDITS for commit 884edac amongst others, by request. 2012-08-14 21:56:31 +01:00
Justin Clark-Casey (justincc)
c42fe6c159 Prevent race conditions when one thread removes an NPC SP before another thread has retreived it after checking whether the NPC exists. 2012-08-14 21:44:06 +01:00
Melanie
a5b6492223 Perform ownership transfer and permission propagation as well as needed
updates on the new temp attachment.
2012-08-14 13:40:13 +01:00
Melanie
1be072f19e Move inititalization to RegionLoaded to avoid a module loading order issue 2012-08-14 09:55:44 +01:00
Melanie
4bbdcfb5ee Implement the temp attachments. UNTESTED 2012-08-14 01:45:02 +01:00
Melanie
9bd2c1b88a As per lindn spec, disable detach and drop for temp attachments 2012-08-14 01:12:27 +01:00
Melanie
62acfabec4 Add the skeleton for the temp attachments module 2012-08-14 00:54:12 +01:00
Melanie
50db8649aa Exclude temp attachemnts from being sent to the avatar service 2012-08-14 00:29:39 +01:00
Melanie
fe4c3a37c0 Lay some groundwork for temp attachments. Decouple attachments from inventory. 2012-08-14 00:12:15 +01:00
SignpostMarv
58c630c18e attempt at replicating behaviour of llList2thing functions in SL
Committed with changes. Please don't sign comments with your name. Please
don't use your own coding style, use the OpenSim project style. Please
don't modify unrelated whitespace.

Signed-off-by: Melanie <melanie@t-data.com>
2012-08-13 19:17:19 +01:00
Robert Adams
3ecd39068c Merge branch 'bulletsim7' 2012-08-10 16:35:00 -07:00
Robert Adams
3a55d5b123 BulletSim: actually update the DLLs and SOs 2012-08-10 16:34:22 -07:00
Robert Adams
0c7ce4fc98 BulletSim: many, many detailed logging messages for physical linkset
debugging.
Linkset bugs fixed where accounting of children would get lost.
Moved scene based vehicle tracking logic from prim to the scene.
Added GetCollisionFlags2 method to BulletSimAPI.
Updated DLLs and SOs.
2012-08-10 16:22:44 -07:00
Robert Adams
3ca770cd2c BulletSim: Add module names to DetailLog output. Fix some problems with linksets that were caused by checking data structures that are changed regularly from taint time code -- resulted in linksets not being unlinked properly. 2012-08-10 08:33:09 -07:00
Robert Adams
320982cae3 BulletSim: add an identifier to the TaintObject call so exceptions that happen when the taint is invoked can be debugged 2012-08-09 15:17:19 -07:00
Robert Adams
38e79b80a8 BulletSim: separate out the constraints by type. The linksets use
6dof constraint but eventually others will be exposed so future
features can use all the Bullet capabilities.
Force children to generate a position update when unlinked.
2012-08-09 15:01:05 -07:00
Robert Adams
5ab151c2d6 BulletSim: add avatar code to keep avatars from ending up trapped under the terrain 2012-08-08 13:48:49 -07:00
Robert Adams
19417fca41 BulletSim: Added avatar capsule scaling for size of avatar.
This also fixes computation of avatar mass.
Added parameter MaxPersistantManifoldPoolSize.
Fixed a parameter setting bug which caused crashes of there were
  more than 400 or so physical objects. I tested up to 5000.
Updated BulletSim DLLs and SOs.
2012-08-07 17:15:06 -07:00
Melanie
926c0b90a1 Release http-in URLs when llResetScript is called 2012-08-07 20:48:22 +01:00
Robert Adams
4adb3471ac BulletSim: update SOs and DLLs to run on more Linux versions. Correct multiple buoyancy settings when character flying. Remove chatty log message on prim destruction. 2012-08-06 12:55:52 -07:00
387 changed files with 9858 additions and 30961 deletions

3
.gitignore vendored
View File

@@ -66,7 +66,6 @@ Examples/*.dll
OpenSim.build
OpenSim.sln
OpenSim.suo
OpenSim.userprefs
Prebuild/Prebuild.build
Prebuild/Prebuild.sln
TestResult.xml
@@ -95,5 +94,3 @@ 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,11 +43,10 @@
<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.md"/>
<include name="BUILDING.txt"/>
<include name="Makefile"/>
<include name="nant-color"/>
<include name="OpenSim.*"/>
@@ -133,16 +132,6 @@
</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>
@@ -246,16 +235,6 @@
<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}" />
@@ -266,7 +245,6 @@
<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

@@ -92,6 +92,7 @@ what it is today.
* Flyte Xevious
* Garmin Kawaguichi
* Gryc Ueusp
* Hiro Lecker
* 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(requestData["persist"]);
bool persist = Convert.ToBoolean((string) 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(requestData["start_region_x"]);
uint regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
uint regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]);
uint regionYLocation = Convert.ToUInt32((Int32) 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(requestData["start_region_x"]);
regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]);
if (requestData.ContainsKey("start_region_y"))
regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]);
// if (requestData.ContainsKey("start_lookat_x"))
// ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]);
@@ -2381,6 +2381,7 @@ 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;
@@ -2435,6 +2436,7 @@ 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;
@@ -2547,6 +2549,7 @@ 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;
@@ -2852,6 +2855,7 @@ 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,16 +312,14 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
// Now that everything is setup we can proceed to
// add THIS agent to the HTTP server's handler list
// 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();
// }
// }
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)
@@ -344,13 +342,11 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
// 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){}
try
{
RemoveAgentHandler(Rest.Name, this);
}
catch (KeyNotFoundException){}
foreach (IRest handler in handlers)
{

View File

@@ -297,9 +297,7 @@ namespace OpenSim.ApplicationPlugins.Rest
{
if (!IsEnabled) return false;
_agents.Add(agentName, handler);
// return _httpd.AddAgentHandler(agentName, handler);
return false;
return _httpd.AddAgentHandler(agentName, handler);
}
/// <summary>
@@ -318,7 +316,7 @@ namespace OpenSim.ApplicationPlugins.Rest
if (_agents[agentName] == handler)
{
_agents.Remove(agentName);
// return _httpd.RemoveAgentHandler(agentName, handler);
return _httpd.RemoveAgentHandler(agentName, handler);
}
return false;
}
@@ -360,10 +358,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,54 +219,25 @@ 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)
{
// 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;
response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
}
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;
@@ -304,43 +275,15 @@ 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))
return false;
string rawEnd = rangeValues[1];
if (rawEnd == "")
{
end = -1;
if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end))
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 : OpenSimTestCase
public class GetTextureHandlerTests
{
[Test]
public void TestTextureNotFound()

View File

@@ -116,22 +116,7 @@ namespace OpenSim.Data
/// <returns>true if the delete was successful, false if it was not</returns>
bool DeleteItems(string[] fields, string[] vals);
/// <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);
bool MoveItem(string id, string newParent);
XInventoryItem[] GetActiveGestures(UUID principalID);
int GetAssetPermissions(UUID principalID, UUID assetID);
}

View File

@@ -2202,5 +2202,18 @@ VALUES
}
}
}
public void SaveExtra(UUID regionID, string name, string value)
{
}
public void RemoveExtra(UUID regionID, string name)
{
}
public Dictionary<string, string> GetExtra(UUID regionID)
{
return null;
}
}
}

View File

@@ -43,12 +43,12 @@ namespace OpenSim.Data.MSSQL
// private static readonly ILog m_log = LogManager.GetLogger(
// MethodBase.GetCurrentMethod().DeclaringType);
private MSSQLFolderHandler m_Folders;
private MSSQLGenericTableHandler<XInventoryFolder> m_Folders;
private MSSQLItemHandler m_Items;
public MSSQLXInventoryData(string conn, string realm)
{
m_Folders = new MSSQLFolderHandler(
m_Folders = new MSSQLGenericTableHandler<XInventoryFolder>(
conn, "inventoryfolders", "InventoryStore");
m_Items = new MSSQLItemHandler(
conn, "inventoryitems", String.Empty);
@@ -85,7 +85,6 @@ namespace OpenSim.Data.MSSQL
{
return m_Folders.Delete(field, val);
}
public bool DeleteFolders(string[] fields, string[] vals)
{
return m_Folders.Delete(fields, vals);
@@ -95,22 +94,15 @@ 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);
@@ -122,7 +114,7 @@ namespace OpenSim.Data.MSSQL
}
}
public class MSSQLItemHandler : MSSQLInventoryHandler<XInventoryItem>
public class MSSQLItemHandler : MSSQLGenericTableHandler<XInventoryItem>
{
public MSSQLItemHandler(string c, string t, string m) :
base(c, t, m)
@@ -131,163 +123,70 @@ namespace OpenSim.Data.MSSQL
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 (SqlConnection conn = new SqlConnection(m_ConnectionString))
using (SqlCommand cmd = new SqlCommand())
{
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;
}
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;
}
IncrementFolderVersion(oldParent);
IncrementFolderVersion(newParent);
return true;
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
using (SqlConnection conn = new SqlConnection(m_ConnectionString))
using (SqlCommand cmd = new SqlCommand())
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = String.Format("select * from inventoryitems where avatarId = @uuid and assetType = @type and flags = 1", m_Realm);
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())
{
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())
{
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())
int perms = 0;
if (reader.Read())
{
int perms = 0;
if (reader.Read())
{
perms = Convert.ToInt32(reader["inventoryCurrentPermissions"]);
}
return perms;
perms = Convert.ToInt32(reader["inventoryCurrentPermissions"]);
}
return perms;
}
}
}
public override bool Store(XInventoryItem item)
{
if (!base.Store(item))
return false;
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;
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))
{
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);
conn.Open();
cmd.Parameters.AddWithValue("@folderID", item.parentFolderID.ToString());
try
{
cmd.ExecuteNonQuery();
@@ -295,11 +194,9 @@ namespace OpenSim.Data.MSSQL
catch (Exception)
{
return false;
}
}
}
}
return true;
}
}
}
}

View File

@@ -219,8 +219,6 @@ 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 = "";
@@ -275,10 +273,6 @@ 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

@@ -1985,5 +1985,74 @@ namespace OpenSim.Data.MySQL
}
}
}
public void SaveExtra(UUID regionID, string name, string val)
{
lock (m_dbLock)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
{
cmd.CommandText = "replace into regionextra values (?RegionID, ?Name, ?value)";
cmd.Parameters.AddWithValue("?RegionID", regionID.ToString());
cmd.Parameters.AddWithValue("?Name", name);
cmd.Parameters.AddWithValue("?value", val);
cmd.ExecuteNonQuery();
}
}
}
}
public void RemoveExtra(UUID regionID, string name)
{
lock (m_dbLock)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
{
cmd.CommandText = "delete from regionextra where RegionID=?RegionID and Name=?Name";
cmd.Parameters.AddWithValue("?RegionID", regionID.ToString());
cmd.Parameters.AddWithValue("?Name", name);
cmd.ExecuteNonQuery();
}
}
}
}
public Dictionary<string, string> GetExtra(UUID regionID)
{
Dictionary<string, string> ret = new Dictionary<string, string>();
lock (m_dbLock)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = dbcon.CreateCommand())
{
cmd.CommandText = "select * from regionextra where RegionID=?RegionID";
cmd.Parameters.AddWithValue("?RegionID", regionID.ToString());
using (IDataReader r = cmd.ExecuteReader())
{
while (r.Read())
{
ret[r["Name"].ToString()] = r["value"].ToString();
}
}
}
}
}
return ret;
}
}
}

View File

@@ -26,10 +26,9 @@
*/
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using log4net;
using MySql.Data.MySqlClient;
using OpenMetaverse;
@@ -42,12 +41,12 @@ namespace OpenSim.Data.MySQL
/// </summary>
public class MySQLXInventoryData : IXInventoryData
{
private MySqlFolderHandler m_Folders;
private MySQLGenericTableHandler<XInventoryFolder> m_Folders;
private MySqlItemHandler m_Items;
public MySQLXInventoryData(string conn, string realm)
{
m_Folders = new MySqlFolderHandler(
m_Folders = new MySQLGenericTableHandler<XInventoryFolder>(
conn, "inventoryfolders", "InventoryStore");
m_Items = new MySqlItemHandler(
conn, "inventoryitems", String.Empty);
@@ -106,11 +105,6 @@ 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);
@@ -122,71 +116,24 @@ namespace OpenSim.Data.MySQL
}
}
public class MySqlItemHandler : MySqlInventoryHandler<XInventoryItem>
public class MySqlItemHandler : MySQLGenericTableHandler<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);
if (ExecuteNonQuery(cmd) == 0)
return false;
return ExecuteNonQuery(cmd) == 0 ? false : true;
}
IncrementFolderVersion(oldParent);
IncrementFolderVersion(newParent);
return true;
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
@@ -237,73 +184,6 @@ 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();
@@ -313,7 +193,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", folderID);
cmd.Parameters.AddWithValue("?folderID", item.parentFolderID.ToString());
try
{
@@ -325,11 +205,9 @@ namespace OpenSim.Data.MySQL
}
cmd.Dispose();
}
dbcon.Close();
}
return true;
}
}
}
}

View File

@@ -895,3 +895,10 @@ CREATE TABLE `regionenvironment` (
COMMIT;
:VERSION 45
BEGIN;
CREATE TABLE `regionextra` (`RegionID` char(36) not null, `Name` varchar(32) not null, `value` text, primary key(`RegionID`, `Name`));
COMMIT;

View File

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

View File

@@ -151,5 +151,18 @@ namespace OpenSim.Data.Null
public void Shutdown()
{
}
public void SaveExtra(UUID regionID, string name, string value)
{
}
public void RemoveExtra(UUID regionID, string name)
{
}
public Dictionary<string, string> GetExtra(UUID regionID)
{
return null;
}
}
}

View File

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

View File

@@ -56,17 +56,23 @@ namespace OpenSim.Data.SQLite
public bool Delete(UUID principalID, string name)
{
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);
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
{
if (ExecuteNonQuery(cmd, m_Connection) > 0)
return true;
}
return false;
return false;
}
finally
{
//CloseCommand(cmd);
}
}
}
}
}

View File

@@ -104,13 +104,12 @@ 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";
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":RegionID", regionID.ToString());
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
return DoLoad(cmd, regionID, create);
}
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":RegionID", regionID.ToString());
return DoLoad(cmd, regionID, create);
}
private EstateSettings DoLoad(SqliteCommand cmd, UUID regionID, bool create)
@@ -187,40 +186,38 @@ namespace OpenSim.Data.SQLite
{
List<string> names = new List<string>(FieldList);
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
IDataReader r = null;
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
names.Remove("EstateID");
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)
foreach (string name in FieldList)
{
if (m_FieldMap[name].GetValue(es) is bool)
{
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");
}
if ((bool)m_FieldMap[name].GetValue(es))
cmd.Parameters.AddWithValue(":"+name, "1");
else
{
cmd.Parameters.AddWithValue(":"+name, m_FieldMap[name].GetValue(es).ToString());
}
cmd.Parameters.AddWithValue(":"+name, "0");
}
else
{
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"]);
@@ -242,28 +239,27 @@ namespace OpenSim.Data.SQLite
string sql = "update estate_settings set "+String.Join(", ", terms.ToArray())+" where EstateID = :EstateID";
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
cmd.CommandText = sql;
foreach (string name in FieldList)
{
cmd.CommandText = sql;
foreach (string name in FieldList)
if (m_FieldMap[name].GetValue(es) is bool)
{
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");
}
if ((bool)m_FieldMap[name].GetValue(es))
cmd.Parameters.AddWithValue(":"+name, "1");
else
{
cmd.Parameters.AddWithValue(":"+name, m_FieldMap[name].GetValue(es).ToString());
}
cmd.Parameters.AddWithValue(":"+name, "0");
}
else
{
cmd.Parameters.AddWithValue(":"+name, m_FieldMap[name].GetValue(es).ToString());
}
cmd.ExecuteNonQuery();
}
cmd.ExecuteNonQuery();
SaveBanList(es);
SaveUUIDList(es.EstateID, "estate_managers", es.EstateManagers);
SaveUUIDList(es.EstateID, "estate_users", es.EstateAccess);
@@ -274,15 +270,12 @@ namespace OpenSim.Data.SQLite
{
es.ClearBans();
IDataReader r;
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = "select bannedUUID from estateban where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", es.EstateID);
cmd.CommandText = "select bannedUUID from estateban where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", es.EstateID);
r = cmd.ExecuteReader();
}
IDataReader r = cmd.ExecuteReader();
while (r.Read())
{
@@ -301,64 +294,60 @@ namespace OpenSim.Data.SQLite
private void SaveBanList(EstateSettings es)
{
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
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)
{
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)
{
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
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)
{
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;
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = "select uuid from "+table+" where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", EstateID);
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
r = cmd.ExecuteReader();
}
cmd.CommandText = "select uuid from "+table+" where EstateID = :EstateID";
cmd.Parameters.AddWithValue(":EstateID", EstateID);
IDataReader r = cmd.ExecuteReader();
while (r.Read())
{
@@ -378,13 +367,12 @@ namespace OpenSim.Data.SQLite
{
string sql = "select estate_settings."+String.Join(",estate_settings.", FieldList)+" from estate_settings where estate_settings.EstateID = :EstateID";
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateID", estateID.ToString());
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
return DoLoad(cmd, UUID.Zero, false);
}
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateID", estateID.ToString());
return DoLoad(cmd, UUID.Zero, false);
}
public List<EstateSettings> LoadEstateSettingsAll()
@@ -403,15 +391,13 @@ namespace OpenSim.Data.SQLite
List<int> result = new List<int>();
string sql = "select EstateID from estate_settings where estate_settings.EstateName = :EstateName";
IDataReader r;
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateName", search);
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
r = cmd.ExecuteReader();
}
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateName", search);
IDataReader r = cmd.ExecuteReader();
while (r.Read())
{
@@ -427,14 +413,12 @@ namespace OpenSim.Data.SQLite
List<int> result = new List<int>();
string sql = "select EstateID from estate_settings";
IDataReader r;
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = sql;
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
r = cmd.ExecuteReader();
}
cmd.CommandText = sql;
IDataReader r = cmd.ExecuteReader();
while (r.Read())
{
@@ -450,15 +434,13 @@ namespace OpenSim.Data.SQLite
List<int> result = new List<int>();
string sql = "select EstateID from estate_settings where estate_settings.EstateOwner = :EstateOwner";
IDataReader r;
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateOwner", ownerID);
SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand();
r = cmd.ExecuteReader();
}
cmd.CommandText = sql;
cmd.Parameters.AddWithValue(":EstateOwner", ownerID);
IDataReader r = cmd.ExecuteReader();
while (r.Read())
{

View File

@@ -90,5 +90,12 @@ 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)
{
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());
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);
return DoQuery(cmd);
}
}
public bool Delete(UUID principalID, string friend)
@@ -69,14 +69,13 @@ namespace OpenSim.Data.SQLite
public bool Delete(string principalID, string friend)
{
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);
SqliteCommand cmd = new SqliteCommand();
ExecuteNonQuery(cmd, m_Connection);
}
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);
return true;
}

View File

@@ -120,35 +120,34 @@ namespace OpenSim.Data.SQLite
}
}
public virtual T[] Get(string field, string key)
public T[] Get(string field, string key)
{
return Get(new string[] { field }, new string[] { key });
}
public virtual T[] Get(string[] fields, string[] keys)
public T[] Get(string[] fields, string[] keys)
{
if (fields.Length != keys.Length)
return new T[0];
List<string> terms = new List<string>();
using (SqliteCommand cmd = new SqliteCommand())
SqliteCommand cmd = new SqliteCommand();
for (int i = 0 ; i < fields.Length ; 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);
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);
}
protected T[] DoQuery(SqliteCommand cmd)
@@ -213,55 +212,53 @@ namespace OpenSim.Data.SQLite
return result.ToArray();
}
public virtual T[] Get(string where)
public T[] Get(string where)
{
using (SqliteCommand cmd = new SqliteCommand())
{
string query = String.Format("select * from {0} where {1}",
m_Realm, where);
SqliteCommand cmd = new SqliteCommand();
cmd.CommandText = query;
string query = String.Format("select * from {0} where {1}",
m_Realm, where);
return DoQuery(cmd);
}
cmd.CommandText = query;
return DoQuery(cmd);
}
public virtual bool Store(T row)
public bool Store(T row)
{
using (SqliteCommand cmd = new SqliteCommand())
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)
{
string query = "";
List<String> names = new List<String>();
List<String> values = new List<String>();
foreach (FieldInfo fi in m_Fields.Values)
{
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;
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;
return false;
}
@@ -270,29 +267,28 @@ namespace OpenSim.Data.SQLite
return Delete(new string[] { field }, new string[] { key });
}
public virtual bool Delete(string[] fields, string[] keys)
public bool Delete(string[] fields, string[] keys)
{
if (fields.Length != keys.Length)
return false;
List<string> terms = new List<string>();
using (SqliteCommand cmd = new SqliteCommand())
SqliteCommand cmd = new SqliteCommand();
for (int i = 0 ; i < fields.Length ; 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;
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;
}
}
}

View File

@@ -1366,12 +1366,6 @@ 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"] };
@@ -1787,15 +1781,9 @@ 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"]));
@@ -2209,10 +2197,10 @@ namespace OpenSim.Data.SQLite
row["OtherCleanTime"] = land.OtherCleanTime;
row["MediaType"] = land.MediaType;
row["MediaDescription"] = land.MediaDescription;
row["MediaSize"] = String.Format("{0},{1}", land.MediaWidth, land.MediaHeight);
row["MediaLoop"] = land.MediaLoop;
row["ObscureMusic"] = land.ObscureMusic;
row["ObscureMedia"] = land.ObscureMedia;
row["MediaSize"] = land.MediaWidth.ToString() + "," + land.MediaHeight.ToString();
row["MediaLoop"] = land.MediaLoop.ToString();
row["ObscureMusic"] = land.ObscureMusic.ToString();
row["ObscureMedia"] = land.ObscureMedia.ToString();
}
/// <summary>
@@ -2902,5 +2890,17 @@ namespace OpenSim.Data.SQLite
}
}
public void SaveExtra(UUID regionID, string name, string value)
{
}
public void RemoveExtra(UUID regionID, string name)
{
}
public Dictionary<string, string> GetExtra(UUID regionID)
{
return null;
}
}
}

View File

@@ -66,21 +66,20 @@ namespace OpenSim.Data.SQLite
if (words.Length > 2)
return new UserAccountData[0];
using (SqliteCommand cmd = new SqliteCommand())
{
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]);
}
SqliteCommand cmd = new SqliteCommand();
return DoQuery(cmd);
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);
}
}
}

View File

@@ -47,7 +47,7 @@ namespace OpenSim.Data.SQLite
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private SqliteFolderHandler m_Folders;
private SQLiteGenericTableHandler<XInventoryFolder> 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 SqliteFolderHandler(
m_Folders = new SQLiteGenericTableHandler<XInventoryFolder>(
conn, "inventoryfolders", "XInventoryStore");
m_Items = new SqliteItemHandler(
conn, "inventoryitems", String.Empty);
@@ -114,11 +114,6 @@ 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);
@@ -130,106 +125,44 @@ namespace OpenSim.Data.SQLite
}
}
public class SqliteItemHandler : SqliteInventoryHandler<XInventoryItem>
public class SqliteItemHandler : SQLiteGenericTableHandler<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)
{
XInventoryItem[] retrievedItems = Get(new string[] { "inventoryID" }, new string[] { id });
if (retrievedItems.Length == 0)
return false;
SqliteCommand cmd = new SqliteCommand();
UUID oldParent = retrievedItems[0].parentFolderID;
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));
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;
return ExecuteNonQuery(cmd, m_Connection) == 0 ? false : true;
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
using (SqliteCommand cmd = new SqliteCommand())
{
cmd.CommandText = String.Format("select * from inventoryitems where avatarId = :uuid and assetType = :type and flags = 1", m_Realm);
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)
{
IDataReader reader;
SqliteCommand cmd = new SqliteCommand();
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()));
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()));
reader = ExecuteReader(cmd, m_Connection);
}
IDataReader reader = ExecuteReader(cmd, m_Connection);
int perms = 0;
@@ -244,81 +177,4 @@ 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,7 +33,6 @@ 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;
@@ -44,12 +43,6 @@ 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,7 +36,6 @@ using NUnit.Framework;
using NUnit.Framework.Constraints;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Tests.Common;
namespace OpenSim.Data.Tests
{
@@ -255,7 +254,7 @@ namespace OpenSim.Data.Tests
}
[TestFixture]
public class PropertyCompareConstraintTest : OpenSimTestCase
public class PropertyCompareConstraintTest
{
public class HasInt
{

View File

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

View File

@@ -330,9 +330,6 @@ 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

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

View File

@@ -83,8 +83,7 @@ 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 all' to get a list of all commands,
or type help <item>' where <item> is one of the following:";
= "For more information, type 'help <item>' where <item> is one of the following:";
/// <value>
/// Commands organized by keyword in a tree
@@ -110,48 +109,19 @@ 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;
}
@@ -197,11 +167,14 @@ namespace OpenSim.Framework.Console
string descriptiveHelp = commandInfo.descriptive_help;
// If we do have some descriptive help then insert a spacing line before for readability.
// If we do have some descriptive help then insert a spacing line before and after for readability.
if (descriptiveHelp != string.Empty)
help.Add(string.Empty);
help.Add(commandInfo.descriptive_help);
if (descriptiveHelp != string.Empty)
help.Add(string.Empty);
}
else
{
@@ -705,6 +678,8 @@ namespace OpenSim.Framework.Console
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public event OnOutputDelegate OnOutput;
public ICommands Commands { get; private set; }
public CommandConsole(string defaultPrompt) : base(defaultPrompt)
@@ -724,12 +699,19 @@ namespace OpenSim.Framework.Console
Output(s);
}
protected void FireOnOutput(string text)
{
OnOutputDelegate onOutput = OnOutput;
if (onOutput != null)
onOutput(text);
}
/// <summary>
/// Display a command prompt on the console and wait for user input
/// </summary>
public void Prompt()
{
string line = ReadLine(DefaultPrompt + "# ", true, true);
string line = ReadLine(m_defaultPrompt + "# ", true, true);
if (line != String.Empty)
Output("Invalid command");

View File

@@ -43,7 +43,15 @@ namespace OpenSim.Framework.Console
public object ConsoleScene { get; set; }
public string DefaultPrompt { get; set; }
/// <summary>
/// The default prompt text.
/// </summary>
public string DefaultPrompt
{
set { m_defaultPrompt = value; }
get { return m_defaultPrompt; }
}
protected string m_defaultPrompt;
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 whole table.
/// Number of spaces to indent the 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 object[] cells)
public void AddRow(params string[] cells)
{
Rows.Add(new ConsoleDisplayTableRow(cells));
}
@@ -113,8 +113,7 @@ namespace OpenSim.Framework.Console
for (int i = 0; i < Columns.Count; i++)
{
if (i != 0)
formatSb.Append(' ', TableSpacing);
formatSb.Append(' ', TableSpacing);
// Can only do left formatting for now
formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width);
@@ -140,16 +139,16 @@ namespace OpenSim.Framework.Console
public struct ConsoleDisplayTableRow
{
public List<object> Cells { get; private set; }
public List<string> Cells { get; private set; }
public ConsoleDisplayTableRow(List<object> cells) : this()
public ConsoleDisplayTableRow(List<string> cells) : this()
{
Cells = cells;
}
public ConsoleDisplayTableRow(params object[] cells) : this()
public ConsoleDisplayTableRow(params string[] cells) : this()
{
Cells = new List<object>(cells);
Cells = new List<string>(cells);
}
}
}

View File

@@ -1,229 +0,0 @@
/*
* 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

@@ -319,6 +319,8 @@ namespace OpenSim.Framework.Console
public override void Output(string text, string level)
{
FireOnOutput(text);
lock (m_commandLine)
{
if (m_cursorYPosition == -1)
@@ -509,4 +511,4 @@ namespace OpenSim.Framework.Console
}
}
}
}
}

View File

@@ -40,22 +40,19 @@ namespace OpenSim.Framework.Console
/// </summary>
public class MockConsole : ICommandConsole
{
public event OnOutputDelegate OnOutput;
private MockCommands m_commands = new MockCommands();
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; }
set {}
}
public object ConsoleScene { get { return null; } }
public void Output(string text, string level) {}
public void Output(string text) {}

View File

@@ -100,6 +100,7 @@ namespace OpenSim.Framework.Console
m_LineNumber++;
m_Scrollback.Add(String.Format("{0}", m_LineNumber)+":"+level+":"+text);
}
FireOnOutput(text.Trim());
System.Console.WriteLine(text.Trim());
}

View File

@@ -31,7 +31,6 @@ 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

@@ -1,508 +0,0 @@
/*
* 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,23 +805,8 @@ 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;
@@ -1099,20 +1084,8 @@ namespace OpenSim.Framework
void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
/// <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 SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, byte source,
byte audible);
void SendInstantMessage(GridInstantMessage im);

View File

@@ -74,14 +74,13 @@ namespace OpenSim.Framework
XmlElement GetXml(XmlDocument doc);
}
public delegate void OnOutputDelegate(string message);
public interface ICommandConsole : IConsole
{
ICommands Commands { get; }
event OnOutputDelegate OnOutput;
/// <summary>
/// The default prompt text.
/// </summary>
string DefaultPrompt { get; set; }
ICommands Commands { get; }
/// <summary>
/// Display a command prompt on the console and wait for user input

View File

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

View File

@@ -87,7 +87,16 @@ namespace OpenSim.Framework
protected string m_creatorId;
/// <value>
/// The CreatorId expressed as a UUID.tely
/// 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.
/// </value>
public UUID CreatorIdAsUuid
{
@@ -100,18 +109,20 @@ namespace OpenSim.Framework
return m_creatorIdAsUuid;
}
set
{
m_creatorIdAsUuid = value;
}
}
protected UUID m_creatorIdAsUuid = UUID.Zero;
/// <summary>
/// Extended creator information of the form <profile url>;<name>
/// </summary>
protected string m_creatorData = string.Empty;
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.
@@ -151,6 +162,7 @@ namespace OpenSim.Framework
name = parts[2];
m_creatorData += ';' + name;
}
}
}

View File

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

View File

@@ -60,21 +60,13 @@ namespace OpenSim.Framework.Monitoring
private static bool m_enabled;
/// <summary>
/// Last memory churn in bytes per millisecond.
/// Average 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,25 +355,10 @@ 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}\n\n",
"{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}",
inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
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);
/*
sb.Append(Environment.NewLine);

View File

@@ -1,88 +0,0 @@
/*
* 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

@@ -1,238 +0,0 @@
/*
* 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,10 +25,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenSim.Framework.Monitoring
{
/// <summary>
@@ -36,24 +32,6 @@ 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();
@@ -62,75 +40,6 @@ 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.
@@ -152,153 +61,5 @@ 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>
public const double WATCHDOG_INTERVAL_MS = 2500.0d;
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;
@@ -231,25 +231,7 @@ namespace OpenSim.Framework.Monitoring
private static bool RemoveThread(int threadID)
{
lock (m_threads)
{
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;
}
}
return m_threads.Remove(threadID);
}
public static bool AbortThread(int threadID)
@@ -380,8 +362,6 @@ namespace OpenSim.Framework.Monitoring
if (MemoryWatchdog.Enabled)
MemoryWatchdog.Update();
StatsManager.RecordStats();
m_watchdogTimer.Start();
}
}

View File

@@ -31,114 +31,63 @@ using System.Reflection;
using OpenMetaverse;
using OpenMetaverse.Packets;
using log4net;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Region.ClientStack.LindenUDP
namespace OpenSim.Framework
{
public sealed class PacketPool
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly PacketPool instance = new PacketPool();
/// <summary>
/// Pool of packets available for reuse.
/// </summary>
private bool packetPoolEnabled = true;
private bool dataBlockPoolEnabled = true;
private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
private static Dictionary<Type, Stack<Object>> DataBlocks =
new Dictionary<Type, Stack<Object>>();
static PacketPool()
{
}
public static PacketPool Instance
{
get { return instance; }
}
public bool RecyclePackets { get; set; }
public bool RecycleDataBlocks { get; set; }
/// <summary>
/// The number of packets pooled
/// </summary>
public int PacketsPooled
public bool RecyclePackets
{
get
{
lock (pool)
return pool.Count;
}
set { packetPoolEnabled = value; }
get { return packetPoolEnabled; }
}
/// <summary>
/// The number of blocks pooled.
/// </summary>
public int BlocksPooled
public bool RecycleDataBlocks
{
get
{
lock (DataBlocks)
return DataBlocks.Count;
}
set { dataBlockPoolEnabled = value; }
get { return dataBlockPoolEnabled; }
}
/// <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 (!RecyclePackets)
if (!packetPoolEnabled)
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
PacketsReused++;
packet = pool[type].Pop();
packet = (pool[type]).Pop();
}
}
@@ -187,7 +136,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
PacketType type = GetType(bytes);
// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
int i = 0;
Packet packet = GetPacket(type);
@@ -205,7 +154,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <param name="packet"></param>
public void ReturnPacket(Packet packet)
{
if (RecycleDataBlocks)
if (dataBlockPoolEnabled)
{
switch (packet.Type)
{
@@ -229,12 +178,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
if (RecyclePackets)
if (packetPoolEnabled)
{
switch (packet.Type)
{
// List pooling packets here
case PacketType.AgentUpdate:
case PacketType.PacketAck:
case PacketType.ObjectUpdate:
case PacketType.ImprovedTerseObjectUpdate:
@@ -249,9 +197,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if ((pool[type]).Count < 50)
{
// m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
pool[type].Push(packet);
(pool[type]).Push(packet);
}
}
break;
@@ -263,21 +209,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
public T GetDataBlock<T>() where T: new()
public static 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
{
@@ -288,7 +229,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
public void ReturnDataBlock<T>(T block) where T: new()
public static void ReturnDataBlock<T>(T block) where T: new()
{
if (block == null)
return;
@@ -303,4 +244,4 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
}
}
}

View File

@@ -192,7 +192,18 @@ 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;
}
@@ -205,6 +216,7 @@ 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);
@@ -236,10 +248,7 @@ 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]
@@ -331,9 +340,9 @@ namespace OpenSim.Framework
_scale = new Vector3(side, side, side);
}
public void SetHeigth(float height)
public void SetHeigth(float heigth)
{
_scale.Z = height;
_scale.Z = heigth;
}
public void SetRadius(float radius)

View File

@@ -120,7 +120,9 @@ namespace OpenSim.Framework
public UUID lastMapUUID = UUID.Zero;
public string lastMapRefresh = "0";
private float m_nonphysPrimMin = 0;
private int m_nonphysPrimMax = 0;
private float m_physPrimMin = 0;
private int m_physPrimMax = 0;
private bool m_clampPrimSize = false;
private int m_objectCapacity = 0;
@@ -285,11 +287,21 @@ namespace OpenSim.Framework
set { m_windlight = value; }
}
public float NonphysPrimMin
{
get { return m_nonphysPrimMin; }
}
public int NonphysPrimMax
{
get { return m_nonphysPrimMax; }
}
public float PhysPrimMin
{
get { return m_physPrimMin; }
}
public int PhysPrimMax
{
get { return m_physPrimMax; }
@@ -623,16 +635,28 @@ namespace OpenSim.Framework
m_regionType = config.GetString("RegionType", String.Empty);
allKeys.Remove("RegionType");
// Prim stuff
//
#region Prim stuff
m_nonphysPrimMin = config.GetFloat("NonphysicalPrimMin", 0);
allKeys.Remove("NonphysicalPrimMin");
m_nonphysPrimMax = config.GetInt("NonphysicalPrimMax", 0);
allKeys.Remove("NonphysicalPrimMax");
m_physPrimMin = config.GetFloat("PhysicalPrimMin", 0);
allKeys.Remove("PhysicalPrimMin");
m_physPrimMax = config.GetInt("PhysicalPrimMax", 0);
allKeys.Remove("PhysicalPrimMax");
m_clampPrimSize = config.GetBoolean("ClampPrimSize", false);
allKeys.Remove("ClampPrimSize");
m_objectCapacity = config.GetInt("MaxPrims", 15000);
allKeys.Remove("MaxPrims");
#endregion
m_agentCapacity = config.GetInt("MaxAgents", 100);
allKeys.Remove("MaxAgents");
@@ -668,10 +692,18 @@ namespace OpenSim.Framework
config.Set("ExternalHostName", m_externalHostName);
if (m_nonphysPrimMin != 0)
config.Set("NonphysicalPrimMax", m_nonphysPrimMin);
if (m_nonphysPrimMax != 0)
config.Set("NonphysicalPrimMax", m_nonphysPrimMax);
if (m_physPrimMin != 0)
config.Set("PhysicalPrimMax", m_physPrimMin);
if (m_physPrimMax != 0)
config.Set("PhysicalPrimMax", m_physPrimMax);
config.Set("ClampPrimSize", m_clampPrimSize.ToString());
if (m_objectCapacity != 0)
@@ -754,9 +786,15 @@ namespace OpenSim.Framework
configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
"Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true);
configMember.addConfigurationOption("nonphysical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT,
"Minimum size for nonphysical prims", m_nonphysPrimMin.ToString(), true);
configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
"Maximum size for nonphysical prims", m_nonphysPrimMax.ToString(), true);
configMember.addConfigurationOption("physical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT,
"Minimum size for nonphysical prims", m_physPrimMin.ToString(), true);
configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
"Maximum size for physical prims", m_physPrimMax.ToString(), true);

View File

@@ -37,7 +37,7 @@ using OpenSim.Tests.Common;
namespace OpenSim.Framework.Serialization.Tests
{
[TestFixture]
public class LandDataSerializerTest : OpenSimTestCase
public class LandDataSerializerTest
{
private LandData land;
private LandData landWithParcelAccessList;

View File

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

View File

@@ -27,6 +27,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
@@ -37,8 +38,6 @@ 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;
@@ -46,12 +45,16 @@ 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 : ServerBase
public abstract class BaseOpenSimServer
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -60,6 +63,27 @@ 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
@@ -72,13 +96,35 @@ namespace OpenSim.Framework.Servers
get { return m_httpServer; }
}
public BaseOpenSimServer() : base()
/// <summary>
/// Holds the non-viewer statistics collection object for this service/server
/// </summary>
protected IStatsCollector m_stats;
public BaseOpenSimServer()
{
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>
@@ -86,18 +132,76 @@ namespace OpenSim.Framework.Servers
/// </summary>
protected virtual void StartupSpecific()
{
if (m_console == null)
return;
if (m_console != null)
{
ILoggerRepository repository = LogManager.GetRepository();
IAppender[] appenders = repository.GetAppenders();
RegisterCommonCommands();
m_console.Commands.AddCommand("General", false, "quit",
"quit",
"Quit the application", HandleQuit);
foreach (IAppender appender in appenders)
{
if (appender.Name == "Console")
{
m_consoleAppender = (OpenSimAppender)appender;
break;
}
}
m_console.Commands.AddCommand("General", false, "shutdown",
"shutdown",
"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()));
}
}
/// <summary>
@@ -122,19 +226,87 @@ namespace OpenSim.Framework.Servers
{
StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n");
sb.Append(GetUptimeReport());
sb.Append(StatsManager.SimExtraStats.Report());
if (m_stats != null)
{
sb.Append(m_stats.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
@@ -169,11 +341,271 @@ 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)
@@ -181,12 +613,27 @@ 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() + "(" + StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
return httpRequest.Query["callback"].ToString() + "(" + m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
}
else
{
return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
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)
{
}
}
}
}
}
}

View File

@@ -54,23 +54,8 @@ 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;
@@ -82,7 +67,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>();
@@ -260,29 +245,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)
{
@@ -311,8 +296,6 @@ namespace OpenSim.Framework.Servers.HttpServer
private void OnRequest(object source, RequestEventArgs args)
{
RequestNumber++;
try
{
IHttpClientContext context = (IHttpClientContext)source;
@@ -422,6 +405,7 @@ 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.
@@ -436,24 +420,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);
Culture.SetCurrentCulture();
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
// // 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;
@@ -465,7 +449,9 @@ namespace OpenSim.Framework.Servers.HttpServer
if (TryGetStreamHandler(handlerKey, out requestHandler))
{
if (DebugLevel >= 3)
LogIncomingToStreamHandler(request, requestHandler);
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found stream handler for {0} {1} {2} {3}",
request.HttpMethod, request.Url.PathAndQuery, requestHandler.Name, requestHandler.Description);
response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
@@ -542,8 +528,11 @@ namespace OpenSim.Framework.Servers.HttpServer
{
case null:
case "text/html":
if (DebugLevel >= 3)
LogIncomingToContentTypeHandler(request);
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
buffer = HandleHTTPRequest(request, response);
break;
@@ -551,8 +540,11 @@ namespace OpenSim.Framework.Servers.HttpServer
case "application/llsd+xml":
case "application/xml+llsd":
case "application/llsd+json":
if (DebugLevel >= 3)
LogIncomingToContentTypeHandler(request);
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
buffer = HandleLLSDRequests(request, response);
break;
@@ -571,7 +563,9 @@ namespace OpenSim.Framework.Servers.HttpServer
if (DoWeHaveALLSDHandler(request.RawUrl))
{
if (DebugLevel >= 3)
LogIncomingToContentTypeHandler(request);
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
buffer = HandleLLSDRequests(request, response);
}
@@ -579,14 +573,18 @@ namespace OpenSim.Framework.Servers.HttpServer
else if (DoWeHaveAHTTPHandler(request.RawUrl))
{
if (DebugLevel >= 3)
LogIncomingToContentTypeHandler(request);
m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
buffer = HandleHTTPRequest(request, response);
}
else
{
if (DebugLevel >= 3)
LogIncomingToXmlRpcHandler(request);
m_log.DebugFormat(
"[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}",
request.HttpMethod, request.Url.PathAndQuery);
// generic login request.
buffer = HandleXmlRpcRequests(request, response);
@@ -645,93 +643,14 @@ namespace OpenSim.Framework.Servers.HttpServer
if (tickdiff > 3000)
{
m_log.InfoFormat(
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
RequestNumber,
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms",
requestMethod,
uriString,
requestHandler != null ? requestHandler.Name : "",
requestHandler != null ? requestHandler.Description : "",
request.RemoteIPEndPoint,
request.RemoteIPEndPoint.ToString(),
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"));
}
}
@@ -827,24 +746,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.
@@ -1282,6 +1201,59 @@ 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)
{
@@ -1716,21 +1688,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,7 +29,6 @@ using System;
using System.Collections.Generic;
using System.Reflection;
using System.Net;
using System.Text;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Console;
@@ -48,12 +47,9 @@ 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 >= 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.
/// 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.
/// </remarks>
public static int DebugLevel
{
@@ -105,28 +101,17 @@ namespace OpenSim.Framework.Servers
get { return new Dictionary<uint, BaseHttpServer>(m_Servers); }
}
public static void RegisterHttpConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"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",
"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.",
HandleDebugHttpCommand);
}
@@ -134,122 +119,27 @@ namespace OpenSim.Framework.Servers
/// Turn on some debugging values for OpenSim.
/// </summary>
/// <param name="args"></param>
private static void HandleDebugHttpCommand(string module, string[] cmdparams)
private static void HandleDebugHttpCommand(string module, string[] args)
{
if (cmdparams.Length < 3)
if (args.Length == 3)
{
MainConsole.Instance.Output("Usage: debug http <in|out|all> 0..6");
return;
}
bool inReqs = false;
bool outReqs = false;
bool allReqs = false;
string subCommand = cmdparams[2];
if (subCommand.ToLower() == "in")
{
inReqs = true;
}
else if (subCommand.ToLower() == "out")
{
outReqs = true;
}
else if (subCommand.ToLower() == "all")
{
allReqs = true;
}
else
{
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)
if (int.TryParse(args[2], out newDebug))
{
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);
MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug);
}
}
else if (args.Length == 2)
{
MainConsole.Instance.OutputFormat("Current debug http level is {0}", MainServer.DebugLevel);
}
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);
MainConsole.Instance.Output("Usage: debug http 0..3");
}
}
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>
/// Register an already started HTTP server to the collection of known servers.
/// </summary>

View File

@@ -1,677 +0,0 @@
/*
* 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,12 +35,11 @@ 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 : OpenSimTestCase
public class OSHttpTests
{
// we need an IHttpClientContext for our tests
public class TestHttpClientContext: IHttpClientContext

View File

@@ -29,12 +29,11 @@ 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 : OpenSimTestCase
public class VersionInfoTests
{
[Test]
public void TestVersionLength()

View File

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

View File

@@ -35,12 +35,10 @@ using OpenMetaverse;
namespace OpenSim.Framework
{
/// <summary>
/// A dictionary containing task inventory items. Indexed by item UUID.
/// A dictionary for task inventory.
/// </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,6 +73,9 @@ 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;
@@ -350,13 +353,14 @@ namespace OpenSim.Framework
}
}
/// <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; }
public bool ScriptRunning {
get {
return _scriptRunning;
}
set {
_scriptRunning = value;
}
}
// See ICloneable
@@ -384,7 +388,6 @@ namespace OpenSim.Framework
public TaskInventoryItem()
{
ScriptRunning = true;
CreationDate = (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
}
}

View File

@@ -24,17 +24,16 @@
* (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 : OpenSimTestCase
public class AgentCircuitDataTest
{
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 : OpenSimTestCase
public class AnimationTests
{
private Animation anim1 = null;
private Animation anim2 = null;

View File

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

View File

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

View File

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

View File

@@ -32,12 +32,11 @@ using OpenMetaverse.StructuredData;
using System;
using System.Globalization;
using System.Threading;
using OpenSim.Tests.Common;
namespace OpenSim.Framework.Tests
{
[TestFixture]
public class MundaneFrameworkTests : OpenSimTestCase
public class MundaneFrameworkTests
{
private bool m_RegionSettingsOnSaveEventFired;
private bool m_RegionLightShareDataOnSaveEventFired;
@@ -303,6 +302,10 @@ 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,12 +31,11 @@ using NUnit.Framework;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Tests.Common;
namespace OpenSim.Framework.Tests
{
[TestFixture]
public class PrimeNumberHelperTests : OpenSimTestCase
public class PrimeNumberHelperTests
{
[Test]
public void TestGetPrime()

View File

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

View File

@@ -47,6 +47,9 @@ 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]
@@ -58,5 +61,6 @@ namespace OpenSim.Framework
Task = 1 << 3,
Texture = 1 << 4,
Asset = 1 << 5,
State = 1 << 6,
}
}

View File

@@ -533,19 +533,6 @@ 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>
@@ -1020,38 +1007,6 @@ 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);
@@ -1639,13 +1594,7 @@ namespace OpenSim.Framework
if (m_ThreadPool != null)
throw new InvalidOperationException("SmartThreadPool is already initialized");
STPStartInfo startInfo = new STPStartInfo();
startInfo.ThreadPoolName = "Util";
startInfo.IdleTimeout = 2000;
startInfo.MaxWorkerThreads = maxThreads;
startInfo.MinWorkerThreads = 2;
m_ThreadPool = new SmartThreadPool(startInfo);
m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2);
}
public static int FireAndForgetCount()
@@ -1718,7 +1667,7 @@ namespace OpenSim.Framework
break;
case FireAndForgetMethod.SmartThreadPool:
if (m_ThreadPool == null)
InitThreadPool(15);
m_ThreadPool = new SmartThreadPool(2000, 15, 2);
m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj });
break;
case FireAndForgetMethod.Thread:
@@ -1747,16 +1696,12 @@ namespace OpenSim.Framework
StringBuilder sb = new StringBuilder();
if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
{
// 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;
}
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,18 +53,10 @@ 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 { get; internal set; }
public static int RequestNumber = 0;
/// <summary>
/// this is the header field used to communicate the local request id
@@ -154,11 +146,7 @@ namespace OpenSim.Framework
private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed)
{
int reqnum = RequestNumber++;
if (DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} ServiceOSD {1} {2} (timeout {3}, compressed {4})",
reqnum, method, url, timeout, compressed);
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
string errorMessage = "unknown error";
int tickstart = Util.EnvironmentTickCount();
@@ -241,7 +229,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > LongCallTime)
m_log.InfoFormat(
"[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
"[OSD REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum,
method,
url,
@@ -250,14 +238,10 @@ 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]: ServiceOSD request {0} {1} {2} FAILED: {3}", reqnum, url, method, errorMessage);
"[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage);
return ErrorResponseMap(errorMessage);
}
@@ -333,11 +317,7 @@ namespace OpenSim.Framework
{
int reqnum = RequestNumber++;
string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown";
if (DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} ServiceForm {1} {2} (timeout {3})",
reqnum, method, url, timeout);
// m_log.DebugFormat("[WEB UTIL]: <{0}> start form request for {1}, method {2}",reqnum,url,method);
string errorMessage = "unknown error";
int tickstart = Util.EnvironmentTickCount();
@@ -400,7 +380,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > LongCallTime)
m_log.InfoFormat(
"[WEB UTIL]: Slow ServiceForm request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
"[SERVICE FORM]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum,
method,
url,
@@ -409,13 +389,9 @@ 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("[WEB UTIL]: ServiceForm request {0} {1} {2} failed: {2}", reqnum, method, url, errorMessage);
m_log.WarnFormat("[SERVICE FORM]: <{0}> form request to {1} failed: {2}", reqnum, url, errorMessage);
return ErrorResponseMap(errorMessage);
}
@@ -667,6 +643,7 @@ namespace OpenSim.Framework
/// <returns></returns>
public static string[] GetPreferredImageTypes(string accept)
{
if (accept == null || accept == string.Empty)
return new string[0];
@@ -718,15 +695,13 @@ namespace OpenSim.Framework
string requestUrl, TRequest obj, Action<TResponse> action)
{
int reqnum = WebUtil.RequestNumber++;
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} AsynchronousRequestObject {1} {2}",
reqnum, verb, requestUrl);
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
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);
@@ -879,7 +854,7 @@ namespace OpenSim.Framework
}
m_log.InfoFormat(
"[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
"[ASYNC REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum,
verb,
requestUrl,
@@ -887,12 +862,6 @@ 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);
}
}
}
@@ -913,11 +882,7 @@ namespace OpenSim.Framework
public static string MakeRequest(string verb, string requestUrl, string obj)
{
int reqnum = WebUtil.RequestNumber++;
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} SynchronousRestForms {1} {2}",
reqnum, verb, requestUrl);
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
int tickstart = Util.EnvironmentTickCount();
int tickdata = 0;
@@ -1002,17 +967,13 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > WebUtil.LongCallTime)
m_log.InfoFormat(
"[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
"[FORMS]: Slow request to <{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;
}
@@ -1037,11 +998,7 @@ namespace OpenSim.Framework
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj)
{
int reqnum = WebUtil.RequestNumber++;
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} SynchronousRestObject {1} {2}",
reqnum, verb, requestUrl);
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
int tickstart = Util.EnvironmentTickCount();
int tickdata = 0;
@@ -1154,7 +1111,7 @@ namespace OpenSim.Framework
}
m_log.InfoFormat(
"[SynchronousRestObjectRequester]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
"[SynchronousRestObjectRequester]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum,
verb,
requestUrl,
@@ -1162,12 +1119,6 @@ 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,6 +188,7 @@ 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

@@ -82,8 +82,8 @@ namespace OpenSim
{
base.ReadExtraConfigSettings();
IConfig startupConfig = Config.Configs["Startup"];
IConfig networkConfig = Config.Configs["Network"];
IConfig startupConfig = m_config.Source.Configs["Startup"];
IConfig networkConfig = m_config.Source.Configs["Network"];
int stpMaxThreads = 15;
@@ -106,6 +106,22 @@ 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))
@@ -148,7 +164,7 @@ namespace OpenSim
break;
case "rest":
m_console = new RemoteConsole("Region");
((RemoteConsole)m_console).ReadConfig(Config);
((RemoteConsole)m_console).ReadConfig(m_config.Source);
break;
default:
m_console = new LocalConsole("Region");
@@ -158,7 +174,6 @@ namespace OpenSim
MainConsole.Instance = m_console;
RegisterCommonAppenders(Config.Configs["Startup"]);
RegisterConsoleCommands();
base.StartupSpecific();
@@ -236,6 +251,12 @@ 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);
@@ -311,6 +332,10 @@ 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);
@@ -344,6 +369,26 @@ 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);
@@ -375,6 +420,7 @@ namespace OpenSim
{
RunCommandScript(m_shutdownCommandsFile);
}
base.ShutdownSpecific();
}
@@ -452,6 +498,35 @@ namespace OpenSim
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>
@@ -556,9 +631,111 @@ namespace OpenSim
bool changed = PopulateRegionEstateInfo(regInfo);
IScene scene;
CreateRegion(regInfo, true, out scene);
if (changed)
regInfo.EstateSettings.Save();
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;
}
}
}
/// <summary>
@@ -627,6 +804,13 @@ 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();
@@ -670,20 +854,12 @@ 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));
@@ -705,18 +881,6 @@ 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>
@@ -750,6 +914,30 @@ 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;
@@ -825,6 +1013,33 @@ 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)
@@ -919,7 +1134,7 @@ namespace OpenSim
aCircuit.Name,
aCircuit.child ? "child" : "root",
aCircuit.circuitcode.ToString(),
aCircuit.IPAddress != null ? aCircuit.IPAddress.ToString() : "not set",
aCircuit.IPAddress.ToString(),
aCircuit.Viewer);
});

View File

@@ -100,7 +100,13 @@ namespace OpenSim
/// <value>
/// The config information passed into the OpenSimulator region server.
/// </value>
public OpenSimConfigSource ConfigSource { get; private set; }
public OpenSimConfigSource ConfigSource
{
get { return m_config; }
set { m_config = value; }
}
protected OpenSimConfigSource m_config;
public List<IClientNetworkServer> ClientServers
{
@@ -148,14 +154,13 @@ namespace OpenSim
protected virtual void LoadConfigSettings(IConfigSource configSource)
{
m_configLoader = new ConfigurationLoader();
ConfigSource = m_configLoader.LoadConfigSettings(configSource, envConfigSource, out m_configSettings, out m_networkServersInfo);
Config = ConfigSource.Source;
m_config = m_configLoader.LoadConfigSettings(configSource, envConfigSource, out m_configSettings, out m_networkServersInfo);
ReadExtraConfigSettings();
}
protected virtual void ReadExtraConfigSettings()
{
IConfig networkConfig = Config.Configs["Network"];
IConfig networkConfig = m_config.Source.Configs["Network"];
if (networkConfig != null)
{
proxyUrl = networkConfig.GetString("proxy_url", "");
@@ -188,7 +193,7 @@ namespace OpenSim
/// </summary>
protected override void StartupSpecific()
{
IConfig startupConfig = Config.Configs["Startup"];
IConfig startupConfig = m_config.Source.Configs["Startup"];
if (startupConfig != null)
{
string pidFile = startupConfig.GetString("PIDFile", String.Empty);
@@ -199,41 +204,29 @@ namespace OpenSim
}
// Load the simulation data service
IConfig simDataConfig = Config.Configs["SimulationDataStore"];
IConfig simDataConfig = m_config.Source.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[] { 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));
m_simulationDataService = ServerUtils.LoadPlugin<ISimulationDataService>(module, new object[] { m_config.Source });
// Load the estate data service
IConfig estateDataConfig = Config.Configs["EstateDataStore"];
IConfig estateDataConfig = m_config.Source.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[] { 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));
m_estateDataService = ServerUtils.LoadPlugin<IEstateDataService>(module, new object[] { m_config.Source });
base.StartupSpecific();
m_stats = StatsManager.SimExtraStats;
// Create a ModuleLoader instance
m_moduleLoader = new ModuleLoader(Config);
m_moduleLoader = new ModuleLoader(m_config.Source);
LoadPlugins();
foreach (IApplicationPlugin plugin in m_plugins)
@@ -241,51 +234,51 @@ namespace OpenSim
plugin.PostInitialise();
}
if (m_console != null)
{
StatsManager.RegisterConsoleCommands(m_console);
AddPluginCommands(m_console);
}
AddPluginCommands();
}
protected virtual void AddPluginCommands(ICommandConsole console)
protected virtual void AddPluginCommands()
{
List<string> topics = GetHelpTopics();
foreach (string topic in topics)
// If console exists add plugin commands.
if (m_console != null)
{
string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
List<string> topics = GetHelpTopics();
// 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)
foreach (string topic in topics)
{
if (s.GetCommanders().ContainsKey(topic))
commander = s.GetCommanders()[topic];
}
string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
if (commander == null)
continue;
// 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);
foreach (string command in commander.Commands.Keys)
{
console.Commands.AddCommand(capitalizedTopic, false,
topic + " " + command,
topic + " " + commander.Commands[command].ShortHelp(),
String.Empty, HandleCommanderCommand);
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);
}
}
}
}
@@ -310,7 +303,7 @@ namespace OpenSim
// Called from base.StartUp()
m_httpServerPort = m_networkServersInfo.HttpListenerPort;
SceneManager.OnRestartSim += HandleRestartRegion;
SceneManager.OnRestartSim += handleRestartRegion;
// Only enable the watchdogs when all regions are ready. Otherwise we get false positives when cpu is
// heavily used during initial startup.
@@ -375,7 +368,7 @@ namespace OpenSim
}
IClientNetworkServer clientServer;
Scene scene = SetupScene(regionInfo, proxyOffset, Config, out clientServer);
Scene scene = SetupScene(regionInfo, proxyOffset, m_config.Source, out clientServer);
m_log.Info("[MODULES]: Loading Region's modules (old style)");
@@ -470,10 +463,10 @@ namespace OpenSim
string estateOwnerPassword = null;
string rawEstateOwnerUuid = null;
if (Config.Configs[ESTATE_SECTION_NAME] != null)
if (m_config.Source.Configs[ESTATE_SECTION_NAME] != null)
{
string defaultEstateOwnerName
= Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerName", "").Trim();
= m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerName", "").Trim();
string[] ownerNames = defaultEstateOwnerName.Split(' ');
if (ownerNames.Length >= 2)
@@ -483,9 +476,9 @@ namespace OpenSim
}
// Info to be used only on Standalone Mode
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);
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);
}
MainConsole.Instance.OutputFormat("Estate {0} has no owner set.", regionInfo.EstateSettings.EstateName);
@@ -552,7 +545,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 at the grid level.");
"[OPENSIM]: Unable to store account. If this simulator is connected to a grid, you must create the estate owner account first.");
}
else
{
@@ -732,7 +725,7 @@ namespace OpenSim
return new Scene(
regionInfo, circuitManager, sceneGridService,
simDataService, estateDataService, m_moduleLoader, false,
Config, m_version);
m_config.Source, m_version);
}
protected void ShutdownClientServer(RegionInfo whichRegion)
@@ -759,11 +752,9 @@ namespace OpenSim
}
}
protected virtual void HandleRestartRegion(RegionInfo whichRegion)
public void handleRestartRegion(RegionInfo whichRegion)
{
m_log.InfoFormat(
"[OPENSIM]: Got restart signal from SceneManager for region {0} ({1},{2})",
whichRegion.RegionName, whichRegion.RegionLocX, whichRegion.RegionLocY);
m_log.Info("[OPENSIM]: Got restart signal from SceneManager");
ShutdownClientServer(whichRegion);
IScene scene;
@@ -775,7 +766,7 @@ namespace OpenSim
protected override PhysicsScene GetPhysicsScene(string osSceneIdentifier)
{
return GetPhysicsScene(
m_configSettings.PhysicsEngine, m_configSettings.MeshEngineName, Config, osSceneIdentifier);
m_configSettings.PhysicsEngine, m_configSettings.MeshEngineName, m_config.Source, osSceneIdentifier);
}
/// <summary>
@@ -909,6 +900,7 @@ 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
@@ -917,7 +909,7 @@ namespace OpenSim
}
catch (Exception e)
{
m_log.Error("[SHUTDOWN]: Ignoring failure during shutdown - ", e);
m_log.ErrorFormat("[SHUTDOWN]: Ignoring failure during shutdown - {0}", e);
}
}
@@ -1011,9 +1003,9 @@ namespace OpenSim
string defaultEstateName = null;
if (Config.Configs[ESTATE_SECTION_NAME] != null)
if (m_config.Source.Configs[ESTATE_SECTION_NAME] != null)
{
defaultEstateName = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateName", null);
defaultEstateName = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateName", null);
if (defaultEstateName != null)
{
@@ -1096,14 +1088,28 @@ 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;
@@ -163,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",
@@ -204,8 +204,6 @@ 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",
@@ -256,12 +254,11 @@ namespace OpenSim.Region.ClientStack.Linden
public string SeedCapRequest(string request, string path, string param,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
m_log.DebugFormat(
"[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
// m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName);
if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
{
m_log.WarnFormat(
m_log.DebugFormat(
"[CAPS]: Unauthorized CAPS client {0} from {1}",
m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint);
@@ -857,22 +854,6 @@ 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,7 +102,6 @@ namespace OpenSim.Region.ClientStack.Linden
// circuit is there.
scene.EventManager.OnClientClosed += ClientClosed;
scene.EventManager.OnMakeChildAgent += MakeChildAgent;
scene.EventManager.OnRegisterCaps += OnRegisterCaps;
@@ -111,10 +110,10 @@ namespace OpenSim.Region.ClientStack.Linden
false,
"debug eq",
"debug eq [0|1|2]",
"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",
"Turn on event queue debugging"
+ "<= 0 - turns off all event queue logging"
+ ">= 1 - turns on outgoing event logging"
+ ">= 2 - turns on poll notification",
HandleDebugEq);
}
else
@@ -227,6 +226,16 @@ 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 : OpenSimTestCase
public class EventQueueTests
{
private TestScene m_scene;

View File

@@ -0,0 +1,234 @@
/*
* 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;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
using System.IO;
using System.Web;
using log4net;
using Nini.Config;
using Mono.Addins;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Imaging;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using Caps = OpenSim.Framework.Capabilities.Caps;
using OpenSim.Capabilities.Handlers;
namespace OpenSim.Region.ClientStack.Linden
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionConsoleModule")]
public class RegionConsoleModule : INonSharedRegionModule, IRegionConsole
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene;
private IEventQueue m_eventQueue;
private Commands m_commands = new Commands();
public ICommands Commands { get { return m_commands; } }
public void Initialise(IConfigSource source)
{
m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help);
}
public void AddRegion(Scene s)
{
m_scene = s;
m_scene.RegisterModuleInterface<IRegionConsole>(this);
}
public void RemoveRegion(Scene s)
{
m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
m_scene = null;
}
public void RegionLoaded(Scene s)
{
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
m_eventQueue = m_scene.RequestModuleInterface<IEventQueue>();
}
public void PostInitialise()
{
}
public void Close() { }
public string Name { get { return "RegionConsoleModule"; } }
public Type ReplaceableInterface
{
get { return null; }
}
public void RegisterCaps(UUID agentID, Caps caps)
{
if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID))
return;
UUID capID = UUID.Random();
m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
caps.RegisterHandler(
"SimConsoleAsync",
new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene));
}
public void SendConsoleOutput(UUID agentID, string message)
{
OSD osd = OSD.FromString(message);
m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID);
}
public bool RunCommand(string command, UUID invokerID)
{
string[] parts = Parser.Parse(command);
Array.Resize(ref parts, parts.Length + 1);
parts[parts.Length - 1] = invokerID.ToString();
if (m_commands.Resolve(parts).Length == 0)
return false;
return true;
}
private void Help(string module, string[] cmd)
{
UUID agentID = new UUID(cmd[cmd.Length - 1]);
Array.Resize(ref cmd, cmd.Length - 1);
List<string> help = Commands.GetHelp(cmd);
string reply = String.Empty;
foreach (string s in help)
{
reply += s + "\n";
}
SendConsoleOutput(agentID, reply);
}
public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn)
{
m_commands.AddCommand(module, shared, command, help, longhelp, fn);
}
}
public class ConsoleHandler : BaseStreamHandler
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private RegionConsoleModule m_consoleModule;
private UUID m_agentID;
private bool m_isGod;
private Scene m_scene;
private bool m_consoleIsOn = false;
public ConsoleHandler(string path, string name, UUID agentID, RegionConsoleModule module, Scene scene)
:base("POST", path, name, agentID.ToString())
{
m_agentID = agentID;
m_consoleModule = module;
m_scene = scene;
m_isGod = m_scene.Permissions.IsGod(agentID);
}
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
StreamReader reader = new StreamReader(request);
string message = reader.ReadToEnd();
OSD osd = OSDParser.DeserializeLLSDXml(message);
string cmd = osd.AsString();
if (cmd == "set console on")
{
if (m_isGod)
{
MainConsole.Instance.OnOutput += ConsoleSender;
m_consoleIsOn = true;
m_consoleModule.SendConsoleOutput(m_agentID, "Console is now on");
}
return new byte[0];
}
else if (cmd == "set console off")
{
MainConsole.Instance.OnOutput -= ConsoleSender;
m_consoleIsOn = false;
m_consoleModule.SendConsoleOutput(m_agentID, "Console is now off");
return new byte[0];
}
if (m_consoleIsOn == false && m_consoleModule.RunCommand(osd.AsString().Trim(), m_agentID))
return new byte[0];
if (m_isGod && m_consoleIsOn)
{
MainConsole.Instance.RunCommand(osd.AsString().Trim());
}
else
{
m_consoleModule.SendConsoleOutput(m_agentID, "Unknown command");
}
return new byte[0];
}
private void ConsoleSender(string text)
{
m_consoleModule.SendConsoleOutput(m_agentID, text);
}
private void OnMakeChildAgent(ScenePresence presence)
{
if (presence.UUID == m_agentID)
{
MainConsole.Instance.OnOutput -= ConsoleSender;
m_consoleIsOn = false;
}
}
}
}

View File

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

View File

@@ -346,17 +346,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private int m_moneyBalance;
private int m_animationSequenceNumber = 1;
private bool m_SendLogoutPacketWhenClosing = true;
/// <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;
private AgentUpdateArgs lastarg;
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
@@ -816,9 +806,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(mov, ThrottleOutPacketType.Unknown);
}
public void SendChatMessage(
string message, byte type, Vector3 fromPos, string fromName,
UUID fromAgentID, UUID ownerID, byte source, byte audible)
public void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName,
UUID fromAgentID, byte source, byte audible)
{
ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator);
reply.ChatData.Audible = audible;
@@ -827,7 +816,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
reply.ChatData.SourceType = source;
reply.ChatData.Position = fromPos;
reply.ChatData.FromName = Util.StringToBytes256(fromName);
reply.ChatData.OwnerID = ownerID;
reply.ChatData.OwnerID = fromAgentID;
reply.ChatData.SourceID = fromAgentID;
OutPacket(reply, ThrottleOutPacketType.Task);
@@ -1587,7 +1576,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null)
{
OutPacket(kill, ThrottleOutPacketType.Task);
OutPacket(kill, ThrottleOutPacketType.State);
}
else
{
@@ -3932,9 +3921,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -3979,10 +3966,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4974,9 +4958,7 @@ 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
= PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock();
block.Data = data;
if (textureEntry != null && textureEntry.Length > 0)
@@ -5208,18 +5190,14 @@ 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);
AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest);
AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest, false);
AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest, false);
AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage);
AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest);
AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer);
@@ -5319,9 +5297,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
AddLocalPacketHandler(PacketType.RemoveTaskInventory, HandleRemoveTaskInventory);
AddLocalPacketHandler(PacketType.MoveTaskInventory, HandleMoveTaskInventory);
AddLocalPacketHandler(PacketType.RezScript, HandleRezScript);
AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest);
AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest);
AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest);
AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest, false);
AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest, false);
AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest, false);
AddLocalPacketHandler(PacketType.TeleportLandmarkRequest, HandleTeleportLandmarkRequest);
AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel);
AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest);
@@ -5439,83 +5417,80 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Scene/Avatar
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
private bool HandleAgentUpdate(IClientAPI sener, Packet Pack)
{
if (OnAgentUpdate != null)
{
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
bool update = false;
AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack;
#region Packet Session and User Check
if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
{
PacketPool.Instance.ReturnPacket(packet);
if (agenUpdate.AgentData.SessionID != SessionId || agenUpdate.AgentData.AgentID != AgentId)
return false;
}
#endregion
bool update = false;
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData;
if (m_lastAgentUpdateArgs != null)
// We can only check when we have something to check
// against.
if (lastarg != null)
{
// These should be ordered from most-likely to
// least likely to change. I've made an initial
// guess at that.
update =
(
(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)
(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)
);
}
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);
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;
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;
UpdateAgent handlerAgentUpdate = OnAgentUpdate;
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
lastarg = arg; // save this set of arguments for nexttime
if (handlerPreAgentUpdate != null)
OnPreAgentUpdate(this, m_lastAgentUpdateArgs);
OnPreAgentUpdate(this, arg);
if (handlerAgentUpdate != null)
OnAgentUpdate(this, m_lastAgentUpdateArgs);
OnAgentUpdate(this, arg);
handlerAgentUpdate = null;
handlerPreAgentUpdate = null;
}
}
PacketPool.Instance.ReturnPacket(packet);
return true;
}
@@ -9079,9 +9054,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
#endregion
string method = Utils.BytesToString(messagePacket.MethodData.Method);
switch (method)
switch (Utils.BytesToString(messagePacket.MethodData.Method))
{
case "getinfo":
if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
@@ -9397,17 +9370,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return true;
default:
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);
}
m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket);
return true;
}
@@ -11793,7 +11756,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)
@@ -11862,13 +11825,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 ", Scene.Name, packet.Type);
Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type);
}
if (!ProcessPacketMethod(packet))
m_log.WarnFormat(
"[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.",
packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name);
m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
PacketPool.Instance.ReturnPacket(packet);
}
private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
@@ -12321,10 +12284,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
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}",
"{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}",
Util.EnvironmentTickCountSubtract(TickLastPacketReceived),
PacketsReceived,
PacketsSent,
@@ -290,7 +290,8 @@ 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.Asset].Count,
m_packetOutboxes[(int)ThrottleOutPacketType.State].Count);
}
public void SendPacketStats()
@@ -336,6 +337,8 @@ 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
@@ -372,6 +375,9 @@ 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;
@@ -672,6 +678,9 @@ 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)
@@ -688,9 +697,11 @@ 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,7 +37,6 @@ 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;
@@ -70,19 +69,6 @@ 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)
@@ -114,11 +100,9 @@ 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;
@@ -127,7 +111,6 @@ 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>
@@ -138,37 +121,28 @@ 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;
@@ -181,18 +155,6 @@ 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;
@@ -213,9 +175,7 @@ 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
@@ -237,7 +197,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_circuitManager = circuitManager;
int sceneThrottleBps = 0;
bool usePools = false;
IConfig config = configSource.Configs["ClientStack.LindenUDP"];
if (config != null)
@@ -263,16 +222,6 @@ 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;
@@ -300,28 +249,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_throttle = new TokenBucket(null, sceneThrottleBps);
ThrottleRates = new ThrottleRates(configSource);
if (usePools)
EnablePools();
}
public void Start()
{
StartInbound();
StartOutbound();
if (m_scene == null)
throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference");
m_elapsedMSSinceLastStatReport = Environment.TickCount;
}
private void StartInbound()
{
m_log.InfoFormat(
"[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
"[LLUDPSERVER]: Starting the LLUDP server in {0} mode",
m_asyncPacketHandling ? "asynchronous" : "synchronous");
base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
base.Start(m_recvBufferSize, m_asyncPacketHandling);
// This thread will process the packets received that are placed on the packetInbox
// Start the packet processing threads
Watchdog.StartThread(
IncomingPacketHandler,
string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
@@ -330,13 +271,6 @@ 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,
@@ -346,90 +280,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
true,
GetWatchdogOutgoingAlarmData,
Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
}
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;
m_elapsedMSSinceLastStatReport = Environment.TickCount;
}
/// <summary>
@@ -454,6 +306,12 @@ 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)
@@ -470,182 +328,6 @@ 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)
@@ -729,8 +411,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
byte[] data = packet.ToBytes();
SendPacketData(udpClient, data, packet.Type, category, method);
}
PacketPool.Instance.ReturnPacket(packet);
}
/// <summary>
@@ -1015,7 +695,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
LLUDPClient udpClient = null;
Packet packet = null;
int packetEnd = buffer.DataLength - 1;
IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
#region Decoding
@@ -1025,7 +705,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 undersized packet
return; // Drop undersizd packet
}
int headerLen = 7;
@@ -1048,13 +728,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
try
{
// 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,
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);
}
@@ -1069,13 +743,11 @@ 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);
}
@@ -1096,9 +768,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// UseCircuitCode handling
if (packet.Type == PacketType.UseCircuitCode)
{
// 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 };
object[] array = new object[] { buffer, packet };
Util.FireAndForget(HandleUseCircuitCode, array);
@@ -1107,7 +777,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Determine which agent this packet came from
IClientAPI client;
if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
if (!m_scene.TryGetClient(address, 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;
@@ -1131,10 +801,6 @@ 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);
}
@@ -1144,10 +810,6 @@ 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);
@@ -1161,10 +823,6 @@ 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,
@@ -1211,8 +869,6 @@ 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);
@@ -1232,21 +888,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#endregion Ping Check Handling
IncomingPacket incomingPacket;
// Inbox insertion
if (UsePools)
{
incomingPacket = m_incomingPacketPool.GetObject();
incomingPacket.Client = (LLClientView)client;
incomingPacket.Packet = packet;
}
else
{
incomingPacket = new IncomingPacket((LLClientView)client, packet);
}
packetInbox.Enqueue(incomingPacket);
packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet));
}
#region BinaryStats
@@ -1332,19 +975,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private void HandleUseCircuitCode(object o)
{
IPEndPoint endPoint = null;
IPEndPoint remoteEndPoint = null;
IClientAPI client = null;
try
{
// DateTime startTime = DateTime.Now;
object[] array = (object[])o;
endPoint = (IPEndPoint)array[0];
UDPPacketBuffer buffer = (UDPPacketBuffer)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, endPoint);
uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint);
remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
AuthenticateResponse sessionInfo;
if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1355,13 +1000,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
uccp.CircuitCode.Code,
uccp.CircuitCode.ID,
uccp.CircuitCode.SessionID,
endPoint,
remoteEndPoint,
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(endPoint, uccp.Header.Sequence);
SendAckImmediate(remoteEndPoint, 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)
@@ -1372,7 +1017,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, endPoint);
uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint);
}
// m_log.DebugFormat(
@@ -1384,7 +1029,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
m_log.ErrorFormat(
"[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
endPoint != null ? endPoint.ToString() : "n/a",
remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a",
client != null ? client.Name : "unknown",
client != null ? client.AgentId.ToString() : "unknown",
e.Message,
@@ -1449,20 +1094,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
IClientAPI client = null;
// 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)
// 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)
{
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();
}
}
@@ -1501,7 +1146,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// on to en-US to avoid number parsing issues
Culture.SetCurrentCulture();
while (IsRunningInbound)
while (base.IsRunning)
{
try
{
@@ -1516,12 +1161,7 @@ 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)
{
@@ -1548,7 +1188,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Action generic every round
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
while (base.IsRunningOutbound)
while (base.IsRunning)
{
try
{
@@ -1675,11 +1315,6 @@ 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++;
@@ -1739,9 +1374,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
npacksSent++;
}
else
{
npackNotSent++;
}
watch2.Stop();
avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks);
@@ -1749,9 +1382,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
else
{
m_log.WarnFormat("[LLUDPSERVER]: Client is not connected");
}
}
}
catch (Exception ex)
@@ -1815,8 +1446,6 @@ 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,8 +30,6 @@ using System.Net;
using System.Net.Sockets;
using System.Threading;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
namespace OpenMetaverse
{
@@ -60,29 +58,17 @@ namespace OpenMetaverse
/// <summary>Flag to process packets asynchronously or synchronously</summary>
private bool m_asyncPacketHandling;
/// <summary>
/// Are we to use object pool(s) to reduce memory churn when receiving data?
/// </summary>
public bool UsePools { get; protected set; }
/// <summary>The all important shutdown flag</summary>
private volatile bool m_shutdownFlag = true;
/// <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>Returns true if the server is currently listening, otherwise false</summary>
public bool IsRunning { get { return !m_shutdownFlag; } }
/// <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;
@@ -90,7 +76,7 @@ namespace OpenMetaverse
}
/// <summary>
/// Start inbound UDP packet handling.
/// Start the UDP server
/// </summary>
/// <param name="recvBufferSize">The size of the receive buffer for
/// the UDP socket. This value is passed up to the operating system
@@ -105,11 +91,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 StartInbound(int recvBufferSize, bool asyncPacketHandling)
public void Start(int recvBufferSize, bool asyncPacketHandling)
{
m_asyncPacketHandling = asyncPacketHandling;
if (!IsRunningInbound)
if (m_shutdownFlag)
{
const int SIO_UDP_CONNRESET = -1744830452;
@@ -141,7 +127,8 @@ namespace OpenMetaverse
m_udpSocket.Bind(ipep);
IsRunningInbound = true;
// we're not shutting down, we're starting up
m_shutdownFlag = false;
// kick off an async receive. The Start() method will return, the
// actual receives will occur asynchronously and will be caught in
@@ -151,69 +138,28 @@ namespace OpenMetaverse
}
/// <summary>
/// Start outbound UDP packet handling.
/// Stops the UDP server
/// </summary>
public void StartOutbound()
public void Stop()
{
IsRunningOutbound = true;
}
public void StopInbound()
{
if (IsRunningInbound)
if (!m_shutdownFlag)
{
// 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 IsRunningInbound = false to inform the other
// threads. Once we have the lock, we set shutdownFlag to inform the other
// threads that the socket is closed.
IsRunningInbound = false;
m_shutdownFlag = true;
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()
{
UDPPacketBuffer buf;
// allocate a packet buffer
//WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut();
UDPPacketBuffer buf = new UDPPacketBuffer();
if (UsePools)
buf = Pool.GetObject();
else
buf = new UDPPacketBuffer();
if (IsRunningInbound)
if (!m_shutdownFlag)
{
try
{
@@ -266,7 +212,7 @@ namespace OpenMetaverse
{
// Asynchronous receive operations will complete here through the call
// to AsyncBeginReceive
if (IsRunningInbound)
if (!m_shutdownFlag)
{
// Asynchronous mode will start another receive before the
// callback for this packet is even fired. Very parallel :-)
@@ -275,6 +221,8 @@ 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
@@ -291,8 +239,7 @@ namespace OpenMetaverse
catch (ObjectDisposedException) { }
finally
{
if (UsePools)
Pool.ReturnObject(buffer);
//wrappedBuffer.Dispose();
// Synchronous mode waits until the packet callback completes
// before starting the receive to fetch another packet
@@ -305,7 +252,7 @@ namespace OpenMetaverse
public void AsyncBeginSend(UDPPacketBuffer buf)
{
if (IsRunningOutbound)
if (!m_shutdownFlag)
{
try
{
@@ -334,4 +281,4 @@ namespace OpenMetaverse
catch (ObjectDisposedException) { }
}
}
}
}

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 : OpenSimTestCase
public class BasicCircuitTests
{
private Scene m_scene;
private TestLLUDPServer m_udpServer;
@@ -65,9 +65,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
}
[SetUp]
public override void SetUp()
public void SetUp()
{
base.SetUp();
m_scene = new SceneHelpers().SetupScene();
}
@@ -144,7 +143,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
public void TestAddClient()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
// XmlConfigurator.Configure();
AddUdpServer();

View File

@@ -43,7 +43,7 @@ using OpenSim.Tests.Common.Mock;
namespace OpenSim.Region.ClientStack.LindenUDP.Tests
{
[TestFixture]
public class LLImageManagerTests : OpenSimTestCase
public class LLImageManagerTests
{
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 : OpenSimTestCase
public class PacketHandlerTests
{
// [Test]
// /// <summary>

View File

@@ -57,36 +57,39 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
/// <summary>
/// Return the xfer uploader for the given transaction.
/// Return a xfer uploader if one does not already exist.
/// </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>
/// <returns>The asset xfer uploader</returns>
public AssetXferUploader RequestXferUploader(UUID transactionID)
/// <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)
{
AssetXferUploader uploader;
lock (XferUploaders)
{
if (!XferUploaders.ContainsKey(transactionID))
{
uploader = new AssetXferUploader(this, m_Scene, transactionID, m_dumpAssetsToFile);
AssetXferUploader uploader = new AssetXferUploader(this, m_Scene, assetID, m_dumpAssetsToFile);
// m_log.DebugFormat(
// "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID);
XferUploaders.Add(transactionID, uploader);
}
else
{
uploader = XferUploaders[transactionID];
return uploader;
}
}
return uploader;
m_log.WarnFormat("[AGENT ASSETS TRANSACTIONS]: Ignoring request for asset xfer uploader {0} since it already exists", transactionID);
return null;
}
public void HandleXfer(ulong xferID, uint packetID, byte[] data)
@@ -148,28 +151,115 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask)
{
AssetXferUploader uploader = RequestXferUploader(transactionID);
AssetXferUploader uploader = null;
uploader.RequestCreateInventoryItem(
remoteClient, folderID, callbackID,
description, name, invType, type, wearableType, nextOwnerMask);
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;
}
public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient,
SceneObjectPart part, UUID transactionID,
TaskInventoryItem item)
{
AssetXferUploader uploader = RequestXferUploader(transactionID);
AssetXferUploader uploader = null;
uploader.RequestUpdateTaskInventoryItem(remoteClient, item);
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);
}
}
public void RequestUpdateInventoryItem(IClientAPI remoteClient,
UUID transactionID, InventoryItemBase item)
{
AssetXferUploader uploader = RequestXferUploader(transactionID);
AssetXferUploader uploader = null;
uploader.RequestUpdateInventoryItem(remoteClient, item);
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);
}
}
}
}
}

View File

@@ -215,7 +215,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
{
m_log.DebugFormat(
"[ASSET TRANSACTION MODULE] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
"[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
AgentAssetTransactions transactions =
@@ -274,8 +274,13 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
uploader.StartUpload(remoteClient, assetID, transaction, type, data, storeLocal, tempFile);
AssetXferUploader uploader = transactions.RequestXferUploader(transaction, assetID);
if (uploader != null)
{
uploader.Initialise(remoteClient, assetID, transaction, type,
data, storeLocal, tempFile);
}
}
/// <summary>

View File

@@ -40,75 +40,39 @@ 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;
private uint m_createItemCallback;
private bool m_updateItem;
private bool m_createItem = false;
private uint m_createItemCallback = 0;
private bool m_updateItem = false;
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 m_transactionID;
private UUID TransactionID = UUID.Zero;
private sbyte type = 0;
private byte wearableType = 0;
public ulong XferID;
private Scene m_Scene;
/// <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)
public AssetXferUploader(AgentAssetTransactions transactions, Scene scene, UUID assetID, bool dumpAssetToFile)
{
m_asset = new AssetBase();
m_transactions = transactions;
m_transactionID = transactionID;
m_Scene = scene;
m_asset = new AssetBase() { FullID = assetID };
m_dumpAssetToFile = dumpAssetToFile;
}
@@ -154,50 +118,30 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
/// <summary>
/// Start asset transfer from the client
/// Initialise asset transfer from the client
/// </summary>
/// <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)
/// <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)
{
// 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.FullID = assetID;
m_asset.Name = "blank";
m_asset.Description = "empty";
m_asset.Type = type;
m_asset.CreatorID = remoteClient.AgentId.ToString();
m_asset.Data = data;
m_asset.Local = storeLocal;
m_asset.Temporary = tempFile;
// m_storeLocal = storeLocal;
TransactionID = transaction;
m_storeLocal = storeLocal;
if (m_asset.Data.Length > 2)
{
@@ -222,35 +166,36 @@ 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_uploadState = UploadState.Complete;
ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID);
m_finished = true;
if (m_createItem)
{
CompleteCreateItem(m_createItemCallback);
DoCreateItem(m_createItemCallback);
}
else if (m_updateItem)
{
CompleteItemUpdate(m_updateItemData);
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);
}
else if (m_updateTaskItem)
else if (m_storeLocal)
{
CompleteTaskItemUpdate(m_updateTaskItemData);
m_Scene.AssetService.Store(m_asset);
}
// 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, m_transactionID);
m_asset.FullID, TransactionID);
if (m_dumpAssetToFile)
{
@@ -278,37 +223,40 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
}
public void RequestCreateInventoryItem(IClientAPI remoteClient,
UUID folderID, uint callbackID,
UUID transactionID, UUID folderID, uint callbackID,
string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask)
{
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)
if (TransactionID == transactionID)
{
if (m_uploadState == UploadState.Complete)
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)
{
CompleteCreateItem(callbackID);
}
else
{
m_createItem = true; //set flag so the inventory item is created when upload is complete
m_createItemCallback = callbackID;
if (m_finished)
{
DoCreateItem(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, InventoryItemBase item)
public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item)
{
// We must lock to avoid a race with a separate thread uploading the asset.
lock (this)
@@ -323,9 +271,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
item.AssetID = m_asset.FullID;
m_Scene.InventoryService.UpdateItem(item);
if (m_uploadState == UploadState.Complete)
if (m_finished)
{
CompleteItemUpdate(item);
StoreAssetForItemUpdate(item);
}
else
{
@@ -339,59 +287,20 @@ 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 when it has been uploaded.
/// Store the asset for the given item.
/// </summary>
/// <param name="item"></param>
private void CompleteItemUpdate(InventoryItemBase item)
private void StoreAssetForItemUpdate(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);
}
/// <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)
private void DoCreateItem(uint callbackID)
{
m_Scene.AssetService.Store(m_asset);
@@ -417,8 +326,20 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
ourClient.SendInventoryItemCreateUpdate(item, callbackID);
else
ourClient.SendAlertMessage("Unable to create inventory item");
}
m_transactions.RemoveXferUploader(m_transactionID);
/// <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;
}
}
}
}

View File

@@ -107,6 +107,8 @@ 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());
@@ -168,6 +170,8 @@ 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);
@@ -502,10 +506,13 @@ namespace Flotsam.RegionModules.AssetCache
// Purge all files last accessed prior to this point
DateTime purgeLine = DateTime.Now - m_FileExpiration;
// 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);
// 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();
}
foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
{
@@ -698,14 +705,11 @@ namespace Flotsam.RegionModules.AssetCache
/// <summary>
/// Iterates through all Scenes, doing a deep scan through assets
/// to update the access time of all assets present in the scene or referenced by assets
/// in the scene.
/// to cache all assets present in the scene or referenced by assets
/// in the scene
/// </summary>
/// <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)
/// <returns></returns>
private int CacheScenes()
{
UuidGatherer gatherer = new UuidGatherer(m_AssetService);
@@ -728,7 +732,7 @@ namespace Flotsam.RegionModules.AssetCache
{
File.SetLastAccessTime(filename, DateTime.Now);
}
else if (storeUncached)
else
{
m_AssetService.Get(assetID.ToString());
}
@@ -856,14 +860,13 @@ namespace Flotsam.RegionModules.AssetCache
break;
case "assets":
m_log.Info("[FLOTSAM ASSET CACHE]: Ensuring assets are cached for all scenes.");
m_log.Info("[FLOTSAM ASSET CACHE]: Caching all assets, in all scenes.");
Util.FireAndForget(delegate {
int assetReferenceTotal = TouchAllSceneAssets(true);
m_log.InfoFormat(
"[FLOTSAM ASSET CACHE]: Completed check with {0} assets.",
assetReferenceTotal);
int assetsCached = CacheScenes();
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached);
});
break;

View File

@@ -48,16 +48,14 @@ 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 : OpenSimTestCase
public class FlotsamAssetCacheTests
{
protected TestScene m_scene;
protected FlotsamAssetCache m_cache;
[SetUp]
public override void SetUp()
public void SetUp()
{
base.SetUp();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");

View File

@@ -75,40 +75,10 @@ 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)
{
@@ -269,7 +239,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
sp.ClearAttachments();
}
public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent)
public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp)
{
lock (sp.AttachmentsSyncLock)
{
@@ -328,7 +298,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
group.AbsolutePosition = attachPos;
if (sp.PresenceType != PresenceType.Npc)
UpdateUserInventoryWithAttachment(sp, group, attachmentPt);
UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp);
AttachToAgent(sp, group, attachmentPt, attachPos, silent);
}
@@ -336,7 +306,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return true;
}
private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt)
private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp)
{
// Remove any previous attachments
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
@@ -346,18 +316,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
{
if (attachments[0].FromItemID != UUID.Zero)
DetachSingleAttachmentToInvInternal(sp, attachments[0]);
else
m_log.WarnFormat(
"[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
// Error logging commented because UUID.Zero now means temp attachment
// else
// m_log.WarnFormat(
// "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
// attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
}
// Add the new attachment to inventory if we don't already have it.
UUID newAttachmentItemID = group.FromItemID;
if (newAttachmentItemID == UUID.Zero)
newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
if (!temp)
{
UUID newAttachmentItemID = group.FromItemID;
if (newAttachmentItemID == UUID.Zero)
newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
}
}
public SceneObjectGroup RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
@@ -436,6 +410,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
UUID inventoryID = so.FromItemID;
// As per Linden spec, drop is disabled for temp attachs
if (inventoryID == UUID.Zero)
return;
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}",
// so.Name, so.LocalId, inventoryID);
@@ -446,7 +424,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
so.PrimCount, sp.UUID, sp.AbsolutePosition))
return;
bool changed = sp.Appearance.DetachAttachment(inventoryID);
bool changed = false;
if (inventoryID != UUID.Zero)
changed = sp.Appearance.DetachAttachment(inventoryID);
if (changed && m_scene.AvatarFactory != null)
m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
@@ -551,6 +531,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
/// <param name="saveAllScripted"></param>
private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp, string scriptedState)
{
if (grp.FromItemID == UUID.Zero)
{
// We can't save temp attachments
grp.HasGroupChanged = false;
return;
}
// Saving attachments for NPCs messes them up for the real owner!
INPCModule module = m_scene.RequestModuleInterface<INPCModule>();
if (module != null)
@@ -561,9 +548,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);
@@ -667,10 +654,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
});
}
// 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.IsSelected = false; // fudge....
so.ScheduleGroupForFullUpdate();
}
@@ -810,7 +794,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
// This will throw if the attachment fails
try
{
AttachObject(sp, objatt, attachmentPt, false);
AttachObject(sp, objatt, attachmentPt, false, false);
}
catch (Exception e)
{
@@ -964,7 +948,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
AttachmentPt &= 0x7f;
// Calls attach with a Zero position
if (AttachObject(sp, part.ParentGroup, AttachmentPt, false))
if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, false))
{
// m_log.Debug(
// "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
@@ -988,7 +972,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID);
if (sp != null && group != null)
if (sp != null && group != null && group.FromItemID != UUID.Zero)
DetachSingleAttachmentToInv(sp, group);
}
@@ -1006,7 +990,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
foreach (SceneObjectGroup group in attachments)
{
if (group.FromItemID == itemID)
if (group.FromItemID == itemID && group.FromItemID != UUID.Zero)
{
DetachSingleAttachmentToInv(sp, group);
return;

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