Author Topic: [Java] Select the fastest mirror in a group of addresses  (Read 8372 times)

0 Members and 1 Guest are viewing this topic.

Offline Chavo

  • x86
  • Hero Member
  • *****
  • Posts: 2219
  • no u
    • View Profile
    • Chavoland
[Java] Select the fastest mirror in a group of addresses
« on: September 11, 2007, 02:01:36 pm »
I needed something to consistently find the closest mirror.  At first I was thinking pings, but realized that relying on ICMP traffic would be a bad gauge if some mirrors disable it.  Then I considered location lookups based on IP but that is too broad for many purposes and often inaccurate.  So behold this 'psuedo-ping' solution! :P

Run it with debug on if you want more verbose information.

Code: [Select]
/*
 * Find the fastest mirror! :)
 */
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

public class MirrorSelector {

private static boolean DEBUG = false;
private static int MAX_TIME = 1000; // timeout time in ms and default length if an error occurs

public static InetSocketAddress selectMirror(InetSocketAddress[] mirrors)
{
Socket s = new Socket();
long[] times = new long[mirrors.length];
long start;

for(int i=0;i<mirrors.length;i++)
{
try{
s = new Socket();
start = System.currentTimeMillis();
s.connect(mirrors[i], MAX_TIME);
times[i] = System.currentTimeMillis() - start;
s.close();
if(DEBUG)
System.out.println("Connecting to " + mirrors[i] + " took " + times[i] + "ms");
}
/* I considered condensing all the specific exceptions into a generic handler
* since they all respond basically the same way
*/
catch(SocketTimeoutException ste)
{
System.out.println("Address " + mirrors[i] + " timed out");
times[i] = MAX_TIME;
}
catch(ConnectException ce)
{
System.out.println("Connect Exception: " + ce.getMessage() + " for " + mirrors[i]);
if(DEBUG)
ce.printStackTrace();
times[i] = MAX_TIME;
}
catch(SocketException se)
{
System.out.println("Unable to connect to " + mirrors[i]
     +", there may be a problem with your network connection.");
if(DEBUG)
se.printStackTrace();
times[i] = MAX_TIME;
}
catch(IOException ioe)
{
System.out.println("Error connecting to " + mirrors[i]);
if(DEBUG)
ioe.printStackTrace();
times[i] = MAX_TIME;
}
}

int fast_id = 0;
long fast_time = MAX_TIME;
for(int i=0;i<times.length;i++)
{
if(times[i] < fast_time)
{
fast_id = i;
fast_time = times[i];
}
}

return mirrors[fast_id];
}

public static InetSocketAddress getClosestMirror(String hostname, int port)
{
InetAddress[] ips;

try{
ips = InetAddress.getAllByName(hostname);
}
catch(UnknownHostException uhe)
{
System.out.println("Unable to resolve host: " + port);
return null;
}

InetSocketAddress[] mirrors = new InetSocketAddress[ips.length];
for(int i=0;i<ips.length;i++)
{
mirrors[i] = new InetSocketAddress(ips[i], port);
}

return selectMirror(mirrors);
}


public static void main(String[] args)
{
System.out.println("Fastest: " + getClosestMirror("google.com", 80));
}
}

Offline Camel

  • Hero Member
  • *****
  • Posts: 1703
    • View Profile
    • BNU Bot
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #1 on: September 11, 2007, 02:13:59 pm »
Neat little utility. Could be very useful. I'll probably steal it.

<Camel> i said what what
<Blaze> in the butt
<Camel> you want to do it in my butt?
<Blaze> in my butt
<Camel> let's do it in the butt
<Blaze> Okay!

Offline Chavo

  • x86
  • Hero Member
  • *****
  • Posts: 2219
  • no u
    • View Profile
    • Chavoland
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #2 on: September 11, 2007, 02:18:20 pm »
Go for it, anything I make public is up for grabs.  Now that doesn't mean you can hack my svn server and claim it is public.... ;)

Offline Camel

  • Hero Member
  • *****
  • Posts: 1703
    • View Profile
    • BNU Bot
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #3 on: September 11, 2007, 02:40:31 pm »
Of course, I always give credit where it's due. Since I use the GPL v2 for my project, I'd be publishing my modified version under that license. Is that okay with you?

Code: [Select]
/**
 * This file is distributed under the GPL
 * $Id$
 */

package net.bnubot.util;

import java.io.IOException;
...
import java.net.UnknownHostException;

