aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ThirdParty/3Di/RegionProxy
diff options
context:
space:
mode:
Diffstat (limited to 'ThirdParty/3Di/RegionProxy')
-rw-r--r--ThirdParty/3Di/RegionProxy/RegionProxyPlugin.cs513
1 files changed, 513 insertions, 0 deletions
diff --git a/ThirdParty/3Di/RegionProxy/RegionProxyPlugin.cs b/ThirdParty/3Di/RegionProxy/RegionProxyPlugin.cs
new file mode 100644
index 0000000..13aec48
--- /dev/null
+++ b/ThirdParty/3Di/RegionProxy/RegionProxyPlugin.cs
@@ -0,0 +1,513 @@
1/*
2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
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* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28
29using System;
30using System.IO;
31using System.Net;
32using System.Xml;
33using System.Text;
34using System.Xml.Serialization;
35using System.Net.Sockets;
36using System.Collections;
37using System.Collections.Generic;
38using System.Diagnostics;
39
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Console;
43using Nwc.XmlRpc;
44
45using Mono.Addins;
46
47[assembly:Addin]
48[assembly:AddinDependency ("OpenSim", "0.5")]
49
50namespace OpenSim.ApplicationPlugins.RegionProxy
51{
52 /* This module has an interface to OpenSim clients that is constant, and is responsible for relaying
53 * messages to and from clients to the region objects. Since the region objects can be duplicated and
54 * moved dynamically, the proxy provides methods for changing and adding regions. If more than one region
55 * is associated with a client port, then the message will be broadcasted to all those regions.
56 *
57 * The client interface port may be blocked. While being blocked, all messages from the clients will be
58 * stored in the proxy. Once the interface port is unblocked again, all stored messages will be resent
59 * to the regions. This functionality is used when moving or cloning an region to make sure that no messages
60 * are sent to the region while it is being reconfigured.
61 *
62 * The proxy opens a XmlRpc interface with these public methods:
63 * - AddPort
64 * - AddRegion
65 * - ChangeRegion
66 * - BlockClientMessages
67 * - UnblockClientMessages
68 */
69
70 [Extension("/OpenSim/Startup")]
71 public class RegionProxyPlugin : IApplicationPlugin
72 {
73 private ProxyServer proxy;
74 private BaseHttpServer command_server;
75 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
76
77 public void Initialise(OpenSimMain openSim)
78 {
79 Console.WriteLine("Starting proxy");
80 string proxyURL = openSim.ConfigSource.Configs["Network"].GetString("proxy_url", "");
81 if(proxyURL.Length==0) return;
82
83 uint port = (uint) Int32.Parse(proxyURL.Split(new char[] { ':' })[2]);
84 command_server = new BaseHttpServer(port);
85 command_server.Start();
86 command_server.AddXmlRPCHandler("AddPort", AddPort);
87 command_server.AddXmlRPCHandler("AddRegion", AddRegion);
88 command_server.AddXmlRPCHandler("DeleteRegion", DeleteRegion);
89 command_server.AddXmlRPCHandler("ChangeRegion", ChangeRegion);
90 command_server.AddXmlRPCHandler("BlockClientMessages", BlockClientMessages);
91 command_server.AddXmlRPCHandler("UnblockClientMessages", UnblockClientMessages);
92 command_server.AddXmlRPCHandler("Stop", Stop);
93
94 proxy=new ProxyServer(m_log);
95 }
96
97 public void Close()
98 {
99 }
100
101 private XmlRpcResponse Stop(XmlRpcRequest request)
102 {
103 try
104 {
105 proxy.Stop();
106 }
107 catch (Exception e)
108 {
109 m_log.Error("[PROXY]" + e.Message);
110 m_log.Error("[PROXY]" + e.StackTrace);
111 }
112 return new XmlRpcResponse();
113 }
114
115 private XmlRpcResponse AddPort(XmlRpcRequest request)
116 {
117 try {
118 int clientPort = (int) request.Params[0];
119 int regionPort = (int) request.Params[1];
120 string regionUrl = (string) request.Params[2];
121 proxy.AddPort(clientPort, regionPort, regionUrl);
122 } catch(Exception e) {
123 m_log.Error("[PROXY]"+e.Message);
124 m_log.Error("[PROXY]"+e.StackTrace);
125 }
126 return new XmlRpcResponse();
127 }
128
129 private XmlRpcResponse AddRegion(XmlRpcRequest request)
130 {
131 try {
132 int currentRegionPort = (int) request.Params[0];
133 string currentRegionUrl = (string) request.Params[1];
134 int newRegionPort = (int) request.Params[2];
135 string newRegionUrl = (string) request.Params[3];
136 proxy.AddRegion(currentRegionPort, currentRegionUrl, newRegionPort, newRegionUrl);
137 } catch(Exception e) {
138 m_log.Error("[PROXY]"+e.Message);
139 m_log.Error("[PROXY]"+e.StackTrace);
140 }
141 return new XmlRpcResponse();
142 }
143
144 private XmlRpcResponse ChangeRegion(XmlRpcRequest request)
145 {
146 try {
147 int currentRegionPort = (int) request.Params[0];
148 string currentRegionUrl = (string) request.Params[1];
149 int newRegionPort = (int) request.Params[2];
150 string newRegionUrl = (string) request.Params[3];
151 proxy.ChangeRegion(currentRegionPort, currentRegionUrl, newRegionPort, newRegionUrl);
152 } catch(Exception e) {
153 m_log.Error("[PROXY]"+e.Message);
154 m_log.Error("[PROXY]"+e.StackTrace);
155 }
156 return new XmlRpcResponse();
157 }
158
159 private XmlRpcResponse DeleteRegion(XmlRpcRequest request)
160 {
161 try {
162 int currentRegionPort = (int) request.Params[0];
163 string currentRegionUrl = (string) request.Params[1];
164 proxy.DeleteRegion(currentRegionPort, currentRegionUrl);
165 } catch(Exception e) {
166 m_log.Error("[PROXY]"+e.Message);
167 m_log.Error("[PROXY]"+e.StackTrace);
168 }
169 return new XmlRpcResponse();
170 }
171
172 private XmlRpcResponse BlockClientMessages(XmlRpcRequest request)
173 {
174 try {
175 string regionUrl = (string) request.Params[0];
176 int regionPort = (int) request.Params[1];
177 proxy.BlockClientMessages(regionUrl, regionPort);
178 } catch(Exception e) {
179 m_log.Error("[PROXY]"+e.Message);
180 m_log.Error("[PROXY]"+e.StackTrace);
181 }
182 return new XmlRpcResponse();
183 }
184
185 private XmlRpcResponse UnblockClientMessages(XmlRpcRequest request)
186 {
187 try {
188 string regionUrl = (string) request.Params[0];
189 int regionPort = (int) request.Params[1];
190 proxy.UnblockClientMessages(regionUrl, regionPort);
191 } catch(Exception e) {
192 m_log.Error("[PROXY]"+e.Message);
193 m_log.Error("[PROXY]"+e.StackTrace);
194 }
195 return new XmlRpcResponse();
196 }
197 }
198
199
200 public class ProxyServer {
201 protected AsyncCallback receivedData;
202 protected ProxyMap proxy_map = new ProxyMap();
203 protected readonly log4net.ILog m_log;
204 protected bool running;
205
206 protected class ProxyMap
207 {
208 public class RegionData
209 {
210 public bool isBlocked = false;
211 public Queue storedMessages = new Queue();
212 public List<EndPoint> regions = new List<EndPoint>();
213 }
214
215 private Dictionary<EndPoint, RegionData> map;
216
217 public ProxyMap() {
218 map = new Dictionary<EndPoint, RegionData>();
219 }
220
221 public void Add(EndPoint client, EndPoint region)
222 {
223 if(map.ContainsKey(client))
224 {
225 map[client].regions.Add(region);
226 }
227 else
228 {
229 RegionData regions = new RegionData();
230 map.Add(client, regions);
231 regions.regions.Add(region);
232 }
233 }
234
235 public RegionData GetRegionData(EndPoint client)
236 {
237 return map[client];
238 }
239
240 public EndPoint GetClient(EndPoint region)
241 {
242 foreach (KeyValuePair<EndPoint, RegionData> pair in map)
243 {
244 if(pair.Value.regions.Contains(region))
245 {
246 return pair.Key;
247 }
248 }
249 return null;
250 }
251 }
252
253 protected class ServerData {
254 public Socket server;
255 public EndPoint clientEP;
256 public EndPoint senderEP;
257 public IPEndPoint serverIP;
258 public byte[] recvBuffer = new byte[4096];
259
260 public ServerData()
261 {
262 server = null;
263 }
264 }
265
266 protected class StoredMessage
267 {
268 public byte[] buffer;
269 public int length;
270 public EndPoint senderEP;
271 public ServerData sd;
272
273 public StoredMessage(byte[] buffer, int length, int maxLength, EndPoint senderEP, ServerData sd)
274 {
275 this.buffer = new byte[maxLength];
276 this.length = length;
277 for(int i=0; i<length; i++) this.buffer[i]=buffer[i];
278 this.senderEP = senderEP;
279 this.sd = sd;
280 }
281 }
282
283 public ProxyServer(log4net.ILog log)
284 {
285 m_log = log;
286 running=false;
287 receivedData = new AsyncCallback(OnReceivedData);
288 }
289
290 public void BlockClientMessages(string regionUrl, int regionPort)
291 {
292 EndPoint client = proxy_map.GetClient(new IPEndPoint(IPAddress.Parse(regionUrl), regionPort));
293 ProxyMap.RegionData rd = proxy_map.GetRegionData(client);
294 rd.isBlocked = true;
295 }
296
297 public void UnblockClientMessages(string regionUrl, int regionPort)
298 {
299 EndPoint client = proxy_map.GetClient(new IPEndPoint(IPAddress.Parse(regionUrl), regionPort));
300 ProxyMap.RegionData rd = proxy_map.GetRegionData(client);
301
302 rd.isBlocked = false;
303 while(rd.storedMessages.Count > 0) {
304 StoredMessage msg = (StoredMessage) rd.storedMessages.Dequeue();
305 //m_log.Verbose("[PROXY]"+"Resending blocked message from {0}", msg.senderEP);
306 SendMessage(msg.buffer, msg.length, msg.senderEP, msg.sd);
307 }
308 }
309
310 public void AddRegion(int oldRegionPort, string oldRegionUrl, int newRegionPort, string newRegionUrl)
311 {
312 //m_log.Verbose("[PROXY]"+"AddRegion {0} {1}", oldRegionPort, newRegionPort);
313 EndPoint client = proxy_map.GetClient(new IPEndPoint(IPAddress.Parse(oldRegionUrl), oldRegionPort));
314 ProxyMap.RegionData data = proxy_map.GetRegionData(client);
315 data.regions.Add(new IPEndPoint(IPAddress.Parse(newRegionUrl), newRegionPort));
316 }
317
318 public void ChangeRegion(int oldRegionPort, string oldRegionUrl, int newRegionPort, string newRegionUrl)
319 {
320 //m_log.Verbose("[PROXY]"+"ChangeRegion {0} {1}", oldRegionPort, newRegionPort);
321 EndPoint client = proxy_map.GetClient(new IPEndPoint(IPAddress.Parse(oldRegionUrl), oldRegionPort));
322 ProxyMap.RegionData data = proxy_map.GetRegionData(client);
323 data.regions.Clear();
324 data.regions.Add(new IPEndPoint(IPAddress.Parse(newRegionUrl), newRegionPort));
325 }
326
327 public void DeleteRegion(int oldRegionPort, string oldRegionUrl)
328 {
329 m_log.InfoFormat("[PROXY]"+"DeleteRegion {0} {1}", oldRegionPort, oldRegionUrl);
330 EndPoint regionEP = new IPEndPoint(IPAddress.Parse(oldRegionUrl), oldRegionPort);
331 EndPoint client = proxy_map.GetClient(regionEP);
332 ProxyMap.RegionData data = proxy_map.GetRegionData(client);
333 data.regions.Remove(regionEP);
334 }
335
336 public void AddPort(int clientPort, int regionPort, string regionUrl)
337 {
338 running = true;
339
340 //m_log.Verbose("[PROXY]"+"AddPort {0} {1}", clientPort, regionPort);
341 IPEndPoint clientEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), clientPort);
342 proxy_map.Add(clientEP, new IPEndPoint(IPAddress.Parse(regionUrl), regionPort));
343
344 ServerData sd = new ServerData();
345 sd.clientEP = new IPEndPoint(clientEP.Address, clientEP.Port);
346
347 OpenPort(sd);
348 }
349
350 protected void OpenPort(ServerData sd)
351 {
352 // sd.clientEP must be set before calling this function
353
354 ClosePort(sd);
355
356 try
357 {
358
359 m_log.InfoFormat("[PROXY] Opening UDP socket on {0}", sd.clientEP);
360 sd.serverIP = new IPEndPoint(IPAddress.Parse("0.0.0.0"), ((IPEndPoint)sd.clientEP).Port);
361 sd.server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
362 sd.server.Bind(sd.serverIP);
363
364 sd.senderEP = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0);
365 //receivedData = new AsyncCallback(OnReceivedData);
366 sd.server.BeginReceiveFrom(sd.recvBuffer, 0, sd.recvBuffer.Length, SocketFlags.None, ref sd.senderEP, receivedData, sd);
367 }
368 catch (Exception e)
369 {
370 m_log.ErrorFormat("[PROXY] Failed to (re)open socket {0}", sd.clientEP);
371 m_log.Error("[PROXY]" + e.Message);
372 m_log.Error("[PROXY]" + e.StackTrace);
373 }
374 }
375
376 protected void ClosePort(ServerData sd)
377 {
378 // Close the port if it exists and is open
379 if (sd.server == null) return;
380
381 try
382 {
383 sd.server.Shutdown(SocketShutdown.Both);
384 sd.server.Close();
385 }
386 catch (Exception)
387 {
388 }
389 }
390
391 public void Stop()
392 {
393 running = false;
394 m_log.InfoFormat("[PROXY] Stopping the proxy server");
395
396 }
397
398
399 protected virtual void OnReceivedData(IAsyncResult result)
400 {
401 if(!running) return;
402
403 ServerData sd = (ServerData)result.AsyncState;
404 sd.senderEP = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0);
405
406 try
407 {
408 int numBytes = sd.server.EndReceiveFrom(result, ref sd.senderEP);
409 if (numBytes > 0)
410 {
411 SendMessage(sd.recvBuffer, numBytes, sd.senderEP, sd);
412 }
413 }
414 catch (Exception e)
415 {
416// OpenPort(sd); // reopen the port just in case
417 m_log.ErrorFormat("[PROXY] EndReceiveFrom failed in {0}", sd.clientEP);
418 m_log.Error("[PROXY]" + e.Message);
419 m_log.Error("[PROXY]" + e.StackTrace);
420 }
421
422 WaitForNextMessage(sd);
423 }
424
425 protected void WaitForNextMessage(ServerData sd)
426 {
427 bool error = true;
428 while (error)
429 {
430 error = false;
431 try
432 {
433 sd.server.BeginReceiveFrom(sd.recvBuffer, 0, sd.recvBuffer.Length, SocketFlags.None, ref sd.senderEP, receivedData, sd);
434 }
435 catch (Exception e)
436 {
437 error = true;
438 m_log.ErrorFormat("[PROXY] BeginReceiveFrom failed, retrying... {0}", sd.clientEP);
439 m_log.Error("[PROXY]" + e.Message);
440 m_log.Error("[PROXY]" + e.StackTrace);
441 OpenPort(sd);
442 }
443 }
444 }
445
446 protected void SendMessage(byte[] buffer, int length, EndPoint senderEP, ServerData sd)
447 {
448 int numBytes = length;
449
450 //m_log.ErrorFormat("[PROXY] Got message from {0} in thread {1}, size {2}", senderEP, sd.clientEP, numBytes);
451 EndPoint client = proxy_map.GetClient(senderEP);
452
453 if (client != null)
454 {
455 try
456 {
457 client = PacketPool.DecodeProxyMessage(buffer, ref numBytes);
458 try
459 {
460 // This message comes from a region object, forward it to the its client
461 sd.server.SendTo(buffer, numBytes, SocketFlags.None, client);
462 //m_log.InfoFormat("[PROXY] Sending region message from {0} to {1}, size {2}", senderEP, client, numBytes);
463 }
464 catch (Exception e)
465 {
466 OpenPort(sd); // reopen the port just in case
467 m_log.ErrorFormat("[PROXY] Failed sending region message from {0} to {1}", senderEP, client);
468 m_log.Error("[PROXY]" + e.Message);
469 m_log.Error("[PROXY]" + e.StackTrace);
470 return;
471 }
472 }
473 catch (Exception e)
474 {
475 OpenPort(sd); // reopen the port just in case
476 m_log.ErrorFormat("[PROXY] Failed decoding region message from {0}", senderEP);
477 m_log.Error("[PROXY]" + e.Message);
478 m_log.Error("[PROXY]" + e.StackTrace);
479 return;
480 }
481
482 }
483 else
484 {
485 // This message comes from a client object, forward it to the the region(s)
486 PacketPool.EncodeProxyMessage(buffer, ref numBytes, senderEP);
487 ProxyMap.RegionData rd = proxy_map.GetRegionData(sd.clientEP);
488 foreach (EndPoint region in rd.regions)
489 {
490 if(rd.isBlocked) {
491 rd.storedMessages.Enqueue(new StoredMessage(buffer, length, numBytes, senderEP, sd));
492 }
493 else
494 {
495 try
496 {
497 sd.server.SendTo(buffer, numBytes, SocketFlags.None, region);
498 //m_log.InfoFormat("[PROXY] Sending client message from {0} to {1}", senderEP, region);
499 }
500 catch (Exception e)
501 {
502 OpenPort(sd); // reopen the port just in case
503 m_log.ErrorFormat("[PROXY] Failed sending client message from {0} to {1}", senderEP, region);
504 m_log.Error("[PROXY]" + e.Message);
505 m_log.Error("[PROXY]" + e.StackTrace);
506 return;
507 }
508 }
509 }
510 }
511 }
512 }
513}