@@ -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+
116142class 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;
135161volatile int PosixAttachListener::_listener = -1 ;
136162bool 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.
169166extern " 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
492365int AttachListener::pd_init () {
366+ AttachListener::set_supported_version (ATTACH_API_V2);
367+
493368 JavaThread* thread = JavaThread::current ();
494369 ThreadBlockInVM tbivm (thread);
495370
0 commit comments