/**
 * http://www.x86labs.org/forum/index.php/topic,10225.0.html
 * @author Chavo
 */
public class MirrorSelector {
...

Quote from: BNU-Bot
[14:36:51] (MirrorSelector) Searching for fastest of 12 hosts for useast.battle.net
[14:36:51] (MirrorSelector) Connecting to useast.battle.net/63.240.202.134 took 32ms
[14:36:51] (MirrorSelector) Connecting to useast.battle.net/63.240.202.138 took 16ms
[14:36:51] (MirrorSelector) Connecting to useast.battle.net/63.240.202.139 took 31ms
[14:36:51] (MirrorSelector) Connecting to useast.battle.net/63.240.202.120 took 32ms
[14:36:51] (MirrorSelector) Connecting to useast.battle.net/63.240.202.121 took 63ms
[14:36:51] (MirrorSelector) Connecting to useast.battle.net/63.240.202.122 took 31ms
[14:36:51] (MirrorSelector) Connecting to useast.battle.net/63.240.202.126 took 31ms
[14:36:51] (MirrorSelector) Connecting to useast.battle.net/63.240.202.127 took 15ms
[14:36:51] (MirrorSelector) Connecting to useast.battle.net/63.240.202.128 took 16ms
[14:36:52] (MirrorSelector) Connecting to useast.battle.net/63.240.202.129 took 31ms
[14:36:52] (MirrorSelector) Connecting to useast.battle.net/63.240.202.130 took 31ms
[14:36:52] (MirrorSelector) Connecting to useast.battle.net/63.240.202.131 took 31ms
[14:36:52] Connecting to useast.battle.net/63.240.202.127:6112
[14:36:52] MPQ: ver-IX86-0.mpq
[14:36:52] (MirrorSelector) There was only one host: jbls.org/72.36.180.162
[14:36:52] Connected to jbls.org/72.36.180.162:9367

<Camel> i said what what
<Blaze> in the butt
<Camel> you want to do it in my butt?
<Blaze> in my butt
<Camel> let's do it in the butt
<Blaze> Okay!

Offline Chavo

  • x86
  • Hero Member
  • *****
  • Posts: 2219
  • no u
    • View Profile
    • Chavoland
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #4 on: September 11, 2007, 02:43:13 pm »
sure, I figured someone might find this useful in a bot

Offline Camel

  • Hero Member
  • *****
  • Posts: 1703
    • View Profile
    • BNU Bot
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #5 on: September 11, 2007, 03:07:45 pm »
http://bnubot.googlecode.com/svn/trunk/BNUBot/src/net/bnubot/util/MirrorSelector.java

Code: [Select]
/**
 * This file is distributed under the GPL
 * $Id$
 */

package net.bnubot.util;

import java.io.IOException;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

/**
 * http://www.x86labs.org/forum/index.php/topic,10225.0.html
 *
 * @author Chavo
 */
public class MirrorSelector {
private static int MAX_TIME = 1000; // timeout time in ms

public static InetAddress selectMirror(InetAddress[] mirrors, int port) {
Socket s = new Socket();
long bestTime = MAX_TIME;
InetAddress bestHost = null;
long start;

for (InetAddress mirror : mirrors) {
long time;
try {
s = new Socket();
start = System.currentTimeMillis();
s.connect(new InetSocketAddress(mirror, port), MAX_TIME);
time = System.currentTimeMillis() - start;
s.close();
Out.debug(MirrorSelector.class, "Connecting to " + mirror.getHostAddress() + " took " + time + "ms");

if (time < bestTime) {
bestTime = time;
bestHost = mirror;
}
} catch (SocketTimeoutException ste) {
Out.error(MirrorSelector.class, "Address " + mirror + " timed out");
} catch (ConnectException ce) {
Out.error(MirrorSelector.class, "Connect Exception: " + ce.getMessage() + " for " + mirror);
Out.exception(ce);
} catch (SocketException se) {
Out.error(MirrorSelector.class, "Unable to connect to " + mirror + ", there may be a problem with your network connection.");
Out.exception(se);
} catch (IOException ioe) {
Out.error(MirrorSelector.class, "Error connecting to " + mirror);
Out.exception(ioe);
}
}

if(bestHost == null) {
bestHost = mirrors[(int)(Math.random() * mirrors.length)];
Out.info(MirrorSelector.class, "There was no clear winner; randomly choosing " + bestHost.getHostAddress());
}
return bestHost;
}

public static InetAddress getClosestMirror(String hostname, int port)
throws UnknownHostException {
InetAddress hosts[] = InetAddress.getAllByName(hostname);
if (hosts.length == 1) {
Out.debug(MirrorSelector.class, "There was only one host: " + hosts[0]);
return hosts[0];
}
Out.info(MirrorSelector.class, "Searching for fastest of " + hosts.length + " hosts for " + hostname);
return selectMirror(hosts, port);
}
}

<Camel> i said what what
<Blaze> in the butt
<Camel> you want to do it in my butt?
<Blaze> in my butt
<Camel> let's do it in the butt
<Blaze> Okay!

Offline Chavo

