-
-
Notifications
You must be signed in to change notification settings - Fork 828
Description
@raphw Pleas help.
We’re facing an issue where our code creates a large number of sockets, and once we hit the OS limit for file descriptors, the program shuts down. We increased the limit using ulimit -n 65535
, but it still feels like a ticking time bomb.
The codebase is large, and we’re not able to find who is creating the sockets or from where. We use Apache HttpClient and many other third-party libraries, so it’s possible a third-party library is doing this.
lsof -p <OUR_CODE_PID> output
lsof -p <OUR_CODE_PID>
# Thousands of sockets like the following are being created:
java <OUR_CODE_PID> <user> <FILE_DESCRIPTOR>u sock(<TYPE_OF_DESCRIPTOR>) 0,9 0t0 <KERNEL_SOCKET_INODE> protocol: TCP
We tried to gather more information using OS commands, but the OS reports these as UNBOUND/EPHEMERAL
and we can’t get any additional details.
We support Java 17, but the current version runs on Java 8.
We attempted to write a java.net.Socket
interceptor using byte-buddy-agent-1.10.0.jar
and byte-buddy-dep-1.10.0.jar
to intercept the java.net.Socket
constructor, but it isn’t working.
We tested the same code against a custom class and it works fine.
Our research suggests that java.net.Socket
is a bootstrap class, so we need to inject the agent into the bootstrap class loader. We tried that as well, but it’s still not working.
Can someone point us in the right direction?
SocketCreationAgent
import java.io.File;
import java.lang.instrument.Instrumentation;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.matcher.ElementMatchers;
public class SocketCreationAgent {
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("SocketCreationAgent loaded");
// WORKS (custom class)
new AgentBuilder.Default()
.ignore(ElementMatchers.none())
.type(ElementMatchers.named("com.soa.socket.interceptor.agent.test.InterceptThisClass"))
.transform((builder, typeDescription, classLoader, module) -> {
System.out.println("Transforming class: " + typeDescription.getName());
return builder.constructor(ElementMatchers.any())
.intercept(Advice.to(SocketInterceptorAdvice.class));
})
.installOn(inst);
// DOES NOT WORK (bootstrap class)
new AgentBuilder.Default()
.ignore(ElementMatchers.none())
.type(ElementMatchers.named("java.net.Socket"))
.transform((builder, typeDescription, classLoader, module) -> {
System.out.println("Transforming class: " + typeDescription.getName());
return builder.constructor(ElementMatchers.any())
.intercept(Advice.to(SocketInterceptorAdvice.class));
})
.installOn(inst);
// DOES NOT WORK (with bootstrap injection)
// Path to the agent JAR that includes SocketInterceptorAdvice.class
File agentJar = new File("socket.interceptor-0.0.1-SNAPSHOT.jar");
new AgentBuilder.Default()
.ignore(ElementMatchers.none())
.enableBootstrapInjection(inst, agentJar) // allow bootstrap class loader to see advice
.type(ElementMatchers.named("java.net.Socket"))
.transform((builder, typeDescription, classLoader, module) -> {
System.out.println("Transforming java.net.Socket");
return builder.constructor(ElementMatchers.any())
.intercept(Advice.to(SocketInterceptorAdvice.class));
})
.installOn(inst);
}
}
SocketInterceptorAdvice
import net.bytebuddy.asm.Advice;
public class SocketInterceptorAdvice {
@Advice.OnMethodEnter
public static void onEnter() {
System.out.println("SocketInterceptorAdvice: constructor called");
Thread.dumpStack();
}
@Advice.OnMethodExit
public static void onExit() {
System.out.println("SocketInterceptorAdvice: constructor finished");
}
}
InterceptThisClass
public class InterceptThisClass {
public InterceptThisClass() {
System.out.println("In Test Constructor.");
}
}
SocketInterceptorTest
import java.io.IOException;
import java.net.Socket;
public class SocketInterceptorTest {
public static void main(String[] args) throws IOException {
// Open a few sockets to test interception
for (int i = 0; i < 3; i++) {
InterceptThisClass t = new InterceptThisClass();
Socket socket = new Socket();
// Socket socket = new Socket("google.com", 80);
}
}
}
Running the test
java -javaagent:/<path>/socket.interceptor-0.0.1-SNAPSHOT.jar SocketInterceptorTest
Sample output which works for custom class but not for java.net.Socket
SocketCreationAgent loaded
Transforming class: socket.interceptor.agent.test.InterceptThisClass
SocketInterceptorAdvice: constructor called
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1336)
at socket.interceptor.agent.test.InterceptThisClass.<init>(InterceptThisClass.java)
at socket.interceptor.agent.test.SocketInterceptorTest.main(SocketInterceptorTest.java:11)
In Test Constructor.
SocketInterceptorAdvice: constructor finished
Transforming class: java.net.Socket
Transforming java.net.Socket
SocketInterceptorAdvice: constructor called
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1336)
at socket.interceptor.agent.test.InterceptThisClass.<init>(InterceptThisClass.java)
at socket.interceptor.agent.test.SocketInterceptorTest.main(SocketInterceptorTest.java:11)
In Test Constructor.
SocketInterceptorAdvice: constructor finished
SocketInterceptorAdvice: constructor called
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1336)
at socket.interceptor.agent.test.InterceptThisClass.<init>(InterceptThisClass.java)
at socket.interceptor.agent.test.SocketInterceptorTest.main(SocketInterceptorTest.java:11)
In Test Constructor.
SocketInterceptorAdvice: constructor finished