From fa218f752003adcfb040053cfb88b36637060de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 7 Oct 2014 17:44:46 +0200 Subject: Block traffic during first connection. Set up routes to UDP unlimited server (since openvpn hasn't finished, it simply blocks traffic) and also DNS server to 10.41.0.1. These values correspond to current leap_platform configuration (https://github.com/leapcode/leap_platform/blob/7bc79e68e5ca913d1d2843c48cde8f946feed09c/puppet/modules/site_openvpn/manifests/init.pp) --- app/src/main/AndroidManifest.xml | 8 ++++++++ app/src/main/java/se/leap/bitmaskclient/EIP.java | 10 +++++++--- .../main/java/se/leap/bitmaskclient/VoidVpnService.java | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 423293b6..bdd541ae 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -35,6 +35,14 @@ android:logo="@drawable/icon" android:label="@string/app" > + + + + + + diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index 43fe0b7c..add5a1d1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -38,8 +38,6 @@ import de.blinkt.openvpn.activities.DisconnectVPN; import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.OpenVpnManagementThread; -import de.blinkt.openvpn.core.OpenVPNService.LocalBinder; -import de.blinkt.openvpn.core.OpenVPNService; import de.blinkt.openvpn.core.ProfileManager; import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; import java.io.IOException; @@ -67,6 +65,7 @@ import org.json.JSONObject; import se.leap.bitmaskclient.Dashboard; import se.leap.bitmaskclient.Provider; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.VoidVpnService; /** * EIP is the abstract base class for interacting with and managing the Encrypted @@ -187,12 +186,17 @@ public final class EIP extends IntentService { */ private void startEIP() { activeGateway = selectGateway(); - + earlyRoutes(); if(activeGateway != null && activeGateway.mVpnProfile != null) { launchActiveGateway(); } } + private void earlyRoutes() { + VoidVpnService voidVpn = new VoidVpnService(); + voidVpn.setUp(context); + } + private void launchActiveGateway() { Intent intent = new Intent(this,LaunchVPN.class); intent.setAction(Intent.ACTION_MAIN); diff --git a/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java new file mode 100644 index 00000000..ec88fd48 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java @@ -0,0 +1,17 @@ +package se.leap.bitmaskclient; + +import android.content.Context; +import android.net.VpnService; + +public class VoidVpnService extends VpnService { + public void setUp(Context context) { + VpnService.prepare(context); // stops the VPN connection created by another application. + Builder builder = new Builder(); + builder.addAddress("10.42.0.8",16); + builder.addRoute("0.0.0.0", 1); + builder.addRoute("128.0.0.0", 1); + builder.addRoute("192.168.1.0", 24); + builder.addDnsServer("10.42.0.1"); + builder.establish(); + } +} -- cgit v1.2.3 From c4df01ab94c85ecf4a106b187a03e4859a857b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 7 Oct 2014 21:17:12 +0200 Subject: Set up early routes on boot too. --- app/src/main/AndroidManifest.xml | 2 ++ app/src/main/java/se/leap/bitmaskclient/EIP.java | 8 +++-- .../se/leap/bitmaskclient/VoidVpnLauncher.java | 36 ++++++++++++++++++++++ .../java/se/leap/bitmaskclient/VoidVpnService.java | 30 ++++++++++++++++-- 4 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bdd541ae..68a99560 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -61,6 +61,8 @@ + diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index add5a1d1..0197692b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -185,16 +185,18 @@ public final class EIP extends IntentService { * Intent to {@link se.leap.openvpn.LaunchVPN} */ private void startEIP() { - activeGateway = selectGateway(); earlyRoutes(); + activeGateway = selectGateway(); + if(activeGateway != null && activeGateway.mVpnProfile != null) { launchActiveGateway(); } } private void earlyRoutes() { - VoidVpnService voidVpn = new VoidVpnService(); - voidVpn.setUp(context); + Intent void_vpn_launcher = new Intent(context, VoidVpnLauncher.class); + void_vpn_launcher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(void_vpn_launcher); } private void launchActiveGateway() { diff --git a/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java b/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java new file mode 100644 index 00000000..23e61eab --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java @@ -0,0 +1,36 @@ +package se.leap.bitmaskclient; + +import android.app.Activity; +import android.content.Intent; +import android.net.VpnService; +import android.os.Bundle; + +public class VoidVpnLauncher extends Activity { + + private static final int VPN_USER_PERMISSION= 71; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setUp(); + } + + public void setUp() { + Intent blocking_intent = VpnService.prepare(getApplicationContext()); // stops the VPN connection created by another application. + if(blocking_intent != null) + startActivityForResult(blocking_intent, VPN_USER_PERMISSION); + else { + onActivityResult(VPN_USER_PERMISSION, RESULT_OK, null); + } + } + + protected void onActivityResult(int requestCode, int resultCode, Intent data){ + if(requestCode == VPN_USER_PERMISSION) { + if(resultCode == RESULT_OK) { + Intent void_vpn_service = new Intent(getApplicationContext(), VoidVpnService.class); + void_vpn_service.setAction(VoidVpnService.START_BLOCKING_VPN_PROFILE); + startService(void_vpn_service); + } + } + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java index ec88fd48..5f7c0ab1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java +++ b/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java @@ -1,11 +1,28 @@ package se.leap.bitmaskclient; -import android.content.Context; +import android.content.Intent; import android.net.VpnService; +import android.util.Log; public class VoidVpnService extends VpnService { - public void setUp(Context context) { - VpnService.prepare(context); // stops the VPN connection created by another application. + + static final String START_BLOCKING_VPN_PROFILE = "se.leap.bitmaskclient.START_BLOCKING_VPN_PROFILE"; + static final String TAG = VoidVpnService.class.getSimpleName(); + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + String action = intent.getAction(); + if (action == START_BLOCKING_VPN_PROFILE) { + new Thread(new Runnable() { + public void run() { + blockConnections(); + } + }).run(); + } + return 0; + } + + public void blockConnections() { Builder builder = new Builder(); builder.addAddress("10.42.0.8",16); builder.addRoute("0.0.0.0", 1); @@ -13,5 +30,12 @@ public class VoidVpnService extends VpnService { builder.addRoute("192.168.1.0", 24); builder.addDnsServer("10.42.0.1"); builder.establish(); + android.util.Log.d(TAG, "VoidVpnService set up"); + try { + new java.net.Socket("sdf.org", 80); + Log.d(TAG, "VoidVpnService doesn's stop traffic"); + } catch (Exception e) { + e.printStackTrace(); + } } } -- cgit v1.2.3 From 8566f7c6f3a5ee3eb668964e3dffb4a753db5b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 7 Oct 2014 21:33:55 +0200 Subject: Finish VoidVpnLauncher activity. It was remaining there, with an empty layout. --- app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java | 3 ++- app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java b/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java index 23e61eab..3b286fbf 100644 --- a/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java +++ b/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java @@ -7,7 +7,7 @@ import android.os.Bundle; public class VoidVpnLauncher extends Activity { - private static final int VPN_USER_PERMISSION= 71; + private static final int VPN_USER_PERMISSION = 71; @Override protected void onCreate(Bundle savedInstanceState) { @@ -32,5 +32,6 @@ public class VoidVpnLauncher extends Activity { startService(void_vpn_service); } } + finish(); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java index 5f7c0ab1..b7289c23 100644 --- a/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java +++ b/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java @@ -24,6 +24,7 @@ public class VoidVpnService extends VpnService { public void blockConnections() { Builder builder = new Builder(); + builder.setSession("Blocking until running"); builder.addAddress("10.42.0.8",16); builder.addRoute("0.0.0.0", 1); builder.addRoute("128.0.0.0", 1); -- cgit v1.2.3 From 35674aa6be80c153a0fbe4a4c15c54e02aef0b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 8 Oct 2014 20:57:09 +0200 Subject: A bit of refactoring. ConfigHelper checks for IllegalArgumentException (trace from play store). EIP location code has been splitted a bit. I'd like to extract OVPNGateway out from EIP, but that's not an easy job and this branch is already lasting to much hehehe. --- .../java/se/leap/bitmaskclient/ConfigHelper.java | 5 +- app/src/main/java/se/leap/bitmaskclient/EIP.java | 305 +++++++++++---------- 2 files changed, 162 insertions(+), 148 deletions(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index a8bd3b7a..c95d0c8b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -18,8 +18,9 @@ package se.leap.bitmaskclient; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.math.BigInteger; import java.io.InputStream; +import java.math.BigInteger; +import java.lang.IllegalArgumentException; import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; @@ -105,6 +106,8 @@ public class ConfigHelper { e.printStackTrace(); } catch (IOException e) { return null; + } catch (IllegalArgumentException e) { + return null; } return (X509Certificate) certificate; diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index 0197692b..4a8bae46 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -16,33 +16,23 @@ */ package se.leap.bitmaskclient; - - - - import android.app.Activity; import android.app.IntentService; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; import android.content.SharedPreferences; -import android.drm.DrmStore.Action; import android.os.Bundle; -import android.os.IBinder; import android.os.ResultReceiver; import android.util.Log; import de.blinkt.openvpn.LaunchVPN; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.activities.DisconnectVPN; -import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; import de.blinkt.openvpn.core.ConfigParser; -import de.blinkt.openvpn.core.OpenVpnManagementThread; +import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; import de.blinkt.openvpn.core.ProfileManager; import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; import java.io.IOException; import java.io.StringReader; -import java.lang.StringBuffer; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; @@ -65,7 +55,6 @@ import org.json.JSONObject; import se.leap.bitmaskclient.Dashboard; import se.leap.bitmaskclient.Provider; import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.VoidVpnService; /** * EIP is the abstract base class for interacting with and managing the Encrypted @@ -105,8 +94,6 @@ public final class EIP extends IntentService { private static Context context; private static ResultReceiver mReceiver; private static boolean mBound = false; - // Used to store actions to "resume" onServiceConnection - private static String mPending = null; private static int parsedEipSerial; private static JSONObject eipDefinition = null; @@ -139,66 +126,136 @@ public final class EIP extends IntentService { } - @Override - protected void onHandleIntent(Intent intent) { - String action = intent.getAction(); - mReceiver = intent.getParcelableExtra(RECEIVER_TAG); + @Override + protected void onHandleIntent(Intent intent) { + String action = intent.getAction(); + mReceiver = intent.getParcelableExtra(RECEIVER_TAG); - if ( action == ACTION_IS_EIP_RUNNING ) - this.isRunning(); - if ( action == ACTION_UPDATE_EIP_SERVICE ) - this.updateEIPService(); - else if ( action == ACTION_START_EIP ) - this.startEIP(); - else if ( action == ACTION_STOP_EIP ) - this.stopEIP(); - else if ( action == ACTION_CHECK_CERT_VALIDITY ) - this.checkCertValidity(); - else if ( action == ACTION_REBUILD_PROFILES ) { - this.updateGateways(); - } - } - - /** - * Checks the last stored status notified by ics-openvpn - * Sends Activity.RESULT_CANCELED to the ResultReceiver that made the - * request if it's not connected, Activity.RESULT_OK otherwise. - */ - - private void isRunning() { - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); - int resultCode = Activity.RESULT_CANCELED; - boolean is_connected = isConnected(); - - resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - - if (mReceiver != null){ - mReceiver.send(resultCode, resultData); - } - - Log.d(TAG, "isRunning() = " + is_connected); - } + if ( action == ACTION_START_EIP ) + startEIP(); + else if ( action == ACTION_STOP_EIP ) + stopEIP(); + else if ( action == ACTION_IS_EIP_RUNNING ) + isRunning(); + else if ( action == ACTION_UPDATE_EIP_SERVICE ) + updateEIPService(); + else if ( action == ACTION_CHECK_CERT_VALIDITY ) + checkCertValidity(); + else if ( action == ACTION_REBUILD_PROFILES ) + updateGateways(); + } - /** - * Initiates an EIP connection by selecting a gateway and preparing and sending an - * Intent to {@link se.leap.openvpn.LaunchVPN} - */ - private void startEIP() { - earlyRoutes(); - activeGateway = selectGateway(); + /** + * Initiates an EIP connection by selecting a gateway and preparing and sending an + * Intent to {@link se.leap.openvpn.LaunchVPN}. + * It also sets up early routes. + */ + private void startEIP() { + earlyRoutes(); + activeGateway = selectGateway(); - if(activeGateway != null && activeGateway.mVpnProfile != null) { - launchActiveGateway(); - } + if(activeGateway != null && activeGateway.mVpnProfile != null) { + launchActiveGateway(); } + } + /** + * Early routes are routes that block traffic until a new + * VpnService is started properly. + */ private void earlyRoutes() { Intent void_vpn_launcher = new Intent(context, VoidVpnLauncher.class); void_vpn_launcher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(void_vpn_launcher); } + /** + * Choose a gateway to connect to based on timezone from system locale data + * + * @return The gateway to connect to + */ + private OVPNGateway selectGateway() { + String closest_location = closestGateway(); + String chosen_host = chooseHost(closest_location); + + return new OVPNGateway(chosen_host); + } + + private String closestGateway() { + TreeMap> offsets = calculateOffsets(); + return offsets.isEmpty() ? "" : offsets.firstEntry().getValue().iterator().next(); + } + + private TreeMap> calculateOffsets() { + TreeMap> offsets = new TreeMap>(); + + int localOffset = Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000; + + JSONObject locations = availableLocations(); + Iterator locations_names = locations.keys(); + while(locations_names.hasNext()) { + try { + String location_name = locations_names.next(); + JSONObject location = locations.getJSONObject(location_name); + + int dist = timezoneDistance(localOffset, location.optInt("timezone")); + + Set set = (offsets.get(dist) != null) ? + offsets.get(dist) : new HashSet(); + + set.add(location_name); + offsets.put(dist, set); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + return offsets; + } + + private JSONObject availableLocations() { + JSONObject locations = null; + try { + if(eipDefinition == null) updateEIPService(); + locations = eipDefinition.getJSONObject("locations"); + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + return locations; + } + + private int timezoneDistance(int local_timezone, int remote_timezone) { + // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 + int dist = Math.abs(local_timezone - remote_timezone); + + // Farther than 12 timezones and it's shorter around the "back" + if (dist > 12) + dist = 12 - (dist -12); // Well i'll be. Absolute values make equations do funny things. + + return dist; + } + + private String chooseHost(String location) { + String chosen_host = ""; + try { + JSONArray gateways = eipDefinition.getJSONArray("gateways"); + for (int i = 0; i < gateways.length(); i++) { + JSONObject gw = gateways.getJSONObject(i); + if ( gw.getString("location").equalsIgnoreCase(location) || location.isEmpty()){ + chosen_host = eipDefinition.getJSONObject("locations").getJSONObject(gw.getString("location")).getString("name"); + break; + } + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return chosen_host; + } + private void launchActiveGateway() { Intent intent = new Intent(this,LaunchVPN.class); intent.setAction(Intent.ACTION_MAIN); @@ -208,30 +265,48 @@ public final class EIP extends IntentService { intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); intent.putExtra(RECEIVER_TAG, mReceiver); startActivity(intent); - mPending = ACTION_START_EIP; } - - /** - * Disconnects the EIP connection gracefully through the bound service or forcefully - * if there is no bound service. Sends a message to the requesting ResultReceiver. - */ - private void stopEIP() { - if(isConnected()) { - Intent disconnect_vpn = new Intent(this, DisconnectVPN.class); - disconnect_vpn.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(disconnect_vpn); - mIsDisconnecting = true; - lastConnectionStatusLevel = ConnectionStatus.UNKNOWN_LEVEL; // Wait for the decision of the user - Log.d(TAG, "mIsDisconnecting = true"); - } + + /** + * Disconnects the EIP connection gracefully through the bound service or forcefully + * if there is no bound service. Sends a message to the requesting ResultReceiver. + */ + private void stopEIP() { + if(isConnected()) { + Intent disconnect_vpn = new Intent(this, DisconnectVPN.class); + disconnect_vpn.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(disconnect_vpn); + mIsDisconnecting = true; + lastConnectionStatusLevel = ConnectionStatus.UNKNOWN_LEVEL; // Wait for the decision of the user + Log.d(TAG, "mIsDisconnecting = true"); + } - if (mReceiver != null){ - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_STOP_EIP); - mReceiver.send(Activity.RESULT_OK, resultData); - } + tellToReceiver(ACTION_STOP_EIP, Activity.RESULT_OK); + } + + private void tellToReceiver(String action, int resultCode) { + if (mReceiver != null){ + Bundle resultData = new Bundle(); + resultData.putString(REQUEST_TAG, action); + mReceiver.send(resultCode, resultData); } + } + + /** + * Checks the last stored status notified by ics-openvpn + * Sends Activity.RESULT_CANCELED to the ResultReceiver that made the + * request if it's not connected, Activity.RESULT_OK otherwise. + */ + + private void isRunning() { + int resultCode = Activity.RESULT_CANCELED; + boolean is_connected = isConnected(); + resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; + + tellToReceiver(ACTION_IS_EIP_RUNNING, resultCode); + } + protected static boolean isConnected() { return lastConnectionStatusLevel != null && lastConnectionStatusLevel.equals(ConnectionStatus.LEVEL_CONNECTED) && !mIsDisconnecting; } @@ -263,70 +338,6 @@ public final class EIP extends IntentService { vpl.removeProfile(context, profiles[current_profile]); } } - /** - * Choose a gateway to connect to based on timezone from system locale data - * - * @return The gateway to connect to - */ - private OVPNGateway selectGateway() { - String closestLocation = closestGateway(); - - JSONArray gateways = null; - String chosenHost = null; - try { - gateways = eipDefinition.getJSONArray("gateways"); - for (int i = 0; i < gateways.length(); i++) { - JSONObject gw = gateways.getJSONObject(i); - if ( gw.getString("location").equalsIgnoreCase(closestLocation) || closestLocation.isEmpty()){ - chosenHost = eipDefinition.getJSONObject("locations").getJSONObject(gw.getString("location")).getString("name"); - break; - } - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - return new OVPNGateway(chosenHost); - } - - private String closestGateway() { - Calendar cal = Calendar.getInstance(); - int localOffset = cal.get(Calendar.ZONE_OFFSET) / 3600000; - TreeMap> offsets = new TreeMap>(); - JSONObject locationsObjects = null; - Iterator locations = null; - try { - locationsObjects = eipDefinition.getJSONObject("locations"); - locations = locationsObjects.keys(); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - while (locations.hasNext()) { - String locationName = locations.next(); - JSONObject location = null; - try { - location = locationsObjects.getJSONObject(locationName); - - // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 - int dist = Math.abs(localOffset - location.optInt("timezone")); - // Farther than 12 timezones and it's shorter around the "back" - if (dist > 12) - dist = 12 - (dist -12); // Well i'll be. Absolute values make equations do funny things. - - Set set = offsets.get(dist); - if (set == null) set = new HashSet(); - set.add(locationName); - offsets.put(dist, set); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - return offsets.isEmpty() ? "" : offsets.firstEntry().getValue().iterator().next(); - } /** * Walk the list of gateways defined in eip-service.json and parse them into -- cgit v1.2.3