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