package com.netifera.platform.net.sockets;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import com.netifera.platform.net.sockets.internal.Activator;
import com.netifera.platform.net.sockets.internal.SocketEngineService;
import com.netifera.platform.util.addresses.inet.InternetAddress;
import com.netifera.platform.util.locators.UDPSocketLocator;
public class UDPChannel extends AsynchronousSocketChannel {
public static UDPChannel open() throws IOException {
return Activator.getInstance().getSocketEngine().openUDP();
}
public UDPChannel(SocketEngineService engine, DatagramChannel channel) {
this.engine = engine;
this.channel = channel;
}
@Override
public DatagramChannel getWrappedChannel() {
return (DatagramChannel)channel;
}
private DatagramSocket getSocket() {
return getWrappedChannel().socket();
}
public void bind(UDPSocketLocator local) throws IOException {
((DatagramChannel)channel).socket().bind(new InetSocketAddress(local.getAddress().toInetAddress(), local.getPort()));
}
public void connect(UDPSocketLocator remote) throws IOException {
InetSocketAddress sockaddr = new InetSocketAddress(remote.getAddress().toInetAddress(), remote.getPort());
((DatagramChannel)channel).connect(sockaddr);
// workarounds for gnu classpath
DatagramSocket socket = getSocket();
if (!socket.isBound()) {
socket.bind(null);
}
if (!socket.isConnected()) {
socket.connect(sockaddr);
}
}
public UDPSocketLocator getRemoteAddress() {
try {
if (getSocket().isClosed() || !getSocket().isConnected()) {
return null;
}
InetSocketAddress address = (InetSocketAddress)getSocket().getRemoteSocketAddress();
if (address == null) {
return null;
}
return new UDPSocketLocator(InternetAddress.fromInetAddress(address.getAddress()), address.getPort());
} catch (Exception e) { // FIXME or document
// if an exception occurs trying to get the remote address, the socket was not connected
return null;
}
}
public UDPSocketLocator getLocalAddress() {
try {
if (getSocket().isClosed() || !getSocket().isBound()) {
return null;
}
InetSocketAddress address = (InetSocketAddress)getSocket().getLocalSocketAddress();
if (address == null) {
return null;
}
return new UDPSocketLocator(InternetAddress.fromInetAddress(address.getAddress()), address.getPort());
} catch (Exception e) { // FIXME or document
// if an exception occurs trying to get the local address, the socket was not bound
return null;
}
}
public Future<UDPSocketLocator> receive(ByteBuffer dst) {
return receive(dst, 30, TimeUnit.SECONDS, null, null);
}
public <A> Future<UDPSocketLocator> receive(ByteBuffer dst,
long timeout, TimeUnit unit,
A attachment, CompletionHandler<UDPSocketLocator, ? super A> handler) {
return engine.asynchronousReceive(this, dst, timeout, unit, attachment, handler);
}
public Future<Integer> send(ByteBuffer src, UDPSocketLocator target) {
return send(src, target, 30, TimeUnit.SECONDS, null, null);
}
public <A> Future<Integer> send(ByteBuffer src, UDPSocketLocator target,
long timeout, TimeUnit unit,
A attachment, CompletionHandler<Integer, ? super A> handler) {
return engine.asynchronousSend(this, src, target, timeout, unit, attachment, handler);
}
@Override
public String toString() {
UDPSocketLocator locator;
StringBuilder sb = new StringBuilder(64);
sb.append("udp/[");
if (getSocket().isClosed()) {
sb.append("closed");
} else {
locator = getLocalAddress();
if (locator == null) {
sb.append("not bound");
} else {
sb.append(locator.getAddress().toString());
sb.append(':');
sb.append(locator.getPort());
}
sb.append(" <> ");
locator = getRemoteAddress();
if (locator == null) {
sb.append("not connected");
} else {
sb.append(locator.getAddress().toString());
sb.append(':');
sb.append(locator.getPort());
}
}
sb.append(']');
return sb.toString();
}
}