PageRenderTime 70ms CodeModel.GetById 32ms 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

Large files files are truncated, but you can click here to view the full file

  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 s…

Large files files are truncated, but you can click here to view the full file