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