/**
* 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.anel.internal;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Arrays;
/**
* Connector for UDP communication.
*
* @since 1.6.0
* @author paphko
*/
class AnelUDPConnector {
/** Buffer for incoming UDP packages. */
private static final int MAX_PACKET_SIZE = 512;
/** Socket for receiving UDP packages. */
private DatagramSocket socket = null;
/** The device IP this connector is listening to / sends to. */
final String host;
/** The port this connector is listening to. */
final int receivePort;
/** The port this connector is sending to. */
final int sendPort;
/**
* Create a new connector to an Anel device via the given host and UDP
* ports.
*
* @param host
* The IP address / network name of the device.
* @param udpReceivePort
* The UDP port to listen for packages.
* @param udpSendPort
* The UDP port to send packages.
*/
AnelUDPConnector(String host, int udpReceivePort, int udpSendPort) {
if (udpReceivePort <= 0) {
throw new IllegalArgumentException("Invalid udpReceivePort: " + udpReceivePort);
}
if (udpSendPort <= 0) {
throw new IllegalArgumentException("Invalid udpSendPort: " + udpSendPort);
}
if (host == null || host.isEmpty()) {
throw new IllegalArgumentException("Missing ipAddress.");
}
this.host = host;
this.receivePort = udpReceivePort;
this.sendPort = udpSendPort;
}
/**
* Initialize socket connection to the UDP receive port.
*
* @throws SocketException
*/
void connect() throws SocketException {
if (socket == null) {
socket = new DatagramSocket(receivePort);
}
}
/**
* Close the socket connection.
*/
void disconnect() {
if (socket != null) {
socket.close();
socket = null;
}
}
/**
* This is a blocking call for receiving data from the specific UDP port.
*
* @return The received data.
* @throws Exception
* If an exception occurred.
*/
byte[] receiveDatagram() throws Exception {
try {
if (socket == null) {
socket = new DatagramSocket(receivePort);
}
// Create a packet
final DatagramPacket packet = new DatagramPacket(new byte[MAX_PACKET_SIZE], MAX_PACKET_SIZE);
// Receive a packet (blocking)
socket.receive(packet);
return Arrays.copyOfRange(packet.getData(), 0, packet.getLength() - 1);
} catch (SocketException e) {
if (e.getMessage() != null && e.getMessage().equals("socket closed")) {
return null; // happens during shutdown
}
throw new Exception(e);
} catch (IOException e) {
throw new Exception(e);
}
}
/**
* Send data to the specified address via the specified UDP port.
*
* @param data
* The data to send.
* @throws Exception
* If an exception occurred.
*/
void sendDatagram(byte[] data) throws Exception {
if (data == null || data.length == 0) {
throw new IllegalArgumentException("data must not be null or empty");
}
try {
final InetAddress ipAddress = InetAddress.getByName(host);
final DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress, sendPort);
final DatagramSocket socket = new DatagramSocket();
socket.send(packet);
socket.close();
} catch (SocketException e) {
throw new Exception(e);
} catch (UnknownHostException e) {
throw new Exception("Could not resolve host: " + host, e);
} catch (IOException e) {
throw new Exception(e);
}
}
}