/*******************************************************************************
* Copyright (c) MOBAC developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package mobac.utilities.debug;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
import java.net.SocketImplFactory;
import java.net.URL;
import mobac.program.Logging;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
/**
* Proxies the default {@link SocketImpl} using reflection. This allows to trace
* all calls into the log file.
*
* Requires SunJRE/SunJDK!
*/
public class MySocketImplFactory implements SocketImplFactory {
private static Logger log = Logger.getLogger(MySocketImplFactory.class);
/**
* @param args
*/
public static void main(String[] args) {
try {
install();
Logging.configureConsoleLogging(Level.TRACE);
HttpURLConnection conn = (HttpURLConnection) new URL("http://google.de")
.openConnection();
conn.connect();
byte[] data = new byte[1024];
new DataInputStream(conn.getInputStream()).readFully(data);
System.out.println(new String(data));
Thread.sleep(1000);
System.gc();
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void install() throws IOException {
try {
Socket.setSocketImplFactory(new MySocketImplFactory());
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException("Unable to install " + MySocketImplFactory.class.getSimpleName(),
e);
}
}
private final Constructor<?> constructor;
private final Method accept;
private final Method bind;
private final Method available;
private final Method create;
private final Method connect1;
private final Method connect2;
private final Method connect3;
private final Method close;
private final Method getInputStream;
private final Method getOutputStream;
private final Method sendUrgentData;
private final Method listen;
public MySocketImplFactory() throws ClassNotFoundException, SecurityException,
NoSuchMethodException {
super();
Class<?> c = Class.forName("java.net.PlainSocketImpl");
constructor = c.getDeclaredConstructor();
constructor.setAccessible(true);
accept = c.getDeclaredMethod("accept", SocketImpl.class);
accept.setAccessible(true);
bind = c.getDeclaredMethod("bind", InetAddress.class, Integer.TYPE);
bind.setAccessible(true);
available = c.getDeclaredMethod("available");
available.setAccessible(true);
create = c.getDeclaredMethod("create", Boolean.TYPE);
create.setAccessible(true);
connect1 = c.getDeclaredMethod("connect", InetAddress.class, Integer.TYPE);
connect1.setAccessible(true);
connect2 = c.getDeclaredMethod("connect", SocketAddress.class, Integer.TYPE);
connect2.setAccessible(true);
connect3 = c.getDeclaredMethod("connect", String.class, Integer.TYPE);
connect3.setAccessible(true);
getInputStream = c.getDeclaredMethod("getInputStream");
getInputStream.setAccessible(true);
getOutputStream = c.getDeclaredMethod("getOutputStream");
getOutputStream.setAccessible(true);
close = c.getDeclaredMethod("close");
close.setAccessible(true);
sendUrgentData = c.getDeclaredMethod("sendUrgentData", Integer.TYPE);
sendUrgentData.setAccessible(true);
listen = c.getDeclaredMethod("listen", Integer.TYPE);
listen.setAccessible(true);
}
public SocketImpl createSocketImpl() {
try {
return new MySocketImpl();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private class MySocketImpl extends SocketImpl {
private final SocketImpl si;
private final int socketId;
private MySocketImpl() throws IllegalArgumentException, InstantiationException,
IllegalAccessException, InvocationTargetException {
si = (SocketImpl) constructor.newInstance();
socketId = si.hashCode();
log.trace("[" + socketId + "] new SocketImpl created");
}
@Override
protected void finalize() throws Throwable {
close();
super.finalize();
}
@Override
protected void accept(SocketImpl s) throws IOException {
log.trace("[" + socketId + "] accept(...)");
try {
accept.invoke(si, s);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
@Override
protected int available() throws IOException {
// log.trace("[" + socketId + "] available()");
try {
return ((Integer) bind.invoke(si)).intValue();
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
@Override
protected void bind(InetAddress host, int port) throws IOException {
log.trace("[" + socketId + "] bind()");
try {
bind.invoke(si, host, port);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
@Override
protected void close() throws IOException {
log.trace("[" + socketId + "] close()");
try {
close.invoke(si);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
@Override
protected void connect(InetAddress address, int port) throws IOException {
log.trace("[" + socketId + "] connect1(..)");
try {
connect1.invoke(si, address, port);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
@Override
protected void connect(SocketAddress address, int timeout) throws IOException {
log.trace("[" + socketId + "] connect2(..)");
try {
connect2.invoke(si, address, timeout);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
@Override
protected void connect(String host, int port) throws IOException {
log.trace("[" + socketId + "] connect3(..)");
try {
connect3.invoke(si, host, port);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
@Override
protected void create(boolean stream) throws IOException {
log.trace("[" + socketId + "] create(..)");
try {
create.invoke(si, stream);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
@Override
protected InputStream getInputStream() throws IOException {
// log.trace("[" + socketId + "] getInputStream()");
try {
return (InputStream) getInputStream.invoke(si);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
public Object getOption(int optID) throws SocketException {
// log.trace("[" + socketId + "] getOption(..)");
return si.getOption(optID);
}
@Override
protected OutputStream getOutputStream() throws IOException {
// log.trace("[" + socketId + "] getOutputStream()");
try {
return (OutputStream) getOutputStream.invoke(si);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
@Override
protected void listen(int backlog) throws IOException {
log.trace("[" + socketId + "] listen(..)");
try {
listen.invoke(si, backlog);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
@Override
protected void sendUrgentData(int data) throws IOException {
// log.trace("[" + socketId + "] sendUrgentData");
try {
sendUrgentData.invoke(si, data);
} catch (Exception e) {
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
}
}
public void setOption(int optID, Object value) throws SocketException {
// log.trace("[" + socketId + "] setOption");
si.setOption(optID, value);
}
}
}