mirror of https://github.com/grpc/grpc.git
commit
5389dc334e
365 changed files with 11283 additions and 4605 deletions
@ -0,0 +1,97 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015-2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H |
||||
#define GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H |
||||
|
||||
#include <grpc++/impl/codegen/config_protobuf.h> |
||||
#include <grpc++/impl/codegen/status.h> |
||||
#include <grpc/impl/codegen/grpc_types.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
/// Interface between the codegen library and the minimal subset of core
|
||||
/// features required by the generated code.
|
||||
///
|
||||
/// All undocumented methods are simply forwarding the call to their namesakes.
|
||||
/// Please refer to their corresponding documentation for details.
|
||||
///
|
||||
/// \warning This interface should be considered internal and private.
|
||||
class CoreCodegenInterface { |
||||
public: |
||||
// Serialize the msg into a buffer created inside the function. The caller
|
||||
// should destroy the returned buffer when done with it. If serialization
|
||||
// fails,
|
||||
// false is returned and buffer is left unchanged.
|
||||
virtual Status SerializeProto(const grpc::protobuf::Message& msg, |
||||
grpc_byte_buffer** buffer) = 0; |
||||
|
||||
// The caller keeps ownership of buffer and msg.
|
||||
virtual Status DeserializeProto(grpc_byte_buffer* buffer, |
||||
grpc::protobuf::Message* msg, |
||||
int max_message_size) = 0; |
||||
|
||||
/// Upon a failed assertion, log the error.
|
||||
virtual void assert_fail(const char* failed_assertion) = 0; |
||||
|
||||
virtual grpc_completion_queue* grpc_completion_queue_create( |
||||
void* reserved) = 0; |
||||
virtual void grpc_completion_queue_destroy(grpc_completion_queue* cq) = 0; |
||||
virtual grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq, |
||||
void* tag, |
||||
gpr_timespec deadline, |
||||
void* reserved) = 0; |
||||
|
||||
virtual void* gpr_malloc(size_t size) = 0; |
||||
virtual void gpr_free(void* p) = 0; |
||||
|
||||
virtual void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) = 0; |
||||
virtual void grpc_metadata_array_init(grpc_metadata_array* array) = 0; |
||||
virtual void grpc_metadata_array_destroy(grpc_metadata_array* array) = 0; |
||||
|
||||
virtual gpr_timespec gpr_inf_future(gpr_clock_type type) = 0; |
||||
}; |
||||
|
||||
extern CoreCodegenInterface* g_core_codegen_interface; |
||||
|
||||
/// Codegen specific version of \a GPR_ASSERT.
|
||||
#define GPR_CODEGEN_ASSERT(x) \ |
||||
do { \
|
||||
if (!(x)) { \
|
||||
grpc::g_core_codegen_interface->assert_fail(#x); \
|
||||
} \
|
||||
} while (0) |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
|
@ -0,0 +1,463 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015-2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCXX_IMPL_CODEGEN_IMPL_ASYNC_STREAM_H |
||||
#define GRPCXX_IMPL_CODEGEN_IMPL_ASYNC_STREAM_H |
||||
|
||||
#include <grpc++/impl/codegen/call.h> |
||||
#include <grpc++/impl/codegen/channel_interface.h> |
||||
#include <grpc++/impl/codegen/core_codegen_interface.h> |
||||
#include <grpc++/impl/codegen/server_context.h> |
||||
#include <grpc++/impl/codegen/service_type.h> |
||||
#include <grpc++/impl/codegen/status.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
class CompletionQueue; |
||||
|
||||
/// Common interface for all client side asynchronous streaming.
|
||||
class ClientAsyncStreamingInterface { |
||||
public: |
||||
virtual ~ClientAsyncStreamingInterface() {} |
||||
|
||||
/// Request notification of the reading of the initial metadata. Completion
|
||||
/// will be notified by \a tag on the associated completion queue.
|
||||
///
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
virtual void ReadInitialMetadata(void* tag) = 0; |
||||
|
||||
/// Request notification completion.
|
||||
///
|
||||
/// \param[out] status To be updated with the operation status.
|
||||
/// \param[in] tag Tag identifying this request.
|
||||
virtual void Finish(Status* status, void* tag) = 0; |
||||
}; |
||||
|
||||
/// An interface that yields a sequence of messages of type \a R.
|
||||
template <class R> |
||||
class AsyncReaderInterface { |
||||
public: |
||||
virtual ~AsyncReaderInterface() {} |
||||
|
||||
/// Read a message of type \a R into \a msg. Completion will be notified by \a
|
||||
/// tag on the associated completion queue.
|
||||
///
|
||||
/// \param[out] msg Where to eventually store the read message.
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
virtual void Read(R* msg, void* tag) = 0; |
||||
}; |
||||
|
||||
/// An interface that can be fed a sequence of messages of type \a W.
|
||||
template <class W> |
||||
class AsyncWriterInterface { |
||||
public: |
||||
virtual ~AsyncWriterInterface() {} |
||||
|
||||
/// Request the writing of \a msg with identifying tag \a tag.
|
||||
///
|
||||
/// Only one write may be outstanding at any given time. This means that
|
||||
/// after calling Write, one must wait to receive \a tag from the completion
|
||||
/// queue BEFORE calling Write again.
|
||||
///
|
||||
/// \param[in] msg The message to be written.
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
virtual void Write(const W& msg, void* tag) = 0; |
||||
}; |
||||
|
||||
template <class R> |
||||
class ClientAsyncReaderInterface : public ClientAsyncStreamingInterface, |
||||
public AsyncReaderInterface<R> {}; |
||||
|
||||
template <class R> |
||||
class ClientAsyncReader GRPC_FINAL : public ClientAsyncReaderInterface<R> { |
||||
public: |
||||
/// Create a stream and write the first request out.
|
||||
template <class W> |
||||
ClientAsyncReader(ChannelInterface* channel, CompletionQueue* cq, |
||||
const RpcMethod& method, ClientContext* context, |
||||
const W& request, void* tag) |
||||
: context_(context), call_(channel->CreateCall(method, context, cq)) { |
||||
init_ops_.set_output_tag(tag); |
||||
init_ops_.SendInitialMetadata(context->send_initial_metadata_); |
||||
// TODO(ctiller): don't assert
|
||||
GPR_CODEGEN_ASSERT(init_ops_.SendMessage(request).ok()); |
||||
init_ops_.ClientSendClose(); |
||||
call_.PerformOps(&init_ops_); |
||||
} |
||||
|
||||
void ReadInitialMetadata(void* tag) GRPC_OVERRIDE { |
||||
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); |
||||
|
||||
meta_ops_.set_output_tag(tag); |
||||
meta_ops_.RecvInitialMetadata(context_); |
||||
call_.PerformOps(&meta_ops_); |
||||
} |
||||
|
||||
void Read(R* msg, void* tag) GRPC_OVERRIDE { |
||||
read_ops_.set_output_tag(tag); |
||||
if (!context_->initial_metadata_received_) { |
||||
read_ops_.RecvInitialMetadata(context_); |
||||
} |
||||
read_ops_.RecvMessage(msg); |
||||
call_.PerformOps(&read_ops_); |
||||
} |
||||
|
||||
void Finish(Status* status, void* tag) GRPC_OVERRIDE { |
||||
finish_ops_.set_output_tag(tag); |
||||
if (!context_->initial_metadata_received_) { |
||||
finish_ops_.RecvInitialMetadata(context_); |
||||
} |
||||
finish_ops_.ClientRecvStatus(context_, status); |
||||
call_.PerformOps(&finish_ops_); |
||||
} |
||||
|
||||
private: |
||||
ClientContext* context_; |
||||
Call call_; |
||||
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose> |
||||
init_ops_; |
||||
CallOpSet<CallOpRecvInitialMetadata> meta_ops_; |
||||
CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_; |
||||
CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_; |
||||
}; |
||||
|
||||
/// Common interface for client side asynchronous writing.
|
||||
template <class W> |
||||
class ClientAsyncWriterInterface : public ClientAsyncStreamingInterface, |
||||
public AsyncWriterInterface<W> { |
||||
public: |
||||
/// Signal the client is done with the writes.
|
||||
///
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
virtual void WritesDone(void* tag) = 0; |
||||
}; |
||||
|
||||
template <class W> |
||||
class ClientAsyncWriter GRPC_FINAL : public ClientAsyncWriterInterface<W> { |
||||
public: |
||||
template <class R> |
||||
ClientAsyncWriter(ChannelInterface* channel, CompletionQueue* cq, |
||||
const RpcMethod& method, ClientContext* context, |
||||
R* response, void* tag) |
||||
: context_(context), call_(channel->CreateCall(method, context, cq)) { |
||||
finish_ops_.RecvMessage(response); |
||||
|
||||
init_ops_.set_output_tag(tag); |
||||
init_ops_.SendInitialMetadata(context->send_initial_metadata_); |
||||
call_.PerformOps(&init_ops_); |
||||
} |
||||
|
||||
void ReadInitialMetadata(void* tag) GRPC_OVERRIDE { |
||||
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); |
||||
|
||||
meta_ops_.set_output_tag(tag); |
||||
meta_ops_.RecvInitialMetadata(context_); |
||||
call_.PerformOps(&meta_ops_); |
||||
} |
||||
|
||||
void Write(const W& msg, void* tag) GRPC_OVERRIDE { |
||||
write_ops_.set_output_tag(tag); |
||||
// TODO(ctiller): don't assert
|
||||
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); |
||||
call_.PerformOps(&write_ops_); |
||||
} |
||||
|
||||
void WritesDone(void* tag) GRPC_OVERRIDE { |
||||
writes_done_ops_.set_output_tag(tag); |
||||
writes_done_ops_.ClientSendClose(); |
||||
call_.PerformOps(&writes_done_ops_); |
||||
} |
||||
|
||||
void Finish(Status* status, void* tag) GRPC_OVERRIDE { |
||||
finish_ops_.set_output_tag(tag); |
||||
if (!context_->initial_metadata_received_) { |
||||
finish_ops_.RecvInitialMetadata(context_); |
||||
} |
||||
finish_ops_.ClientRecvStatus(context_, status); |
||||
call_.PerformOps(&finish_ops_); |
||||
} |
||||
|
||||
private: |
||||
ClientContext* context_; |
||||
Call call_; |
||||
CallOpSet<CallOpSendInitialMetadata> init_ops_; |
||||
CallOpSet<CallOpRecvInitialMetadata> meta_ops_; |
||||
CallOpSet<CallOpSendMessage> write_ops_; |
||||
CallOpSet<CallOpClientSendClose> writes_done_ops_; |
||||
CallOpSet<CallOpRecvInitialMetadata, CallOpGenericRecvMessage, |
||||
CallOpClientRecvStatus> finish_ops_; |
||||
}; |
||||
|
||||
/// Client-side interface for asynchronous bi-directional streaming.
|
||||
template <class W, class R> |
||||
class ClientAsyncReaderWriterInterface : public ClientAsyncStreamingInterface, |
||||
public AsyncWriterInterface<W>, |
||||
public AsyncReaderInterface<R> { |
||||
public: |
||||
/// Signal the client is done with the writes.
|
||||
///
|
||||
/// \param[in] tag The tag identifying the operation.
|
||||
virtual void WritesDone(void* tag) = 0; |
||||
}; |
||||
|
||||
template <class W, class R> |
||||
class ClientAsyncReaderWriter GRPC_FINAL |
||||
: public ClientAsyncReaderWriterInterface<W, R> { |
||||
public: |
||||
ClientAsyncReaderWriter(ChannelInterface* channel, CompletionQueue* cq, |
||||
const RpcMethod& method, ClientContext* context, |
||||
void* tag) |
||||
: context_(context), call_(channel->CreateCall(method, context, cq)) { |
||||
init_ops_.set_output_tag(tag); |
||||
init_ops_.SendInitialMetadata(context->send_initial_metadata_); |
||||
call_.PerformOps(&init_ops_); |
||||
} |
||||
|
||||
void ReadInitialMetadata(void* tag) GRPC_OVERRIDE { |
||||
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); |
||||
|
||||
meta_ops_.set_output_tag(tag); |
||||
meta_ops_.RecvInitialMetadata(context_); |
||||
call_.PerformOps(&meta_ops_); |
||||
} |
||||
|
||||
void Read(R* msg, void* tag) GRPC_OVERRIDE { |
||||
read_ops_.set_output_tag(tag); |
||||
if (!context_->initial_metadata_received_) { |
||||
read_ops_.RecvInitialMetadata(context_); |
||||
} |
||||
read_ops_.RecvMessage(msg); |
||||
call_.PerformOps(&read_ops_); |
||||
} |
||||
|
||||
void Write(const W& msg, void* tag) GRPC_OVERRIDE { |
||||
write_ops_.set_output_tag(tag); |
||||
// TODO(ctiller): don't assert
|
||||
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); |
||||
call_.PerformOps(&write_ops_); |
||||
} |
||||
|
||||
void WritesDone(void* tag) GRPC_OVERRIDE { |
||||
writes_done_ops_.set_output_tag(tag); |
||||
writes_done_ops_.ClientSendClose(); |
||||
call_.PerformOps(&writes_done_ops_); |
||||
} |
||||
|
||||
void Finish(Status* status, void* tag) GRPC_OVERRIDE { |
||||
finish_ops_.set_output_tag(tag); |
||||
if (!context_->initial_metadata_received_) { |
||||
finish_ops_.RecvInitialMetadata(context_); |
||||
} |
||||
finish_ops_.ClientRecvStatus(context_, status); |
||||
call_.PerformOps(&finish_ops_); |
||||
} |
||||
|
||||
private: |
||||
ClientContext* context_; |
||||
Call call_; |
||||
CallOpSet<CallOpSendInitialMetadata> init_ops_; |
||||
CallOpSet<CallOpRecvInitialMetadata> meta_ops_; |
||||
CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_; |
||||
CallOpSet<CallOpSendMessage> write_ops_; |
||||
CallOpSet<CallOpClientSendClose> writes_done_ops_; |
||||
CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_; |
||||
}; |
||||
|
||||
template <class W, class R> |
||||
class ServerAsyncReader GRPC_FINAL : public ServerAsyncStreamingInterface, |
||||
public AsyncReaderInterface<R> { |
||||
public: |
||||
explicit ServerAsyncReader(ServerContext* ctx) |
||||
: call_(nullptr, nullptr, nullptr), ctx_(ctx) {} |
||||
|
||||
void SendInitialMetadata(void* tag) GRPC_OVERRIDE { |
||||
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); |
||||
|
||||
meta_ops_.set_output_tag(tag); |
||||
meta_ops_.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
call_.PerformOps(&meta_ops_); |
||||
} |
||||
|
||||
void Read(R* msg, void* tag) GRPC_OVERRIDE { |
||||
read_ops_.set_output_tag(tag); |
||||
read_ops_.RecvMessage(msg); |
||||
call_.PerformOps(&read_ops_); |
||||
} |
||||
|
||||
void Finish(const W& msg, const Status& status, void* tag) { |
||||
finish_ops_.set_output_tag(tag); |
||||
if (!ctx_->sent_initial_metadata_) { |
||||
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
} |
||||
// The response is dropped if the status is not OK.
|
||||
if (status.ok()) { |
||||
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, |
||||
finish_ops_.SendMessage(msg)); |
||||
} else { |
||||
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status); |
||||
} |
||||
call_.PerformOps(&finish_ops_); |
||||
} |
||||
|
||||
void FinishWithError(const Status& status, void* tag) { |
||||
GPR_CODEGEN_ASSERT(!status.ok()); |
||||
finish_ops_.set_output_tag(tag); |
||||
if (!ctx_->sent_initial_metadata_) { |
||||
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
} |
||||
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status); |
||||
call_.PerformOps(&finish_ops_); |
||||
} |
||||
|
||||
private: |
||||
void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; } |
||||
|
||||
Call call_; |
||||
ServerContext* ctx_; |
||||
CallOpSet<CallOpSendInitialMetadata> meta_ops_; |
||||
CallOpSet<CallOpRecvMessage<R>> read_ops_; |
||||
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, |
||||
CallOpServerSendStatus> finish_ops_; |
||||
}; |
||||
|
||||
template <class W> |
||||
class ServerAsyncWriter GRPC_FINAL : public ServerAsyncStreamingInterface, |
||||
public AsyncWriterInterface<W> { |
||||
public: |
||||
explicit ServerAsyncWriter(ServerContext* ctx) |
||||
: call_(nullptr, nullptr, nullptr), ctx_(ctx) {} |
||||
|
||||
void SendInitialMetadata(void* tag) GRPC_OVERRIDE { |
||||
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); |
||||
|
||||
meta_ops_.set_output_tag(tag); |
||||
meta_ops_.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
call_.PerformOps(&meta_ops_); |
||||
} |
||||
|
||||
void Write(const W& msg, void* tag) GRPC_OVERRIDE { |
||||
write_ops_.set_output_tag(tag); |
||||
if (!ctx_->sent_initial_metadata_) { |
||||
write_ops_.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
} |
||||
// TODO(ctiller): don't assert
|
||||
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); |
||||
call_.PerformOps(&write_ops_); |
||||
} |
||||
|
||||
void Finish(const Status& status, void* tag) { |
||||
finish_ops_.set_output_tag(tag); |
||||
if (!ctx_->sent_initial_metadata_) { |
||||
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
} |
||||
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status); |
||||
call_.PerformOps(&finish_ops_); |
||||
} |
||||
|
||||
private: |
||||
void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; } |
||||
|
||||
Call call_; |
||||
ServerContext* ctx_; |
||||
CallOpSet<CallOpSendInitialMetadata> meta_ops_; |
||||
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_; |
||||
CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_; |
||||
}; |
||||
|
||||
/// Server-side interface for asynchronous bi-directional streaming.
|
||||
template <class W, class R> |
||||
class ServerAsyncReaderWriter GRPC_FINAL : public ServerAsyncStreamingInterface, |
||||
public AsyncWriterInterface<W>, |
||||
public AsyncReaderInterface<R> { |
||||
public: |
||||
explicit ServerAsyncReaderWriter(ServerContext* ctx) |
||||
: call_(nullptr, nullptr, nullptr), ctx_(ctx) {} |
||||
|
||||
void SendInitialMetadata(void* tag) GRPC_OVERRIDE { |
||||
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); |
||||
|
||||
meta_ops_.set_output_tag(tag); |
||||
meta_ops_.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
call_.PerformOps(&meta_ops_); |
||||
} |
||||
|
||||
void Read(R* msg, void* tag) GRPC_OVERRIDE { |
||||
read_ops_.set_output_tag(tag); |
||||
read_ops_.RecvMessage(msg); |
||||
call_.PerformOps(&read_ops_); |
||||
} |
||||
|
||||
void Write(const W& msg, void* tag) GRPC_OVERRIDE { |
||||
write_ops_.set_output_tag(tag); |
||||
if (!ctx_->sent_initial_metadata_) { |
||||
write_ops_.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
} |
||||
// TODO(ctiller): don't assert
|
||||
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); |
||||
call_.PerformOps(&write_ops_); |
||||
} |
||||
|
||||
void Finish(const Status& status, void* tag) { |
||||
finish_ops_.set_output_tag(tag); |
||||
if (!ctx_->sent_initial_metadata_) { |
||||
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_); |
||||
ctx_->sent_initial_metadata_ = true; |
||||
} |
||||
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status); |
||||
call_.PerformOps(&finish_ops_); |
||||
} |
||||
|
||||
private: |
||||
friend class ::grpc::Server; |
||||
|
||||
void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; } |
||||
|
||||
Call call_; |
||||
ServerContext* ctx_; |
||||
CallOpSet<CallOpSendInitialMetadata> meta_ops_; |
||||
CallOpSet<CallOpRecvMessage<R>> read_ops_; |
||||
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_; |
||||
CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_; |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCXX_IMPL_CODEGEN_IMPL_ASYNC_STREAM_H
|
@ -0,0 +1,152 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCXX_IMPL_CODEGEN_IMPL_STATUS_CODE_ENUM_H |
||||
#define GRPCXX_IMPL_CODEGEN_IMPL_STATUS_CODE_ENUM_H |
||||
|
||||
namespace grpc { |
||||
|
||||
enum StatusCode { |
||||
/// Not an error; returned on success.
|
||||
OK = 0, |
||||
|
||||
/// The operation was cancelled (typically by the caller).
|
||||
CANCELLED = 1, |
||||
|
||||
/// Unknown error. An example of where this error may be returned is if a
|
||||
/// Status value received from another address space belongs to an error-space
|
||||
/// that is not known in this address space. Also errors raised by APIs that
|
||||
/// do not return enough error information may be converted to this error.
|
||||
UNKNOWN = 2, |
||||
|
||||
/// Client specified an invalid argument. Note that this differs from
|
||||
/// FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are
|
||||
/// problematic regardless of the state of the system (e.g., a malformed file
|
||||
/// name).
|
||||
INVALID_ARGUMENT = 3, |
||||
|
||||
/// Deadline expired before operation could complete. For operations that
|
||||
/// change the state of the system, this error may be returned even if the
|
||||
/// operation has completed successfully. For example, a successful response
|
||||
/// from a server could have been delayed long enough for the deadline to
|
||||
/// expire.
|
||||
DEADLINE_EXCEEDED = 4, |
||||
|
||||
/// Some requested entity (e.g., file or directory) was not found.
|
||||
NOT_FOUND = 5, |
||||
|
||||
/// Some entity that we attempted to create (e.g., file or directory) already
|
||||
/// exists.
|
||||
ALREADY_EXISTS = 6, |
||||
|
||||
/// The caller does not have permission to execute the specified operation.
|
||||
/// PERMISSION_DENIED must not be used for rejections caused by exhausting
|
||||
/// some resource (use RESOURCE_EXHAUSTED instead for those errors).
|
||||
/// PERMISSION_DENIED must not be used if the caller can not be identified
|
||||
/// (use UNAUTHENTICATED instead for those errors).
|
||||
PERMISSION_DENIED = 7, |
||||
|
||||
/// The request does not have valid authentication credentials for the
|
||||
/// operation.
|
||||
UNAUTHENTICATED = 16, |
||||
|
||||
/// Some resource has been exhausted, perhaps a per-user quota, or perhaps the
|
||||
/// entire file system is out of space.
|
||||
RESOURCE_EXHAUSTED = 8, |
||||
|
||||
/// Operation was rejected because the system is not in a state required for
|
||||
/// the operation's execution. For example, directory to be deleted may be
|
||||
/// non-empty, an rmdir operation is applied to a non-directory, etc.
|
||||
///
|
||||
/// A litmus test that may help a service implementor in deciding
|
||||
/// between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
|
||||
/// (a) Use UNAVAILABLE if the client can retry just the failing call.
|
||||
/// (b) Use ABORTED if the client should retry at a higher-level
|
||||
/// (e.g., restarting a read-modify-write sequence).
|
||||
/// (c) Use FAILED_PRECONDITION if the client should not retry until
|
||||
/// the system state has been explicitly fixed. E.g., if an "rmdir"
|
||||
/// fails because the directory is non-empty, FAILED_PRECONDITION
|
||||
/// should be returned since the client should not retry unless
|
||||
/// they have first fixed up the directory by deleting files from it.
|
||||
/// (d) Use FAILED_PRECONDITION if the client performs conditional
|
||||
/// REST Get/Update/Delete on a resource and the resource on the
|
||||
/// server does not match the condition. E.g., conflicting
|
||||
/// read-modify-write on the same resource.
|
||||
FAILED_PRECONDITION = 9, |
||||
|
||||
/// The operation was aborted, typically due to a concurrency issue like
|
||||
/// sequencer check failures, transaction aborts, etc.
|
||||
///
|
||||
/// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
|
||||
/// and UNAVAILABLE.
|
||||
ABORTED = 10, |
||||
|
||||
/// Operation was attempted past the valid range. E.g., seeking or reading
|
||||
/// past end of file.
|
||||
///
|
||||
/// Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed
|
||||
/// if the system state changes. For example, a 32-bit file system will
|
||||
/// generate INVALID_ARGUMENT if asked to read at an offset that is not in the
|
||||
/// range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from
|
||||
/// an offset past the current file size.
|
||||
///
|
||||
/// There is a fair bit of overlap between FAILED_PRECONDITION and
|
||||
/// OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error)
|
||||
/// when it applies so that callers who are iterating through a space can
|
||||
/// easily look for an OUT_OF_RANGE error to detect when they are done.
|
||||
OUT_OF_RANGE = 11, |
||||
|
||||
/// Operation is not implemented or not supported/enabled in this service.
|
||||
UNIMPLEMENTED = 12, |
||||
|
||||
/// Internal errors. Means some invariants expected by underlying System has
|
||||
/// been broken. If you see one of these errors, Something is very broken.
|
||||
INTERNAL = 13, |
||||
|
||||
/// The service is currently unavailable. This is a most likely a transient
|
||||
/// condition and may be corrected by retrying with a backoff.
|
||||
///
|
||||
/// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
|
||||
/// and UNAVAILABLE.
|
||||
UNAVAILABLE = 14, |
||||
|
||||
/// Unrecoverable data loss or corruption.
|
||||
DATA_LOSS = 15, |
||||
|
||||
/// Force users to include a default branch:
|
||||
DO_NOT_USE = -1 |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCXX_IMPL_CODEGEN_IMPL_STATUS_CODE_ENUM_H
|
@ -0,0 +1,72 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015-2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/census/grpc_plugin.h" |
||||
|
||||
#include <limits.h> |
||||
|
||||
#include <grpc/census.h> |
||||
|
||||
#include "src/core/census/grpc_filter.h" |
||||
#include "src/core/surface/channel_init.h" |
||||
#include "src/core/channel/channel_stack_builder.h" |
||||
|
||||
static bool maybe_add_census_filter(grpc_channel_stack_builder *builder, |
||||
void *arg_must_be_null) { |
||||
const grpc_channel_args *args = |
||||
grpc_channel_stack_builder_get_channel_arguments(builder); |
||||
if (grpc_channel_args_is_census_enabled(args)) { |
||||
return grpc_channel_stack_builder_prepend_filter( |
||||
builder, &grpc_client_census_filter, NULL, NULL); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
void census_grpc_plugin_init(void) { |
||||
/* Only initialize census if no one else has and some features are
|
||||
* available. */ |
||||
if (census_enabled() == CENSUS_FEATURE_NONE && |
||||
census_supported() != CENSUS_FEATURE_NONE) { |
||||
if (census_initialize(census_supported())) { /* enable all features. */ |
||||
gpr_log(GPR_ERROR, "Could not initialize census."); |
||||
} |
||||
} |
||||
grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, |
||||
maybe_add_census_filter, NULL); |
||||
grpc_channel_init_register_stage(GRPC_CLIENT_UCHANNEL, INT_MAX, |
||||
maybe_add_census_filter, NULL); |
||||
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, |
||||
maybe_add_census_filter, NULL); |
||||
} |
||||
|
||||
void census_grpc_plugin_destroy(void) { census_shutdown(); } |
@ -0,0 +1,40 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015-2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_CENSUS_GRPC_PLUGIN_H |
||||
#define GRPC_CORE_CENSUS_GRPC_PLUGIN_H |
||||
|
||||
void census_grpc_plugin_init(void); |
||||
void census_grpc_plugin_destroy(void); |
||||
|
||||
#endif /* GRPC_CORE_CENSUS_GRPC_PLUGIN_H */ |
@ -0,0 +1,259 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/channel/channel_stack_builder.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
int grpc_trace_channel_stack_builder = 0; |
||||
|
||||
typedef struct filter_node { |
||||
struct filter_node *next; |
||||
struct filter_node *prev; |
||||
const grpc_channel_filter *filter; |
||||
grpc_post_filter_create_init_func init; |
||||
void *init_arg; |
||||
} filter_node; |
||||
|
||||
struct grpc_channel_stack_builder { |
||||
// sentinel nodes for filters that have been added
|
||||
filter_node begin; |
||||
filter_node end; |
||||
// various set/get-able parameters
|
||||
const grpc_channel_args *args; |
||||
grpc_transport *transport; |
||||
const char *name; |
||||
}; |
||||
|
||||
struct grpc_channel_stack_builder_iterator { |
||||
grpc_channel_stack_builder *builder; |
||||
filter_node *node; |
||||
}; |
||||
|
||||
grpc_channel_stack_builder *grpc_channel_stack_builder_create(void) { |
||||
grpc_channel_stack_builder *b = gpr_malloc(sizeof(*b)); |
||||
memset(b, 0, sizeof(*b)); |
||||
|
||||
b->begin.filter = NULL; |
||||
b->end.filter = NULL; |
||||
b->begin.next = &b->end; |
||||
b->begin.prev = &b->end; |
||||
b->end.next = &b->begin; |
||||
b->end.prev = &b->begin; |
||||
|
||||
return b; |
||||
} |
||||
|
||||
static grpc_channel_stack_builder_iterator *create_iterator_at_filter_node( |
||||
grpc_channel_stack_builder *builder, filter_node *node) { |
||||
grpc_channel_stack_builder_iterator *it = gpr_malloc(sizeof(*it)); |
||||
it->builder = builder; |
||||
it->node = node; |
||||
return it; |
||||
} |
||||
|
||||
void grpc_channel_stack_builder_iterator_destroy( |
||||
grpc_channel_stack_builder_iterator *it) { |
||||
gpr_free(it); |
||||
} |
||||
|
||||
grpc_channel_stack_builder_iterator * |
||||
grpc_channel_stack_builder_create_iterator_at_first( |
||||
grpc_channel_stack_builder *builder) { |
||||
return create_iterator_at_filter_node(builder, &builder->begin); |
||||
} |
||||
|
||||
grpc_channel_stack_builder_iterator * |
||||
grpc_channel_stack_builder_create_iterator_at_last( |
||||
grpc_channel_stack_builder *builder) { |
||||
return create_iterator_at_filter_node(builder, &builder->end); |
||||
} |
||||
|
||||
bool grpc_channel_stack_builder_move_next( |
||||
grpc_channel_stack_builder_iterator *iterator) { |
||||
if (iterator->node == &iterator->builder->end) return false; |
||||
iterator->node = iterator->node->next; |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_channel_stack_builder_move_prev( |
||||
grpc_channel_stack_builder_iterator *iterator) { |
||||
if (iterator->node == &iterator->builder->begin) return false; |
||||
iterator->node = iterator->node->prev; |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_channel_stack_builder_move_prev( |
||||
grpc_channel_stack_builder_iterator *iterator); |
||||
|
||||
void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder, |
||||
const char *name) { |
||||
GPR_ASSERT(builder->name == NULL); |
||||
builder->name = name; |
||||
} |
||||
|
||||
void grpc_channel_stack_builder_set_channel_arguments( |
||||
grpc_channel_stack_builder *builder, const grpc_channel_args *args) { |
||||
GPR_ASSERT(builder->args == NULL); |
||||
builder->args = args; |
||||
} |
||||
|
||||
void grpc_channel_stack_builder_set_transport( |
||||
grpc_channel_stack_builder *builder, grpc_transport *transport) { |
||||
GPR_ASSERT(builder->transport == NULL); |
||||
builder->transport = transport; |
||||
} |
||||
|
||||
grpc_transport *grpc_channel_stack_builder_get_transport( |
||||
grpc_channel_stack_builder *builder) { |
||||
return builder->transport; |
||||
} |
||||
|
||||
const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments( |
||||
grpc_channel_stack_builder *builder) { |
||||
return builder->args; |
||||
} |
||||
|
||||
bool grpc_channel_stack_builder_append_filter( |
||||
grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, |
||||
grpc_post_filter_create_init_func post_init_func, void *user_data) { |
||||
grpc_channel_stack_builder_iterator *it = |
||||
grpc_channel_stack_builder_create_iterator_at_last(builder); |
||||
bool ok = grpc_channel_stack_builder_add_filter_before( |
||||
it, filter, post_init_func, user_data); |
||||
grpc_channel_stack_builder_iterator_destroy(it); |
||||
return ok; |
||||
} |
||||
|
||||
bool grpc_channel_stack_builder_prepend_filter( |
||||
grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, |
||||
grpc_post_filter_create_init_func post_init_func, void *user_data) { |
||||
grpc_channel_stack_builder_iterator *it = |
||||
grpc_channel_stack_builder_create_iterator_at_first(builder); |
||||
bool ok = grpc_channel_stack_builder_add_filter_after( |
||||
it, filter, post_init_func, user_data); |
||||
grpc_channel_stack_builder_iterator_destroy(it); |
||||
return ok; |
||||
} |
||||
|
||||
static void add_after(filter_node *before, const grpc_channel_filter *filter, |
||||
grpc_post_filter_create_init_func post_init_func, |
||||
void *user_data) { |
||||
filter_node *new = gpr_malloc(sizeof(*new)); |
||||
new->next = before->next; |
||||
new->prev = before; |
||||
new->next->prev = new->prev->next = new; |
||||
new->filter = filter; |
||||
new->init = post_init_func; |
||||
new->init_arg = user_data; |
||||
} |
||||
|
||||
bool grpc_channel_stack_builder_add_filter_before( |
||||
grpc_channel_stack_builder_iterator *iterator, |
||||
const grpc_channel_filter *filter, |
||||
grpc_post_filter_create_init_func post_init_func, void *user_data) { |
||||
if (iterator->node == &iterator->builder->begin) return false; |
||||
add_after(iterator->node->prev, filter, post_init_func, user_data); |
||||
return true; |
||||
} |
||||
|
||||
bool grpc_channel_stack_builder_add_filter_after( |
||||
grpc_channel_stack_builder_iterator *iterator, |
||||
const grpc_channel_filter *filter, |
||||
grpc_post_filter_create_init_func post_init_func, void *user_data) { |
||||
if (iterator->node == &iterator->builder->end) return false; |
||||
add_after(iterator->node, filter, post_init_func, user_data); |
||||
return true; |
||||
} |
||||
|
||||
void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder) { |
||||
filter_node *p = builder->begin.next; |
||||
while (p != &builder->end) { |
||||
filter_node *next = p->next; |
||||
gpr_free(p); |
||||
p = next; |
||||
} |
||||
gpr_free(builder); |
||||
} |
||||
|
||||
void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx, |
||||
grpc_channel_stack_builder *builder, |
||||
size_t prefix_bytes, int initial_refs, |
||||
grpc_iomgr_cb_func destroy, |
||||
void *destroy_arg) { |
||||
// count the number of filters
|
||||
size_t num_filters = 0; |
||||
for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { |
||||
gpr_log(GPR_DEBUG, "%d: %s", num_filters, p->filter->name); |
||||
num_filters++; |
||||
} |
||||
|
||||
// create an array of filters
|
||||
const grpc_channel_filter **filters = |
||||
gpr_malloc(sizeof(*filters) * num_filters); |
||||
size_t i = 0; |
||||
for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { |
||||
filters[i++] = p->filter; |
||||
} |
||||
|
||||
// calculate the size of the channel stack
|
||||
size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters); |
||||
|
||||
// allocate memory, with prefix_bytes followed by channel_stack_size
|
||||
char *result = gpr_malloc(prefix_bytes + channel_stack_size); |
||||
// fetch a pointer to the channel stack
|
||||
grpc_channel_stack *channel_stack = |
||||
(grpc_channel_stack *)(result + prefix_bytes); |
||||
// and initialize it
|
||||
grpc_channel_stack_init(exec_ctx, initial_refs, destroy, |
||||
destroy_arg == NULL ? result : destroy_arg, filters, |
||||
num_filters, builder->args, builder->name, |
||||
channel_stack); |
||||
|
||||
// run post-initialization functions
|
||||
i = 0; |
||||
for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { |
||||
if (p->init != NULL) { |
||||
p->init(channel_stack, grpc_channel_stack_element(channel_stack, i), |
||||
p->init_arg); |
||||
} |
||||
i++; |
||||
} |
||||
|
||||
grpc_channel_stack_builder_destroy(builder); |
||||
gpr_free((grpc_channel_filter **)filters); |
||||
|
||||
return result; |
||||
} |
@ -0,0 +1,155 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H |
||||
#define GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "src/core/channel/channel_args.h" |
||||
#include "src/core/channel/channel_stack.h" |
||||
|
||||
/// grpc_channel_stack_builder offers a programmatic interface to selected
|
||||
/// and order channel filters
|
||||
typedef struct grpc_channel_stack_builder grpc_channel_stack_builder; |
||||
typedef struct grpc_channel_stack_builder_iterator |
||||
grpc_channel_stack_builder_iterator; |
||||
|
||||
/// Create a new channel stack builder
|
||||
grpc_channel_stack_builder *grpc_channel_stack_builder_create(void); |
||||
|
||||
/// Assign a name to the channel stack: \a name must be statically allocated
|
||||
void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder, |
||||
const char *name); |
||||
|
||||
/// Attach \a transport to the builder (does not take ownership)
|
||||
void grpc_channel_stack_builder_set_transport( |
||||
grpc_channel_stack_builder *builder, grpc_transport *transport); |
||||
|
||||
/// Fetch attached transport
|
||||
grpc_transport *grpc_channel_stack_builder_get_transport( |
||||
grpc_channel_stack_builder *builder); |
||||
|
||||
/// Set channel arguments: \a args must continue to exist until after
|
||||
/// grpc_channel_stack_builder_finish returns
|
||||
void grpc_channel_stack_builder_set_channel_arguments( |
||||
grpc_channel_stack_builder *builder, const grpc_channel_args *args); |
||||
|
||||
/// Return a borrowed pointer to the channel arguments
|
||||
const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments( |
||||
grpc_channel_stack_builder *builder); |
||||
|
||||
/// Begin iterating over already defined filters in the builder at the beginning
|
||||
grpc_channel_stack_builder_iterator * |
||||
grpc_channel_stack_builder_create_iterator_at_first( |
||||
grpc_channel_stack_builder *builder); |
||||
|
||||
/// Begin iterating over already defined filters in the builder at the end
|
||||
grpc_channel_stack_builder_iterator * |
||||
grpc_channel_stack_builder_create_iterator_at_last( |
||||
grpc_channel_stack_builder *builder); |
||||
|
||||
/// Is an iterator at the first element?
|
||||
bool grpc_channel_stack_builder_iterator_is_first( |
||||
grpc_channel_stack_builder_iterator *iterator); |
||||
|
||||
/// Is an iterator at the end?
|
||||
bool grpc_channel_stack_builder_iterator_is_end( |
||||
grpc_channel_stack_builder_iterator *iterator); |
||||
|
||||
/// Move an iterator to the next item
|
||||
bool grpc_channel_stack_builder_move_next( |
||||
grpc_channel_stack_builder_iterator *iterator); |
||||
|
||||
/// Move an iterator to the previous item
|
||||
bool grpc_channel_stack_builder_move_prev( |
||||
grpc_channel_stack_builder_iterator *iterator); |
||||
|
||||
typedef void (*grpc_post_filter_create_init_func)( |
||||
grpc_channel_stack *channel_stack, grpc_channel_element *elem, void *arg); |
||||
|
||||
/// Add \a filter to the stack, after \a iterator.
|
||||
/// Call \a post_init_func(..., \a user_data) once the channel stack is
|
||||
/// created.
|
||||
bool grpc_channel_stack_builder_add_filter_after( |
||||
grpc_channel_stack_builder_iterator *iterator, |
||||
const grpc_channel_filter *filter, |
||||
grpc_post_filter_create_init_func post_init_func, |
||||
void *user_data) GRPC_MUST_USE_RESULT; |
||||
|
||||
/// Add \a filter to the stack, before \a iterator.
|
||||
/// Call \a post_init_func(..., \a user_data) once the channel stack is
|
||||
/// created.
|
||||
bool grpc_channel_stack_builder_add_filter_before( |
||||
grpc_channel_stack_builder_iterator *iterator, |
||||
const grpc_channel_filter *filter, |
||||
grpc_post_filter_create_init_func post_init_func, |
||||
void *user_data) GRPC_MUST_USE_RESULT; |
||||
|
||||
/// Add \a filter to the beginning of the filter list.
|
||||
/// Call \a post_init_func(..., \a user_data) once the channel stack is
|
||||
/// created.
|
||||
bool grpc_channel_stack_builder_prepend_filter( |
||||
grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, |
||||
grpc_post_filter_create_init_func post_init_func, |
||||
void *user_data) GRPC_MUST_USE_RESULT; |
||||
|
||||
/// Add \a filter to the end of the filter list.
|
||||
/// Call \a post_init_func(..., \a user_data) once the channel stack is
|
||||
/// created.
|
||||
bool grpc_channel_stack_builder_append_filter( |
||||
grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, |
||||
grpc_post_filter_create_init_func post_init_func, |
||||
void *user_data) GRPC_MUST_USE_RESULT; |
||||
|
||||
/// Terminate iteration and destroy \a iterator
|
||||
void grpc_channel_stack_builder_iterator_destroy( |
||||
grpc_channel_stack_builder_iterator *iterator); |
||||
|
||||
/// Destroy the builder, return the freshly minted channel stack
|
||||
/// Allocates \a prefix_bytes bytes before the channel stack
|
||||
/// Returns the base pointer of the allocated block
|
||||
/// \a initial_refs, \a destroy, \a destroy_arg are as per
|
||||
/// grpc_channel_stack_init
|
||||
void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx, |
||||
grpc_channel_stack_builder *builder, |
||||
size_t prefix_bytes, int initial_refs, |
||||
grpc_iomgr_cb_func destroy, |
||||
void *destroy_arg); |
||||
|
||||
/// Destroy the builder without creating a channel stack
|
||||
void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder); |
||||
|
||||
extern int grpc_trace_channel_stack_builder; |
||||
|
||||
#endif /* GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue