Java Debug Wire Protocol Transport Interface
(jdwpTransport)

A transport is implemented as a series of functions in a dynamic
library (sometimes called a DLL, or shared library).
The library exports an onload function that is invoked by
the JDWP (or other) agent at startup-time.

Like JVMTI, jdwpTransport functions are accessed through an
interface pointer called the environment pointer. An
environment pointer is a pointer to an environment and has type
jdwpTransportEnv*. The environment pointer is returned to
the JDWP (or other) agent from the onload function.

A transport may support a single environment or it may support
multiple environments. In other words, a transport may be used by
only one, or multiple agents at the same time. If a transport
supports multiple environments then each call to the onload
function will return a new environment pointer. If a transport only
supports a single environment then second, and subsequent calls to
the onload function will return an error.

A transport is thread-safe and jdwpTransport functions can be
used by multiple concurrent threads. For example, one thread may be
blocked in the jdwpTransport ReadPacket function waiting
for a packet while another thread invokes WritePacket
function to write a packet.

In most cases jdwpTransport functions return a
jdwpTransportError value indicating return status. Some
functions return additional values through pointers provided by the
calling function. In cases where the return values are allocated by
a jdwpTransport function then the function will use the memory
allocation routine specified by the agent. The memory allocation
routines are specified to the transport, at start-up, via the
onload function.

In the event of an error (that is, one of the jdwpTransport
functions returns a value other than
JDWPTRANSPORT_ERROR_NONE) then a string representing the
error can be subsequently obtained through a call to the
jdwpTransport function GetLastError. Errors are recorded
on a per-thread basis. The GetLastError function will
return a string represetning the last error that was encountered by
the current thread only.

Developing a Transport implementation

A transport library can be developed in any native language that
supports C language calling conventions and C or C++
definitions.

The function, data type, and constant definitions needed for
using the jdwpTransport interface are defined in the include file
jdwpTransport.h. To use these definitions add the Java SE include
directory to your include path :-

#include "jdwpTransport.h"

Transport Start-Up

The transport library must export an onload function with
the following prototype :-

This function will be called by the JDWP (or other agent) when
the library is loaded.

The jvm argument is the JNI invocation interface
obtained by agent by invoking JNI's GetJavaVM
function.

The callback argument is a pointer to a function table
of memory management routines that the transport must use to
allocate the memory for return values that are allocated by the
transport implementation :-

The lifespan of the callback argument is the
onload function and therefore the transport must take a copy
of the function table in the jdwpTransport_OnLoad
function.

The function table has two entries. The alloc function
allocates an area of memory. It has a single argument to specify
the number of bytes to allocate. It returns a pointer to the
begining of the allocated memory, or NULL if the memory request
cannot be honored. If the number of bytes requested is zero then
NULL is returned. The free function deallocates an area of
memory that was previously allocated using the alloc
function.

The memory management functions provided by the agent are thread
safe and the transport implementation is not required to
synchronize calls to the these functions. The implementation of the
memory management functions are guaranteed not to call any
jdwpTransport function.

version is the version of the transport interface that
the agent expects. This must be specified as
JDWPTRANSPORT_VERSION_1_0.

env is a pointer to the environment pointer returned by
the function.

The jdwpTransport_OnLoad function returns
JNI_OK if the transport initializes successfully. If
initialization fails then one of the following errors is returned
:

JNI_ENOMEM
JNI_EVERSION
JNI_EEXIST

JNI_ENOMEM is returned if there is insufficient memory
to complete initialization.

JNI_EVERSION is returned if the version in the
version argument is not
JDWPTRANSPORT_VERSION_1_0.

JNI_EEXIST is returned if the transport only supports a
single environment, and the environment pointer was previously
returned by the first call to the onload function.

Connection Management

The connection management functions are used to establish and
close the connection to the debugger. A connection provides a
reliable flow of JDWP packets to and from the debugger. Packets
written to a connection are read, by the debugger, in exactly the
order in which they were written. Similarly, any packets written to
the connection by the debugger are read in the order in which they
were written.

