aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/ClientViewBase.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/ClientViewBase.cs')
-rw-r--r--OpenSim/Region/ClientStack/ClientViewBase.cs326
1 files changed, 326 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/ClientViewBase.cs b/OpenSim/Region/ClientStack/ClientViewBase.cs
new file mode 100644
index 0000000..048f4df
--- /dev/null
+++ b/OpenSim/Region/ClientStack/ClientViewBase.cs
@@ -0,0 +1,326 @@
1
2/*
3* Copyright (c) Contributors, http://www.openmetaverse.org/
4* See CONTRIBUTORS.TXT for a full list of copyright holders.
5*
6* Redistribution and use in source and binary forms, with or without
7* modification, are permitted provided that the following conditions are met:
8* * Redistributions of source code must retain the above copyright
9* notice, this list of conditions and the following disclaimer.
10* * Redistributions in binary form must reproduce the above copyright
11* notice, this list of conditions and the following disclaimer in the
12* documentation and/or other materials provided with the distribution.
13* * Neither the name of the OpenSim Project nor the
14* names of its contributors may be used to endorse or promote products
15* derived from this software without specific prior written permission.
16*
17* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
18* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
21* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*
28*/
29using System;
30using System.Collections.Generic;
31using System.Net;
32using System.Net.Sockets;
33using System.Timers;
34using libsecondlife;
35using libsecondlife.Packets;
36using OpenSim.Framework.Console;
37using OpenSim.Framework.Utilities;
38
39namespace OpenSim.Region.ClientStack
40{
41 public class ClientViewBase
42 {
43 protected BlockingQueue<QueItem> PacketQueue;
44 protected Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
45 protected Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
46
47 protected Timer AckTimer;
48 protected uint Sequence = 0;
49 protected object SequenceLock = new object();
50 protected const int MAX_APPENDED_ACKS = 10;
51 protected const int RESEND_TIMEOUT = 4000;
52 protected const int MAX_SEQUENCE = 0xFFFFFF;
53
54 public uint CircuitCode;
55 public EndPoint userEP;
56
57 protected PacketServer m_networkServer;
58
59 public ClientViewBase()
60 {
61
62 }
63
64 protected virtual void ProcessInPacket(Packet Pack)
65 {
66
67 }
68
69 protected virtual void ProcessOutPacket(Packet Pack)
70 {
71 // Keep track of when this packet was sent out
72 Pack.TickCount = Environment.TickCount;
73
74 Console.WriteLine(CircuitCode + ":OUT: " + Pack.Type.ToString());
75
76 if (!Pack.Header.Resent)
77 {
78 // Set the sequence number
79 lock (SequenceLock)
80 {
81 if (Sequence >= MAX_SEQUENCE)
82 Sequence = 1;
83 else
84 Sequence++;
85 Pack.Header.Sequence = Sequence;
86 }
87
88 if (Pack.Header.Reliable) //DIRTY HACK
89 {
90 lock (NeedAck)
91 {
92 if (!NeedAck.ContainsKey(Pack.Header.Sequence))
93 {
94 try
95 {
96 NeedAck.Add(Pack.Header.Sequence, Pack);
97 }
98 catch (Exception e) // HACKY
99 {
100 e.ToString();
101 // Ignore
102 // Seems to throw a exception here occasionally
103 // of 'duplicate key' despite being locked.
104 // !?!?!?
105 }
106 }
107 else
108 {
109 // Client.Log("Attempted to add a duplicate sequence number (" +
110 // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " +
111 // packet.Type.ToString(), Helpers.LogLevel.Warning);
112 }
113 }
114
115 // Don't append ACKs to resent packets, in case that's what was causing the
116 // delivery to fail
117 if (!Pack.Header.Resent)
118 {
119 // Append any ACKs that need to be sent out to this packet
120 lock (PendingAcks)
121 {
122 if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS &&
123 Pack.Type != PacketType.PacketAck &&
124 Pack.Type != PacketType.LogoutRequest)
125 {
126 Pack.Header.AckList = new uint[PendingAcks.Count];
127 int i = 0;
128
129 foreach (uint ack in PendingAcks.Values)
130 {
131 Pack.Header.AckList[i] = ack;
132 i++;
133 }
134
135 PendingAcks.Clear();
136 Pack.Header.AppendedAcks = true;
137 }
138 }
139 }
140 }
141 }
142
143 byte[] ZeroOutBuffer = new byte[4096];
144 byte[] sendbuffer;
145 sendbuffer = Pack.ToBytes();
146
147 try
148 {
149 if (Pack.Header.Zerocoded)
150 {
151 int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer);
152 m_networkServer.SendPacketTo(ZeroOutBuffer, packetsize, SocketFlags.None, CircuitCode);//userEP);
153 }
154 else
155 {
156 m_networkServer.SendPacketTo(sendbuffer, sendbuffer.Length, SocketFlags.None, CircuitCode); //userEP);
157 }
158 }
159 catch (Exception)
160 {
161 MainLog.Instance.Warn("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread");
162 this.KillThread();
163 }
164
165 }
166
167 public virtual void InPacket(Packet NewPack)
168 {
169 // Handle appended ACKs
170 if (NewPack.Header.AppendedAcks)
171 {
172 lock (NeedAck)
173 {
174 foreach (uint ack in NewPack.Header.AckList)
175 {
176 NeedAck.Remove(ack);
177 }
178 }
179 }
180
181 // Handle PacketAck packets
182 if (NewPack.Type == PacketType.PacketAck)
183 {
184 PacketAckPacket ackPacket = (PacketAckPacket)NewPack;
185
186 lock (NeedAck)
187 {
188 foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
189 {
190 NeedAck.Remove(block.ID);
191 }
192 }
193 }
194 else if ((NewPack.Type == PacketType.StartPingCheck))
195 {
196 //reply to pingcheck
197 StartPingCheckPacket startPing = (StartPingCheckPacket)NewPack;
198 CompletePingCheckPacket endPing = new CompletePingCheckPacket();
199 endPing.PingID.PingID = startPing.PingID.PingID;
200 OutPacket(endPing);
201 }
202 else
203 {
204 QueItem item = new QueItem();
205 item.Packet = NewPack;
206 item.Incoming = true;
207 this.PacketQueue.Enqueue(item);
208 }
209
210 }
211
212 public virtual void OutPacket(Packet NewPack)
213 {
214 QueItem item = new QueItem();
215 item.Packet = NewPack;
216 item.Incoming = false;
217 this.PacketQueue.Enqueue(item);
218 }
219
220 # region Low Level Packet Methods
221
222 protected void ack_pack(Packet Pack)
223 {
224 if (Pack.Header.Reliable)
225 {
226 PacketAckPacket ack_it = new PacketAckPacket();
227 ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
228 ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
229 ack_it.Packets[0].ID = Pack.Header.Sequence;
230 ack_it.Header.Reliable = false;
231
232 OutPacket(ack_it);
233
234 }
235 /*
236 if (Pack.Header.Reliable)
237 {
238 lock (PendingAcks)
239 {
240 uint sequence = (uint)Pack.Header.Sequence;
241 if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
242 }
243 }*/
244 }
245
246 protected void ResendUnacked()
247 {
248 int now = Environment.TickCount;
249
250 lock (NeedAck)
251 {
252 foreach (Packet packet in NeedAck.Values)
253 {
254 if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent))
255 {
256 MainLog.Instance.Verbose( "Resending " + packet.Type.ToString() + " packet, " +
257 (now - packet.TickCount) + "ms have passed");
258
259 packet.Header.Resent = true;
260 OutPacket(packet);
261 }
262 }
263 }
264 }
265
266 protected void SendAcks()
267 {
268 lock (PendingAcks)
269 {
270 if (PendingAcks.Count > 0)
271 {
272 if (PendingAcks.Count > 250)
273 {
274 // FIXME: Handle the odd case where we have too many pending ACKs queued up
275 MainLog.Instance.Verbose( "Too many ACKs queued up!");
276 return;
277 }
278
279 //OpenSim.Framework.Console.MainLog.Instance.WriteLine("Sending PacketAck");
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}