package DBProxy.Core;
/*
* Base proxy code. This should really just move data back and forth
* Calling plugins as needed
*/
import DBProxy.MySQL.Protocol.Flags;
import DBProxy.MySQL.Protocol.Handshake;
import DBProxy.MySQL.Protocol.HandshakeResponse;
import DBProxy.Plugins.Base;
import java.net.Socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.BufferedInputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
public class Engine implements Runnable {
public Logger logger = Logger.getLogger("Engine");
public int port = 0;
public Socket clientSocket = null;
public InputStream clientIn = null;
public OutputStream clientOut = null;
// Plugins
public List<Base> plugins;
// Packet Buffer. ArrayList so we can grow/shrink dynamically
public ArrayList<byte[]> buffer = new ArrayList<>();
public int offset = 0;
// Stop the thread?
public boolean running = true;
// What sorta of result set should we expect?
public int expectedResultSet = Flags.RS_OK;
// Connection info
public Handshake handshake = null;
public HandshakeResponse authReply = null;
public String schema = "";
public String query = "";
public long statusFlags = 0;
public long sequenceId = 0;
// Buffer or directly pass though the data
public boolean bufferResultSet = true;
public boolean packResultSet = true;
// Modes
public int mode = Flags.MODE_INIT;
// Allow plugins to muck with the modes
public int nextMode = Flags.MODE_INIT;
public Engine(int port, Socket clientSocket, List<Base> plugins) throws IOException {
this.port = port;
this.plugins = plugins;
this.clientSocket = clientSocket;
this.clientSocket.setPerformancePreferences(0, 2, 1);
this.clientSocket.setTcpNoDelay(true);
this.clientSocket.setTrafficClass(0x10);
this.clientSocket.setKeepAlive(true);
this.clientIn = new BufferedInputStream(this.clientSocket.getInputStream(), 16384);
this.clientOut = this.clientSocket.getOutputStream();
}
public void run() {
try {
while (this.running) {
switch (this.mode) {
case Flags.MODE_INIT:
this.logger.trace("MODE_INIT");
this.nextMode = Flags.MODE_READ_HANDSHAKE;
for (Base plugin : this.plugins)
plugin.init(this);
break;
case Flags.MODE_READ_HANDSHAKE:
this.logger.trace("MODE_READ_HANDSHAKE");
this.nextMode = Flags.MODE_SEND_HANDSHAKE;
for (Base plugin : this.plugins)
plugin.read_handshake(this);
break;
case Flags.MODE_SEND_HANDSHAKE:
this.logger.trace("MODE_SEND_HANDSHAKE");
this.nextMode = Flags.MODE_READ_AUTH;
for (Base plugin : this.plugins)
plugin.send_handshake(this);
break;
case Flags.MODE_READ_AUTH:
this.logger.trace("MODE_READ_AUTH");
this.nextMode = Flags.MODE_SEND_AUTH;
for (Base plugin : this.plugins)
plugin.read_auth(this);
break;
case Flags.MODE_SEND_AUTH:
this.logger.trace("MODE_SEND_AUTH");
this.nextMode = Flags.MODE_READ_AUTH_RESULT;
for (Base plugin : this.plugins)
plugin.send_auth(this);
break;
case Flags.MODE_READ_AUTH_RESULT:
this.logger.trace("MODE_READ_AUTH_RESULT");
this.nextMode = Flags.MODE_SEND_AUTH_RESULT;
for (Base plugin : this.plugins)
plugin.read_auth_result(this);
break;
case Flags.MODE_SEND_AUTH_RESULT:
this.logger.trace("MODE_SEND_AUTH_RESULT");
this.nextMode = Flags.MODE_READ_QUERY;
for (Base plugin : this.plugins)
plugin.send_auth_result(this);
break;
case Flags.MODE_READ_QUERY:
this.logger.trace("MODE_READ_QUERY");
this.nextMode = Flags.MODE_SEND_QUERY;
for (Base plugin : this.plugins)
plugin.read_query(this);
break;
case Flags.MODE_SEND_QUERY:
this.logger.trace("MODE_SEND_QUERY");
this.nextMode = Flags.MODE_READ_QUERY_RESULT;
for (Base plugin : this.plugins)
plugin.send_query(this);
break;
case Flags.MODE_READ_QUERY_RESULT:
this.logger.trace("MODE_READ_QUERY_RESULT");
this.nextMode = Flags.MODE_SEND_QUERY_RESULT;
for (Base plugin : this.plugins)
plugin.read_query_result(this);
break;
case Flags.MODE_SEND_QUERY_RESULT:
this.logger.trace("MODE_SEND_QUERY_RESULT");
this.nextMode = Flags.MODE_READ_QUERY;
for (Base plugin : this.plugins)
plugin.send_query_result(this);
break;
case Flags.MODE_CLEANUP:
this.logger.trace("MODE_CLEANUP");
this.nextMode = Flags.MODE_CLEANUP;
for (Base plugin : this.plugins)
plugin.cleanup(this);
this.halt();
break;
default:
this.logger.fatal("UNKNOWN MODE "+this.mode);
this.halt();
break;
}
this.mode = this.nextMode;
}
this.logger.info("Exiting thread.");
this.clientSocket.close();
}
catch (IOException e) {}
finally {
try {
this.clientSocket.close();
}
catch (IOException e) {}
try {
for (Base plugin : this.plugins)
plugin.cleanup(this);
}
catch (IOException e) {}
}
}
public void buffer_result_set() {
if (!this.bufferResultSet)
this.bufferResultSet = true;
}
public void halt() {
this.logger.trace("Halting!");
this.running = false;
}
public void clear_buffer() {
this.logger.trace("Clearing Buffer.");
this.offset = 0;
// With how ehcache works, if we clear the buffer via .clear(), it also
// clears the cached value. Create a new ArrayList and count on java
// cleaning up after ourselves.
this.buffer = new ArrayList<byte[]>();
}
}