From 4be3f7c49bc1bfb6dcc677459be5eec4951bda9d Mon Sep 17 00:00:00 2001 From: MW Date: Fri, 16 Feb 2007 16:06:40 +0000 Subject: [PATCH] started using BerkeleyDB as local database --- AgentManager.cs | 220 ++++++++++++++++++++++++++++++++++++++- AssemblyInfo.cs | 4 +- AssetManager.cs | 220 ++++++++++++++++++++++++++++++++------- AssetServer.cs | 76 +++++++++++++- Assets.cs | 105 +++++++++++++++++++ BerkeleyDatabase.cs | 205 +++++++++++++++++++++++++++++++++++++ ClientConnection.cs | 105 +++++++------------ Controller.cs | 32 ++++-- Globals.cs | 2 +- GridManager.cs | 4 +- GridServer.cs | 20 +++- InstantMessaging.cs | 2 +- InventoryManager.cs | 2 +- LocalAssetCache.cs | 46 +++++++++ LocalStorageBase.cs | 132 ++++++++++++++++++++++++ LoginServer.cs | 32 +++--- OpenSimLite.csproj | 16 ++- PhysicsManager.cs | 2 +- PrimManager.cs | 20 +++- SceneGraph.cs | 244 +++++++++++++++++++++++++++++++++++++++++--- ScriptManager.cs | 8 +- UserServer.cs | 49 ++++++++- Utility.cs | 65 +++++++++++- ViewerServer.cs | 186 ++++++++++++++++++--------------- 24 files changed, 1549 insertions(+), 248 deletions(-) create mode 100644 Assets.cs create mode 100644 BerkeleyDatabase.cs create mode 100644 LocalAssetCache.cs create mode 100644 LocalStorageBase.cs diff --git a/AgentManager.cs b/AgentManager.cs index 56d51a8509..84248139c7 100644 --- a/AgentManager.cs +++ b/AgentManager.cs @@ -26,24 +26,173 @@ */ using System; +using System.Collections.Generic; using libsecondlife; +using libsecondlife.Packets; -namespace OpenSimLite +namespace OpenSim { /// /// Manages Agent details. /// public class AgentManager { - public AgentManager() + public Dictionary AgentList; + private uint _localNumber=0; + private Server _server; + + public AgentManager(Server server) { + _server=server; + this.AgentList = new Dictionary(); } public AgentName GetAgentName(LLUUID AgentID) { - AgentName name = new AgentName(); + + AgentName name; + if(AgentList.ContainsKey(AgentID)) + { + name=AgentList[AgentID].Name; + } + else + { + name = new AgentName(); + } return(name); } + + public AgentProfile GetAgent(LLUUID id) + { + if(!this.AgentList.ContainsKey(id)) + { + return null; + } + else + { + AgentProfile avatar = this.AgentList[id]; + return avatar; + } + } + /// + /// + /// + /// + public void AddAgent(AgentProfile agent) + { + this.AgentList.Add(agent.Avatar.FullID, agent); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public bool NewAgent(NetworkInfo userInfo, string first, string last, LLUUID baseFolder, LLUUID inventoryFolder) + { + Console.WriteLine("new agent called"); + AgentProfile agent = new AgentProfile(); + agent.Avatar.FullID = userInfo.User.AgentID; + agent.Avatar.NetInfo = userInfo; + agent.Avatar.NetInfo.User.FirstName =first; + agent.Avatar.NetInfo.User.LastName = last; + agent.Avatar.Position = new LLVector3(100, 100, 22); + agent.Avatar.BaseFolder = baseFolder; + agent.Avatar.InventoryFolder = inventoryFolder; + agent.Avatar.LocalID = 8880000 + this._localNumber; + this._localNumber++; + this.AgentList.Add(agent.Avatar.FullID, agent); + + //Create new Wearable Assets and place in Inventory + //this.assetManager.CreateNewInventorySet(ref agent, userInfo); + + return(true); + } + + /// + /// + /// + /// + public void RemoveAgent(NetworkInfo userInfo) + { + this.AgentList.Remove(userInfo.User.AgentID); + + //tell other clients to delete this avatar + } + + /// + /// + /// + /// + public void AgentJoin(NetworkInfo userInfo) + { + //inform client of join comlete + libsecondlife.Packets.AgentMovementCompletePacket mov = new AgentMovementCompletePacket(); + mov.AgentData.SessionID = userInfo.User.SessionID; + mov.AgentData.AgentID = userInfo.User.AgentID; + mov.Data.RegionHandle = Globals.Instance.RegionHandle; + mov.Data.Timestamp = 1169838966; + mov.Data.Position = new LLVector3(100f, 100f, 22f); + mov.Data.LookAt = new LLVector3(0.99f, 0.042f, 0); + _server.SendPacket(mov, true, userInfo); + } + + public void RequestWearables(NetworkInfo userInfo) + { + AgentProfile Agent = this.AgentList[userInfo.User.AgentID]; + AgentWearablesUpdatePacket aw = new AgentWearablesUpdatePacket(); + aw.AgentData.AgentID = userInfo.User.AgentID; + aw.AgentData.SerialNum = 0; + aw.AgentData.SessionID = userInfo.User.SessionID; + + aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[13]; + AgentWearablesUpdatePacket.WearableDataBlock awb = null; + awb = new AgentWearablesUpdatePacket.WearableDataBlock(); + awb.WearableType = (byte)0; + awb.AssetID = Agent.Avatar.Wearables[0].AssetID; + awb.ItemID = Agent.Avatar.Wearables[0].ItemID; + aw.WearableData[0] = awb; + + awb = new AgentWearablesUpdatePacket.WearableDataBlock(); + awb.WearableType =(byte)1; + awb.AssetID = Agent.Avatar.Wearables[1].AssetID; + awb.ItemID = Agent.Avatar.Wearables[1].ItemID; + aw.WearableData[1] = awb; + + for(int i=2; i<13; i++) + { + awb = new AgentWearablesUpdatePacket.WearableDataBlock(); + awb.WearableType = (byte)i; + awb.AssetID = new LLUUID("00000000-0000-0000-0000-000000000000"); + awb.ItemID = new LLUUID("00000000-0000-0000-0000-000000000000"); + aw.WearableData[i] = awb; + } + + _server.SendPacket(aw, true, userInfo); + } + + public void SendPacketToAllExcept(Packet packet, LLUUID exceptAgent) + { + foreach (KeyValuePair kp in this.AgentList) + { + if(kp.Value.Avatar.NetInfo.User.AgentID != exceptAgent) + { + _server.SendPacket(packet, true, kp.Value.Avatar.NetInfo); + } + } + } + + public void SendPacketToALL(Packet packet) + { + foreach (KeyValuePair kp in this.AgentList) + { + _server.SendPacket(packet, true, kp.Value.Avatar.NetInfo); + } + } } public struct AgentName @@ -54,9 +203,74 @@ namespace OpenSimLite public class AgentProfile { + public AgentName Name; + public AvatarData Avatar; + //public AgentInventory Inventory; + public AgentProfile() + { + Name = new AgentName(); + Avatar = new AvatarData(); + } + } + + public class AvatarData : Node + { + public NetworkInfo NetInfo; + public LLUUID FullID; + public uint LocalID; + //public LLQuaternion Rotation; + public bool Walk = false; + public bool Started = false; + //public TextureEntry TextureEntry; + public AvatarWearable[] Wearables; + public LLUUID InventoryFolder; + public LLUUID BaseFolder; + public AvatarParams VisParams; + + public List ObjectUpdateList; + public List TerseUpdateList; + + public AvatarData() + { + Wearables=new AvatarWearable[2]; //should be 13 + for(int i = 0; i < 2; i++) + { + Wearables[i] = new AvatarWearable(); + } + this.SceneType = 1; //Avatar type + + this.ObjectUpdateList = new List(); + this.TerseUpdateList = new List(); + VisParams = new AvatarParams(); + } + } + + public class AvatarWearable + { + public LLUUID AssetID; + public LLUUID ItemID; + + public AvatarWearable() { } } + + + public class AvatarParams + { + public byte[] Params; + + public AvatarParams() + { + Params = new byte [ 218]; + for(int i = 0; i < 218; i++) + { + Params[i] = 100; + } + } + + } + } diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs index 88d8e1022e..d465bc69ed 100644 --- a/AssemblyInfo.cs +++ b/AssemblyInfo.cs @@ -8,11 +8,11 @@ using System.Runtime.InteropServices; // change them to the information which is associated with the assembly // you compile. -[assembly: AssemblyTitle("OpenSimLite")] +[assembly: AssemblyTitle("OpenSim")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("OpenSim project")] -[assembly: AssemblyProduct("OpenSimLite")] +[assembly: AssemblyProduct("OpenSim")] [assembly: AssemblyCopyright("(c) OpenSim project")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/AssetManager.cs b/AssetManager.cs index 81071901b8..e053eb8350 100644 --- a/AssetManager.cs +++ b/AssetManager.cs @@ -30,23 +30,33 @@ using System.Collections.Generic; using libsecondlife; using libsecondlife.Packets; -namespace OpenSimLite +namespace OpenSim { /// /// Manages local cache of assets and their sending to viewers. /// - public class AssetManager + public class AssetManager : IAssetReceived { public Dictionary Assets; public Dictionary Textures; + + public List AssetRequests = new List(); //assets ready to be sent to viewers + public List TextureRequests = new List(); //textures ready to be sent + + public List RequestedAssets = new List(); //Assets requested from the asset server + public List RequestedTextures = new List(); //Textures requested from the asset server + private AssetServer _assetServer; + private Server _server; /// /// /// - public AssetManager(AssetServer assetServer) + public AssetManager(Server server, AssetServer assetServer) { - _assetServer=assetServer; + _server = server; + _assetServer = assetServer; + _assetServer.SetReceiver(this); } /// @@ -54,15 +64,8 @@ namespace OpenSimLite /// private void RunAssetManager() { - - } - - /// - /// - /// - private void ProcessAssetQueue() - { - + this.ProcessAssetQueue(); + this.ProcessTextureQueue(); } /// @@ -70,9 +73,97 @@ namespace OpenSimLite /// private void ProcessTextureQueue() { + if(this.TextureRequests.Count == 0) + { + //no requests waiting + return; + } + int num; + //should be running in its own thread but for now is called by timer + + if(this.TextureRequests.Count < 5) + { + //lower than 5 so do all of them + num = this.TextureRequests.Count; + } + else + { + num=5; + } + TextureRequest req; + for(int i = 0; i < num; i++) + { + req=(TextureRequest)this.TextureRequests[i]; + + if(req.PacketCounter == 0) + { + //first time for this request so send imagedata packet + if(req.NumPackets == 1) + { + //only one packet so send whole file + ImageDataPacket im = new ImageDataPacket(); + im.ImageID.Packets = 1; + im.ImageID.ID = req.ImageInfo.FullID; + im.ImageID.Size = (uint)req.ImageInfo.Data.Length; + im.ImageData.Data = req.ImageInfo.Data; + im.ImageID.Codec = 2; + _server.SendPacket(im, true, req.RequestUser); + req.PacketCounter++; + //req.ImageInfo.l= time; + //System.Console.WriteLine("sent texture: "+req.image_info.FullID); + } + else + { + //more than one packet so split file up + ImageDataPacket im = new ImageDataPacket(); + im.ImageID.Packets = (ushort)req.NumPackets; + im.ImageID.ID = req.ImageInfo.FullID; + im.ImageID.Size = (uint)req.ImageInfo.Data.Length; + im.ImageData.Data = new byte[600]; + Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600); + im.ImageID.Codec = 2; + _server.SendPacket(im, true, req.RequestUser); + req.PacketCounter++; + //req.ImageInfo.last_used = time; + //System.Console.WriteLine("sent first packet of texture: + } + } + else + { + //send imagepacket + //more than one packet so split file up + ImagePacketPacket im = new ImagePacketPacket(); + im.ImageID.Packet = (ushort)req.PacketCounter; + im.ImageID.ID = req.ImageInfo.FullID; + int size = req.ImageInfo.Data.Length - 600 - 1000*(req.PacketCounter - 1); + if(size > 1000) size = 1000; + im.ImageData.Data = new byte[size]; + Array.Copy(req.ImageInfo.Data, 600 + 1000*(req.PacketCounter - 1), im.ImageData.Data, 0, size); + _server.SendPacket(im, true, req.RequestUser); + req.PacketCounter++; + //req.ImageInfo.last_used = time; + //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID); + } + } + + //remove requests that have been completed + for(int i = 0; i < num; i++) + { + req=(TextureRequest)this.TextureRequests[i]; + if(req.PacketCounter == req.NumPackets) + { + this.TextureRequests.Remove(req); + } + } } - + public void AssetReceived(AssetBase asset) + { + //check if it is a texture or not + //then add to the correct cache list + //then check for waiting requests for this asset/texture (in the Requested lists) + //and move those requests into the Requests list. + } #region Assets /// /// @@ -81,8 +172,32 @@ namespace OpenSimLite /// public void AddAssetRequest(NetworkInfo userInfo, TransferRequestPacket transferRequest) { - LLUUID RequestID = new LLUUID(transferRequest.TransferInfo.Params, 0); + LLUUID requestID = new LLUUID(transferRequest.TransferInfo.Params, 0); //check to see if asset is in local cache, if not we need to request it from asset server. + if(!this.Assets.ContainsKey(requestID)) + { + //not found asset + // so request from asset server + AssetRequest request = new AssetRequest(); + request.RequestUser = userInfo; + request.RequestImage = requestID; + this.AssetRequests.Add(request); + this._assetServer.RequestAsset(requestID); + return; + } + //it is in our cache + AssetInfo info = this.Assets[requestID]; + + //work out how many packets it should be sent in + // and add to the AssetRequests list + } + + /// + /// + /// + private void ProcessAssetQueue() + { + } #endregion @@ -96,39 +211,72 @@ namespace OpenSimLite public void AddTextureRequest(NetworkInfo userInfo, LLUUID imageID) { //check to see if texture is in local cache, if not request from asset server + if(!this.Textures.ContainsKey(imageID)) + { + /*not found image so send back image not in data base message + ImageNotInDatabasePacket im_not = new ImageNotInDatabasePacket(); + im_not.ImageID.ID=imageID; + _server.SendPacket(im_not, true, userInfo);*/ + + //not is cache so request from asset server + TextureRequest request = new TextureRequest(); + request.RequestUser = userInfo; + request.RequestImage = imageID; + this.TextureRequests.Add(request); + this._assetServer.RequestAsset(imageID); + return; + } + TextureImage imag = this.Textures[imageID]; + TextureRequest req = new TextureRequest(); + req.RequestUser = userInfo; + req.RequestImage = imageID; + req.ImageInfo = imag; + + if(imag.Data.LongLength>600) + { + //over 600 bytes so split up file + req.NumPackets = 1 + (int)(imag.Data.Length-600+999)/1000; + } + else + { + req.NumPackets = 1; + } + + this.TextureRequests.Add(req); } #endregion } - - public class AssetBase + + public class AssetRequest { - public byte[] Data; - public LLUUID FullID; - public sbyte Type; - public sbyte InvType; - public string Name; - public string Description; - public string Filename; + public NetworkInfo RequestUser; + public LLUUID RequestImage; + public AssetInfo asset_inf; + public long data_pointer = 0; + public int num_packets = 0; + public int packet_counter = 0; + //public bool AssetInCache; + //public int TimeRequested; - public AssetBase() + public AssetRequest() { } } - //needed? - public class TextureImage + public class TextureRequest { - public TextureImage() - { - - } - } - - public class AssetInfo - { - public AssetInfo() + public NetworkInfo RequestUser; + public LLUUID RequestImage; + public TextureImage ImageInfo; + public long DataPointer = 0; + public int NumPackets = 0; + public int PacketCounter = 0; + //public bool TextureInCache; + //public int TimeRequested; + + public TextureRequest() { } diff --git a/AssetServer.cs b/AssetServer.cs index 89b55f12bc..db6967ab47 100644 --- a/AssetServer.cs +++ b/AssetServer.cs @@ -26,14 +26,20 @@ */ using System; +using libsecondlife; +using BerkeleyDb; +using Kds.Serialization; +using Kds.Serialization.Buffer; -namespace OpenSimLite +namespace OpenSim { /// /// Handles connection to Asset Server. /// - public class AssetServer + public class AssetServer : IAssetServer { + private IAssetReceived _receiver; + public AssetServer() { } @@ -46,5 +52,71 @@ namespace OpenSimLite } } + public void SetReceiver(IAssetReceived receiver) + { + this._receiver = receiver; + } + public void RequestAsset(LLUUID assetID) + { + AssetBase asset = null; + byte[] dataBuffer = new byte[4096]; + byte[] keyBuffer = new byte[256]; + int index; + DbEntry keyEntry; + DbEntry dataEntry; + dataEntry = DbEntry.InOut(dataBuffer, 0, 4096); + index = 0; + BerkeleyDatabases.Instance.dbs.Formatter.Serialize(assetID.ToStringHyphenated(), keyBuffer, ref index); + byte[] co= new byte[44]; + Array.Copy(keyBuffer,co,44); + keyEntry = DbEntry.InOut(co, 0, 44); + ReadStatus status = BerkeleyDatabases.Instance.dbs.AssetDb.Get(null, ref keyEntry, ref dataEntry, DbFile.ReadFlags.None); + if (status != ReadStatus.Success) + { + throw new ApplicationException("Read failed"); + } + index = 0; + BerkeleyDatabases.Instance.dbs.Formatter.Deserialize(ref asset, dataEntry.Buffer, ref index); + this._receiver.AssetReceived( asset); + } + public void UpdateAsset(AssetBase asset) + { + //can we use UploadNewAsset to update as well? + this.UploadNewAsset(asset); + } + public void UploadNewAsset(AssetBase asset) + { + byte[] dataBuffer = new byte[4096]; + byte[] keyBuffer = new byte[256]; + int index; + DbEntry keyEntry; + DbEntry dataEntry; + index = 0; + BerkeleyDatabases.Instance.dbs.Formatter.Serialize(asset.FullID.ToStringHyphenated(), keyBuffer, ref index); + byte[] co= new byte[44]; + Array.Copy(keyBuffer,co,44); + keyEntry = DbEntry.InOut(co, 0, 44); + index = 0; + BerkeleyDatabases.Instance.dbs.Formatter.Serialize(asset, dataBuffer, ref index); + dataEntry = DbEntry.InOut(dataBuffer, 0, index); + WriteStatus status = BerkeleyDatabases.Instance.dbs.AssetDb.Put(null, ref keyEntry, ref dataEntry, DbFile.WriteFlags.None); + if (status != WriteStatus.Success) + throw new ApplicationException("Put failed"); + } + + } + + public interface IAssetServer + { + void SetReceiver(IAssetReceived receiver); + void RequestAsset(LLUUID assetID); + void UpdateAsset(AssetBase asset); + void UploadNewAsset(AssetBase asset); + } + + // could change to delegate + public interface IAssetReceived + { + void AssetReceived(AssetBase asset); } } diff --git a/Assets.cs b/Assets.cs new file mode 100644 index 0000000000..a15c0e9fed --- /dev/null +++ b/Assets.cs @@ -0,0 +1,105 @@ +/* +* Copyright (c) OpenSim project, http://sim.opensecondlife.org/ +* +* 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 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 ``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 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 libsecondlife; + +namespace OpenSim +{ + /// + /// Description of Assets. + /// + public class AssetBase + { + public byte[] Data; + public LLUUID FullID; + public sbyte Type; + public sbyte InvType; + public string Name; + public string Description; + public string Filename; + + public AssetBase() + { + + } + } + + public class PrimAsset: AssetBase + { + public PrimData PrimData; + + public PrimAsset() + { + this.PrimData = new PrimData(); + } + } + public class PrimData + { + public LLUUID OwnerID; + public byte PCode; + public byte PathBegin; + public byte PathEnd; + public byte PathScaleX; + public byte PathScaleY; + public byte PathShearX; + public byte PathShearY; + public sbyte PathSkew; + public byte ProfileBegin; + public byte ProfileEnd; + public LLVector3 Scale; + public byte PathCurve; + public byte ProfileCurve; + public uint ParentID=0; + public byte ProfileHollow; + //public bool DataBaseStorage=false; + + public PrimData() + { + + } + } + + //a hangover from the old code, so is it needed for future use? + public class TextureImage: AssetBase + { + public TextureImage() + { + + } + } + + //a hangover from the old code, so is it needed for future use? + public class AssetInfo :AssetBase + { + public AssetInfo() + { + + } + } + +} diff --git a/BerkeleyDatabase.cs b/BerkeleyDatabase.cs new file mode 100644 index 0000000000..3456039097 --- /dev/null +++ b/BerkeleyDatabase.cs @@ -0,0 +1,205 @@ +/* +* Copyright (c) OpenSim project, http://sim.opensecondlife.org/ +* +* 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 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 ``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 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 libsecondlife; +using BerkeleyDb; +using System.IO; +using Kds.Serialization; +using Kds.Serialization.Buffer; + +namespace OpenSim +{ + /// + /// Description of BerkeleyDatabase. + /// + public class BerkeleyDatabases + { + + public const string primDbName = "prim.db"; + public const string assetDbName = "asset.db"; + + + // will be initialized on first access to static field in a thread-safe way + private static readonly BerkeleyDatabases instance = new BerkeleyDatabases(); + private FileStream errStream; + private string dbDir; + private DbBTree primDb; + private DbBTree assetDb; + + // used for key gnerator call-backs, not thread-safe + private BEFormatter formatter; + private byte[] keyBuffer = new byte[2048]; + + private BerkeleyDatabases() { + formatter = new BEFormatter(); + formatter.RegisterField(new PrimAssetField(formatter)); + formatter.RegisterField(new AssetBaseField(formatter)); + + } + ~BerkeleyDatabases() + { + this.Close(); + } + + public BerkeleyDatabases dbs; + + // singleton + public static BerkeleyDatabases Instance { + get { return instance; } + } + + public void Open(string dbDir, string appName, Stream errStream) { + this.dbDir = dbDir; + //Remove(); + + // open local prim database + Db db = new Db(DbCreateFlags.None); + db.ErrorPrefix = appName; + db.ErrorStream = errStream; + primDb = (DbBTree)db.Open(null, PrimDbName, null, DbType.BTree, Db.OpenFlags.Create, 0); + + //open asset server database + db = new Db(DbCreateFlags.None); + db.ErrorPrefix = appName; + db.ErrorStream = errStream; + assetDb = (DbBTree)db.Open(null, AssetDbName, null, DbType.BTree, Db.OpenFlags.Create, 0); + + } + + public void Remove() { + try { + Db db = new Db(DbCreateFlags.None); + db.Remove(PrimDbName, null); + } + catch { } + + try { + Db db = new Db(DbCreateFlags.None); + db.Remove(AssetDbName, null); + } + catch { } + + } + + public void Close() { + if (primDb != null) { + primDb.GetDb().Close(); + primDb = null; + } + + if (assetDb != null) { + assetDb.GetDb().Close(); + assetDb = null; + } + + } + + public BEFormatter Formatter { + get { return formatter; } + } + + public string PrimDbName { + get { return Path.Combine(dbDir, primDbName); } + } + + public DbBTree PrimDb { + get { return primDb; } + } + + public string AssetDbName { + get { return Path.Combine(dbDir, assetDbName); } + } + + public DbBTree AssetDb { + get { return assetDb; } + } + + public void Startup() + { + dbs = BerkeleyDatabases.Instance; + string dbPath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Db"); + string appName = Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase); + errStream = File.Open(Path.Combine(dbPath, "errors.txt"), FileMode.OpenOrCreate, FileAccess.Write); + dbs.Open(dbPath, appName, errStream); + } + } + + public class PrimAssetField: ReferenceField + { + public PrimAssetField(Formatter formatter) : base(formatter) { } + + protected override void SerializeValue(PrimAsset value) { + Formatter.Serialize(value.Name); + Formatter.Serialize(value.Description); + + } + + protected override void DeserializeInstance(ref PrimAsset instance) { + if (instance == null) + instance = new PrimAsset(); + } + + protected override void DeserializeMembers(PrimAsset instance) { + Formatter.Deserialize(ref instance.Name); + Formatter.Deserialize(ref instance.Description); + + } + + protected override void SkipValue() { + if (Formatter.Skip()) + Formatter.Skip(); + } + } + + public class AssetBaseField: ReferenceField + { + public AssetBaseField(Formatter formatter) : base(formatter) { } + + protected override void SerializeValue(AssetBase value) { + Formatter.Serialize(value.Name); + Formatter.Serialize(value.Description); + + } + + protected override void DeserializeInstance(ref AssetBase instance) { + if (instance == null) + instance = new AssetBase(); + } + + protected override void DeserializeMembers(AssetBase instance) { + Formatter.Deserialize(ref instance.Name); + Formatter.Deserialize(ref instance.Description); + + } + + protected override void SkipValue() { + if (Formatter.Skip()) + Formatter.Skip(); + } + } +} diff --git a/ClientConnection.cs b/ClientConnection.cs index 89dcc425c1..bcda5991f9 100644 --- a/ClientConnection.cs +++ b/ClientConnection.cs @@ -31,7 +31,7 @@ using System.Threading; using libsecondlife; using libsecondlife.Packets; -namespace OpenSimLite +namespace OpenSim { /// /// Hanldes a single clients connection. Runs in own thread. @@ -40,6 +40,9 @@ namespace OpenSimLite { public static GridManager Grid; public static SceneGraph Scene; + public static AgentManager AgentManager; + public static PrimManager PrimManager; + public byte ConnectionType=1; private Thread _mthread; @@ -50,6 +53,7 @@ namespace OpenSimLite public override void Start() { _mthread = new Thread(new ThreadStart(RunClientRead)); + _mthread.IsBackground = true; _mthread.Start(); } @@ -64,16 +68,45 @@ namespace OpenSimLite switch(packet.Type) { case PacketType.UseCircuitCode: - //should be a new user joining - Console.WriteLine("new agent"); + Console.WriteLine("new circuit"); + //should be a new user/circuit joining + // add agents profile to agentmanager + string first = "",last =""; + LLUUID baseFolder = null, inventoryFolder =null; + + //rather than use IncomingLogins list, the logon object could be passed to this connection on creation + lock(Globals.Instance.IncomingLogins) + { + for(int i = 0; i < Globals.Instance.IncomingLogins.Count; i++) + { + if(Globals.Instance.IncomingLogins[i].Agent == this.NetInfo.User.AgentID) + { + first = Globals.Instance.IncomingLogins[i].First; + last = Globals.Instance.IncomingLogins[i].Last; + baseFolder = Globals.Instance.IncomingLogins[i].BaseFolder; + inventoryFolder = Globals.Instance.IncomingLogins[i].InventoryFolder; + Globals.Instance.IncomingLogins.RemoveAt(i); + break; + } + } + } + if(first != "") + { + AgentManager.NewAgent(this.NetInfo, first, last, baseFolder, inventoryFolder); + } break; case PacketType.CompleteAgentMovement: //Agent completing movement to region + // so send region handshake Grid.SendRegionData(this.NetInfo); + // send movmentcomplete reply + Scene.AgentCompletingMove(this.NetInfo); break; case PacketType.RegionHandshakeReply: Console.WriteLine("RegionHandshake reply"); Scene.SendTerrainData(this.NetInfo); + Scene.AddNewAvatar(AgentManager.GetAgent(this.NetInfo.User.AgentID).Avatar); + // send current avatars and prims data break; default: break; @@ -82,7 +115,7 @@ namespace OpenSimLite } catch (Exception e) { - Console.WriteLine(e.Message); + Console.WriteLine(e.Message + ", So die!"); } } } @@ -101,67 +134,5 @@ namespace OpenSimLite { } - } - - public class BlockingQueue< T > - { - private Queue< T > _queue = new Queue< T >(); - private object _queueSync = new object(); - - public void Enqueue(T value) - { - lock(_queueSync) - { - _queue.Enqueue(value); - Monitor.Pulse(_queueSync); - } - } - - public T Dequeue() - { - lock(_queueSync) - { - if( _queue.Count < 1) - Monitor.Wait(_queueSync); - - return _queue.Dequeue(); - } - } - } - - public class NonBlockingQueue< T > - { - private Queue< T > _queue = new Queue< T >(); - private object _queueSync = new object(); - - public void Enqueue(T value) - { - lock(_queueSync) - { - _queue.Enqueue(value); - } - } - - public T Dequeue() - { - T rValue = default(T); - lock(_queueSync) - { - if( _queue.Count > 0) - { - rValue = _queue.Dequeue(); - } - } - return rValue; - } - - public int Count - { - get - { - return(_queue.Count); - } - } - } - + } } diff --git a/Controller.cs b/Controller.cs index 608e2dd5e7..6dd5d72b69 100644 --- a/Controller.cs +++ b/Controller.cs @@ -31,7 +31,7 @@ using System.Collections.Generic; using libsecondlife; using libsecondlife.Packets; -namespace OpenSimLite +namespace OpenSim { class Controller { @@ -40,29 +40,47 @@ namespace OpenSimLite private LoginServer _loginServer; private GridManager _gridManager; private AgentManager _agentManager; + private AssetManager _assetManager; private SceneGraph _scene; + private PrimManager _primManager; public static void Main(string[] args) { Controller c = new Controller(); - while( true ) - System.Threading.Thread.Sleep( 1000 ); + bool Run=true; + while( Run ) + { + + string input = Console.ReadLine(); + + if(input == "Exit") + { + Run = false; + } + + } + + BerkeleyDatabases.Instance.Close(); } public Controller() { - _viewerServer = new Server(); _backboneServers = new BackboneServers(); - _agentManager = new AgentManager(); + _viewerServer = new Server(_backboneServers.UserServer); + _agentManager = new AgentManager(_viewerServer); _gridManager = new GridManager(_viewerServer, _agentManager); - _scene = new SceneGraph(_viewerServer); + _scene = new SceneGraph(_viewerServer, _agentManager); + _assetManager = new AssetManager(_viewerServer, _backboneServers.AssetServer); ClientConnection.Grid = _gridManager; ClientConnection.Scene = _scene; + ClientConnection.AgentManager = _agentManager; _viewerServer.Startup(); + BerkeleyDatabases.Instance.Startup(); + _primManager = new PrimManager(); if(Globals.Instance.StartLoginServer) { - _loginServer = new LoginServer(); + _loginServer = new LoginServer(_backboneServers.UserServer); _loginServer.Startup(); } diff --git a/Globals.cs b/Globals.cs index b79bb9017d..0f90e60001 100644 --- a/Globals.cs +++ b/Globals.cs @@ -29,7 +29,7 @@ using System; using System.Collections.Generic; using libsecondlife; -namespace OpenSimLite +namespace OpenSim { /// /// Description of Globals. diff --git a/GridManager.cs b/GridManager.cs index 31c10473cd..b45c1ff4d4 100644 --- a/GridManager.cs +++ b/GridManager.cs @@ -32,7 +32,7 @@ using libsecondlife; using libsecondlife.Packets; using System.Collections.Generic; -namespace OpenSimLite +namespace OpenSim { /// @@ -213,7 +213,7 @@ namespace OpenSimLite } /// - /// + /// most of this should be moved into the grid server class /// private void LoadGrid() { diff --git a/GridServer.cs b/GridServer.cs index 87a3b25ec3..3cfeba6bcc 100644 --- a/GridServer.cs +++ b/GridServer.cs @@ -26,17 +26,33 @@ */ using System; +using libsecondlife; -namespace OpenSimLite +namespace OpenSim { /// /// Handles connection to Grid Servers. /// also Sim to Sim connections? /// - public class GridServer + public class GridServer //:IGridServer { public GridServer() { } } + + public interface IGridServer + { + bool RequestConnection(RegionInfo myRegion); + UUIDBlock RequestUUIDBlock(); + RegionInfo[] RequestNeighbours(); + } + + public struct UUIDBlock + { + public LLUUID BlockStart; + public LLUUID BlockEnd; + } + } + diff --git a/InstantMessaging.cs b/InstantMessaging.cs index da40d86625..2ae51c7c7f 100644 --- a/InstantMessaging.cs +++ b/InstantMessaging.cs @@ -27,7 +27,7 @@ using System; -namespace OpenSimLite +namespace OpenSim { /// /// Description of InstantMessaging. diff --git a/InventoryManager.cs b/InventoryManager.cs index c6aedb605a..56f2759135 100644 --- a/InventoryManager.cs +++ b/InventoryManager.cs @@ -29,7 +29,7 @@ using System; using System.Collections.Generic; using libsecondlife; -namespace OpenSimLite +namespace OpenSim { /// /// Local cache of Inventories diff --git a/LocalAssetCache.cs b/LocalAssetCache.cs new file mode 100644 index 0000000000..35a40b0788 --- /dev/null +++ b/LocalAssetCache.cs @@ -0,0 +1,46 @@ +/* +* Copyright (c) OpenSim project, http://sim.opensecondlife.org/ +* +* 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 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 ``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 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; + +namespace OpenSim +{ + /// + /// Description of LocalAssetCache. + /// + public class LocalAssetCache + { + public LocalAssetCache() + { + } + } + + public interface ILocalCacheStorage + { + void SaveAsset(AssetBase asset); + } +} diff --git a/LocalStorageBase.cs b/LocalStorageBase.cs new file mode 100644 index 0000000000..c062335e04 --- /dev/null +++ b/LocalStorageBase.cs @@ -0,0 +1,132 @@ +/* +* Copyright (c) OpenSim project, http://sim.opensecondlife.org/ +* +* 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 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 ``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 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 BerkeleyDb; +using Kds.Serialization; +using Kds.Serialization.Buffer; +using libsecondlife; + +namespace OpenSim +{ + /// + /// Description of LocalPrimDB. + /// + /// + public class LocalPrimDb :ILocalPrimStorage + { + public LocalPrimDb() + { + + } + + public void LoadScene(IPrimReceiver receiver) + { + + } + public void CreateNewPrimStorage(PrimAsset prim) + { + byte[] dataBuffer = new byte[4096]; + byte[] keyBuffer = new byte[256]; + int index; + DbEntry keyEntry; + DbEntry dataEntry; + index = 0; + BerkeleyDatabases.Instance.dbs.Formatter.Serialize(prim.FullID.ToStringHyphenated(), keyBuffer, ref index); + byte[] co= new byte[44]; + Array.Copy(keyBuffer,co,44); + keyEntry = DbEntry.InOut(co, 0, 44); + index = 0; + BerkeleyDatabases.Instance.dbs.Formatter.Serialize(prim, dataBuffer, ref index); + dataEntry = DbEntry.InOut(dataBuffer, 0, index); + WriteStatus status = BerkeleyDatabases.Instance.dbs.PrimDb.Put(null, ref keyEntry, ref dataEntry, DbFile.WriteFlags.None); + if (status != WriteStatus.Success) + throw new ApplicationException("Put failed"); + + } + public void UpdatePrimStorage(PrimAsset prim) + { + //can we just use CreateNewPrimStorage to update a prim? + this.CreateNewPrimStorage(prim); + } + public void RemovePrimStorage() + { + + } + public PrimAsset GetPrimFromStroage(LLUUID primID) + { + PrimAsset prim = null; + byte[] dataBuffer = new byte[4096]; + byte[] keyBuffer = new byte[256]; + int index; + DbEntry keyEntry; + DbEntry dataEntry; + dataEntry = DbEntry.InOut(dataBuffer, 0, 4096); + index = 0; + BerkeleyDatabases.Instance.dbs.Formatter.Serialize(primID.ToStringHyphenated(), keyBuffer, ref index); + byte[] co= new byte[44]; + Array.Copy(keyBuffer,co,44); + keyEntry = DbEntry.InOut(co, 0, 44); + ReadStatus status = BerkeleyDatabases.Instance.dbs.PrimDb.Get(null, ref keyEntry, ref dataEntry, DbFile.ReadFlags.None); + if (status != ReadStatus.Success) + { + throw new ApplicationException("Read failed"); + } + index = 0; + BerkeleyDatabases.Instance.dbs.Formatter.Deserialize(ref prim, dataEntry.Buffer, ref index); + return prim; + } + + /// + /// test function + /// + public void ReadWholedatabase() + { + foreach (KeyDataPair entry in BerkeleyDatabases.Instance.dbs.PrimDb.OpenCursor(null, DbFileCursor.CreateFlags.None)) { + PrimAsset vendor = null; + int index = entry.Data.Start; + BerkeleyDatabases.Instance.dbs.Formatter.Deserialize(ref vendor, entry.Data.Buffer, ref index); + Console.WriteLine("prim found: "+vendor.Name + " "+ vendor.Description); + } + } + } + + public interface ILocalPrimStorage + { + void LoadScene(IPrimReceiver receiver); + void CreateNewPrimStorage(PrimAsset prim); + void UpdatePrimStorage(PrimAsset prim); + void RemovePrimStorage(); + PrimAsset GetPrimFromStroage(LLUUID primID); + } + + //change to delegate? + public interface IPrimReceiver + { + void ReceivePrim(PrimAsset prim); + } +} diff --git a/LoginServer.cs b/LoginServer.cs index c5ac284afd..8b2c0a3967 100644 --- a/LoginServer.cs +++ b/LoginServer.cs @@ -37,18 +37,19 @@ using System.Collections; using System.Xml; using libsecondlife; -namespace OpenSimLite +namespace OpenSim { /// /// When running in local (default) mode , handles client logins. /// public class LoginServer { - public LoginServer() + public LoginServer(UserServer userServer) { - + _userServer = userServer; } private Logon _login; + private UserServer _userServer; private ushort _loginPort = Globals.Instance.LoginServerPort; public IPAddress clientAddress = IPAddress.Loopback; public IPAddress remoteAddress = IPAddress.Any; @@ -58,7 +59,7 @@ namespace OpenSimLite private string _defaultResponse; private string _mpasswd; - private bool _needPassswd=false; + private bool _needPasswd=false; // InitializeLoginProxy: initialize the login proxy private void InitializeLoginProxy() { @@ -66,7 +67,7 @@ namespace OpenSimLite loginServer.Bind(new IPEndPoint(remoteAddress, _loginPort)); loginServer.Listen(1); - this._needPassswd=Globals.Instance.NeedPasswd; + this._needPasswd=Globals.Instance.NeedPasswd; //read in default response string StreamReader SR; string lines; @@ -94,7 +95,7 @@ namespace OpenSimLite private void RunLoginProxy() { - Console.WriteLine("Starting Login Sever"); + Console.WriteLine("Starting Login Server"); try { for (;;) @@ -145,7 +146,7 @@ namespace OpenSimLite { // read one line of the header line = reader.ReadLine(); - + // check for premature EOF if (line == null) throw new Exception("EOF in client HTTP header"); @@ -157,7 +158,6 @@ namespace OpenSimLite } while (line != ""); // read the HTTP body into a buffer - this._login = new Logon(); char[] content = new char[contentLength]; reader.Read(content, 0, contentLength); @@ -180,6 +180,7 @@ namespace OpenSimLite { first = "test"; } + if(requestData.Contains("last")) { last = (string)requestData["last"]; @@ -188,6 +189,7 @@ namespace OpenSimLite { last = "User"+NumClients.ToString(); } + if(requestData.Contains("passwd")) { passwd = (string)requestData["passwd"]; @@ -235,6 +237,7 @@ namespace OpenSimLite CustomiseLoginResponse( responseData, first, last ); + this._login = new Logon(); //copy data to login object _login.First = first; _login.Last = last; @@ -243,9 +246,10 @@ namespace OpenSimLite _login.BaseFolder = BaseFolderID; _login.InventoryFolder = InventoryFolderID; - lock(Globals.Instance.IncomingLogins) + //working on local computer so lets add to the userserver's list of sessions + lock(this._userServer.Sessions) { - Globals.Instance.IncomingLogins.Add(_login); + this._userServer.Sessions.Add(_login); } // forward the XML-RPC response to the client @@ -279,11 +283,11 @@ namespace OpenSimLite protected virtual bool Authenticate(string first, string last, string passwd) { - if(this._needPassswd) + if(this._needPasswd) { //every user needs the password to login - string encodedpass = passwd.Remove(0,3); //remove $1$ - if(encodedpass == this._mpasswd) + string encodedPass = passwd.Remove(0,3); //remove $1$ + if(encodedPass == this._mpasswd) { return true; } @@ -294,7 +298,7 @@ namespace OpenSimLite } else { - //not need password to login + //do not need password to login return true; } } diff --git a/OpenSimLite.csproj b/OpenSimLite.csproj index 3833a9f06d..50081a135c 100644 --- a/OpenSimLite.csproj +++ b/OpenSimLite.csproj @@ -1,8 +1,8 @@  Exe - OpenSimLite - OpenSimLite + OpenSim + OpenSim Debug AnyCPU {782CCAFD-7313-4638-ADAC-53703DF24DF0} @@ -31,6 +31,14 @@ bin\Debug\libsecondlife.dll False + + bin\Debug\libdb_dotNET43.dll + False + + + bin\Debug\Kds.Serialization.dll + False + @@ -52,6 +60,10 @@ + + + + \ No newline at end of file diff --git a/PhysicsManager.cs b/PhysicsManager.cs index 62e2016bd0..991be5a787 100644 --- a/PhysicsManager.cs +++ b/PhysicsManager.cs @@ -27,7 +27,7 @@ using System; -namespace OpenSimLite +namespace OpenSim { /// /// Description of PhysicsManager. diff --git a/PrimManager.cs b/PrimManager.cs index 27a77de8ef..b861d22aff 100644 --- a/PrimManager.cs +++ b/PrimManager.cs @@ -26,16 +26,34 @@ */ using System; +using libsecondlife; -namespace OpenSimLite +namespace OpenSim { /// /// Manages and provides local cache of Prims. /// public class PrimManager { + private LocalPrimDb _localPrimDB; + public PrimManager() { + this._localPrimDB = new LocalPrimDb(); + + + //database test + /*PrimAsset prim = new PrimAsset(); + prim.Name="happy now"; + prim.Description= "test"; + prim.FullID = new LLUUID("00000000-0000-0000-0000-000000000008"); + this._localPrimDB.CreateNewPrimStorage(prim); + + PrimAsset prim1 = this._localPrimDB.GetPrimFromStroage( new LLUUID("00000000-0000-0000-0000-000000000008")); + Console.WriteLine("prim recieved : "+prim1.Name + " "+ prim1.Description); + */ + //this._localPrimDB.ReadWholedatabase(); } + } } diff --git a/SceneGraph.cs b/SceneGraph.cs index 1ff47176c5..547388422e 100644 --- a/SceneGraph.cs +++ b/SceneGraph.cs @@ -32,7 +32,7 @@ using System.Threading; using libsecondlife; using libsecondlife.Packets; -namespace OpenSimLite +namespace OpenSim { /// /// Manages prim and avatar sim positions and movements and updating clients @@ -45,7 +45,10 @@ namespace OpenSimLite private Server _server; private System.Text.Encoding _enc = System.Text.Encoding.ASCII; private libsecondlife.Packets.ObjectUpdatePacket.ObjectDataBlock _avatarTemplate; - + private int _objectCount=0; + private UpdateSender _updateSender; + private AgentManager _agentManager; + public NonBlockingQueue Commands; @@ -54,21 +57,112 @@ namespace OpenSimLite private object _sendTerrainSync = new object(); #endregion - public SceneGraph(Server server) + public SceneGraph(Server server, AgentManager agentManager) { _server = server; RootNode = new Node(); _physics = new PhysicsManager(this); Commands = new NonBlockingQueue(); Terrain = new Terrain(); - + _updateSender = new UpdateSender(_server, agentManager); + _agentManager = agentManager; //testing this.SetupTemplate("objectupate168.dat"); + _updateSender.Startup(); } public void Update() { + // run physics engine to update positions etc since last frame + // process command list + lock(this.Commands) //do we want to stop new commands being added while we process? + { + while(this.Commands.Count > 0) + { + UpdateCommand command = this.Commands.Dequeue(); + switch(command.CommandType) + { + case 1: + break; + default: + break; + } + } + } + + // check to see if any new avatars have joined since last frame + //if so send data to clients. + lock(this.RootNode) + { + for (int i = 0; i < this.RootNode.ChildrenCount; i++) + { + //for now we will limit avatars to being a child of the rootnode + if(this.RootNode.GetChild(i).SceneType == 1) //check it is a avatar node + { + AvatarData avatar =(AvatarData) this.RootNode.GetChild(i); + int updatemask = avatar.UpdateFlag & (128); + if(updatemask == 128) //is a new avatar? + { + this.SendAvatarDataToAll(avatar); + + //should send a avatar appearance to other clients except the avatar's owner + + //and send complete scene update to the new avatar's owner + this.SendCompleteSceneTo(avatar); + + //reset new avatar flag + //avatar.UpdateFlag -= 128; + } + } + } + } + + //send updates to clients + //might be better to do these updates reverse to how is done here + // ie.. loop through the avatars and find objects /other avatars in their range/vision + //instead of looping through all objects/avatars and then finding avatars in range + //but that would mean looping through all objects/avatar for each avatar, + //rather than looping through just the avatars for each object/avatar + lock(this.RootNode) + { + for (int i = 0; i < this.RootNode.ChildrenCount; i++) + { + if(this.RootNode.GetChild(i).SceneType == 1) //check it is a avatar node + { + AvatarData avatar =(AvatarData) this.RootNode.GetChild(i); + int updatemask = avatar.UpdateFlag & (1); + if(updatemask == 1) + { + //avatar has changed velocity + //check what avatars are in range and add to their update lists + //but for now we will say all avatars are in range + for (int n = 0; n < this.RootNode.ChildrenCount; n++) + { + if(this.RootNode.GetChild(n).SceneType == 1) //check it is a avatar node + { + AvatarData avatar2 =(AvatarData) this.RootNode.GetChild(i); + int newmask = avatar2.UpdateFlag & (128); + if(newmask != 128) //is a new avatar? + { + //no its not so let add to its updatelist + avatar2.TerseUpdateList.Add(this.CreateTerseBlock(avatar)); + } + } + } + } + } + } + } + + //now reset all update flags + lock(this.RootNode) + { + for (int i = 0; i < this.RootNode.ChildrenCount; i++) + { + this.RootNode.GetChild(i).UpdateFlag = 0; + } + } } #region send terrain data @@ -80,13 +174,15 @@ namespace OpenSimLite { lock(this._sendTerrainSync) { - string data_path = System.AppDomain.CurrentDomain.BaseDirectory + @"\layer_data\"; + string data_path = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory ,"layer_data" ); //send layerdata LayerDataPacket layerpack = new LayerDataPacket(); layerpack.LayerID.Type = 76; - this.SendLayerData(userInfo, layerpack, data_path+@"layerdata0.dat"); + this.SendLayerData(userInfo, layerpack, Path.Combine(data_path,"layerdata0.dat")); Console.WriteLine("Sent terrain data"); + + //test this.SendAvatarData(userInfo); } } @@ -112,6 +208,32 @@ namespace OpenSimLite } #endregion + public void AgentCompletingMove(NetworkInfo userInfo) + { + libsecondlife.Packets.AgentMovementCompletePacket mov = new AgentMovementCompletePacket(); + mov.AgentData.SessionID = userInfo.User.SessionID; + mov.AgentData.AgentID = userInfo.User.AgentID; + mov.Data.RegionHandle = Globals.Instance.RegionHandle; + mov.Data.Timestamp = 1169838966; + mov.Data.Position = new LLVector3(100f, 100f, 22f); + mov.Data.LookAt = new LLVector3(0.99f, 0.042f, 0); + _server.SendPacket(mov, true, userInfo); + } + + public void AddNewAvatar(AvatarData avatar) + { + lock(this.RootNode) + { + avatar.SceneName = "Avatar" + this._objectCount.ToString("00000"); + this._objectCount++; + this.RootNode.AddChild(avatar); + } + avatar.UpdateFlag = 128; + + //add to new clients list? + + } + #region testing //test only private void SendAvatarData(NetworkInfo userInfo) @@ -132,7 +254,7 @@ namespace OpenSimLite //userInfo.User.FullName = "FirstName STRING RW SV " + userInfo.first_name + "\nLastName STRING RW SV " + userInfo.last_name + " \0"; libsecondlife.LLVector3 pos2 = new LLVector3(100f, 100.0f, 22.0f); - byte[] pb = pos2.GetBytes(); + byte[] pb = pos2.GetBytes(); Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); //this._localNumber++; @@ -142,7 +264,7 @@ namespace OpenSimLite //test only private void SetupTemplate(string name) { - + //should be replaced with completely code generated packets int i = 0; FileInfo fInfo = new FileInfo(name); long numBytes = fInfo.Length; @@ -168,7 +290,44 @@ namespace OpenSimLite } #endregion + private void SendAvatarDataToAll(AvatarData avatar) + { + ObjectUpdatePacket objupdate = new ObjectUpdatePacket(); + objupdate.RegionData.RegionHandle = Globals.Instance.RegionHandle; + objupdate.RegionData.TimeDilation = 0; + objupdate.ObjectData = new libsecondlife.Packets.ObjectUpdatePacket.ObjectDataBlock[1]; + + objupdate.ObjectData[0] = _avatarTemplate; + objupdate.ObjectData[0].ID = avatar.LocalID; + objupdate.ObjectData[0].FullID = avatar.NetInfo.User.AgentID; + objupdate.ObjectData[0].NameValue = _enc.GetBytes("FirstName STRING RW SV " + avatar.NetInfo.User.FirstName + "\nLastName STRING RW SV " + avatar.NetInfo.User.LastName + " \0"); + + libsecondlife.LLVector3 pos2 = new LLVector3(100f, 100.0f, 22.0f); + byte[] pb = pos2.GetBytes(); + Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); + + SendInfo send = new SendInfo(); + send.Incr = true; + send.NetInfo = avatar.NetInfo; + send.Packet = objupdate; + send.SentTo = 1; //to all clients + this._updateSender.SendList.Enqueue(send); + } + public void SendCompleteSceneTo(AvatarData avatar) + { + + } + + public ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateTerseBlock(AvatarData avatar) + { + return(null); + } + + public void SendAvatarAppearanceToAllExcept(AvatarData avatar) + { + + } } //any need for separate nodes and sceneobjects? @@ -176,7 +335,12 @@ namespace OpenSimLite public class Node { private List _children; - private List _attached; + //private List _attached; + public byte SceneType; + public string SceneName; + public LLVector3 Position; + public LLVector3 Velocity = new LLVector3(0,0,0); + public byte UpdateFlag; public List ChildNodes { @@ -186,6 +350,14 @@ namespace OpenSimLite } } + public int ChildrenCount + { + get + { + return(_children.Count); + } + } + /* public List AttachedObjexts { get @@ -193,13 +365,13 @@ namespace OpenSimLite return(_attached); } } - + */ public Node() { _children = new List(); - _attached = new List(); + //_attached = new List(); } - + /* /// /// /// @@ -252,6 +424,7 @@ namespace OpenSimLite } return(rValue); } + */ /// /// @@ -289,15 +462,18 @@ namespace OpenSimLite } } + /* public class SceneObject { public byte SceneType; + public string SceneName; public SceneObject() { } - } + }*/ + public class Terrain { @@ -326,7 +502,7 @@ namespace OpenSimLite public class UpdateCommand { public byte CommandType; - public SceneObject SObject; + public Node SObject; public LLVector3 Position; public LLVector3 Velocity; public LLQuaternion Rotation; @@ -341,29 +517,63 @@ namespace OpenSimLite { public BlockingQueue SendList; private Thread mthread; + private Server _server; + private AgentManager _agentManager; - public UpdateSender() + public UpdateSender(Server server, AgentManager agentManager) { SendList = new BlockingQueue(); + _server = server; + _agentManager = agentManager; } public void Startup() { mthread = new Thread(new System.Threading.ThreadStart(RunSender)); + mthread.IsBackground = true; mthread.Start(); } private void RunSender() { - + //process SendList and send packets to clients + try + { + for(;;) + { + SendInfo sendInfo; + sendInfo = this.SendList.Dequeue(); + + switch(sendInfo.SentTo) + { + case 0: + this._server.SendPacket(sendInfo.Packet, sendInfo.Incr, sendInfo.NetInfo); + break; + case 1: + this._agentManager.SendPacketToALL(sendInfo.Packet); + break; + case 2: + this._agentManager.SendPacketToAllExcept(sendInfo.Packet, sendInfo.NetInfo.User.AgentID); + break; + default: + break; + } + + } + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } } } public class SendInfo { public Packet Packet; - public bool Incr; + public bool Incr = true; public NetworkInfo NetInfo; + public byte SentTo = 0; // 0 just this client, 1 to all clients, 2 to all except this client. public SendInfo() { diff --git a/ScriptManager.cs b/ScriptManager.cs index 656fdd2de7..654249bb7c 100644 --- a/ScriptManager.cs +++ b/ScriptManager.cs @@ -27,7 +27,7 @@ using System; -namespace OpenSimLite +namespace OpenSim { /// /// Description of ScriptManager. @@ -39,10 +39,10 @@ namespace OpenSimLite } } - public interface ScriptPlugin + public interface IScriptPlugin { - ScriptObject ICompileScript(string script); - bool IStart(); + ScriptObject CompileScript(string script); + bool Start(); } public interface ScriptObject diff --git a/UserServer.cs b/UserServer.cs index f272ed2991..f6671438e9 100644 --- a/UserServer.cs +++ b/UserServer.cs @@ -26,17 +26,21 @@ */ using System; +using libsecondlife; +using System.Collections.Generic; -namespace OpenSimLite +namespace OpenSim { /// /// Handles connection to User Servers /// /// - public class UserServer + public class UserServer :IUserServer { + public List Sessions = new List(); //should change to something other than logon classes? public UserServer() { + Sessions = new List(); } private void Initialise() @@ -47,5 +51,46 @@ namespace OpenSimLite } } + + public AuthenticateResponse AuthenticateSession(LLUUID sessionID, LLUUID agentID, uint circuitCode) + { + //For Grid use: + //should check to see if it is a teleportation, if so then we should be expecting this session, agent. (?) + //if not check with User server/ login server that it is authorised. + + //but for now we are running local + AuthenticateResponse user = new AuthenticateResponse(); + + lock(this.Sessions) + { + + for(int i = 0; i < Sessions.Count; i++) + { + if((Sessions[i].Agent == agentID) && (Sessions[i].Session == sessionID)) + { + user.Authorised = true; + user.LogonInfo = Sessions[i]; + } + } + } + return(user); + } + } + + public interface IUserServer + { + AuthenticateResponse AuthenticateSession(LLUUID sessionID, LLUUID agentID, uint circuitCode); + } + + public class AuthenticateResponse + { + public bool Authorised; + public Logon LogonInfo; + + public AuthenticateResponse() + { + + } + } } diff --git a/Utility.cs b/Utility.cs index d657764e4f..1549f11006 100644 --- a/Utility.cs +++ b/Utility.cs @@ -27,10 +27,12 @@ using System; using System.Text; +using System.Collections.Generic; +using System.Threading; using System.Text.RegularExpressions; using System.Security.Cryptography; -namespace OpenSimLite +namespace OpenSim { /// /// Description of Utility. @@ -54,4 +56,65 @@ namespace OpenSimLite return Regex.Replace(BitConverter.ToString(encodedBytes), "-", "").ToLower(); } } + + public class BlockingQueue< T > + { + private Queue< T > _queue = new Queue< T >(); + private object _queueSync = new object(); + + public void Enqueue(T value) + { + lock(_queueSync) + { + _queue.Enqueue(value); + Monitor.Pulse(_queueSync); + } + } + + public T Dequeue() + { + lock(_queueSync) + { + if( _queue.Count < 1) + Monitor.Wait(_queueSync); + + return _queue.Dequeue(); + } + } + } + + public class NonBlockingQueue< T > + { + private Queue< T > _queue = new Queue< T >(); + private object _queueSync = new object(); + + public void Enqueue(T value) + { + lock(_queueSync) + { + _queue.Enqueue(value); + } + } + + public T Dequeue() + { + T rValue = default(T); + lock(_queueSync) + { + if( _queue.Count > 0) + { + rValue = _queue.Dequeue(); + } + } + return rValue; + } + + public int Count + { + get + { + return(_queue.Count); + } + } + } } diff --git a/ViewerServer.cs b/ViewerServer.cs index d39f459b84..9a689906d1 100644 --- a/ViewerServer.cs +++ b/ViewerServer.cs @@ -35,7 +35,7 @@ using System.Net; using System.Net.Sockets; using System.Timers; -namespace OpenSimLite +namespace OpenSim { /// /// Manages Viewer connections @@ -55,7 +55,7 @@ namespace OpenSimLite } }*/ - //for now though, we will use a slightly adapted version of the server + //for now though, we will use a adapted version of the server // class from version 0.1 public class Server { @@ -66,6 +66,7 @@ namespace OpenSimLite /// The Region class that this Simulator wraps // public Region Region; + private object _sendPacketSync = new object(); /// /// Used internally to track sim disconnections, do not modify this /// variable @@ -116,13 +117,14 @@ namespace OpenSimLite private System.Timers.Timer AckTimer; private Server_Settings Settings=new Server_Settings(); public ArrayList User_agents=new ArrayList(); + private IUserServer _userServer; /// /// /// - public Server() + public Server(IUserServer userServer) { - + this._userServer = userServer; } /// @@ -207,110 +209,113 @@ namespace OpenSimLite /// Increment sequence number? public void SendPacket(Packet packet, bool incrementSequence, NetworkInfo User_info) { - byte[] buffer; - int bytes; - - if (!connected && packet.Type != PacketType.UseCircuitCode) + lock(this._sendPacketSync) { - // Client.Log("Trying to send a " + packet.Type.ToString() + " packet when the socket is closed", - // Helpers.LogLevel.Info); + byte[] buffer; + int bytes; - return; - } - - if (packet.Header.AckList.Length > 0) - { - // Scrub any appended ACKs since all of the ACK handling is done here - packet.Header.AckList = new uint[0]; - } - packet.Header.AppendedAcks = false; - - // Keep track of when this packet was sent out - packet.TickCount = Environment.TickCount; - - if (incrementSequence) - { - // Set the sequence number - lock (SequenceLock) + if (!connected && packet.Type != PacketType.UseCircuitCode) { - if (Sequence > Settings.MAX_SEQUENCE) - Sequence = 1; - else - Sequence++; - packet.Header.Sequence = Sequence; + // Client.Log("Trying to send a " + packet.Type.ToString() + " packet when the socket is closed", + // Helpers.LogLevel.Info); + + return; } - if (packet.Header.Reliable) + if (packet.Header.AckList.Length > 0) { - lock (User_info.NeedAck) + // Scrub any appended ACKs since all of the ACK handling is done here + packet.Header.AckList = new uint[0]; + } + packet.Header.AppendedAcks = false; + + // Keep track of when this packet was sent out + packet.TickCount = Environment.TickCount; + + if (incrementSequence) + { + // Set the sequence number + lock (SequenceLock) { - if (!User_info.NeedAck.ContainsKey(packet.Header.Sequence)) - { - User_info.NeedAck.Add(packet.Header.Sequence, packet); - } + if (Sequence > Settings.MAX_SEQUENCE) + Sequence = 1; else - { - // Client.Log("Attempted to add a duplicate sequence number (" + - // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " + - // packet.Type.ToString(), Helpers.LogLevel.Warning); - } + Sequence++; + packet.Header.Sequence = Sequence; } - // Don't append ACKs to resent packets, in case that's what was causing the - // delivery to fail - if (!packet.Header.Resent) + if (packet.Header.Reliable) { - // Append any ACKs that need to be sent out to this packet - lock (User_info.PendingAcks) + lock (User_info.NeedAck) { - if (User_info.PendingAcks.Count > 0 && User_info.PendingAcks.Count < Settings.MAX_APPENDED_ACKS && - packet.Type != PacketType.PacketAck && - packet.Type != PacketType.LogoutRequest) + if (!User_info.NeedAck.ContainsKey(packet.Header.Sequence)) { - packet.Header.AckList = new uint[User_info.PendingAcks.Count]; - int i = 0; - - foreach (uint ack in User_info.PendingAcks.Values) - { - packet.Header.AckList[i] = ack; - i++; - } + User_info.NeedAck.Add(packet.Header.Sequence, packet); + } + else + { + // Client.Log("Attempted to add a duplicate sequence number (" + + // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " + + // packet.Type.ToString(), Helpers.LogLevel.Warning); + } + } - User_info.PendingAcks.Clear(); - packet.Header.AppendedAcks = true; + // Don't append ACKs to resent packets, in case that's what was causing the + // delivery to fail + if (!packet.Header.Resent) + { + // Append any ACKs that need to be sent out to this packet + lock (User_info.PendingAcks) + { + if (User_info.PendingAcks.Count > 0 && User_info.PendingAcks.Count < Settings.MAX_APPENDED_ACKS && + packet.Type != PacketType.PacketAck && + packet.Type != PacketType.LogoutRequest) + { + packet.Header.AckList = new uint[User_info.PendingAcks.Count]; + int i = 0; + + foreach (uint ack in User_info.PendingAcks.Values) + { + packet.Header.AckList[i] = ack; + i++; + } + + User_info.PendingAcks.Clear(); + packet.Header.AppendedAcks = true; + } } } } } - } - // Serialize the packet - buffer = packet.ToBytes(); - bytes = buffer.Length; + // Serialize the packet + buffer = packet.ToBytes(); + bytes = buffer.Length; - try - { - // Zerocode if needed - if (packet.Header.Zerocoded) + try { - lock (ZeroOutBuffer) + // Zerocode if needed + if (packet.Header.Zerocoded) { - bytes = Helpers.ZeroEncode(buffer, bytes, ZeroOutBuffer); - Connection.SendTo(ZeroOutBuffer, bytes, SocketFlags.None,User_info.endpoint); + lock (ZeroOutBuffer) + { + bytes = Helpers.ZeroEncode(buffer, bytes, ZeroOutBuffer); + Connection.SendTo(ZeroOutBuffer, bytes, SocketFlags.None,User_info.endpoint); + } + } + else + { + + Connection.SendTo(buffer, bytes, SocketFlags.None,User_info.endpoint); } } - else + catch (SocketException) { - - Connection.SendTo(buffer, bytes, SocketFlags.None,User_info.endpoint); - } - } - catch (SocketException) - { - //Client.Log("Tried to send a " + packet.Type.ToString() + " on a closed socket", - // Helpers.LogLevel.Warning); + //Client.Log("Tried to send a " + packet.Type.ToString() + " on a closed socket", + // Helpers.LogLevel.Warning); - Disconnect(); + Disconnect(); + } } } @@ -425,6 +430,23 @@ namespace OpenSimLite { //new connection UseCircuitCodePacket cir_pack=(UseCircuitCodePacket)packet; + //should check that this session/circuit is authorised + AuthenticateResponse sessionInfo = this._userServer.AuthenticateSession(cir_pack.CircuitCode.SessionID, cir_pack.CircuitCode.ID, cir_pack.CircuitCode.Code); + if(!sessionInfo.Authorised) + { + //session/circuit not authorised + //so do something about it + } + else + { + //is authorised so add the logon object to the incominglogin list + //should be a better way of doing this now the login server connects to the user server + // like passing the logon object straight to the ClientConnection + lock(Globals.Instance.IncomingLogins) + { + Globals.Instance.IncomingLogins.Add(sessionInfo.LogonInfo); + } + } NetworkInfo new_user=new NetworkInfo(); new_user.CircuitCode=cir_pack.CircuitCode.Code; new_user.User.AgentID=cir_pack.CircuitCode.ID;