//
// anyRemote android client
// a bluetooth/wi-fi remote control for Linux.
//
// Copyright (C) 2011-2016 Mikhail Fedotov <anyremote@mail.ru>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
package anyremote.client.android.util;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import anyremote.client.android.anyRemote;
import anyremote.client.android.util.IScanner;
import anyremote.client.android.util.ScanMessage;
//
// IP search
//
public class IPScanner implements IScanner {
static final String DEFAULT_IP_PORT = "5197";
static final int MAX_PING_TASKS = 16;
static final int MAX_SUBNET_ADDR = 254;
Handler searchFormHandler;
volatile Integer asyncNum = new Integer(-1);
ArrayList<String> hosts = new ArrayList<String>();
PingTask ipSearchTask = null;
public IPScanner(Handler hdl) {
searchFormHandler = hdl;
}
public void startScan() {
if (ipSearchTask != null) {
anyRemote._log("IPScanner", "startScan: already scanning");
return;
}
String ip = anyRemote.getLocalIpAddress();
if (ip == null) {
Message msg = searchFormHandler.obtainMessage(SCAN_FAILED);
msg.sendToTarget();
return;
}
anyRemote._log("IPScanner", "startScan "+ip);
scanSubNet(ip.substring(0,ip.lastIndexOf('.')+1));
//scanSubNet("172.16.32.");
}
public void stopScan () {
synchronized (asyncNum) {
asyncNum = -1;
}
if (ipSearchTask != null) {
anyRemote._log("IPScanner", "stopScan");
ipSearchTask.cancel(true);
}
}
private void scanSubNet(String subnet){
anyRemote._log("IPScanner", "scanSubNet "+subnet);
hosts.clear();
asyncNum = 0;
Message msg = searchFormHandler.obtainMessage(SCAN_STARTED);
msg.sendToTarget();
ipSearchTask = new PingTask();
ipSearchTask.execute(subnet);
}
class PingTask extends AsyncTask<String, Integer, Void> {
@Override
protected Void doInBackground(String... params) {
for (int i=1; i<MAX_SUBNET_ADDR; i++){
anyRemote._log("IPScanner", "PingTask.doInBackground Trying: " + params[0] + String.valueOf(i));
synchronized (asyncNum) {
if (asyncNum < 0) {
// cancel search
anyRemote._log("IPScanner", "PingTask.doInBackground Search cancelled");
i = 255;
} else {
asyncNum++;
}
}
if (i < MAX_SUBNET_ADDR) {
PingHostTask mTask = new PingHostTask();
int apiVersion = Integer.valueOf(android.os.Build.VERSION.SDK);
if (apiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { // API 11
mTask.executeOnExecutor(THREAD_POOL_EXECUTOR, params[0] + String.valueOf(i));
} else {
mTask.execute(params[0] + String.valueOf(i));
}
while (asyncNum > MAX_PING_TASKS) {
anyRemote._log("IPScanner", "PingTask.doInBackground Waiting to run : " + asyncNum);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
}
}
publishProgress(i);
}
while (asyncNum > 0) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
}
return null;
}
@Override
protected void onProgressUpdate(Integer... progress) {
anyRemote._log("IPScanner", "PingTask.onProgressUpdate "+progress[0]);
// dynamically add discovered hosts
synchronized (hosts) {
for (int h = 0;h<hosts.size();h++) {
ScanMessage sm = new ScanMessage();
sm.name = "socket://"+hosts.get(h);
sm.address = "socket://"+hosts.get(h) + ":" + DEFAULT_IP_PORT;
Message msg = searchFormHandler.obtainMessage(SCAN_FOUND, sm);
msg.sendToTarget();
}
hosts.clear();
}
synchronized (asyncNum) {
if (asyncNum > 0) {
anyRemote._log("IPScanner", "PingTask.onProgressUpdate " + asyncNum);
ScanMessage sm = new ScanMessage();
sm.name = progress[0]+"/255";
Message msg = searchFormHandler.obtainMessage(SCAN_PROGRESS, sm);
msg.sendToTarget();
}
}
}
@Override
protected void onPostExecute(Void unused) {
Message msg = searchFormHandler.obtainMessage(SCAN_FINISHED);
msg.sendToTarget();
asyncNum = -1;
ipSearchTask = null;
}
@Override
protected void onCancelled() {
Message msg = searchFormHandler.obtainMessage(SCAN_FINISHED);
msg.sendToTarget();
asyncNum = -1;
ipSearchTask = null;
}
}
class PingHostTask extends AsyncTask<String, Void, Void> {
/*PipedOutputStream mPOut;
PipedInputStream mPIn;
LineNumberReader mReader;
Process mProcess;*/
/*
@Override
protected void onPreExecute() {
/*mPOut = new PipedOutputStream();
try {
mPIn = new PipedInputStream(mPOut);
mReader = new LineNumberReader(new InputStreamReader(mPIn));
} catch (IOException e) {
cancel(true);
}
}*/
/*public void stop() {
Process p = mProcess;
if (p != null) {
p.destroy();
}
cancel(true);
}*/
@Override
protected Void doInBackground(String... params) {
anyRemote._log("IPScanner", "PingHostTask.doInBackground START");
try {
InetAddress inetAddress = InetAddress.getByName(params[0]);
anyRemote._log("IPScanner", "PingHostTask.doInBackground # " + inetAddress);
if (inetAddress.isReachable(1000)) {
synchronized (asyncNum) {
if (asyncNum < 0) {
return null;
}
}
anyRemote._log("IPScanner", "PingHostTask.doInBackground reachable # " + params[0]);
String host = inetAddress.getHostName();
synchronized (hosts) {
hosts.add(host);
}
synchronized (asyncNum) {
asyncNum--;
}
return null;
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
/*try {
log("start # " + params[0]);
String cmd = "/system/bin/ping -q -n -w 1 -c 1 " + params[0];
Process mProcess = new ProcessBuilder()
.command(cmd)
.redirectErrorStream(true).start();
log("started # " + params[0]);
try {
InputStream in = mProcess.getInputStream();
OutputStream out = mProcess.getOutputStream();
byte[] buffer = new byte[1024];
int count;
log("AA " + params[0]);
// in -> buffer -> mPOut -> mReader -> 1 line of ping
// information to parse
while ((count = in.read(buffer)) != -1) {
mPOut.write(buffer, 0, count);
// publishProgress();
}
log("done for # " + params[0] + " " + buffer);
out.close();
in.close();
mPOut.close();
mPIn.close();
} finally {
mProcess.destroy();
mProcess = null;
}
} catch (IOException e) {
log("IOException for # " + params[0] + " " + e.getMessage());
}*/
synchronized (asyncNum) {
asyncNum--;
}
anyRemote._log("IPScanner", "PingHostTask.doInBackground Down # " + params[0]);
return null;
}
/*
@Override
protected void onProgressUpdate(Void... values) {
try {
// Is a line ready to read from the "ping" command?
while (mReader.ready()) {
// This just displays the output, you should typically parse it I guess.
log("Got "+mReader.readLine());
}
} catch (IOException t) {
}
}*/
}
}