Removing contents of ThirdParty/3Di. The load balancer can now be found

at http://forge.opensimulator.org/gf/project/loadbalancer/

config key: svn.rmdir
0.6.3-post-fixes
Mike Mazur 2009-01-28 01:56:04 +00:00
parent 7aa216d574
commit fefe0ff3d9
12 changed files with 0 additions and 2825 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
<Addin id="LoadBalancer" version="0.1">
<Runtime>
<Import assembly="OpenSim.ApplicationPlugins.LoadBalancer.dll" />
</Runtime>
<Dependencies>
<Addin id="OpenSim" version="0.5" />
<Addin id="RegionProxy" version="0.1" />
</Dependencies>
<Extension path="/OpenSim/Startup">
<Plugin id="LoadBalancer" type="OpenSim.ApplicationPlugins.LoadBalancer.LoadBalancerPlugin" />
</Extension>
</Addin>

View File

@ -1,225 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace OpenSim.ApplicationPlugins.LoadBalancer
{
public class AsynchronousClient
{
private static ManualResetEvent connectDone = new ManualResetEvent(false);
private static ManualResetEvent sendDone = new ManualResetEvent(false);
public static Socket StartClient(string hostname, int port)
{
try
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(hostname);
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
/*
Send(client,"This is a test<EOF>");
sendDone.WaitOne();
Receive(client);
receiveDone.WaitOne();
client.Shutdown(SocketShutdown.Both);
client.Close();
*/
return client;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
throw new Exception("socket error !!");
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket) ar.AsyncState;
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString());
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static void Send(Socket client, byte[] byteData)
{
client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket) ar.AsyncState;
int bytesSent = client.EndSend(ar);
if (bytesSent > 0)
{
//Console.WriteLine("Sent {0} bytes to server.", bytesSent);
}
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
public class InternalPacketHeader
{
public Guid agent_id;
private byte[] buffer = new byte[32];
public int numbytes;
public int region_port;
public int throttlePacketType;
public int type;
public void FromBytes(byte[] bytes)
{
MemoryStream memstr = new MemoryStream(bytes);
memstr.Seek(0, SeekOrigin.Begin);
BinaryReader binread = new BinaryReader(memstr);
type = binread.ReadInt32();
throttlePacketType = binread.ReadInt32();
numbytes = binread.ReadInt32();
agent_id = new Guid(binread.ReadBytes(16));
region_port = binread.ReadInt32();
binread.Close();
}
public byte[] ToBytes()
{
int i = 0;
buffer[i++] = (byte) (type % 256);
buffer[i++] = (byte) ((type >> 8) % 256);
buffer[i++] = (byte) ((type >> 16) % 256);
buffer[i++] = (byte) ((type >> 24) % 256);
buffer[i++] = (byte) (throttlePacketType % 256);
buffer[i++] = (byte) ((throttlePacketType >> 8) % 256);
buffer[i++] = (byte) ((throttlePacketType >> 16) % 256);
buffer[i++] = (byte) ((throttlePacketType >> 24) % 256);
buffer[i++] = (byte) (numbytes % 256);
buffer[i++] = (byte) ((numbytes >> 8) % 256);
buffer[i++] = (byte) ((numbytes >> 16) % 256);
buffer[i++] = (byte) ((numbytes >> 24) % 256);
// no endian care
Buffer.BlockCopy(agent_id.ToByteArray(), 0, buffer, i, 16);
i += 16;
buffer[i++] = (byte) (region_port % 256);
buffer[i++] = (byte) ((region_port >> 8) % 256);
buffer[i++] = (byte) ((region_port >> 16) % 256);
buffer[i++] = (byte) ((region_port >> 24) % 256);
return buffer;
}
}
public class TcpClient
{
public static int internalPacketHeaderSize = 4 * 4 + 16 * 1;
private Socket mConnection;
private string mHostname;
private int mPort;
public TcpClient(string hostname, int port)
{
mHostname = hostname;
mPort = port;
mConnection = null;
}
public void connect()
{
mConnection = AsynchronousClient.StartClient(mHostname, mPort);
}
/*
public void receive()
{
if (mConnection == null)
{
throw new Exception("client not initialized");
}
try
{
AsynchronousClient.Receive(this.mConnection);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
mConnection = null;
}
}
*/
public void send(InternalPacketHeader header, byte[] packet)
{
lock (this)
{
if (mConnection == null)
{
// throw new Exception("client not initialized");
connect();
}
AsynchronousClient.Send(mConnection, header.ToBytes());
/*
for (int i = 0; i < 10; i++)
{
Console.Write(packet[i] + " ");
}
Console.WriteLine("");
*/
AsynchronousClient.Send(mConnection, packet);
}
}
}
}

View File

