corrade-vassal – Blame information for rev 1
?pathlinks?
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 | } |