Connections are established either actively or
passively. Establishing the connection actively means
that the jdwpTransport's Attach function is called to
initiate the connection the debugger. Establishing the connection
passively means that the jdwpTransport's
StartListening function is used to put the transport into
listen mode so that it listens for a connection from a
debugger. Once in listen mode the Accept function is used
to accept the connection. Irrespective of how the connection is
established the Close function is used to close the
connection, and IsOpen is used to test if a connection is
open to the debugger.

Attach

Attaches to the debugger. Attaching to the debugger involves two
steps. First, a connection is established to the specified
address. Once a connection is established a
handshake is performed to ensure that the connection is
indeed established to a debugger. Handshaking involves the exchange
of ASCII string JDWP-Handshake as specified in the Java Debug Wire Protocol specification.

The address argument is a pointer to a string
representing the address of the debugger. The exact format is
specific to the transport (In the case of a TCP/IP based transport
the address may include the hostname and port number of the
debugger. In the case of a transport that supports connections
through a serial port it might be the device name of the serial
port).

The attachTimeout argument specifies a timeout to use
when attaching. If the transport supports an attach timeout (see
GetCapabilities) and if the
attachTimeout is positive then it specifies the timeout,
in milliseconds (more or less), to use when attaching to the
debugger. If the transport does not support an attach timeout, or
if attachTimeout is specified as zero then a timeout is
not used when attaching.

The handshakeTimeout argument specifies a timeout to
use when handshaking with the debugger. If the transport supports a
handshake timeout (see GetCapabilities) and if the
handshakeTimeout is positive then it specifies the
timeout, in milliseconds (more or less), to use when handshaking
with the debugger. The exact usage of the handshake timeout is
specific to the transport - for example one implementation may use
the timeout as an inter-character timeout while waiting for the
JDWP-Handshake message from the debugger. Another
implementation may use the timeout to indicate the total duration
allowed for the handshake exchange. In general the purpose of the
handshake timeout is to allow for error handling in the event that
the transport connects to something other than a valid debugger. If
the transport does not support a handshake timeout, or if the
handshakeTimeout is specified as zero then a timeout is
not used when handshaking.

JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT is returned if
address is invalid or timeout is negative.

JDWPTRANSPORT_ERROR_ILLEGAL_STATE is returned if the
transport is currently in listen mode (see StartListening), or there is already an open
connection to the debugger (see IsOpen).

JDWPTRANSPORT_ERROR_IO_ERROR is returned if there is an
error (other than an attach timeout) attaching to the debugger.
Note that errors during the start-up handshake (including a
handshake timeout) are considered I/O errors. I/O errors are
specific to the transport. GetLastError
can be used to obtain a string representation of the error.

JDWPTRANSPORT_ERROR_TIMEOUT is returned if the
transport supports an attach timeout, and if the
attachTimeout value is positive, and if the connection to
the debugger cannot be established within that attachTimeout
period.

StartListening

Puts the transport into listen mode to listen for a
connection from a debugger.

The address argument is a pointer to a string
representing the local address that the transport should listen on.
The exact format is specific to the transport (In the case of a
TCP/IP based transport the address might a local TCP port number.
In the case of a transport that supports connections through a
serial port it might be the device name of a serial port). The
address argument can be specified as NULL or as
an empty string (first character is \0). In that case the
transport listens on a default address that is specific to the
transport.

If actualAddress is not NULL then it is set to
the address of a string returned by the StartListening
function. The returned string will contain the string
representation of the address that the transport is listening on.
This may, or may not, differ from the address provided in the
address argument. The string is allocated using the
allocation callback provided to the transport when the
jdwpTransport_OnLoad function was called. The caller is
responsible for freeing the returned string.

JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT is returned if
address is invalid.

JDWPTRANSPORT_ERROR_ILLEGAL_STATE is returned if there
is already an open connection to a debugger (see IsOpen), or the transport is already in listen
mode.

JDWPTRANSPORT_ERROR_IO_ERROR is returned if there is an
error putting the transport into listen mode. The nature of the
error is specific to the transport. GetLastError can be used to obtain a string
representing the error.

StopListening

jdwpTransportError
StopListening(jdwpTransportEnv* env)

Takes the transport out of listen mode so that it's no
longer listening for connections from a debugger.

