diff options
Diffstat (limited to 'Server.cs')
-rw-r--r-- | Server.cs | 645 |
1 files changed, 0 insertions, 645 deletions
diff --git a/Server.cs b/Server.cs deleted file mode 100644 index 5e1bb5a..0000000 --- a/Server.cs +++ /dev/null | |||
@@ -1,645 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) OpenSim project, http://sim.opensecondlife.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 | |||
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 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 | byte[] buffer; | ||
203 | int bytes; | ||
204 | |||
205 | if (!connected && packet.Type != PacketType.UseCircuitCode) | ||
206 | { | ||
207 | // Client.Log("Trying to send a " + packet.Type.ToString() + " packet when the socket is closed", | ||
208 | // Helpers.LogLevel.Info); | ||
209 | |||
210 | return; | ||
211 | } | ||
212 | |||
213 | if (packet.Header.AckList.Length > 0) | ||
214 | { | ||
215 | // Scrub any appended ACKs since all of the ACK handling is done here | ||
216 | packet.Header.AckList = new uint[0]; | ||
217 | } | ||
218 | packet.Header.AppendedAcks = false; | ||
219 | |||
220 | // Keep track of when this packet was sent out | ||
221 | packet.TickCount = Environment.TickCount; | ||
222 | |||
223 | if (incrementSequence) | ||
224 | { | ||
225 | // Set the sequence number | ||
226 | lock (SequenceLock) | ||
227 | { | ||
228 | if (Sequence > Settings.MAX_SEQUENCE) | ||
229 | Sequence = 1; | ||
230 | else | ||
231 | Sequence++; | ||
232 | packet.Header.Sequence = Sequence; | ||
233 | } | ||
234 | |||
235 | if (packet.Header.Reliable) | ||
236 | { | ||
237 | lock (User_info.NeedAck) | ||
238 | { | ||
239 | if (!User_info.NeedAck.ContainsKey(packet.Header.Sequence)) | ||
240 | { | ||
241 | User_info.NeedAck.Add(packet.Header.Sequence, packet); | ||
242 | } | ||
243 | else | ||
244 | { | ||
245 | // Client.Log("Attempted to add a duplicate sequence number (" + | ||
246 | // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " + | ||
247 | // packet.Type.ToString(), Helpers.LogLevel.Warning); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | // Don't append ACKs to resent packets, in case that's what was causing the | ||
252 | // delivery to fail | ||
253 | if (!packet.Header.Resent) | ||
254 | { | ||
255 | // Append any ACKs that need to be sent out to this packet | ||
256 | lock (User_info.PendingAcks) | ||
257 | { | ||
258 | if (User_info.PendingAcks.Count > 0 && User_info.PendingAcks.Count < Settings.MAX_APPENDED_ACKS && | ||
259 | packet.Type != PacketType.PacketAck && | ||
260 | packet.Type != PacketType.LogoutRequest) | ||
261 | { | ||
262 | packet.Header.AckList = new uint[User_info.PendingAcks.Count]; | ||
263 | int i = 0; | ||
264 | |||
265 | foreach (uint ack in User_info.PendingAcks.Values) | ||
266 | { | ||
267 | packet.Header.AckList[i] = ack; | ||
268 | i++; | ||
269 | } | ||
270 | |||
271 | User_info.PendingAcks.Clear(); | ||
272 | packet.Header.AppendedAcks = true; | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | |||
279 | // Serialize the packet | ||
280 | buffer = packet.ToBytes(); | ||
281 | bytes = buffer.Length; | ||
282 | |||
283 | try | ||
284 | { | ||
285 | // Zerocode if needed | ||
286 | if (packet.Header.Zerocoded) | ||
287 | { | ||
288 | lock (ZeroOutBuffer) | ||
289 | { | ||
290 | bytes = Helpers.ZeroEncode(buffer, bytes, ZeroOutBuffer); | ||
291 | Connection.SendTo(ZeroOutBuffer, bytes, SocketFlags.None,User_info.endpoint); | ||
292 | } | ||
293 | } | ||
294 | else | ||
295 | { | ||
296 | |||
297 | Connection.SendTo(buffer, bytes, SocketFlags.None,User_info.endpoint); | ||
298 | } | ||
299 | } | ||
300 | catch (SocketException) | ||
301 | { | ||
302 | //Client.Log("Tried to send a " + packet.Type.ToString() + " on a closed socket", | ||
303 | // Helpers.LogLevel.Warning); | ||
304 | |||
305 | Disconnect(); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | /// <summary> | ||
310 | /// Send a raw byte array payload as a packet | ||
311 | /// </summary> | ||
312 | /// <param name="payload">The packet payload</param> | ||
313 | /// <param name="setSequence">Whether the second, third, and fourth bytes | ||
314 | /// should be modified to the current stream sequence number</param> | ||
315 | /// <summary> | ||
316 | /// Returns Simulator Name as a String | ||
317 | /// </summary> | ||
318 | /// <returns></returns> | ||
319 | public override string ToString() | ||
320 | { | ||
321 | return( " (" + ipEndPoint.ToString() + ")"); | ||
322 | } | ||
323 | |||
324 | /// <summary> | ||
325 | /// Sends out pending acknowledgements | ||
326 | /// </summary> | ||
327 | private void SendAcks(UserAgentInfo User_info) | ||
328 | { | ||
329 | lock (User_info.PendingAcks) | ||
330 | { | ||
331 | if (connected && User_info.PendingAcks.Count > 0) | ||
332 | { | ||
333 | if (User_info.PendingAcks.Count > 250) | ||
334 | { | ||
335 | // FIXME: Handle the odd case where we have too many pending ACKs queued up | ||
336 | //Client.Log("Too many ACKs queued up!", Helpers.LogLevel.Error); | ||
337 | return; | ||
338 | } | ||
339 | |||
340 | int i = 0; | ||
341 | PacketAckPacket acks = new PacketAckPacket(); | ||
342 | acks.Packets = new PacketAckPacket.PacketsBlock[User_info.PendingAcks.Count]; | ||
343 | |||
344 | foreach (uint ack in User_info.PendingAcks.Values) | ||
345 | { | ||
346 | acks.Packets[i] = new PacketAckPacket.PacketsBlock(); | ||
347 | acks.Packets[i].ID = ack; | ||
348 | i++; | ||
349 | } | ||
350 | |||
351 | acks.Header.Reliable = false; | ||
352 | SendPacket(acks, true,User_info); | ||
353 | |||
354 | User_info.PendingAcks.Clear(); | ||
355 | } | ||
356 | } | ||
357 | } | ||
358 | /// <summary> | ||
359 | /// Resend unacknowledged packets | ||
360 | /// </summary> | ||
361 | private void ResendUnacked(UserAgentInfo User_info) | ||
362 | { | ||
363 | if (connected) | ||
364 | { | ||
365 | int now = Environment.TickCount; | ||
366 | |||
367 | lock (User_info.NeedAck) | ||
368 | { | ||
369 | foreach (Packet packet in User_info.NeedAck.Values) | ||
370 | { | ||
371 | if (now - packet.TickCount > Settings.RESEND_TIMEOUT) | ||
372 | { | ||
373 | // Client.Log("Resending " + packet.Type.ToString() + " packet, " + | ||
374 | // (now - packet.TickCount) + "ms have passed", Helpers.LogLevel.Info); | ||
375 | |||
376 | packet.Header.Resent = true; | ||
377 | SendPacket(packet, false,User_info); | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | /// <summary> | ||
384 | /// Callback handler for incomming data | ||
385 | /// </summary> | ||
386 | /// <param name="result"></param> | ||
387 | private void OnReceivedData(IAsyncResult result) | ||
388 | { | ||
389 | |||
390 | ipeSender = new IPEndPoint(IPAddress.Any, 0); | ||
391 | epSender = (EndPoint)ipeSender; | ||
392 | Packet packet = null; | ||
393 | int numBytes; | ||
394 | |||
395 | // If we're receiving data the sim connection is open | ||
396 | connected = true; | ||
397 | |||
398 | // Update the disconnect flag so this sim doesn't time out | ||
399 | DisconnectCandidate = false; | ||
400 | UserAgentInfo User_info=null; | ||
401 | |||
402 | lock (RecvBuffer) | ||
403 | { | ||
404 | // Retrieve the incoming packet | ||
405 | try | ||
406 | { | ||
407 | numBytes = Connection.EndReceiveFrom(result, ref epSender); | ||
408 | |||
409 | //find user_agent_info | ||
410 | |||
411 | int packetEnd = numBytes - 1; | ||
412 | packet = Packet.BuildPacket(RecvBuffer, ref packetEnd, ZeroBuffer); | ||
413 | |||
414 | |||
415 | //should check if login/useconnection packet first | ||
416 | if (packet.Type == PacketType.UseCircuitCode) | ||
417 | { | ||
418 | UseCircuitCodePacket cir_pack=(UseCircuitCodePacket)packet; | ||
419 | UserAgentInfo new_user=new UserAgentInfo(); | ||
420 | new_user.circuitCode=cir_pack.CircuitCode.Code; | ||
421 | new_user.AgentID=cir_pack.CircuitCode.ID; | ||
422 | new_user.SessionID=cir_pack.CircuitCode.SessionID; | ||
423 | new_user.endpoint=epSender; | ||
424 | new_user.Inbox = new Queue<uint>(Settings.INBOX_SIZE); | ||
425 | |||
426 | this.CallbackObject.NewUserCallback(new_user); | ||
427 | this.User_agents.Add(new_user); | ||
428 | |||
429 | } | ||
430 | |||
431 | |||
432 | UserAgentInfo temp_agent=null; | ||
433 | IPEndPoint send_ip=(IPEndPoint)epSender; | ||
434 | // this.callback_object.error("incoming: address is "+send_ip.Address +"port number is: "+send_ip.Port.ToString()); | ||
435 | |||
436 | for(int ii=0; ii<this.User_agents.Count ; ii++) | ||
437 | { | ||
438 | temp_agent=(UserAgentInfo)this.User_agents[ii]; | ||
439 | IPEndPoint ag_ip=(IPEndPoint)temp_agent.endpoint; | ||
440 | //this.callback_object.error("searching: address is "+ag_ip.Address +"port number is: "+ag_ip.Port.ToString()); | ||
441 | |||
442 | if((ag_ip.Address.ToString()==send_ip.Address.ToString()) && (ag_ip.Port.ToString()==send_ip.Port.ToString())) | ||
443 | { | ||
444 | //this.callback_object.error("found user"); | ||
445 | User_info=temp_agent; | ||
446 | break; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null); | ||
451 | } | ||
452 | catch (SocketException) | ||
453 | { | ||
454 | // Client.Log(endPoint.ToString() + " socket is closed, shutting down " + this.Region.Name, | ||
455 | // Helpers.LogLevel.Info); | ||
456 | |||
457 | connected = false; | ||
458 | //Network.DisconnectSim(this); | ||
459 | return; | ||
460 | } | ||
461 | } | ||
462 | if(User_info==null) | ||
463 | { | ||
464 | |||
465 | //error finding agent | ||
466 | this.CallbackObject.ErrorCallback("no user found"); | ||
467 | return; | ||
468 | } | ||
469 | |||
470 | // Fail-safe check | ||
471 | if (packet == null) | ||
472 | { | ||
473 | this.CallbackObject.ErrorCallback("couldn't build packet"); | ||
474 | // Client.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning); | ||
475 | return; | ||
476 | } | ||
477 | //this.callback_object.error("past tests"); | ||
478 | // Track the sequence number for this packet if it's marked as reliable | ||
479 | if (packet.Header.Reliable) | ||
480 | { | ||
481 | if (User_info.PendingAcks.Count > Settings.MAX_PENDING_ACKS) | ||
482 | { | ||
483 | SendAcks(User_info); | ||
484 | } | ||
485 | |||
486 | // Check if we already received this packet | ||
487 | if (User_info.Inbox.Contains(packet.Header.Sequence)) | ||
488 | { | ||
489 | //Client.Log("Received a duplicate " + packet.Type.ToString() + ", sequence=" + | ||
490 | // packet.Header.Sequence + ", resent=" + ((packet.Header.Resent) ? "Yes" : "No") + | ||
491 | // ", Inbox.Count=" + Inbox.Count + ", NeedAck.Count=" + NeedAck.Count, | ||
492 | // Helpers.LogLevel.Info); | ||
493 | |||
494 | // Send an ACK for this packet immediately | ||
495 | //SendAck(packet.Header.Sequence); | ||
496 | |||
497 | // TESTING: Try just queuing up ACKs for resent packets instead of immediately triggering an ACK | ||
498 | lock (User_info.PendingAcks) | ||
499 | { | ||
500 | uint sequence = (uint)packet.Header.Sequence; | ||
501 | if (!User_info.PendingAcks.ContainsKey(sequence)) { User_info.PendingAcks[sequence] = sequence; } | ||
502 | } | ||
503 | |||
504 | // Avoid firing a callback twice for the same packet | ||
505 | // this.callback_object.error("avoiding callback"); | ||
506 | return; | ||
507 | } | ||
508 | else | ||
509 | { | ||
510 | lock (User_info.PendingAcks) | ||
511 | { | ||
512 | uint sequence = (uint)packet.Header.Sequence; | ||
513 | if (!User_info.PendingAcks.ContainsKey(sequence)) { User_info.PendingAcks[sequence] = sequence; } | ||
514 | } | ||
515 | } | ||
516 | } | ||
517 | |||
518 | // Add this packet to our inbox | ||
519 | lock (User_info.Inbox) | ||
520 | { | ||
521 | while (User_info.Inbox.Count >= Settings.INBOX_SIZE) | ||
522 | { | ||
523 | User_info.Inbox.Dequeue(); | ||
524 | } | ||
525 | User_info.Inbox.Enqueue(packet.Header.Sequence); | ||
526 | } | ||
527 | |||
528 | // Handle appended ACKs | ||
529 | if (packet.Header.AppendedAcks) | ||
530 | { | ||
531 | lock (User_info.NeedAck) | ||
532 | { | ||
533 | foreach (uint ack in packet.Header.AckList) | ||
534 | { | ||
535 | User_info.NeedAck.Remove(ack); | ||
536 | } | ||
537 | } | ||
538 | } | ||
539 | |||
540 | // Handle PacketAck packets | ||
541 | if (packet.Type == PacketType.PacketAck) | ||
542 | { | ||
543 | PacketAckPacket ackPacket = (PacketAckPacket)packet; | ||
544 | |||
545 | lock (User_info.NeedAck) | ||
546 | { | ||
547 | foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets) | ||
548 | { | ||
549 | User_info.NeedAck.Remove(block.ID); | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | |||
554 | this.CallbackObject.MainCallback(packet,User_info); | ||
555 | |||
556 | } | ||
557 | |||
558 | private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea) | ||
559 | { | ||
560 | if (connected) | ||
561 | { | ||
562 | |||
563 | //TODO for each user_agent_info | ||
564 | for(int i=0; i<this.User_agents.Count; i++) | ||
565 | { | ||
566 | UserAgentInfo user=(UserAgentInfo)this.User_agents[i]; | ||
567 | |||
568 | SendAcks(user); | ||
569 | ResendUnacked(user); | ||
570 | } | ||
571 | } | ||
572 | } | ||
573 | } | ||
574 | |||
575 | public class Server_Settings | ||
576 | { | ||
577 | /// <summary>The version of libsecondlife (not the SL protocol itself)</summary> | ||
578 | public string VERSION = "libsecondlife 0.0.9"; | ||
579 | /// <summary>XML-RPC login server to connect to</summary> | ||
580 | public string LOGIN_SERVER = "https://login.agni.lindenlab.com/cgi-bin/login.cgi"; | ||
581 | |||
582 | /// <summary>Millisecond interval between ticks, where all ACKs are | ||
583 | /// sent out and the age of unACKed packets is checked</summary> | ||
584 | public readonly int NETWORK_TICK_LENGTH = 500; | ||
585 | /// <summary>The maximum value of a packet sequence number. After that | ||
586 | /// we assume the sequence number just rolls over? Or maybe the | ||
587 | /// protocol isn't able to sustain a connection past that</summary> | ||
588 | public readonly int MAX_SEQUENCE = 0xFFFFFF; | ||
589 | /// <summary>Number of milliseconds before a teleport attempt will time | ||
590 | /// out</summary> | ||
591 | public readonly int TELEPORT_TIMEOUT = 18 * 1000; | ||
592 | |||
593 | /// <summary>Number of milliseconds before NetworkManager.Logout() will time out</summary> | ||
594 | public int LOGOUT_TIMEOUT = 5 * 1000; | ||
595 | /// <summary>Number of milliseconds for xml-rpc to timeout</summary> | ||
596 | public int LOGIN_TIMEOUT = 30 * 1000; | ||
597 | /// <summary>The maximum size of the sequence number inbox, used to | ||
598 | /// check for resent and/or duplicate packets</summary> | ||
599 | public int INBOX_SIZE = 100; | ||
600 | /// <summary>Milliseconds before a packet is assumed lost and resent</summary> | ||
601 | public int RESEND_TIMEOUT = 4000; | ||
602 | /// <summary>Milliseconds before the connection to a simulator is | ||
603 | /// assumed lost</summary> | ||
604 | public int SIMULATOR_TIMEOUT = 15000; | ||
605 | /// <summary>Maximum number of queued ACKs to be sent before SendAcks() | ||
606 | /// is forced</summary> | ||
607 | public int MAX_PENDING_ACKS = 10; | ||
608 | /// <summary>Maximum number of ACKs to append to a packet</summary> | ||
609 | public int MAX_APPENDED_ACKS = 10; | ||
610 | /// <summary>Cost of uploading an asset</summary> | ||
611 | public int UPLOAD_COST { get { return priceUpload; } } | ||
612 | |||
613 | |||
614 | private int priceUpload = 0; | ||
615 | |||
616 | public Server_Settings() | ||
617 | { | ||
618 | |||
619 | } | ||
620 | } | ||
621 | |||
622 | public class UserAgentInfo | ||
623 | { | ||
624 | public EndPoint endpoint; | ||
625 | public LLUUID AgentID; | ||
626 | public LLUUID SessionID; | ||
627 | public uint circuitCode; | ||
628 | public string name; | ||
629 | public uint localID; | ||
630 | public string first_name; | ||
631 | public string last_name; | ||
632 | |||
633 | public Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); | ||
634 | // Sequence numbers of packets we've received from the simulator | ||
635 | public Queue<uint> Inbox; | ||
636 | // ACKs that are queued up to be sent to the simulator | ||
637 | public Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); | ||
638 | |||
639 | public UserAgentInfo() | ||
640 | { | ||
641 | |||
642 | } | ||
643 | } | ||
644 | |||
645 | } | ||