@ -1,219 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace OpenSim.ApplicationPlugins.LoadBalancer
{
public class StateObject
{
public const int BufferSize = 2048;
public byte[] buffer = new byte[BufferSize];
public InternalPacketHeader header = null;
public MemoryStream ms_ptr = new MemoryStream();
public Socket workSocket = null;
}
public class AsynchronousSocketListener
{
public static ManualResetEvent allDone = new ManualResetEvent(false);
public static string data = null;
#region KIRYU
#region Delegates
public delegate void PacketRecieveHandler(InternalPacketHeader header, byte[] buff);
#endregion
public static PacketRecieveHandler PacketHandler = null;
#endregion
public AsynchronousSocketListener()
{
}
public static void StartListening(int port)
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
allDone.Reset();
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
/*
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
*/
}
public static void AcceptCallback(IAsyncResult ar)
{
allDone.Set();
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.workSocket;
try
{
int bytesRead = handler.EndReceive(ar);
//MainLog.Instance.Verbose("TCPSERVER", "Received packet [{0}]", bytesRead);
if (bytesRead > 0)
{
state.ms_ptr.Write(state.buffer, 0, bytesRead);
}
else
{
//MainLog.Instance.Verbose("TCPSERVER", "Connection terminated");
return;
}
long rest_size = state.ms_ptr.Length;
long current_pos = 0;
while (rest_size > TcpClient.internalPacketHeaderSize)
{
if ((state.header == null) && (rest_size >= TcpClient.internalPacketHeaderSize))
{
//MainLog.Instance.Verbose("TCPSERVER", "Processing header");
// reading header
state.header = new InternalPacketHeader();
byte[] headerbytes = new byte[TcpClient.internalPacketHeaderSize];
state.ms_ptr.Position = current_pos;
state.ms_ptr.Read(headerbytes, 0, TcpClient.internalPacketHeaderSize);
state.ms_ptr.Seek(0, SeekOrigin.End);
state.header.FromBytes(headerbytes);
}
if ((state.header != null) && (rest_size >= state.header.numbytes + TcpClient.internalPacketHeaderSize))
{
//MainLog.Instance.Verbose("TCPSERVER", "Processing body");
// reading body
byte[] packet = new byte[state.header.numbytes];
state.ms_ptr.Position = current_pos + TcpClient.internalPacketHeaderSize;
state.ms_ptr.Read(packet, 0, state.header.numbytes);
/*
for (int i=0; i<state.header.numbytes; i++)
{
System.Console.Write(packet[i] + " ");
}
System.Console.WriteLine();
*/
state.ms_ptr.Seek(0, SeekOrigin.End);
// call loadbarancer function
if (PacketHandler == null)
{
//MainLog.Instance.Verbose("TCPSERVER", "PacketHandler not found");
}
else
{
//MainLog.Instance.Verbose("TCPSERVER", "calling PacketHandler");
PacketHandler(state.header, packet);
}
int read_size = state.header.numbytes + TcpClient.internalPacketHeaderSize;
state.header = null;
rest_size -= read_size;
current_pos += read_size;
if (rest_size < TcpClient.internalPacketHeaderSize)
{
byte[] rest_bytes = new byte[rest_size];
state.ms_ptr.Position = read_size;
state.ms_ptr.Read(rest_bytes, 0, (int) rest_size);
state.ms_ptr.Close();
state.ms_ptr = new MemoryStream();
state.ms_ptr.Write(rest_bytes, 0, (int) rest_size);
break;
}
}
} // while (true)
}
catch (Exception)
{
//MainLog.Instance.Verbose("TCPSERVER", e.ToString());
//MainLog.Instance.Verbose("TCPSERVER", e.StackTrace);
}
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
}
public class TcpServer
{
private int mPort = 11000;
public TcpServer()
{
}
public TcpServer(int port)
{
mPort = port;
}
public void start()
{
AsynchronousSocketListener.StartListening(mPort);
}
}
}

View File

@ -1,82 +0,0 @@
INTRODUCTION
This folder contains code that implement:
1. Dynamic load balancing
OpenSim is allowing many regions to share a region server, but the optimal
number of regions on each server depends on the load of each region, something
which may change as time goes on. 3Di is working on a load balancer that
allows the current load to be monitored and regions to be reassigned without
requiring the servers to be restarted. To move a region, its state is
serialized, and a new clone is created on the target server using this
stream. The old region is then destroyed and the client viewer updated to use
the new region address.
2. Region splitting
Currently each region can hold only a small number of avatars. To allow more
avatars in each region, 3Di has implemented region splitting, in which several
copies of a given region can be distributed across the region servers. Each
sub-region updates a fraction of the avatars, and sends state updates to the
other sub-regions.
IMPLEMENTATION
The code is organised as follows:
* LoadBalancer: communicates with other region servers and creates/destroys
regions on command
* RegionMonitor/MonitorGUI: provides a browser GUI, showing the state of the
grid, and provides buttons for controlling region movement, splitting, and
merging.
* RegionMonitor/ServerPlugin: this is a region server plugin which
communicates with the load balancer GUI to provide information
on the identity and status of the regions on the grid
* RegionProxy: maps messages from a clients to the true location of a region.
USAGE
In order to use these additions the following lines have to be added to
OpenSim.ini:
proxy_offset = -1000
proxy_url = http://10.8.1.50:9001
serialize_dir = /mnt/temp/
If defined, proxy_offset defines how to calculate the true region port, e.g.
if the XML defines the port as 9000 the actual port is 8000 if proxy_offset
is -1000. The RegionProxy module will open a port at 9000 which the clients
can connect to, and route all traffic from there to port 8000. This allows
the region proxy to run on region server together with regions without
blocking them by using the same port number.
The proxy location is defined in proxy_url. When splitting, the region state
is stored on a file in the folder specified in serialize_dir. This has to be
a shared folder which both region servers involved in the split have access to.
3. Monitor GUI
RegionMonitor/MonitorGUI is used to view status of all the managed Region
servers, and send "Move", "Split", "Merge" commands to a specified Regions
server.
MonitorGUI is a web-based application. You can access it through a web browser.
Its back-end is written in perl. (CGI script)
Pre-requierments (CentOS, Fedora)
RPM package "perl-XML-RPC" and relevant packages.
Installation
1. Install Apache
2. copy all the files undef "ThirdParty/3Di/RegionMonitor/MonitorGUI/htdocs" to
"$APACHE_ROOT/htdocs"
3. Configuration in "monitor.cgi"
* 10th line, set the value to your "monitor.cgi"'s location.
* 11th line, set the value to your Grid server.
* 12th line, set your region proxy port number here.
(ref. OpenSim.ini::NetWork::http_listener_port)
* The code also works fine with mod_perl.