  • x86
  • Hero Member
  • *****
  • Posts: 2219
  • no u
    • View Profile
    • Chavoland
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #6 on: September 11, 2007, 03:13:41 pm »
spiffy, make sure you give yourself credit too!

Offline Ender

  • x86
  • Hero Member
  • *****
  • Posts: 2390
    • View Profile
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #7 on: September 11, 2007, 04:11:49 pm »
Chavo, did you recently change your name? Sadly, I don't know you :(

Offline Chavo

  • x86
  • Hero Member
  • *****
  • Posts: 2219
  • no u
    • View Profile
    • Chavoland
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #8 on: September 11, 2007, 04:19:21 pm »
Yea, I was unTactical.  I realized that this is the only place that I still used that name and there wasn't any need.

Offline iago

  • Leader
  • Administrator
  • Hero Member
  • *****
  • Posts: 17914
  • Fnord.
    • View Profile
    • SkullSecurity
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #9 on: September 11, 2007, 04:32:27 pm »
Chavo, did you recently change your name? Sadly, I don't know you :(
Haha, I hate it when that happens. Normally when a name changes like that I'll go into a person's post history or mistyped-password log or something to find out who it actually is, then reset their name. :)

Offline Chavo

  • x86
  • Hero Member
  • *****
  • Posts: 2219
  • no u
    • View Profile
    • Chavoland
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #10 on: September 11, 2007, 04:35:50 pm »
I thought I had changed it a while back...

Offline iago

  • Leader
  • Administrator
  • Hero Member
  • *****
  • Posts: 17914
  • Fnord.
    • View Profile
    • SkullSecurity
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #11 on: September 11, 2007, 04:52:32 pm »
Did I change it back? I don't really pay attention to whose usernames I fix. :)

Offline Newby

  • x86
  • Hero Member
  • *****
  • Posts: 10877
  • Thrash!
    • View Profile
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #12 on: September 11, 2007, 08:17:39 pm »
lol. I just go by avatars. Haha.

Anyway, LoRd[nK]/Eric/whateverthefuckhecallshimself did this a while back in VB. I remember because he shared the code with me and it wouldn't work right on my old slow POS computer, but worked fine on my "brand new" one 4 years ago or so.
- Newby
http://www.x86labs.org

Quote
[17:32:45] * xar sets mode: -oooooooooo algorithm ban chris cipher newby stdio TehUser tnarongi|away vursed warz
[17:32:54] * xar sets mode: +o newby
[17:32:58] <xar> new rule
[17:33:02] <xar> me and newby rule all

I'd bet that you're currently bloated like a water ballon on a hot summer's day.

That analogy doesn't even make sense.  Why would a water balloon be especially bloated on a hot summer's day? For your sake, I hope there wasn't too much logic testing on your LSAT. 

Offline Joe

  • B&
  • x86
  • Hero Member
  • *****
  • Posts: 10319
  • In Soviet Russia, text read you!
    • View Profile
    • Github
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #13 on: September 12, 2007, 01:03:15 pm »
StarCraft did this, too! It sends SYN's out to all the servers it resolves, and then only SYNACK's the one that ACK's the fastest.
I'd personally do as Joe suggests

You might be right about that, Joe.


Offline iago

  • Leader
  • Administrator
  • Hero Member
  • *****
  • Posts: 17914
  • Fnord.
    • View Profile
    • SkullSecurity
Re: [Java] Select the fastest mirror in a group of addresses
« Reply #14 on: September 12, 2007, 01:39:29 pm »
StarCraft did this, too! It sends SYN's out to all the servers it resolves, and then only SYNACK's the one that ACK's the fastest.
You got SYNACK and ACK backwards there. Starcraft only ACKs the server that SYNACKs the fastest is what you wanted.

But in any case, Starcraft doesn't use that level of control, it simply uses a connect() systemcall. It is possible that something automated is happening on the system level, but it's not Starcraft itself that does that.