/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.lightwaverf.internal; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Enumeration; import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import org.openhab.binding.lightwaverf.internal.message.LightwaveRfStringMessageListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Class that listens to the LAN for commands either sent to the LightwaveRF * Wifi link or replies from the lightwaveRF Wifi link. Upon receiving a valid * command this will notify all listeners of the message received. * * @author Neil Renaud * @since 1.7.0 */ public class LightwaveRFReceiverThread implements Runnable { private static final Logger logger = LoggerFactory.getLogger(LightwaveRFReceiverThread.class); private final CopyOnWriteArrayList<LightwaveRfStringMessageListener> listeners = new CopyOnWriteArrayList<LightwaveRfStringMessageListener>(); private final DatagramSocket receiveSocket; private final Set<InetAddress> localIps; private boolean running = true; public LightwaveRFReceiverThread(DatagramSocket socket) throws SocketException, UnknownHostException { this.receiveSocket = socket; localIps = getIpAddresses(); } /** * Gets a list of INetAddresses for this server. Allowing us to filter out * broadcast packets we receive that we originally sent * * @return */ private Set<InetAddress> getIpAddresses() { Set<InetAddress> ips = new LinkedHashSet<InetAddress>(); try { Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface iface = interfaces.nextElement(); // filters out 127.0.0.1 and inactive interfaces if (iface.isLoopback() || !iface.isUp()) { continue; } Enumeration<InetAddress> addresses = iface.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); ips.add(addr); } } } catch (SocketException e) { throw new RuntimeException(e); } return ips; } /** * Stop the LightwaveRFSender Will close the socket wait for the thread to * exit and null the socket */ public synchronized void stopRunning() { running = false; } /** * Run method, this will listen to the socket and receive messages. The * blocking is stopped when the socket is closed. */ @Override public void run() { String message = null; try { message = receiveUDP(); if (message != null) { notifyMessage(message); } } catch (IOException e) { if (!(running == false && receiveSocket.isClosed())) { // If running isn't false and the socket isn't closed log the // error logger.error("Error receiving message", e); } } } /** * Receive the next UDP packet on the socket * * @return * @throws IOException */ private String receiveUDP() throws IOException { String receivedMessage = ""; byte[] receiveData = new byte[1024]; DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); receiveSocket.receive(receivePacket); receivedMessage = new String(receivePacket.getData(), 0, receivePacket.getLength()); logger.debug("Message received from: " + receivePacket.getAddress() + " message:" + receivedMessage); if (localIps.contains(receivePacket.getAddress())) { logger.debug("Own Message received and will be discarded: {}", receivedMessage); return null; } return receivedMessage; } /** * Add listener to be notified of messages received on the socket * * @param listener */ public void addListener(LightwaveRfStringMessageListener listener) { listeners.add(listener); } /** * Remove listener to stop being notified of messages being received on the * socket. * * @param listener */ public void removeListener(LightwaveRfStringMessageListener listener) { listeners.remove(listener); } /** * Notify all listeners of a message * * @param message */ private void notifyMessage(String message) { for (LightwaveRfStringMessageListener messageListener : listeners) { try { messageListener.messageReceived(message); } catch (Exception e) { logger.error("Unexpected error when notifying listeners of this message[" + message + "] message hasn't been processed", e); } } } }