Commit 16fd0d59 authored by Vít Kabele's avatar Vít Kabele

Server protobuf. Proof of concept. No error checks

parent f39e3e9f
......@@ -26,15 +26,7 @@
<classpathentry kind="src" path="disl/src-test"/>
<classpathentry kind="src" path="shvm/src/src-dislreserver"/>
<classpathentry kind="src" path="shvm/src/src-msg-analyze"/>
<classpathentry kind="src" path="shvm/src/src-msg-close"/>
<classpathentry kind="src" path="shvm/src/src-msg-classinfo"/>
<classpathentry kind="src" path="shvm/src/src-msg-newclass"/>
<classpathentry kind="src" path="shvm/src/src-msg-objfree"/>
<classpathentry kind="src" path="shvm/src/src-msg-reganalysis"/>
<classpathentry kind="src" path="shvm/src/src-msg-instr"/>
<classpathentry kind="src" path="shvm/src/src-msg-stringinfo"/>
<classpathentry kind="src" path="shvm/src/src-msg-threadend"/>
<classpathentry kind="src" path="shvm/src/src-msg-threadinfo"/>
<classpathentry kind="src" path="shvm/src/src-msg-analyze-mtdispatch"/>
<classpathentry kind="src" path="shvm/src/src-remoteanalysis"/>
<classpathentry kind="src" path="shvm/src/src-reqdispatch"/>
......@@ -42,6 +34,7 @@
<classpathentry kind="src" path="shvm/src/src-util"/>
<classpathentry kind="src" path="shvm/src/src-server-api"/>
<classpathentry kind="src" path="shvm/src-test"/>
<classpathentry kind="src" path="shvm/src/src-proto"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="output/lib/disl-bypass.jar"/>
<classpathentry kind="lib" path="lib/disl/log4j.jar" sourcepath="lib/devel/log4j-source.jar"/>
......
......@@ -55,15 +55,8 @@
<src path="src/src-dislreserver" />
<src path="src/src-msg-analyze" />
<src path="src/src-msg-analyze-mtdispatch" />
<src path="src/src-msg-classinfo" />
<src path="src/src-msg-close" />
<src path="src/src-msg-instr" />
<src path="src/src-msg-newclass" />
<src path="src/src-msg-objfree" />
<src path="src/src-msg-reganalysis" />
<src path="src/src-msg-stringinfo" />
<src path="src/src-msg-threadend" />
<src path="src/src-msg-threadinfo" />
<src path="src/src-proto" />
<src path="src/src-remoteanalysis" />
<src path="src/src-reqdispatch" />
<src path="src/src-server-api" />
......
package ch.usi.dag.dislreserver;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import ch.usi.dag.util.logging.Logger;
......@@ -47,7 +48,28 @@ public abstract class DiSLREServer {
ISHVM server = new SHVM (socket, __log, debug);
server.run ();
try {
final SocketChannel clientSocket = socket.accept ();
__log.debug (
"connection from %s", clientSocket.getRemoteAddress ()
);
processRequests (clientSocket.socket (), server);
clientSocket.close ();
} catch (final ClosedByInterruptException cbie) {
//
// The server was interrupted, we are shutting down.
//
} catch (final IOException ioe) {
//
// Communication error -- just log a message here.
//
__log.error ("error accepting a connection: %s", ioe.getMessage ());
}
__log.debug ("server shutting down");
__closeSocket (socket);
......@@ -57,6 +79,39 @@ public abstract class DiSLREServer {
}
private static void processRequests (final Socket sock, final ISHVM server) {
try {
final DataInputStream is = new DataInputStream (
new BufferedInputStream (sock.getInputStream ()));
final DataOutputStream os = new DataOutputStream (
new BufferedOutputStream (sock.getOutputStream ()));
RequestDispatcher requestDispatcher = new RequestDispatcher (server);
Protocol.AgentMessage agentMessage;
int messageSize;
byte[] pole;
while (true) {
try {
messageSize = is.readInt ();
} catch (EOFException e){
break;
}
pole = new byte[messageSize];
is.readFully (pole,0, messageSize);
agentMessage = Protocol.AgentMessage.parseFrom (pole);
requestDispatcher.ProcessMessage (agentMessage);
}
} catch (final Exception e) {
Log.__logError (e, __log);
}
}
//
......
......@@ -7,11 +7,9 @@
package ch.usi.dag.dislreserver;
import java.io.*;
import java.net.Socket;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import ch.usi.dag.dislreserver.remoteanalysis.RemoteAnalysis;
import ch.usi.dag.util.logging.Logger;
/**
......@@ -39,11 +37,6 @@ public class SHVM implements ISHVM {
@Deprecated
private final boolean __debug;
/**
* Request dispatcher
*/
private final RequestDispatcher __requestDispatcher;
/**
* Shadow VM context. It's used in the request dispatcher,
* but since the name is {@link SHVMContext} it does make
......@@ -51,6 +44,8 @@ public class SHVM implements ISHVM {
*/
private final SHVMContext __shvmContext;
private final AnalysisHandler __anlHndl;
/**
* Public constructor
......@@ -69,51 +64,154 @@ public class SHVM implements ISHVM {
__debug = debug;
__shvmContext = new SHVMContext (__log);
__requestDispatcher = new RequestDispatcher (__shvmContext);
__anlHndl = new AnalysisHandler (__shvmContext);
}
/**
* Process the batch of analysis invocations on the ShadowVM. Only shadowVM knows, how to
* unmarshall the data.
*
* @param rawData Packed raw data
*/
@Override
public void run () {
public void HandleAnalyze (byte[] rawData)
{
try {
final SocketChannel clientSocket = __socket.accept ();
__anlHndl
.handle (
new DataInputStream (new ByteArrayInputStream (rawData)),
null,
__debug
);
} catch (DiSLREServerException e){}
}
/**
* Handle the message with data about some previously loaded class.
*
* @param tag Unique identifier of class in context of single VM
* @param signature Class signature (i.e. Java/lang/String)
* @param generic Class generics. Empty string if class is not generic, otherwise class signature.
* @param loaderTag Unique identifier of the class loader in context of single VM.
* @param superClassTag Unique identifier of super class in context of single VM.
*/
@Override public void HandleClassInfo (
long tag, String signature, String generic, long loaderTag, long superClassTag)
{
__shvmContext
.getShadowClassTable ()
.registerClass (tag, signature, generic, loaderTag, superClassTag);
}
@Override
public void HandleClose ()
{
// invoke atExit on all analyses
for (final RemoteAnalysis analysis : __shvmContext.getAnalysisResolver ().getAllAnalyses ()) {
try {
analysis.atExit ();
} catch (final Exception e) {
// report error during analysis invocation
System.err.format (
"DiSL-RE: exception in analysis %s.atExit(): %s\n",
analysis.getClass ().getName (), e.getMessage ()
);
final Throwable cause = e.getCause ();
if (cause != null) {
cause.printStackTrace (System.err);
}
}
}
}
__log.debug (
"connection from %s", clientSocket.getRemoteAddress ()
);
processRequests (clientSocket.socket ());
clientSocket.close ();
@Override
public void HandleNewClass (String name, long tag, byte[] data)
{
__shvmContext
.getShadowClassTable ()
.loadClass (name, tag, data);
}
} catch (final ClosedByInterruptException cbie) {
//
// The server was interrupted, we are shutting down.
//
} catch (final IOException ioe) {
//
// Communication error -- just log a message here.
//
__log.error ("error accepting a connection: %s", ioe.getMessage ());
}
/**
* Handle the batch of object freeing messages.
*
* @param tags Tags of freed objects.
*/
@Override
public void HandleObjectFree (long[] tags)
{
__anlHndl.objectsFreed (tags);
}
private void processRequests (final Socket sock) {
/**
* Register new analysis method in context of current ShadowVM.
*
* @param analysisID Id of the analysis method.
* @param descriptor Descriptor of method. I.e. its signature.
*/
@Override
public void HandleRegisterAnalysis (int analysisID, String descriptor)
{
try {
final DataInputStream is = new DataInputStream (
new BufferedInputStream (sock.getInputStream ()));
final DataOutputStream os = new DataOutputStream (
new BufferedOutputStream (sock.getOutputStream ()));
while (true) {
final byte requestNo = is.readByte ();
if (__requestDispatcher.dispatch (requestNo, is, os, __debug)) {
break;
}
}
__shvmContext
.getAnalysisResolver ()
.registerMethodId ((short)analysisID, descriptor);
__log.debug ("DiSL-RE: registered %s as analysis method %d\n", descriptor, analysisID);
} catch (DiSLREServerException e) {
} catch (final Exception e) {
Log.__logError (e, __log);
}
}
/**
* Change the value of the string specified by the tag.
*
* @param tag Unique identifier of the string.
* @param value Actual value of string.
*/
@Override
public void HandleStringInfo (long tag, String value)
{
__shvmContext
.getShadowObjectTable ()
.registerShadowString (tag, value);
}
/**
* Notify the ShadowVm about death of a thread
*
* @param threadID Id of a thread.
*/
@Override
public void HandleThreadEnd (long threadID)
{
__anlHndl
.threadEnded (threadID);
}
/**
* Change the value of parameters assigned with given thread.
*
* @param tag Unique identifier of the thread.
* @param name Name of the thread.
* @param isDaemon Whether the thread runs as a daemon.
*/
@Override
public void HandleThreadInfo (long tag, String name, boolean isDaemon)
{
__shvmContext
.getShadowObjectTable ()
.registerShadowThread (tag, name, isDaemon);
}
}
package ch.usi.dag.dislreserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public final class ClassInfoHandler implements RequestHandler {
/**
* Reference to the shadow VM context.
* This is used to retrieve/modify the global state
* of SHVM instead of relying on global variables.
*/
private final SHVMContext __shvmContext;
ClassInfoHandler(
final SHVMContext shvmContext
) {
__shvmContext = shvmContext;
}
@Override
public void handle (
final DataInputStream is, final DataOutputStream os,
final boolean debug
) throws DiSLREServerException {
try {
final long netReference = is.readLong ();
final String typeDescriptor = is.readUTF ();
final String classGenericStr = is.readUTF ();
final long classLoaderNetReference = is.readLong ();
final long superclassNetReference = is.readLong ();
__shvmContext
.getShadowClassTable ()
.registerClass (
netReference, typeDescriptor, classGenericStr,
classLoaderNetReference, superclassNetReference
);
} catch (final IOException e) {
throw new DiSLREServerException (e);
}
}
@Override
public void exit () {
// do nothing
}
}
package ch.usi.dag.dislreserver;
import ch.usi.dag.dislreserver.remoteanalysis.RemoteAnalysis;
import java.io.DataInputStream;
import java.io.DataOutputStream;
/**
* CloseHandler class.
*
* Handle the request signalizing the end of analysis.
* This includes calling "destructor" on all registered event handlers
* and on all analyses.
*/
public final class CloseHandler implements RequestHandler {
/**
* Reference to the shadow VM context.
* This is used to retrieve/modify the global state
* of SHVM instead of relying on global variables.
*/
private final SHVMContext __shvmContext;
/**
* Reference to the request dispatcher.
*/
private final RequestDispatcher __requestDispatcher;
/**
* The default constructor.
*
* @param shvmContext Shadow VM Context
* @param requestDispatcher Request dispatcher instance
*/
CloseHandler(
final SHVMContext shvmContext,
final RequestDispatcher requestDispatcher
) {
__shvmContext = shvmContext;
__requestDispatcher = requestDispatcher;
}
/**
* Handle the Close request. This includes calling exit on each request handler
* and proper ending of all running analyses.
*
* @param is Input stream
* @param os Output stream
* @param debug Debug flag
*/
@Override
public void handle (
final DataInputStream is, final DataOutputStream os, final boolean debug
) {
// call exit on all request handlers - waits for all uncompleted actions
for (final RequestHandler handler : __requestDispatcher.getAllHandlers ()) {
handler.exit ();
}
// invoke atExit on all analyses
for (final RemoteAnalysis analysis : __shvmContext.getAnalysisResolver ().getAllAnalyses ()) {
try {
analysis.atExit ();
} catch (final Exception e) {
// report error during analysis invocation
System.err.format (
"DiSL-RE: exception in analysis %s.atExit(): %s\n",
analysis.getClass ().getName (), e.getMessage ()
);
final Throwable cause = e.getCause ();
if (cause != null) {
cause.printStackTrace (System.err);
}
}
}
}
@Override
public void exit () {
// empty
}
}
package ch.usi.dag.dislreserver;
import ch.usi.dag.dislreserver.shadow.ShadowClassTable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* NewClassHandler class
*
* Handle the request signalizing that a new class has been loaded
* to the observed virtual machine.
*/
public class NewClassHandler implements RequestHandler {
/**
* Reference to the shadow VM context.
* This is used to retrieve/modify the global state
* of SHVM instead of relying on global variables.
*/
private final SHVMContext __shvmContext;
NewClassHandler(
final SHVMContext shvmContext
) {
__shvmContext = shvmContext;
}
@Override
public void handle (
final DataInputStream is, final DataOutputStream os, final boolean debug
) throws DiSLREServerException {
try {
final String classInternalName = is.readUTF ();
final long classLoaderNetReference = is.readLong ();
final int classCodeLength = is.readInt ();
final byte [] classCode = new byte [classCodeLength];
is.readFully (classCode);
__shvmContext.getShadowClassTable ().loadClass (
classInternalName, classLoaderNetReference, classCode
);
} catch (final IOException e) {
throw new DiSLREServerException (e);
}
}
@Override
public void exit () {
// do nothing
}
}
package ch.usi.dag.dislreserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* ObjectFreeHandler class
*
* Handle the request notifying about the object free event in observed VM
*/
public class ObjectFreeHandler implements RequestHandler {
private final AnalysisHandler analysisHandler;
ObjectFreeHandler (AnalysisHandler anlHndl) {
analysisHandler = anlHndl;
}
@Override
public void handle (
DataInputStream is,
DataOutputStream os,
boolean debug
) throws DiSLREServerException
{
try {
int freeCount = is.readInt ();
long[] objFreeIDs = new long[freeCount];
for (int i = 0; i < freeCount; ++i) {
long netref = is.readLong ();
objFreeIDs[i] = netref;
}
analysisHandler.objectsFreed (objFreeIDs);
} catch (IOException e) {
throw new DiSLREServerException (e);
}
}
@Override
public void exit () {}
}
package ch.usi.dag.dislreserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* Register analysis method handler
*/
public final class RegAnalysisHandler implements RequestHandler {
/**
* Current {@link SHVM} context.
*/
private final SHVMContext __shvmContext;
/**
* Default constructor.
*
* @param shvmContext
*/
RegAnalysisHandler(final SHVMContext shvmContext) {
__shvmContext = shvmContext;
}
@Override
public void handle(
final DataInputStream is,
final DataOutputStream os,
final boolean debug
) throws DiSLREServerException
{
try {
final short methodId = is.readShort();
String methodString = is.readUTF();
// register method
__shvmContext.getAnalysisResolver ().registerMethodId(methodId, methodString);
if (debug) {
System.out.printf(
"DiSL-RE: registered %s as analysis method %d\n",
methodString.toString(), methodId);
}
} catch (final IOException ioe) {
throw new DiSLREServerException(ioe);
}
}
@Override
public void exit() {}
}
package ch.usi.dag.dislreserver;
import ch.usi.dag.dislreserver.shadow.ShadowObjectTable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public final class StringInfoHandler implements RequestHandler {
/**
* Reference to the shadow VM context.
* This is used to retrieve/modify the global state
* of SHVM instead of relying on global variables.
*/
private final SHVMContext __shvmContext;
StringInfoHandler(
final SHVMContext shvmContext
) {
__shvmContext = shvmContext;
}
@Override
public void handle (
final DataInputStream is, final DataOutputStream os,
final boolean debug
) throws DiSLREServerException {
try {
final long netReference = is.readLong ();
final String value = is.readUTF ();
__shvmContext.getShadowObjectTable ().registerShadowString (netReference, value);
} catch (final IOException e) {
throw new DiSLREServerException (e);
}
}
@Override
public void exit () {
// do nothing
}