|
|
|
@ -42,6 +42,60 @@ |
|
|
|
|
#include "src/core/lib/transport/status_metadata.h" |
|
|
|
|
#include "src/core/lib/transport/transport.h" |
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG |
|
|
|
|
static void grpc_binder_stream_ref(grpc_binder_stream* s, const char* reason) { |
|
|
|
|
grpc_stream_ref(s->refcount, reason); |
|
|
|
|
} |
|
|
|
|
static void grpc_binder_stream_unref(grpc_binder_stream* s, |
|
|
|
|
const char* reason) { |
|
|
|
|
grpc_stream_unref(s->refcount, reason); |
|
|
|
|
} |
|
|
|
|
static void grpc_binder_ref_transport(grpc_binder_transport* t, |
|
|
|
|
const char* reason, const char* file, |
|
|
|
|
int line) { |
|
|
|
|
t->refs.Ref(grpc_core::DebugLocation(file, line), reason); |
|
|
|
|
} |
|
|
|
|
static void grpc_binder_unref_transport(grpc_binder_transport* t, |
|
|
|
|
const char* reason, const char* file, |
|
|
|
|
int line) { |
|
|
|
|
if (t->refs.Unref(grpc_core::DebugLocation(file, line), reason)) { |
|
|
|
|
delete t; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
static void grpc_binder_stream_ref(grpc_binder_stream* s) { |
|
|
|
|
grpc_stream_ref(s->refcount); |
|
|
|
|
} |
|
|
|
|
static void grpc_binder_stream_unref(grpc_binder_stream* s) { |
|
|
|
|
grpc_stream_unref(s->refcount); |
|
|
|
|
} |
|
|
|
|
static void grpc_binder_ref_transport(grpc_binder_transport* t) { |
|
|
|
|
t->refs.Ref(); |
|
|
|
|
} |
|
|
|
|
static void grpc_binder_unref_transport(grpc_binder_transport* t) { |
|
|
|
|
if (t->refs.Unref()) { |
|
|
|
|
delete t; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG |
|
|
|
|
#define GRPC_BINDER_STREAM_REF(stream, reason) \ |
|
|
|
|
grpc_binder_stream_ref(stream, reason) |
|
|
|
|
#define GRPC_BINDER_STREAM_UNREF(stream, reason) \ |
|
|
|
|
grpc_binder_stream_unref(stream, reason) |
|
|
|
|
#define GRPC_BINDER_REF_TRANSPORT(t, r) \ |
|
|
|
|
grpc_binder_ref_transport(t, r, __FILE__, __LINE__) |
|
|
|
|
#define GRPC_BINDER_UNREF_TRANSPORT(t, r) \ |
|
|
|
|
grpc_binder_unref_transport(t, r, __FILE__, __LINE__) |
|
|
|
|
#else |
|
|
|
|
#define GRPC_BINDER_STREAM_REF(stream, reason) grpc_binder_stream_ref(stream) |
|
|
|
|
#define GRPC_BINDER_STREAM_UNREF(stream, reason) \ |
|
|
|
|
grpc_binder_stream_unref(stream) |
|
|
|
|
#define GRPC_BINDER_REF_TRANSPORT(t, r) grpc_binder_ref_transport(t) |
|
|
|
|
#define GRPC_BINDER_UNREF_TRANSPORT(t, r) grpc_binder_unref_transport(t) |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static int init_stream(grpc_transport* gt, grpc_stream* gs, |
|
|
|
|
grpc_stream_refcount* refcount, const void* server_data, |
|
|
|
|
grpc_core::Arena* arena) { |
|
|
|
@ -51,8 +105,8 @@ static int init_stream(grpc_transport* gt, grpc_stream* gs, |
|
|
|
|
grpc_binder_transport* t = reinterpret_cast<grpc_binder_transport*>(gt); |
|
|
|
|
// TODO(mingcl): Figure out if we need to worry about concurrent invocation
|
|
|
|
|
// here
|
|
|
|
|
new (gs) grpc_binder_stream(t, arena, server_data, t->NewStreamTxCode(), |
|
|
|
|
t->is_client); |
|
|
|
|
new (gs) grpc_binder_stream(t, refcount, server_data, arena, |
|
|
|
|
t->NewStreamTxCode(), t->is_client); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -64,8 +118,8 @@ static void set_pollset_set(grpc_transport*, grpc_stream*, grpc_pollset_set*) { |
|
|
|
|
gpr_log(GPR_INFO, __func__); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void AssignMetadata(grpc_metadata_batch* mb, grpc_core::Arena* arena, |
|
|
|
|
const grpc_binder::Metadata& md) { |
|
|
|
|
static void AssignMetadata(grpc_metadata_batch* mb, grpc_core::Arena* arena, |
|
|
|
|
const grpc_binder::Metadata& md) { |
|
|
|
|
grpc_metadata_batch_init(mb); |
|
|
|
|
for (auto& p : md) { |
|
|
|
|
grpc_linked_mdelem* glm = static_cast<grpc_linked_mdelem*>( |
|
|
|
@ -82,51 +136,226 @@ void AssignMetadata(grpc_metadata_batch* mb, grpc_core::Arena* arena, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, |
|
|
|
|
grpc_transport_stream_op_batch* op) { |
|
|
|
|
GPR_TIMER_SCOPE("perform_stream_op", 0); |
|
|
|
|
gpr_log(GPR_INFO, "%s = %p %p %p", __func__, gt, gs, op); |
|
|
|
|
grpc_binder_transport* gbt = reinterpret_cast<grpc_binder_transport*>(gt); |
|
|
|
|
grpc_binder_stream* gbs = reinterpret_cast<grpc_binder_stream*>(gs); |
|
|
|
|
static void cancel_stream_locked(grpc_binder_transport* gbt, |
|
|
|
|
grpc_binder_stream* gbs, |
|
|
|
|
grpc_error_handle error) { |
|
|
|
|
gpr_log(GPR_INFO, "cancel_stream_locked"); |
|
|
|
|
if (!gbs->is_closed) { |
|
|
|
|
GPR_ASSERT(gbs->cancel_self_error == GRPC_ERROR_NONE); |
|
|
|
|
gbs->is_closed = true; |
|
|
|
|
gbs->cancel_self_error = GRPC_ERROR_REF(error); |
|
|
|
|
gbt->transport_stream_receiver->CancelStream(gbs->tx_code); |
|
|
|
|
gbt->registered_stream.erase(gbs->tx_code); |
|
|
|
|
if (gbs->recv_initial_metadata_ready != nullptr) { |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, gbs->recv_initial_metadata_ready, |
|
|
|
|
GRPC_ERROR_REF(error)); |
|
|
|
|
gbs->recv_initial_metadata_ready = nullptr; |
|
|
|
|
gbs->recv_initial_metadata = nullptr; |
|
|
|
|
gbs->trailing_metadata_available = nullptr; |
|
|
|
|
} |
|
|
|
|
if (gbs->recv_message_ready != nullptr) { |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, gbs->recv_message_ready, |
|
|
|
|
GRPC_ERROR_REF(error)); |
|
|
|
|
gbs->recv_message_ready = nullptr; |
|
|
|
|
gbs->recv_message = nullptr; |
|
|
|
|
gbs->call_failed_before_recv_message = nullptr; |
|
|
|
|
} |
|
|
|
|
if (gbs->recv_trailing_metadata_finished != nullptr) { |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, |
|
|
|
|
gbs->recv_trailing_metadata_finished, |
|
|
|
|
GRPC_ERROR_REF(error)); |
|
|
|
|
gbs->recv_trailing_metadata_finished = nullptr; |
|
|
|
|
gbs->recv_trailing_metadata = nullptr; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
GRPC_ERROR_UNREF(error); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void recv_initial_metadata_locked(void* arg, |
|
|
|
|
grpc_error_handle /*error*/) { |
|
|
|
|
gpr_log(GPR_INFO, "recv_initial_metadata_locked"); |
|
|
|
|
RecvInitialMetadataArgs* args = static_cast<RecvInitialMetadataArgs*>(arg); |
|
|
|
|
|
|
|
|
|
grpc_binder_stream* gbs = args->gbs; |
|
|
|
|
|
|
|
|
|
if (!gbs->is_closed) { |
|
|
|
|
grpc_error_handle error = [&] { |
|
|
|
|
GPR_ASSERT(gbs->recv_initial_metadata); |
|
|
|
|
GPR_ASSERT(gbs->recv_initial_metadata_ready); |
|
|
|
|
if (!args->initial_metadata.ok()) { |
|
|
|
|
gpr_log(GPR_ERROR, "Failed to parse initial metadata"); |
|
|
|
|
return absl_status_to_grpc_error(args->initial_metadata.status()); |
|
|
|
|
} |
|
|
|
|
AssignMetadata(gbs->recv_initial_metadata, gbs->arena, |
|
|
|
|
*args->initial_metadata); |
|
|
|
|
return GRPC_ERROR_NONE; |
|
|
|
|
}(); |
|
|
|
|
|
|
|
|
|
grpc_closure* cb = gbs->recv_initial_metadata_ready; |
|
|
|
|
gbs->recv_initial_metadata_ready = nullptr; |
|
|
|
|
gbs->recv_initial_metadata = nullptr; |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error); |
|
|
|
|
} |
|
|
|
|
GRPC_BINDER_STREAM_UNREF(gbs, "recv_initial_metadata"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void recv_message_locked(void* arg, grpc_error_handle /*error*/) { |
|
|
|
|
gpr_log(GPR_INFO, "recv_message_locked"); |
|
|
|
|
RecvMessageArgs* args = static_cast<RecvMessageArgs*>(arg); |
|
|
|
|
|
|
|
|
|
grpc_binder_stream* gbs = args->gbs; |
|
|
|
|
|
|
|
|
|
if (!gbs->is_closed) { |
|
|
|
|
grpc_error_handle error = [&] { |
|
|
|
|
GPR_ASSERT(gbs->recv_message); |
|
|
|
|
GPR_ASSERT(gbs->recv_message_ready); |
|
|
|
|
if (!args->message.ok()) { |
|
|
|
|
gpr_log(GPR_ERROR, "Failed to receive message"); |
|
|
|
|
if (args->message.status().message() == |
|
|
|
|
grpc_binder::TransportStreamReceiver:: |
|
|
|
|
kGrpcBinderTransportCancelledGracefully) { |
|
|
|
|
gpr_log(GPR_ERROR, "message cancelled gracefully"); |
|
|
|
|
// Cancelled because we've already received trailing metadata.
|
|
|
|
|
// It's not an error in this case.
|
|
|
|
|
return GRPC_ERROR_NONE; |
|
|
|
|
} else { |
|
|
|
|
return absl_status_to_grpc_error(args->message.status()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
grpc_slice_buffer buf; |
|
|
|
|
grpc_slice_buffer_init(&buf); |
|
|
|
|
grpc_slice_buffer_add(&buf, grpc_slice_from_cpp_string(*args->message)); |
|
|
|
|
|
|
|
|
|
gbs->sbs.Init(&buf, 0); |
|
|
|
|
gbs->recv_message->reset(gbs->sbs.get()); |
|
|
|
|
return GRPC_ERROR_NONE; |
|
|
|
|
}(); |
|
|
|
|
|
|
|
|
|
if (error != GRPC_ERROR_NONE && |
|
|
|
|
gbs->call_failed_before_recv_message != nullptr) { |
|
|
|
|
*gbs->call_failed_before_recv_message = true; |
|
|
|
|
} |
|
|
|
|
grpc_closure* cb = gbs->recv_message_ready; |
|
|
|
|
gbs->recv_message_ready = nullptr; |
|
|
|
|
gbs->recv_message = nullptr; |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
GRPC_BINDER_STREAM_UNREF(gbs, "recv_message"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void recv_trailing_metadata_locked(void* arg, |
|
|
|
|
grpc_error_handle /*error*/) { |
|
|
|
|
gpr_log(GPR_INFO, "recv_trailing_metadata_locked"); |
|
|
|
|
RecvTrailingMetadataArgs* args = static_cast<RecvTrailingMetadataArgs*>(arg); |
|
|
|
|
|
|
|
|
|
grpc_binder_stream* gbs = args->gbs; |
|
|
|
|
|
|
|
|
|
if (!gbs->is_closed) { |
|
|
|
|
grpc_error_handle error = [&] { |
|
|
|
|
GPR_ASSERT(gbs->recv_trailing_metadata); |
|
|
|
|
GPR_ASSERT(gbs->recv_trailing_metadata_finished); |
|
|
|
|
if (!args->trailing_metadata.ok()) { |
|
|
|
|
gpr_log(GPR_ERROR, "Failed to receive trailing metadata"); |
|
|
|
|
return absl_status_to_grpc_error(args->trailing_metadata.status()); |
|
|
|
|
} |
|
|
|
|
if (!gbs->is_client) { |
|
|
|
|
// Client will not send non-empty trailing metadata.
|
|
|
|
|
if (!args->trailing_metadata.value().empty()) { |
|
|
|
|
gpr_log(GPR_ERROR, "Server receives non-empty trailing metadata."); |
|
|
|
|
return GRPC_ERROR_CANCELLED; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
AssignMetadata(gbs->recv_trailing_metadata, gbs->arena, |
|
|
|
|
*args->trailing_metadata); |
|
|
|
|
// Append status to metadata
|
|
|
|
|
// TODO(b/192208695): See if we can avoid to manually put status
|
|
|
|
|
// code into the header
|
|
|
|
|
gpr_log(GPR_INFO, "status = %d", args->status); |
|
|
|
|
grpc_linked_mdelem* glm = static_cast<grpc_linked_mdelem*>( |
|
|
|
|
gbs->arena->Alloc(sizeof(grpc_linked_mdelem))); |
|
|
|
|
glm->md = grpc_get_reffed_status_elem(args->status); |
|
|
|
|
GPR_ASSERT(grpc_metadata_batch_link_tail(gbs->recv_trailing_metadata, |
|
|
|
|
glm) == GRPC_ERROR_NONE); |
|
|
|
|
gpr_log(GPR_INFO, "trailing_metadata = %p", |
|
|
|
|
gbs->recv_trailing_metadata); |
|
|
|
|
gpr_log(GPR_INFO, "glm = %p", glm); |
|
|
|
|
} |
|
|
|
|
return GRPC_ERROR_NONE; |
|
|
|
|
}(); |
|
|
|
|
|
|
|
|
|
grpc_closure* cb = gbs->recv_trailing_metadata_finished; |
|
|
|
|
gbs->recv_trailing_metadata_finished = nullptr; |
|
|
|
|
gbs->recv_trailing_metadata = nullptr; |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error); |
|
|
|
|
} |
|
|
|
|
GRPC_BINDER_STREAM_UNREF(gbs, "recv_trailing_metadata"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void perform_stream_op_locked(void* stream_op, |
|
|
|
|
grpc_error_handle /*error*/) { |
|
|
|
|
grpc_transport_stream_op_batch* op = |
|
|
|
|
static_cast<grpc_transport_stream_op_batch*>(stream_op); |
|
|
|
|
grpc_binder_stream* gbs = |
|
|
|
|
static_cast<grpc_binder_stream*>(op->handler_private.extra_arg); |
|
|
|
|
grpc_binder_transport* gbt = gbs->t; |
|
|
|
|
if (op->cancel_stream) { |
|
|
|
|
// TODO(waynetu): Is this true?
|
|
|
|
|
GPR_ASSERT(!op->send_initial_metadata && !op->send_message && |
|
|
|
|
!op->send_trailing_metadata && !op->recv_initial_metadata && |
|
|
|
|
!op->recv_message && !op->recv_trailing_metadata); |
|
|
|
|
gpr_log(GPR_INFO, "cancel_stream"); |
|
|
|
|
gpr_log( |
|
|
|
|
GPR_INFO, "cancel_stream error = %s", |
|
|
|
|
grpc_error_std_string(op->payload->cancel_stream.cancel_error).c_str()); |
|
|
|
|
gbs->cancellation_error = |
|
|
|
|
grpc_error_to_absl_status(op->payload->cancel_stream.cancel_error); |
|
|
|
|
// Send trailing metadata to inform the other end about the cancellation,
|
|
|
|
|
// regardless if we'd already done that or not.
|
|
|
|
|
grpc_binder::Transaction cancel_tx(gbs->GetTxCode(), gbs->GetThenIncSeq(), |
|
|
|
|
gbt->is_client); |
|
|
|
|
cancel_tx.SetSuffix(grpc_binder::Metadata{}); |
|
|
|
|
absl::Status status = gbt->wire_writer->RpcCall(cancel_tx); |
|
|
|
|
gbt->transport_stream_receiver->CancelStream(gbs->tx_code, |
|
|
|
|
gbs->cancellation_error); |
|
|
|
|
GRPC_ERROR_UNREF(op->payload->cancel_stream.cancel_error); |
|
|
|
|
cancel_stream_locked(gbt, gbs, op->payload->cancel_stream.cancel_error); |
|
|
|
|
if (op->on_complete != nullptr) { |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->on_complete, |
|
|
|
|
absl_status_to_grpc_error(status)); |
|
|
|
|
gpr_log(GPR_INFO, "on_complete closure schuduled"); |
|
|
|
|
} |
|
|
|
|
GRPC_BINDER_STREAM_UNREF(gbs, "perform_stream_op"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (gbs->is_closed) { |
|
|
|
|
if (op->recv_initial_metadata) { |
|
|
|
|
grpc_core::ExecCtx::Run( |
|
|
|
|
DEBUG_LOCATION, |
|
|
|
|
op->payload->recv_initial_metadata.recv_initial_metadata_ready, |
|
|
|
|
GRPC_ERROR_REF(gbs->cancel_self_error)); |
|
|
|
|
} |
|
|
|
|
if (op->recv_message) { |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, |
|
|
|
|
op->payload->recv_message.recv_message_ready, |
|
|
|
|
GRPC_ERROR_REF(gbs->cancel_self_error)); |
|
|
|
|
} |
|
|
|
|
if (op->recv_trailing_metadata) { |
|
|
|
|
grpc_core::ExecCtx::Run( |
|
|
|
|
DEBUG_LOCATION, |
|
|
|
|
op->payload->recv_trailing_metadata.recv_trailing_metadata_ready, |
|
|
|
|
GRPC_ERROR_REF(gbs->cancel_self_error)); |
|
|
|
|
} |
|
|
|
|
if (op->on_complete != nullptr) { |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->on_complete, |
|
|
|
|
GRPC_ERROR_REF(gbs->cancel_self_error)); |
|
|
|
|
} |
|
|
|
|
GRPC_BINDER_STREAM_UNREF(gbs, "perform_stream_op"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::unique_ptr<grpc_binder::Transaction> tx; |
|
|
|
|
int tx_code = gbs->tx_code; |
|
|
|
|
|
|
|
|
|
if (op->send_initial_metadata || op->send_message || |
|
|
|
|
op->send_trailing_metadata) { |
|
|
|
|
// Only increment sequence number when there's a send operation.
|
|
|
|
|
tx = absl::make_unique<grpc_binder::Transaction>( |
|
|
|
|
/*tx_code=*/gbs->GetTxCode(), /*seq_num=*/gbs->GetThenIncSeq(), |
|
|
|
|
gbt->is_client); |
|
|
|
|
/*tx_code=*/tx_code, /*seq_num=*/gbs->GetThenIncSeq(), gbt->is_client); |
|
|
|
|
} |
|
|
|
|
if (op->send_initial_metadata && gbs->cancellation_error.ok()) { |
|
|
|
|
if (op->send_initial_metadata) { |
|
|
|
|
gpr_log(GPR_INFO, "send_initial_metadata"); |
|
|
|
|
grpc_binder::Metadata init_md; |
|
|
|
|
auto batch = op->payload->send_initial_metadata.send_initial_metadata; |
|
|
|
@ -155,7 +384,7 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, |
|
|
|
|
} |
|
|
|
|
tx->SetPrefix(init_md); |
|
|
|
|
} |
|
|
|
|
if (op->send_message && gbs->cancellation_error.ok()) { |
|
|
|
|
if (op->send_message) { |
|
|
|
|
gpr_log(GPR_INFO, "send_message"); |
|
|
|
|
size_t remaining = op->payload->send_message.send_message->length(); |
|
|
|
|
std::string message_data; |
|
|
|
@ -181,7 +410,8 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, |
|
|
|
|
// use-after-free issue in call.cc?
|
|
|
|
|
op->payload->send_message.send_message.reset(); |
|
|
|
|
} |
|
|
|
|
if (op->send_trailing_metadata && gbs->cancellation_error.ok()) { |
|
|
|
|
|
|
|
|
|
if (op->send_trailing_metadata) { |
|
|
|
|
gpr_log(GPR_INFO, "send_trailing_metadata"); |
|
|
|
|
auto batch = op->payload->send_trailing_metadata.send_trailing_metadata; |
|
|
|
|
grpc_binder::Metadata trailing_metadata; |
|
|
|
@ -212,137 +442,79 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, |
|
|
|
|
} |
|
|
|
|
if (op->recv_initial_metadata) { |
|
|
|
|
gpr_log(GPR_INFO, "recv_initial_metadata"); |
|
|
|
|
if (!gbs->cancellation_error.ok()) { |
|
|
|
|
grpc_core::ExecCtx::Run( |
|
|
|
|
DEBUG_LOCATION, |
|
|
|
|
op->payload->recv_initial_metadata.recv_initial_metadata_ready, |
|
|
|
|
absl_status_to_grpc_error(gbs->cancellation_error)); |
|
|
|
|
} else { |
|
|
|
|
gbs->recv_initial_metadata_ready = |
|
|
|
|
op->payload->recv_initial_metadata.recv_initial_metadata_ready; |
|
|
|
|
gbs->recv_initial_metadata = |
|
|
|
|
op->payload->recv_initial_metadata.recv_initial_metadata; |
|
|
|
|
gbt->transport_stream_receiver->RegisterRecvInitialMetadata( |
|
|
|
|
gbs->tx_code, |
|
|
|
|
[gbs](absl::StatusOr<grpc_binder::Metadata> initial_metadata) { |
|
|
|
|
grpc_core::ExecCtx exec_ctx; |
|
|
|
|
GPR_ASSERT(gbs->recv_initial_metadata); |
|
|
|
|
GPR_ASSERT(gbs->recv_initial_metadata_ready); |
|
|
|
|
if (!initial_metadata.ok()) { |
|
|
|
|
gpr_log(GPR_ERROR, "Failed to parse initial metadata"); |
|
|
|
|
grpc_core::ExecCtx::Run( |
|
|
|
|
DEBUG_LOCATION, gbs->recv_initial_metadata_ready, |
|
|
|
|
absl_status_to_grpc_error(initial_metadata.status())); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
AssignMetadata(gbs->recv_initial_metadata, gbs->arena, |
|
|
|
|
*initial_metadata); |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, |
|
|
|
|
gbs->recv_initial_metadata_ready, |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
gbs->recv_initial_metadata_ready = |
|
|
|
|
op->payload->recv_initial_metadata.recv_initial_metadata_ready; |
|
|
|
|
gbs->recv_initial_metadata = |
|
|
|
|
op->payload->recv_initial_metadata.recv_initial_metadata; |
|
|
|
|
gbs->trailing_metadata_available = |
|
|
|
|
op->payload->recv_initial_metadata.trailing_metadata_available; |
|
|
|
|
GRPC_BINDER_STREAM_REF(gbs, "recv_initial_metadata"); |
|
|
|
|
gbt->transport_stream_receiver->RegisterRecvInitialMetadata( |
|
|
|
|
tx_code, [tx_code, gbs, |
|
|
|
|
gbt](absl::StatusOr<grpc_binder::Metadata> initial_metadata) { |
|
|
|
|
grpc_core::ExecCtx exec_ctx; |
|
|
|
|
if (gbs->is_closed) { |
|
|
|
|
GRPC_BINDER_STREAM_UNREF(gbs, "recv_initial_metadata"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
gbs->recv_initial_metadata_args.tx_code = tx_code; |
|
|
|
|
gbs->recv_initial_metadata_args.initial_metadata = |
|
|
|
|
std::move(initial_metadata); |
|
|
|
|
gbt->combiner->Run( |
|
|
|
|
GRPC_CLOSURE_INIT(&gbs->recv_initial_metadata_closure, |
|
|
|
|
recv_initial_metadata_locked, |
|
|
|
|
&gbs->recv_initial_metadata_args, nullptr), |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
if (op->recv_message) { |
|
|
|
|
gpr_log(GPR_INFO, "recv_message"); |
|
|
|
|
if (!gbs->cancellation_error.ok()) { |
|
|
|
|
grpc_core::ExecCtx::Run( |
|
|
|
|
DEBUG_LOCATION, op->payload->recv_message.recv_message_ready, |
|
|
|
|
absl_status_to_grpc_error(gbs->cancellation_error)); |
|
|
|
|
} else { |
|
|
|
|
gbs->recv_message_ready = op->payload->recv_message.recv_message_ready; |
|
|
|
|
gbs->recv_message = op->payload->recv_message.recv_message; |
|
|
|
|
gbt->transport_stream_receiver->RegisterRecvMessage( |
|
|
|
|
gbs->tx_code, [gbs](absl::StatusOr<std::string> message) { |
|
|
|
|
grpc_core::ExecCtx exec_ctx; |
|
|
|
|
GPR_ASSERT(gbs->recv_message); |
|
|
|
|
GPR_ASSERT(gbs->recv_message_ready); |
|
|
|
|
if (!message.ok()) { |
|
|
|
|
gpr_log(GPR_ERROR, "Failed to receive message"); |
|
|
|
|
if (message.status().message() == |
|
|
|
|
grpc_binder::TransportStreamReceiver:: |
|
|
|
|
kGrpcBinderTransportCancelledGracefully) { |
|
|
|
|
gpr_log(GPR_ERROR, "message cancelled gracefully"); |
|
|
|
|
// Cancelled because we've already received trailing metadata.
|
|
|
|
|
// It's not an error in this case.
|
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, gbs->recv_message_ready, |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
} else { |
|
|
|
|
grpc_core::ExecCtx::Run( |
|
|
|
|
DEBUG_LOCATION, gbs->recv_message_ready, |
|
|
|
|
absl_status_to_grpc_error(message.status())); |
|
|
|
|
} |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
grpc_slice_buffer buf; |
|
|
|
|
grpc_slice_buffer_init(&buf); |
|
|
|
|
grpc_slice_buffer_add(&buf, grpc_slice_from_cpp_string(*message)); |
|
|
|
|
|
|
|
|
|
gbs->sbs.Init(&buf, 0); |
|
|
|
|
gbs->recv_message->reset(gbs->sbs.get()); |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, gbs->recv_message_ready, |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
gbs->recv_message_ready = op->payload->recv_message.recv_message_ready; |
|
|
|
|
gbs->recv_message = op->payload->recv_message.recv_message; |
|
|
|
|
gbs->call_failed_before_recv_message = |
|
|
|
|
op->payload->recv_message.call_failed_before_recv_message; |
|
|
|
|
GRPC_BINDER_STREAM_REF(gbs, "recv_message"); |
|
|
|
|
gbt->transport_stream_receiver->RegisterRecvMessage( |
|
|
|
|
tx_code, [tx_code, gbs, gbt](absl::StatusOr<std::string> message) { |
|
|
|
|
grpc_core::ExecCtx exec_ctx; |
|
|
|
|
if (gbs->is_closed) { |
|
|
|
|
GRPC_BINDER_STREAM_UNREF(gbs, "recv_message"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
gbs->recv_message_args.tx_code = tx_code; |
|
|
|
|
gbs->recv_message_args.message = std::move(message); |
|
|
|
|
gbt->combiner->Run( |
|
|
|
|
GRPC_CLOSURE_INIT(&gbs->recv_message_closure, recv_message_locked, |
|
|
|
|
&gbs->recv_message_args, nullptr), |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
if (op->recv_trailing_metadata) { |
|
|
|
|
gpr_log(GPR_INFO, "recv_trailing_metadata"); |
|
|
|
|
if (!gbs->cancellation_error.ok()) { |
|
|
|
|
grpc_core::ExecCtx::Run( |
|
|
|
|
DEBUG_LOCATION, |
|
|
|
|
op->payload->recv_trailing_metadata.recv_trailing_metadata_ready, |
|
|
|
|
absl_status_to_grpc_error(gbs->cancellation_error)); |
|
|
|
|
} else { |
|
|
|
|
gbs->recv_trailing_metadata_finished = |
|
|
|
|
op->payload->recv_trailing_metadata.recv_trailing_metadata_ready; |
|
|
|
|
gbs->recv_trailing_metadata = |
|
|
|
|
op->payload->recv_trailing_metadata.recv_trailing_metadata; |
|
|
|
|
gbt->transport_stream_receiver->RegisterRecvTrailingMetadata( |
|
|
|
|
gbs->tx_code, |
|
|
|
|
[gbs](absl::StatusOr<grpc_binder::Metadata> trailing_metadata, |
|
|
|
|
int status) { |
|
|
|
|
grpc_core::ExecCtx exec_ctx; |
|
|
|
|
GPR_ASSERT(gbs->recv_trailing_metadata); |
|
|
|
|
GPR_ASSERT(gbs->recv_trailing_metadata_finished); |
|
|
|
|
if (!trailing_metadata.ok()) { |
|
|
|
|
gpr_log(GPR_ERROR, "Failed to receive trailing metadata"); |
|
|
|
|
grpc_core::ExecCtx::Run( |
|
|
|
|
DEBUG_LOCATION, gbs->recv_trailing_metadata_finished, |
|
|
|
|
absl_status_to_grpc_error(trailing_metadata.status())); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (!gbs->is_client) { |
|
|
|
|
// Client will not send non-empty trailing metadata.
|
|
|
|
|
if (!trailing_metadata.value().empty()) { |
|
|
|
|
gpr_log(GPR_ERROR, |
|
|
|
|
"Server receives non-empty trailing metadata."); |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, |
|
|
|
|
gbs->recv_trailing_metadata_finished, |
|
|
|
|
GRPC_ERROR_CANCELLED); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
AssignMetadata(gbs->recv_trailing_metadata, gbs->arena, |
|
|
|
|
*trailing_metadata); |
|
|
|
|
// Append status to metadata
|
|
|
|
|
// TODO(b/192208695): See if we can avoid to manually put status
|
|
|
|
|
// code into the header
|
|
|
|
|
gpr_log(GPR_INFO, "status = %d", status); |
|
|
|
|
grpc_linked_mdelem* glm = static_cast<grpc_linked_mdelem*>( |
|
|
|
|
gbs->arena->Alloc(sizeof(grpc_linked_mdelem))); |
|
|
|
|
glm->md = grpc_get_reffed_status_elem(status); |
|
|
|
|
GPR_ASSERT(grpc_metadata_batch_link_tail( |
|
|
|
|
gbs->recv_trailing_metadata, glm) == |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
gpr_log(GPR_INFO, "trailing_metadata = %p", |
|
|
|
|
gbs->recv_trailing_metadata); |
|
|
|
|
gpr_log(GPR_INFO, "glm = %p", glm); |
|
|
|
|
} |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, |
|
|
|
|
gbs->recv_trailing_metadata_finished, |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
gbs->recv_trailing_metadata_finished = |
|
|
|
|
op->payload->recv_trailing_metadata.recv_trailing_metadata_ready; |
|
|
|
|
gbs->recv_trailing_metadata = |
|
|
|
|
op->payload->recv_trailing_metadata.recv_trailing_metadata; |
|
|
|
|
GRPC_BINDER_STREAM_REF(gbs, "recv_trailing_metadata"); |
|
|
|
|
gbt->transport_stream_receiver->RegisterRecvTrailingMetadata( |
|
|
|
|
tx_code, [tx_code, gbs, gbt]( |
|
|
|
|
absl::StatusOr<grpc_binder::Metadata> trailing_metadata, |
|
|
|
|
int status) { |
|
|
|
|
grpc_core::ExecCtx exec_ctx; |
|
|
|
|
if (gbs->is_closed) { |
|
|
|
|
GRPC_BINDER_STREAM_UNREF(gbs, "recv_trailing_metadata"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
gbs->recv_trailing_metadata_args.tx_code = tx_code; |
|
|
|
|
gbs->recv_trailing_metadata_args.trailing_metadata = |
|
|
|
|
std::move(trailing_metadata); |
|
|
|
|
gbs->recv_trailing_metadata_args.status = status; |
|
|
|
|
gbt->combiner->Run( |
|
|
|
|
GRPC_CLOSURE_INIT(&gbs->recv_trailing_metadata_closure, |
|
|
|
|
recv_trailing_metadata_locked, |
|
|
|
|
&gbs->recv_trailing_metadata_args, nullptr), |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
// Only send transaction when there's a send op presented.
|
|
|
|
|
absl::Status status = absl::OkStatus(); |
|
|
|
@ -356,12 +528,39 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, |
|
|
|
|
absl_status_to_grpc_error(status)); |
|
|
|
|
gpr_log(GPR_INFO, "on_complete closure schuduled"); |
|
|
|
|
} |
|
|
|
|
GRPC_BINDER_STREAM_UNREF(gbs, "perform_stream_op"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) { |
|
|
|
|
gpr_log(GPR_INFO, __func__); |
|
|
|
|
static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, |
|
|
|
|
grpc_transport_stream_op_batch* op) { |
|
|
|
|
GPR_TIMER_SCOPE("perform_stream_op", 0); |
|
|
|
|
gpr_log(GPR_INFO, "%s = %p %p %p", __func__, gt, gs, op); |
|
|
|
|
grpc_binder_transport* gbt = reinterpret_cast<grpc_binder_transport*>(gt); |
|
|
|
|
grpc_core::MutexLock lock(&gbt->mu); |
|
|
|
|
grpc_binder_stream* gbs = reinterpret_cast<grpc_binder_stream*>(gs); |
|
|
|
|
GRPC_BINDER_STREAM_REF(gbs, "perform_stream_op"); |
|
|
|
|
op->handler_private.extra_arg = gbs; |
|
|
|
|
gbt->combiner->Run(GRPC_CLOSURE_INIT(&op->handler_private.closure, |
|
|
|
|
perform_stream_op_locked, op, nullptr), |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void close_transport_locked(grpc_binder_transport* gbt) { |
|
|
|
|
gbt->state_tracker.SetState(GRPC_CHANNEL_SHUTDOWN, absl::OkStatus(), |
|
|
|
|
"transport closed due to disconnection/goaway"); |
|
|
|
|
while (!gbt->registered_stream.empty()) { |
|
|
|
|
cancel_stream_locked( |
|
|
|
|
gbt, gbt->registered_stream.begin()->second, |
|
|
|
|
grpc_error_set_int( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("transport closed"), |
|
|
|
|
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void perform_transport_op_locked(void* transport_op, |
|
|
|
|
grpc_error_handle /*error*/) { |
|
|
|
|
grpc_transport_op* op = static_cast<grpc_transport_op*>(transport_op); |
|
|
|
|
grpc_binder_transport* gbt = |
|
|
|
|
static_cast<grpc_binder_transport*>(op->handler_private.extra_arg); |
|
|
|
|
// TODO(waynetu): Should we lock here to avoid data race?
|
|
|
|
|
if (op->start_connectivity_watch != nullptr) { |
|
|
|
|
gbt->state_tracker.AddWatcher(op->start_connectivity_watch_state, |
|
|
|
@ -387,33 +586,58 @@ static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) { |
|
|
|
|
GRPC_ERROR_UNREF(op->goaway_error); |
|
|
|
|
} |
|
|
|
|
if (do_close) { |
|
|
|
|
gbt->state_tracker.SetState(GRPC_CHANNEL_SHUTDOWN, absl::OkStatus(), |
|
|
|
|
"transport closed due to disconnection/goaway"); |
|
|
|
|
close_transport_locked(gbt); |
|
|
|
|
} |
|
|
|
|
GRPC_BINDER_UNREF_TRANSPORT(gbt, "perform_transport_op"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void destroy_stream(grpc_transport* gt, grpc_stream* gs, |
|
|
|
|
grpc_closure* then_schedule_closure) { |
|
|
|
|
static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) { |
|
|
|
|
gpr_log(GPR_INFO, __func__); |
|
|
|
|
grpc_binder_transport* gbt = reinterpret_cast<grpc_binder_transport*>(gt); |
|
|
|
|
grpc_binder_stream* gbs = reinterpret_cast<grpc_binder_stream*>(gs); |
|
|
|
|
gbt->transport_stream_receiver->Clear(gbs->tx_code); |
|
|
|
|
// TODO(waynetu): Currently, there's nothing to be cleaned up. If additional
|
|
|
|
|
// fields are added to grpc_binder_stream in the future, we might need to use
|
|
|
|
|
// reference-counting to determine who does the actual cleaning.
|
|
|
|
|
op->handler_private.extra_arg = gbt; |
|
|
|
|
GRPC_BINDER_REF_TRANSPORT(gbt, "perform_transport_op"); |
|
|
|
|
gbt->combiner->Run( |
|
|
|
|
GRPC_CLOSURE_INIT(&op->handler_private.closure, |
|
|
|
|
perform_transport_op_locked, op, nullptr), |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void destroy_stream_locked(void* sp, grpc_error_handle /*error*/) { |
|
|
|
|
grpc_binder_stream* gbs = static_cast<grpc_binder_stream*>(sp); |
|
|
|
|
grpc_binder_transport* gbt = gbs->t; |
|
|
|
|
cancel_stream_locked( |
|
|
|
|
gbt, gbs, |
|
|
|
|
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("destroy stream"), |
|
|
|
|
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); |
|
|
|
|
gbs->~grpc_binder_stream(); |
|
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, then_schedule_closure, |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void destroy_transport(grpc_transport* gt) { |
|
|
|
|
static void destroy_stream(grpc_transport* /*gt*/, grpc_stream* gs, |
|
|
|
|
grpc_closure* then_schedule_closure) { |
|
|
|
|
gpr_log(GPR_INFO, __func__); |
|
|
|
|
grpc_binder_transport* gbt = reinterpret_cast<grpc_binder_transport*>(gt); |
|
|
|
|
grpc_binder_stream* gbs = reinterpret_cast<grpc_binder_stream*>(gs); |
|
|
|
|
gbs->destroy_stream_then_closure = then_schedule_closure; |
|
|
|
|
gbs->t->combiner->Run(GRPC_CLOSURE_INIT(&gbs->destroy_stream, |
|
|
|
|
destroy_stream_locked, gbs, nullptr), |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void destroy_transport_locked(void* gt, grpc_error_handle /*error*/) { |
|
|
|
|
grpc_binder_transport* gbt = static_cast<grpc_binder_transport*>(gt); |
|
|
|
|
close_transport_locked(gbt); |
|
|
|
|
// Release the references held by the transport.
|
|
|
|
|
gbt->wire_reader = nullptr; |
|
|
|
|
gbt->transport_stream_receiver = nullptr; |
|
|
|
|
gbt->wire_writer = nullptr; |
|
|
|
|
gbt->Unref(); |
|
|
|
|
GRPC_BINDER_UNREF_TRANSPORT(gbt, "transport destroyed"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void destroy_transport(grpc_transport* gt) { |
|
|
|
|
gpr_log(GPR_INFO, __func__); |
|
|
|
|
grpc_binder_transport* gbt = reinterpret_cast<grpc_binder_transport*>(gt); |
|
|
|
|
gbt->combiner->Run( |
|
|
|
|
GRPC_CLOSURE_CREATE(destroy_transport_locked, gbt, nullptr), |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_endpoint* get_endpoint(grpc_transport*) { |
|
|
|
@ -435,32 +659,46 @@ static const grpc_transport_vtable vtable = {sizeof(grpc_binder_stream), |
|
|
|
|
|
|
|
|
|
static const grpc_transport_vtable* get_vtable() { return &vtable; } |
|
|
|
|
|
|
|
|
|
static void accept_stream_locked(void* gt, grpc_error_handle /*error*/) { |
|
|
|
|
grpc_binder_transport* gbt = static_cast<grpc_binder_transport*>(gt); |
|
|
|
|
if (gbt->accept_stream_fn) { |
|
|
|
|
// must pass in a non-null value.
|
|
|
|
|
(*gbt->accept_stream_fn)(gbt->accept_stream_user_data, &gbt->base, gbt); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_binder_transport::grpc_binder_transport( |
|
|
|
|
std::unique_ptr<grpc_binder::Binder> binder, bool is_client) |
|
|
|
|
: is_client(is_client), |
|
|
|
|
combiner(grpc_combiner_create()), |
|
|
|
|
state_tracker(is_client ? "binder_transport_client" |
|
|
|
|
: "binder_transport_server"), |
|
|
|
|
refs(1, nullptr) { |
|
|
|
|
gpr_log(GPR_INFO, __func__); |
|
|
|
|
base.vtable = get_vtable(); |
|
|
|
|
GRPC_CLOSURE_INIT(&accept_stream_closure, accept_stream_locked, this, |
|
|
|
|
nullptr); |
|
|
|
|
transport_stream_receiver = |
|
|
|
|
std::make_shared<grpc_binder::TransportStreamReceiverImpl>( |
|
|
|
|
is_client, /*accept_stream_callback=*/[this] { |
|
|
|
|
grpc_core::ExecCtx exec_ctx; |
|
|
|
|
grpc_core::MutexLock lock(&mu); |
|
|
|
|
if (accept_stream_fn) { |
|
|
|
|
// must pass in a non-null value.
|
|
|
|
|
(*accept_stream_fn)(accept_stream_user_data, &base, this); |
|
|
|
|
} |
|
|
|
|
combiner->Run(&accept_stream_closure, GRPC_ERROR_NONE); |
|
|
|
|
}); |
|
|
|
|
// WireReader holds a ref to grpc_binder_transport.
|
|
|
|
|
Ref(); |
|
|
|
|
GRPC_BINDER_REF_TRANSPORT(this, "wire reader"); |
|
|
|
|
wire_reader = grpc_core::MakeOrphanable<grpc_binder::WireReaderImpl>( |
|
|
|
|
transport_stream_receiver, is_client, |
|
|
|
|
/*on_destruct_callback=*/[this] { Unref(); }); |
|
|
|
|
/*on_destruct_callback=*/[this] { |
|
|
|
|
// Unref transport when destructed.
|
|
|
|
|
GRPC_BINDER_UNREF_TRANSPORT(this, "wire reader"); |
|
|
|
|
}); |
|
|
|
|
wire_writer = wire_reader->SetupTransport(std::move(binder)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_binder_transport::~grpc_binder_transport() { |
|
|
|
|
GRPC_COMBINER_UNREF(combiner, "binder_transport"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_transport* grpc_create_binder_transport_client( |
|
|
|
|
std::unique_ptr<grpc_binder::Binder> endpoint_binder) { |
|
|
|
|
gpr_log(GPR_INFO, __func__); |
|
|
|
|