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 17package libcore.net; 18 19import dalvik.system.CloseGuard; 20import java.io.Closeable; 21import java.io.FileDescriptor; 22import java.io.IOException; 23import java.net.SocketException; 24import java.util.Arrays; 25import 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 */ 34public class RawSocket implements Closeable { 35 /** 36 * Ethernet IP protocol type, part of the L2 header of IP packets. 37 */ 38 public static final short ETH_P_IP = (short) 0x0800; 39 40 /** 41 * Ethernet ARP protocol type, part of the L2 header of ARP packets. 42 */ 43 public static final short ETH_P_ARP = (short) 0x0806; 44 45 private static native void create(FileDescriptor fd, short 46 protocolType, String interfaceName) 47 throws SocketException; 48 private static native int sendPacket(FileDescriptor fd, 49 String interfaceName, short protocolType, byte[] destMac, byte[] packet, 50 int offset, int byteCount); 51 private static native int recvPacket(FileDescriptor fd, byte[] packet, 52 int offset, int byteCount, int destPort, int timeoutMillis); 53 54 private final FileDescriptor fd; 55 private final String mInterfaceName; 56 private final short mProtocolType; 57 private final CloseGuard guard = CloseGuard.get(); 58 59 /** 60 * Creates a socket on the specified interface. 61 */ 62 public RawSocket(String interfaceName, short protocolType) 63 throws SocketException { 64 mInterfaceName = interfaceName; 65 mProtocolType = protocolType; 66 fd = new FileDescriptor(); 67 create(fd, mProtocolType, mInterfaceName); 68 guard.open("close"); 69 } 70 71 /** 72 * Reads a raw packet into the specified buffer, with the 73 * specified timeout. If the destPort is -1, then the IP 74 * destination port is not verified, otherwise only packets 75 * destined for the specified UDP port are returned. Returns the 76 * length actually read. No indication of overflow is signaled. 77 * The packet data will start at the IP header (EthernetII 78 * dest/source/type headers are removed). 79 */ 80 public int read(byte[] packet, int offset, int byteCount, int destPort, 81 int timeoutMillis) { 82 if (packet == null) { 83 throw new NullPointerException("packet == null"); 84 } 85 86 Arrays.checkOffsetAndCount(packet.length, offset, byteCount); 87 88 if (destPort > 65535) { 89 throw new IllegalArgumentException("Port out of range: " 90 + destPort); 91 } 92 93 return recvPacket(fd, packet, offset, byteCount, destPort, 94 timeoutMillis); 95 } 96 97 /** 98 * Writes a raw packet to the desired interface. A L2 header will 99 * be added which includes the specified destination address, our 100 * source MAC, and the specified protocol type. The caller is responsible 101 * for computing correct IP-header and payload checksums. 102 */ 103 public int write(byte[] destMac, byte[] packet, int offset, int byteCount) { 104 if (destMac == null) { 105 throw new NullPointerException("destMac == null"); 106 } 107 108 if (packet == null) { 109 throw new NullPointerException("packet == null"); 110 } 111 112 Arrays.checkOffsetAndCount(packet.length, offset, byteCount); 113 114 if (destMac.length != 6) { 115 throw new IllegalArgumentException("MAC length must be 6: " 116 + destMac.length); 117 } 118 119 return sendPacket(fd, mInterfaceName, mProtocolType, destMac, packet, 120 offset, byteCount); 121 } 122 123 /** 124 * Closes the socket. After this method is invoked, subsequent 125 * read/write operations will fail. 126 */ 127 public void close() throws IOException { 128 guard.close(); 129 IoBridge.closeSocket(fd); 130 } 131 132 @Override protected void finalize() throws Throwable { 133 try { 134 if (guard != null) { 135 guard.warnIfOpen(); 136 } 137 close(); 138 } finally { 139 super.finalize(); 140 } 141 } 142} 143