Skip to content

Commit dc71e8c

Browse files
author
Alex Menkov
committed
8342995: Enhance Attach API to support arbitrary length arguments - Linux
Reviewed-by: sspitsyn, kevinw
1 parent 4f44cf6 commit dc71e8c

File tree

5 files changed

+133
-228
lines changed

5 files changed

+133
-228
lines changed

src/hotspot/os/posix/attachListener_posix.cpp

+51-176
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,7 @@ class PosixAttachListener: AllStatic {
7676

7777
static bool _atexit_registered;
7878

79-
// reads a request from the given connected socket
80-
static PosixAttachOperation* read_request(int s);
81-
8279
public:
83-
enum {
84-
ATTACH_PROTOCOL_VER = 1 // protocol version
85-
};
86-
enum {
87-
ATTACH_ERROR_BADVERSION = 101 // error codes
88-
};
89-
9080
static void set_path(char* path) {
9181
if (path == nullptr) {
9282
_path[0] = '\0';
@@ -107,25 +97,61 @@ class PosixAttachListener: AllStatic {
10797
static bool has_path() { return _has_path; }
10898
static int listener() { return _listener; }
10999

110-
// write the given buffer to a socket
111-
static int write_fully(int s, char* buf, size_t len);
112-
113100
static PosixAttachOperation* dequeue();
114101
};
115102

103+
class SocketChannel : public AttachOperation::RequestReader, public AttachOperation::ReplyWriter {
104+
private:
105+
int _socket;
106+
public:
107+
SocketChannel(int socket) : _socket(socket) {}
108+
~SocketChannel() {
109+
close();
110+
}
111+
112+
bool opened() const {
113+
return _socket != -1;
114+
}
115+
116+
void close() {
117+
if (opened()) {
118+
::close(_socket);
119+
_socket = -1;
120+
}
121+
}
122+
123+
// RequestReader
124+
int read(void* buffer, int size) override {
125+
ssize_t n;
126+
RESTARTABLE(::read(_socket, buffer, (size_t)size), n);
127+
return checked_cast<int>(n);
128+
}
129+
130+
// ReplyWriter
131+
int write(const void* buffer, int size) override {
132+
ssize_t n;
133+
RESTARTABLE(::write(_socket, buffer, size), n);
134+
return checked_cast<int>(n);
135+
}
136+
// called after writing all data
137+
void flush() override {
138+
::shutdown(_socket, SHUT_RDWR);
139+
}
140+
};
141+
116142
class PosixAttachOperation: public AttachOperation {
117143
private:
118144
// the connection to the client
119-
int _socket;
145+
SocketChannel _socket_channel;
120146

121147
public:
122-
void complete(jint res, bufferedStream* st);
148+
void complete(jint res, bufferedStream* st) override;
123149

124-
void set_socket(int s) { _socket = s; }
125-
int socket() const { return _socket; }
150+
PosixAttachOperation(int socket) : AttachOperation(), _socket_channel(socket) {
151+
}
126152

127-
PosixAttachOperation(char* name) : AttachOperation(name) {
128-
set_socket(-1);
153+
bool read_request() {
154+
return AttachOperation::read_request(&_socket_channel, &_socket_channel);
129155
}
130156
};
131157

@@ -135,35 +161,6 @@ bool PosixAttachListener::_has_path;
135161
volatile int PosixAttachListener::_listener = -1;
136162
bool PosixAttachListener::_atexit_registered = false;
137163

138-
// Supporting class to help split a buffer into individual components
139-
class ArgumentIterator : public StackObj {
140-
private:
141-
char* _pos;
142-
char* _end;
143-
public:
144-
ArgumentIterator(char* arg_buffer, size_t arg_size) {
145-
_pos = arg_buffer;
146-
_end = _pos + arg_size - 1;
147-
}
148-
char* next() {
149-
if (*_pos == '\0') {
150-
// advance the iterator if possible (null arguments)
151-
if (_pos < _end) {
152-
_pos += 1;
153-
}
154-
return nullptr;
155-
}
156-
char* res = _pos;
157-
char* next_pos = strchr(_pos, '\0');
158-
if (next_pos < _end) {
159-
next_pos++;
160-
}
161-
_pos = next_pos;
162-
return res;
163-
}
164-
};
165-
166-
167164
// atexit hook to stop listener and unlink the file that it is
168165
// bound too.
169166
extern "C" {
@@ -249,103 +246,6 @@ int PosixAttachListener::init() {
249246
return 0;
250247
}
251248

252-
// Given a socket that is connected to a peer we read the request and
253-
// create an AttachOperation. As the socket is blocking there is potential
254-
// for a denial-of-service if the peer does not response. However this happens
255-
// after the peer credentials have been checked and in the worst case it just
256-
// means that the attach listener thread is blocked.
257-
//
258-
PosixAttachOperation* PosixAttachListener::read_request(int s) {
259-
char ver_str[8];
260-
os::snprintf_checked(ver_str, sizeof(ver_str), "%d", ATTACH_PROTOCOL_VER);
261-
262-
// The request is a sequence of strings so we first figure out the
263-
// expected count and the maximum possible length of the request.
264-
// The request is:
265-
// <ver>0<cmd>0<arg>0<arg>0<arg>0
266-
// where <ver> is the protocol version (1), <cmd> is the command
267-
// name ("load", "datadump", ...), and <arg> is an argument
268-
int expected_str_count = 2 + AttachOperation::arg_count_max;
269-
const size_t max_len = (sizeof(ver_str) + 1) + (AttachOperation::name_length_max + 1) +
270-
AttachOperation::arg_count_max*(AttachOperation::arg_length_max + 1);
271-
272-
char buf[max_len];
273-
int str_count = 0;
274-
275-
// Read until all (expected) strings have been read, the buffer is
276-
// full, or EOF.
277-
278-
size_t off = 0;
279-
size_t left = max_len;
280-
281-
do {
282-
ssize_t n;
283-
RESTARTABLE(read(s, buf+off, left), n);
284-
assert(n <= checked_cast<ssize_t>(left), "buffer was too small, impossible!");
285-
buf[max_len - 1] = '\0';
286-
if (n == -1) {
287-
return nullptr; // reset by peer or other error
288-
}
289-
if (n == 0) {
290-
break;
291-
}
292-
for (ssize_t i=0; i<n; i++) {
293-
if (buf[off+i] == 0) {
294-
// EOS found
295-
str_count++;
296-
297-
// The first string is <ver> so check it now to
298-
// check for protocol mismatch
299-
if (str_count == 1) {
300-
if ((strlen(buf) != strlen(ver_str)) ||
301-
(atoi(buf) != ATTACH_PROTOCOL_VER)) {
302-
char msg[32];
303-
os::snprintf_checked(msg, sizeof(msg), "%d\n", ATTACH_ERROR_BADVERSION);
304-
write_fully(s, msg, strlen(msg));
305-
return nullptr;
306-
}
307-
}
308-
}
309-
}
310-
off += n;
311-
left -= n;
312-
} while (left > 0 && str_count < expected_str_count);
313-
314-
if (str_count != expected_str_count) {
315-
return nullptr; // incomplete request
316-
}
317-
318-
// parse request
319-
320-
ArgumentIterator args(buf, (max_len)-left);
321-
322-
// version already checked
323-
char* v = args.next();
324-
325-
char* name = args.next();
326-
if (name == nullptr || strlen(name) > AttachOperation::name_length_max) {
327-
return nullptr;
328-
}
329-
330-
PosixAttachOperation* op = new PosixAttachOperation(name);
331-
332-
for (int i=0; i<AttachOperation::arg_count_max; i++) {
333-
char* arg = args.next();
334-
if (arg == nullptr) {
335-
op->set_arg(i, nullptr);
336-
} else {
337-
if (strlen(arg) > AttachOperation::arg_length_max) {
338-
delete op;
339-
return nullptr;
340-
}
341-
op->set_arg(i, arg);
342-
}
343-
}
344-
345-
op->set_socket(s);
346-
return op;
347-
}
348-
349249
// Dequeue an operation
350250
//
351251
// In the Linux and BSD implementations, there is only a single operation and
@@ -400,31 +300,16 @@ PosixAttachOperation* PosixAttachListener::dequeue() {
400300
#endif
401301

402302
// peer credential look okay so we read the request
403-
PosixAttachOperation* op = read_request(s);
404-
if (op == nullptr) {
405-
::close(s);
303+
PosixAttachOperation* op = new PosixAttachOperation(s);
304+
if (!op->read_request()) {
305+
delete op;
406306
continue;
407307
} else {
408308
return op;
409309
}
410310
}
411311
}
412312

413-
// write the given buffer to the socket
414-
int PosixAttachListener::write_fully(int s, char* buf, size_t len) {
415-
do {
416-
ssize_t n = ::write(s, buf, len);
417-
if (n == -1) {
418-
if (errno != EINTR) return -1;
419-
} else {
420-
buf += n;
421-
len -= n;
422-
}
423-
}
424-
while (len > 0);
425-
return 0;
426-
}
427-
428313
// Complete an operation by sending the operation result and any result
429314
// output to the client. At this time the socket is in blocking mode so
430315
// potentially we can block if there is a lot of data and the client is
@@ -437,19 +322,7 @@ void PosixAttachOperation::complete(jint result, bufferedStream* st) {
437322
JavaThread* thread = JavaThread::current();
438323
ThreadBlockInVM tbivm(thread);
439324

440-
// write operation result
441-
char msg[32];
442-
os::snprintf_checked(msg, sizeof(msg), "%d\n", result);
443-
int rc = PosixAttachListener::write_fully(this->socket(), msg, strlen(msg));
444-
445-
// write any result data
446-
if (rc == 0) {
447-
PosixAttachListener::write_fully(this->socket(), (char*) st->base(), st->size());
448-
::shutdown(this->socket(), 2);
449-
}
450-
451-
// done
452-
::close(this->socket());
325+
write_reply(&_socket_channel, result, st);
453326

454327
delete this;
455328
}
@@ -490,6 +363,8 @@ void AttachListener::vm_start() {
490363
}
491364

492365
int AttachListener::pd_init() {
366+
AttachListener::set_supported_version(ATTACH_API_V2);
367+
493368
JavaThread* thread = JavaThread::current();
494369
ThreadBlockInVM tbivm(thread);
495370

src/hotspot/os/windows/attachListener_windows.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ class Win32AttachOperation: public AttachOperation {
152152
}
153153

154154
bool read_request() {
155-
return AttachOperation::read_request(&_pipe);
155+
return AttachOperation::read_request(&_pipe, &_pipe);
156156
}
157157

158158
public:

0 commit comments

Comments
 (0)