Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.net;
     18 
     19 import dalvik.system.CloseGuard;
     20 import java.io.Closeable;
     21 import java.io.FileDescriptor;
     22 import java.io.IOException;
     23 import java.net.SocketException;
     24 import java.util.Arrays;
     25 import libcore.io.IoBridge;
     26 
     27 /**
     28  * This class allows raw L2 packets to be sent and received via the
     29  * specified network interface.  The receive-side implementation is
     30  * restricted to UDP packets for efficiency.
     31  *
     32  * @hide
     33  */
     34 public class RawSocket implements Closeable {
     35     private static native void create(FileDescriptor fd, String interfaceName)
     36             throws SocketException;
     37     private static native int sendPacket(FileDescriptor fd,
     38         String interfaceName, byte[] destMac, byte[] packet, int offset,
     39         int byteCount);
     40     private static native int recvPacket(FileDescriptor fd, byte[] packet,
     41         int offset, int byteCount, int destPort, int timeoutMillis);
     42 
     43     private final FileDescriptor fd;
     44     private final String mInterfaceName;
     45     private final CloseGuard guard = CloseGuard.get();
     46 
     47     /**
     48      * Creates a socket on the specified interface.
     49      */
     50     public RawSocket(String interfaceName) throws SocketException {
     51         mInterfaceName = interfaceName;
     52         fd = new FileDescriptor();
     53         create(fd, mInterfaceName);
     54         guard.open("close");
     55     }
     56 
     57     /**
     58      * Reads a raw packet into the specified buffer, with the
     59      * specified timeout.  Packets not destined for the desired UDP
     60      * port are discarded.  Returns the length actually read.  No
     61      * indication of overflow is signaled.  The packet data will start
     62      * at the IP header (EthernetII dest/source/type headers are
     63      * removed).
     64      */
     65     public int read(byte[] packet, int offset, int byteCount, int destPort,
     66         int timeoutMillis) {
     67         if (packet == null) {
     68             throw new NullPointerException("packet == null");
     69         }
     70 
     71         Arrays.checkOffsetAndCount(packet.length, offset, byteCount);
     72 
     73         if (destPort < 0 || destPort > 65535) {
     74             throw new IllegalArgumentException("Port out of range: "
     75                 + destPort);
     76         }
     77 
     78         return recvPacket(fd, packet, offset, byteCount, destPort,
     79             timeoutMillis);
     80     }
     81 
     82     /**
     83      * Writes a raw packet to the desired interface.  A L2 header will
     84      * be added which includes the specified destination address, our
     85      * source MAC, and the IP type.  The caller is responsible for
     86      * computing correct IP-header and payload checksums.
     87      */
     88     public int write(byte[] destMac, byte[] packet, int offset, int byteCount) {
     89         if (destMac == null) {
     90             throw new NullPointerException("destMac == null");
     91         }
     92 
     93         if (packet == null) {
     94             throw new NullPointerException("packet == null");
     95         }
     96 
     97         Arrays.checkOffsetAndCount(packet.length, offset, byteCount);
     98 
     99         if (destMac.length != 6) {
    100             throw new IllegalArgumentException("MAC length must be 6: "
    101                 + destMac.length);
    102         }
    103 
    104         return sendPacket(fd, mInterfaceName, destMac, packet, offset,
    105             byteCount);
    106     }
    107 
    108     /**
    109      * Closes the socket.  After this method is invoked, subsequent
    110      * read/write operations will fail.
    111      */
    112     public void close() throws IOException {
    113         guard.close();
    114         IoBridge.closeSocket(fd);
    115     }
    116 
    117     @Override protected void finalize() throws Throwable {
    118         try {
    119             if (guard != null) {
    120                 guard.warnIfOpen();
    121             }
    122             close();
    123         } finally {
    124             super.finalize();
    125         }
    126     }
    127 }
    128