corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * GridProxy.cs: implementation of OpenMetaverse 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 openmetaverse.org 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  
33 using System;
34 using System.IO;
35 using System.Net;
36 using System.Xml;
37 using System.Text;
38 using System.Threading;
39 using System.Net.Sockets;
40 using System.Collections.Generic;
41 using System.Text.RegularExpressions;
42 using OpenMetaverse;
43 using OpenMetaverse.Http;
44 using OpenMetaverse.Packets;
45 using OpenMetaverse.StructuredData;
46 using log4net;
47 using Nwc.XmlRpc;
48 using Logger = Nwc.XmlRpc.Logger;
49  
50 namespace GridProxy
51 {
52 /// <summary>
53 /// Proxy Configuration Class
54 /// </summary>
55 public class ProxyConfig
56 {
57 /// <summary>
58 /// The user agent reported to the remote server
59 /// </summary>
60 public string userAgent;
61 /// <summary>
62 /// Email address of the proxy application's author
63 /// </summary>
64 public string author;
65 /// <summary>
66 /// The port the proxy server will listen on
67 /// </summary>
68 public ushort loginPort = 8080;
69 /// <summary>
70 /// The IP Address the proxy server will communication with the client on
71 /// </summary>
72 public IPAddress clientFacingAddress = IPAddress.Loopback;
73 /// <summary>
74 /// The IP Address the proxy server will communicate with the server on
75 /// </summary>
76 public IPAddress remoteFacingAddress = IPAddress.Any;
77 /// <summary>
78 /// The URI of the login server
79 /// </summary>
80 public Uri remoteLoginUri = new Uri("https://login.agni.lindenlab.com/cgi-bin/login.cgi");
81  
82 /// <summary>
83 /// construct a default proxy configuration with the specified userAgent and author
84 /// </summary>
85 /// <param name="userAgent">The user agent reported to the remote server</param>
86 /// <param name="author">Email address of the proxy application's author</param>
87 public ProxyConfig(string userAgent, string author)
88 {
89 this.userAgent = userAgent;
90 this.author = author;
91 }
92  
93 /// <summary>
94 /// construct a default proxy configuration, parsing command line arguments (try --help)
95 /// </summary>
96 /// <param name="userAgent">The user agent reported to the remote server</param>
97 /// <param name="author">Email address of the proxy application's author</param>
98 /// <param name="args">An array containing the parameters to use to override the proxy
99 /// servers default settings</param>
100 public ProxyConfig(string userAgent, string author, string[] args, bool exitOnError)
101 : this(userAgent, author)
102 {
103 Dictionary<string, ArgumentParser> argumentParsers = new Dictionary<string, ArgumentParser>();
104 argumentParsers["help"] = new ArgumentParser(ParseHelp);
105 argumentParsers["proxy-help"] = new ArgumentParser(ParseHelp);
106 argumentParsers["proxy-login-port"] = new ArgumentParser(ParseLoginPort);
107 argumentParsers["proxy-client-facing-address"] = new ArgumentParser(ParseClientFacingAddress);
108 argumentParsers["proxy-remote-facing-address"] = new ArgumentParser(ParseRemoteFacingAddress);
109 argumentParsers["proxy-remote-login-uri"] = new ArgumentParser(ParseRemoteLoginUri);
110  
111 foreach (string arg in args)
112 {
113 foreach (string argument in argumentParsers.Keys)
114 {
115 Match match = (new Regex("^--" + argument + "(?:=(.*))?$")).Match(arg);
116 if (match.Success)
117 {
118 string value;
119 if (match.Groups[1].Captures.Count == 1)
120 value = match.Groups[1].Captures[0].ToString();
121 else
122 value = null;
123 try
124 {
125 ((ArgumentParser)argumentParsers[argument])(value);
126 }
127 catch
128 {
129 Console.WriteLine("invalid value for --" + argument);
130 if (exitOnError)
131 {
132 ParseHelp(null);
133 }
134 else
135 {
136 throw;
137 }
138 }
139 }
140 }
141 }
142 }
143  
144 private delegate void ArgumentParser(string value);
145  
146 private void ParseHelp(string value)
147 {
148 Console.WriteLine("Proxy command-line arguments:");
149 Console.WriteLine(" --help display this help");
150 Console.WriteLine(" --proxy-login-port=<port> listen for logins on <port>");
151 Console.WriteLine(" --proxy-client-facing-address=<IP> communicate with client via <IP>");
152 Console.WriteLine(" --proxy-remote-facing-address=<IP> communicate with server via <IP>");
153 Console.WriteLine(" --proxy-remote-login-uri=<URI> use SL login server at <URI>");
154 Console.WriteLine(" --log-all log all packets by default in Analyst");
155 Console.WriteLine(" --log-whitelist=<file> log packets listed in file, one name per line");
156 Console.WriteLine(" --no-log-blacklist=<file> don't log packets in file, one name per line");
157 Console.WriteLine(" --output=<logfile> log Analyst output to a file");
158  
159 Environment.Exit(1);
160 }
161  
162 private void ParseLoginPort(string value)
163 {
164 loginPort = Convert.ToUInt16(value);
165 }
166  
167 private void ParseClientFacingAddress(string value)
168 {
169 clientFacingAddress = IPAddress.Parse(value);
170 }
171  
172 private void ParseRemoteFacingAddress(string value)
173 {
174 remoteFacingAddress = IPAddress.Parse(value);
175 }
176  
177 private void ParseRemoteLoginUri(string value)
178 {
179 remoteLoginUri = new Uri(value);
180 }
181 }
182  
183 // Proxy: OpenMetaverse proxy server
184 // A Proxy instance is only prepared to deal with one client at a time.
185 public class Proxy
186 {
187 public ProxyConfig proxyConfig;
188 private string loginURI;
189  
190 static List<string> BinaryResponseCaps = new List<string>()
191 {
192 "GetTexture",
193 "GetMesh",
194 "GetMesh2"
195 };
196  
197 /*
198 * Proxy Management
199 */
200  
201 // Proxy: construct a proxy server with the given configuration
202 public Proxy(ProxyConfig proxyConfig)
203 {
204 this.proxyConfig = proxyConfig;
205  
206 ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
207 ServicePointManager.Expect100Continue = false;
208 // Even though this will compile on Mono 2.4, it throws a runtime exception
209 //ServicePointManager.ServerCertificateValidationCallback = TrustAllCertificatePolicy.TrustAllCertificateHandler;
210  
211 InitializeLoginProxy();
212 InitializeSimProxy();
213 InitializeCaps();
214 }
215  
216 object keepAliveLock = new object();
217  
218 // Start: begin accepting clients
219 public void Start()
220 {
221 lock (this)
222 {
223 System.Threading.Monitor.Enter(keepAliveLock);
224 (new Thread(new ThreadStart(KeepAlive))).Start();
225  
226 RunSimProxy();
227  
228 Thread runLoginProxy = new Thread(new ThreadStart(RunLoginProxy));
229 runLoginProxy.IsBackground = true;
230 runLoginProxy.Name = "Login Proxy";
231 runLoginProxy.Start();
232  
233 IPEndPoint endPoint = (IPEndPoint)loginServer.LocalEndPoint;
234 IPAddress displayAddress;
235 if (endPoint.Address == IPAddress.Any)
236 displayAddress = IPAddress.Loopback;
237 else
238 displayAddress = endPoint.Address;
239 loginURI = "http://" + displayAddress + ":" + endPoint.Port + "/";
240  
241 OpenMetaverse.Logger.Log("Proxy ready at " + loginURI, Helpers.LogLevel.Info);
242 }
243 }
244  
245 // Stop: allow foreground threads to die
246 public void Stop()
247 {
248 lock (this)
249 {
250 System.Threading.Monitor.Exit(keepAliveLock);
251 }
252 }
253  
254 // KeepAlive: blocks until the proxy is free to shut down
255 public void KeepAlive()
256 {
257  
258 OpenMetaverse.Logger.Log(">T> KeepAlive", Helpers.LogLevel.Debug);
259  
260 lock (keepAliveLock) { };
261  
262 if (loginServer.Connected)
263 {
264 loginServer.Disconnect(false);
265 loginServer.Shutdown(SocketShutdown.Both);
266 }
267  
268 loginServer.Close();
269  
270 OpenMetaverse.Logger.Log("<T< KeepAlive", Helpers.LogLevel.Debug);
271 }
272  
273 // AddDelegate: add callback packetDelegate for packets of type packetName going direction
274 public void AddDelegate(PacketType packetType, Direction direction, PacketDelegate packetDelegate)
275 {
276 lock (this)
277 {
278 Dictionary<PacketType, List<PacketDelegate>> delegates = (direction == Direction.Incoming ? incomingDelegates : outgoingDelegates);
279 if (!delegates.ContainsKey(packetType))
280 {
281 delegates[packetType] = new List<PacketDelegate>();
282 }
283 List<PacketDelegate> delegateArray = delegates[packetType];
284 if (!delegateArray.Contains(packetDelegate))
285 {
286 delegateArray.Add(packetDelegate);
287 }
288 }
289 }
290  
291 // RemoveDelegate: remove callback for packets of type packetName going direction
292 public void RemoveDelegate(PacketType packetType, Direction direction, PacketDelegate packetDelegate)
293 {
294 lock (this)
295 {
296 Dictionary<PacketType, List<PacketDelegate>> delegates = (direction == Direction.Incoming ? incomingDelegates : outgoingDelegates);
297 if (!delegates.ContainsKey(packetType))
298 {
299 return;
300 }
301 List<PacketDelegate> delegateArray = delegates[packetType];
302 if (delegateArray.Contains(packetDelegate))
303 {
304 delegateArray.Remove(packetDelegate);
305 }
306 }
307 }
308  
309 private Packet callDelegates(Dictionary<PacketType, List<PacketDelegate>> delegates, Packet packet, IPEndPoint remoteEndPoint)
310 {
311 PacketType origType = packet.Type;
312 foreach (PacketDelegate del in delegates[origType])
313 {
314 try { packet = del(packet, remoteEndPoint); }
315 catch (Exception ex) { OpenMetaverse.Logger.Log("Error in packet delegate", Helpers.LogLevel.Warning, ex); }
316  
317 // FIXME: how should we handle the packet type changing?
318 if (packet == null || packet.Type != origType) break;
319 }
320 return packet;
321 }
322  
323 // InjectPacket: send packet to the client or server when direction is Incoming or Outgoing, respectively
324 public void InjectPacket(Packet packet, Direction direction)
325 {
326 lock (this)
327 {
328 if (activeCircuit == null)
329 {
330 // no active circuit; queue the packet for injection once we have one
331 List<Packet> queue = direction == Direction.Incoming ? queuedIncomingInjections : queuedOutgoingInjections;
332 queue.Add(packet);
333 }
334 else
335 // tell the active sim proxy to inject the packet
336 ((SimProxy)simProxies[activeCircuit]).Inject(packet, direction);
337 }
338 }
339  
340 /*
341 * Login Proxy
342 */
343  
344 private Socket loginServer;
345 private int capsReqCount = 0;
346  
347 // InitializeLoginProxy: initialize the login proxy
348 private void InitializeLoginProxy()
349 {
350 try
351 {
352 loginServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
353 loginServer.Bind(new IPEndPoint(proxyConfig.clientFacingAddress, proxyConfig.loginPort));
354 loginServer.Listen(1);
355 }
356 catch (SocketException e)
357 {
358 OpenMetaverse.Logger.Log("Socket Exception", Helpers.LogLevel.Error, e);
359 }
360 catch (ObjectDisposedException e)
361 {
362 OpenMetaverse.Logger.Log("Socket Object is disposed Exception", Helpers.LogLevel.Error, e);
363 }
364 }
365  
366 // RunLoginProxy: process login requests from clients
367 private void RunLoginProxy()
368 {
369 OpenMetaverse.Logger.Log(">T> RunLoginProxy", Helpers.LogLevel.Debug);
370  
371 try
372 {
373 for (; ; )
374 {
375 try
376 {
377 Socket client = loginServer.Accept();
378  
379 Thread connThread = new Thread((ThreadStart)delegate
380 {
381 OpenMetaverse.Logger.Log(">T> LoginProxy", Helpers.LogLevel.Debug);
382 ProxyHTTP(client);
383 OpenMetaverse.Logger.Log("<T< LoginProxy", Helpers.LogLevel.Debug);
384 });
385  
386 connThread.IsBackground = true;
387 connThread.Name = "LoginProxy";
388 connThread.Start();
389 }
390 catch (SocketException e)
391 {
392 // indicates we've told the listener to shutdown
393 if (e.SocketErrorCode == SocketError.Interrupted)
394 break;
395  
396 OpenMetaverse.Logger.Log("Login Failed", Helpers.LogLevel.Error, e);
397 break;
398 }
399 catch (ObjectDisposedException)
400 {
401 break;
402 }
403 // send any packets queued for injection
404 if (activeCircuit != null)
405 {
406 lock (this)
407 {
408 SimProxy activeProxy = (SimProxy)simProxies[activeCircuit];
409 foreach (Packet packet in queuedOutgoingInjections)
410 activeProxy.Inject(packet, Direction.Outgoing);
411 queuedOutgoingInjections = new List<Packet>();
412 }
413 }
414 }
415 }
416 catch (Exception e)
417 {
418 OpenMetaverse.Logger.Log("Exception in RunLoginProxy", Helpers.LogLevel.Error, e);
419 }
420  
421 OpenMetaverse.Logger.Log("<T< RunLoginProxy", Helpers.LogLevel.Debug);
422 }
423  
424 private class HandyNetReader
425 {
426 private NetworkStream netStream;
427 private const int BUF_SIZE = 8192;
428 private byte[] buf = new byte[BUF_SIZE];
429 private int bufFill = 0;
430  
431 public HandyNetReader(NetworkStream s)
432 {
433 netStream = s;
434 }
435  
436 public byte[] ReadLine()
437 {
438 int i = -1;
439 while (true)
440 {
441 i = Array.IndexOf(buf, (byte)'\n', 0, bufFill);
442 if (i >= 0) break;
443 if (bufFill >= BUF_SIZE) return null;
444 if (!ReadMore()) return null;
445 }
446 if (bufFill < (i + 1)) return null;
447 byte[] ret = new byte[i];
448 Array.Copy(buf, ret, i);
449 Array.Copy(buf, i + 1, buf, 0, bufFill - (i + 1));
450 bufFill -= i + 1;
451 return ret;
452 }
453  
454 private bool ReadMore()
455 {
456 try
457 {
458 int n = netStream.Read(buf, bufFill, BUF_SIZE - bufFill);
459 bufFill += n;
460 return n > 0;
461 }
462 catch
463 {
464 return false;
465 }
466 }
467  
468 public int Read(byte[] rbuf, int start, int len)
469 {
470 int read = 0;
471 while (len > bufFill)
472 {
473 Array.Copy(buf, 0, rbuf, start, bufFill);
474 start += bufFill; len -= bufFill;
475 read += bufFill; bufFill = 0;
476 if (!ReadMore()) break;
477 }
478 if (bufFill < len) return 0;
479 Array.Copy(buf, 0, rbuf, start, len);
480 Array.Copy(buf, len, buf, 0, bufFill - len);
481 bufFill -= len; read += len;
482 return read;
483 }
484 }
485  
486 // ProxyHTTP: proxy a HTTP request
487 private void ProxyHTTP(Socket client)
488 {
489 NetworkStream netStream = new NetworkStream(client);
490 HandyNetReader reader = new HandyNetReader(netStream);
491  
492 string line = null;
493 int reqNo;
494 int contentLength = 0;
495 string contentType = "";
496 Match match;
497 string uri;
498 string meth;
499 Dictionary<string, string> headers = new Dictionary<string, string>();
500  
501 lock (this)
502 {
503 capsReqCount++; reqNo = capsReqCount;
504 }
505  
506 byte[] byteLine = reader.ReadLine();
507 if (byteLine == null)
508 {
509 //This dirty hack is part of the LIBOMV-457 workaround
510 //The connecting libomv client being proxied can manage to trigger a null from the ReadLine()
511 //The happens just after the seed request and is not seen again. TODO find this bug in the library.
512 netStream.Close(); client.Close();
513 return;
514 }
515  
516 if (byteLine != null) line = Encoding.UTF8.GetString(byteLine).Replace("\r", "");
517  
518 if (line == null)
519 throw new Exception("EOF in client HTTP header");
520  
521 match = new Regex(@"^(\S+)\s+(\S+)\s+(HTTP/\d\.\d)$").Match(line);
522  
523 if (!match.Success)
524 {
525 OpenMetaverse.Logger.Log("[" + reqNo + "] Bad request!", Helpers.LogLevel.Warning);
526 byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n");
527 netStream.Write(wr, 0, wr.Length);
528 netStream.Close(); client.Close();
529 return;
530 }
531  
532 meth = match.Groups[1].Captures[0].ToString();
533 uri = match.Groups[2].Captures[0].ToString();
534  
535 OpenMetaverse.Logger.Log(String.Format("[{0}] {1}:{2}", reqNo, meth, uri), Helpers.LogLevel.Debug);
536  
537 // read HTTP header
538 do
539 {
540 // read one line of the header
541 line = Encoding.UTF8.GetString(reader.ReadLine()).Replace("\r", "");
542  
543 // check for premature EOF
544 if (line == null)
545 throw new Exception("EOF in client HTTP header");
546  
547 if (line == "") break;
548  
549 match = new Regex(@"^([^:]+):\s*(.*)$").Match(line);
550  
551 if (!match.Success)
552 {
553 OpenMetaverse.Logger.Log(String.Format("[{0}] Bad Header: '{1}'", reqNo, line), Helpers.LogLevel.Warning);
554 byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n");
555 netStream.Write(wr, 0, wr.Length);
556 netStream.Close(); client.Close();
557 return;
558 }
559  
560 string key = match.Groups[1].Captures[0].ToString();
561 string val = match.Groups[2].Captures[0].ToString();
562 headers[key.ToLower()] = val;
563 } while (line != "");
564  
565 if (headers.ContainsKey("content-length"))
566 {
567 contentLength = Convert.ToInt32(headers["content-length"]);
568 }
569  
570 if (headers.ContainsKey("content-type"))
571 {
572 contentType = headers["content-type"];
573 }
574  
575 // read the HTTP body into a buffer
576 byte[] content = new byte[contentLength];
577 reader.Read(content, 0, contentLength);
578  
579 if (contentLength < 8192)
580 OpenMetaverse.Logger.Log(String.Format("[{0}] request length={1}:\n{2}", reqNo, contentLength, Utils.BytesToString(content)), Helpers.LogLevel.Debug);
581  
582 if (uri == "/")
583 {
584 if (contentType == "application/xml+llsd" || contentType == "application/xml")
585 {
586 ProxyLoginSD(netStream, content);
587 }
588 else
589 {
590 ProxyLogin(netStream, content);
591 }
592 }
593 else if (new Regex(@"^/https?://.*$").Match(uri).Success)
594 {
595 ProxyCaps(netStream, meth, uri.Substring(1), headers, content, reqNo);
596 }
597 else if (new Regex(@"^/https?:/.*$").Match(uri).Success)
598 {
599 //This is a libomv client and the proxy CAPS URI has been munged by the C# URI class
600 //Part of the LIBOMV-457 work around, TODO make this much nicer.
601 uri = uri.Replace(":/", "://");
602 ProxyCaps(netStream, meth, uri.Substring(1), headers, content, reqNo);
603 }
604 else
605 {
606 OpenMetaverse.Logger.Log("404 not found: " + uri, Helpers.LogLevel.Error);
607 byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 404 Not Found\r\nContent-Length: 0\r\n\r\n");
608 netStream.Write(wr, 0, wr.Length);
609 netStream.Close(); client.Close();
610 return;
611 }
612  
613 netStream.Close();
614 client.Close();
615  
616 }
617  
618 public ObservableDictionary<string, CapInfo> KnownCaps = new ObservableDictionary<string, CapInfo>();
619 //private Dictionary<string, bool> SubHack = new Dictionary<string, bool>();
620  
621 private void ProxyCaps(NetworkStream netStream, string meth, string uri, Dictionary<string, string> headers, byte[] content, int reqNo)
622 {
623 Match match = new Regex(@"^(https?)://([^:/]+)(:\d+)?(/.*)$").Match(uri);
624 if (!match.Success)
625 {
626 OpenMetaverse.Logger.Log("[" + reqNo + "] Malformed proxy URI: " + uri, Helpers.LogLevel.Error);
627 byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 404 Not Found\r\nContent-Length: 0\r\n\r\n");
628 netStream.Write(wr, 0, wr.Length);
629 return;
630 }
631  
632 CapInfo cap = null;
633 lock (this)
634 {
635 string capuri = Regex.Replace(uri, @"/?\?.*$", string.Empty);
636  
637 if (KnownCaps.ContainsKey(capuri))
638 {
639 cap = KnownCaps[capuri];
640 }
641 }
642  
643 CapsRequest capReq = null; bool shortCircuit = false; bool requestFailed = false;
644 if (cap != null)
645 {
646 capReq = new CapsRequest(cap);
647  
648 if (cap.ReqFmt == CapsDataFormat.OSD)
649 {
650 capReq.Request = OSDParser.DeserializeLLSDXml(content);
651 }
652 else
653 {
654 capReq.Request = OSDParser.DeserializeLLSDXml(content);
655 }
656  
657 capReq.RawRequest = content;
658 capReq.FullUri = uri;
659  
660 foreach (CapsDelegate d in cap.GetDelegates())
661 {
662 if (d(capReq, CapsStage.Request)) { shortCircuit = true; break; }
663 }
664 }
665  
666 byte[] respBuf = null;
667 string consoleMsg = String.Empty;
668  
669 if (shortCircuit)
670 {
671 byte[] wr = Encoding.UTF8.GetBytes("HTTP/1.0 200 OK\r\n");
672 netStream.Write(wr, 0, wr.Length);
673 }
674 else
675 {
676 HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
677 req.KeepAlive = false;
678  
679 foreach (string header in headers.Keys)
680 {
681 if (header == "connection" ||
682 header == "content-length" || header == "date" || header == "expect" ||
683 header == "host" || header == "if-modified-since" || header == "referer" ||
684 header == "transfer-encoding" || header == "user-agent" ||
685 header == "proxy-connection" || header == "accept-encoding")
686 {
687 // can't touch these!
688 }
689 else if (header == "accept")
690 {
691 req.Accept = headers["accept"];
692 }
693 else if (header == "content-type")
694 {
695 req.ContentType = headers["content-type"];
696 }
697 else if (header == "range")
698 {
699 string rangeHeader = headers[header];
700 string[] parts = rangeHeader.Split('=');
701  
702 if (parts.Length == 2)
703 {
704 string[] range = parts[1].Split('-');
705 int from;
706 int to;
707  
708 if (range.Length == 2)
709 {
710 if (int.TryParse(range[0], out from)
711 && int.TryParse(range[1], out to))
712 {
713 req.AddRange(parts[0], from, to);
714 }
715 }
716 else if (range.Length == 1 && int.TryParse(range[0], out to))
717 {
718 req.AddRange(parts[0], to);
719 }
720 }
721 }
722 else
723 {
724 req.Headers[header] = headers[header];
725 }
726 }
727 if (capReq != null)
728 {
729 capReq.RequestHeaders = req.Headers;
730 }
731  
732 req.Method = meth;
733  
734 // can't do gets on requests with a content body
735 // without throwing a protocol exception. So force it to post
736 // incase our parser stupidly set it to GET due to the viewer
737 // doing something stupid like sending an empty request
738 if (content.Length > 0)
739 req.Method = "POST";
740  
741 req.ContentLength = content.Length;
742  
743 HttpWebResponse resp;
744 try
745 {
746 if (content.Length > 0)
747 {
748 Stream reqStream = req.GetRequestStream();
749 reqStream.Write(content, 0, content.Length);
750 reqStream.Close();
751 }
752 else if (cap == null)
753 {
754 OpenMetaverse.Logger.Log(string.Format("{0} {1}", req.Method, req.Address.ToString()), Helpers.LogLevel.Info);
755 }
756 resp = (HttpWebResponse)req.GetResponse();
757 }
758  
759 catch (WebException e)
760 {
761 if (e.Status == WebExceptionStatus.Timeout || e.Status == WebExceptionStatus.SendFailure)
762 {
763 OpenMetaverse.Logger.Log("Request timeout", Helpers.LogLevel.Warning, e);
764 byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 504 Proxy Request Timeout\r\nContent-Length: 0\r\n\r\n");
765 netStream.Write(wr, 0, wr.Length);
766 return;
767 }
768 else if (e.Status == WebExceptionStatus.ProtocolError && e.Response != null)
769 {
770 resp = (HttpWebResponse)e.Response; requestFailed = true;
771 }
772 else
773 {
774 OpenMetaverse.Logger.Log("Request error", Helpers.LogLevel.Error, e);
775 byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 502 Gateway Error\r\nContent-Length: 0\r\n\r\n"); // FIXME
776 netStream.Write(wr, 0, wr.Length);
777 return;
778 }
779 }
780  
781 try
782 {
783 Stream respStream = resp.GetResponseStream();
784 int read;
785 int length = 0;
786 respBuf = new byte[256];
787  
788 do
789 {
790 read = respStream.Read(respBuf, length, 256);
791 if (read > 0)
792 {
793 length += read;
794 Array.Resize(ref respBuf, length + 256);
795 }
796 } while (read > 0);
797  
798 Array.Resize(ref respBuf, length);
799  
800 if (capReq != null && !requestFailed)
801 {
802 if (cap.RespFmt == CapsDataFormat.OSD)
803 {
804 capReq.Response = OSDParser.DeserializeLLSDXml(respBuf);
805 }
806 else
807 {
808 capReq.Response = OSDParser.DeserializeLLSDXml(respBuf);
809 }
810 capReq.RawResponse = respBuf;
811  
812 }
813  
814 consoleMsg += "[" + reqNo + "] Response from " + uri + "\nStatus: " + (int)resp.StatusCode + " " + resp.StatusDescription + "\n";
815  
816 {
817 byte[] wr = Encoding.UTF8.GetBytes("HTTP/1.0 " + (int)resp.StatusCode + " " + resp.StatusDescription + "\r\n");
818 netStream.Write(wr, 0, wr.Length);
819 }
820  
821 if (capReq != null)
822 capReq.ResponseHeaders = resp.Headers;
823  
824 for (int i = 0; i < resp.Headers.Count; i++)
825 {
826 string key = resp.Headers.Keys[i];
827 string val = resp.Headers[i];
828 string lkey = key.ToLower();
829 if (lkey != "content-length" && lkey != "transfer-encoding" && lkey != "connection")
830 {
831 consoleMsg += key + ": " + val + "\n";
832 byte[] wr = Encoding.UTF8.GetBytes(key + ": " + val + "\r\n");
833 netStream.Write(wr, 0, wr.Length);
834 }
835 }
836 }
837 catch (Exception ex)
838 {
839 // TODO: Should we handle this somehow?
840 OpenMetaverse.Logger.DebugLog("Failed writing output: " + ex.Message);
841 }
842 }
843  
844 if (cap != null && !requestFailed && !capReq.Response.ToString().Equals("undef"))
845 {
846 foreach (CapsDelegate d in cap.GetDelegates())
847 {
848 try
849 {
850 if (d(capReq, CapsStage.Response)) { break; }
851 }
852 catch (InvalidCastException ex)
853 {
854 OpenMetaverse.Logger.Log("Invalid Cast thrown trying to cast OSD to OSDMap: \n'" + capReq.Response.AsString() + "' Length=" + capReq.RawResponse.Length.ToString() + "\n",
855 Helpers.LogLevel.Error, ex);
856 }
857 catch (Exception ex)
858 {
859 OpenMetaverse.Logger.Log("Error firing delegate", Helpers.LogLevel.Error, ex);
860 }
861 }
862  
863 if (cap.RespFmt == CapsDataFormat.OSD)
864 {
865 respBuf = OSDParser.SerializeLLSDXmlBytes((OSD)capReq.Response);
866 }
867 else
868 {
869 respBuf = OSDParser.SerializeLLSDXmlBytes(capReq.Response);
870 }
871 }
872  
873  
874 string respString;
875 if (cap == null || cap.RespFmt == CapsDataFormat.Binary)
876 {
877 respString = "<data>";
878 }
879 else
880 {
881 respString = Encoding.UTF8.GetString(respBuf);
882 }
883  
884 consoleMsg += "\n" + respString + "\n--------";
885 OpenMetaverse.Logger.Log(consoleMsg, Helpers.LogLevel.Debug);
886 OpenMetaverse.Logger.Log("[" + reqNo + "] Fixed-up response:\n" + respString + "\n--------", Helpers.LogLevel.Debug);
887  
888 try
889 {
890 byte[] wr2 = Encoding.UTF8.GetBytes("Content-Length: " + respBuf.Length + "\r\n\r\n");
891 netStream.Write(wr2, 0, wr2.Length);
892  
893 netStream.Write(respBuf, 0, respBuf.Length);
894 }
895 catch (SocketException) { }
896 catch (IOException) { }
897 catch (Exception e)
898 {
899 OpenMetaverse.Logger.Log("Exception: Error writing to stream " + e, Helpers.LogLevel.Error, e);
900 }
901  
902 return;
903 }
904  
905 private bool FixupSeedCapsResponse(CapsRequest capReq, CapsStage stage)
906 {
907 if (stage != CapsStage.Response) return false;
908  
909 OSDMap nm = new OSDMap();
910  
911 if (capReq.Response.Type == OSDType.Map)
912 {
913 OSDMap m = (OSDMap)capReq.Response;
914  
915 foreach (string key in m.Keys)
916 {
917 string val = m[key].AsString();
918  
919 if (!String.IsNullOrEmpty(val))
920 {
921 if (!KnownCaps.ContainsKey(val))
922 {
923 CapsDataFormat resFmt = BinaryResponseCaps.Contains(key) ? CapsDataFormat.Binary : CapsDataFormat.OSD;
924 CapsDataFormat reqFmt = CapsDataFormat.OSD;
925 CapInfo newCap = new CapInfo(val, capReq.Info.Sim, key, reqFmt, resFmt);
926 newCap.AddDelegate(new CapsDelegate(KnownCapDelegate));
927 lock (this) { KnownCaps[val] = newCap; }
928 }
929 nm[key] = OSD.FromString(loginURI + val);
930 }
931 else
932 {
933 nm[key] = OSD.FromString(val);
934 }
935 }
936 }
937  
938 capReq.Response = nm;
939 return false;
940 }
941  
942 private Dictionary<string, List<CapsDelegate>> KnownCapsDelegates = new Dictionary<string, List<CapsDelegate>>();
943  
944  
945 private void InitializeCaps()
946 {
947 AddCapsDelegate("EventQueueGet", new CapsDelegate(FixupEventQueueGet));
948 }
949  
950 public void AddCapsDelegate(string CapName, CapsDelegate capsDelegate)
951 {
952 lock (this)
953 {
954  
955 if (!KnownCapsDelegates.ContainsKey(CapName))
956 {
957 KnownCapsDelegates[CapName] = new List<CapsDelegate>();
958 }
959 List<CapsDelegate> delegateArray = KnownCapsDelegates[CapName];
960 if (!delegateArray.Contains(capsDelegate))
961 {
962 delegateArray.Add(capsDelegate);
963 }
964 }
965 }
966  
967 public void RemoveCapRequestDelegate(string CapName, CapsDelegate capsDelegate)
968 {
969 lock (this)
970 {
971  
972 if (!KnownCapsDelegates.ContainsKey(CapName))
973 {
974 return;
975 }
976 List<CapsDelegate> delegateArray = KnownCapsDelegates[CapName];
977 if (delegateArray.Contains(capsDelegate))
978 {
979 delegateArray.Remove(capsDelegate);
980 }
981 }
982 }
983  
984 private bool KnownCapDelegate(CapsRequest capReq, CapsStage stage)
985 {
986 lock (this)
987 {
988 if (!KnownCapsDelegates.ContainsKey(capReq.Info.CapType))
989 return false;
990  
991 if (stage == CapsStage.Response)
992 {
993 if (capReq.Response != null && capReq.Response is OSDMap)
994 {
995 OSDMap map = (OSDMap)capReq.Response;
996  
997 if (map.ContainsKey("uploader"))
998 {
999 string val = map["uploader"].AsString();
1000  
1001 if (!KnownCaps.ContainsKey(val))
1002 {
1003 CapInfo newCap = new CapInfo(val, capReq.Info.Sim, capReq.Info.CapType, CapsDataFormat.Binary, CapsDataFormat.OSD);
1004 newCap.AddDelegate(new CapsDelegate(KnownCapDelegate));
1005 lock (this) { KnownCaps[val] = newCap; }
1006 }
1007  
1008 map["uploader"] = OSD.FromString(loginURI + val);
1009 }
1010 }
1011 }
1012  
1013 List<CapsDelegate> delegates = KnownCapsDelegates[capReq.Info.CapType];
1014  
1015 foreach (CapsDelegate d in delegates)
1016 {
1017 if (d(capReq, stage)) { return true; }
1018 }
1019 }
1020  
1021 return false;
1022 }
1023  
1024 private bool FixupEventQueueGet(CapsRequest capReq, CapsStage stage)
1025 {
1026 if (stage != CapsStage.Response) return false;
1027  
1028 OSDMap map = null;
1029 if (capReq.Response is OSDMap)
1030 map = (OSDMap)capReq.Response;
1031 else return false;
1032  
1033 OSDArray array = null;
1034 if (map.ContainsKey("events") && map["events"] is OSDArray)
1035 array = (OSDArray)map["events"];
1036 else
1037 return false;
1038  
1039 for (int i = 0; i < array.Count; i++)
1040 {
1041 OSDMap evt = (OSDMap)array[i];
1042  
1043 string message = evt["message"].AsString();
1044 OSDMap body = (OSDMap)evt["body"];
1045  
1046 if (message == "TeleportFinish" || message == "CrossedRegion")
1047 {
1048 OSDMap info = null;
1049 if (message == "TeleportFinish")
1050 info = (OSDMap)(((OSDArray)body["Info"])[0]);
1051 else
1052 info = (OSDMap)(((OSDArray)body["RegionData"])[0]);
1053 byte[] bytes = info["SimIP"].AsBinary();
1054 uint simIP = Utils.BytesToUInt(bytes);
1055 ushort simPort = (ushort)info["SimPort"].AsInteger();
1056 string capsURL = info["SeedCapability"].AsString();
1057  
1058 GenericCheck(ref simIP, ref simPort, ref capsURL, capReq.Info.Sim == activeCircuit);
1059  
1060 info["SeedCapability"] = OSD.FromString(capsURL);
1061 bytes[0] = (byte)(simIP % 256);
1062 bytes[1] = (byte)((simIP >> 8) % 256);
1063 bytes[2] = (byte)((simIP >> 16) % 256);
1064 bytes[3] = (byte)((simIP >> 24) % 256);
1065 info["SimIP"] = OSD.FromBinary(bytes);
1066 info["SimPort"] = OSD.FromInteger(simPort);
1067 }
1068 else if (message == "EnableSimulator")
1069 {
1070 OSDMap info = null;
1071 info = (OSDMap)(((OSDArray)body["SimulatorInfo"])[0]);
1072 byte[] bytes = info["IP"].AsBinary();
1073 uint IP = Utils.BytesToUInt(bytes);
1074 ushort Port = (ushort)info["Port"].AsInteger();
1075 string capsURL = null;
1076  
1077 GenericCheck(ref IP, ref Port, ref capsURL, capReq.Info.Sim == activeCircuit);
1078  
1079 bytes[0] = (byte)(IP % 256);
1080 bytes[1] = (byte)((IP >> 8) % 256);
1081 bytes[2] = (byte)((IP >> 16) % 256);
1082 bytes[3] = (byte)((IP >> 24) % 256);
1083 info["IP"] = OSD.FromBinary(bytes);
1084 info["Port"] = OSD.FromInteger(Port);
1085 }
1086 else if (message == "EstablishAgentCommunication")
1087 {
1088 string ipAndPort = body["sim-ip-and-port"].AsString();
1089 string[] pieces = ipAndPort.Split(':');
1090 byte[] bytes = IPAddress.Parse(pieces[0]).GetAddressBytes();
1091 uint simIP = Utils.BytesToUInt(bytes);
1092 ushort simPort = (ushort)Convert.ToInt32(pieces[1]);
1093  
1094 string capsURL = body["seed-capability"].AsString();
1095  
1096 OpenMetaverse.Logger.Log("DEBUG: Got EstablishAgentCommunication for " + ipAndPort + " with seed cap " + capsURL, Helpers.LogLevel.Debug);
1097  
1098 GenericCheck(ref simIP, ref simPort, ref capsURL, false);
1099 body["seed-capability"] = OSD.FromString(capsURL);
1100 string ipport = String.Format("{0}:{1}", new IPAddress(simIP), simPort);
1101 body["sim-ip-and-port"] = OSD.FromString(ipport);
1102  
1103 OpenMetaverse.Logger.Log("DEBUG: Modified EstablishAgentCommunication to " + body["sim-ip-and-port"].AsString() + " with seed cap " + capsURL, Helpers.LogLevel.Debug);
1104 }
1105 }
1106 return false;
1107 }
1108  
1109 private void ProxyLogin(NetworkStream netStream, byte[] content)
1110 {
1111 lock (this)
1112 {
1113 // incase some silly person tries to access with their web browser
1114 if (content.Length <= 0)
1115 return;
1116  
1117 // convert the body into an XML-RPC request
1118 XmlRpcRequest request = (XmlRpcRequest)(new XmlRpcRequestDeserializer()).Deserialize(Encoding.UTF8.GetString(content));
1119  
1120 // call the loginRequestDelegate
1121 lock (loginRequestDelegates)
1122 {
1123 foreach (XmlRpcRequestDelegate d in loginRequestDelegates)
1124 {
1125 try { d(this, new XmlRpcRequestEventArgs(request)); }
1126 //try { d(request); }
1127 catch (Exception e) { OpenMetaverse.Logger.Log("Exception in login request delegate" + e, Helpers.LogLevel.Error, e); }
1128 }
1129 }
1130 XmlRpcResponse response;
1131 try
1132 {
1133 // forward the XML-RPC request to the server
1134 response = (XmlRpcResponse)request.Send(proxyConfig.remoteLoginUri.ToString(),
1135 30 * 1000); // 30 second timeout
1136 }
1137 catch (Exception e)
1138 {
1139 OpenMetaverse.Logger.Log("Error during login response", Helpers.LogLevel.Error, e);
1140 return;
1141 }
1142  
1143 System.Collections.Hashtable responseData;
1144 try
1145 {
1146 responseData = (System.Collections.Hashtable)response.Value;
1147 }
1148 catch (Exception e)
1149 {
1150 OpenMetaverse.Logger.Log(e.Message, Helpers.LogLevel.Error);
1151 return;
1152 }
1153  
1154 // proxy any simulator address given in the XML-RPC response
1155 if (responseData.Contains("sim_ip") && responseData.Contains("sim_port"))
1156 {
1157 IPEndPoint realSim = new IPEndPoint(IPAddress.Parse((string)responseData["sim_ip"]), Convert.ToUInt16(responseData["sim_port"]));
1158 IPEndPoint fakeSim = ProxySim(realSim);
1159 responseData["sim_ip"] = fakeSim.Address.ToString();
1160 responseData["sim_port"] = fakeSim.Port;
1161 activeCircuit = realSim;
1162 }
1163  
1164 // start a new proxy session
1165 Reset();
1166  
1167 if (responseData.Contains("seed_capability"))
1168 {
1169 CapInfo info = new CapInfo((string)responseData["seed_capability"], activeCircuit, "SeedCapability");
1170 info.AddDelegate(new CapsDelegate(FixupSeedCapsResponse));
1171  
1172 KnownCaps[(string)responseData["seed_capability"]] = info;
1173 responseData["seed_capability"] = loginURI + responseData["seed_capability"];
1174 }
1175  
1176 // forward the XML-RPC response to the client
1177 StreamWriter writer = new StreamWriter(netStream);
1178 writer.Write("HTTP/1.0 200 OK\r\n");
1179 writer.Write("Content-type: text/xml\r\n");
1180 writer.Write("\r\n");
1181  
1182 XmlTextWriter responseWriter = new XmlTextWriter(writer);
1183 XmlRpcResponseSerializer.Singleton.Serialize(responseWriter, response);
1184 responseWriter.Close(); writer.Close();
1185  
1186 lock (loginResponseDelegates)
1187 {
1188 foreach (XmlRpcResponseDelegate d in loginResponseDelegates)
1189 {
1190 try { d(response); }
1191 catch (Exception e) { OpenMetaverse.Logger.Log("Exception in login response delegate" + e, Helpers.LogLevel.Error, e); }
1192 }
1193 }
1194  
1195 }
1196 }
1197  
1198 private void ProxyLoginSD(NetworkStream netStream, byte[] content)
1199 {
1200 lock (this)
1201 {
1202 AutoResetEvent remoteComplete = new AutoResetEvent(false);
1203 CapsClient loginRequest = new CapsClient(proxyConfig.remoteLoginUri);
1204 OSD response = null;
1205 loginRequest.OnComplete += new CapsClient.CompleteCallback(
1206 delegate(CapsClient client, OSD result, Exception error)
1207 {
1208 if (error == null)
1209 {
1210 if (result != null && result.Type == OSDType.Map)
1211 {
1212 response = result;
1213 }
1214 }
1215 remoteComplete.Set();
1216 }
1217 );
1218 loginRequest.BeginGetResponse(content, "application/llsd+xml", 1000 * 100);
1219 remoteComplete.WaitOne(1000 * 100, false);
1220  
1221 if (response == null)
1222 {
1223 byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n");
1224 netStream.Write(wr, 0, wr.Length);
1225 return;
1226 }
1227  
1228 OSDMap map = (OSDMap)response;
1229  
1230 OSD llsd;
1231 string sim_port = null, sim_ip = null, seed_capability = null;
1232 map.TryGetValue("sim_port", out llsd);
1233 if (llsd != null) sim_port = llsd.AsString();
1234 map.TryGetValue("sim_ip", out llsd);
1235 if (llsd != null) sim_ip = llsd.AsString();
1236 map.TryGetValue("seed_capability", out llsd);
1237 if (llsd != null) seed_capability = llsd.AsString();
1238  
1239 if (sim_port == null || sim_ip == null || seed_capability == null)
1240 {
1241 if (map != null)
1242 {
1243 OpenMetaverse.Logger.Log("Connection to server failed, returned LLSD error follows:\n" + map.ToString(), Helpers.LogLevel.Error);
1244 }
1245 byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n");
1246 netStream.Write(wr, 0, wr.Length);
1247 return;
1248 }
1249  
1250 IPEndPoint realSim = new IPEndPoint(IPAddress.Parse(sim_ip), Convert.ToUInt16(sim_port));
1251 IPEndPoint fakeSim = ProxySim(realSim);
1252 map["sim_ip"] = OSD.FromString(fakeSim.Address.ToString());
1253 map["sim_port"] = OSD.FromInteger(fakeSim.Port);
1254 activeCircuit = realSim;
1255  
1256 // start a new proxy session
1257 Reset();
1258  
1259 CapInfo info = new CapInfo(seed_capability, activeCircuit, "SeedCapability");
1260 info.AddDelegate(new CapsDelegate(FixupSeedCapsResponse));
1261  
1262 KnownCaps[seed_capability] = info;
1263 map["seed_capability"] = OSD.FromString(loginURI + seed_capability);
1264  
1265 StreamWriter writer = new StreamWriter(netStream);
1266 writer.Write("HTTP/1.0 200 OK\r\n");
1267 writer.Write("Content-type: application/xml+llsd\r\n");
1268 writer.Write("\r\n");
1269 writer.Write(OSDParser.SerializeLLSDXmlString(response));
1270 writer.Close();
1271 }
1272 }
1273  
1274 /*
1275 * Sim Proxy
1276 */
1277  
1278 private Socket simFacingSocket;
1279 public IPEndPoint activeCircuit = null;
1280 private Dictionary<IPEndPoint, IPEndPoint> proxyEndPoints = new Dictionary<IPEndPoint, IPEndPoint>();
1281 private Dictionary<IPEndPoint, SimProxy> simProxies = new Dictionary<IPEndPoint, SimProxy>();
1282 private Dictionary<EndPoint, SimProxy> proxyHandlers = new Dictionary<EndPoint, SimProxy>();
1283 //private XmlRpcRequestDelegate loginRequestDelegate = null;
1284 //private XmlRpcResponseDelegate loginResponseDelegate = null;
1285  
1286 public List<XmlRpcRequestDelegate> loginRequestDelegates = new List<XmlRpcRequestDelegate>();
1287 public List<XmlRpcResponseDelegate> loginResponseDelegates = new List<XmlRpcResponseDelegate>();
1288  
1289 private Dictionary<PacketType, List<PacketDelegate>> incomingDelegates = new Dictionary<PacketType, List<PacketDelegate>>();
1290 private Dictionary<PacketType, List<PacketDelegate>> outgoingDelegates = new Dictionary<PacketType, List<PacketDelegate>>();
1291 private List<Packet> queuedIncomingInjections = new List<Packet>();
1292 private List<Packet> queuedOutgoingInjections = new List<Packet>();
1293  
1294 // InitializeSimProxy: initialize the sim proxy
1295 private void InitializeSimProxy()
1296 {
1297 InitializeAddressCheckers();
1298  
1299 simFacingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
1300 simFacingSocket.Bind(new IPEndPoint(proxyConfig.remoteFacingAddress, 0));
1301 Reset();
1302 }
1303  
1304 // Reset: start a new session
1305 private void Reset()
1306 {
1307 foreach (SimProxy simProxy in simProxies.Values)
1308 simProxy.Reset();
1309  
1310 KnownCaps.Clear();
1311 }
1312  
1313 private byte[] receiveBuffer = new byte[8192];
1314 private byte[] zeroBuffer = new byte[8192];
1315 private EndPoint remoteEndPoint = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
1316  
1317 // RunSimProxy: start listening for packets from remote sims
1318 private void RunSimProxy()
1319 {
1320 simFacingSocket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, new AsyncCallback(ReceiveFromSim), null);
1321 }
1322  
1323 // ReceiveFromSim: packet received from a remote sim
1324 private void ReceiveFromSim(IAsyncResult ar)
1325 {
1326 lock (this)
1327 try
1328 {
1329 //if (!simFacingSocket.Connected) return;
1330 // pause listening and fetch the packet
1331 bool needsZero = false;
1332 bool needsCopy = true;
1333 int length;
1334 length = simFacingSocket.EndReceiveFrom(ar, ref remoteEndPoint);
1335  
1336 if (proxyHandlers.ContainsKey(remoteEndPoint))
1337 {
1338 // find the proxy responsible for forwarding this packet
1339 SimProxy simProxy = (SimProxy)proxyHandlers[remoteEndPoint];
1340  
1341 // interpret the packet according to the SL protocol
1342 Packet packet;
1343 int end = length - 1;
1344  
1345 packet = Packet.BuildPacket(receiveBuffer, ref end, zeroBuffer);
1346  
1347 // check for ACKs we're waiting for
1348 packet = simProxy.CheckAcks(packet, Direction.Incoming, ref length, ref needsCopy);
1349  
1350 // modify sequence numbers to account for injections
1351 uint oldSequence = packet.Header.Sequence;
1352 packet = simProxy.ModifySequence(packet, Direction.Incoming, ref length, ref needsCopy);
1353  
1354 // keep track of sequence numbers
1355 if (packet.Header.Sequence > simProxy.incomingSequence)
1356 simProxy.incomingSequence = packet.Header.Sequence;
1357  
1358 // check the packet for addresses that need proxying
1359 if (incomingCheckers.ContainsKey(packet.Type))
1360 {
1361 /* if (needsZero) {
1362 length = Helpers.ZeroDecode(packet.Header.Data, length, zeroBuffer);
1363 packet.Header.Data = zeroBuffer;
1364 needsZero = false;
1365 } */
1366  
1367 Packet newPacket = ((AddressChecker)incomingCheckers[packet.Type])(packet);
1368 SwapPacket(packet, newPacket);
1369 packet = newPacket;
1370 needsCopy = false;
1371 }
1372  
1373 // pass the packet to any callback delegates
1374 if (incomingDelegates.ContainsKey(packet.Type))
1375 {
1376 /* if (needsZero) {
1377 length = Helpers.ZeroDecode(packet.Header.Data, length, zeroBuffer);
1378 packet.Header.Data = zeroBuffer;
1379 needsCopy = true;
1380 } */
1381  
1382 if (packet.Header.AckList != null && needsCopy)
1383 {
1384 uint[] newAcks = new uint[packet.Header.AckList.Length];
1385 Array.Copy(packet.Header.AckList, 0, newAcks, 0, newAcks.Length);
1386 packet.Header.AckList = newAcks; // FIXME
1387 }
1388  
1389 try
1390 {
1391 Packet newPacket = callDelegates(incomingDelegates, packet, (IPEndPoint)remoteEndPoint);
1392 if (newPacket == null)
1393 {
1394 if (packet.Header.Reliable)
1395 simProxy.Inject(SpoofAck(oldSequence), Direction.Outgoing);
1396  
1397 if (packet.Header.AppendedAcks)
1398 packet = SeparateAck(packet);
1399 else
1400 packet = null;
1401 }
1402 else
1403 {
1404 bool oldReliable = packet.Header.Reliable;
1405 bool newReliable = newPacket.Header.Reliable;
1406 if (oldReliable && !newReliable)
1407 simProxy.Inject(SpoofAck(oldSequence), Direction.Outgoing);
1408 else if (!oldReliable && newReliable)
1409 simProxy.WaitForAck(packet, Direction.Incoming);
1410  
1411 SwapPacket(packet, newPacket);
1412 packet = newPacket;
1413 }
1414 }
1415 catch (Exception e)
1416 {
1417 OpenMetaverse.Logger.Log("Exception in incoming delegate", Helpers.LogLevel.Error, e);
1418 }
1419  
1420 if (packet != null)
1421 simProxy.SendPacket(packet, false);
1422 }
1423 else
1424 simProxy.SendPacket(packet, needsZero);
1425 }
1426 else
1427 // ignore packets from unknown peers
1428 OpenMetaverse.Logger.Log("Dropping packet from unknown peer " + remoteEndPoint, Helpers.LogLevel.Warning);
1429 }
1430 catch (Exception e)
1431 {
1432 OpenMetaverse.Logger.Log("Error processing incoming packet from simulator", Helpers.LogLevel.Error, e);
1433 }
1434 finally
1435 {
1436 // resume listening
1437 try
1438 {
1439 simFacingSocket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None,
1440 ref remoteEndPoint, new AsyncCallback(ReceiveFromSim), null);
1441 }
1442 catch (Exception e)
1443 {
1444 OpenMetaverse.Logger.Log("Listener Socket Exception", Helpers.LogLevel.Error, e);
1445 }
1446 }
1447 }
1448  
1449 // SendPacket: send a packet to a sim from our fake client endpoint
1450 public void SendPacket(Packet packet, IPEndPoint endPoint, bool skipZero)
1451 {
1452  
1453 byte[] buffer = packet.ToBytes();
1454 if (skipZero || !packet.Header.Zerocoded)
1455 simFacingSocket.SendTo(buffer, buffer.Length, SocketFlags.None, endPoint);
1456 else
1457 {
1458 int zeroLength = Helpers.ZeroEncode(buffer, buffer.Length, zeroBuffer);
1459 simFacingSocket.SendTo(zeroBuffer, zeroLength, SocketFlags.None, endPoint);
1460 }
1461 }
1462  
1463 // SpoofAck: create an ACK for the given packet
1464 public Packet SpoofAck(uint sequence)
1465 {
1466 PacketAckPacket spoof = new PacketAckPacket();
1467 spoof.Packets = new PacketAckPacket.PacketsBlock[1];
1468 spoof.Packets[0] = new PacketAckPacket.PacketsBlock();
1469 spoof.Packets[0].ID = sequence;
1470 return (Packet)spoof;
1471 }
1472  
1473 // SeparateAck: create a standalone PacketAck for packet's appended ACKs
1474 public Packet SeparateAck(Packet packet)
1475 {
1476 PacketAckPacket seperate = new PacketAckPacket();
1477 seperate.Packets = new PacketAckPacket.PacketsBlock[packet.Header.AckList.Length];
1478  
1479 for (int i = 0; i < packet.Header.AckList.Length; ++i)
1480 {
1481 seperate.Packets[i] = new PacketAckPacket.PacketsBlock();
1482 seperate.Packets[i].ID = packet.Header.AckList[i];
1483 }
1484  
1485 Packet ack = seperate;
1486 ack.Header.Sequence = packet.Header.Sequence;
1487 return ack;
1488 }
1489  
1490 // SwapPacket: copy the sequence number and appended ACKs from one packet to another
1491 public static void SwapPacket(Packet oldPacket, Packet newPacket)
1492 {
1493 newPacket.Header.Sequence = oldPacket.Header.Sequence;
1494  
1495 int oldAcks = oldPacket.Header.AppendedAcks ? oldPacket.Header.AckList.Length : 0;
1496 int newAcks = newPacket.Header.AppendedAcks ? newPacket.Header.AckList.Length : 0;
1497  
1498 if (oldAcks != 0 || newAcks != 0)
1499 {
1500 uint[] newAckList = new uint[oldAcks];
1501 Array.Copy(oldPacket.Header.AckList, 0, newAckList, 0, oldAcks);
1502  
1503 newPacket.Header.AckList = newAckList;
1504 newPacket.Header.AppendedAcks = oldPacket.Header.AppendedAcks;
1505 }
1506 }
1507  
1508 // ProxySim: return the proxy for the specified sim, creating it if it doesn't exist
1509 private IPEndPoint ProxySim(IPEndPoint simEndPoint)
1510 {
1511 if (proxyEndPoints.ContainsKey(simEndPoint))
1512 // return the existing proxy
1513 return (IPEndPoint)proxyEndPoints[simEndPoint];
1514 else
1515 {
1516 // return a new proxy
1517 SimProxy simProxy = new SimProxy(proxyConfig, simEndPoint, this);
1518 IPEndPoint fakeSim = simProxy.LocalEndPoint();
1519 OpenMetaverse.Logger.Log("Creating proxy for " + simEndPoint + " at " + fakeSim, Helpers.LogLevel.Info);
1520 simProxy.Run();
1521 proxyEndPoints.Add(simEndPoint, fakeSim);
1522 simProxies.Add(simEndPoint, simProxy);
1523 return fakeSim;
1524 }
1525 }
1526  
1527 // AddHandler: remember which sim proxy corresponds to a given sim
1528 private void AddHandler(EndPoint endPoint, SimProxy proxy)
1529 {
1530 proxyHandlers.Add(endPoint, proxy);
1531 }
1532  
1533 // SimProxy: proxy for a single simulator
1534 private class SimProxy
1535 {
1536 //private ProxyConfig proxyConfig;
1537 private IPEndPoint remoteEndPoint;
1538 private Proxy proxy;
1539 private Socket socket;
1540 public uint incomingSequence;
1541 public uint outgoingSequence;
1542 private List<uint> incomingInjections;
1543 private List<uint> outgoingInjections;
1544 private uint incomingOffset = 0;
1545 private uint outgoingOffset = 0;
1546 private Dictionary<uint, Packet> incomingAcks;
1547 private Dictionary<uint, Packet> outgoingAcks;
1548 private List<uint> incomingSeenAcks;
1549 private List<uint> outgoingSeenAcks;
1550  
1551 // SimProxy: construct a proxy for a single simulator
1552 public SimProxy(ProxyConfig proxyConfig, IPEndPoint simEndPoint, Proxy proxy)
1553 {
1554 //this.proxyConfig = proxyConfig;
1555 remoteEndPoint = new IPEndPoint(simEndPoint.Address, simEndPoint.Port);
1556 this.proxy = proxy;
1557 socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
1558 socket.Bind(new IPEndPoint(proxyConfig.clientFacingAddress, 0));
1559 proxy.AddHandler(remoteEndPoint, this);
1560 Reset();
1561 }
1562  
1563 // Reset: start a new session
1564 public void Reset()
1565 {
1566 incomingSequence = 0;
1567 outgoingSequence = 0;
1568 incomingInjections = new List<uint>();
1569 outgoingInjections = new List<uint>();
1570 incomingAcks = new Dictionary<uint, Packet>();
1571 outgoingAcks = new Dictionary<uint, Packet>();
1572 incomingSeenAcks = new List<uint>();
1573 outgoingSeenAcks = new List<uint>();
1574 }
1575  
1576 // BackgroundTasks: resend unacknowledged packets and keep data structures clean
1577 private void BackgroundTasks()
1578 {
1579 try
1580 {
1581 int tick = 1;
1582 int incomingInjectionsPoint = 0;
1583 int outgoingInjectionsPoint = 0;
1584 int incomingSeenAcksPoint = 0;
1585 int outgoingSeenAcksPoint = 0;
1586  
1587 for (; ; Thread.Sleep(1000)) lock (proxy)
1588 {
1589 if ((tick = (tick + 1) % 60) == 0)
1590 {
1591 for (int i = 0; i < incomingInjectionsPoint; ++i)
1592 {
1593 incomingInjections.RemoveAt(0);
1594 ++incomingOffset;
1595 }
1596 incomingInjectionsPoint = incomingInjections.Count;
1597  
1598 for (int i = 0; i < outgoingInjectionsPoint; ++i)
1599 {
1600 outgoingInjections.RemoveAt(0);
1601 ++outgoingOffset;
1602 }
1603 outgoingInjectionsPoint = outgoingInjections.Count;
1604  
1605 for (int i = 0; i < incomingSeenAcksPoint; ++i)
1606 {
1607 incomingAcks.Remove(incomingSeenAcks[0]);
1608 incomingSeenAcks.RemoveAt(0);
1609 }
1610 incomingSeenAcksPoint = incomingSeenAcks.Count;
1611  
1612 for (int i = 0; i < outgoingSeenAcksPoint; ++i)
1613 {
1614 outgoingAcks.Remove(outgoingSeenAcks[0]);
1615 outgoingSeenAcks.RemoveAt(0);
1616 }
1617 outgoingSeenAcksPoint = outgoingSeenAcks.Count;
1618 }
1619  
1620 foreach (uint id in incomingAcks.Keys)
1621 if (!incomingSeenAcks.Contains(id))
1622 {
1623 Packet packet = (Packet)incomingAcks[id];
1624 packet.Header.Resent = true;
1625 SendPacket(packet, false);
1626 }
1627  
1628 foreach (uint id in outgoingAcks.Keys)
1629 if (!outgoingSeenAcks.Contains(id))
1630 {
1631 Packet packet = (Packet)outgoingAcks[id];
1632 packet.Header.Resent = true;
1633 proxy.SendPacket(packet, remoteEndPoint, false);
1634 }
1635 }
1636 }
1637 catch (Exception e)
1638 {
1639 OpenMetaverse.Logger.Log("Exception running BackgroundTasks", Helpers.LogLevel.Error, e);
1640 }
1641 }
1642  
1643 // LocalEndPoint: return the endpoint that the client should communicate with
1644 public IPEndPoint LocalEndPoint()
1645 {
1646 return (IPEndPoint)socket.LocalEndPoint;
1647 }
1648  
1649 private byte[] receiveBuffer = new byte[8192];
1650 private byte[] zeroBuffer = new byte[8192];
1651 private EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
1652 bool firstReceive = true;
1653  
1654 // Run: forward packets from the client to the sim
1655 public void Run()
1656 {
1657 Thread backgroundTasks = new Thread(new ThreadStart(BackgroundTasks));
1658 backgroundTasks.IsBackground = true;
1659 backgroundTasks.Start();
1660 socket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref clientEndPoint, new AsyncCallback(ReceiveFromClient), null);
1661 }
1662  
1663 // ReceiveFromClient: packet received from the client
1664 private void ReceiveFromClient(IAsyncResult ar)
1665 {
1666 lock (proxy)
1667 {
1668 try
1669 {
1670 // pause listening and fetch the packet
1671 bool needsZero = false;
1672 bool needsCopy = true;
1673 int length = 0;
1674  
1675 try { length = socket.EndReceiveFrom(ar, ref clientEndPoint); }
1676 catch (SocketException) { }
1677  
1678 if (length != 0)
1679 {
1680 // interpret the packet according to the SL protocol
1681 int end = length - 1;
1682 Packet packet = OpenMetaverse.Packets.Packet.BuildPacket(receiveBuffer, ref end, zeroBuffer);
1683  
1684 //OpenMetaverse.Logger.Log("-> " + packet.Type + " #" + packet.Header.Sequence, Helpers.LogLevel.Debug);
1685  
1686 // check for ACKs we're waiting for
1687 packet = CheckAcks(packet, Direction.Outgoing, ref length, ref needsCopy);
1688  
1689 // modify sequence numbers to account for injections
1690 uint oldSequence = packet.Header.Sequence;
1691 packet = ModifySequence(packet, Direction.Outgoing, ref length, ref needsCopy);
1692  
1693 // keep track of sequence numbers
1694 if (packet.Header.Sequence > outgoingSequence)
1695 outgoingSequence = packet.Header.Sequence;
1696  
1697 // check the packet for addresses that need proxying
1698 if (proxy.outgoingCheckers.ContainsKey(packet.Type))
1699 {
1700 /* if (packet.Header.Zerocoded) {
1701 length = Helpers.ZeroDecode(packet.Header.Data, length, zeroBuffer);
1702 packet.Header.Data = zeroBuffer;
1703 needsZero = false;
1704 } */
1705  
1706 Packet newPacket = ((AddressChecker)proxy.outgoingCheckers[packet.Type])(packet);
1707 SwapPacket(packet, newPacket);
1708 packet = newPacket;
1709 needsCopy = false;
1710 }
1711  
1712 // pass the packet to any callback delegates
1713 if (proxy.outgoingDelegates.ContainsKey(packet.Type))
1714 {
1715 if (packet.Header.AckList != null && needsCopy)
1716 {
1717 uint[] newAcks = new uint[packet.Header.AckList.Length];
1718 Array.Copy(packet.Header.AckList, 0, newAcks, 0, newAcks.Length);
1719 packet.Header.AckList = newAcks; // FIXME
1720 }
1721  
1722 try
1723 {
1724 Packet newPacket = proxy.callDelegates(proxy.outgoingDelegates, packet, remoteEndPoint);
1725 if (newPacket == null)
1726 {
1727 if (packet.Header.Reliable)
1728 Inject(proxy.SpoofAck(oldSequence), Direction.Incoming);
1729  
1730 if (packet.Header.AppendedAcks)
1731 packet = proxy.SeparateAck(packet);
1732 else
1733 packet = null;
1734 }
1735 else
1736 {
1737 bool oldReliable = packet.Header.Reliable;
1738 bool newReliable = newPacket.Header.Reliable;
1739 if (oldReliable && !newReliable)
1740 Inject(proxy.SpoofAck(oldSequence), Direction.Incoming);
1741 else if (!oldReliable && newReliable)
1742 WaitForAck(packet, Direction.Outgoing);
1743  
1744 SwapPacket(packet, newPacket);
1745 packet = newPacket;
1746 }
1747 }
1748 catch (Exception e)
1749 {
1750 OpenMetaverse.Logger.Log("exception in outgoing delegate", Helpers.LogLevel.Error, e);
1751 }
1752  
1753 if (packet != null)
1754 proxy.SendPacket(packet, remoteEndPoint, false);
1755 }
1756 else
1757 proxy.SendPacket(packet, remoteEndPoint, needsZero);
1758  
1759 // send any packets queued for injection
1760 if (firstReceive)
1761 {
1762 firstReceive = false;
1763 foreach (Packet queuedPacket in proxy.queuedIncomingInjections)
1764 Inject(queuedPacket, Direction.Incoming);
1765 proxy.queuedIncomingInjections = new List<Packet>();
1766 }
1767 }
1768 }
1769 catch (Exception e)
1770 {
1771 OpenMetaverse.Logger.Log("Proxy error sending packet", Helpers.LogLevel.Error, e);
1772 }
1773 finally
1774 {
1775 // resume listening
1776 try
1777 {
1778 socket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None,
1779 ref clientEndPoint, new AsyncCallback(ReceiveFromClient), null);
1780 }
1781 catch (SocketException e)
1782 {
1783 OpenMetaverse.Logger.Log("Socket Shutdown: " + e.SocketErrorCode, Helpers.LogLevel.Warning);
1784 }
1785 }
1786 }
1787 }
1788  
1789 // SendPacket: send a packet from the sim to the client via our fake sim endpoint
1790 public void SendPacket(Packet packet, bool skipZero)
1791 {
1792 byte[] buffer = packet.ToBytes();
1793 if (skipZero || !packet.Header.Zerocoded)
1794 socket.SendTo(buffer, buffer.Length, SocketFlags.None, clientEndPoint);
1795 else
1796 {
1797 int zeroLength = Helpers.ZeroEncode(buffer, buffer.Length, zeroBuffer);
1798 socket.SendTo(zeroBuffer, zeroLength, SocketFlags.None, clientEndPoint);
1799 }
1800 }
1801  
1802 // Inject: inject a packet
1803 public void Inject(Packet packet, Direction direction)
1804 {
1805 if (direction == Direction.Incoming)
1806 {
1807 if (firstReceive)
1808 {
1809 proxy.queuedIncomingInjections.Add(packet);
1810 return;
1811 }
1812  
1813 incomingInjections.Add(++incomingSequence);
1814 packet.Header.Sequence = incomingSequence;
1815 }
1816 else
1817 {
1818 outgoingInjections.Add(++outgoingSequence);
1819 packet.Header.Sequence = outgoingSequence;
1820 }
1821  
1822 if (packet.Header.Reliable)
1823 WaitForAck(packet, direction);
1824  
1825 if (direction == Direction.Incoming)
1826 {
1827 byte[] buffer = packet.ToBytes();
1828 if (!packet.Header.Zerocoded)
1829 socket.SendTo(buffer, buffer.Length, SocketFlags.None, clientEndPoint);
1830 else
1831 {
1832 int zeroLength = Helpers.ZeroEncode(buffer, buffer.Length, zeroBuffer);
1833 socket.SendTo(zeroBuffer, zeroLength, SocketFlags.None, clientEndPoint);
1834 }
1835 }
1836 else
1837 proxy.SendPacket(packet, remoteEndPoint, false);
1838 }
1839  
1840 // WaitForAck: take care of resending a packet until it's ACKed
1841 public void WaitForAck(Packet packet, Direction direction)
1842 {
1843 Dictionary<uint, Packet> table = direction == Direction.Incoming ? incomingAcks : outgoingAcks;
1844 table.Add(packet.Header.Sequence, packet);
1845 }
1846  
1847 // CheckAcks: check for and remove ACKs of packets we've injected
1848 public Packet CheckAcks(Packet packet, Direction direction, ref int length, ref bool needsCopy)
1849 {
1850 Dictionary<uint, Packet> acks = direction == Direction.Incoming ? outgoingAcks : incomingAcks;
1851 List<uint> seenAcks = direction == Direction.Incoming ? outgoingSeenAcks : incomingSeenAcks;
1852  
1853 if (acks.Count == 0)
1854 return packet;
1855  
1856 // check for embedded ACKs
1857 if (packet.Type == PacketType.PacketAck)
1858 {
1859 bool changed = false;
1860 List<PacketAckPacket.PacketsBlock> newPacketBlocks = new List<PacketAckPacket.PacketsBlock>();
1861 foreach (PacketAckPacket.PacketsBlock pb in ((PacketAckPacket)packet).Packets)
1862 {
1863 uint id = pb.ID;
1864 if (acks.ContainsKey(id))
1865 {
1866 acks.Remove(id);
1867 seenAcks.Add(id);
1868 changed = true;
1869 }
1870 else
1871 {
1872 newPacketBlocks.Add(pb);
1873 }
1874 }
1875 if (changed)
1876 {
1877 PacketAckPacket newPacket = new PacketAckPacket();
1878 newPacket.Packets = new PacketAckPacket.PacketsBlock[newPacketBlocks.Count];
1879  
1880 int a = 0;
1881 foreach (PacketAckPacket.PacketsBlock pb in newPacketBlocks)
1882 {
1883 newPacket.Packets[a++] = pb;
1884 }
1885  
1886 SwapPacket(packet, (Packet)newPacket);
1887 packet = newPacket;
1888 needsCopy = false;
1889 }
1890 }
1891  
1892 // check for appended ACKs
1893 if (packet.Header.AppendedAcks)
1894 {
1895 int ackCount = packet.Header.AckList.Length;
1896 for (int i = 0; i < ackCount; )
1897 {
1898 uint ackID = packet.Header.AckList[i]; // FIXME FIXME FIXME
1899  
1900 if (acks.ContainsKey(ackID))
1901 {
1902 uint[] newAcks = new uint[ackCount - 1];
1903 Array.Copy(packet.Header.AckList, 0, newAcks, 0, i);
1904 Array.Copy(packet.Header.AckList, i + 1, newAcks, i, ackCount - i - 1);
1905 packet.Header.AckList = newAcks;
1906 --ackCount;
1907 acks.Remove(ackID);
1908 seenAcks.Add(ackID);
1909 needsCopy = false;
1910 }
1911 else
1912 ++i;
1913 }
1914 if (ackCount == 0)
1915 {
1916 packet.Header.AppendedAcks = false;
1917 packet.Header.AckList = new uint[0];
1918 }
1919 }
1920  
1921 return packet;
1922 }
1923  
1924 // ModifySequence: modify a packet's sequence number and ACK IDs to account for injections
1925 public Packet ModifySequence(Packet packet, Direction direction, ref int length, ref bool needsCopy)
1926 {
1927 List<uint> ourInjections = direction == Direction.Outgoing ? outgoingInjections : incomingInjections;
1928 List<uint> theirInjections = direction == Direction.Incoming ? outgoingInjections : incomingInjections;
1929 uint ourOffset = direction == Direction.Outgoing ? outgoingOffset : incomingOffset;
1930 uint theirOffset = direction == Direction.Incoming ? outgoingOffset : incomingOffset;
1931  
1932 uint newSequence = (uint)(packet.Header.Sequence + ourOffset);
1933 foreach (uint injection in ourInjections)
1934 if (newSequence >= injection)
1935 ++newSequence;
1936  
1937 packet.Header.Sequence = newSequence;
1938  
1939 if (packet.Header.AppendedAcks)
1940 {
1941 int ackCount = packet.Header.AckList.Length;
1942 for (int i = 0; i < ackCount; ++i)
1943 {
1944 //int offset = length - (ackCount - i) * 4 - 1;
1945 uint ackID = packet.Header.AckList[i] - theirOffset;
1946  
1947 for (int j = theirInjections.Count - 1; j >= 0; --j)
1948 if (ackID >= (uint)theirInjections[j])
1949 --ackID;
1950  
1951 packet.Header.AckList[i] = ackID;
1952 }
1953 }
1954  
1955 if (packet.Type == PacketType.PacketAck)
1956 {
1957 PacketAckPacket pap = (PacketAckPacket)packet;
1958 foreach (PacketAckPacket.PacketsBlock pb in pap.Packets)
1959 {
1960 uint ackID = (uint)pb.ID - theirOffset;
1961  
1962 for (int i = theirInjections.Count - 1; i >= 0; --i)
1963 if (ackID >= (uint)theirInjections[i])
1964 --ackID;
1965  
1966 pb.ID = ackID;
1967  
1968 }
1969  
1970 switch (packet.Header.Frequency)
1971 {
1972 case PacketFrequency.High: length = 7; break;
1973 case PacketFrequency.Medium: length = 8; break;
1974 case PacketFrequency.Low: length = 10; break;
1975 }
1976  
1977 needsCopy = false;
1978 }
1979  
1980 return packet;
1981 }
1982 }
1983  
1984 // Checkers swap proxy addresses in for real addresses. A few constraints:
1985 // - Checkers must not alter the incoming packet.
1986 // - Checkers must return a freshly built packet, even if nothing's changed.
1987 // - The incoming packet's buffer may be longer than the length of the data it contains.
1988 // - The incoming packet's buffer must not be used after the checker returns.
1989 // This is all because checkers may be operating on data that's still in a scratch buffer.
1990 delegate Packet AddressChecker(Packet packet);
1991  
1992 Dictionary<PacketType, AddressChecker> incomingCheckers = new Dictionary<PacketType, AddressChecker>();
1993 Dictionary<PacketType, AddressChecker> outgoingCheckers = new Dictionary<PacketType, AddressChecker>();
1994  
1995 // InitializeAddressCheckers: initialize delegates that check packets for addresses that need proxying
1996 private void InitializeAddressCheckers()
1997 {
1998 // TODO: what do we do with mysteries and empty IPs?
1999 AddMystery(PacketType.OpenCircuit);
2000 //AddMystery(PacketType.AgentPresenceResponse);
2001  
2002 incomingCheckers.Add(PacketType.TeleportFinish, new AddressChecker(CheckTeleportFinish));
2003 incomingCheckers.Add(PacketType.CrossedRegion, new AddressChecker(CheckCrossedRegion));
2004 incomingCheckers.Add(PacketType.EnableSimulator, new AddressChecker(CheckEnableSimulator));
2005 //incomingCheckers.Add("UserLoginLocationReply", new AddressChecker(CheckUserLoginLocationReply));
2006 }
2007  
2008 // AddMystery: add a checker delegate that logs packets we're watching for development purposes
2009 private void AddMystery(PacketType type)
2010 {
2011 incomingCheckers.Add(type, new AddressChecker(LogIncomingMysteryPacket));
2012 outgoingCheckers.Add(type, new AddressChecker(LogOutgoingMysteryPacket));
2013 }
2014  
2015 // GenericCheck: replace the sim address in a packet with our proxy address
2016 private void GenericCheck(ref uint simIP, ref ushort simPort, ref string simCaps, bool active)
2017 {
2018 IPAddress sim_ip = new IPAddress((long)simIP);
2019  
2020 IPEndPoint realSim = new IPEndPoint(sim_ip, Convert.ToInt32(simPort));
2021 IPEndPoint fakeSim = ProxySim(realSim);
2022  
2023 simPort = (ushort)fakeSim.Port;
2024 byte[] bytes = fakeSim.Address.GetAddressBytes();
2025 simIP = Utils.BytesToUInt(bytes);
2026 if (simCaps != null && simCaps.Length > 0)
2027 {
2028 CapInfo info = new CapInfo(simCaps, realSim, "SeedCapability");
2029 info.AddDelegate(new CapsDelegate(FixupSeedCapsResponse));
2030 lock (this)
2031 {
2032 KnownCaps[simCaps] = info;
2033 }
2034 simCaps = loginURI + simCaps;
2035 }
2036  
2037 if (active)
2038 activeCircuit = realSim;
2039 }
2040  
2041 // CheckTeleportFinish: check TeleportFinish packets
2042 private Packet CheckTeleportFinish(Packet packet)
2043 {
2044 TeleportFinishPacket tfp = (TeleportFinishPacket)packet;
2045 string simCaps = Encoding.UTF8.GetString(tfp.Info.SeedCapability).Replace("\0", "");
2046 GenericCheck(ref tfp.Info.SimIP, ref tfp.Info.SimPort, ref simCaps, true);
2047 tfp.Info.SeedCapability = Utils.StringToBytes(simCaps);
2048 return (Packet)tfp;
2049 }
2050  
2051 // CheckEnableSimulator: check EnableSimulator packets
2052 private Packet CheckEnableSimulator(Packet packet)
2053 {
2054 EnableSimulatorPacket esp = (EnableSimulatorPacket)packet;
2055 string simCaps = null;
2056 GenericCheck(ref esp.SimulatorInfo.IP, ref esp.SimulatorInfo.Port, ref simCaps, false);
2057 return (Packet)esp;
2058 }
2059  
2060 // CheckCrossedRegion: check CrossedRegion packets
2061 private Packet CheckCrossedRegion(Packet packet)
2062 {
2063 CrossedRegionPacket crp = (CrossedRegionPacket)packet;
2064 string simCaps = Encoding.UTF8.GetString(crp.RegionData.SeedCapability).Replace("\0", "");
2065 GenericCheck(ref crp.RegionData.SimIP, ref crp.RegionData.SimPort, ref simCaps, true);
2066 crp.RegionData.SeedCapability = Utils.StringToBytes(simCaps);
2067 return (Packet)crp;
2068 }
2069  
2070 // LogPacket: log a packet dump
2071 private Packet LogPacket(Packet packet, string type)
2072 {
2073 OpenMetaverse.Logger.Log(type + " packet:\n" + packet, Helpers.LogLevel.Info);
2074 return packet;
2075 }
2076  
2077 // LogIncomingMysteryPacket: log an incoming packet we're watching for development purposes
2078 private Packet LogIncomingMysteryPacket(Packet packet)
2079 {
2080 return LogPacket(packet, "incoming mystery");
2081 }
2082  
2083 // LogOutgoingMysteryPacket: log an outgoing packet we're watching for development purposes
2084 private Packet LogOutgoingMysteryPacket(Packet packet)
2085 {
2086 return LogPacket(packet, "outgoing mystery");
2087 }
2088  
2089 public void AddLoginRequestDelegate(XmlRpcRequestDelegate xmlRpcRequestDelegate)
2090 {
2091 lock (loginRequestDelegates)
2092 if (!loginRequestDelegates.Contains(xmlRpcRequestDelegate))
2093 loginRequestDelegates.Add(xmlRpcRequestDelegate);
2094  
2095 }
2096  
2097 public void AddLoginResponseDelegate(XmlRpcResponseDelegate xmlRpcResponseDelegate)
2098 {
2099 lock (loginResponseDelegates)
2100 if (!loginResponseDelegates.Contains(xmlRpcResponseDelegate))
2101 loginResponseDelegates.Add(xmlRpcResponseDelegate);
2102 }
2103 }
2104  
2105  
2106 // Describes the data format of a capability
2107 public enum CapsDataFormat
2108 {
2109 Binary = 0,
2110 OSD = 1
2111 }
2112  
2113 // Describes a caps URI
2114 public class CapInfo
2115 {
2116 private string uri;
2117 private IPEndPoint sim;
2118 private string type;
2119 private CapsDataFormat reqFmt;
2120 private CapsDataFormat respFmt;
2121  
2122 private List<CapsDelegate> Delegates = new List<CapsDelegate>();
2123  
2124  
2125 public CapInfo(string URI, IPEndPoint Sim, string CapType)
2126 :
2127 this(URI, Sim, CapType, CapsDataFormat.OSD, CapsDataFormat.OSD) { }
2128 public CapInfo(string URI, IPEndPoint Sim, string CapType, CapsDataFormat ReqFmt, CapsDataFormat RespFmt)
2129 {
2130 uri = URI; sim = Sim; type = CapType; reqFmt = ReqFmt; respFmt = RespFmt;
2131 }
2132 public string URI
2133 {
2134 get { return uri; }
2135 }
2136 public string CapType
2137 {
2138 get { return type; } /* EventQueueGet, etc */
2139 }
2140 public IPEndPoint Sim
2141 {
2142 get { return sim; }
2143 }
2144 public CapsDataFormat ReqFmt
2145 {
2146 get { return reqFmt; } /* expected request format */
2147 }
2148 public CapsDataFormat RespFmt
2149 {
2150 get { return respFmt; } /* expected response format */
2151 }
2152  
2153 public void AddDelegate(CapsDelegate deleg)
2154 {
2155 lock (this)
2156 {
2157 if (!Delegates.Contains(deleg))
2158 {
2159 Delegates.Add(deleg);
2160 }
2161 }
2162 }
2163 public void RemoveDelegate(CapsDelegate deleg)
2164 {
2165 lock (this)
2166 {
2167 if (Delegates.Contains(deleg))
2168 {
2169 Delegates.Remove(deleg);
2170 }
2171 }
2172 }
2173  
2174 // inefficient, but avoids potential deadlocks.
2175 public List<CapsDelegate> GetDelegates()
2176 {
2177 lock (this)
2178 {
2179 return new List<CapsDelegate>(Delegates);
2180 }
2181 }
2182 }
2183  
2184 // Information associated with a caps request/response
2185 public class CapsRequest
2186 {
2187 public CapsRequest(CapInfo info)
2188 {
2189 Info = info;
2190 }
2191  
2192 public readonly CapInfo Info;
2193  
2194 // The request
2195 public OSD Request = null;
2196  
2197 // The corresponding response
2198 public OSD Response = null;
2199  
2200 public byte[] RawRequest = null;
2201 public byte[] RawResponse = null;
2202  
2203 public WebHeaderCollection RequestHeaders = new WebHeaderCollection();
2204 public WebHeaderCollection ResponseHeaders = new WebHeaderCollection();
2205  
2206 public string FullUri = string.Empty;
2207  
2208 }
2209  
2210 // XmlRpcRequestDelegate: specifies a delegate to be called for XML-RPC requests
2211 public delegate void XmlRpcRequestDelegate(object sender, XmlRpcRequestEventArgs e);
2212  
2213 // XmlRpcResponseDelegate: specifies a delegate to be called for XML-RPC responses
2214 public delegate void XmlRpcResponseDelegate(XmlRpcResponse response);
2215  
2216 // PacketDelegate: specifies a delegate to be called when a packet passes through the proxy
2217 public delegate Packet PacketDelegate(Packet packet, IPEndPoint endPoint);
2218  
2219 // Delegate for a caps request. Generally called twice - first with stage = CapsStage.Request
2220 // before the request is sent, then with stage = CapsStage.Response when the response is
2221 // received. Returning true causes all the subsequent delegates in that stage to be skipped,
2222 // and in the case of CapsStage.Request also prevents the request being forwarded. In this
2223 // case, you should set req.Response to the response you want to return.
2224 // Can modify req.Request and req.Response, with the expected effects.
2225 public delegate bool CapsDelegate(CapsRequest req, CapsStage stage);
2226  
2227 // Direction: specifies whether a packet is going to the client (Incoming) or to a sim (Outgoing)
2228 public enum Direction
2229 {
2230 Incoming,
2231 Outgoing
2232 }
2233 public enum CapsStage
2234 {
2235 Request,
2236 Response
2237 }
2238  
2239 public class XmlRpcRequestEventArgs : EventArgs
2240 {
2241 public XmlRpcRequest m_Request;
2242  
2243 public XmlRpcRequestEventArgs(XmlRpcRequest request)
2244 {
2245 this.m_Request = request;
2246 }
2247 }
2248 }
2249  
2250