corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2009, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Net;
29 using System.Collections.Generic;
30 using System.Text;
31 using System.Text.RegularExpressions;
32 using System.Reflection;
33 using GridProxy;
34 using Nwc.XmlRpc;
35 using OpenMetaverse.Packets;
36 using OpenMetaverse.StructuredData;
37 using OpenMetaverse;
38  
39 namespace GridProxyGUI
40 {
41 public class ProxyManager
42 {
43 // fired when a new packet arrives
44 public delegate void PacketLogHandler(Packet packet, Direction direction, IPEndPoint endpoint);
45 public static event PacketLogHandler OnPacketLog;
46  
47 // fired when a message arrives over a known capability
48 public delegate void MessageLogHandler(CapsRequest req, CapsStage stage);
49 public static event MessageLogHandler OnMessageLog;
50  
51 // handle login request/response data
52 public delegate void LoginLogHandler(object request, Direction direction);
53 public static event LoginLogHandler OnLoginResponse;
54  
55 // fired when a new Capability is added to the KnownCaps Dictionary
56 public delegate void CapsAddedHandler(CapInfo cap);
57 public static event CapsAddedHandler OnCapabilityAdded;
58  
59 // Handle messages sent via the EventQueue
60 public delegate void EventQueueMessageHandler(CapsRequest req, CapsStage stage);
61 public static event EventQueueMessageHandler OnEventMessageLog;
62  
63 private string _Port;
64 private string _ListenIP;
65 private string _LoginURI;
66  
67 public ProxyFrame Proxy;
68  
69 private Assembly openmvAssembly;
70  
71 public ProxyManager(string port, string listenIP, string loginUri)
72 {
73 openmvAssembly = Assembly.Load("OpenMetaverse");
74 if (openmvAssembly == null) throw new Exception("Assembly load exception");
75  
76 _Port = string.Format("--proxy-login-port={0}", port);
77  
78 IPAddress remoteIP; // not used
79 if (IPAddress.TryParse(listenIP, out remoteIP))
80 _ListenIP = String.Format("--proxy-client-facing-address={0}", listenIP);
81 else
82 _ListenIP = "--proxy-client-facing-address=127.0.0.1";
83  
84 if (String.IsNullOrEmpty(loginUri))
85 _LoginURI = "--proxy-remote-login-uri=https://login.agni.lindenlab.com/cgi-bin/login.cgi";
86 else
87 _LoginURI = "--proxy-remote-login-uri=" + loginUri;
88  
89  
90 string[] args = { _Port, _ListenIP, _LoginURI };
91 /*
92 help
93 proxy-help
94 proxy-login-port
95 proxy-client-facing-address
96 proxy-remote-facing-address
97 proxy-remote-login-uri
98 verbose
99 quiet
100 */
101  
102 ProxyConfig pc = new ProxyConfig("WinGridProxy", "Jim Radford", args, false);
103  
104 Proxy = new ProxyFrame(args, pc);
105  
106 Proxy.proxy.AddLoginRequestDelegate(new XmlRpcRequestDelegate(LoginRequest));
107 Proxy.proxy.AddLoginResponseDelegate(new XmlRpcResponseDelegate(LoginResponse));
108  
109 Proxy.proxy.AddCapsDelegate("EventQueueGet", new CapsDelegate(EventQueueGetHandler));
110  
111 // this is so we are informed of any new capabilities that are added to the KnownCaps dictionary
112 Proxy.proxy.KnownCaps.AddDelegate(OpenMetaverse.DictionaryEventAction.Add, new OpenMetaverse.DictionaryChangeCallback(KnownCapsAddedHandler));
113 }
114  
115 public void Start()
116 {
117 Proxy.proxy.Start();
118 }
119  
120 public void Stop()
121 {
122 Proxy.proxy.Stop();
123 }
124  
125 public void KnownCapsAddedHandler(OpenMetaverse.DictionaryEventAction action, System.Collections.DictionaryEntry de)
126 {
127 if (OnCapabilityAdded != null)
128 OnCapabilityAdded((CapInfo)de.Value);
129 }
130  
131 private void LoginRequest(object sender, XmlRpcRequestEventArgs e)
132 {
133 if (OnLoginResponse != null)
134 OnLoginResponse(e.m_Request, Direction.Outgoing);
135 }
136  
137 private void LoginResponse(XmlRpcResponse response)
138 {
139 if (OnLoginResponse != null)
140 OnLoginResponse(response, Direction.Incoming);
141 }
142  
143  
144 internal OpenMetaverse.ObservableDictionary<string, CapInfo> GetCapabilities()
145 {
146 return Proxy.proxy.KnownCaps;
147 }
148  
149 internal void AddCapsDelegate(string capsKey, bool add)
150 {
151 if (add)
152 Proxy.proxy.AddCapsDelegate(capsKey, new CapsDelegate(CapsHandler));
153 else
154 Proxy.proxy.RemoveCapRequestDelegate(capsKey, new CapsDelegate(CapsHandler));
155  
156 }
157  
158 private bool CapsHandler(CapsRequest req, CapsStage stage)
159 {
160 if (OnMessageLog != null)
161 OnMessageLog(req, stage);
162 return false;
163 }
164  
165 /// <summary>
166 /// Process individual messages that arrive via the EventQueue and convert each indvidual event into a format
167 /// suitable for processing by the IMessage system
168 /// </summary>
169 /// <param name="req"></param>
170 /// <param name="stage"></param>
171 /// <returns></returns>
172 private bool EventQueueGetHandler(CapsRequest req, CapsStage stage)
173 {
174 if (stage == CapsStage.Response && req.Response is OSDMap)
175 {
176 OSDMap map = (OSDMap)req.Response;
177  
178 if (map.ContainsKey("events"))
179 {
180 OSDArray eventsArray = (OSDArray)map["events"];
181  
182 for (int i = 0; i < eventsArray.Count; i++)
183 {
184 OSDMap bodyMap = (OSDMap)eventsArray[i];
185 if (OnEventMessageLog != null)
186 {
187 CapInfo capInfo = new CapInfo(req.Info.URI, req.Info.Sim, bodyMap["message"].AsString());
188 CapsRequest capReq = new CapsRequest(capInfo);
189 capReq.RequestHeaders = req.RequestHeaders;
190 capReq.ResponseHeaders = req.ResponseHeaders;
191 capReq.Request = null;// req.Request;
192 capReq.RawRequest = null;// req.RawRequest;
193 capReq.RawResponse = OSDParser.SerializeLLSDXmlBytes(bodyMap);
194 capReq.Response = bodyMap;
195  
196 OnEventMessageLog(capReq, CapsStage.Response);
197 }
198 }
199 }
200 }
201 return false;
202 }
203  
204 private static PacketType PacketTypeFromName(string name)
205 {
206 Type packetTypeType = typeof(PacketType);
207 System.Reflection.FieldInfo f = packetTypeType.GetField(name);
208 if (f == null)
209 {//throw new ArgumentException("Bad packet type");
210 return PacketType.Error;
211 }
212  
213 return (PacketType)Enum.ToObject(packetTypeType, (int)f.GetValue(packetTypeType));
214 }
215  
216 internal void AddUDPDelegate(string packetType, bool add)
217 {
218 AddUDPDelegate(PacketTypeFromName(packetType), add);
219 }
220  
221 internal void AddUDPDelegate(PacketType packetType, bool add)
222 {
223 if (add)
224 {
225 Proxy.proxy.AddDelegate(packetType, Direction.Incoming, new PacketDelegate(PacketInHandler));
226 Proxy.proxy.AddDelegate(packetType, Direction.Outgoing, new PacketDelegate(PacketOutHandler));
227 }
228 else
229 {
230 Proxy.proxy.RemoveDelegate(packetType, Direction.Incoming, new PacketDelegate(PacketInHandler));
231 Proxy.proxy.RemoveDelegate(packetType, Direction.Outgoing, new PacketDelegate(PacketOutHandler));
232 }
233 }
234  
235 private Packet PacketInHandler(Packet packet, IPEndPoint endPoint)
236 {
237 if (OnPacketLog != null)
238 OnPacketLog(packet, Direction.Incoming, endPoint);
239  
240 return packet;
241 }
242  
243 private Packet PacketOutHandler(Packet packet, IPEndPoint endPoint)
244 {
245 if (OnPacketLog != null)
246 OnPacketLog(packet, Direction.Outgoing, endPoint);
247  
248 return packet;
249 }
250  
251 internal void InjectPacket(string packetData, bool toSimulator)
252 {
253 Direction direction = Direction.Incoming;
254 string name = null;
255 string block = null;
256 object blockObj = null;
257 Type packetClass = null;
258 Packet packet = null;
259  
260 try
261 {
262 foreach (string line in packetData.Split(new[] { '\n' }))
263 {
264 Match match;
265  
266 if (name == null)
267 {
268 match = (new Regex(@"^\s*(in|out)\s+(\w+)\s*$")).Match(line);
269 if (!match.Success)
270 {
271 OpenMetaverse.Logger.Log("expecting direction and packet name, got: " + line, OpenMetaverse.Helpers.LogLevel.Error);
272 return;
273 }
274  
275 string lineDir = match.Groups[1].Captures[0].ToString();
276 string lineName = match.Groups[2].Captures[0].ToString();
277  
278 if (lineDir == "in")
279 direction = Direction.Incoming;
280 else if (lineDir == "out")
281 direction = Direction.Outgoing;
282 else
283 {
284 OpenMetaverse.Logger.Log("expecting 'in' or 'out', got: " + line, OpenMetaverse.Helpers.LogLevel.Error);
285 return;
286 }
287  
288 name = lineName;
289 packetClass = openmvAssembly.GetType("OpenMetaverse.Packets." + name + "Packet");
290 if (packetClass == null) throw new Exception("Couldn't get class " + name + "Packet");
291 ConstructorInfo ctr = packetClass.GetConstructor(new Type[] { });
292 if (ctr == null) throw new Exception("Couldn't get suitable constructor for " + name + "Packet");
293 packet = (Packet)ctr.Invoke(new object[] { });
294 }
295 else
296 {
297 match = (new Regex(@"^\s*\[(\w+)\]\s*$")).Match(line);
298 if (match.Success)
299 {
300 block = match.Groups[1].Captures[0].ToString();
301 FieldInfo blockField = packetClass.GetField(block);
302 if (blockField == null) throw new Exception("Couldn't get " + name + "Packet." + block);
303 Type blockClass = blockField.FieldType;
304 if (blockClass.IsArray)
305 {
306 blockClass = blockClass.GetElementType();
307 ConstructorInfo ctr = blockClass.GetConstructor(new Type[] { });
308 if (ctr == null) throw new Exception("Couldn't get suitable constructor for " + blockClass.Name);
309 blockObj = ctr.Invoke(new object[] { });
310 object[] arr = (object[])blockField.GetValue(packet);
311 object[] narr = (object[])Array.CreateInstance(blockClass, arr.Length + 1);
312 Array.Copy(arr, narr, arr.Length);
313 narr[arr.Length] = blockObj;
314 blockField.SetValue(packet, narr);
315 //Console.WriteLine("Added block "+block);
316 }
317 else
318 {
319 blockObj = blockField.GetValue(packet);
320 }
321 if (blockObj == null) throw new Exception("Got " + name + "Packet." + block + " == null");
322 //Console.WriteLine("Got block " + name + "Packet." + block);
323  
324 continue;
325 }
326  
327 if (block == null)
328 {
329 OpenMetaverse.Logger.Log("expecting block name, got: " + line, OpenMetaverse.Helpers.LogLevel.Error);
330 return;
331 }
332  
333 match = (new Regex(@"^\s*(\w+)\s*=\s*(.*)$")).Match(line);
334 if (match.Success)
335 {
336 string lineField = match.Groups[1].Captures[0].ToString();
337 string lineValue = match.Groups[2].Captures[0].ToString();
338 object fval;
339  
340 //FIXME: use of MagicCast inefficient
341 //if (lineValue == "$Value")
342 // fval = MagicCast(name, block, lineField, value);
343 if (lineValue == "$UUID")
344 fval = UUID.Random();
345 else if (lineValue == "$AgentID")
346 fval = Proxy.AgentID;
347 else if (lineValue == "$SessionID")
348 fval = Proxy.SessionID;
349 else
350 fval = MagicCast(name, block, lineField, lineValue);
351  
352 MagicSetField(blockObj, lineField, fval);
353 continue;
354 }
355 OpenMetaverse.Logger.Log("expecting block name or field, got: " + line, OpenMetaverse.Helpers.LogLevel.Error);
356 return;
357 }
358 }
359  
360 if (name == null)
361 {
362  
363 OpenMetaverse.Logger.Log("expecting direction and packet name, got EOF", OpenMetaverse.Helpers.LogLevel.Error);
364 return;
365 }
366  
367 packet.Header.Reliable = true;
368  
369 Proxy.proxy.InjectPacket(packet, direction);
370  
371 OpenMetaverse.Logger.Log("Injected " + name, OpenMetaverse.Helpers.LogLevel.Info);
372 }
373 catch (Exception e)
374 {
375 OpenMetaverse.Logger.Log("failed to injected " + name, OpenMetaverse.Helpers.LogLevel.Error, e);
376 }
377 }
378  
379 private static void MagicSetField(object obj, string field, object val)
380 {
381 Type cls = obj.GetType();
382  
383 FieldInfo fieldInf = cls.GetField(field);
384 if (fieldInf == null)
385 {
386 PropertyInfo prop = cls.GetProperty(field);
387 if (prop == null) throw new Exception("Couldn't find field " + cls.Name + "." + field);
388 prop.SetValue(obj, val, null);
389 //throw new Exception("FIXME: can't set properties");
390 }
391 else
392 {
393 fieldInf.SetValue(obj, val);
394 }
395 }
396  
397 // MagicCast: given a packet/block/field name and a string, convert the string to a value of the appropriate type
398 private object MagicCast(string name, string block, string field, string value)
399 {
400 Type packetClass = openmvAssembly.GetType("OpenMetaverse.Packets." + name + "Packet");
401 if (packetClass == null) throw new Exception("Couldn't get class " + name + "Packet");
402  
403 FieldInfo blockField = packetClass.GetField(block);
404 if (blockField == null) throw new Exception("Couldn't get " + name + "Packet." + block);
405 Type blockClass = blockField.FieldType;
406 if (blockClass.IsArray) blockClass = blockClass.GetElementType();
407 // Console.WriteLine("DEBUG: " + blockClass.Name);
408  
409 FieldInfo fieldField = blockClass.GetField(field); PropertyInfo fieldProp = null;
410 Type fieldClass = null;
411 if (fieldField == null)
412 {
413 fieldProp = blockClass.GetProperty(field);
414 if (fieldProp == null) throw new Exception("Couldn't get " + name + "Packet." + block + "." + field);
415 fieldClass = fieldProp.PropertyType;
416 }
417 else
418 {
419 fieldClass = fieldField.FieldType;
420 }
421  
422 try
423 {
424 if (fieldClass == typeof(byte))
425 {
426 return Convert.ToByte(value);
427 }
428 else if (fieldClass == typeof(ushort))
429 {
430 return Convert.ToUInt16(value);
431 }
432 else if (fieldClass == typeof(uint))
433 {
434 return Convert.ToUInt32(value);
435 }
436 else if (fieldClass == typeof(ulong))
437 {
438 return Convert.ToUInt64(value);
439 }
440 else if (fieldClass == typeof(sbyte))
441 {
442 return Convert.ToSByte(value);
443 }
444 else if (fieldClass == typeof(short))
445 {
446 return Convert.ToInt16(value);
447 }
448 else if (fieldClass == typeof(int))
449 {
450 return Convert.ToInt32(value);
451 }
452 else if (fieldClass == typeof(long))
453 {
454 return Convert.ToInt64(value);
455 }
456 else if (fieldClass == typeof(float))
457 {
458 return Convert.ToSingle(value);
459 }
460 else if (fieldClass == typeof(double))
461 {
462 return Convert.ToDouble(value);
463 }
464 else if (fieldClass == typeof(UUID))
465 {
466 return new UUID(value);
467 }
468 else if (fieldClass == typeof(bool))
469 {
470 if (value.ToLower() == "true")
471 return true;
472 else if (value.ToLower() == "false")
473 return false;
474 else
475 throw new Exception();
476 }
477 else if (fieldClass == typeof(byte[]))
478 {
479 return Utils.StringToBytes(value);
480 }
481 else if (fieldClass == typeof(Vector3))
482 {
483 Vector3 result;
484 if (Vector3.TryParse(value, out result))
485 return result;
486 else
487 throw new Exception();
488 }
489 else if (fieldClass == typeof(Vector3d))
490 {
491 Vector3d result;
492 if (Vector3d.TryParse(value, out result))
493 return result;
494 else
495 throw new Exception();
496 }
497 else if (fieldClass == typeof(Vector4))
498 {
499 Vector4 result;
500 if (Vector4.TryParse(value, out result))
501 return result;
502 else
503 throw new Exception();
504 }
505 else if (fieldClass == typeof(Quaternion))
506 {
507 Quaternion result;
508 if (Quaternion.TryParse(value, out result))
509 return result;
510 else
511 throw new Exception();
512 }
513 else
514 {
515 throw new Exception("unsupported field type " + fieldClass);
516 }
517 }
518 catch
519 {
520 throw new Exception("unable to interpret " + value + " as " + fieldClass);
521 }
522 }
523 }
524  
525  
526  
527 }