PageRenderTime 33ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 1ms

/old/libsl1550/SLProxy/SLProxy.cs

https://bitbucket.org/KyanhaLLC/opensim-libs
C# | 2013 lines | 1566 code | 247 blank | 200 comment | 252 complexity | dfcd0dd9a9c7d4043de480f24a0db18a MD5 | raw file
Possible License(s): Apache-2.0, BSD-2-Clause, MIT, LGPL-2.1, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, GPL-3.0, BSD-3-Clause
  1. /*
  2. * SLProxy.cs: implementation of Second Life proxy library
  3. *
  4. * Copyright (c) 2006 Austin Jennings
  5. * Pregen modifications made by Andrew Ortman on Dec 10, 2006 -> Dec 20, 2006
  6. *
  7. *
  8. * All rights reserved.
  9. *
  10. * - Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice, this
  14. * list of conditions and the following disclaimer.
  15. * - Neither the name of the Second Life Reverse Engineering Team nor the names
  16. * of its contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  21. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  24. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  25. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  26. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  29. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30. * POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. // #define DEBUG_SEQUENCE
  33. // #define DEBUG_CAPS
  34. // #define DEBUG_THREADS
  35. using Nwc.XmlRpc;
  36. using System;
  37. using System.Collections.Generic;
  38. using System.IO;
  39. using System.Net;
  40. using System.Net.Sockets;
  41. using System.Text;
  42. using System.Text.RegularExpressions;
  43. using System.Threading;
  44. using System.Xml;
  45. using libsecondlife;
  46. using libsecondlife.StructuredData;
  47. using libsecondlife.Packets;
  48. // SLProxy: proxy library for Second Life
  49. namespace SLProxy
  50. {
  51. // ProxyConfig: configuration for proxy objects
  52. public class ProxyConfig
  53. {
  54. // userAgent: name of the proxy application
  55. public string userAgent;
  56. // author: email address of the proxy application's author
  57. public string author;
  58. // loginPort: port that the login proxy will listen on
  59. public ushort loginPort = 8080;
  60. // clientFacingAddress: address from which to communicate with the client
  61. public IPAddress clientFacingAddress = IPAddress.Loopback;
  62. // remoteFacingAddress: address from which to communicate with the server
  63. public IPAddress remoteFacingAddress = IPAddress.Any;
  64. // remoteLoginUri: URI for Second Life's login server
  65. public Uri remoteLoginUri = new Uri("https://login.agni.lindenlab.com/cgi-bin/login.cgi");
  66. // verbose: whether or not to print informative messages
  67. public bool verbose = true;
  68. // ProxyConfig: construct a default proxy configuration with the specified userAgent, author, and protocol
  69. public ProxyConfig(string userAgent, string author)
  70. {
  71. this.userAgent = userAgent;
  72. this.author = author;
  73. }
  74. // ProxyConfig: construct a default proxy configuration, parsing command line arguments (try --proxy-help)
  75. public ProxyConfig(string userAgent, string author, string[] args)
  76. : this(userAgent, author)
  77. {
  78. Dictionary<string, ArgumentParser> argumentParsers = new Dictionary<string, ArgumentParser>();
  79. argumentParsers["proxy-help"] = new ArgumentParser(ParseHelp);
  80. argumentParsers["proxy-login-port"] = new ArgumentParser(ParseLoginPort);
  81. argumentParsers["proxy-client-facing-address"] = new ArgumentParser(ParseClientFacingAddress);
  82. argumentParsers["proxy-remote-facing-address"] = new ArgumentParser(ParseRemoteFacingAddress);
  83. argumentParsers["proxy-remote-login-uri"] = new ArgumentParser(ParseRemoteLoginUri);
  84. argumentParsers["proxy-verbose"] = new ArgumentParser(ParseVerbose);
  85. argumentParsers["proxy-quiet"] = new ArgumentParser(ParseQuiet);
  86. foreach (string arg in args)
  87. foreach (string argument in argumentParsers.Keys)
  88. {
  89. Match match = (new Regex("^--" + argument + "(?:=(.*))?$")).Match(arg);
  90. if (match.Success)
  91. {
  92. string value;
  93. if (match.Groups[1].Captures.Count == 1)
  94. value = match.Groups[1].Captures[0].ToString();
  95. else
  96. value = null;
  97. try
  98. {
  99. ((ArgumentParser)argumentParsers[argument])(value);
  100. }
  101. catch
  102. {
  103. Console.WriteLine("invalid value for --" + argument);
  104. ParseHelp(null);
  105. }
  106. }
  107. }
  108. }
  109. private delegate void ArgumentParser(string value);
  110. private void ParseHelp(string value)
  111. {
  112. Console.WriteLine("Proxy command-line arguments:");
  113. Console.WriteLine(" --proxy-help display this help");
  114. Console.WriteLine(" --proxy-login-port=<port> listen for logins on <port>");
  115. Console.WriteLine(" --proxy-client-facing-address=<IP> communicate with client via <IP>");
  116. Console.WriteLine(" --proxy-remote-facing-address=<IP> communicate with server via <IP>");
  117. Console.WriteLine(" --proxy-remote-login-uri=<URI> use SL login server at <URI>");
  118. Console.WriteLine(" --proxy-verbose display proxy notifications");
  119. Console.WriteLine(" --proxy-quiet suppress proxy notifications");
  120. Environment.Exit(1);
  121. }
  122. private void ParseLoginPort(string value)
  123. {
  124. loginPort = Convert.ToUInt16(value);
  125. }
  126. private void ParseClientFacingAddress(string value)
  127. {
  128. clientFacingAddress = IPAddress.Parse(value);
  129. }
  130. private void ParseRemoteFacingAddress(string value)
  131. {
  132. remoteFacingAddress = IPAddress.Parse(value);
  133. }
  134. private void ParseRemoteLoginUri(string value)
  135. {
  136. remoteLoginUri = new Uri(value);
  137. }
  138. private void ParseVerbose(string value)
  139. {
  140. if (value != null)
  141. throw new Exception();
  142. verbose = true;
  143. }
  144. private void ParseQuiet(string value)
  145. {
  146. if (value != null)
  147. throw new Exception();
  148. verbose = false;
  149. }
  150. }
  151. // Proxy: Second Life proxy server
  152. // A Proxy instance is only prepared to deal with one client at a time.
  153. public class Proxy
  154. {
  155. private ProxyConfig proxyConfig;
  156. private string loginURI;
  157. /*
  158. * Proxy Management
  159. */
  160. // Proxy: construct a proxy server with the given configuration
  161. public Proxy(ProxyConfig proxyConfig)
  162. {
  163. this.proxyConfig = proxyConfig;
  164. InitializeLoginProxy();
  165. InitializeSimProxy();
  166. InitializeCaps();
  167. }
  168. object keepAliveLock = new Object();
  169. // Start: begin accepting clients
  170. public void Start()
  171. {
  172. lock (this)
  173. {
  174. System.Threading.Monitor.Enter(keepAliveLock);
  175. (new Thread(new ThreadStart(KeepAlive))).Start();
  176. RunSimProxy();
  177. Thread runLoginProxy = new Thread(new ThreadStart(RunLoginProxy));
  178. runLoginProxy.IsBackground = true;
  179. runLoginProxy.Start();
  180. IPEndPoint endPoint = (IPEndPoint)loginServer.LocalEndPoint;
  181. IPAddress displayAddress;
  182. if (endPoint.Address == IPAddress.Any)
  183. displayAddress = IPAddress.Loopback;
  184. else
  185. displayAddress = endPoint.Address;
  186. loginURI = "http://" + displayAddress + ":" + endPoint.Port + "/";
  187. Log("proxy ready at " + loginURI, false);
  188. }
  189. }
  190. // Stop: allow foreground threads to die
  191. public void Stop()
  192. {
  193. lock (this)
  194. {
  195. System.Threading.Monitor.Exit(keepAliveLock);
  196. }
  197. }
  198. // KeepAlive: blocks until the proxy is free to shut down
  199. public void KeepAlive()
  200. {
  201. #if DEBUG_THREADS
  202. Console.WriteLine(">T> KeepAlive");
  203. #endif
  204. lock (keepAliveLock) { };
  205. #if DEBUG_THREADS
  206. Console.WriteLine("<T< KeepAlive");
  207. #endif
  208. }
  209. // SetLoginRequestDelegate: specify a callback loginRequestDelegate that will be called when the client requests login
  210. public void SetLoginRequestDelegate(XmlRpcRequestDelegate loginRequestDelegate)
  211. {
  212. lock (this)
  213. {
  214. this.loginRequestDelegate = loginRequestDelegate;
  215. }
  216. }
  217. // SetLoginResponseDelegate: specify a callback loginResponseDelegate that will be called when the server responds to login
  218. public void SetLoginResponseDelegate(XmlRpcResponseDelegate loginResponseDelegate)
  219. {
  220. lock (this)
  221. {
  222. this.loginResponseDelegate = loginResponseDelegate;
  223. }
  224. }
  225. // AddDelegate: add callback packetDelegate for packets of type packetName going direction
  226. public void AddDelegate(PacketType packetType, Direction direction, PacketDelegate packetDelegate)
  227. {
  228. lock (this)
  229. {
  230. Dictionary<PacketType, List<PacketDelegate>> delegates = (direction == Direction.Incoming ? incomingDelegates : outgoingDelegates);
  231. if (!delegates.ContainsKey(packetType))
  232. {
  233. delegates[packetType] = new List<PacketDelegate>();
  234. }
  235. List<PacketDelegate> delegateArray = delegates[packetType];
  236. if (!delegateArray.Contains(packetDelegate))
  237. {
  238. delegateArray.Add(packetDelegate);
  239. }
  240. }
  241. }
  242. // RemoveDelegate: remove callback for packets of type packetName going direction
  243. public void RemoveDelegate(PacketType packetType, Direction direction, PacketDelegate packetDelegate)
  244. {
  245. lock (this)
  246. {
  247. Dictionary<PacketType, List<PacketDelegate>> delegates = (direction == Direction.Incoming ? incomingDelegates : outgoingDelegates);
  248. if (!delegates.ContainsKey(packetType))
  249. {
  250. return;
  251. }
  252. List<PacketDelegate> delegateArray = delegates[packetType];
  253. if (delegateArray.Contains(packetDelegate))
  254. {
  255. delegateArray.Remove(packetDelegate);
  256. }
  257. }
  258. }
  259. private Packet callDelegates(Dictionary<PacketType, List<PacketDelegate>> delegates, Packet packet, IPEndPoint remoteEndPoint)
  260. {
  261. PacketType origType = packet.Type;
  262. foreach (PacketDelegate del in delegates[origType])
  263. {
  264. packet = del(packet, remoteEndPoint);
  265. // FIXME: how should we handle the packet type changing?
  266. if (packet == null || packet.Type != origType) break;
  267. }
  268. return packet;
  269. }
  270. // InjectPacket: send packet to the client or server when direction is Incoming or Outgoing, respectively
  271. public void InjectPacket(Packet packet, Direction direction)
  272. {
  273. lock (this)
  274. {
  275. if (activeCircuit == null)
  276. {
  277. // no active circuit; queue the packet for injection once we have one
  278. List<Packet> queue = direction == Direction.Incoming ? queuedIncomingInjections : queuedOutgoingInjections;
  279. queue.Add(packet);
  280. }
  281. else
  282. // tell the active sim proxy to inject the packet
  283. ((SimProxy)simProxies[activeCircuit]).Inject(packet, direction);
  284. }
  285. }
  286. // Log: write message to the console if in verbose mode
  287. private void Log(object message, bool important)
  288. {
  289. if (proxyConfig.verbose || important)
  290. Console.WriteLine(message);
  291. }
  292. /*
  293. * Login Proxy
  294. */
  295. private Socket loginServer;
  296. private int capsReqCount = 0;
  297. // InitializeLoginProxy: initialize the login proxy
  298. private void InitializeLoginProxy()
  299. {
  300. loginServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  301. loginServer.Bind(new IPEndPoint(proxyConfig.clientFacingAddress, proxyConfig.loginPort));
  302. loginServer.Listen(1);
  303. }
  304. // RunLoginProxy: process login requests from clients
  305. private void RunLoginProxy()
  306. {
  307. #if DEBUG_THREADS
  308. Console.WriteLine(">T> RunLoginProxy");
  309. #endif
  310. try
  311. {
  312. for (; ; )
  313. {
  314. Socket client = loginServer.Accept();
  315. IPEndPoint clientEndPoint = (IPEndPoint)client.RemoteEndPoint;
  316. try
  317. {
  318. Thread connThread = new Thread((ThreadStart)delegate
  319. {
  320. #if DEBUG_THREADS
  321. Console.WriteLine(">T> ProxyHTTP");
  322. #endif
  323. ProxyHTTP(client);
  324. #if DEBUG_THREADS
  325. Console.WriteLine("<T< ProxyHTTP");
  326. } catch (Exception e) {
  327. Console.WriteLine("ProxyHTTP: {0}", e.Message);
  328. }
  329. #endif
  330. });
  331. connThread.IsBackground = true;
  332. connThread.Start();
  333. }
  334. catch (Exception e)
  335. {
  336. Log("login failed: " + e.Message, false);
  337. }
  338. // send any packets queued for injection
  339. if (activeCircuit != null) lock (this)
  340. {
  341. SimProxy activeProxy = (SimProxy)simProxies[activeCircuit];
  342. foreach (Packet packet in queuedOutgoingInjections)
  343. activeProxy.Inject(packet, Direction.Outgoing);
  344. queuedOutgoingInjections = new List<Packet>();
  345. }
  346. }
  347. }
  348. catch (Exception e)
  349. {
  350. Console.WriteLine(e.Message);
  351. Console.WriteLine(e.StackTrace);
  352. }
  353. #if DEBUG_THREADS
  354. Console.WriteLine("<T< RunLoginProxy");
  355. #endif
  356. }
  357. private class HandyNetReader
  358. {
  359. private NetworkStream netStream;
  360. private const int BUF_SIZE = 8192;
  361. private byte[] buf = new byte[BUF_SIZE];
  362. private int bufFill = 0;
  363. public HandyNetReader(NetworkStream s)
  364. {
  365. netStream = s;
  366. }
  367. public byte[] ReadLine()
  368. {
  369. int i = -1;
  370. while (true)
  371. {
  372. i = Array.IndexOf(buf, (byte)'\n', 0, bufFill);
  373. if (i >= 0) break;
  374. if (bufFill >= BUF_SIZE) return null;
  375. if (!ReadMore()) return null;
  376. }
  377. byte[] ret = new byte[i];
  378. Array.Copy(buf, ret, i);
  379. Array.Copy(buf, i + 1, buf, 0, bufFill - (i + 1));
  380. bufFill -= i + 1;
  381. return ret;
  382. }
  383. private bool ReadMore()
  384. {
  385. int n = netStream.Read(buf, bufFill, BUF_SIZE - bufFill);
  386. bufFill += n;
  387. return n > 0;
  388. }
  389. public int Read(byte[] rbuf, int start, int len)
  390. {
  391. int read = 0;
  392. while (len > bufFill)
  393. {
  394. Array.Copy(buf, 0, rbuf, start, bufFill);
  395. start += bufFill; len -= bufFill;
  396. read += bufFill; bufFill = 0;
  397. if (!ReadMore()) break;
  398. }
  399. Array.Copy(buf, 0, rbuf, start, len);
  400. Array.Copy(buf, len, buf, 0, bufFill - len);
  401. bufFill -= len; read += len;
  402. return read;
  403. }
  404. }
  405. // ProxyHTTP: proxy a HTTP request
  406. private void ProxyHTTP(Socket client)
  407. {
  408. NetworkStream netStream = new NetworkStream(client);
  409. HandyNetReader reader = new HandyNetReader(netStream);
  410. string line = null;
  411. int reqNo;
  412. int contentLength = 0;
  413. Match match;
  414. string uri;
  415. string meth;
  416. Dictionary<string, string> headers = new Dictionary<string, string>();
  417. lock (this)
  418. {
  419. capsReqCount++; reqNo = capsReqCount;
  420. }
  421. byte[] byteLine = reader.ReadLine();
  422. if (byteLine != null) line = Encoding.UTF8.GetString(byteLine).Replace("\r", "");
  423. if (line == null)
  424. throw new Exception("EOF in client HTTP header");
  425. match = new Regex(@"^(\S+)\s+(\S+)\s+(HTTP/\d\.\d)$").Match(line);
  426. if (!match.Success)
  427. {
  428. Console.WriteLine("[" + reqNo + "] Bad request!");
  429. byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n");
  430. netStream.Write(wr, 0, wr.Length);
  431. netStream.Close(); client.Close();
  432. return;
  433. }
  434. meth = match.Groups[1].Captures[0].ToString();
  435. uri = match.Groups[2].Captures[0].ToString();
  436. #if DEBUG_CAPS
  437. Console.WriteLine("[" + reqNo + "] " + meth + ": " + uri); // FIXME - for debugging only
  438. #endif
  439. // read HTTP header
  440. do
  441. {
  442. // read one line of the header
  443. line = Encoding.UTF8.GetString(reader.ReadLine()).Replace("\r", "");
  444. // check for premature EOF
  445. if (line == null)
  446. throw new Exception("EOF in client HTTP header");
  447. if (line == "") break;
  448. match = new Regex(@"^([^:]+):\s*(.*)$").Match(line);
  449. if (!match.Success)
  450. {
  451. Console.WriteLine("[" + reqNo + "] Bad header: '" + line + "'");
  452. byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n");
  453. netStream.Write(wr, 0, wr.Length);
  454. netStream.Close(); client.Close();
  455. return;
  456. }
  457. string key = match.Groups[1].Captures[0].ToString();
  458. string val = match.Groups[2].Captures[0].ToString();
  459. headers[key.ToLower()] = val;
  460. } while (line != "");
  461. if (headers.ContainsKey("content-length"))
  462. {
  463. contentLength = Convert.ToInt32(headers["content-length"]);
  464. }
  465. // read the HTTP body into a buffer
  466. byte[] content = new byte[contentLength];
  467. reader.Read(content, 0, contentLength);
  468. #if DEBUG_CAPS
  469. if (contentLength < 8192) Console.WriteLine("[" + reqNo + "] request length = " + contentLength + ":\n" + Helpers.FieldToUTF8String(content) + "\n-------------");
  470. #endif
  471. if (uri == "/")
  472. {
  473. ProxyLogin(netStream, content);
  474. }
  475. else if (new Regex(@"^/https?://.*$").Match(uri).Success)
  476. {
  477. ProxyCaps(netStream, meth, uri.Substring(1), headers, content, reqNo);
  478. }
  479. else
  480. {
  481. Console.WriteLine("404 not found: " + uri);
  482. byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 404 Not Found\r\nContent-Length: 0\r\n\r\n");
  483. netStream.Write(wr, 0, wr.Length);
  484. netStream.Close(); client.Close();
  485. return;
  486. }
  487. netStream.Close();
  488. client.Close();
  489. }
  490. private Dictionary<string, CapInfo> KnownCaps;
  491. private Dictionary<string, bool> SubHack = new Dictionary<string, bool>();
  492. private void ProxyCaps(NetworkStream netStream, string meth, string uri, Dictionary<string, string> headers, byte[] content, int reqNo)
  493. {
  494. Match match = new Regex(@"^(https?)://([^:/]+)(:\d+)?(/.*)$").Match(uri);
  495. if (!match.Success)
  496. {
  497. Console.WriteLine("[" + reqNo + "] Malformed proxy URI: " + uri);
  498. byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 404 Not Found\r\nContent-Length: 0\r\n\r\n");
  499. netStream.Write(wr, 0, wr.Length);
  500. return;
  501. }
  502. //DEBUG: Console.WriteLine("[" + reqNo + "] : " + meth);
  503. CapInfo cap = null;
  504. lock (this)
  505. {
  506. if (KnownCaps.ContainsKey(uri))
  507. {
  508. cap = KnownCaps[uri];
  509. }
  510. }
  511. CapsRequest capReq = null; bool shortCircuit = false; bool requestFailed = false;
  512. if (cap != null)
  513. {
  514. capReq = new CapsRequest(cap);
  515. if (cap.ReqFmt == CapsDataFormat.LLSD)
  516. {
  517. capReq.Request = LLSDParser.DeserializeXml(content);
  518. }
  519. else
  520. {
  521. capReq.Request = content;
  522. }
  523. foreach (CapsDelegate d in cap.GetDelegates())
  524. {
  525. if (d(capReq, CapsStage.Request)) { shortCircuit = true; break; }
  526. }
  527. if (cap.ReqFmt == CapsDataFormat.LLSD)
  528. {
  529. content = LLSDParser.SerializeXmlBytes((LLSD)capReq.Request);
  530. }
  531. else
  532. {
  533. content = (byte[])capReq.Request;
  534. }
  535. }
  536. byte[] respBuf = null;
  537. string consoleMsg = String.Empty;
  538. if (shortCircuit)
  539. {
  540. byte[] wr = Encoding.UTF8.GetBytes("HTTP/1.0 200 OK\r\n");
  541. netStream.Write(wr, 0, wr.Length);
  542. }
  543. else
  544. {
  545. HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
  546. req.KeepAlive = false;
  547. foreach (string header in headers.Keys)
  548. {
  549. if (header == "accept" || header == "connection" ||
  550. header == "content-length" || header == "date" || header == "expect" ||
  551. header == "host" || header == "if-modified-since" || header == "referer" ||
  552. header == "transfer-encoding" || header == "user-agent" ||
  553. header == "proxy-connection")
  554. {
  555. // can't touch these!
  556. }
  557. else if (header == "content-type")
  558. {
  559. req.ContentType = headers["content-type"];
  560. }
  561. else
  562. {
  563. req.Headers[header] = headers[header];
  564. }
  565. }
  566. req.Method = meth;
  567. req.ContentLength = content.Length;
  568. HttpWebResponse resp;
  569. try
  570. {
  571. Stream reqStream = req.GetRequestStream();
  572. reqStream.Write(content, 0, content.Length);
  573. reqStream.Close();
  574. resp = (HttpWebResponse)req.GetResponse();
  575. }
  576. catch (WebException e)
  577. {
  578. if (e.Status == WebExceptionStatus.Timeout || e.Status == WebExceptionStatus.SendFailure)
  579. {
  580. Console.WriteLine("Request timeout");
  581. byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 504 Proxy Request Timeout\r\nContent-Length: 0\r\n\r\n");
  582. netStream.Write(wr, 0, wr.Length);
  583. return;
  584. }
  585. else if (e.Status == WebExceptionStatus.ProtocolError && e.Response != null)
  586. {
  587. resp = (HttpWebResponse)e.Response; requestFailed = true;
  588. }
  589. else
  590. {
  591. Console.WriteLine("Request error: " + e.ToString());
  592. byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 502 Gateway Error\r\nContent-Length: 0\r\n\r\n"); // FIXME
  593. netStream.Write(wr, 0, wr.Length);
  594. return;
  595. }
  596. }
  597. try
  598. {
  599. Stream respStream = resp.GetResponseStream();
  600. int read;
  601. int length = 0;
  602. respBuf = new byte[256];
  603. do
  604. {
  605. read = respStream.Read(respBuf, length, 256);
  606. if (read > 0)
  607. {
  608. length += read;
  609. Array.Resize(ref respBuf, length + 256);
  610. }
  611. } while (read > 0);
  612. Array.Resize(ref respBuf, length);
  613. if (capReq != null && !requestFailed)
  614. {
  615. if (cap.RespFmt == CapsDataFormat.LLSD)
  616. {
  617. capReq.Response = LLSDParser.DeserializeXml(respBuf);
  618. }
  619. else
  620. {
  621. capReq.Response = respBuf;
  622. }
  623. }
  624. consoleMsg += "[" + reqNo + "] Response from " + uri + "\nStatus: " + (int)resp.StatusCode + " " + resp.StatusDescription + "\n";
  625. {
  626. byte[] wr = Encoding.UTF8.GetBytes("HTTP/1.0 " + (int)resp.StatusCode + " " + resp.StatusDescription + "\r\n");
  627. netStream.Write(wr, 0, wr.Length);
  628. }
  629. for (int i = 0; i < resp.Headers.Count; i++)
  630. {
  631. string key = resp.Headers.Keys[i];
  632. string val = resp.Headers[i];
  633. string lkey = key.ToLower();
  634. if (lkey != "content-length" && lkey != "transfer-encoding" && lkey != "connection")
  635. {
  636. consoleMsg += key + ": " + val + "\n";
  637. byte[] wr = Encoding.UTF8.GetBytes(key + ": " + val + "\r\n");
  638. netStream.Write(wr, 0, wr.Length);
  639. }
  640. }
  641. }
  642. catch (Exception)
  643. {
  644. // TODO: Should we handle this somehow?
  645. }
  646. }
  647. if (cap != null && !requestFailed)
  648. {
  649. foreach (CapsDelegate d in cap.GetDelegates())
  650. {
  651. try
  652. {
  653. if (d(capReq, CapsStage.Response)) { break; }
  654. }
  655. catch (Exception e)
  656. {
  657. Console.WriteLine(e.ToString()); break;
  658. }
  659. }
  660. if (cap.RespFmt == CapsDataFormat.LLSD)
  661. {
  662. respBuf = LLSDParser.SerializeXmlBytes((LLSD)capReq.Response);
  663. }
  664. else
  665. {
  666. respBuf = (byte[])capReq.Response;
  667. }
  668. }
  669. consoleMsg += "\n" + Encoding.UTF8.GetString(respBuf) + "\n--------";
  670. #if DEBUG_CAPS
  671. Console.WriteLine(consoleMsg);
  672. #endif
  673. /* try {
  674. if(resp.StatusCode == HttpStatusCode.OK) respBuf = CapsFixup(uri,respBuf);
  675. } catch(Exception e) {
  676. Console.WriteLine("["+reqNo+"] Couldn't fixup response: "+e.ToString());
  677. } */
  678. #if DEBUG_CAPS
  679. Console.WriteLine("[" + reqNo + "] Fixed-up response:\n" + Encoding.UTF8.GetString(respBuf) + "\n--------");
  680. #endif
  681. try
  682. {
  683. byte[] wr2 = Encoding.UTF8.GetBytes("Content-Length: " + respBuf.Length + "\r\n\r\n");
  684. netStream.Write(wr2, 0, wr2.Length);
  685. netStream.Write(respBuf, 0, respBuf.Length);
  686. }
  687. catch (Exception e)
  688. {
  689. Console.WriteLine(e.ToString());
  690. }
  691. return;
  692. }
  693. private bool FixupSeedCapsResponse(CapsRequest capReq, CapsStage stage)
  694. {
  695. if (stage != CapsStage.Response) return false;
  696. Dictionary<string, object> m = (Dictionary<string, object>)capReq.Response;
  697. Dictionary<string, object> nm = new Dictionary<string, object>();
  698. foreach (string key in m.Keys)
  699. {
  700. string val = (string)m[key];
  701. if (!String.IsNullOrEmpty(val))
  702. {
  703. if (!KnownCaps.ContainsKey(val))
  704. {
  705. CapInfo newCap = new CapInfo(val, capReq.Info.Sim, key);
  706. newCap.AddDelegate(new CapsDelegate(KnownCapDelegate));
  707. lock (this) { KnownCaps[val] = newCap; }
  708. }
  709. nm[key] = loginURI + val;
  710. }
  711. else
  712. {
  713. nm[key] = val;
  714. }
  715. }
  716. capReq.Response = nm;
  717. return false;
  718. }
  719. private Dictionary<string, List<CapsDelegate>> KnownCapsDelegates = new Dictionary<string, List<CapsDelegate>>();
  720. private void InitializeCaps()
  721. {
  722. AddCapsDelegate("EventQueueGet", new CapsDelegate(FixupEventQueueGet));
  723. }
  724. public void AddCapsDelegate(string CapName, CapsDelegate capsDelegate)
  725. {
  726. lock (this)
  727. {
  728. if (!KnownCapsDelegates.ContainsKey(CapName))
  729. {
  730. KnownCapsDelegates[CapName] = new List<CapsDelegate>();
  731. }
  732. List<CapsDelegate> delegateArray = KnownCapsDelegates[CapName];
  733. if (!delegateArray.Contains(capsDelegate))
  734. {
  735. delegateArray.Add(capsDelegate);
  736. }
  737. }
  738. }
  739. public void RemoveCapRequestDelegate(string CapName, CapsDelegate capsDelegate)
  740. {
  741. lock (this)
  742. {
  743. if (!KnownCapsDelegates.ContainsKey(CapName))
  744. {
  745. return;
  746. }
  747. List<CapsDelegate> delegateArray = KnownCapsDelegates[CapName];
  748. if (delegateArray.Contains(capsDelegate))
  749. {
  750. delegateArray.Remove(capsDelegate);
  751. }
  752. }
  753. }
  754. private bool KnownCapDelegate(CapsRequest capReq, CapsStage stage)
  755. {
  756. lock (this)
  757. {
  758. if (!KnownCapsDelegates.ContainsKey(capReq.Info.CapType))
  759. return false;
  760. List<CapsDelegate> delegates = KnownCapsDelegates[capReq.Info.CapType];
  761. foreach (CapsDelegate d in delegates)
  762. {
  763. if (d(capReq, stage)) { return true; }
  764. }
  765. }
  766. return false;
  767. }
  768. private bool FixupEventQueueGet(CapsRequest capReq, CapsStage stage)
  769. {
  770. if (stage != CapsStage.Response) return false;
  771. foreach (Dictionary<string, object> evt in (List<object>)((Dictionary<string, object>)capReq.Response)["events"])
  772. {
  773. string message = (string)evt["message"];
  774. Dictionary<string, object> body = (Dictionary<string, object>)evt["body"];
  775. if (message == "TeleportFinish" || message == "CrossedRegion")
  776. {
  777. Dictionary<string, object> info = null;
  778. if (message == "TeleportFinish")
  779. info = (Dictionary<string, object>)(((List<object>)body["Info"])[0]);
  780. else
  781. info = (Dictionary<string, object>)(((List<object>)body["RegionData"])[0]);
  782. byte[] bytes = (byte[])info["SimIP"];
  783. uint simIP = Helpers.BytesToUIntBig((byte[])info["SimIP"]);
  784. ushort simPort = (ushort)(int)info["SimPort"];
  785. string capsURL = (string)info["SeedCapability"];
  786. GenericCheck(ref simIP, ref simPort, ref capsURL, capReq.Info.Sim == activeCircuit);
  787. info["SeedCapability"] = capsURL;
  788. bytes[0] = (byte)(simIP % 256);
  789. bytes[1] = (byte)((simIP >> 8) % 256);
  790. bytes[2] = (byte)((simIP >> 16) % 256);
  791. bytes[3] = (byte)((simIP >> 24) % 256);
  792. info["SimIP"] = bytes;
  793. info["SimPort"] = (int)simPort;
  794. }
  795. else if (message == "EstablishAgentCommunication")
  796. {
  797. string ipAndPort = (string)body["sim-ip-and-port"];
  798. string[] pieces = ipAndPort.Split(':');
  799. byte[] bytes = IPAddress.Parse(pieces[0]).GetAddressBytes();
  800. uint simIP = (uint)(bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24));
  801. ushort simPort = (ushort)Convert.ToInt32(pieces[1]);
  802. string capsURL = (string)body["seed-capability"];
  803. Console.WriteLine("DEBUG: Got EstablishAgentCommunication for " + ipAndPort + " with seed cap " + capsURL);
  804. GenericCheck(ref simIP, ref simPort, ref capsURL, false);
  805. body["seed-capability"] = capsURL;
  806. body["sim-ip-and-port"] = new IPAddress((uint)simIP).ToString() + ":" + simPort;
  807. Console.WriteLine("DEBUG: Modified EstablishAgentCommunication to " + (string)body["sim-ip-and-port"] + " with seed cap " + capsURL);
  808. }
  809. }
  810. return false;
  811. }
  812. private void ProxyLogin(NetworkStream netStream, byte[] content)
  813. {
  814. lock (this)
  815. {
  816. // convert the body into an XML-RPC request
  817. XmlRpcRequest request = (XmlRpcRequest)(new XmlRpcRequestDeserializer()).Deserialize(Encoding.UTF8.GetString(content));
  818. // call the loginRequestDelegate
  819. if (loginRequestDelegate != null)
  820. try
  821. {
  822. loginRequestDelegate(request);
  823. }
  824. catch (Exception e)
  825. {
  826. Log("exception in login request deligate: " + e.Message, true);
  827. Log(e.StackTrace, true);
  828. }
  829. // add our userAgent and author to the request
  830. System.Collections.Hashtable requestParams = new System.Collections.Hashtable();
  831. if (proxyConfig.userAgent != null)
  832. requestParams["user-agent"] = proxyConfig.userAgent;
  833. if (proxyConfig.author != null)
  834. requestParams["author"] = proxyConfig.author;
  835. request.Params.Add(requestParams);
  836. XmlRpcResponse response;
  837. try
  838. {
  839. // forward the XML-RPC request to the server
  840. response = (XmlRpcResponse)request.Send(proxyConfig.remoteLoginUri.ToString(),
  841. 60000); //added 60 second timeout -- Andrew
  842. }
  843. catch (Exception e)
  844. {
  845. Console.WriteLine(e.Message);
  846. return;
  847. }
  848. System.Collections.Hashtable responseData = (System.Collections.Hashtable)response.Value;
  849. // proxy any simulator address given in the XML-RPC response
  850. if (responseData.Contains("sim_ip") && responseData.Contains("sim_port"))
  851. {
  852. IPEndPoint realSim = new IPEndPoint(IPAddress.Parse((string)responseData["sim_ip"]), Convert.ToUInt16(responseData["sim_port"]));
  853. IPEndPoint fakeSim = ProxySim(realSim);
  854. responseData["sim_ip"] = fakeSim.Address.ToString();
  855. responseData["sim_port"] = fakeSim.Port;
  856. activeCircuit = realSim;
  857. }
  858. // start a new proxy session
  859. Reset();
  860. if (responseData.Contains("seed_capability"))
  861. {
  862. CapInfo info = new CapInfo((string)responseData["seed_capability"], activeCircuit, "SeedCapability");
  863. info.AddDelegate(new CapsDelegate(FixupSeedCapsResponse));
  864. KnownCaps[(string)responseData["seed_capability"]] = info;
  865. responseData["seed_capability"] = loginURI + responseData["seed_capability"];
  866. }
  867. // call the loginResponseDelegate
  868. if (loginResponseDelegate != null)
  869. {
  870. try
  871. {
  872. loginResponseDelegate(response);
  873. }
  874. catch (Exception e)
  875. {
  876. Log("exception in login response delegate: " + e.Message, true);
  877. Log(e.StackTrace, true);
  878. }
  879. }
  880. // forward the XML-RPC response to the client
  881. StreamWriter writer = new StreamWriter(netStream);
  882. writer.Write("HTTP/1.0 200 OK\r\n");
  883. writer.Write("Content-type: text/xml\r\n");
  884. writer.Write("\r\n");
  885. XmlTextWriter responseWriter = new XmlTextWriter(writer);
  886. XmlRpcResponseSerializer.Singleton.Serialize(responseWriter, response);
  887. responseWriter.Close(); writer.Close();
  888. }
  889. }
  890. /*
  891. * Sim Proxy
  892. */
  893. private Socket simFacingSocket;
  894. private IPEndPoint activeCircuit = null;
  895. private Dictionary<IPEndPoint, IPEndPoint> proxyEndPoints = new Dictionary<IPEndPoint, IPEndPoint>();
  896. private Dictionary<IPEndPoint, SimProxy> simProxies = new Dictionary<IPEndPoint, SimProxy>();
  897. private Dictionary<EndPoint, SimProxy> proxyHandlers = new Dictionary<EndPoint, SimProxy>();
  898. private XmlRpcRequestDelegate loginRequestDelegate = null;
  899. private XmlRpcResponseDelegate loginResponseDelegate = null;
  900. private Dictionary<PacketType, List<PacketDelegate>> incomingDelegates = new Dictionary<PacketType, List<PacketDelegate>>();
  901. private Dictionary<PacketType, List<PacketDelegate>> outgoingDelegates = new Dictionary<PacketType, List<PacketDelegate>>();
  902. private List<Packet> queuedIncomingInjections = new List<Packet>();
  903. private List<Packet> queuedOutgoingInjections = new List<Packet>();
  904. // InitializeSimProxy: initialize the sim proxy
  905. private void InitializeSimProxy()
  906. {
  907. InitializeAddressCheckers();
  908. simFacingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  909. simFacingSocket.Bind(new IPEndPoint(proxyConfig.remoteFacingAddress, 0));
  910. Reset();
  911. }
  912. // Reset: start a new session
  913. private void Reset()
  914. {
  915. foreach (SimProxy simProxy in simProxies.Values)
  916. simProxy.Reset();
  917. KnownCaps = new Dictionary<string, CapInfo>();
  918. }
  919. private byte[] receiveBuffer = new byte[8192];
  920. private byte[] zeroBuffer = new byte[8192];
  921. private EndPoint remoteEndPoint = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
  922. // RunSimProxy: start listening for packets from remote sims
  923. private void RunSimProxy()
  924. {
  925. #if DEBUG_THREADS
  926. Console.WriteLine(">R> RunSimProxy");
  927. #endif
  928. simFacingSocket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, new AsyncCallback(ReceiveFromSim), null);
  929. }
  930. // ReceiveFromSim: packet received from a remote sim
  931. private void ReceiveFromSim(IAsyncResult ar)
  932. {
  933. lock (this) try
  934. {
  935. // pause listening and fetch the packet
  936. bool needsZero = false;
  937. bool needsCopy = true;
  938. int length;
  939. length = simFacingSocket.EndReceiveFrom(ar, ref remoteEndPoint);
  940. if (proxyHandlers.ContainsKey(remoteEndPoint))
  941. {
  942. // find the proxy responsible for forwarding this packet
  943. SimProxy simProxy = (SimProxy)proxyHandlers[remoteEndPoint];
  944. // interpret the packet according to the SL protocol
  945. Packet packet;
  946. int end = length - 1;
  947. packet = Packet.BuildPacket(receiveBuffer, ref end, zeroBuffer);
  948. #if DEBUG_SEQUENCE
  949. Console.WriteLine("<- " + packet.Type + " #" + packet.Header.Sequence);
  950. #endif
  951. // check for ACKs we're waiting for
  952. packet = simProxy.CheckAcks(packet, Direction.Incoming, ref length, ref needsCopy);
  953. // modify sequence numbers to account for injections
  954. uint oldSequence = packet.Header.Sequence;
  955. packet = simProxy.ModifySequence(packet, Direction.Incoming, ref length, ref needsCopy);
  956. // keep track of sequence numbers
  957. if (packet.Header.Sequence > simProxy.incomingSequence)
  958. simProxy.incomingSequence = packet.Header.Sequence;
  959. // check the packet for addresses that need proxying
  960. if (incomingCheckers.ContainsKey(packet.Type))
  961. {
  962. /* if (needsZero) {
  963. length = Helpers.ZeroDecode(packet.Header.Data, length, zeroBuffer);
  964. packet.Header.Data = zeroBuffer;
  965. needsZero = false;
  966. } */
  967. Packet newPacket = ((AddressChecker)incomingCheckers[packet.Type])(packet);
  968. SwapPacket(packet, newPacket);
  969. packet = newPacket;
  970. needsCopy = false;
  971. }
  972. // pass the packet to any callback delegates
  973. if (incomingDelegates.ContainsKey(packet.Type))
  974. {
  975. /* if (needsZero) {
  976. length = Helpers.ZeroDecode(packet.Header.Data, length, zeroBuffer);
  977. packet.Header.Data = zeroBuffer;
  978. needsCopy = true;
  979. } */
  980. if (needsCopy)
  981. {
  982. byte[] newData = new byte[packet.Header.Data.Length];
  983. Array.Copy(packet.Header.Data, 0, newData, 0, packet.Header.Data.Length);
  984. packet.Header.Data = newData; // FIXME
  985. }
  986. try
  987. {
  988. Packet newPacket = callDelegates(incomingDelegates, packet, (IPEndPoint)remoteEndPoint);
  989. if (newPacket == null)
  990. {
  991. if ((packet.Header.Flags & Helpers.MSG_RELIABLE) != 0)
  992. simProxy.Inject(SpoofAck(oldSequence), Direction.Outgoing);
  993. if ((packet.Header.Flags & Helpers.MSG_APPENDED_ACKS) != 0)
  994. packet = SeparateAck(packet);
  995. else
  996. packet = null;
  997. }
  998. else
  999. {
  1000. bool oldReliable = (packet.Header.Flags & Helpers.MSG_RELIABLE) != 0;
  1001. bool newReliable = (newPacket.Header.Flags & Helpers.MSG_RELIABLE) != 0;
  1002. if (oldReliable && !newReliable)
  1003. simProxy.Inject(SpoofAck(oldSequence), Direction.Outgoing);
  1004. else if (!oldReliable && newReliable)
  1005. simProxy.WaitForAck(packet, Direction.Incoming);
  1006. SwapPacket(packet, newPacket);
  1007. packet = newPacket;
  1008. }
  1009. }
  1010. catch (Exception e)
  1011. {
  1012. Log("exception in incoming delegate: " + e.Message, true);
  1013. Log(e.StackTrace, true);
  1014. }
  1015. if (packet != null)
  1016. simProxy.SendPacket(packet, false);
  1017. }
  1018. else
  1019. simProxy.SendPacket(packet, needsZero);
  1020. }
  1021. else
  1022. // ignore packets from unknown peers
  1023. Log("dropping packet from " + remoteEndPoint, false);
  1024. }
  1025. catch (Exception e)
  1026. {
  1027. Console.WriteLine(e.Message);
  1028. Console.WriteLine(e.StackTrace);
  1029. }
  1030. finally
  1031. {
  1032. // resume listening
  1033. simFacingSocket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, new AsyncCallback(ReceiveFromSim), null);
  1034. }
  1035. }
  1036. // SendPacket: send a packet to a sim from our fake client endpoint
  1037. public void SendPacket(Packet packet, IPEndPoint endPoint, bool skipZero)
  1038. {
  1039. byte[] buffer = packet.ToBytes();
  1040. if (skipZero || (packet.Header.Data[0] & Helpers.MSG_ZEROCODED) == 0)
  1041. simFacingSocket.SendTo(buffer, buffer.Length, SocketFlags.None, endPoint);
  1042. else
  1043. {
  1044. int zeroLength = Helpers.ZeroEncode(buffer, buffer.Length, zeroBuffer);
  1045. simFacingSocket.SendTo(zeroBuffer, zeroLength, SocketFlags.None, endPoint);
  1046. }
  1047. }
  1048. // SpoofAck: create an ACK for the given packet
  1049. public Packet SpoofAck(uint sequence)
  1050. {
  1051. PacketAckPacket spoof = new PacketAckPacket();
  1052. spoof.Packets = new PacketAckPacket.PacketsBlock[1];
  1053. spoof.Packets[0] = new PacketAckPacket.PacketsBlock();
  1054. spoof.Packets[0].ID = sequence;
  1055. return (Packet)spoof;
  1056. //Legacy:
  1057. ////Hashtable blocks = new Hashtable();
  1058. ////Hashtable fields = new Hashtable();
  1059. ////fields["ID"] = (uint)sequence;
  1060. ////blocks[fields] = "Packets";
  1061. ////return .BuildPacket("PacketAck", proxyConfig.protocol, blocks, Helpers.MSG_ZEROCODED);
  1062. }
  1063. // SeparateAck: create a standalone PacketAck for packet's appended ACKs
  1064. public Packet SeparateAck(Packet packet)
  1065. {
  1066. PacketAckPacket seperate = new PacketAckPacket();
  1067. seperate.Packets = new PacketAckPacket.PacketsBlock[packet.Header.AckList.Length];
  1068. for (int i = 0; i < packet.Header.AckList.Length; ++i)
  1069. {
  1070. seperate.Packets[i].ID = packet.Header.AckList[i];
  1071. }
  1072. Packet ack = seperate;
  1073. ack.Header.Sequence = packet.Header.Sequence;
  1074. return ack;
  1075. }
  1076. // SwapPacket: copy the sequence number and appended ACKs from one packet to another
  1077. public static void SwapPacket(Packet oldPacket, Packet newPacket)
  1078. {
  1079. newPacket.Header.Sequence = oldPacket.Header.Sequence;
  1080. int oldAcks = (oldPacket.Header.Data[0] & Helpers.MSG_APPENDED_ACKS) == 0 ? 0 : oldPacket.Header.AckList.Length;
  1081. int newAcks = (newPacket.Header.Data[0] & Helpers.MSG_APPENDED_ACKS) == 0 ? 0 : newPacket.Header.AckList.Length;
  1082. if (oldAcks != 0 || newAcks != 0)
  1083. {
  1084. uint[] newAckList = new uint[oldAcks];
  1085. Array.Copy(oldPacket.Header.AckList, 0, newAckList, 0, oldAcks);
  1086. newPacket.Header.AckList = newAckList;
  1087. newPacket.Header.AppendedAcks = oldPacket.Header.AppendedAcks;
  1088. }
  1089. }
  1090. // ProxySim: return the proxy for the specified sim, creating it if it doesn't exist
  1091. private IPEndPoint ProxySim(IPEndPoint simEndPoint)
  1092. {
  1093. if (proxyEndPoints.ContainsKey(simEndPoint))
  1094. // return the existing proxy
  1095. return (IPEndPoint)proxyEndPoints[simEndPoint];
  1096. else
  1097. {
  1098. // return a new proxy
  1099. SimProxy simProxy = new SimProxy(proxyConfig, simEndPoint, this);
  1100. IPEndPoint fakeSim = simProxy.LocalEndPoint();
  1101. Log("creating proxy for " + simEndPoint + " at " + fakeSim, false);
  1102. simProxy.Run();
  1103. proxyEndPoints.Add(simEndPoint, fakeSim);
  1104. simProxies.Add(simEndPoint, simProxy);
  1105. return fakeSim;
  1106. }
  1107. }
  1108. // AddHandler: remember which sim proxy corresponds to a given sim
  1109. private void AddHandler(EndPoint endPoint, SimProxy proxy)
  1110. {
  1111. proxyHandlers.Add(endPoint, proxy);
  1112. }
  1113. // SimProxy: proxy for a single simulator
  1114. private class SimProxy
  1115. {
  1116. private ProxyConfig proxyConfig;
  1117. private IPEndPoint remoteEndPoint;
  1118. private Proxy proxy;
  1119. private Socket socket;
  1120. public uint incomingSequence;
  1121. public uint outgoingSequence;
  1122. private List<uint> incomingInjections;
  1123. private List<uint> outgoingInjections;
  1124. private uint incomingOffset = 0;
  1125. private uint outgoingOffset = 0;
  1126. private Dictionary<uint, Packet> incomingAcks;
  1127. private Dictionary<uint, Packet> outgoingAcks;
  1128. private List<uint> incomingSeenAcks;
  1129. private List<uint> outgoingSeenAcks;
  1130. // SimProxy: construct a proxy for a single simulator
  1131. public SimProxy(ProxyConfig proxyConfig, IPEndPoint simEndPoint, Proxy proxy)
  1132. {
  1133. this.proxyConfig = proxyConfig;
  1134. remoteEndPoint = new IPEndPoint(simEndPoint.Address, simEndPoint.Port);
  1135. this.proxy = proxy;
  1136. socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  1137. socket.Bind(new IPEndPoint(proxyConfig.clientFacingAddress, 0));
  1138. proxy.AddHandler(remoteEndPoint, this);
  1139. Reset();
  1140. }
  1141. // Reset: start a new session
  1142. public void Reset()
  1143. {
  1144. incomingSequence = 0;
  1145. outgoingSequence = 0;
  1146. incomingInjections = new List<uint>();
  1147. outgoingInjections = new List<uint>();
  1148. incomingAcks = new Dictionary<uint, Packet>();
  1149. outgoingAcks = new Dictionary<uint, Packet>();
  1150. incomingSeenAcks = new List<uint>();
  1151. outgoingSeenAcks = new List<uint>();
  1152. }
  1153. // BackgroundTasks: resend unacknowledged packets and keep data structures clean
  1154. private void BackgroundTasks()
  1155. {
  1156. #if DEBUG_THREADS
  1157. Console.WriteLine(">T> BackgroundTasks-{0}", LocalEndPoint().Port);
  1158. #endif
  1159. try
  1160. {
  1161. int tick = 1;
  1162. int incomingInjectionsPoint = 0;
  1163. int outgoingInjectionsPoint = 0;
  1164. int incomingSeenAcksPoint = 0;
  1165. int outgoingSeenAcksPoint = 0;
  1166. for (; ; Thread.Sleep(1000)) lock (proxy)
  1167. {
  1168. if ((tick = (tick + 1) % 60) == 0)
  1169. {
  1170. for (int i = 0; i < incomingInjectionsPoint; ++i)
  1171. {
  1172. incomingInjections.RemoveAt(0);
  1173. ++incomingOffset;
  1174. #if DEBUG_SEQUENCE
  1175. Console.WriteLine("incomingOffset = " + incomingOffset);
  1176. #endif
  1177. }
  1178. incomingInjectionsPoint = incomingInjections.Count;
  1179. for (int i = 0; i < outgoingInjectionsPoint; ++i)
  1180. {
  1181. outgoingInjections.RemoveAt(0);
  1182. ++outgoingOffset;
  1183. #if DEBUG_SEQUENCE
  1184. Console.WriteLine("outgoingOffset = " + outgoingOffset);
  1185. #endif
  1186. }
  1187. outgoingInjectionsPoint = outgoingInjections.Count;
  1188. for (int i = 0; i < incomingSeenAcksPoint; ++i)
  1189. {
  1190. #if DEBUG_SEQUENCE
  1191. Console.WriteLine("incomingAcks.Remove(" + incomingSeenAcks[0] + ")");
  1192. #endif
  1193. incomingAcks.Remove(incomingSeenAcks[0]);
  1194. incomingSeenAcks.RemoveAt(0);
  1195. }
  1196. incomingSeenAcksPoint = incomingSeenAcks.Count;
  1197. for (int i = 0; i < outgoingSeenAcksPoint; ++i)
  1198. {
  1199. #if DEBUG_SEQUENCE
  1200. Console.WriteLine("outgoingAcks.Remove(" + outgoingSeenAcks[0] + ")");
  1201. #endif
  1202. outgoingAcks.Remove(outgoingSeenAcks[0]);
  1203. outgoingSeenAcks.RemoveAt(0);
  1204. }
  1205. outgoingSeenAcksPoint = outgoingSeenAcks.Count;
  1206. }
  1207. foreach (uint id in incomingAcks.Keys)
  1208. if (!incomingSeenAcks.Contains(id))
  1209. {
  1210. Packet packet = (Packet)incomingAcks[id];
  1211. packet.Header.Data[0] |= Helpers.MSG_RESENT;
  1212. #if DEBUG_SEQUENCE
  1213. Console.WriteLine("RESEND <- " + packet.Type + " #" + packet.Header.Sequence);
  1214. #endif
  1215. SendPacket(packet, false);
  1216. }
  1217. foreach (uint id in outgoingAcks.Keys)
  1218. if (!outgoingSeenAcks.Contains(id))
  1219. {
  1220. Packet packet = (Packet)outgoingAcks[id];
  1221. packet.Header.Data[0] |= Helpers.MSG_RESENT;
  1222. #if DEBUG_SEQUENCE
  1223. Console.WriteLine("RESEND -> " + packet.Type + " #" + packet.Header.Sequence);
  1224. #endif
  1225. proxy.SendPacket(packet, remoteEndPoint, false);
  1226. }
  1227. }
  1228. }
  1229. catch (Exception e)
  1230. {
  1231. Console.WriteLine(e.Message);
  1232. Console.WriteLine(e.StackTrace);
  1233. }
  1234. #if DEBUG_THREADS
  1235. Console.WriteLine("<T< BackgroundTasks");
  1236. #endif
  1237. }
  1238. // LocalEndPoint: return the endpoint that the client should communicate with
  1239. public IPEndPoint LocalEndPoint()
  1240. {
  1241. return (IPEndPoint)socket.LocalEndPoint;
  1242. }
  1243. private byte[] receiveBuffer = new byte[8192];
  1244. private byte[] zeroBuffer = new byte[8192];
  1245. private EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
  1246. bool firstReceive = true;
  1247. // Run: forward packets from the client to the sim
  1248. public void Run()
  1249. {
  1250. Thread backgroundTasks = new Thread(new ThreadStart(BackgroundTasks));
  1251. backgroundTasks.IsBackground = true;
  1252. backgroundTasks.Start();
  1253. #if DEBUG_THREADS
  1254. Console.WriteLine(">R> Run-{0}", LocalEndPoint().Port);
  1255. #endif
  1256. socket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref clientEndPoint, new AsyncCallback(ReceiveFromClient), null);
  1257. }
  1258. // ReceiveFromClient: packet received from the client
  1259. private void ReceiveFromClient(IAsyncResult ar)
  1260. {
  1261. lock (proxy)
  1262. {
  1263. try
  1264. {
  1265. // pause listening and fetch the packet
  1266. bool needsZero = false;
  1267. bool needsCopy = true;
  1268. int length;
  1269. length = socket.EndReceiveFrom(ar, ref clientEndPoint);
  1270. // interpret the packet according to the SL protocol
  1271. int end = length - 1;
  1272. Packet packet = libsecondlife.Packets.Packet.BuildPacket(receiveBuffer, ref end, zeroBuffer);
  1273. #if DEBUG_SEQUENCE
  1274. Console.WriteLine("-> " + packet.Type + " #" + packet.Header.Sequence);
  1275. #endif
  1276. // check for ACKs we're waiting for
  1277. packet = CheckAcks(packet, Direction.Outgoing, ref length, ref needsCopy);
  1278. // modify sequence numbers to account for injections
  1279. uint oldSequence = packet.Header.Sequence;
  1280. packet = ModifySequence(packet, Direction.Outgoing, ref length, ref needsCopy);
  1281. // keep track of sequence numbers
  1282. if (packet.Header.Sequence > outgoingSequence)
  1283. outgoingSequence = packet.Header.Sequence;
  1284. // check the packet for addresses that need proxying
  1285. if (proxy.outgoingCheckers.ContainsKey(packet.Type))
  1286. {
  1287. /* if (packet.Header.Zerocoded) {
  1288. length = Helpers.ZeroDecode(packet.Header.Data, length, zeroBuffer);
  1289. packet.Header.Data = zeroBuffer;
  1290. needsZero = false;
  1291. } */
  1292. Packet newPacket = ((AddressChecker)proxy.outgoingCheckers[packet.Type])(packet);
  1293. SwapPacket(packet, newPacket);
  1294. packet = newPacket;
  1295. length = packet.Header.Data.Length;
  1296. needsCopy = false;
  1297. }
  1298. // pass the packet to any callback delegates
  1299. if (proxy.outgoingDelegates.ContainsKey(packet.Type))
  1300. {
  1301. /* if (packet.Header.Zerocoded) {
  1302. length = Helpers.ZeroDecode(packet.Header.Data, length, zeroBuffer);
  1303. packet.Header.Data = zeroBuffer;
  1304. needsCopy = true;
  1305. } */
  1306. if (needsCopy)
  1307. {
  1308. byte[] newData = new byte[packet.Header.Data.Length];
  1309. Array.Copy(packet.Header.Data, 0, newData, 0, packet.Header.Data.Length);
  1310. packet.Header.Data = newData; // FIXME!!!
  1311. }
  1312. try
  1313. {
  1314. Packet newPacket = proxy.callDelegates(proxy.outgoingDelegates, packet, remoteEndPoint);
  1315. if (newPacket == null)
  1316. {
  1317. if ((packet.Header.Flags & Helpers.MSG_RELIABLE) != 0)
  1318. Inject(proxy.SpoofAck(oldSequence), Direction.Incoming);
  1319. if ((packet.Header.Flags & Helpers.MSG_APPENDED_ACKS) != 0)
  1320. packet = proxy.SeparateAck(packet);
  1321. else
  1322. packet = null;
  1323. }
  1324. else
  1325. {
  1326. bool oldReliable = (packet.Header.Flags & Helpers.MSG_RELIABLE) != 0;
  1327. bool newReliable = (newPacket.Header.Flags & Helpers.MSG_RELIABLE) != 0;
  1328. if (oldReliable && !newReliable)
  1329. Inject(proxy.SpoofAck(oldSequence), Direction.Incoming);
  1330. else if (!oldReliable && newReliable)
  1331. WaitForAck(packet, Direction.Outgoing);
  1332. SwapPacket(packet, newPacket);
  1333. packet = newPacket;
  1334. }
  1335. }
  1336. catch (Exception e)
  1337. {
  1338. proxy.Log("exception in outgoing delegate: " + e.Message, true);
  1339. proxy.Log(e.StackTrace, true);
  1340. }
  1341. if (packet != null)
  1342. proxy.SendPacket(packet, remoteEndPoint, false);
  1343. }
  1344. else
  1345. proxy.SendPacket(packet, remoteEndPoint, needsZero);
  1346. // send any packets queued for injection
  1347. if (firstReceive)
  1348. {
  1349. firstReceive = false;
  1350. foreach (Packet queuedPacket in proxy.queuedIncomingInjections)
  1351. Inject(queuedPacket, Direction.Incoming);
  1352. proxy.queuedIncomingInjections = new List<Packet>();
  1353. }
  1354. }
  1355. catch (Exception e)
  1356. {
  1357. Console.WriteLine(e.Message);
  1358. Console.WriteLine(e.StackTrace);
  1359. }
  1360. finally
  1361. {
  1362. // resume listening
  1363. socket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref clientEndPoint, new AsyncCallback(ReceiveFromClient), null);
  1364. }
  1365. }
  1366. }
  1367. // SendPacket: send a packet from the sim to the client via our fake sim endpoint
  1368. public void SendPacket(Packet packet, bool skipZero)
  1369. {
  1370. byte[] buffer = packet.ToBytes();
  1371. if (skipZero || (packet.Header.Data[0] & Helpers.MSG_ZEROCODED) == 0)
  1372. socket.SendTo(buffer, buffer.Length, SocketFlags.None, clientEndPoint);
  1373. else
  1374. {
  1375. int zeroLength = Helpers.ZeroEncode(buffer, buffer.Length, zeroBuffer);
  1376. socket.SendTo(zeroBuffer, zeroLength, SocketFlags.None, clientEndPoint);
  1377. }
  1378. }
  1379. // Inject: inject a packet
  1380. public void Inject(Packet packet, Direction direction)
  1381. {
  1382. if (direction == Direction.Incoming)
  1383. {
  1384. if (firstReceive)
  1385. {
  1386. proxy.queuedIncomingInjections.Add(packet);
  1387. return;
  1388. }
  1389. incomingInjections.Add(++incomingSequence);
  1390. packet.Header.Sequence = incomingSequence;
  1391. }
  1392. else
  1393. {
  1394. outgoingInjections.Add(++outgoingSequence);
  1395. packet.Header.Sequence = outgoingSequence;
  1396. }
  1397. #if DEBUG_SEQUENCE
  1398. Console.WriteLine("INJECT " + (direction == Direction.Incoming ? "<-" : "->") + " " + packet.Type + " #" + packet.Header.Sequence);
  1399. #endif
  1400. if ((packet.Header.Data[0] & Helpers.MSG_RELIABLE) != 0)
  1401. WaitForAck(packet, direction);
  1402. if (direction == Direction.Incoming)
  1403. {
  1404. byte[] buffer = packet.ToBytes();
  1405. if ((packet.Header.Data[0] & Helpers.MSG_ZEROCODED) == 0)
  1406. socket.SendTo(buffer, buffer.Length, SocketFlags.None, clientEndPoint);
  1407. else
  1408. {
  1409. int zeroLength = Helpers.ZeroEncode(buffer, buffer.Length, zeroBuffer);
  1410. socket.SendTo(zeroBuffer, zeroLength, SocketFlags.None, clientEndPoint);
  1411. }
  1412. }
  1413. else
  1414. proxy.SendPacket(packet, remoteEndPoint, false);
  1415. }
  1416. // WaitForAck: take care of resending a packet until it's ACKed
  1417. public void WaitForAck(Packet packet, Direction direction)
  1418. {
  1419. Dictionary<uint, Packet> table = direction == Direction.Incoming ? incomingAcks : outgoingAcks;
  1420. table.Add(packet.Header.Sequence, packet);
  1421. }
  1422. // CheckAcks: check for and remove ACKs of packets we've injected
  1423. public Packet CheckAcks(Packet packet, Direction direction, ref int length, ref bool needsCopy)
  1424. {
  1425. Dictionary<uint, Packet> acks = direction == Direction.Incoming ? outgoingAcks : incomingAcks;
  1426. List<uint> seenAcks = direction == Direction.Incoming ? outgoingSeenAcks : incomingSeenAcks;
  1427. if (acks.Count == 0)
  1428. return packet;
  1429. // check for embedded ACKs
  1430. if (packet.Type == PacketType.PacketAck)
  1431. {
  1432. bool changed = false;
  1433. List<PacketAckPacket.PacketsBlock> newPacketBlocks = new List<PacketAckPacket.PacketsBlock>();
  1434. foreach (PacketAckPacket.PacketsBlock pb in ((PacketAckPacket)packet).Packets)
  1435. {
  1436. uint id = pb.ID;
  1437. #if DEBUG_SEQUENCE
  1438. string hrup = "Check !" + id;
  1439. #endif
  1440. if (acks.ContainsKey(id))
  1441. {
  1442. #if DEBUG_SEQUENCE
  1443. hrup += " get's";
  1444. #endif
  1445. seenAcks.Add(id);
  1446. changed = true;
  1447. }
  1448. else
  1449. newPacketBlocks.Add(pb);
  1450. #if DEBUG_SEQUENCE
  1451. Console.WriteLine(hrup);
  1452. #endif
  1453. }
  1454. if (changed)
  1455. {
  1456. PacketAckPacket newPacket = new PacketAckPacket();
  1457. newPacket.Packets = new PacketAckPacket.PacketsBlock[newPacketBlocks.Count];
  1458. int a = 0;
  1459. foreach (PacketAckPacket.PacketsBlock pb in newPacketBlocks)
  1460. {
  1461. newPacket.Packets[a++] = pb;
  1462. }
  1463. SwapPacket(packet, (Packet)newPacket);
  1464. packet = newPacket;
  1465. length = packet.Header.Data.Length;
  1466. needsCopy = false;
  1467. }
  1468. }
  1469. // check for appended ACKs
  1470. if ((packet.Header.Data[0] & Helpers.MSG_APPENDED_ACKS) != 0)
  1471. {
  1472. int ackCount = packet.Header.AckList.Length;
  1473. for (int i = 0; i < ackCount; )
  1474. {
  1475. uint ackID = packet.Header.AckList[i]; // FIXME FIXME FIXME
  1476. #if DEBUG_SEQUENCE
  1477. string hrup = "Check @" + ackID;
  1478. #endif
  1479. if (acks.ContainsKey(ackID))
  1480. {
  1481. #if DEBUG_SEQUENCE
  1482. hrup += " get's";
  1483. #endif
  1484. uint[] newAcks = new uint[ackCount - 1];
  1485. Array.Copy(packet.Header.AckList, 0, newAcks, 0, i);
  1486. Array.Copy(packet.Header.AckList, i + 1, newAcks, i, ackCount - i - 1);
  1487. packet.Header.AckList = newAcks;
  1488. --ackCount;
  1489. seenAcks.Add(ackID);
  1490. needsCopy = false;
  1491. }
  1492. else
  1493. ++i;
  1494. #if DEBUG_SEQUENCE
  1495. Console.WriteLine(hrup);
  1496. #endif
  1497. }
  1498. if (ackCount == 0)
  1499. {
  1500. packet.Header.Flags ^= Helpers.MSG_APPENDED_ACKS;
  1501. packet.Header.AckList = new uint[0];
  1502. }
  1503. }
  1504. return packet;
  1505. }
  1506. // ModifySequence: modify a packet's sequence number and ACK IDs to account for injections
  1507. public Packet ModifySequence(Packet packet, Direction direction, ref int length, ref bool needsCopy)
  1508. {
  1509. List<uint> ourInjections = direction == Direction.Outgoing ? outgoingInjections : incomingInjections;
  1510. List<uint> theirInjections = direction == Direction.Incoming ? outgoingInjections : incomingInjections;
  1511. uint ourOffset = direction == Direction.Outgoing ? outgoingOffset : incomingOffset;
  1512. uint theirOffset = direction == Direction.Incoming ? outgoingOffset : incomingOffset;
  1513. uint newSequence = (uint)(packet.Header.Sequence + ourOffset);
  1514. foreach (uint injection in ourInjections)
  1515. if (newSequence >= injection)
  1516. ++newSequence;
  1517. #if DEBUG_SEQUENCE
  1518. Console.WriteLine("Mod #" + packet.Header.Sequence + " = " + newSequence);
  1519. #endif
  1520. packet.Header.Sequence = newSequence;
  1521. if ((packet.Header.Flags & Helpers.MSG_APPENDED_ACKS) != 0)
  1522. {
  1523. int ackCount = packet.Header.AckList.Length;
  1524. for (int i = 0; i < ackCount; ++i)
  1525. {
  1526. int offset = length - (ackCount - i) * 4 - 1;
  1527. uint ackID = packet.Header.AckList[i] - theirOffset;
  1528. #if DEBUG_SEQUENCE
  1529. uint hrup = packet.Header.AckList[i];
  1530. #endif
  1531. for (int j = theirInjections.Count - 1; j >= 0; --j)
  1532. if (ackID >= (uint)theirInjections[j])
  1533. --ackID;
  1534. #if DEBUG_SEQUENCE
  1535. Console.WriteLine("Mod @" + hrup + " = " + ackID);
  1536. #endif
  1537. packet.Header.AckList[i] = ackID;
  1538. }
  1539. }
  1540. if (packet.Type == PacketType.PacketAck)
  1541. {
  1542. PacketAckPacket pap = (PacketAckPacket)packet;
  1543. foreach (PacketAckPacket.PacketsBlock pb in pap.Packets)
  1544. {
  1545. uint ackID = (uint)pb.ID - theirOffset;
  1546. #if DEBUG_SEQUENCE
  1547. uint hrup = (uint)pb.ID;
  1548. #endif
  1549. for (int i = theirInjections.Count - 1; i >= 0; --i)
  1550. if (ackID >= (uint)theirInjections[i])
  1551. --ackID;
  1552. #if DEBUG_SEQUENCE
  1553. Console.WriteLine("Mod !" + hrup + " = " + ackID);
  1554. #endif
  1555. pb.ID = ackID;
  1556. }
  1557. //SwapPacket(packet, (Packet)pap);
  1558. // packet = (Packet)pap;
  1559. length = packet.Header.Data.Length;
  1560. needsCopy = false;
  1561. }
  1562. return packet;
  1563. }
  1564. }
  1565. // Checkers swap proxy addresses in for real addresses. A few constraints:
  1566. // - Checkers must not alter the incoming packet.
  1567. // - Checkers must return a freshly built packet, even if nothing's changed.
  1568. // - The incoming packet's buffer may be longer than the length of the data it contains.
  1569. // - The incoming packet's buffer must not be used after the checker returns.
  1570. // This is all because checkers may be operating on data that's still in a scratch buffer.
  1571. delegate Packet AddressChecker(Packet packet);
  1572. Dictionary<PacketType, AddressChecker> incomingCheckers = new Dictionary<PacketType, AddressChecker>();
  1573. Dictionary<PacketType, AddressChecker> outgoingCheckers = new Dictionary<PacketType, AddressChecker>();
  1574. // InitializeAddressCheckers: initialize delegates that check packets for addresses that need proxying
  1575. private void InitializeAddressCheckers()
  1576. {
  1577. // TODO: what do we do with mysteries and empty IPs?
  1578. AddMystery(PacketType.OpenCircuit);
  1579. //AddMystery(PacketType.AgentPresenceResponse);
  1580. incomingCheckers.Add(PacketType.TeleportFinish, new AddressChecker(CheckTeleportFinish));
  1581. incomingCheckers.Add(PacketType.CrossedRegion, new AddressChecker(CheckCrossedRegion));
  1582. incomingCheckers.Add(PacketType.EnableSimulator, new AddressChecker(CheckEnableSimulator));
  1583. //incomingCheckers.Add("UserLoginLocationReply", new AddressChecker(CheckUserLoginLocationReply));
  1584. }
  1585. // AddMystery: add a checker delegate that logs packets we're watching for development purposes
  1586. private void AddMystery(PacketType type)
  1587. {
  1588. incomingCheckers.Add(type, new AddressChecker(LogIncomingMysteryPacket));
  1589. outgoingCheckers.Add(type, new AddressChecker(LogOutgoingMysteryPacket));
  1590. }
  1591. // GenericCheck: replace the sim address in a packet with our proxy address
  1592. private void GenericCheck(ref uint simIP, ref ushort simPort, ref string simCaps, bool active)
  1593. {
  1594. IPAddress sim_ip = new IPAddress((long)simIP);
  1595. IPEndPoint realSim = new IPEndPoint(sim_ip, Convert.ToInt32(simPort));
  1596. IPEndPoint fakeSim = ProxySim(realSim);
  1597. simPort = (ushort)fakeSim.Port;
  1598. int i = 0;
  1599. byte[] bytes = fakeSim.Address.GetAddressBytes();
  1600. simIP = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24));
  1601. if (simCaps != null && simCaps.Length > 0)
  1602. {
  1603. CapInfo info = new CapInfo(simCaps, realSim, "SeedCapability");
  1604. info.AddDelegate(new CapsDelegate(FixupSeedCapsResponse));
  1605. lock (this)
  1606. {
  1607. KnownCaps[simCaps] = info;
  1608. }
  1609. simCaps = loginURI + simCaps;
  1610. }
  1611. if (active)
  1612. activeCircuit = realSim;
  1613. }
  1614. // CheckTeleportFinish: check TeleportFinish packets
  1615. private Packet CheckTeleportFinish(Packet packet)
  1616. {
  1617. TeleportFinishPacket tfp = (TeleportFinishPacket)packet;
  1618. string simCaps = Encoding.UTF8.GetString(tfp.Info.SeedCapability).Replace("\0", "");
  1619. GenericCheck(ref tfp.Info.SimIP, ref tfp.Info.SimPort, ref simCaps, true);
  1620. tfp.Info.SeedCapability = Helpers.StringToField(simCaps);
  1621. return (Packet)tfp;
  1622. }
  1623. // CheckEnableSimulator: check EnableSimulator packets
  1624. private Packet CheckEnableSimulator(Packet packet)
  1625. {
  1626. EnableSimulatorPacket esp = (EnableSimulatorPacket)packet;
  1627. string simCaps = null;
  1628. GenericCheck(ref esp.SimulatorInfo.IP, ref esp.SimulatorInfo.Port, ref simCaps, false);
  1629. return (Packet)esp;
  1630. }
  1631. // CheckCrossedRegion: check CrossedRegion packets
  1632. private Packet CheckCrossedRegion(Packet packet)
  1633. {
  1634. CrossedRegionPacket crp = (CrossedRegionPacket)packet;
  1635. string simCaps = Encoding.UTF8.GetString(crp.RegionData.SeedCapability).Replace("\0", "");
  1636. GenericCheck(ref crp.RegionData.SimIP, ref crp.RegionData.SimPort, ref simCaps, true);
  1637. crp.RegionData.SeedCapability = Helpers.StringToField(simCaps);
  1638. return (Packet)crp;
  1639. }
  1640. // LogPacket: log a packet dump
  1641. private Packet LogPacket(Packet packet, string type)
  1642. {
  1643. Log(type + " packet:", true);
  1644. Log(packet, true);
  1645. return packet;
  1646. }
  1647. // LogIncomingMysteryPacket: log an incoming packet we're watching for development purposes
  1648. private Packet LogIncomingMysteryPacket(Packet packet)
  1649. {
  1650. return LogPacket(packet, "incoming mystery");
  1651. }
  1652. // LogOutgoingMysteryPacket: log an outgoing packet we're watching for development purposes
  1653. private Packet LogOutgoingMysteryPacket(Packet packet)
  1654. {
  1655. return LogPacket (packet , "outgoing mystery");
  1656. }
  1657. }
  1658. // Describes the data format of a capability
  1659. public enum CapsDataFormat
  1660. {
  1661. Binary = 0,
  1662. LLSD = 1
  1663. }
  1664. // Describes a caps URI
  1665. public class CapInfo
  1666. {
  1667. private string uri;
  1668. private IPEndPoint sim;
  1669. private string type;
  1670. private CapsDataFormat reqFmt;
  1671. private CapsDataFormat respFmt;
  1672. private List<CapsDelegate> Delegates = new List<CapsDelegate>();
  1673. public CapInfo(string URI, IPEndPoint Sim, string CapType)
  1674. :
  1675. this(URI, Sim, CapType, CapsDataFormat.LLSD, CapsDataFormat.LLSD) { }
  1676. public CapInfo(string URI, IPEndPoint Sim, string CapType, CapsDataFormat ReqFmt, CapsDataFormat RespFmt)
  1677. {
  1678. uri = URI; sim = Sim; type = CapType; reqFmt = ReqFmt; respFmt = RespFmt;
  1679. }
  1680. public string URI
  1681. {
  1682. get { return uri; }
  1683. }
  1684. public string CapType
  1685. {
  1686. get { return type; } /* EventQueueGet, etc */
  1687. }
  1688. public IPEndPoint Sim
  1689. {
  1690. get { return sim; }
  1691. }
  1692. public CapsDataFormat ReqFmt
  1693. {
  1694. get { return reqFmt; } /* expected request format */
  1695. }
  1696. public CapsDataFormat RespFmt
  1697. {
  1698. get { return respFmt; } /* expected response format */
  1699. }
  1700. public void AddDelegate(CapsDelegate deleg)
  1701. {
  1702. lock (this)
  1703. {
  1704. if (!Delegates.Contains(deleg))
  1705. {
  1706. Delegates.Add(deleg);
  1707. }
  1708. }
  1709. }
  1710. public void RemoveDelegate(CapsDelegate deleg)
  1711. {
  1712. lock (this)
  1713. {
  1714. if (Delegates.Contains(deleg))
  1715. {
  1716. Delegates.Remove(deleg);
  1717. }
  1718. }
  1719. }
  1720. // inefficient, but avoids potential deadlocks.
  1721. public List<CapsDelegate> GetDelegates()
  1722. {
  1723. lock (this)
  1724. {
  1725. return new List<CapsDelegate>(Delegates);
  1726. }
  1727. }
  1728. }
  1729. // Information associated with a caps request/response
  1730. public class CapsRequest
  1731. {
  1732. public CapsRequest(CapInfo info)
  1733. {
  1734. Info = info;
  1735. }
  1736. public readonly CapInfo Info;
  1737. // The request
  1738. public object Request = null;
  1739. // The corresponding response
  1740. public object Response = null;
  1741. }
  1742. // XmlRpcRequestDelegate: specifies a delegate to be called for XML-RPC requests
  1743. public delegate void XmlRpcRequestDelegate(XmlRpcRequest request);
  1744. // XmlRpcResponseDelegate: specifies a delegate to be called for XML-RPC responses
  1745. public delegate void XmlRpcResponseDelegate(XmlRpcResponse response);
  1746. // PacketDelegate: specifies a delegate to be called when a packet passes through the proxy
  1747. public delegate Packet PacketDelegate(Packet packet, IPEndPoint endPoint);
  1748. // Delegate for a caps request. Generally called twice - first with stage = CapsStage.Request
  1749. // before the request is sent, then with stage = CapsStage.Response when the response is
  1750. // received. Returning true causes all the subsequent delegates in that stage to be skipped,
  1751. // and in the case of CapsStage.Request also prevents the request being forwarded. In this
  1752. // case, you should set req.Response to the response you want to return.
  1753. // Can modify req.Request and req.Response, with the expected effects.
  1754. public delegate bool CapsDelegate(CapsRequest req, CapsStage stage);
  1755. // Direction: specifies whether a packet is going to the client (Incoming) or to a sim (Outgoing)
  1756. public enum Direction
  1757. {
  1758. Incoming,
  1759. Outgoing
  1760. }
  1761. public enum CapsStage
  1762. {
  1763. Request,
  1764. Response
  1765. }
  1766. }