1 /* Copyright (C) 2017 The Android Open Source Project
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This file implements interfaces from the file jdwpTransport.h. This
5 * implementation is licensed under the same terms as the file
6 * jdwpTransport.h. The copyright and license information for the file
7 * jdwpTransport.h follows.
8 *
9 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
10 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
11 *
12 * This code is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 only, as
14 * published by the Free Software Foundation. Oracle designates this
15 * particular file as subject to the "Classpath" exception as provided
16 * by Oracle in the LICENSE file that accompanied this code.
17 *
18 * This code is distributed in the hope that it will be useful, but WITHOUT
19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * version 2 for more details (a copy is included in the LICENSE file that
22 * accompanied this code).
23 *
24 * You should have received a copy of the GNU General Public License version
25 * 2 along with this work; if not, write to the Free Software Foundation,
26 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 *
28 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
29 * or visit www.oracle.com if you need additional information or have any
30 * questions.
31 */
32
33 #include "dt_fd_forward.h"
34
35 #include <string>
36 #include <vector>
37
38 #include <android-base/endian.h>
39 #include <android-base/logging.h>
40 #include <android-base/parseint.h>
41 #include <android-base/stringprintf.h>
42
43 #include <sys/ioctl.h>
44 #include <sys/eventfd.h>
45 #include <sys/socket.h>
46 #include <sys/types.h>
47 #include <unistd.h>
48 #include <poll.h>
49
50 #include <jni.h>
51 #include <jdwpTransport.h>
52
53 #include <base/strlcpy.h>
54
55 namespace dt_fd_forward {
56
57 // Helper that puts line-number in error message.
58 #define DT_IO_ERROR(f) \
59 SetLastError(::android::base::StringPrintf("%s:%d - %s: %s", \
60 __FILE__, __LINE__, f, strerror(errno)))
61
62 extern const jdwpTransportNativeInterface_ gTransportInterface;
63
64 template <typename T> static T HostToNetwork(T in);
65 template <typename T> static T NetworkToHost(T in);
66
HostToNetwork(int8_t in)67 template<> int8_t HostToNetwork(int8_t in) { return in; }
NetworkToHost(int8_t in)68 template<> int8_t NetworkToHost(int8_t in) { return in; }
HostToNetwork(int16_t in)69 template<> int16_t HostToNetwork(int16_t in) { return htons(in); }
NetworkToHost(int16_t in)70 template<> int16_t NetworkToHost(int16_t in) { return ntohs(in); }
HostToNetwork(int32_t in)71 template<> int32_t HostToNetwork(int32_t in) { return htonl(in); }
NetworkToHost(int32_t in)72 template<> int32_t NetworkToHost(int32_t in) { return ntohl(in); }
73
FdForwardTransport(jdwpTransportCallback * cb)74 FdForwardTransport::FdForwardTransport(jdwpTransportCallback* cb)
75 : mem_(*cb),
76 read_fd_(-1),
77 write_fd_(-1),
78 wakeup_fd_(eventfd(0, EFD_NONBLOCK)),
79 listen_fd_(-1),
80 close_notify_fd_(-1),
81 state_(TransportState::kClosed),
82 current_seq_num_(0) {}
83
~FdForwardTransport()84 FdForwardTransport::~FdForwardTransport() { }
85
ChangeState(TransportState old_state,TransportState new_state)86 bool FdForwardTransport::ChangeState(TransportState old_state, TransportState new_state) {
87 if (old_state == state_) {
88 state_ = new_state;
89 state_cv_.notify_all();
90 return true;
91 } else {
92 return false;
93 }
94 }
95
PerformAttach(int listen_fd)96 jdwpTransportError FdForwardTransport::PerformAttach(int listen_fd) {
97 jdwpTransportError err = SetupListen(listen_fd);
98 if (err != OK) {
99 return OK;
100 }
101 err = Accept();
102 StopListening();
103 return err;
104 }
105
SendListenMessage(const android::base::unique_fd & fd)106 static void SendListenMessage(const android::base::unique_fd& fd) {
107 TEMP_FAILURE_RETRY(send(fd, kListenStartMessage, sizeof(kListenStartMessage), MSG_EOR));
108 }
109
110 // Copy from file_utils, so we do not need to depend on libartbase.
DupCloexec(int fd)111 static int DupCloexec(int fd) {
112 #if defined(__linux__)
113 return fcntl(fd, F_DUPFD_CLOEXEC, 0);
114 #else
115 return dup(fd);
116 #endif
117 }
118
SetupListen(int listen_fd)119 jdwpTransportError FdForwardTransport::SetupListen(int listen_fd) {
120 std::lock_guard<std::mutex> lk(state_mutex_);
121 if (!ChangeState(TransportState::kClosed, TransportState::kListenSetup)) {
122 return ERR(ILLEGAL_STATE);
123 } else {
124 listen_fd_.reset(DupCloexec(listen_fd));
125 SendListenMessage(listen_fd_);
126 CHECK(ChangeState(TransportState::kListenSetup, TransportState::kListening));
127 return OK;
128 }
129 }
130
SendListenEndMessage(const android::base::unique_fd & fd)131 static void SendListenEndMessage(const android::base::unique_fd& fd) {
132 TEMP_FAILURE_RETRY(send(fd, kListenEndMessage, sizeof(kListenEndMessage), MSG_EOR));
133 }
134
StopListening()135 jdwpTransportError FdForwardTransport::StopListening() {
136 std::lock_guard<std::mutex> lk(state_mutex_);
137 if (listen_fd_ != -1) {
138 SendListenEndMessage(listen_fd_);
139 }
140 // Don't close the listen_fd_ since we might need it for later calls to listen.
141 if (ChangeState(TransportState::kListening, TransportState::kClosed) ||
142 state_ == TransportState::kOpen) {
143 listen_fd_.reset();
144 }
145 return OK;
146 }
147
148 // Last error message.
149 thread_local std::string global_last_error_;
150
SetLastError(const std::string & desc)151 void FdForwardTransport::SetLastError(const std::string& desc) {
152 LOG(ERROR) << desc;
153 global_last_error_ = desc;
154 }
155
ReadFullyWithoutChecks(void * data,size_t ndata)156 IOResult FdForwardTransport::ReadFullyWithoutChecks(void* data, size_t ndata) {
157 uint8_t* bdata = reinterpret_cast<uint8_t*>(data);
158 size_t nbytes = 0;
159 while (nbytes < ndata) {
160 int res = TEMP_FAILURE_RETRY(read(read_fd_, bdata + nbytes, ndata - nbytes));
161 if (res < 0) {
162 DT_IO_ERROR("Failed read()");
163 return IOResult::kError;
164 } else if (res == 0) {
165 return IOResult::kEOF;
166 } else {
167 nbytes += res;
168 }
169 }
170 return IOResult::kOk;
171 }
172
ReadUpToMax(void * data,size_t ndata,size_t * read_amount)173 IOResult FdForwardTransport::ReadUpToMax(void* data, size_t ndata, /*out*/size_t* read_amount) {
174 CHECK_GE(read_fd_.get(), 0);
175 int avail;
176 int res = TEMP_FAILURE_RETRY(ioctl(read_fd_, FIONREAD, &avail));
177 if (res < 0) {
178 DT_IO_ERROR("Failed ioctl(read_fd_, FIONREAD, &avail)");
179 return IOResult::kError;
180 }
181 size_t to_read = std::min(static_cast<size_t>(avail), ndata);
182 *read_amount = to_read;
183 if (*read_amount == 0) {
184 // Check if the read would cause an EOF.
185 struct pollfd pollfd = { read_fd_, POLLRDHUP, 0 };
186 res = TEMP_FAILURE_RETRY(poll(&pollfd, /*nfds*/1, /*timeout*/0));
187 if (res < 0 || (pollfd.revents & POLLERR) == POLLERR) {
188 DT_IO_ERROR("Failed poll on read fd.");
189 return IOResult::kError;
190 }
191 return ((pollfd.revents & (POLLRDHUP | POLLHUP)) == 0) ? IOResult::kOk : IOResult::kEOF;
192 }
193
194 return ReadFullyWithoutChecks(data, to_read);
195 }
196
ReadFully(void * data,size_t ndata)197 IOResult FdForwardTransport::ReadFully(void* data, size_t ndata) {
198 uint64_t seq_num = current_seq_num_;
199 size_t nbytes = 0;
200 while (nbytes < ndata) {
201 size_t read_len;
202 struct pollfd pollfds[2];
203 {
204 std::lock_guard<std::mutex> lk(state_mutex_);
205 // Operations in this block must not cause an unbounded pause.
206 if (state_ != TransportState::kOpen || seq_num != current_seq_num_) {
207 // Async-close occurred!
208 return IOResult::kInterrupt;
209 } else {
210 CHECK_GE(read_fd_.get(), 0);
211 }
212 IOResult res = ReadUpToMax(reinterpret_cast<uint8_t*>(data) + nbytes,
213 ndata - nbytes,
214 /*out*/&read_len);
215 if (res != IOResult::kOk) {
216 return res;
217 } else {
218 nbytes += read_len;
219 }
220
221 pollfds[0] = { read_fd_, POLLRDHUP | POLLIN, 0 };
222 pollfds[1] = { wakeup_fd_, POLLIN, 0 };
223 }
224 if (read_len == 0) {
225 // No more data. Sleep without locks until more is available. We don't actually check for any
226 // errors since possible ones are (1) the read_fd_ is closed or wakeup happens which are both
227 // fine since the wakeup_fd_ or the poll failing will wake us up.
228 int poll_res = TEMP_FAILURE_RETRY(poll(pollfds, 2, -1));
229 if (poll_res < 0) {
230 DT_IO_ERROR("Failed to poll!");
231 }
232 // Clear the wakeup_fd regardless.
233 uint64_t val;
234 int unused = TEMP_FAILURE_RETRY(read(wakeup_fd_, &val, sizeof(val)));
235 DCHECK(unused == sizeof(val) || errno == EAGAIN);
236 if (poll_res < 0) {
237 return IOResult::kError;
238 }
239 }
240 }
241 return IOResult::kOk;
242 }
243
244 // A helper that allows us to lock the eventfd 'fd'.
245 class ScopedEventFdLock {
246 public:
ScopedEventFdLock(const android::base::unique_fd & fd)247 explicit ScopedEventFdLock(const android::base::unique_fd& fd) : fd_(fd), data_(0) {
248 TEMP_FAILURE_RETRY(read(fd_, &data_, sizeof(data_)));
249 }
250
~ScopedEventFdLock()251 ~ScopedEventFdLock() {
252 TEMP_FAILURE_RETRY(write(fd_, &data_, sizeof(data_)));
253 }
254
255 private:
256 const android::base::unique_fd& fd_;
257 uint64_t data_;
258 };
259
WriteFullyWithoutChecks(const void * data,size_t ndata)260 IOResult FdForwardTransport::WriteFullyWithoutChecks(const void* data, size_t ndata) {
261 ScopedEventFdLock sefdl(write_lock_fd_);
262 const uint8_t* bdata = static_cast<const uint8_t*>(data);
263 size_t nbytes = 0;
264 while (nbytes < ndata) {
265 int res = TEMP_FAILURE_RETRY(write(write_fd_, bdata + nbytes, ndata - nbytes));
266 if (res < 0) {
267 DT_IO_ERROR("Failed write()");
268 return IOResult::kError;
269 } else if (res == 0) {
270 return IOResult::kEOF;
271 } else {
272 nbytes += res;
273 }
274 }
275 return IOResult::kOk;
276 }
277
WriteFully(const void * data,size_t ndata)278 IOResult FdForwardTransport::WriteFully(const void* data, size_t ndata) {
279 std::lock_guard<std::mutex> lk(state_mutex_);
280 if (state_ != TransportState::kOpen) {
281 return IOResult::kInterrupt;
282 }
283 return WriteFullyWithoutChecks(data, ndata);
284 }
285
SendAcceptMessage(int fd)286 static void SendAcceptMessage(int fd) {
287 TEMP_FAILURE_RETRY(send(fd, kAcceptMessage, sizeof(kAcceptMessage), MSG_EOR));
288 }
289
ReceiveFdsFromSocket(bool * do_handshake)290 IOResult FdForwardTransport::ReceiveFdsFromSocket(bool* do_handshake) {
291 union {
292 cmsghdr cm;
293 uint8_t buffer[CMSG_SPACE(sizeof(FdSet))];
294 } msg_union;
295 // This lets us know if we need to do a handshake or not.
296 char message[128];
297 iovec iov;
298 iov.iov_base = message;
299 iov.iov_len = sizeof(message);
300
301 msghdr msg;
302 memset(&msg, 0, sizeof(msg));
303 msg.msg_iov = &iov;
304 msg.msg_iovlen = 1;
305 msg.msg_control = msg_union.buffer;
306 msg.msg_controllen = sizeof(msg_union.buffer);
307
308 cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
309 cmsg->cmsg_len = msg.msg_controllen;
310 cmsg->cmsg_level = SOL_SOCKET;
311 cmsg->cmsg_type = SCM_RIGHTS;
312 memset(reinterpret_cast<int*>(CMSG_DATA(cmsg)), -1, FdSet::kDataLength);
313
314 int res = TEMP_FAILURE_RETRY(recvmsg(listen_fd_, &msg, 0));
315 if (res <= 0) {
316 DT_IO_ERROR("Failed to receive fds!");
317 return IOResult::kError;
318 }
319 FdSet out_fds = FdSet::ReadData(CMSG_DATA(cmsg));
320 bool failed = false;
321 if (out_fds.read_fd_ < 0 ||
322 out_fds.write_fd_ < 0 ||
323 out_fds.write_lock_fd_ < 0) {
324 DT_IO_ERROR("Received fds were invalid!");
325 failed = true;
326 } else if (strcmp(kPerformHandshakeMessage, message) == 0) {
327 *do_handshake = true;
328 } else if (strcmp(kSkipHandshakeMessage, message) == 0) {
329 *do_handshake = false;
330 } else {
331 DT_IO_ERROR("Unknown message sent with fds.");
332 failed = true;
333 }
334
335 if (failed) {
336 if (out_fds.read_fd_ >= 0) {
337 close(out_fds.read_fd_);
338 }
339 if (out_fds.write_fd_ >= 0) {
340 close(out_fds.write_fd_);
341 }
342 if (out_fds.write_lock_fd_ >= 0) {
343 close(out_fds.write_lock_fd_);
344 }
345 return IOResult::kError;
346 }
347
348 read_fd_.reset(out_fds.read_fd_);
349 write_fd_.reset(out_fds.write_fd_);
350 write_lock_fd_.reset(out_fds.write_lock_fd_);
351
352 // We got the fds. Send ack.
353 close_notify_fd_.reset(DupCloexec(listen_fd_));
354 SendAcceptMessage(close_notify_fd_);
355
356 return IOResult::kOk;
357 }
358
359 // Accept the connection. Note that we match the behavior of other transports which is to just close
360 // the connection and try again if we get a bad handshake.
Accept()361 jdwpTransportError FdForwardTransport::Accept() {
362 // TODO Work with timeouts.
363 while (true) {
364 std::unique_lock<std::mutex> lk(state_mutex_);
365 while (!ChangeState(TransportState::kListening, TransportState::kOpening)) {
366 if (state_ == TransportState::kClosed ||
367 state_ == TransportState::kOpen) {
368 return ERR(ILLEGAL_STATE);
369 }
370 state_cv_.wait(lk);
371 }
372
373 bool do_handshake = false;
374 DCHECK_NE(listen_fd_.get(), -1);
375 if (ReceiveFdsFromSocket(&do_handshake) != IOResult::kOk) {
376 CHECK(ChangeState(TransportState::kOpening, TransportState::kListening));
377 return ERR(IO_ERROR);
378 }
379
380 current_seq_num_++;
381
382 // Moved to the opening state.
383 if (do_handshake) {
384 // Perform the handshake
385 char handshake_recv[sizeof(kJdwpHandshake)];
386 memset(handshake_recv, 0, sizeof(handshake_recv));
387 IOResult res = ReadFullyWithoutChecks(handshake_recv, sizeof(handshake_recv));
388 if (res != IOResult::kOk ||
389 strncmp(handshake_recv, kJdwpHandshake, sizeof(kJdwpHandshake)) != 0) {
390 DT_IO_ERROR("Failed to read handshake");
391 CHECK(ChangeState(TransportState::kOpening, TransportState::kListening));
392 CloseFdsLocked();
393 // Retry.
394 continue;
395 }
396 res = WriteFullyWithoutChecks(kJdwpHandshake, sizeof(kJdwpHandshake));
397 if (res != IOResult::kOk) {
398 DT_IO_ERROR("Failed to write handshake");
399 CHECK(ChangeState(TransportState::kOpening, TransportState::kListening));
400 CloseFdsLocked();
401 // Retry.
402 continue;
403 }
404 }
405 break;
406 }
407 CHECK(ChangeState(TransportState::kOpening, TransportState::kOpen));
408 return OK;
409 }
410
SendClosingMessage(int fd)411 void SendClosingMessage(int fd) {
412 if (fd >= 0) {
413 TEMP_FAILURE_RETRY(send(fd, kCloseMessage, sizeof(kCloseMessage), MSG_EOR));
414 }
415 }
416
417 // Actually close the fds associated with this transport.
CloseFdsLocked()418 void FdForwardTransport::CloseFdsLocked() {
419 // We have a different set of fd's now. Increase the seq number.
420 current_seq_num_++;
421
422 // All access to these is locked under the state_mutex_ so we are safe to close these.
423 {
424 ScopedEventFdLock sefdl(write_lock_fd_);
425 if (close_notify_fd_ >= 0) {
426 SendClosingMessage(close_notify_fd_);
427 }
428 close_notify_fd_.reset();
429 read_fd_.reset();
430 write_fd_.reset();
431 close_notify_fd_.reset();
432 }
433 write_lock_fd_.reset();
434
435 // Send a wakeup in case we have any in-progress reads/writes.
436 uint64_t data = 1;
437 TEMP_FAILURE_RETRY(write(wakeup_fd_, &data, sizeof(data)));
438 }
439
Close()440 jdwpTransportError FdForwardTransport::Close() {
441 std::lock_guard<std::mutex> lk(state_mutex_);
442 jdwpTransportError res =
443 ChangeState(TransportState::kOpen, TransportState::kClosed) ? OK : ERR(ILLEGAL_STATE);
444 // Send a wakeup after changing the state even if nothing actually happened.
445 uint64_t data = 1;
446 TEMP_FAILURE_RETRY(write(wakeup_fd_, &data, sizeof(data)));
447 if (res == OK) {
448 CloseFdsLocked();
449 }
450 return res;
451 }
452
453 // A helper class to read and parse the JDWP packet.
454 class PacketReader {
455 public:
PacketReader(FdForwardTransport * transport,jdwpPacket * pkt)456 PacketReader(FdForwardTransport* transport, jdwpPacket* pkt)
457 : transport_(transport),
458 pkt_(pkt),
459 is_eof_(false),
460 is_err_(false) {}
ReadFully()461 bool ReadFully() {
462 // Zero out.
463 memset(pkt_, 0, sizeof(jdwpPacket));
464 int32_t len = ReadInt32(); // read len
465 if (is_err_) {
466 return false;
467 } else if (is_eof_) {
468 return true;
469 } else if (len < 11) {
470 transport_->DT_IO_ERROR("Packet with len < 11 received!");
471 return false;
472 }
473 pkt_->type.cmd.len = len;
474 pkt_->type.cmd.id = ReadInt32();
475 pkt_->type.cmd.flags = ReadByte();
476 if (is_err_) {
477 return false;
478 } else if (is_eof_) {
479 return true;
480 } else if ((pkt_->type.reply.flags & JDWPTRANSPORT_FLAGS_REPLY) == JDWPTRANSPORT_FLAGS_REPLY) {
481 ReadReplyPacket();
482 } else {
483 ReadCmdPacket();
484 }
485 return !is_err_;
486 }
487
488 private:
ReadReplyPacket()489 void ReadReplyPacket() {
490 pkt_->type.reply.errorCode = ReadInt16();
491 pkt_->type.reply.data = ReadRemaining();
492 }
493
ReadCmdPacket()494 void ReadCmdPacket() {
495 pkt_->type.cmd.cmdSet = ReadByte();
496 pkt_->type.cmd.cmd = ReadByte();
497 pkt_->type.cmd.data = ReadRemaining();
498 }
499
500 template <typename T>
HandleResult(IOResult res,T val,T fail)501 T HandleResult(IOResult res, T val, T fail) {
502 switch (res) {
503 case IOResult::kError:
504 is_err_ = true;
505 return fail;
506 case IOResult::kOk:
507 return val;
508 case IOResult::kEOF:
509 is_eof_ = true;
510 pkt_->type.cmd.len = 0;
511 return fail;
512 case IOResult::kInterrupt:
513 transport_->DT_IO_ERROR("Failed to read, concurrent close!");
514 is_err_ = true;
515 return fail;
516 }
517 }
518
ReadRemaining()519 jbyte* ReadRemaining() {
520 if (is_eof_ || is_err_) {
521 return nullptr;
522 }
523 jbyte* out = nullptr;
524 jint rem = pkt_->type.cmd.len - 11;
525 CHECK_GE(rem, 0);
526 if (rem == 0) {
527 return nullptr;
528 } else {
529 out = reinterpret_cast<jbyte*>(transport_->Alloc(rem));
530 IOResult res = transport_->ReadFully(out, rem);
531 jbyte* ret = HandleResult(res, out, static_cast<jbyte*>(nullptr));
532 if (ret != out) {
533 transport_->Free(out);
534 }
535 return ret;
536 }
537 }
538
ReadByte()539 jbyte ReadByte() {
540 if (is_eof_ || is_err_) {
541 return -1;
542 }
543 jbyte out;
544 IOResult res = transport_->ReadFully(&out, sizeof(out));
545 return HandleResult(res, NetworkToHost(out), static_cast<jbyte>(-1));
546 }
547
ReadInt16()548 jshort ReadInt16() {
549 if (is_eof_ || is_err_) {
550 return -1;
551 }
552 jshort out;
553 IOResult res = transport_->ReadFully(&out, sizeof(out));
554 return HandleResult(res, NetworkToHost(out), static_cast<jshort>(-1));
555 }
556
ReadInt32()557 jint ReadInt32() {
558 if (is_eof_ || is_err_) {
559 return -1;
560 }
561 jint out;
562 IOResult res = transport_->ReadFully(&out, sizeof(out));
563 return HandleResult(res, NetworkToHost(out), -1);
564 }
565
566 FdForwardTransport* transport_;
567 jdwpPacket* pkt_;
568 bool is_eof_;
569 bool is_err_;
570 };
571
ReadPacket(jdwpPacket * pkt)572 jdwpTransportError FdForwardTransport::ReadPacket(jdwpPacket* pkt) {
573 if (pkt == nullptr) {
574 return ERR(ILLEGAL_ARGUMENT);
575 }
576 PacketReader reader(this, pkt);
577 if (reader.ReadFully()) {
578 return OK;
579 } else {
580 return ERR(IO_ERROR);
581 }
582 }
583
584 // A class that writes a packet to the transport.
585 class PacketWriter {
586 public:
PacketWriter(FdForwardTransport * transport,const jdwpPacket * pkt)587 PacketWriter(FdForwardTransport* transport, const jdwpPacket* pkt)
588 : transport_(transport), pkt_(pkt), data_() {}
589
WriteFully()590 bool WriteFully() {
591 PushInt32(pkt_->type.cmd.len);
592 PushInt32(pkt_->type.cmd.id);
593 PushByte(pkt_->type.cmd.flags);
594 if ((pkt_->type.reply.flags & JDWPTRANSPORT_FLAGS_REPLY) == JDWPTRANSPORT_FLAGS_REPLY) {
595 PushInt16(pkt_->type.reply.errorCode);
596 PushData(pkt_->type.reply.data, pkt_->type.reply.len - 11);
597 } else {
598 PushByte(pkt_->type.cmd.cmdSet);
599 PushByte(pkt_->type.cmd.cmd);
600 PushData(pkt_->type.cmd.data, pkt_->type.cmd.len - 11);
601 }
602 IOResult res = transport_->WriteFully(data_.data(), data_.size());
603 return res == IOResult::kOk;
604 }
605
606 private:
PushInt32(int32_t data)607 void PushInt32(int32_t data) {
608 data = HostToNetwork(data);
609 PushData(&data, sizeof(data));
610 }
PushInt16(int16_t data)611 void PushInt16(int16_t data) {
612 data = HostToNetwork(data);
613 PushData(&data, sizeof(data));
614 }
PushByte(jbyte data)615 void PushByte(jbyte data) {
616 data_.push_back(HostToNetwork(data));
617 }
618
PushData(void * d,size_t size)619 void PushData(void* d, size_t size) {
620 uint8_t* bytes = reinterpret_cast<uint8_t*>(d);
621 data_.insert(data_.end(), bytes, bytes + size);
622 }
623
624 FdForwardTransport* transport_;
625 const jdwpPacket* pkt_;
626 std::vector<uint8_t> data_;
627 };
628
WritePacket(const jdwpPacket * pkt)629 jdwpTransportError FdForwardTransport::WritePacket(const jdwpPacket* pkt) {
630 if (pkt == nullptr) {
631 return ERR(ILLEGAL_ARGUMENT);
632 }
633 PacketWriter writer(this, pkt);
634 if (writer.WriteFully()) {
635 return OK;
636 } else {
637 return ERR(IO_ERROR);
638 }
639 }
640
IsOpen()641 jboolean FdForwardTransport::IsOpen() {
642 return state_ == TransportState::kOpen;
643 }
644
Alloc(size_t s)645 void* FdForwardTransport::Alloc(size_t s) {
646 return mem_.alloc(s);
647 }
648
Free(void * data)649 void FdForwardTransport::Free(void* data) {
650 mem_.free(data);
651 }
652
GetLastError(char ** err)653 jdwpTransportError FdForwardTransport::GetLastError(/*out*/char** err) {
654 std::string data = global_last_error_;
655 *err = reinterpret_cast<char*>(Alloc(data.size() + 1));
656 strlcpy(*err, data.c_str(), data.size() + 1);
657 return OK;
658 }
659
AsFdForward(jdwpTransportEnv * env)660 static FdForwardTransport* AsFdForward(jdwpTransportEnv* env) {
661 return reinterpret_cast<FdForwardTransport*>(env);
662 }
663
ParseAddress(const std::string & addr,int * listen_sock)664 static jdwpTransportError ParseAddress(const std::string& addr,
665 /*out*/int* listen_sock) {
666 if (!android::base::ParseInt(addr.c_str(), listen_sock) || *listen_sock < 0) {
667 LOG(ERROR) << "address format is <fd_num> not " << addr;
668 return ERR(ILLEGAL_ARGUMENT);
669 }
670 return OK;
671 }
672
673 class JdwpTransportFunctions {
674 public:
GetCapabilities(jdwpTransportEnv * env ATTRIBUTE_UNUSED,JDWPTransportCapabilities * capabilities_ptr)675 static jdwpTransportError GetCapabilities(jdwpTransportEnv* env ATTRIBUTE_UNUSED,
676 /*out*/ JDWPTransportCapabilities* capabilities_ptr) {
677 // We don't support any of the optional capabilities (can_timeout_attach, can_timeout_accept,
678 // can_timeout_handshake) so just return a zeroed capabilities ptr.
679 // TODO We should maybe support these timeout options.
680 memset(capabilities_ptr, 0, sizeof(JDWPTransportCapabilities));
681 return OK;
682 }
683
684 // Address is <sock_fd>
Attach(jdwpTransportEnv * env,const char * address,jlong attach_timeout ATTRIBUTE_UNUSED,jlong handshake_timeout ATTRIBUTE_UNUSED)685 static jdwpTransportError Attach(jdwpTransportEnv* env,
686 const char* address,
687 jlong attach_timeout ATTRIBUTE_UNUSED,
688 jlong handshake_timeout ATTRIBUTE_UNUSED) {
689 if (address == nullptr || *address == '\0') {
690 return ERR(ILLEGAL_ARGUMENT);
691 }
692 int listen_fd;
693 jdwpTransportError err = ParseAddress(address, &listen_fd);
694 if (err != OK) {
695 return err;
696 }
697 return AsFdForward(env)->PerformAttach(listen_fd);
698 }
699
StartListening(jdwpTransportEnv * env,const char * address,char ** actual_address)700 static jdwpTransportError StartListening(jdwpTransportEnv* env,
701 const char* address,
702 /*out*/ char** actual_address) {
703 if (address == nullptr || *address == '\0') {
704 return ERR(ILLEGAL_ARGUMENT);
705 }
706 int listen_fd;
707 jdwpTransportError err = ParseAddress(address, &listen_fd);
708 if (err != OK) {
709 return err;
710 }
711 err = AsFdForward(env)->SetupListen(listen_fd);
712 if (err != OK) {
713 return err;
714 }
715 if (actual_address != nullptr) {
716 *actual_address = reinterpret_cast<char*>(AsFdForward(env)->Alloc(strlen(address) + 1));
717 memcpy(*actual_address, address, strlen(address) + 1);
718 }
719 return OK;
720 }
721
StopListening(jdwpTransportEnv * env)722 static jdwpTransportError StopListening(jdwpTransportEnv* env) {
723 return AsFdForward(env)->StopListening();
724 }
725
Accept(jdwpTransportEnv * env,jlong accept_timeout ATTRIBUTE_UNUSED,jlong handshake_timeout ATTRIBUTE_UNUSED)726 static jdwpTransportError Accept(jdwpTransportEnv* env,
727 jlong accept_timeout ATTRIBUTE_UNUSED,
728 jlong handshake_timeout ATTRIBUTE_UNUSED) {
729 return AsFdForward(env)->Accept();
730 }
731
IsOpen(jdwpTransportEnv * env)732 static jboolean IsOpen(jdwpTransportEnv* env) {
733 return AsFdForward(env)->IsOpen();
734 }
735
Close(jdwpTransportEnv * env)736 static jdwpTransportError Close(jdwpTransportEnv* env) {
737 return AsFdForward(env)->Close();
738 }
739
ReadPacket(jdwpTransportEnv * env,jdwpPacket * pkt)740 static jdwpTransportError ReadPacket(jdwpTransportEnv* env, jdwpPacket *pkt) {
741 return AsFdForward(env)->ReadPacket(pkt);
742 }
743
WritePacket(jdwpTransportEnv * env,const jdwpPacket * pkt)744 static jdwpTransportError WritePacket(jdwpTransportEnv* env, const jdwpPacket* pkt) {
745 return AsFdForward(env)->WritePacket(pkt);
746 }
747
GetLastError(jdwpTransportEnv * env,char ** error)748 static jdwpTransportError GetLastError(jdwpTransportEnv* env, char** error) {
749 return AsFdForward(env)->GetLastError(error);
750 }
751 };
752
753 // The actual struct holding all the entrypoints into the jdwpTransport interface.
754 const jdwpTransportNativeInterface_ gTransportInterface = {
755 nullptr, // reserved1
756 JdwpTransportFunctions::GetCapabilities,
757 JdwpTransportFunctions::Attach,
758 JdwpTransportFunctions::StartListening,
759 JdwpTransportFunctions::StopListening,
760 JdwpTransportFunctions::Accept,
761 JdwpTransportFunctions::IsOpen,
762 JdwpTransportFunctions::Close,
763 JdwpTransportFunctions::ReadPacket,
764 JdwpTransportFunctions::WritePacket,
765 JdwpTransportFunctions::GetLastError,
766 };
767
768 extern "C"
jdwpTransport_OnLoad(JavaVM * vm ATTRIBUTE_UNUSED,jdwpTransportCallback * cb,jint version,jdwpTransportEnv ** env)769 JNIEXPORT jint JNICALL jdwpTransport_OnLoad(JavaVM* vm ATTRIBUTE_UNUSED,
770 jdwpTransportCallback* cb,
771 jint version,
772 jdwpTransportEnv** /*out*/env) {
773 if (version != JDWPTRANSPORT_VERSION_1_0) {
774 LOG(ERROR) << "unknown version " << version;
775 return JNI_EVERSION;
776 }
777 void* data = cb->alloc(sizeof(FdForwardTransport));
778 if (data == nullptr) {
779 LOG(ERROR) << "Failed to allocate data for transport!";
780 return JNI_ENOMEM;
781 }
782 FdForwardTransport* transport =
783 new (data) FdForwardTransport(cb);
784 transport->functions = &gTransportInterface;
785 *env = transport;
786 return JNI_OK;
787 }
788
789 } // namespace dt_fd_forward
790