jnr.unixsocket.UnixDatagramSocket Maven / Gradle / Ivy
/*
* Copyright (C) 2016 Fritz Elfert
*
* This file is part of the JNR project.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package jnr.unixsocket;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.channels.DatagramChannel;
import java.nio.channels.UnsupportedAddressTypeException;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* A SOCK_DGRAM variant of an AF_UNIX socket.
* This specializaton of DatagramSocket delegates
* most of it's funtionality to the corresponding
* UnixDatagramChannel.
*/
public class UnixDatagramSocket extends DatagramSocket {
private final UnixDatagramChannel chan;
private final AtomicBoolean closed = new AtomicBoolean(false);
/**
* Constructs a new instance.
* @param channel The channel to use.
* @throws SocketException if the socket could not be created.
*/
UnixDatagramSocket(final UnixDatagramChannel channel) throws SocketException {
chan = channel;
}
/**
* Constructs a new unbound instance.
* @throws SocketException if the socket could not be created.
*/
public UnixDatagramSocket() throws SocketException {
chan = null;
}
/**
* Binds this UnixDatagramSocket to a specific AF_UNIX address.
*
* If the address is {@code null}, then on Linux, an autobind will be performed,
* which will bind this socket in Linux' abstract namespace on a unique path, chosen by
* the system. On all other platforms, A temporary path in the regular filesystem will be chosen.
*
* @param local The {@link UnixSocketAddress} to bind to.
* @throws SocketException if any error happens during the bind, or if the
* socket is already bound.
* @throws UnsupportedAddressTypeException if addr is a SocketAddress subclass
* not supported by this socket.
*/
@Override
public void bind(final SocketAddress local) throws SocketException {
if (null != chan) {
if (isClosed()) {
throw new SocketException("Socket is closed");
}
if (isBound()) {
throw new SocketException("already bound");
}
try {
chan.bind(local);
} catch (IOException e) {
throw (SocketException)new SocketException().initCause(e);
}
}
}
@Override
public synchronized void disconnect() {
if (isClosed()) {
return;
}
if (null != chan) {
try {
chan.disconnect();
} catch (IOException e) {
ignore();
}
}
}
@Override
public synchronized void close() {
if (null != chan && closed.compareAndSet(false, true)) {
try {
chan.close();
} catch (IOException e) {
ignore();
}
}
}
@Override
public void connect(SocketAddress addr) throws SocketException {
try {
chan.connect(addr);
} catch (IOException e) {
throw (SocketException)new SocketException().initCause(e);
}
}
@Override
public void connect(InetAddress addr, int port) {
throw new UnsupportedOperationException("connect(InetAddress, int) is not supported");
}
@Override
public DatagramChannel getChannel() {
return chan;
}
/**
* Returns the address to which this socket is connected (NOT implemented).
* Since AF_UNIX sockets can not have an InetAddress, this returns always {@code null}.
* Use {@link #getRemoteSocketAddress} instead, which always returns a {@link UnixSocketAddress}.
* @return {@code null} always.
*/
@Override
public InetAddress getInetAddress() {
return null;
}
/**
* Returns the address of the endpoint this socket is bound to.
*
* @return a {@code SocketAddress} representing the local endpoint of this
* socket, or {@code null} if it is closed or not bound.
* A non-null return value is always of type {@link UnixSocketAddress}
* @see #bind(SocketAddress)
*/
@Override
public SocketAddress getLocalSocketAddress() {
if (isClosed()) {
return null;
}
if (null == chan) {
return null;
}
return chan.getLocalSocketAddress();
}
/**
* Returns the address of the endpoint this socket is connected to, or
* {@code null} if it is unconnected.
*
* @return a {@code SocketAddress} representing the remote
* endpoint of this socket, or {@code null} if it is
* not connected.
* A non-null return value is always of type {@link UnixSocketAddress}
*/
@Override
public SocketAddress getRemoteSocketAddress() {
if (!isConnected()) {
return null;
}
return chan.getRemoteSocketAddress();
}
@Override
public boolean isBound() {
if (null == chan) {
return false;
}
return chan.isBound();
}
@Override
public boolean isClosed() {
if (null == chan) {
return false;
}
return closed.get();
}
@Override
public boolean isConnected() {
if (null == chan) {
return false;
}
return chan.isConnected();
}
/**
* Retrieves the credentials for this UNIX socket. Clients calling this
* method will receive the server's credentials, and servers will receive
* the client's credentials. User ID, group ID, and PID are supplied.
*
* See man unix 7; SCM_CREDENTIALS
*
* @throws UnsupportedOperationException if the underlying socket library
* doesn't support the SO_PEERCRED option
* @throws SocketException if fetching the socket option failed.
*
* @return the credentials of the remote; null if not connected
*/
public final Credentials getCredentials() throws SocketException {
if (!chan.isConnected()) {
return null;
}
try {
return chan.getOption(UnixSocketOptions.SO_PEERCRED);
} catch (IOException e) {
throw (SocketException)new SocketException().initCause(e);
}
}
@Override
public int getReceiveBufferSize() throws SocketException {
try {
return chan.getOption(UnixSocketOptions.SO_RCVBUF).intValue();
} catch (IOException e) {
throw (SocketException)new SocketException().initCause(e);
}
}
@Override
public int getSendBufferSize() throws SocketException {
try {
return chan.getOption(UnixSocketOptions.SO_SNDBUF).intValue();
} catch (IOException e) {
throw (SocketException)new SocketException().initCause(e);
}
}
@Override
public int getSoTimeout() throws SocketException {
try {
return chan.getOption(UnixSocketOptions.SO_RCVTIMEO).intValue();
} catch (IOException e) {
throw (SocketException)new SocketException().initCause(e);
}
}
@Override
public void setReceiveBufferSize(int size) throws SocketException {
try {
chan.setOption(UnixSocketOptions.SO_RCVBUF, Integer.valueOf(size));
} catch (IOException e) {
throw (SocketException)new SocketException().initCause(e);
}
}
@Override
public void setSendBufferSize(int size) throws SocketException {
try {
chan.setOption(UnixSocketOptions.SO_SNDBUF, Integer.valueOf(size));
} catch (IOException e) {
throw (SocketException)new SocketException().initCause(e);
}
}
@Override
public void setSoTimeout(int timeout) throws SocketException {
try {
chan.setOption(UnixSocketOptions.SO_RCVTIMEO, Integer.valueOf(timeout));
} catch (IOException e) {
throw (SocketException)new SocketException().initCause(e);
}
}
/**
* Sends a datagram packet from this socket (NOT implemented).
* Unfortunately, {@link java.net.DatagramPacket} is final and can not deal
* with AF_UNIX addresses. Therefore, this functionality was omitted.
* @see java.net.DatagramPacket
* @see java.net.DatagramSocket#send
* @throws UnsupportedOperationException always.
*/
@Override
public void send(DatagramPacket p) throws IOException {
throw new UnsupportedOperationException("sending DatagramPackets is not supported");
}
/**
* Receives a datagram packet from this socket (NOT implemented).
* Unfortunately, {@link java.net.DatagramPacket} is final and can not deal
* with AF_UNIX addresses. Therefore, this functionality was omitted.
* @see java.net.DatagramPacket
* @see java.net.DatagramSocket#receive
* @throws UnsupportedOperationException always.
*/
@Override
public synchronized void receive(DatagramPacket p) throws IOException {
throw new UnsupportedOperationException("receiving DatagramPackets is not supported");
}
private void ignore() {
}
}