If the transport is in listen mode then it will be taken
out of this mode. If there is an open (see IsOpen) connection to a debugger then it is
unaffected by this function. In other words, StopListening
does not close a connection to the debugger. If the transport is
not in listen mode then this function does nothing and no error is
returned.

JDWPTRANSPORT_ERROR_IO_ERROR is returned if there is an
error taking the transport out of listen mode. The nature of the
error is specific to the transport. GetLastError can be used to obtain a string
representing the error.

Accept

Accepts a connection from a debugger. Accepting a connection
from a debugger involves two steps. Firstly, a connection is
established by the debugger. Once a connection is established a
handshake is performed to ensure that the connection was
indeed established by a debugger. Handshaking involves the exchange
of ASCII string JDWP-Handshake as specified in the Java Debug Wire Protocol specification.

The acceptTimeout argument specifies the timeout to use
while waiting for the debugger to connect. If the transport
supports an accept timeout (see GetCapabilities) and if the
acceptTimeout is positive then it specifies the timeout,
in milliseconds (more or less), to use when waiting for a
connection from a debugger. If the transport does not support an
accept timeout, or if timeout is specified as zero then
block indefinitely waiting for a connection.

The handshakeTimeout argument specifies a timeout to
use when handshaking with the debugger. If the transport supports a
handshake timeout (see GetCapabilities) and if the
handshakeTimeout is positive then it specifies the
timeout, in milliseconds (more or less), to use when handshaking
with the debugger. The exact usage of the handshake timeout is
specific to the transport - for example one implementation may use
the timeout as an inter-character timeout while waiting for the
JDWP-Handshake message from the debugger. Another
implementation may use the timeout to indicate the total duration
allowed for the handshake exchange. In general the purpose of the
handshake timeout is to allow for error handling in the event that
something other than a debugger establishes a connection to the
debuggee. If the transport does not support a handshake timeout, or
if the handshakeTimeout is specified as zero then a
timeout is not used when handshaking.

JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT is returned if
attachTimeout or handshakeTimeout is
negative.

JDWPTRANSPORT_ERROR_ILLEGAL_STATE is returned if there
is already an open connection to a debugger (see IsOpen), or if the transport is not in listen mode
(see StartListening).

JDWPTRANSPORT_ERROR_IO_ERROR is returned if there is an
error (other than an accept timeout) while accepting a connection
from a debugger. Note that errors during the start-up handshake
(including a handshake timeout) are considered I/O errors. The
nature of the error is specific to the transport. GetLastError can be used to obtain a string
representing the error.

JDWPTRANSPORT_ERROR_TIMEOUT is returned if the
transport supports an accept timeout, and if the
acceptTimeout value is positive, and if the connection to
the debugger cannot be established within that timeout period.

Note: A thread that is blocked in Accept waiting
for a connection from a debugger can be interrupted by another
thread calling StopListening. In that case the thread that
called Accept will return
JDWPTRANSPORT_ERROR_IO_ERROR indicating an I/O error has
occurred. If a thread blocked in Accept has accepted a
connection and is in the process of handshaking with the debugger
then StopListening will not interrupt the connection.

IsOpen

jboolean
isOpen(jdwpTransportEnv* env)

Tells whether or not there is a connection open to a
debugger.

Returns JNI_TRUE if, and only if, there is an open
connection to a debugger. Otherwise it returns
JNI_FALSE.

Close

jdwpTransportError
Close(jdwpTransportEnv* env)

Closes an open connection to a debugger.

If there isn't an open connection to a debugger (see IsOpen) then this function does nothing and no error
is returned.

If there are threads blocked in any I/O functions (namely,
ReadPacket and WritePacket), then these I/O functions will be
interrupted by the close and will return an
JDWPTRANSPORT_ERROR_IO_ERROR indicating an I/O error has
occurred.

JDWPTRANSPORT_ERROR_IO_ERROR is returned if there is an
error closing the connection. The nature of the error is specific
to the transport. GetLastError can be
used to obtain a string representing the error.

I/O Functions

The I/O functions are used for reading and writing JDWP packets
from and to the debugger.

