diff -r 537ddd8aa407 -r 2036ebfaccda src/org/sipdroid/net/impl/OSNetworkSystem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/net/impl/OSNetworkSystem.java Fri Nov 20 19:29:42 2009 +0100 @@ -0,0 +1,748 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// BEGIN android-note +// address length was changed from long to int for performance reasons. +// END android-note + +package org.sipdroid.net.impl; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.SocketImpl; +import java.net.UnknownHostException; +import java.nio.channels.Channel; +// BEGIN android-removed +// import java.nio.channels.SelectableChannel; +// END android-removed +/* + * + * This Class is used for native code wrap, the implement class of + * INetworkSystem. + * + */ +public final class OSNetworkSystem { + + // ---------------------------------------------------- + // Class Variables + // ---------------------------------------------------- + + private static final int ERRORCODE_SOCKET_TIMEOUT = -209; + + private static OSNetworkSystem ref = new OSNetworkSystem(); + + private static final int INETADDR_REACHABLE = 0; + + private static boolean isNetworkInited = false; + + // ---------------------------------------------------- + // Class Constructor + // ---------------------------------------------------- + + // can not be instantiated. + private OSNetworkSystem() { + super(); + } + + /* + * @return a static ref of this class + */ + public static OSNetworkSystem getOSNetworkSystem() { + return ref; + } + + // Useing when cache set/get is OK + // public static native void oneTimeInitializationDatagram( + // boolean jcl_IPv6_support); + // + // public static native void oneTimeInitializationSocket( + // boolean jcl_IPv6_support); + + // -------------------------------------------------- + // java codes that wrap native codes + // -------------------------------------------------- + + public void createSocket(FileDescriptor fd, boolean preferIPv4Stack) + throws IOException { + createSocketImpl(fd, preferIPv4Stack); + } + + public void createDatagramSocket(FileDescriptor fd, boolean preferIPv4Stack) + throws SocketException { + createDatagramSocketImpl(fd, preferIPv4Stack); + } + + public int read(FileDescriptor aFD, byte[] data, int offset, int count, + int timeout) throws IOException { + return readSocketImpl(aFD, data, offset, count, timeout); + } + + public int readDirect(FileDescriptor aFD, int address, int offset, int count, + int timeout) throws IOException { + return readSocketDirectImpl(aFD, address, offset, count, timeout); + } + + public int write(FileDescriptor aFD, byte[] data, int offset, int count) + throws IOException { + return writeSocketImpl(aFD, data, offset, count); + } + + public int writeDirect(FileDescriptor aFD, int address, int offset, + int count) throws IOException { + return writeSocketDirectImpl(aFD, address, offset, count); + } + + public void setNonBlocking(FileDescriptor aFD, boolean block) + throws IOException { + setNonBlockingImpl(aFD, block); + } + + public void connectDatagram(FileDescriptor aFD, int port, int trafficClass, + InetAddress inetAddress) throws SocketException { + connectDatagramImpl2(aFD, port, trafficClass, inetAddress); + } + + public int connect(FileDescriptor aFD, int trafficClass, + InetAddress inetAddress, int port) throws IOException{ + return connectSocketImpl(aFD, trafficClass, inetAddress, port); + } + + // BEGIN android-changed + public int connectWithTimeout(FileDescriptor aFD, int timeout, + int trafficClass, InetAddress inetAddress, int port, int step, + byte[] context) throws IOException{ + return connectWithTimeoutSocketImpl(aFD, timeout, trafficClass, + inetAddress, port, step, context); + } + // END android-changed + + public void connectStreamWithTimeoutSocket(FileDescriptor aFD, int aport, + int timeout, int trafficClass, InetAddress inetAddress) + throws IOException { + connectStreamWithTimeoutSocketImpl(aFD, aport, timeout, trafficClass, + inetAddress); + } + + public void bind(FileDescriptor aFD, int port, InetAddress inetAddress) + throws SocketException { + socketBindImpl(aFD, port, inetAddress); + } + + public boolean bind2(FileDescriptor aFD, int port, boolean bindToDevice, + InetAddress inetAddress) throws SocketException { + return socketBindImpl2(aFD, port, bindToDevice, inetAddress); + } + + public void accept(FileDescriptor fdServer, SocketImpl newSocket, + FileDescriptor fdnewSocket, int timeout) throws IOException { + acceptSocketImpl(fdServer, newSocket, fdnewSocket, timeout); + } + + public int sendDatagram(FileDescriptor fd, byte[] data, int offset, + int length, int port, boolean bindToDevice, int trafficClass, + InetAddress inetAddress) throws IOException { + return sendDatagramImpl(fd, data, offset, length, port, bindToDevice, + trafficClass, inetAddress); + } + + public int sendDatagramDirect(FileDescriptor fd, int address, int offset, + int length, int port, boolean bindToDevice, int trafficClass, + InetAddress inetAddress) throws IOException { + return sendDatagramDirectImpl(fd, address, offset, length, port, bindToDevice, + trafficClass, inetAddress); + } + + public int sendDatagram2(FileDescriptor fd, byte[] data, int offset, + int length, int port, InetAddress inetAddress) throws IOException { + return sendDatagramImpl2(fd, data, offset, length, port, inetAddress); + } + + public int receiveDatagram(FileDescriptor aFD, DatagramPacket packet, + byte[] data, int offset, int length, int receiveTimeout, + boolean peek) throws IOException { + return receiveDatagramImpl(aFD, packet, data, offset, length, + receiveTimeout, peek); + } + + public int receiveDatagramDirect(FileDescriptor aFD, DatagramPacket packet, + int address, int offset, int length, int receiveTimeout, + boolean peek) throws IOException { + return receiveDatagramDirectImpl(aFD, packet, address, offset, length, + receiveTimeout, peek); + } + + public int recvConnectedDatagram(FileDescriptor aFD, DatagramPacket packet, + byte[] data, int offset, int length, int receiveTimeout, + boolean peek) throws IOException { + return recvConnectedDatagramImpl(aFD, packet, data, offset, length, + receiveTimeout, peek); + } + + public int recvConnectedDatagramDirect(FileDescriptor aFD, DatagramPacket packet, int address, + int offset, int length, int receiveTimeout, boolean peek) + throws IOException { + return recvConnectedDatagramDirectImpl(aFD, packet, address, offset, length, receiveTimeout, peek); + } + + public int peekDatagram(FileDescriptor aFD, InetAddress sender, + int receiveTimeout) throws IOException { + return peekDatagramImpl(aFD, sender, receiveTimeout); + } + + public int sendConnectedDatagram(FileDescriptor fd, byte[] data, + int offset, int length, boolean bindToDevice) throws IOException { + return sendConnectedDatagramImpl(fd, data, offset, length, bindToDevice); + } + + public int sendConnectedDatagramDirect(FileDescriptor fd, int address, + int offset, int length, boolean bindToDevice) throws IOException { + return sendConnectedDatagramDirectImpl(fd, address, offset, length, bindToDevice); + } + + public void disconnectDatagram(FileDescriptor aFD) throws SocketException { + disconnectDatagramImpl(aFD); + } + + public void createMulticastSocket(FileDescriptor aFD, + boolean preferIPv4Stack) throws SocketException { + createMulticastSocketImpl(aFD, preferIPv4Stack); + } + + public void createServerStreamSocket(FileDescriptor aFD, + boolean preferIPv4Stack) throws SocketException { + createServerStreamSocketImpl(aFD, preferIPv4Stack); + } + + public int receiveStream(FileDescriptor aFD, byte[] data, int offset, + int count, int timeout) throws IOException { + return receiveStreamImpl(aFD, data, offset, count, timeout); + } + + public int sendStream(FileDescriptor fd, byte[] data, int offset, int count) + throws IOException { + return sendStreamImpl(fd, data, offset, count); + } + + public void shutdownInput(FileDescriptor descriptor) throws IOException { + shutdownInputImpl(descriptor); + } + + public void shutdownOutput(FileDescriptor descriptor) throws IOException { + shutdownOutputImpl(descriptor); + } + + public boolean supportsUrgentData(FileDescriptor fd) { + return supportsUrgentDataImpl(fd); + } + + public void sendUrgentData(FileDescriptor fd, byte value) { + sendUrgentDataImpl(fd, value); + } + + public int availableStream(FileDescriptor aFD) throws SocketException { + return availableStreamImpl(aFD); + } + + // BEGIN android-removed + // public void acceptStreamSocket(FileDescriptor fdServer, + // SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout) + // throws IOException { + // acceptStreamSocketImpl(fdServer, newSocket, fdnewSocket, timeout); + // } + // + // public void createStreamSocket(FileDescriptor aFD, boolean preferIPv4Stack) + // throws SocketException { + // createStreamSocketImpl(aFD, preferIPv4Stack); + // } + // END android-removed + + public void listenStreamSocket(FileDescriptor aFD, int backlog) + throws SocketException { + listenStreamSocketImpl(aFD, backlog); + } + + // BEGIN android-removed + // public boolean isReachableByICMP(final InetAddress dest, + // InetAddress source, final int ttl, final int timeout) { + // return INETADDR_REACHABLE == isReachableByICMPImpl(dest, source, ttl, + // timeout); + // } + // END android-removed + + /* + * + * @param + * readChannels all channels interested in read and accept + * @param + * writeChannels all channels interested in write and connect + * @param timeout + * timeout in millis @return a set of channels that are ready for operation + * @throws + * SocketException @return int array, each int approve one of the * channel if OK + */ + + public int[] select(FileDescriptor[] readFDs, + FileDescriptor[] writeFDs, long timeout) + throws SocketException { + int countRead = readFDs.length; + int countWrite = writeFDs.length; + int result = 0; + if (0 == countRead + countWrite) { + return (new int[0]); + } + int[] flags = new int[countRead + countWrite]; + + // handle timeout in native + result = selectImpl(readFDs, writeFDs, countRead, countWrite, flags, + timeout); + + if (0 <= result) { + return flags; + } + if (ERRORCODE_SOCKET_TIMEOUT == result) { + return new int[0]; + } + throw new SocketException(); + + } + + public InetAddress getSocketLocalAddress(FileDescriptor aFD, + boolean preferIPv6Addresses) { + return getSocketLocalAddressImpl(aFD, preferIPv6Addresses); + } + + /* + * Query the IP stack for the local port to which this socket is bound. + * + * @param aFD the socket descriptor @param preferIPv6Addresses address + * preference for nodes that support both IPv4 and IPv6 @return int the + * local port to which the socket is bound + */ + public int getSocketLocalPort(FileDescriptor aFD, + boolean preferIPv6Addresses) { + return getSocketLocalPortImpl(aFD, preferIPv6Addresses); + } + + /* + * Query the IP stack for the nominated socket option. + * + * @param aFD the socket descriptor @param opt the socket option type + * @return the nominated socket option value + * + * @throws SocketException if the option is invalid + */ + public Object getSocketOption(FileDescriptor aFD, int opt) + throws SocketException { + return getSocketOptionImpl(aFD, opt); + } + + /* + * Set the nominated socket option in the IP stack. + * + * @param aFD the socket descriptor @param opt the option selector @param + * optVal the nominated option value + * + * @throws SocketException if the option is invalid or cannot be set + */ + public void setSocketOption(FileDescriptor aFD, int opt, Object optVal) + throws SocketException { + setSocketOptionImpl(aFD, opt, optVal); + } + + public int getSocketFlags() { + return getSocketFlagsImpl(); + } + + /* + * Close the socket in the IP stack. + * + * @param aFD the socket descriptor + */ + public void socketClose(FileDescriptor aFD) throws IOException { + socketCloseImpl(aFD); + } + + public InetAddress getHostByAddr(byte[] addr) throws UnknownHostException { + return getHostByAddrImpl(addr); + } + + public InetAddress getHostByName(String addr, boolean preferIPv6Addresses) + throws UnknownHostException { + return getHostByNameImpl(addr, preferIPv6Addresses); + } + + public void setInetAddress(InetAddress sender, byte[] address) { + setInetAddressImpl(sender, address); + } + + // --------------------------------------------------- + // Native Codes + // --------------------------------------------------- + + static native void createSocketImpl(FileDescriptor fd, + boolean preferIPv4Stack); + + /* + * Allocate a datagram socket in the IP stack. The socket is associated with + * the aFD. + * + * @param aFD the FileDescriptor to associate with the socket @param + * preferIPv4Stack IP stack preference if underlying platform is V4/V6 + * @exception SocketException upon an allocation error + */ + static native void createDatagramSocketImpl(FileDescriptor aFD, + boolean preferIPv4Stack) throws SocketException; + + static native int readSocketImpl(FileDescriptor aFD, byte[] data, + int offset, int count, int timeout) throws IOException; + + static native int readSocketDirectImpl(FileDescriptor aFD, int address, + int offset, int count, int timeout) throws IOException; + + static native int writeSocketImpl(FileDescriptor fd, byte[] data, + int offset, int count) throws IOException; + + static native int writeSocketDirectImpl(FileDescriptor fd, int address, + int offset, int count) throws IOException; + + static native void setNonBlockingImpl(FileDescriptor aFD, + boolean block); + + static native int connectSocketImpl(FileDescriptor aFD, + int trafficClass, InetAddress inetAddress, int port); + + // BEGIN android-changed + static native int connectWithTimeoutSocketImpl( + FileDescriptor aFD, int timeout, int trafficClass, + InetAddress hostname, int port, int step, byte[] context); + // END android-changed + + static native void connectStreamWithTimeoutSocketImpl(FileDescriptor aFD, + int aport, int timeout, int trafficClass, InetAddress inetAddress) + throws IOException; + + static native void socketBindImpl(FileDescriptor aFD, int port, + InetAddress inetAddress) throws SocketException; + + static native void listenStreamSocketImpl(FileDescriptor aFD, int backlog) + throws SocketException; + + static native int availableStreamImpl(FileDescriptor aFD) + throws SocketException; + + static native void acceptSocketImpl(FileDescriptor fdServer, + SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout) + throws IOException; + + static native boolean supportsUrgentDataImpl(FileDescriptor fd); + + static native void sendUrgentDataImpl(FileDescriptor fd, byte value); + + /* + * Connect the socket to a port and address + * + * @param aFD the FileDescriptor to associate with the socket @param port + * the port to connect to @param trafficClass the traffic Class to be used + * then the connection is made @param inetAddress address to connect to. + * + * @exception SocketException if the connect fails + */ + static native void connectDatagramImpl2(FileDescriptor aFD, + int port, int trafficClass, InetAddress inetAddress) + throws SocketException; + + /* + * Disconnect the socket to a port and address + * + * @param aFD the FileDescriptor to associate with the socket + * + * @exception SocketException if the disconnect fails + */ + static native void disconnectDatagramImpl(FileDescriptor aFD) + throws SocketException; + + /* + * Allocate a datagram socket in the IP stack. The socket is associated with + * the aFD. + * + * @param aFD the FileDescriptor to associate with the socket @param + * preferIPv4Stack IP stack preference if underlying platform is V4/V6 + * @exception SocketException upon an allocation error + */ + + /* + * Bind the socket to the port/localhost in the IP stack. + * + * @param aFD the socket descriptor @param port the option selector @param + * bindToDevice bind the socket to the specified interface @param + * inetAddress address to connect to. @return if bind successful @exception + * SocketException thrown if bind operation fails + */ + static native boolean socketBindImpl2(FileDescriptor aFD, + int port, boolean bindToDevice, InetAddress inetAddress) + throws SocketException; + + /* + * Peek on the socket, update sender address and answer the + * sender port. + * + * @param aFD the socket FileDescriptor @param sender an InetAddress, to be + * updated with the sender's address @param receiveTimeout the maximum + * length of time the socket should block, reading @return int the sender + * port + * + * @exception IOException upon an read error or timeout + */ + static native int peekDatagramImpl(FileDescriptor aFD, + InetAddress sender, int receiveTimeout) throws IOException; + + /* + * Recieve data on the socket into the specified buffer. The packet fields + * data & length are passed in addition to + * packet to eliminate the JNI field access calls. + * + * @param aFD the socket FileDescriptor @param packet the DatagramPacket to + * receive into @param data the data buffer of the packet @param offset the + * offset in the data buffer @param length the length of the data buffer in + * the packet @param receiveTimeout the maximum length of time the socket + * should block, reading @param peek indicates to peek at the data @return + * number of data received @exception IOException upon an read error or + * timeout + */ + static native int receiveDatagramImpl(FileDescriptor aFD, + DatagramPacket packet, byte[] data, int offset, int length, + int receiveTimeout, boolean peek) throws IOException; + + static native int receiveDatagramDirectImpl(FileDescriptor aFD, + DatagramPacket packet, int address, int offset, int length, + int receiveTimeout, boolean peek) throws IOException; + + /* + * Recieve data on the connected socket into the specified buffer. The + * packet fields data & length are passed in + * addition to packet to eliminate the JNI field access + * calls. + * + * @param aFD the socket FileDescriptor @param packet the DatagramPacket to + * receive into @param data the data buffer of the packet @param offset the + * offset in the data buffer @param length the length of the data buffer in + * the packet @param receiveTimeout the maximum length of time the socket + * should block, reading @param peek indicates to peek at the data @return + * number of data received @exception IOException upon an read error or + * timeout + */ + static native int recvConnectedDatagramImpl(FileDescriptor aFD, + DatagramPacket packet, byte[] data, int offset, int length, + int receiveTimeout, boolean peek) throws IOException; + + static native int recvConnectedDatagramDirectImpl(FileDescriptor aFD, + DatagramPacket packet, int address, int offset, int length, + int receiveTimeout, boolean peek) throws IOException; + + /* + * Send the data to the nominated target address + * and port. These values are derived from the + * DatagramPacket to reduce the field calls within JNI. + * + * @param fd the socket FileDescriptor @param data the data buffer of the + * packet @param offset the offset in the data buffer @param length the + * length of the data buffer in the packet @param port the target host port + * @param bindToDevice if bind to device @param trafficClass the traffic + * class to be used when the datagram is sent @param inetAddress address to + * connect to. @return number of data send + * + * @exception IOException upon an read error or timeout + */ + static native int sendDatagramImpl(FileDescriptor fd, + byte[] data, int offset, int length, int port, + boolean bindToDevice, int trafficClass, InetAddress inetAddress) + throws IOException; + + static native int sendDatagramDirectImpl(FileDescriptor fd, + int address, int offset, int length, int port, + boolean bindToDevice, int trafficClass, InetAddress inetAddress) + throws IOException; + + /* + * Send the data to the address and port to which the was + * connnected and port. + * + * @param fd the socket FileDescriptor @param data the data buffer of the + * packet @param offset the offset in the data buffer @param length the + * length of the data buffer in the packet @param bindToDevice not used, + * current kept in case needed as was the case for sendDatagramImpl @return + * number of data send @exception IOException upon an read error or timeout + */ + static native int sendConnectedDatagramImpl(FileDescriptor fd, + byte[] data, int offset, int length, boolean bindToDevice) + throws IOException; + + static native int sendConnectedDatagramDirectImpl(FileDescriptor fd, + int address, int offset, int length, boolean bindToDevice) + throws IOException; + + /* + * Answer the result of attempting to create a server stream socket in the + * IP stack. Any special options required for server sockets will be set by + * this method. + * + * @param aFD the socket FileDescriptor @param preferIPv4Stack if use IPV4 + * @exception SocketException if an error occurs while creating the socket + */ + static native void createServerStreamSocketImpl(FileDescriptor aFD, + boolean preferIPv4Stack) throws SocketException; + + /* + * Answer the result of attempting to create a multicast socket in the IP + * stack. Any special options required for server sockets will be set by + * this method. + * + * @param aFD the socket FileDescriptor @param preferIPv4Stack if use IPV4 + * @exception SocketException if an error occurs while creating the socket + */ + static native void createMulticastSocketImpl(FileDescriptor aFD, + boolean preferIPv4Stack) throws SocketException; + + /* + * Recieve at most count bytes into the buffer data + * at the offset on the socket. + * + * @param aFD the socket FileDescriptor @param data the receive buffer + * @param offset the offset into the buffer @param count the max number of + * bytes to receive @param timeout the max time the read operation should + * block waiting for data @return int the actual number of bytes read + * @throws IOException @exception SocketException if an error occurs while + * reading + */ + static native int receiveStreamImpl(FileDescriptor aFD, byte[] data, + int offset, int count, int timeout) throws IOException; + + /* + * Send count bytes from the buffer data at + * the offset, on the socket. + * + * @param fd + * + * @param data the send buffer @param offset the offset into the buffer + * @param count the number of bytes to receive @return int the actual number + * of bytes sent @throws IOException @exception SocketException if an error + * occurs while writing + */ + static native int sendStreamImpl(FileDescriptor fd, byte[] data, + int offset, int count) throws IOException; + + private native void shutdownInputImpl(FileDescriptor descriptor) + throws IOException; + + private native void shutdownOutputImpl(FileDescriptor descriptor) + throws IOException; + + // BEGIN android-removed + // static native void acceptStreamSocketImpl(FileDescriptor fdServer, + // SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout) + // throws IOException; + // + // static native void createStreamSocketImpl(FileDescriptor aFD, + // boolean preferIPv4Stack) throws SocketException; + // END android-removed + + static native int sendDatagramImpl2(FileDescriptor fd, byte[] data, + int offset, int length, int port, InetAddress inetAddress) + throws IOException; + + static native int selectImpl(FileDescriptor[] readfd, + FileDescriptor[] writefd, int cread, int cwirte, int[] flags, + long timeout); + + static native InetAddress getSocketLocalAddressImpl(FileDescriptor aFD, + boolean preferIPv6Addresses); + + /* + * Query the IP stack for the local port to which this socket is bound. + * + * @param aFD the socket descriptor @param preferIPv6Addresses address + * preference for nodes that support both IPv4 and IPv6 @return int the + * local port to which the socket is bound + */ + static native int getSocketLocalPortImpl(FileDescriptor aFD, + boolean preferIPv6Addresses); + + /* + * Query the IP stack for the nominated socket option. + * + * @param aFD the socket descriptor @param opt the socket option type + * @return the nominated socket option value + * + * @throws SocketException if the option is invalid + */ + static native Object getSocketOptionImpl(FileDescriptor aFD, int opt) + throws SocketException; + + /* + * Set the nominated socket option in the IP stack. + * + * @param aFD the socket descriptor @param opt the option selector @param + * optVal the nominated option value + * + * @throws SocketException if the option is invalid or cannot be set + */ + static native void setSocketOptionImpl(FileDescriptor aFD, int opt, + Object optVal) throws SocketException; + + static native int getSocketFlagsImpl(); + + /* + * Close the socket in the IP stack. + * + * @param aFD the socket descriptor + */ + static native void socketCloseImpl(FileDescriptor aFD); + + static native InetAddress getHostByAddrImpl(byte[] addr) + throws UnknownHostException; + + static native InetAddress getHostByNameImpl(String addr, + boolean preferIPv6Addresses) throws UnknownHostException; + + native void setInetAddressImpl(InetAddress sender, byte[] address); + + // BEGIN android-removed + // native int isReachableByICMPImpl(InetAddress addr, InetAddress local, + // int ttl, int timeout); + // END android-removed + + native Channel inheritedChannelImpl(); + + public Channel inheritedChannel() { + return inheritedChannelImpl(); + } + + public void oneTimeInitialization(boolean jcl_supports_ipv6){ + if (!isNetworkInited){ + oneTimeInitializationImpl(jcl_supports_ipv6); + isNetworkInited = true; + } + } + + native void oneTimeInitializationImpl (boolean jcl_supports_ipv6); +} \ No newline at end of file