/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ // BEGIN android-note // Address length was changed from long to int for performance reasons. // Harmony implements INetworkSystem's methods with native methods; Android // implements them with Java that call through to native wrappers. // TODO: change the native code to eliminate the wrappers // END android-note package org.apache.harmony.luni.platform; 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 wraps native code that implements the INetworkSystem interface. */ final class OSNetworkSystem implements INetworkSystem { private static final int ERRORCODE_SOCKET_TIMEOUT = -209; private static final int ERRORCODE_SOCKET_INTERRUPTED = -208; private static final int INETADDR_REACHABLE = 0; private static boolean isNetworkInited = false; private static OSNetworkSystem singleton = new OSNetworkSystem(); /** * Answers the unique instance of the OSNetworkSystem. * * @return the network system interface instance */ public static OSNetworkSystem getOSNetworkSystem() { return singleton; } // Can not be instantiated. private OSNetworkSystem() { super(); } public void accept(FileDescriptor fdServer, SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout) throws IOException { acceptSocketImpl(fdServer, newSocket, fdnewSocket, timeout); } static native void acceptSocketImpl(FileDescriptor fdServer, SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout) throws IOException; // BEGIN android-removed // public void acceptStreamSocket(FileDescriptor fdServer, // SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout) // throws IOException { // acceptStreamSocketImpl(fdServer, newSocket, fdnewSocket, timeout); // } // static native void acceptStreamSocketImpl(FileDescriptor fdServer, // SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout) // throws IOException; // END android-removed public int availableStream(FileDescriptor fd) throws SocketException { return availableStreamImpl(fd); } static native int availableStreamImpl(FileDescriptor aFD) throws SocketException; /** * Associates a local address with a socket. * * @param fd * the socket descriptor * @param port * the port number * @param inetAddress * address to bind * @throws SocketException * thrown if bind operation fails */ public void bind(FileDescriptor fd, InetAddress inetAddress, int port) throws SocketException { socketBindImpl(fd, port, inetAddress); } static native void socketBindImpl(FileDescriptor aFD, int port, InetAddress inetAddress) throws SocketException; public int connect(FileDescriptor fd, int trafficClass, InetAddress inetAddress, int port) throws IOException{ return connectSocketImpl(fd, trafficClass, inetAddress, port); } static native int connectSocketImpl(FileDescriptor aFD, int trafficClass, InetAddress inetAddress, int port); public void connectDatagram(FileDescriptor fd, int port, int trafficClass, InetAddress inetAddress) throws SocketException { connectDatagramImpl2(fd, port, trafficClass, inetAddress); } static native void connectDatagramImpl2(FileDescriptor aFD, int port, int trafficClass, InetAddress inetAddress) throws SocketException; public void connectStreamWithTimeoutSocket(FileDescriptor aFD, int aport, int timeout, int trafficClass, InetAddress inetAddress) throws IOException { connectStreamWithTimeoutSocketImpl(aFD, aport, timeout, trafficClass, inetAddress); } static native void connectStreamWithTimeoutSocketImpl(FileDescriptor aFD, int aport, int timeout, int trafficClass, InetAddress inetAddress) throws IOException; // BEGIN android-changed // changed context from Long to byte[] public int connectWithTimeout(FileDescriptor fd, int timeout, int trafficClass, InetAddress inetAddress, int port, int step, byte[] context) throws IOException { return connectWithTimeoutSocketImpl(fd, timeout, trafficClass, inetAddress, port, step, context); } static native int connectWithTimeoutSocketImpl(FileDescriptor aFD, int timeout, int trafficClass, InetAddress hostname, int port, int step, byte[] context); // END android-changed public void createDatagramSocket(FileDescriptor fd, boolean preferIPv4Stack) throws SocketException { createDatagramSocketImpl(fd, preferIPv4Stack); } /* * Allocate a datagram socket in the IP stack. The socket is associated with * the <code>aFD</code>. * * @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; public void createServerStreamSocket(FileDescriptor fd, boolean preferIPv4Stack) throws SocketException { createServerStreamSocketImpl(fd, preferIPv4Stack); } /* * 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; public void createStreamSocket(FileDescriptor fd, boolean preferIPv4Stack) throws SocketException { createStreamSocketImpl(fd, preferIPv4Stack); } static native void createStreamSocketImpl(FileDescriptor aFD, boolean preferIPv4Stack) throws SocketException; /** * Disconnect the socket to a port and address *a * @param fd * the FileDescriptor associated with the socket * * @throws SocketException * if the disconnect fails */ public void disconnectDatagram(FileDescriptor fd) throws SocketException { disconnectDatagramImpl(fd); } static native void disconnectDatagramImpl(FileDescriptor aFD) throws SocketException; public InetAddress getHostByAddr(byte[] ipAddress) throws UnknownHostException { // BEGIN android-changed // Wallpaper fix for http://b/1851257. This is a layering violation, // but at least the method has the right return type. // TODO: Fix the socket code to remove this method altogether. return InetAddress.getByAddress(ipAddress); // END android-changed } // BEGIN android-removed // static native InetAddress getHostByAddrImpl(byte[] addr) // throws UnknownHostException; // END android-removed // BEGIN android-removed public InetAddress getHostByName(String hostName, boolean preferIPv6Addresses) throws UnknownHostException { // BEGIN android-changed // Wallpaper fix for http://b/1851257. return InetAddress.getByName(hostName); // END android-changed } // BEGIN android-removed // static native InetAddress getHostByNameImpl(String addr, // boolean preferIPv6Addresses) throws UnknownHostException; // END android-removed public int getSocketFlags() { return getSocketFlagsImpl(); } public native String byteArrayToIpString(byte[] address) throws UnknownHostException; public native byte[] ipStringToByteArray(String address) throws UnknownHostException; static native int getSocketFlagsImpl(); public InetAddress getSocketLocalAddress(FileDescriptor fd, boolean preferIPv6Addresses) { return getSocketLocalAddressImpl(fd, preferIPv6Addresses); } 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 the local port to which the socket is bound */ public int getSocketLocalPort(FileDescriptor aFD, boolean preferIPv6Addresses) { return getSocketLocalPortImpl(aFD, preferIPv6Addresses); } static native int getSocketLocalPortImpl(FileDescriptor aFD, boolean preferIPv6Addresses); /** * Query the IP stack for the nominated socket option. * * @param fd * 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 fd, int opt) throws SocketException { return getSocketOptionImpl(fd, opt); } static native Object getSocketOptionImpl(FileDescriptor aFD, int opt) throws SocketException; public Channel inheritedChannel() { return inheritedChannelImpl(); } native Channel inheritedChannelImpl(); // 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); // } // native int isReachableByICMPImpl(InetAddress addr, // InetAddress local, int ttl, int timeout); // END android-removed public void listenStreamSocket(FileDescriptor aFD, int backlog) throws SocketException { listenStreamSocketImpl(aFD, backlog); } static native void listenStreamSocketImpl(FileDescriptor aFD, int backlog) throws SocketException; public void oneTimeInitialization(boolean jcl_supports_ipv6) { if (!isNetworkInited) { oneTimeInitializationImpl(jcl_supports_ipv6); isNetworkInited = true; } } native void oneTimeInitializationImpl (boolean jcl_supports_ipv6); /** * Peek on the socket, update <code>sender</code> address and answer the * sender port. * * @param fd * 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 the sender port * * @throws IOException * upon an read error or timeout */ public int peekDatagram(FileDescriptor fd, InetAddress sender, int receiveTimeout) throws IOException { return peekDatagramImpl(fd, sender, receiveTimeout); } static native int peekDatagramImpl(FileDescriptor aFD, InetAddress sender, int receiveTimeout) throws IOException; /** * Read available bytes from the given file descriptor into a byte array. * * The read has an optional timeout parameter, which if non-zero is the * length of time that the read will wait on a select call to see if any * bytes are available for reading. If the timeout expires the method * returns zero to indicate no bytes were read. * * @param fd * the socket file descriptor to read * @param data * the byte array in which to store the results * @param offset * the offset into the byte array in which to start reading the * results * @param count * the maximum number of bytes to read * @param timeout * the length of time to wait for the bytes, in milliseconds; or * zero to indicate no timeout applied. When there is no timeout * applied the read may block based upon socket options. * @return number of bytes read, or zero if there were no bytes available * before the timeout occurred, or -1 to indicate the socket is * closed * @throws IOException * if an underlying socket exception occurred */ public int read(FileDescriptor fd, byte[] data, int offset, int count, int timeout) throws IOException { return readSocketImpl(fd, data, offset, count, timeout); } static native int readSocketImpl(FileDescriptor aFD, byte[] data, int offset, int count, int timeout) throws IOException; /** * Read available bytes from the given file descriptor into OS memory at a * given address. * * @param fd * the socket file descriptor to read * @param address * the address of the memory in which to store the results * @param count * the maximum number of bytes to read * @param timeout * the length of time to wait for the bytes, in milliseconds * @return number of bytes read, or zero if there were no bytes available * before the timeout occurred, or -1 to indicate the socket is * closed * @throws IOException * if an underlying socket exception occurred */ public int readDirect(FileDescriptor fd, int address, int offset, int count, int timeout) throws IOException { return readSocketDirectImpl(fd, address, offset, count, timeout); } static native int readSocketDirectImpl(FileDescriptor aFD, int address, int offset, int count, int timeout) throws IOException; /** * Receive data on the socket into the specified buffer. The packet fields * <code>data</code> & <code>length</code> are passed in addition to * <code>packet</code> to eliminate the JNI field access calls. * * @param fd * 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 * @throws IOException * upon an read error or timeout */ public int receiveDatagram(FileDescriptor fd, DatagramPacket packet, byte[] data, int offset, int length, int receiveTimeout, boolean peek) throws IOException { return receiveDatagramImpl(fd, packet, data, offset, length, receiveTimeout, peek); } static native int receiveDatagramImpl(FileDescriptor aFD, DatagramPacket packet, byte[] data, int offset, int length, int receiveTimeout, boolean peek) throws IOException; public int receiveDatagramDirect(FileDescriptor fd, DatagramPacket packet, int address, int offset, int length, int receiveTimeout, boolean peek) throws IOException { return receiveDatagramDirectImpl(fd, packet, address, offset, length, receiveTimeout, peek); } static native int receiveDatagramDirectImpl(FileDescriptor aFD, DatagramPacket packet, int address, int offset, int length, int receiveTimeout, boolean peek) throws IOException; /** * Receive at most <code>count</code> bytes into the buffer * <code>data</code> at the <code>offset</code> 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 the actual number of bytes read * @throws IOException * @throws SocketException * if an error occurs while reading * @deprecated use {@link #read(FileDescriptor, byte[], int, int, int)} */ public int receiveStream(FileDescriptor aFD, byte[] data, int offset, int count, int timeout) throws IOException { return receiveStreamImpl(aFD, data, offset, count, timeout); } static native int receiveStreamImpl(FileDescriptor aFD, byte[] data, int offset, int count, int timeout) throws IOException; // BEGIN android-added /** * Send <code>count</code> bytes from the buffer <code>data</code> at * the <code>offset</code>, 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 */ public int sendStream(FileDescriptor fd, byte[] data, int offset, int count) throws IOException { return sendStreamImpl(fd, data, offset, count); } static native int sendStreamImpl(FileDescriptor fd, byte[] data, int offset, int count) throws IOException; // END android-added /** * Recieve data on the connected socket into the specified buffer. The * packet fields <code>data</code> and <code>length</code> are passed in * addition to <code>packet</code> to eliminate the JNI field access calls. * * @param fd * 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 * @throws IOException * upon an read error or timeout */ public int recvConnectedDatagram(FileDescriptor fd, DatagramPacket packet, byte[] data, int offset, int length, int receiveTimeout, boolean peek) throws IOException { return recvConnectedDatagramImpl(fd, packet, data, offset, length, receiveTimeout, peek); } static native int recvConnectedDatagramImpl(FileDescriptor aFD, DatagramPacket packet, byte[] data, int offset, int length, int receiveTimeout, boolean peek) throws IOException; 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); } static native int recvConnectedDatagramDirectImpl(FileDescriptor aFD, DatagramPacket packet, int address, int offset, int length, int receiveTimeout, boolean peek) throws IOException; /** * Select the given file descriptors for read and write operations. * * The file descriptors passed in as readFDs will be selected for read-ready * operations, and those in the writeFDs will be selected for write-ready * operations. A file descriptor can appear in either or both array, and * must not be <code>null</code>. If the file descriptor is closed during * the select the behavior depends upon the underlying OS. * * Upon return the result is a single array of length * <code>readFDs.length</code> + <code>writeFDs.length</code> laid out as * the result of the select operation on the corresponding file descriptors. * * @param readFDs * all sockets interested in read and accept * @param writeFDs * all sockets interested in write and connect * @param timeout * timeout in milliseconds * @return each element describes the corresponding state of the descriptor * in the read and write arrays. * @throws SocketException */ 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]; assert validateFDs(readFDs, writeFDs) : "Invalid file descriptor arrays"; //$NON-NLS-1$ // handle timeout in native result = selectImpl(readFDs, writeFDs, countRead, countWrite, flags, timeout); if (0 <= result) { return flags; } if (ERRORCODE_SOCKET_TIMEOUT == result || ERRORCODE_SOCKET_INTERRUPTED == result) { return new int[0]; } throw new SocketException(); } static native int selectImpl(FileDescriptor[] readfd, FileDescriptor[] writefd, int cread, int cwirte, int[] flags, long timeout); /** * Send the <code>data</code> to the address and port to which the was * connected and <code>port</code>. * * @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 * @throws IOException * upon an read error or timeout */ public int sendConnectedDatagram(FileDescriptor fd, byte[] data, int offset, int length, boolean bindToDevice) throws IOException { return sendConnectedDatagramImpl(fd, data, offset, length, bindToDevice); } static native int sendConnectedDatagramImpl(FileDescriptor fd, byte[] data, int offset, int length, boolean bindToDevice) throws IOException; public int sendConnectedDatagramDirect(FileDescriptor fd, int address, int offset, int length, boolean bindToDevice) throws IOException { return sendConnectedDatagramDirectImpl(fd, address, offset, length, bindToDevice); } static native int sendConnectedDatagramDirectImpl(FileDescriptor fd, int address, int offset, int length, boolean bindToDevice) throws IOException; /** * Send the <code>data</code> to the nominated target <code>address</code> * and <code>port</code>. 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 * * @throws IOException * upon an read error or 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); } static native int sendDatagramImpl(FileDescriptor fd, byte[] data, int offset, int length, int port, boolean bindToDevice, int trafficClass, InetAddress inetAddress) throws IOException; 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); } static native int sendDatagramImpl2(FileDescriptor fd, byte[] data, int offset, int length, int port, InetAddress inetAddress) throws IOException; 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); } static native int sendDatagramDirectImpl(FileDescriptor fd, int address, int offset, int length, int port, boolean bindToDevice, int trafficClass, InetAddress inetAddress) throws IOException; public void sendUrgentData(FileDescriptor fd, byte value) { sendUrgentDataImpl(fd, value); } static native void sendUrgentDataImpl(FileDescriptor fd, byte value); public void setInetAddress(InetAddress sender, byte[] address) { setInetAddressImpl(sender, address); } native void setInetAddressImpl(InetAddress sender, byte[] address); public void setNonBlocking(FileDescriptor fd, boolean block) throws IOException { setNonBlockingImpl(fd, block); } static native void setNonBlockingImpl(FileDescriptor aFD, boolean block); /** * 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); } static native void setSocketOptionImpl(FileDescriptor aFD, int opt, Object optVal) throws SocketException; public void shutdownInput(FileDescriptor descriptor) throws IOException { shutdownInputImpl(descriptor); } private native void shutdownInputImpl(FileDescriptor descriptor) throws IOException; public void shutdownOutput(FileDescriptor fd) throws IOException { shutdownOutputImpl(fd); } private native void shutdownOutputImpl(FileDescriptor descriptor) throws IOException; /** * Close the socket in the IP stack. * * @param fd * the socket descriptor */ public void socketClose(FileDescriptor fd) throws IOException { socketCloseImpl(fd); } static native void socketCloseImpl(FileDescriptor fD); public boolean supportsUrgentData(FileDescriptor fd) { return supportsUrgentDataImpl(fd); } static native boolean supportsUrgentDataImpl(FileDescriptor fd); /* * Used to check if the file descriptor arrays are valid before passing them * into the select native call. */ private boolean validateFDs(FileDescriptor[] readFDs, FileDescriptor[] writeFDs) { for (FileDescriptor fd : readFDs) { // Also checks fd not null if (!fd.valid()) { return false; } } for (FileDescriptor fd : writeFDs) { if (!fd.valid()) { return false; } } return true; } /** * Write bytes from a byte array to a socket. * * @param fd * the socket on which to write the bytes * @param data * the array containing the bytes to be written * @param offset * the offset in the byte array from which to take the bytes * @param count * the maximum number of bytes to be written. Callers are trusted * not to send values of length+count that are larger than * data.length * @return the actual number of bytes written, which will be between zero * and count * @throws IOException * if there is an underlying socket problem */ public int write(FileDescriptor fd, byte[] data, int offset, int count) throws IOException { return writeSocketImpl(fd, data, offset, count); } static native int writeSocketImpl(FileDescriptor fd, byte[] data, int offset, int count) throws IOException; /** * Write bytes from the given address to a socket. * * @param fd * the socket on which to write the bytes * @param address * the start address of the bytes to be written * @param count * the maximum number of bytes to be written * @return the actual number of bytes written, which will be between zero * and count * @throws IOException * if there is an underlying socket problem */ public int writeDirect(FileDescriptor fd, int address, int offset, int count) throws IOException { return writeSocketDirectImpl(fd, address, offset, count); } static native int writeSocketDirectImpl(FileDescriptor fd, int address, int offset, int count) throws IOException; }