corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.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 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Threading;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Net;
32 using System.Net.Sockets;
33 using System.Globalization;
34 using System.IO;
35 using OpenMetaverse.Packets;
36 using OpenMetaverse.StructuredData;
37 using OpenMetaverse.Interfaces;
38 using OpenMetaverse.Messages.Linden;
39  
40 namespace OpenMetaverse
41 {
42 /// <summary>
43 /// NetworkManager is responsible for managing the network layer of
44 /// OpenMetaverse. It tracks all the server connections, serializes
45 /// outgoing traffic and deserializes incoming traffic, and provides
46 /// instances of delegates for network-related events.
47 /// </summary>
48 public partial class NetworkManager
49 {
50 #region Enums
51  
52 /// <summary>
53 /// Explains why a simulator or the grid disconnected from us
54 /// </summary>
55 public enum DisconnectType
56 {
57 /// <summary>The client requested the logout or simulator disconnect</summary>
58 ClientInitiated,
59 /// <summary>The server notified us that it is disconnecting</summary>
60 ServerInitiated,
61 /// <summary>Either a socket was closed or network traffic timed out</summary>
62 NetworkTimeout,
63 /// <summary>The last active simulator shut down</summary>
64 SimShutdown
65 }
66  
67 #endregion Enums
68  
69 #region Structs
70  
71 /// <summary>
72 /// Holds a simulator reference and a decoded packet, these structs are put in
73 /// the packet inbox for event handling
74 /// </summary>
75 public struct IncomingPacket
76 {
77 /// <summary>Reference to the simulator that this packet came from</summary>
78 public Simulator Simulator;
79 /// <summary>Packet that needs to be processed</summary>
80 public Packet Packet;
81  
82 public IncomingPacket(Simulator simulator, Packet packet)
83 {
84 Simulator = simulator;
85 Packet = packet;
86 }
87 }
88  
89 /// <summary>
90 /// Holds a simulator reference and a serialized packet, these structs are put in
91 /// the packet outbox for sending
92 /// </summary>
93 public class OutgoingPacket
94 {
95 /// <summary>Reference to the simulator this packet is destined for</summary>
96 public readonly Simulator Simulator;
97 /// <summary>Packet that needs to be sent</summary>
98 public readonly UDPPacketBuffer Buffer;
99 /// <summary>Sequence number of the wrapped packet</summary>
100 public uint SequenceNumber;
101 /// <summary>Number of times this packet has been resent</summary>
102 public int ResendCount;
103 /// <summary>Environment.TickCount when this packet was last sent over the wire</summary>
104 public int TickCount;
105 /// <summary>Type of the packet</summary>
106 public PacketType Type;
107  
108 public OutgoingPacket(Simulator simulator, UDPPacketBuffer buffer, PacketType type)
109 {
110 Simulator = simulator;
111 Buffer = buffer;
112 this.Type = type;
113 }
114 }
115  
116 #endregion Structs
117  
118 #region Delegates
119  
120 /// <summary>The event subscribers, null of no subscribers</summary>
121 private EventHandler<PacketSentEventArgs> m_PacketSent;
122  
123 ///<summary>Raises the PacketSent Event</summary>
124 /// <param name="e">A PacketSentEventArgs object containing
125 /// the data sent from the simulator</param>
126 protected virtual void OnPacketSent(PacketSentEventArgs e)
127 {
128 EventHandler<PacketSentEventArgs> handler = m_PacketSent;
129 if (handler != null)
130 handler(this, e);
131 }
132  
133 /// <summary>Thread sync lock object</summary>
134 private readonly object m_PacketSentLock = new object();
135  
136 /// <summary>Raised when the simulator sends us data containing
137 /// ...</summary>
138 public event EventHandler<PacketSentEventArgs> PacketSent
139 {
140 add { lock (m_PacketSentLock) { m_PacketSent += value; } }
141 remove { lock (m_PacketSentLock) { m_PacketSent -= value; } }
142 }
143  
144 /// <summary>The event subscribers, null of no subscribers</summary>
145 private EventHandler<LoggedOutEventArgs> m_LoggedOut;
146  
147 ///<summary>Raises the LoggedOut Event</summary>
148 /// <param name="e">A LoggedOutEventArgs object containing
149 /// the data sent from the simulator</param>
150 protected virtual void OnLoggedOut(LoggedOutEventArgs e)
151 {
152 EventHandler<LoggedOutEventArgs> handler = m_LoggedOut;
153 if (handler != null)
154 handler(this, e);
155 }
156  
157 /// <summary>Thread sync lock object</summary>
158 private readonly object m_LoggedOutLock = new object();
159  
160 /// <summary>Raised when the simulator sends us data containing
161 /// ...</summary>
162 public event EventHandler<LoggedOutEventArgs> LoggedOut
163 {
164 add { lock (m_LoggedOutLock) { m_LoggedOut += value; } }
165 remove { lock (m_LoggedOutLock) { m_LoggedOut -= value; } }
166 }
167  
168 /// <summary>The event subscribers, null of no subscribers</summary>
169 private EventHandler<SimConnectingEventArgs> m_SimConnecting;
170  
171 ///<summary>Raises the SimConnecting Event</summary>
172 /// <param name="e">A SimConnectingEventArgs object containing
173 /// the data sent from the simulator</param>
174 protected virtual void OnSimConnecting(SimConnectingEventArgs e)
175 {
176 EventHandler<SimConnectingEventArgs> handler = m_SimConnecting;
177 if (handler != null)
178 handler(this, e);
179 }
180  
181 /// <summary>Thread sync lock object</summary>
182 private readonly object m_SimConnectingLock = new object();
183  
184 /// <summary>Raised when the simulator sends us data containing
185 /// ...</summary>
186 public event EventHandler<SimConnectingEventArgs> SimConnecting
187 {
188 add { lock (m_SimConnectingLock) { m_SimConnecting += value; } }
189 remove { lock (m_SimConnectingLock) { m_SimConnecting -= value; } }
190 }
191  
192 /// <summary>The event subscribers, null of no subscribers</summary>
193 private EventHandler<SimConnectedEventArgs> m_SimConnected;
194  
195 ///<summary>Raises the SimConnected Event</summary>
196 /// <param name="e">A SimConnectedEventArgs object containing
197 /// the data sent from the simulator</param>
198 protected virtual void OnSimConnected(SimConnectedEventArgs e)
199 {
200 EventHandler<SimConnectedEventArgs> handler = m_SimConnected;
201 if (handler != null)
202 handler(this, e);
203 }
204  
205 /// <summary>Thread sync lock object</summary>
206 private readonly object m_SimConnectedLock = new object();
207  
208 /// <summary>Raised when the simulator sends us data containing
209 /// ...</summary>
210 public event EventHandler<SimConnectedEventArgs> SimConnected
211 {
212 add { lock (m_SimConnectedLock) { m_SimConnected += value; } }
213 remove { lock (m_SimConnectedLock) { m_SimConnected -= value; } }
214 }
215  
216 /// <summary>The event subscribers, null of no subscribers</summary>
217 private EventHandler<SimDisconnectedEventArgs> m_SimDisconnected;
218  
219 ///<summary>Raises the SimDisconnected Event</summary>
220 /// <param name="e">A SimDisconnectedEventArgs object containing
221 /// the data sent from the simulator</param>
222 protected virtual void OnSimDisconnected(SimDisconnectedEventArgs e)
223 {
224 EventHandler<SimDisconnectedEventArgs> handler = m_SimDisconnected;
225 if (handler != null)
226 handler(this, e);
227 }
228  
229 /// <summary>Thread sync lock object</summary>
230 private readonly object m_SimDisconnectedLock = new object();
231  
232 /// <summary>Raised when the simulator sends us data containing
233 /// ...</summary>
234 public event EventHandler<SimDisconnectedEventArgs> SimDisconnected
235 {
236 add { lock (m_SimDisconnectedLock) { m_SimDisconnected += value; } }
237 remove { lock (m_SimDisconnectedLock) { m_SimDisconnected -= value; } }
238 }
239  
240 /// <summary>The event subscribers, null of no subscribers</summary>
241 private EventHandler<DisconnectedEventArgs> m_Disconnected;
242  
243 ///<summary>Raises the Disconnected Event</summary>
244 /// <param name="e">A DisconnectedEventArgs object containing
245 /// the data sent from the simulator</param>
246 protected virtual void OnDisconnected(DisconnectedEventArgs e)
247 {
248 EventHandler<DisconnectedEventArgs> handler = m_Disconnected;
249 if (handler != null)
250 handler(this, e);
251 }
252  
253 /// <summary>Thread sync lock object</summary>
254 private readonly object m_DisconnectedLock = new object();
255  
256 /// <summary>Raised when the simulator sends us data containing
257 /// ...</summary>
258 public event EventHandler<DisconnectedEventArgs> Disconnected
259 {
260 add { lock (m_DisconnectedLock) { m_Disconnected += value; } }
261 remove { lock (m_DisconnectedLock) { m_Disconnected -= value; } }
262 }
263  
264 /// <summary>The event subscribers, null of no subscribers</summary>
265 private EventHandler<SimChangedEventArgs> m_SimChanged;
266  
267 ///<summary>Raises the SimChanged Event</summary>
268 /// <param name="e">A SimChangedEventArgs object containing
269 /// the data sent from the simulator</param>
270 protected virtual void OnSimChanged(SimChangedEventArgs e)
271 {
272 EventHandler<SimChangedEventArgs> handler = m_SimChanged;
273 if (handler != null)
274 handler(this, e);
275 }
276  
277 /// <summary>Thread sync lock object</summary>
278 private readonly object m_SimChangedLock = new object();
279  
280 /// <summary>Raised when the simulator sends us data containing
281 /// ...</summary>
282 public event EventHandler<SimChangedEventArgs> SimChanged
283 {
284 add { lock (m_SimChangedLock) { m_SimChanged += value; } }
285 remove { lock (m_SimChangedLock) { m_SimChanged -= value; } }
286 }
287  
288 /// <summary>The event subscribers, null of no subscribers</summary>
289 private EventHandler<EventQueueRunningEventArgs> m_EventQueueRunning;
290  
291 ///<summary>Raises the EventQueueRunning Event</summary>
292 /// <param name="e">A EventQueueRunningEventArgs object containing
293 /// the data sent from the simulator</param>
294 protected virtual void OnEventQueueRunning(EventQueueRunningEventArgs e)
295 {
296 EventHandler<EventQueueRunningEventArgs> handler = m_EventQueueRunning;
297 if (handler != null)
298 handler(this, e);
299 }
300  
301 /// <summary>Thread sync lock object</summary>
302 private readonly object m_EventQueueRunningLock = new object();
303  
304 /// <summary>Raised when the simulator sends us data containing
305 /// ...</summary>
306 public event EventHandler<EventQueueRunningEventArgs> EventQueueRunning
307 {
308 add { lock (m_EventQueueRunningLock) { m_EventQueueRunning += value; } }
309 remove { lock (m_EventQueueRunningLock) { m_EventQueueRunning -= value; } }
310 }
311  
312 #endregion Delegates
313  
314 #region Properties
315  
316 /// <summary>Unique identifier associated with our connections to
317 /// simulators</summary>
318 public uint CircuitCode
319 {
320 get { return _CircuitCode; }
321 set { _CircuitCode = value; }
322 }
323 /// <summary>The simulator that the logged in avatar is currently
324 /// occupying</summary>
325 public Simulator CurrentSim
326 {
327 get { return _CurrentSim; }
328 set { _CurrentSim = value; }
329 }
330 /// <summary>Shows whether the network layer is logged in to the
331 /// grid or not</summary>
332 public bool Connected { get { return connected; } }
333 /// <summary>Number of packets in the incoming queue</summary>
334 public int InboxCount { get { return PacketInbox.Count; } }
335 /// <summary>Number of packets in the outgoing queue</summary>
336 public int OutboxCount { get { return PacketOutbox.Count; } }
337  
338 #endregion Properties
339  
340 /// <summary>All of the simulators we are currently connected to</summary>
341 public List<Simulator> Simulators = new List<Simulator>();
342  
343 /// <summary>Handlers for incoming capability events</summary>
344 internal CapsEventDictionary CapsEvents;
345 /// <summary>Handlers for incoming packets</summary>
346 internal PacketEventDictionary PacketEvents;
347 /// <summary>Incoming packets that are awaiting handling</summary>
348 internal BlockingQueue<IncomingPacket> PacketInbox = new BlockingQueue<IncomingPacket>(Settings.PACKET_INBOX_SIZE);
349 /// <summary>Outgoing packets that are awaiting handling</summary>
350 internal BlockingQueue<OutgoingPacket> PacketOutbox = new BlockingQueue<OutgoingPacket>(Settings.PACKET_INBOX_SIZE);
351  
352 private GridClient Client;
353 private Timer DisconnectTimer;
354 private uint _CircuitCode;
355 private Simulator _CurrentSim = null;
356 private bool connected = false;
357  
358 /// <summary>
359 /// Default constructor
360 /// </summary>
361 /// <param name="client">Reference to the GridClient object</param>
362 public NetworkManager(GridClient client)
363 {
364 Client = client;
365  
366 PacketEvents = new PacketEventDictionary(client);
367 CapsEvents = new CapsEventDictionary(client);
368  
369 // Register internal CAPS callbacks
370 RegisterEventCallback("EnableSimulator", new Caps.EventQueueCallback(EnableSimulatorHandler));
371  
372 // Register the internal callbacks
373 RegisterCallback(PacketType.RegionHandshake, RegionHandshakeHandler);
374 RegisterCallback(PacketType.StartPingCheck, StartPingCheckHandler, false);
375 RegisterCallback(PacketType.DisableSimulator, DisableSimulatorHandler);
376 RegisterCallback(PacketType.KickUser, KickUserHandler);
377 RegisterCallback(PacketType.LogoutReply, LogoutReplyHandler);
378 RegisterCallback(PacketType.CompletePingCheck, CompletePingCheckHandler, false);
379 RegisterCallback(PacketType.SimStats, SimStatsHandler, false);
380  
381 // GLOBAL SETTING: Don't force Expect-100: Continue headers on HTTP POST calls
382 ServicePointManager.Expect100Continue = false;
383 }
384  
385 /// <summary>
386 /// Register an event handler for a packet. This is a low level event
387 /// interface and should only be used if you are doing something not
388 /// supported in the library
389 /// </summary>
390 /// <param name="type">Packet type to trigger events for</param>
391 /// <param name="callback">Callback to fire when a packet of this type
392 /// is received</param>
393 public void RegisterCallback(PacketType type, EventHandler<PacketReceivedEventArgs> callback)
394 {
395 RegisterCallback(type, callback, true);
396 }
397  
398 /// <summary>
399 /// Register an event handler for a packet. This is a low level event
400 /// interface and should only be used if you are doing something not
401 /// supported in the library
402 /// </summary>
403 /// <param name="type">Packet type to trigger events for</param>
404 /// <param name="callback">Callback to fire when a packet of this type
405 /// is received</param>
406 /// <param name="isAsync">True if the callback should be ran
407 /// asynchronously. Only set this to false (synchronous for callbacks
408 /// that will always complete quickly)</param>
409 /// <remarks>If any callback for a packet type is marked as
410 /// asynchronous, all callbacks for that packet type will be fired
411 /// asynchronously</remarks>
412 public void RegisterCallback(PacketType type, EventHandler<PacketReceivedEventArgs> callback, bool isAsync)
413 {
414 PacketEvents.RegisterEvent(type, callback, isAsync);
415 }
416  
417 /// <summary>
418 /// Unregister an event handler for a packet. This is a low level event
419 /// interface and should only be used if you are doing something not
420 /// supported in the library
421 /// </summary>
422 /// <param name="type">Packet type this callback is registered with</param>
423 /// <param name="callback">Callback to stop firing events for</param>
424 public void UnregisterCallback(PacketType type, EventHandler<PacketReceivedEventArgs> callback)
425 {
426 PacketEvents.UnregisterEvent(type, callback);
427 }
428  
429 /// <summary>
430 /// Register a CAPS event handler. This is a low level event interface
431 /// and should only be used if you are doing something not supported in
432 /// the library
433 /// </summary>
434 /// <param name="capsEvent">Name of the CAPS event to register a handler for</param>
435 /// <param name="callback">Callback to fire when a CAPS event is received</param>
436 public void RegisterEventCallback(string capsEvent, Caps.EventQueueCallback callback)
437 {
438 CapsEvents.RegisterEvent(capsEvent, callback);
439 }
440  
441 /// <summary>
442 /// Unregister a CAPS event handler. This is a low level event interface
443 /// and should only be used if you are doing something not supported in
444 /// the library
445 /// </summary>
446 /// <param name="capsEvent">Name of the CAPS event this callback is
447 /// registered with</param>
448 /// <param name="callback">Callback to stop firing events for</param>
449 public void UnregisterEventCallback(string capsEvent, Caps.EventQueueCallback callback)
450 {
451 CapsEvents.UnregisterEvent(capsEvent, callback);
452 }
453  
454 /// <summary>
455 /// Send a packet to the simulator the avatar is currently occupying
456 /// </summary>
457 /// <param name="packet">Packet to send</param>
458 public void SendPacket(Packet packet)
459 {
460 // try CurrentSim, however directly after login this will
461 // be null, so if it is, we'll try to find the first simulator
462 // we're connected to in order to send the packet.
463 Simulator simulator = CurrentSim;
464  
465 if (simulator == null && Client.Network.Simulators.Count >= 1)
466 {
467 Logger.DebugLog("CurrentSim object was null, using first found connected simulator", Client);
468 simulator = Client.Network.Simulators[0];
469 }
470  
471 if (simulator != null && simulator.Connected)
472 {
473 simulator.SendPacket(packet);
474 }
475 else
476 {
477 //throw new NotConnectedException("Packet received before simulator packet processing threads running, make certain you are completely logged in");
478 Logger.Log("Packet received before simulator packet processing threads running, make certain you are completely logged in.", Helpers.LogLevel.Error);
479 }
480 }
481  
482 /// <summary>
483 /// Send a packet to a specified simulator
484 /// </summary>
485 /// <param name="packet">Packet to send</param>
486 /// <param name="simulator">Simulator to send the packet to</param>
487 public void SendPacket(Packet packet, Simulator simulator)
488 {
489 if (simulator != null)
490 {
491 simulator.SendPacket(packet);
492 }
493 else
494 {
495 Logger.Log("Packet received before simulator packet processing threads running, make certain you are completely logged in", Helpers.LogLevel.Error);
496 }
497 }
498  
499 /// <summary>
500 /// Connect to a simulator
501 /// </summary>
502 /// <param name="ip">IP address to connect to</param>
503 /// <param name="port">Port to connect to</param>
504 /// <param name="handle">Handle for this simulator, to identify its
505 /// location in the grid</param>
506 /// <param name="setDefault">Whether to set CurrentSim to this new
507 /// connection, use this if the avatar is moving in to this simulator</param>
508 /// <param name="seedcaps">URL of the capabilities server to use for
509 /// this sim connection</param>
510 /// <returns>A Simulator object on success, otherwise null</returns>
511 public Simulator Connect(IPAddress ip, ushort port, ulong handle, bool setDefault, string seedcaps)
512 {
513 IPEndPoint endPoint = new IPEndPoint(ip, (int)port);
514 return Connect(endPoint, handle, setDefault, seedcaps);
515 }
516  
517 /// <summary>
518 /// Connect to a simulator
519 /// </summary>
520 /// <param name="endPoint">IP address and port to connect to</param>
521 /// <param name="handle">Handle for this simulator, to identify its
522 /// location in the grid</param>
523 /// <param name="setDefault">Whether to set CurrentSim to this new
524 /// connection, use this if the avatar is moving in to this simulator</param>
525 /// <param name="seedcaps">URL of the capabilities server to use for
526 /// this sim connection</param>
527 /// <returns>A Simulator object on success, otherwise null</returns>
528 public Simulator Connect(IPEndPoint endPoint, ulong handle, bool setDefault, string seedcaps)
529 {
530 Simulator simulator = FindSimulator(endPoint);
531  
532 if (simulator == null)
533 {
534 // We're not tracking this sim, create a new Simulator object
535 simulator = new Simulator(Client, endPoint, handle);
536  
537 // Immediately add this simulator to the list of current sims. It will be removed if the
538 // connection fails
539 lock (Simulators) Simulators.Add(simulator);
540 }
541  
542 if (!simulator.Connected)
543 {
544 if (!connected)
545 {
546 // Mark that we are connecting/connected to the grid
547 //
548 connected = true;
549  
550 // Open the queues in case this is a reconnect and they were shut down
551 PacketInbox.Open();
552 PacketOutbox.Open();
553  
554 // Start the packet decoding thread
555 Thread decodeThread = new Thread(new ThreadStart(IncomingPacketHandler));
556 decodeThread.Name = "Incoming UDP packet dispatcher";
557 decodeThread.Start();
558  
559 // Start the packet sending thread
560 Thread sendThread = new Thread(new ThreadStart(OutgoingPacketHandler));
561 sendThread.Name = "Outgoing UDP packet dispatcher";
562 sendThread.Start();
563 }
564  
565 // raise the SimConnecting event and allow any event
566 // subscribers to cancel the connection
567 if (m_SimConnecting != null)
568 {
569 SimConnectingEventArgs args = new SimConnectingEventArgs(simulator);
570 OnSimConnecting(args);
571  
572 if (args.Cancel)
573 {
574 // Callback is requesting that we abort this connection
575 lock (Simulators)
576 {
577 Simulators.Remove(simulator);
578 }
579 return null;
580 }
581 }
582  
583 // Attempt to establish a connection to the simulator
584 if (simulator.Connect(setDefault))
585 {
586 if (DisconnectTimer == null)
587 {
588 // Start a timer that checks if we've been disconnected
589 DisconnectTimer = new Timer(new TimerCallback(DisconnectTimer_Elapsed), null,
590 Client.Settings.SIMULATOR_TIMEOUT, Client.Settings.SIMULATOR_TIMEOUT);
591 }
592  
593 if (setDefault)
594 {
595 SetCurrentSim(simulator, seedcaps);
596 }
597  
598 // Raise the SimConnected event
599 if (m_SimConnected != null)
600 {
601 OnSimConnected(new SimConnectedEventArgs(simulator));
602 }
603  
604 // If enabled, send an AgentThrottle packet to the server to increase our bandwidth
605 if (Client.Settings.SEND_AGENT_THROTTLE)
606 {
607 Client.Throttle.Set(simulator);
608 }
609  
610 return simulator;
611 }
612 else
613 {
614 // Connection failed, remove this simulator from our list and destroy it
615 lock (Simulators)
616 {
617 Simulators.Remove(simulator);
618 }
619  
620 return null;
621 }
622 }
623 else if (setDefault)
624 {
625 // Move in to this simulator
626 simulator.handshakeComplete = false;
627 simulator.UseCircuitCode(true);
628 Client.Self.CompleteAgentMovement(simulator);
629  
630 // We're already connected to this server, but need to set it to the default
631 SetCurrentSim(simulator, seedcaps);
632  
633 // Send an initial AgentUpdate to complete our movement in to the sim
634 if (Client.Settings.SEND_AGENT_UPDATES)
635 {
636 Client.Self.Movement.SendUpdate(true, simulator);
637 }
638  
639 return simulator;
640 }
641 else
642 {
643 // Already connected to this simulator and wasn't asked to set it as the default,
644 // just return a reference to the existing object
645 return simulator;
646 }
647 }
648  
649 /// <summary>
650 /// Begins the non-blocking logout. Makes sure that the LoggedOut event is
651 /// called even if the server does not send a logout reply, and Shutdown()
652 /// is properly called.
653 /// </summary>
654 public void BeginLogout()
655 {
656 // Wait for a logout response (by way of the LoggedOut event. If the
657 // response is received, shutdown will be fired in the callback.
658 // Otherwise we fire it manually with a NetworkTimeout type after LOGOUT_TIMEOUT
659 System.Timers.Timer timeout = new System.Timers.Timer();
660  
661 EventHandler<LoggedOutEventArgs> callback = delegate(object sender, LoggedOutEventArgs e) {
662 Shutdown(DisconnectType.ClientInitiated);
663 timeout.Stop();
664 };
665  
666 LoggedOut += callback;
667  
668 timeout.Interval = Client.Settings.LOGOUT_TIMEOUT;
669 timeout.Elapsed += delegate(object sender, System.Timers.ElapsedEventArgs e) {
670 timeout.Stop();
671 Shutdown(DisconnectType.NetworkTimeout);
672 OnLoggedOut(new LoggedOutEventArgs(new List<UUID>()));
673 };
674 timeout.Start();
675  
676 // Send the packet requesting a clean logout
677 RequestLogout();
678  
679 LoggedOut -= callback;
680 }
681  
682 /// <summary>
683 /// Initiate a blocking logout request. This will return when the logout
684 /// handshake has completed or when <code>Settings.LOGOUT_TIMEOUT</code>
685 /// has expired and the network layer is manually shut down
686 /// </summary>
687 public void Logout()
688 {
689 AutoResetEvent logoutEvent = new AutoResetEvent(false);
690 EventHandler<LoggedOutEventArgs> callback = delegate(object sender, LoggedOutEventArgs e) { logoutEvent.Set(); };
691  
692 LoggedOut += callback;
693  
694 // Send the packet requesting a clean logout
695 RequestLogout();
696  
697 // Wait for a logout response. If the response is received, shutdown
698 // will be fired in the callback. Otherwise we fire it manually with
699 // a NetworkTimeout type
700 if (!logoutEvent.WaitOne(Client.Settings.LOGOUT_TIMEOUT, false))
701 Shutdown(DisconnectType.NetworkTimeout);
702  
703 LoggedOut -= callback;
704 }
705  
706 /// <summary>
707 /// Initiate the logout process. The <code>Shutdown()</code> function
708 /// needs to be manually called.
709 /// </summary>
710 public void RequestLogout()
711 {
712 // No need to run the disconnect timer any more
713 if (DisconnectTimer != null)
714 {
715 DisconnectTimer.Dispose();
716 DisconnectTimer = null;
717 }
718  
719 // This will catch a Logout when the client is not logged in
720 if (CurrentSim == null || !connected)
721 {
722 Logger.Log("Ignoring RequestLogout(), client is already logged out", Helpers.LogLevel.Warning, Client);
723 return;
724 }
725  
726 Logger.Log("Logging out", Helpers.LogLevel.Info, Client);
727  
728 // Send a logout request to the current sim
729 LogoutRequestPacket logout = new LogoutRequestPacket();
730 logout.AgentData.AgentID = Client.Self.AgentID;
731 logout.AgentData.SessionID = Client.Self.SessionID;
732 SendPacket(logout);
733 }
734  
735 /// <summary>
736 /// Close a connection to the given simulator
737 /// </summary>
738 /// <param name="simulator"></param>
739 /// <param name="sendCloseCircuit"></param>
740 public void DisconnectSim(Simulator simulator, bool sendCloseCircuit)
741 {
742 if (simulator != null)
743 {
744 simulator.Disconnect(sendCloseCircuit);
745  
746 // Fire the SimDisconnected event if a handler is registered
747 if (m_SimDisconnected != null)
748 {
749 OnSimDisconnected(new SimDisconnectedEventArgs(simulator, DisconnectType.NetworkTimeout));
750 }
751  
752 lock (Simulators) Simulators.Remove(simulator);
753  
754 if (Simulators.Count == 0) Shutdown(DisconnectType.SimShutdown);
755 }
756 else
757 {
758 Logger.Log("DisconnectSim() called with a null Simulator reference", Helpers.LogLevel.Warning, Client);
759 }
760 }
761  
762  
763 /// <summary>
764 /// Shutdown will disconnect all the sims except for the current sim
765 /// first, and then kill the connection to CurrentSim. This should only
766 /// be called if the logout process times out on <code>RequestLogout</code>
767 /// </summary>
768 /// <param name="type">Type of shutdown</param>
769 public void Shutdown(DisconnectType type)
770 {
771 Shutdown(type, type.ToString());
772 }
773  
774 /// <summary>
775 /// Shutdown will disconnect all the sims except for the current sim
776 /// first, and then kill the connection to CurrentSim. This should only
777 /// be called if the logout process times out on <code>RequestLogout</code>
778 /// </summary>
779 /// <param name="type">Type of shutdown</param>
780 /// <param name="message">Shutdown message</param>
781 public void Shutdown(DisconnectType type, string message)
782 {
783 Logger.Log("NetworkManager shutdown initiated", Helpers.LogLevel.Info, Client);
784  
785 // Send a CloseCircuit packet to simulators if we are initiating the disconnect
786 bool sendCloseCircuit = (type == DisconnectType.ClientInitiated || type == DisconnectType.NetworkTimeout);
787  
788 lock (Simulators)
789 {
790 // Disconnect all simulators except the current one
791 for (int i = 0; i < Simulators.Count; i++)
792 {
793 if (Simulators[i] != null && Simulators[i] != CurrentSim)
794 {
795 Simulators[i].Disconnect(sendCloseCircuit);
796  
797 // Fire the SimDisconnected event if a handler is registered
798 if (m_SimDisconnected != null)
799 {
800 OnSimDisconnected(new SimDisconnectedEventArgs(Simulators[i], type));
801 }
802 }
803 }
804  
805 Simulators.Clear();
806 }
807  
808 if (CurrentSim != null)
809 {
810 // Kill the connection to the curent simulator
811 CurrentSim.Disconnect(sendCloseCircuit);
812  
813 // Fire the SimDisconnected event if a handler is registered
814 if (m_SimDisconnected != null)
815 {
816 OnSimDisconnected(new SimDisconnectedEventArgs(CurrentSim, type));
817 }
818 }
819  
820 // Clear out all of the packets that never had time to process
821 PacketInbox.Close();
822 PacketOutbox.Close();
823  
824 connected = false;
825  
826 // Fire the disconnected callback
827 if (m_Disconnected != null)
828 {
829 OnDisconnected(new DisconnectedEventArgs(type, message));
830 }
831 }
832  
833 /// <summary>
834 /// Searches through the list of currently connected simulators to find
835 /// one attached to the given IPEndPoint
836 /// </summary>
837 /// <param name="endPoint">IPEndPoint of the Simulator to search for</param>
838 /// <returns>A Simulator reference on success, otherwise null</returns>
839 public Simulator FindSimulator(IPEndPoint endPoint)
840 {
841 lock (Simulators)
842 {
843 for (int i = 0; i < Simulators.Count; i++)
844 {
845 if (Simulators[i].IPEndPoint.Equals(endPoint))
846 return Simulators[i];
847 }
848 }
849  
850 return null;
851 }
852  
853 internal void RaisePacketSentEvent(byte[] data, int bytesSent, Simulator simulator)
854 {
855 if (m_PacketSent != null)
856 {
857 OnPacketSent(new PacketSentEventArgs(data, bytesSent, simulator));
858 }
859 }
860  
861 /// <summary>
862 /// Fire an event when an event queue connects for capabilities
863 /// </summary>
864 /// <param name="simulator">Simulator the event queue is attached to</param>
865 internal void RaiseConnectedEvent(Simulator simulator)
866 {
867 if (m_EventQueueRunning != null)
868 {
869 OnEventQueueRunning(new EventQueueRunningEventArgs(simulator));
870 }
871 }
872  
873 private void OutgoingPacketHandler()
874 {
875 OutgoingPacket outgoingPacket = null;
876 Simulator simulator;
877  
878 // FIXME: This is kind of ridiculous. Port the HTB code from Simian over ASAP!
879 System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
880  
881 while (connected)
882 {
883 if (PacketOutbox.Dequeue(100, ref outgoingPacket))
884 {
885 simulator = outgoingPacket.Simulator;
886  
887 // Very primitive rate limiting, keeps a fixed buffer of time between each packet
888 stopwatch.Stop();
889 if (stopwatch.ElapsedMilliseconds < 10)
890 {
891 //Logger.DebugLog(String.Format("Rate limiting, last packet was {0}ms ago", ms));
892 Thread.Sleep(10 - (int)stopwatch.ElapsedMilliseconds);
893 }
894  
895 simulator.SendPacketFinal(outgoingPacket);
896 stopwatch.Start();
897 }
898 }
899 }
900  
901 private void IncomingPacketHandler()
902 {
903 IncomingPacket incomingPacket = new IncomingPacket();
904 Packet packet = null;
905 Simulator simulator = null;
906  
907 while (connected)
908 {
909 // Reset packet to null for the check below
910 packet = null;
911  
912 if (PacketInbox.Dequeue(100, ref incomingPacket))
913 {
914 packet = incomingPacket.Packet;
915 simulator = incomingPacket.Simulator;
916  
917 if (packet != null)
918 {
919 // Skip blacklisted packets
920 if (UDPBlacklist.Contains(packet.Type.ToString()))
921 {
922 Logger.Log(String.Format("Discarding Blacklisted packet {0} from {1}",
923 packet.Type, simulator.IPEndPoint), Helpers.LogLevel.Warning);
924 return;
925 }
926  
927 // Fire the callback(s), if any
928 PacketEvents.RaiseEvent(packet.Type, packet, simulator);
929 }
930 }
931 }
932 }
933  
934 private void SetCurrentSim(Simulator simulator, string seedcaps)
935 {
936 if (simulator != CurrentSim)
937 {
938 Simulator oldSim = CurrentSim;
939 lock (Simulators) CurrentSim = simulator; // CurrentSim is synchronized against Simulators
940  
941 simulator.SetSeedCaps(seedcaps);
942  
943 // If the current simulator changed fire the callback
944 if (m_SimChanged != null && simulator != oldSim)
945 {
946 OnSimChanged(new SimChangedEventArgs(oldSim));
947 }
948 }
949 }
950  
951 #region Timers
952  
953 private void DisconnectTimer_Elapsed(object obj)
954 {
955 if (!connected || CurrentSim == null)
956 {
957 if (DisconnectTimer != null)
958 {
959 DisconnectTimer.Dispose();
960 DisconnectTimer = null;
961 }
962 connected = false;
963 }
964 else if (CurrentSim.DisconnectCandidate)
965 {
966 // The currently occupied simulator hasn't sent us any traffic in a while, shutdown
967 Logger.Log("Network timeout for the current simulator (" +
968 CurrentSim.ToString() + "), logging out", Helpers.LogLevel.Warning, Client);
969  
970 if (DisconnectTimer != null)
971 {
972 DisconnectTimer.Dispose();
973 DisconnectTimer = null;
974 }
975  
976 connected = false;
977  
978 // Shutdown the network layer
979 Shutdown(DisconnectType.NetworkTimeout);
980 }
981 else
982 {
983 // Mark the current simulator as potentially disconnected each time this timer fires.
984 // If the timer is fired again before any packets are received, an actual disconnect
985 // sequence will be triggered
986 CurrentSim.DisconnectCandidate = true;
987 }
988 }
989  
990 #endregion Timers
991  
992 #region Packet Callbacks
993  
994 /// <summary>Process an incoming packet and raise the appropriate events</summary>
995 /// <param name="sender">The sender</param>
996 /// <param name="e">The EventArgs object containing the packet data</param>
997 protected void LogoutReplyHandler(object sender, PacketReceivedEventArgs e)
998 {
999 LogoutReplyPacket logout = (LogoutReplyPacket)e.Packet;
1000  
1001 if ((logout.AgentData.SessionID == Client.Self.SessionID) && (logout.AgentData.AgentID == Client.Self.AgentID))
1002 {
1003 Logger.DebugLog("Logout reply received", Client);
1004  
1005 // Deal with callbacks, if any
1006 if (m_LoggedOut != null)
1007 {
1008 List<UUID> itemIDs = new List<UUID>();
1009  
1010 foreach (LogoutReplyPacket.InventoryDataBlock InventoryData in logout.InventoryData)
1011 {
1012 itemIDs.Add(InventoryData.ItemID);
1013 }
1014  
1015 OnLoggedOut(new LoggedOutEventArgs(itemIDs));
1016 }
1017  
1018 // If we are receiving a LogoutReply packet assume this is a client initiated shutdown
1019 Shutdown(DisconnectType.ClientInitiated);
1020 }
1021 else
1022 {
1023 Logger.Log("Invalid Session or Agent ID received in Logout Reply... ignoring", Helpers.LogLevel.Warning, Client);
1024 }
1025 }
1026  
1027 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1028 /// <param name="sender">The sender</param>
1029 /// <param name="e">The EventArgs object containing the packet data</param>
1030 protected void StartPingCheckHandler(object sender, PacketReceivedEventArgs e)
1031 {
1032 StartPingCheckPacket incomingPing = (StartPingCheckPacket)e.Packet;
1033 CompletePingCheckPacket ping = new CompletePingCheckPacket();
1034 ping.PingID.PingID = incomingPing.PingID.PingID;
1035 ping.Header.Reliable = false;
1036 // TODO: We can use OldestUnacked to correct transmission errors
1037 // I don't think that's right. As far as I can tell, the Viewer
1038 // only uses this to prune its duplicate-checking buffer. -bushing
1039  
1040 SendPacket(ping, e.Simulator);
1041 }
1042  
1043 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1044 /// <param name="sender">The sender</param>
1045 /// <param name="e">The EventArgs object containing the packet data</param>
1046 protected void CompletePingCheckHandler(object sender, PacketReceivedEventArgs e)
1047 {
1048 CompletePingCheckPacket pong = (CompletePingCheckPacket)e.Packet;
1049 //String retval = "Pong2: " + (Environment.TickCount - e.Simulator.Stats.LastPingSent);
1050 //if ((pong.PingID.PingID - e.Simulator.Stats.LastPingID + 1) != 0)
1051 // retval += " (gap of " + (pong.PingID.PingID - e.Simulator.Stats.LastPingID + 1) + ")";
1052  
1053 e.Simulator.Stats.LastLag = Environment.TickCount - e.Simulator.Stats.LastPingSent;
1054 e.Simulator.Stats.ReceivedPongs++;
1055 // Client.Log(retval, Helpers.LogLevel.Info);
1056 }
1057  
1058 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1059 /// <param name="sender">The sender</param>
1060 /// <param name="e">The EventArgs object containing the packet data</param>
1061 protected void SimStatsHandler(object sender, PacketReceivedEventArgs e)
1062 {
1063 if (!Client.Settings.ENABLE_SIMSTATS)
1064 {
1065 return;
1066 }
1067 SimStatsPacket stats = (SimStatsPacket)e.Packet;
1068 for (int i = 0; i < stats.Stat.Length; i++)
1069 {
1070 SimStatsPacket.StatBlock s = stats.Stat[i];
1071 switch (s.StatID)
1072 {
1073 case 0:
1074 e.Simulator.Stats.Dilation = s.StatValue;
1075 break;
1076 case 1:
1077 e.Simulator.Stats.FPS = Convert.ToInt32(s.StatValue);
1078 break;
1079 case 2:
1080 e.Simulator.Stats.PhysicsFPS = s.StatValue;
1081 break;
1082 case 3:
1083 e.Simulator.Stats.AgentUpdates = s.StatValue;
1084 break;
1085 case 4:
1086 e.Simulator.Stats.FrameTime = s.StatValue;
1087 break;
1088 case 5:
1089 e.Simulator.Stats.NetTime = s.StatValue;
1090 break;
1091 case 6:
1092 e.Simulator.Stats.OtherTime = s.StatValue;
1093 break;
1094 case 7:
1095 e.Simulator.Stats.PhysicsTime = s.StatValue;
1096 break;
1097 case 8:
1098 e.Simulator.Stats.AgentTime = s.StatValue;
1099 break;
1100 case 9:
1101 e.Simulator.Stats.ImageTime = s.StatValue;
1102 break;
1103 case 10:
1104 e.Simulator.Stats.ScriptTime = s.StatValue;
1105 break;
1106 case 11:
1107 e.Simulator.Stats.Objects = Convert.ToInt32(s.StatValue);
1108 break;
1109 case 12:
1110 e.Simulator.Stats.ScriptedObjects = Convert.ToInt32(s.StatValue);
1111 break;
1112 case 13:
1113 e.Simulator.Stats.Agents = Convert.ToInt32(s.StatValue);
1114 break;
1115 case 14:
1116 e.Simulator.Stats.ChildAgents = Convert.ToInt32(s.StatValue);
1117 break;
1118 case 15:
1119 e.Simulator.Stats.ActiveScripts = Convert.ToInt32(s.StatValue);
1120 break;
1121 case 16:
1122 e.Simulator.Stats.LSLIPS = Convert.ToInt32(s.StatValue);
1123 break;
1124 case 17:
1125 e.Simulator.Stats.INPPS = Convert.ToInt32(s.StatValue);
1126 break;
1127 case 18:
1128 e.Simulator.Stats.OUTPPS = Convert.ToInt32(s.StatValue);
1129 break;
1130 case 19:
1131 e.Simulator.Stats.PendingDownloads = Convert.ToInt32(s.StatValue);
1132 break;
1133 case 20:
1134 e.Simulator.Stats.PendingUploads = Convert.ToInt32(s.StatValue);
1135 break;
1136 case 21:
1137 e.Simulator.Stats.VirtualSize = Convert.ToInt32(s.StatValue);
1138 break;
1139 case 22:
1140 e.Simulator.Stats.ResidentSize = Convert.ToInt32(s.StatValue);
1141 break;
1142 case 23:
1143 e.Simulator.Stats.PendingLocalUploads = Convert.ToInt32(s.StatValue);
1144 break;
1145 case 24:
1146 e.Simulator.Stats.UnackedBytes = Convert.ToInt32(s.StatValue);
1147 break;
1148 }
1149 }
1150 }
1151  
1152 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1153 /// <param name="sender">The sender</param>
1154 /// <param name="e">The EventArgs object containing the packet data</param>
1155 protected void RegionHandshakeHandler(object sender, PacketReceivedEventArgs e)
1156 {
1157 RegionHandshakePacket handshake = (RegionHandshakePacket)e.Packet;
1158 Simulator simulator = e.Simulator;
1159 e.Simulator.ID = handshake.RegionInfo.CacheID;
1160  
1161 simulator.IsEstateManager = handshake.RegionInfo.IsEstateManager;
1162 simulator.Name = Utils.BytesToString(handshake.RegionInfo.SimName);
1163 simulator.SimOwner = handshake.RegionInfo.SimOwner;
1164 simulator.TerrainBase0 = handshake.RegionInfo.TerrainBase0;
1165 simulator.TerrainBase1 = handshake.RegionInfo.TerrainBase1;
1166 simulator.TerrainBase2 = handshake.RegionInfo.TerrainBase2;
1167 simulator.TerrainBase3 = handshake.RegionInfo.TerrainBase3;
1168 simulator.TerrainDetail0 = handshake.RegionInfo.TerrainDetail0;
1169 simulator.TerrainDetail1 = handshake.RegionInfo.TerrainDetail1;
1170 simulator.TerrainDetail2 = handshake.RegionInfo.TerrainDetail2;
1171 simulator.TerrainDetail3 = handshake.RegionInfo.TerrainDetail3;
1172 simulator.TerrainHeightRange00 = handshake.RegionInfo.TerrainHeightRange00;
1173 simulator.TerrainHeightRange01 = handshake.RegionInfo.TerrainHeightRange01;
1174 simulator.TerrainHeightRange10 = handshake.RegionInfo.TerrainHeightRange10;
1175 simulator.TerrainHeightRange11 = handshake.RegionInfo.TerrainHeightRange11;
1176 simulator.TerrainStartHeight00 = handshake.RegionInfo.TerrainStartHeight00;
1177 simulator.TerrainStartHeight01 = handshake.RegionInfo.TerrainStartHeight01;
1178 simulator.TerrainStartHeight10 = handshake.RegionInfo.TerrainStartHeight10;
1179 simulator.TerrainStartHeight11 = handshake.RegionInfo.TerrainStartHeight11;
1180 simulator.WaterHeight = handshake.RegionInfo.WaterHeight;
1181 simulator.Flags = (RegionFlags)handshake.RegionInfo.RegionFlags;
1182 simulator.BillableFactor = handshake.RegionInfo.BillableFactor;
1183 simulator.Access = (SimAccess)handshake.RegionInfo.SimAccess;
1184  
1185 simulator.RegionID = handshake.RegionInfo2.RegionID;
1186 simulator.ColoLocation = Utils.BytesToString(handshake.RegionInfo3.ColoName);
1187 simulator.CPUClass = handshake.RegionInfo3.CPUClassID;
1188 simulator.CPURatio = handshake.RegionInfo3.CPURatio;
1189 simulator.ProductName = Utils.BytesToString(handshake.RegionInfo3.ProductName);
1190 simulator.ProductSku = Utils.BytesToString(handshake.RegionInfo3.ProductSKU);
1191  
1192 if (handshake.RegionInfo4 != null && handshake.RegionInfo4.Length > 0)
1193 {
1194 simulator.Protocols = (RegionProtocols)handshake.RegionInfo4[0].RegionProtocols;
1195 // Yes, overwrite region flags if we have extended version of them
1196 simulator.Flags = (RegionFlags)handshake.RegionInfo4[0].RegionFlagsExtended;
1197 }
1198  
1199 // Send a RegionHandshakeReply
1200 RegionHandshakeReplyPacket reply = new RegionHandshakeReplyPacket();
1201 reply.AgentData.AgentID = Client.Self.AgentID;
1202 reply.AgentData.SessionID = Client.Self.SessionID;
1203 reply.RegionInfo.Flags = (uint)RegionProtocols.SelfAppearanceSupport;
1204 SendPacket(reply, simulator);
1205  
1206 // We're officially connected to this sim
1207 simulator.connected = true;
1208 simulator.handshakeComplete = true;
1209 simulator.ConnectedEvent.Set();
1210 }
1211  
1212 protected void EnableSimulatorHandler(string capsKey, IMessage message, Simulator simulator)
1213 {
1214 if (!Client.Settings.MULTIPLE_SIMS) return;
1215  
1216 EnableSimulatorMessage msg = (EnableSimulatorMessage)message;
1217  
1218 for (int i = 0; i < msg.Simulators.Length; i++)
1219 {
1220 IPAddress ip = msg.Simulators[i].IP;
1221 ushort port = (ushort)msg.Simulators[i].Port;
1222 ulong handle = msg.Simulators[i].RegionHandle;
1223  
1224 IPEndPoint endPoint = new IPEndPoint(ip, port);
1225  
1226 if (FindSimulator(endPoint) != null) return;
1227  
1228 if (Connect(ip, port, handle, false, null) == null)
1229 {
1230 Logger.Log("Unabled to connect to new sim " + ip + ":" + port,
1231 Helpers.LogLevel.Error, Client);
1232 }
1233 }
1234 }
1235  
1236 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1237 /// <param name="sender">The sender</param>
1238 /// <param name="e">The EventArgs object containing the packet data</param>
1239 protected void DisableSimulatorHandler(object sender, PacketReceivedEventArgs e)
1240 {
1241 DisconnectSim(e.Simulator, false);
1242 }
1243  
1244 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1245 /// <param name="sender">The sender</param>
1246 /// <param name="e">The EventArgs object containing the packet data</param>
1247 protected void KickUserHandler(object sender, PacketReceivedEventArgs e)
1248 {
1249 string message = Utils.BytesToString(((KickUserPacket)e.Packet).UserInfo.Reason);
1250  
1251 // Shutdown the network layer
1252 Shutdown(DisconnectType.ServerInitiated, message);
1253 }
1254  
1255 #endregion Packet Callbacks
1256 }
1257 #region EventArgs
1258  
1259 public class PacketReceivedEventArgs : EventArgs
1260 {
1261 private readonly Packet m_Packet;
1262 private readonly Simulator m_Simulator;
1263  
1264 public Packet Packet { get { return m_Packet; } }
1265 public Simulator Simulator { get { return m_Simulator; } }
1266  
1267 public PacketReceivedEventArgs(Packet packet, Simulator simulator)
1268 {
1269 this.m_Packet = packet;
1270 this.m_Simulator = simulator;
1271 }
1272 }
1273  
1274 public class LoggedOutEventArgs : EventArgs
1275 {
1276 private readonly List<UUID> m_InventoryItems;
1277 public List<UUID> InventoryItems;
1278  
1279 public LoggedOutEventArgs(List<UUID> inventoryItems)
1280 {
1281 this.m_InventoryItems = inventoryItems;
1282 }
1283 }
1284  
1285 public class PacketSentEventArgs : EventArgs
1286 {
1287 private readonly byte[] m_Data;
1288 private readonly int m_SentBytes;
1289 private readonly Simulator m_Simulator;
1290  
1291 public byte[] Data { get { return m_Data; } }
1292 public int SentBytes { get { return m_SentBytes; } }
1293 public Simulator Simulator { get { return m_Simulator; } }
1294  
1295 public PacketSentEventArgs(byte[] data, int bytesSent, Simulator simulator)
1296 {
1297 this.m_Data = data;
1298 this.m_SentBytes = bytesSent;
1299 this.m_Simulator = simulator;
1300 }
1301 }
1302  
1303 public class SimConnectingEventArgs : EventArgs
1304 {
1305 private readonly Simulator m_Simulator;
1306 private bool m_Cancel;
1307  
1308 public Simulator Simulator { get { return m_Simulator; } }
1309  
1310 public bool Cancel
1311 {
1312 get { return m_Cancel; }
1313 set { m_Cancel = value; }
1314 }
1315  
1316 public SimConnectingEventArgs(Simulator simulator)
1317 {
1318 this.m_Simulator = simulator;
1319 this.m_Cancel = false;
1320 }
1321 }
1322  
1323 public class SimConnectedEventArgs : EventArgs
1324 {
1325 private readonly Simulator m_Simulator;
1326 public Simulator Simulator { get { return m_Simulator; } }
1327  
1328 public SimConnectedEventArgs(Simulator simulator)
1329 {
1330 this.m_Simulator = simulator;
1331 }
1332 }
1333  
1334 public class SimDisconnectedEventArgs : EventArgs
1335 {
1336 private readonly Simulator m_Simulator;
1337 private readonly NetworkManager.DisconnectType m_Reason;
1338  
1339 public Simulator Simulator { get { return m_Simulator; } }
1340 public NetworkManager.DisconnectType Reason { get { return m_Reason; } }
1341  
1342 public SimDisconnectedEventArgs(Simulator simulator, NetworkManager.DisconnectType reason)
1343 {
1344 this.m_Simulator = simulator;
1345 this.m_Reason = reason;
1346 }
1347 }
1348  
1349 public class DisconnectedEventArgs : EventArgs
1350 {
1351 private readonly NetworkManager.DisconnectType m_Reason;
1352 private readonly String m_Message;
1353  
1354 public NetworkManager.DisconnectType Reason { get { return m_Reason; } }
1355 public String Message { get { return m_Message; } }
1356  
1357 public DisconnectedEventArgs(NetworkManager.DisconnectType reason, String message)
1358 {
1359 this.m_Reason = reason;
1360 this.m_Message = message;
1361 }
1362 }
1363  
1364 public class SimChangedEventArgs : EventArgs
1365 {
1366 private readonly Simulator m_PreviousSimulator;
1367  
1368 public Simulator PreviousSimulator { get { return m_PreviousSimulator; } }
1369  
1370 public SimChangedEventArgs(Simulator previousSimulator)
1371 {
1372 this.m_PreviousSimulator = previousSimulator;
1373 }
1374 }
1375  
1376 public class EventQueueRunningEventArgs : EventArgs
1377 {
1378 private readonly Simulator m_Simulator;
1379  
1380 public Simulator Simulator { get { return m_Simulator; } }
1381  
1382 public EventQueueRunningEventArgs(Simulator simulator)
1383 {
1384 this.m_Simulator = simulator;
1385 }
1386 }
1387 #endregion
1388 }