aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Server.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Server.cs')
-rw-r--r--Server.cs756
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
28using System;
29using System.Collections.Generic;
30using libsecondlife;
31using System.Collections;
32using libsecondlife.Packets;
33using libsecondlife.AssetSystem;
34using System.Net;
35using System.Net.Sockets;
36using System.Timers;
37
38//really hacked , messy code
39
40namespace 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}