aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/TCPJSONStream/TCPJsonWebSocketServer.cs
blob: c0f679296a2b72ce96b5e78e65abdc0eaf01f016 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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 { };

        

    }
}