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