Skip to content

Commit

Permalink
added ServerSockets and address binding
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukas Vacek committed Feb 9, 2015
1 parent e27921c commit ab2224d
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 45 deletions.
1 change: 1 addition & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/app.iml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
Expand Down
157 changes: 114 additions & 43 deletions app/src/main/java/github/luv/mockgeofix/MockLocationService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,26 @@
import android.preference.PreferenceManager;
import android.util.Log;

import java.io.IOException;
import java.net.BindException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Vector;

public class MockLocationService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener {
String TAG = "MockLocationService";

protected MockLocationThread mThread = null;
SharedPreferences pref = null;
protected SharedPreferences pref = null;

public final static String STARTED = "STARTED";
public final static String STOPPED = "STOPPED";
public final static String ERROR = "ERROR";

protected int port = 5554;

protected String lastErr;

public class Binder extends android.os.Binder {
Expand All @@ -36,7 +44,6 @@ public void onCreate() {
pref = PreferenceManager.getDefaultSharedPreferences(
getApplicationContext());

updatePort();
pref.registerOnSharedPreferenceChangeListener(this);
}

Expand All @@ -52,27 +59,11 @@ public IBinder onBind(Intent intent) {

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals("listen_port")) {
updatePort();
}
}

protected synchronized void updatePort() {
if (pref == null) {return;}
try {
port = Integer.parseInt(pref.getString("listen_port", ""));
if (port < 0 || port > 65535) {
throw new NumberFormatException("Invalid port number.");
if (key.equals("listen_port") || key.equals("listen_ip")) {
if (mThread != null) {
mThread.rebind();
mThread.interrupt();
}
} catch (NumberFormatException ex) {
String portStr = Integer.toString(port);
Log.e(TAG, String.format("Invalid port number %s. Defaulting to 5554", portStr));
errorHasOccurred(String.format("Invalid port number %s. Defaulting to 5554.",
portStr));
port = 5554;
}
if (mThread != null) {
mThread.updatePort();
}
}

Expand All @@ -85,9 +76,8 @@ public boolean isRunning() {

public void start() {
if (mThread == null) {
mThread = new MockLocationThread(getApplicationContext(), this);
mThread = new MockLocationThread(getApplicationContext(), this );
mThread.start();
broadcast(STARTED);
}
}

Expand All @@ -113,6 +103,46 @@ protected void errorHasOccurred(String err) {
lastErr = err;
broadcast(ERROR);
}
protected Vector<SocketAddress> getBindAddresses() {
Vector<SocketAddress> ret = new Vector<>();

/* retrieve port settings from preferences */
String portStr = pref.getString("listen_port", "");
int port;
try {
port = Integer.parseInt(portStr);
if (port < 0 || port > 65535) {
throw new NumberFormatException("Invalid port number.");
}
} catch (NumberFormatException ex) {
Log.e(TAG, String.format("Invalid port number %s. Defaulting to 5554", portStr));
errorHasOccurred(String.format("Invalid port number %s. Defaulting to 5554.",
portStr));
port = 5554;
}

/* retrieve interfaces to listen on, set port and return a vector of SocketAddresses */
String ifaceName = pref.getString("listen_ip","ALL");

if (ifaceName.equals("ALL")) {
ret.add( new InetSocketAddress(port) );
return ret;
}

try {
NetworkInterface iface = NetworkInterface.getByName(ifaceName);
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
ret.add(new InetSocketAddress(address, port));
}
} catch(SocketException ex) {
Log.e(TAG, "SocketException thrown (getBindAddress)");
} catch (NullPointerException ex) {
Log.e(TAG, "NullPointerException thrown (getBindAddress)");
}
return ret;
}

/* helper methods */
protected void broadcast(String msg) {
Expand All @@ -123,41 +153,82 @@ protected void broadcast(String msg) {
}

class MockLocationThread extends Thread {
Context mContext;
MockLocationService mService;
String TAG = "MockLocationService.Thread";

protected Context mContext;
protected MockLocationService mService;
protected Vector<SocketAddress> mBindAddresses;

public MockLocationThread(Context context, MockLocationService service) {
mContext = context;
mService = service;
}
private boolean stop = false;
private boolean mStop = false;
private boolean mRebind = false;

public void kill() {
stop = true;
public void rebind() {
mRebind = true;
}

public void updatePort() {
// bind to the new port
public void kill() {
mStop = true;
}

@SuppressWarnings({"InfiniteLoopStatement", "EmptyCatchBlock"})
@Override
public void run() {
super.run();
Vector<ServerSocket> ssockets = new Vector<>();
try {
// bind to the tcp port and only on success call:
//mService.errorHasOccurred("TEST ERR");
mService.threadHasStartedSuccessfully();
while (!stop) {
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(mContext);
String port = pref.getString("listen_port", "");
Log.d(String.format("PORT %s", port), "running");
while (!mStop) {
mBindAddresses = mService.getBindAddresses();
for (SocketAddress address : mBindAddresses) {
ServerSocket ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(address);
ssockets.add(ss);
}
mService.threadHasStartedSuccessfully();
try {
Thread.sleep(1000, 0);
} catch (InterruptedException ex) {
while (!mStop && !mRebind) {
Log.d(TAG, "running");
try {
Thread.sleep(1000, 0);
} catch (InterruptedException ex) {
}
}
} finally {
for (ServerSocket ss : ssockets) {
try {
if (!ss.isClosed()) { ss.close(); }
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
ssockets.clear();
}
}
} catch (SocketException e) {
Log.e(TAG, e.toString() );
// most common errors
if (e.getClass() == BindException.class && e.getMessage().contains("EADDRINUSE")) {
mService.errorHasOccurred(mContext.getString(R.string.err_address_already_in_use));
} else if (e.getClass() == BindException.class && e.getMessage().contains("EACCES") ) {
mService.errorHasOccurred(mContext.getString(R.string.err_socket_permission_denied));
} else {
mService.errorHasOccurred(e.toString());
}
} catch (IOException e) {
Log.e(TAG, e.toString() );
mService.errorHasOccurred(e.toString());
} finally {
for (ServerSocket ss : ssockets) {
try {
if (!ss.isClosed()) { ss.close(); }
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
mService.threadHasStopped();
}
}
Expand Down
9 changes: 7 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@
\n\nPassword is provided using the following telnet command:
\nPASSWORD &lt;password&gt;
\nExample: PASSWORD blue-taco</b></string>
<string name="hello_blank_fragment">Hello blank fragment</string>

<string name="invalid_port">That\'s an invalid port number. Port must be a number between 0 and 65535.</string>


<!-- main activity -->
<string name="status">status: </string>
Expand All @@ -39,4 +38,10 @@
<string name="start">start</string>
<string name="listens_on">Listens on: </string>

<!-- errors -->
<string name="invalid_port">That\'s an invalid port number. Port must be a number between 0 and 65535.</string>
<string name="err_address_already_in_use">Binding error. Address/port already in use.</string>
<string name="err_socket_permission_denied">Binding error. Permission denied. (You should use port number >=1024.)</string>


</resources>

0 comments on commit ab2224d

Please sign in to comment.