Loading services/net/java/android/net/ip/ConnectivityPacketTracker.java +3 −3 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ package android.net.ip; import static android.system.OsConstants.*; import android.net.NetworkUtils; import android.net.util.BlockingSocketReader; import android.net.util.PacketReader; import android.net.util.ConnectivityPacketSummary; import android.os.Handler; import android.system.ErrnoException; Loading Loading @@ -65,7 +65,7 @@ public class ConnectivityPacketTracker { private final String mTag; private final LocalLog mLog; private final BlockingSocketReader mPacketListener; private final PacketReader mPacketListener; private boolean mRunning; private String mDisplayName; Loading Loading @@ -101,7 +101,7 @@ public class ConnectivityPacketTracker { mDisplayName = null; } private final class PacketListener extends BlockingSocketReader { private final class PacketListener extends PacketReader { private final int mIfIndex; private final byte mHwAddr[]; Loading services/net/java/android/net/ip/IpClient.java +10 −0 Original line number Diff line number Diff line Loading @@ -815,6 +815,15 @@ public class IpClient extends StateMachine { pw.println(Objects.toString(provisioningConfig, "N/A")); pw.decreaseIndent(); final IpReachabilityMonitor iprm = mIpReachabilityMonitor; if (iprm != null) { pw.println(); pw.println(mTag + " current IpReachabilityMonitor state:"); pw.increaseIndent(); iprm.dump(pw); pw.decreaseIndent(); } pw.println(); pw.println(mTag + " StateMachine dump:"); pw.increaseIndent(); Loading Loading @@ -1237,6 +1246,7 @@ public class IpClient extends StateMachine { mIpReachabilityMonitor = new IpReachabilityMonitor( mContext, mInterfaceName, getHandler(), mLog, new IpReachabilityMonitor.Callback() { @Override Loading services/net/java/android/net/ip/IpNeighborMonitor.java 0 → 100644 +236 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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 android.net.ip; import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkErrorMessage; import android.net.netlink.NetlinkMessage; import android.net.netlink.NetlinkSocket; import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNdMsg; import android.net.netlink.StructNlMsgHdr; import android.net.util.PacketReader; import android.net.util.SharedLog; import android.os.Handler; import android.os.SystemClock; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; import android.system.Os; import android.system.OsConstants; import android.util.Log; import com.android.internal.util.BitUtils; import libcore.io.IoUtils; import libcore.io.Libcore; import java.io.FileDescriptor; import java.net.InetAddress; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.StringJoiner; /** * IpNeighborMonitor. * * Monitors the kernel rtnetlink neighbor notifications and presents to callers * NeighborEvents describing each event. Callers can provide a consumer instance * to both filter (e.g. by interface index and IP address) and handle the * generated NeighborEvents. * * @hide */ public class IpNeighborMonitor extends PacketReader { private static final String TAG = IpNeighborMonitor.class.getSimpleName(); private static final boolean DBG = false; private static final boolean VDBG = false; /** * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND) * for the given IP address on the specified interface index. * * @return 0 if the request was successfully passed to the kernel; otherwise return * a non-zero error code. */ public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) { final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex; if (DBG) { Log.d(TAG, msgSnippet); } final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage( 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null); try { NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg); } catch (ErrnoException e) { Log.e(TAG, "Error " + msgSnippet + ": " + e); return -e.errno; } return 0; } public static class NeighborEvent { final long elapsedMs; final short msgType; final int ifindex; final InetAddress ip; final short nudState; final byte[] linkLayerAddr; public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip, short nudState, byte[] linkLayerAddr) { this.elapsedMs = elapsedMs; this.msgType = msgType; this.ifindex = ifindex; this.ip = ip; this.nudState = nudState; this.linkLayerAddr = linkLayerAddr; } boolean isConnected() { return (msgType != NetlinkConstants.RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState); } boolean isValid() { return (msgType != NetlinkConstants.RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState); } @Override public String toString() { final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}"); return j.add("@" + elapsedMs) .add(NetlinkConstants.stringForNlMsgType(msgType)) .add("if=" + ifindex) .add(ip.getHostAddress()) .add(StructNdMsg.stringForNudState(nudState)) .add("[" + NetlinkConstants.hexify(linkLayerAddr) + "]") .toString(); } } public interface NeighborEventConsumer { // Every neighbor event received on the netlink socket is passed in // here. Subclasses should filter for events of interest. public void accept(NeighborEvent event); } private final SharedLog mLog; private final NeighborEventConsumer mConsumer; public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) { super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE); mLog = log.forSubComponent(TAG); mConsumer = (cb != null) ? cb : (event) -> { /* discard */ }; } @Override protected FileDescriptor createFd() { FileDescriptor fd = null; try { fd = NetlinkSocket.forProto(OsConstants.NETLINK_ROUTE); Os.bind(fd, (SocketAddress)(new NetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH))); Os.connect(fd, (SocketAddress)(new NetlinkSocketAddress(0, 0))); if (VDBG) { final NetlinkSocketAddress nlAddr = (NetlinkSocketAddress) Os.getsockname(fd); Log.d(TAG, "bound to sockaddr_nl{" + BitUtils.uint32(nlAddr.getPortId()) + ", " + nlAddr.getGroupsMask() + "}"); } } catch (ErrnoException|SocketException e) { logError("Failed to create rtnetlink socket", e); IoUtils.closeQuietly(fd); return null; } return fd; } @Override protected void handlePacket(byte[] recvbuf, int length) { final long whenMs = SystemClock.elapsedRealtime(); final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length); byteBuffer.order(ByteOrder.nativeOrder()); parseNetlinkMessageBuffer(byteBuffer, whenMs); } private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) { while (byteBuffer.remaining() > 0) { final int position = byteBuffer.position(); final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer); if (nlMsg == null || nlMsg.getHeader() == null) { byteBuffer.position(position); mLog.e("unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer)); break; } final int srcPortId = nlMsg.getHeader().nlmsg_pid; if (srcPortId != 0) { mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId)); break; } if (nlMsg instanceof NetlinkErrorMessage) { mLog.e("netlink error: " + nlMsg); continue; } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) { mLog.i("non-rtnetlink neighbor msg: " + nlMsg); continue; } evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs); } } private void evaluateRtNetlinkNeighborMessage( RtNetlinkNeighborMessage neighMsg, long whenMs) { final short msgType = neighMsg.getHeader().nlmsg_type; final StructNdMsg ndMsg = neighMsg.getNdHeader(); if (ndMsg == null) { mLog.e("RtNetlinkNeighborMessage without ND message header!"); return; } final int ifindex = ndMsg.ndm_ifindex; final InetAddress destination = neighMsg.getDestination(); final short nudState = (msgType == NetlinkConstants.RTM_DELNEIGH) ? StructNdMsg.NUD_NONE : ndMsg.ndm_state; final NeighborEvent event = new NeighborEvent( whenMs, msgType, ifindex, destination, nudState, neighMsg.getLinkLayerAddress()); if (VDBG) { Log.d(TAG, neighMsg.toString()); } if (DBG) { Log.d(TAG, event.toString()); } mConsumer.accept(event); } } services/net/java/android/net/ip/IpReachabilityMonitor.java +97 −289 File changed.Preview size limit exceeded, changes collapsed. Show changes services/net/java/android/net/netlink/NetlinkSocket.java +40 −94 Original line number Diff line number Diff line Loading @@ -16,16 +16,24 @@ package android.net.netlink; import static android.system.OsConstants.AF_NETLINK; import static android.system.OsConstants.EIO; import static android.system.OsConstants.EPROTO; import static android.system.OsConstants.ETIMEDOUT; import static android.system.OsConstants.SO_RCVBUF; import static android.system.OsConstants.SO_RCVTIMEO; import static android.system.OsConstants.SO_SNDTIMEO; import static android.system.OsConstants.SOCK_DGRAM; import static android.system.OsConstants.SOL_SOCKET; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; import android.system.Os; import android.system.OsConstants; import android.system.StructTimeval; import android.util.Log; import libcore.io.IoUtils; import libcore.io.Libcore; import java.io.Closeable; import java.io.FileDescriptor; import java.io.InterruptedIOException; import java.net.SocketAddress; Loading @@ -37,28 +45,27 @@ import java.nio.ByteOrder; /** * NetlinkSocket * * A small wrapper class to assist with AF_NETLINK socket operations. * A small static class to assist with AF_NETLINK socket operations. * * @hide */ public class NetlinkSocket implements Closeable { public class NetlinkSocket { private static final String TAG = "NetlinkSocket"; private static final int SOCKET_RECV_BUFSIZE = 64 * 1024; private static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; final private FileDescriptor mDescriptor; private NetlinkSocketAddress mAddr; private long mLastRecvTimeoutMs; private long mLastSendTimeoutMs; public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; public static final int SOCKET_RECV_BUFSIZE = 64 * 1024; public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException { final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage"; try (NetlinkSocket nlSocket = new NetlinkSocket(nlProto)) { final long IO_TIMEOUT = 300L; nlSocket.connectToKernel(); nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT); final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT); FileDescriptor fd; try { fd = forProto(nlProto); connectToKernel(fd); sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT); final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT); // recvMessage() guaranteed to not return null if it did not throw. final NetlinkMessage response = NetlinkMessage.parse(bytes); if (response != null && response instanceof NetlinkErrorMessage && Loading @@ -81,61 +88,30 @@ public class NetlinkSocket implements Closeable { errmsg = response.toString(); } Log.e(TAG, errPrefix + ", errmsg=" + errmsg); throw new ErrnoException(errmsg, OsConstants.EPROTO); throw new ErrnoException(errmsg, EPROTO); } } catch (InterruptedIOException e) { Log.e(TAG, errPrefix, e); throw new ErrnoException(errPrefix, OsConstants.ETIMEDOUT, e); throw new ErrnoException(errPrefix, ETIMEDOUT, e); } catch (SocketException e) { Log.e(TAG, errPrefix, e); throw new ErrnoException(errPrefix, OsConstants.EIO, e); } } public NetlinkSocket(int nlProto) throws ErrnoException { mDescriptor = Os.socket( OsConstants.AF_NETLINK, OsConstants.SOCK_DGRAM, nlProto); Os.setsockoptInt( mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_RCVBUF, SOCKET_RECV_BUFSIZE); throw new ErrnoException(errPrefix, EIO, e); } public NetlinkSocketAddress getLocalAddress() throws ErrnoException { return (NetlinkSocketAddress) Os.getsockname(mDescriptor); IoUtils.closeQuietly(fd); } public void bind(NetlinkSocketAddress localAddr) throws ErrnoException, SocketException { Os.bind(mDescriptor, (SocketAddress)localAddr); } public void connectTo(NetlinkSocketAddress peerAddr) throws ErrnoException, SocketException { Os.connect(mDescriptor, (SocketAddress) peerAddr); } public void connectToKernel() throws ErrnoException, SocketException { connectTo(new NetlinkSocketAddress(0, 0)); } /** * Wait indefinitely (or until underlying socket error) for a * netlink message of at most DEFAULT_RECV_BUFSIZE size. */ public ByteBuffer recvMessage() throws ErrnoException, InterruptedIOException { return recvMessage(DEFAULT_RECV_BUFSIZE, 0); public static FileDescriptor forProto(int nlProto) throws ErrnoException { final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto); Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE); return fd; } /** * Wait up to |timeoutMs| (or until underlying socket error) for a * netlink message of at most DEFAULT_RECV_BUFSIZE size. */ public ByteBuffer recvMessage(long timeoutMs) throws ErrnoException, InterruptedIOException { return recvMessage(DEFAULT_RECV_BUFSIZE, timeoutMs); public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException { Os.connect(fd, (SocketAddress) (new NetlinkSocketAddress(0, 0))); } private void checkTimeout(long timeoutMs) { private static void checkTimeout(long timeoutMs) { if (timeoutMs < 0) { throw new IllegalArgumentException("Negative timeouts not permitted"); } Loading @@ -147,21 +123,14 @@ public class NetlinkSocket implements Closeable { * * Multi-threaded calls with different timeouts will cause unexpected results. */ public ByteBuffer recvMessage(int bufsize, long timeoutMs) public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs) throws ErrnoException, IllegalArgumentException, InterruptedIOException { checkTimeout(timeoutMs); synchronized (mDescriptor) { if (mLastRecvTimeoutMs != timeoutMs) { Os.setsockoptTimeval(mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); mLastRecvTimeoutMs = timeoutMs; } } Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); int length = Os.read(mDescriptor, byteBuffer); int length = Os.read(fd, byteBuffer); if (length == bufsize) { Log.w(TAG, "maximum read"); } Loading @@ -171,40 +140,17 @@ public class NetlinkSocket implements Closeable { return byteBuffer; } /** * Send a message to a peer to which this socket has previously connected. * * This blocks until completion or an error occurs. */ public boolean sendMessage(byte[] bytes, int offset, int count) throws ErrnoException, InterruptedIOException { return sendMessage(bytes, offset, count, 0); } /** * Send a message to a peer to which this socket has previously connected, * waiting at most |timeoutMs| milliseconds for the send to complete. * * Multi-threaded calls with different timeouts will cause unexpected results. */ public boolean sendMessage(byte[] bytes, int offset, int count, long timeoutMs) public static int sendMessage( FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs) throws ErrnoException, IllegalArgumentException, InterruptedIOException { checkTimeout(timeoutMs); synchronized (mDescriptor) { if (mLastSendTimeoutMs != timeoutMs) { Os.setsockoptTimeval(mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); mLastSendTimeoutMs = timeoutMs; } } return (count == Os.write(mDescriptor, bytes, offset, count)); } @Override public void close() { IoUtils.closeQuietly(mDescriptor); Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); return Os.write(fd, bytes, offset, count); } } Loading
services/net/java/android/net/ip/ConnectivityPacketTracker.java +3 −3 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ package android.net.ip; import static android.system.OsConstants.*; import android.net.NetworkUtils; import android.net.util.BlockingSocketReader; import android.net.util.PacketReader; import android.net.util.ConnectivityPacketSummary; import android.os.Handler; import android.system.ErrnoException; Loading Loading @@ -65,7 +65,7 @@ public class ConnectivityPacketTracker { private final String mTag; private final LocalLog mLog; private final BlockingSocketReader mPacketListener; private final PacketReader mPacketListener; private boolean mRunning; private String mDisplayName; Loading Loading @@ -101,7 +101,7 @@ public class ConnectivityPacketTracker { mDisplayName = null; } private final class PacketListener extends BlockingSocketReader { private final class PacketListener extends PacketReader { private final int mIfIndex; private final byte mHwAddr[]; Loading
services/net/java/android/net/ip/IpClient.java +10 −0 Original line number Diff line number Diff line Loading @@ -815,6 +815,15 @@ public class IpClient extends StateMachine { pw.println(Objects.toString(provisioningConfig, "N/A")); pw.decreaseIndent(); final IpReachabilityMonitor iprm = mIpReachabilityMonitor; if (iprm != null) { pw.println(); pw.println(mTag + " current IpReachabilityMonitor state:"); pw.increaseIndent(); iprm.dump(pw); pw.decreaseIndent(); } pw.println(); pw.println(mTag + " StateMachine dump:"); pw.increaseIndent(); Loading Loading @@ -1237,6 +1246,7 @@ public class IpClient extends StateMachine { mIpReachabilityMonitor = new IpReachabilityMonitor( mContext, mInterfaceName, getHandler(), mLog, new IpReachabilityMonitor.Callback() { @Override Loading
services/net/java/android/net/ip/IpNeighborMonitor.java 0 → 100644 +236 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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 android.net.ip; import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkErrorMessage; import android.net.netlink.NetlinkMessage; import android.net.netlink.NetlinkSocket; import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNdMsg; import android.net.netlink.StructNlMsgHdr; import android.net.util.PacketReader; import android.net.util.SharedLog; import android.os.Handler; import android.os.SystemClock; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; import android.system.Os; import android.system.OsConstants; import android.util.Log; import com.android.internal.util.BitUtils; import libcore.io.IoUtils; import libcore.io.Libcore; import java.io.FileDescriptor; import java.net.InetAddress; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.StringJoiner; /** * IpNeighborMonitor. * * Monitors the kernel rtnetlink neighbor notifications and presents to callers * NeighborEvents describing each event. Callers can provide a consumer instance * to both filter (e.g. by interface index and IP address) and handle the * generated NeighborEvents. * * @hide */ public class IpNeighborMonitor extends PacketReader { private static final String TAG = IpNeighborMonitor.class.getSimpleName(); private static final boolean DBG = false; private static final boolean VDBG = false; /** * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND) * for the given IP address on the specified interface index. * * @return 0 if the request was successfully passed to the kernel; otherwise return * a non-zero error code. */ public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) { final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex; if (DBG) { Log.d(TAG, msgSnippet); } final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage( 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null); try { NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg); } catch (ErrnoException e) { Log.e(TAG, "Error " + msgSnippet + ": " + e); return -e.errno; } return 0; } public static class NeighborEvent { final long elapsedMs; final short msgType; final int ifindex; final InetAddress ip; final short nudState; final byte[] linkLayerAddr; public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip, short nudState, byte[] linkLayerAddr) { this.elapsedMs = elapsedMs; this.msgType = msgType; this.ifindex = ifindex; this.ip = ip; this.nudState = nudState; this.linkLayerAddr = linkLayerAddr; } boolean isConnected() { return (msgType != NetlinkConstants.RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState); } boolean isValid() { return (msgType != NetlinkConstants.RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState); } @Override public String toString() { final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}"); return j.add("@" + elapsedMs) .add(NetlinkConstants.stringForNlMsgType(msgType)) .add("if=" + ifindex) .add(ip.getHostAddress()) .add(StructNdMsg.stringForNudState(nudState)) .add("[" + NetlinkConstants.hexify(linkLayerAddr) + "]") .toString(); } } public interface NeighborEventConsumer { // Every neighbor event received on the netlink socket is passed in // here. Subclasses should filter for events of interest. public void accept(NeighborEvent event); } private final SharedLog mLog; private final NeighborEventConsumer mConsumer; public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) { super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE); mLog = log.forSubComponent(TAG); mConsumer = (cb != null) ? cb : (event) -> { /* discard */ }; } @Override protected FileDescriptor createFd() { FileDescriptor fd = null; try { fd = NetlinkSocket.forProto(OsConstants.NETLINK_ROUTE); Os.bind(fd, (SocketAddress)(new NetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH))); Os.connect(fd, (SocketAddress)(new NetlinkSocketAddress(0, 0))); if (VDBG) { final NetlinkSocketAddress nlAddr = (NetlinkSocketAddress) Os.getsockname(fd); Log.d(TAG, "bound to sockaddr_nl{" + BitUtils.uint32(nlAddr.getPortId()) + ", " + nlAddr.getGroupsMask() + "}"); } } catch (ErrnoException|SocketException e) { logError("Failed to create rtnetlink socket", e); IoUtils.closeQuietly(fd); return null; } return fd; } @Override protected void handlePacket(byte[] recvbuf, int length) { final long whenMs = SystemClock.elapsedRealtime(); final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length); byteBuffer.order(ByteOrder.nativeOrder()); parseNetlinkMessageBuffer(byteBuffer, whenMs); } private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) { while (byteBuffer.remaining() > 0) { final int position = byteBuffer.position(); final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer); if (nlMsg == null || nlMsg.getHeader() == null) { byteBuffer.position(position); mLog.e("unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer)); break; } final int srcPortId = nlMsg.getHeader().nlmsg_pid; if (srcPortId != 0) { mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId)); break; } if (nlMsg instanceof NetlinkErrorMessage) { mLog.e("netlink error: " + nlMsg); continue; } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) { mLog.i("non-rtnetlink neighbor msg: " + nlMsg); continue; } evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs); } } private void evaluateRtNetlinkNeighborMessage( RtNetlinkNeighborMessage neighMsg, long whenMs) { final short msgType = neighMsg.getHeader().nlmsg_type; final StructNdMsg ndMsg = neighMsg.getNdHeader(); if (ndMsg == null) { mLog.e("RtNetlinkNeighborMessage without ND message header!"); return; } final int ifindex = ndMsg.ndm_ifindex; final InetAddress destination = neighMsg.getDestination(); final short nudState = (msgType == NetlinkConstants.RTM_DELNEIGH) ? StructNdMsg.NUD_NONE : ndMsg.ndm_state; final NeighborEvent event = new NeighborEvent( whenMs, msgType, ifindex, destination, nudState, neighMsg.getLinkLayerAddress()); if (VDBG) { Log.d(TAG, neighMsg.toString()); } if (DBG) { Log.d(TAG, event.toString()); } mConsumer.accept(event); } }
services/net/java/android/net/ip/IpReachabilityMonitor.java +97 −289 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/net/java/android/net/netlink/NetlinkSocket.java +40 −94 Original line number Diff line number Diff line Loading @@ -16,16 +16,24 @@ package android.net.netlink; import static android.system.OsConstants.AF_NETLINK; import static android.system.OsConstants.EIO; import static android.system.OsConstants.EPROTO; import static android.system.OsConstants.ETIMEDOUT; import static android.system.OsConstants.SO_RCVBUF; import static android.system.OsConstants.SO_RCVTIMEO; import static android.system.OsConstants.SO_SNDTIMEO; import static android.system.OsConstants.SOCK_DGRAM; import static android.system.OsConstants.SOL_SOCKET; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; import android.system.Os; import android.system.OsConstants; import android.system.StructTimeval; import android.util.Log; import libcore.io.IoUtils; import libcore.io.Libcore; import java.io.Closeable; import java.io.FileDescriptor; import java.io.InterruptedIOException; import java.net.SocketAddress; Loading @@ -37,28 +45,27 @@ import java.nio.ByteOrder; /** * NetlinkSocket * * A small wrapper class to assist with AF_NETLINK socket operations. * A small static class to assist with AF_NETLINK socket operations. * * @hide */ public class NetlinkSocket implements Closeable { public class NetlinkSocket { private static final String TAG = "NetlinkSocket"; private static final int SOCKET_RECV_BUFSIZE = 64 * 1024; private static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; final private FileDescriptor mDescriptor; private NetlinkSocketAddress mAddr; private long mLastRecvTimeoutMs; private long mLastSendTimeoutMs; public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; public static final int SOCKET_RECV_BUFSIZE = 64 * 1024; public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException { final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage"; try (NetlinkSocket nlSocket = new NetlinkSocket(nlProto)) { final long IO_TIMEOUT = 300L; nlSocket.connectToKernel(); nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT); final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT); FileDescriptor fd; try { fd = forProto(nlProto); connectToKernel(fd); sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT); final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT); // recvMessage() guaranteed to not return null if it did not throw. final NetlinkMessage response = NetlinkMessage.parse(bytes); if (response != null && response instanceof NetlinkErrorMessage && Loading @@ -81,61 +88,30 @@ public class NetlinkSocket implements Closeable { errmsg = response.toString(); } Log.e(TAG, errPrefix + ", errmsg=" + errmsg); throw new ErrnoException(errmsg, OsConstants.EPROTO); throw new ErrnoException(errmsg, EPROTO); } } catch (InterruptedIOException e) { Log.e(TAG, errPrefix, e); throw new ErrnoException(errPrefix, OsConstants.ETIMEDOUT, e); throw new ErrnoException(errPrefix, ETIMEDOUT, e); } catch (SocketException e) { Log.e(TAG, errPrefix, e); throw new ErrnoException(errPrefix, OsConstants.EIO, e); } } public NetlinkSocket(int nlProto) throws ErrnoException { mDescriptor = Os.socket( OsConstants.AF_NETLINK, OsConstants.SOCK_DGRAM, nlProto); Os.setsockoptInt( mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_RCVBUF, SOCKET_RECV_BUFSIZE); throw new ErrnoException(errPrefix, EIO, e); } public NetlinkSocketAddress getLocalAddress() throws ErrnoException { return (NetlinkSocketAddress) Os.getsockname(mDescriptor); IoUtils.closeQuietly(fd); } public void bind(NetlinkSocketAddress localAddr) throws ErrnoException, SocketException { Os.bind(mDescriptor, (SocketAddress)localAddr); } public void connectTo(NetlinkSocketAddress peerAddr) throws ErrnoException, SocketException { Os.connect(mDescriptor, (SocketAddress) peerAddr); } public void connectToKernel() throws ErrnoException, SocketException { connectTo(new NetlinkSocketAddress(0, 0)); } /** * Wait indefinitely (or until underlying socket error) for a * netlink message of at most DEFAULT_RECV_BUFSIZE size. */ public ByteBuffer recvMessage() throws ErrnoException, InterruptedIOException { return recvMessage(DEFAULT_RECV_BUFSIZE, 0); public static FileDescriptor forProto(int nlProto) throws ErrnoException { final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto); Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE); return fd; } /** * Wait up to |timeoutMs| (or until underlying socket error) for a * netlink message of at most DEFAULT_RECV_BUFSIZE size. */ public ByteBuffer recvMessage(long timeoutMs) throws ErrnoException, InterruptedIOException { return recvMessage(DEFAULT_RECV_BUFSIZE, timeoutMs); public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException { Os.connect(fd, (SocketAddress) (new NetlinkSocketAddress(0, 0))); } private void checkTimeout(long timeoutMs) { private static void checkTimeout(long timeoutMs) { if (timeoutMs < 0) { throw new IllegalArgumentException("Negative timeouts not permitted"); } Loading @@ -147,21 +123,14 @@ public class NetlinkSocket implements Closeable { * * Multi-threaded calls with different timeouts will cause unexpected results. */ public ByteBuffer recvMessage(int bufsize, long timeoutMs) public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs) throws ErrnoException, IllegalArgumentException, InterruptedIOException { checkTimeout(timeoutMs); synchronized (mDescriptor) { if (mLastRecvTimeoutMs != timeoutMs) { Os.setsockoptTimeval(mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); mLastRecvTimeoutMs = timeoutMs; } } Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); int length = Os.read(mDescriptor, byteBuffer); int length = Os.read(fd, byteBuffer); if (length == bufsize) { Log.w(TAG, "maximum read"); } Loading @@ -171,40 +140,17 @@ public class NetlinkSocket implements Closeable { return byteBuffer; } /** * Send a message to a peer to which this socket has previously connected. * * This blocks until completion or an error occurs. */ public boolean sendMessage(byte[] bytes, int offset, int count) throws ErrnoException, InterruptedIOException { return sendMessage(bytes, offset, count, 0); } /** * Send a message to a peer to which this socket has previously connected, * waiting at most |timeoutMs| milliseconds for the send to complete. * * Multi-threaded calls with different timeouts will cause unexpected results. */ public boolean sendMessage(byte[] bytes, int offset, int count, long timeoutMs) public static int sendMessage( FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs) throws ErrnoException, IllegalArgumentException, InterruptedIOException { checkTimeout(timeoutMs); synchronized (mDescriptor) { if (mLastSendTimeoutMs != timeoutMs) { Os.setsockoptTimeval(mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); mLastSendTimeoutMs = timeoutMs; } } return (count == Os.write(mDescriptor, bytes, offset, count)); } @Override public void close() { IoUtils.closeQuietly(mDescriptor); Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); return Os.write(fd, bytes, offset, count); } }