/* * #%~ * org.overture.ide.debug * %% * Copyright (C) 2008 - 2014 Overture * %% * 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 3 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/gpl-3.0.html>. * #~% */ package org.overture.ide.debug.core.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.overture.ide.debug.core.VdmDebugPlugin; import org.overture.ide.debug.core.dbgp.internal.DbgpDebugingEngine; import org.overture.ide.debug.core.dbgp.internal.DbgpSession; import org.overture.ide.debug.core.dbgp.internal.DbgpWorkingThread; 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("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("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) { VdmDebugPlugin.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) { VdmDebugPlugin.log(e); } super.requestTermination(); } private IDbgpServerListener listener; public void setListener(IDbgpServerListener listener) { this.listener = listener; } }