diff options
Diffstat (limited to 'Server.cs')
-rw-r--r-- | Server.cs | 756 |
1 files changed, 756 insertions, 0 deletions
diff --git a/Server.cs b/Server.cs new file mode 100644 index 0000000..1917922 --- /dev/null +++ b/Server.cs | |||
@@ -0,0 +1,756 @@ | |||
1 | /* | ||
2 | * * Copyright (c) <year>, <copyright holder> | ||
3 | * All rights reserved. | ||
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 <organization> 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 <copyright holder> ``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 <copyright holder> 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 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using libsecondlife; | ||
31 | using System.Collections; | ||
32 | using libsecondlife.Packets; | ||
33 | using libsecondlife.AssetSystem; | ||
34 | using System.Net; | ||
35 | using System.Net.Sockets; | ||
36 | using System.Timers; | ||
37 | |||
38 | //really hacked , messy code | ||
39 | |||
40 | namespace Second_server | ||
41 | { | ||
42 | /// <summary> | ||
43 | /// Description of Server. | ||
44 | /// </summary> | ||
45 | public interface Server_callback | ||
46 | { | ||
47 | void main_callback(Packet pack, User_Agent_info User_info); | ||
48 | void new_user(User_Agent_info User_info); | ||
49 | void error(string text); | ||
50 | } | ||
51 | public class Server | ||
52 | { | ||
53 | /// <summary>A public reference to the client that this Simulator object | ||
54 | /// is attached to</summary> | ||
55 | //public SecondLife Client; | ||
56 | |||
57 | /// <summary>The Region class that this Simulator wraps</summary> | ||
58 | // public Region Region; | ||
59 | |||
60 | /// <summary> | ||
61 | /// Used internally to track sim disconnections, do not modify this | ||
62 | /// variable | ||
63 | /// </summary> | ||
64 | public bool DisconnectCandidate = false; | ||
65 | |||
66 | /// <summary> | ||
67 | /// The ID number associated with this particular connection to the | ||
68 | /// simulator, used to emulate TCP connections. This is used | ||
69 | /// internally for packets that have a CircuitCode field | ||
70 | /// </summary> | ||
71 | public uint CircuitCode | ||
72 | { | ||
73 | get { return circuitCode; } | ||
74 | set { circuitCode = value; } | ||
75 | } | ||
76 | |||
77 | /// <summary> | ||
78 | /// The IP address and port of the server | ||
79 | /// </summary> | ||
80 | public IPEndPoint IPEndPoint | ||
81 | { | ||
82 | get { return ipEndPoint; } | ||
83 | } | ||
84 | |||
85 | /// <summary> | ||
86 | /// A boolean representing whether there is a working connection to the | ||
87 | /// simulator or not | ||
88 | /// </summary> | ||
89 | public bool Connected | ||
90 | { | ||
91 | get { return connected; } | ||
92 | } | ||
93 | |||
94 | private Server_callback callback_object; | ||
95 | //private NetworkManager Network; | ||
96 | // private Dictionary<PacketType, List<NetworkManager.PacketCallback>> Callbacks; | ||
97 | private uint Sequence = 0; | ||
98 | private object SequenceLock = new object(); | ||
99 | private byte[] RecvBuffer = new byte[4096]; | ||
100 | private byte[] ZeroBuffer = new byte[8192]; | ||
101 | private byte[] ZeroOutBuffer = new byte[4096]; | ||
102 | private Socket Connection = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); | ||
103 | private AsyncCallback ReceivedData; | ||
104 | // Packets we sent out that need ACKs from the simulator | ||
105 | // private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); | ||
106 | // Sequence numbers of packets we've received from the simulator | ||
107 | // private Queue<uint> Inbox; | ||
108 | // ACKs that are queued up to be sent to the simulator | ||
109 | //private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); | ||
110 | private bool connected = false; | ||
111 | private uint circuitCode; | ||
112 | private IPEndPoint ipEndPoint; | ||
113 | private EndPoint endPoint; | ||
114 | private IPEndPoint ipeSender; | ||
115 | private EndPoint epSender; | ||
116 | private System.Timers.Timer AckTimer; | ||
117 | private Server_Settings Settings=new Server_Settings(); | ||
118 | public ArrayList User_agents=new ArrayList(); | ||
119 | |||
120 | /// <summary> | ||
121 | /// Constructor for Simulator | ||
122 | /// </summary> | ||
123 | /// <param name="client"></param> | ||
124 | /// <param name="callbacks"></param> | ||
125 | /// <param name="circuit"></param> | ||
126 | /// <param name="ip"></param> | ||
127 | /// <param name="port"></param> | ||
128 | public Server(Server_callback s_callback) | ||
129 | { | ||
130 | |||
131 | this.callback_object=s_callback; | ||
132 | // Client = client; | ||
133 | // Network = client.Network; | ||
134 | // Callbacks = callbacks; | ||
135 | // Region = new Region(client); | ||
136 | // circuitCode = circuit; | ||
137 | // Inbox = new Queue<uint>(Settings.INBOX_SIZE); | ||
138 | AckTimer = new System.Timers.Timer(Settings.NETWORK_TICK_LENGTH); | ||
139 | AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed); | ||
140 | |||
141 | // Initialize the callback for receiving a new packet | ||
142 | ReceivedData = new AsyncCallback(this.OnReceivedData); | ||
143 | |||
144 | // Client.Log("Connecting to " + ip.ToString() + ":" + port, Helpers.LogLevel.Info); | ||
145 | |||
146 | try | ||
147 | { | ||
148 | // Create an endpoint that we will be communicating with (need it in two | ||
149 | // types due to .NET weirdness) | ||
150 | // ipEndPoint = new IPEndPoint(ip, port); | ||
151 | ipEndPoint = new IPEndPoint(IPAddress.Any, 1000); | ||
152 | |||
153 | |||
154 | endPoint = (EndPoint)ipEndPoint; | ||
155 | |||
156 | // Associate this simulator's socket with the given ip/port and start listening | ||
157 | Connection.Bind(endPoint); | ||
158 | |||
159 | ipeSender = new IPEndPoint(IPAddress.Any, 0); | ||
160 | //The epSender identifies the incoming clients | ||
161 | epSender = (EndPoint) ipeSender; | ||
162 | Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null); | ||
163 | |||
164 | |||
165 | // Start the ACK timer | ||
166 | AckTimer.Start(); | ||
167 | |||
168 | |||
169 | |||
170 | // Track the current time for timeout purposes | ||
171 | //int start = Environment.TickCount; | ||
172 | |||
173 | /* while (true) | ||
174 | { | ||
175 | if (connected || Environment.TickCount - start > Settings.SIMULATOR_TIMEOUT) | ||
176 | { | ||
177 | return; | ||
178 | } | ||
179 | System.Threading.Thread.Sleep(10); | ||
180 | }*/ | ||
181 | } | ||
182 | catch (Exception e) | ||
183 | { | ||
184 | // Client.Log(e.ToString(), Helpers.LogLevel.Error); | ||
185 | System.Console.WriteLine(e.Message); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | /// <summary> | ||
190 | /// Disconnect a Simulator | ||
191 | /// </summary> | ||
192 | public void Disconnect() | ||
193 | { | ||
194 | if (connected) | ||
195 | { | ||
196 | connected = false; | ||
197 | AckTimer.Stop(); | ||
198 | |||
199 | // Send the CloseCircuit notice | ||
200 | CloseCircuitPacket close = new CloseCircuitPacket(); | ||
201 | |||
202 | if (Connection.Connected) | ||
203 | { | ||
204 | try | ||
205 | { | ||
206 | // Connection.Send(close.ToBytes()); | ||
207 | } | ||
208 | catch (SocketException) | ||
209 | { | ||
210 | // There's a high probability of this failing if the network is | ||
211 | // disconnecting, so don't even bother logging the error | ||
212 | } | ||
213 | } | ||
214 | |||
215 | try | ||
216 | { | ||
217 | // Shut the socket communication down | ||
218 | // Connection.Shutdown(SocketShutdown.Both); | ||
219 | } | ||
220 | catch (SocketException) | ||
221 | { | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | |||
226 | /// <summary> | ||
227 | /// Sends a packet | ||
228 | /// </summary> | ||
229 | /// <param name="packet">Packet to be sent</param> | ||
230 | /// <param name="incrementSequence">Increment sequence number?</param> | ||
231 | public void SendPacket(Packet packet, bool incrementSequence, User_Agent_info User_info) | ||
232 | { | ||
233 | byte[] buffer; | ||
234 | int bytes; | ||
235 | |||
236 | if (!connected && packet.Type != PacketType.UseCircuitCode) | ||
237 | { | ||
238 | // Client.Log("Trying to send a " + packet.Type.ToString() + " packet when the socket is closed", | ||
239 | // Helpers.LogLevel.Info); | ||
240 | |||
241 | return; | ||
242 | } | ||
243 | |||
244 | if (packet.Header.AckList.Length > 0) | ||
245 | { | ||
246 | // Scrub any appended ACKs since all of the ACK handling is done here | ||
247 | packet.Header.AckList = new uint[0]; | ||
248 | } | ||
249 | packet.Header.AppendedAcks = false; | ||
250 | |||
251 | // Keep track of when this packet was sent out | ||
252 | packet.TickCount = Environment.TickCount; | ||
253 | |||
254 | if (incrementSequence) | ||
255 | { | ||
256 | // Set the sequence number | ||
257 | lock (SequenceLock) | ||
258 | { | ||
259 | if (Sequence > Settings.MAX_SEQUENCE) | ||
260 | Sequence = 1; | ||
261 | else | ||
262 | Sequence++; | ||
263 | packet.Header.Sequence = Sequence; | ||
264 | } | ||
265 | |||
266 | if (packet.Header.Reliable) | ||
267 | { | ||
268 | lock (User_info.NeedAck) | ||
269 | { | ||
270 | if (!User_info.NeedAck.ContainsKey(packet.Header.Sequence)) | ||
271 | { | ||
272 | User_info.NeedAck.Add(packet.Header.Sequence, packet); | ||
273 | } | ||
274 | else | ||
275 | { | ||
276 | // Client.Log("Attempted to add a duplicate sequence number (" + | ||
277 | // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " + | ||
278 | // packet.Type.ToString(), Helpers.LogLevel.Warning); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | // Don't append ACKs to resent packets, in case that's what was causing the | ||
283 | // delivery to fail | ||
284 | if (!packet.Header.Resent) | ||
285 | { | ||
286 | // Append any ACKs that need to be sent out to this packet | ||
287 | lock (User_info.PendingAcks) | ||
288 | { | ||
289 | if (User_info.PendingAcks.Count > 0 && User_info.PendingAcks.Count < Settings.MAX_APPENDED_ACKS && | ||
290 | packet.Type != PacketType.PacketAck && | ||
291 | packet.Type != PacketType.LogoutRequest) | ||
292 | { | ||
293 | packet.Header.AckList = new uint[User_info.PendingAcks.Count]; | ||
294 | |||
295 | int i = 0; | ||
296 | |||
297 | foreach (uint ack in User_info.PendingAcks.Values) | ||
298 | { | ||
299 | packet.Header.AckList[i] = ack; | ||
300 | i++; | ||
301 | } | ||
302 | |||
303 | User_info.PendingAcks.Clear(); | ||
304 | packet.Header.AppendedAcks = true; | ||
305 | } | ||
306 | } | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | |||
311 | // Serialize the packet | ||
312 | buffer = packet.ToBytes(); | ||
313 | bytes = buffer.Length; | ||
314 | |||
315 | try | ||
316 | { | ||
317 | // Zerocode if needed | ||
318 | if (packet.Header.Zerocoded) | ||
319 | { | ||
320 | lock (ZeroOutBuffer) | ||
321 | { | ||
322 | bytes = Helpers.ZeroEncode(buffer, bytes, ZeroOutBuffer); | ||
323 | Connection.SendTo(ZeroOutBuffer, bytes, SocketFlags.None,User_info.endpoint); | ||
324 | } | ||
325 | } | ||
326 | else | ||
327 | { | ||
328 | |||
329 | Connection.SendTo(buffer, bytes, SocketFlags.None,User_info.endpoint); | ||
330 | } | ||
331 | } | ||
332 | catch (SocketException) | ||
333 | { | ||
334 | //Client.Log("Tried to send a " + packet.Type.ToString() + " on a closed socket", | ||
335 | // Helpers.LogLevel.Warning); | ||
336 | |||
337 | Disconnect(); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | /// <summary> | ||
342 | /// Send a raw byte array payload as a packet | ||
343 | /// </summary> | ||
344 | /// <param name="payload">The packet payload</param> | ||
345 | /// <param name="setSequence">Whether the second, third, and fourth bytes | ||
346 | /// should be modified to the current stream sequence number</param> | ||
347 | /* public void SendPacket(byte[] payload, bool setSequence) | ||
348 | { | ||
349 | if (connected) | ||
350 | { | ||
351 | try | ||
352 | { | ||
353 | if (setSequence && payload.Length > 3) | ||
354 | { | ||
355 | lock (SequenceLock) | ||
356 | { | ||
357 | payload[1] = (byte)(Sequence >> 16); | ||
358 | payload[2] = (byte)(Sequence >> 8); | ||
359 | payload[3] = (byte)(Sequence % 256); | ||
360 | Sequence++; | ||
361 | } | ||
362 | } | ||
363 | |||
364 | Connection.Send(payload, payload.Length, SocketFlags.None); | ||
365 | } | ||
366 | catch (SocketException e) | ||
367 | { | ||
368 | // Client.Log(e.ToString(), Helpers.LogLevel.Error); | ||
369 | } | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | // Client.Log("Attempted to send a " + payload.Length + " byte payload when " + | ||
374 | // "we are disconnected", Helpers.LogLevel.Warning); | ||
375 | } | ||
376 | } | ||
377 | */ | ||
378 | /// <summary> | ||
379 | /// Returns Simulator Name as a String | ||
380 | /// </summary> | ||
381 | /// <returns></returns> | ||
382 | public override string ToString() | ||
383 | { | ||
384 | return( " (" + ipEndPoint.ToString() + ")"); | ||
385 | } | ||
386 | |||
387 | /// <summary> | ||
388 | /// Sends out pending acknowledgements | ||
389 | /// </summary> | ||
390 | private void SendAcks(User_Agent_info User_info) | ||
391 | { | ||
392 | lock (User_info.PendingAcks) | ||
393 | { | ||
394 | if (connected && User_info.PendingAcks.Count > 0) | ||
395 | { | ||
396 | if (User_info.PendingAcks.Count > 250) | ||
397 | { | ||
398 | // FIXME: Handle the odd case where we have too many pending ACKs queued up | ||
399 | //Client.Log("Too many ACKs queued up!", Helpers.LogLevel.Error); | ||
400 | return; | ||
401 | } | ||
402 | |||
403 | int i = 0; | ||
404 | PacketAckPacket acks = new PacketAckPacket(); | ||
405 | acks.Packets = new PacketAckPacket.PacketsBlock[User_info.PendingAcks.Count]; | ||
406 | |||
407 | foreach (uint ack in User_info.PendingAcks.Values) | ||
408 | { | ||
409 | acks.Packets[i] = new PacketAckPacket.PacketsBlock(); | ||
410 | acks.Packets[i].ID = ack; | ||
411 | i++; | ||
412 | } | ||
413 | |||
414 | acks.Header.Reliable = false; | ||
415 | SendPacket(acks, true,User_info); | ||
416 | |||
417 | User_info.PendingAcks.Clear(); | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | /// <summary> | ||
422 | /// Resend unacknowledged packets | ||
423 | /// </summary> | ||
424 | private void ResendUnacked(User_Agent_info User_info) | ||
425 | { | ||
426 | if (connected) | ||
427 | { | ||
428 | int now = Environment.TickCount; | ||
429 | |||
430 | lock (User_info.NeedAck) | ||
431 | { | ||
432 | foreach (Packet packet in User_info.NeedAck.Values) | ||
433 | { | ||
434 | if (now - packet.TickCount > Settings.RESEND_TIMEOUT) | ||
435 | { | ||
436 | // Client.Log("Resending " + packet.Type.ToString() + " packet, " + | ||
437 | // (now - packet.TickCount) + "ms have passed", Helpers.LogLevel.Info); | ||
438 | |||
439 | packet.Header.Resent = true; | ||
440 | SendPacket(packet, false,User_info); | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | /// <summary> | ||
447 | /// Callback handler for incomming data | ||
448 | /// </summary> | ||
449 | /// <param name="result"></param> | ||
450 | private void OnReceivedData(IAsyncResult result) | ||
451 | { | ||
452 | |||
453 | ipeSender = new IPEndPoint(IPAddress.Any, 0); | ||
454 | epSender = (EndPoint)ipeSender; | ||
455 | Packet packet = null; | ||
456 | int numBytes; | ||
457 | |||
458 | // If we're receiving data the sim connection is open | ||
459 | connected = true; | ||
460 | |||
461 | // Update the disconnect flag so this sim doesn't time out | ||
462 | DisconnectCandidate = false; | ||
463 | User_Agent_info User_info=null; | ||
464 | |||
465 | lock (RecvBuffer) | ||
466 | { | ||
467 | // Retrieve the incoming packet | ||
468 | try | ||
469 | { | ||
470 | numBytes = Connection.EndReceiveFrom(result, ref epSender); | ||
471 | |||
472 | //find user_agent_info | ||
473 | |||
474 | int packetEnd = numBytes - 1; | ||
475 | packet = Packet.BuildPacket(RecvBuffer, ref packetEnd, ZeroBuffer); | ||
476 | |||
477 | |||
478 | //should check if login/useconnection packet first | ||
479 | if (packet.Type == PacketType.UseCircuitCode) | ||
480 | { | ||
481 | UseCircuitCodePacket cir_pack=(UseCircuitCodePacket)packet; | ||
482 | User_Agent_info new_user=new User_Agent_info(); | ||
483 | new_user.circuitCode=cir_pack.CircuitCode.Code; | ||
484 | new_user.AgentID=cir_pack.CircuitCode.ID; | ||
485 | new_user.SessionID=cir_pack.CircuitCode.SessionID; | ||
486 | new_user.endpoint=epSender; | ||
487 | new_user.Inbox = new Queue<uint>(Settings.INBOX_SIZE); | ||
488 | |||
489 | this.callback_object.new_user(new_user); | ||
490 | this.User_agents.Add(new_user); | ||
491 | |||
492 | } | ||
493 | |||
494 | |||
495 | User_Agent_info temp_agent=null; | ||
496 | IPEndPoint send_ip=(IPEndPoint)epSender; | ||
497 | // this.callback_object.error("incoming: address is "+send_ip.Address +"port number is: "+send_ip.Port.ToString()); | ||
498 | |||
499 | for(int ii=0; ii<this.User_agents.Count ; ii++) | ||
500 | { | ||
501 | temp_agent=(User_Agent_info)this.User_agents[ii]; | ||
502 | IPEndPoint ag_ip=(IPEndPoint)temp_agent.endpoint; | ||
503 | //this.callback_object.error("searching: address is "+ag_ip.Address +"port number is: "+ag_ip.Port.ToString()); | ||
504 | |||
505 | if((ag_ip.Address.ToString()==send_ip.Address.ToString()) && (ag_ip.Port.ToString()==send_ip.Port.ToString())) | ||
506 | { | ||
507 | //this.callback_object.error("found user"); | ||
508 | User_info=temp_agent; | ||
509 | break; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null); | ||
514 | } | ||
515 | catch (SocketException) | ||
516 | { | ||
517 | // Client.Log(endPoint.ToString() + " socket is closed, shutting down " + this.Region.Name, | ||
518 | // Helpers.LogLevel.Info); | ||
519 | |||
520 | connected = false; | ||
521 | //Network.DisconnectSim(this); | ||
522 | return; | ||
523 | } | ||
524 | } | ||
525 | if(User_info==null) | ||
526 | { | ||
527 | |||
528 | //error finding agent | ||
529 | this.callback_object.error("no user found"); | ||
530 | return; | ||
531 | } | ||
532 | |||
533 | // Fail-safe check | ||
534 | if (packet == null) | ||
535 | { | ||
536 | this.callback_object.error("couldn't build packet"); | ||
537 | // Client.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning); | ||
538 | return; | ||
539 | } | ||
540 | //this.callback_object.error("past tests"); | ||
541 | // Track the sequence number for this packet if it's marked as reliable | ||
542 | if (packet.Header.Reliable) | ||
543 | { | ||
544 | if (User_info.PendingAcks.Count > Settings.MAX_PENDING_ACKS) | ||
545 | { | ||
546 | SendAcks(User_info); | ||
547 | } | ||
548 | |||
549 | // Check if we already received this packet | ||
550 | if (User_info.Inbox.Contains(packet.Header.Sequence)) | ||
551 | { | ||
552 | //Client.Log("Received a duplicate " + packet.Type.ToString() + ", sequence=" + | ||
553 | // packet.Header.Sequence + ", resent=" + ((packet.Header.Resent) ? "Yes" : "No") + | ||
554 | // ", Inbox.Count=" + Inbox.Count + ", NeedAck.Count=" + NeedAck.Count, | ||
555 | // Helpers.LogLevel.Info); | ||
556 | |||
557 | // Send an ACK for this packet immediately | ||
558 | //SendAck(packet.Header.Sequence); | ||
559 | |||
560 | // TESTING: Try just queuing up ACKs for resent packets instead of immediately triggering an ACK | ||
561 | lock (User_info.PendingAcks) | ||
562 | { | ||
563 | uint sequence = (uint)packet.Header.Sequence; | ||
564 | if (!User_info.PendingAcks.ContainsKey(sequence)) { User_info.PendingAcks[sequence] = sequence; } | ||
565 | } | ||
566 | |||
567 | // Avoid firing a callback twice for the same packet | ||
568 | // this.callback_object.error("avoiding callback"); | ||
569 | return; | ||
570 | } | ||
571 | else | ||
572 | { | ||
573 | lock (User_info.PendingAcks) | ||
574 | { | ||
575 | uint sequence = (uint)packet.Header.Sequence; | ||
576 | if (!User_info.PendingAcks.ContainsKey(sequence)) { User_info.PendingAcks[sequence] = sequence; } | ||
577 | } | ||
578 | } | ||
579 | } | ||
580 | |||
581 | // Add this packet to our inbox | ||
582 | lock (User_info.Inbox) | ||
583 | { | ||
584 | while (User_info.Inbox.Count >= Settings.INBOX_SIZE) | ||
585 | { | ||
586 | User_info.Inbox.Dequeue(); | ||
587 | } | ||
588 | User_info.Inbox.Enqueue(packet.Header.Sequence); | ||
589 | } | ||
590 | |||
591 | // Handle appended ACKs | ||
592 | if (packet.Header.AppendedAcks) | ||
593 | { | ||
594 | lock (User_info.NeedAck) | ||
595 | { | ||
596 | foreach (uint ack in packet.Header.AckList) | ||
597 | { | ||
598 | User_info.NeedAck.Remove(ack); | ||
599 | } | ||
600 | } | ||
601 | } | ||
602 | |||
603 | // Handle PacketAck packets | ||
604 | if (packet.Type == PacketType.PacketAck) | ||
605 | { | ||
606 | PacketAckPacket ackPacket = (PacketAckPacket)packet; | ||
607 | |||
608 | lock (User_info.NeedAck) | ||
609 | { | ||
610 | foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets) | ||
611 | { | ||
612 | User_info.NeedAck.Remove(block.ID); | ||
613 | } | ||
614 | } | ||
615 | } | ||
616 | |||
617 | // this.callback_object.error("calling callback"); | ||
618 | this.callback_object.main_callback(packet,User_info); | ||
619 | // this.callback_object.error("finished"); | ||
620 | // Fire the registered packet events | ||
621 | #region FireCallbacks | ||
622 | /* if (Callbacks.ContainsKey(packet.Type)) | ||
623 | { | ||
624 | List<NetworkManager.PacketCallback> callbackArray = Callbacks[packet.Type]; | ||
625 | |||
626 | // Fire any registered callbacks | ||
627 | foreach (NetworkManager.PacketCallback callback in callbackArray) | ||
628 | { | ||
629 | if (callback != null) | ||
630 | { | ||
631 | try | ||
632 | { | ||
633 | callback(packet, this); | ||
634 | } | ||
635 | catch (Exception e) | ||
636 | { | ||
637 | Client.Log("Caught an exception in a packet callback: " + e.ToString(), | ||
638 | Helpers.LogLevel.Error); | ||
639 | } | ||
640 | } | ||
641 | } | ||
642 | } | ||
643 | |||
644 | if (Callbacks.ContainsKey(PacketType.Default)) | ||
645 | { | ||
646 | List<NetworkManager.PacketCallback> callbackArray = Callbacks[PacketType.Default]; | ||
647 | |||
648 | // Fire any registered callbacks | ||
649 | foreach (NetworkManager.PacketCallback callback in callbackArray) | ||
650 | { | ||
651 | if (callback != null) | ||
652 | { | ||
653 | try | ||
654 | { | ||
655 | callback(packet, this); | ||
656 | } | ||
657 | catch (Exception e) | ||
658 | { | ||
659 | Client.Log("Caught an exception in a packet callback: " + e.ToString(), | ||
660 | Helpers.LogLevel.Error); | ||
661 | } | ||
662 | } | ||
663 | } | ||
664 | } | ||
665 | */ | ||
666 | #endregion FireCallbacks | ||
667 | } | ||
668 | |||
669 | private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea) | ||
670 | { | ||
671 | if (connected) | ||
672 | { | ||
673 | |||
674 | //TODO for each user_agent_info | ||
675 | for(int i=0; i<this.User_agents.Count; i++) | ||
676 | { | ||
677 | User_Agent_info user=(User_Agent_info)this.User_agents[i]; | ||
678 | |||
679 | SendAcks(user); | ||
680 | ResendUnacked(user); | ||
681 | } | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | |||
686 | public class Server_Settings | ||
687 | { | ||
688 | /// <summary>The version of libsecondlife (not the SL protocol itself)</summary> | ||
689 | public string VERSION = "libsecondlife 0.0.9"; | ||
690 | /// <summary>XML-RPC login server to connect to</summary> | ||
691 | public string LOGIN_SERVER = "https://login.agni.lindenlab.com/cgi-bin/login.cgi"; | ||
692 | |||
693 | /// <summary>Millisecond interval between ticks, where all ACKs are | ||
694 | /// sent out and the age of unACKed packets is checked</summary> | ||
695 | public readonly int NETWORK_TICK_LENGTH = 500; | ||
696 | /// <summary>The maximum value of a packet sequence number. After that | ||
697 | /// we assume the sequence number just rolls over? Or maybe the | ||
698 | /// protocol isn't able to sustain a connection past that</summary> | ||
699 | public readonly int MAX_SEQUENCE = 0xFFFFFF; | ||
700 | /// <summary>Number of milliseconds before a teleport attempt will time | ||
701 | /// out</summary> | ||
702 | public readonly int TELEPORT_TIMEOUT = 18 * 1000; | ||
703 | |||
704 | /// <summary>Number of milliseconds before NetworkManager.Logout() will time out</summary> | ||
705 | public int LOGOUT_TIMEOUT = 5 * 1000; | ||
706 | /// <summary>Number of milliseconds for xml-rpc to timeout</summary> | ||
707 | public int LOGIN_TIMEOUT = 30 * 1000; | ||
708 | /// <summary>The maximum size of the sequence number inbox, used to | ||
709 | /// check for resent and/or duplicate packets</summary> | ||
710 | public int INBOX_SIZE = 100; | ||
711 | /// <summary>Milliseconds before a packet is assumed lost and resent</summary> | ||
712 | public int RESEND_TIMEOUT = 4000; | ||
713 | /// <summary>Milliseconds before the connection to a simulator is | ||
714 | /// assumed lost</summary> | ||
715 | public int SIMULATOR_TIMEOUT = 15000; | ||
716 | /// <summary>Maximum number of queued ACKs to be sent before SendAcks() | ||
717 | /// is forced</summary> | ||
718 | public int MAX_PENDING_ACKS = 10; | ||
719 | /// <summary>Maximum number of ACKs to append to a packet</summary> | ||
720 | public int MAX_APPENDED_ACKS = 10; | ||
721 | /// <summary>Cost of uploading an asset</summary> | ||
722 | public int UPLOAD_COST { get { return priceUpload; } } | ||
723 | |||
724 | |||
725 | private int priceUpload = 0; | ||
726 | |||
727 | public Server_Settings() | ||
728 | { | ||
729 | |||
730 | } | ||
731 | } | ||
732 | |||
733 | public class User_Agent_info | ||
734 | { | ||
735 | public EndPoint endpoint; | ||
736 | public LLUUID AgentID; | ||
737 | public LLUUID SessionID; | ||
738 | public uint circuitCode; | ||
739 | public string name; | ||
740 | public uint localID; | ||
741 | public string first_name; | ||
742 | public string last_name; | ||
743 | |||
744 | public Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); | ||
745 | // Sequence numbers of packets we've received from the simulator | ||
746 | public Queue<uint> Inbox; | ||
747 | // ACKs that are queued up to be sent to the simulator | ||
748 | public Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); | ||
749 | |||
750 | public User_Agent_info() | ||
751 | { | ||
752 | |||
753 | } | ||
754 | } | ||
755 | |||
756 | } | ||