Merge "Restrict scope of switch Repair Mode"
This commit is contained in:
@@ -42,7 +42,6 @@ import android.net.NetworkUtils;
|
|||||||
import android.net.SocketKeepalive.InvalidPacketException;
|
import android.net.SocketKeepalive.InvalidPacketException;
|
||||||
import android.net.SocketKeepalive.InvalidSocketException;
|
import android.net.SocketKeepalive.InvalidSocketException;
|
||||||
import android.net.TcpKeepalivePacketData;
|
import android.net.TcpKeepalivePacketData;
|
||||||
import android.net.TcpKeepalivePacketData.TcpSocketInfo;
|
|
||||||
import android.net.util.IpUtils;
|
import android.net.util.IpUtils;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -492,19 +491,14 @@ public class KeepaliveTracker {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TcpKeepalivePacketData packet = null;
|
final TcpKeepalivePacketData packet;
|
||||||
try {
|
try {
|
||||||
TcpSocketInfo tsi = TcpKeepaliveController.switchToRepairMode(fd);
|
packet = TcpKeepaliveController.getTcpKeepalivePacket(fd);
|
||||||
packet = TcpKeepalivePacketData.tcpKeepalivePacket(tsi);
|
|
||||||
} catch (InvalidPacketException | InvalidSocketException e) {
|
} catch (InvalidPacketException | InvalidSocketException e) {
|
||||||
try {
|
|
||||||
TcpKeepaliveController.switchOutOfRepairMode(fd);
|
|
||||||
} catch (ErrnoException e1) {
|
|
||||||
Log.e(TAG, "Couldn't move fd out of repair mode after failure to start keepalive");
|
|
||||||
}
|
|
||||||
notifyErrorCallback(cb, e.error);
|
notifyErrorCallback(cb, e.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeepaliveInfo ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
|
KeepaliveInfo ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
|
||||||
KeepaliveInfo.TYPE_TCP, fd);
|
KeepaliveInfo.TYPE_TCP, fd);
|
||||||
Log.d(TAG, "Created keepalive: " + ki.toString());
|
Log.d(TAG, "Created keepalive: " + ki.toString());
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ import static android.system.OsConstants.TIOCOUTQ;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.net.NetworkUtils;
|
import android.net.NetworkUtils;
|
||||||
|
import android.net.SocketKeepalive.InvalidPacketException;
|
||||||
import android.net.SocketKeepalive.InvalidSocketException;
|
import android.net.SocketKeepalive.InvalidSocketException;
|
||||||
|
import android.net.TcpKeepalivePacketData;
|
||||||
import android.net.TcpKeepalivePacketData.TcpSocketInfo;
|
import android.net.TcpKeepalivePacketData.TcpSocketInfo;
|
||||||
import android.net.TcpRepairWindow;
|
import android.net.TcpRepairWindow;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -103,16 +105,25 @@ public class TcpKeepaliveController {
|
|||||||
mFdHandlerQueue = connectivityServiceHandler.getLooper().getQueue();
|
mFdHandlerQueue = connectivityServiceHandler.getLooper().getQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Build tcp keepalive packet. */
|
||||||
|
public static TcpKeepalivePacketData getTcpKeepalivePacket(@NonNull FileDescriptor fd)
|
||||||
|
throws InvalidPacketException, InvalidSocketException {
|
||||||
|
try {
|
||||||
|
final TcpSocketInfo tsi = switchToRepairMode(fd);
|
||||||
|
return TcpKeepalivePacketData.tcpKeepalivePacket(tsi);
|
||||||
|
} catch (InvalidPacketException | InvalidSocketException e) {
|
||||||
|
switchOutOfRepairMode(fd);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Switch the tcp socket to repair mode and query tcp socket information.
|
* Switch the tcp socket to repair mode and query detail tcp information.
|
||||||
*
|
*
|
||||||
* @param fd the fd of socket on which to use keepalive offload
|
* @param fd the fd of socket on which to use keepalive offload.
|
||||||
* @return a {@link TcpKeepalivePacketData#TcpSocketInfo} object for current
|
* @return a {@link TcpKeepalivePacketData#TcpSocketInfo} object for current
|
||||||
* tcp/ip information.
|
* tcp/ip information.
|
||||||
*/
|
*/
|
||||||
// TODO : make this private. It's far too confusing that this gets called from outside
|
private static TcpSocketInfo switchToRepairMode(FileDescriptor fd)
|
||||||
// at a time that nobody can understand.
|
|
||||||
public static TcpSocketInfo switchToRepairMode(FileDescriptor fd)
|
|
||||||
throws InvalidSocketException {
|
throws InvalidSocketException {
|
||||||
if (DBG) Log.i(TAG, "switchToRepairMode to start tcp keepalive : " + fd);
|
if (DBG) Log.i(TAG, "switchToRepairMode to start tcp keepalive : " + fd);
|
||||||
final SocketAddress srcSockAddr;
|
final SocketAddress srcSockAddr;
|
||||||
@@ -157,10 +168,12 @@ public class TcpKeepaliveController {
|
|||||||
// Query sequence and ack number
|
// Query sequence and ack number
|
||||||
dropAllIncomingPackets(fd, true);
|
dropAllIncomingPackets(fd, true);
|
||||||
try {
|
try {
|
||||||
// Enter tcp repair mode.
|
// Switch to tcp repair mode.
|
||||||
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_ON);
|
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_ON);
|
||||||
|
|
||||||
// Check if socket is idle.
|
// Check if socket is idle.
|
||||||
if (!isSocketIdle(fd)) {
|
if (!isSocketIdle(fd)) {
|
||||||
|
Log.e(TAG, "Socket is not idle");
|
||||||
throw new InvalidSocketException(ERROR_SOCKET_NOT_IDLE);
|
throw new InvalidSocketException(ERROR_SOCKET_NOT_IDLE);
|
||||||
}
|
}
|
||||||
// Query write sequence number from SEND_QUEUE.
|
// Query write sequence number from SEND_QUEUE.
|
||||||
@@ -173,9 +186,14 @@ public class TcpKeepaliveController {
|
|||||||
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE);
|
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE);
|
||||||
// Finally, check if socket is still idle. TODO : this check needs to move to
|
// Finally, check if socket is still idle. TODO : this check needs to move to
|
||||||
// after starting polling to prevent a race.
|
// after starting polling to prevent a race.
|
||||||
if (!isSocketIdle(fd)) {
|
if (!isReceiveQueueEmpty(fd)) {
|
||||||
|
Log.e(TAG, "Fatal: receive queue of this socket is not empty");
|
||||||
throw new InvalidSocketException(ERROR_INVALID_SOCKET);
|
throw new InvalidSocketException(ERROR_INVALID_SOCKET);
|
||||||
}
|
}
|
||||||
|
if (!isSendQueueEmpty(fd)) {
|
||||||
|
Log.e(TAG, "Socket is not idle");
|
||||||
|
throw new InvalidSocketException(ERROR_SOCKET_NOT_IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
// Query tcp window size.
|
// Query tcp window size.
|
||||||
trw = NetworkUtils.getTcpRepairWindow(fd);
|
trw = NetworkUtils.getTcpRepairWindow(fd);
|
||||||
@@ -205,10 +223,13 @@ public class TcpKeepaliveController {
|
|||||||
*
|
*
|
||||||
* @param fd the fd of socket to switch back to normal.
|
* @param fd the fd of socket to switch back to normal.
|
||||||
*/
|
*/
|
||||||
// TODO : make this private.
|
private static void switchOutOfRepairMode(@NonNull final FileDescriptor fd) {
|
||||||
public static void switchOutOfRepairMode(@NonNull final FileDescriptor fd)
|
try {
|
||||||
throws ErrnoException {
|
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_OFF);
|
||||||
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_OFF);
|
} catch (ErrnoException e) {
|
||||||
|
Log.e(TAG, "Cannot switch socket out of repair mode", e);
|
||||||
|
// Well, there is not much to do here to recover
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -262,13 +283,8 @@ public class TcpKeepaliveController {
|
|||||||
mListeners.remove(slot);
|
mListeners.remove(slot);
|
||||||
}
|
}
|
||||||
mFdHandlerQueue.removeOnFileDescriptorEventListener(fd);
|
mFdHandlerQueue.removeOnFileDescriptorEventListener(fd);
|
||||||
try {
|
if (DBG) Log.d(TAG, "Moving socket out of repair mode for stop : " + fd);
|
||||||
if (DBG) Log.d(TAG, "Moving socket out of repair mode for stop : " + fd);
|
switchOutOfRepairMode(fd);
|
||||||
switchOutOfRepairMode(fd);
|
|
||||||
} catch (ErrnoException e) {
|
|
||||||
Log.e(TAG, "Cannot switch socket out of repair mode", e);
|
|
||||||
// Well, there is not much to do here to recover
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InetAddress getAddress(InetSocketAddress inetAddr) {
|
private static InetAddress getAddress(InetSocketAddress inetAddr) {
|
||||||
|
|||||||
Reference in New Issue
Block a user