Merge "Refactor RouterAdvertisementDaemon with FdEventsReader" into main
This commit is contained in:
commit
093433c8b8
1 changed files with 105 additions and 33 deletions
|
|
@ -18,6 +18,7 @@ package android.net.ip;
|
|||
|
||||
import static android.system.OsConstants.AF_INET6;
|
||||
import static android.system.OsConstants.IPPROTO_ICMPV6;
|
||||
import static android.system.OsConstants.SOCK_NONBLOCK;
|
||||
import static android.system.OsConstants.SOCK_RAW;
|
||||
import static android.system.OsConstants.SOL_SOCKET;
|
||||
import static android.system.OsConstants.SO_SNDTIMEO;
|
||||
|
|
@ -38,12 +39,19 @@ import android.net.LinkAddress;
|
|||
import android.net.MacAddress;
|
||||
import android.net.TrafficStats;
|
||||
import android.net.util.SocketUtils;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.StructTimeval;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.net.module.util.FdEventsReader;
|
||||
import com.android.net.module.util.InterfaceParams;
|
||||
import com.android.net.module.util.structs.Icmpv6Header;
|
||||
import com.android.net.module.util.structs.LlaOption;
|
||||
|
|
@ -103,6 +111,10 @@ public class RouterAdvertisementDaemon {
|
|||
|
||||
private static final int DAY_IN_SECONDS = 86_400;
|
||||
|
||||
// Commands for IpServer to control RouterAdvertisementDaemon
|
||||
private static final int CMD_START = 1;
|
||||
private static final int CMD_STOP = 2;
|
||||
|
||||
private final InterfaceParams mInterface;
|
||||
private final InetSocketAddress mAllNodes;
|
||||
|
||||
|
|
@ -120,9 +132,13 @@ public class RouterAdvertisementDaemon {
|
|||
@GuardedBy("mLock")
|
||||
private RaParams mRaParams;
|
||||
|
||||
// To be accessed only from RaMessageHandler
|
||||
private RsPacketListener mRsPacketListener;
|
||||
|
||||
private volatile FileDescriptor mSocket;
|
||||
private volatile MulticastTransmitter mMulticastTransmitter;
|
||||
private volatile UnicastResponder mUnicastResponder;
|
||||
private volatile RaMessageHandler mRaMessageHandler;
|
||||
private volatile HandlerThread mRaHandlerThread;
|
||||
|
||||
/** Encapsulate the RA parameters for RouterAdvertisementDaemon.*/
|
||||
public static class RaParams {
|
||||
|
|
@ -244,6 +260,74 @@ public class RouterAdvertisementDaemon {
|
|||
}
|
||||
}
|
||||
|
||||
private class RaMessageHandler extends Handler {
|
||||
RaMessageHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case CMD_START:
|
||||
mRsPacketListener = new RsPacketListener(this);
|
||||
mRsPacketListener.start();
|
||||
break;
|
||||
case CMD_STOP:
|
||||
if (mRsPacketListener != null) {
|
||||
mRsPacketListener.stop();
|
||||
mRsPacketListener = null;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unknown message, cmd = " + String.valueOf(msg.what));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class RsPacketListener extends FdEventsReader<RsPacketListener.RecvBuffer> {
|
||||
private static final class RecvBuffer {
|
||||
// The recycled buffer for receiving Router Solicitations from clients.
|
||||
// If the RS is larger than IPV6_MIN_MTU the packets are truncated.
|
||||
// This is fine since currently only byte 0 is examined anyway.
|
||||
final byte[] mBytes = new byte[IPV6_MIN_MTU];
|
||||
final InetSocketAddress mSrcAddr = new InetSocketAddress(0);
|
||||
}
|
||||
|
||||
RsPacketListener(@NonNull Handler handler) {
|
||||
super(handler, new RecvBuffer());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int recvBufSize(@NonNull RecvBuffer buffer) {
|
||||
return buffer.mBytes.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileDescriptor createFd() {
|
||||
return mSocket;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int readPacket(@NonNull FileDescriptor fd, @NonNull RecvBuffer buffer)
|
||||
throws Exception {
|
||||
return Os.recvfrom(
|
||||
fd, buffer.mBytes, 0, buffer.mBytes.length, 0 /* flags */, buffer.mSrcAddr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handlePacket(@NonNull RecvBuffer buffer, int length) {
|
||||
// Do the least possible amount of validations.
|
||||
if (buffer.mSrcAddr == null
|
||||
|| length <= 0
|
||||
|| buffer.mBytes[0] != asByte(ICMPV6_ROUTER_SOLICITATION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
maybeSendRA(buffer.mSrcAddr);
|
||||
}
|
||||
}
|
||||
|
||||
public RouterAdvertisementDaemon(InterfaceParams ifParams) {
|
||||
mInterface = ifParams;
|
||||
mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
|
||||
|
|
@ -274,26 +358,36 @@ public class RouterAdvertisementDaemon {
|
|||
/** Start router advertisement daemon. */
|
||||
public boolean start() {
|
||||
if (!createSocket()) {
|
||||
Log.e(TAG, "Failed to start RouterAdvertisementDaemon.");
|
||||
return false;
|
||||
}
|
||||
|
||||
mMulticastTransmitter = new MulticastTransmitter();
|
||||
mMulticastTransmitter.start();
|
||||
|
||||
mUnicastResponder = new UnicastResponder();
|
||||
mUnicastResponder.start();
|
||||
mRaHandlerThread = new HandlerThread(TAG);
|
||||
mRaHandlerThread.start();
|
||||
mRaMessageHandler = new RaMessageHandler(mRaHandlerThread.getLooper());
|
||||
|
||||
return true;
|
||||
return sendMessage(CMD_START);
|
||||
}
|
||||
|
||||
/** Stop router advertisement daemon. */
|
||||
public void stop() {
|
||||
if (!sendMessage(CMD_STOP)) {
|
||||
Log.e(TAG, "RouterAdvertisementDaemon has been stopped or was never started.");
|
||||
return;
|
||||
}
|
||||
|
||||
mRaHandlerThread.quitSafely();
|
||||
mRaHandlerThread = null;
|
||||
mRaMessageHandler = null;
|
||||
|
||||
closeSocket();
|
||||
// Wake up mMulticastTransmitter thread to interrupt a potential 1 day sleep before
|
||||
// the thread's termination.
|
||||
maybeNotifyMulticastTransmitter();
|
||||
mMulticastTransmitter = null;
|
||||
mUnicastResponder = null;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
|
|
@ -503,7 +597,7 @@ public class RouterAdvertisementDaemon {
|
|||
|
||||
final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_NEIGHBOR);
|
||||
try {
|
||||
mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
||||
mSocket = Os.socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_ICMPV6);
|
||||
// Setting SNDTIMEO is purely for defensive purposes.
|
||||
Os.setsockoptTimeval(
|
||||
mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(send_timout_ms));
|
||||
|
|
@ -565,34 +659,12 @@ public class RouterAdvertisementDaemon {
|
|||
}
|
||||
}
|
||||
|
||||
private final class UnicastResponder extends Thread {
|
||||
private final InetSocketAddress mSolicitor = new InetSocketAddress(0);
|
||||
// The recycled buffer for receiving Router Solicitations from clients.
|
||||
// If the RS is larger than IPV6_MIN_MTU the packets are truncated.
|
||||
// This is fine since currently only byte 0 is examined anyway.
|
||||
private final byte[] mSolicitation = new byte[IPV6_MIN_MTU];
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (isSocketValid()) {
|
||||
try {
|
||||
// Blocking receive.
|
||||
final int rval = Os.recvfrom(
|
||||
mSocket, mSolicitation, 0, mSolicitation.length, 0, mSolicitor);
|
||||
// Do the least possible amount of validation.
|
||||
if (rval < 1 || mSolicitation[0] != asByte(ICMPV6_ROUTER_SOLICITATION)) {
|
||||
continue;
|
||||
}
|
||||
} catch (ErrnoException | SocketException e) {
|
||||
if (isSocketValid()) {
|
||||
Log.e(TAG, "recvfrom error: " + e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
maybeSendRA(mSolicitor);
|
||||
}
|
||||
private boolean sendMessage(int cmd) {
|
||||
if (mRaMessageHandler == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mRaMessageHandler.sendMessage(Message.obtain(mRaMessageHandler, cmd));
|
||||
}
|
||||
|
||||
// TODO: Consider moving this to run on a provided Looper as a Handler,
|
||||
|
|
|
|||
Loading…
Reference in a new issue