aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/OpenSim.RegionServer/Client
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/OpenSim.RegionServer/Client')
-rw-r--r--OpenSim/OpenSim.RegionServer/Client/ClientView.Grid.cs192
-rw-r--r--OpenSim/OpenSim.RegionServer/Client/ClientView.PacketHandlers.cs196
-rw-r--r--OpenSim/OpenSim.RegionServer/Client/ClientView.ProcessPackets.cs519
-rw-r--r--OpenSim/OpenSim.RegionServer/Client/ClientView.cs459
-rw-r--r--OpenSim/OpenSim.RegionServer/Client/ClientViewBase.cs326
5 files changed, 1692 insertions, 0 deletions
diff --git a/OpenSim/OpenSim.RegionServer/Client/ClientView.Grid.cs b/OpenSim/OpenSim.RegionServer/Client/ClientView.Grid.cs
new file mode 100644
index 0000000..514435a
--- /dev/null
+++ b/OpenSim/OpenSim.RegionServer/Client/ClientView.Grid.cs
@@ -0,0 +1,192 @@
1/*
2* Copyright (c) Contributors, http://www.openmetaverse.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using libsecondlife;
32using libsecondlife.Packets;
33using Nwc.XmlRpc;
34using System.Net;
35using System.Net.Sockets;
36using System.IO;
37using System.Threading;
38using System.Timers;
39using OpenSim.Framework.Interfaces;
40using OpenSim.Framework.Types;
41using OpenSim.Framework.Inventory;
42using OpenSim.Framework.Utilities;
43using OpenSim.RegionServer.Simulator;
44using OpenSim.RegionServer.Assets;
45using OpenSim.Framework.Console;
46
47namespace OpenSim.RegionServer.Client
48{
49 public partial class ClientView
50 {
51
52 public void EnableNeighbours()
53 {
54 if ((this.m_gridServer.GetName() == "Remote") && (!this.m_child))
55 {
56 Hashtable SimParams;
57 ArrayList SendParams;
58 XmlRpcRequest GridReq;
59 XmlRpcResponse GridResp;
60 List<Packet> enablePackets = new List<Packet>();
61
62 RemoteGridBase gridServer = (RemoteGridBase)this.m_gridServer;
63
64 foreach (Hashtable neighbour in gridServer.neighbours)
65 {
66 try
67 {
68 string neighbourIPStr = (string)neighbour["sim_ip"];
69 System.Net.IPAddress neighbourIP = System.Net.IPAddress.Parse(neighbourIPStr);
70 ushort neighbourPort = (ushort)Convert.ToInt32(neighbour["sim_port"]);
71 string reqUrl = "http://" + neighbourIPStr + ":" + neighbourPort.ToString();
72
73 MainConsole.Instance.Verbose("Requesting " + reqUrl);
74
75 SimParams = new Hashtable();
76 SimParams["session_id"] = this.SessionID.ToString();
77 SimParams["secure_session_id"] = this.SecureSessionID.ToString();
78 SimParams["firstname"] = this.ClientAvatar.firstname;
79 SimParams["lastname"] = this.ClientAvatar.lastname;
80 SimParams["agent_id"] = this.AgentID.ToString();
81 SimParams["circuit_code"] = (Int32)this.CircuitCode;
82 SimParams["child_agent"] = "1";
83 SendParams = new ArrayList();
84 SendParams.Add(SimParams);
85
86 GridReq = new XmlRpcRequest("expect_user", SendParams);
87 GridResp = GridReq.Send(reqUrl, 3000);
88 EnableSimulatorPacket enablesimpacket = new EnableSimulatorPacket();
89 enablesimpacket.SimulatorInfo = new EnableSimulatorPacket.SimulatorInfoBlock();
90 enablesimpacket.SimulatorInfo.Handle = Helpers.UIntsToLong((uint)(Convert.ToInt32(neighbour["region_locx"]) * 256), (uint)(Convert.ToInt32(neighbour["region_locy"]) * 256));
91
92
93 byte[] byteIP = neighbourIP.GetAddressBytes();
94 enablesimpacket.SimulatorInfo.IP = (uint)byteIP[3] << 24;
95 enablesimpacket.SimulatorInfo.IP += (uint)byteIP[2] << 16;
96 enablesimpacket.SimulatorInfo.IP += (uint)byteIP[1] << 8;
97 enablesimpacket.SimulatorInfo.IP += (uint)byteIP[0];
98 enablesimpacket.SimulatorInfo.Port = neighbourPort;
99 enablePackets.Add(enablesimpacket);
100 }
101 catch (Exception e)
102 {
103 MainConsole.Instance.Notice("Could not connect to neighbour " + neighbour["sim_ip"] + ":" + neighbour["sim_port"] + ", continuing.");
104 }
105 }
106 Thread.Sleep(3000);
107 foreach (Packet enable in enablePackets)
108 {
109 this.OutPacket(enable);
110 }
111 enablePackets.Clear();
112
113 }
114 }
115
116 public void CrossSimBorder(LLVector3 avatarpos)
117 { // VERY VERY BASIC
118
119 LLVector3 newpos = avatarpos;
120 uint neighbourx = this.m_regionData.RegionLocX;
121 uint neighboury = this.m_regionData.RegionLocY;
122
123 if (avatarpos.X < 0)
124 {
125 neighbourx -= 1;
126 newpos.X = 254;
127 }
128 if (avatarpos.X > 255)
129 {
130 neighbourx += 1;
131 newpos.X = 1;
132 }
133 if (avatarpos.Y < 0)
134 {
135 neighboury -= 1;
136 newpos.Y = 254;
137 }
138 if (avatarpos.Y > 255)
139 {
140 neighboury += 1;
141 newpos.Y = 1;
142 }
143 MainConsole.Instance.Notice("SimClient.cs:CrossSimBorder() - Crossing border to neighbouring sim at [" + neighbourx.ToString() + "," + neighboury.ToString() + "]");
144
145 Hashtable SimParams;
146 ArrayList SendParams;
147 XmlRpcRequest GridReq;
148 XmlRpcResponse GridResp;
149 foreach (Hashtable borderingSim in ((RemoteGridBase)m_gridServer).neighbours)
150 {
151 if (((string)borderingSim["region_locx"]).Equals(neighbourx.ToString()) && ((string)borderingSim["region_locy"]).Equals(neighboury.ToString()))
152 {
153 SimParams = new Hashtable();
154 SimParams["firstname"] = this.ClientAvatar.firstname;
155 SimParams["lastname"] = this.ClientAvatar.lastname;
156 SimParams["circuit_code"] = this.CircuitCode.ToString();
157 SimParams["pos_x"] = newpos.X.ToString();
158 SimParams["pos_y"] = newpos.Y.ToString();
159 SimParams["pos_z"] = newpos.Z.ToString();
160 SendParams = new ArrayList();
161 SendParams.Add(SimParams);
162
163 GridReq = new XmlRpcRequest("agent_crossing", SendParams);
164 GridResp = GridReq.Send("http://" + borderingSim["sim_ip"] + ":" + borderingSim["sim_port"], 3000);
165
166 CrossedRegionPacket NewSimPack = new CrossedRegionPacket();
167 NewSimPack.AgentData = new CrossedRegionPacket.AgentDataBlock();
168 NewSimPack.AgentData.AgentID = this.AgentID;
169 NewSimPack.AgentData.SessionID = this.SessionID;
170 NewSimPack.Info = new CrossedRegionPacket.InfoBlock();
171 NewSimPack.Info.Position = newpos;
172 NewSimPack.Info.LookAt = new LLVector3(0.99f, 0.042f, 0); // copied from Avatar.cs - SHOULD BE DYNAMIC!!!!!!!!!!
173 NewSimPack.RegionData = new libsecondlife.Packets.CrossedRegionPacket.RegionDataBlock();
174 NewSimPack.RegionData.RegionHandle = Helpers.UIntsToLong((uint)(Convert.ToInt32(borderingSim["region_locx"]) * 256), (uint)(Convert.ToInt32(borderingSim["region_locy"]) * 256));
175 System.Net.IPAddress neighbourIP = System.Net.IPAddress.Parse((string)borderingSim["sim_ip"]);
176 byte[] byteIP = neighbourIP.GetAddressBytes();
177 NewSimPack.RegionData.SimIP = (uint)byteIP[3] << 24;
178 NewSimPack.RegionData.SimIP += (uint)byteIP[2] << 16;
179 NewSimPack.RegionData.SimIP += (uint)byteIP[1] << 8;
180 NewSimPack.RegionData.SimIP += (uint)byteIP[0];
181 NewSimPack.RegionData.SimPort = (ushort)Convert.ToInt32(borderingSim["sim_port"]);
182 NewSimPack.RegionData.SeedCapability = new byte[0];
183 lock (PacketQueue)
184 {
185 ProcessOutPacket(NewSimPack);
186 DowngradeClient();
187 }
188 }
189 }
190 }
191 }
192}
diff --git a/OpenSim/OpenSim.RegionServer/Client/ClientView.PacketHandlers.cs b/OpenSim/OpenSim.RegionServer/Client/ClientView.PacketHandlers.cs
new file mode 100644
index 0000000..4af0485
--- /dev/null
+++ b/OpenSim/OpenSim.RegionServer/Client/ClientView.PacketHandlers.cs
@@ -0,0 +1,196 @@
1/*
2* Copyright (c) Contributors, http://www.openmetaverse.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using libsecondlife;
32using libsecondlife.Packets;
33using Nwc.XmlRpc;
34using System.Net;
35using System.Net.Sockets;
36using System.IO;
37using System.Threading;
38using System.Timers;
39using OpenSim.Framework.Interfaces;
40using OpenSim.Framework.Types;
41using OpenSim.Framework.Inventory;
42using OpenSim.Framework.Utilities;
43using OpenSim.RegionServer.Simulator;
44using OpenSim.RegionServer.Assets;
45using OpenSim.Framework.Console;
46
47namespace OpenSim.RegionServer.Client
48{
49 public partial class ClientView
50 {
51 protected virtual void RegisterLocalPacketHandlers()
52 {
53 this.AddLocalPacketHandler(PacketType.LogoutRequest, this.Logout);
54 this.AddLocalPacketHandler(PacketType.AgentCachedTexture, this.AgentTextureCached);
55 this.AddLocalPacketHandler(PacketType.MultipleObjectUpdate, this.MultipleObjUpdate);
56 }
57
58 protected virtual bool Logout(ClientView simClient, Packet packet)
59 {
60 MainConsole.Instance.Notice("OpenSimClient.cs:ProcessInPacket() - Got a logout request");
61 //send reply to let the client logout
62 LogoutReplyPacket logReply = new LogoutReplyPacket();
63 logReply.AgentData.AgentID = this.AgentID;
64 logReply.AgentData.SessionID = this.SessionID;
65 logReply.InventoryData = new LogoutReplyPacket.InventoryDataBlock[1];
66 logReply.InventoryData[0] = new LogoutReplyPacket.InventoryDataBlock();
67 logReply.InventoryData[0].ItemID = LLUUID.Zero;
68 OutPacket(logReply);
69 //tell all clients to kill our object
70 KillObjectPacket kill = new KillObjectPacket();
71 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
72 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
73 kill.ObjectData[0].ID = this.ClientAvatar.localid;
74 foreach (ClientView client in m_clientThreads.Values)
75 {
76 client.OutPacket(kill);
77 }
78 if (this.m_userServer != null)
79 {
80 this.m_inventoryCache.ClientLeaving(this.AgentID, this.m_userServer);
81 }
82 else
83 {
84 this.m_inventoryCache.ClientLeaving(this.AgentID, null);
85 }
86
87 m_gridServer.LogoutSession(this.SessionID, this.AgentID, this.CircuitCode);
88 /*lock (m_world.Entities)
89 {
90 m_world.Entities.Remove(this.AgentID);
91 }*/
92 m_world.RemoveViewerAgent(this);
93 //need to do other cleaning up here too
94 m_clientThreads.Remove(this.CircuitCode);
95 m_networkServer.RemoveClientCircuit(this.CircuitCode);
96 this.ClientThread.Abort();
97 return true;
98 }
99
100 protected bool AgentTextureCached(ClientView simclient, Packet packet)
101 {
102 AgentCachedTexturePacket chechedtex = (AgentCachedTexturePacket)packet;
103 AgentCachedTextureResponsePacket cachedresp = new AgentCachedTextureResponsePacket();
104 cachedresp.AgentData.AgentID = this.AgentID;
105 cachedresp.AgentData.SessionID = this.SessionID;
106 cachedresp.AgentData.SerialNum = this.cachedtextureserial;
107 this.cachedtextureserial++;
108 cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[chechedtex.WearableData.Length];
109 for (int i = 0; i < chechedtex.WearableData.Length; i++)
110 {
111 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
112 cachedresp.WearableData[i].TextureIndex = chechedtex.WearableData[i].TextureIndex;
113 cachedresp.WearableData[i].TextureID = LLUUID.Zero;
114 cachedresp.WearableData[i].HostName = new byte[0];
115 }
116 this.OutPacket(cachedresp);
117 return true;
118 }
119
120 protected bool MultipleObjUpdate(ClientView simClient, Packet packet)
121 {
122 MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet;
123 for (int i = 0; i < multipleupdate.ObjectData.Length; i++)
124 {
125 if (multipleupdate.ObjectData[i].Type == 9) //change position
126 {
127 libsecondlife.LLVector3 pos = new LLVector3(multipleupdate.ObjectData[i].Data, 0);
128 OnUpdatePrimPosition(multipleupdate.ObjectData[i].ObjectLocalID, pos, this);
129 //should update stored position of the prim
130 }
131 else if (multipleupdate.ObjectData[i].Type == 10)//rotation
132 {
133 libsecondlife.LLQuaternion rot = new LLQuaternion(multipleupdate.ObjectData[i].Data, 0, true);
134 OnUpdatePrimRotation(multipleupdate.ObjectData[i].ObjectLocalID, rot, this);
135 }
136 else if (multipleupdate.ObjectData[i].Type == 13)//scale
137 {
138 libsecondlife.LLVector3 scale = new LLVector3(multipleupdate.ObjectData[i].Data, 12);
139 OnUpdatePrimScale(multipleupdate.ObjectData[i].ObjectLocalID, scale, this);
140 }
141 }
142 return true;
143 }
144
145 public void RequestMapLayer() //should be getting the map layer from the grid server
146 {
147 //send a layer covering the 800,800 - 1200,1200 area (should be covering the requested area)
148 MapLayerReplyPacket mapReply = new MapLayerReplyPacket();
149 mapReply.AgentData.AgentID = this.AgentID;
150 mapReply.AgentData.Flags = 0;
151 mapReply.LayerData = new MapLayerReplyPacket.LayerDataBlock[1];
152 mapReply.LayerData[0] = new MapLayerReplyPacket.LayerDataBlock();
153 mapReply.LayerData[0].Bottom = this.m_regionData.RegionLocY - 50;
154 mapReply.LayerData[0].Left = this.m_regionData.RegionLocX - 50;
155 mapReply.LayerData[0].Top = this.m_regionData.RegionLocY + 50;
156 mapReply.LayerData[0].Right = this.m_regionData.RegionLocX + 50;
157 mapReply.LayerData[0].ImageID = new LLUUID("00000000-0000-0000-9999-000000000005");
158 this.OutPacket(mapReply);
159 }
160
161 public void RequestMapBlocks(int minX, int minY, int maxX, int maxY)
162 {
163 IList simMapProfiles = m_gridServer.RequestMapBlocks(minX, minY, maxX, maxY);
164 int len;
165 if (simMapProfiles == null)
166 len = 0;
167 else
168 len = simMapProfiles.Count;
169
170 int i;
171 int mtu = 24; // Number of regions to send per packet. Will be more precise in future. ( TODO )
172 for (i = 0; i < len; i += mtu)
173 {
174 MapBlockReplyPacket mbReply = new MapBlockReplyPacket();
175 mbReply.AgentData.AgentID = this.AgentID;
176
177 mbReply.Data = new MapBlockReplyPacket.DataBlock[Math.Min(mtu, len - i)];
178 int j;
179 for (j = 0; (j < mtu) && ((i + j) < len); j++)
180 {
181 Hashtable mp = (Hashtable)simMapProfiles[j];
182 mbReply.Data[j] = new MapBlockReplyPacket.DataBlock();
183 mbReply.Data[j].Name = libsecondlife.Helpers.StringToField((string)mp["name"]);
184 mbReply.Data[j].Access = System.Convert.ToByte(mp["access"]);
185 mbReply.Data[j].Agents = System.Convert.ToByte(mp["agents"]);
186 mbReply.Data[j].MapImageID = new LLUUID((string)mp["map-image-id"]);
187 mbReply.Data[j].RegionFlags = System.Convert.ToUInt32(mp["region-flags"]);
188 mbReply.Data[j].WaterHeight = System.Convert.ToByte(mp["water-height"]);
189 mbReply.Data[j].X = System.Convert.ToUInt16(mp["x"]);
190 mbReply.Data[j].Y = System.Convert.ToUInt16(mp["y"]);
191 }
192 this.OutPacket(mbReply);
193 }
194 }
195 }
196}
diff --git a/OpenSim/OpenSim.RegionServer/Client/ClientView.ProcessPackets.cs b/OpenSim/OpenSim.RegionServer/Client/ClientView.ProcessPackets.cs
new file mode 100644
index 0000000..b07749e
--- /dev/null
+++ b/OpenSim/OpenSim.RegionServer/Client/ClientView.ProcessPackets.cs
@@ -0,0 +1,519 @@
1/*
2* Copyright (c) Contributors, http://www.openmetaverse.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using libsecondlife;
32using libsecondlife.Packets;
33using Nwc.XmlRpc;
34using System.Net;
35using System.Net.Sockets;
36using System.IO;
37using System.Threading;
38using System.Timers;
39using OpenSim.Framework.Interfaces;
40using OpenSim.Framework.Types;
41using OpenSim.Framework.Inventory;
42using OpenSim.Framework.Utilities;
43using OpenSim.RegionServer.Simulator;
44using OpenSim.RegionServer.Assets;
45using OpenSim.Framework.Console;
46
47namespace OpenSim.RegionServer.Client
48{
49 public partial class ClientView
50 {
51 public delegate void GenericCall(ClientView remoteClient);
52 public delegate void GenericCall2();
53 public delegate void GenericCall3(Packet packet); // really don't want to be passing packets in these events, so this is very temporary.
54 public delegate void GenericCall4(Packet packet, ClientView remoteClient);
55 public delegate void UpdateShape(uint localID, ObjectShapePacket.ObjectDataBlock shapeBlock);
56 public delegate void ObjectSelect(uint localID, ClientView remoteClient);
57 public delegate void UpdatePrimFlags(uint localID, Packet packet, ClientView remoteClient);
58 public delegate void UpdatePrimTexture(uint localID, byte[] texture, ClientView remoteClient);
59 public delegate void UpdatePrimVector(uint localID, LLVector3 pos, ClientView remoteClient);
60 public delegate void UpdatePrimRotation(uint localID, LLQuaternion rot, ClientView remoteClient);
61 public delegate void StatusChange(bool status);
62
63
64 public event ChatFromViewer OnChatFromViewer;
65 public event RezObject OnRezObject;
66 public event GenericCall4 OnDeRezObject;
67 public event ModifyTerrain OnModifyTerrain;
68 public event GenericCall OnRegionHandShakeReply;
69 public event GenericCall OnRequestWearables;
70 public event SetAppearance OnSetAppearance;
71 public event GenericCall2 OnCompleteMovementToRegion;
72 public event GenericCall3 OnAgentUpdate;
73 public event StartAnim OnStartAnim;
74 public event GenericCall OnRequestAvatarsData;
75 public event LinkObjects OnLinkObjects;
76 public event GenericCall4 OnAddPrim;
77 public event UpdateShape OnUpdatePrimShape;
78 public event ObjectSelect OnObjectSelect;
79 public event UpdatePrimFlags OnUpdatePrimFlags;
80 public event UpdatePrimTexture OnUpdatePrimTexture;
81 public event UpdatePrimVector OnUpdatePrimPosition;
82 public event UpdatePrimRotation OnUpdatePrimRotation;
83 public event UpdatePrimVector OnUpdatePrimScale;
84 public event StatusChange OnChildAgentStatus;
85
86 public event ParcelPropertiesRequest OnParcelPropertiesRequest;
87 public event ParcelDivideRequest OnParcelDivideRequest;
88 public event ParcelJoinRequest OnParcelJoinRequest;
89 public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest;
90
91 protected override void ProcessInPacket(Packet Pack)
92 {
93 ack_pack(Pack);
94 debug = true;
95 if (debug)
96 {
97 if (Pack.Type != PacketType.AgentUpdate)
98 {
99 Console.WriteLine("IN: " + Pack.Type.ToString());
100 }
101 }
102
103
104 if (this.ProcessPacketMethod(Pack))
105 {
106 //there is a handler registered that handled this packet type
107 return;
108 }
109 else
110 {
111 System.Text.Encoding _enc = System.Text.Encoding.ASCII;
112
113 switch (Pack.Type)
114 {
115 case PacketType.ViewerEffect:
116 ViewerEffectPacket viewer = (ViewerEffectPacket)Pack;
117 foreach (ClientView client in m_clientThreads.Values)
118 {
119 if (client.AgentID != this.AgentID)
120 {
121 viewer.AgentData.AgentID = client.AgentID;
122 viewer.AgentData.SessionID = client.SessionID;
123 client.OutPacket(viewer);
124 }
125 }
126 break;
127
128 #region New Event System - World/Avatar
129 case PacketType.ChatFromViewer:
130 ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack;
131 if (Util.FieldToString(inchatpack.ChatData.Message) == "")
132 {
133 //empty message so don't bother with it
134 break;
135 }
136 string fromName = ClientAvatar.firstname + " " + ClientAvatar.lastname;
137 byte[] message = inchatpack.ChatData.Message;
138 byte type = inchatpack.ChatData.Type;
139 LLVector3 fromPos = ClientAvatar.Pos;
140 LLUUID fromAgentID = AgentID;
141 this.OnChatFromViewer(message, type, fromPos, fromName, fromAgentID);
142 break;
143 case PacketType.RezObject:
144 RezObjectPacket rezPacket = (RezObjectPacket)Pack;
145 AgentInventory inven = this.m_inventoryCache.GetAgentsInventory(this.AgentID);
146 if (inven != null)
147 {
148 if (inven.InventoryItems.ContainsKey(rezPacket.InventoryData.ItemID))
149 {
150 AssetBase asset = this.m_assetCache.GetAsset(inven.InventoryItems[rezPacket.InventoryData.ItemID].AssetID);
151 if (asset != null)
152 {
153 this.OnRezObject(asset, rezPacket.RezData.RayEnd);
154 this.m_inventoryCache.DeleteInventoryItem(this, rezPacket.InventoryData.ItemID);
155 }
156 }
157 }
158 break;
159 case PacketType.DeRezObject:
160 OnDeRezObject(Pack, this);
161 break;
162 case PacketType.ModifyLand:
163 ModifyLandPacket modify = (ModifyLandPacket)Pack;
164 if (modify.ParcelData.Length > 0)
165 {
166 OnModifyTerrain(modify.ModifyBlock.Action, modify.ParcelData[0].North, modify.ParcelData[0].West);
167 }
168 break;
169 case PacketType.RegionHandshakeReply:
170 OnRegionHandShakeReply(this);
171 break;
172 case PacketType.AgentWearablesRequest:
173 OnRequestWearables(this);
174 OnRequestAvatarsData(this);
175 break;
176 case PacketType.AgentSetAppearance:
177 AgentSetAppearancePacket appear = (AgentSetAppearancePacket)Pack;
178 OnSetAppearance(appear.ObjectData.TextureEntry, appear.VisualParam);
179 break;
180 case PacketType.CompleteAgentMovement:
181 if (this.m_child) this.UpgradeClient();
182 OnCompleteMovementToRegion();
183 this.EnableNeighbours();
184 break;
185 case PacketType.AgentUpdate:
186 OnAgentUpdate(Pack);
187 break;
188 case PacketType.AgentAnimation:
189 if (!m_child)
190 {
191 AgentAnimationPacket AgentAni = (AgentAnimationPacket)Pack;
192 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
193 {
194 if (AgentAni.AnimationList[i].StartAnim)
195 {
196 OnStartAnim(AgentAni.AnimationList[i].AnimID, 1);
197 }
198 }
199 }
200 break;
201
202 #endregion
203
204 #region New Event System - Objects/Prims
205 case PacketType.ObjectLink:
206 ObjectLinkPacket link = (ObjectLinkPacket)Pack;
207 uint parentprimid = 0;
208 List<uint> childrenprims = new List<uint>();
209 if (link.ObjectData.Length > 1)
210 {
211 parentprimid = link.ObjectData[0].ObjectLocalID;
212
213 for (int i = 1; i < link.ObjectData.Length; i++)
214 {
215 childrenprims.Add(link.ObjectData[i].ObjectLocalID);
216 }
217 }
218 OnLinkObjects(parentprimid, childrenprims);
219 break;
220 case PacketType.ObjectAdd:
221 m_world.AddNewPrim((ObjectAddPacket)Pack, this);
222 OnAddPrim(Pack, this);
223 break;
224 case PacketType.ObjectShape:
225 ObjectShapePacket shape = (ObjectShapePacket)Pack;
226 for (int i = 0; i < shape.ObjectData.Length; i++)
227 {
228 OnUpdatePrimShape(shape.ObjectData[i].ObjectLocalID, shape.ObjectData[i]);
229 }
230 break;
231 case PacketType.ObjectSelect:
232 ObjectSelectPacket incomingselect = (ObjectSelectPacket)Pack;
233 for (int i = 0; i < incomingselect.ObjectData.Length; i++)
234 {
235 OnObjectSelect(incomingselect.ObjectData[i].ObjectLocalID, this);
236 }
237 break;
238 case PacketType.ObjectFlagUpdate:
239 ObjectFlagUpdatePacket flags = (ObjectFlagUpdatePacket)Pack;
240 OnUpdatePrimFlags(flags.AgentData.ObjectLocalID, Pack, this);
241 break;
242 case PacketType.ObjectImage:
243 ObjectImagePacket imagePack = (ObjectImagePacket)Pack;
244 for (int i = 0; i < imagePack.ObjectData.Length; i++)
245 {
246 OnUpdatePrimTexture(imagePack.ObjectData[i].ObjectLocalID, imagePack.ObjectData[i].TextureEntry, this);
247
248 }
249 break;
250 #endregion
251
252 #region Inventory/Asset/Other related packets
253 case PacketType.RequestImage:
254 RequestImagePacket imageRequest = (RequestImagePacket)Pack;
255 for (int i = 0; i < imageRequest.RequestImage.Length; i++)
256 {
257 m_assetCache.AddTextureRequest(this, imageRequest.RequestImage[i].Image);
258 }
259 break;
260 case PacketType.TransferRequest:
261 TransferRequestPacket transfer = (TransferRequestPacket)Pack;
262 m_assetCache.AddAssetRequest(this, transfer);
263 break;
264 case PacketType.AssetUploadRequest:
265 AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
266 this.UploadAssets.HandleUploadPacket(request, request.AssetBlock.TransactionID.Combine(this.SecureSessionID));
267 break;
268 case PacketType.RequestXfer:
269 break;
270 case PacketType.SendXferPacket:
271 this.UploadAssets.HandleXferPacket((SendXferPacketPacket)Pack);
272 break;
273 case PacketType.CreateInventoryFolder:
274 CreateInventoryFolderPacket invFolder = (CreateInventoryFolderPacket)Pack;
275 m_inventoryCache.CreateNewInventoryFolder(this, invFolder.FolderData.FolderID, (ushort)invFolder.FolderData.Type, Util.FieldToString(invFolder.FolderData.Name), invFolder.FolderData.ParentID);
276 break;
277 case PacketType.CreateInventoryItem:
278 CreateInventoryItemPacket createItem = (CreateInventoryItemPacket)Pack;
279 if (createItem.InventoryBlock.TransactionID != LLUUID.Zero)
280 {
281 this.UploadAssets.CreateInventoryItem(createItem);
282 }
283 else
284 {
285 this.CreateInventoryItem(createItem);
286 }
287 break;
288 case PacketType.FetchInventory:
289 FetchInventoryPacket FetchInventory = (FetchInventoryPacket)Pack;
290 m_inventoryCache.FetchInventory(this, FetchInventory);
291 break;
292 case PacketType.FetchInventoryDescendents:
293 FetchInventoryDescendentsPacket Fetch = (FetchInventoryDescendentsPacket)Pack;
294 m_inventoryCache.FetchInventoryDescendents(this, Fetch);
295 break;
296 case PacketType.UpdateInventoryItem:
297 UpdateInventoryItemPacket update = (UpdateInventoryItemPacket)Pack;
298 for (int i = 0; i < update.InventoryData.Length; i++)
299 {
300 if (update.InventoryData[i].TransactionID != LLUUID.Zero)
301 {
302 AssetBase asset = m_assetCache.GetAsset(update.InventoryData[i].TransactionID.Combine(this.SecureSessionID));
303 if (asset != null)
304 {
305 m_inventoryCache.UpdateInventoryItemAsset(this, update.InventoryData[i].ItemID, asset);
306 }
307 else
308 {
309 asset = this.UploadAssets.AddUploadToAssetCache(update.InventoryData[i].TransactionID);
310 if (asset != null)
311 {
312 m_inventoryCache.UpdateInventoryItemAsset(this, update.InventoryData[i].ItemID, asset);
313 }
314 else
315 {
316
317 }
318 }
319 }
320 else
321 {
322 m_inventoryCache.UpdateInventoryItemDetails(this, update.InventoryData[i].ItemID, update.InventoryData[i]); ;
323 }
324 }
325 break;
326 case PacketType.RequestTaskInventory:
327 RequestTaskInventoryPacket requesttask = (RequestTaskInventoryPacket)Pack;
328 ReplyTaskInventoryPacket replytask = new ReplyTaskInventoryPacket();
329 bool foundent = false;
330 foreach (Entity ent in m_world.Entities.Values)
331 {
332 if (ent.localid == requesttask.InventoryData.LocalID)
333 {
334 replytask.InventoryData.TaskID = ent.uuid;
335 replytask.InventoryData.Serial = 0;
336 replytask.InventoryData.Filename = new byte[0];
337 foundent = true;
338 }
339 }
340 if (foundent)
341 {
342 this.OutPacket(replytask);
343 }
344 break;
345 case PacketType.UpdateTaskInventory:
346 UpdateTaskInventoryPacket updatetask = (UpdateTaskInventoryPacket)Pack;
347 AgentInventory myinventory = this.m_inventoryCache.GetAgentsInventory(this.AgentID);
348 if (myinventory != null)
349 {
350 if (updatetask.UpdateData.Key == 0)
351 {
352 if (myinventory.InventoryItems[updatetask.InventoryData.ItemID] != null)
353 {
354 if (myinventory.InventoryItems[updatetask.InventoryData.ItemID].Type == 7)
355 {
356 LLUUID noteaid = myinventory.InventoryItems[updatetask.InventoryData.ItemID].AssetID;
357 AssetBase assBase = this.m_assetCache.GetAsset(noteaid);
358 if (assBase != null)
359 {
360 foreach (Entity ent in m_world.Entities.Values)
361 {
362 if (ent.localid == updatetask.UpdateData.LocalID)
363 {
364 if (ent is OpenSim.RegionServer.Simulator.Primitive)
365 {
366 this.m_world.AddScript(ent, Util.FieldToString(assBase.Data));
367 }
368 }
369 }
370 }
371 }
372 }
373 }
374 }
375 break;
376 case PacketType.MapLayerRequest:
377 // This be busted.
378 MapLayerRequestPacket MapRequest = (MapLayerRequestPacket)Pack;
379 this.RequestMapLayer();
380 this.RequestMapBlocks((int)this.m_regionData.RegionLocX - 5, (int)this.m_regionData.RegionLocY - 5, (int)this.m_regionData.RegionLocX + 5, (int)this.m_regionData.RegionLocY + 5);
381 break;
382
383 case PacketType.MapBlockRequest:
384 MapBlockRequestPacket MapBRequest = (MapBlockRequestPacket)Pack;
385 this.RequestMapBlocks(MapBRequest.PositionData.MinX, MapBRequest.PositionData.MinY, MapBRequest.PositionData.MaxX, MapBRequest.PositionData.MaxY);
386 break;
387
388 case PacketType.MapNameRequest:
389 // TODO.
390 break;
391
392 case PacketType.TeleportLandmarkRequest:
393 TeleportLandmarkRequestPacket tpReq = (TeleportLandmarkRequestPacket)Pack;
394
395 TeleportStartPacket tpStart = new TeleportStartPacket();
396 tpStart.Info.TeleportFlags = 8; // tp via lm
397 this.OutPacket(tpStart);
398
399 TeleportProgressPacket tpProgress = new TeleportProgressPacket();
400 tpProgress.Info.Message = (new System.Text.ASCIIEncoding()).GetBytes("sending_landmark");
401 tpProgress.Info.TeleportFlags = 8;
402 tpProgress.AgentData.AgentID = tpReq.Info.AgentID;
403 this.OutPacket(tpProgress);
404
405 // Fetch landmark
406 LLUUID lmid = tpReq.Info.LandmarkID;
407 AssetBase lma = this.m_assetCache.GetAsset(lmid);
408 if (lma != null)
409 {
410 AssetLandmark lm = new AssetLandmark(lma);
411
412 if (lm.RegionID == m_regionData.SimUUID)
413 {
414 TeleportLocalPacket tpLocal = new TeleportLocalPacket();
415
416 tpLocal.Info.AgentID = tpReq.Info.AgentID;
417 tpLocal.Info.TeleportFlags = 8; // Teleport via landmark
418 tpLocal.Info.LocationID = 2;
419 tpLocal.Info.Position = lm.Position;
420 OutPacket(tpLocal);
421 }
422 else
423 {
424 TeleportCancelPacket tpCancel = new TeleportCancelPacket();
425 tpCancel.Info.AgentID = tpReq.Info.AgentID;
426 tpCancel.Info.SessionID = tpReq.Info.SessionID;
427 OutPacket(tpCancel);
428 }
429 }
430 else
431 {
432 Console.WriteLine("Cancelling Teleport - fetch asset not yet implemented");
433
434 TeleportCancelPacket tpCancel = new TeleportCancelPacket();
435 tpCancel.Info.AgentID = tpReq.Info.AgentID;
436 tpCancel.Info.SessionID = tpReq.Info.SessionID;
437 OutPacket(tpCancel);
438 }
439 break;
440 case PacketType.TeleportLocationRequest:
441 TeleportLocationRequestPacket tpLocReq = (TeleportLocationRequestPacket)Pack;
442 Console.WriteLine(tpLocReq.ToString());
443
444 tpStart = new TeleportStartPacket();
445 tpStart.Info.TeleportFlags = 16; // Teleport via location
446 Console.WriteLine(tpStart.ToString());
447 OutPacket(tpStart);
448
449 if (m_regionData.RegionHandle != tpLocReq.Info.RegionHandle)
450 {
451 /* m_gridServer.getRegion(tpLocReq.Info.RegionHandle); */
452 Console.WriteLine("Inter-sim teleport not yet implemented");
453 TeleportCancelPacket tpCancel = new TeleportCancelPacket();
454 tpCancel.Info.SessionID = tpLocReq.AgentData.SessionID;
455 tpCancel.Info.AgentID = tpLocReq.AgentData.AgentID;
456
457 OutPacket(tpCancel);
458 }
459 else
460 {
461 Console.WriteLine("Local teleport");
462 TeleportLocalPacket tpLocal = new TeleportLocalPacket();
463 tpLocal.Info.AgentID = tpLocReq.AgentData.AgentID;
464 tpLocal.Info.TeleportFlags = tpStart.Info.TeleportFlags;
465 tpLocal.Info.LocationID = 2;
466 tpLocal.Info.LookAt = tpLocReq.Info.LookAt;
467 tpLocal.Info.Position = tpLocReq.Info.Position;
468 OutPacket(tpLocal);
469
470 }
471 break;
472 #endregion
473
474 #region Parcel Packets
475 case PacketType.ParcelPropertiesRequest:
476 ParcelPropertiesRequestPacket propertiesRequest = (ParcelPropertiesRequestPacket)Pack;
477 OnParcelPropertiesRequest((int)Math.Round(propertiesRequest.ParcelData.West), (int)Math.Round(propertiesRequest.ParcelData.South), (int)Math.Round(propertiesRequest.ParcelData.East), (int)Math.Round(propertiesRequest.ParcelData.North),propertiesRequest.ParcelData.SequenceID,propertiesRequest.ParcelData.SnapSelection, this);
478 break;
479 case PacketType.ParcelDivide:
480 ParcelDividePacket parcelDivide = (ParcelDividePacket)Pack;
481 OnParcelDivideRequest((int)Math.Round(parcelDivide.ParcelData.West), (int)Math.Round(parcelDivide.ParcelData.South), (int)Math.Round(parcelDivide.ParcelData.East), (int)Math.Round(parcelDivide.ParcelData.North), this);
482 break;
483 case PacketType.ParcelJoin:
484 ParcelJoinPacket parcelJoin = (ParcelJoinPacket)Pack;
485 OnParcelJoinRequest((int)Math.Round(parcelJoin.ParcelData.West), (int)Math.Round(parcelJoin.ParcelData.South), (int)Math.Round(parcelJoin.ParcelData.East), (int)Math.Round(parcelJoin.ParcelData.North), this);
486 break;
487 case PacketType.ParcelPropertiesUpdate:
488 ParcelPropertiesUpdatePacket updatePacket = (ParcelPropertiesUpdatePacket)Pack;
489 OnParcelPropertiesUpdateRequest(updatePacket, this);
490 break;
491 #endregion
492
493 #region unimplemented handlers
494 case PacketType.AgentIsNowWearing:
495 // AgentIsNowWearingPacket wear = (AgentIsNowWearingPacket)Pack;
496 break;
497 case PacketType.ObjectScale:
498 break;
499 case PacketType.MoneyBalanceRequest:
500 //This need to be actually done and not thrown back with fake infos
501 break;
502
503 case PacketType.EstateCovenantRequest:
504 //This should be actually done and not thrown back with fake info
505 EstateCovenantRequestPacket estateCovenantRequest = (EstateCovenantRequestPacket)Pack;
506 EstateCovenantReplyPacket estateCovenantReply = new EstateCovenantReplyPacket();
507 estateCovenantReply.Data.EstateName = libsecondlife.Helpers.StringToField("Leet Estate");
508 estateCovenantReply.Data.EstateOwnerID = LLUUID.Zero;
509 estateCovenantReply.Data.CovenantID = LLUUID.Zero;
510 estateCovenantReply.Data.CovenantTimestamp = (uint)0;
511 this.OutPacket((Packet)estateCovenantReply);
512 MainConsole.Instance.Notice("Sent Temporary Estate packet (they are in leet estate)");
513 break;
514 #endregion
515 }
516 }
517 }
518 }
519}
diff --git a/OpenSim/OpenSim.RegionServer/Client/ClientView.cs b/OpenSim/OpenSim.RegionServer/Client/ClientView.cs
new file mode 100644
index 0000000..6d7c3f2
--- /dev/null
+++ b/OpenSim/OpenSim.RegionServer/Client/ClientView.cs
@@ -0,0 +1,459 @@
1/*
2* Copyright (c) Contributors, http://www.openmetaverse.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28
29using System;
30using System.Collections;
31using System.Collections.Generic;
32using libsecondlife;
33using libsecondlife.Packets;
34using Nwc.XmlRpc;
35using System.Net;
36using System.Net.Sockets;
37using System.IO;
38using System.Threading;
39using System.Timers;
40using OpenSim.Framework.Interfaces;
41using OpenSim.Framework.Types;
42using OpenSim.Framework.Inventory;
43using OpenSim.Framework.Utilities;
44using OpenSim.RegionServer.Simulator;
45using OpenSim.RegionServer.Assets;
46using OpenSim.Framework.Console;
47
48namespace OpenSim.RegionServer.Client
49{
50 public delegate bool PacketMethod(ClientView simClient, Packet packet);
51
52 /// <summary>
53 /// Handles new client connections
54 /// Constructor takes a single Packet and authenticates everything
55 /// </summary>
56 public partial class ClientView : ClientViewBase, IClientAPI
57 {
58 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
59 protected Dictionary<PacketType, PacketMethod> m_packetHandlers = new Dictionary<PacketType, PacketMethod>(); //local handlers for this instance
60
61 public LLUUID AgentID;
62 public LLUUID SessionID;
63 public LLUUID SecureSessionID = LLUUID.Zero;
64 public bool m_child;
65 public Simulator.Avatar ClientAvatar;
66 private UseCircuitCodePacket cirpack;
67 public Thread ClientThread;
68 public LLVector3 startpos;
69
70 private AgentAssetUpload UploadAssets;
71 private LLUUID newAssetFolder = LLUUID.Zero;
72 private bool debug = false;
73 private World m_world;
74 private Dictionary<uint, ClientView> m_clientThreads;
75 private AssetCache m_assetCache;
76 private IGridServer m_gridServer;
77 private IUserServer m_userServer = null;
78 private InventoryCache m_inventoryCache;
79 public bool m_sandboxMode;
80 private int cachedtextureserial = 0;
81 private RegionInfo m_regionData;
82 protected AuthenticateSessionsBase m_authenticateSessionsHandler;
83
84 public IUserServer UserServer
85 {
86 set
87 {
88 this.m_userServer = value;
89 }
90 }
91
92 public LLVector3 StartPos
93 {
94 get
95 {
96 return startpos;
97 }
98 set
99 {
100 startpos = value;
101 }
102 }
103
104 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)
105 {
106 m_world = world;
107 m_clientThreads = clientThreads;
108 m_assetCache = assetCache;
109 m_gridServer = gridServer;
110 m_networkServer = application;
111 m_inventoryCache = inventoryCache;
112 m_sandboxMode = sandboxMode;
113 m_child = child;
114 m_regionData = regionDat;
115 m_authenticateSessionsHandler = authenSessions;
116 MainConsole.Instance.Notice("OpenSimClient.cs - Started up new client thread to handle incoming request");
117 cirpack = initialcirpack;
118 userEP = remoteEP;
119
120 if (m_gridServer.GetName() == "Remote")
121 {
122 this.m_child = m_authenticateSessionsHandler.GetAgentChildStatus(initialcirpack.CircuitCode.Code);
123 this.startpos = m_authenticateSessionsHandler.GetPosition(initialcirpack.CircuitCode.Code);
124
125 // Dont rez new users underground
126 float aboveGround = 3.0f; // rez at least 3 meters above ground
127 if (this.startpos.Z < (m_world.Terrain[(int)this.startpos.X, (int)this.startpos.Y] + aboveGround))
128 this.startpos.Z = m_world.Terrain[(int)this.startpos.X, (int)this.startpos.Y] + aboveGround;
129
130 }
131 else
132 {
133 this.startpos = new LLVector3(128, 128, m_world.Terrain[(int)128, (int)128] + 15.0f); // new LLVector3(128.0f, 128.0f, 60f);
134 }
135
136 PacketQueue = new BlockingQueue<QueItem>();
137
138 this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache);
139 AckTimer = new System.Timers.Timer(500);
140 AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
141 AckTimer.Start();
142
143 this.RegisterLocalPacketHandlers();
144
145
146 m_world.parcelManager.sendParcelOverlay(this);
147
148 ClientThread = new Thread(new ThreadStart(AuthUser));
149 ClientThread.IsBackground = true;
150 ClientThread.Start();
151 }
152
153 # region Client Methods
154 public void UpgradeClient()
155 {
156 MainConsole.Instance.Notice("SimClient.cs:UpgradeClient() - upgrading child to full agent");
157 this.m_child = false;
158 //this.m_world.RemoveViewerAgent(this);
159 if (!this.m_sandboxMode)
160 {
161 this.startpos = m_authenticateSessionsHandler.GetPosition(CircuitCode);
162 m_authenticateSessionsHandler.UpdateAgentChildStatus(CircuitCode, false);
163 }
164 OnChildAgentStatus(this.m_child);
165 //this.InitNewClient();
166 }
167
168 public void DowngradeClient()
169 {
170 MainConsole.Instance.Notice("SimClient.cs:UpgradeClient() - changing full agent to child");
171 this.m_child = true;
172 OnChildAgentStatus(this.m_child);
173 //this.m_world.RemoveViewerAgent(this);
174 //this.m_world.AddViewerAgent(this);
175 }
176
177 public void KillClient()
178 {
179 KillObjectPacket kill = new KillObjectPacket();
180 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
181 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
182 kill.ObjectData[0].ID = this.ClientAvatar.localid;
183 foreach (ClientView client in m_clientThreads.Values)
184 {
185 client.OutPacket(kill);
186 }
187 if (this.m_userServer != null)
188 {
189 this.m_inventoryCache.ClientLeaving(this.AgentID, this.m_userServer);
190 }
191 else
192 {
193 this.m_inventoryCache.ClientLeaving(this.AgentID, null);
194 }
195
196 m_world.RemoveViewerAgent(this);
197
198 m_clientThreads.Remove(this.CircuitCode);
199 m_networkServer.RemoveClientCircuit(this.CircuitCode);
200 this.ClientThread.Abort();
201 }
202 #endregion
203
204 # region Packet Handling
205 public static bool AddPacketHandler(PacketType packetType, PacketMethod handler)
206 {
207 bool result = false;
208 lock (PacketHandlers)
209 {
210 if (!PacketHandlers.ContainsKey(packetType))
211 {
212 PacketHandlers.Add(packetType, handler);
213 result = true;
214 }
215 }
216 return result;
217 }
218
219 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler)
220 {
221 bool result = false;
222 lock (m_packetHandlers)
223 {
224 if (!m_packetHandlers.ContainsKey(packetType))
225 {
226 m_packetHandlers.Add(packetType, handler);
227 result = true;
228 }
229 }
230 return result;
231 }
232
233 protected virtual bool ProcessPacketMethod(Packet packet)
234 {
235 bool result = false;
236 bool found = false;
237 PacketMethod method;
238 if (m_packetHandlers.TryGetValue(packet.Type, out method))
239 {
240 //there is a local handler for this packet type
241 result = method(this, packet);
242 }
243 else
244 {
245 //there is not a local handler so see if there is a Global handler
246 lock (PacketHandlers)
247 {
248 found = PacketHandlers.TryGetValue(packet.Type, out method);
249 }
250 if (found)
251 {
252 result = method(this, packet);
253 }
254 }
255 return result;
256 }
257
258 protected virtual void ClientLoop()
259 {
260 MainConsole.Instance.Notice("OpenSimClient.cs:ClientLoop() - Entered loop");
261 while (true)
262 {
263 QueItem nextPacket = PacketQueue.Dequeue();
264 if (nextPacket.Incoming)
265 {
266 //is a incoming packet
267 ProcessInPacket(nextPacket.Packet);
268 }
269 else
270 {
271 //is a out going packet
272 ProcessOutPacket(nextPacket.Packet);
273 }
274 }
275 }
276 # endregion
277
278 # region Setup
279
280 protected virtual void InitNewClient()
281 {
282 MainConsole.Instance.Notice("OpenSimClient.cs:InitNewClient() - Adding viewer agent to world");
283 this.ClientAvatar = m_world.AddViewerAgent(this);
284 }
285
286 protected virtual void AuthUser()
287 {
288 // AuthenticateResponse sessionInfo = m_gridServer.AuthenticateSession(cirpack.CircuitCode.SessionID, cirpack.CircuitCode.ID, cirpack.CircuitCode.Code);
289 AuthenticateResponse sessionInfo = this.m_networkServer.AuthenticateSession(cirpack.CircuitCode.SessionID, cirpack.CircuitCode.ID, cirpack.CircuitCode.Code);
290 if (!sessionInfo.Authorised)
291 {
292 //session/circuit not authorised
293 OpenSim.Framework.Console.MainConsole.Instance.Notice("OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString());
294 ClientThread.Abort();
295 }
296 else
297 {
298 OpenSim.Framework.Console.MainConsole.Instance.Notice("OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString());
299 //session is authorised
300 this.AgentID = cirpack.CircuitCode.ID;
301 this.SessionID = cirpack.CircuitCode.SessionID;
302 this.CircuitCode = cirpack.CircuitCode.Code;
303 InitNewClient();
304 this.ClientAvatar.firstname = sessionInfo.LoginInfo.First;
305 this.ClientAvatar.lastname = sessionInfo.LoginInfo.Last;
306 if (sessionInfo.LoginInfo.SecureSession != LLUUID.Zero)
307 {
308 this.SecureSessionID = sessionInfo.LoginInfo.SecureSession;
309 }
310
311 // Create Inventory, currently only works for sandbox mode
312 if (m_sandboxMode)
313 {
314 this.SetupInventory(sessionInfo);
315 }
316
317 ClientLoop();
318 }
319 }
320 # endregion
321
322
323 protected override void KillThread()
324 {
325 this.ClientThread.Abort();
326 }
327
328 #region World/Avatar To Viewer Methods
329
330 public void SendChatMessage(byte[] message, byte type, LLVector3 fromPos, string fromName, LLUUID fromAgentID)
331 {
332 System.Text.Encoding enc = System.Text.Encoding.ASCII;
333 libsecondlife.Packets.ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket();
334 reply.ChatData.Audible = 1;
335 reply.ChatData.Message = message;
336 reply.ChatData.ChatType = type;
337 reply.ChatData.SourceType = 1;
338 reply.ChatData.Position = fromPos;
339 reply.ChatData.FromName = enc.GetBytes(fromName + "\0");
340 reply.ChatData.OwnerID = fromAgentID;
341 reply.ChatData.SourceID = fromAgentID;
342
343 this.OutPacket(reply);
344 }
345
346 public void SendAppearance(AvatarWearable[] wearables)
347 {
348 AgentWearablesUpdatePacket aw = new AgentWearablesUpdatePacket();
349 aw.AgentData.AgentID = this.AgentID;
350 aw.AgentData.SerialNum = 0;
351 aw.AgentData.SessionID = this.SessionID;
352
353 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[13];
354 AgentWearablesUpdatePacket.WearableDataBlock awb;
355 for (int i = 0; i < wearables.Length; i++)
356 {
357 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
358 awb.WearableType = (byte)i;
359 awb.AssetID = wearables[i].AssetID;
360 awb.ItemID = wearables[i].ItemID;
361 aw.WearableData[i] = awb;
362 }
363
364 this.OutPacket(aw);
365 }
366 #endregion
367
368 #region Inventory Creation
369 private void SetupInventory(AuthenticateResponse sessionInfo)
370 {
371 AgentInventory inventory = null;
372 if (sessionInfo.LoginInfo.InventoryFolder != null)
373 {
374 inventory = this.CreateInventory(sessionInfo.LoginInfo.InventoryFolder);
375 if (sessionInfo.LoginInfo.BaseFolder != null)
376 {
377 if (!inventory.HasFolder(sessionInfo.LoginInfo.BaseFolder))
378 {
379 m_inventoryCache.CreateNewInventoryFolder(this, sessionInfo.LoginInfo.BaseFolder);
380 }
381 this.newAssetFolder = sessionInfo.LoginInfo.BaseFolder;
382 AssetBase[] inventorySet = m_assetCache.CreateNewInventorySet(this.AgentID);
383 if (inventorySet != null)
384 {
385 for (int i = 0; i < inventorySet.Length; i++)
386 {
387 if (inventorySet[i] != null)
388 {
389 m_inventoryCache.AddNewInventoryItem(this, sessionInfo.LoginInfo.BaseFolder, inventorySet[i]);
390 }
391 }
392 }
393 }
394 }
395 }
396 private AgentInventory CreateInventory(LLUUID baseFolder)
397 {
398 AgentInventory inventory = null;
399 if (this.m_userServer != null)
400 {
401 // a user server is set so request the inventory from it
402 MainConsole.Instance.Verbose("getting inventory from user server");
403 inventory = m_inventoryCache.FetchAgentsInventory(this.AgentID, m_userServer);
404 }
405 else
406 {
407 inventory = new AgentInventory();
408 inventory.AgentID = this.AgentID;
409 inventory.CreateRootFolder(this.AgentID, false);
410 m_inventoryCache.AddNewAgentsInventory(inventory);
411 m_inventoryCache.CreateNewInventoryFolder(this, baseFolder);
412 }
413 return inventory;
414 }
415
416 private void CreateInventoryItem(CreateInventoryItemPacket packet)
417 {
418 if (!(packet.InventoryBlock.Type == 3 || packet.InventoryBlock.Type == 7))
419 {
420 MainConsole.Instance.Warn("Attempted to create " + Util.FieldToString(packet.InventoryBlock.Name) + " in inventory. Unsupported type");
421 return;
422 }
423
424 //lets try this out with creating a notecard
425 AssetBase asset = new AssetBase();
426
427 asset.Name = Util.FieldToString(packet.InventoryBlock.Name);
428 asset.Description = Util.FieldToString(packet.InventoryBlock.Description);
429 asset.InvType = packet.InventoryBlock.InvType;
430 asset.Type = packet.InventoryBlock.Type;
431 asset.FullID = LLUUID.Random();
432
433 switch (packet.InventoryBlock.Type)
434 {
435 case 7: // Notecard
436 asset.Data = new byte[0];
437 break;
438
439 case 3: // Landmark
440 String content;
441 content = "Landmark version 2\n";
442 content += "region_id " + m_regionData.SimUUID + "\n";
443 String strPos = String.Format("%.2f %.2f %.2f>",
444 this.ClientAvatar.Pos.X,
445 this.ClientAvatar.Pos.Y,
446 this.ClientAvatar.Pos.Z);
447 content += "local_pos " + strPos + "\n";
448 asset.Data = (new System.Text.ASCIIEncoding()).GetBytes(content);
449 break;
450 default:
451 break;
452 }
453 m_assetCache.AddAsset(asset);
454 m_inventoryCache.AddNewInventoryItem(this, packet.InventoryBlock.FolderID, asset);
455 }
456 #endregion
457
458 }
459}
diff --git a/OpenSim/OpenSim.RegionServer/Client/ClientViewBase.cs b/OpenSim/OpenSim.RegionServer/Client/ClientViewBase.cs
new file mode 100644
index 0000000..2ff245f
--- /dev/null
+++ b/OpenSim/OpenSim.RegionServer/Client/ClientViewBase.cs
@@ -0,0 +1,326 @@
1/*
2* Copyright (c) Contributors, http://www.openmetaverse.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using libsecondlife;
32using libsecondlife.Packets;
33using System.Net;
34using System.Net.Sockets;
35using System.IO;
36using System.Threading;
37using System.Timers;
38using OpenSim.Framework.Utilities;
39using OpenSim.Framework.Interfaces;
40using OpenSim.Framework.Console;
41
42namespace OpenSim.RegionServer.Client
43{
44 public class ClientViewBase
45 {
46 protected BlockingQueue<QueItem> PacketQueue;
47 protected Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
48 protected Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
49
50 protected System.Timers.Timer AckTimer;
51 protected uint Sequence = 0;
52 protected object SequenceLock = new object();
53 protected const int MAX_APPENDED_ACKS = 10;
54 protected const int RESEND_TIMEOUT = 4000;
55 protected const int MAX_SEQUENCE = 0xFFFFFF;
56
57 public uint CircuitCode;
58 public EndPoint userEP;
59
60 protected OpenSimNetworkHandler m_networkServer;
61
62 public ClientViewBase()
63 {
64
65 }
66
67 protected virtual void ProcessInPacket(Packet Pack)
68 {
69
70 }
71
72 protected virtual void ProcessOutPacket(Packet Pack)
73 {
74 // Keep track of when this packet was sent out
75 Pack.TickCount = Environment.TickCount;
76
77
78 if (!Pack.Header.Resent)
79 {
80 // Set the sequence number
81 lock (SequenceLock)
82 {
83 if (Sequence >= MAX_SEQUENCE)
84 Sequence = 1;
85 else
86 Sequence++;
87 Pack.Header.Sequence = Sequence;
88 }
89
90 if (Pack.Header.Reliable) //DIRTY HACK
91 {
92 lock (NeedAck)
93 {
94 if (!NeedAck.ContainsKey(Pack.Header.Sequence))
95 {
96 try
97 {
98 NeedAck.Add(Pack.Header.Sequence, Pack);
99 }
100 catch (Exception e) // HACKY
101 {
102 e.ToString();
103 // Ignore
104 // Seems to throw a exception here occasionally
105 // of 'duplicate key' despite being locked.
106 // !?!?!?
107 }
108 }
109 else
110 {
111 // Client.Log("Attempted to add a duplicate sequence number (" +
112 // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " +
113 // packet.Type.ToString(), Helpers.LogLevel.Warning);
114 }
115 }
116
117 // Don't append ACKs to resent packets, in case that's what was causing the
118 // delivery to fail
119 if (!Pack.Header.Resent)
120 {
121 // Append any ACKs that need to be sent out to this packet
122 lock (PendingAcks)
123 {
124 if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS &&
125 Pack.Type != PacketType.PacketAck &&
126 Pack.Type != PacketType.LogoutRequest)
127 {
128 Pack.Header.AckList = new uint[PendingAcks.Count];
129 int i = 0;
130
131 foreach (uint ack in PendingAcks.Values)
132 {
133 Pack.Header.AckList[i] = ack;
134 i++;
135 }
136
137 PendingAcks.Clear();
138 Pack.Header.AppendedAcks = true;
139 }
140 }
141 }
142 }
143 }
144
145 byte[] ZeroOutBuffer = new byte[4096];
146 byte[] sendbuffer;
147 sendbuffer = Pack.ToBytes();
148
149 try
150 {
151 if (Pack.Header.Zerocoded)
152 {
153 int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer);
154 m_networkServer.SendPacketTo(ZeroOutBuffer, packetsize, SocketFlags.None, CircuitCode);//userEP);
155 }
156 else
157 {
158 m_networkServer.SendPacketTo(sendbuffer, sendbuffer.Length, SocketFlags.None, CircuitCode); //userEP);
159 }
160 }
161 catch (Exception)
162 {
163 MainConsole.Instance.Warn("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread");
164 this.KillThread();
165 }
166
167 }
168
169 public virtual void InPacket(Packet NewPack)
170 {
171 // Handle appended ACKs
172 if (NewPack.Header.AppendedAcks)
173 {
174 lock (NeedAck)
175 {
176 foreach (uint ack in NewPack.Header.AckList)
177 {
178 NeedAck.Remove(ack);
179 }
180 }
181 }
182
183 // Handle PacketAck packets
184 if (NewPack.Type == PacketType.PacketAck)
185 {
186 PacketAckPacket ackPacket = (PacketAckPacket)NewPack;
187
188 lock (NeedAck)
189 {
190 foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
191 {
192 NeedAck.Remove(block.ID);
193 }
194 }
195 }
196 else if ((NewPack.Type == PacketType.StartPingCheck))
197 {
198 //reply to pingcheck
199 libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)NewPack;
200 libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket();
201 endPing.PingID.PingID = startPing.PingID.PingID;
202 OutPacket(endPing);
203 }
204 else
205 {
206 QueItem item = new QueItem();
207 item.Packet = NewPack;
208 item.Incoming = true;
209 this.PacketQueue.Enqueue(item);
210 }
211
212 }
213
214 public virtual void OutPacket(Packet NewPack)
215 {
216 QueItem item = new QueItem();
217 item.Packet = NewPack;
218 item.Incoming = false;
219 this.PacketQueue.Enqueue(item);
220 }
221
222 # region Low Level Packet Methods
223
224 protected void ack_pack(Packet Pack)
225 {
226 if (Pack.Header.Reliable)
227 {
228 libsecondlife.Packets.PacketAckPacket ack_it = new PacketAckPacket();
229 ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
230 ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
231 ack_it.Packets[0].ID = Pack.Header.Sequence;
232 ack_it.Header.Reliable = false;
233
234 OutPacket(ack_it);
235
236 }
237 /*
238 if (Pack.Header.Reliable)
239 {
240 lock (PendingAcks)
241 {
242 uint sequence = (uint)Pack.Header.Sequence;
243 if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
244 }
245 }*/
246 }
247
248 protected void ResendUnacked()
249 {
250 int now = Environment.TickCount;
251
252 lock (NeedAck)
253 {
254 foreach (Packet packet in NeedAck.Values)
255 {
256 if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent))
257 {
258 OpenSim.Framework.Console.MainConsole.Instance.Verbose("Resending " + packet.Type.ToString() + " packet, " +
259 (now - packet.TickCount) + "ms have passed");
260
261 packet.Header.Resent = true;
262 OutPacket(packet);
263 }
264 }
265 }
266 }
267
268 protected void SendAcks()
269 {
270 lock (PendingAcks)
271 {
272 if (PendingAcks.Count > 0)
273 {
274 if (PendingAcks.Count > 250)
275 {
276 // FIXME: Handle the odd case where we have too many pending ACKs queued up
277 OpenSim.Framework.Console.MainConsole.Instance.Verbose("Too many ACKs queued up!");
278 return;
279 }
280
281
282 int i = 0;
283 PacketAckPacket acks = new PacketAckPacket();
284 acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count];
285
286 foreach (uint ack in PendingAcks.Values)
287 {
288 acks.Packets[i] = new PacketAckPacket.PacketsBlock();
289 acks.Packets[i].ID = ack;
290 i++;
291 }
292
293 acks.Header.Reliable = false;
294 OutPacket(acks);
295
296 PendingAcks.Clear();
297 }
298 }
299 }
300
301 protected void AckTimer_Elapsed(object sender, ElapsedEventArgs ea)
302 {
303 SendAcks();
304 ResendUnacked();
305 }
306 #endregion
307
308 protected virtual void KillThread()
309 {
310
311 }
312
313 #region Nested Classes
314
315 public class QueItem
316 {
317 public QueItem()
318 {
319 }
320
321 public Packet Packet;
322 public bool Incoming;
323 }
324 #endregion
325 }
326}