package org.eclipse.dltk.dbgp;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.dltk.dbgp.internal.DbgpDebugingEngine;
import org.eclipse.dltk.dbgp.internal.DbgpSession;
import org.eclipse.dltk.dbgp.internal.DbgpWorkingThread;
import org.eclipse.dltk.debug.core.DLTKDebugPlugin;
public class DbgpServer extends DbgpWorkingThread {
private final int port;
private ServerSocket server;
private final int clientTimeout;
public static int findAvailablePort(int fromPort, int toPort) {
if (fromPort > toPort) {
throw new IllegalArgumentException(
Messages.DbgpServer_startPortShouldBeLessThanOrEqualToEndPort);
}
int port = fromPort;
ServerSocket socket = null;
while (port <= toPort) {
try {
socket = new ServerSocket(port);
return port;
} catch (IOException e) {
++port;
} finally {
if (socket != null)
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return -1;
}
private static final int STATE_NONE = 0;
private static final int STATE_STARTED = 1;
private static final int STATE_CLOSED = 2;
private final Object stateLock = new Object();
private int state = STATE_NONE;
public boolean isStarted() {
synchronized (stateLock) {
return state == STATE_STARTED;
}
}
public boolean waitStarted() {
return waitStarted(15000);
}
public boolean waitStarted(long timeout) {
synchronized (stateLock) {
if (state == STATE_STARTED) {
return true;
} else if (state == STATE_CLOSED) {
return false;
}
try {
stateLock.wait(timeout);
} catch (InterruptedException e) {
// ignore
}
return state == STATE_STARTED;
}
}
protected void workingCycle() throws Exception, IOException {
try {
server = new ServerSocket(port);
synchronized (stateLock) {
state = STATE_STARTED;
stateLock.notifyAll();
}
while (!server.isClosed()) {
final Socket client = server.accept();
client.setSoTimeout(clientTimeout);
createSession(client);
}
} finally {
if (server != null && !server.isClosed()) {
server.close();
}
synchronized (stateLock) {
state = STATE_CLOSED;
stateLock.notifyAll();
}
}
}
private static final class DbgpSessionJob extends Job {
private final Socket client;
private final IDbgpServerListener listener;
private DbgpSessionJob(Socket client, IDbgpServerListener listener) {
super(Messages.DbgpServer_acceptingDebuggingEngineConnection);
this.client = client;
this.listener = listener;
setSystem(true);
}
public boolean shouldSchedule() {
return listener != null;
}
protected IStatus run(IProgressMonitor monitor) {
DbgpDebugingEngine engine = null;
try {
engine = new DbgpDebugingEngine(client);
DbgpSession session = new DbgpSession(engine);
listener.clientConnected(session);
} catch (Exception e) {
DLTKDebugPlugin.log(e);
if (engine != null)
engine.requestTermination();
}
return Status.OK_STATUS;
}
}
private void createSession(final Socket client) {
Job job = new DbgpSessionJob(client, listener);
job.schedule();
}
public DbgpServer(int port, int clientTimeout) {
super("DbgpServer"); //$NON-NLS-1$
this.port = port;
this.clientTimeout = clientTimeout;
}
/**
* @param port
* @param serverTimeout
* @param clientTimeout
* @deprecated use {@link #DbgpServer(int, int)}
*/
public DbgpServer(int port, int serverTimeout, int clientTimeout) {
this(port, clientTimeout);
}
public void requestTermination() {
try {
if (server != null) {
server.close();
}
} catch (IOException e) {
DLTKDebugPlugin.log(e);
}
super.requestTermination();
}
private IDbgpServerListener listener;
public void setListener(IDbgpServerListener listener) {
this.listener = listener;
}
}