blob: 08a7d09bc547322b6df26034c37ced60e329b931 [file] [log] [blame]
/*
* 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 {
/**
* Ethernet IP protocol type, part of the L2 header of IP packets.
*/
public static final short ETH_P_IP = (short) 0x0800;
/**
* Ethernet ARP protocol type, part of the L2 header of ARP packets.
*/
public static final short ETH_P_ARP = (short) 0x0806;
private static native void create(FileDescriptor fd, short
protocolType, String interfaceName)
throws SocketException;
private static native int sendPacket(FileDescriptor fd,
String interfaceName, short protocolType, 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 short mProtocolType;
private final CloseGuard guard = CloseGuard.get();
/**
* Creates a socket on the specified interface.
*/
public RawSocket(String interfaceName, short protocolType)
throws SocketException {
mInterfaceName = interfaceName;
mProtocolType = protocolType;
fd = new FileDescriptor();
create(fd, mProtocolType, mInterfaceName);
guard.open("close");
}
/**
* Reads a raw packet into the specified buffer, with the
* specified timeout. If the destPort is -1, then the IP
* destination port is not verified, otherwise only packets
* destined for the specified UDP port are returned. 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 > 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 specified protocol 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, mProtocolType, 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();
}
}
}