aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/ClientStack/TCPJSONStream/ClientAcceptedEventArgs.cs50
-rw-r--r--OpenSim/Region/ClientStack/TCPJSONStream/ClientNetworkContext.cs146
-rw-r--r--OpenSim/Region/ClientStack/TCPJSONStream/DisconnectedEventArgs.cs17
-rw-r--r--OpenSim/Region/ClientStack/TCPJSONStream/OpenSimWebSocketBase.cs73
-rw-r--r--OpenSim/Region/ClientStack/TCPJSONStream/TCPJsonWebSocketServer.cs163
-rw-r--r--prebuild.xml45
6 files changed, 494 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/TCPJSONStream/ClientAcceptedEventArgs.cs b/OpenSim/Region/ClientStack/TCPJSONStream/ClientAcceptedEventArgs.cs
new file mode 100644
index 0000000..a58eab1
--- /dev/null
+++ b/OpenSim/Region/ClientStack/TCPJSONStream/ClientAcceptedEventArgs.cs
@@ -0,0 +1,50 @@
1using System;
2using System.Net.Sockets;
3
4namespace OpenSim.Region.ClientStack.TCPJSONStream
5{
6 /// <summary>
7 /// Invoked when a client have been accepted by the <see cref="HttpListener"/>
8 /// </summary>
9 /// <remarks>
10 /// Can be used to revoke incoming connections
11 /// </remarks>
12 public class ClientAcceptedEventArgs : EventArgs
13 {
14 private readonly Socket _socket;
15 private bool _revoke;
16
17 /// <summary>
18 /// Initializes a new instance of the <see cref="ClientAcceptedEventArgs"/> class.
19 /// </summary>
20 /// <param name="socket">The socket.</param>
21 public ClientAcceptedEventArgs(Socket socket)
22 {
23 _socket = socket;
24 }
25
26 /// <summary>
27 /// Accepted socket.
28 /// </summary>
29 public Socket Socket
30 {
31 get { return _socket; }
32 }
33
34 /// <summary>
35 /// Client should be revoked.
36 /// </summary>
37 public bool Revoked
38 {
39 get { return _revoke; }
40 }
41
42 /// <summary>
43 /// Client may not be handled.
44 /// </summary>
45 public void Revoke()
46 {
47 _revoke = true;
48 }
49 }
50} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/TCPJSONStream/ClientNetworkContext.cs b/OpenSim/Region/ClientStack/TCPJSONStream/ClientNetworkContext.cs
new file mode 100644
index 0000000..b077b6a
--- /dev/null
+++ b/OpenSim/Region/ClientStack/TCPJSONStream/ClientNetworkContext.cs
@@ -0,0 +1,146 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Net;
5using System.Net.Sockets;
6using System.Text;
7
8namespace OpenSim.Region.ClientStack.TCPJSONStream
9{
10 public class ClientNetworkContext
11 {
12 private Socket _socket;
13 private string _remoteAddress;
14 private string _remotePort;
15 private WebSocketConnectionStage _wsConnectionStatus = WebSocketConnectionStage.Accept;
16 private int _bytesLeft;
17 private NetworkStream _stream;
18 private byte[] _buffer;
19 public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { };
20
21 public ClientNetworkContext(IPEndPoint endPoint, int port, Stream stream, int buffersize, Socket sock)
22 {
23 _socket = sock;
24 _remoteAddress = endPoint.Address.ToString();
25 _remotePort = port.ToString();
26 _stream = stream as NetworkStream;
27 _buffer = new byte[buffersize];
28
29
30 }
31
32 public void BeginRead()
33 {
34 _wsConnectionStatus = WebSocketConnectionStage.Http;
35 try
36 {
37 _stream.BeginRead(_buffer, 0, _buffer.Length, OnReceive, _wsConnectionStatus);
38 }
39 catch (IOException err)
40 {
41 //m_log.Debug(err.ToString());
42 }
43 }
44
45 private void OnReceive(IAsyncResult ar)
46 {
47 try
48 {
49 int bytesRead = _stream.EndRead(ar);
50 if (bytesRead == 0)
51 {
52
53 Disconnected(this, new DisconnectedEventArgs(SocketError.ConnectionReset));
54 return;
55 }
56
57 }
58 catch (Exception)
59 {
60 }
61 }
62 /// <summary>
63 /// send a whole buffer
64 /// </summary>
65 /// <param name="buffer">buffer to send</param>
66 /// <exception cref="ArgumentNullException"></exception>
67 public void Send(byte[] buffer)
68 {
69 if (buffer == null)
70 throw new ArgumentNullException("buffer");
71 Send(buffer, 0, buffer.Length);
72 }
73
74 /// <summary>
75 /// Send data using the stream
76 /// </summary>
77 /// <param name="buffer">Contains data to send</param>
78 /// <param name="offset">Start position in buffer</param>
79 /// <param name="size">number of bytes to send</param>
80 /// <exception cref="ArgumentNullException"></exception>
81 /// <exception cref="ArgumentOutOfRangeException"></exception>
82 public void Send(byte[] buffer, int offset, int size)
83 {
84
85 if (offset + size > buffer.Length)
86 throw new ArgumentOutOfRangeException("offset", offset, "offset + size is beyond end of buffer.");
87
88 if (_stream != null && _stream.CanWrite)
89 {
90 try
91 {
92 _stream.Write(buffer, offset, size);
93 }
94 catch (IOException)
95 {
96
97 }
98 }
99
100 }
101 private void Reset()
102 {
103 if (_stream == null)
104 return;
105 _stream.Dispose();
106 _stream = null;
107 if (_socket == null)
108 return;
109 if (_socket.Connected)
110 _socket.Disconnect(true);
111 _socket = null;
112 }
113 }
114
115 public enum WebSocketConnectionStage
116 {
117 Reuse,
118 Accept,
119 Http,
120 WebSocket,
121 Closed
122 }
123
124 public enum FrameOpCodesRFC6455
125 {
126 Continue = 0x0,
127 Text = 0x1,
128 Binary = 0x2,
129 Close = 0x8,
130 Ping = 0x9,
131 Pong = 0xA
132 }
133
134 public enum DataState
135 {
136 Empty = 0,
137 Waiting = 1,
138 Receiving = 2,
139 Complete = 3,
140 Closed = 4,
141 Ping = 5,
142 Pong = 6
143 }
144
145
146}
diff --git a/OpenSim/Region/ClientStack/TCPJSONStream/DisconnectedEventArgs.cs b/OpenSim/Region/ClientStack/TCPJSONStream/DisconnectedEventArgs.cs
new file mode 100644
index 0000000..32880cc
--- /dev/null
+++ b/OpenSim/Region/ClientStack/TCPJSONStream/DisconnectedEventArgs.cs
@@ -0,0 +1,17 @@
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Net.Sockets;
5using System.Text;
6
7namespace OpenSim.Region.ClientStack.TCPJSONStream
8{
9 public class DisconnectedEventArgs:EventArgs
10 {
11 public SocketError Error { get; private set; }
12 public DisconnectedEventArgs(SocketError err)
13 {
14 Error = err;
15 }
16 }
17}
diff --git a/OpenSim/Region/ClientStack/TCPJSONStream/OpenSimWebSocketBase.cs b/OpenSim/Region/ClientStack/TCPJSONStream/OpenSimWebSocketBase.cs
new file mode 100644
index 0000000..379438d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/TCPJSONStream/OpenSimWebSocketBase.cs
@@ -0,0 +1,73 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
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 OpenSimulator Project 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 THE DEVELOPERS ``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 THE CONTRIBUTORS 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.Net;
30using Nini.Config;
31using OpenSim.Framework;
32
33namespace OpenSim.Region.ClientStack.TCPJSONStream
34{
35 public sealed class TCPJsonWebSocketBase : IClientNetworkServer
36 {
37 private TCPJsonWebSocketServer m_tcpServer;
38
39 public TCPJsonWebSocketBase()
40 {
41 }
42
43 public void Initialise(IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager authenticateClass)
44 {
45 m_tcpServer = new TCPJsonWebSocketServer(_listenIP,ref port, proxyPortOffsetParm, allow_alternate_port,configSource,authenticateClass);
46 }
47
48 public void NetworkStop()
49 {
50 m_tcpServer.Stop();
51 }
52
53 public bool HandlesRegion(Location x)
54 {
55 return m_tcpServer.HandlesRegion(x);
56 }
57
58 public void AddScene(IScene x)
59 {
60 m_tcpServer.AddScene(x);
61 }
62
63 public void Start()
64 {
65 m_tcpServer.Start();
66 }
67
68 public void Stop()
69 {
70 m_tcpServer.Stop();
71 }
72 }
73} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/TCPJSONStream/TCPJsonWebSocketServer.cs b/OpenSim/Region/ClientStack/TCPJSONStream/TCPJsonWebSocketServer.cs
new file mode 100644
index 0000000..c0f6792
--- /dev/null
+++ b/OpenSim/Region/ClientStack/TCPJSONStream/TCPJsonWebSocketServer.cs
@@ -0,0 +1,163 @@
1using System;
2using System.Collections.Generic;
3using System.Net;
4using System.Net.Sockets;
5using System.Reflection;
6using System.Text;
7using System.Threading;
8using Nini.Config;
9using OpenSim.Framework;
10using OpenSim.Region.Framework.Scenes;
11using log4net;
12
13namespace OpenSim.Region.ClientStack.TCPJSONStream
14{
15 public delegate void ExceptionHandler(object source, Exception exception);
16
17 public class TCPJsonWebSocketServer
18 {
19 private readonly IPAddress _address;
20 private readonly int _port;
21 private readonly ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
22 private TcpListener _listener;
23 private int _pendingAccepts;
24 private bool _shutdown;
25 private int _backlogAcceptQueueLength = 5;
26 private Scene m_scene;
27 private Location m_location;
28 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
29
30 public event EventHandler<ClientAcceptedEventArgs> Accepted = delegate { };
31
32
33 public TCPJsonWebSocketServer(IPAddress _listenIP, ref uint port, int proxyPortOffsetParm,
34 bool allow_alternate_port, IConfigSource configSource,
35 AgentCircuitManager authenticateClass)
36 {
37 _address = _listenIP;
38 _port = (int)port; //Why is a uint passed in?
39 }
40 public void Stop()
41 {
42 _shutdown = true;
43 _listener.Stop();
44 if (!_shutdownEvent.WaitOne())
45 m_log.Error("[WEBSOCKETSERVER]: Failed to shutdown listener properly.");
46 _listener = null;
47 }
48
49 public bool HandlesRegion(Location x)
50 {
51 return x == m_location;
52 }
53
54 public void AddScene(IScene scene)
55 {
56 if (m_scene != null)
57 {
58 m_log.Debug("[WEBSOCKETSERVER]: AddScene() called but I already have a scene.");
59 return;
60 }
61 if (!(scene is Scene))
62 {
63 m_log.Error("[WEBSOCKETSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType());
64 return;
65 }
66
67 m_scene = (Scene)scene;
68 m_location = new Location(m_scene.RegionInfo.RegionHandle);
69 }
70
71 public void Start()
72 {
73 _listener = new TcpListener(_address, _port);
74 _listener.Start(_backlogAcceptQueueLength);
75 Interlocked.Increment(ref _pendingAccepts);
76 _listener.BeginAcceptSocket(OnAccept, null);
77 }
78
79 private void OnAccept(IAsyncResult ar)
80 {
81 bool beginAcceptCalled = false;
82 try
83 {
84 int count = Interlocked.Decrement(ref _pendingAccepts);
85 if (_shutdown)
86 {
87 if (count == 0)
88 _shutdownEvent.Set();
89 return;
90 }
91 Interlocked.Increment(ref _pendingAccepts);
92 _listener.BeginAcceptSocket(OnAccept, null);
93 beginAcceptCalled = true;
94 Socket socket = _listener.EndAcceptSocket(ar);
95 if (!OnAcceptingSocket(socket))
96 {
97 socket.Disconnect(true);
98 return;
99 }
100 ClientNetworkContext context = new ClientNetworkContext((IPEndPoint) socket.RemoteEndPoint, _port,
101 new NetworkStream(socket), 16384, socket);
102 //HttpRequestParser parser;
103 context.BeginRead();
104
105 }
106 catch (Exception err)
107 {
108 if (ExceptionThrown == null)
109#if DEBUG
110 throw;
111#else
112 _logWriter.Write(this, LogPrio.Fatal, err.Message);
113 // we can't really do anything but close the connection
114#endif
115 if (ExceptionThrown != null)
116 ExceptionThrown(this, err);
117
118 if (!beginAcceptCalled)
119 RetryBeginAccept();
120
121 }
122 }
123
124 private void RetryBeginAccept()
125 {
126 try
127 {
128
129 _listener.BeginAcceptSocket(OnAccept, null);
130 }
131 catch (Exception err)
132 {
133
134 if (ExceptionThrown == null)
135#if DEBUG
136 throw;
137#else
138 // we can't really do anything but close the connection
139#endif
140 if (ExceptionThrown != null)
141 ExceptionThrown(this, err);
142 }
143 }
144
145 private bool OnAcceptingSocket(Socket sock)
146 {
147 ClientAcceptedEventArgs args = new ClientAcceptedEventArgs(sock);
148 Accepted(this, args);
149 return !args.Revoked;
150 }
151 /// <summary>
152 /// Catch exceptions not handled by the listener.
153 /// </summary>
154 /// <remarks>
155 /// Exceptions will be thrown during debug mode if this event is not used,
156 /// exceptions will be printed to console and suppressed during release mode.
157 /// </remarks>
158 public event ExceptionHandler ExceptionThrown = delegate { };
159
160
161
162 }
163}
diff --git a/prebuild.xml b/prebuild.xml
index 329ff73..d8b4145 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -1466,6 +1466,8 @@
1466 </Files> 1466 </Files>
1467 </Project> 1467 </Project>
1468 1468
1469
1470
1469 <Project frameworkVersion="v3_5" name="OpenSim.Region.ClientStack.LindenCaps" path="OpenSim/Region/ClientStack/Linden/Caps" type="Library"> 1471 <Project frameworkVersion="v3_5" name="OpenSim.Region.ClientStack.LindenCaps" path="OpenSim/Region/ClientStack/Linden/Caps" type="Library">
1470 <Configuration name="Debug"> 1472 <Configuration name="Debug">
1471 <Options> 1473 <Options>
@@ -1508,6 +1510,49 @@
1508 </Files> 1510 </Files>
1509 </Project> 1511 </Project>
1510 1512
1513 <Project frameworkVersion="v3_5" name="OpenSim.Region.ClientStack.TCPJSONStream" path="OpenSim/Region/ClientStack/TCPJSONStream" type="Library">
1514 <Configuration name="Debug">
1515 <Options>
1516 <OutputPath>../../../../bin/</OutputPath>
1517 </Options>
1518 </Configuration>
1519 <Configuration name="Release">
1520 <Options>
1521 <OutputPath>../../../../bin/</OutputPath>
1522 </Options>
1523 </Configuration>
1524
1525 <ReferencePath>../../../../bin/</ReferencePath>
1526 <Reference name="System"/>
1527 <Reference name="System.Core"/>
1528 <Reference name="System.Drawing"/>
1529 <Reference name="System.Xml"/>
1530 <Reference name="System.Web"/>
1531 <Reference name="OpenMetaverseTypes" path="../../../../bin/"/>
1532 <Reference name="OpenMetaverse.StructuredData" path="../../../../bin/"/>
1533 <Reference name="OpenMetaverse" path="../../../../bin/"/>
1534 <Reference name="OpenSim.Data"/>
1535 <Reference name="OpenSim.Framework"/>
1536 <Reference name="OpenSim.Framework.Monitoring"/>
1537 <Reference name="OpenSim.Framework.Servers"/>
1538 <Reference name="OpenSim.Framework.Servers.HttpServer"/>
1539 <Reference name="OpenSim.Framework.Console"/>
1540 <Reference name="OpenSim.Framework.Communications"/>
1541 <Reference name="OpenSim.Region.ClientStack"/>
1542 <Reference name="OpenSim.Region.Framework"/>
1543 <Reference name="OpenSim.Services.Interfaces"/>
1544 <Reference name="Nini" path="../../../../bin/"/>
1545 <Reference name="log4net" path="../../../../bin/"/>
1546 <Reference name="C5" path="../../../../bin/"/>
1547 <Reference name="Nini" path="../../../../bin/"/>
1548
1549 <Files>
1550 <Match pattern="*.cs" recurse="true">
1551 <Exclude name="Tests" pattern="Tests"/>
1552 </Match>
1553 </Files>
1554 </Project>
1555
1511 <Project frameworkVersion="v3_5" name="OpenSim.Region.CoreModules" path="OpenSim/Region/CoreModules" type="Library"> 1556 <Project frameworkVersion="v3_5" name="OpenSim.Region.CoreModules" path="OpenSim/Region/CoreModules" type="Library">
1512 <Configuration name="Debug"> 1557 <Configuration name="Debug">
1513 <Options> 1558 <Options>