| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <lib/fidl/cpp/transaction_header.h> |
| #include <lib/fidl/cpp/wire/server.h> |
| |
| namespace fidl { |
| |
| namespace internal { |
| |
| const UnknownMethodHandlerEntry UnknownMethodHandlerEntry::kClosedProtocolHandlerEntry{ |
| .openness = ::fidl::internal::Openness::kClosed, |
| .dispatch = nullptr, |
| .send_reply = nullptr, |
| }; |
| |
| ::fidl::DispatchResult TryDispatch(void* impl, ::fidl::IncomingHeaderAndMessage& msg, |
| fidl::internal::MessageStorageViewBase* storage_view, |
| ::fidl::Transaction* txn, const MethodEntry* begin, |
| const MethodEntry* end) { |
| if (!msg.ok()) { |
| txn->InternalError(fidl::UnbindInfo{msg}, fidl::ErrorOrigin::kReceive); |
| // |TryDispatch| is used to ad-hoc compose protocols by trying a series of |
| // |TryDispatch|. If the message has an error, exit the cascade of dispatch |
| // attempts early since it is meaningless to keep trying otherwise. |
| return ::fidl::DispatchResult::kFound; |
| } |
| auto* hdr = msg.header(); |
| while (begin < end) { |
| if (hdr->ordinal == begin->ordinal) { |
| const fidl_message_header& header = *msg.header(); |
| auto metadata = fidl::WireFormatMetadata::FromTransactionalHeader(header); |
| fidl::EncodedMessage body_message = std::move(msg).SkipTransactionHeader(); |
| fidl::Status decode_status = begin->dispatch(impl, body_message, metadata, storage_view, txn); |
| std::move(body_message).CloseHandles(); |
| if (unlikely(!decode_status.ok())) { |
| ZX_DEBUG_ASSERT(decode_status.reason() == fidl::Reason::kDecodeError); |
| txn->InternalError(UnbindInfo{decode_status}, fidl::ErrorOrigin::kReceive); |
| } |
| return ::fidl::DispatchResult::kFound; |
| } |
| ++begin; |
| } |
| return ::fidl::DispatchResult::kNotFound; |
| } |
| |
| void Dispatch(void* impl, ::fidl::IncomingHeaderAndMessage& msg, |
| fidl::internal::MessageStorageViewBase* storage_view, ::fidl::Transaction* txn, |
| const MethodEntry* begin, const MethodEntry* end, |
| const UnknownMethodHandlerEntry* unknown_method_handler) { |
| ::fidl::DispatchResult result = TryDispatch(impl, msg, storage_view, txn, begin, end); |
| switch (result) { |
| case ::fidl::DispatchResult::kNotFound: { |
| auto* hdr = msg.header(); |
| ::fidl::UnknownMethodType unknown_interaction_type = |
| ::fidl::internal::UnknownMethodTypeFromHeader(hdr); |
| if (::fidl::IsFlexibleInteraction(hdr) && |
| ::fidl::internal::CanHandleMethod(unknown_method_handler->openness, |
| unknown_interaction_type)) { |
| if (unknown_interaction_type == ::fidl::UnknownMethodType::kTwoWay) { |
| auto reply = ::fidl::internal::UnknownMethodReply::MakeReplyFor( |
| hdr->ordinal, ::fidl::MessageDynamicFlags::kFlexibleMethod); |
| (unknown_method_handler->send_reply)(reply, txn); |
| } |
| std::move(msg).CloseHandles(); |
| unknown_method_handler->dispatch(impl, hdr->ordinal, unknown_interaction_type, txn); |
| break; |
| } |
| std::move(msg).CloseHandles(); |
| txn->InternalError(::fidl::UnbindInfo::UnknownOrdinal(), ::fidl::ErrorOrigin::kReceive); |
| } break; |
| case ::fidl::DispatchResult::kFound: |
| break; |
| } |
| } |
| |
| ::fidl::Status WeakEventSenderInner::SendEvent(::fidl::OutgoingMessage& message) const { |
| if (auto binding = binding_.lock()) { |
| message.set_txid(0); |
| message.Write(binding->transport()); |
| if (!message.ok()) { |
| HandleSendError(message.error()); |
| return message.error(); |
| } |
| return fidl::Status::Ok(); |
| } |
| return fidl::Status::Unbound(); |
| } |
| |
| void WeakEventSenderInner::HandleSendError(fidl::Status error) const { |
| if (auto binding = binding_.lock()) { |
| binding->HandleError(std::move(binding), {UnbindInfo{error}, ErrorOrigin::kSend}); |
| } |
| } |
| |
| } // namespace internal |
| |
| } // namespace fidl |