164 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C#
		
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Net;
 | |
| using System.Net.Sockets;
 | |
| using System.Reflection;
 | |
| using System.Text;
 | |
| using System.Threading;
 | |
| using Nini.Config;
 | |
| using OpenSim.Framework;
 | |
| using OpenSim.Region.Framework.Scenes;
 | |
| using log4net;
 | |
| 
 | |
| namespace OpenSim.Region.ClientStack.TCPJSONStream
 | |
| {
 | |
|     public delegate void ExceptionHandler(object source, Exception exception);
 | |
| 
 | |
|     public class TCPJsonWebSocketServer
 | |
|     {
 | |
|         private readonly IPAddress _address;
 | |
|         private readonly int _port;
 | |
|         private readonly ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
 | |
|         private TcpListener _listener;
 | |
|         private int _pendingAccepts;
 | |
|         private bool _shutdown;
 | |
|         private int _backlogAcceptQueueLength = 5;
 | |
|         private Scene m_scene;
 | |
|         private Location m_location;
 | |
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 | |
| 
 | |
|         public event EventHandler<ClientAcceptedEventArgs> Accepted = delegate { };
 | |
| 
 | |
| 
 | |
|         public TCPJsonWebSocketServer(IPAddress _listenIP, ref uint port, int proxyPortOffsetParm,
 | |
|                                       bool allow_alternate_port, IConfigSource configSource,
 | |
|                                       AgentCircuitManager authenticateClass)
 | |
|         {
 | |
|             _address = _listenIP;
 | |
|             _port = (int)port;  //Why is a uint passed in?
 | |
|         }
 | |
|         public void Stop()
 | |
|         {
 | |
|             _shutdown = true;
 | |
|             _listener.Stop();
 | |
|             if (!_shutdownEvent.WaitOne())
 | |
|                 m_log.Error("[WEBSOCKETSERVER]: Failed to shutdown listener properly.");
 | |
|             _listener = null;
 | |
|         }
 | |
| 
 | |
|         public bool HandlesRegion(Location x)
 | |
|         {
 | |
|             return x == m_location;
 | |
|         }
 | |
| 
 | |
|         public void AddScene(IScene scene)
 | |
|         {
 | |
|             if (m_scene != null)
 | |
|             {
 | |
|                 m_log.Debug("[WEBSOCKETSERVER]: AddScene() called but I already have a scene.");
 | |
|                 return;
 | |
|             }
 | |
|             if (!(scene is Scene))
 | |
|             {
 | |
|                 m_log.Error("[WEBSOCKETSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType());
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             m_scene = (Scene)scene;
 | |
|             m_location = new Location(m_scene.RegionInfo.RegionHandle);
 | |
|         }
 | |
| 
 | |
|         public void Start()
 | |
|         {
 | |
|             _listener = new TcpListener(_address, _port);
 | |
|             _listener.Start(_backlogAcceptQueueLength);
 | |
|             Interlocked.Increment(ref _pendingAccepts);
 | |
|             _listener.BeginAcceptSocket(OnAccept, null);
 | |
|         }
 | |
| 
 | |
|         private void OnAccept(IAsyncResult ar)
 | |
|         {
 | |
|             bool beginAcceptCalled = false;
 | |
|             try
 | |
|             {
 | |
|                 int count = Interlocked.Decrement(ref _pendingAccepts);
 | |
|                 if (_shutdown)
 | |
|                 {
 | |
|                     if (count == 0)
 | |
|                         _shutdownEvent.Set();
 | |
|                     return;
 | |
|                 }
 | |
|                 Interlocked.Increment(ref _pendingAccepts);
 | |
|                 _listener.BeginAcceptSocket(OnAccept, null);
 | |
|                 beginAcceptCalled = true;
 | |
|                 Socket socket = _listener.EndAcceptSocket(ar);
 | |
|                 if (!OnAcceptingSocket(socket))
 | |
|                 {
 | |
|                     socket.Disconnect(true);
 | |
|                     return;
 | |
|                 }
 | |
|                 ClientNetworkContext context = new ClientNetworkContext((IPEndPoint) socket.RemoteEndPoint, _port,
 | |
|                                                                         new NetworkStream(socket), 16384, socket);
 | |
|                 HttpRequestParser parser;
 | |
|                 context.BeginRead();
 | |
| 
 | |
|             }
 | |
|             catch (Exception err)
 | |
|             {
 | |
|                 if (ExceptionThrown == null)
 | |
| #if DEBUG
 | |
|                     throw;
 | |
| #else
 | |
|                    _logWriter.Write(this, LogPrio.Fatal, err.Message);
 | |
|                 // we can't really do anything but close the connection
 | |
| #endif
 | |
|                 if (ExceptionThrown != null)
 | |
|                     ExceptionThrown(this, err);
 | |
| 
 | |
|                 if (!beginAcceptCalled)
 | |
|                     RetryBeginAccept();
 | |
| 
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void RetryBeginAccept()
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 
 | |
|                 _listener.BeginAcceptSocket(OnAccept, null);
 | |
|             }
 | |
|             catch (Exception err)
 | |
|             {
 | |
|                 
 | |
|                 if (ExceptionThrown == null)
 | |
| #if DEBUG
 | |
|                     throw;
 | |
| #else
 | |
|                 // we can't really do anything but close the connection
 | |
| #endif
 | |
|                 if (ExceptionThrown != null)
 | |
|                     ExceptionThrown(this, err);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private bool OnAcceptingSocket(Socket sock)
 | |
|         {
 | |
|             ClientAcceptedEventArgs args = new ClientAcceptedEventArgs(sock);
 | |
|             Accepted(this, args);
 | |
|             return !args.Revoked;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Catch exceptions not handled by the listener.
 | |
|         /// </summary>
 | |
|         /// <remarks>
 | |
|         /// Exceptions will be thrown during debug mode if this event is not used,
 | |
|         /// exceptions will be printed to console and suppressed during release mode.
 | |
|         /// </remarks>
 | |
|         public event ExceptionHandler ExceptionThrown = delegate { };
 | |
| 
 | |
|         
 | |
| 
 | |
|     }
 | |
| }
 |