2007-03-22 10:11:15 +00:00
/ *
Copyright ( c ) OpenSim project , http : //osgrid.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 < organization > 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 < copyright holder > ` ` 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 < copyright holder > 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 libsecondlife ;
using libsecondlife.Packets ;
2007-04-17 12:03:52 +00:00
using Nwc.XmlRpc ;
2007-03-22 10:11:15 +00:00
using System.Net ;
using System.Net.Sockets ;
using System.IO ;
using System.Threading ;
using System.Timers ;
using OpenSim.Framework.Interfaces ;
2007-04-25 13:03:48 +00:00
using OpenSim.Framework.Types ;
2007-03-22 10:11:15 +00:00
using OpenSim.Framework.Inventory ;
using OpenSim.Framework.Utilities ;
using OpenSim.world ;
using OpenSim.Assets ;
namespace OpenSim
{
2007-05-21 16:06:58 +00:00
public delegate bool PacketMethod ( ClientView simClient , Packet packet ) ;
2007-03-31 21:18:05 +00:00
2007-03-22 10:11:15 +00:00
/// <summary>
/// Handles new client connections
/// Constructor takes a single Packet and authenticates everything
/// </summary>
2007-05-21 16:06:58 +00:00
public partial class ClientView : ClientViewBase
2007-03-22 10:11:15 +00:00
{
2007-05-22 11:25:34 +00:00
protected static Dictionary < PacketType , PacketMethod > PacketHandlers = new Dictionary < PacketType , PacketMethod > ( ) ; //Global/static handlers for all clients
protected Dictionary < PacketType , PacketMethod > m_packetHandlers = new Dictionary < PacketType , PacketMethod > ( ) ; //local handlers for this instance
2007-03-22 10:11:15 +00:00
public LLUUID AgentID ;
public LLUUID SessionID ;
public LLUUID SecureSessionID = LLUUID . Zero ;
2007-04-17 12:03:52 +00:00
public bool m_child ;
2007-03-22 10:11:15 +00:00
public world . Avatar ClientAvatar ;
private UseCircuitCodePacket cirpack ;
2007-04-17 01:38:20 +00:00
public Thread ClientThread ;
2007-04-17 12:03:52 +00:00
public LLVector3 startpos ;
2007-05-21 16:06:58 +00:00
2007-03-25 17:34:58 +00:00
private AgentAssetUpload UploadAssets ;
2007-03-22 10:11:15 +00:00
private LLUUID newAssetFolder = LLUUID . Zero ;
2007-03-30 15:51:38 +00:00
private bool debug = false ;
2007-03-27 21:42:14 +00:00
private World m_world ;
2007-05-21 16:06:58 +00:00
private Dictionary < uint , ClientView > m_clientThreads ;
2007-03-27 21:42:14 +00:00
private AssetCache m_assetCache ;
private IGridServer m_gridServer ;
2007-03-28 18:10:52 +00:00
private IUserServer m_userServer = null ;
2007-03-27 21:42:14 +00:00
private InventoryCache m_inventoryCache ;
2007-04-17 12:03:52 +00:00
public bool m_sandboxMode ;
2007-03-30 12:12:33 +00:00
private int cachedtextureserial = 0 ;
2007-04-17 12:03:52 +00:00
private RegionInfo m_regionData ;
2007-05-17 13:23:53 +00:00
protected AuthenticateSessionsBase m_authenticateSessionsHandler ;
2007-03-22 10:11:15 +00:00
2007-03-28 18:10:52 +00:00
public IUserServer UserServer
{
set
{
this . m_userServer = value ;
}
}
2007-05-21 16:06:58 +00:00
public ClientView ( EndPoint remoteEP , UseCircuitCodePacket initialcirpack , World world , Dictionary < uint , ClientView > clientThreads , AssetCache assetCache , IGridServer gridServer , OpenSimNetworkHandler application , InventoryCache inventoryCache , bool sandboxMode , bool child , RegionInfo regionDat , AuthenticateSessionsBase authenSessions )
2007-04-01 10:19:21 +00:00
{
m_world = world ;
m_clientThreads = clientThreads ;
m_assetCache = assetCache ;
m_gridServer = gridServer ;
2007-05-16 15:46:22 +00:00
m_networkServer = application ;
2007-04-01 10:19:21 +00:00
m_inventoryCache = inventoryCache ;
m_sandboxMode = sandboxMode ;
2007-04-17 12:03:52 +00:00
m_child = child ;
m_regionData = regionDat ;
2007-05-17 13:23:53 +00:00
m_authenticateSessionsHandler = authenSessions ;
2007-05-16 16:01:01 +00:00
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( OpenSim . Framework . Console . LogPriority . LOW , "OpenSimClient.cs - Started up new client thread to handle incoming request" ) ;
2007-04-01 10:19:21 +00:00
cirpack = initialcirpack ;
userEP = remoteEP ;
2007-05-16 18:11:09 +00:00
2007-05-17 14:37:57 +00:00
if ( m_gridServer . GetName ( ) = = "Remote" )
2007-04-17 12:03:52 +00:00
{
2007-05-19 18:32:01 +00:00
this . m_child = m_authenticateSessionsHandler . GetAgentChildStatus ( initialcirpack . CircuitCode . Code ) ;
2007-05-17 13:39:30 +00:00
this . startpos = m_authenticateSessionsHandler . GetPosition ( initialcirpack . CircuitCode . Code ) ;
2007-05-19 18:32:01 +00:00
//Console.WriteLine("start pos is " + this.startpos.X + " , " + this.startpos.Y + " , " + this.startpos.Z);
2007-04-17 12:03:52 +00:00
}
else
2007-05-17 14:37:57 +00:00
{
2007-04-22 04:49:12 +00:00
this . startpos = new LLVector3 ( 128 , 128 , m_world . Terrain [ ( int ) 128 , ( int ) 128 ] + 15.0f ) ; // new LLVector3(128.0f, 128.0f, 60f);
2007-05-17 14:37:57 +00:00
}
2007-04-01 10:19:21 +00:00
PacketQueue = new BlockingQueue < QueItem > ( ) ;
this . UploadAssets = new AgentAssetUpload ( this , m_assetCache , m_inventoryCache ) ;
AckTimer = new System . Timers . Timer ( 500 ) ;
AckTimer . Elapsed + = new ElapsedEventHandler ( AckTimer_Elapsed ) ;
AckTimer . Start ( ) ;
this . RegisterLocalPacketHandlers ( ) ;
ClientThread = new Thread ( new ThreadStart ( AuthUser ) ) ;
ClientThread . IsBackground = true ;
ClientThread . Start ( ) ;
}
2007-05-16 16:01:01 +00:00
# region Client Methods
2007-04-17 12:03:52 +00:00
public void UpgradeClient ( )
{
2007-05-16 16:01:01 +00:00
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( OpenSim . Framework . Console . LogPriority . LOW , "SimClient.cs:UpgradeClient() - upgrading child to full agent" ) ;
2007-04-17 12:03:52 +00:00
this . m_child = false ;
this . m_world . RemoveViewerAgent ( this ) ;
if ( ! this . m_sandboxMode )
{
2007-05-19 18:32:01 +00:00
this . startpos = m_authenticateSessionsHandler . GetPosition ( CircuitCode ) ;
m_authenticateSessionsHandler . UpdateAgentChildStatus ( CircuitCode , false ) ;
//Console.WriteLine("upgrade start pos is " + this.startpos.X + " , " + this.startpos.Y + " , " + this.startpos.Z);
2007-04-17 12:03:52 +00:00
}
this . InitNewClient ( ) ;
}
public void DowngradeClient ( )
{
2007-05-16 16:01:01 +00:00
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( OpenSim . Framework . Console . LogPriority . LOW , "SimClient.cs:UpgradeClient() - changing full agent to child" ) ;
2007-04-17 12:03:52 +00:00
this . m_child = true ;
this . m_world . RemoveViewerAgent ( this ) ;
this . m_world . AddViewerAgent ( this ) ;
}
public void KillClient ( )
{
KillObjectPacket kill = new KillObjectPacket ( ) ;
kill . ObjectData = new KillObjectPacket . ObjectDataBlock [ 1 ] ;
kill . ObjectData [ 0 ] = new KillObjectPacket . ObjectDataBlock ( ) ;
kill . ObjectData [ 0 ] . ID = this . ClientAvatar . localid ;
2007-05-21 16:06:58 +00:00
foreach ( ClientView client in m_clientThreads . Values )
2007-04-17 12:03:52 +00:00
{
client . OutPacket ( kill ) ;
}
if ( this . m_userServer ! = null )
{
this . m_inventoryCache . ClientLeaving ( this . AgentID , this . m_userServer ) ;
}
else
{
this . m_inventoryCache . ClientLeaving ( this . AgentID , null ) ;
}
m_world . RemoveViewerAgent ( this ) ;
m_clientThreads . Remove ( this . CircuitCode ) ;
2007-05-16 15:46:22 +00:00
m_networkServer . RemoveClientCircuit ( this . CircuitCode ) ;
2007-04-17 12:03:52 +00:00
this . ClientThread . Abort ( ) ;
}
2007-05-16 16:01:01 +00:00
# endregion
2007-04-17 12:03:52 +00:00
2007-05-16 16:01:01 +00:00
# region Packet Handling
2007-03-31 21:18:05 +00:00
public static bool AddPacketHandler ( PacketType packetType , PacketMethod handler )
{
bool result = false ;
lock ( PacketHandlers )
{
if ( ! PacketHandlers . ContainsKey ( packetType ) )
{
PacketHandlers . Add ( packetType , handler ) ;
result = true ;
}
}
return result ;
}
2007-04-01 10:19:21 +00:00
public bool AddLocalPacketHandler ( PacketType packetType , PacketMethod handler )
{
bool result = false ;
lock ( m_packetHandlers )
{
if ( ! m_packetHandlers . ContainsKey ( packetType ) )
{
m_packetHandlers . Add ( packetType , handler ) ;
result = true ;
}
}
return result ;
}
2007-03-31 21:18:05 +00:00
protected virtual bool ProcessPacketMethod ( Packet packet )
{
bool result = false ;
bool found = false ;
PacketMethod method ;
2007-04-01 10:19:21 +00:00
if ( m_packetHandlers . TryGetValue ( packet . Type , out method ) )
2007-03-31 21:18:05 +00:00
{
2007-04-01 10:19:21 +00:00
//there is a local handler for this packet type
result = method ( this , packet ) ;
2007-03-31 21:18:05 +00:00
}
2007-04-01 10:19:21 +00:00
else
2007-03-31 21:18:05 +00:00
{
2007-04-01 10:19:21 +00:00
//there is not a local handler so see if there is a Global handler
lock ( PacketHandlers )
{
found = PacketHandlers . TryGetValue ( packet . Type , out method ) ;
}
if ( found )
{
result = method ( this , packet ) ;
}
2007-03-31 21:18:05 +00:00
}
return result ;
}
2007-03-22 10:11:15 +00:00
protected virtual void ClientLoop ( )
{
2007-05-16 16:01:01 +00:00
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( OpenSim . Framework . Console . LogPriority . LOW , "OpenSimClient.cs:ClientLoop() - Entered loop" ) ;
2007-03-22 10:11:15 +00:00
while ( true )
{
QueItem nextPacket = PacketQueue . Dequeue ( ) ;
if ( nextPacket . Incoming )
{
//is a incoming packet
ProcessInPacket ( nextPacket . Packet ) ;
}
else
{
//is a out going packet
ProcessOutPacket ( nextPacket . Packet ) ;
}
}
}
2007-05-22 11:25:34 +00:00
# endregion
2007-03-22 10:11:15 +00:00
2007-05-16 16:01:01 +00:00
# region Setup
2007-03-22 10:11:15 +00:00
protected virtual void InitNewClient ( )
{
2007-05-16 16:01:01 +00:00
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( OpenSim . Framework . Console . LogPriority . LOW , "OpenSimClient.cs:InitNewClient() - Adding viewer agent to world" ) ;
2007-03-31 21:18:05 +00:00
2007-03-27 21:42:14 +00:00
m_world . AddViewerAgent ( this ) ;
world . Entity tempent = m_world . Entities [ this . AgentID ] ;
2007-03-31 21:18:05 +00:00
2007-03-22 10:11:15 +00:00
this . ClientAvatar = ( world . Avatar ) tempent ;
}
protected virtual void AuthUser ( )
{
2007-05-16 16:01:01 +00:00
// AuthenticateResponse sessionInfo = m_gridServer.AuthenticateSession(cirpack.CircuitCode.SessionID, cirpack.CircuitCode.ID, cirpack.CircuitCode.Code);
2007-05-16 15:46:22 +00:00
AuthenticateResponse sessionInfo = this . m_networkServer . AuthenticateSession ( cirpack . CircuitCode . SessionID , cirpack . CircuitCode . ID , cirpack . CircuitCode . Code ) ;
2007-03-22 10:11:15 +00:00
if ( ! sessionInfo . Authorised )
{
//session/circuit not authorised
2007-05-16 16:01:01 +00:00
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( OpenSim . Framework . Console . LogPriority . NORMAL , "OpenSimClient.cs:AuthUser() - New user request denied to " + userEP . ToString ( ) ) ;
2007-03-22 10:11:15 +00:00
ClientThread . Abort ( ) ;
}
else
{
2007-05-16 16:01:01 +00:00
OpenSim . Framework . Console . MainConsole . Instance . WriteLine ( OpenSim . Framework . Console . LogPriority . NORMAL , "OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP . ToString ( ) ) ;
2007-03-22 10:11:15 +00:00
//session is authorised
this . AgentID = cirpack . CircuitCode . ID ;
this . SessionID = cirpack . CircuitCode . SessionID ;
this . CircuitCode = cirpack . CircuitCode . Code ;
InitNewClient ( ) ; //shouldn't be called here as we might be a child agent and not want a full avatar
this . ClientAvatar . firstname = sessionInfo . LoginInfo . First ;
this . ClientAvatar . lastname = sessionInfo . LoginInfo . Last ;
if ( sessionInfo . LoginInfo . SecureSession ! = LLUUID . Zero )
{
this . SecureSessionID = sessionInfo . LoginInfo . SecureSession ;
}
// Create Inventory, currently only works for sandbox mode
2007-03-27 21:42:14 +00:00
if ( m_sandboxMode )
2007-03-22 10:11:15 +00:00
{
2007-05-16 15:46:22 +00:00
this . SetupInventory ( sessionInfo ) ;
}
ClientLoop ( ) ;
}
}
2007-05-16 16:01:01 +00:00
# endregion
2007-05-16 15:46:22 +00:00
2007-05-21 16:06:58 +00:00
protected override void KillThread ( )
{
this . ClientThread . Abort ( ) ;
}
#region World/Avatar To Viewer Methods
public void SendChatMessage ( byte [ ] message , byte type , LLVector3 fromPos , string fromName , LLUUID fromAgentID )
{
System . Text . Encoding enc = System . Text . Encoding . ASCII ;
libsecondlife . Packets . ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket ( ) ;
reply . ChatData . Audible = 1 ;
reply . ChatData . Message = message ;
reply . ChatData . ChatType = type ;
reply . ChatData . SourceType = 1 ;
reply . ChatData . Position = fromPos ;
reply . ChatData . FromName = enc . GetBytes ( fromName + "\0" ) ;
reply . ChatData . OwnerID = fromAgentID ;
reply . ChatData . SourceID = fromAgentID ;
this . OutPacket ( reply ) ;
}
2007-05-21 19:12:18 +00:00
public void SendAppearance ( AvatarWearable [ ] wearables )
{
AgentWearablesUpdatePacket aw = new AgentWearablesUpdatePacket ( ) ;
aw . AgentData . AgentID = this . AgentID ;
aw . AgentData . SerialNum = 0 ;
aw . AgentData . SessionID = this . SessionID ;
aw . WearableData = new AgentWearablesUpdatePacket . WearableDataBlock [ 13 ] ;
AgentWearablesUpdatePacket . WearableDataBlock awb ;
for ( int i = 0 ; i < wearables . Length ; i + + )
{
awb = new AgentWearablesUpdatePacket . WearableDataBlock ( ) ;
awb . WearableType = ( byte ) i ;
awb . AssetID = wearables [ i ] . AssetID ;
awb . ItemID = wearables [ i ] . ItemID ;
aw . WearableData [ i ] = awb ;
}
this . OutPacket ( aw ) ;
}
2007-05-21 16:06:58 +00:00
# endregion
2007-05-16 15:46:22 +00:00
#region Inventory Creation
2007-05-16 16:01:01 +00:00
private void SetupInventory ( AuthenticateResponse sessionInfo )
2007-05-16 15:46:22 +00:00
{
AgentInventory inventory = null ;
if ( sessionInfo . LoginInfo . InventoryFolder ! = null )
{
inventory = this . CreateInventory ( sessionInfo . LoginInfo . InventoryFolder ) ;
if ( sessionInfo . LoginInfo . BaseFolder ! = null )
{
if ( ! inventory . HasFolder ( sessionInfo . LoginInfo . BaseFolder ) )
2007-03-22 10:11:15 +00:00
{
2007-05-16 15:46:22 +00:00
m_inventoryCache . CreateNewInventoryFolder ( this , sessionInfo . LoginInfo . BaseFolder ) ;
}
this . newAssetFolder = sessionInfo . LoginInfo . BaseFolder ;
AssetBase [ ] inventorySet = m_assetCache . CreateNewInventorySet ( this . AgentID ) ;
if ( inventorySet ! = null )
{
for ( int i = 0 ; i < inventorySet . Length ; i + + )
2007-03-22 10:11:15 +00:00
{
2007-05-16 15:46:22 +00:00
if ( inventorySet [ i ] ! = null )
2007-03-22 10:11:15 +00:00
{
2007-05-16 15:46:22 +00:00
m_inventoryCache . AddNewInventoryItem ( this , sessionInfo . LoginInfo . BaseFolder , inventorySet [ i ] ) ;
2007-03-22 10:11:15 +00:00
}
}
}
}
}
}
2007-03-28 18:10:52 +00:00
private AgentInventory CreateInventory ( LLUUID baseFolder )
2007-03-22 10:11:15 +00:00
{
2007-03-28 18:10:52 +00:00
AgentInventory inventory = null ;
if ( this . m_userServer ! = null )
{
// a user server is set so request the inventory from it
2007-03-29 17:04:24 +00:00
Console . WriteLine ( "getting inventory from user server" ) ;
2007-03-28 18:10:52 +00:00
inventory = m_inventoryCache . FetchAgentsInventory ( this . AgentID , m_userServer ) ;
}
else
{
inventory = new AgentInventory ( ) ;
inventory . AgentID = this . AgentID ;
inventory . CreateRootFolder ( this . AgentID , false ) ;
m_inventoryCache . AddNewAgentsInventory ( inventory ) ;
m_inventoryCache . CreateNewInventoryFolder ( this , baseFolder ) ;
}
return inventory ;
2007-03-22 10:11:15 +00:00
}
2007-03-30 11:09:51 +00:00
private void CreateInventoryItem ( CreateInventoryItemPacket packet )
{
2007-05-11 21:03:11 +00:00
if ( ! ( packet . InventoryBlock . Type = = 3 | | packet . InventoryBlock . Type = = 7 ) )
{
System . Console . WriteLine ( "Attempted to create " + Util . FieldToString ( packet . InventoryBlock . Name ) + " in inventory. Unsupported type" ) ;
return ;
}
//lets try this out with creating a notecard
AssetBase asset = new AssetBase ( ) ;
asset . Name = Util . FieldToString ( packet . InventoryBlock . Name ) ;
asset . Description = Util . FieldToString ( packet . InventoryBlock . Description ) ;
asset . InvType = packet . InventoryBlock . InvType ;
asset . Type = packet . InventoryBlock . Type ;
asset . FullID = LLUUID . Random ( ) ;
switch ( packet . InventoryBlock . Type )
2007-03-30 11:09:51 +00:00
{
2007-05-11 21:03:11 +00:00
case 7 : // Notecard
asset . Data = new byte [ 0 ] ;
break ;
case 3 : // Landmark
String content ;
2007-05-13 12:25:08 +00:00
content = "Landmark version 2\n" ;
2007-05-11 21:03:11 +00:00
content + = "region_id " + m_regionData . SimUUID + "\n" ;
String strPos = String . Format ( "%.2f %.2f %.2f>" ,
this . ClientAvatar . Pos . X ,
this . ClientAvatar . Pos . Y ,
this . ClientAvatar . Pos . Z ) ;
content + = "local_pos " + strPos + "\n" ;
asset . Data = ( new System . Text . ASCIIEncoding ( ) ) . GetBytes ( content ) ;
break ;
default :
break ;
2007-03-30 11:09:51 +00:00
}
2007-05-11 21:03:11 +00:00
m_assetCache . AddAsset ( asset ) ;
m_inventoryCache . AddNewInventoryItem ( this , packet . InventoryBlock . FolderID , asset ) ;
2007-03-30 11:09:51 +00:00
}
2007-05-16 15:46:22 +00:00
# endregion
2007-05-15 21:33:03 +00:00
2007-03-22 10:11:15 +00:00
}
}