Merge
This commit is contained in:
commit
407a3044c3
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -33,7 +33,8 @@
|
|||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
JDWPTRANSPORT_VERSION_1_0 = 0x00010000
|
JDWPTRANSPORT_VERSION_1_0 = 0x00010000,
|
||||||
|
JDWPTRANSPORT_VERSION_1_1 = 0x00010001
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -142,6 +143,13 @@ typedef jint (JNICALL *jdwpTransport_OnLoad_t)(JavaVM *jvm,
|
|||||||
jint version,
|
jint version,
|
||||||
jdwpTransportEnv** env);
|
jdwpTransportEnv** env);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JDWP transport configuration from the agent.
|
||||||
|
*/
|
||||||
|
typedef struct jdwpTransportConfiguration {
|
||||||
|
/* Field added in JDWPTRANSPORT_VERSION_1_1: */
|
||||||
|
const char* allowed_peers; /* Peers allowed for connection */
|
||||||
|
} jdwpTransportConfiguration;
|
||||||
|
|
||||||
|
|
||||||
/* Function Interface */
|
/* Function Interface */
|
||||||
@ -191,6 +199,9 @@ struct jdwpTransportNativeInterface_ {
|
|||||||
jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env,
|
jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env,
|
||||||
char** error);
|
char** error);
|
||||||
|
|
||||||
|
/* 12: SetTransportConfiguration added in JDWPTRANSPORT_VERSION_1_1 */
|
||||||
|
jdwpTransportError (JNICALL *SetTransportConfiguration)(jdwpTransportEnv* env,
|
||||||
|
jdwpTransportConfiguration *config);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -248,6 +259,10 @@ struct _jdwpTransportEnv {
|
|||||||
return functions->GetLastError(this, error);
|
return functions->GetLastError(this, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SetTransportConfiguration added in JDWPTRANSPORT_VERSION_1_1 */
|
||||||
|
jdwpTransportError SetTransportConfiguration(jdwpTransportEnv* env,
|
||||||
|
return functions->SetTransportConfiguration(this, config);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
};
|
};
|
||||||
|
@ -34,6 +34,9 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
#else
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -73,6 +76,19 @@ static jdwpTransportEnv single_env = (jdwpTransportEnv)&interface;
|
|||||||
static jint recv_fully(int, char *, int);
|
static jint recv_fully(int, char *, int);
|
||||||
static jint send_fully(int, char *, int);
|
static jint send_fully(int, char *, int);
|
||||||
|
|
||||||
|
/* version >= JDWPTRANSPORT_VERSION_1_1 */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t subnet;
|
||||||
|
uint32_t netmask;
|
||||||
|
} AllowedPeerInfo;
|
||||||
|
|
||||||
|
#define STR(x) #x
|
||||||
|
#define MAX_PEER_ENTRIES 32
|
||||||
|
#define MAX_PEERS_STR STR(MAX_PEER_ENTRIES)
|
||||||
|
static AllowedPeerInfo _peers[MAX_PEER_ENTRIES];
|
||||||
|
static int _peers_cnt = 0;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record the last error for this thread.
|
* Record the last error for this thread.
|
||||||
*/
|
*/
|
||||||
@ -260,7 +276,7 @@ parseAddress(const char *address, struct sockaddr_in *sa) {
|
|||||||
char *colon;
|
char *colon;
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
memset((void *)sa,0,sizeof(struct sockaddr_in));
|
memset((void *)sa, 0, sizeof(struct sockaddr_in));
|
||||||
sa->sin_family = AF_INET;
|
sa->sin_family = AF_INET;
|
||||||
|
|
||||||
/* check for host:port or port */
|
/* check for host:port or port */
|
||||||
@ -274,7 +290,7 @@ parseAddress(const char *address, struct sockaddr_in *sa) {
|
|||||||
if (colon == NULL) {
|
if (colon == NULL) {
|
||||||
// bind to localhost only if no address specified
|
// bind to localhost only if no address specified
|
||||||
sa->sin_addr.s_addr = getLocalHostAddress();
|
sa->sin_addr.s_addr = getLocalHostAddress();
|
||||||
} else if (strncmp(address,"localhost:",10) == 0) {
|
} else if (strncmp(address, "localhost:", 10) == 0) {
|
||||||
// optimize for common case
|
// optimize for common case
|
||||||
sa->sin_addr.s_addr = getLocalHostAddress();
|
sa->sin_addr.s_addr = getLocalHostAddress();
|
||||||
} else if (*address == '*' && *(address+1) == ':') {
|
} else if (*address == '*' && *(address+1) == ':') {
|
||||||
@ -286,7 +302,7 @@ parseAddress(const char *address, struct sockaddr_in *sa) {
|
|||||||
char *hostname;
|
char *hostname;
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
|
|
||||||
buf = (*callback->alloc)((int)strlen(address)+1);
|
buf = (*callback->alloc)((int)strlen(address) + 1);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
|
RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
|
||||||
}
|
}
|
||||||
@ -320,6 +336,131 @@ parseAddress(const char *address, struct sockaddr_in *sa) {
|
|||||||
return JDWPTRANSPORT_ERROR_NONE;
|
return JDWPTRANSPORT_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
ip_s2u(const char *instr, uint32_t *ip) {
|
||||||
|
// Convert string representation of ip to integer
|
||||||
|
// in network byte order (big-endian)
|
||||||
|
char t[4] = { 0, 0, 0, 0 };
|
||||||
|
const char *s = instr;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (*s == '.') {
|
||||||
|
++i;
|
||||||
|
++s;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*s == 0 || *s == '+' || *s == '/') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*s < '0' || *s > '9') {
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
t[i] = (t[i] * 10) + (*s - '0');
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ip = *(uint32_t*)(t);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
mask_s2u(const char *instr, uint32_t *mask) {
|
||||||
|
// Convert the number of bits to a netmask
|
||||||
|
// in network byte order (big-endian)
|
||||||
|
unsigned char m = 0;
|
||||||
|
const char *s = instr;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (*s == 0 || *s == '+') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*s < '0' || *s > '9') {
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
m = (m * 10) + (*s - '0');
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m == 0 || m > 32) {
|
||||||
|
// Drop invalid input
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
|
||||||
|
*mask = htonl(-1 << (32 - m));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ip_in_subnet(uint32_t subnet, uint32_t mask, uint32_t ipaddr) {
|
||||||
|
return (ipaddr & mask) == subnet;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jdwpTransportError
|
||||||
|
parseAllowedPeers(const char *allowed_peers) {
|
||||||
|
// Build a list of allowed peers from char string
|
||||||
|
// of format 192.168.0.10+192.168.0.0/24
|
||||||
|
const char *s = NULL;
|
||||||
|
const char *p = allowed_peers;
|
||||||
|
uint32_t ip = 0;
|
||||||
|
uint32_t mask = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
s = ip_s2u(p, &ip);
|
||||||
|
if (s == p) {
|
||||||
|
_peers_cnt = 0;
|
||||||
|
fprintf(stderr, "Error in allow option: '%s'\n", s);
|
||||||
|
RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
|
||||||
|
"invalid IP address in allow option");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s == '/') {
|
||||||
|
// netmask specified
|
||||||
|
s = mask_s2u(s + 1, &mask);
|
||||||
|
if (*(s - 1) == '/') {
|
||||||
|
// Input is not consumed, something bad happened
|
||||||
|
_peers_cnt = 0;
|
||||||
|
fprintf(stderr, "Error in allow option: '%s'\n", s);
|
||||||
|
RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
|
||||||
|
"invalid netmask in allow option");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// reset netmask
|
||||||
|
mask = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s == '+' || *s == 0) {
|
||||||
|
if (_peers_cnt >= MAX_PEER_ENTRIES) {
|
||||||
|
fprintf(stderr, "Error in allow option: '%s'\n", allowed_peers);
|
||||||
|
RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
|
||||||
|
"exceeded max number of allowed peers: " MAX_PEERS_STR);
|
||||||
|
}
|
||||||
|
_peers[_peers_cnt].subnet = ip;
|
||||||
|
_peers[_peers_cnt].netmask = mask;
|
||||||
|
_peers_cnt++;
|
||||||
|
if (*s == 0) {
|
||||||
|
// end of options
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// advance to next IP block
|
||||||
|
p = s + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JDWPTRANSPORT_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
isPeerAllowed(struct sockaddr_in *peer) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < _peers_cnt; ++i) {
|
||||||
|
int peer_ip = peer->sin_addr.s_addr;
|
||||||
|
if (ip_in_subnet(_peers[i].subnet, _peers[i].netmask, peer_ip)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static jdwpTransportError JNICALL
|
static jdwpTransportError JNICALL
|
||||||
socketTransport_getCapabilities(jdwpTransportEnv* env,
|
socketTransport_getCapabilities(jdwpTransportEnv* env,
|
||||||
@ -412,7 +553,7 @@ static jdwpTransportError JNICALL
|
|||||||
socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout)
|
socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout)
|
||||||
{
|
{
|
||||||
socklen_t socketLen;
|
socklen_t socketLen;
|
||||||
int err;
|
int err = JDWPTRANSPORT_ERROR_NONE;
|
||||||
struct sockaddr_in socket;
|
struct sockaddr_in socket;
|
||||||
jlong startTime = (jlong)0;
|
jlong startTime = (jlong)0;
|
||||||
|
|
||||||
@ -474,14 +615,34 @@ socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handsha
|
|||||||
return JDWPTRANSPORT_ERROR_IO_ERROR;
|
return JDWPTRANSPORT_ERROR_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handshake with the debugger */
|
/*
|
||||||
err = handshake(socketFD, handshakeTimeout);
|
* version >= JDWPTRANSPORT_VERSION_1_1:
|
||||||
|
* Verify that peer is allowed to connect.
|
||||||
|
*/
|
||||||
|
if (_peers_cnt > 0) {
|
||||||
|
if (!isPeerAllowed(&socket)) {
|
||||||
|
char ebuf[64] = { 0 };
|
||||||
|
char buf[INET_ADDRSTRLEN] = { 0 };
|
||||||
|
const char* addr_str = inet_ntop(AF_INET, &(socket.sin_addr), buf, INET_ADDRSTRLEN);
|
||||||
|
sprintf(ebuf, "ERROR: Peer not allowed to connect: %s\n",
|
||||||
|
(addr_str == NULL) ? "<bad address>" : addr_str);
|
||||||
|
dbgsysSocketClose(socketFD);
|
||||||
|
socketFD = -1;
|
||||||
|
err = JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT;
|
||||||
|
setLastError(err, ebuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socketFD > 0) {
|
||||||
|
/* handshake with the debugger */
|
||||||
|
err = handshake(socketFD, handshakeTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the handshake fails then close the connection. If there if an accept
|
* If the handshake fails then close the connection. If there if an accept
|
||||||
* timeout then we must adjust the timeout for the next poll.
|
* timeout then we must adjust the timeout for the next poll.
|
||||||
*/
|
*/
|
||||||
if (err) {
|
if (err != JDWPTRANSPORT_ERROR_NONE) {
|
||||||
fprintf(stderr, "Debugger failed to attach: %s\n", getLastError());
|
fprintf(stderr, "Debugger failed to attach: %s\n", getLastError());
|
||||||
dbgsysSocketClose(socketFD);
|
dbgsysSocketClose(socketFD);
|
||||||
socketFD = -1;
|
socketFD = -1;
|
||||||
@ -743,20 +904,20 @@ socketTransport_readPacket(jdwpTransportEnv* env, jdwpPacket* packet) {
|
|||||||
packet->type.cmd.len = length;
|
packet->type.cmd.len = length;
|
||||||
|
|
||||||
|
|
||||||
n = recv_fully(socketFD,(char *)&(packet->type.cmd.id),sizeof(jint));
|
n = recv_fully(socketFD,(char *)&(packet->type.cmd.id), sizeof(jint));
|
||||||
if (n < (int)sizeof(jint)) {
|
if (n < (int)sizeof(jint)) {
|
||||||
RETURN_RECV_ERROR(n);
|
RETURN_RECV_ERROR(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
packet->type.cmd.id = (jint)dbgsysNetworkToHostLong(packet->type.cmd.id);
|
packet->type.cmd.id = (jint)dbgsysNetworkToHostLong(packet->type.cmd.id);
|
||||||
|
|
||||||
n = recv_fully(socketFD,(char *)&(packet->type.cmd.flags),sizeof(jbyte));
|
n = recv_fully(socketFD,(char *)&(packet->type.cmd.flags), sizeof(jbyte));
|
||||||
if (n < (int)sizeof(jbyte)) {
|
if (n < (int)sizeof(jbyte)) {
|
||||||
RETURN_RECV_ERROR(n);
|
RETURN_RECV_ERROR(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
|
if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
|
||||||
n = recv_fully(socketFD,(char *)&(packet->type.reply.errorCode),sizeof(jbyte));
|
n = recv_fully(socketFD,(char *)&(packet->type.reply.errorCode), sizeof(jbyte));
|
||||||
if (n < (int)sizeof(jshort)) {
|
if (n < (int)sizeof(jshort)) {
|
||||||
RETURN_RECV_ERROR(n);
|
RETURN_RECV_ERROR(n);
|
||||||
}
|
}
|
||||||
@ -765,12 +926,12 @@ socketTransport_readPacket(jdwpTransportEnv* env, jdwpPacket* packet) {
|
|||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmdSet),sizeof(jbyte));
|
n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmdSet), sizeof(jbyte));
|
||||||
if (n < (int)sizeof(jbyte)) {
|
if (n < (int)sizeof(jbyte)) {
|
||||||
RETURN_RECV_ERROR(n);
|
RETURN_RECV_ERROR(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmd),sizeof(jbyte));
|
n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmd), sizeof(jbyte));
|
||||||
if (n < (int)sizeof(jbyte)) {
|
if (n < (int)sizeof(jbyte)) {
|
||||||
RETURN_RECV_ERROR(n);
|
RETURN_RECV_ERROR(n);
|
||||||
}
|
}
|
||||||
@ -814,11 +975,44 @@ socketTransport_getLastError(jdwpTransportEnv* env, char** msgP) {
|
|||||||
return JDWPTRANSPORT_ERROR_NONE;
|
return JDWPTRANSPORT_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static jdwpTransportError JNICALL
|
||||||
|
socketTransport_setConfiguration(jdwpTransportEnv* env, jdwpTransportConfiguration* cfg) {
|
||||||
|
const char* allowed_peers = NULL;
|
||||||
|
|
||||||
|
if (cfg == NULL) {
|
||||||
|
RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
|
||||||
|
"NULL pointer to transport configuration is invalid");
|
||||||
|
}
|
||||||
|
allowed_peers = cfg->allowed_peers;
|
||||||
|
_peers_cnt = 0;
|
||||||
|
if (allowed_peers != NULL) {
|
||||||
|
size_t len = strlen(allowed_peers);
|
||||||
|
if (len == 0) { /* Impossible: parseOptions() would reject it */
|
||||||
|
fprintf(stderr, "Error in allow option: '%s'\n", allowed_peers);
|
||||||
|
RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
|
||||||
|
"allow option should not be empty");
|
||||||
|
} else if (*allowed_peers == '*') {
|
||||||
|
if (len != 1) {
|
||||||
|
fprintf(stderr, "Error in allow option: '%s'\n", allowed_peers);
|
||||||
|
RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
|
||||||
|
"allow option '*' cannot be expanded");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int err = parseAllowedPeers(allowed_peers);
|
||||||
|
if (err != JDWPTRANSPORT_ERROR_NONE) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JDWPTRANSPORT_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
jint JNICALL
|
jint JNICALL
|
||||||
jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
|
jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
|
||||||
jint version, jdwpTransportEnv** result)
|
jint version, jdwpTransportEnv** env)
|
||||||
{
|
{
|
||||||
if (version != JDWPTRANSPORT_VERSION_1_0) {
|
if (version < JDWPTRANSPORT_VERSION_1_0 ||
|
||||||
|
version > JDWPTRANSPORT_VERSION_1_1) {
|
||||||
return JNI_EVERSION;
|
return JNI_EVERSION;
|
||||||
}
|
}
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
@ -842,7 +1036,10 @@ jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
|
|||||||
interface.ReadPacket = &socketTransport_readPacket;
|
interface.ReadPacket = &socketTransport_readPacket;
|
||||||
interface.WritePacket = &socketTransport_writePacket;
|
interface.WritePacket = &socketTransport_writePacket;
|
||||||
interface.GetLastError = &socketTransport_getLastError;
|
interface.GetLastError = &socketTransport_getLastError;
|
||||||
*result = &single_env;
|
if (version >= JDWPTRANSPORT_VERSION_1_1) {
|
||||||
|
interface.SetTransportConfiguration = &socketTransport_setConfiguration;
|
||||||
|
}
|
||||||
|
*env = &single_env;
|
||||||
|
|
||||||
/* initialized TLS */
|
/* initialized TLS */
|
||||||
tlsIndex = dbgsysTlsAlloc();
|
tlsIndex = dbgsysTlsAlloc();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -89,6 +89,7 @@ typedef struct TransportSpec {
|
|||||||
char *name;
|
char *name;
|
||||||
char *address;
|
char *address;
|
||||||
long timeout;
|
long timeout;
|
||||||
|
char *allow;
|
||||||
} TransportSpec;
|
} TransportSpec;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -564,7 +565,8 @@ startTransport(void *item, void *arg)
|
|||||||
|
|
||||||
LOG_MISC(("Begin startTransport"));
|
LOG_MISC(("Begin startTransport"));
|
||||||
serror = transport_startTransport(enumArg->isServer, transport->name,
|
serror = transport_startTransport(enumArg->isServer, transport->name,
|
||||||
transport->address, transport->timeout);
|
transport->address, transport->timeout,
|
||||||
|
transport->allow);
|
||||||
if (serror != JDWP_ERROR(NONE)) {
|
if (serror != JDWP_ERROR(NONE)) {
|
||||||
ERROR_MESSAGE(("JDWP Transport %s failed to initialize, %s(%d)",
|
ERROR_MESSAGE(("JDWP Transport %s failed to initialize, %s(%d)",
|
||||||
transport->name, jdwpErrorText(serror), serror));
|
transport->name, jdwpErrorText(serror), serror));
|
||||||
@ -1060,7 +1062,6 @@ parseOptions(char *options)
|
|||||||
if (transports == NULL) {
|
if (transports == NULL) {
|
||||||
EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"transports");
|
EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"transports");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
current = names;
|
current = names;
|
||||||
@ -1080,6 +1081,9 @@ parseOptions(char *options)
|
|||||||
goto syntax_error;
|
goto syntax_error;
|
||||||
}
|
}
|
||||||
currentTransport->name = current;
|
currentTransport->name = current;
|
||||||
|
currentTransport->address = NULL;
|
||||||
|
currentTransport->allow = NULL;
|
||||||
|
currentTransport->timeout = 0L;
|
||||||
current += strlen(current) + 1;
|
current += strlen(current) + 1;
|
||||||
} else if (strcmp(buf, "address") == 0) {
|
} else if (strcmp(buf, "address") == 0) {
|
||||||
if (currentTransport == NULL) {
|
if (currentTransport == NULL) {
|
||||||
@ -1092,7 +1096,18 @@ parseOptions(char *options)
|
|||||||
}
|
}
|
||||||
currentTransport->address = current;
|
currentTransport->address = current;
|
||||||
current += strlen(current) + 1;
|
current += strlen(current) + 1;
|
||||||
} else if (strcmp(buf, "timeout") == 0) {
|
} else if (strcmp(buf, "allow") == 0) {
|
||||||
|
if (currentTransport == NULL) {
|
||||||
|
errmsg = "allow specified without transport";
|
||||||
|
goto bad_option_with_errmsg;
|
||||||
|
}
|
||||||
|
/*LINTED*/
|
||||||
|
if (!get_tok(&str, current, (int)(end - current), ',')) {
|
||||||
|
goto syntax_error;
|
||||||
|
}
|
||||||
|
currentTransport->allow = current;
|
||||||
|
current += strlen(current) + 1;
|
||||||
|
} else if (strcmp(buf, "timeout") == 0) {
|
||||||
if (currentTransport == NULL) {
|
if (currentTransport == NULL) {
|
||||||
errmsg = "timeout specified without transport";
|
errmsg = "timeout specified without transport";
|
||||||
goto bad_option_with_errmsg;
|
goto bad_option_with_errmsg;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -29,7 +29,9 @@
|
|||||||
#include "debugLoop.h"
|
#include "debugLoop.h"
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
|
|
||||||
static jdwpTransportEnv *transport;
|
static jdwpTransportEnv *transport = NULL;
|
||||||
|
static unsigned transportVersion = JDWPTRANSPORT_VERSION_1_0;
|
||||||
|
|
||||||
static jrawMonitorID listenerLock;
|
static jrawMonitorID listenerLock;
|
||||||
static jrawMonitorID sendLock;
|
static jrawMonitorID sendLock;
|
||||||
|
|
||||||
@ -41,6 +43,8 @@ typedef struct TransportInfo {
|
|||||||
jdwpTransportEnv *transport;
|
jdwpTransportEnv *transport;
|
||||||
char *address;
|
char *address;
|
||||||
long timeout;
|
long timeout;
|
||||||
|
char *allowed_peers;
|
||||||
|
unsigned transportVersion;
|
||||||
} TransportInfo;
|
} TransportInfo;
|
||||||
|
|
||||||
static struct jdwpTransportCallback callback = {jvmtiAllocate, jvmtiDeallocate};
|
static struct jdwpTransportCallback callback = {jvmtiAllocate, jvmtiDeallocate};
|
||||||
@ -135,7 +139,7 @@ loadTransportLibrary(const char *libdir, const char *name)
|
|||||||
* JDK 1.2 javai.c v1.61
|
* JDK 1.2 javai.c v1.61
|
||||||
*/
|
*/
|
||||||
static jdwpError
|
static jdwpError
|
||||||
loadTransport(const char *name, jdwpTransportEnv **transportPtr)
|
loadTransport(const char *name, TransportInfo *info)
|
||||||
{
|
{
|
||||||
JNIEnv *env;
|
JNIEnv *env;
|
||||||
jdwpTransport_OnLoad_t onLoad;
|
jdwpTransport_OnLoad_t onLoad;
|
||||||
@ -147,6 +151,10 @@ loadTransport(const char *name, jdwpTransportEnv **transportPtr)
|
|||||||
ERROR_MESSAGE(("library name is empty"));
|
ERROR_MESSAGE(("library name is empty"));
|
||||||
return JDWP_ERROR(TRANSPORT_LOAD);
|
return JDWP_ERROR(TRANSPORT_LOAD);
|
||||||
}
|
}
|
||||||
|
if (info == NULL) {
|
||||||
|
ERROR_MESSAGE(("internal error: info should not be NULL"));
|
||||||
|
return JDWP_ERROR(TRANSPORT_LOAD);
|
||||||
|
}
|
||||||
|
|
||||||
/* First, look in sun.boot.library.path. This should find the standard
|
/* First, look in sun.boot.library.path. This should find the standard
|
||||||
* dt_socket and dt_shmem transport libraries, or any library
|
* dt_socket and dt_shmem transport libraries, or any library
|
||||||
@ -192,22 +200,34 @@ loadTransport(const char *name, jdwpTransportEnv **transportPtr)
|
|||||||
|
|
||||||
/* Get transport interface */
|
/* Get transport interface */
|
||||||
env = getEnv();
|
env = getEnv();
|
||||||
if ( env != NULL ) {
|
if (env != NULL) {
|
||||||
jdwpTransportEnv *t;
|
jdwpTransportEnv *t = NULL;
|
||||||
JavaVM *jvm;
|
JavaVM *jvm = NULL;
|
||||||
jint ver;
|
jint rc;
|
||||||
|
size_t i;
|
||||||
|
/* If a new version is added here, update 'case JNI_EVERSION' below. */
|
||||||
|
jint supported_versions[2] = {JDWPTRANSPORT_VERSION_1_1, JDWPTRANSPORT_VERSION_1_0};
|
||||||
|
|
||||||
JNI_FUNC_PTR(env,GetJavaVM)(env, &jvm);
|
JNI_FUNC_PTR(env,GetJavaVM)(env, &jvm);
|
||||||
ver = (*onLoad)(jvm, &callback, JDWPTRANSPORT_VERSION_1_0, &t);
|
|
||||||
if (ver != JNI_OK) {
|
/* Try version 1.1 first, fallback to 1.0 on error */
|
||||||
switch (ver) {
|
for (i = 0; i < sizeof(supported_versions); ++i) {
|
||||||
|
rc = (*onLoad)(jvm, &callback, supported_versions[i], &t);
|
||||||
|
if (rc != JNI_EVERSION) {
|
||||||
|
info->transportVersion = supported_versions[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc != JNI_OK) {
|
||||||
|
switch (rc) {
|
||||||
case JNI_ENOMEM :
|
case JNI_ENOMEM :
|
||||||
ERROR_MESSAGE(("insufficient memory to complete initialization"));
|
ERROR_MESSAGE(("insufficient memory to complete initialization"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JNI_EVERSION :
|
case JNI_EVERSION :
|
||||||
ERROR_MESSAGE(("transport doesn't recognize version %x",
|
ERROR_MESSAGE(("transport doesn't recognize all supported versions: "
|
||||||
JDWPTRANSPORT_VERSION_1_0));
|
"{ 1_1, 1_0 }"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JNI_EEXIST :
|
case JNI_EEXIST :
|
||||||
@ -215,13 +235,19 @@ loadTransport(const char *name, jdwpTransportEnv **transportPtr)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERROR_MESSAGE(("unrecognized error %d from transport", ver));
|
ERROR_MESSAGE(("unrecognized error %d from transport", rc));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return JDWP_ERROR(TRANSPORT_INIT);
|
return JDWP_ERROR(TRANSPORT_INIT);
|
||||||
}
|
}
|
||||||
*transportPtr = t;
|
|
||||||
|
/* Store transport version to global variable to be able to
|
||||||
|
* set correct transport version for subsequent connect,
|
||||||
|
* even if info is already deallocated.
|
||||||
|
*/
|
||||||
|
transportVersion = info->transportVersion;
|
||||||
|
info->transport = t;
|
||||||
} else {
|
} else {
|
||||||
return JDWP_ERROR(TRANSPORT_LOAD);
|
return JDWP_ERROR(TRANSPORT_LOAD);
|
||||||
}
|
}
|
||||||
@ -314,7 +340,6 @@ acceptThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
|
|||||||
|
|
||||||
info = (TransportInfo*)(void*)arg;
|
info = (TransportInfo*)(void*)arg;
|
||||||
t = info->transport;
|
t = info->transport;
|
||||||
|
|
||||||
rc = (*t)->Accept(t, info->timeout, 0);
|
rc = (*t)->Accept(t, info->timeout, 0);
|
||||||
|
|
||||||
/* System property no longer needed */
|
/* System property no longer needed */
|
||||||
@ -339,8 +364,10 @@ acceptThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
|
|||||||
static void JNICALL
|
static void JNICALL
|
||||||
attachThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
|
attachThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
|
||||||
{
|
{
|
||||||
|
TransportInfo *info = (TransportInfo*)(void*)arg;
|
||||||
|
|
||||||
LOG_MISC(("Begin attach thread"));
|
LOG_MISC(("Begin attach thread"));
|
||||||
connectionInitiated((jdwpTransportEnv *)(void*)arg);
|
connectionInitiated(info->transport);
|
||||||
LOG_MISC(("End attach thread"));
|
LOG_MISC(("End attach thread"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,13 +445,26 @@ launch(char *command, char *name, char *address)
|
|||||||
|
|
||||||
jdwpError
|
jdwpError
|
||||||
transport_startTransport(jboolean isServer, char *name, char *address,
|
transport_startTransport(jboolean isServer, char *name, char *address,
|
||||||
long timeout)
|
long timeout, char *allowed_peers)
|
||||||
{
|
{
|
||||||
jvmtiStartFunction func;
|
jvmtiStartFunction func;
|
||||||
jdwpTransportEnv *trans;
|
|
||||||
char threadName[MAXPATHLEN + 100];
|
char threadName[MAXPATHLEN + 100];
|
||||||
jint err;
|
jint err;
|
||||||
jdwpError serror;
|
jdwpError serror;
|
||||||
|
jdwpTransportConfiguration cfg = {0};
|
||||||
|
TransportInfo *info;
|
||||||
|
jdwpTransportEnv *trans;
|
||||||
|
|
||||||
|
info = jvmtiAllocate(sizeof(*info));
|
||||||
|
if (info == NULL) {
|
||||||
|
return JDWP_ERROR(OUT_OF_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
info->transport = transport;
|
||||||
|
info->transportVersion = transportVersion;
|
||||||
|
info->name = NULL;
|
||||||
|
info->address = NULL;
|
||||||
|
info->allowed_peers = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the transport is already loaded then use it
|
* If the transport is already loaded then use it
|
||||||
@ -434,28 +474,24 @@ transport_startTransport(jboolean isServer, char *name, char *address,
|
|||||||
* That probably means we have a bag a transport environments
|
* That probably means we have a bag a transport environments
|
||||||
* to correspond to the transports bag.
|
* to correspond to the transports bag.
|
||||||
*/
|
*/
|
||||||
if (transport != NULL) {
|
if (info->transport == NULL) {
|
||||||
trans = transport;
|
serror = loadTransport(name, info);
|
||||||
} else {
|
|
||||||
serror = loadTransport(name, &trans);
|
|
||||||
if (serror != JDWP_ERROR(NONE)) {
|
if (serror != JDWP_ERROR(NONE)) {
|
||||||
|
jvmtiDeallocate(info);
|
||||||
return serror;
|
return serror;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isServer) {
|
// Cache the value
|
||||||
|
trans = info->transport;
|
||||||
|
|
||||||
|
if (isServer) {
|
||||||
char *retAddress;
|
char *retAddress;
|
||||||
char *launchCommand;
|
char *launchCommand;
|
||||||
TransportInfo *info;
|
|
||||||
jvmtiError error;
|
jvmtiError error;
|
||||||
int len;
|
int len;
|
||||||
char* prop_value;
|
char* prop_value;
|
||||||
|
|
||||||
info = jvmtiAllocate(sizeof(*info));
|
|
||||||
if (info == NULL) {
|
|
||||||
return JDWP_ERROR(OUT_OF_MEMORY);
|
|
||||||
}
|
|
||||||
info->timeout = timeout;
|
info->timeout = timeout;
|
||||||
|
|
||||||
info->name = jvmtiAllocate((int)strlen(name)+1);
|
info->name = jvmtiAllocate((int)strlen(name)+1);
|
||||||
@ -465,7 +501,6 @@ transport_startTransport(jboolean isServer, char *name, char *address,
|
|||||||
}
|
}
|
||||||
(void)strcpy(info->name, name);
|
(void)strcpy(info->name, name);
|
||||||
|
|
||||||
info->address = NULL;
|
|
||||||
if (address != NULL) {
|
if (address != NULL) {
|
||||||
info->address = jvmtiAllocate((int)strlen(address)+1);
|
info->address = jvmtiAllocate((int)strlen(address)+1);
|
||||||
if (info->address == NULL) {
|
if (info->address == NULL) {
|
||||||
@ -475,7 +510,32 @@ transport_startTransport(jboolean isServer, char *name, char *address,
|
|||||||
(void)strcpy(info->address, address);
|
(void)strcpy(info->address, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
info->transport = trans;
|
if (info->transportVersion == JDWPTRANSPORT_VERSION_1_0) {
|
||||||
|
if (allowed_peers != NULL) {
|
||||||
|
ERROR_MESSAGE(("Allow parameter is specified but transport doesn't support it"));
|
||||||
|
serror = JDWP_ERROR(TRANSPORT_INIT);
|
||||||
|
goto handleError;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Memory is allocated only for transport versions > 1.0
|
||||||
|
* as the version 1.0 does not support the 'allow' option.
|
||||||
|
*/
|
||||||
|
if (allowed_peers != NULL) {
|
||||||
|
info->allowed_peers = jvmtiAllocate((int)strlen(allowed_peers) + 1);
|
||||||
|
if (info->allowed_peers == NULL) {
|
||||||
|
serror = JDWP_ERROR(OUT_OF_MEMORY);
|
||||||
|
goto handleError;
|
||||||
|
}
|
||||||
|
(void)strcpy(info->allowed_peers, allowed_peers);
|
||||||
|
}
|
||||||
|
cfg.allowed_peers = info->allowed_peers;
|
||||||
|
err = (*trans)->SetTransportConfiguration(trans, &cfg);
|
||||||
|
if (err != JDWPTRANSPORT_ERROR_NONE) {
|
||||||
|
printLastError(trans, err);
|
||||||
|
serror = JDWP_ERROR(TRANSPORT_INIT);
|
||||||
|
goto handleError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = (*trans)->StartListening(trans, address, &retAddress);
|
err = (*trans)->StartListening(trans, address, &retAddress);
|
||||||
if (err != JDWPTRANSPORT_ERROR_NONE) {
|
if (err != JDWPTRANSPORT_ERROR_NONE) {
|
||||||
@ -527,6 +587,7 @@ transport_startTransport(jboolean isServer, char *name, char *address,
|
|||||||
handleError:
|
handleError:
|
||||||
jvmtiDeallocate(info->name);
|
jvmtiDeallocate(info->name);
|
||||||
jvmtiDeallocate(info->address);
|
jvmtiDeallocate(info->address);
|
||||||
|
jvmtiDeallocate(info->allowed_peers);
|
||||||
jvmtiDeallocate(info);
|
jvmtiDeallocate(info);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@ -543,6 +604,10 @@ handleError:
|
|||||||
if (err != JDWPTRANSPORT_ERROR_NONE) {
|
if (err != JDWPTRANSPORT_ERROR_NONE) {
|
||||||
printLastError(trans, err);
|
printLastError(trans, err);
|
||||||
serror = JDWP_ERROR(TRANSPORT_INIT);
|
serror = JDWP_ERROR(TRANSPORT_INIT);
|
||||||
|
/* The name, address and allowed_peers fields in 'info'
|
||||||
|
* are not allocated in the non-server case so
|
||||||
|
* they do not need to be freed. */
|
||||||
|
jvmtiDeallocate(info);
|
||||||
return serror;
|
return serror;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,7 +618,7 @@ handleError:
|
|||||||
(void)strcat(threadName, name);
|
(void)strcat(threadName, name);
|
||||||
|
|
||||||
func = &attachThread;
|
func = &attachThread;
|
||||||
err = spawnNewThread(func, (void*)trans, threadName);
|
err = spawnNewThread(func, (void*)info, threadName);
|
||||||
serror = map2jdwpError(err);
|
serror = map2jdwpError(err);
|
||||||
}
|
}
|
||||||
return serror;
|
return serror;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,7 +30,8 @@
|
|||||||
|
|
||||||
void transport_initialize(void);
|
void transport_initialize(void);
|
||||||
void transport_reset(void);
|
void transport_reset(void);
|
||||||
jdwpError transport_startTransport(jboolean isServer, char *name, char *address, long timeout);
|
jdwpError transport_startTransport(jboolean isServer, char *name, char *address,
|
||||||
|
long timeout, char *allowed_peers);
|
||||||
|
|
||||||
jint transport_receivePacket(jdwpPacket *);
|
jint transport_receivePacket(jdwpPacket *);
|
||||||
jint transport_sendPacket(jdwpPacket *);
|
jint transport_sendPacket(jdwpPacket *);
|
||||||
|
200
jdk/test/com/sun/jdi/BasicJDWPConnectionTest.java
Normal file
200
jdk/test/com/sun/jdi/BasicJDWPConnectionTest.java
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code 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
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @summary Smoke test for JDWP hardening
|
||||||
|
* @library /lib/testlibrary
|
||||||
|
* @library /test/lib
|
||||||
|
* @run driver BasicJDWPConnectionTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
|
||||||
|
import jdk.test.lib.apps.LingeredApp;
|
||||||
|
import jdk.testlibrary.Utils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public class BasicJDWPConnectionTest {
|
||||||
|
|
||||||
|
public static int handshake(int port) throws IOException {
|
||||||
|
// Connect to the debuggee and handshake
|
||||||
|
int res = -1;
|
||||||
|
Socket s = null;
|
||||||
|
try {
|
||||||
|
s = new Socket("localhost", port);
|
||||||
|
s.getOutputStream().write("JDWP-Handshake".getBytes("UTF-8"));
|
||||||
|
byte[] buffer = new byte[24];
|
||||||
|
res = s.getInputStream().read(buffer);
|
||||||
|
}
|
||||||
|
catch (SocketException ex) {
|
||||||
|
// pass
|
||||||
|
} finally {
|
||||||
|
if (s != null) {
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayList<String> prepareCmd(int port, String allowOpt) {
|
||||||
|
String address = "*:" + String.valueOf(port);
|
||||||
|
ArrayList<String> cmd = new ArrayList<>();
|
||||||
|
|
||||||
|
String jdwpArgs = "-agentlib:jdwp=transport=dt_socket,server=y," +
|
||||||
|
"suspend=n,address=" + address + allowOpt;
|
||||||
|
cmd.add(jdwpArgs);
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void positiveTest(String testName, String allowOpt)
|
||||||
|
throws InterruptedException, IOException {
|
||||||
|
System.err.println("\nStarting " + testName);
|
||||||
|
int port = Utils.getFreePort();
|
||||||
|
ArrayList<String> cmd = prepareCmd(port, allowOpt);
|
||||||
|
|
||||||
|
LingeredApp a = LingeredApp.startApp(cmd);
|
||||||
|
int res = handshake(port);
|
||||||
|
a.stopApp();
|
||||||
|
if (res < 0) {
|
||||||
|
throw new RuntimeException(testName + " FAILED");
|
||||||
|
}
|
||||||
|
System.err.println(testName + " PASSED");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void negativeTest(String testName, String allowOpt)
|
||||||
|
throws InterruptedException, IOException {
|
||||||
|
System.err.println("\nStarting " + testName);
|
||||||
|
int port = Utils.getFreePort();
|
||||||
|
ArrayList<String> cmd = prepareCmd(port, allowOpt);
|
||||||
|
|
||||||
|
LingeredApp a = LingeredApp.startApp(cmd);
|
||||||
|
int res = handshake(port);
|
||||||
|
a.stopApp();
|
||||||
|
if (res > 0) {
|
||||||
|
System.err.println(testName + ": res=" + res);
|
||||||
|
throw new RuntimeException(testName + " FAILED");
|
||||||
|
}
|
||||||
|
System.err.println(testName + ": returned a negative code as expected: " + res);
|
||||||
|
System.err.println(testName + " PASSED");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void badAllowOptionTest(String testName, String allowOpt)
|
||||||
|
throws InterruptedException, IOException {
|
||||||
|
System.err.println("\nStarting " + testName);
|
||||||
|
int port = Utils.getFreePort();
|
||||||
|
ArrayList<String> cmd = prepareCmd(port, allowOpt);
|
||||||
|
|
||||||
|
try {
|
||||||
|
LingeredApp a = LingeredApp.startApp(cmd);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
System.err.println(testName + ": caught expected IOException");
|
||||||
|
System.err.println(testName + " PASSED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new RuntimeException(testName + " FAILED");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DefaultTest() throws InterruptedException, IOException {
|
||||||
|
// No allow option is the same as the allow option ',allow=*' is passed
|
||||||
|
String allowOpt = "";
|
||||||
|
positiveTest("DefaultTest", allowOpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ExplicitDefaultTest() throws InterruptedException, IOException {
|
||||||
|
// Explicit permission for connections from everywhere
|
||||||
|
String allowOpt = ",allow=*";
|
||||||
|
positiveTest("ExplicitDefaultTest" ,allowOpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AllowTest() throws InterruptedException, IOException {
|
||||||
|
String allowOpt = ",allow=127.0.0.1";
|
||||||
|
positiveTest("AllowTest", allowOpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MultiAllowTest() throws InterruptedException, IOException {
|
||||||
|
String allowOpt = ",allow=127.0.0.1+10.0.0.0/8+172.16.0.0/12+192.168.0.0/24";
|
||||||
|
positiveTest("MultiAllowTest", allowOpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DenyTest() throws InterruptedException, IOException {
|
||||||
|
// Bad allow address
|
||||||
|
String allowOpt = ",allow=0.0.0.0";
|
||||||
|
negativeTest("DenyTest", allowOpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MultiDenyTest() throws InterruptedException, IOException {
|
||||||
|
// Wrong separator ';' is used for allow option
|
||||||
|
String allowOpt = ",allow=127.0.0.1;192.168.0.0/24";
|
||||||
|
badAllowOptionTest("MultiDenyTest", allowOpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EmptyAllowOptionTest() throws InterruptedException, IOException {
|
||||||
|
// Empty allow option
|
||||||
|
String allowOpt = ",allow=";
|
||||||
|
badAllowOptionTest("EmptyAllowOptionTest", allowOpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ExplicitMultiDefault1Test() throws InterruptedException, IOException {
|
||||||
|
// Bad mix of allow option '*' with address value
|
||||||
|
String allowOpt = ",allow=*+allow=127.0.0.1";
|
||||||
|
badAllowOptionTest("ExplicitMultiDefault1Test", allowOpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ExplicitMultiDefault2Test() throws InterruptedException, IOException {
|
||||||
|
// Bad mix of allow address value with '*'
|
||||||
|
String allowOpt = ",allow=allow=127.0.0.1+*";
|
||||||
|
badAllowOptionTest("ExplicitMultiDefault2Test", allowOpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
DefaultTest();
|
||||||
|
ExplicitDefaultTest();
|
||||||
|
AllowTest();
|
||||||
|
MultiAllowTest();
|
||||||
|
DenyTest();
|
||||||
|
MultiDenyTest();
|
||||||
|
EmptyAllowOptionTest();
|
||||||
|
ExplicitMultiDefault1Test();
|
||||||
|
ExplicitMultiDefault2Test();
|
||||||
|
System.err.println("\nTest PASSED");
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
System.err.println("\nTest ERROR, getFreePort");
|
||||||
|
ex.printStackTrace();
|
||||||
|
System.exit(3);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
System.err.println("\nTest ERROR");
|
||||||
|
ex.printStackTrace();
|
||||||
|
System.exit(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user