/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.debug.core.xdebug.dbgp.protocol;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import org.eclipse.php.internal.debug.core.xdebug.dbgp.DBGpLogger;
public class DBGpCommand {
private static final String id = " -i "; //$NON-NLS-1$
// -------------------------------------------------------------------------
// status and feature management commands
// -------------------------------------------------------------------------
public static final String status = "status"; //$NON-NLS-1$
public static final String featureGet = "feature_get"; //$NON-NLS-1$
public static final String featureSet = "feature_set"; //$NON-NLS-1$
// -------------------------------------------------------------------------
// execution commands "cmd -i id"
// -------------------------------------------------------------------------
public static final String run = "run"; //$NON-NLS-1$
public static final String stepInto = "step_into"; //$NON-NLS-1$
public static final String stepOver = "step_over"; //$NON-NLS-1$
public static final String StepOut = "step_out"; //$NON-NLS-1$
public static final String stop = "stop"; //$NON-NLS-1$
public static final String detach = "detach"; //$NON-NLS-1$
// -------------------------------------------------------------------------
// breakpoint cmds
// -------------------------------------------------------------------------
// breakpoint_set -i id [arguments] -- base64(expression)
// arguments are:
// -t type: line/call/return/conditional/exception/watch
// -s state: enabled/disabled
// -f filename
// -n lineno
// -m function
// -x exception
// -h hit_value
// -o hit_condidtion
// -r 0|1
// expression in php for conditional breakpoints
public static final String breakPointSet = "breakpoint_set"; //$NON-NLS-1$
// breakpoint_get -i id -d bp_id (bp_id = breakpoint id);
public static final String breakPointGet = "breakpoint_get"; //$NON-NLS-1$
// breakpoint_update -i id -d bp_id [arguments]
// -s
// -n
// -h
// -o
public static final String breakPointUpdate = "breakpoint_update"; //$NON-NLS-1$
// breakpoint_remove -i id -d bp_id
public static final String breakPointRemove = "breakpoint_remove"; //$NON-NLS-1$
// breakpoint_list -i id
public static final String breakPointList = "breakpoint_list"; //$NON-NLS-1$
// -------------------------------------------------------------------------
// stack commands
// -------------------------------------------------------------------------
// stack-depth -i id
public static final String stackDepth = "stack-depth"; //$NON-NLS-1$
// stack_get -i id -d depth (-d is optional)
public static final String stackGet = "stack_get"; //$NON-NLS-1$
// -------------------------------------------------------------------------
// variable/streams management commands
// -------------------------------------------------------------------------
// property_set -i id -n property_long_name -d {NUM} -l data_length --
// {DATA}
public static final String propSet = "property_set"; //$NON-NLS-1$
// property_get -i id -n property_long_name
public static final String propGet = "property_get"; //$NON-NLS-1$
// property_value -i id -n property_long_name
public static final String propValue = "property_value"; //$NON-NLS-1$
// context_get -i id -d depth
public static final String contextGet = "context_get"; //$NON-NLS-1$
// eval -i id -- {DATA}
public static final String eval = "eval"; //$NON-NLS-1$
// stdout/stderr -i id -c 0|1|2
public static final String stdout = "stdout"; //$NON-NLS-1$
public static final String stderr = "stderr"; //$NON-NLS-1$
// break
public static final String suspend = "break"; //$NON-NLS-1$
Socket socket;
OutputStreamWriter outStream;
private static int trId = 0;
private static Object idMonitor = new Object();
private int lastIdSent;
private String lastCmdSent;
public String getLastCmdSent() {
return lastCmdSent;
}
public DBGpCommand(Socket socket) {
this.socket = socket;
/*
* try { outStream = new OutputStreamWriter(socket.getOutputStream(),
* ENCODING); } catch (UnsupportedEncodingException e) {
* DBGpLogger.logException(null, this, e); // do nothing until we
* actually try to send a command } catch (IOException e) {
* DBGpLogger.logException(null, this, e); // do nothing until we
* actually try to send a command }
*/
}
public int send(String command, String args, int cmdId, String encoding) throws IOException {
try {
return writeToStream(command, args, cmdId, encoding);
} catch (IOException e) {
DBGpLogger.logException(null, this, e);
throw e;
}
}
public static int getNextId() {
synchronized (idMonitor) {
trId++;
if (trId < 0) {
trId = 1;
}
}
return trId;
}
private int writeToStream(String command, String args, int cmdId, String encoding) throws IOException {
String fullCmd = command + id + cmdId;
if (args != null) {
fullCmd = fullCmd + " " + args; //$NON-NLS-1$
}
if (DBGpLogger.debugCmd()) {
DBGpLogger.debug("cmd: " + fullCmd); //$NON-NLS-1$
}
synchronized (socket) {
OutputStream os = socket.getOutputStream();
// Bug: 226860
// Want to avoid 2 writes as some tcpip implementations
// may delay waiting for a response from the 1st write
// we could set the tcpNoDelay option on the socket
// but given this is the only write we can accept the
// delay for a response to reduce bandwidth.
//
// implemented this way as we only want to send
// a single \0 byte to terminate the command whereas
// an encoding such as utf-16 would result in 2 bytes
byte[] cmdBytes = fullCmd.getBytes(encoding);
byte[] cmdWithTerm = new byte[cmdBytes.length + 1];
System.arraycopy(cmdBytes, 0, cmdWithTerm, 0, cmdBytes.length);
os.write(cmdWithTerm);
os.flush();
lastIdSent = cmdId;
lastCmdSent = fullCmd;
/*
* System.out.print("streamed:");
* System.out.write(fullCmd.getBytes(encoding));
* System.out.write(0); System.out.flush(); System.out.println();
*
* outStream.write(command); outStream.write(id);
* outStream.write(Integer.toString(cmdId)); if (args != null) {
* outStream.write(" " + args); } outStream.write(0);
* outStream.flush();
*/
}
return cmdId;
}
public int getLastIdSent() {
int id;
// we need to synchronise on the socket to ensure that if we get called
// on a different thread, lastIdSent is at the latest value which occurs
// after the last part of the write and the update takes place and is
// controlled by the syncing of the socket.
synchronized (socket) {
id = lastIdSent;
}
return id;
}
}