Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/transport/socket/socketTransport.c
38813 views
/*1* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24#include <stdio.h>25#include <string.h>26#include <errno.h>27#include <stdlib.h>28#include <ctype.h>2930#include "jdwpTransport.h"31#include "sysSocket.h"3233/*34* The Socket Transport Library.35*36* This module is an implementation of the Java Debug Wire Protocol Transport37* Service Provider Interface - see src/share/javavm/export/jdwpTransport.h.38*/3940static int serverSocketFD;41static int socketFD = -1;42static jdwpTransportCallback *callback;43static JavaVM *jvm;44static int tlsIndex;45static jboolean initialized;46static struct jdwpTransportNativeInterface_ interface;47static jdwpTransportEnv single_env = (jdwpTransportEnv)&interface;4849#define RETURN_ERROR(err, msg) \50if (1==1) { \51setLastError(err, msg); \52return err; \53}5455#define RETURN_IO_ERROR(msg) RETURN_ERROR(JDWPTRANSPORT_ERROR_IO_ERROR, msg);5657#define RETURN_RECV_ERROR(n) \58if (n == 0) { \59RETURN_ERROR(JDWPTRANSPORT_ERROR_IO_ERROR, "premature EOF"); \60} else { \61RETURN_IO_ERROR("recv error"); \62}6364#define HEADER_SIZE 1165#define MAX_DATA_SIZE 10006667static jint recv_fully(int, char *, int);68static jint send_fully(int, char *, int);6970/*71* Record the last error for this thread.72*/73static void74setLastError(jdwpTransportError err, char *newmsg) {75char buf[255];76char *msg;7778/* get any I/O first in case any system calls override errno */79if (err == JDWPTRANSPORT_ERROR_IO_ERROR) {80dbgsysGetLastIOError(buf, sizeof(buf));81}8283msg = (char *)dbgsysTlsGet(tlsIndex);84if (msg != NULL) {85(*callback->free)(msg);86}8788if (err == JDWPTRANSPORT_ERROR_IO_ERROR) {89char *join_str = ": ";90int msg_len = (int)strlen(newmsg) + (int)strlen(join_str) +91(int)strlen(buf) + 3;92msg = (*callback->alloc)(msg_len);93if (msg != NULL) {94strcpy(msg, newmsg);95strcat(msg, join_str);96strcat(msg, buf);97}98} else {99msg = (*callback->alloc)((int)strlen(newmsg)+1);100if (msg != NULL) {101strcpy(msg, newmsg);102}103}104105dbgsysTlsPut(tlsIndex, msg);106}107108/*109* Return the last error for this thread (may be NULL)110*/111static char*112getLastError() {113return (char *)dbgsysTlsGet(tlsIndex);114}115116static jdwpTransportError117setOptions(int fd)118{119jvalue dontcare;120int err;121122dontcare.i = 0; /* keep compiler happy */123124err = dbgsysSetSocketOption(fd, SO_REUSEADDR, JNI_TRUE, dontcare);125if (err < 0) {126RETURN_IO_ERROR("setsockopt SO_REUSEADDR failed");127}128129err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare);130if (err < 0) {131RETURN_IO_ERROR("setsockopt TCPNODELAY failed");132}133134return JDWPTRANSPORT_ERROR_NONE;135}136137static jdwpTransportError138handshake(int fd, jlong timeout) {139const char *hello = "JDWP-Handshake";140char b[16];141int rv, helloLen, received;142143if (timeout > 0) {144dbgsysConfigureBlocking(fd, JNI_FALSE);145}146helloLen = (int)strlen(hello);147received = 0;148while (received < helloLen) {149int n;150char *buf;151if (timeout > 0) {152rv = dbgsysPoll(fd, JNI_TRUE, JNI_FALSE, (long)timeout);153if (rv <= 0) {154setLastError(0, "timeout during handshake");155return JDWPTRANSPORT_ERROR_IO_ERROR;156}157}158buf = b;159buf += received;160n = recv_fully(fd, buf, helloLen-received);161if (n == 0) {162setLastError(0, "handshake failed - connection prematurally closed");163return JDWPTRANSPORT_ERROR_IO_ERROR;164}165if (n < 0) {166RETURN_IO_ERROR("recv failed during handshake");167}168received += n;169}170if (timeout > 0) {171dbgsysConfigureBlocking(fd, JNI_TRUE);172}173if (strncmp(b, hello, received) != 0) {174char msg[80+2*16];175b[received] = '\0';176/*177* We should really use snprintf here but it's not available on Windows.178* We can't use jio_snprintf without linking the transport against the VM.179*/180sprintf(msg, "handshake failed - received >%s< - expected >%s<", b, hello);181setLastError(0, msg);182return JDWPTRANSPORT_ERROR_IO_ERROR;183}184185if (send_fully(fd, (char*)hello, helloLen) != helloLen) {186RETURN_IO_ERROR("send failed during handshake");187}188return JDWPTRANSPORT_ERROR_NONE;189}190191static jdwpTransportError192parseAddress(const char *address, struct sockaddr_in *sa, uint32_t defaultHost) {193char *colon;194195memset((void *)sa,0,sizeof(struct sockaddr_in));196sa->sin_family = AF_INET;197198/* check for host:port or port */199colon = strchr(address, ':');200if (colon == NULL) {201u_short port = (u_short)atoi(address);202sa->sin_port = dbgsysHostToNetworkShort(port);203sa->sin_addr.s_addr = dbgsysHostToNetworkLong(defaultHost);204} else {205char *buf;206char *hostname;207u_short port;208uint32_t addr;209210buf = (*callback->alloc)((int)strlen(address)+1);211if (buf == NULL) {212RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");213}214strcpy(buf, address);215buf[colon - address] = '\0';216hostname = buf;217port = atoi(colon + 1);218sa->sin_port = dbgsysHostToNetworkShort(port);219220/*221* First see if the host is a literal IP address.222* If not then try to resolve it.223*/224addr = dbgsysInetAddr(hostname);225if (addr == 0xffffffff) {226struct hostent *hp = dbgsysGetHostByName(hostname);227if (hp == NULL) {228/* don't use RETURN_IO_ERROR as unknown host is normal */229setLastError(0, "gethostbyname: unknown host");230(*callback->free)(buf);231return JDWPTRANSPORT_ERROR_IO_ERROR;232}233234/* lookup was successful */235memcpy(&(sa->sin_addr), hp->h_addr_list[0], hp->h_length);236} else {237sa->sin_addr.s_addr = addr;238}239240(*callback->free)(buf);241}242243return JDWPTRANSPORT_ERROR_NONE;244}245246247static jdwpTransportError JNICALL248socketTransport_getCapabilities(jdwpTransportEnv* env,249JDWPTransportCapabilities* capabilitiesPtr)250{251JDWPTransportCapabilities result;252253memset(&result, 0, sizeof(result));254result.can_timeout_attach = JNI_TRUE;255result.can_timeout_accept = JNI_TRUE;256result.can_timeout_handshake = JNI_TRUE;257258*capabilitiesPtr = result;259260return JDWPTRANSPORT_ERROR_NONE;261}262263264static jdwpTransportError JNICALL265socketTransport_startListening(jdwpTransportEnv* env, const char* address,266char** actualAddress)267{268struct sockaddr_in sa;269int err;270271memset((void *)&sa,0,sizeof(struct sockaddr_in));272sa.sin_family = AF_INET;273274/* no address provided */275if ((address == NULL) || (address[0] == '\0')) {276address = "0";277}278279err = parseAddress(address, &sa, INADDR_ANY);280if (err != JDWPTRANSPORT_ERROR_NONE) {281return err;282}283284serverSocketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0);285if (serverSocketFD < 0) {286RETURN_IO_ERROR("socket creation failed");287}288289err = setOptions(serverSocketFD);290if (err) {291return err;292}293294err = dbgsysBind(serverSocketFD, (struct sockaddr *)&sa, sizeof(sa));295if (err < 0) {296RETURN_IO_ERROR("bind failed");297}298299err = dbgsysListen(serverSocketFD, 1);300if (err < 0) {301RETURN_IO_ERROR("listen failed");302}303304{305char buf[20];306socklen_t len = sizeof(sa);307jint portNum;308err = dbgsysGetSocketName(serverSocketFD,309(struct sockaddr *)&sa, &len);310portNum = dbgsysNetworkToHostShort(sa.sin_port);311sprintf(buf, "%d", portNum);312*actualAddress = (*callback->alloc)((int)strlen(buf) + 1);313if (*actualAddress == NULL) {314RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");315} else {316strcpy(*actualAddress, buf);317}318}319320return JDWPTRANSPORT_ERROR_NONE;321}322323static jdwpTransportError JNICALL324socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout)325{326socklen_t socketLen;327int err;328struct sockaddr_in socket;329jlong startTime = (jlong)0;330331/*332* Use a default handshake timeout if not specified - this avoids an indefinite333* hang in cases where something other than a debugger connects to our port.334*/335if (handshakeTimeout == 0) {336handshakeTimeout = 2000;337}338339do {340/*341* If there is an accept timeout then we put the socket in non-blocking342* mode and poll for a connection.343*/344if (acceptTimeout > 0) {345int rv;346dbgsysConfigureBlocking(serverSocketFD, JNI_FALSE);347startTime = dbgsysCurrentTimeMillis();348rv = dbgsysPoll(serverSocketFD, JNI_TRUE, JNI_FALSE, (long)acceptTimeout);349if (rv <= 0) {350/* set the last error here as could be overridden by configureBlocking */351if (rv == 0) {352setLastError(JDWPTRANSPORT_ERROR_IO_ERROR, "poll failed");353}354/* restore blocking state */355dbgsysConfigureBlocking(serverSocketFD, JNI_TRUE);356if (rv == 0) {357RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "timed out waiting for connection");358} else {359return JDWPTRANSPORT_ERROR_IO_ERROR;360}361}362}363364/*365* Accept the connection366*/367memset((void *)&socket,0,sizeof(struct sockaddr_in));368socketLen = sizeof(socket);369socketFD = dbgsysAccept(serverSocketFD,370(struct sockaddr *)&socket,371&socketLen);372/* set the last error here as could be overridden by configureBlocking */373if (socketFD < 0) {374setLastError(JDWPTRANSPORT_ERROR_IO_ERROR, "accept failed");375}376/*377* Restore the blocking state - note that the accepted socket may be in378* blocking or non-blocking mode (platform dependent). However as there379* is a handshake timeout set then it will go into non-blocking mode380* anyway for the handshake.381*/382if (acceptTimeout > 0) {383dbgsysConfigureBlocking(serverSocketFD, JNI_TRUE);384}385if (socketFD < 0) {386return JDWPTRANSPORT_ERROR_IO_ERROR;387}388389/* handshake with the debugger */390err = handshake(socketFD, handshakeTimeout);391392/*393* If the handshake fails then close the connection. If there if an accept394* timeout then we must adjust the timeout for the next poll.395*/396if (err) {397fprintf(stderr, "Debugger failed to attach: %s\n", getLastError());398dbgsysSocketClose(socketFD);399socketFD = -1;400if (acceptTimeout > 0) {401long endTime = dbgsysCurrentTimeMillis();402acceptTimeout -= (endTime - startTime);403if (acceptTimeout <= 0) {404setLastError(JDWPTRANSPORT_ERROR_IO_ERROR,405"timeout waiting for debugger to connect");406return JDWPTRANSPORT_ERROR_IO_ERROR;407}408}409}410} while (socketFD < 0);411412return JDWPTRANSPORT_ERROR_NONE;413}414415static jdwpTransportError JNICALL416socketTransport_stopListening(jdwpTransportEnv *env)417{418if (serverSocketFD < 0) {419RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_STATE, "connection not open");420}421if (dbgsysSocketClose(serverSocketFD) < 0) {422RETURN_IO_ERROR("close failed");423}424serverSocketFD = -1;425return JDWPTRANSPORT_ERROR_NONE;426}427428static jdwpTransportError JNICALL429socketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong attachTimeout,430jlong handshakeTimeout)431{432struct sockaddr_in sa;433int err;434435if (addressString == NULL || addressString[0] == '\0') {436RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "address is missing");437}438439err = parseAddress(addressString, &sa, 0x7f000001);440if (err != JDWPTRANSPORT_ERROR_NONE) {441return err;442}443444socketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0);445if (socketFD < 0) {446RETURN_IO_ERROR("unable to create socket");447}448449err = setOptions(socketFD);450if (err) {451return err;452}453454/*455* To do a timed connect we make the socket non-blocking456* and poll with a timeout;457*/458if (attachTimeout > 0) {459dbgsysConfigureBlocking(socketFD, JNI_FALSE);460}461462err = dbgsysConnect(socketFD, (struct sockaddr *)&sa, sizeof(sa));463if (err == DBG_EINPROGRESS && attachTimeout > 0) {464err = dbgsysFinishConnect(socketFD, (long)attachTimeout);465466if (err == DBG_ETIMEOUT) {467dbgsysConfigureBlocking(socketFD, JNI_TRUE);468RETURN_ERROR(JDWPTRANSPORT_ERROR_TIMEOUT, "connect timed out");469}470}471472if (err < 0) {473RETURN_IO_ERROR("connect failed");474}475476if (attachTimeout > 0) {477dbgsysConfigureBlocking(socketFD, JNI_TRUE);478}479480err = handshake(socketFD, handshakeTimeout);481if (err) {482dbgsysSocketClose(socketFD);483socketFD = -1;484return err;485}486487return JDWPTRANSPORT_ERROR_NONE;488}489490static jboolean JNICALL491socketTransport_isOpen(jdwpTransportEnv* env)492{493if (socketFD >= 0) {494return JNI_TRUE;495} else {496return JNI_FALSE;497}498}499500static jdwpTransportError JNICALL501socketTransport_close(jdwpTransportEnv* env)502{503int fd = socketFD;504socketFD = -1;505if (fd < 0) {506return JDWPTRANSPORT_ERROR_NONE;507}508#ifdef _AIX509/*510AIX needs a workaround for I/O cancellation, see:511http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/close.htm512...513The close subroutine is blocked until all subroutines which use the file514descriptor return to usr space. For example, when a thread is calling close515and another thread is calling select with the same file descriptor, the516close subroutine does not return until the select call returns.517...518*/519shutdown(fd, 2);520#endif521if (dbgsysSocketClose(fd) < 0) {522/*523* close failed - it's pointless to restore socketFD here because524* any subsequent close will likely fail as well.525*/526RETURN_IO_ERROR("close failed");527}528return JDWPTRANSPORT_ERROR_NONE;529}530531static jdwpTransportError JNICALL532socketTransport_writePacket(jdwpTransportEnv* env, const jdwpPacket *packet)533{534jint len, data_len, id;535/*536* room for header and up to MAX_DATA_SIZE data bytes537*/538char header[HEADER_SIZE + MAX_DATA_SIZE];539jbyte *data;540541/* packet can't be null */542if (packet == NULL) {543RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is NULL");544}545546len = packet->type.cmd.len; /* includes header */547data_len = len - HEADER_SIZE;548549/* bad packet */550if (data_len < 0) {551RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid length");552}553554/* prepare the header for transmission */555len = (jint)dbgsysHostToNetworkLong(len);556id = (jint)dbgsysHostToNetworkLong(packet->type.cmd.id);557558memcpy(header + 0, &len, 4);559memcpy(header + 4, &id, 4);560header[8] = packet->type.cmd.flags;561if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {562jshort errorCode =563dbgsysHostToNetworkShort(packet->type.reply.errorCode);564memcpy(header + 9, &errorCode, 2);565} else {566header[9] = packet->type.cmd.cmdSet;567header[10] = packet->type.cmd.cmd;568}569570data = packet->type.cmd.data;571/* Do one send for short packets, two for longer ones */572if (data_len <= MAX_DATA_SIZE) {573memcpy(header + HEADER_SIZE, data, data_len);574if (send_fully(socketFD, (char *)&header, HEADER_SIZE + data_len) !=575HEADER_SIZE + data_len) {576RETURN_IO_ERROR("send failed");577}578} else {579memcpy(header + HEADER_SIZE, data, MAX_DATA_SIZE);580if (send_fully(socketFD, (char *)&header, HEADER_SIZE + MAX_DATA_SIZE) !=581HEADER_SIZE + MAX_DATA_SIZE) {582RETURN_IO_ERROR("send failed");583}584/* Send the remaining data bytes right out of the data area. */585if (send_fully(socketFD, (char *)data + MAX_DATA_SIZE,586data_len - MAX_DATA_SIZE) != data_len - MAX_DATA_SIZE) {587RETURN_IO_ERROR("send failed");588}589}590591return JDWPTRANSPORT_ERROR_NONE;592}593594static jint595recv_fully(int f, char *buf, int len)596{597int nbytes = 0;598while (nbytes < len) {599int res = dbgsysRecv(f, buf + nbytes, len - nbytes, 0);600if (res < 0) {601return res;602} else if (res == 0) {603break; /* eof, return nbytes which is less than len */604}605nbytes += res;606}607return nbytes;608}609610jint611send_fully(int f, char *buf, int len)612{613int nbytes = 0;614while (nbytes < len) {615int res = dbgsysSend(f, buf + nbytes, len - nbytes, 0);616if (res < 0) {617return res;618} else if (res == 0) {619break; /* eof, return nbytes which is less than len */620}621nbytes += res;622}623return nbytes;624}625626static jdwpTransportError JNICALL627socketTransport_readPacket(jdwpTransportEnv* env, jdwpPacket* packet) {628jint length, data_len;629jint n;630631/* packet can't be null */632if (packet == NULL) {633RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is null");634}635636/* read the length field */637n = recv_fully(socketFD, (char *)&length, sizeof(jint));638639/* check for EOF */640if (n == 0) {641packet->type.cmd.len = 0;642return JDWPTRANSPORT_ERROR_NONE;643}644if (n != sizeof(jint)) {645RETURN_RECV_ERROR(n);646}647648length = (jint)dbgsysNetworkToHostLong(length);649packet->type.cmd.len = length;650651652n = recv_fully(socketFD,(char *)&(packet->type.cmd.id),sizeof(jint));653if (n < (int)sizeof(jint)) {654RETURN_RECV_ERROR(n);655}656657packet->type.cmd.id = (jint)dbgsysNetworkToHostLong(packet->type.cmd.id);658659n = recv_fully(socketFD,(char *)&(packet->type.cmd.flags),sizeof(jbyte));660if (n < (int)sizeof(jbyte)) {661RETURN_RECV_ERROR(n);662}663664if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {665n = recv_fully(socketFD,(char *)&(packet->type.reply.errorCode),sizeof(jbyte));666if (n < (int)sizeof(jshort)) {667RETURN_RECV_ERROR(n);668}669670/* FIXME - should the error be converted to host order?? */671672673} else {674n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmdSet),sizeof(jbyte));675if (n < (int)sizeof(jbyte)) {676RETURN_RECV_ERROR(n);677}678679n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmd),sizeof(jbyte));680if (n < (int)sizeof(jbyte)) {681RETURN_RECV_ERROR(n);682}683}684685data_len = length - ((sizeof(jint) * 2) + (sizeof(jbyte) * 3));686687if (data_len < 0) {688setLastError(0, "Badly formed packet received - invalid length");689return JDWPTRANSPORT_ERROR_IO_ERROR;690} else if (data_len == 0) {691packet->type.cmd.data = NULL;692} else {693packet->type.cmd.data= (*callback->alloc)(data_len);694695if (packet->type.cmd.data == NULL) {696RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");697}698699n = recv_fully(socketFD,(char *)packet->type.cmd.data, data_len);700if (n < data_len) {701(*callback->free)(packet->type.cmd.data);702RETURN_RECV_ERROR(n);703}704}705706return JDWPTRANSPORT_ERROR_NONE;707}708709static jdwpTransportError JNICALL710socketTransport_getLastError(jdwpTransportEnv* env, char** msgP) {711char *msg = (char *)dbgsysTlsGet(tlsIndex);712if (msg == NULL) {713return JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE;714}715*msgP = (*callback->alloc)((int)strlen(msg)+1);716if (*msgP == NULL) {717return JDWPTRANSPORT_ERROR_OUT_OF_MEMORY;718}719strcpy(*msgP, msg);720return JDWPTRANSPORT_ERROR_NONE;721}722723JNIEXPORT jint JNICALL724jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,725jint version, jdwpTransportEnv** result)726{727if (version != JDWPTRANSPORT_VERSION_1_0) {728return JNI_EVERSION;729}730if (initialized) {731/*732* This library doesn't support multiple environments (yet)733*/734return JNI_EEXIST;735}736initialized = JNI_TRUE;737jvm = vm;738callback = cbTablePtr;739740/* initialize interface table */741interface.GetCapabilities = &socketTransport_getCapabilities;742interface.Attach = &socketTransport_attach;743interface.StartListening = &socketTransport_startListening;744interface.StopListening = &socketTransport_stopListening;745interface.Accept = &socketTransport_accept;746interface.IsOpen = &socketTransport_isOpen;747interface.Close = &socketTransport_close;748interface.ReadPacket = &socketTransport_readPacket;749interface.WritePacket = &socketTransport_writePacket;750interface.GetLastError = &socketTransport_getLastError;751*result = &single_env;752753/* initialized TLS */754tlsIndex = dbgsysTlsAlloc();755return JNI_OK;756}757758759