0N/A/*
2362N/A * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A#include <stdio.h>
0N/A#include <string.h>
0N/A#include <errno.h>
0N/A#include <stdlib.h>
0N/A#include <ctype.h>
0N/A
0N/A#include "jdwpTransport.h"
0N/A#include "sysSocket.h"
0N/A
0N/A/*
0N/A * The Socket Transport Library.
0N/A *
0N/A * This module is an implementation of the Java Debug Wire Protocol Transport
0N/A * Service Provider Interface - see src/share/javavm/export/jdwpTransport.h.
0N/A */
0N/A
0N/Astatic int serverSocketFD;
0N/Astatic int socketFD = -1;
0N/Astatic jdwpTransportCallback *callback;
0N/Astatic JavaVM *jvm;
0N/Astatic int tlsIndex;
0N/Astatic jboolean initialized;
0N/Astatic struct jdwpTransportNativeInterface_ interface;
0N/Astatic jdwpTransportEnv single_env = (jdwpTransportEnv)&interface;
0N/A
0N/A#define RETURN_ERROR(err, msg) \
0N/A if (1==1) { \
0N/A setLastError(err, msg); \
0N/A return err; \
0N/A }
0N/A
0N/A#define RETURN_IO_ERROR(msg) RETURN_ERROR(JDWPTRANSPORT_ERROR_IO_ERROR, msg);
0N/A
0N/A#define RETURN_RECV_ERROR(n) \
0N/A if (n == 0) { \
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_IO_ERROR, "premature EOF"); \
0N/A } else { \
0N/A RETURN_IO_ERROR("recv error"); \
0N/A }
0N/A
0N/A#define HEADER_SIZE 11
0N/A#define MAX_DATA_SIZE 1000
0N/A
4632N/Astatic jint recv_fully(int, char *, int);
4632N/Astatic jint send_fully(int, char *, int);
4632N/A
0N/A/*
0N/A * Record the last error for this thread.
0N/A */
0N/Astatic void
0N/AsetLastError(jdwpTransportError err, char *newmsg) {
0N/A char buf[255];
0N/A char *msg;
0N/A
0N/A /* get any I/O first in case any system calls override errno */
0N/A if (err == JDWPTRANSPORT_ERROR_IO_ERROR) {
0N/A dbgsysGetLastIOError(buf, sizeof(buf));
0N/A }
0N/A
0N/A msg = (char *)dbgsysTlsGet(tlsIndex);
0N/A if (msg != NULL) {
0N/A (*callback->free)(msg);
0N/A }
0N/A
0N/A if (err == JDWPTRANSPORT_ERROR_IO_ERROR) {
0N/A char *join_str = ": ";
439N/A int msg_len = (int)strlen(newmsg) + (int)strlen(join_str) +
439N/A (int)strlen(buf) + 3;
0N/A msg = (*callback->alloc)(msg_len);
0N/A if (msg != NULL) {
0N/A strcpy(msg, newmsg);
0N/A strcat(msg, join_str);
0N/A strcat(msg, buf);
0N/A }
0N/A } else {
439N/A msg = (*callback->alloc)((int)strlen(newmsg)+1);
0N/A if (msg != NULL) {
0N/A strcpy(msg, newmsg);
0N/A }
0N/A }
0N/A
0N/A dbgsysTlsPut(tlsIndex, msg);
0N/A}
0N/A
0N/A/*
0N/A * Return the last error for this thread (may be NULL)
0N/A */
0N/Astatic char*
0N/AgetLastError() {
0N/A return (char *)dbgsysTlsGet(tlsIndex);
0N/A}
0N/A
0N/Astatic jdwpTransportError
0N/AsetOptions(int fd)
0N/A{
0N/A jvalue dontcare;
0N/A int err;
0N/A
0N/A dontcare.i = 0; /* keep compiler happy */
0N/A
0N/A err = dbgsysSetSocketOption(fd, SO_REUSEADDR, JNI_TRUE, dontcare);
0N/A if (err < 0) {
0N/A RETURN_IO_ERROR("setsockopt SO_REUSEADDR failed");
0N/A }
0N/A
0N/A err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare);
0N/A if (err < 0) {
0N/A RETURN_IO_ERROR("setsockopt TCPNODELAY failed");
0N/A }
0N/A
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/Astatic jdwpTransportError
0N/Ahandshake(int fd, jlong timeout) {
1611N/A const char *hello = "JDWP-Handshake";
0N/A char b[16];
1611N/A int rv, helloLen, received;
0N/A
0N/A if (timeout > 0) {
0N/A dbgsysConfigureBlocking(fd, JNI_FALSE);
0N/A }
1611N/A helloLen = (int)strlen(hello);
0N/A received = 0;
1611N/A while (received < helloLen) {
0N/A int n;
0N/A char *buf;
0N/A if (timeout > 0) {
0N/A rv = dbgsysPoll(fd, JNI_TRUE, JNI_FALSE, (long)timeout);
0N/A if (rv <= 0) {
0N/A setLastError(0, "timeout during handshake");
0N/A return JDWPTRANSPORT_ERROR_IO_ERROR;
0N/A }
0N/A }
0N/A buf = b;
0N/A buf += received;
4632N/A n = recv_fully(fd, buf, helloLen-received);
0N/A if (n == 0) {
0N/A setLastError(0, "handshake failed - connection prematurally closed");
0N/A return JDWPTRANSPORT_ERROR_IO_ERROR;
0N/A }
0N/A if (n < 0) {
0N/A RETURN_IO_ERROR("recv failed during handshake");
0N/A }
0N/A received += n;
0N/A }
0N/A if (timeout > 0) {
0N/A dbgsysConfigureBlocking(fd, JNI_TRUE);
0N/A }
1611N/A if (strncmp(b, hello, received) != 0) {
1611N/A char msg[80+2*16];
1611N/A b[received] = '\0';
1611N/A /*
1611N/A * We should really use snprintf here but it's not available on Windows.
1611N/A * We can't use jio_snprintf without linking the transport against the VM.
1611N/A */
1611N/A sprintf(msg, "handshake failed - received >%s< - expected >%s<", b, hello);
1611N/A setLastError(0, msg);
1611N/A return JDWPTRANSPORT_ERROR_IO_ERROR;
0N/A }
0N/A
4632N/A if (send_fully(fd, (char*)hello, helloLen) != helloLen) {
0N/A RETURN_IO_ERROR("send failed during handshake");
0N/A }
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/Astatic jdwpTransportError
439N/AparseAddress(const char *address, struct sockaddr_in *sa, uint32_t defaultHost) {
0N/A char *colon;
0N/A
0N/A memset((void *)sa,0,sizeof(struct sockaddr_in));
0N/A sa->sin_family = AF_INET;
0N/A
0N/A /* check for host:port or port */
0N/A colon = strchr(address, ':');
0N/A if (colon == NULL) {
0N/A u_short port = (u_short)atoi(address);
0N/A sa->sin_port = dbgsysHostToNetworkShort(port);
0N/A sa->sin_addr.s_addr = dbgsysHostToNetworkLong(defaultHost);
0N/A } else {
0N/A char *buf;
0N/A char *hostname;
0N/A u_short port;
439N/A uint32_t addr;
0N/A
439N/A buf = (*callback->alloc)((int)strlen(address)+1);
0N/A if (buf == NULL) {
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
0N/A }
0N/A strcpy(buf, address);
0N/A buf[colon - address] = '\0';
0N/A hostname = buf;
0N/A port = atoi(colon + 1);
0N/A sa->sin_port = dbgsysHostToNetworkShort(port);
0N/A
0N/A /*
0N/A * First see if the host is a literal IP address.
0N/A * If not then try to resolve it.
0N/A */
0N/A addr = dbgsysInetAddr(hostname);
0N/A if (addr == 0xffffffff) {
0N/A struct hostent *hp = dbgsysGetHostByName(hostname);
0N/A if (hp == NULL) {
0N/A /* don't use RETURN_IO_ERROR as unknown host is normal */
0N/A setLastError(0, "gethostbyname: unknown host");
0N/A (*callback->free)(buf);
0N/A return JDWPTRANSPORT_ERROR_IO_ERROR;
0N/A }
0N/A
0N/A /* lookup was successful */
0N/A memcpy(&(sa->sin_addr), hp->h_addr_list[0], hp->h_length);
0N/A } else {
0N/A sa->sin_addr.s_addr = addr;
0N/A }
0N/A
0N/A (*callback->free)(buf);
0N/A }
0N/A
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/A
0N/Astatic jdwpTransportError JNICALL
0N/AsocketTransport_getCapabilities(jdwpTransportEnv* env,
0N/A JDWPTransportCapabilities* capabilitiesPtr)
0N/A{
0N/A JDWPTransportCapabilities result;
0N/A
0N/A memset(&result, 0, sizeof(result));
0N/A result.can_timeout_attach = JNI_TRUE;
0N/A result.can_timeout_accept = JNI_TRUE;
0N/A result.can_timeout_handshake = JNI_TRUE;
0N/A
0N/A *capabilitiesPtr = result;
0N/A
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/A
0N/Astatic jdwpTransportError JNICALL
0N/AsocketTransport_startListening(jdwpTransportEnv* env, const char* address,
0N/A char** actualAddress)
0N/A{
0N/A struct sockaddr_in sa;
0N/A int err;
0N/A
0N/A memset((void *)&sa,0,sizeof(struct sockaddr_in));
0N/A sa.sin_family = AF_INET;
0N/A
0N/A /* no address provided */
0N/A if ((address == NULL) || (address[0] == '\0')) {
0N/A address = "0";
0N/A }
0N/A
0N/A err = parseAddress(address, &sa, INADDR_ANY);
0N/A if (err != JDWPTRANSPORT_ERROR_NONE) {
0N/A return err;
0N/A }
0N/A
0N/A serverSocketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0);
0N/A if (serverSocketFD < 0) {
0N/A RETURN_IO_ERROR("socket creation failed");
0N/A }
0N/A
0N/A err = setOptions(serverSocketFD);
0N/A if (err) {
0N/A return err;
0N/A }
0N/A
0N/A err = dbgsysBind(serverSocketFD, (struct sockaddr *)&sa, sizeof(sa));
0N/A if (err < 0) {
0N/A RETURN_IO_ERROR("bind failed");
0N/A }
0N/A
0N/A err = dbgsysListen(serverSocketFD, 1);
0N/A if (err < 0) {
0N/A RETURN_IO_ERROR("listen failed");
0N/A }
0N/A
0N/A {
0N/A char buf[20];
0N/A int len = sizeof(sa);
0N/A jint portNum;
0N/A err = dbgsysGetSocketName(serverSocketFD,
0N/A (struct sockaddr *)&sa, &len);
0N/A portNum = dbgsysNetworkToHostShort(sa.sin_port);
0N/A sprintf(buf, "%d", portNum);
439N/A *actualAddress = (*callback->alloc)((int)strlen(buf) + 1);
0N/A if (*actualAddress == NULL) {
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
0N/A } else {
0N/A strcpy(*actualAddress, buf);
0N/A }
0N/A }
0N/A
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/Astatic jdwpTransportError JNICALL
0N/AsocketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout)
0N/A{
0N/A int socketLen, err;
0N/A struct sockaddr_in socket;
0N/A jlong startTime = (jlong)0;
0N/A
0N/A /*
0N/A * Use a default handshake timeout if not specified - this avoids an indefinite
0N/A * hang in cases where something other than a debugger connects to our port.
0N/A */
0N/A if (handshakeTimeout == 0) {
0N/A handshakeTimeout = 2000;
0N/A }
0N/A
0N/A do {
0N/A /*
0N/A * If there is an accept timeout then we put the socket in non-blocking
0N/A * mode and poll for a connection.
0N/A */
0N/A if (acceptTimeout > 0) {
0N/A int rv;
0N/A dbgsysConfigureBlocking(serverSocketFD, JNI_FALSE);
0N/A startTime = dbgsysCurrentTimeMillis();
0N/A rv = dbgsysPoll(serverSocketFD, JNI_TRUE, JNI_FALSE, (long)acceptTimeout);
0N/A if (rv <= 0) {
0N/A /* set the last error here as could be overridden by configureBlocking */
0N/A if (rv == 0) {
0N/A setLastError(JDWPTRANSPORT_ERROR_IO_ERROR, "poll failed");
0N/A }
0N/A /* restore blocking state */
0N/A dbgsysConfigureBlocking(serverSocketFD, JNI_TRUE);
0N/A if (rv == 0) {
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "timed out waiting for connection");
0N/A } else {
0N/A return JDWPTRANSPORT_ERROR_IO_ERROR;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Accept the connection
0N/A */
0N/A memset((void *)&socket,0,sizeof(struct sockaddr_in));
0N/A socketLen = sizeof(socket);
0N/A socketFD = dbgsysAccept(serverSocketFD,
0N/A (struct sockaddr *)&socket,
0N/A &socketLen);
0N/A /* set the last error here as could be overridden by configureBlocking */
0N/A if (socketFD < 0) {
0N/A setLastError(JDWPTRANSPORT_ERROR_IO_ERROR, "accept failed");
0N/A }
0N/A /*
0N/A * Restore the blocking state - note that the accepted socket may be in
0N/A * blocking or non-blocking mode (platform dependent). However as there
0N/A * is a handshake timeout set then it will go into non-blocking mode
0N/A * anyway for the handshake.
0N/A */
0N/A if (acceptTimeout > 0) {
0N/A dbgsysConfigureBlocking(serverSocketFD, JNI_TRUE);
0N/A }
0N/A if (socketFD < 0) {
0N/A return JDWPTRANSPORT_ERROR_IO_ERROR;
0N/A }
0N/A
0N/A /* handshake with the debugger */
0N/A err = handshake(socketFD, handshakeTimeout);
0N/A
0N/A /*
0N/A * If the handshake fails then close the connection. If there if an accept
0N/A * timeout then we must adjust the timeout for the next poll.
0N/A */
0N/A if (err) {
0N/A fprintf(stderr, "Debugger failed to attach: %s\n", getLastError());
0N/A dbgsysSocketClose(socketFD);
0N/A socketFD = -1;
0N/A if (acceptTimeout > 0) {
0N/A long endTime = dbgsysCurrentTimeMillis();
0N/A acceptTimeout -= (endTime - startTime);
0N/A if (acceptTimeout <= 0) {
0N/A setLastError(JDWPTRANSPORT_ERROR_IO_ERROR,
0N/A "timeout waiting for debugger to connect");
0N/A return JDWPTRANSPORT_ERROR_IO_ERROR;
0N/A }
0N/A }
0N/A }
0N/A } while (socketFD < 0);
0N/A
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/Astatic jdwpTransportError JNICALL
0N/AsocketTransport_stopListening(jdwpTransportEnv *env)
0N/A{
0N/A if (serverSocketFD < 0) {
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "connection not open");
0N/A }
0N/A if (dbgsysSocketClose(serverSocketFD) < 0) {
0N/A RETURN_IO_ERROR("close failed");
0N/A }
0N/A serverSocketFD = -1;
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/Astatic jdwpTransportError JNICALL
0N/AsocketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong attachTimeout,
0N/A jlong handshakeTimeout)
0N/A{
0N/A struct sockaddr_in sa;
0N/A int err;
0N/A
0N/A if (addressString == NULL || addressString[0] == '\0') {
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "address is missing");
0N/A }
0N/A
0N/A err = parseAddress(addressString, &sa, 0x7f000001);
0N/A if (err != JDWPTRANSPORT_ERROR_NONE) {
0N/A return err;
0N/A }
0N/A
0N/A socketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0);
0N/A if (socketFD < 0) {
0N/A RETURN_IO_ERROR("unable to create socket");
0N/A }
0N/A
0N/A err = setOptions(socketFD);
0N/A if (err) {
0N/A return err;
0N/A }
0N/A
0N/A /*
0N/A * To do a timed connect we make the socket non-blocking
0N/A * and poll with a timeout;
0N/A */
0N/A if (attachTimeout > 0) {
0N/A dbgsysConfigureBlocking(socketFD, JNI_FALSE);
0N/A }
0N/A
0N/A err = dbgsysConnect(socketFD, (struct sockaddr *)&sa, sizeof(sa));
0N/A if (err == DBG_EINPROGRESS && attachTimeout > 0) {
0N/A err = dbgsysFinishConnect(socketFD, (long)attachTimeout);
0N/A
0N/A if (err == DBG_ETIMEOUT) {
0N/A dbgsysConfigureBlocking(socketFD, JNI_TRUE);
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "connect timed out");
0N/A }
0N/A }
0N/A
0N/A if (err < 0) {
0N/A RETURN_IO_ERROR("connect failed");
0N/A }
0N/A
0N/A if (attachTimeout > 0) {
0N/A dbgsysConfigureBlocking(socketFD, JNI_TRUE);
0N/A }
0N/A
0N/A err = handshake(socketFD, handshakeTimeout);
0N/A if (err) {
0N/A dbgsysSocketClose(socketFD);
0N/A socketFD = -1;
0N/A return err;
0N/A }
0N/A
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/Astatic jboolean JNICALL
0N/AsocketTransport_isOpen(jdwpTransportEnv* env)
0N/A{
0N/A if (socketFD >= 0) {
0N/A return JNI_TRUE;
0N/A } else {
0N/A return JNI_FALSE;
0N/A }
0N/A}
0N/A
0N/Astatic jdwpTransportError JNICALL
0N/AsocketTransport_close(jdwpTransportEnv* env)
0N/A{
0N/A int fd = socketFD;
0N/A socketFD = -1;
0N/A if (fd < 0) {
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A }
0N/A if (dbgsysSocketClose(fd) < 0) {
0N/A /*
0N/A * close failed - it's pointless to restore socketFD here because
0N/A * any subsequent close will likely fail aswell.
0N/A */
0N/A RETURN_IO_ERROR("close failed");
0N/A }
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/Astatic jdwpTransportError JNICALL
0N/AsocketTransport_writePacket(jdwpTransportEnv* env, const jdwpPacket *packet)
0N/A{
0N/A jint len, data_len, id;
0N/A /*
0N/A * room for header and up to MAX_DATA_SIZE data bytes
0N/A */
0N/A char header[HEADER_SIZE + MAX_DATA_SIZE];
0N/A jbyte *data;
0N/A
0N/A /* packet can't be null */
0N/A if (packet == NULL) {
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is NULL");
0N/A }
0N/A
0N/A len = packet->type.cmd.len; /* includes header */
0N/A data_len = len - HEADER_SIZE;
0N/A
0N/A /* bad packet */
0N/A if (data_len < 0) {
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid length");
0N/A }
0N/A
0N/A /* prepare the header for transmission */
0N/A len = (jint)dbgsysHostToNetworkLong(len);
0N/A id = (jint)dbgsysHostToNetworkLong(packet->type.cmd.id);
0N/A
0N/A memcpy(header + 0, &len, 4);
0N/A memcpy(header + 4, &id, 4);
0N/A header[8] = packet->type.cmd.flags;
0N/A if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
0N/A jshort errorCode =
0N/A dbgsysHostToNetworkShort(packet->type.reply.errorCode);
0N/A memcpy(header + 9, &errorCode, 2);
0N/A } else {
0N/A header[9] = packet->type.cmd.cmdSet;
0N/A header[10] = packet->type.cmd.cmd;
0N/A }
0N/A
0N/A data = packet->type.cmd.data;
0N/A /* Do one send for short packets, two for longer ones */
0N/A if (data_len <= MAX_DATA_SIZE) {
0N/A memcpy(header + HEADER_SIZE, data, data_len);
4632N/A if (send_fully(socketFD, (char *)&header, HEADER_SIZE + data_len) !=
0N/A HEADER_SIZE + data_len) {
0N/A RETURN_IO_ERROR("send failed");
0N/A }
0N/A } else {
0N/A memcpy(header + HEADER_SIZE, data, MAX_DATA_SIZE);
4632N/A if (send_fully(socketFD, (char *)&header, HEADER_SIZE + MAX_DATA_SIZE) !=
0N/A HEADER_SIZE + MAX_DATA_SIZE) {
0N/A RETURN_IO_ERROR("send failed");
0N/A }
0N/A /* Send the remaining data bytes right out of the data area. */
4632N/A if (send_fully(socketFD, (char *)data + MAX_DATA_SIZE,
4632N/A data_len - MAX_DATA_SIZE) != data_len - MAX_DATA_SIZE) {
0N/A RETURN_IO_ERROR("send failed");
0N/A }
0N/A }
0N/A
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/Astatic jint
0N/Arecv_fully(int f, char *buf, int len)
0N/A{
0N/A int nbytes = 0;
0N/A while (nbytes < len) {
0N/A int res = dbgsysRecv(f, buf + nbytes, len - nbytes, 0);
0N/A if (res < 0) {
0N/A return res;
0N/A } else if (res == 0) {
0N/A break; /* eof, return nbytes which is less than len */
0N/A }
0N/A nbytes += res;
0N/A }
0N/A return nbytes;
0N/A}
0N/A
4632N/Ajint
4632N/Asend_fully(int f, char *buf, int len)
4632N/A{
4632N/A int nbytes = 0;
4632N/A while (nbytes < len) {
4632N/A int res = dbgsysSend(f, buf + nbytes, len - nbytes, 0);
4632N/A if (res < 0) {
4632N/A return res;
4632N/A } else if (res == 0) {
4632N/A break; /* eof, return nbytes which is less than len */
4632N/A }
4632N/A nbytes += res;
4632N/A }
4632N/A return nbytes;
4632N/A}
4632N/A
0N/Astatic jdwpTransportError JNICALL
0N/AsocketTransport_readPacket(jdwpTransportEnv* env, jdwpPacket* packet) {
0N/A jint length, data_len;
0N/A jint n;
0N/A
0N/A /* packet can't be null */
0N/A if (packet == NULL) {
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is null");
0N/A }
0N/A
0N/A /* read the length field */
0N/A n = recv_fully(socketFD, (char *)&length, sizeof(jint));
0N/A
0N/A /* check for EOF */
0N/A if (n == 0) {
0N/A packet->type.cmd.len = 0;
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A }
0N/A if (n != sizeof(jint)) {
0N/A RETURN_RECV_ERROR(n);
0N/A }
0N/A
0N/A length = (jint)dbgsysNetworkToHostLong(length);
0N/A packet->type.cmd.len = length;
0N/A
0N/A
0N/A n = recv_fully(socketFD,(char *)&(packet->type.cmd.id),sizeof(jint));
0N/A if (n < (int)sizeof(jint)) {
0N/A RETURN_RECV_ERROR(n);
0N/A }
0N/A
0N/A packet->type.cmd.id = (jint)dbgsysNetworkToHostLong(packet->type.cmd.id);
0N/A
0N/A n = recv_fully(socketFD,(char *)&(packet->type.cmd.flags),sizeof(jbyte));
0N/A if (n < (int)sizeof(jbyte)) {
0N/A RETURN_RECV_ERROR(n);
0N/A }
0N/A
0N/A if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
0N/A n = recv_fully(socketFD,(char *)&(packet->type.reply.errorCode),sizeof(jbyte));
0N/A if (n < (int)sizeof(jshort)) {
0N/A RETURN_RECV_ERROR(n);
0N/A }
0N/A
0N/A /* FIXME - should the error be converted to host order?? */
0N/A
0N/A
0N/A } else {
0N/A n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmdSet),sizeof(jbyte));
0N/A if (n < (int)sizeof(jbyte)) {
0N/A RETURN_RECV_ERROR(n);
0N/A }
0N/A
0N/A n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmd),sizeof(jbyte));
0N/A if (n < (int)sizeof(jbyte)) {
0N/A RETURN_RECV_ERROR(n);
0N/A }
0N/A }
0N/A
0N/A data_len = length - ((sizeof(jint) * 2) + (sizeof(jbyte) * 3));
0N/A
0N/A if (data_len < 0) {
0N/A setLastError(0, "Badly formed packet received - invalid length");
0N/A return JDWPTRANSPORT_ERROR_IO_ERROR;
0N/A } else if (data_len == 0) {
0N/A packet->type.cmd.data = NULL;
0N/A } else {
0N/A packet->type.cmd.data= (*callback->alloc)(data_len);
0N/A
0N/A if (packet->type.cmd.data == NULL) {
0N/A RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
0N/A }
0N/A
0N/A n = recv_fully(socketFD,(char *)packet->type.cmd.data, data_len);
0N/A if (n < data_len) {
0N/A (*callback->free)(packet->type.cmd.data);
0N/A RETURN_RECV_ERROR(n);
0N/A }
0N/A }
0N/A
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/Astatic jdwpTransportError JNICALL
0N/AsocketTransport_getLastError(jdwpTransportEnv* env, char** msgP) {
0N/A char *msg = (char *)dbgsysTlsGet(tlsIndex);
0N/A if (msg == NULL) {
0N/A return JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE;
0N/A }
439N/A *msgP = (*callback->alloc)((int)strlen(msg)+1);
0N/A if (*msgP == NULL) {
0N/A return JDWPTRANSPORT_ERROR_OUT_OF_MEMORY;
0N/A }
0N/A strcpy(*msgP, msg);
0N/A return JDWPTRANSPORT_ERROR_NONE;
0N/A}
0N/A
0N/AJNIEXPORT jint JNICALL
0N/AjdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
0N/A jint version, jdwpTransportEnv** result)
0N/A{
0N/A if (version != JDWPTRANSPORT_VERSION_1_0) {
0N/A return JNI_EVERSION;
0N/A }
0N/A if (initialized) {
0N/A /*
0N/A * This library doesn't support multiple environments (yet)
0N/A */
0N/A return JNI_EEXIST;
0N/A }
0N/A initialized = JNI_TRUE;
0N/A jvm = vm;
0N/A callback = cbTablePtr;
0N/A
0N/A /* initialize interface table */
0N/A interface.GetCapabilities = &socketTransport_getCapabilities;
0N/A interface.Attach = &socketTransport_attach;
0N/A interface.StartListening = &socketTransport_startListening;
0N/A interface.StopListening = &socketTransport_stopListening;
0N/A interface.Accept = &socketTransport_accept;
0N/A interface.IsOpen = &socketTransport_isOpen;
0N/A interface.Close = &socketTransport_close;
0N/A interface.ReadPacket = &socketTransport_readPacket;
0N/A interface.WritePacket = &socketTransport_writePacket;
0N/A interface.GetLastError = &socketTransport_getLastError;
0N/A *result = &single_env;
0N/A
0N/A /* initialized TLS */
0N/A tlsIndex = dbgsysTlsAlloc();
0N/A return JNI_OK;
0N/A}