This function does a blocking read on an open connection.
It blocks indefinitely until a complete JDWP packet can be
returned, or in the case of a transport based on a stream-oriented
protocol, end-of-stream is encountered.

The packet argument is the address of a
jdwpPacket structure that is populated by this function.
The packet.type.cmd.len or packet.type.reply.len
field (depending on if the packet is a command or reply packet) is
populated with the length of the packet. If end of stream is
encountered the length field will be set to 0 and all
other fields in the packet will be undefined. If end of stream is
encountered after reading some, but not all, bytes of a packet it
is considered an I/O error and
JDWPTRANSPORT_ERROR_IO_ERROR will be returned. In that
case the length field will not be populated. When an entire packet
is read then all fields in the packet are populated with values in
host order. This may, or may not, differ from the big endian order
require when transmitting JDWP packets.

The packet.type.cmd.data or
packet.type.reply.data field (depending on if the packet
is a command or reply packet) will be populated with NULL
or a pointer to the packet data allocated by this function. Packet
data is allocated using the allocation callback provided to the
transport when the jdwpTransport_OnLoad function was
called. The caller is responsible to free it. The layout of the
packet data (that is the data following the header, if any) is
returned to the caller in the byte ordering in which it was
received.

The ReadPacket function does not do any integrity
checking on the returned packet except checking that the length of
the packet (as indicated by the first 4 bytes) is >= 11
bytes. If the length field is less than 11 bytes then
JDWPTRANSPORT_ERROR_IO_ERROR is returned.

JDWPTRANSPORT_ERROR_IO_ERROR is returned if an I/O
error occurs when reading, the connection is closed asynchronously
by another thread calling the Close function,
or a badly formed packet (length field less than 11 bytes)
is received. I/O errors are specific to the transport. GetLastError can be used to obtain a string
representing the error.

JDWPTRANSPORT_ERROR_ILLEGAL_STATE is returned if there
isn't an open connection to a debugger (see IsOpen).

JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT is returned if
packet is NULL

WritePacket

The packet argument is a pointer to a
jdwpPacket structure. All fields in the packet header must
be stored in host order. The packet data field
(packet.type.cmd.data or packet.type.reply.data)
must be NULL, or a pointer to a location containing packet
data that immediately follows the header. The packet data is must
be in network order (big endian) ready for transmission.

JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT if packet
is NULL, or if the packet length field
(packet.type.cmd.len or packet.type.reply.len) is
less than 11, or it is greater than 11 but the packet data field
(packet.type.cmd.data or packet.type.reply.data)
is NULL.

JDWPTRANSPORT_ERROR_IO_ERROR is returned if an I/O
error occurs when writing, or the connection is closed
asynchronously by another thread calling the Close function. I/O errors are specific to the
transport. GetLastError can be used to
obtain a string representing the error.

JDWPTRANSPORT_ERROR_ILLEGAL_STATE is returned if there
isn't an open connection to a debugger (see IsOpen).

Miscellaneous Functions

GetLastError

jdwpTransportError
GetLastError(jdwpTransportEnv* env, char** msg);

Returns the string representation of the last error.

When an error occurs it is recorded on a per-thread basis. A
subsequent call to GetLastError returns the string
representation of the last I/O error.

The msg argument is a pointer to a null-terminated
string returned by this function. The string is allocated using the
allocation callback provided to the transport when the
jdwpTransport_OnLoad function was called. The caller is
responsible to free the returned string.

Returns via capabilitiesPtr the optional jdwpTransport
features supported by this transport. The capabilities structure
contains a number of boolean flags indicating whether the named
feature is supported. The current set of flags is:

Boolean Flag

Meaning

can_timeout_attach

Indicates if the transport supports attaching with a
timeout

can_timeout_accept

Indicates if the transport supports an accept timeout

can_timeout_handshake

Indicates if the transport supports a timeout when performing
the initial handshake with the debugger when the connection is
established

This function does not return any errors.

Universal Errors

Error

Meaning

JDWPTRANSPORT_ERROR_NONE

No error has occurred. This is the error code that is returned
on successful completion of the function.

JDWPTRANSPORT_ERROR_OUT_OF_MEMORY

The function needed to allocate memory and no more memory was
available for allocation.