Android Question Reflection, TCP Socket and how can I change TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT

HectorPuk

New Member
Licensed User
Hello Folks,

My name is Héctor and this is my first post. I have a basic understanding of java and some experience with VB.

For my socket client app, I am trying to change the three parameters mention on the subject.

By means of Reflection, I was able to enable the keepalive in my socket.

B4X:
Dim ClientApp As Socket
Dim r as Reflector

ClientApp.Connect("192.168.1.8",10003, 500)
r.Target = ClientApp
r.Target = r.GetField("socket")
r.RunMethod2("setKeepAlive", True, "java.lang.boolean")

I was able to change TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT at Android level using adb shell. The effect is for all sockets until the next Andriod recycle

B4X:
echo 60 > /proc/sys/net/ipv4/tcp_keepalive_time

  # echo 10 > /proc/sys/net/ipv4/tcp_keepalive_intvl

  # echo 5 > /proc/sys/net/ipv4/tcp_keepalive_probes

Now I want to change from within my B4A app and just for my session. Searching for it I have found a class -android.system.Os- that has the method "public static void setsockoptInt(FileDescriptor fd, int level, int option, int value)" that should allow me to do what I need.

The problem is that this class cannot be instantiated and I dont know if that is possible with reflection.

Does anyone have an idea to deal with this? I havent seen B4A JavaObject because I am trying to stick to Reflection.

Best Regards.

Hector.
 

OliverA

Expert
Licensed User
Longtime User
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
With inline Java:
B4X:
Sub Activity_Click
   Dim s As Socket
   s.Initialize("S")
   Dim r As Reflector
   r.Target = s
   Dim socket As JavaObject = r.GetField("socket")
   Dim jo As JavaObject = Me
   jo.RunMethod("setKeepaliveSocketOptions", Array(socket, 1000, 1000, 3))
End Sub

#if Java

import java.io.FileDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.Socket;
private final static int SOL_TCP = 6;
     private final static int TCP_KEEPIDLE = 4;
     private final static int TCP_KEEPINTVL = 5;
     private final static int TCP_KEEPCNT = 6;

public static void setKeepaliveSocketOptions(Socket socket, int idleTimeout, int interval, int count) throws Exception{
      socket.setKeepAlive(true);
      Field socketImplField = Class.forName("java.net.Socket").getDeclaredField("impl");
      socketImplField.setAccessible(true);
      if(socketImplField != null) {
      Object plainSocketImpl = socketImplField.get(socket);
      Field fileDescriptorField = Class.forName("java.net.SocketImpl").getDeclaredField("fd");
      if(fileDescriptorField != null) {
      fileDescriptorField.setAccessible(true);
      FileDescriptor fileDescriptor = (FileDescriptor)fileDescriptorField.get(plainSocketImpl);
      Class libCoreClass = Class.forName("libcore.io.Libcore");
      Field osField = libCoreClass.getDeclaredField("os");
      osField.setAccessible(true);
      Object libcoreOs = osField.get(libCoreClass);
      Method setSocketOptsMethod = Class.forName("libcore.io.ForwardingOs").getDeclaredMethod("setsockoptInt", FileDescriptor.class, int.class, int.class, int.class);
      if(setSocketOptsMethod != null) {
      setSocketOptsMethod.invoke(libcoreOs, fileDescriptor, SOL_TCP, TCP_KEEPIDLE, idleTimeout);
      setSocketOptsMethod.invoke(libcoreOs, fileDescriptor, SOL_TCP, TCP_KEEPINTVL, interval);
      setSocketOptsMethod.invoke(libcoreOs, fileDescriptor, SOL_TCP, TCP_KEEPCNT, count);
      }
      }
      }
     }
#End If

Seems to work fine.
 
Upvote 0

HectorPuk

New Member
Licensed User
With inline Java:
B4X:
Sub Activity_Click
   Dim s As Socket
   s.Initialize("S")
   Dim r As Reflector
   r.Target = s
   Dim socket As JavaObject = r.GetField("socket")
   Dim jo As JavaObject = Me
   jo.RunMethod("setKeepaliveSocketOptions", Array(socket, 1000, 1000, 3))
End Sub

#if Java

import java.io.FileDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.Socket;
private final static int SOL_TCP = 6;
     private final static int TCP_KEEPIDLE = 4;
     private final static int TCP_KEEPINTVL = 5;
     private final static int TCP_KEEPCNT = 6;

public static void setKeepaliveSocketOptions(Socket socket, int idleTimeout, int interval, int count) throws Exception{
      socket.setKeepAlive(true);
      Field socketImplField = Class.forName("java.net.Socket").getDeclaredField("impl");
      socketImplField.setAccessible(true);
      if(socketImplField != null) {
      Object plainSocketImpl = socketImplField.get(socket);
      Field fileDescriptorField = Class.forName("java.net.SocketImpl").getDeclaredField("fd");
      if(fileDescriptorField != null) {
      fileDescriptorField.setAccessible(true);
      FileDescriptor fileDescriptor = (FileDescriptor)fileDescriptorField.get(plainSocketImpl);
      Class libCoreClass = Class.forName("libcore.io.Libcore");
      Field osField = libCoreClass.getDeclaredField("os");
      osField.setAccessible(true);
      Object libcoreOs = osField.get(libCoreClass);
      Method setSocketOptsMethod = Class.forName("libcore.io.ForwardingOs").getDeclaredMethod("setsockoptInt", FileDescriptor.class, int.class, int.class, int.class);
      if(setSocketOptsMethod != null) {
      setSocketOptsMethod.invoke(libcoreOs, fileDescriptor, SOL_TCP, TCP_KEEPIDLE, idleTimeout);
      setSocketOptsMethod.invoke(libcoreOs, fileDescriptor, SOL_TCP, TCP_KEEPINTVL, interval);
      setSocketOptsMethod.invoke(libcoreOs, fileDescriptor, SOL_TCP, TCP_KEEPCNT, count);
      }
      }
      }
     }
#End If

Seems to work fine.

Thanks a lot Erel!! I didnt know about inline Java. Sound more than perfect.
 
Upvote 0
Top