package com.openfarmanager.android.dialogs; import android.app.Dialog; import android.content.Context; import android.net.DhcpInfo; import android.net.wifi.WifiManager; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.Window; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.GridView; import android.widget.ProgressBar; import android.widget.TextView; import com.openfarmanager.android.App; import com.openfarmanager.android.R; import com.openfarmanager.android.controllers.FileSystemController; import com.openfarmanager.android.core.dbadapters.VendorDbAdapter; import com.openfarmanager.android.utils.HardwareUtils; import com.openfarmanager.android.utils.NetworkCalculator; import com.openfarmanager.android.utils.NetworkUtil; import com.openfarmanager.android.utils.NetworkUtils; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.Socket; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * author: Vlad Namashko */ public class NetworkScanDialog extends Dialog { private final static int[] DPORTS = {22, 135, 139, 445, 80}; private Handler mHandler; private View mDialogView; private EditText mIpAddress; private EditText mMask; private TextView mError; private Button mScanButton; private ProgressBar mProgressBar; private GridView mAvailableHosts; private String mMyIpAddress; private NetworkScanTask mNetworkScanTask; private ExecutorService mThreadPoolExecutor; private final LinkedList<String> mReachableHosts = new LinkedList<String>(); private boolean mIsScanning; public NetworkScanDialog(Context context, Handler handler) { super(context, R.style.Action_Dialog); mHandler = handler; } @Override public void dismiss() { super.dismiss(); if (mNetworkScanTask != null) { mNetworkScanTask.cancel(true); mNetworkScanTask = null; } if (mThreadPoolExecutor != null) { mThreadPoolExecutor.shutdownNow(); } } @Override public void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); mDialogView = View.inflate(App.sInstance.getApplicationContext(), R.layout.dialog_scan_local_network, null); mIpAddress = (EditText) mDialogView.findViewById(R.id.ip_address); mMask = (EditText) mDialogView.findViewById(R.id.ip_mask); mError = (TextView) mDialogView.findViewById(R.id.error); mScanButton = (Button) mDialogView.findViewById(R.id.scan); mProgressBar = (ProgressBar) mDialogView.findViewById(R.id.progress); mAvailableHosts = (GridView) mDialogView.findViewById(R.id.hosts); setContentView(mDialogView); findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dismiss(); mHandler.sendEmptyMessage(FileSystemController.SMB_SCAN_CANCELED); } }); mScanButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mIsScanning) { if (mThreadPoolExecutor != null) { mThreadPoolExecutor.shutdownNow(); } stopScanning(0); } else { mError.setVisibility(View.GONE); String stringIp = mIpAddress.getText().toString(); String stringMask = mMask.getText().toString(); if (!NetworkUtil.isValidIp(stringIp) || !NetworkUtil.isCorrectMask(stringMask)) { mError.setText(R.string.error_subnet_addresses_not_correct); mError.setVisibility(View.VISIBLE); return; } if (mNetworkScanTask != null) { mNetworkScanTask.cancel(true); } mNetworkScanTask = new NetworkScanTask(); mNetworkScanTask.execute(stringIp, stringMask); } } }); mAvailableHosts.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { stopScanning(0); dismiss(); String selectedIp = ((TextView) view).getText().toString().split("\n")[0]; mHandler.sendMessage(mHandler.obtainMessage(FileSystemController.SMB_IP_SELECTED, selectedIp)); } }); WifiManager manager = (WifiManager) App.sInstance.getSystemService(Context.WIFI_SERVICE); DhcpInfo dhcpInfo = manager.getDhcpInfo(); try { String stringIp = mMyIpAddress = NetworkUtil.ipIntToStringRevert(dhcpInfo.ipAddress); int maskCidr = 24; List<InterfaceAddress> interfaceAddresses = NetworkInterface.getByInetAddress( InetAddress.getByAddress(NetworkCalculator.ipIntToBytesReverted(dhcpInfo.ipAddress))).getInterfaceAddresses(); for (InterfaceAddress address : interfaceAddresses) { if (address.getAddress().getHostAddress().equals(stringIp)) { maskCidr = address.getNetworkPrefixLength(); } } String stringMask = NetworkCalculator.ipBytesToString(NetworkCalculator.cidrToQuad(maskCidr)); mIpAddress.setText(stringIp); mMask.setText(stringMask); } catch (Exception ignore) { ignore.printStackTrace(); } } private void stopScanning(int errorCode) { mIsScanning = false; mIpAddress.setEnabled(true); mMask.setEnabled(true); mScanButton.setText(R.string.btn_scan); mProgressBar.setVisibility(View.GONE); if (errorCode != 0) { mError.setText(R.string.error_subnet_addresses_not_correct); mError.setVisibility(View.VISIBLE); } } private class NetworkScanTask extends AsyncTask<String, Void, Void> { private int mErrorCode; private int mIpsInNetwork; private AtomicInteger mScannedIps = new AtomicInteger(); @Override protected void onPreExecute() { super.onPreExecute(); mIpAddress.setEnabled(false); mMask.setEnabled(false); mScannedIps.set(0); mProgressBar.setVisibility(View.VISIBLE); mScanButton.setText(R.string.btn_stop); mReachableHosts.clear(); mIsScanning = true; } @Override protected Void doInBackground(String ... strings) { String stringIp = strings[0]; String stringMask = strings[1]; String[] ips; try { ips = NetworkUtil.allStringAddressesInSubnet(stringIp, stringMask); mIpsInNetwork = ips.length; } catch (Exception e) { mErrorCode = R.string.error_subnet_addresses_not_correct; e.printStackTrace(); return null; } mThreadPoolExecutor = Executors.newFixedThreadPool(20); for (final String ip : ips) { if (ip.equals(mMyIpAddress)) { continue; } mThreadPoolExecutor.submit(new Runnable() { @Override public void run() { try { InetAddress address = InetAddress.getByName(ip); boolean isReachable = false; try { if (mIsScanning && address.isReachable(250) || NetworkUtils.ping(ip)) { isReachable = true; } else if (mIsScanning) { Socket s = new Socket(); for (int port : DPORTS) { try { s.bind(null); s.connect(new InetSocketAddress(ip, port), 250); isReachable = true; break; } catch (Exception ignored) { } finally { try { s.close(); } catch (Exception ignored) { } } } // last resort if (mIsScanning && !isReachable) { String mac = HardwareUtils.getHardwareAddress(ip); if (!HardwareUtils.NOMAC.equals(mac)) { isReachable = true; } } } } catch (Exception ignore) {} if (isReachable) { synchronized (mReachableHosts) { String ipLabel = ip; if (!ipLabel.equals(address.getHostName())) { ipLabel += "\n" + address.getHostName(); } String mac = HardwareUtils.getHardwareAddress(ip); ipLabel += "\n" + VendorDbAdapter.getVendor(Integer.parseInt(mac.substring(0, 8).replace(":", ""), 16)); mReachableHosts.add(ipLabel); mHandler.post(new Runnable() { @Override public void run() { if (mAvailableHosts.getVisibility() == View.GONE) { mAvailableHosts.setVisibility(View.VISIBLE); } mAvailableHosts.setAdapter(new ArrayAdapter<>(App.sInstance.getApplicationContext(), android.R.layout.simple_list_item_1, mReachableHosts.toArray(new String[mReachableHosts.size()]))); } }); } } mScannedIps.incrementAndGet(); NetworkScanTask.this.publishProgress(); } catch (IOException e) { e.printStackTrace(); } } }); } mThreadPoolExecutor.shutdown(); try { mThreadPoolExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); stopScanning(mErrorCode); } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); mProgressBar.setProgress(100 * mScannedIps.get() / mIpsInNetwork); } } }