| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed 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. |
| */ |
| |
| package libcore.net; |
| |
| import dalvik.system.CloseGuard; |
| import java.io.Closeable; |
| import java.io.FileDescriptor; |
| import java.io.IOException; |
| import java.net.SocketException; |
| import java.util.Arrays; |
| import libcore.io.IoBridge; |
| |
| /** |
| * This class allows raw L2 packets to be sent and received via the |
| * specified network interface. The receive-side implementation is |
| * restricted to UDP packets for efficiency. |
| * |
| * @hide |
| */ |
| public class RawSocket implements Closeable { |
| private static native void create(FileDescriptor fd, String interfaceName) |
| throws SocketException; |
| private static native int sendPacket(FileDescriptor fd, |
| String interfaceName, byte[] destMac, byte[] packet, int offset, |
| int byteCount); |
| private static native int recvPacket(FileDescriptor fd, byte[] packet, |
| int offset, int byteCount, int destPort, int timeoutMillis); |
| |
| private final FileDescriptor fd; |
| private final String mInterfaceName; |
| private final CloseGuard guard = CloseGuard.get(); |
| |
| /** |
| * Creates a socket on the specified interface. |
| */ |
| public RawSocket(String interfaceName) throws SocketException { |
| mInterfaceName = interfaceName; |
| fd = new FileDescriptor(); |
| create(fd, mInterfaceName); |
| guard.open("close"); |
| } |
| |
| /** |
| * Reads a raw packet into the specified buffer, with the |
| * specified timeout. Packets not destined for the desired UDP |
| * port are discarded. Returns the length actually read. No |
| * indication of overflow is signaled. The packet data will start |
| * at the IP header (EthernetII dest/source/type headers are |
| * removed). |
| */ |
| public int read(byte[] packet, int offset, int byteCount, int destPort, |
| int timeoutMillis) { |
| if (packet == null) { |
| throw new NullPointerException("packet == null"); |
| } |
| |
| Arrays.checkOffsetAndCount(packet.length, offset, byteCount); |
| |
| if (destPort < 0 || destPort > 65535) { |
| throw new IllegalArgumentException("Port out of range: " |
| + destPort); |
| } |
| |
| return recvPacket(fd, packet, offset, byteCount, destPort, |
| timeoutMillis); |
| } |
| |
| /** |
| * Writes a raw packet to the desired interface. A L2 header will |
| * be added which includes the specified destination address, our |
| * source MAC, and the IP type. The caller is responsible for |
| * computing correct IP-header and payload checksums. |
| */ |
| public int write(byte[] destMac, byte[] packet, int offset, int byteCount) { |
| if (destMac == null) { |
| throw new NullPointerException("destMac == null"); |
| } |
| |
| if (packet == null) { |
| throw new NullPointerException("packet == null"); |
| } |
| |
| Arrays.checkOffsetAndCount(packet.length, offset, byteCount); |
| |
| if (destMac.length != 6) { |
| throw new IllegalArgumentException("MAC length must be 6: " |
| + destMac.length); |
| } |
| |
| return sendPacket(fd, mInterfaceName, destMac, packet, offset, |
| byteCount); |
| } |
| |
| /** |
| * Closes the socket. After this method is invoked, subsequent |
| * read/write operations will fail. |
| */ |
| public void close() throws IOException { |
| guard.close(); |
| IoBridge.closeSocket(fd); |
| } |
| |
| @Override protected void finalize() throws Throwable { |
| try { |
| if (guard != null) { |
| guard.warnIfOpen(); |
| } |
| close(); |
| } finally { |
| super.finalize(); |
| } |
| } |
| } |