aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Server.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Server.cs')
-rw-r--r--Server.cs645
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
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 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}