FileDocCategorySizeDatePackage
PlainDatagramSocketImpl.javaAPI DocAndroid 1.5 API15451Wed May 06 22:41:04 BST 2009org.apache.harmony.luni.net

PlainDatagramSocketImpl

public class PlainDatagramSocketImpl extends DatagramSocketImpl
The default, concrete instance of datagram sockets. This class does not support security checks. Alternative types of DatagramSocketImpl's may be used by setting the impl.prefix system property.

Fields Summary
static final int
MULTICAST_IF
static final int
MULTICAST_TTL
static final int
TCP_NODELAY
static final int
FLAG_SHUTDOWN
private static final int
SO_BROADCAST
static final int
IP_MULTICAST_ADD
static final int
IP_MULTICAST_DROP
static final int
IP_MULTICAST_TTL
static final int
REUSEADDR_AND_REUSEPORT
for datagram and multicast sockets we have to set REUSEADDR and REUSEPORT when REUSEADDR is set for other types of sockets we need to just set REUSEADDR therefore we have this other option which sets both if supported by the platform. this cannot be in SOCKET_OPTIONS because since it is a public interface it ends up being public even if it is not declared public
private boolean
bindToDevice
private byte[]
ipaddress
private int
ttl
private org.apache.harmony.luni.platform.INetworkSystem
netImpl
private volatile boolean
isNativeConnected
public int
receiveTimeout
public boolean
streaming
public boolean
shutdownInput
private InetAddress
connectedAddress
used to keep address to which the socket was connected to at the native level
private int
connectedPort
private int
trafficClass
used to store the trafficClass value which is simply returned as the value that was set. We also need it to pass it to methods that specify an address packets are going to be sent to
Constructors Summary
public PlainDatagramSocketImpl(FileDescriptor fd, int localPort)


         
        super();
        this.fd = fd;
        this.localPort = localPort;
    
public PlainDatagramSocketImpl()

        super();
        fd = new FileDescriptor();
    
Methods Summary
public voidbind(int port, java.net.InetAddress addr)

        String prop = AccessController.doPrivileged(new PriviAction<String>("bindToDevice")); //$NON-NLS-1$
        boolean useBindToDevice = prop != null && prop.toLowerCase().equals("true"); //$NON-NLS-1$
        bindToDevice = netImpl.bind2(fd, port, useBindToDevice, addr);
        if (0 != port) {
            localPort = port;
        } else {
            localPort = netImpl.getSocketLocalPort(fd, NetUtil.preferIPv6Addresses());
        }

        try {
            // Ignore failures
            setOption(SO_BROADCAST, Boolean.TRUE);
        } catch (IOException e) {
        }
    
public voidclose()

        synchronized (fd) {
            if (fd.valid()) {
                try {
                    netImpl.socketClose(fd);
                } catch (IOException e) {
                }
                fd = new FileDescriptor();
            }
        }
    
public voidconnect(java.net.InetAddress inetAddr, int port)


        // connectDatagram impl2
        netImpl.connectDatagram(fd, port, trafficClass, inetAddr);

        // if we get here then we are connected at the native level
        try {
            connectedAddress = InetAddress.getByAddress(inetAddr.getAddress());
        } catch (UnknownHostException e) {
            // this is never expected to happen as we should not have gotten
            // here if the address is not resolvable
            throw new SocketException(Msg.getString("K0317", inetAddr.getHostName())); //$NON-NLS-1$
        }
        connectedPort = port;
        isNativeConnected = true;
    
public voidcreate()

        netImpl.createDatagramSocket(fd, NetUtil.preferIPv4Stack());
    
public voiddisconnect()

        try {
            netImpl.disconnectDatagram(fd);
        } catch (Exception e) {
            // there is currently no way to return an error so just eat any
            // exception
        }
        connectedPort = -1;
        connectedAddress = null;
        isNativeConnected = false;
    
protected voidfinalize()

        close();
    
public java.lang.ObjectgetOption(int optID)

        if (optID == SocketOptions.SO_TIMEOUT) {
            return Integer.valueOf(receiveTimeout);
        } else if (optID == SocketOptions.IP_TOS) {
            return Integer.valueOf(trafficClass);
        } else {
            // Call the native first so there will be
            // an exception if the socket if closed.
            Object result = netImpl.getSocketOption(fd, optID);
            if (optID == SocketOptions.IP_MULTICAST_IF
                    && (netImpl.getSocketFlags() & MULTICAST_IF) != 0) {
                try {
                    return InetAddress.getByAddress(ipaddress);
                } catch (UnknownHostException e) {
                    return null;
                }
            }
            return result;
        }
    
public bytegetTTL()

        // Call the native first so there will be an exception if the socket if
        // closed.
        byte result = ((Byte) getOption(IP_MULTICAST_TTL)).byteValue();
        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
            return (byte) ttl;
        }
        return result;
    
public intgetTimeToLive()

        // Call the native first so there will be an exception if the socket if
        // closed.
        int result = (((Byte) getOption(IP_MULTICAST_TTL)).byteValue()) & 0xFF;
        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
            return ttl;
        }
        return result;
    
public voidjoin(java.net.InetAddress addr)

        setOption(IP_MULTICAST_ADD, new GenericIPMreq(addr));
    
public voidjoinGroup(java.net.SocketAddress addr, java.net.NetworkInterface netInterface)

        if (addr instanceof InetSocketAddress) {
            InetAddress groupAddr = ((InetSocketAddress) addr).getAddress();
            setOption(IP_MULTICAST_ADD, new GenericIPMreq(groupAddr, netInterface));
        }
    
