aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorTedd Hansen2008-01-12 00:48:58 +0000
committerTedd Hansen2008-01-12 00:48:58 +0000
commit1e9a66cbaae97759c5c4e936664b5cc7a4feca89 (patch)
tree902166cca5b637ca85d97a6d8b8d941a4ed4a138 /OpenSim/Region
parentFix some warnings under mono. (diff)
downloadopensim-SC-1e9a66cbaae97759c5c4e936664b5cc7a4feca89.zip
opensim-SC-1e9a66cbaae97759c5c4e936664b5cc7a4feca89.tar.gz
opensim-SC-1e9a66cbaae97759c5c4e936664b5cc7a4feca89.tar.bz2
opensim-SC-1e9a66cbaae97759c5c4e936664b5cc7a4feca89.tar.xz
ScriptServer communication protocol (v1), primitive RPC-like TCP client/server
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/TRPC/TCPClient.cs109
-rw-r--r--OpenSim/Region/ScriptEngine/Common/TRPC/TCPCommon.cs33
-rw-r--r--OpenSim/Region/ScriptEngine/Common/TRPC/TCPServer.cs106
-rw-r--r--OpenSim/Region/ScriptEngine/Common/TRPC/TCPSocket.cs86
-rw-r--r--OpenSim/Region/ScriptEngine/Common/TRPC_Remote.cs144
-rw-r--r--OpenSim/Region/ScriptEngine/RemoteServer/EventManager.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/RemoteServer/RemoteServer.cs16
7 files changed, 489 insertions, 11 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/TRPC/TCPClient.cs b/OpenSim/Region/ScriptEngine/Common/TRPC/TCPClient.cs
new file mode 100644
index 0000000..3230614
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Common/TRPC/TCPClient.cs
@@ -0,0 +1,109 @@
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Net;
5using System.Net.Sockets;
6using System.Text;
7
8namespace OpenSim.Region.ScriptEngine.Common.TRPC
9{
10 public class TCPClient: TCPCommon.ClientInterface
11 {
12
13 public TCPClient()
14 {
15 }
16 private readonly Dictionary<int, TCPSocket> Clients = new Dictionary<int, TCPSocket>();
17 private int ClientCount = 0;
18
19
20 public event TCPCommon.ClientConnectedDelegate ClientConnected;
21 public event TCPCommon.DataReceivedDelegate DataReceived;
22 public event TCPCommon.DataSentDelegate DataSent;
23 public event TCPCommon.CloseDelegate Close;
24 public event TCPCommon.ConnectErrorDelegate ConnectError;
25
26
27 /// <summary>
28 /// Creates client connection
29 /// </summary>
30 public void Connect(string RemoteHost, int RemotePort)
31 {
32 Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
33 IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(RemoteHost), RemotePort);
34 newsock.BeginConnect(ipe, new AsyncCallback(asyncConnected), newsock);
35
36
37 }
38
39 public void Disconnect(int ID)
40 {
41 Clients[ID].Disconnect();
42 }
43
44 void asyncConnected(IAsyncResult iar)
45 {
46 Socket client = (Socket)iar.AsyncState;
47 try
48 {
49 client.EndConnect(iar);
50
51
52 int id = ClientCount++;
53 TCPSocket S = new TCPSocket(id, client);
54
55 // Add to dictionary
56 Clients.Add(id, S);
57
58 // Add event handlers
59 S.Close += new TCPSocket.CloseDelegate(S_Close);
60 S.DataReceived += new TCPSocket.DataReceivedDelegate(S_DataReceived);
61 S.DataSent += new TCPSocket.DataSentDelegate(S_DataSent);
62
63 // Start it
64 S.Start();
65
66 Debug.WriteLine("Connection established: " + client.RemoteEndPoint.ToString());
67
68 // Fire Connected-event
69 if (ClientConnected != null)
70 ClientConnected(id, client.RemoteEndPoint);
71
72 }
73 catch (SocketException sex)
74 {
75 if (ConnectError != null)
76 ConnectError(sex.Message);
77 }
78 }
79
80
81
82
83 void S_DataSent(int ID, int length)
84 {
85 if (DataSent != null)
86 DataSent(ID, length);
87 }
88
89 void S_DataReceived(int ID, byte[] data, int offset, int length)
90 {
91 if (DataReceived != null)
92 DataReceived(ID, data, offset, length);
93 }
94
95 void S_Close(int ID)
96 {
97 if (Close != null)
98 Close(ID);
99 Clients.Remove(ID);
100 }
101
102 public void Send(int clientID, byte[] data, int offset, int len)
103 {
104 Clients[clientID].Send(clientID, data, offset, len);
105 }
106
107
108 }
109} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/TRPC/TCPCommon.cs b/OpenSim/Region/ScriptEngine/Common/TRPC/TCPCommon.cs
new file mode 100644
index 0000000..83548b4
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Common/TRPC/TCPCommon.cs
@@ -0,0 +1,33 @@
1namespace OpenSim.Region.ScriptEngine.Common.TRPC
2{
3 public class TCPCommon
4 {
5 public delegate void ClientConnectedDelegate(int ID, System.Net.EndPoint Remote);
6 public delegate void DataReceivedDelegate(int ID, byte[] data, int offset, int length);
7 public delegate void DataSentDelegate(int ID, int length);
8 public delegate void CloseDelegate(int ID);
9 public delegate void ConnectErrorDelegate(string Reason);
10
11
12 public interface ServerAndClientInterface
13 {
14 void Send(int clientID, byte[] data, int offset, int len);
15 event ClientConnectedDelegate ClientConnected;
16 event DataReceivedDelegate DataReceived;
17 event DataSentDelegate DataSent;
18 event CloseDelegate Close;
19 }
20 public interface ClientInterface : ServerAndClientInterface
21 {
22 event TCPCommon.ConnectErrorDelegate ConnectError;
23 void Connect(string RemoteHost, int RemotePort);
24 void Disconnect(int ID);
25 }
26 public interface ServerInterface : ServerAndClientInterface
27 {
28 void StartListen();
29 void StopListen();
30 }
31
32 }
33} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/TRPC/TCPServer.cs b/OpenSim/Region/ScriptEngine/Common/TRPC/TCPServer.cs
new file mode 100644
index 0000000..3af898a
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Common/TRPC/TCPServer.cs
@@ -0,0 +1,106 @@
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Net;
5using System.Net.Sockets;
6using TCPCommon=OpenSim.Region.ScriptEngine.Common.TRPC.TCPCommon;
7
8namespace OpenSim.Region.ScriptEngine.Common.TRPC
9{
10 public class TCPServer: TCPCommon.ServerInterface
11 {
12 public readonly int LocalPort;
13 public TCPServer(int localPort)
14 {
15 LocalPort = localPort;
16 }
17
18 private Socket server;
19
20 /// <summary>
21 /// Starts listening for new connections
22 /// </summary>
23 public void StartListen()
24 {
25 server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
26 IPEndPoint ipe = new IPEndPoint(IPAddress.Any, LocalPort);
27 server.Bind(ipe);
28 server.Listen(10);
29 server.BeginAccept(new AsyncCallback(AsyncAcceptConnections), server);
30 }
31 /// <summary>
32 /// Stops listening for new connections
33 /// </summary>
34 public void StopListen()
35 {
36 server.Close();
37 server = null;
38 }
39
40 private readonly Dictionary<int, TCPSocket> Clients = new Dictionary<int, TCPSocket>();
41 private int ClientCount = 0;
42
43
44 public event TCPCommon.ClientConnectedDelegate ClientConnected;
45 public event TCPCommon.DataReceivedDelegate DataReceived;
46 public event TCPCommon.DataSentDelegate DataSent;
47 public event TCPCommon.CloseDelegate Close;
48
49 /// <summary>
50 /// Async callback for new connections
51 /// </summary>
52 /// <param name="ar"></param>
53 private void AsyncAcceptConnections(IAsyncResult ar)
54 {
55 int id = ClientCount++;
56 Socket oldserver = (Socket)ar.AsyncState;
57 Socket client = oldserver.EndAccept(ar);
58 TCPSocket S = new TCPSocket(id, client);
59
60 // Add to dictionary
61 Clients.Add(id, S);
62
63 // Add event handlers
64 S.Close += new TCPSocket.CloseDelegate(S_Close);
65 S.DataReceived += new TCPSocket.DataReceivedDelegate(S_DataReceived);
66 S.DataSent += new TCPSocket.DataSentDelegate(S_DataSent);
67
68 // Start it
69 S.Start();
70
71 Debug.WriteLine("Connection received: " + client.RemoteEndPoint.ToString());
72
73 // Fire Connected-event
74 if (ClientConnected != null)
75 ClientConnected(id, client.RemoteEndPoint);
76
77 }
78
79 void S_DataSent(int ID, int length)
80 {
81 if (DataSent != null)
82 DataSent(ID, length);
83 }
84
85 void S_DataReceived(int ID, byte[] data, int offset, int length)
86 {
87 if (DataReceived != null)
88 DataReceived(ID, data, offset, length);
89 }
90
91 void S_Close(int ID)
92 {
93 if (Close != null)
94 Close(ID);
95 Clients.Remove(ID);
96 }
97
98 public void Send(int clientID, byte[] data, int offset, int len)
99 {
100 Clients[clientID].Send(clientID, data, offset, len);
101 }
102
103
104
105 }
106} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/TRPC/TCPSocket.cs b/OpenSim/Region/ScriptEngine/Common/TRPC/TCPSocket.cs
new file mode 100644
index 0000000..1079846
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Common/TRPC/TCPSocket.cs
@@ -0,0 +1,86 @@
1using System;
2using System.Net.Sockets;
3
4namespace OpenSim.Region.ScriptEngine.Common.TRPC
5{
6 public class TCPSocket
7 {
8
9 public readonly Socket Client;
10 public readonly int ID;
11
12 public delegate void DataReceivedDelegate(int ID, byte[] data, int offset, int length);
13 public delegate void DataSentDelegate(int ID, int length);
14 public delegate void CloseDelegate(int ID);
15 public event DataReceivedDelegate DataReceived;
16 public event DataSentDelegate DataSent;
17 public event CloseDelegate Close;
18
19 private byte[] RecvQueue = new byte[4096];
20 private int RecvQueueSize = 4096;
21
22 public TCPSocket(int id, Socket client)
23 {
24 ID = id;
25 Client = client;
26 }
27 public void Start()
28 {
29 // Start listening
30 BeginReceive();
31 }
32
33 private void BeginReceive()
34 {
35 Client.BeginReceive(RecvQueue, 0, RecvQueueSize, SocketFlags.None, new AsyncCallback(asyncDataReceived), Client);
36 }
37
38 /// <summary>
39 /// Callback for successful receive (or connection close)
40 /// </summary>
41 /// <param name="ar"></param>
42 private void asyncDataReceived(IAsyncResult ar)
43 {
44 Socket client = (Socket)ar.AsyncState;
45 int recv = client.EndReceive(ar);
46
47 // Is connection closed?
48 if (recv == 0)
49 {
50 client.Close();
51 Close(ID);
52 return;
53 }
54
55 // Call receive event
56 DataReceived(ID, RecvQueue, 0, recv);
57
58 // Start new receive
59 BeginReceive();
60
61 }
62
63
64 public void Send(int clientID, byte[] data, int offset, int len)
65 {
66 Client.BeginSend(data, offset, len, SocketFlags.None, new AsyncCallback(asyncDataSent), Client);
67 }
68
69 /// <summary>
70 /// Callback for successful send
71 /// </summary>
72 /// <param name="ar"></param>
73 void asyncDataSent(IAsyncResult ar)
74 {
75 Socket client = (Socket)ar.AsyncState;
76 int sent = client.EndSend(ar);
77 DataSent(ID, sent);
78 }
79
80 public void Disconnect()
81 {
82 Client.Close();
83 Close(ID);
84 }
85 }
86} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Common/TRPC_Remote.cs b/OpenSim/Region/ScriptEngine/Common/TRPC_Remote.cs
new file mode 100644
index 0000000..f8ec7b5
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Common/TRPC_Remote.cs
@@ -0,0 +1,144 @@
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Text;
5using OpenSim.Region.ScriptEngine.Common.TRPC;
6
7namespace OpenSim.Region.ScriptEngine.Common
8{
9 public class TRPC_Remote
10 {
11 public readonly int MaxQueueSize = 1024 * 10;
12 public readonly TCPCommon.ServerAndClientInterface TCPS;
13
14 public delegate void ReceiveCommandDelegate(int ID, string Command, params object[] p);
15 public event ReceiveCommandDelegate ReceiveCommand;
16
17 // TODO: Maybe we should move queue into TCPSocket so we won't have to keep one queue instance per connection
18 private System.Collections.Generic.Dictionary<int, InQueueStruct> InQueue = new Dictionary<int, InQueueStruct>();
19 private class InQueueStruct
20 {
21 public byte[] Queue;
22 public int QueueSize;
23 public object QueueLockObject = new object();
24 }
25
26 public TRPC_Remote(TCPCommon.ServerAndClientInterface TCPClientOrServer)
27 {
28 TCPS = TCPClientOrServer;
29 TCPS.Close += new TCPCommon.CloseDelegate(TCPS_Close);
30 TCPS.ClientConnected += new TCPCommon.ClientConnectedDelegate(TCPS_ClientConnected);
31 TCPS.DataReceived += new TCPCommon.DataReceivedDelegate(TCPS_DataReceived);
32 //TCPS.StartListen();
33 }
34
35 void TCPS_ClientConnected(int ID, System.Net.EndPoint Remote)
36 {
37 // Create a incoming queue for this connection
38 InQueueStruct iq = new InQueueStruct();
39 iq.Queue = new byte[MaxQueueSize];
40 iq.QueueSize = 0;
41 InQueue.Add(ID, iq);
42 }
43
44 void TCPS_Close(int ID)
45 {
46 // Remove queue
47 InQueue.Remove(ID);
48 }
49
50 void TCPS_DataReceived(int ID, byte[] data, int offset, int length)
51 {
52 // Copy new data to incoming queue
53 lock (InQueue[ID].QueueLockObject)
54 {
55 Array.Copy(data, offset, InQueue[ID].Queue, InQueue[ID].QueueSize, length);
56 InQueue[ID].QueueSize += length;
57
58 // Process incoming queue
59 ProcessQueue(ID);
60 }
61 }
62
63 private void ProcessQueue(int ID)
64 {
65
66 // This is just a temp implementation -- not so fast :)
67
68 InQueueStruct myIQS = InQueue[ID];
69 if (myIQS.QueueSize == 0)
70 return;
71
72 string receivedData = Encoding.ASCII.GetString(myIQS.Queue, 0, myIQS.QueueSize);
73 Debug.WriteLine("RAW: " + receivedData);
74
75
76 byte newLine = 10;
77 while (true)
78 {
79 bool ShouldProcess = false;
80 int lineEndPos = 0;
81
82 // Look for newline
83 for (int i = 0; i < myIQS.QueueSize; i++)
84 {
85 if (myIQS.Queue[i] == newLine)
86 {
87 ShouldProcess = true;
88 lineEndPos = i;
89 break;
90 }
91 }
92
93 // Process it?
94 if (!ShouldProcess)
95 return;
96 // Yes
97 string cmdLine = Encoding.ASCII.GetString(myIQS.Queue, 0, lineEndPos);
98 Debug.WriteLine("Command: " + cmdLine);
99
100 // Fix remaining queue in an inefficient way
101 byte[] newQueue = new byte[MaxQueueSize];
102 Array.Copy(myIQS.Queue, lineEndPos, newQueue, 0, myIQS.QueueSize - lineEndPos);
103 myIQS.Queue = newQueue;
104 myIQS.QueueSize -= (lineEndPos + 1);
105
106 // Now back to the command
107 string[] parts = cmdLine.Split(',');
108 if (parts.Length > 0)
109 {
110 string cmd = parts[0];
111 int paramCount = parts.Length - 1;
112 string[] param = null;
113
114 if (paramCount > 0)
115 {
116 // Process all parameters (decoding them from URL encoding)
117 param = new string[paramCount];
118 for (int i = 1; i < parts.Length; i++)
119 {
120 param[i - 1] = System.Web.HttpUtility.UrlDecode(parts[i]);
121 }
122 }
123
124 ReceiveCommand(ID, cmd, param);
125 }
126 }
127 }
128
129 public void SendCommand(int ID, string Command, params object[] p)
130 {
131 // Call PacketFactory to have it create a packet for us
132
133 //string[] tmpP = new string[p.Length];
134 string tmpStr = Command;
135 for (int i = 0; i < p.Length; i++)
136 {
137 tmpStr += "," + System.Web.HttpUtility.UrlEncode(p[i].ToString()); // .Replace(",", "%44")
138 }
139 tmpStr += "\n";
140 byte[] byteData = Encoding.ASCII.GetBytes(tmpStr);
141 TCPS.Send(ID, byteData, 0, byteData.Length);
142 }
143 }
144} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/RemoteServer/EventManager.cs b/OpenSim/Region/ScriptEngine/RemoteServer/EventManager.cs
index d56c1fb..1b37378 100644
--- a/OpenSim/Region/ScriptEngine/RemoteServer/EventManager.cs
+++ b/OpenSim/Region/ScriptEngine/RemoteServer/EventManager.cs
@@ -48,6 +48,7 @@ namespace OpenSim.Region.ScriptEngine.RemoteServer
48 { 48 {
49 myScriptEngine = _ScriptEngine; 49 myScriptEngine = _ScriptEngine;
50 50
51
51 myScriptEngine.Log.Verbose("RemoteEngine", "Hooking up to server events"); 52 myScriptEngine.Log.Verbose("RemoteEngine", "Hooking up to server events");
52 //myScriptEngine.World.EventManager.OnObjectGrab += touch_start; 53 //myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
53 myScriptEngine.World.EventManager.OnRezScript += OnRezScript; 54 myScriptEngine.World.EventManager.OnRezScript += OnRezScript;
@@ -61,10 +62,11 @@ namespace OpenSim.Region.ScriptEngine.RemoteServer
61 { 62 {
62 // WE ARE CREATING A NEW SCRIPT ... CREATE SCRIPT, GET A REMOTEID THAT WE MAP FROM LOCALID 63 // WE ARE CREATING A NEW SCRIPT ... CREATE SCRIPT, GET A REMOTEID THAT WE MAP FROM LOCALID
63 myScriptEngine.Log.Verbose("RemoteEngine", "Creating new script (with connection)"); 64 myScriptEngine.Log.Verbose("RemoteEngine", "Creating new script (with connection)");
65
66
64 ScriptServerInterfaces.ServerRemotingObject obj = myScriptEngine.m_RemoteServer.Connect("localhost", 1234); 67 ScriptServerInterfaces.ServerRemotingObject obj = myScriptEngine.m_RemoteServer.Connect("localhost", 1234);
65
66 remoteScript.Add(localID, obj); 68 remoteScript.Add(localID, obj);
67 //remoteScript[localID].Events.OnRezScript(localID, itemID, script); 69 remoteScript[localID].Events().OnRezScript(localID, itemID, script);
68 70
69 } 71 }
70 72
diff --git a/OpenSim/Region/ScriptEngine/RemoteServer/RemoteServer.cs b/OpenSim/Region/ScriptEngine/RemoteServer/RemoteServer.cs
index 6fc6c5c..38eb9b9 100644
--- a/OpenSim/Region/ScriptEngine/RemoteServer/RemoteServer.cs
+++ b/OpenSim/Region/ScriptEngine/RemoteServer/RemoteServer.cs
@@ -13,19 +13,17 @@ namespace OpenSim.Region.ScriptEngine.RemoteServer
13 // Handles connections to servers 13 // Handles connections to servers
14 // Create and returns server object 14 // Create and returns server object
15 15
16 public RemoteServer()
17 {
18 TcpChannel chan = new TcpChannel();
19 ChannelServices.RegisterChannel(chan, true);
20 }
21
16 public ScriptServerInterfaces.ServerRemotingObject Connect(string hostname, int port) 22 public ScriptServerInterfaces.ServerRemotingObject Connect(string hostname, int port)
17 { 23 {
18 // Create a channel for communicating w/ the remote object 24 // Create a channel for communicating w/ the remote object
19 // Notice no port is specified on the client 25 // Notice no port is specified on the client
20 TcpChannel chan = new TcpChannel(); 26
21 try
22 {
23 ChannelServices.RegisterChannel(chan, true);
24 }
25 catch (System.Runtime.Remoting.RemotingException)
26 {
27 System.Console.WriteLine("Error: tcp already registered, RemoteServer.cs in OpenSim.Region.ScriptEngine.RemoteServer line 24");
28 }
29 try 27 try
30 { 28 {
31 29