/*
* This file is part of Arduino.
*
* Arduino 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 2 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
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.packages.discoverers;
import java.io.IOException;
import java.net.InetAddress;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import javax.jmdns.JmDNS;
import javax.jmdns.NetworkTopologyDiscovery;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import javax.jmdns.impl.DNSTaskStarter;
public class NetworkDiscovery implements ServiceListener {
private class bonour {
public String address;
public String name;
public String board;
public String distroversion;
public String port;
public boolean ssh_upload;
public boolean tcp_check;
public boolean auth_upload;
public bonour() {
this.address = ""; //$NON-NLS-1$
this.name = ""; //$NON-NLS-1$
this.board = ""; //$NON-NLS-1$
this.distroversion = ""; //$NON-NLS-1$
this.port = ""; //$NON-NLS-1$
this.ssh_upload = true;
this.tcp_check = true;
this.auth_upload = false;
}
public String getLabel() {
return this.name + " at " + this.address + " (" + this.board + ")" + this.distroversion + " " + this.port; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
}
private static Timer timer = new Timer("Network discovery timer"); //$NON-NLS-1$ ;
private static final HashSet<bonour> myComPorts = new HashSet<>(); // well
// not
// really
// com
// ports
// but
// we treat them like com ports
private final static Map<InetAddress, JmDNS> mappedJmDNSs = new Hashtable<>();
private static NetworkDiscovery me = null;
private NetworkDiscovery() {
DNSTaskStarter.Factory.setClassDelegate(new ArduinoDNSTaskStarter());
}
public static String[] getList() {
String[] ret = new String[myComPorts.size()];
int curPort = 0;
Iterator<bonour> iterator = myComPorts.iterator();
while (iterator.hasNext()) {
bonour board = iterator.next();
ret[curPort++] = board.getLabel();
}
return ret;
}
public static void start() {
if (me == null) {
me = new NetworkDiscovery();
}
new NetworkChecker(NetworkTopologyDiscovery.Factory.getInstance()).start(timer);
}
public static void stop() {
timer.purge();
// we don't close each JmDNS instance as it's too slow
}
@SuppressWarnings("resource")
@Override
public void serviceAdded(ServiceEvent serviceEvent) {
String type = serviceEvent.getType();
String name = serviceEvent.getName();
JmDNS dns = serviceEvent.getDNS();
dns.requestServiceInfo(type, name);
ServiceInfo serviceInfo = dns.getServiceInfo(type, name);
if (serviceInfo != null) {
dns.requestServiceInfo(type, name);
}
}
@Override
public void serviceRemoved(ServiceEvent serviceEvent) {
String name = serviceEvent.getName();
synchronized (this) {
removeBoardswithSameName(name);
}
}
@Override
public void serviceResolved(ServiceEvent serviceEvent) {
ServiceInfo info = serviceEvent.getInfo();
for (InetAddress inetAddress : info.getInet4Addresses()) {
bonour newItem = new bonour();
newItem.address = inetAddress.getHostAddress();
newItem.name = serviceEvent.getName();
if (info.hasData()) {
newItem.board = info.getPropertyString("board"); //$NON-NLS-1$
newItem.distroversion = info.getPropertyString("distro_version"); //$NON-NLS-1$
newItem.name = info.getServer();
String useSSH = info.getPropertyString("ssh_upload"); //$NON-NLS-1$
String checkTCP = info.getPropertyString("tcp_check"); //$NON-NLS-1$
String useAuth = info.getPropertyString("auth_upload"); //$NON-NLS-1$
if (useSSH != null && useSSH.contentEquals("no")) //$NON-NLS-1$
newItem.ssh_upload = false;
if (checkTCP != null && checkTCP.contentEquals("no")) //$NON-NLS-1$
newItem.tcp_check = false;
if (useAuth != null && useAuth.contentEquals("yes")) //$NON-NLS-1$
newItem.auth_upload = true;
}
while (newItem.name.endsWith(".")) { //$NON-NLS-1$
newItem.name = newItem.name.substring(0, newItem.name.length() - 1);
}
newItem.port = Integer.toString(info.getPort());
synchronized (this) {
removeBoardswithSameAdress(newItem);
myComPorts.add(newItem);
}
}
}
private static void removeBoardswithSameAdress(bonour newBoard) {
Iterator<bonour> iterator = myComPorts.iterator();
while (iterator.hasNext()) {
bonour board = iterator.next();
if (newBoard.address.equals(board.address)) {
iterator.remove();
}
}
}
private static void removeBoardswithSameName(String name) {
Iterator<bonour> iterator = myComPorts.iterator();
while (iterator.hasNext()) {
bonour board = iterator.next();
if (name.equals(board.name)) {
iterator.remove();
}
}
}
@SuppressWarnings("resource")
public static void inetAddressAdded(InetAddress address) {
if (mappedJmDNSs.containsKey(address)) {
return;
}
try {
JmDNS jmDNS = JmDNS.create(address);
jmDNS.addServiceListener("_arduino._tcp.local.", me); //$NON-NLS-1$
mappedJmDNSs.put(address, jmDNS);
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("resource")
public static void inetAddressRemoved(InetAddress address) {
JmDNS jmDNS = mappedJmDNSs.remove(address);
if (jmDNS != null) {
try {
jmDNS.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static bonour getBoardByName(String name) {
Iterator<bonour> iterator = myComPorts.iterator();
while (iterator.hasNext()) {
bonour board = iterator.next();
if (name.equals(board.name)) {
return board;
}
}
return null;
}
public static String getAddress(String name) {
bonour board = getBoardByName(name);
if (board == null)
return null;
return board.address;
}
public static String getPort(String name) {
bonour board = getBoardByName(name);
if (board == null)
return new String();
return board.port;
}
public static boolean hasAuth(String name) {
bonour board = getBoardByName(name);
if (board == null)
return false;
return board.auth_upload;
}
public static boolean isSSH(String name) {
bonour board = getBoardByName(name);
if (board == null)
return false;
return board.ssh_upload;
}
public static boolean needstcpCheck(String name) {
bonour board = getBoardByName(name);
if (board == null)
return false;
return board.tcp_check;
}
}