public voidleave(java.net.InetAddress addr)

        setOption(IP_MULTICAST_DROP, new GenericIPMreq(addr));
    
public voidleaveGroup(java.net.SocketAddress addr, java.net.NetworkInterface netInterface)

        if (addr instanceof InetSocketAddress) {
            InetAddress groupAddr = ((InetSocketAddress) addr).getAddress();
            setOption(IP_MULTICAST_DROP, new GenericIPMreq(groupAddr, netInterface));
        }
    
protected intpeek(java.net.InetAddress sender)

        if (isNativeConnected) {
            /*
             * in this case we know the port and address from which the data
             * must have be been received as the socket is connected. However,
             * we still need to do the receive in order to know that there was
             * data received. We use a short buffer as we don't actually need
             * the packet, only the knowledge that it is there
             */
            byte[] storageArray = new byte[10];
            DatagramPacket pack = new DatagramPacket(storageArray, storageArray.length);
            netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
                    .getLength(), receiveTimeout, true); // peek
            // to set the sender ,we now use a native function
            // sender.ipaddress = connectedAddress.getAddress();
            netImpl.setInetAddress(sender, connectedAddress.getAddress());
            return connectedPort;
        }
        return netImpl.peekDatagram(fd, sender, receiveTimeout);
    
public intpeekData(java.net.DatagramPacket pack)

        try {
            if (isNativeConnected) {
                netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
                        .getLength(), receiveTimeout, true); // peek
                updatePacketRecvAddress(pack);
            } else {
                // receiveDatagram 2
                netImpl.receiveDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
                        .getLength(), receiveTimeout, true); // peek
            }
        } catch (InterruptedIOException e) {
            throw new SocketTimeoutException(e.toString());
        }
        return pack.getPort();
    
public voidreceive(java.net.DatagramPacket pack)

        try {
            if (isNativeConnected) {
                // do not peek
                netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
                        .getLength(), receiveTimeout, false);
                updatePacketRecvAddress(pack);
            } else {
                // receiveDatagramImpl2
                netImpl.receiveDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
                        .getLength(), receiveTimeout, false);
            }
        } catch (InterruptedIOException e) {
            throw new SocketTimeoutException(e.getMessage());
        }
    
public voidsend(java.net.DatagramPacket packet)


        if (isNativeConnected) {
            netImpl.sendConnectedDatagram(fd, packet.getData(), packet.getOffset(), packet
                    .getLength(), bindToDevice);
        } else {
            // sendDatagramImpl2
            netImpl.sendDatagram(fd, packet.getData(), packet.getOffset(), packet.getLength(),
                    packet.getPort(), bindToDevice, trafficClass, packet.getAddress());
        }
    
public voidsetOption(int optID, java.lang.Object val)
Set the nominated socket option. As the timeouts are not set as options in the IP stack, the value is stored in an instance field.

throws
SocketException thrown if the option value is unsupported or invalid

        /*
         * for datagram sockets on some platforms we have to set both the
         * REUSEADDR AND REUSEPORT so for REUSEADDR set this option option which
         * tells the VM to set the two values as appropriate for the platform
         */
        if (optID == SocketOptions.SO_REUSEADDR) {
            optID = REUSEADDR_AND_REUSEPORT;
        }

        if (optID == SocketOptions.SO_TIMEOUT) {
            receiveTimeout = ((Integer) val).intValue();
        } else {
            int flags = netImpl.getSocketFlags();
            try {
                netImpl.setSocketOption(fd, optID | (flags << 16), val);
            } catch (SocketException e) {
                // we don't throw an exception for IP_TOS even if the platform
                // won't let us set the requested value
                if (optID != SocketOptions.IP_TOS) {
                    throw e;
                }
            }
            if (optID == SocketOptions.IP_MULTICAST_IF && (flags & MULTICAST_IF) != 0) {
                InetAddress inet = (InetAddress) val;
                if (NetUtil.bytesToInt(inet.getAddress(), 0) == 0 || inet.isLoopbackAddress()) {
                    ipaddress = ((InetAddress) val).getAddress();
                } else {
                    InetAddress local = null;
                    try {
                        local = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        throw new SocketException("getLocalHost(): " + e.toString());
                    }
                    if (inet.equals(local)) {
                        ipaddress = ((InetAddress) val).getAddress();
                    } else {
                        throw new SocketException(val + " != getLocalHost(): " + local);
                    }
                }
            }
            /*
             * save this value as it is actually used differently for IPv4 and
             * IPv6 so we cannot get the value using the getOption. The option
             * is actually only set for IPv4 and a masked version of the value
             * will be set as only a subset of the values are allowed on the
             * socket. Therefore we need to retain it to return the value that
             * was set. We also need the value to be passed into a number of
             * natives so that it can be used properly with IPv6
             */
            if (optID == SocketOptions.IP_TOS) {
                trafficClass = ((Integer) val).intValue();
            }
        }
    
public voidsetTTL(byte ttl)

        setOption(IP_MULTICAST_TTL, Byte.valueOf(ttl));
        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
            this.ttl = ttl;
        }
    
public voidsetTimeToLive(int ttl)

        setOption(IP_MULTICAST_TTL, Byte.valueOf((byte) (ttl & 0xFF)));
        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
            this.ttl = ttl;
        }
    
private voidupdatePacketRecvAddress(java.net.DatagramPacket packet)
Set the received address and port in the packet. We do this when the Datagram socket is connected at the native level and the recvConnnectedDatagramImpl does not update the packet with address from which the packet was received

param
packet the packet to be updated

        packet.setAddress(connectedAddress);
        packet.setPort(connectedPort);