TRPC_Remote.cs 7.5 KB

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