1975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt/*
2975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * Copyright (C) 2010 The Android Open Source Project
3975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt *
4975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * Licensed under the Apache License, Version 2.0 (the "License");
5975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * you may not use this file except in compliance with the License.
6975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * You may obtain a copy of the License at
7975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt *
8975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt *      http://www.apache.org/licenses/LICENSE-2.0
9975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt *
10975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * Unless required by applicable law or agreed to in writing, software
11975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * distributed under the License is distributed on an "AS IS" BASIS,
12975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * See the License for the specific language governing permissions and
14975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * limitations under the License.
15975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt */
16975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
17975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnuttpackage libcore.net;
18975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
19975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnuttimport dalvik.system.CloseGuard;
20975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnuttimport java.io.Closeable;
21975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnuttimport java.io.FileDescriptor;
22975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnuttimport java.io.IOException;
23975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnuttimport java.net.SocketException;
24975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnuttimport java.util.Arrays;
250b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport libcore.io.IoBridge;
26975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
27975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt/**
28975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * This class allows raw L2 packets to be sent and received via the
29975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * specified network interface.  The receive-side implementation is
30975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * restricted to UDP packets for efficiency.
31975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt *
32975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt * @hide
33975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt */
34975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnuttpublic class RawSocket implements Closeable {
355f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff    /**
365f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     * Ethernet IP protocol type, part of the L2 header of IP packets.
375f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     */
385f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff    public static final short ETH_P_IP = (short) 0x0800;
395f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff
405f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff    /**
415f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     * Ethernet ARP protocol type, part of the L2 header of ARP packets.
425f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     */
435f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff    public static final short ETH_P_ARP = (short) 0x0806;
445f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff
455f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff    private static native void create(FileDescriptor fd, short
465f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff            protocolType, String interfaceName)
47975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            throws SocketException;
48975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    private static native int sendPacket(FileDescriptor fd,
495f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff        String interfaceName, short protocolType, byte[] destMac, byte[] packet,
505f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff        int offset, int byteCount);
51975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    private static native int recvPacket(FileDescriptor fd, byte[] packet,
52975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        int offset, int byteCount, int destPort, int timeoutMillis);
53975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
54975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    private final FileDescriptor fd;
55975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    private final String mInterfaceName;
565f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff    private final short mProtocolType;
57975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    private final CloseGuard guard = CloseGuard.get();
58975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
59975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    /**
60975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt     * Creates a socket on the specified interface.
61975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt     */
625f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff    public RawSocket(String interfaceName, short protocolType)
635f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff        throws SocketException {
64975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        mInterfaceName = interfaceName;
655f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff        mProtocolType = protocolType;
66975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        fd = new FileDescriptor();
675f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff        create(fd, mProtocolType, mInterfaceName);
68975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        guard.open("close");
69975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    }
70975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
71975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    /**
72975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt     * Reads a raw packet into the specified buffer, with the
735f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     * specified timeout.  If the destPort is -1, then the IP
745f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     * destination port is not verified, otherwise only packets
755f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     * destined for the specified UDP port are returned.  Returns the
765f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     * length actually read.  No indication of overflow is signaled.
775f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     * The packet data will start at the IP header (EthernetII
785f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     * dest/source/type headers are removed).
79975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt     */
80975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    public int read(byte[] packet, int offset, int byteCount, int destPort,
81975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        int timeoutMillis) {
82975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        if (packet == null) {
83975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            throw new NullPointerException("packet == null");
84975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        }
85975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
86975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        Arrays.checkOffsetAndCount(packet.length, offset, byteCount);
87975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
885f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff        if (destPort > 65535) {
89975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            throw new IllegalArgumentException("Port out of range: "
90975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt                + destPort);
91975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        }
92975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
93975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        return recvPacket(fd, packet, offset, byteCount, destPort,
94975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            timeoutMillis);
95975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    }
96975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
97975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    /**
98975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt     * Writes a raw packet to the desired interface.  A L2 header will
99975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt     * be added which includes the specified destination address, our
1005f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     * source MAC, and the specified protocol type.  The caller is responsible
1015f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff     * for computing correct IP-header and payload checksums.
102975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt     */
103975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    public int write(byte[] destMac, byte[] packet, int offset, int byteCount) {
104975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        if (destMac == null) {
105975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            throw new NullPointerException("destMac == null");
106975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        }
107975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
108975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        if (packet == null) {
109975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            throw new NullPointerException("packet == null");
110975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        }
111975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
112975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        Arrays.checkOffsetAndCount(packet.length, offset, byteCount);
113975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
114975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        if (destMac.length != 6) {
115975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            throw new IllegalArgumentException("MAC length must be 6: "
116975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt                + destMac.length);
117975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        }
118975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
1195f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff        return sendPacket(fd, mInterfaceName, mProtocolType, destMac, packet,
1205f0ed6ed5798a3e6ad642bcd5382b864796cdcb8Irfan Sheriff            offset, byteCount);
121975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    }
122975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
123975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    /**
124975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt     * Closes the socket.  After this method is invoked, subsequent
125975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt     * read/write operations will fail.
126975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt     */
127975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    public void close() throws IOException {
128975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        guard.close();
1290b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        IoBridge.closeSocket(fd);
130975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    }
131975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt
132975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    @Override protected void finalize() throws Throwable {
133975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        try {
134975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            if (guard != null) {
135975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt                guard.warnIfOpen();
136975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            }
137975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            close();
138975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        } finally {
139975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt            super.finalize();
140975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt        }
141975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt    }
142975dc421bdf9f207ed88b3fbedbba558f0f62c3cStan Chesnutt}
143