blob: ffafaf43b147617476dccd6b2bbea25d68a1ed00 [file]
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_CORE_EXT_TRANSPORT_BINDER_UTILS_TRANSPORT_STREAM_RECEIVER_IMPL_H
#define GRPC_CORE_EXT_TRANSPORT_BINDER_UTILS_TRANSPORT_STREAM_RECEIVER_IMPL_H
#include <grpc/support/port_platform.h>
#include <functional>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>
#include "src/core/ext/transport/binder/utils/transport_stream_receiver.h"
#include "src/core/lib/gprpp/sync.h"
namespace grpc_binder {
// Routes the data received from transport to corresponding streams
class TransportStreamReceiverImpl : public TransportStreamReceiver {
public:
explicit TransportStreamReceiverImpl(
bool is_client, std::function<void()> accept_stream_callback = nullptr)
: is_client_(is_client),
accept_stream_callback_(accept_stream_callback) {}
void RegisterRecvInitialMetadata(StreamIdentifier id,
InitialMetadataCallbackType cb) override;
void RegisterRecvMessage(StreamIdentifier id,
MessageDataCallbackType cb) override;
void RegisterRecvTrailingMetadata(StreamIdentifier id,
TrailingMetadataCallbackType cb) override;
void NotifyRecvInitialMetadata(
StreamIdentifier id, absl::StatusOr<Metadata> initial_metadata) override;
void NotifyRecvMessage(StreamIdentifier id,
absl::StatusOr<std::string> message) override;
void NotifyRecvTrailingMetadata(StreamIdentifier id,
absl::StatusOr<Metadata> trailing_metadata,
int status) override;
void CancelStream(StreamIdentifier id) override;
private:
// Trailing metadata marks the end of one-side of the stream. Thus, after
// receiving trailing metadata from the other-end, we know that there will
// never be in-coming message data anymore, and all recv_message callbacks
// (as well as recv_initial_metadata callback, if there's any) registered will
// never be satisfied. This function cancels all such callbacks gracefully
// (with GRPC_ERROR_NONE) to avoid being blocked waiting for them.
void OnRecvTrailingMetadata(StreamIdentifier id);
void CancelInitialMetadataCallback(StreamIdentifier id, absl::Status error);
void CancelMessageCallback(StreamIdentifier id, absl::Status error);
void CancelTrailingMetadataCallback(StreamIdentifier id, absl::Status error);
std::map<StreamIdentifier, InitialMetadataCallbackType> initial_metadata_cbs_;
std::map<StreamIdentifier, MessageDataCallbackType> message_cbs_;
std::map<StreamIdentifier, TrailingMetadataCallbackType>
trailing_metadata_cbs_;
// TODO(waynetu): Better thread safety design. For example, use separate
// mutexes for different type of messages.
grpc_core::Mutex m_;
// TODO(waynetu): gRPC surface layer will not wait for the current message to
// be delivered before sending the next message. The following implementation
// is still buggy with the current implementation of wire writer if
// transaction issued first completes after the one issued later does. This is
// because we just take the first element out of the queue and assume it's the
// one issued first without further checking, which results in callbacks being
// invoked with incorrect data.
//
// This should be fixed in the wire writer level and make sure out-of-order
// messages will be re-ordered by it. In such case, the queueing approach will
// work fine. Refer to the TODO in WireWriterImpl::ProcessTransaction() at
// wire_reader_impl.cc for detecting and resolving out-of-order transactions.
//
// TODO(waynetu): Use absl::flat_hash_map.
std::map<StreamIdentifier, std::queue<absl::StatusOr<Metadata>>>
pending_initial_metadata_ ABSL_GUARDED_BY(m_);
std::map<StreamIdentifier, std::queue<absl::StatusOr<std::string>>>
pending_message_ ABSL_GUARDED_BY(m_);
std::map<StreamIdentifier,
std::queue<std::pair<absl::StatusOr<Metadata>, int>>>
pending_trailing_metadata_ ABSL_GUARDED_BY(m_);
// Record whether or not the recv_message callbacks of a given stream is
// cancelled. Although we explicitly cancel the registered recv_message() in
// CancelRecvMessageCallbacksDueToTrailingMetadata(), there are chances that
// the registration comes "after" we receive trailing metadata. Therefore,
// when RegisterRecvMessage() gets called, we should check whether
// recv_message_cancelled_ contains the corresponding stream ID, and if so,
// directly cancel the callback gracefully without pending it.
std::set<StreamIdentifier> trailing_metadata_recvd_ ABSL_GUARDED_BY(m_);
bool is_client_;
// Called when receiving initial metadata to inform the server about a new
// stream.
std::function<void()> accept_stream_callback_;
};
} // namespace grpc_binder
#endif // GRPC_CORE_EXT_TRANSPORT_BINDER_UTILS_TRANSPORT_STREAM_RECEIVER_IMPL_H