TRPC_Remote.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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 OpenSim 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. */
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Diagnostics;
  31. using System.Text;
  32. using libsecondlife;
  33. using OpenSim.Region.ScriptEngine.Common.TRPC;
  34. namespace OpenSim.Region.ScriptEngine.Common
  35. {
  36. public class TRPC_Remote
  37. {
  38. public readonly int MaxQueueSize = 1024 * 10;
  39. public readonly TCPCommon.ServerAndClientInterface TCPS;
  40. public delegate void ReceiveCommandDelegate(int ID, string Command, params object[] p);
  41. public event ReceiveCommandDelegate ReceiveCommand;
  42. System.Collections.Generic.Dictionary<string, Type> TypeDictionary = new Dictionary<string, Type>();
  43. Type[] Types =
  44. {
  45. typeof(System.String),
  46. typeof(System.Int16),
  47. typeof(System.Int32),
  48. typeof(System.Int64),
  49. typeof(System.Double),
  50. typeof(System.Decimal),
  51. typeof(System.Array),
  52. typeof(LLUUID),
  53. typeof(System.UInt16),
  54. typeof(System.UInt32),
  55. typeof(System.UInt64)
  56. };
  57. // TODO: Maybe we should move queue into TCPSocket so we won't have to keep one queue instance per connection
  58. private System.Collections.Generic.Dictionary<int, InQueueStruct> InQueue = new Dictionary<int, InQueueStruct>();
  59. private class InQueueStruct
  60. {
  61. public byte[] Queue;
  62. public int QueueSize;
  63. public object QueueLockObject = new object();
  64. }
  65. public TRPC_Remote(TCPCommon.ServerAndClientInterface TCPClientOrServer)
  66. {
  67. TCPS = TCPClientOrServer;
  68. TCPS.Close += new TCPCommon.CloseDelegate(TCPS_Close);
  69. TCPS.ClientConnected += new TCPCommon.ClientConnectedDelegate(TCPS_ClientConnected);
  70. TCPS.DataReceived += new TCPCommon.DataReceivedDelegate(TCPS_DataReceived);
  71. //TCPS.StartListen();
  72. // Make a lookup dictionary for types
  73. foreach (Type t in Types)
  74. {
  75. TypeDictionary.Add(t.ToString(), t);
  76. }
  77. }
  78. void TCPS_ClientConnected(int ID, System.Net.EndPoint Remote)
  79. {
  80. // Create a incoming queue for this connection
  81. InQueueStruct iq = new InQueueStruct();
  82. iq.Queue = new byte[MaxQueueSize];
  83. iq.QueueSize = 0;
  84. InQueue.Add(ID, iq);
  85. }
  86. void TCPS_Close(int ID)
  87. {
  88. // Remove queue
  89. InQueue.Remove(ID);
  90. }
  91. void TCPS_DataReceived(int ID, byte[] data, int offset, int length)
  92. {
  93. // Copy new data to incoming queue
  94. lock (InQueue[ID].QueueLockObject)
  95. {
  96. Array.Copy(data, offset, InQueue[ID].Queue, InQueue[ID].QueueSize, length);
  97. InQueue[ID].QueueSize += length;
  98. // Process incoming queue
  99. ProcessQueue(ID);
  100. }
  101. }
  102. private void ProcessQueue(int ID)
  103. {
  104. // This is just a temp implementation -- not so fast :)
  105. InQueueStruct myIQS = InQueue[ID];
  106. if (myIQS.QueueSize == 0)
  107. return;
  108. string receivedData = Encoding.ASCII.GetString(myIQS.Queue, 0, myIQS.QueueSize);
  109. Debug.WriteLine("RAW: " + receivedData);
  110. byte newLine = 10;
  111. while (true)
  112. {
  113. bool ShouldProcess = false;
  114. int lineEndPos = 0;
  115. // Look for newline
  116. for (int i = 0; i < myIQS.QueueSize; i++)
  117. {
  118. if (myIQS.Queue[i] == newLine)
  119. {
  120. ShouldProcess = true;
  121. lineEndPos = i;
  122. break;
  123. }
  124. }
  125. // Process it?
  126. if (!ShouldProcess)
  127. return;
  128. // Yes
  129. string cmdLine = Encoding.ASCII.GetString(myIQS.Queue, 0, lineEndPos);
  130. Debug.WriteLine("Command: " + cmdLine);
  131. // Fix remaining queue in an inefficient way
  132. byte[] newQueue = new byte[MaxQueueSize];
  133. Array.Copy(myIQS.Queue, lineEndPos, newQueue, 0, myIQS.QueueSize - lineEndPos);
  134. myIQS.Queue = newQueue;
  135. myIQS.QueueSize -= (lineEndPos + 1);
  136. // Now back to the command
  137. string[] parts = cmdLine.Split(',');
  138. if (parts.Length > 0)
  139. {
  140. string cmd = parts[0];
  141. int paramCount = parts.Length - 1;
  142. object[] param = null;
  143. if (paramCount > 0)
  144. {
  145. // Process all parameters (decoding them from URL encoding)
  146. param = new object[paramCount];
  147. for (int i = 1; i < parts.Length; i++)
  148. {
  149. string[] spl;
  150. spl = System.Web.HttpUtility.UrlDecode(parts[i]).Split('|');
  151. string t = spl[0];
  152. param[i - 1] = Convert.ChangeType(spl[1], TypeLookup(t));
  153. }
  154. }
  155. ReceiveCommand(ID, cmd, param);
  156. }
  157. }
  158. }
  159. private Type TypeLookup(string t)
  160. {
  161. Type ret = TypeDictionary[t];
  162. if (ret != null)
  163. return ret;
  164. return typeof(object);
  165. }
  166. public void SendCommand(int ID, string Command, params object[] p)
  167. {
  168. // Call PacketFactory to have it create a packet for us
  169. //string[] tmpP = new string[p.Length];
  170. string tmpStr = Command;
  171. for (int i = 0; i < p.Length; i++)
  172. {
  173. tmpStr += "," + p[i].GetType().ToString() + "|" + System.Web.HttpUtility.UrlEncode(p[i].ToString()); // .Replace(",", "%44")
  174. }
  175. tmpStr += "\n";
  176. byte[] byteData = Encoding.ASCII.GetBytes(tmpStr);
  177. TCPS.Send(ID, byteData, 0, byteData.Length);
  178. }
  179. }
  180. }