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