Java tutorial
/******************************************************************************* * * Mobility First - mSocket library * Copyright (C) 2013, 2014 - University of Massachusetts Amherst * Contact: arun@cs.umass.edu * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Initial developer(s): Arun Venkataramani, Aditya Yadav, Emmanuel Cecchet. * Contributor(s): ______________________. * *******************************************************************************/ package edu.umass.cs.msocket.proxy; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.URL; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; import org.json.JSONArray; import edu.umass.cs.gns.client.GnsProtocol.AccessType; import edu.umass.cs.gns.client.GuidEntry; import edu.umass.cs.gns.client.UniversalGnsClient; import edu.umass.cs.gns.client.util.KeyPairUtils; import edu.umass.cs.msocket.common.GnsConstants; import edu.umass.cs.msocket.gns.GnsCredentials; import edu.umass.cs.msocket.proxy.forwarder.ProxyLoadStatistics; import edu.umass.cs.msocket.proxy.location.GlobalPosition; /** * This class defines a ProxyGnsPublisher * * @author <a href="mailto:cecchet@cs.umass.edu">Emmanuel Cecchet</a> * @version 1.0 */ public class ProxyGnsPublisher extends Thread { private String proxyGroupName; private String proxyName; private GnsCredentials gnsCredentials; private GnsTimerKeepalive gnsTimer; private boolean killed = false; private SocketAddress proxySocketAddres; private static final Logger logger = Logger.getLogger("GnsProxy"); /** * Creates a new <code>ProxyGnsPublisher</code> object * * @param gnsCredentials GNS connection and account GUID to use * @param proxyName Entity name this proxy is known as in the GNS * @param proxyGroupName Entity name of the group GUID for the proxy group * this proxy belongs to * @param socketAddress the address the proxy is currently listening to, * waiting for connections from mServerSockets */ public ProxyGnsPublisher(GnsCredentials gnsCredentials, String proxyName, String proxyGroupName, SocketAddress socketAddress) { this.gnsCredentials = gnsCredentials; this.proxyGroupName = proxyGroupName; this.proxyName = proxyName; this.proxySocketAddres = socketAddress; } /** * Establish a connection with the GNS, register the proxy in the proxy group, * start a monitoring socket and register its IP in the GNS, * * @throws Exception */ public void registerProxyInGns() throws Exception { logger.info("Looking for proxy " + proxyName + " GUID and certificates..."); GuidEntry myGuid = KeyPairUtils.getGuidEntryFromPreferences( gnsCredentials.getGnsHost() + ":" + gnsCredentials.getGnsPort(), proxyName); final UniversalGnsClient gnsClient = gnsCredentials.getGnsClient(); if (myGuid == null) { logger.info("No keys found for proxy " + proxyName + ". Generating new GUID and keys"); myGuid = gnsClient.guidCreate(gnsCredentials.getGuidEntry(), proxyName); } logger.info("Proxy has guid " + myGuid.getGuid()); // Determine our IP String sIp = null; BufferedReader in; InetAddress addr; try { addr = ((InetSocketAddress) proxySocketAddres).getAddress(); if (addr != null && !addr.isLinkLocalAddress() && !addr.isLoopbackAddress() && !addr.isSiteLocalAddress()) sIp = addr.getHostAddress(); } catch (Exception e) { logger.log(Level.WARNING, "Failed to resolve proxy address " + proxySocketAddres, e); } if (sIp == null) { logger.warning("Local proxy address (" + proxySocketAddres + ") does not seem to be a public address"); try { logger.info("Determining local IP"); // Determine our external IP address by contacting http://icanhazip.com URL whatismyip = new URL("http://icanhazip.com"); in = new BufferedReader(new InputStreamReader(whatismyip.openStream())); sIp = in.readLine(); in.close(); } catch (Exception e) { } } ProxyInfo proxyInfo = new ProxyInfo(myGuid.getGuid(), proxyName, sIp); try { // Contact http://freegeoip.net/csv/[IP] to resolve IP address location URL locator = new URL("http://freegeoip.net/csv/" + sIp); in = new BufferedReader(new InputStreamReader(locator.openStream())); String csv = in.readLine(); in.close(); // Read location result StringTokenizer st = new StringTokenizer(csv, ","); if (!st.hasMoreTokens()) throw new IOException("Failed to read IP"); st.nextToken(); // IP if (!st.hasMoreTokens()) throw new IOException("Failed to read country code"); String countryCode = st.nextToken().replace("\"", ""); proxyInfo.setCountryCode(countryCode); if (!st.hasMoreTokens()) throw new IOException("Failed to read country name"); String countryName = st.nextToken().replace("\"", ""); proxyInfo.setCountryName(countryName); if (!st.hasMoreTokens()) throw new IOException("Failed to read state code"); String stateCode = st.nextToken().replace("\"", ""); proxyInfo.setStateCode(stateCode); if (!st.hasMoreTokens()) throw new IOException("Failed to read state name"); String stateName = st.nextToken().replace("\"", ""); proxyInfo.setStateName(stateName); if (!st.hasMoreTokens()) throw new IOException("Failed to read city"); String city = st.nextToken().replace("\"", ""); proxyInfo.setCity(city); if (!st.hasMoreTokens()) throw new IOException("Failed to read zip"); String zip = st.nextToken().replace("\"", ""); proxyInfo.setZipCode(zip); if (!st.hasMoreTokens()) throw new IOException("Failed to read latitude"); String latitudeStr = st.nextToken().replace("\"", ""); double latitude = Double.parseDouble(latitudeStr); if (!st.hasMoreTokens()) throw new IOException("Failed to read longitude"); String longitudeStr = st.nextToken().replace("\"", ""); double longitude = Double.parseDouble(longitudeStr); proxyInfo.setLatLong(new GlobalPosition(latitude, longitude, 0)); } catch (Exception e) { logger.log(Level.WARNING, "Failed to locate IP address " + e); } // Look for the group GUID String groupGuid = gnsClient.lookupGuid(proxyGroupName); // Check if we are a member of the group boolean isVerified = false; try { JSONArray members = gnsClient.groupGetMembers(groupGuid, myGuid); for (int i = 0; i < members.length(); i++) { if (myGuid.getGuid().equals(members.get(i))) { isVerified = true; break; } } } catch (Exception e) { /* * At this point we couldn't get or parse the member list probably because * we don't have read access to it. This means we are not a verified * member. */ logger.log(Level.INFO, "Could not access the proxy group member list because we are not likely a group member yet (" + e + ")"); } // Make sure we advertise ourselves as a proxy and make the field readable // by everyone gnsClient.fieldReplaceOrCreate(myGuid.getGuid(), GnsConstants.SERVICE_TYPE_FIELD, new JSONArray().put(GnsConstants.PROXY_SERVICE), myGuid); gnsClient.aclAdd(AccessType.READ_WHITELIST, myGuid, GnsConstants.SERVICE_TYPE_FIELD, null); // Publish external IP (readable by everyone) InetSocketAddress externalIP = (InetSocketAddress) proxySocketAddres; gnsClient.fieldReplaceOrCreate(myGuid.getGuid(), GnsConstants.PROXY_EXTERNAL_IP_FIELD, new JSONArray().put(externalIP.getAddress().getHostAddress() + ":" + externalIP.getPort()), myGuid); gnsClient.aclAdd(AccessType.READ_WHITELIST, myGuid, GnsConstants.PROXY_EXTERNAL_IP_FIELD, null); // Update our location if geolocation resolution worked if (proxyInfo.getLatLong() != null) gnsClient.setLocation(proxyInfo.getLatLong().getLongitude(), proxyInfo.getLatLong().getLatitude(), myGuid); if (!isVerified) { logger.log(Level.WARNING, "This proxy has not been verified yet, it will stay in the unverified list until it gets added to the proxy group"); } gnsTimer = new GnsTimerKeepalive(gnsCredentials, myGuid, 1000); gnsTimer.start(); } /** * Publishes a new location for the proxy * * @param longitude new proxy longitude * @param latitude new proxy latitude * @throws Exception if a GNS error occurs */ public void publishNewProxyLocation(double longitude, double latitude) throws Exception { gnsCredentials.getGnsClient().setLocation(longitude, latitude, gnsCredentials.getGuidEntry()); } /** * Terminate this proxy and its GnsTimerKeepAlive thread */ public void killIt() { killed = true; gnsTimer.killIt(); } /** * @see java.lang.Thread#run() */ @Override public void run() { final GuidEntry guidEntry = gnsCredentials.getGuidEntry(); while (!killed) { try { Thread.sleep(1000); gnsCredentials.getGnsClient().fieldReplaceOrCreate(guidEntry.getGuid(), GnsConstants.PROXY_LOAD, ProxyLoadStatistics.serializeLoadInformation(), guidEntry); } catch (Exception e) { logger.log(Level.WARNING, " Error while publishing proxy load in the GNS" + e, e); } } } }