View File

@ -1,214 +0,0 @@
package MonitorGUI::View;
use strict;
my @server_list;
my $max_port;
my $regions;
sub screen_header {
return << "HEADER";
<HTML>
<HEAD>
<STYLE TYPE="text/css">
<!--
a:link {font-size: 12pt; text-decoration:none; color:#0000ff ;}
a:visited {font-size: 12pt; text-decoration:none; color:#ff0000 ;}
a:active {font-size: 12pt; text-decoration:none; color:#00ff00 ;}
a:hover {font-size: 12pt; text-decoration:underline; color:#ff00ff ;}
td {font-size: 12pt;border:0;}
th {background-color:#000000; font-size: 12pt;border:0; color:#FFFFFF; }
tr {background-color:#FFFFFF; }
b {font-size: 12pt;}
//table {background-color:#000000; }
-->
</STYLE>
<META http-equiv="content-type" content="text/html;charset=UTF-8" />
<META name="refresh" content="300" />
<TITLE>Region Monitor GUI, 3Di</TITLE>
</HEAD>
<BODY>
HEADER
}
sub screen_footer {
return << "FOOTER";
</BODY>
</HTML>
FOOTER
}
sub html {
my $grid_info = shift;
my $regions_list = $grid_info->{"sim-profiles"};
$regions = undef;
foreach(@$regions_list) {
my $ip = $_->{sim_ip} || "UNKNOWN";
my $port = $_->{sim_port} || "UNKNOWN";
$regions->{$ip}->{$port} = $_;
if (!$regions->{max_port} || $regions->{max_port} < $port) {
$regions->{max_port} = $port;
}
}
@server_list = keys %$regions;
$max_port = $regions->{max_port};
my $html = "";
foreach my $machine (@server_list) {
next if ($machine eq "max_port");
$html .= &_machine_view($machine, $regions->{$machine});
}
return $html;
}
sub _machine_view {
my ($ip, $info) = @_;
my $region_html = "";
foreach my $region (keys %$info) {
$region_html .= &_region_html($info->{$region});
}
my $html =<< "MACHINE_HTML";
<h3>$ip</h3>
$region_html
<hr size=0 noshade />
MACHINE_HTML
}
sub _region_html {
my $region_info = shift;
my $name = $region_info->{name} || "UNKNOWN";
my $x = $region_info->{x} || -1;
my $y = $region_info->{y} || -1;
my $ip = $region_info->{sim_ip} || "UNKNOWN";
my $port = $region_info->{sim_port} || "UNKNOWN";
my $get_scene_presence_filter = $region_info->{get_scene_presence_filter};
my $get_scene_presence = $region_info->{get_scene_presence};
my $get_avatar_filter = $region_info->{get_avatar_filter};
my $get_avatar = $region_info->{get_avatar};
my $avatar_names = $region_info->{avatar_names};
my $action_forms = &_action_forms($region_info);
my $html = <<"REGION_HTML";
<strong>$name</strong><br/>
$ip:$port | X: $x Y: $y<br/>
<table border="0">
<tr>
<td>get_avatar</td>
<td>$get_avatar</td>
<td></td>
</tr>
<tr>
<td>get_avatar_filter</td>
<td>$get_avatar_filter</td>
<td>$avatar_names</td>
</tr>
<tr>
<td>get_scene_presence</td>
<td>$get_scene_presence</td>
<td></td>
</tr>
<tr>
<td>get_scene_presence_filter</td>
<td>$get_scene_presence_filter</td>
<td></td>
</tr>
</table>
$action_forms
REGION_HTML
return $html;
}
sub _action_forms {
my $region_info = shift;
my $ip = $region_info->{sim_ip};
my $port = $region_info->{sim_port};
my $default_input_port = $max_port + 1;
my $move_to_options = "";
my $split_to_options = "";
my $merge_ip_options = "";
foreach(@server_list) {
next if ($_ eq "max_port");
$merge_ip_options .= "<option value=\"$_\">$_\n";
$split_to_options .= "<option value=\"$_\">$_\n";
#next if ($_ eq $ip);
$move_to_options .= "<option value=\"$_\">$_\n";
}
my $merge_port_options = "";
my $merge_disabled = "disabled";
foreach(keys %{$regions->{$ip}}) {
next if ($_ eq $port);
$merge_disabled = "";
}
# for(9000..$max_port) { # TODO :
# next if ($_ eq $port);
# $merge_port_options .= "<option value=\"$_\">$_\n";
# }
my %port = ();
foreach my $ip (keys %$regions) {
next if ($ip eq "max_port");
print STDERR "--" . $ip . "\n";
foreach my $region_port (keys %{$regions->{$ip}}) {
print STDERR "---" . $region_port . "\n";
$port{$region_port} = 1;
}
}
foreach (keys %port) {
$merge_port_options .= "<option value=\"$_\">$_\n";
$merge_disabled = "";
}
return << "ACTION_FORMS";
<table>
<tr>
<form method="POST">
<td>
<input type="hidden" name="A" value="move" />
<input type="hidden" name="from_ip" value="$ip" />
<input type="hidden" name="from_port" value="$port" />
<input type="submit" value="Move to" />
<select name="to_ip">
$move_to_options
</select>:
<input type="text" name="to_port" size="5" value="$default_input_port"/>
</td>
</form>
<td>
&nbsp;&nbsp;|&nbsp;&nbsp;
</td>
<form method="POST">
<td>
<input type="hidden" name="A" value="split" />
<input type="hidden" name="from_ip" value="$ip" />
<input type="hidden" name="from_port" value="$port" />
<input type="submit" value="Split to" />
<select name="to_ip">
$split_to_options
</select>:
<input type="text" name="to_port" size="5" value="$default_input_port"/>
</td>
</form>
<td>
&nbsp;&nbsp;|&nbsp;&nbsp;
</td>
<form method="POST">
<td>
<input type="hidden" name="A" value="merge" />
<input type="hidden" name="from_ip" value="$ip" />
<input type="hidden" name="master_port" value="$port" />
<input type="submit" value="Merge" $merge_disabled />
<select name="slave_ip" $merge_disabled>
$merge_ip_options
</select>
<select name="slave_port" $merge_disabled>
$merge_port_options
</select>
</td>
</form>
</tr>
</table>
ACTION_FORMS
}
1;

View File

@ -1,91 +0,0 @@
package MyCGI;
use strict;
use CGI;
sub getParam {
my $cgi;
if ($ARGV[0]) {
$cgi = new CGI($ARGV[0]);
} else {
$cgi = new CGI;
}
my @param_names = $cgi->param();
my %param = ();
foreach (@param_names) {
$param{$_} = $cgi->param($_);
}
return \%param;
}
sub getCookie {
my $name = shift;
my $cookie_value = &CGI::cookie($name);
return &_parse($cookie_value);
}
sub outputHtml {
my ($charset, $html) = @_;
print &CGI::header(-charset => $charset);
print $html;
}
sub outputXml {
my ($charset, $xml) = @_;
print &CGI::header( -type => 'text/xml', -charset => $charset );
print $xml;
}
sub makeCookieValue {
my $param = shift;
my @data = ();
foreach(keys %$param) {
push(@data, $_ . "=" . $param->{$_});
}
return join("&", @data);
}
sub setCookie {
my $param = shift;
my $cookie = &CGI::cookie(
-name => $param->{name} || return,
-value => $param->{value},
-domain => $param->{domain},
-path => $param->{path},
-expires => $param->{expires},
);
return &CGI::header(-cookie => $cookie);
}
sub redirect {
my $dest = shift;
&CGI::redirect($dest);
}
sub urlEncode {
my $str = shift;
$str =~ s/([^\w ])/'%'.unpack('H2', $1)/eg;
$str =~ tr/ /+/;
return $str;
}
sub urlDecode {
my $str = shift;
$str =~ tr/+/ /;
$str =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg;
return $str;
}
sub _parse {
my $value = shift;
my @pair = split(/&/, $value);
my %data = ();
foreach(@pair) {
my ($name, $value) = split(/=/, $_);
$data{$name} = $value;
}
return \%data;
}
1;

View File

@ -1,100 +0,0 @@
package XML::RPC;
use strict;
use Carp;
use RPC::XML;
use RPC::XML::Parser;
use RPC::XML::Client;
sub new {
my ($this, $url) = @_;
my %fields = (
parser => new RPC::XML::Parser(),
url => $url,
);
return bless \%fields, $this;
}
sub receive {
my ($this, $xmldata, $handler) = @_;
my $response = undef;
eval {
my $request = $this->{parser}->parse($xmldata);
my @args = map {$_->value} @{$request->args};
$response = $handler->($request->{name}, @args);
};
if ($@) {
my %error = (
"error" => "ERROR",
"message" => $@,
);
$response = \%error;
}
if ( ref($response) eq "RPC::XML::response" ) {
return $response->as_string;
}
else {
return RPC::XML::response->new($response)->as_string;
}
}
sub call {
my ($this, $method_name, $param) = @_;
if (!$this->{url}) {
Carp::croak("XMLRPC: url not set for calling $method_name");
}
my $client = RPC::XML::Client->new($this->{url});
my $request_param = undef;
my $req = undef;
if (ref $param eq "ARRAY") {
$request_param = &_make_array_param($param);
$req = RPC::XML::request->new(
$method_name,
@$request_param,
);
} elsif (ref $param eq "HASH"){
$request_param = &_make_hash_param($param);
$req = RPC::XML::request->new(
$method_name,
$request_param,
);
} else {
Carp::croak("unexpected param type");
}
my $rpc_res = undef;
eval {
$rpc_res = $client->send_request($req);
};
if ($@) {
Carp::croak("request " . $this->{url} . "/" . $method_name . " failed. $@" );
}
if (ref($rpc_res) eq "RPC::XML::struct") {
my %res = map { $_ => $rpc_res->{$_}->value } keys %$rpc_res; # remember good perl !!
return \%res;
} elsif (ref($rpc_res) eq "RPC::XML::string") {
return $rpc_res->value;
} else {
return undef;
}
}
sub _make_array_param {
my $param = shift;
my @array_param = ();
foreach (@$param) {
push @array_param, RPC::XML::string->new($_); # @@@ only string type
}
return \@array_param;
}
sub _make_hash_param {
my $param = shift;
my %hash_param = ();
foreach (keys %$param) {
$hash_param{$_} = RPC::XML::string->new($param->{$_}); # @@@ only string type
}
return RPC::XML::struct->new(\%hash_param);
}
1;

View File

@ -1,202 +0,0 @@
#!/usr/bin/perl -w
use strict;
use Carp;
use MyCGI;
use XML::RPC;
use MonitorGUI::View;
use vars qw ($THIS_URL $GRID_SERVER_URL $DEFAULT_PROXY_PORT);
$THIS_URL = "http://10.8.1.165/monitorgui/monitor.cgi";
$GRID_SERVER_URL = "http://10.8.1.165/opensim/grid.cgi";
$DEFAULT_PROXY_PORT = 9000;
my %ACTIONS = (
# Region commands
move => \&move_command,
split => \&split_command,
merge => \&merge_command,
# display commands
default => \&main_screen,
refresh => \&refresh,
);
# ##################
# main
my $param = &MyCGI::getParam;
my $act = $param->{A} || "default";
my $contents = "";
if (!$ACTIONS{$act}) {
&gui_error("404 NOT FOUND");
} else {
eval {
$ACTIONS{$act}->($param);
};
if ($@) {
&gui_error($@);
}
}
# #################
# Region Commands
sub move_command {
my $param = shift;
# from
my $from_ip = $param->{from_ip} || Carp::croak("not enough params (from_ip)");
my $from_port = $param->{from_port} || Carp::croak("not enough params (from_port)");
my $from_url = "http://" . $param->{from_ip} . ":" . $DEFAULT_PROXY_PORT;
# to
my $to_ip = $param->{to_ip} || Carp::croak("not enough params (to_ip)");
my $to_port = $param->{to_port} || Carp::croak("not enough params (to_port)");
my $to_url = "http://" . $param->{to_ip} . ":" . $DEFAULT_PROXY_PORT;
# commands
eval {
&OpenSim::Utility::XMLRPCCall_array($from_url, "SerializeRegion", [$from_ip, $from_port]);
&OpenSim::Utility::XMLRPCCall_array($to_url, "DeserializeRegion_Move", [$from_ip, $from_port, $to_ip, $to_port]);
&OpenSim::Utility::XMLRPCCall_array($from_url, "TerminateRegion", [$from_port]);
};
if ($@) {
print STDERR "Get Status Error: $@\n";
}
# client refresh
&redirect_refresh({wait=>5, force=>"$from_url|$to_url", msg=>"Move region $from_ip:$from_port from $from_url to $to_url"});
}
sub split_command {
my $param = shift;
# from
my $from_ip = $param->{from_ip} || Carp::croak("not enough params (from_ip)");
my $from_port = $param->{from_port} || Carp::croak("not enough params (from_port)");
my $from_url = "http://" . $param->{from_ip} . ":" . $DEFAULT_PROXY_PORT;
# to
my $to_ip = $param->{to_ip} || Carp::croak("not enough params (to_ip)");
my $to_port = $param->{to_port} || Carp::croak("not enough params (to_port)");
my $to_url = "http://" . $param->{to_ip} . ":" . $DEFAULT_PROXY_PORT;
# commands
eval {
&OpenSim::Utility::XMLRPCCall_array($from_url, "SerializeRegion", [$from_ip, $from_port]);
&OpenSim::Utility::XMLRPCCall_array($to_url, "DeserializeRegion_Clone", [$from_ip, $from_port, $to_ip, $to_port]);
};
if ($@) {
print STDERR "Get Status Error: $@\n";
}
&redirect_refresh({wait=>5, force=>"$from_url", msg=>"Split region $from_ip:$from_port"});
}
sub merge_command {
my $param = shift;
# from
my $from_ip = $param->{from_ip} || Carp::croak("not enough params (from_ip)");
my $url = "http://" . $param->{from_ip} . ":" . $DEFAULT_PROXY_PORT;
# ports
my $master_port = $param->{master_port} || Carp::croak("not enough params (master_port)");
my $slave_ip = $param->{slave_ip} || Carp::croak("not enough params (slave_ip)");
my $slave_port = $param->{slave_port} || Carp::croak("not enough params (slave_port)");
my $slave_url = "http://" . $param->{slave_ip} . ":" . $DEFAULT_PROXY_PORT;
# commands
eval {
&XMLRPCCall_array($url, "MergeRegions", [$from_ip, $master_port]);
&XMLRPCCall_array($slave_url, "TerminateRegion", [$slave_port]);
};
if ($@) {
print STDERR "Get Status Error: $@\n";
}
&redirect_refresh({wait=>5, force=>"$url", msg=>"Merge region $from_ip:$master_port, $slave_port"});
}
# #################
# Display
sub main_screen {
my %xml_rpc_param = (
# TODO: should be 0 - 65535 ?
xmin => 999, ymin => 999, xmax => 1010, ymax => 1010,
);
my $res_obj = undef;
eval {
$res_obj = &XMLRPCCall($GRID_SERVER_URL, "map_block", \%xml_rpc_param);
};
if ($@) {
&gui_error("map_block Error: " . $@);
}
my %copy_obj = %$res_obj;
my $getstatus_failed = "<font color=\"red\">GetStatus Failed</font>";
my $regions_list = $res_obj->{"sim-profiles"};
foreach(@$regions_list) {
if ($_->{sim_ip} && $_->{sim_port}) {
my $url = "http://" . $_->{sim_ip} . ":" . $DEFAULT_PROXY_PORT;
my $port = $_->{sim_port};
my $res = undef;
eval {
$res = &XMLRPCCall_array($url, "GetStatus", [$port]);
};
if ($@) {
print STDERR "Get Status Error: $@\n";
}
$_->{get_scene_presence_filter} = $res ? $res->{get_scene_presence_filter} : $getstatus_failed;
$_->{get_scene_presence} = $res ? $res->{get_scene_presence} : $getstatus_failed;
$_->{get_avatar_filter} = $res ? $res->{get_avatar_filter} : $getstatus_failed;
$_->{get_avatar} = $res ? $res->{get_avatar} : $getstatus_failed;
$_->{avatar_names} = $res ? $res->{avatar_names} : "NO USER";
}
}
my $html = &MonitorGUI::View::html(\%copy_obj);
&MyCGI::outputHtml("UTF-8", &MonitorGUI::View::screen_header . $html . &MonitorGUI::View::screen_footer);
}
sub gui_error {
my $msg = shift;
&MyCGI::outputHtml("UTF-8", "<h1>ERROR</h1><hr />$msg");
}
sub redirect_refresh {
my $args = shift;
my $wait = $args->{wait};
my $force = $args->{force} || "";
my $msg = $args->{msg} || "";
my $param = "A=refresh&wait=$wait&ip=$force&msg=$msg";
my $dist_url = $THIS_URL . "?" . $param;
&MyCGI::redirect($dist_url);
}
sub refresh {
my $param = shift;
my $msg = $param->{msg} || "";
my $wait = $param->{wait} || 0;
my $force = $param->{ip} || "";
#my $jump_url = $force ? "$THIS_URL?A=force&ip=$force" : $THIS_URL;
my $jump_url = $THIS_URL;
my $html =<< "HTML";
<html>
<head>
<meta http-equiv="Refresh" content="$wait;URL=$jump_url" />
<title>Region Monitor GUI REFRESH</title>
</head>
<body>
<h3>$msg</h3>
<br>
wait <font color="red"><b>$wait</b></font> sec for server to take effect ... <br>
(* The page will jump to "Monitor Screen" automatically)
</body>
</html>
HTML
&MyCGI::outputHtml("UTF-8", $html);
}
# ##################
# Utility
sub XMLRPCCall {
my ($url, $methodname, $param) = @_;
my $xmlrpc = new XML::RPC($url);
my $result = $xmlrpc->call($methodname, $param);
return $result;
}
sub XMLRPCCall_array {
my ($url, $methodname, $param) = @_;
my $xmlrpc = new XML::RPC($url);
my $result = $xmlrpc->call($methodname, @$param);
return $result;
}

View File

@ -1,21 +0,0 @@
How to get this working on Linux/Apache:
Create a new directory /var/www/monitor and copy all files htdocs/* files there.
Include these lines in /etc/apache2/httpdocs
---
<Directory /var/www/monitor>
Options +ExecCGI
</Directory>
AddHandler cgi-script .cgi
---
Restart Apache: sudo /etc/init.d/apache2 restart
Check that the perl XML-RPC modules is available ("sudo apt-get install librcp-xml-perl" on Ubuntu)
Edit /var/www/monitor/monitor.cgi to update the IP addresses for the Grid server (TODO: improve this)
Start OpenSim in grid mode, use a browser to open http://localhost/monitor/monitor.cgi

View File

@ -1,554 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using log4net;
using Mono.Addins;
using Nwc.XmlRpc;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
namespace OpenSim.ApplicationPlugins.RegionProxy
{
/* This module has an interface to OpenSim clients that is constant, and is responsible for relaying
* messages to and from clients to the region objects. Since the region objects can be duplicated and
* moved dynamically, the proxy provides methods for changing and adding regions. If more than one region
* is associated with a client port, then the message will be broadcasted to all those regions.
*
* The client interface port may be blocked. While being blocked, all messages from the clients will be
* stored in the proxy. Once the interface port is unblocked again, all stored messages will be resent
* to the regions. This functionality is used when moving or cloning an region to make sure that no messages
* are sent to the region while it is being reconfigured.
*
* The proxy opens a XmlRpc interface with these public methods:
* - AddPort
* - AddRegion
* - ChangeRegion
* - BlockClientMessages
* - UnblockClientMessages
*/
public class RegionProxyPlugin : IApplicationPlugin
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private BaseHttpServer command_server;
private ProxyServer proxy;
#region IApplicationPlugin Members
// TODO: required by IPlugin, but likely not at all right
string m_name = "RegionProxy";
string m_version = "0.1";
public string Version { get { return m_version; } }
public string Name { get { return m_name; } }
public void Initialise()
{
m_log.Info("[PROXY]: " + Name + " cannot be default-initialized!");
throw new PluginNotInitialisedException (Name);
}
public void Initialise(OpenSimBase openSim)
{
m_log.Info("[PROXY] Starting proxy");
string proxyURL = openSim.ConfigSource.Source.Configs["Network"].GetString("proxy_url", "");
if (proxyURL.Length == 0) return;
uint port = (uint) Int32.Parse(proxyURL.Split(new char[] {':'})[2]);
command_server = new BaseHttpServer(port);
command_server.Start();
command_server.AddXmlRPCHandler("AddPort", AddPort);
command_server.AddXmlRPCHandler("AddRegion", AddRegion);
command_server.AddXmlRPCHandler("DeleteRegion", DeleteRegion);
command_server.AddXmlRPCHandler("ChangeRegion", ChangeRegion);
command_server.AddXmlRPCHandler("BlockClientMessages", BlockClientMessages);
command_server.AddXmlRPCHandler("UnblockClientMessages", UnblockClientMessages);
command_server.AddXmlRPCHandler("Stop", Stop);
proxy = new ProxyServer(m_log);
}
public void Dispose()
{
}
#endregion
private XmlRpcResponse Stop(XmlRpcRequest request)
{
try
{
proxy.Stop();
}
catch (Exception e)
{
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
}
return new XmlRpcResponse();
}
private XmlRpcResponse AddPort(XmlRpcRequest request)
{
try
{
int clientPort = (int) request.Params[0];
int regionPort = (int) request.Params[1];
string regionUrl = (string) request.Params[2];
proxy.AddPort(clientPort, regionPort, regionUrl);
}
catch (Exception e)
{
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
}
return new XmlRpcResponse();
}
private XmlRpcResponse AddRegion(XmlRpcRequest request)
{
try
{
int currentRegionPort = (int) request.Params[0];
string currentRegionUrl = (string) request.Params[1];
int newRegionPort = (int) request.Params[2];
string newRegionUrl = (string) request.Params[3];
proxy.AddRegion(currentRegionPort, currentRegionUrl, newRegionPort, newRegionUrl);
}
catch (Exception e)
{
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
}
return new XmlRpcResponse();
}
private XmlRpcResponse ChangeRegion(XmlRpcRequest request)
{
try
{
int currentRegionPort = (int) request.Params[0];
string currentRegionUrl = (string) request.Params[1];
int newRegionPort = (int) request.Params[2];
string newRegionUrl = (string) request.Params[3];
proxy.ChangeRegion(currentRegionPort, currentRegionUrl, newRegionPort, newRegionUrl);
}
catch (Exception e)
{
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
}
return new XmlRpcResponse();
}
private XmlRpcResponse DeleteRegion(XmlRpcRequest request)
{
try
{
int currentRegionPort = (int) request.Params[0];
string currentRegionUrl = (string) request.Params[1];
proxy.DeleteRegion(currentRegionPort, currentRegionUrl);
}
catch (Exception e)
{
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
}
return new XmlRpcResponse();
}
private XmlRpcResponse BlockClientMessages(XmlRpcRequest request)
{
try
{
string regionUrl = (string) request.Params[0];
int regionPort = (int) request.Params[1];
proxy.BlockClientMessages(regionUrl, regionPort);
}
catch (Exception e)
{
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
}
return new XmlRpcResponse();
}
private XmlRpcResponse UnblockClientMessages(XmlRpcRequest request)
{
try
{
string regionUrl = (string) request.Params[0];
int regionPort = (int) request.Params[1];
proxy.UnblockClientMessages(regionUrl, regionPort);
}
catch (Exception e)
{
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
}
return new XmlRpcResponse();
}
}
public class ProxyServer
{
protected readonly ILog m_log;
protected ProxyMap proxy_map = new ProxyMap();
protected AsyncCallback receivedData;
protected bool running;
public ProxyServer(ILog log)
{
m_log = log;
running = false;
receivedData = new AsyncCallback(OnReceivedData);
}
public void BlockClientMessages(string regionUrl, int regionPort)
{
EndPoint client = proxy_map.GetClient(new IPEndPoint(IPAddress.Parse(regionUrl), regionPort));
ProxyMap.RegionData rd = proxy_map.GetRegionData(client);
rd.isBlocked = true;
}
public void UnblockClientMessages(string regionUrl, int regionPort)
{
EndPoint client = proxy_map.GetClient(new IPEndPoint(IPAddress.Parse(regionUrl), regionPort));
ProxyMap.RegionData rd = proxy_map.GetRegionData(client);
rd.isBlocked = false;
while (rd.storedMessages.Count > 0)
{
StoredMessage msg = (StoredMessage) rd.storedMessages.Dequeue();
//m_log.Verbose("[PROXY]"+"Resending blocked message from {0}", msg.senderEP);
SendMessage(msg.buffer, msg.length, msg.senderEP, msg.sd);
}
}
public void AddRegion(int oldRegionPort, string oldRegionUrl, int newRegionPort, string newRegionUrl)
{
//m_log.Verbose("[PROXY]"+"AddRegion {0} {1}", oldRegionPort, newRegionPort);
EndPoint client = proxy_map.GetClient(new IPEndPoint(IPAddress.Parse(oldRegionUrl), oldRegionPort));
ProxyMap.RegionData data = proxy_map.GetRegionData(client);
data.regions.Add(new IPEndPoint(IPAddress.Parse(newRegionUrl), newRegionPort));
}
public void ChangeRegion(int oldRegionPort, string oldRegionUrl, int newRegionPort, string newRegionUrl)
{
//m_log.Verbose("[PROXY]"+"ChangeRegion {0} {1}", oldRegionPort, newRegionPort);
EndPoint client = proxy_map.GetClient(new IPEndPoint(IPAddress.Parse(oldRegionUrl), oldRegionPort));
ProxyMap.RegionData data = proxy_map.GetRegionData(client);
data.regions.Clear();
data.regions.Add(new IPEndPoint(IPAddress.Parse(newRegionUrl), newRegionPort));
}
public void DeleteRegion(int oldRegionPort, string oldRegionUrl)
{
m_log.InfoFormat("[PROXY]" + "DeleteRegion {0} {1}", oldRegionPort, oldRegionUrl);
EndPoint regionEP = new IPEndPoint(IPAddress.Parse(oldRegionUrl), oldRegionPort);
EndPoint client = proxy_map.GetClient(regionEP);
ProxyMap.RegionData data = proxy_map.GetRegionData(client);
data.regions.Remove(regionEP);
}
public void AddPort(int clientPort, int regionPort, string regionUrl)
{
running = true;
//m_log.Verbose("[PROXY]"+"AddPort {0} {1}", clientPort, regionPort);
IPEndPoint clientEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), clientPort);
proxy_map.Add(clientEP, new IPEndPoint(IPAddress.Parse(regionUrl), regionPort));
ServerData sd = new ServerData();
sd.clientEP = new IPEndPoint(clientEP.Address, clientEP.Port);
OpenPort(sd);
}
protected void OpenPort(ServerData sd)
{
// sd.clientEP must be set before calling this function
ClosePort(sd);
try
{
m_log.InfoFormat("[PROXY] Opening special UDP socket on {0}", sd.clientEP);
sd.serverIP = new IPEndPoint(IPAddress.Parse("0.0.0.0"), ((IPEndPoint) sd.clientEP).Port);
sd.server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sd.server.Bind(sd.serverIP);
sd.senderEP = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0);
//receivedData = new AsyncCallback(OnReceivedData);
sd.server.BeginReceiveFrom(sd.recvBuffer, 0, sd.recvBuffer.Length, SocketFlags.None, ref sd.senderEP, receivedData, sd);
}
catch (Exception e)
{
m_log.ErrorFormat("[PROXY] Failed to (re)open socket {0}", sd.clientEP);
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
}
}
protected static void ClosePort(ServerData sd)
{
// Close the port if it exists and is open
if (sd.server == null) return;
try
{
sd.server.Shutdown(SocketShutdown.Both);
sd.server.Close();
}
catch (Exception)
{
}
}
public void Stop()
{
running = false;
m_log.InfoFormat("[PROXY] Stopping the proxy server");
}
protected virtual void OnReceivedData(IAsyncResult result)
{
if (!running) return;
ServerData sd = (ServerData) result.AsyncState;
sd.senderEP = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0);
try
{
int numBytes = sd.server.EndReceiveFrom(result, ref sd.senderEP);
if (numBytes > 0)
{
SendMessage(sd.recvBuffer, numBytes, sd.senderEP, sd);
}
}
catch (Exception e)
{
// OpenPort(sd); // reopen the port just in case
m_log.ErrorFormat("[PROXY] EndReceiveFrom failed in {0}", sd.clientEP);
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
}
WaitForNextMessage(sd);
}
protected void WaitForNextMessage(ServerData sd)
{
bool error = true;
while (error)
{
error = false;
try
{
sd.server.BeginReceiveFrom(sd.recvBuffer, 0, sd.recvBuffer.Length, SocketFlags.None, ref sd.senderEP, receivedData, sd);
}
catch (Exception e)
{
error = true;
m_log.ErrorFormat("[PROXY] BeginReceiveFrom failed, retrying... {0}", sd.clientEP);
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
OpenPort(sd);
}
}
}
protected void SendMessage(byte[] buffer, int length, EndPoint senderEP, ServerData sd)
{
int numBytes = length;
//m_log.ErrorFormat("[PROXY] Got message from {0} in thread {1}, size {2}", senderEP, sd.clientEP, numBytes);
EndPoint client = proxy_map.GetClient(senderEP);
if (client == null)
{
// This message comes from a client object, forward it to the the region(s)
ProxyCodec.EncodeProxyMessage(buffer, ref numBytes, senderEP);
ProxyMap.RegionData rd = proxy_map.GetRegionData(sd.clientEP);
foreach (EndPoint region in rd.regions)
{
if (rd.isBlocked)
{
rd.storedMessages.Enqueue(new StoredMessage(buffer, length, numBytes, senderEP, sd));
}
else
{
try
{
sd.server.SendTo(buffer, numBytes, SocketFlags.None, region);
//m_log.InfoFormat("[PROXY] Sending client message from {0} to {1}", senderEP, region);
}
catch (Exception e)
{
OpenPort(sd); // reopen the port just in case
m_log.ErrorFormat("[PROXY] Failed sending client message from {0} to {1}", senderEP, region);
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
return;
}
}
}
}
else
{
try
{
client = ProxyCodec.DecodeProxyMessage(buffer, ref numBytes);
try
{
// This message comes from a region object, forward it to the its client
sd.server.SendTo(buffer, numBytes, SocketFlags.None, client);
//m_log.InfoFormat("[PROXY] Sending region message from {0} to {1}, size {2}", senderEP, client, numBytes);
}
catch (Exception e)
{
OpenPort(sd); // reopen the port just in case
m_log.ErrorFormat("[PROXY] Failed sending region message from {0} to {1}", senderEP, client);
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
return;
}
}
catch (Exception e)
{
OpenPort(sd); // reopen the port just in case
m_log.ErrorFormat("[PROXY] Failed decoding region message from {0}", senderEP);
m_log.Error("[PROXY]" + e.Message);
m_log.Error("[PROXY]" + e.StackTrace);
return;
}
}
}
#region Nested type: ProxyMap
protected class ProxyMap
{
private Dictionary<EndPoint, RegionData> map;
public ProxyMap()
{
map = new Dictionary<EndPoint, RegionData>();
}
public void Add(EndPoint client, EndPoint region)
{
if (map.ContainsKey(client))
{
map[client].regions.Add(region);
}
else
{
RegionData regions = new RegionData();
map.Add(client, regions);
regions.regions.Add(region);
}
}
public RegionData GetRegionData(EndPoint client)
{
return map[client];
}
public EndPoint GetClient(EndPoint region)
{
foreach (KeyValuePair<EndPoint, RegionData> pair in map)
{
if (pair.Value.regions.Contains(region))
{
return pair.Key;
}
}
return null;
}
#region Nested type: RegionData
public class RegionData
{
public bool isBlocked = false;
public List<EndPoint> regions = new List<EndPoint>();
public Queue storedMessages = new Queue();
}
#endregion
}
#endregion
#region Nested type: ServerData
protected class ServerData
{
public EndPoint clientEP;
public byte[] recvBuffer = new byte[4096];
public EndPoint senderEP;
public Socket server;
public IPEndPoint serverIP;
public ServerData()
{
server = null;
}
}
#endregion
#region Nested type: StoredMessage
protected class StoredMessage
{
public byte[] buffer;
public int length;
public ServerData sd;
public EndPoint senderEP;
public StoredMessage(byte[] buffer, int length, int maxLength, EndPoint senderEP, ServerData sd)
{
this.buffer = new byte[maxLength];
this.length = length;
for (int i = 0; i < length; i++) this.buffer[i] = buffer[i];
this.senderEP = senderEP;
this.sd = sd;
}
}
#endregion
}
}

View File

@ -1,11 +0,0 @@
<Addin id="RegionProxy" version="0.1">
<Runtime>
<Import assembly="OpenSim.ApplicationPlugins.RegionProxy.dll" />
</Runtime>
<Dependencies>
<Addin id="OpenSim" version="0.5" />
</Dependencies>
<Extension path="/OpenSim/Startup">
<Plugin id="RegionProxy" type="OpenSim.ApplicationPlugins.RegionProxy.RegionProxyPlugin" />
</Extension>
</Addin>