adding pods method of package managing

This commit is contained in:
talksik
2021-12-13 12:34:20 -08:00
parent dad674aca7
commit 705203d7bd
5871 changed files with 1259393 additions and 3 deletions
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+85
View File
@@ -0,0 +1,85 @@
gRPC - An RPC library and framework
===================================
gRPC is a modern, open source, high-performance remote procedure call (RPC) framework that can run anywhere. gRPC enables client and server applications to communicate transparently, and simplifies the building of connected systems.
<table>
<tr>
<td><b>Homepage:</b></td>
<td><a href="https://grpc.io/">grpc.io</a></td>
</tr>
<tr>
<td><b>Mailing List:</b></td>
<td><a href="https://groups.google.com/forum/#!forum/grpc-io">grpc-io@googlegroups.com</a></td>
</tr>
</table>
[![Join the chat at https://gitter.im/grpc/grpc](https://badges.gitter.im/grpc/grpc.svg)](https://gitter.im/grpc/grpc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# To start using gRPC
To maximize usability, gRPC supports the standard method for adding dependencies to a user's chosen language (if there is one).
In most languages, the gRPC runtime comes as a package available in a user's language package manager.
For instructions on how to use the language-specific gRPC runtime for a project, please refer to these documents
* [C++](src/cpp): follow the instructions under the `src/cpp` directory
* [C#](src/csharp): NuGet package `Grpc`
* [Dart](https://github.com/grpc/grpc-dart): pub package `grpc`
* [Go](https://github.com/grpc/grpc-go): `go get google.golang.org/grpc`
* [Java](https://github.com/grpc/grpc-java): Use JARs from Maven Central Repository
* [Node](https://github.com/grpc/grpc-node): `npm install grpc`
* [Objective-C](src/objective-c): Add `gRPC-ProtoRPC` dependency to podspec
* [PHP](src/php): `pecl install grpc`
* [Python](src/python/grpcio): `pip install grpcio`
* [Ruby](src/ruby): `gem install grpc`
* [WebJS](https://github.com/grpc/grpc-web): follow the grpc-web instructions
Per-language quickstart guides and tutorials can be found in the [documentation section on the grpc.io website](https://grpc.io/docs/). Code examples are available in the [examples](examples) directory.
Precompiled bleeding-edge package builds of gRPC `master` branch's `HEAD` are uploaded daily to [packages.grpc.io](https://packages.grpc.io).
# To start developing gRPC
Contributions are welcome!
Please read [How to contribute](CONTRIBUTING.md) which will guide you through the entire workflow of how to build the source code, how to run the tests, and how to contribute changes to
the gRPC codebase.
The "How to contribute" document also contains info on how the contribution process works and contains best practices for creating contributions.
# Troubleshooting
Sometimes things go wrong. Please check out the [Troubleshooting guide](TROUBLESHOOTING.md) if you are experiencing issues with gRPC.
# Performance
See the [Performance dashboard](https://performance-dot-grpc-testing.appspot.com/explore?dashboard=5652536396611584) for performance numbers of master branch daily builds.
# Concepts
See [gRPC Concepts](CONCEPTS.md)
# About This Repository
This repository contains source code for gRPC libraries implemented in multiple languages written on top of a shared C core library [src/core](src/core).
Libraries in different languages may be in various states of development. We are seeking contributions for all of these libraries:
| Language | Source |
|-------------------------|-------------------------------------|
| Shared C [core library] | [src/core](src/core) |
| C++ | [src/cpp](src/cpp) |
| Ruby | [src/ruby](src/ruby) |
| Python | [src/python](src/python) |
| PHP | [src/php](src/php) |
| C# (core library based) | [src/csharp](src/csharp) |
| Objective-C | [src/objective-c](src/objective-c) |
| Language | Source repo |
|-------------------------|------------------------------------------------------|
| Java | [grpc-java](https://github.com/grpc/grpc-java) |
| Go | [grpc-go](https://github.com/grpc/grpc-go) |
| NodeJS | [grpc-node](https://github.com/grpc/grpc-node) |
| WebJS | [grpc-web](https://github.com/grpc/grpc-web) |
| Dart | [grpc-dart](https://github.com/grpc/grpc-dart) |
| .NET (pure C# impl.) | [grpc-dotnet](https://github.com/grpc/grpc-dotnet) |
+4644
View File
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
/*
*
* Copyright 2018 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 GRPCPP_ALARM_H
#define GRPCPP_ALARM_H
#include <grpcpp/alarm_impl.h>
namespace grpc {
typedef ::grpc_impl::Alarm Alarm;
}
#endif // GRPCPP_ALARM_H
+125
View File
@@ -0,0 +1,125 @@
/*
*
* Copyright 2015 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.
*
*/
/// An Alarm posts the user-provided tag to its associated completion queue or
/// invokes the user-provided function on expiry or cancellation.
#ifndef GRPCPP_ALARM_IMPL_H
#define GRPCPP_ALARM_IMPL_H
#include <functional>
#include <grpc/grpc.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/time.h>
#include <grpcpp/impl/grpc_library.h>
namespace grpc_impl {
class Alarm : private ::grpc::GrpcLibraryCodegen {
public:
/// Create an unset completion queue alarm
Alarm();
/// Destroy the given completion queue alarm, cancelling it in the process.
~Alarm();
/// DEPRECATED: Create and set a completion queue alarm instance associated to
/// \a cq.
/// This form is deprecated because it is inherently racy.
/// \internal We rely on the presence of \a cq for grpc initialization. If \a
/// cq were ever to be removed, a reference to a static
/// internal::GrpcLibraryInitializer instance would need to be introduced
/// here. \endinternal.
template <typename T>
Alarm(::grpc::CompletionQueue* cq, const T& deadline, void* tag) : Alarm() {
SetInternal(cq, ::grpc::TimePoint<T>(deadline).raw_time(), tag);
}
/// Trigger an alarm instance on completion queue \a cq at the specified time.
/// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel),
/// an event with tag \a tag will be added to \a cq. If the alarm expired, the
/// event's success bit will be true, false otherwise (ie, upon cancellation).
template <typename T>
void Set(::grpc::CompletionQueue* cq, const T& deadline, void* tag) {
SetInternal(cq, ::grpc::TimePoint<T>(deadline).raw_time(), tag);
}
/// Alarms aren't copyable.
Alarm(const Alarm&) = delete;
Alarm& operator=(const Alarm&) = delete;
/// Alarms are movable.
Alarm(Alarm&& rhs) : alarm_(rhs.alarm_) { rhs.alarm_ = nullptr; }
Alarm& operator=(Alarm&& rhs) {
alarm_ = rhs.alarm_;
rhs.alarm_ = nullptr;
return *this;
}
/// Cancel a completion queue alarm. Calling this function over an alarm that
/// has already fired has no effect.
void Cancel();
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
/// Set an alarm to invoke callback \a f. The argument to the callback
/// states whether the alarm expired at \a deadline (true) or was cancelled
/// (false)
template <typename T>
void Set(const T& deadline, std::function<void(bool)> f) {
SetInternal(::grpc::TimePoint<T>(deadline).raw_time(), std::move(f));
}
#endif
/// NOTE: class experimental_type is not part of the public API of this class
/// TODO(vjpai): Move these contents to the public API of Alarm when
/// they are no longer experimental
class experimental_type {
public:
explicit experimental_type(Alarm* alarm) : alarm_(alarm) {}
/// Set an alarm to invoke callback \a f. The argument to the callback
/// states whether the alarm expired at \a deadline (true) or was cancelled
/// (false)
template <typename T>
void Set(const T& deadline, std::function<void(bool)> f) {
alarm_->SetInternal(::grpc::TimePoint<T>(deadline).raw_time(),
std::move(f));
}
private:
Alarm* alarm_;
};
/// NOTE: The function experimental() is not stable public API. It is a view
/// to the experimental components of this class. It may be changed or removed
/// at any time.
experimental_type experimental() { return experimental_type(this); }
private:
void SetInternal(::grpc::CompletionQueue* cq, gpr_timespec deadline,
void* tag);
void SetInternal(gpr_timespec deadline, std::function<void(bool)> f);
::grpc::internal::CompletionQueueTag* alarm_;
};
} // namespace grpc_impl
#endif // GRPCPP_ALARM_IMPL_H
+37
View File
@@ -0,0 +1,37 @@
/*
*
* Copyright 2015 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 GRPCPP_CHANNEL_H
#define GRPCPP_CHANNEL_H
#include <grpcpp/channel_impl.h>
namespace grpc {
typedef ::grpc_impl::Channel Channel;
namespace experimental {
/// Resets the channel's connection backoff.
/// TODO(roth): Once we see whether this proves useful, either create a gRFC
/// and change this to be a method of the Channel class, or remove it.
void ChannelResetConnectionBackoff(Channel* channel);
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_CHANNEL_H
+126
View File
@@ -0,0 +1,126 @@
/*
*
* Copyright 2015 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 GRPCPP_CHANNEL_IMPL_H
#define GRPCPP_CHANNEL_IMPL_H
#include <memory>
#include <grpc/grpc.h>
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/completion_queue_impl.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/sync.h>
struct grpc_channel;
namespace grpc {
std::shared_ptr<::grpc_impl::Channel> CreateChannelInternal(
const grpc::string& host, grpc_channel* c_channel,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
} // namespace grpc
namespace grpc_impl {
namespace experimental {
/// Resets the channel's connection backoff.
/// TODO(roth): Once we see whether this proves useful, either create a gRFC
/// and change this to be a method of the Channel class, or remove it.
void ChannelResetConnectionBackoff(Channel* channel);
} // namespace experimental
/// Channels represent a connection to an endpoint. Created by \a CreateChannel.
class Channel final : public ::grpc::ChannelInterface,
public ::grpc::internal::CallHook,
public std::enable_shared_from_this<Channel>,
private ::grpc::GrpcLibraryCodegen {
public:
~Channel();
/// Get the current channel state. If the channel is in IDLE and
/// \a try_to_connect is set to true, try to connect.
grpc_connectivity_state GetState(bool try_to_connect) override;
/// Returns the LB policy name, or the empty string if not yet available.
grpc::string GetLoadBalancingPolicyName() const;
/// Returns the service config in JSON form, or the empty string if
/// not available.
grpc::string GetServiceConfigJSON() const;
private:
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
friend void experimental::ChannelResetConnectionBackoff(Channel* channel);
friend std::shared_ptr<Channel> grpc::CreateChannelInternal(
const grpc::string& host, grpc_channel* c_channel,
std::vector<std::unique_ptr<
::grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
friend class ::grpc::internal::InterceptedChannel;
Channel(const grpc::string& host, grpc_channel* c_channel,
std::vector<std::unique_ptr<
::grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
::grpc::internal::Call CreateCall(const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
::grpc_impl::CompletionQueue* cq) override;
void PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops,
::grpc::internal::Call* call) override;
void* RegisterMethod(const char* method) override;
void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline,
::grpc_impl::CompletionQueue* cq,
void* tag) override;
bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) override;
::grpc_impl::CompletionQueue* CallbackCQ() override;
::grpc::internal::Call CreateCallInternal(
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, ::grpc_impl::CompletionQueue* cq,
size_t interceptor_pos) override;
const grpc::string host_;
grpc_channel* const c_channel_; // owned
// mu_ protects callback_cq_ (the per-channel callbackable completion queue)
grpc::internal::Mutex mu_;
// callback_cq_ references the callbackable completion queue associated
// with this channel (if any). It is set on the first call to CallbackCQ().
// It is _not owned_ by the channel; ownership belongs with its internal
// shutdown callback tag (invoked when the CQ is fully shutdown).
::grpc_impl::CompletionQueue* callback_cq_ = nullptr;
std::vector<
std::unique_ptr<::grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators_;
};
} // namespace grpc_impl
#endif // GRPCPP_CHANNEL_IMPL_H
+39
View File
@@ -0,0 +1,39 @@
/*
*
* Copyright 2015 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.
*
*/
/// A ClientContext allows the person implementing a service client to:
///
/// - Add custom metadata key-value pairs that will propagated to the server
/// side.
/// - Control call settings such as compression and authentication.
/// - Initial and trailing metadata coming from the server.
/// - Get performance metrics (ie, census).
///
/// Context settings are only relevant to the call they are invoked with, that
/// is to say, they aren't sticky. Some of these settings, such as the
/// compression options, can be made persistent at channel construction time
/// (see \a grpc::CreateCustomChannel).
///
/// \warning ClientContext instances should \em not be reused across rpcs.
#ifndef GRPCPP_CLIENT_CONTEXT_H
#define GRPCPP_CLIENT_CONTEXT_H
#include <grpcpp/impl/codegen/client_context.h>
#endif // GRPCPP_CLIENT_CONTEXT_H
+24
View File
@@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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 GRPCPP_COMPLETION_QUEUE_H
#define GRPCPP_COMPLETION_QUEUE_H
#include <grpcpp/impl/codegen/completion_queue.h>
#endif // GRPCPP_COMPLETION_QUEUE_H
+24
View File
@@ -0,0 +1,24 @@
/*
*
* Copyright 2019 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 GRPCPP_COMPLETION_QUEUE_IMPL_H
#define GRPCPP_COMPLETION_QUEUE_IMPL_H
#include <grpcpp/impl/codegen/completion_queue_impl.h>
#endif // GRPCPP_COMPLETION_QUEUE_IMPL_H
+57
View File
@@ -0,0 +1,57 @@
/*
*
* Copyright 2019 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 GRPCPP_CREATE_CHANNEL_H
#define GRPCPP_CREATE_CHANNEL_H
#include <grpcpp/create_channel_impl.h>
#include <grpcpp/support/channel_arguments.h>
namespace grpc {
static inline std::shared_ptr<::grpc::Channel> CreateChannel(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds) {
return ::grpc_impl::CreateChannelImpl(target, creds);
}
static inline std::shared_ptr<::grpc::Channel> CreateCustomChannel(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args) {
return ::grpc_impl::CreateCustomChannelImpl(target, creds, args);
}
namespace experimental {
static inline std::shared_ptr<::grpc::Channel>
CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
return ::grpc_impl::experimental::CreateCustomChannelWithInterceptors(
target, creds, args, std::move(interceptor_creators));
}
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_CREATE_CHANNEL_H
+78
View File
@@ -0,0 +1,78 @@
/*
*
* Copyright 2015 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 GRPCPP_CREATE_CHANNEL_IMPL_H
#define GRPCPP_CREATE_CHANNEL_IMPL_H
#include <memory>
#include <grpcpp/channel.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/security/credentials.h>
#include <grpcpp/support/channel_arguments.h>
#include <grpcpp/support/config.h>
namespace grpc_impl {
/// Create a new \a Channel pointing to \a target.
///
/// \param target The URI of the endpoint to connect to.
/// \param creds Credentials to use for the created channel. If it does not
/// hold an object or is invalid, a lame channel (one on which all operations
/// fail) is returned.
std::shared_ptr<::grpc::Channel> CreateChannelImpl(
const grpc::string& target,
const std::shared_ptr<::grpc::ChannelCredentials>& creds);
/// Create a new \em custom \a Channel pointing to \a target.
///
/// \warning For advanced use and testing ONLY. Override default channel
/// arguments only if necessary.
///
/// \param target The URI of the endpoint to connect to.
/// \param creds Credentials to use for the created channel. If it does not
/// hold an object or is invalid, a lame channel (one on which all operations
/// fail) is returned.
/// \param args Options for channel creation.
std::shared_ptr<::grpc::Channel> CreateCustomChannelImpl(
const grpc::string& target,
const std::shared_ptr<::grpc::ChannelCredentials>& creds,
const ::grpc::ChannelArguments& args);
namespace experimental {
/// Create a new \em custom \a Channel pointing to \a target with \a
/// interceptors being invoked per call.
///
/// \warning For advanced use and testing ONLY. Override default channel
/// arguments only if necessary.
///
/// \param target The URI of the endpoint to connect to.
/// \param creds Credentials to use for the created channel. If it does not
/// hold an object or is invalid, a lame channel (one on which all operations
/// fail) is returned.
/// \param args Options for channel creation.
std::shared_ptr<::grpc::Channel> CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<grpc::ChannelCredentials>& creds,
const ::grpc::ChannelArguments& args,
std::vector<
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
} // namespace experimental
} // namespace grpc_impl
#endif // GRPCPP_CREATE_CHANNEL_IMPL_H
+57
View File
@@ -0,0 +1,57 @@
/*
*
* Copyright 2019 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 GRPCPP_CREATE_CHANNEL_POSIX_H
#define GRPCPP_CREATE_CHANNEL_POSIX_H
#include <grpcpp/create_channel_posix_impl.h>
namespace grpc {
#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
static inline std::shared_ptr<Channel> CreateInsecureChannelFromFd(
const grpc::string& target, int fd) {
return ::grpc_impl::CreateInsecureChannelFromFd(target, fd);
}
static inline std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd(
const grpc::string& target, int fd, const ChannelArguments& args) {
return ::grpc_impl::CreateCustomInsecureChannelFromFd(target, fd, args);
}
namespace experimental {
static inline std::shared_ptr<Channel>
CreateCustomInsecureChannelWithInterceptorsFromFd(
const grpc::string& target, int fd, const ChannelArguments& args,
std::unique_ptr<std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
interceptor_creators) {
return ::grpc_impl::experimental::
CreateCustomInsecureChannelWithInterceptorsFromFd(
target, fd, args, std::move(interceptor_creators));
}
} // namespace experimental
#endif // GPR_SUPPORT_CHANNELS_FROM_FD
} // namespace grpc
#endif // GRPCPP_CREATE_CHANNEL_POSIX_H
+70
View File
@@ -0,0 +1,70 @@
/*
*
* Copyright 2016 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 GRPCPP_CREATE_CHANNEL_POSIX_IMPL_H
#define GRPCPP_CREATE_CHANNEL_POSIX_IMPL_H
#include <memory>
#include <grpc/support/port_platform.h>
#include <grpcpp/channel.h>
#include <grpcpp/support/channel_arguments.h>
namespace grpc_impl {
#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
/// Create a new \a Channel communicating over the given file descriptor.
///
/// \param target The name of the target.
/// \param fd The file descriptor representing a socket.
std::shared_ptr<grpc::Channel> CreateInsecureChannelFromFd(
const grpc::string& target, int fd);
/// Create a new \a Channel communicating over given file descriptor with custom
/// channel arguments.
///
/// \param target The name of the target.
/// \param fd The file descriptor representing a socket.
/// \param args Options for channel creation.
std::shared_ptr<grpc::Channel> CreateCustomInsecureChannelFromFd(
const grpc::string& target, int fd, const grpc::ChannelArguments& args);
namespace experimental {
/// Create a new \a Channel communicating over given file descriptor with custom
/// channel arguments.
///
/// \param target The name of the target.
/// \param fd The file descriptor representing a socket.
/// \param args Options for channel creation.
/// \param interceptor_creators Vector of interceptor factory objects.
std::shared_ptr<grpc::Channel>
CreateCustomInsecureChannelWithInterceptorsFromFd(
const grpc::string& target, int fd, const grpc::ChannelArguments& args,
std::unique_ptr<std::vector<
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>>
interceptor_creators);
} // namespace experimental
#endif // GPR_SUPPORT_CHANNELS_FROM_FD
} // namespace grpc_impl
#endif // GRPCPP_CREATE_CHANNEL_POSIX_IMPL_H
@@ -0,0 +1,47 @@
/*
*
* Copyright 2016 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 GRPCPP_EXT_HEALTH_CHECK_SERVICE_SERVER_BUILDER_OPTION_H
#define GRPCPP_EXT_HEALTH_CHECK_SERVICE_SERVER_BUILDER_OPTION_H
#include <memory>
#include <grpcpp/health_check_service_interface.h>
#include <grpcpp/impl/server_builder_option.h>
#include <grpcpp/support/config.h>
namespace grpc {
class HealthCheckServiceServerBuilderOption : public ServerBuilderOption {
public:
/// The ownership of \a hc will be taken and transferred to the grpc server.
/// To explicitly disable default service, pass in a nullptr.
explicit HealthCheckServiceServerBuilderOption(
std::unique_ptr<HealthCheckServiceInterface> hc);
~HealthCheckServiceServerBuilderOption() override {}
void UpdateArguments(ChannelArguments* args) override;
void UpdatePlugins(
std::vector<std::unique_ptr<ServerBuilderPlugin>>* plugins) override;
private:
std::unique_ptr<HealthCheckServiceInterface> hc_;
};
} // namespace grpc
#endif // GRPCPP_EXT_HEALTH_CHECK_SERVICE_SERVER_BUILDER_OPTION_H
@@ -0,0 +1,24 @@
/*
*
* Copyright 2018 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 GRPCPP_GENERIC_ASYNC_GENERIC_SERVICE_H
#define GRPCPP_GENERIC_ASYNC_GENERIC_SERVICE_H
#include <grpcpp/impl/codegen/async_generic_service.h>
#endif // GRPCPP_GENERIC_ASYNC_GENERIC_SERVICE_H
+30
View File
@@ -0,0 +1,30 @@
/*
*
* Copyright 2015 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 GRPCPP_GENERIC_GENERIC_STUB_H
#define GRPCPP_GENERIC_GENERIC_STUB_H
#include <grpcpp/generic/generic_stub_impl.h>
namespace grpc {
typedef ::grpc_impl::GenericStub GenericStub;
} // namespace grpc
#endif // GRPCPP_GENERIC_GENERIC_STUB_H
+216
View File
@@ -0,0 +1,216 @@
/*
*
* Copyright 2015 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 GRPCPP_GENERIC_GENERIC_STUB_IMPL_H
#define GRPCPP_GENERIC_GENERIC_STUB_IMPL_H
#include <functional>
#include <grpcpp/client_context.h>
#include <grpcpp/impl/rpc_method.h>
#include <grpcpp/support/async_stream_impl.h>
#include <grpcpp/support/async_unary_call_impl.h>
#include <grpcpp/support/byte_buffer.h>
#include <grpcpp/support/client_callback_impl.h>
#include <grpcpp/support/status.h>
namespace grpc {
typedef ::grpc_impl::ClientAsyncReaderWriter<ByteBuffer, ByteBuffer>
GenericClientAsyncReaderWriter;
typedef ::grpc_impl::ClientAsyncResponseReader<ByteBuffer>
GenericClientAsyncResponseReader;
} // namespace grpc
namespace grpc_impl {
class CompletionQueue;
/// Generic stubs provide a type-unaware interface to call gRPC methods
/// by name. In practice, the Request and Response types should be basic
/// types like grpc::ByteBuffer or proto::MessageLite (the base protobuf).
template <class RequestType, class ResponseType>
class TemplatedGenericStub final {
public:
explicit TemplatedGenericStub(std::shared_ptr<grpc::ChannelInterface> channel)
: channel_(channel) {}
/// Setup a call to a named method \a method using \a context, but don't
/// start it. Let it be started explicitly with StartCall and a tag.
/// The return value only indicates whether or not registration of the call
/// succeeded (i.e. the call won't proceed if the return value is nullptr).
std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>
PrepareCall(ClientContext* context, const grpc::string& method,
CompletionQueue* cq) {
return CallInternal(channel_.get(), context, method, cq, false, nullptr);
}
/// Setup a unary call to a named method \a method using \a context, and don't
/// start it. Let it be started explicitly with StartCall.
/// The return value only indicates whether or not registration of the call
/// succeeded (i.e. the call won't proceed if the return value is nullptr).
std::unique_ptr<ClientAsyncResponseReader<ResponseType>> PrepareUnaryCall(
ClientContext* context, const grpc::string& method,
const RequestType& request, CompletionQueue* cq) {
return std::unique_ptr<ClientAsyncResponseReader<ResponseType>>(
internal::ClientAsyncResponseReaderFactory<ResponseType>::Create(
channel_.get(), cq,
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, false));
}
/// DEPRECATED for multi-threaded use
/// Begin a call to a named method \a method using \a context.
/// A tag \a tag will be delivered to \a cq when the call has been started
/// (i.e, initial metadata has been sent).
/// The return value only indicates whether or not registration of the call
/// succeeded (i.e. the call won't proceed if the return value is nullptr).
std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> Call(
ClientContext* context, const grpc::string& method, CompletionQueue* cq,
void* tag) {
return CallInternal(channel_.get(), context, method, cq, true, tag);
}
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
/// Setup and start a unary call to a named method \a method using
/// \a context and specifying the \a request and \a response buffers.
void UnaryCall(ClientContext* context, const grpc::string& method,
const RequestType* request, ResponseType* response,
std::function<void(grpc::Status)> on_completion) {
UnaryCallInternal(context, method, request, response,
std::move(on_completion));
}
/// Setup a unary call to a named method \a method using
/// \a context and specifying the \a request and \a response buffers.
/// Like any other reactor-based RPC, it will not be activated until
/// StartCall is invoked on its reactor.
void PrepareUnaryCall(ClientContext* context, const grpc::string& method,
const RequestType* request, ResponseType* response,
ClientUnaryReactor* reactor) {
PrepareUnaryCallInternal(context, method, request, response, reactor);
}
/// Setup a call to a named method \a method using \a context and tied to
/// \a reactor . Like any other bidi streaming RPC, it will not be activated
/// until StartCall is invoked on its reactor.
void PrepareBidiStreamingCall(
ClientContext* context, const grpc::string& method,
ClientBidiReactor<RequestType, ResponseType>* reactor) {
PrepareBidiStreamingCallInternal(context, method, reactor);
}
#endif
/// NOTE: class experimental_type is not part of the public API of this class
/// TODO(vjpai): Move these contents to the public API of GenericStub when
/// they are no longer experimental
class experimental_type {
public:
explicit experimental_type(TemplatedGenericStub* stub) : stub_(stub) {}
/// Setup and start a unary call to a named method \a method using
/// \a context and specifying the \a request and \a response buffers.
void UnaryCall(ClientContext* context, const grpc::string& method,
const RequestType* request, ResponseType* response,
std::function<void(grpc::Status)> on_completion) {
stub_->UnaryCallInternal(context, method, request, response,
std::move(on_completion));
}
/// Setup a unary call to a named method \a method using
/// \a context and specifying the \a request and \a response buffers.
/// Like any other reactor-based RPC, it will not be activated until
/// StartCall is invoked on its reactor.
void PrepareUnaryCall(ClientContext* context, const grpc::string& method,
const RequestType* request, ResponseType* response,
ClientUnaryReactor* reactor) {
stub_->PrepareUnaryCallInternal(context, method, request, response,
reactor);
}
/// Setup a call to a named method \a method using \a context and tied to
/// \a reactor . Like any other bidi streaming RPC, it will not be activated
/// until StartCall is invoked on its reactor.
void PrepareBidiStreamingCall(
ClientContext* context, const grpc::string& method,
ClientBidiReactor<RequestType, ResponseType>* reactor) {
stub_->PrepareBidiStreamingCallInternal(context, method, reactor);
}
private:
TemplatedGenericStub* stub_;
};
/// NOTE: The function experimental() is not stable public API. It is a view
/// to the experimental components of this class. It may be changed or removed
/// at any time.
experimental_type experimental() { return experimental_type(this); }
private:
std::shared_ptr<grpc::ChannelInterface> channel_;
void UnaryCallInternal(ClientContext* context, const grpc::string& method,
const RequestType* request, ResponseType* response,
std::function<void(grpc::Status)> on_completion) {
internal::CallbackUnaryCall(
channel_.get(),
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, response, std::move(on_completion));
}
void PrepareUnaryCallInternal(ClientContext* context,
const grpc::string& method,
const RequestType* request,
ResponseType* response,
ClientUnaryReactor* reactor) {
internal::ClientCallbackUnaryFactory::Create<RequestType, ResponseType>(
channel_.get(),
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, response, reactor);
}
void PrepareBidiStreamingCallInternal(
ClientContext* context, const grpc::string& method,
ClientBidiReactor<RequestType, ResponseType>* reactor) {
internal::ClientCallbackReaderWriterFactory<RequestType, ResponseType>::
Create(channel_.get(),
grpc::internal::RpcMethod(
method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
context, reactor);
}
std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>
CallInternal(grpc::ChannelInterface* channel, ClientContext* context,
const grpc::string& method, CompletionQueue* cq, bool start,
void* tag) {
return std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>(
internal::ClientAsyncReaderWriterFactory<RequestType, ResponseType>::
Create(
channel, cq,
grpc::internal::RpcMethod(
method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
context, start, tag));
}
};
typedef TemplatedGenericStub<grpc::ByteBuffer, grpc::ByteBuffer> GenericStub;
} // namespace grpc_impl
#endif // GRPCPP_GENERIC_GENERIC_STUB_IMPL_H
+68
View File
@@ -0,0 +1,68 @@
/*
*
* Copyright 2015 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.
*
*/
/// \mainpage gRPC C++ API
///
/// The gRPC C++ API mainly consists of the following classes:
/// <br>
/// - grpc::Channel, which represents the connection to an endpoint. See [the
/// gRPC Concepts page](https://grpc.io/docs/guides/concepts.html) for more
/// details. Channels are created by the factory function grpc::CreateChannel.
///
/// - grpc::CompletionQueue, the producer-consumer queue used for all
/// asynchronous communication with the gRPC runtime.
///
/// - grpc::ClientContext and grpc::ServerContext, where optional configuration
/// for an RPC can be set, such as setting custom metadata to be conveyed to the
/// peer, compression settings, authentication, etc.
///
/// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder.
///
/// Streaming calls are handled with the streaming classes in
/// \ref sync_stream.h and
/// \ref async_stream.h.
///
/// Refer to the
/// [examples](https://github.com/grpc/grpc/blob/master/examples/cpp)
/// for code putting these pieces into play.
#ifndef GRPCPP_GRPCPP_H
#define GRPCPP_GRPCPP_H
// Pragma for http://include-what-you-use.org/ tool, tells that following
// headers are not private for grpcpp.h and are part of its interface.
// IWYU pragma: begin_exports
#include <grpc/grpc.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/create_channel_posix.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include <grpcpp/server_context.h>
#include <grpcpp/server_posix.h>
// IWYU pragma: end_exports
namespace grpc {
/// Return gRPC library version.
grpc::string Version();
} // namespace grpc
#endif // GRPCPP_GRPCPP_H
@@ -0,0 +1,41 @@
/*
*
* Copyright 2019 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 GRPCPP_HEALTH_CHECK_SERVICE_INTERFACE_H
#define GRPCPP_HEALTH_CHECK_SERVICE_INTERFACE_H
#include <grpcpp/health_check_service_interface_impl.h>
namespace grpc {
const char kHealthCheckServiceInterfaceArg[] =
"grpc.health_check_service_interface";
typedef ::grpc_impl::HealthCheckServiceInterface HealthCheckServiceInterface;
static inline void EnableDefaultHealthCheckService(bool enable) {
::grpc_impl::EnableDefaultHealthCheckService(enable);
}
static inline bool DefaultHealthCheckServiceEnabled() {
return ::grpc_impl::DefaultHealthCheckServiceEnabled();
}
} // namespace grpc
#endif // GRPCPP_HEALTH_CHECK_SERVICE_INTERFACE_H
@@ -0,0 +1,55 @@
/*
*
* Copyright 2016 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 GRPCPP_HEALTH_CHECK_SERVICE_INTERFACE_IMPL_H
#define GRPCPP_HEALTH_CHECK_SERVICE_INTERFACE_IMPL_H
#include <grpcpp/support/config.h>
namespace grpc_impl {
/// The gRPC server uses this interface to expose the health checking service
/// without depending on protobuf.
class HealthCheckServiceInterface {
public:
virtual ~HealthCheckServiceInterface() {}
/// Set or change the serving status of the given \a service_name.
virtual void SetServingStatus(const grpc::string& service_name,
bool serving) = 0;
/// Apply to all registered service names.
virtual void SetServingStatus(bool serving) = 0;
/// Set all registered service names to not serving and prevent future
/// state changes.
virtual void Shutdown() {}
};
/// Enable/disable the default health checking service. This applies to all C++
/// servers created afterwards. For each server, user can override the default
/// with a HealthCheckServiceServerBuilderOption.
/// NOT thread safe.
void EnableDefaultHealthCheckService(bool enable);
/// Returns whether the default health checking service is enabled.
/// NOT thread safe.
bool DefaultHealthCheckServiceEnabled();
} // namespace grpc_impl
#endif // GRPCPP_HEALTH_CHECK_SERVICE_INTERFACE_IMPL_H
+24
View File
@@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CALL_H
#define GRPCPP_IMPL_CALL_H
#include <grpcpp/impl/codegen/call.h>
#endif // GRPCPP_IMPL_CALL_H
@@ -0,0 +1,37 @@
/*
*
* Copyright 2017 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 GRPCPP_IMPL_CHANNEL_ARGUMENT_OPTION_H
#define GRPCPP_IMPL_CHANNEL_ARGUMENT_OPTION_H
#include <map>
#include <memory>
#include <grpcpp/impl/server_builder_option.h>
#include <grpcpp/support/channel_arguments.h>
namespace grpc {
std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
const grpc::string& name, const grpc::string& value);
std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
const grpc::string& name, int value);
} // namespace grpc
#endif // GRPCPP_IMPL_CHANNEL_ARGUMENT_OPTION_H
+24
View File
@@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CLIENT_UNARY_CALL_H
#define GRPCPP_IMPL_CLIENT_UNARY_CALL_H
#include <grpcpp/impl/codegen/client_unary_call.h>
#endif // GRPCPP_IMPL_CLIENT_UNARY_CALL_H
@@ -0,0 +1,163 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H
#define GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H
#include <grpc/impl/codegen/port_platform.h>
#include <grpcpp/impl/codegen/async_stream_impl.h>
#include <grpcpp/impl/codegen/byte_buffer.h>
#include <grpcpp/impl/codegen/server_callback_handlers.h>
#include <grpcpp/impl/codegen/server_callback_impl.h>
struct grpc_server;
namespace grpc {
typedef ::grpc_impl::ServerAsyncReaderWriter<ByteBuffer, ByteBuffer>
GenericServerAsyncReaderWriter;
typedef ::grpc_impl::ServerAsyncResponseWriter<ByteBuffer>
GenericServerAsyncResponseWriter;
typedef ::grpc_impl::ServerAsyncReader<ByteBuffer, ByteBuffer>
GenericServerAsyncReader;
typedef ::grpc_impl::ServerAsyncWriter<ByteBuffer> GenericServerAsyncWriter;
class GenericServerContext final : public ::grpc_impl::ServerContext {
public:
const grpc::string& method() const { return method_; }
const grpc::string& host() const { return host_; }
private:
friend class grpc_impl::Server;
friend class grpc::ServerInterface;
void Clear() {
method_.clear();
host_.clear();
::grpc_impl::ServerContext::Clear();
}
grpc::string method_;
grpc::string host_;
};
// A generic service at the server side accepts all RPC methods and hosts. It is
// typically used in proxies. The generic service can be registered to a server
// which also has other services.
// Sample usage:
// ServerBuilder builder;
// auto cq = builder.AddCompletionQueue();
// AsyncGenericService generic_service;
// builder.RegisterAsyncGenericService(&generic_service);
// auto server = builder.BuildAndStart();
//
// // request a new call
// GenericServerContext context;
// GenericServerAsyncReaderWriter stream;
// generic_service.RequestCall(&context, &stream, cq.get(), cq.get(), tag);
//
// When tag is retrieved from cq->Next(), context.method() can be used to look
// at the method and the RPC can be handled accordingly.
class AsyncGenericService final {
public:
AsyncGenericService() : server_(nullptr) {}
void RequestCall(GenericServerContext* ctx,
GenericServerAsyncReaderWriter* reader_writer,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag);
private:
friend class grpc_impl::Server;
grpc_impl::Server* server_;
};
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
#endif
/// \a ServerGenericBidiReactor is the reactor class for bidi streaming RPCs
/// invoked on a CallbackGenericService. It is just a ServerBidi reactor with
/// ByteBuffer arguments.
using ServerGenericBidiReactor =
::grpc_impl::ServerBidiReactor<ByteBuffer, ByteBuffer>;
class GenericCallbackServerContext final
: public ::grpc_impl::CallbackServerContext {
public:
const grpc::string& method() const { return method_; }
const grpc::string& host() const { return host_; }
private:
friend class ::grpc_impl::Server;
friend class ::grpc::ServerInterface;
void Clear() {
method_.clear();
host_.clear();
::grpc_impl::CallbackServerContext::Clear();
}
grpc::string method_;
grpc::string host_;
};
/// \a CallbackGenericService is the base class for generic services implemented
/// using the callback API and registered through the ServerBuilder using
/// RegisterCallbackGenericService.
class CallbackGenericService {
public:
CallbackGenericService() {}
virtual ~CallbackGenericService() {}
/// The "method handler" for the generic API. This function should be
/// overridden to provide a ServerGenericBidiReactor that implements the
/// application-level interface for this RPC. Unimplemented by default.
virtual ServerGenericBidiReactor* CreateReactor(
GenericCallbackServerContext* /*ctx*/) {
class Reactor : public ServerGenericBidiReactor {
public:
Reactor() { this->Finish(Status(StatusCode::UNIMPLEMENTED, "")); }
void OnDone() override { delete this; }
};
return new Reactor;
}
private:
friend class ::grpc_impl::Server;
::grpc_impl::internal::CallbackBidiHandler<ByteBuffer, ByteBuffer>*
Handler() {
return new ::grpc_impl::internal::CallbackBidiHandler<ByteBuffer,
ByteBuffer>(
[this](::grpc_impl::CallbackServerContext* ctx) {
return CreateReactor(static_cast<GenericCallbackServerContext*>(ctx));
});
}
grpc_impl::Server* server_{nullptr};
};
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
} // namespace experimental
#endif
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H
+95
View File
@@ -0,0 +1,95 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H
#define GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H
#include <grpcpp/impl/codegen/async_stream_impl.h>
namespace grpc {
namespace internal {
typedef ::grpc_impl::internal::ClientAsyncStreamingInterface
ClientAsyncStreamingInterface;
template <class R>
using AsyncReaderInterface = ::grpc_impl::internal::AsyncReaderInterface<R>;
template <class W>
using AsyncWriterInterface = ::grpc_impl::internal::AsyncWriterInterface<W>;
} // namespace internal
template <class R>
using ClientAsyncReaderInterface = ::grpc_impl::ClientAsyncReaderInterface<R>;
template <class R>
using ClientAsyncReader = ::grpc_impl::ClientAsyncReader<R>;
template <class W>
using ClientAsyncWriterInterface = ::grpc_impl::ClientAsyncWriterInterface<W>;
template <class W>
using ClientAsyncWriter = ::grpc_impl::ClientAsyncWriter<W>;
template <class W, class R>
using ClientAsyncReaderWriterInterface =
::grpc_impl::ClientAsyncReaderWriterInterface<W, R>;
template <class W, class R>
using ClientAsyncReaderWriter = ::grpc_impl::ClientAsyncReaderWriter<W, R>;
template <class W, class R>
using ServerAsyncReaderInterface =
::grpc_impl::ServerAsyncReaderInterface<W, R>;
template <class W, class R>
using ServerAsyncReader = ::grpc_impl::ServerAsyncReader<W, R>;
template <class W>
using ServerAsyncWriterInterface = ::grpc_impl::ServerAsyncWriterInterface<W>;
template <class W>
using ServerAsyncWriter = ::grpc_impl::ServerAsyncWriter<W>;
template <class W, class R>
using ServerAsyncReaderWriterInterface =
::grpc_impl::ServerAsyncReaderWriterInterface<W, R>;
template <class W, class R>
using ServerAsyncReaderWriter = ::grpc_impl::ServerAsyncReaderWriter<W, R>;
namespace internal {
template <class R>
using ClientAsyncReaderFactory =
::grpc_impl::internal::ClientAsyncReaderFactory<R>;
template <class W>
using ClientAsyncWriterFactory =
::grpc_impl::internal::ClientAsyncWriterFactory<W>;
template <class W, class R>
using ClientAsyncReaderWriterFactory =
::grpc_impl::internal::ClientAsyncReaderWriterFactory<W, R>;
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,46 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
#define GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
#include <grpcpp/impl/codegen/async_unary_call_impl.h>
namespace grpc {
template <class R>
using ClientAsyncResponseReaderInterface =
grpc_impl::ClientAsyncResponseReaderInterface<R>;
template <class R>
using ClientAsyncResponseReader = grpc_impl::ClientAsyncResponseReader<R>;
template <class W>
using ServerAsyncResponseWriter = ::grpc_impl::ServerAsyncResponseWriter<W>;
namespace internal {
template <class R>
using ClientAsyncResponseReaderFactory =
::grpc_impl::internal::ClientAsyncResponseReaderFactory<R>;
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
@@ -0,0 +1,314 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H
#define GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/client_context_impl.h>
#include <grpcpp/impl/codegen/server_context_impl.h>
#include <grpcpp/impl/codegen/service_type.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
/// An interface relevant for async client side unary RPCs (which send
/// one request message to a server and receive one response message).
template <class R>
class ClientAsyncResponseReaderInterface {
public:
virtual ~ClientAsyncResponseReaderInterface() {}
/// Start the call that was set up by the constructor, but only if the
/// constructor was invoked through the "Prepare" API which doesn't actually
/// start the call
virtual void StartCall() = 0;
/// Request notification of the reading of initial metadata. Completion
/// will be notified by \a tag on the associated completion queue.
/// This call is optional, but if it is used, it cannot be used concurrently
/// with or after the \a Finish method.
///
/// \param[in] tag Tag identifying this request.
virtual void ReadInitialMetadata(void* tag) = 0;
/// Request to receive the server's response \a msg and final \a status for
/// the call, and to notify \a tag on this call's completion queue when
/// finished.
///
/// This function will return when either:
/// - when the server's response message and status have been received.
/// - when the server has returned a non-OK status (no message expected in
/// this case).
/// - when the call failed for some reason and the library generated a
/// non-OK status.
///
/// \param[in] tag Tag identifying this request.
/// \param[out] status To be updated with the operation status.
/// \param[out] msg To be filled in with the server's response message.
virtual void Finish(R* msg, ::grpc::Status* status, void* tag) = 0;
};
namespace internal {
template <class R>
class ClientAsyncResponseReaderFactory {
public:
/// Start a call and write the request out if \a start is set.
/// \a tag will be notified on \a cq when the call has been started (i.e.
/// intitial metadata sent) and \a request has been written out.
/// If \a start is not set, the actual call must be initiated by StartCall
/// Note that \a context will be used to fill in custom initial metadata
/// used to send to the server when starting the call.
template <class W>
static ClientAsyncResponseReader<R>* Create(
::grpc::ChannelInterface* channel, ::grpc_impl::CompletionQueue* cq,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, const W& request, bool start) {
::grpc::internal::Call call = channel->CreateCall(method, context, cq);
return new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
call.call(), sizeof(ClientAsyncResponseReader<R>)))
ClientAsyncResponseReader<R>(call, context, request, start);
}
};
} // namespace internal
/// Async API for client-side unary RPCs, where the message response
/// received from the server is of type \a R.
template <class R>
class ClientAsyncResponseReader final
: public ClientAsyncResponseReaderInterface<R> {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* /*ptr*/, std::size_t size) {
GPR_CODEGEN_ASSERT(size == sizeof(ClientAsyncResponseReader));
}
// This operator should never be called as the memory should be freed as part
// of the arena destruction. It only exists to provide a matching operator
// delete to the operator new so that some compilers will not complain (see
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
// there are no tests catching the compiler warning.
static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
void StartCall() override {
GPR_CODEGEN_ASSERT(!started_);
started_ = true;
StartCallInternal();
}
/// See \a ClientAsyncResponseReaderInterface::ReadInitialMetadata for
/// semantics.
///
/// Side effect:
/// - the \a ClientContext associated with this call is updated with
/// possible initial and trailing metadata sent from the server.
void ReadInitialMetadata(void* tag) override {
GPR_CODEGEN_ASSERT(started_);
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
single_buf.set_output_tag(tag);
single_buf.RecvInitialMetadata(context_);
call_.PerformOps(&single_buf);
initial_metadata_read_ = true;
}
/// See \a ClientAysncResponseReaderInterface::Finish for semantics.
///
/// Side effect:
/// - the \a ClientContext associated with this call is updated with
/// possible initial and trailing metadata sent from the server.
void Finish(R* msg, ::grpc::Status* status, void* tag) override {
GPR_CODEGEN_ASSERT(started_);
if (initial_metadata_read_) {
finish_buf.set_output_tag(tag);
finish_buf.RecvMessage(msg);
finish_buf.AllowNoMessage();
finish_buf.ClientRecvStatus(context_, status);
call_.PerformOps(&finish_buf);
} else {
single_buf.set_output_tag(tag);
single_buf.RecvInitialMetadata(context_);
single_buf.RecvMessage(msg);
single_buf.AllowNoMessage();
single_buf.ClientRecvStatus(context_, status);
call_.PerformOps(&single_buf);
}
}
private:
friend class internal::ClientAsyncResponseReaderFactory<R>;
::grpc_impl::ClientContext* const context_;
::grpc::internal::Call call_;
bool started_;
bool initial_metadata_read_ = false;
template <class W>
ClientAsyncResponseReader(::grpc::internal::Call call,
::grpc_impl::ClientContext* context,
const W& request, bool start)
: context_(context), call_(call), started_(start) {
// Bind the metadata at time of StartCallInternal but set up the rest here
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(single_buf.SendMessage(request).ok());
single_buf.ClientSendClose();
if (start) StartCallInternal();
}
void StartCallInternal() {
single_buf.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
}
// disable operator new
static void* operator new(std::size_t size);
static void* operator new(std::size_t /*size*/, void* p) { return p; }
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose,
::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpRecvMessage<R>,
::grpc::internal::CallOpClientRecvStatus>
single_buf;
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>,
::grpc::internal::CallOpClientRecvStatus>
finish_buf;
};
/// Async server-side API for handling unary calls, where the single
/// response message sent to the client is of type \a W.
template <class W>
class ServerAsyncResponseWriter final
: public ::grpc::internal::ServerAsyncStreamingInterface {
public:
explicit ServerAsyncResponseWriter(::grpc_impl::ServerContext* ctx)
: call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
/// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
///
/// Side effect:
/// The initial metadata that will be sent to the client from this op will
/// be taken from the \a ServerContext associated with the call.
///
/// \param[in] tag Tag identifying this request.
void SendInitialMetadata(void* tag) override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_buf_.set_output_tag(tag);
meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_buf_);
}
/// Indicate that the stream is to be finished and request notification
/// when the server has sent the appropriate signals to the client to
/// end the call. Should not be used concurrently with other operations.
///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of the call.
/// \param[in] msg Message to be sent to the client.
///
/// Side effect:
/// - also sends initial metadata if not already sent (using the
/// \a ServerContext associated with this call).
///
/// Note: if \a status has a non-OK code, then \a msg will not be sent,
/// and the client will receive only the status with possible trailing
/// metadata.
void Finish(const W& msg, const ::grpc::Status& status, void* tag) {
finish_buf_.set_output_tag(tag);
finish_buf_.set_core_cq_tag(&finish_buf_);
if (!ctx_->sent_initial_metadata_) {
finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// The response is dropped if the status is not OK.
if (status.ok()) {
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_,
finish_buf_.SendMessage(msg));
} else {
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
}
call_.PerformOps(&finish_buf_);
}
/// Indicate that the stream is to be finished with a non-OK status,
/// and request notification for when the server has finished sending the
/// appropriate signals to the client to end the call.
/// Should not be used concurrently with other operations.
///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of the call.
/// - Note: \a status must have a non-OK code.
///
/// Side effect:
/// - also sends initial metadata if not already sent (using the
/// \a ServerContext associated with this call).
void FinishWithError(const ::grpc::Status& status, void* tag) {
GPR_CODEGEN_ASSERT(!status.ok());
finish_buf_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_buf_);
}
private:
void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
::grpc::internal::Call call_;
::grpc_impl::ServerContext* ctx_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
meta_buf_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpServerSendStatus>
finish_buf_;
};
} // namespace grpc_impl
namespace std {
template <class R>
class default_delete<::grpc_impl::ClientAsyncResponseReader<R>> {
public:
void operator()(void* /*p*/) {}
};
template <class R>
class default_delete<::grpc_impl::ClientAsyncResponseReaderInterface<R>> {
public:
void operator()(void* /*p*/) {}
};
} // namespace std
#endif // GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H
+233
View File
@@ -0,0 +1,233 @@
/*
*
* Copyright 2017 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 GRPCPP_IMPL_CODEGEN_BYTE_BUFFER_H
#define GRPCPP_IMPL_CODEGEN_BYTE_BUFFER_H
#include <grpc/impl/codegen/byte_buffer.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/serialization_traits.h>
#include <grpcpp/impl/codegen/slice.h>
#include <grpcpp/impl/codegen/status.h>
#include <vector>
namespace grpc_impl {
namespace internal {
template <class RequestType, class ResponseType>
class CallbackUnaryHandler;
template <class RequestType, class ResponseType>
class CallbackServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <::grpc::StatusCode code>
class ErrorMethodHandler;
} // namespace internal
} // namespace grpc_impl
namespace grpc {
class ServerInterface;
class ByteBuffer;
class ServerInterface;
namespace internal {
class CallOpSendMessage;
template <class R>
class CallOpRecvMessage;
class CallOpGenericRecvMessage;
class ExternalConnectionAcceptorImpl;
template <class R>
class DeserializeFuncType;
class GrpcByteBufferPeer;
} // namespace internal
/// A sequence of bytes.
class ByteBuffer final {
public:
/// Constuct an empty buffer.
ByteBuffer() : buffer_(nullptr) {}
/// Construct buffer from \a slices, of which there are \a nslices.
ByteBuffer(const Slice* slices, size_t nslices) {
// The following assertions check that the representation of a grpc::Slice
// is identical to that of a grpc_slice: it has a grpc_slice field, and
// nothing else.
static_assert(std::is_same<decltype(slices[0].slice_), grpc_slice>::value,
"Slice must have same representation as grpc_slice");
static_assert(sizeof(Slice) == sizeof(grpc_slice),
"Slice must have same representation as grpc_slice");
// The following assertions check that the representation of a ByteBuffer is
// identical to grpc_byte_buffer*: it has a grpc_byte_buffer* field,
// and nothing else.
static_assert(std::is_same<decltype(buffer_), grpc_byte_buffer*>::value,
"ByteBuffer must have same representation as "
"grpc_byte_buffer*");
static_assert(sizeof(ByteBuffer) == sizeof(grpc_byte_buffer*),
"ByteBuffer must have same representation as "
"grpc_byte_buffer*");
// The const_cast is legal if grpc_raw_byte_buffer_create() does no more
// than its advertised side effect of increasing the reference count of the
// slices it processes, and such an increase does not affect the semantics
// seen by the caller of this constructor.
buffer_ = g_core_codegen_interface->grpc_raw_byte_buffer_create(
reinterpret_cast<grpc_slice*>(const_cast<Slice*>(slices)), nslices);
}
/// Constuct a byte buffer by referencing elements of existing buffer
/// \a buf. Wrapper of core function grpc_byte_buffer_copy . This is not
/// a deep copy; it is just a referencing. As a result, its performance is
/// size-independent.
ByteBuffer(const ByteBuffer& buf) : buffer_(nullptr) { operator=(buf); }
~ByteBuffer() {
if (buffer_) {
g_core_codegen_interface->grpc_byte_buffer_destroy(buffer_);
}
}
/// Wrapper of core function grpc_byte_buffer_copy . This is not
/// a deep copy; it is just a referencing. As a result, its performance is
/// size-independent.
ByteBuffer& operator=(const ByteBuffer& buf) {
if (this != &buf) {
Clear(); // first remove existing data
}
if (buf.buffer_) {
// then copy
buffer_ = g_core_codegen_interface->grpc_byte_buffer_copy(buf.buffer_);
}
return *this;
}
/// Dump (read) the buffer contents into \a slices.
Status Dump(std::vector<Slice>* slices) const;
/// Remove all data.
void Clear() {
if (buffer_) {
g_core_codegen_interface->grpc_byte_buffer_destroy(buffer_);
buffer_ = nullptr;
}
}
/// Make a duplicate copy of the internals of this byte
/// buffer so that we have our own owned version of it.
/// bbuf.Duplicate(); is equivalent to bbuf=bbuf; but is actually readable.
/// This is not a deep copy; it is a referencing and its performance
/// is size-independent.
void Duplicate() {
buffer_ = g_core_codegen_interface->grpc_byte_buffer_copy(buffer_);
}
/// Forget underlying byte buffer without destroying
/// Use this only for un-owned byte buffers
void Release() { buffer_ = nullptr; }
/// Buffer size in bytes.
size_t Length() const {
return buffer_ == nullptr
? 0
: g_core_codegen_interface->grpc_byte_buffer_length(buffer_);
}
/// Swap the state of *this and *other.
void Swap(ByteBuffer* other) {
grpc_byte_buffer* tmp = other->buffer_;
other->buffer_ = buffer_;
buffer_ = tmp;
}
/// Is this ByteBuffer valid?
bool Valid() const { return (buffer_ != nullptr); }
private:
friend class SerializationTraits<ByteBuffer, void>;
friend class ServerInterface;
friend class internal::CallOpSendMessage;
template <class R>
friend class internal::CallOpRecvMessage;
friend class internal::CallOpGenericRecvMessage;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc_impl::internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc_impl::internal::ServerStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc_impl::internal::CallbackUnaryHandler;
template <class RequestType, class ResponseType>
friend class ::grpc_impl::internal::CallbackServerStreamingHandler;
template <StatusCode code>
friend class ::grpc_impl::internal::ErrorMethodHandler;
template <class R>
friend class internal::DeserializeFuncType;
friend class ProtoBufferReader;
friend class ProtoBufferWriter;
friend class internal::GrpcByteBufferPeer;
friend class internal::ExternalConnectionAcceptorImpl;
grpc_byte_buffer* buffer_;
// takes ownership
void set_buffer(grpc_byte_buffer* buf) {
if (buffer_) {
Clear();
}
buffer_ = buf;
}
grpc_byte_buffer* c_buffer() { return buffer_; }
grpc_byte_buffer** c_buffer_ptr() { return &buffer_; }
class ByteBufferPointer {
public:
ByteBufferPointer(const ByteBuffer* b)
: bbuf_(const_cast<ByteBuffer*>(b)) {}
operator ByteBuffer*() { return bbuf_; }
operator grpc_byte_buffer*() { return bbuf_->buffer_; }
operator grpc_byte_buffer**() { return &bbuf_->buffer_; }
private:
ByteBuffer* bbuf_;
};
ByteBufferPointer bbuf_ptr() const { return ByteBufferPointer(this); }
};
template <>
class SerializationTraits<ByteBuffer, void> {
public:
static Status Deserialize(ByteBuffer* byte_buffer, ByteBuffer* dest) {
dest->set_buffer(byte_buffer->buffer_);
return Status::OK;
}
static Status Serialize(const ByteBuffer& source, ByteBuffer* buffer,
bool* own_buffer) {
*buffer = source;
*own_buffer = true;
return g_core_codegen_interface->ok();
}
};
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_BYTE_BUFFER_H
+96
View File
@@ -0,0 +1,96 @@
/*
*
* Copyright 2018 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 GRPCPP_IMPL_CODEGEN_CALL_H
#define GRPCPP_IMPL_CODEGEN_CALL_H
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/call_hook.h>
namespace grpc_impl {
class CompletionQueue;
}
namespace grpc {
namespace experimental {
class ClientRpcInfo;
class ServerRpcInfo;
} // namespace experimental
namespace internal {
class CallHook;
class CallOpSetInterface;
/// Straightforward wrapping of the C call object
class Call final {
public:
Call()
: call_hook_(nullptr),
cq_(nullptr),
call_(nullptr),
max_receive_message_size_(-1) {}
/** call is owned by the caller */
Call(grpc_call* call, CallHook* call_hook, ::grpc_impl::CompletionQueue* cq)
: call_hook_(call_hook),
cq_(cq),
call_(call),
max_receive_message_size_(-1) {}
Call(grpc_call* call, CallHook* call_hook, ::grpc_impl::CompletionQueue* cq,
experimental::ClientRpcInfo* rpc_info)
: call_hook_(call_hook),
cq_(cq),
call_(call),
max_receive_message_size_(-1),
client_rpc_info_(rpc_info) {}
Call(grpc_call* call, CallHook* call_hook, ::grpc_impl::CompletionQueue* cq,
int max_receive_message_size, experimental::ServerRpcInfo* rpc_info)
: call_hook_(call_hook),
cq_(cq),
call_(call),
max_receive_message_size_(max_receive_message_size),
server_rpc_info_(rpc_info) {}
void PerformOps(CallOpSetInterface* ops) {
call_hook_->PerformOpsOnCall(ops, this);
}
grpc_call* call() const { return call_; }
::grpc_impl::CompletionQueue* cq() const { return cq_; }
int max_receive_message_size() const { return max_receive_message_size_; }
experimental::ClientRpcInfo* client_rpc_info() const {
return client_rpc_info_;
}
experimental::ServerRpcInfo* server_rpc_info() const {
return server_rpc_info_;
}
private:
CallHook* call_hook_;
::grpc_impl::CompletionQueue* cq_;
grpc_call* call_;
int max_receive_message_size_;
experimental::ClientRpcInfo* client_rpc_info_ = nullptr;
experimental::ServerRpcInfo* server_rpc_info_ = nullptr;
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CALL_H
+39
View File
@@ -0,0 +1,39 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_CALL_HOOK_H
#define GRPCPP_IMPL_CODEGEN_CALL_HOOK_H
namespace grpc {
namespace internal {
class CallOpSetInterface;
class Call;
/// This is an interface that Channel and Server implement to allow them to hook
/// performing ops.
class CallHook {
public:
virtual ~CallHook() {}
virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0;
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CALL_HOOK_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,59 @@
/*
*
* Copyright 2018 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 GRPCPP_IMPL_CODEGEN_CALL_OP_SET_INTERFACE_H
#define GRPCPP_IMPL_CODEGEN_CALL_OP_SET_INTERFACE_H
#include <grpcpp/impl/codegen/completion_queue_tag.h>
namespace grpc {
namespace internal {
class Call;
/// An abstract collection of call ops, used to generate the
/// grpc_call_op structure to pass down to the lower layers,
/// and as it is-a CompletionQueueTag, also massages the final
/// completion into the correct form for consumption in the C++
/// API.
class CallOpSetInterface : public CompletionQueueTag {
public:
/// Fills in grpc_op, starting from ops[*nops] and moving
/// upwards.
virtual void FillOps(internal::Call* call) = 0;
/// Get the tag to be used at the core completion queue. Generally, the
/// value of core_cq_tag will be "this". However, it can be overridden if we
/// want core to process the tag differently (e.g., as a core callback)
virtual void* core_cq_tag() = 0;
// This will be called while interceptors are run if the RPC is a hijacked
// RPC. This should set hijacking state for each of the ops.
virtual void SetHijackingState() = 0;
// Should be called after interceptors are done running
virtual void ContinueFillOpsAfterInterception() = 0;
// Should be called after interceptors are done running on the finalize result
// path
virtual void ContinueFinalizeResultAfterInterception() = 0;
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CALL_OP_SET_INTERFACE_H
@@ -0,0 +1,222 @@
/*
*
* Copyright 2018 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 GRPCPP_IMPL_CODEGEN_CALLBACK_COMMON_H
#define GRPCPP_IMPL_CODEGEN_CALLBACK_COMMON_H
#include <functional>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc {
namespace internal {
/// An exception-safe way of invoking a user-specified callback function
// TODO(vjpai): decide whether it is better for this to take a const lvalue
// parameter or an rvalue parameter, or if it even matters
template <class Func, class... Args>
void CatchingCallback(Func&& func, Args&&... args) {
#if GRPC_ALLOW_EXCEPTIONS
try {
func(std::forward<Args>(args)...);
} catch (...) {
// nothing to return or change here, just don't crash the library
}
#else // GRPC_ALLOW_EXCEPTIONS
func(std::forward<Args>(args)...);
#endif // GRPC_ALLOW_EXCEPTIONS
}
template <class Reactor, class Func, class... Args>
Reactor* CatchingReactorGetter(Func&& func, Args&&... args) {
#if GRPC_ALLOW_EXCEPTIONS
try {
return func(std::forward<Args>(args)...);
} catch (...) {
// fail the RPC, don't crash the library
return nullptr;
}
#else // GRPC_ALLOW_EXCEPTIONS
return func(std::forward<Args>(args)...);
#endif // GRPC_ALLOW_EXCEPTIONS
}
// The contract on these tags is that they are single-shot. They must be
// constructed and then fired at exactly one point. There is no expectation
// that they can be reused without reconstruction.
class CallbackWithStatusTag
: public grpc_experimental_completion_queue_functor {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* /*ptr*/, std::size_t size) {
GPR_CODEGEN_ASSERT(size == sizeof(CallbackWithStatusTag));
}
// This operator should never be called as the memory should be freed as part
// of the arena destruction. It only exists to provide a matching operator
// delete to the operator new so that some compilers will not complain (see
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
// there are no tests catching the compiler warning.
static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
CallbackWithStatusTag(grpc_call* call, std::function<void(Status)> f,
CompletionQueueTag* ops)
: call_(call), func_(std::move(f)), ops_(ops) {
g_core_codegen_interface->grpc_call_ref(call);
functor_run = &CallbackWithStatusTag::StaticRun;
// A client-side callback should never be run inline since they will always
// have work to do from the user application. So, set the parent's
// inlineable field to false
inlineable = false;
}
~CallbackWithStatusTag() {}
Status* status_ptr() { return &status_; }
// force_run can not be performed on a tag if operations using this tag
// have been sent to PerformOpsOnCall. It is intended for error conditions
// that are detected before the operations are internally processed.
void force_run(Status s) {
status_ = std::move(s);
Run(true);
}
private:
grpc_call* call_;
std::function<void(Status)> func_;
CompletionQueueTag* ops_;
Status status_;
static void StaticRun(grpc_experimental_completion_queue_functor* cb,
int ok) {
static_cast<CallbackWithStatusTag*>(cb)->Run(static_cast<bool>(ok));
}
void Run(bool ok) {
void* ignored = ops_;
if (!ops_->FinalizeResult(&ignored, &ok)) {
// The tag was swallowed
return;
}
GPR_CODEGEN_ASSERT(ignored == ops_);
// Last use of func_ or status_, so ok to move them out
auto func = std::move(func_);
auto status = std::move(status_);
func_ = nullptr; // reset to clear this out for sure
status_ = Status(); // reset to clear this out for sure
CatchingCallback(std::move(func), std::move(status));
g_core_codegen_interface->grpc_call_unref(call_);
}
};
/// CallbackWithSuccessTag can be reused multiple times, and will be used in
/// this fashion for streaming operations. As a result, it shouldn't clear
/// anything up until its destructor
class CallbackWithSuccessTag
: public grpc_experimental_completion_queue_functor {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* /*ptr*/, std::size_t size) {
GPR_CODEGEN_ASSERT(size == sizeof(CallbackWithSuccessTag));
}
// This operator should never be called as the memory should be freed as part
// of the arena destruction. It only exists to provide a matching operator
// delete to the operator new so that some compilers will not complain (see
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
// there are no tests catching the compiler warning.
static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
CallbackWithSuccessTag() : call_(nullptr) {}
CallbackWithSuccessTag(const CallbackWithSuccessTag&) = delete;
CallbackWithSuccessTag& operator=(const CallbackWithSuccessTag&) = delete;
~CallbackWithSuccessTag() { Clear(); }
// Set can only be called on a default-constructed or Clear'ed tag.
// It should never be called on a tag that was constructed with arguments
// or on a tag that has been Set before unless the tag has been cleared.
// can_inline indicates that this particular callback can be executed inline
// (without needing a thread hop) and is only used for library-provided server
// callbacks.
void Set(grpc_call* call, std::function<void(bool)> f,
CompletionQueueTag* ops, bool can_inline) {
GPR_CODEGEN_ASSERT(call_ == nullptr);
g_core_codegen_interface->grpc_call_ref(call);
call_ = call;
func_ = std::move(f);
ops_ = ops;
functor_run = &CallbackWithSuccessTag::StaticRun;
inlineable = can_inline;
}
void Clear() {
if (call_ != nullptr) {
grpc_call* call = call_;
call_ = nullptr;
func_ = nullptr;
g_core_codegen_interface->grpc_call_unref(call);
}
}
CompletionQueueTag* ops() { return ops_; }
// force_run can not be performed on a tag if operations using this tag
// have been sent to PerformOpsOnCall. It is intended for error conditions
// that are detected before the operations are internally processed.
void force_run(bool ok) { Run(ok); }
/// check if this tag is currently set
operator bool() const { return call_ != nullptr; }
private:
grpc_call* call_;
std::function<void(bool)> func_;
CompletionQueueTag* ops_;
static void StaticRun(grpc_experimental_completion_queue_functor* cb,
int ok) {
static_cast<CallbackWithSuccessTag*>(cb)->Run(static_cast<bool>(ok));
}
void Run(bool ok) {
void* ignored = ops_;
// Allow a "false" return value from FinalizeResult to silence the
// callback, just as it silences a CQ tag in the async cases
#ifndef NDEBUG
auto* ops = ops_;
#endif
bool do_callback = ops_->FinalizeResult(&ignored, &ok);
GPR_CODEGEN_DEBUG_ASSERT(ignored == ops);
if (do_callback) {
CatchingCallback(func_, ok);
}
}
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CALLBACK_COMMON_H
@@ -0,0 +1,176 @@
/*
*
* Copyright 2016 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 GRPCPP_IMPL_CODEGEN_CHANNEL_INTERFACE_H
#define GRPCPP_IMPL_CODEGEN_CHANNEL_INTERFACE_H
#include <grpc/impl/codegen/connectivity_state.h>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/time.h>
namespace grpc_impl {
class ClientContext;
class CompletionQueue;
template <class R>
class ClientReader;
template <class W>
class ClientWriter;
template <class W, class R>
class ClientReaderWriter;
namespace internal {
template <class InputMessage, class OutputMessage>
class CallbackUnaryCallImpl;
template <class R>
class ClientAsyncReaderFactory;
template <class W>
class ClientAsyncWriterFactory;
template <class W, class R>
class ClientAsyncReaderWriterFactory;
template <class R>
class ClientAsyncResponseReaderFactory;
template <class W, class R>
class ClientCallbackReaderWriterFactory;
template <class R>
class ClientCallbackReaderFactory;
template <class W>
class ClientCallbackWriterFactory;
class ClientCallbackUnaryFactory;
} // namespace internal
} // namespace grpc_impl
namespace grpc {
class ChannelInterface;
namespace experimental {
class DelegatingChannel;
}
namespace internal {
class Call;
class CallOpSetInterface;
class RpcMethod;
class InterceptedChannel;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
} // namespace internal
/// Codegen interface for \a grpc::Channel.
class ChannelInterface {
public:
virtual ~ChannelInterface() {}
/// Get the current channel state. If the channel is in IDLE and
/// \a try_to_connect is set to true, try to connect.
virtual grpc_connectivity_state GetState(bool try_to_connect) = 0;
/// Return the \a tag on \a cq when the channel state is changed or \a
/// deadline expires. \a GetState needs to called to get the current state.
template <typename T>
void NotifyOnStateChange(grpc_connectivity_state last_observed, T deadline,
::grpc_impl::CompletionQueue* cq, void* tag) {
TimePoint<T> deadline_tp(deadline);
NotifyOnStateChangeImpl(last_observed, deadline_tp.raw_time(), cq, tag);
}
/// Blocking wait for channel state change or \a deadline expiration.
/// \a GetState needs to called to get the current state.
template <typename T>
bool WaitForStateChange(grpc_connectivity_state last_observed, T deadline) {
TimePoint<T> deadline_tp(deadline);
return WaitForStateChangeImpl(last_observed, deadline_tp.raw_time());
}
/// Wait for this channel to be connected
template <typename T>
bool WaitForConnected(T deadline) {
grpc_connectivity_state state;
while ((state = GetState(true)) != GRPC_CHANNEL_READY) {
if (!WaitForStateChange(state, deadline)) return false;
}
return true;
}
private:
template <class R>
friend class ::grpc_impl::ClientReader;
template <class W>
friend class ::grpc_impl::ClientWriter;
template <class W, class R>
friend class ::grpc_impl::ClientReaderWriter;
template <class R>
friend class ::grpc_impl::internal::ClientAsyncReaderFactory;
template <class W>
friend class ::grpc_impl::internal::ClientAsyncWriterFactory;
template <class W, class R>
friend class ::grpc_impl::internal::ClientAsyncReaderWriterFactory;
template <class R>
friend class ::grpc_impl::internal::ClientAsyncResponseReaderFactory;
template <class W, class R>
friend class ::grpc_impl::internal::ClientCallbackReaderWriterFactory;
template <class R>
friend class ::grpc_impl::internal::ClientCallbackReaderFactory;
template <class W>
friend class ::grpc_impl::internal::ClientCallbackWriterFactory;
friend class ::grpc_impl::internal::ClientCallbackUnaryFactory;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
friend class ::grpc_impl::internal::CallbackUnaryCallImpl;
friend class ::grpc::internal::RpcMethod;
friend class ::grpc::experimental::DelegatingChannel;
friend class ::grpc::internal::InterceptedChannel;
virtual internal::Call CreateCall(const internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
::grpc_impl::CompletionQueue* cq) = 0;
virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) = 0;
virtual void* RegisterMethod(const char* method) = 0;
virtual void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline,
::grpc_impl::CompletionQueue* cq,
void* tag) = 0;
virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) = 0;
// EXPERIMENTAL
// This is needed to keep codegen_test_minimal happy. InterceptedChannel needs
// to make use of this but can't directly call Channel's implementation
// because of the test.
// Returns an empty Call object (rather than being pure) since this is a new
// method and adding a new pure method to an interface would be a breaking
// change (even though this is private and non-API)
virtual internal::Call CreateCallInternal(
const internal::RpcMethod& /*method*/,
::grpc_impl::ClientContext* /*context*/,
::grpc_impl::CompletionQueue* /*cq*/, size_t /*interceptor_pos*/) {
return internal::Call();
}
// EXPERIMENTAL
// A method to get the callbackable completion queue associated with this
// channel. If the return value is nullptr, this channel doesn't support
// callback operations.
// TODO(vjpai): Consider a better default like using a global CQ
// Returns nullptr (rather than being pure) since this is a post-1.0 method
// and adding a new pure method to an interface would be a breaking change
// (even though this is private and non-API)
virtual ::grpc_impl::CompletionQueue* CallbackCQ() { return nullptr; }
};
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CHANNEL_INTERFACE_H
@@ -0,0 +1,76 @@
/*
*
* Copyright 2018 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 GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
#define GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
#include <grpcpp/impl/codegen/client_callback_impl.h>
namespace grpc {
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
template <class Response>
using ClientCallbackReader = ::grpc_impl::ClientCallbackReader<Response>;
template <class Request>
using ClientCallbackWriter = ::grpc_impl::ClientCallbackWriter<Request>;
template <class Request, class Response>
using ClientCallbackReaderWriter =
::grpc_impl::ClientCallbackReaderWriter<Request, Response>;
template <class Response>
using ClientReadReactor = ::grpc_impl::ClientReadReactor<Response>;
template <class Request>
using ClientWriteReactor = ::grpc_impl::ClientWriteReactor<Request>;
template <class Request, class Response>
using ClientBidiReactor = ::grpc_impl::ClientBidiReactor<Request, Response>;
typedef ::grpc_impl::ClientUnaryReactor ClientUnaryReactor;
#endif
// TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
namespace experimental {
template <class Response>
using ClientCallbackReader = ::grpc_impl::ClientCallbackReader<Response>;
template <class Request>
using ClientCallbackWriter = ::grpc_impl::ClientCallbackWriter<Request>;
template <class Request, class Response>
using ClientCallbackReaderWriter =
::grpc_impl::ClientCallbackReaderWriter<Request, Response>;
template <class Response>
using ClientReadReactor = ::grpc_impl::ClientReadReactor<Response>;
template <class Request>
using ClientWriteReactor = ::grpc_impl::ClientWriteReactor<Request>;
template <class Request, class Response>
using ClientBidiReactor = ::grpc_impl::ClientBidiReactor<Request, Response>;
typedef ::grpc_impl::ClientUnaryReactor ClientUnaryReactor;
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,31 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H
#define GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H
#include <grpcpp/impl/codegen/client_context_impl.h>
namespace grpc {
typedef ::grpc_impl::ClientContext ClientContext;
typedef ::grpc_impl::PropagationOptions PropagationOptions;
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H
@@ -0,0 +1,519 @@
/*
*
* Copyright 2015 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.
*
*/
/// A ClientContext allows the person implementing a service client to:
///
/// - Add custom metadata key-value pairs that will propagated to the server
/// side.
/// - Control call settings such as compression and authentication.
/// - Initial and trailing metadata coming from the server.
/// - Get performance metrics (ie, census).
///
/// Context settings are only relevant to the call they are invoked with, that
/// is to say, they aren't sticky. Some of these settings, such as the
/// compression options, can be made persistent at channel construction time
/// (see \a grpc::CreateCustomChannel).
///
/// \warning ClientContext instances should \em not be reused across rpcs.
#ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H
#define GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H
#include <map>
#include <memory>
#include <string>
#include <grpc/impl/codegen/compression_types.h>
#include <grpc/impl/codegen/propagation_bits.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/create_auth_context.h>
#include <grpcpp/impl/codegen/metadata_map.h>
#include <grpcpp/impl/codegen/rpc_method.h>
#include <grpcpp/impl/codegen/security/auth_context.h>
#include <grpcpp/impl/codegen/slice.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/string_ref.h>
#include <grpcpp/impl/codegen/sync.h>
#include <grpcpp/impl/codegen/time.h>
struct census_context;
struct grpc_call;
namespace grpc {
class ChannelInterface;
namespace internal {
class RpcMethod;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
class CallOpClientRecvStatus;
class CallOpRecvInitialMetadata;
class ServerContextImpl;
} // namespace internal
namespace testing {
class InteropClientContextInspector;
} // namespace testing
} // namespace grpc
namespace grpc_impl {
namespace internal {
template <class InputMessage, class OutputMessage>
class CallbackUnaryCallImpl;
template <class Request, class Response>
class ClientCallbackReaderWriterImpl;
template <class Response>
class ClientCallbackReaderImpl;
template <class Request>
class ClientCallbackWriterImpl;
class ClientCallbackUnaryImpl;
class ClientContextAccessor;
} // namespace internal
class CallCredentials;
class Channel;
class CompletionQueue;
class ServerContext;
template <class R>
class ClientReader;
template <class W>
class ClientWriter;
template <class W, class R>
class ClientReaderWriter;
template <class R>
class ClientAsyncReader;
template <class W>
class ClientAsyncWriter;
template <class W, class R>
class ClientAsyncReaderWriter;
template <class R>
class ClientAsyncResponseReader;
class ServerContextBase;
class CallbackServerContext;
/// Options for \a ClientContext::FromServerContext specifying which traits from
/// the \a ServerContext to propagate (copy) from it into a new \a
/// ClientContext.
///
/// \see ClientContext::FromServerContext
class PropagationOptions {
public:
PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {}
PropagationOptions& enable_deadline_propagation() {
propagate_ |= GRPC_PROPAGATE_DEADLINE;
return *this;
}
PropagationOptions& disable_deadline_propagation() {
propagate_ &= ~GRPC_PROPAGATE_DEADLINE;
return *this;
}
PropagationOptions& enable_census_stats_propagation() {
propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
return *this;
}
PropagationOptions& disable_census_stats_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
return *this;
}
PropagationOptions& enable_census_tracing_propagation() {
propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
return *this;
}
PropagationOptions& disable_census_tracing_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
return *this;
}
PropagationOptions& enable_cancellation_propagation() {
propagate_ |= GRPC_PROPAGATE_CANCELLATION;
return *this;
}
PropagationOptions& disable_cancellation_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CANCELLATION;
return *this;
}
uint32_t c_bitmask() const { return propagate_; }
private:
uint32_t propagate_;
};
/// A ClientContext allows the person implementing a service client to:
///
/// - Add custom metadata key-value pairs that will propagated to the server
/// side.
/// - Control call settings such as compression and authentication.
/// - Initial and trailing metadata coming from the server.
/// - Get performance metrics (ie, census).
///
/// Context settings are only relevant to the call they are invoked with, that
/// is to say, they aren't sticky. Some of these settings, such as the
/// compression options, can be made persistent at channel construction time
/// (see \a grpc::CreateCustomChannel).
///
/// \warning ClientContext instances should \em not be reused across rpcs.
/// \warning The ClientContext instance used for creating an rpc must remain
/// alive and valid for the lifetime of the rpc.
class ClientContext {
public:
ClientContext();
~ClientContext();
/// Create a new \a ClientContext as a child of an incoming server call,
/// according to \a options (\see PropagationOptions).
///
/// \param server_context The source server context to use as the basis for
/// constructing the client context.
/// \param options The options controlling what to copy from the \a
/// server_context.
///
/// \return A newly constructed \a ClientContext instance based on \a
/// server_context, with traits propagated (copied) according to \a options.
static std::unique_ptr<ClientContext> FromServerContext(
const grpc_impl::ServerContext& server_context,
PropagationOptions options = PropagationOptions());
static std::unique_ptr<ClientContext> FromCallbackServerContext(
const grpc_impl::CallbackServerContext& server_context,
PropagationOptions options = PropagationOptions());
/// Add the (\a meta_key, \a meta_value) pair to the metadata associated with
/// a client call. These are made available at the server side by the \a
/// grpc::ServerContext::client_metadata() method.
///
/// \warning This method should only be called before invoking the rpc.
///
/// \param meta_key The metadata key. If \a meta_value is binary data, it must
/// end in "-bin".
/// \param meta_value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddMetadata(const grpc::string& meta_key,
const grpc::string& meta_value);
/// Return a collection of initial metadata key-value pairs. Note that keys
/// may happen more than once (ie, a \a std::multimap is returned).
///
/// \warning This method should only be called after initial metadata has been
/// received. For streaming calls, see \a
/// ClientReaderInterface::WaitForInitialMetadata().
///
/// \return A multimap of initial metadata key-value pairs from the server.
const std::multimap<grpc::string_ref, grpc::string_ref>&
GetServerInitialMetadata() const {
GPR_CODEGEN_ASSERT(initial_metadata_received_);
return *recv_initial_metadata_.map();
}
/// Return a collection of trailing metadata key-value pairs. Note that keys
/// may happen more than once (ie, a \a std::multimap is returned).
///
/// \warning This method is only callable once the stream has finished.
///
/// \return A multimap of metadata trailing key-value pairs from the server.
const std::multimap<grpc::string_ref, grpc::string_ref>&
GetServerTrailingMetadata() const {
// TODO(yangg) check finished
return *trailing_metadata_.map();
}
/// Set the deadline for the client call.
///
/// \warning This method should only be called before invoking the rpc.
///
/// \param deadline the deadline for the client call. Units are determined by
/// the type used. The deadline is an absolute (not relative) time.
template <typename T>
void set_deadline(const T& deadline) {
grpc::TimePoint<T> deadline_tp(deadline);
deadline_ = deadline_tp.raw_time();
}
/// EXPERIMENTAL: Indicate that this request is idempotent.
/// By default, RPCs are assumed to <i>not</i> be idempotent.
///
/// If true, the gRPC library assumes that it's safe to initiate
/// this RPC multiple times.
void set_idempotent(bool idempotent) { idempotent_ = idempotent; }
/// EXPERIMENTAL: Set this request to be cacheable.
/// If set, grpc is free to use the HTTP GET verb for sending the request,
/// with the possibility of receiving a cached response.
void set_cacheable(bool cacheable) { cacheable_ = cacheable; }
/// EXPERIMENTAL: Trigger wait-for-ready or not on this request.
/// See https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md.
/// If set, if an RPC is made when a channel's connectivity state is
/// TRANSIENT_FAILURE or CONNECTING, the call will not "fail fast",
/// and the channel will wait until the channel is READY before making the
/// call.
void set_wait_for_ready(bool wait_for_ready) {
wait_for_ready_ = wait_for_ready;
wait_for_ready_explicitly_set_ = true;
}
/// DEPRECATED: Use set_wait_for_ready() instead.
void set_fail_fast(bool fail_fast) { set_wait_for_ready(!fail_fast); }
/// Return the deadline for the client call.
std::chrono::system_clock::time_point deadline() const {
return grpc::Timespec2Timepoint(deadline_);
}
/// Return a \a gpr_timespec representation of the client call's deadline.
gpr_timespec raw_deadline() const { return deadline_; }
/// Set the per call authority header (see
/// https://tools.ietf.org/html/rfc7540#section-8.1.2.3).
void set_authority(const grpc::string& authority) { authority_ = authority; }
/// Return the authentication context for the associated client call.
/// It is only valid to call this during the lifetime of the client call.
///
/// \see grpc::AuthContext.
std::shared_ptr<const grpc::AuthContext> auth_context() const {
if (auth_context_.get() == nullptr) {
auth_context_ = grpc::CreateAuthContext(call_);
}
return auth_context_;
}
/// Set credentials for the client call.
///
/// A credentials object encapsulates all the state needed by a client to
/// authenticate with a server and make various assertions, e.g., about the
/// clients identity, role, or whether it is authorized to make a particular
/// call.
///
/// It is legal to call this only before initial metadata is sent.
///
/// \see https://grpc.io/docs/guides/auth.html
void set_credentials(
const std::shared_ptr<grpc_impl::CallCredentials>& creds);
/// EXPERIMENTAL debugging API
///
/// Returns the credentials for the client call. This should be used only in
/// tests and for diagnostic purposes, and should not be used by application
/// logic.
std::shared_ptr<grpc_impl::CallCredentials> credentials() { return creds_; }
/// Return the compression algorithm the client call will request be used.
/// Note that the gRPC runtime may decide to ignore this request, for example,
/// due to resource constraints.
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
}
/// Set \a algorithm to be the compression algorithm used for the client call.
///
/// \param algorithm The compression algorithm used for the client call.
void set_compression_algorithm(grpc_compression_algorithm algorithm);
/// Flag whether the initial metadata should be \a corked
///
/// If \a corked is true, then the initial metadata will be coalesced with the
/// write of first message in the stream. As a result, any tag set for the
/// initial metadata operation (starting a client-streaming or bidi-streaming
/// RPC) will not actually be sent to the completion queue or delivered
/// via Next.
///
/// \param corked The flag indicating whether the initial metadata is to be
/// corked or not.
void set_initial_metadata_corked(bool corked) {
initial_metadata_corked_ = corked;
}
/// Return the peer uri in a string.
/// It is only valid to call this during the lifetime of the client call.
///
/// \warning This value is never authenticated or subject to any security
/// related code. It must not be used for any authentication related
/// functionality. Instead, use auth_context.
///
/// \return The call's peer URI.
grpc::string peer() const;
/// Sets the census context.
/// It is only valid to call this before the client call is created. A common
/// place of setting census context is from within the DefaultConstructor
/// method of GlobalCallbacks.
void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
/// Returns the census context that has been set, or nullptr if not set.
struct census_context* census_context() const {
return census_context_;
}
/// Send a best-effort out-of-band cancel on the call associated with
/// this client context. The call could be in any stage; e.g., if it is
/// already finished, it may still return success.
///
/// There is no guarantee the call will be cancelled.
///
/// Note that TryCancel() does not change any of the tags that are pending
/// on the completion queue. All pending tags will still be delivered
/// (though their ok result may reflect the effect of cancellation).
void TryCancel();
/// Global Callbacks
///
/// Can be set exactly once per application to install hooks whenever
/// a client context is constructed and destructed.
class GlobalCallbacks {
public:
virtual ~GlobalCallbacks() {}
virtual void DefaultConstructor(ClientContext* context) = 0;
virtual void Destructor(ClientContext* context) = 0;
};
static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
/// Should be used for framework-level extensions only.
/// Applications never need to call this method.
grpc_call* c_call() { return call_; }
/// EXPERIMENTAL debugging API
///
/// if status is not ok() for an RPC, this will return a detailed string
/// of the gRPC Core error that led to the failure. It should not be relied
/// upon for anything other than gaining more debug data in failure cases.
grpc::string debug_error_string() const { return debug_error_string_; }
private:
// Disallow copy and assign.
ClientContext(const ClientContext&);
ClientContext& operator=(const ClientContext&);
friend class ::grpc::testing::InteropClientContextInspector;
friend class ::grpc::internal::CallOpClientRecvStatus;
friend class ::grpc::internal::CallOpRecvInitialMetadata;
friend class ::grpc_impl::Channel;
template <class R>
friend class ::grpc_impl::ClientReader;
template <class W>
friend class ::grpc_impl::ClientWriter;
template <class W, class R>
friend class ::grpc_impl::ClientReaderWriter;
template <class R>
friend class ::grpc_impl::ClientAsyncReader;
template <class W>
friend class ::grpc_impl::ClientAsyncWriter;
template <class W, class R>
friend class ::grpc_impl::ClientAsyncReaderWriter;
template <class R>
friend class ::grpc_impl::ClientAsyncResponseReader;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
friend class ::grpc_impl::internal::CallbackUnaryCallImpl;
template <class Request, class Response>
friend class ::grpc_impl::internal::ClientCallbackReaderWriterImpl;
template <class Response>
friend class ::grpc_impl::internal::ClientCallbackReaderImpl;
template <class Request>
friend class ::grpc_impl::internal::ClientCallbackWriterImpl;
friend class ::grpc_impl::internal::ClientCallbackUnaryImpl;
friend class ::grpc_impl::internal::ClientContextAccessor;
// Used by friend class CallOpClientRecvStatus
void set_debug_error_string(const grpc::string& debug_error_string) {
debug_error_string_ = debug_error_string;
}
grpc_call* call() const { return call_; }
void set_call(grpc_call* call,
const std::shared_ptr<::grpc_impl::Channel>& channel);
grpc::experimental::ClientRpcInfo* set_client_rpc_info(
const char* method, grpc::internal::RpcMethod::RpcType type,
grpc::ChannelInterface* channel,
const std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>& creators,
size_t interceptor_pos) {
rpc_info_ = grpc::experimental::ClientRpcInfo(this, type, method, channel);
rpc_info_.RegisterInterceptors(creators, interceptor_pos);
return &rpc_info_;
}
uint32_t initial_metadata_flags() const {
return (idempotent_ ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST : 0) |
(wait_for_ready_ ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0) |
(cacheable_ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST : 0) |
(wait_for_ready_explicitly_set_
? GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
: 0) |
(initial_metadata_corked_ ? GRPC_INITIAL_METADATA_CORKED : 0);
}
grpc::string authority() { return authority_; }
void SendCancelToInterceptors();
static std::unique_ptr<ClientContext> FromInternalServerContext(
const grpc_impl::ServerContextBase& server_context,
PropagationOptions options);
bool initial_metadata_received_;
bool wait_for_ready_;
bool wait_for_ready_explicitly_set_;
bool idempotent_;
bool cacheable_;
std::shared_ptr<::grpc_impl::Channel> channel_;
grpc::internal::Mutex mu_;
grpc_call* call_;
bool call_canceled_;
gpr_timespec deadline_;
grpc::string authority_;
std::shared_ptr<grpc_impl::CallCredentials> creds_;
mutable std::shared_ptr<const grpc::AuthContext> auth_context_;
struct census_context* census_context_;
std::multimap<grpc::string, grpc::string> send_initial_metadata_;
mutable grpc::internal::MetadataMap recv_initial_metadata_;
mutable grpc::internal::MetadataMap trailing_metadata_;
grpc_call* propagate_from_call_;
PropagationOptions propagation_options_;
grpc_compression_algorithm compression_algorithm_;
bool initial_metadata_corked_;
grpc::string debug_error_string_;
grpc::experimental::ClientRpcInfo rpc_info_;
};
} // namespace grpc_impl
#endif // GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H
@@ -0,0 +1,194 @@
/*
*
* Copyright 2018 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 GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H
#define GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H
#include <memory>
#include <vector>
#include <grpcpp/impl/codegen/interceptor.h>
#include <grpcpp/impl/codegen/rpc_method.h>
#include <grpcpp/impl/codegen/string_ref.h>
namespace grpc_impl {
class Channel;
class ClientContext;
} // namespace grpc_impl
namespace grpc {
namespace internal {
class InterceptorBatchMethodsImpl;
}
namespace experimental {
class ClientRpcInfo;
// A factory interface for creation of client interceptors. A vector of
// factories can be provided at channel creation which will be used to create a
// new vector of client interceptors per RPC. Client interceptor authors should
// create a subclass of ClientInterceptorFactorInterface which creates objects
// of their interceptors.
class ClientInterceptorFactoryInterface {
public:
virtual ~ClientInterceptorFactoryInterface() {}
// Returns a pointer to an Interceptor object on successful creation, nullptr
// otherwise. If nullptr is returned, this server interceptor factory is
// ignored for the purposes of that RPC.
virtual Interceptor* CreateClientInterceptor(ClientRpcInfo* info) = 0;
};
} // namespace experimental
namespace internal {
extern experimental::ClientInterceptorFactoryInterface*
g_global_client_interceptor_factory;
}
/// ClientRpcInfo represents the state of a particular RPC as it
/// appears to an interceptor. It is created and owned by the library and
/// passed to the CreateClientInterceptor method of the application's
/// ClientInterceptorFactoryInterface implementation
namespace experimental {
class ClientRpcInfo {
public:
// TODO(yashykt): Stop default-constructing ClientRpcInfo and remove UNKNOWN
// from the list of possible Types.
/// Type categorizes RPCs by unary or streaming type
enum class Type {
UNARY,
CLIENT_STREAMING,
SERVER_STREAMING,
BIDI_STREAMING,
UNKNOWN // UNKNOWN is not API and will be removed later
};
~ClientRpcInfo() {}
// Delete copy constructor but allow default move constructor
ClientRpcInfo(const ClientRpcInfo&) = delete;
ClientRpcInfo(ClientRpcInfo&&) = default;
// Getter methods
/// Return the fully-specified method name
const char* method() const { return method_; }
/// Return a pointer to the channel on which the RPC is being sent
ChannelInterface* channel() { return channel_; }
/// Return a pointer to the underlying ClientContext structure associated
/// with the RPC to support features that apply to it
grpc_impl::ClientContext* client_context() { return ctx_; }
/// Return the type of the RPC (unary or a streaming flavor)
Type type() const { return type_; }
private:
static_assert(Type::UNARY ==
static_cast<Type>(internal::RpcMethod::NORMAL_RPC),
"violated expectation about Type enum");
static_assert(Type::CLIENT_STREAMING ==
static_cast<Type>(internal::RpcMethod::CLIENT_STREAMING),
"violated expectation about Type enum");
static_assert(Type::SERVER_STREAMING ==
static_cast<Type>(internal::RpcMethod::SERVER_STREAMING),
"violated expectation about Type enum");
static_assert(Type::BIDI_STREAMING ==
static_cast<Type>(internal::RpcMethod::BIDI_STREAMING),
"violated expectation about Type enum");
// Default constructor should only be used by ClientContext
ClientRpcInfo() = default;
// Constructor will only be called from ClientContext
ClientRpcInfo(grpc_impl::ClientContext* ctx,
internal::RpcMethod::RpcType type, const char* method,
grpc::ChannelInterface* channel)
: ctx_(ctx),
type_(static_cast<Type>(type)),
method_(method),
channel_(channel) {}
// Move assignment should only be used by ClientContext
// TODO(yashykt): Delete move assignment
ClientRpcInfo& operator=(ClientRpcInfo&&) = default;
// Runs interceptor at pos \a pos.
void RunInterceptor(
experimental::InterceptorBatchMethods* interceptor_methods, size_t pos) {
GPR_CODEGEN_ASSERT(pos < interceptors_.size());
interceptors_[pos]->Intercept(interceptor_methods);
}
void RegisterInterceptors(
const std::vector<std::unique_ptr<
experimental::ClientInterceptorFactoryInterface>>& creators,
size_t interceptor_pos) {
if (interceptor_pos > creators.size()) {
// No interceptors to register
return;
}
// NOTE: The following is not a range-based for loop because it will only
// iterate over a portion of the creators vector.
for (auto it = creators.begin() + interceptor_pos; it != creators.end();
++it) {
auto* interceptor = (*it)->CreateClientInterceptor(this);
if (interceptor != nullptr) {
interceptors_.push_back(
std::unique_ptr<experimental::Interceptor>(interceptor));
}
}
if (internal::g_global_client_interceptor_factory != nullptr) {
interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(
internal::g_global_client_interceptor_factory
->CreateClientInterceptor(this)));
}
}
grpc_impl::ClientContext* ctx_ = nullptr;
// TODO(yashykt): make type_ const once move-assignment is deleted
Type type_{Type::UNKNOWN};
const char* method_ = nullptr;
grpc::ChannelInterface* channel_ = nullptr;
std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
bool hijacked_ = false;
size_t hijacked_interceptor_ = 0;
friend class internal::InterceptorBatchMethodsImpl;
friend class grpc_impl::ClientContext;
};
// PLEASE DO NOT USE THIS. ALWAYS PREFER PER CHANNEL INTERCEPTORS OVER A GLOBAL
// INTERCEPTOR. IF USAGE IS ABSOLUTELY NECESSARY, PLEASE READ THE SAFETY NOTES.
// Registers a global client interceptor factory object, which is used for all
// RPCs made in this process. The application is responsible for maintaining the
// life of the object while gRPC operations are in progress. The global
// interceptor factory should only be registered once at the start of the
// process before any gRPC operations have begun.
void RegisterGlobalClientInterceptorFactory(
ClientInterceptorFactoryInterface* factory);
// For testing purposes only
void TestOnlyResetGlobalClientInterceptorFactory();
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H
@@ -0,0 +1,94 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
#define GRPCPP_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
class ClientContext;
} // namespace grpc_impl
namespace grpc {
namespace internal {
class RpcMethod;
/// Wrapper that performs a blocking unary call
template <class InputMessage, class OutputMessage>
Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
grpc_impl::ClientContext* context,
const InputMessage& request, OutputMessage* result) {
return BlockingUnaryCallImpl<InputMessage, OutputMessage>(
channel, method, context, request, result)
.status();
}
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl {
public:
BlockingUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method,
grpc_impl::ClientContext* context,
const InputMessage& request, OutputMessage* result) {
::grpc_impl::CompletionQueue cq(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}); // Pluckable completion queue
::grpc::internal::Call call(channel->CreateCall(method, context, &cq));
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
CallOpClientSendClose, CallOpClientRecvStatus>
ops;
status_ = ops.SendMessagePtr(&request);
if (!status_.ok()) {
return;
}
ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
ops.RecvInitialMetadata(context);
ops.RecvMessage(result);
ops.AllowNoMessage();
ops.ClientSendClose();
ops.ClientRecvStatus(context, &status_);
call.PerformOps(&ops);
cq.Pluck(&ops);
// Some of the ops might fail. If the ops fail in the core layer, status
// would reflect the error. But, if the ops fail in the C++ layer, the
// status would still be the same as the one returned by gRPC Core. This can
// happen if deserialization of the message fails.
// TODO(yashykt): If deserialization fails, but the status received is OK,
// then it might be a good idea to change the status to something better
// than StatusCode::UNIMPLEMENTED to reflect this.
if (!ops.got_message && status_.ok()) {
status_ = Status(StatusCode::UNIMPLEMENTED,
"No message returned for unary request");
}
}
Status status() { return status_; }
private:
Status status_;
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
@@ -0,0 +1,31 @@
/*
*
* Copyright 2015-2016 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 GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_H
#define GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_H
#include <grpcpp/impl/codegen/completion_queue_impl.h>
namespace grpc {
typedef ::grpc_impl::CompletionQueue CompletionQueue;
typedef ::grpc_impl::ServerCompletionQueue ServerCompletionQueue;
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_H
@@ -0,0 +1,454 @@
/*
*
* Copyright 2015-2016 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.
*
*/
/// A completion queue implements a concurrent producer-consumer queue, with
/// two main API-exposed methods: \a Next and \a AsyncNext. These
/// methods are the essential component of the gRPC C++ asynchronous API.
/// There is also a \a Shutdown method to indicate that a given completion queue
/// will no longer have regular events. This must be called before the
/// completion queue is destroyed.
/// All completion queue APIs are thread-safe and may be used concurrently with
/// any other completion queue API invocation; it is acceptable to have
/// multiple threads calling \a Next or \a AsyncNext on the same or different
/// completion queues, or to call these methods concurrently with a \a Shutdown
/// elsewhere.
/// \remark{All other API calls on completion queue should be completed before
/// a completion queue destructor is called.}
#ifndef GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_IMPL_H
#define GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_IMPL_H
#include <list>
#include <grpc/impl/codegen/atm.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/sync.h>
#include <grpcpp/impl/codegen/time.h>
struct grpc_completion_queue;
namespace grpc_impl {
class Channel;
class Server;
class ServerBuilder;
template <class R>
class ClientReader;
template <class W>
class ClientWriter;
template <class W, class R>
class ClientReaderWriter;
template <class R>
class ServerReader;
template <class W>
class ServerWriter;
class ServerContextBase;
namespace internal {
template <class W, class R>
class ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler;
template <::grpc::StatusCode code>
class ErrorMethodHandler;
} // namespace internal
} // namespace grpc_impl
namespace grpc {
class ChannelInterface;
class ServerInterface;
namespace internal {
class CompletionQueueTag;
class RpcMethod;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
template <class Op1, class Op2, class Op3, class Op4, class Op5, class Op6>
class CallOpSet;
} // namespace internal
extern CoreCodegenInterface* g_core_codegen_interface;
} // namespace grpc
namespace grpc_impl {
/// A thin wrapper around \ref grpc_completion_queue (see \ref
/// src/core/lib/surface/completion_queue.h).
/// See \ref doc/cpp/perf_notes.md for notes on best practices for high
/// performance servers.
class CompletionQueue : private ::grpc::GrpcLibraryCodegen {
public:
/// Default constructor. Implicitly creates a \a grpc_completion_queue
/// instance.
CompletionQueue()
: CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING,
nullptr}) {}
/// Wrap \a take, taking ownership of the instance.
///
/// \param take The completion queue instance to wrap. Ownership is taken.
explicit CompletionQueue(grpc_completion_queue* take);
/// Destructor. Destroys the owned wrapped completion queue / instance.
~CompletionQueue() {
::grpc::g_core_codegen_interface->grpc_completion_queue_destroy(cq_);
}
/// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT.
enum NextStatus {
SHUTDOWN, ///< The completion queue has been shutdown and fully-drained
GOT_EVENT, ///< Got a new event; \a tag will be filled in with its
///< associated value; \a ok indicating its success.
TIMEOUT ///< deadline was reached.
};
/// Read from the queue, blocking until an event is available or the queue is
/// shutting down.
///
/// \param tag [out] Updated to point to the read event's tag.
/// \param ok [out] true if read a successful event, false otherwise.
///
/// Note that each tag sent to the completion queue (through RPC operations
/// or alarms) will be delivered out of the completion queue by a call to
/// Next (or a related method), regardless of whether the operation succeeded
/// or not. Success here means that this operation completed in the normal
/// valid manner.
///
/// Server-side RPC request: \a ok indicates that the RPC has indeed
/// been started. If it is false, the server has been Shutdown
/// before this particular call got matched to an incoming RPC.
///
/// Client-side StartCall/RPC invocation: \a ok indicates that the RPC is
/// going to go to the wire. If it is false, it not going to the wire. This
/// would happen if the channel is either permanently broken or
/// transiently broken but with the fail-fast option. (Note that async unary
/// RPCs don't post a CQ tag at this point, nor do client-streaming
/// or bidi-streaming RPCs that have the initial metadata corked option set.)
///
/// Client-side Write, Client-side WritesDone, Server-side Write,
/// Server-side Finish, Server-side SendInitialMetadata (which is
/// typically included in Write or Finish when not done explicitly):
/// \a ok means that the data/metadata/status/etc is going to go to the
/// wire. If it is false, it not going to the wire because the call
/// is already dead (i.e., canceled, deadline expired, other side
/// dropped the channel, etc).
///
/// Client-side Read, Server-side Read, Client-side
/// RecvInitialMetadata (which is typically included in Read if not
/// done explicitly): \a ok indicates whether there is a valid message
/// that got read. If not, you know that there are certainly no more
/// messages that can ever be read from this stream. For the client-side
/// operations, this only happens because the call is dead. For the
/// server-sider operation, though, this could happen because the client
/// has done a WritesDone already.
///
/// Client-side Finish: \a ok should always be true
///
/// Server-side AsyncNotifyWhenDone: \a ok should always be true
///
/// Alarm: \a ok is true if it expired, false if it was canceled
///
/// \return true if got an event, false if the queue is fully drained and
/// shut down.
bool Next(void** tag, bool* ok) {
return (AsyncNextInternal(tag, ok,
::grpc::g_core_codegen_interface->gpr_inf_future(
GPR_CLOCK_REALTIME)) != SHUTDOWN);
}
/// Read from the queue, blocking up to \a deadline (or the queue's shutdown).
/// Both \a tag and \a ok are updated upon success (if an event is available
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
/// \param tag [out] Upon success, updated to point to the event's tag.
/// \param ok [out] Upon success, true if a successful event, false otherwise
/// See documentation for CompletionQueue::Next for explanation of ok
/// \param deadline [in] How long to block in wait for an event.
///
/// \return The type of event read.
template <typename T>
NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) {
::grpc::TimePoint<T> deadline_tp(deadline);
return AsyncNextInternal(tag, ok, deadline_tp.raw_time());
}
/// EXPERIMENTAL
/// First executes \a F, then reads from the queue, blocking up to
/// \a deadline (or the queue's shutdown).
/// Both \a tag and \a ok are updated upon success (if an event is available
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
/// \param f [in] Function to execute before calling AsyncNext on this queue.
/// \param tag [out] Upon success, updated to point to the event's tag.
/// \param ok [out] Upon success, true if read a regular event, false
/// otherwise.
/// \param deadline [in] How long to block in wait for an event.
///
/// \return The type of event read.
template <typename T, typename F>
NextStatus DoThenAsyncNext(F&& f, void** tag, bool* ok, const T& deadline) {
CompletionQueueTLSCache cache = CompletionQueueTLSCache(this);
f();
if (cache.Flush(tag, ok)) {
return GOT_EVENT;
} else {
return AsyncNext(tag, ok, deadline);
}
}
/// Request the shutdown of the queue.
///
/// \warning This method must be called at some point if this completion queue
/// is accessed with Next or AsyncNext. \a Next will not return false
/// until this method has been called and all pending tags have been drained.
/// (Likewise for \a AsyncNext returning \a NextStatus::SHUTDOWN .)
/// Only once either one of these methods does that (that is, once the queue
/// has been \em drained) can an instance of this class be destroyed.
/// Also note that applications must ensure that no work is enqueued on this
/// completion queue after this method is called.
void Shutdown();
/// Returns a \em raw pointer to the underlying \a grpc_completion_queue
/// instance.
///
/// \warning Remember that the returned instance is owned. No transfer of
/// owership is performed.
grpc_completion_queue* cq() { return cq_; }
protected:
/// Private constructor of CompletionQueue only visible to friend classes
CompletionQueue(const grpc_completion_queue_attributes& attributes) {
cq_ = ::grpc::g_core_codegen_interface->grpc_completion_queue_create(
::grpc::g_core_codegen_interface->grpc_completion_queue_factory_lookup(
&attributes),
&attributes, NULL);
InitialAvalanching(); // reserve this for the future shutdown
}
private:
// Friends for access to server registration lists that enable checking and
// logging on shutdown
friend class ::grpc_impl::ServerBuilder;
friend class ::grpc_impl::Server;
// Friend synchronous wrappers so that they can access Pluck(), which is
// a semi-private API geared towards the synchronous implementation.
template <class R>
friend class ::grpc_impl::ClientReader;
template <class W>
friend class ::grpc_impl::ClientWriter;
template <class W, class R>
friend class ::grpc_impl::ClientReaderWriter;
template <class R>
friend class ::grpc_impl::ServerReader;
template <class W>
friend class ::grpc_impl::ServerWriter;
template <class W, class R>
friend class ::grpc_impl::internal::ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc_impl::internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc_impl::internal::ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc_impl::internal::ServerStreamingHandler;
template <class Streamer, bool WriteNeeded>
friend class ::grpc_impl::internal::TemplatedBidiStreamingHandler;
template <::grpc::StatusCode code>
friend class ::grpc_impl::internal::ErrorMethodHandler;
friend class ::grpc_impl::ServerContextBase;
friend class ::grpc::ServerInterface;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
// Friends that need access to constructor for callback CQ
friend class ::grpc_impl::Channel;
// For access to Register/CompleteAvalanching
template <class Op1, class Op2, class Op3, class Op4, class Op5, class Op6>
friend class ::grpc::internal::CallOpSet;
/// EXPERIMENTAL
/// Creates a Thread Local cache to store the first event
/// On this completion queue queued from this thread. Once
/// initialized, it must be flushed on the same thread.
class CompletionQueueTLSCache {
public:
CompletionQueueTLSCache(CompletionQueue* cq);
~CompletionQueueTLSCache();
bool Flush(void** tag, bool* ok);
private:
CompletionQueue* cq_;
bool flushed_;
};
NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
/// Wraps \a grpc_completion_queue_pluck.
/// \warning Must not be mixed with calls to \a Next.
bool Pluck(::grpc::internal::CompletionQueueTag* tag) {
auto deadline =
::grpc::g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME);
while (true) {
auto ev = ::grpc::g_core_codegen_interface->grpc_completion_queue_pluck(
cq_, tag, deadline, nullptr);
bool ok = ev.success != 0;
void* ignored = tag;
if (tag->FinalizeResult(&ignored, &ok)) {
GPR_CODEGEN_ASSERT(ignored == tag);
return ok;
}
}
}
/// Performs a single polling pluck on \a tag.
/// \warning Must not be mixed with calls to \a Next.
///
/// TODO: sreek - This calls tag->FinalizeResult() even if the cq_ is already
/// shutdown. This is most likely a bug and if it is a bug, then change this
/// implementation to simple call the other TryPluck function with a zero
/// timeout. i.e:
/// TryPluck(tag, gpr_time_0(GPR_CLOCK_REALTIME))
void TryPluck(::grpc::internal::CompletionQueueTag* tag) {
auto deadline =
::grpc::g_core_codegen_interface->gpr_time_0(GPR_CLOCK_REALTIME);
auto ev = ::grpc::g_core_codegen_interface->grpc_completion_queue_pluck(
cq_, tag, deadline, nullptr);
if (ev.type == GRPC_QUEUE_TIMEOUT) return;
bool ok = ev.success != 0;
void* ignored = tag;
// the tag must be swallowed if using TryPluck
GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
}
/// Performs a single polling pluck on \a tag. Calls tag->FinalizeResult if
/// the pluck() was successful and returned the tag.
///
/// This exects tag->FinalizeResult (if called) to return 'false' i.e expects
/// that the tag is internal not something that is returned to the user.
void TryPluck(::grpc::internal::CompletionQueueTag* tag,
gpr_timespec deadline) {
auto ev = ::grpc::g_core_codegen_interface->grpc_completion_queue_pluck(
cq_, tag, deadline, nullptr);
if (ev.type == GRPC_QUEUE_TIMEOUT || ev.type == GRPC_QUEUE_SHUTDOWN) {
return;
}
bool ok = ev.success != 0;
void* ignored = tag;
GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
}
/// Manage state of avalanching operations : completion queue tags that
/// trigger other completion queue operations. The underlying core completion
/// queue should not really shutdown until all avalanching operations have
/// been finalized. Note that we maintain the requirement that an avalanche
/// registration must take place before CQ shutdown (which must be maintained
/// elsehwere)
void InitialAvalanching() {
gpr_atm_rel_store(&avalanches_in_flight_, static_cast<gpr_atm>(1));
}
void RegisterAvalanching() {
gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_,
static_cast<gpr_atm>(1));
}
void CompleteAvalanching() {
if (gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_,
static_cast<gpr_atm>(-1)) == 1) {
::grpc::g_core_codegen_interface->grpc_completion_queue_shutdown(cq_);
}
}
void RegisterServer(const Server* server) {
(void)server;
#ifndef NDEBUG
grpc::internal::MutexLock l(&server_list_mutex_);
server_list_.push_back(server);
#endif
}
void UnregisterServer(const Server* server) {
(void)server;
#ifndef NDEBUG
grpc::internal::MutexLock l(&server_list_mutex_);
server_list_.remove(server);
#endif
}
bool ServerListEmpty() const {
#ifndef NDEBUG
grpc::internal::MutexLock l(&server_list_mutex_);
return server_list_.empty();
#endif
return true;
}
grpc_completion_queue* cq_; // owned
gpr_atm avalanches_in_flight_;
// List of servers associated with this CQ. Even though this is only used with
// NDEBUG, instantiate it in all cases since otherwise the size will be
// inconsistent.
mutable grpc::internal::Mutex server_list_mutex_;
std::list<const Server*> server_list_ /* GUARDED_BY(server_list_mutex_) */;
};
/// A specific type of completion queue used by the processing of notifications
/// by servers. Instantiated by \a ServerBuilder or Server (for health checker).
class ServerCompletionQueue : public CompletionQueue {
public:
bool IsFrequentlyPolled() { return polling_type_ != GRPC_CQ_NON_LISTENING; }
protected:
/// Default constructor
ServerCompletionQueue() : polling_type_(GRPC_CQ_DEFAULT_POLLING) {}
private:
/// \param completion_type indicates whether this is a NEXT or CALLBACK
/// completion queue.
/// \param polling_type Informs the GRPC library about the type of polling
/// allowed on this completion queue. See grpc_cq_polling_type's description
/// in grpc_types.h for more details.
/// \param shutdown_cb is the shutdown callback used for CALLBACK api queues
ServerCompletionQueue(grpc_cq_completion_type completion_type,
grpc_cq_polling_type polling_type,
grpc_experimental_completion_queue_functor* shutdown_cb)
: CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, completion_type, polling_type,
shutdown_cb}),
polling_type_(polling_type) {}
grpc_cq_polling_type polling_type_;
friend class ::grpc_impl::ServerBuilder;
friend class ::grpc_impl::Server;
};
} // namespace grpc_impl
#endif // GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_IMPL_H
@@ -0,0 +1,54 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
#define GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
namespace grpc {
namespace internal {
/// An interface allowing implementors to process and filter event tags.
class CompletionQueueTag {
public:
virtual ~CompletionQueueTag() {}
/// FinalizeResult must be called before informing user code that the
/// operation bound to the underlying core completion queue tag has
/// completed. In practice, this means:
///
/// 1. For the sync API - before returning from Pluck
/// 2. For the CQ-based async API - before returning from Next
/// 3. For the callback-based API - before invoking the user callback
///
/// This is the method that translates from core-side tag/status to
/// C++ API-observable tag/status.
///
/// The return value is the status of the operation (returning status is the
/// general behavior of this function). If this function returns false, the
/// tag is dropped and not returned from the completion queue: this concept is
/// for events that are observed at core but not requested by the user
/// application (e.g., server shutdown, for server unimplemented method
/// responses, or for cases where a server-side RPC doesn't have a completion
/// notification registered using AsyncNotifyWhenDone)
virtual bool FinalizeResult(void** tag, bool* status) = 0;
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
+41
View File
@@ -0,0 +1,41 @@
/*
*
* Copyright 2016 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 GRPCPP_IMPL_CODEGEN_CONFIG_H
#define GRPCPP_IMPL_CODEGEN_CONFIG_H
#ifndef GRPC_CUSTOM_STRING
#include <string>
#define GRPC_CUSTOM_STRING std::string
#endif
/// The following macros are deprecated and appear only for users
/// with PB files generated using gRPC 1.0.x plugins. They should
/// not be used in new code
#define GRPC_OVERRIDE override // deprecated
#define GRPC_FINAL final // deprecated
namespace grpc {
typedef GRPC_CUSTOM_STRING string;
using std::to_string;
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CONFIG_H
+127
View File
@@ -0,0 +1,127 @@
/*
*
* Copyright 2016 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 GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_H
#define GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_H
// This file should be compiled as part of grpcpp.
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
namespace grpc {
/// Implementation of the core codegen interface.
class CoreCodegen final : public CoreCodegenInterface {
private:
virtual const grpc_completion_queue_factory*
grpc_completion_queue_factory_lookup(
const grpc_completion_queue_attributes* attributes) override;
virtual grpc_completion_queue* grpc_completion_queue_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attributes,
void* reserved) override;
grpc_completion_queue* grpc_completion_queue_create_for_next(
void* reserved) override;
grpc_completion_queue* grpc_completion_queue_create_for_pluck(
void* reserved) override;
void grpc_completion_queue_shutdown(grpc_completion_queue* cq) override;
void grpc_completion_queue_destroy(grpc_completion_queue* cq) override;
grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq, void* tag,
gpr_timespec deadline,
void* reserved) override;
void* gpr_malloc(size_t size) override;
void gpr_free(void* p) override;
void grpc_init() override;
void grpc_shutdown() override;
void gpr_mu_init(gpr_mu* mu) override;
void gpr_mu_destroy(gpr_mu* mu) override;
void gpr_mu_lock(gpr_mu* mu) override;
void gpr_mu_unlock(gpr_mu* mu) override;
void gpr_cv_init(gpr_cv* cv) override;
void gpr_cv_destroy(gpr_cv* cv) override;
int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) override;
void gpr_cv_signal(gpr_cv* cv) override;
void gpr_cv_broadcast(gpr_cv* cv) override;
grpc_call_error grpc_call_start_batch(grpc_call* call, const grpc_op* ops,
size_t nops, void* tag,
void* reserved) override;
grpc_call_error grpc_call_cancel_with_status(grpc_call* call,
grpc_status_code status,
const char* description,
void* reserved) override;
void grpc_call_ref(grpc_call* call) override;
void grpc_call_unref(grpc_call* call) override;
void* grpc_call_arena_alloc(grpc_call* call, size_t length) override;
const char* grpc_call_error_to_string(grpc_call_error error) override;
grpc_byte_buffer* grpc_byte_buffer_copy(grpc_byte_buffer* bb) override;
void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) override;
size_t grpc_byte_buffer_length(grpc_byte_buffer* bb) override;
int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
grpc_byte_buffer* buffer) override;
void grpc_byte_buffer_reader_destroy(
grpc_byte_buffer_reader* reader) override;
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
grpc_slice* slice) override;
int grpc_byte_buffer_reader_peek(grpc_byte_buffer_reader* reader,
grpc_slice** slice) override;
grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slice,
size_t nslices) override;
grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
void (*destroy)(void*),
void* user_data) override;
grpc_slice grpc_slice_new_with_len(void* p, size_t len,
void (*destroy)(void*, size_t)) override;
grpc_slice grpc_empty_slice() override;
grpc_slice grpc_slice_malloc(size_t length) override;
void grpc_slice_unref(grpc_slice slice) override;
grpc_slice grpc_slice_ref(grpc_slice slice) override;
grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split) override;
grpc_slice grpc_slice_split_head(grpc_slice* s, size_t split) override;
grpc_slice grpc_slice_sub(grpc_slice s, size_t begin, size_t end) override;
void grpc_slice_buffer_add(grpc_slice_buffer* sb, grpc_slice slice) override;
void grpc_slice_buffer_pop(grpc_slice_buffer* sb) override;
grpc_slice grpc_slice_from_static_buffer(const void* buffer,
size_t length) override;
grpc_slice grpc_slice_from_copied_buffer(const void* buffer,
size_t length) override;
void grpc_metadata_array_init(grpc_metadata_array* array) override;
void grpc_metadata_array_destroy(grpc_metadata_array* array) override;
gpr_timespec gpr_inf_future(gpr_clock_type type) override;
gpr_timespec gpr_time_0(gpr_clock_type type) override;
virtual const Status& ok() override;
virtual const Status& cancelled() override;
void assert_fail(const char* failed_assertion, const char* file,
int line) override;
};
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_H
@@ -0,0 +1,164 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
#define GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
#include <grpc/impl/codegen/byte_buffer.h>
#include <grpc/impl/codegen/byte_buffer_reader.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/impl/codegen/sync.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/status.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:
virtual ~CoreCodegenInterface() = default;
/// Upon a failed assertion, log the error.
virtual void assert_fail(const char* failed_assertion, const char* file,
int line) = 0;
virtual const grpc_completion_queue_factory*
grpc_completion_queue_factory_lookup(
const grpc_completion_queue_attributes* attributes) = 0;
virtual grpc_completion_queue* grpc_completion_queue_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attributes, void* reserved) = 0;
virtual grpc_completion_queue* grpc_completion_queue_create_for_next(
void* reserved) = 0;
virtual grpc_completion_queue* grpc_completion_queue_create_for_pluck(
void* reserved) = 0;
virtual void grpc_completion_queue_shutdown(grpc_completion_queue* cq) = 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;
// These are only to be used to fix edge cases involving grpc_init and
// grpc_shutdown. Calling grpc_init from the codegen interface before
// the real grpc_init is called will cause a crash, so if you use this
// function, ensure that it is not the first call to grpc_init.
virtual void grpc_init() = 0;
virtual void grpc_shutdown() = 0;
virtual void gpr_mu_init(gpr_mu* mu) = 0;
virtual void gpr_mu_destroy(gpr_mu* mu) = 0;
virtual void gpr_mu_lock(gpr_mu* mu) = 0;
virtual void gpr_mu_unlock(gpr_mu* mu) = 0;
virtual void gpr_cv_init(gpr_cv* cv) = 0;
virtual void gpr_cv_destroy(gpr_cv* cv) = 0;
virtual int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu,
gpr_timespec abs_deadline) = 0;
virtual void gpr_cv_signal(gpr_cv* cv) = 0;
virtual void gpr_cv_broadcast(gpr_cv* cv) = 0;
virtual grpc_byte_buffer* grpc_byte_buffer_copy(grpc_byte_buffer* bb) = 0;
virtual void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) = 0;
virtual size_t grpc_byte_buffer_length(grpc_byte_buffer* bb)
GRPC_MUST_USE_RESULT = 0;
virtual int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
grpc_byte_buffer* buffer)
GRPC_MUST_USE_RESULT = 0;
virtual void grpc_byte_buffer_reader_destroy(
grpc_byte_buffer_reader* reader) = 0;
virtual int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
grpc_slice* slice) = 0;
virtual int grpc_byte_buffer_reader_peek(grpc_byte_buffer_reader* reader,
grpc_slice** slice) = 0;
virtual grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slice,
size_t nslices) = 0;
virtual grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
void (*destroy)(void*),
void* user_data) = 0;
virtual grpc_slice grpc_slice_new_with_len(void* p, size_t len,
void (*destroy)(void*,
size_t)) = 0;
virtual grpc_call_error grpc_call_start_batch(grpc_call* call,
const grpc_op* ops, size_t nops,
void* tag, void* reserved) = 0;
virtual grpc_call_error grpc_call_cancel_with_status(grpc_call* call,
grpc_status_code status,
const char* description,
void* reserved) = 0;
virtual void grpc_call_ref(grpc_call* call) = 0;
virtual void grpc_call_unref(grpc_call* call) = 0;
virtual void* grpc_call_arena_alloc(grpc_call* call, size_t length) = 0;
virtual const char* grpc_call_error_to_string(grpc_call_error error) = 0;
virtual grpc_slice grpc_empty_slice() = 0;
virtual grpc_slice grpc_slice_malloc(size_t length) = 0;
virtual void grpc_slice_unref(grpc_slice slice) = 0;
virtual grpc_slice grpc_slice_ref(grpc_slice slice) = 0;
virtual grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split) = 0;
virtual grpc_slice grpc_slice_split_head(grpc_slice* s, size_t split) = 0;
virtual grpc_slice grpc_slice_sub(grpc_slice s, size_t begin, size_t end) = 0;
virtual void grpc_slice_buffer_add(grpc_slice_buffer* sb,
grpc_slice slice) = 0;
virtual void grpc_slice_buffer_pop(grpc_slice_buffer* sb) = 0;
virtual grpc_slice grpc_slice_from_static_buffer(const void* buffer,
size_t length) = 0;
virtual grpc_slice grpc_slice_from_copied_buffer(const void* buffer,
size_t length) = 0;
virtual void grpc_metadata_array_init(grpc_metadata_array* array) = 0;
virtual void grpc_metadata_array_destroy(grpc_metadata_array* array) = 0;
virtual const Status& ok() = 0;
virtual const Status& cancelled() = 0;
virtual gpr_timespec gpr_inf_future(gpr_clock_type type) = 0;
virtual gpr_timespec gpr_time_0(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 (GPR_UNLIKELY(!(x))) { \
grpc::g_core_codegen_interface->assert_fail(#x, __FILE__, __LINE__); \
} \
} while (0)
/// Codegen specific version of \a GPR_DEBUG_ASSERT.
#ifndef NDEBUG
#define GPR_CODEGEN_DEBUG_ASSERT(x) GPR_CODEGEN_ASSERT(x)
#else
#define GPR_CODEGEN_DEBUG_ASSERT(x) \
do { \
} while (0)
#endif
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
@@ -0,0 +1,33 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_CREATE_AUTH_CONTEXT_H
#define GRPCPP_IMPL_CODEGEN_CREATE_AUTH_CONTEXT_H
#include <memory>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/security/auth_context.h>
namespace grpc {
std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call);
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_CREATE_AUTH_CONTEXT_H
@@ -0,0 +1,87 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_CODEGEN_DELEGATING_CHANNEL_H
#define GRPCPP_IMPL_CODEGEN_DELEGATING_CHANNEL_H
namespace grpc {
namespace experimental {
class DelegatingChannel : public ::grpc::ChannelInterface {
public:
virtual ~DelegatingChannel() {}
DelegatingChannel(std::shared_ptr<::grpc::ChannelInterface> delegate_channel)
: delegate_channel_(delegate_channel) {}
grpc_connectivity_state GetState(bool try_to_connect) override {
return delegate_channel()->GetState(try_to_connect);
}
std::shared_ptr<::grpc::ChannelInterface> delegate_channel() {
return delegate_channel_;
}
private:
internal::Call CreateCall(const internal::RpcMethod& method,
ClientContext* context,
::grpc_impl::CompletionQueue* cq) final {
return delegate_channel()->CreateCall(method, context, cq);
}
void PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) final {
delegate_channel()->PerformOpsOnCall(ops, call);
}
void* RegisterMethod(const char* method) final {
return delegate_channel()->RegisterMethod(method);
}
void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline,
::grpc_impl::CompletionQueue* cq,
void* tag) override {
delegate_channel()->NotifyOnStateChangeImpl(last_observed, deadline, cq,
tag);
}
bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) override {
return delegate_channel()->WaitForStateChangeImpl(last_observed, deadline);
}
internal::Call CreateCallInternal(const internal::RpcMethod& method,
ClientContext* context,
::grpc_impl::CompletionQueue* cq,
size_t interceptor_pos) final {
return delegate_channel()->CreateCallInternal(method, context, cq,
interceptor_pos);
}
::grpc_impl::CompletionQueue* CallbackCQ() final {
return delegate_channel()->CallbackCQ();
}
std::shared_ptr<::grpc::ChannelInterface> delegate_channel_;
};
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_DELEGATING_CHANNEL_H
+64
View File
@@ -0,0 +1,64 @@
/*
*
* Copyright 2016 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 GRPCPP_IMPL_CODEGEN_GRPC_LIBRARY_H
#define GRPCPP_IMPL_CODEGEN_GRPC_LIBRARY_H
#include <grpcpp/impl/codegen/core_codegen_interface.h>
namespace grpc {
class GrpcLibraryInterface {
public:
virtual ~GrpcLibraryInterface() = default;
virtual void init() = 0;
virtual void shutdown() = 0;
};
/// Initialized by \a grpc::GrpcLibraryInitializer from
/// <grpcpp/impl/grpc_library.h>
extern GrpcLibraryInterface* g_glip;
/// Classes that require gRPC to be initialized should inherit from this class.
class GrpcLibraryCodegen {
public:
GrpcLibraryCodegen(bool call_grpc_init = true) : grpc_init_called_(false) {
if (call_grpc_init) {
GPR_CODEGEN_ASSERT(g_glip &&
"gRPC library not initialized. See "
"grpc::internal::GrpcLibraryInitializer.");
g_glip->init();
grpc_init_called_ = true;
}
}
virtual ~GrpcLibraryCodegen() {
if (grpc_init_called_) {
GPR_CODEGEN_ASSERT(g_glip &&
"gRPC library not initialized. See "
"grpc::internal::GrpcLibraryInitializer.");
g_glip->shutdown();
}
}
private:
bool grpc_init_called_;
};
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_GRPC_LIBRARY_H
@@ -0,0 +1,87 @@
/*
*
* Copyright 2018 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 GRPCPP_IMPL_CODEGEN_INTERCEPTED_CHANNEL_H
#define GRPCPP_IMPL_CODEGEN_INTERCEPTED_CHANNEL_H
#include <grpcpp/impl/codegen/channel_interface.h>
namespace grpc_impl {
class CompletionQueue;
}
namespace grpc {
namespace internal {
class InterceptorBatchMethodsImpl;
/// An InterceptedChannel is available to client Interceptors. An
/// InterceptedChannel is unique to an interceptor, and when an RPC is started
/// on this channel, only those interceptors that come after this interceptor
/// see the RPC.
class InterceptedChannel : public ChannelInterface {
public:
virtual ~InterceptedChannel() { channel_ = nullptr; }
/// Get the current channel state. If the channel is in IDLE and
/// \a try_to_connect is set to true, try to connect.
grpc_connectivity_state GetState(bool try_to_connect) override {
return channel_->GetState(try_to_connect);
}
private:
InterceptedChannel(ChannelInterface* channel, size_t pos)
: channel_(channel), interceptor_pos_(pos) {}
Call CreateCall(const RpcMethod& method, ::grpc_impl::ClientContext* context,
::grpc_impl::CompletionQueue* cq) override {
return channel_->CreateCallInternal(method, context, cq, interceptor_pos_);
}
void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) override {
return channel_->PerformOpsOnCall(ops, call);
}
void* RegisterMethod(const char* method) override {
return channel_->RegisterMethod(method);
}
void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline,
::grpc_impl::CompletionQueue* cq,
void* tag) override {
return channel_->NotifyOnStateChangeImpl(last_observed, deadline, cq, tag);
}
bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) override {
return channel_->WaitForStateChangeImpl(last_observed, deadline);
}
::grpc_impl::CompletionQueue* CallbackCQ() override {
return channel_->CallbackCQ();
}
ChannelInterface* channel_;
size_t interceptor_pos_;
friend class InterceptorBatchMethodsImpl;
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_INTERCEPTED_CHANNEL_H
+227
View File
@@ -0,0 +1,227 @@
/*
*
* Copyright 2018 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 GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H
#define GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/byte_buffer.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/metadata_map.h>
namespace grpc {
class ChannelInterface;
class Status;
namespace experimental {
/// An enumeration of different possible points at which the \a Intercept
/// method of the \a Interceptor interface may be called. Any given call
/// to \a Intercept will include one or more of these hook points, and
/// each hook point makes certain types of information available to the
/// interceptor.
/// In these enumeration names, PRE_SEND means that an interception has taken
/// place between the time the application provided a certain type of data
/// (e.g., initial metadata, status) and the time that that data goes to the
/// other side. POST_SEND means that the data has been committed for going to
/// the other side (even if it has not yet been received at the other side).
/// PRE_RECV means an interception between the time that a certain
/// operation has been requested and it is available. POST_RECV means that a
/// result is available but has not yet been passed back to the application.
/// A batch of interception points will only contain either PRE or POST hooks
/// but not both types. For example, a batch with PRE_SEND hook points will not
/// contain POST_RECV or POST_SEND ops. Likewise, a batch with POST_* ops can
/// not contain PRE_* ops.
enum class InterceptionHookPoints {
/// The first three in this list are for clients and servers
PRE_SEND_INITIAL_METADATA,
PRE_SEND_MESSAGE,
POST_SEND_MESSAGE,
PRE_SEND_STATUS, // server only
PRE_SEND_CLOSE, // client only: WritesDone for stream; after write in unary
/// The following three are for hijacked clients only. A batch with PRE_RECV_*
/// hook points will never contain hook points of other types.
PRE_RECV_INITIAL_METADATA,
PRE_RECV_MESSAGE,
PRE_RECV_STATUS,
/// The following two are for all clients and servers
POST_RECV_INITIAL_METADATA,
POST_RECV_MESSAGE,
POST_RECV_STATUS, // client only
POST_RECV_CLOSE, // server only
/// This is a special hook point available to both clients and servers when
/// TryCancel() is performed.
/// - No other hook points will be present along with this.
/// - It is illegal for an interceptor to block/delay this operation.
/// - ALL interceptors see this hook point irrespective of whether the
/// RPC was hijacked or not.
PRE_SEND_CANCEL,
NUM_INTERCEPTION_HOOKS
};
/// Class that is passed as an argument to the \a Intercept method
/// of the application's \a Interceptor interface implementation. It has five
/// purposes:
/// 1. Indicate which hook points are present at a specific interception
/// 2. Allow an interceptor to inform the library that an RPC should
/// continue to the next stage of its processing (which may be another
/// interceptor or the main path of the library)
/// 3. Allow an interceptor to hijack the processing of the RPC (only for
/// client-side RPCs with PRE_SEND_INITIAL_METADATA) so that it does not
/// proceed with normal processing beyond that stage
/// 4. Access the relevant fields of an RPC at each interception point
/// 5. Set some fields of an RPC at each interception point, when possible
class InterceptorBatchMethods {
public:
virtual ~InterceptorBatchMethods() {}
/// Determine whether the current batch has an interception hook point
/// of type \a type
virtual bool QueryInterceptionHookPoint(InterceptionHookPoints type) = 0;
/// Signal that the interceptor is done intercepting the current batch of the
/// RPC. Every interceptor must either call Proceed or Hijack on each
/// interception. In most cases, only Proceed will be used. Explicit use of
/// Proceed is what enables interceptors to delay the processing of RPCs
/// while they perform other work.
/// Proceed is a no-op if the batch contains PRE_SEND_CANCEL. Simply returning
/// from the Intercept method does the job of continuing the RPC in this case.
/// This is because PRE_SEND_CANCEL is always in a separate batch and is not
/// allowed to be delayed.
virtual void Proceed() = 0;
/// Indicate that the interceptor has hijacked the RPC (only valid if the
/// batch contains send_initial_metadata on the client side). Later
/// interceptors in the interceptor list will not be called. Later batches
/// on the same RPC will go through interception, but only up to the point
/// of the hijacking interceptor.
virtual void Hijack() = 0;
/// Send Message Methods
/// GetSerializedSendMessage and GetSendMessage/ModifySendMessage are the
/// available methods to view and modify the request payload. An interceptor
/// can access the payload in either serialized form or non-serialized form
/// but not both at the same time.
/// gRPC performs serialization in a lazy manner, which means
/// that a call to GetSerializedSendMessage will result in a serialization
/// operation if the payload stored is not in the serialized form already; the
/// non-serialized form will be lost and GetSendMessage will no longer return
/// a valid pointer, and this will remain true for later interceptors too.
/// This can change however if ModifySendMessage is used to replace the
/// current payload. Note that ModifySendMessage requires a new payload
/// message in the non-serialized form. This will overwrite the existing
/// payload irrespective of whether it had been serialized earlier. Also note
/// that gRPC Async API requires early serialization of the payload which
/// means that the payload would be available in the serialized form only
/// unless an interceptor replaces the payload with ModifySendMessage.
/// Returns a modifable ByteBuffer holding the serialized form of the message
/// that is going to be sent. Valid for PRE_SEND_MESSAGE interceptions.
/// A return value of nullptr indicates that this ByteBuffer is not valid.
virtual ByteBuffer* GetSerializedSendMessage() = 0;
/// Returns a non-modifiable pointer to the non-serialized form of the message
/// to be sent. Valid for PRE_SEND_MESSAGE interceptions. A return value of
/// nullptr indicates that this field is not valid.
virtual const void* GetSendMessage() = 0;
/// Overwrites the message to be sent with \a message. \a message should be in
/// the non-serialized form expected by the method. Valid for PRE_SEND_MESSAGE
/// interceptions. Note that the interceptor is responsible for maintaining
/// the life of the message till it is serialized or it receives the
/// POST_SEND_MESSAGE interception point, whichever happens earlier. The
/// modifying interceptor may itself force early serialization by calling
/// GetSerializedSendMessage.
virtual void ModifySendMessage(const void* message) = 0;
/// Checks whether the SEND MESSAGE op succeeded. Valid for POST_SEND_MESSAGE
/// interceptions.
virtual bool GetSendMessageStatus() = 0;
/// Returns a modifiable multimap of the initial metadata to be sent. Valid
/// for PRE_SEND_INITIAL_METADATA interceptions. A value of nullptr indicates
/// that this field is not valid.
virtual std::multimap<grpc::string, grpc::string>*
GetSendInitialMetadata() = 0;
/// Returns the status to be sent. Valid for PRE_SEND_STATUS interceptions.
virtual Status GetSendStatus() = 0;
/// Overwrites the status with \a status. Valid for PRE_SEND_STATUS
/// interceptions.
virtual void ModifySendStatus(const Status& status) = 0;
/// Returns a modifiable multimap of the trailing metadata to be sent. Valid
/// for PRE_SEND_STATUS interceptions. A value of nullptr indicates
/// that this field is not valid.
virtual std::multimap<grpc::string, grpc::string>*
GetSendTrailingMetadata() = 0;
/// Returns a pointer to the modifiable received message. Note that the
/// message is already deserialized but the type is not set; the interceptor
/// should static_cast to the appropriate type before using it. This is valid
/// for PRE_RECV_MESSAGE and POST_RECV_MESSAGE interceptions; nullptr for not
/// valid
virtual void* GetRecvMessage() = 0;
/// Returns a modifiable multimap of the received initial metadata.
/// Valid for PRE_RECV_INITIAL_METADATA and POST_RECV_INITIAL_METADATA
/// interceptions; nullptr if not valid
virtual std::multimap<grpc::string_ref, grpc::string_ref>*
GetRecvInitialMetadata() = 0;
/// Returns a modifiable view of the received status on PRE_RECV_STATUS and
/// POST_RECV_STATUS interceptions; nullptr if not valid.
virtual Status* GetRecvStatus() = 0;
/// Returns a modifiable multimap of the received trailing metadata on
/// PRE_RECV_STATUS and POST_RECV_STATUS interceptions; nullptr if not valid
virtual std::multimap<grpc::string_ref, grpc::string_ref>*
GetRecvTrailingMetadata() = 0;
/// Gets an intercepted channel. When a call is started on this interceptor,
/// only interceptors after the current interceptor are created from the
/// factory objects registered with the channel. This allows calls to be
/// started from interceptors without infinite regress through the interceptor
/// list.
virtual std::unique_ptr<ChannelInterface> GetInterceptedChannel() = 0;
/// On a hijacked RPC, an interceptor can decide to fail a PRE_RECV_MESSAGE
/// op. This would be a signal to the reader that there will be no more
/// messages, or the stream has failed or been cancelled.
virtual void FailHijackedRecvMessage() = 0;
/// On a hijacked RPC/ to-be hijacked RPC, this can be called to fail a SEND
/// MESSAGE op
virtual void FailHijackedSendMessage() = 0;
};
/// Interface for an interceptor. Interceptor authors must create a class
/// that derives from this parent class.
class Interceptor {
public:
virtual ~Interceptor() {}
/// The one public method of an Interceptor interface. Override this to
/// trigger the desired actions at the hook points described above.
virtual void Intercept(InterceptorBatchMethods* methods) = 0;
};
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H
@@ -0,0 +1,556 @@
/*
*
* Copyright 2018 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 GRPCPP_IMPL_CODEGEN_INTERCEPTOR_COMMON_H
#define GRPCPP_IMPL_CODEGEN_INTERCEPTOR_COMMON_H
#include <array>
#include <functional>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/call_op_set_interface.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/intercepted_channel.h>
#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpc/impl/codegen/grpc_types.h>
namespace grpc {
namespace internal {
class InterceptorBatchMethodsImpl
: public experimental::InterceptorBatchMethods {
public:
InterceptorBatchMethodsImpl() {
for (auto i = static_cast<experimental::InterceptionHookPoints>(0);
i < experimental::InterceptionHookPoints::NUM_INTERCEPTION_HOOKS;
i = static_cast<experimental::InterceptionHookPoints>(
static_cast<size_t>(i) + 1)) {
hooks_[static_cast<size_t>(i)] = false;
}
}
~InterceptorBatchMethodsImpl() {}
bool QueryInterceptionHookPoint(
experimental::InterceptionHookPoints type) override {
return hooks_[static_cast<size_t>(type)];
}
void Proceed() override {
if (call_->client_rpc_info() != nullptr) {
return ProceedClient();
}
GPR_CODEGEN_ASSERT(call_->server_rpc_info() != nullptr);
ProceedServer();
}
void Hijack() override {
// Only the client can hijack when sending down initial metadata
GPR_CODEGEN_ASSERT(!reverse_ && ops_ != nullptr &&
call_->client_rpc_info() != nullptr);
// It is illegal to call Hijack twice
GPR_CODEGEN_ASSERT(!ran_hijacking_interceptor_);
auto* rpc_info = call_->client_rpc_info();
rpc_info->hijacked_ = true;
rpc_info->hijacked_interceptor_ = current_interceptor_index_;
ClearHookPoints();
ops_->SetHijackingState();
ran_hijacking_interceptor_ = true;
rpc_info->RunInterceptor(this, current_interceptor_index_);
}
void AddInterceptionHookPoint(experimental::InterceptionHookPoints type) {
hooks_[static_cast<size_t>(type)] = true;
}
ByteBuffer* GetSerializedSendMessage() override {
GPR_CODEGEN_ASSERT(orig_send_message_ != nullptr);
if (*orig_send_message_ != nullptr) {
GPR_CODEGEN_ASSERT(serializer_(*orig_send_message_).ok());
*orig_send_message_ = nullptr;
}
return send_message_;
}
const void* GetSendMessage() override {
GPR_CODEGEN_ASSERT(orig_send_message_ != nullptr);
return *orig_send_message_;
}
void ModifySendMessage(const void* message) override {
GPR_CODEGEN_ASSERT(orig_send_message_ != nullptr);
*orig_send_message_ = message;
}
bool GetSendMessageStatus() override { return !*fail_send_message_; }
std::multimap<grpc::string, grpc::string>* GetSendInitialMetadata() override {
return send_initial_metadata_;
}
Status GetSendStatus() override {
return Status(static_cast<StatusCode>(*code_), *error_message_,
*error_details_);
}
void ModifySendStatus(const Status& status) override {
*code_ = static_cast<grpc_status_code>(status.error_code());
*error_details_ = status.error_details();
*error_message_ = status.error_message();
}
std::multimap<grpc::string, grpc::string>* GetSendTrailingMetadata()
override {
return send_trailing_metadata_;
}
void* GetRecvMessage() override { return recv_message_; }
std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvInitialMetadata()
override {
return recv_initial_metadata_->map();
}
Status* GetRecvStatus() override { return recv_status_; }
void FailHijackedSendMessage() override {
GPR_CODEGEN_ASSERT(hooks_[static_cast<size_t>(
experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)]);
*fail_send_message_ = true;
}
std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvTrailingMetadata()
override {
return recv_trailing_metadata_->map();
}
void SetSendMessage(ByteBuffer* buf, const void** msg,
bool* fail_send_message,
std::function<Status(const void*)> serializer) {
send_message_ = buf;
orig_send_message_ = msg;
fail_send_message_ = fail_send_message;
serializer_ = serializer;
}
void SetSendInitialMetadata(
std::multimap<grpc::string, grpc::string>* metadata) {
send_initial_metadata_ = metadata;
}
void SetSendStatus(grpc_status_code* code, grpc::string* error_details,
grpc::string* error_message) {
code_ = code;
error_details_ = error_details;
error_message_ = error_message;
}
void SetSendTrailingMetadata(
std::multimap<grpc::string, grpc::string>* metadata) {
send_trailing_metadata_ = metadata;
}
void SetRecvMessage(void* message, bool* got_message) {
recv_message_ = message;
got_message_ = got_message;
}
void SetRecvInitialMetadata(MetadataMap* map) {
recv_initial_metadata_ = map;
}
void SetRecvStatus(Status* status) { recv_status_ = status; }
void SetRecvTrailingMetadata(MetadataMap* map) {
recv_trailing_metadata_ = map;
}
std::unique_ptr<ChannelInterface> GetInterceptedChannel() override {
auto* info = call_->client_rpc_info();
if (info == nullptr) {
return std::unique_ptr<ChannelInterface>(nullptr);
}
// The intercepted channel starts from the interceptor just after the
// current interceptor
return std::unique_ptr<ChannelInterface>(new InterceptedChannel(
info->channel(), current_interceptor_index_ + 1));
}
void FailHijackedRecvMessage() override {
GPR_CODEGEN_ASSERT(hooks_[static_cast<size_t>(
experimental::InterceptionHookPoints::PRE_RECV_MESSAGE)]);
*got_message_ = false;
}
// Clears all state
void ClearState() {
reverse_ = false;
ran_hijacking_interceptor_ = false;
ClearHookPoints();
}
// Prepares for Post_recv operations
void SetReverse() {
reverse_ = true;
ran_hijacking_interceptor_ = false;
ClearHookPoints();
}
// This needs to be set before interceptors are run
void SetCall(Call* call) { call_ = call; }
// This needs to be set before interceptors are run using RunInterceptors().
// Alternatively, RunInterceptors(std::function<void(void)> f) can be used.
void SetCallOpSetInterface(CallOpSetInterface* ops) { ops_ = ops; }
// SetCall should have been called before this.
// Returns true if the interceptors list is empty
bool InterceptorsListEmpty() {
auto* client_rpc_info = call_->client_rpc_info();
if (client_rpc_info != nullptr) {
if (client_rpc_info->interceptors_.size() == 0) {
return true;
} else {
return false;
}
}
auto* server_rpc_info = call_->server_rpc_info();
if (server_rpc_info == nullptr ||
server_rpc_info->interceptors_.size() == 0) {
return true;
}
return false;
}
// This should be used only by subclasses of CallOpSetInterface. SetCall and
// SetCallOpSetInterface should have been called before this. After all the
// interceptors are done running, either ContinueFillOpsAfterInterception or
// ContinueFinalizeOpsAfterInterception will be called. Note that neither of
// them is invoked if there were no interceptors registered.
bool RunInterceptors() {
GPR_CODEGEN_ASSERT(ops_);
auto* client_rpc_info = call_->client_rpc_info();
if (client_rpc_info != nullptr) {
if (client_rpc_info->interceptors_.size() == 0) {
return true;
} else {
RunClientInterceptors();
return false;
}
}
auto* server_rpc_info = call_->server_rpc_info();
if (server_rpc_info == nullptr ||
server_rpc_info->interceptors_.size() == 0) {
return true;
}
RunServerInterceptors();
return false;
}
// Returns true if no interceptors are run. Returns false otherwise if there
// are interceptors registered. After the interceptors are done running \a f
// will be invoked. This is to be used only by BaseAsyncRequest and
// SyncRequest.
bool RunInterceptors(std::function<void(void)> f) {
// This is used only by the server for initial call request
GPR_CODEGEN_ASSERT(reverse_ == true);
GPR_CODEGEN_ASSERT(call_->client_rpc_info() == nullptr);
auto* server_rpc_info = call_->server_rpc_info();
if (server_rpc_info == nullptr ||
server_rpc_info->interceptors_.size() == 0) {
return true;
}
callback_ = std::move(f);
RunServerInterceptors();
return false;
}
private:
void RunClientInterceptors() {
auto* rpc_info = call_->client_rpc_info();
if (!reverse_) {
current_interceptor_index_ = 0;
} else {
if (rpc_info->hijacked_) {
current_interceptor_index_ = rpc_info->hijacked_interceptor_;
} else {
current_interceptor_index_ = rpc_info->interceptors_.size() - 1;
}
}
rpc_info->RunInterceptor(this, current_interceptor_index_);
}
void RunServerInterceptors() {
auto* rpc_info = call_->server_rpc_info();
if (!reverse_) {
current_interceptor_index_ = 0;
} else {
current_interceptor_index_ = rpc_info->interceptors_.size() - 1;
}
rpc_info->RunInterceptor(this, current_interceptor_index_);
}
void ProceedClient() {
auto* rpc_info = call_->client_rpc_info();
if (rpc_info->hijacked_ && !reverse_ &&
current_interceptor_index_ == rpc_info->hijacked_interceptor_ &&
!ran_hijacking_interceptor_) {
// We now need to provide hijacked recv ops to this interceptor
ClearHookPoints();
ops_->SetHijackingState();
ran_hijacking_interceptor_ = true;
rpc_info->RunInterceptor(this, current_interceptor_index_);
return;
}
if (!reverse_) {
current_interceptor_index_++;
// We are going down the stack of interceptors
if (current_interceptor_index_ < rpc_info->interceptors_.size()) {
if (rpc_info->hijacked_ &&
current_interceptor_index_ > rpc_info->hijacked_interceptor_) {
// This is a hijacked RPC and we are done with hijacking
ops_->ContinueFillOpsAfterInterception();
} else {
rpc_info->RunInterceptor(this, current_interceptor_index_);
}
} else {
// we are done running all the interceptors without any hijacking
ops_->ContinueFillOpsAfterInterception();
}
} else {
// We are going up the stack of interceptors
if (current_interceptor_index_ > 0) {
// Continue running interceptors
current_interceptor_index_--;
rpc_info->RunInterceptor(this, current_interceptor_index_);
} else {
// we are done running all the interceptors without any hijacking
ops_->ContinueFinalizeResultAfterInterception();
}
}
}
void ProceedServer() {
auto* rpc_info = call_->server_rpc_info();
if (!reverse_) {
current_interceptor_index_++;
if (current_interceptor_index_ < rpc_info->interceptors_.size()) {
return rpc_info->RunInterceptor(this, current_interceptor_index_);
} else if (ops_) {
return ops_->ContinueFillOpsAfterInterception();
}
} else {
// We are going up the stack of interceptors
if (current_interceptor_index_ > 0) {
// Continue running interceptors
current_interceptor_index_--;
return rpc_info->RunInterceptor(this, current_interceptor_index_);
} else if (ops_) {
return ops_->ContinueFinalizeResultAfterInterception();
}
}
GPR_CODEGEN_ASSERT(callback_);
callback_();
}
void ClearHookPoints() {
for (auto i = static_cast<experimental::InterceptionHookPoints>(0);
i < experimental::InterceptionHookPoints::NUM_INTERCEPTION_HOOKS;
i = static_cast<experimental::InterceptionHookPoints>(
static_cast<size_t>(i) + 1)) {
hooks_[static_cast<size_t>(i)] = false;
}
}
std::array<bool,
static_cast<size_t>(
experimental::InterceptionHookPoints::NUM_INTERCEPTION_HOOKS)>
hooks_;
size_t current_interceptor_index_ = 0; // Current iterator
bool reverse_ = false;
bool ran_hijacking_interceptor_ = false;
Call* call_ = nullptr; // The Call object is present along with CallOpSet
// object/callback
CallOpSetInterface* ops_ = nullptr;
std::function<void(void)> callback_;
ByteBuffer* send_message_ = nullptr;
bool* fail_send_message_ = nullptr;
const void** orig_send_message_ = nullptr;
std::function<Status(const void*)> serializer_;
std::multimap<grpc::string, grpc::string>* send_initial_metadata_;
grpc_status_code* code_ = nullptr;
grpc::string* error_details_ = nullptr;
grpc::string* error_message_ = nullptr;
std::multimap<grpc::string, grpc::string>* send_trailing_metadata_ = nullptr;
void* recv_message_ = nullptr;
bool* got_message_ = nullptr;
MetadataMap* recv_initial_metadata_ = nullptr;
Status* recv_status_ = nullptr;
MetadataMap* recv_trailing_metadata_ = nullptr;
};
// A special implementation of InterceptorBatchMethods to send a Cancel
// notification down the interceptor stack
class CancelInterceptorBatchMethods
: public experimental::InterceptorBatchMethods {
public:
bool QueryInterceptionHookPoint(
experimental::InterceptionHookPoints type) override {
if (type == experimental::InterceptionHookPoints::PRE_SEND_CANCEL) {
return true;
} else {
return false;
}
}
void Proceed() override {
// This is a no-op. For actual continuation of the RPC simply needs to
// return from the Intercept method
}
void Hijack() override {
// Only the client can hijack when sending down initial metadata
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call Hijack on a method which has a "
"Cancel notification");
}
ByteBuffer* GetSerializedSendMessage() override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call GetSendMessage on a method which "
"has a Cancel notification");
return nullptr;
}
bool GetSendMessageStatus() override {
GPR_CODEGEN_ASSERT(
false &&
"It is illegal to call GetSendMessageStatus on a method which "
"has a Cancel notification");
return false;
}
const void* GetSendMessage() override {
GPR_CODEGEN_ASSERT(
false &&
"It is illegal to call GetOriginalSendMessage on a method which "
"has a Cancel notification");
return nullptr;
}
void ModifySendMessage(const void* /*message*/) override {
GPR_CODEGEN_ASSERT(
false &&
"It is illegal to call ModifySendMessage on a method which "
"has a Cancel notification");
}
std::multimap<grpc::string, grpc::string>* GetSendInitialMetadata() override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call GetSendInitialMetadata on a "
"method which has a Cancel notification");
return nullptr;
}
Status GetSendStatus() override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call GetSendStatus on a method which "
"has a Cancel notification");
return Status();
}
void ModifySendStatus(const Status& /*status*/) override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call ModifySendStatus on a method "
"which has a Cancel notification");
return;
}
std::multimap<grpc::string, grpc::string>* GetSendTrailingMetadata()
override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call GetSendTrailingMetadata on a "
"method which has a Cancel notification");
return nullptr;
}
void* GetRecvMessage() override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call GetRecvMessage on a method which "
"has a Cancel notification");
return nullptr;
}
std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvInitialMetadata()
override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call GetRecvInitialMetadata on a "
"method which has a Cancel notification");
return nullptr;
}
Status* GetRecvStatus() override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call GetRecvStatus on a method which "
"has a Cancel notification");
return nullptr;
}
std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvTrailingMetadata()
override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call GetRecvTrailingMetadata on a "
"method which has a Cancel notification");
return nullptr;
}
std::unique_ptr<ChannelInterface> GetInterceptedChannel() override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call GetInterceptedChannel on a "
"method which has a Cancel notification");
return std::unique_ptr<ChannelInterface>(nullptr);
}
void FailHijackedRecvMessage() override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call FailHijackedRecvMessage on a "
"method which has a Cancel notification");
}
void FailHijackedSendMessage() override {
GPR_CODEGEN_ASSERT(false &&
"It is illegal to call FailHijackedSendMessage on a "
"method which has a Cancel notification");
}
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_INTERCEPTOR_COMMON_H
@@ -0,0 +1,93 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_CODEGEN_MESSAGE_ALLOCATOR_H
#define GRPCPP_IMPL_CODEGEN_MESSAGE_ALLOCATOR_H
namespace grpc {
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
#endif
// NOTE: This is an API for advanced users who need custom allocators.
// Per rpc struct for the allocator. This is the interface to return to user.
class RpcAllocatorState {
public:
virtual ~RpcAllocatorState() = default;
// Optionally deallocate request early to reduce the size of working set.
// A custom MessageAllocator needs to be registered to make use of this.
// This is not abstract because implementing it is optional.
virtual void FreeRequest() {}
};
// This is the interface returned by the allocator.
// grpc library will call the methods to get request/response pointers and to
// release the object when it is done.
template <typename RequestT, typename ResponseT>
class MessageHolder : public RpcAllocatorState {
public:
// Release this object. For example, if the custom allocator's
// AllocateMessasge creates an instance of a subclass with new, the Release()
// should do a "delete this;".
virtual void Release() = 0;
RequestT* request() { return request_; }
ResponseT* response() { return response_; }
protected:
void set_request(RequestT* request) { request_ = request; }
void set_response(ResponseT* response) { response_ = response; }
private:
// NOTE: subclasses should set these pointers.
RequestT* request_;
ResponseT* response_;
};
// A custom allocator can be set via the generated code to a callback unary
// method, such as SetMessageAllocatorFor_Echo(custom_allocator). The allocator
// needs to be alive for the lifetime of the server.
// Implementations need to be thread-safe.
template <typename RequestT, typename ResponseT>
class MessageAllocator {
public:
virtual ~MessageAllocator() = default;
virtual MessageHolder<RequestT, ResponseT>* AllocateMessages() = 0;
};
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
} // namespace experimental
#endif
// TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
using ::grpc::RpcAllocatorState;
template <typename RequestT, typename ResponseT>
using MessageHolder = ::grpc::MessageHolder<RequestT, ResponseT>;
template <typename RequestT, typename ResponseT>
using MessageAllocator = ::grpc::MessageAllocator<RequestT, ResponseT>;
} // namespace experimental
#endif
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_MESSAGE_ALLOCATOR_H
+105
View File
@@ -0,0 +1,105 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_METADATA_MAP_H
#define GRPCPP_IMPL_CODEGEN_METADATA_MAP_H
#include <map>
#include <grpc/impl/codegen/log.h>
#include <grpcpp/impl/codegen/slice.h>
namespace grpc {
namespace internal {
const char kBinaryErrorDetailsKey[] = "grpc-status-details-bin";
class MetadataMap {
public:
MetadataMap() { Setup(); }
~MetadataMap() { Destroy(); }
grpc::string GetBinaryErrorDetails() {
// if filled_, extract from the multimap for O(log(n))
if (filled_) {
auto iter = map_.find(kBinaryErrorDetailsKey);
if (iter != map_.end()) {
return grpc::string(iter->second.begin(), iter->second.length());
}
}
// if not yet filled, take the O(n) lookup to avoid allocating the
// multimap until it is requested.
// TODO(ncteisen): plumb this through core as a first class object, just
// like code and message.
else {
for (size_t i = 0; i < arr_.count; i++) {
if (strncmp(reinterpret_cast<const char*>(
GRPC_SLICE_START_PTR(arr_.metadata[i].key)),
kBinaryErrorDetailsKey,
GRPC_SLICE_LENGTH(arr_.metadata[i].key)) == 0) {
return grpc::string(reinterpret_cast<const char*>(
GRPC_SLICE_START_PTR(arr_.metadata[i].value)),
GRPC_SLICE_LENGTH(arr_.metadata[i].value));
}
}
}
return grpc::string();
}
std::multimap<grpc::string_ref, grpc::string_ref>* map() {
FillMap();
return &map_;
}
grpc_metadata_array* arr() { return &arr_; }
void Reset() {
filled_ = false;
map_.clear();
Destroy();
Setup();
}
private:
bool filled_ = false;
grpc_metadata_array arr_;
std::multimap<grpc::string_ref, grpc::string_ref> map_;
void Destroy() {
g_core_codegen_interface->grpc_metadata_array_destroy(&arr_);
}
void Setup() { memset(&arr_, 0, sizeof(arr_)); }
void FillMap() {
if (filled_) return;
filled_ = true;
for (size_t i = 0; i < arr_.count; i++) {
// TODO(yangg) handle duplicates?
map_.insert(std::pair<grpc::string_ref, grpc::string_ref>(
StringRefFromSlice(&arr_.metadata[i].key),
StringRefFromSlice(&arr_.metadata[i].value)));
}
}
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_METADATA_MAP_H
@@ -0,0 +1,73 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_CODEGEN_METHOD_HANDLER_H
#define GRPCPP_IMPL_CODEGEN_METHOD_HANDLER_H
#include <grpcpp/impl/codegen/method_handler_impl.h>
namespace grpc {
namespace internal {
template <class ServiceType, class RequestType, class ResponseType>
using BidiStreamingHandler =
::grpc_impl::internal::BidiStreamingHandler<ServiceType, RequestType,
ResponseType>;
template <class ServiceType, class RequestType, class ResponseType>
using RpcMethodHandler =
::grpc_impl::internal::RpcMethodHandler<ServiceType, RequestType,
ResponseType>;
template <class ServiceType, class RequestType, class ResponseType>
using ClientStreamingHandler =
::grpc_impl::internal::ClientStreamingHandler<ServiceType, RequestType,
ResponseType>;
template <class ServiceType, class RequestType, class ResponseType>
using ServerStreamingHandler =
::grpc_impl::internal::ServerStreamingHandler<ServiceType, RequestType,
ResponseType>;
template <class Streamer, bool WriteNeeded>
using TemplatedBidiStreamingHandler =
::grpc_impl::internal::TemplatedBidiStreamingHandler<Streamer, WriteNeeded>;
template <class RequestType, class ResponseType>
using StreamedUnaryHandler =
::grpc_impl::internal::StreamedUnaryHandler<RequestType, ResponseType>;
template <class RequestType, class ResponseType>
using SplitServerStreamingHandler =
::grpc_impl::internal::SplitServerStreamingHandler<RequestType,
ResponseType>;
template <StatusCode code>
using ErrorMethodHandler = ::grpc_impl::internal::ErrorMethodHandler<code>;
using UnknownMethodHandler = ::grpc_impl::internal::UnknownMethodHandler;
using ResourceExhaustedHandler =
::grpc_impl::internal::ResourceExhaustedHandler;
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_METHOD_HANDLER_H
@@ -0,0 +1,388 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
#define GRPCPP_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
#include <grpcpp/impl/codegen/byte_buffer.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/rpc_service_method.h>
#include <grpcpp/impl/codegen/sync_stream_impl.h>
namespace grpc_impl {
namespace internal {
// Invoke the method handler, fill in the status, and
// return whether or not we finished safely (without an exception).
// Note that exception handling is 0-cost in most compiler/library
// implementations (except when an exception is actually thrown),
// so this process doesn't require additional overhead in the common case.
// Additionally, we don't need to return if we caught an exception or not;
// the handling is the same in either case.
template <class Callable>
::grpc::Status CatchingFunctionHandler(Callable&& handler) {
#if GRPC_ALLOW_EXCEPTIONS
try {
return handler();
} catch (...) {
return ::grpc::Status(::grpc::StatusCode::UNKNOWN,
"Unexpected error in RPC handling");
}
#else // GRPC_ALLOW_EXCEPTIONS
return handler();
#endif // GRPC_ALLOW_EXCEPTIONS
}
/// A wrapper class of an application provided rpc method handler.
template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler : public ::grpc::internal::MethodHandler {
public:
RpcMethodHandler(
std::function<::grpc::Status(ServiceType*, ::grpc_impl::ServerContext*,
const RequestType*, ResponseType*)>
func,
ServiceType* service)
: func_(func), service_(service) {}
void RunHandler(const HandlerParameter& param) final {
ResponseType rsp;
::grpc::Status status = param.status;
if (status.ok()) {
status = CatchingFunctionHandler([this, &param, &rsp] {
return func_(
service_,
static_cast<::grpc_impl::ServerContext*>(param.server_context),
static_cast<RequestType*>(param.request), &rsp);
});
static_cast<RequestType*>(param.request)->~RequestType();
}
GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpServerSendStatus>
ops;
ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
if (status.ok()) {
status = ops.SendMessagePtr(&rsp);
}
ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
param.call->cq()->Pluck(&ops);
}
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
::grpc::Status* status, void** /*handler_data*/) final {
::grpc::ByteBuffer buf;
buf.set_buffer(req);
auto* request =
new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
call, sizeof(RequestType))) RequestType();
*status =
::grpc::SerializationTraits<RequestType>::Deserialize(&buf, request);
buf.Release();
if (status->ok()) {
return request;
}
request->~RequestType();
return nullptr;
}
private:
/// Application provided rpc handler function.
std::function<::grpc::Status(ServiceType*, ::grpc_impl::ServerContext*,
const RequestType*, ResponseType*)>
func_;
// The class the above handler function lives in.
ServiceType* service_;
};
/// A wrapper class of an application provided client streaming handler.
template <class ServiceType, class RequestType, class ResponseType>
class ClientStreamingHandler : public ::grpc::internal::MethodHandler {
public:
ClientStreamingHandler(
std::function<::grpc::Status(ServiceType*, ::grpc_impl::ServerContext*,
::grpc_impl::ServerReader<RequestType>*,
ResponseType*)>
func,
ServiceType* service)
: func_(func), service_(service) {}
void RunHandler(const HandlerParameter& param) final {
::grpc_impl::ServerReader<RequestType> reader(
param.call,
static_cast<::grpc_impl::ServerContext*>(param.server_context));
ResponseType rsp;
::grpc::Status status =
CatchingFunctionHandler([this, &param, &reader, &rsp] {
return func_(
service_,
static_cast<::grpc_impl::ServerContext*>(param.server_context),
&reader, &rsp);
});
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpServerSendStatus>
ops;
if (!param.server_context->sent_initial_metadata_) {
ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
}
if (status.ok()) {
status = ops.SendMessagePtr(&rsp);
}
ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
param.call->cq()->Pluck(&ops);
}
private:
std::function<::grpc::Status(ServiceType*, ::grpc_impl::ServerContext*,
::grpc_impl::ServerReader<RequestType>*,
ResponseType*)>
func_;
ServiceType* service_;
};
/// A wrapper class of an application provided server streaming handler.
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler : public ::grpc::internal::MethodHandler {
public:
ServerStreamingHandler(
std::function<::grpc::Status(ServiceType*, ::grpc_impl::ServerContext*,
const RequestType*,
::grpc_impl::ServerWriter<ResponseType>*)>
func,
ServiceType* service)
: func_(func), service_(service) {}
void RunHandler(const HandlerParameter& param) final {
::grpc::Status status = param.status;
if (status.ok()) {
::grpc_impl::ServerWriter<ResponseType> writer(
param.call,
static_cast<::grpc_impl::ServerContext*>(param.server_context));
status = CatchingFunctionHandler([this, &param, &writer] {
return func_(
service_,
static_cast<::grpc_impl::ServerContext*>(param.server_context),
static_cast<RequestType*>(param.request), &writer);
});
static_cast<RequestType*>(param.request)->~RequestType();
}
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpServerSendStatus>
ops;
if (!param.server_context->sent_initial_metadata_) {
ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
}
ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
if (param.server_context->has_pending_ops_) {
param.call->cq()->Pluck(&param.server_context->pending_ops_);
}
param.call->cq()->Pluck(&ops);
}
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
::grpc::Status* status, void** /*handler_data*/) final {
::grpc::ByteBuffer buf;
buf.set_buffer(req);
auto* request =
new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
call, sizeof(RequestType))) RequestType();
*status =
::grpc::SerializationTraits<RequestType>::Deserialize(&buf, request);
buf.Release();
if (status->ok()) {
return request;
}
request->~RequestType();
return nullptr;
}
private:
std::function<::grpc::Status(ServiceType*, ::grpc_impl::ServerContext*,
const RequestType*,
::grpc_impl::ServerWriter<ResponseType>*)>
func_;
ServiceType* service_;
};
/// A wrapper class of an application provided bidi-streaming handler.
/// This also applies to server-streamed implementation of a unary method
/// with the additional requirement that such methods must have done a
/// write for status to be ok
/// Since this is used by more than 1 class, the service is not passed in.
/// Instead, it is expected to be an implicitly-captured argument of func
/// (through bind or something along those lines)
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler : public ::grpc::internal::MethodHandler {
public:
TemplatedBidiStreamingHandler(
std::function<::grpc::Status(::grpc_impl::ServerContext*, Streamer*)>
func)
: func_(func), write_needed_(WriteNeeded) {}
void RunHandler(const HandlerParameter& param) final {
Streamer stream(param.call, static_cast<::grpc_impl::ServerContext*>(
param.server_context));
::grpc::Status status = CatchingFunctionHandler([this, &param, &stream] {
return func_(
static_cast<::grpc_impl::ServerContext*>(param.server_context),
&stream);
});
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpServerSendStatus>
ops;
if (!param.server_context->sent_initial_metadata_) {
ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
if (write_needed_ && status.ok()) {
// If we needed a write but never did one, we need to mark the
// status as a fail
status = ::grpc::Status(::grpc::StatusCode::INTERNAL,
"Service did not provide response message");
}
}
ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
if (param.server_context->has_pending_ops_) {
param.call->cq()->Pluck(&param.server_context->pending_ops_);
}
param.call->cq()->Pluck(&ops);
}
private:
std::function<::grpc::Status(::grpc_impl::ServerContext*, Streamer*)> func_;
const bool write_needed_;
};
template <class ServiceType, class RequestType, class ResponseType>
class BidiStreamingHandler
: public TemplatedBidiStreamingHandler<
::grpc_impl::ServerReaderWriter<ResponseType, RequestType>, false> {
public:
BidiStreamingHandler(
std::function<::grpc::Status(
ServiceType*, ::grpc_impl::ServerContext*,
::grpc_impl::ServerReaderWriter<ResponseType, RequestType>*)>
func,
ServiceType* service)
: TemplatedBidiStreamingHandler<
::grpc_impl::ServerReaderWriter<ResponseType, RequestType>, false>(
std::bind(func, service, std::placeholders::_1,
std::placeholders::_2)) {}
};
template <class RequestType, class ResponseType>
class StreamedUnaryHandler
: public TemplatedBidiStreamingHandler<
::grpc_impl::ServerUnaryStreamer<RequestType, ResponseType>, true> {
public:
explicit StreamedUnaryHandler(
std::function<::grpc::Status(
::grpc_impl::ServerContext*,
::grpc_impl::ServerUnaryStreamer<RequestType, ResponseType>*)>
func)
: TemplatedBidiStreamingHandler<
::grpc_impl::ServerUnaryStreamer<RequestType, ResponseType>, true>(
func) {}
};
template <class RequestType, class ResponseType>
class SplitServerStreamingHandler
: public TemplatedBidiStreamingHandler<
::grpc_impl::ServerSplitStreamer<RequestType, ResponseType>, false> {
public:
explicit SplitServerStreamingHandler(
std::function<::grpc::Status(
::grpc_impl::ServerContext*,
::grpc_impl::ServerSplitStreamer<RequestType, ResponseType>*)>
func)
: TemplatedBidiStreamingHandler<
::grpc_impl::ServerSplitStreamer<RequestType, ResponseType>, false>(
func) {}
};
/// General method handler class for errors that prevent real method use
/// e.g., handle unknown method by returning UNIMPLEMENTED error.
template <::grpc::StatusCode code>
class ErrorMethodHandler : public ::grpc::internal::MethodHandler {
public:
template <class T>
static void FillOps(::grpc_impl::ServerContextBase* context, T* ops) {
::grpc::Status status(code, "");
if (!context->sent_initial_metadata_) {
ops->SendInitialMetadata(&context->initial_metadata_,
context->initial_metadata_flags());
if (context->compression_level_set()) {
ops->set_compression_level(context->compression_level());
}
context->sent_initial_metadata_ = true;
}
ops->ServerSendStatus(&context->trailing_metadata_, status);
}
void RunHandler(const HandlerParameter& param) final {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpServerSendStatus>
ops;
FillOps(param.server_context, &ops);
param.call->PerformOps(&ops);
param.call->cq()->Pluck(&ops);
}
void* Deserialize(grpc_call* /*call*/, grpc_byte_buffer* req,
::grpc::Status* /*status*/, void** /*handler_data*/) final {
// We have to destroy any request payload
if (req != nullptr) {
::grpc::g_core_codegen_interface->grpc_byte_buffer_destroy(req);
}
return nullptr;
}
};
typedef ErrorMethodHandler<::grpc::StatusCode::UNIMPLEMENTED>
UnknownMethodHandler;
typedef ErrorMethodHandler<::grpc::StatusCode::RESOURCE_EXHAUSTED>
ResourceExhaustedHandler;
} // namespace internal
} // namespace grpc_impl
#endif // GRPCPP_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
+61
View File
@@ -0,0 +1,61 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_RPC_METHOD_H
#define GRPCPP_IMPL_CODEGEN_RPC_METHOD_H
#include <memory>
#include <grpcpp/impl/codegen/channel_interface.h>
namespace grpc {
namespace internal {
/// Descriptor of an RPC method
class RpcMethod {
public:
enum RpcType {
NORMAL_RPC = 0,
CLIENT_STREAMING, // request streaming
SERVER_STREAMING, // response streaming
BIDI_STREAMING
};
RpcMethod(const char* name, RpcType type)
: name_(name), method_type_(type), channel_tag_(NULL) {}
RpcMethod(const char* name, RpcType type,
const std::shared_ptr<ChannelInterface>& channel)
: name_(name),
method_type_(type),
channel_tag_(channel->RegisterMethod(name)) {}
const char* name() const { return name_; }
RpcType method_type() const { return method_type_; }
void SetMethodType(RpcType type) { method_type_ = type; }
void* channel_tag() const { return channel_tag_; }
private:
const char* const name_;
RpcType method_type_;
void* const channel_tag_;
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_RPC_METHOD_H
@@ -0,0 +1,156 @@
/*
*
* Copyright 2016 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 GRPCPP_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
#define GRPCPP_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
#include <climits>
#include <functional>
#include <map>
#include <memory>
#include <vector>
#include <grpc/impl/codegen/log.h>
#include <grpcpp/impl/codegen/byte_buffer.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/rpc_method.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
class ServerContextBase;
} // namespace grpc_impl
namespace grpc {
namespace internal {
/// Base class for running an RPC handler.
class MethodHandler {
public:
virtual ~MethodHandler() {}
struct HandlerParameter {
/// Constructor for HandlerParameter
///
/// \param c : the gRPC Call structure for this server call
/// \param context : the ServerContext structure for this server call
/// \param req : the request payload, if appropriate for this RPC
/// \param req_status : the request status after any interceptors have run
/// \param handler_data: internal data for the handler.
/// \param requester : used only by the callback API. It is a function
/// called by the RPC Controller to request another RPC (and also
/// to set up the state required to make that request possible)
HandlerParameter(Call* c, ::grpc_impl::ServerContextBase* context,
void* req, Status req_status, void* handler_data,
std::function<void()> requester)
: call(c),
server_context(context),
request(req),
status(req_status),
internal_data(handler_data),
call_requester(std::move(requester)) {}
~HandlerParameter() {}
Call* const call;
::grpc_impl::ServerContextBase* const server_context;
void* const request;
const Status status;
void* const internal_data;
const std::function<void()> call_requester;
};
virtual void RunHandler(const HandlerParameter& param) = 0;
/* Returns a pointer to the deserialized request. \a status reflects the
result of deserialization. This pointer and the status should be filled in
a HandlerParameter and passed to RunHandler. It is illegal to access the
pointer after calling RunHandler. Ownership of the deserialized request is
retained by the handler. Returns nullptr if deserialization failed. */
virtual void* Deserialize(grpc_call* /*call*/, grpc_byte_buffer* req,
Status* /*status*/, void** /*handler_data*/) {
GPR_CODEGEN_ASSERT(req == nullptr);
return nullptr;
}
};
/// Server side rpc method class
class RpcServiceMethod : public RpcMethod {
public:
/// Takes ownership of the handler
RpcServiceMethod(const char* name, RpcMethod::RpcType type,
MethodHandler* handler)
: RpcMethod(name, type),
server_tag_(nullptr),
api_type_(ApiType::SYNC),
handler_(handler) {}
enum class ApiType {
SYNC,
ASYNC,
RAW,
CALL_BACK, // not CALLBACK because that is reserved in Windows
RAW_CALL_BACK,
};
void set_server_tag(void* tag) { server_tag_ = tag; }
void* server_tag() const { return server_tag_; }
/// if MethodHandler is nullptr, then this is an async method
MethodHandler* handler() const { return handler_.get(); }
ApiType api_type() const { return api_type_; }
void SetHandler(MethodHandler* handler) { handler_.reset(handler); }
void SetServerApiType(RpcServiceMethod::ApiType type) {
if ((api_type_ == ApiType::SYNC) &&
(type == ApiType::ASYNC || type == ApiType::RAW)) {
// this marks this method as async
handler_.reset();
} else if (api_type_ != ApiType::SYNC) {
// this is not an error condition, as it allows users to declare a server
// like WithRawMethod_foo<AsyncService>. However since it
// overwrites behavior, it should be logged.
gpr_log(
GPR_INFO,
"You are marking method %s as '%s', even though it was "
"previously marked '%s'. This behavior will overwrite the original "
"behavior. If you expected this then ignore this message.",
name(), TypeToString(api_type_), TypeToString(type));
}
api_type_ = type;
}
private:
void* server_tag_;
ApiType api_type_;
std::unique_ptr<MethodHandler> handler_;
const char* TypeToString(RpcServiceMethod::ApiType type) {
switch (type) {
case ApiType::SYNC:
return "sync";
case ApiType::ASYNC:
return "async";
case ApiType::RAW:
return "raw";
case ApiType::CALL_BACK:
return "callback";
case ApiType::RAW_CALL_BACK:
return "raw_callback";
default:
GPR_UNREACHABLE_CODE(return "unknown");
}
}
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
@@ -0,0 +1,95 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
#define GRPCPP_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
#include <iterator>
#include <vector>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/string_ref.h>
struct grpc_auth_context;
struct grpc_auth_property;
struct grpc_auth_property_iterator;
namespace grpc {
class SecureAuthContext;
typedef std::pair<string_ref, string_ref> AuthProperty;
class AuthPropertyIterator
: public std::iterator<std::input_iterator_tag, const AuthProperty> {
public:
~AuthPropertyIterator();
AuthPropertyIterator& operator++();
AuthPropertyIterator operator++(int);
bool operator==(const AuthPropertyIterator& rhs) const;
bool operator!=(const AuthPropertyIterator& rhs) const;
const AuthProperty operator*();
protected:
AuthPropertyIterator();
AuthPropertyIterator(const grpc_auth_property* property,
const grpc_auth_property_iterator* iter);
private:
friend class SecureAuthContext;
const grpc_auth_property* property_;
// The following items form a grpc_auth_property_iterator.
const grpc_auth_context* ctx_;
size_t index_;
const char* name_;
};
/// Class encapsulating the Authentication Information.
///
/// It includes the secure identity of the peer, the type of secure transport
/// used as well as any other properties required by the authorization layer.
class AuthContext {
public:
virtual ~AuthContext() {}
/// Returns true if the peer is authenticated.
virtual bool IsPeerAuthenticated() const = 0;
/// A peer identity.
///
/// It is, in general, comprised of one or more properties (in which case they
/// have the same name).
virtual std::vector<grpc::string_ref> GetPeerIdentity() const = 0;
virtual grpc::string GetPeerIdentityPropertyName() const = 0;
/// Returns all the property values with the given name.
virtual std::vector<grpc::string_ref> FindPropertyValues(
const grpc::string& name) const = 0;
/// Iteration over all the properties.
virtual AuthPropertyIterator begin() const = 0;
virtual AuthPropertyIterator end() const = 0;
/// Mutation functions: should only be used by an AuthMetadataProcessor.
virtual void AddProperty(const grpc::string& key,
const string_ref& value) = 0;
virtual bool SetPeerIdentityPropertyName(const string& name) = 0;
};
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
@@ -0,0 +1,62 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
#define GRPCPP_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
namespace grpc {
/// Defines how to serialize and deserialize some type.
///
/// Used for hooking different message serialization API's into GRPC.
/// Each SerializationTraits<Message> implementation must provide the
/// following functions:
/// 1. static Status Serialize(const Message& msg,
/// ByteBuffer* buffer,
/// bool* own_buffer);
/// OR
/// static Status Serialize(const Message& msg,
/// grpc_byte_buffer** buffer,
/// bool* own_buffer);
/// The former is preferred; the latter is deprecated
///
/// 2. static Status Deserialize(ByteBuffer* buffer,
/// Message* msg);
/// OR
/// static Status Deserialize(grpc_byte_buffer* buffer,
/// Message* msg);
/// The former is preferred; the latter is deprecated
///
/// Serialize is required to convert message to a ByteBuffer, and
/// return that byte buffer through *buffer. *own_buffer should
/// be set to true if the caller owns said byte buffer, or false if
/// ownership is retained elsewhere.
///
/// Deserialize is required to convert buffer into the message stored at
/// msg. max_receive_message_size is passed in as a bound on the maximum
/// number of message bytes Deserialize should accept.
///
/// Both functions return a Status, allowing them to explain what went
/// wrong if required.
template <class Message,
class UnusedButHereForPartialTemplateSpecialization = void>
class SerializationTraits;
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
@@ -0,0 +1,56 @@
/*
*
* Copyright 2018 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 GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H
#define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H
#include <grpcpp/impl/codegen/server_callback_impl.h>
namespace grpc {
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
template <class Request>
using ServerReadReactor = ::grpc_impl::ServerReadReactor<Request>;
template <class Response>
using ServerWriteReactor = ::grpc_impl::ServerWriteReactor<Response>;
template <class Request, class Response>
using ServerBidiReactor = ::grpc_impl::ServerBidiReactor<Request, Response>;
using ServerUnaryReactor = ::grpc_impl::ServerUnaryReactor;
#endif
// TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
namespace experimental {
template <class Request>
using ServerReadReactor = ::grpc_impl::ServerReadReactor<Request>;
template <class Response>
using ServerWriteReactor = ::grpc_impl::ServerWriteReactor<Response>;
template <class Request, class Response>
using ServerBidiReactor = ::grpc_impl::ServerBidiReactor<Request, Response>;
using ServerUnaryReactor = ::grpc_impl::ServerUnaryReactor;
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H
@@ -0,0 +1,880 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_HANDLERS_H
#define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_HANDLERS_H
#include <grpcpp/impl/codegen/message_allocator.h>
#include <grpcpp/impl/codegen/rpc_service_method.h>
#include <grpcpp/impl/codegen/server_callback_impl.h>
#include <grpcpp/impl/codegen/server_context_impl.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
namespace internal {
template <class RequestType, class ResponseType>
class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
public:
explicit CallbackUnaryHandler(
std::function<ServerUnaryReactor*(::grpc_impl::CallbackServerContext*,
const RequestType*, ResponseType*)>
get_reactor)
: get_reactor_(std::move(get_reactor)) {}
void SetMessageAllocator(
::grpc::experimental::MessageAllocator<RequestType, ResponseType>*
allocator) {
allocator_ = allocator;
}
void RunHandler(const HandlerParameter& param) final {
// Arena allocate a controller structure (that includes request/response)
::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call());
auto* allocator_state = static_cast<
::grpc::experimental::MessageHolder<RequestType, ResponseType>*>(
param.internal_data);
auto* call = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(ServerCallbackUnaryImpl)))
ServerCallbackUnaryImpl(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
param.call, allocator_state, std::move(param.call_requester));
param.server_context->BeginCompletionOp(
param.call, [call](bool) { call->MaybeDone(); }, call);
ServerUnaryReactor* reactor = nullptr;
if (param.status.ok()) {
reactor = ::grpc::internal::CatchingReactorGetter<ServerUnaryReactor>(
get_reactor_,
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
call->request(), call->response());
}
if (reactor == nullptr) {
// if deserialization or reactor creator failed, we need to fail the call
reactor = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(UnimplementedUnaryReactor)))
UnimplementedUnaryReactor(
::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""));
}
/// Invoke SetupReactor as the last part of the handler
call->SetupReactor(reactor);
}
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
::grpc::Status* status, void** handler_data) final {
::grpc::ByteBuffer buf;
buf.set_buffer(req);
RequestType* request = nullptr;
::grpc::experimental::MessageHolder<RequestType, ResponseType>*
allocator_state = nullptr;
if (allocator_ != nullptr) {
allocator_state = allocator_->AllocateMessages();
} else {
allocator_state =
new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
call, sizeof(DefaultMessageHolder<RequestType, ResponseType>)))
DefaultMessageHolder<RequestType, ResponseType>();
}
*handler_data = allocator_state;
request = allocator_state->request();
*status =
::grpc::SerializationTraits<RequestType>::Deserialize(&buf, request);
buf.Release();
if (status->ok()) {
return request;
}
// Clean up on deserialization failure.
allocator_state->Release();
return nullptr;
}
private:
std::function<ServerUnaryReactor*(::grpc_impl::CallbackServerContext*,
const RequestType*, ResponseType*)>
get_reactor_;
::grpc::experimental::MessageAllocator<RequestType, ResponseType>*
allocator_ = nullptr;
class ServerCallbackUnaryImpl : public ServerCallbackUnary {
public:
void Finish(::grpc::Status s) override {
// A callback that only contains a call to MaybeDone can be run as an
// inline callback regardless of whether or not OnDone is inlineable
// because if the actual OnDone callback needs to be scheduled, MaybeDone
// is responsible for dispatching to an executor thread if needed. Thus,
// when setting up the finish_tag_, we can set its own callback to
// inlineable.
finish_tag_.Set(
call_.call(),
[this](bool) {
this->MaybeDone(
reactor_.load(std::memory_order_relaxed)->InternalInlineable());
},
&finish_ops_, /*can_inline=*/true);
finish_ops_.set_core_cq_tag(&finish_tag_);
if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// The response is dropped if the status is not OK.
if (s.ok()) {
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_,
finish_ops_.SendMessagePtr(response()));
} else {
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);
}
finish_ops_.set_core_cq_tag(&finish_tag_);
call_.PerformOps(&finish_ops_);
}
void SendInitialMetadata() override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
this->Ref();
// The callback for this function should not be marked inline because it
// is directly invoking a user-controlled reaction
// (OnSendInitialMetadataDone). Thus it must be dispatched to an executor
// thread. However, any OnDone needed after that can be inlined because it
// is already running on an executor thread.
meta_tag_.Set(call_.call(),
[this](bool ok) {
ServerUnaryReactor* reactor =
reactor_.load(std::memory_order_relaxed);
reactor->OnSendInitialMetadataDone(ok);
this->MaybeDone(/*inlineable_ondone=*/true);
},
&meta_ops_, /*can_inline=*/false);
meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
meta_ops_.set_core_cq_tag(&meta_tag_);
call_.PerformOps(&meta_ops_);
}
private:
friend class CallbackUnaryHandler<RequestType, ResponseType>;
ServerCallbackUnaryImpl(
::grpc_impl::CallbackServerContext* ctx, ::grpc::internal::Call* call,
::grpc::experimental::MessageHolder<RequestType, ResponseType>*
allocator_state,
std::function<void()> call_requester)
: ctx_(ctx),
call_(*call),
allocator_state_(allocator_state),
call_requester_(std::move(call_requester)) {
ctx_->set_message_allocator_state(allocator_state);
}
/// SetupReactor binds the reactor (which also releases any queued
/// operations), maybe calls OnCancel if possible/needed, and maybe marks
/// the completion of the RPC. This should be the last component of the
/// handler.
void SetupReactor(ServerUnaryReactor* reactor) {
reactor_.store(reactor, std::memory_order_relaxed);
this->BindReactor(reactor);
this->MaybeCallOnCancel(reactor);
this->MaybeDone(reactor->InternalInlineable());
}
const RequestType* request() { return allocator_state_->request(); }
ResponseType* response() { return allocator_state_->response(); }
void CallOnDone() override {
reactor_.load(std::memory_order_relaxed)->OnDone();
grpc_call* call = call_.call();
auto call_requester = std::move(call_requester_);
allocator_state_->Release();
this->~ServerCallbackUnaryImpl(); // explicitly call destructor
::grpc::g_core_codegen_interface->grpc_call_unref(call);
call_requester();
}
ServerReactor* reactor() override {
return reactor_.load(std::memory_order_relaxed);
}
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
meta_ops_;
::grpc::internal::CallbackWithSuccessTag meta_tag_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpServerSendStatus>
finish_ops_;
::grpc::internal::CallbackWithSuccessTag finish_tag_;
::grpc_impl::CallbackServerContext* const ctx_;
::grpc::internal::Call call_;
::grpc::experimental::MessageHolder<RequestType, ResponseType>* const
allocator_state_;
std::function<void()> call_requester_;
// reactor_ can always be loaded/stored with relaxed memory ordering because
// its value is only set once, independently of other data in the object,
// and the loads that use it will always actually come provably later even
// though they are from different threads since they are triggered by
// actions initiated only by the setting up of the reactor_ variable. In
// a sense, it's a delayed "const": it gets its value from the SetupReactor
// method (not the constructor, so it's not a true const), but it doesn't
// change after that and it only gets used by actions caused, directly or
// indirectly, by that setup. This comment also applies to the reactor_
// variables of the other streaming objects in this file.
std::atomic<ServerUnaryReactor*> reactor_;
// callbacks_outstanding_ follows a refcount pattern
std::atomic<intptr_t> callbacks_outstanding_{
3}; // reserve for start, Finish, and CompletionOp
};
};
template <class RequestType, class ResponseType>
class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
public:
explicit CallbackClientStreamingHandler(
std::function<ServerReadReactor<RequestType>*(
::grpc_impl::CallbackServerContext*, ResponseType*)>
get_reactor)
: get_reactor_(std::move(get_reactor)) {}
void RunHandler(const HandlerParameter& param) final {
// Arena allocate a reader structure (that includes response)
::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call());
auto* reader = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(ServerCallbackReaderImpl)))
ServerCallbackReaderImpl(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
param.call, std::move(param.call_requester));
// Inlineable OnDone can be false in the CompletionOp callback because there
// is no read reactor that has an inlineable OnDone; this only applies to
// the DefaultReactor (which is unary).
param.server_context->BeginCompletionOp(
param.call,
[reader](bool) { reader->MaybeDone(/*inlineable_ondone=*/false); },
reader);
ServerReadReactor<RequestType>* reactor = nullptr;
if (param.status.ok()) {
reactor = ::grpc::internal::CatchingReactorGetter<
ServerReadReactor<RequestType>>(
get_reactor_,
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
reader->response());
}
if (reactor == nullptr) {
// if deserialization or reactor creator failed, we need to fail the call
reactor = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(UnimplementedReadReactor<RequestType>)))
UnimplementedReadReactor<RequestType>(
::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""));
}
reader->SetupReactor(reactor);
}
private:
std::function<ServerReadReactor<RequestType>*(
::grpc_impl::CallbackServerContext*, ResponseType*)>
get_reactor_;
class ServerCallbackReaderImpl : public ServerCallbackReader<RequestType> {
public:
void Finish(::grpc::Status s) override {
// A finish tag with only MaybeDone can have its callback inlined
// regardless even if OnDone is not inlineable because this callback just
// checks a ref and then decides whether or not to dispatch OnDone.
finish_tag_.Set(call_.call(),
[this](bool) {
// Inlineable OnDone can be false here because there is
// no read reactor that has an inlineable OnDone; this
// only applies to the DefaultReactor (which is unary).
this->MaybeDone(/*inlineable_ondone=*/false);
},
&finish_ops_, /*can_inline=*/true);
if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// The response is dropped if the status is not OK.
if (s.ok()) {
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_,
finish_ops_.SendMessagePtr(&resp_));
} else {
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);
}
finish_ops_.set_core_cq_tag(&finish_tag_);
call_.PerformOps(&finish_ops_);
}
void SendInitialMetadata() override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
this->Ref();
// The callback for this function should not be inlined because it invokes
// a user-controlled reaction, but any resulting OnDone can be inlined in
// the executor to which this callback is dispatched.
meta_tag_.Set(call_.call(),
[this](bool ok) {
ServerReadReactor<RequestType>* reactor =
reactor_.load(std::memory_order_relaxed);
reactor->OnSendInitialMetadataDone(ok);
this->MaybeDone(/*inlineable_ondone=*/true);
},
&meta_ops_, /*can_inline=*/false);
meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
meta_ops_.set_core_cq_tag(&meta_tag_);
call_.PerformOps(&meta_ops_);
}
void Read(RequestType* req) override {
this->Ref();
read_ops_.RecvMessage(req);
call_.PerformOps(&read_ops_);
}
private:
friend class CallbackClientStreamingHandler<RequestType, ResponseType>;
ServerCallbackReaderImpl(::grpc_impl::CallbackServerContext* ctx,
::grpc::internal::Call* call,
std::function<void()> call_requester)
: ctx_(ctx), call_(*call), call_requester_(std::move(call_requester)) {}
void SetupReactor(ServerReadReactor<RequestType>* reactor) {
reactor_.store(reactor, std::memory_order_relaxed);
// The callback for this function should not be inlined because it invokes
// a user-controlled reaction, but any resulting OnDone can be inlined in
// the executor to which this callback is dispatched.
read_tag_.Set(call_.call(),
[this, reactor](bool ok) {
reactor->OnReadDone(ok);
this->MaybeDone(/*inlineable_ondone=*/true);
},
&read_ops_, /*can_inline=*/false);
read_ops_.set_core_cq_tag(&read_tag_);
this->BindReactor(reactor);
this->MaybeCallOnCancel(reactor);
// Inlineable OnDone can be false here because there is no read
// reactor that has an inlineable OnDone; this only applies to the
// DefaultReactor (which is unary).
this->MaybeDone(/*inlineable_ondone=*/false);
}
~ServerCallbackReaderImpl() {}
ResponseType* response() { return &resp_; }
void CallOnDone() override {
reactor_.load(std::memory_order_relaxed)->OnDone();
grpc_call* call = call_.call();
auto call_requester = std::move(call_requester_);
this->~ServerCallbackReaderImpl(); // explicitly call destructor
::grpc::g_core_codegen_interface->grpc_call_unref(call);
call_requester();
}
ServerReactor* reactor() override {
return reactor_.load(std::memory_order_relaxed);
}
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
meta_ops_;
::grpc::internal::CallbackWithSuccessTag meta_tag_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpServerSendStatus>
finish_ops_;
::grpc::internal::CallbackWithSuccessTag finish_tag_;
::grpc::internal::CallOpSet<
::grpc::internal::CallOpRecvMessage<RequestType>>
read_ops_;
::grpc::internal::CallbackWithSuccessTag read_tag_;
::grpc_impl::CallbackServerContext* const ctx_;
::grpc::internal::Call call_;
ResponseType resp_;
std::function<void()> call_requester_;
// The memory ordering of reactor_ follows ServerCallbackUnaryImpl.
std::atomic<ServerReadReactor<RequestType>*> reactor_;
// callbacks_outstanding_ follows a refcount pattern
std::atomic<intptr_t> callbacks_outstanding_{
3}; // reserve for OnStarted, Finish, and CompletionOp
};
};
template <class RequestType, class ResponseType>
class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
public:
explicit CallbackServerStreamingHandler(
std::function<ServerWriteReactor<ResponseType>*(
::grpc_impl::CallbackServerContext*, const RequestType*)>
get_reactor)
: get_reactor_(std::move(get_reactor)) {}
void RunHandler(const HandlerParameter& param) final {
// Arena allocate a writer structure
::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call());
auto* writer = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(ServerCallbackWriterImpl)))
ServerCallbackWriterImpl(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
param.call, static_cast<RequestType*>(param.request),
std::move(param.call_requester));
// Inlineable OnDone can be false in the CompletionOp callback because there
// is no write reactor that has an inlineable OnDone; this only applies to
// the DefaultReactor (which is unary).
param.server_context->BeginCompletionOp(
param.call,
[writer](bool) { writer->MaybeDone(/*inlineable_ondone=*/false); },
writer);
ServerWriteReactor<ResponseType>* reactor = nullptr;
if (param.status.ok()) {
reactor = ::grpc::internal::CatchingReactorGetter<
ServerWriteReactor<ResponseType>>(
get_reactor_,
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
writer->request());
}
if (reactor == nullptr) {
// if deserialization or reactor creator failed, we need to fail the call
reactor = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(UnimplementedWriteReactor<ResponseType>)))
UnimplementedWriteReactor<ResponseType>(
::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""));
}
writer->SetupReactor(reactor);
}
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
::grpc::Status* status, void** /*handler_data*/) final {
::grpc::ByteBuffer buf;
buf.set_buffer(req);
auto* request =
new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
call, sizeof(RequestType))) RequestType();
*status =
::grpc::SerializationTraits<RequestType>::Deserialize(&buf, request);
buf.Release();
if (status->ok()) {
return request;
}
request->~RequestType();
return nullptr;
}
private:
std::function<ServerWriteReactor<ResponseType>*(
::grpc_impl::CallbackServerContext*, const RequestType*)>
get_reactor_;
class ServerCallbackWriterImpl : public ServerCallbackWriter<ResponseType> {
public:
void Finish(::grpc::Status s) override {
// A finish tag with only MaybeDone can have its callback inlined
// regardless even if OnDone is not inlineable because this callback just
// checks a ref and then decides whether or not to dispatch OnDone.
finish_tag_.Set(call_.call(),
[this](bool) {
// Inlineable OnDone can be false here because there is
// no write reactor that has an inlineable OnDone; this
// only applies to the DefaultReactor (which is unary).
this->MaybeDone(/*inlineable_ondone=*/false);
},
&finish_ops_, /*can_inline=*/true);
finish_ops_.set_core_cq_tag(&finish_tag_);
if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);
call_.PerformOps(&finish_ops_);
}
void SendInitialMetadata() override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
this->Ref();
// The callback for this function should not be inlined because it invokes
// a user-controlled reaction, but any resulting OnDone can be inlined in
// the executor to which this callback is dispatched.
meta_tag_.Set(call_.call(),
[this](bool ok) {
ServerWriteReactor<ResponseType>* reactor =
reactor_.load(std::memory_order_relaxed);
reactor->OnSendInitialMetadataDone(ok);
this->MaybeDone(/*inlineable_ondone=*/true);
},
&meta_ops_, /*can_inline=*/false);
meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
meta_ops_.set_core_cq_tag(&meta_tag_);
call_.PerformOps(&meta_ops_);
}
void Write(const ResponseType* resp,
::grpc::WriteOptions options) override {
this->Ref();
if (options.is_last_message()) {
options.set_buffer_hint();
}
if (!ctx_->sent_initial_metadata_) {
write_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
write_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// TODO(vjpai): don't assert
GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok());
call_.PerformOps(&write_ops_);
}
void WriteAndFinish(const ResponseType* resp, ::grpc::WriteOptions options,
::grpc::Status s) override {
// This combines the write into the finish callback
// Don't send any message if the status is bad
if (s.ok()) {
// TODO(vjpai): don't assert
GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok());
}
Finish(std::move(s));
}
private:
friend class CallbackServerStreamingHandler<RequestType, ResponseType>;
ServerCallbackWriterImpl(::grpc_impl::CallbackServerContext* ctx,
::grpc::internal::Call* call,
const RequestType* req,
std::function<void()> call_requester)
: ctx_(ctx),
call_(*call),
req_(req),
call_requester_(std::move(call_requester)) {}
void SetupReactor(ServerWriteReactor<ResponseType>* reactor) {
reactor_.store(reactor, std::memory_order_relaxed);
// The callback for this function should not be inlined because it invokes
// a user-controlled reaction, but any resulting OnDone can be inlined in
// the executor to which this callback is dispatched.
write_tag_.Set(call_.call(),
[this, reactor](bool ok) {
reactor->OnWriteDone(ok);
this->MaybeDone(/*inlineable_ondone=*/true);
},
&write_ops_, /*can_inline=*/false);
write_ops_.set_core_cq_tag(&write_tag_);
this->BindReactor(reactor);
this->MaybeCallOnCancel(reactor);
// Inlineable OnDone can be false here because there is no write
// reactor that has an inlineable OnDone; this only applies to the
// DefaultReactor (which is unary).
this->MaybeDone(/*inlineable_ondone=*/false);
}
~ServerCallbackWriterImpl() { req_->~RequestType(); }
const RequestType* request() { return req_; }
void CallOnDone() override {
reactor_.load(std::memory_order_relaxed)->OnDone();
grpc_call* call = call_.call();
auto call_requester = std::move(call_requester_);
this->~ServerCallbackWriterImpl(); // explicitly call destructor
::grpc::g_core_codegen_interface->grpc_call_unref(call);
call_requester();
}
ServerReactor* reactor() override {
return reactor_.load(std::memory_order_relaxed);
}
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
meta_ops_;
::grpc::internal::CallbackWithSuccessTag meta_tag_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpServerSendStatus>
finish_ops_;
::grpc::internal::CallbackWithSuccessTag finish_tag_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage>
write_ops_;
::grpc::internal::CallbackWithSuccessTag write_tag_;
::grpc_impl::CallbackServerContext* const ctx_;
::grpc::internal::Call call_;
const RequestType* req_;
std::function<void()> call_requester_;
// The memory ordering of reactor_ follows ServerCallbackUnaryImpl.
std::atomic<ServerWriteReactor<ResponseType>*> reactor_;
// callbacks_outstanding_ follows a refcount pattern
std::atomic<intptr_t> callbacks_outstanding_{
3}; // reserve for OnStarted, Finish, and CompletionOp
};
};
template <class RequestType, class ResponseType>
class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
public:
explicit CallbackBidiHandler(
std::function<ServerBidiReactor<RequestType, ResponseType>*(
::grpc_impl::CallbackServerContext*)>
get_reactor)
: get_reactor_(std::move(get_reactor)) {}
void RunHandler(const HandlerParameter& param) final {
::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call());
auto* stream = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(ServerCallbackReaderWriterImpl)))
ServerCallbackReaderWriterImpl(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
param.call, std::move(param.call_requester));
// Inlineable OnDone can be false in the CompletionOp callback because there
// is no bidi reactor that has an inlineable OnDone; this only applies to
// the DefaultReactor (which is unary).
param.server_context->BeginCompletionOp(
param.call,
[stream](bool) { stream->MaybeDone(/*inlineable_ondone=*/false); },
stream);
ServerBidiReactor<RequestType, ResponseType>* reactor = nullptr;
if (param.status.ok()) {
reactor = ::grpc::internal::CatchingReactorGetter<
ServerBidiReactor<RequestType, ResponseType>>(
get_reactor_, static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context));
}
if (reactor == nullptr) {
// if deserialization or reactor creator failed, we need to fail the call
reactor = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(),
sizeof(UnimplementedBidiReactor<RequestType, ResponseType>)))
UnimplementedBidiReactor<RequestType, ResponseType>(
::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""));
}
stream->SetupReactor(reactor);
}
private:
std::function<ServerBidiReactor<RequestType, ResponseType>*(
::grpc_impl::CallbackServerContext*)>
get_reactor_;
class ServerCallbackReaderWriterImpl
: public ServerCallbackReaderWriter<RequestType, ResponseType> {
public:
void Finish(::grpc::Status s) override {
// A finish tag with only MaybeDone can have its callback inlined
// regardless even if OnDone is not inlineable because this callback just
// checks a ref and then decides whether or not to dispatch OnDone.
finish_tag_.Set(call_.call(),
[this](bool) {
// Inlineable OnDone can be false here because there is
// no bidi reactor that has an inlineable OnDone; this
// only applies to the DefaultReactor (which is unary).
this->MaybeDone(/*inlineable_ondone=*/false);
},
&finish_ops_, /*can_inline=*/true);
finish_ops_.set_core_cq_tag(&finish_tag_);
if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);
call_.PerformOps(&finish_ops_);
}
void SendInitialMetadata() override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
this->Ref();
// The callback for this function should not be inlined because it invokes
// a user-controlled reaction, but any resulting OnDone can be inlined in
// the executor to which this callback is dispatched.
meta_tag_.Set(call_.call(),
[this](bool ok) {
ServerBidiReactor<RequestType, ResponseType>* reactor =
reactor_.load(std::memory_order_relaxed);
reactor->OnSendInitialMetadataDone(ok);
this->MaybeDone(/*inlineable_ondone=*/true);
},
&meta_ops_, /*can_inline=*/false);
meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
meta_ops_.set_core_cq_tag(&meta_tag_);
call_.PerformOps(&meta_ops_);
}
void Write(const ResponseType* resp,
::grpc::WriteOptions options) override {
this->Ref();
if (options.is_last_message()) {
options.set_buffer_hint();
}
if (!ctx_->sent_initial_metadata_) {
write_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
write_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// TODO(vjpai): don't assert
GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok());
call_.PerformOps(&write_ops_);
}
void WriteAndFinish(const ResponseType* resp, ::grpc::WriteOptions options,
::grpc::Status s) override {
// Don't send any message if the status is bad
if (s.ok()) {
// TODO(vjpai): don't assert
GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok());
}
Finish(std::move(s));
}
void Read(RequestType* req) override {
this->Ref();
read_ops_.RecvMessage(req);
call_.PerformOps(&read_ops_);
}
private:
friend class CallbackBidiHandler<RequestType, ResponseType>;
ServerCallbackReaderWriterImpl(::grpc_impl::CallbackServerContext* ctx,
::grpc::internal::Call* call,
std::function<void()> call_requester)
: ctx_(ctx), call_(*call), call_requester_(std::move(call_requester)) {}
void SetupReactor(ServerBidiReactor<RequestType, ResponseType>* reactor) {
reactor_.store(reactor, std::memory_order_relaxed);
// The callbacks for these functions should not be inlined because they
// invoke user-controlled reactions, but any resulting OnDones can be
// inlined in the executor to which a callback is dispatched.
write_tag_.Set(call_.call(),
[this, reactor](bool ok) {
reactor->OnWriteDone(ok);
this->MaybeDone(/*inlineable_ondone=*/true);
},
&write_ops_, /*can_inline=*/false);
write_ops_.set_core_cq_tag(&write_tag_);
read_tag_.Set(call_.call(),
[this, reactor](bool ok) {
reactor->OnReadDone(ok);
this->MaybeDone(/*inlineable_ondone=*/true);
},
&read_ops_, /*can_inline=*/false);
read_ops_.set_core_cq_tag(&read_tag_);
this->BindReactor(reactor);
this->MaybeCallOnCancel(reactor);
// Inlineable OnDone can be false here because there is no bidi
// reactor that has an inlineable OnDone; this only applies to the
// DefaultReactor (which is unary).
this->MaybeDone(/*inlineable_ondone=*/false);
}
void CallOnDone() override {
reactor_.load(std::memory_order_relaxed)->OnDone();
grpc_call* call = call_.call();
auto call_requester = std::move(call_requester_);
this->~ServerCallbackReaderWriterImpl(); // explicitly call destructor
::grpc::g_core_codegen_interface->grpc_call_unref(call);
call_requester();
}
ServerReactor* reactor() override {
return reactor_.load(std::memory_order_relaxed);
}
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
meta_ops_;
::grpc::internal::CallbackWithSuccessTag meta_tag_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpServerSendStatus>
finish_ops_;
::grpc::internal::CallbackWithSuccessTag finish_tag_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage>
write_ops_;
::grpc::internal::CallbackWithSuccessTag write_tag_;
::grpc::internal::CallOpSet<
::grpc::internal::CallOpRecvMessage<RequestType>>
read_ops_;
::grpc::internal::CallbackWithSuccessTag read_tag_;
::grpc_impl::CallbackServerContext* const ctx_;
::grpc::internal::Call call_;
std::function<void()> call_requester_;
// The memory ordering of reactor_ follows ServerCallbackUnaryImpl.
std::atomic<ServerBidiReactor<RequestType, ResponseType>*> reactor_;
// callbacks_outstanding_ follows a refcount pattern
std::atomic<intptr_t> callbacks_outstanding_{
3}; // reserve for OnStarted, Finish, and CompletionOp
};
};
} // namespace internal
} // namespace grpc_impl
#endif // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_HANDLERS_H
@@ -0,0 +1,780 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_IMPL_H
#define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_IMPL_H
#include <atomic>
#include <functional>
#include <type_traits>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/call_op_set.h>
#include <grpcpp/impl/codegen/callback_common.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/message_allocator.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
// Declare base class of all reactors as internal
namespace internal {
// Forward declarations
template <class Request, class Response>
class CallbackUnaryHandler;
template <class Request, class Response>
class CallbackClientStreamingHandler;
template <class Request, class Response>
class CallbackServerStreamingHandler;
template <class Request, class Response>
class CallbackBidiHandler;
class ServerReactor {
public:
virtual ~ServerReactor() = default;
virtual void OnDone() = 0;
virtual void OnCancel() = 0;
// The following is not API. It is for internal use only and specifies whether
// all reactions of this Reactor can be run without an extra executor
// scheduling. This should only be used for internally-defined reactors with
// trivial reactions.
virtual bool InternalInlineable() { return false; }
private:
template <class Request, class Response>
friend class CallbackUnaryHandler;
template <class Request, class Response>
friend class CallbackClientStreamingHandler;
template <class Request, class Response>
friend class CallbackServerStreamingHandler;
template <class Request, class Response>
friend class CallbackBidiHandler;
};
/// The base class of ServerCallbackUnary etc.
class ServerCallbackCall {
public:
virtual ~ServerCallbackCall() {}
// This object is responsible for tracking when it is safe to call OnDone and
// OnCancel. OnDone should not be called until the method handler is complete,
// Finish has been called, the ServerContext CompletionOp (which tracks
// cancellation or successful completion) has completed, and all outstanding
// Read/Write actions have seen their reactions. OnCancel should not be called
// until after the method handler is done and the RPC has completed with a
// cancellation. This is tracked by counting how many of these conditions have
// been met and calling OnCancel when none remain unmet.
// Public versions of MaybeDone: one where we don't know the reactor in
// advance (used for the ServerContext CompletionOp), and one for where we
// know the inlineability of the OnDone reaction. You should set the inline
// flag to true if either the Reactor is InternalInlineable() or if this
// callback is already being forced to run dispatched to an executor
// (typically because it contains additional work than just the MaybeDone).
void MaybeDone() {
if (GPR_UNLIKELY(Unref() == 1)) {
ScheduleOnDone(reactor()->InternalInlineable());
}
}
void MaybeDone(bool inline_ondone) {
if (GPR_UNLIKELY(Unref() == 1)) {
ScheduleOnDone(inline_ondone);
}
}
// Fast version called with known reactor passed in, used from derived
// classes, typically in non-cancel case
void MaybeCallOnCancel(ServerReactor* reactor) {
if (GPR_UNLIKELY(UnblockCancellation())) {
CallOnCancel(reactor);
}
}
// Slower version called from object that doesn't know the reactor a priori
// (such as the ServerContext CompletionOp which is formed before the
// reactor). This is used in cancel cases only, so it's ok to be slower and
// invoke a virtual function.
void MaybeCallOnCancel() {
if (GPR_UNLIKELY(UnblockCancellation())) {
CallOnCancel(reactor());
}
}
protected:
/// Increases the reference count
void Ref() { callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); }
private:
virtual ServerReactor* reactor() = 0;
// CallOnDone performs the work required at completion of the RPC: invoking
// the OnDone function and doing all necessary cleanup. This function is only
// ever invoked on a fully-Unref'fed ServerCallbackCall.
virtual void CallOnDone() = 0;
// If the OnDone reaction is inlineable, execute it inline. Otherwise send it
// to an executor.
void ScheduleOnDone(bool inline_ondone);
// If the OnCancel reaction is inlineable, execute it inline. Otherwise send
// it to an executor.
void CallOnCancel(ServerReactor* reactor);
// Implement the cancellation constraint counter. Return true if OnCancel
// should be called, false otherwise.
bool UnblockCancellation() {
return on_cancel_conditions_remaining_.fetch_sub(
1, std::memory_order_acq_rel) == 1;
}
/// Decreases the reference count and returns the previous value
int Unref() {
return callbacks_outstanding_.fetch_sub(1, std::memory_order_acq_rel);
}
std::atomic_int on_cancel_conditions_remaining_{2};
std::atomic_int callbacks_outstanding_{
3}; // reserve for start, Finish, and CompletionOp
};
template <class Request, class Response>
class DefaultMessageHolder
: public ::grpc::experimental::MessageHolder<Request, Response> {
public:
DefaultMessageHolder() {
this->set_request(&request_obj_);
this->set_response(&response_obj_);
}
void Release() override {
// the object is allocated in the call arena.
this->~DefaultMessageHolder<Request, Response>();
}
private:
Request request_obj_;
Response response_obj_;
};
} // namespace internal
// Forward declarations
class ServerUnaryReactor;
template <class Request>
class ServerReadReactor;
template <class Response>
class ServerWriteReactor;
template <class Request, class Response>
class ServerBidiReactor;
// NOTE: The actual call/stream object classes are provided as API only to
// support mocking. There are no implementations of these class interfaces in
// the API.
class ServerCallbackUnary : public internal::ServerCallbackCall {
public:
virtual ~ServerCallbackUnary() {}
virtual void Finish(::grpc::Status s) = 0;
virtual void SendInitialMetadata() = 0;
protected:
// Use a template rather than explicitly specifying ServerUnaryReactor to
// delay binding and avoid a circular forward declaration issue
template <class Reactor>
void BindReactor(Reactor* reactor) {
reactor->InternalBindCall(this);
}
};
template <class Request>
class ServerCallbackReader : public internal::ServerCallbackCall {
public:
virtual ~ServerCallbackReader() {}
virtual void Finish(::grpc::Status s) = 0;
virtual void SendInitialMetadata() = 0;
virtual void Read(Request* msg) = 0;
protected:
void BindReactor(ServerReadReactor<Request>* reactor) {
reactor->InternalBindReader(this);
}
};
template <class Response>
class ServerCallbackWriter : public internal::ServerCallbackCall {
public:
virtual ~ServerCallbackWriter() {}
virtual void Finish(::grpc::Status s) = 0;
virtual void SendInitialMetadata() = 0;
virtual void Write(const Response* msg, ::grpc::WriteOptions options) = 0;
virtual void WriteAndFinish(const Response* msg, ::grpc::WriteOptions options,
::grpc::Status s) = 0;
protected:
void BindReactor(ServerWriteReactor<Response>* reactor) {
reactor->InternalBindWriter(this);
}
};
template <class Request, class Response>
class ServerCallbackReaderWriter : public internal::ServerCallbackCall {
public:
virtual ~ServerCallbackReaderWriter() {}
virtual void Finish(::grpc::Status s) = 0;
virtual void SendInitialMetadata() = 0;
virtual void Read(Request* msg) = 0;
virtual void Write(const Response* msg, ::grpc::WriteOptions options) = 0;
virtual void WriteAndFinish(const Response* msg, ::grpc::WriteOptions options,
::grpc::Status s) = 0;
protected:
void BindReactor(ServerBidiReactor<Request, Response>* reactor) {
reactor->InternalBindStream(this);
}
};
// The following classes are the reactor interfaces that are to be implemented
// by the user, returned as the output parameter of the method handler for a
// callback method. Note that none of the classes are pure; all reactions have a
// default empty reaction so that the user class only needs to override those
// classes that it cares about.
/// \a ServerBidiReactor is the interface for a bidirectional streaming RPC.
template <class Request, class Response>
class ServerBidiReactor : public internal::ServerReactor {
public:
// NOTE: Initializing stream_ as a constructor initializer rather than a
// default initializer because gcc-4.x requires a copy constructor for
// default initializing a templated member, which isn't ok for atomic.
// TODO(vjpai): Switch to default constructor and default initializer when
// gcc-4.x is no longer supported
ServerBidiReactor() : stream_(nullptr) {}
~ServerBidiReactor() = default;
/// Send any initial metadata stored in the RPC context. If not invoked,
/// any initial metadata will be passed along with the first Write or the
/// Finish (if there are no writes).
void StartSendInitialMetadata() {
ServerCallbackReaderWriter<Request, Response>* stream =
stream_.load(std::memory_order_acquire);
if (stream == nullptr) {
grpc::internal::MutexLock l(&stream_mu_);
stream = stream_.load(std::memory_order_relaxed);
if (stream == nullptr) {
backlog_.send_initial_metadata_wanted = true;
return;
}
}
stream->SendInitialMetadata();
}
/// Initiate a read operation.
///
/// \param[out] req Where to eventually store the read message. Valid when
/// the library calls OnReadDone
void StartRead(Request* req) {
ServerCallbackReaderWriter<Request, Response>* stream =
stream_.load(std::memory_order_acquire);
if (stream == nullptr) {
grpc::internal::MutexLock l(&stream_mu_);
stream = stream_.load(std::memory_order_relaxed);
if (stream == nullptr) {
backlog_.read_wanted = req;
return;
}
}
stream->Read(req);
}
/// Initiate a write operation.
///
/// \param[in] resp The message to be written. The library does not take
/// ownership but the caller must ensure that the message is
/// not deleted or modified until OnWriteDone is called.
void StartWrite(const Response* resp) {
StartWrite(resp, ::grpc::WriteOptions());
}
/// Initiate a write operation with specified options.
///
/// \param[in] resp The message to be written. The library does not take
/// ownership but the caller must ensure that the message is
/// not deleted or modified until OnWriteDone is called.
/// \param[in] options The WriteOptions to use for writing this message
void StartWrite(const Response* resp, ::grpc::WriteOptions options) {
ServerCallbackReaderWriter<Request, Response>* stream =
stream_.load(std::memory_order_acquire);
if (stream == nullptr) {
grpc::internal::MutexLock l(&stream_mu_);
stream = stream_.load(std::memory_order_relaxed);
if (stream == nullptr) {
backlog_.write_wanted = resp;
backlog_.write_options_wanted = std::move(options);
return;
}
}
stream->Write(resp, std::move(options));
}
/// Initiate a write operation with specified options and final RPC Status,
/// which also causes any trailing metadata for this RPC to be sent out.
/// StartWriteAndFinish is like merging StartWriteLast and Finish into a
/// single step. A key difference, though, is that this operation doesn't have
/// an OnWriteDone reaction - it is considered complete only when OnDone is
/// available. An RPC can either have StartWriteAndFinish or Finish, but not
/// both.
///
/// \param[in] resp The message to be written. The library does not take
/// ownership but the caller must ensure that the message is
/// not deleted or modified until OnDone is called.
/// \param[in] options The WriteOptions to use for writing this message
/// \param[in] s The status outcome of this RPC
void StartWriteAndFinish(const Response* resp, ::grpc::WriteOptions options,
::grpc::Status s) {
ServerCallbackReaderWriter<Request, Response>* stream =
stream_.load(std::memory_order_acquire);
if (stream == nullptr) {
grpc::internal::MutexLock l(&stream_mu_);
stream = stream_.load(std::memory_order_relaxed);
if (stream == nullptr) {
backlog_.write_and_finish_wanted = true;
backlog_.write_wanted = resp;
backlog_.write_options_wanted = std::move(options);
backlog_.status_wanted = std::move(s);
return;
}
}
stream->WriteAndFinish(resp, std::move(options), std::move(s));
}
/// Inform system of a planned write operation with specified options, but
/// allow the library to schedule the actual write coalesced with the writing
/// of trailing metadata (which takes place on a Finish call).
///
/// \param[in] resp The message to be written. The library does not take
/// ownership but the caller must ensure that the message is
/// not deleted or modified until OnWriteDone is called.
/// \param[in] options The WriteOptions to use for writing this message
void StartWriteLast(const Response* resp, ::grpc::WriteOptions options) {
StartWrite(resp, std::move(options.set_last_message()));
}
/// Indicate that the stream is to be finished and the trailing metadata and
/// RPC status are to be sent. Every RPC MUST be finished using either Finish
/// or StartWriteAndFinish (but not both), even if the RPC is already
/// cancelled.
///
/// \param[in] s The status outcome of this RPC
void Finish(::grpc::Status s) {
ServerCallbackReaderWriter<Request, Response>* stream =
stream_.load(std::memory_order_acquire);
if (stream == nullptr) {
grpc::internal::MutexLock l(&stream_mu_);
stream = stream_.load(std::memory_order_relaxed);
if (stream == nullptr) {
backlog_.finish_wanted = true;
backlog_.status_wanted = std::move(s);
return;
}
}
stream->Finish(std::move(s));
}
/// Notifies the application that an explicit StartSendInitialMetadata
/// operation completed. Not used when the sending of initial metadata
/// piggybacks onto the first write.
///
/// \param[in] ok Was it successful? If false, no further write-side operation
/// will succeed.
virtual void OnSendInitialMetadataDone(bool /*ok*/) {}
/// Notifies the application that a StartRead operation completed.
///
/// \param[in] ok Was it successful? If false, no further read-side operation
/// will succeed.
virtual void OnReadDone(bool /*ok*/) {}
/// Notifies the application that a StartWrite (or StartWriteLast) operation
/// completed.
///
/// \param[in] ok Was it successful? If false, no further write-side operation
/// will succeed.
virtual void OnWriteDone(bool /*ok*/) {}
/// Notifies the application that all operations associated with this RPC
/// have completed. This is an override (from the internal base class) but
/// still abstract, so derived classes MUST override it to be instantiated.
void OnDone() override = 0;
/// Notifies the application that this RPC has been cancelled. This is an
/// override (from the internal base class) but not final, so derived classes
/// should override it if they want to take action.
void OnCancel() override {}
private:
friend class ServerCallbackReaderWriter<Request, Response>;
// May be overridden by internal implementation details. This is not a public
// customization point.
virtual void InternalBindStream(
ServerCallbackReaderWriter<Request, Response>* stream) {
// TODO(vjpai): When stream_or_backlog_ becomes a variant (see below), use
// a scoped MutexLock and std::swap stream_or_backlog_ with a variant that
// has stream, then std::get<PreBindBacklog> out of that after the lock.
// Do likewise with the remaining InternalBind* functions as well.
grpc::internal::ReleasableMutexLock l(&stream_mu_);
PreBindBacklog ops(std::move(backlog_));
stream_.store(stream, std::memory_order_release);
l.Unlock();
if (ops.send_initial_metadata_wanted) {
stream->SendInitialMetadata();
}
if (ops.read_wanted != nullptr) {
stream->Read(ops.read_wanted);
}
if (ops.write_and_finish_wanted) {
stream->WriteAndFinish(ops.write_wanted,
std::move(ops.write_options_wanted),
std::move(ops.status_wanted));
} else {
if (ops.write_wanted != nullptr) {
stream->Write(ops.write_wanted, std::move(ops.write_options_wanted));
}
if (ops.finish_wanted) {
stream->Finish(std::move(ops.status_wanted));
}
}
}
grpc::internal::Mutex stream_mu_;
// TODO(vjpai): Make stream_or_backlog_ into a std::variant or absl::variant
// once C++17 or ABSL is supported since stream and backlog are
// mutually exclusive in this class. Do likewise with the
// remaining reactor classes and their backlogs as well.
std::atomic<ServerCallbackReaderWriter<Request, Response>*> stream_{nullptr};
struct PreBindBacklog {
bool send_initial_metadata_wanted = false;
bool write_and_finish_wanted = false;
bool finish_wanted = false;
Request* read_wanted = nullptr;
const Response* write_wanted = nullptr;
::grpc::WriteOptions write_options_wanted;
::grpc::Status status_wanted;
};
PreBindBacklog backlog_ /* GUARDED_BY(stream_mu_) */;
};
/// \a ServerReadReactor is the interface for a client-streaming RPC.
template <class Request>
class ServerReadReactor : public internal::ServerReactor {
public:
ServerReadReactor() : reader_(nullptr) {}
~ServerReadReactor() = default;
/// The following operation initiations are exactly like ServerBidiReactor.
void StartSendInitialMetadata() {
ServerCallbackReader<Request>* reader =
reader_.load(std::memory_order_acquire);
if (reader == nullptr) {
grpc::internal::MutexLock l(&reader_mu_);
reader = reader_.load(std::memory_order_relaxed);
if (reader == nullptr) {
backlog_.send_initial_metadata_wanted = true;
return;
}
}
reader->SendInitialMetadata();
}
void StartRead(Request* req) {
ServerCallbackReader<Request>* reader =
reader_.load(std::memory_order_acquire);
if (reader == nullptr) {
grpc::internal::MutexLock l(&reader_mu_);
reader = reader_.load(std::memory_order_relaxed);
if (reader == nullptr) {
backlog_.read_wanted = req;
return;
}
}
reader->Read(req);
}
void Finish(::grpc::Status s) {
ServerCallbackReader<Request>* reader =
reader_.load(std::memory_order_acquire);
if (reader == nullptr) {
grpc::internal::MutexLock l(&reader_mu_);
reader = reader_.load(std::memory_order_relaxed);
if (reader == nullptr) {
backlog_.finish_wanted = true;
backlog_.status_wanted = std::move(s);
return;
}
}
reader->Finish(std::move(s));
}
/// The following notifications are exactly like ServerBidiReactor.
virtual void OnSendInitialMetadataDone(bool /*ok*/) {}
virtual void OnReadDone(bool /*ok*/) {}
void OnDone() override = 0;
void OnCancel() override {}
private:
friend class ServerCallbackReader<Request>;
// May be overridden by internal implementation details. This is not a public
// customization point.
virtual void InternalBindReader(ServerCallbackReader<Request>* reader) {
grpc::internal::ReleasableMutexLock l(&reader_mu_);
PreBindBacklog ops(std::move(backlog_));
reader_.store(reader, std::memory_order_release);
l.Unlock();
if (ops.send_initial_metadata_wanted) {
reader->SendInitialMetadata();
}
if (ops.read_wanted != nullptr) {
reader->Read(ops.read_wanted);
}
if (ops.finish_wanted) {
reader->Finish(std::move(ops.status_wanted));
}
}
grpc::internal::Mutex reader_mu_;
std::atomic<ServerCallbackReader<Request>*> reader_{nullptr};
struct PreBindBacklog {
bool send_initial_metadata_wanted = false;
bool finish_wanted = false;
Request* read_wanted = nullptr;
::grpc::Status status_wanted;
};
PreBindBacklog backlog_ /* GUARDED_BY(reader_mu_) */;
};
/// \a ServerWriteReactor is the interface for a server-streaming RPC.
template <class Response>
class ServerWriteReactor : public internal::ServerReactor {
public:
ServerWriteReactor() : writer_(nullptr) {}
~ServerWriteReactor() = default;
/// The following operation initiations are exactly like ServerBidiReactor.
void StartSendInitialMetadata() {
ServerCallbackWriter<Response>* writer =
writer_.load(std::memory_order_acquire);
if (writer == nullptr) {
grpc::internal::MutexLock l(&writer_mu_);
writer = writer_.load(std::memory_order_relaxed);
if (writer == nullptr) {
backlog_.send_initial_metadata_wanted = true;
return;
}
}
writer->SendInitialMetadata();
}
void StartWrite(const Response* resp) {
StartWrite(resp, ::grpc::WriteOptions());
}
void StartWrite(const Response* resp, ::grpc::WriteOptions options) {
ServerCallbackWriter<Response>* writer =
writer_.load(std::memory_order_acquire);
if (writer == nullptr) {
grpc::internal::MutexLock l(&writer_mu_);
writer = writer_.load(std::memory_order_relaxed);
if (writer == nullptr) {
backlog_.write_wanted = resp;
backlog_.write_options_wanted = std::move(options);
return;
}
}
writer->Write(resp, std::move(options));
}
void StartWriteAndFinish(const Response* resp, ::grpc::WriteOptions options,
::grpc::Status s) {
ServerCallbackWriter<Response>* writer =
writer_.load(std::memory_order_acquire);
if (writer == nullptr) {
grpc::internal::MutexLock l(&writer_mu_);
writer = writer_.load(std::memory_order_relaxed);
if (writer == nullptr) {
backlog_.write_and_finish_wanted = true;
backlog_.write_wanted = resp;
backlog_.write_options_wanted = std::move(options);
backlog_.status_wanted = std::move(s);
return;
}
}
writer->WriteAndFinish(resp, std::move(options), std::move(s));
}
void StartWriteLast(const Response* resp, ::grpc::WriteOptions options) {
StartWrite(resp, std::move(options.set_last_message()));
}
void Finish(::grpc::Status s) {
ServerCallbackWriter<Response>* writer =
writer_.load(std::memory_order_acquire);
if (writer == nullptr) {
grpc::internal::MutexLock l(&writer_mu_);
writer = writer_.load(std::memory_order_relaxed);
if (writer == nullptr) {
backlog_.finish_wanted = true;
backlog_.status_wanted = std::move(s);
return;
}
}
writer->Finish(std::move(s));
}
/// The following notifications are exactly like ServerBidiReactor.
virtual void OnSendInitialMetadataDone(bool /*ok*/) {}
virtual void OnWriteDone(bool /*ok*/) {}
void OnDone() override = 0;
void OnCancel() override {}
private:
friend class ServerCallbackWriter<Response>;
// May be overridden by internal implementation details. This is not a public
// customization point.
virtual void InternalBindWriter(ServerCallbackWriter<Response>* writer) {
grpc::internal::ReleasableMutexLock l(&writer_mu_);
PreBindBacklog ops(std::move(backlog_));
writer_.store(writer, std::memory_order_release);
l.Unlock();
if (ops.send_initial_metadata_wanted) {
writer->SendInitialMetadata();
}
if (ops.write_and_finish_wanted) {
writer->WriteAndFinish(ops.write_wanted,
std::move(ops.write_options_wanted),
std::move(ops.status_wanted));
} else {
if (ops.write_wanted != nullptr) {
writer->Write(ops.write_wanted, std::move(ops.write_options_wanted));
}
if (ops.finish_wanted) {
writer->Finish(std::move(ops.status_wanted));
}
}
}
grpc::internal::Mutex writer_mu_;
std::atomic<ServerCallbackWriter<Response>*> writer_{nullptr};
struct PreBindBacklog {
bool send_initial_metadata_wanted = false;
bool write_and_finish_wanted = false;
bool finish_wanted = false;
const Response* write_wanted = nullptr;
::grpc::WriteOptions write_options_wanted;
::grpc::Status status_wanted;
};
PreBindBacklog backlog_ /* GUARDED_BY(writer_mu_) */;
};
class ServerUnaryReactor : public internal::ServerReactor {
public:
ServerUnaryReactor() : call_(nullptr) {}
~ServerUnaryReactor() = default;
/// The following operation initiations are exactly like ServerBidiReactor.
void StartSendInitialMetadata() {
ServerCallbackUnary* call = call_.load(std::memory_order_acquire);
if (call == nullptr) {
grpc::internal::MutexLock l(&call_mu_);
call = call_.load(std::memory_order_relaxed);
if (call == nullptr) {
backlog_.send_initial_metadata_wanted = true;
return;
}
}
call->SendInitialMetadata();
}
void Finish(::grpc::Status s) {
ServerCallbackUnary* call = call_.load(std::memory_order_acquire);
if (call == nullptr) {
grpc::internal::MutexLock l(&call_mu_);
call = call_.load(std::memory_order_relaxed);
if (call == nullptr) {
backlog_.finish_wanted = true;
backlog_.status_wanted = std::move(s);
return;
}
}
call->Finish(std::move(s));
}
/// The following notifications are exactly like ServerBidiReactor.
virtual void OnSendInitialMetadataDone(bool /*ok*/) {}
void OnDone() override = 0;
void OnCancel() override {}
private:
friend class ServerCallbackUnary;
// May be overridden by internal implementation details. This is not a public
// customization point.
virtual void InternalBindCall(ServerCallbackUnary* call) {
grpc::internal::ReleasableMutexLock l(&call_mu_);
PreBindBacklog ops(std::move(backlog_));
call_.store(call, std::memory_order_release);
l.Unlock();
if (ops.send_initial_metadata_wanted) {
call->SendInitialMetadata();
}
if (ops.finish_wanted) {
call->Finish(std::move(ops.status_wanted));
}
}
grpc::internal::Mutex call_mu_;
std::atomic<ServerCallbackUnary*> call_{nullptr};
struct PreBindBacklog {
bool send_initial_metadata_wanted = false;
bool finish_wanted = false;
::grpc::Status status_wanted;
};
PreBindBacklog backlog_ /* GUARDED_BY(call_mu_) */;
};
namespace internal {
template <class Base>
class FinishOnlyReactor : public Base {
public:
explicit FinishOnlyReactor(::grpc::Status s) { this->Finish(std::move(s)); }
void OnDone() override { this->~FinishOnlyReactor(); }
};
using UnimplementedUnaryReactor = FinishOnlyReactor<ServerUnaryReactor>;
template <class Request>
using UnimplementedReadReactor = FinishOnlyReactor<ServerReadReactor<Request>>;
template <class Response>
using UnimplementedWriteReactor =
FinishOnlyReactor<ServerWriteReactor<Response>>;
template <class Request, class Response>
using UnimplementedBidiReactor =
FinishOnlyReactor<ServerBidiReactor<Request, Response>>;
} // namespace internal
} // namespace grpc_impl
#endif // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_IMPL_H
@@ -0,0 +1,42 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
#define GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
#include <grpcpp/impl/codegen/server_context_impl.h>
namespace grpc {
typedef ::grpc_impl::ServerContext ServerContext;
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
typedef ::grpc_impl::ServerContextBase ServerContextBase;
typedef ::grpc_impl::CallbackServerContext CallbackServerContext;
#endif
// TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
namespace experimental {
typedef ::grpc_impl::ServerContextBase ServerContextBase;
typedef ::grpc_impl::CallbackServerContext CallbackServerContext;
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
@@ -0,0 +1,602 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H
#define GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H
#include <atomic>
#include <cassert>
#include <map>
#include <memory>
#include <type_traits>
#include <vector>
#include <grpc/impl/codegen/port_platform.h>
#include <grpc/impl/codegen/compression_types.h>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/call_op_set.h>
#include <grpcpp/impl/codegen/callback_common.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/create_auth_context.h>
#include <grpcpp/impl/codegen/message_allocator.h>
#include <grpcpp/impl/codegen/metadata_map.h>
#include <grpcpp/impl/codegen/security/auth_context.h>
#include <grpcpp/impl/codegen/server_callback_impl.h>
#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/string_ref.h>
#include <grpcpp/impl/codegen/time.h>
struct grpc_metadata;
struct grpc_call;
struct census_context;
namespace grpc_impl {
class ClientContext;
class CompletionQueue;
class Server;
template <class W, class R>
class ServerAsyncReader;
template <class W>
class ServerAsyncWriter;
template <class W>
class ServerAsyncResponseWriter;
template <class W, class R>
class ServerAsyncReaderWriter;
template <class R>
class ServerReader;
template <class W>
class ServerWriter;
namespace internal {
template <class ServiceType, class RequestType, class ResponseType>
class BidiStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackUnaryHandler;
template <class RequestType, class ResponseType>
class CallbackClientStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackServerStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackBidiHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class Base>
class FinishOnlyReactor;
template <class W, class R>
class ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
class ServerReactor;
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler;
template <::grpc::StatusCode code>
class ErrorMethodHandler;
} // namespace internal
} // namespace grpc_impl
namespace grpc {
class GenericServerContext;
class ServerInterface;
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
#endif
class GenericCallbackServerContext;
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
} // namespace experimental
#endif
namespace internal {
class Call;
} // namespace internal
namespace testing {
class InteropServerContextInspector;
class ServerContextTestSpouse;
class DefaultReactorTestPeer;
} // namespace testing
} // namespace grpc
namespace grpc_impl {
/// Base class of ServerContext. Experimental until callback API is final.
class ServerContextBase {
public:
virtual ~ServerContextBase();
/// Return the deadline for the server call.
std::chrono::system_clock::time_point deadline() const {
return ::grpc::Timespec2Timepoint(deadline_);
}
/// Return a \a gpr_timespec representation of the server call's deadline.
gpr_timespec raw_deadline() const { return deadline_; }
/// Add the (\a key, \a value) pair to the initial metadata
/// associated with a server call. These are made available at the client side
/// by the \a grpc::ClientContext::GetServerInitialMetadata() method.
///
/// \warning This method should only be called before sending initial metadata
/// to the client (which can happen explicitly, or implicitly when sending a
/// a response message or status to the client).
///
/// \param key The metadata key. If \a value is binary data, it must
/// end in "-bin".
/// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
/// Add the (\a key, \a value) pair to the initial metadata
/// associated with a server call. These are made available at the client
/// side by the \a grpc::ClientContext::GetServerTrailingMetadata() method.
///
/// \warning This method should only be called before sending trailing
/// metadata to the client (which happens when the call is finished and a
/// status is sent to the client).
///
/// \param key The metadata key. If \a value is binary data,
/// it must end in "-bin".
/// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
/// IsCancelled is always safe to call when using sync or callback API.
/// When using async API, it is only safe to call IsCancelled after
/// the AsyncNotifyWhenDone tag has been delivered. Thread-safe.
bool IsCancelled() const;
/// Cancel the Call from the server. This is a best-effort API and
/// depending on when it is called, the RPC may still appear successful to
/// the client.
/// For example, if TryCancel() is called on a separate thread, it might race
/// with the server handler which might return success to the client before
/// TryCancel() was even started by the thread.
///
/// It is the caller's responsibility to prevent such races and ensure that if
/// TryCancel() is called, the serverhandler must return Status::CANCELLED.
/// The only exception is that if the serverhandler is already returning an
/// error status code, it is ok to not return Status::CANCELLED even if
/// TryCancel() was called.
///
/// Note that TryCancel() does not change any of the tags that are pending
/// on the completion queue. All pending tags will still be delivered
/// (though their ok result may reflect the effect of cancellation).
void TryCancel() const;
/// Return a collection of initial metadata key-value pairs sent from the
/// client. Note that keys may happen more than
/// once (ie, a \a std::multimap is returned).
///
/// It is safe to use this method after initial metadata has been received,
/// Calls always begin with the client sending initial metadata, so this is
/// safe to access as soon as the call has begun on the server side.
///
/// \return A multimap of initial metadata key-value pairs from the server.
const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata()
const {
return *client_metadata_.map();
}
/// Return the compression algorithm to be used by the server call.
grpc_compression_level compression_level() const {
return compression_level_;
}
/// Set \a level to be the compression level used for the server call.
///
/// \param level The compression level used for the server call.
void set_compression_level(grpc_compression_level level) {
compression_level_set_ = true;
compression_level_ = level;
}
/// Return a bool indicating whether the compression level for this call
/// has been set (either implicitly or through a previous call to
/// \a set_compression_level.
bool compression_level_set() const { return compression_level_set_; }
/// Return the compression algorithm the server call will request be used.
/// Note that the gRPC runtime may decide to ignore this request, for example,
/// due to resource constraints, or if the server is aware the client doesn't
/// support the requested algorithm.
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
}
/// Set \a algorithm to be the compression algorithm used for the server call.
///
/// \param algorithm The compression algorithm used for the server call.
void set_compression_algorithm(grpc_compression_algorithm algorithm);
/// Set the serialized load reporting costs in \a cost_data for the call.
void SetLoadReportingCosts(const std::vector<grpc::string>& cost_data);
/// Return the authentication context for this server call.
///
/// \see grpc::AuthContext.
std::shared_ptr<const ::grpc::AuthContext> auth_context() const {
if (auth_context_.get() == nullptr) {
auth_context_ = ::grpc::CreateAuthContext(call_);
}
return auth_context_;
}
/// Return the peer uri in a string.
/// WARNING: this value is never authenticated or subject to any security
/// related code. It must not be used for any authentication related
/// functionality. Instead, use auth_context.
grpc::string peer() const;
/// Get the census context associated with this server call.
const struct census_context* census_context() const;
/// Should be used for framework-level extensions only.
/// Applications never need to call this method.
grpc_call* c_call() { return call_; }
protected:
/// Async only. Has to be called before the rpc starts.
/// Returns the tag in completion queue when the rpc finishes.
/// IsCancelled() can then be called to check whether the rpc was cancelled.
/// TODO(vjpai): Fix this so that the tag is returned even if the call never
/// starts (https://github.com/grpc/grpc/issues/10136).
void AsyncNotifyWhenDone(void* tag) {
has_notify_when_done_tag_ = true;
async_notify_when_done_tag_ = tag;
}
/// NOTE: This is an API for advanced users who need custom allocators.
/// Get and maybe mutate the allocator state associated with the current RPC.
/// Currently only applicable for callback unary RPC methods.
/// WARNING: This is experimental API and could be changed or removed.
::grpc::experimental::RpcAllocatorState* GetRpcAllocatorState() {
return message_allocator_state_;
}
/// Get a library-owned default unary reactor for use in minimal reaction
/// cases. This supports typical unary RPC usage of providing a response and
/// status. It supports immediate Finish (finish from within the method
/// handler) or delayed Finish (finish called after the method handler
/// invocation). It does not support reacting to cancellation or completion,
/// or early sending of initial metadata. Since this is a library-owned
/// reactor, it should not be delete'd or freed in any way. This is more
/// efficient than creating a user-owned reactor both because of avoiding an
/// allocation and because its minimal reactions are optimized using a core
/// surface flag that allows their reactions to run inline without any
/// thread-hop.
///
/// This method should not be called more than once or called after return
/// from the method handler.
///
/// WARNING: This is experimental API and could be changed or removed.
::grpc_impl::ServerUnaryReactor* DefaultReactor() {
// Short-circuit the case where a default reactor was already set up by
// the TestPeer.
if (test_unary_ != nullptr) {
return reinterpret_cast<Reactor*>(&default_reactor_);
}
new (&default_reactor_) Reactor;
#ifndef NDEBUG
bool old = false;
assert(default_reactor_used_.compare_exchange_strong(
old, true, std::memory_order_relaxed));
#else
default_reactor_used_.store(true, std::memory_order_relaxed);
#endif
return reinterpret_cast<Reactor*>(&default_reactor_);
}
/// Constructors for use by derived classes
ServerContextBase();
ServerContextBase(gpr_timespec deadline, grpc_metadata_array* arr);
private:
friend class ::grpc::testing::InteropServerContextInspector;
friend class ::grpc::testing::ServerContextTestSpouse;
friend class ::grpc::testing::DefaultReactorTestPeer;
friend class ::grpc::ServerInterface;
friend class ::grpc_impl::Server;
template <class W, class R>
friend class ::grpc_impl::ServerAsyncReader;
template <class W>
friend class ::grpc_impl::ServerAsyncWriter;
template <class W>
friend class ::grpc_impl::ServerAsyncResponseWriter;
template <class W, class R>
friend class ::grpc_impl::ServerAsyncReaderWriter;
template <class R>
friend class ::grpc_impl::ServerReader;
template <class W>
friend class ::grpc_impl::ServerWriter;
template <class W, class R>
friend class ::grpc_impl::internal::ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc_impl::internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc_impl::internal::ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc_impl::internal::ServerStreamingHandler;
template <class Streamer, bool WriteNeeded>
friend class ::grpc_impl::internal::TemplatedBidiStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc_impl::internal::CallbackUnaryHandler;
template <class RequestType, class ResponseType>
friend class ::grpc_impl::internal::CallbackClientStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc_impl::internal::CallbackServerStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc_impl::internal::CallbackBidiHandler;
template <::grpc::StatusCode code>
friend class ::grpc_impl::internal::ErrorMethodHandler;
template <class Base>
friend class ::grpc_impl::internal::FinishOnlyReactor;
friend class ::grpc_impl::ClientContext;
friend class ::grpc::GenericServerContext;
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
friend class ::grpc::GenericCallbackServerContext;
#else
friend class ::grpc::experimental::GenericCallbackServerContext;
#endif
/// Prevent copying.
ServerContextBase(const ServerContextBase&);
ServerContextBase& operator=(const ServerContextBase&);
class CompletionOp;
void BeginCompletionOp(
::grpc::internal::Call* call, std::function<void(bool)> callback,
::grpc_impl::internal::ServerCallbackCall* callback_controller);
/// Return the tag queued by BeginCompletionOp()
::grpc::internal::CompletionQueueTag* GetCompletionOpTag();
void set_call(grpc_call* call) { call_ = call; }
void BindDeadlineAndMetadata(gpr_timespec deadline, grpc_metadata_array* arr);
void Clear();
void Setup(gpr_timespec deadline);
uint32_t initial_metadata_flags() const { return 0; }
::grpc::experimental::ServerRpcInfo* set_server_rpc_info(
const char* method, ::grpc::internal::RpcMethod::RpcType type,
const std::vector<std::unique_ptr<
::grpc::experimental::ServerInterceptorFactoryInterface>>& creators) {
if (creators.size() != 0) {
rpc_info_ = new ::grpc::experimental::ServerRpcInfo(this, method, type);
rpc_info_->RegisterInterceptors(creators);
}
return rpc_info_;
}
void set_message_allocator_state(
::grpc::experimental::RpcAllocatorState* allocator_state) {
message_allocator_state_ = allocator_state;
}
CompletionOp* completion_op_;
bool has_notify_when_done_tag_;
void* async_notify_when_done_tag_;
::grpc::internal::CallbackWithSuccessTag completion_tag_;
gpr_timespec deadline_;
grpc_call* call_;
::grpc_impl::CompletionQueue* cq_;
bool sent_initial_metadata_;
mutable std::shared_ptr<const ::grpc::AuthContext> auth_context_;
mutable ::grpc::internal::MetadataMap client_metadata_;
std::multimap<grpc::string, grpc::string> initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_;
bool compression_level_set_;
grpc_compression_level compression_level_;
grpc_compression_algorithm compression_algorithm_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage>
pending_ops_;
bool has_pending_ops_;
::grpc::experimental::ServerRpcInfo* rpc_info_;
::grpc::experimental::RpcAllocatorState* message_allocator_state_ = nullptr;
class Reactor : public ServerUnaryReactor {
public:
void OnCancel() override {}
void OnDone() override {}
// Override InternalInlineable for this class since its reactions are
// trivial and thus do not need to be run from the executor (triggering a
// thread hop). This should only be used by internal reactors (thus the
// name) and not by user application code.
bool InternalInlineable() override { return true; }
};
void SetupTestDefaultReactor(std::function<void(::grpc::Status)> func) {
test_unary_.reset(new TestServerCallbackUnary(this, std::move(func)));
}
bool test_status_set() const {
return (test_unary_ != nullptr) && test_unary_->status_set();
}
::grpc::Status test_status() const { return test_unary_->status(); }
class TestServerCallbackUnary : public ::grpc_impl::ServerCallbackUnary {
public:
TestServerCallbackUnary(ServerContextBase* ctx,
std::function<void(::grpc::Status)> func)
: reactor_(ctx->DefaultReactor()), func_(std::move(func)) {
this->BindReactor(reactor_);
}
void Finish(::grpc::Status s) override {
status_ = s;
func_(std::move(s));
status_set_.store(true, std::memory_order_release);
}
void SendInitialMetadata() override {}
bool status_set() const {
return status_set_.load(std::memory_order_acquire);
}
::grpc::Status status() const { return status_; }
private:
void CallOnDone() override {}
::grpc_impl::internal::ServerReactor* reactor() override {
return reactor_;
}
::grpc_impl::ServerUnaryReactor* const reactor_;
std::atomic_bool status_set_{false};
::grpc::Status status_;
const std::function<void(::grpc::Status s)> func_;
};
typename std::aligned_storage<sizeof(Reactor), alignof(Reactor)>::type
default_reactor_;
std::atomic_bool default_reactor_used_{false};
std::unique_ptr<TestServerCallbackUnary> test_unary_;
};
/// A ServerContext or CallbackServerContext allows the code implementing a
/// service handler to:
///
/// - Add custom initial and trailing metadata key-value pairs that will
/// propagated to the client side.
/// - Control call settings such as compression and authentication.
/// - Access metadata coming from the client.
/// - Get performance metrics (ie, census).
///
/// Context settings are only relevant to the call handler they are supplied to,
/// that is to say, they aren't sticky across multiple calls. Some of these
/// settings, such as the compression options, can be made persistent at server
/// construction time by specifying the appropriate \a ChannelArguments
/// to a \a grpc::ServerBuilder, via \a ServerBuilder::AddChannelArgument.
///
/// \warning ServerContext instances should \em not be reused across rpcs.
class ServerContext : public ServerContextBase {
public:
ServerContext() {} // for async calls
using ServerContextBase::AddInitialMetadata;
using ServerContextBase::AddTrailingMetadata;
using ServerContextBase::IsCancelled;
using ServerContextBase::SetLoadReportingCosts;
using ServerContextBase::TryCancel;
using ServerContextBase::auth_context;
using ServerContextBase::c_call;
using ServerContextBase::census_context;
using ServerContextBase::client_metadata;
using ServerContextBase::compression_algorithm;
using ServerContextBase::compression_level;
using ServerContextBase::compression_level_set;
using ServerContextBase::deadline;
using ServerContextBase::peer;
using ServerContextBase::raw_deadline;
using ServerContextBase::set_compression_algorithm;
using ServerContextBase::set_compression_level;
// Sync/CQ-based Async ServerContext only
using ServerContextBase::AsyncNotifyWhenDone;
private:
// Constructor for internal use by server only
friend class ::grpc_impl::Server;
ServerContext(gpr_timespec deadline, grpc_metadata_array* arr)
: ServerContextBase(deadline, arr) {}
// CallbackServerContext only
using ServerContextBase::DefaultReactor;
using ServerContextBase::GetRpcAllocatorState;
/// Prevent copying.
ServerContext(const ServerContext&) = delete;
ServerContext& operator=(const ServerContext&) = delete;
};
class CallbackServerContext : public ServerContextBase {
public:
/// Public constructors are for direct use only by mocking tests. In practice,
/// these objects will be owned by the library.
CallbackServerContext() {}
using ServerContextBase::AddInitialMetadata;
using ServerContextBase::AddTrailingMetadata;
using ServerContextBase::IsCancelled;
using ServerContextBase::SetLoadReportingCosts;
using ServerContextBase::TryCancel;
using ServerContextBase::auth_context;
using ServerContextBase::c_call;
using ServerContextBase::census_context;
using ServerContextBase::client_metadata;
using ServerContextBase::compression_algorithm;
using ServerContextBase::compression_level;
using ServerContextBase::compression_level_set;
using ServerContextBase::deadline;
using ServerContextBase::peer;
using ServerContextBase::raw_deadline;
using ServerContextBase::set_compression_algorithm;
using ServerContextBase::set_compression_level;
// CallbackServerContext only
using ServerContextBase::DefaultReactor;
using ServerContextBase::GetRpcAllocatorState;
private:
// Sync/CQ-based Async ServerContext only
using ServerContextBase::AsyncNotifyWhenDone;
/// Prevent copying.
CallbackServerContext(const CallbackServerContext&) = delete;
CallbackServerContext& operator=(const CallbackServerContext&) = delete;
};
} // namespace grpc_impl
static_assert(std::is_base_of<::grpc_impl::ServerContextBase,
::grpc_impl::ServerContext>::value,
"improper base class");
static_assert(std::is_base_of<::grpc_impl::ServerContextBase,
::grpc_impl::CallbackServerContext>::value,
"improper base class");
static_assert(sizeof(::grpc_impl::ServerContextBase) ==
sizeof(::grpc_impl::ServerContext),
"wrong size");
static_assert(sizeof(::grpc_impl::ServerContextBase) ==
sizeof(::grpc_impl::CallbackServerContext),
"wrong size");
#endif // GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H
@@ -0,0 +1,143 @@
/*
*
* Copyright 2018 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 GRPCPP_IMPL_CODEGEN_SERVER_INTERCEPTOR_H
#define GRPCPP_IMPL_CODEGEN_SERVER_INTERCEPTOR_H
#include <atomic>
#include <vector>
#include <grpcpp/impl/codegen/interceptor.h>
#include <grpcpp/impl/codegen/rpc_method.h>
#include <grpcpp/impl/codegen/string_ref.h>
namespace grpc_impl {
class ServerContextBase;
} // namespace grpc_impl
namespace grpc {
namespace internal {
class InterceptorBatchMethodsImpl;
}
namespace experimental {
class ServerRpcInfo;
// A factory interface for creation of server interceptors. A vector of
// factories can be provided to ServerBuilder which will be used to create a new
// vector of server interceptors per RPC. Server interceptor authors should
// create a subclass of ServerInterceptorFactorInterface which creates objects
// of their interceptors.
class ServerInterceptorFactoryInterface {
public:
virtual ~ServerInterceptorFactoryInterface() {}
// Returns a pointer to an Interceptor object on successful creation, nullptr
// otherwise. If nullptr is returned, this server interceptor factory is
// ignored for the purposes of that RPC.
virtual Interceptor* CreateServerInterceptor(ServerRpcInfo* info) = 0;
};
/// ServerRpcInfo represents the state of a particular RPC as it
/// appears to an interceptor. It is created and owned by the library and
/// passed to the CreateServerInterceptor method of the application's
/// ServerInterceptorFactoryInterface implementation
class ServerRpcInfo {
public:
/// Type categorizes RPCs by unary or streaming type
enum class Type { UNARY, CLIENT_STREAMING, SERVER_STREAMING, BIDI_STREAMING };
~ServerRpcInfo() {}
// Delete all copy and move constructors and assignments
ServerRpcInfo(const ServerRpcInfo&) = delete;
ServerRpcInfo& operator=(const ServerRpcInfo&) = delete;
ServerRpcInfo(ServerRpcInfo&&) = delete;
ServerRpcInfo& operator=(ServerRpcInfo&&) = delete;
// Getter methods
/// Return the fully-specified method name
const char* method() const { return method_; }
/// Return the type of the RPC (unary or a streaming flavor)
Type type() const { return type_; }
/// Return a pointer to the underlying ServerContext structure associated
/// with the RPC to support features that apply to it
grpc_impl::ServerContextBase* server_context() { return ctx_; }
private:
static_assert(Type::UNARY ==
static_cast<Type>(internal::RpcMethod::NORMAL_RPC),
"violated expectation about Type enum");
static_assert(Type::CLIENT_STREAMING ==
static_cast<Type>(internal::RpcMethod::CLIENT_STREAMING),
"violated expectation about Type enum");
static_assert(Type::SERVER_STREAMING ==
static_cast<Type>(internal::RpcMethod::SERVER_STREAMING),
"violated expectation about Type enum");
static_assert(Type::BIDI_STREAMING ==
static_cast<Type>(internal::RpcMethod::BIDI_STREAMING),
"violated expectation about Type enum");
ServerRpcInfo(grpc_impl::ServerContextBase* ctx, const char* method,
internal::RpcMethod::RpcType type)
: ctx_(ctx), method_(method), type_(static_cast<Type>(type)) {}
// Runs interceptor at pos \a pos.
void RunInterceptor(
experimental::InterceptorBatchMethods* interceptor_methods, size_t pos) {
GPR_CODEGEN_ASSERT(pos < interceptors_.size());
interceptors_[pos]->Intercept(interceptor_methods);
}
void RegisterInterceptors(
const std::vector<
std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>&
creators) {
for (const auto& creator : creators) {
auto* interceptor = creator->CreateServerInterceptor(this);
if (interceptor != nullptr) {
interceptors_.push_back(
std::unique_ptr<experimental::Interceptor>(interceptor));
}
}
}
void Ref() { ref_.fetch_add(1, std::memory_order_relaxed); }
void Unref() {
if (GPR_UNLIKELY(ref_.fetch_sub(1, std::memory_order_acq_rel) == 1)) {
delete this;
}
}
grpc_impl::ServerContextBase* ctx_ = nullptr;
const char* method_ = nullptr;
const Type type_;
std::atomic<intptr_t> ref_{1};
std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
friend class internal::InterceptorBatchMethodsImpl;
friend class grpc_impl::ServerContextBase;
};
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SERVER_INTERCEPTOR_H
@@ -0,0 +1,403 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_SERVER_INTERFACE_H
#define GRPCPP_IMPL_CODEGEN_SERVER_INTERFACE_H
#include <grpc/impl/codegen/port_platform.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/byte_buffer.h>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/call_hook.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/interceptor_common.h>
#include <grpcpp/impl/codegen/rpc_service_method.h>
#include <grpcpp/impl/codegen/server_context_impl.h>
namespace grpc_impl {
class Channel;
class CompletionQueue;
class ServerCompletionQueue;
class ServerCredentials;
} // namespace grpc_impl
namespace grpc {
class AsyncGenericService;
class GenericServerContext;
class Service;
extern CoreCodegenInterface* g_core_codegen_interface;
/// Models a gRPC server.
///
/// Servers are configured and started via \a grpc::ServerBuilder.
namespace internal {
class ServerAsyncStreamingInterface;
} // namespace internal
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
#endif
class CallbackGenericService;
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
} // namespace experimental
#endif
namespace experimental {
class ServerInterceptorFactoryInterface;
} // namespace experimental
class ServerInterface : public internal::CallHook {
public:
virtual ~ServerInterface() {}
/// \a Shutdown does the following things:
///
/// 1. Shutdown the server: deactivate all listening ports, mark it in
/// "shutdown mode" so that further call Request's or incoming RPC matches
/// are no longer allowed. Also return all Request'ed-but-not-yet-active
/// calls as failed (!ok). This refers to calls that have been requested
/// at the server by the server-side library or application code but that
/// have not yet been matched to incoming RPCs from the client. Note that
/// this would even include default calls added automatically by the gRPC
/// C++ API without the user's input (e.g., "Unimplemented RPC method")
///
/// 2. Block until all rpc method handlers invoked automatically by the sync
/// API finish.
///
/// 3. If all pending calls complete (and all their operations are
/// retrieved by Next) before \a deadline expires, this finishes
/// gracefully. Otherwise, forcefully cancel all pending calls associated
/// with the server after \a deadline expires. In the case of the sync API,
/// if the RPC function for a streaming call has already been started and
/// takes a week to complete, the RPC function won't be forcefully
/// terminated (since that would leave state corrupt and incomplete) and
/// the method handler will just keep running (which will prevent the
/// server from completing the "join" operation that it needs to do at
/// shutdown time).
///
/// All completion queue associated with the server (for example, for async
/// serving) must be shutdown *after* this method has returned:
/// See \a ServerBuilder::AddCompletionQueue for details.
/// They must also be drained (by repeated Next) after being shutdown.
///
/// \param deadline How long to wait until pending rpcs are forcefully
/// terminated.
template <class T>
void Shutdown(const T& deadline) {
ShutdownInternal(TimePoint<T>(deadline).raw_time());
}
/// Shutdown the server without a deadline and forced cancellation.
///
/// All completion queue associated with the server (for example, for async
/// serving) must be shutdown *after* this method has returned:
/// See \a ServerBuilder::AddCompletionQueue for details.
void Shutdown() {
ShutdownInternal(
g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_MONOTONIC));
}
/// Block waiting for all work to complete.
///
/// \warning The server must be either shutting down or some other thread must
/// call \a Shutdown for this function to ever return.
virtual void Wait() = 0;
protected:
friend class ::grpc::Service;
/// Register a service. This call does not take ownership of the service.
/// The service must exist for the lifetime of the Server instance.
virtual bool RegisterService(const grpc::string* host, Service* service) = 0;
/// Register a generic service. This call does not take ownership of the
/// service. The service must exist for the lifetime of the Server instance.
virtual void RegisterAsyncGenericService(AsyncGenericService* service) = 0;
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
/// Register a callback generic service. This call does not take ownership of
/// the service. The service must exist for the lifetime of the Server
/// instance. May not be abstract since this is a post-1.0 API addition.
virtual void RegisterCallbackGenericService(CallbackGenericService*
/*service*/) {}
#else
/// NOTE: class experimental_registration_interface is not part of the public
/// API of this class
/// TODO(vjpai): Move these contents to public API when no longer experimental
class experimental_registration_interface {
public:
virtual ~experimental_registration_interface() {}
/// May not be abstract since this is a post-1.0 API addition
virtual void RegisterCallbackGenericService(
experimental::CallbackGenericService* /*service*/) {}
};
/// NOTE: The function experimental_registration() is not stable public API.
/// It is a view to the experimental components of this class. It may be
/// changed or removed at any time. May not be abstract since this is a
/// post-1.0 API addition
virtual experimental_registration_interface* experimental_registration() {
return nullptr;
}
#endif
/// Tries to bind \a server to the given \a addr.
///
/// It can be invoked multiple times.
///
/// \param addr The address to try to bind to the server (eg, localhost:1234,
/// 192.168.1.1:31416, [::1]:27182, etc.).
/// \params creds The credentials associated with the server.
///
/// \return bound port number on success, 0 on failure.
///
/// \warning It's an error to call this method on an already started server.
virtual int AddListeningPort(const grpc::string& addr,
grpc_impl::ServerCredentials* creds) = 0;
/// Start the server.
///
/// \param cqs Completion queues for handling asynchronous services. The
/// caller is required to keep all completion queues live until the server is
/// destroyed.
/// \param num_cqs How many completion queues does \a cqs hold.
virtual void Start(::grpc_impl::ServerCompletionQueue** cqs,
size_t num_cqs) = 0;
virtual void ShutdownInternal(gpr_timespec deadline) = 0;
virtual int max_receive_message_size() const = 0;
virtual grpc_server* server() = 0;
virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) = 0;
class BaseAsyncRequest : public internal::CompletionQueueTag {
public:
BaseAsyncRequest(ServerInterface* server,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag, bool delete_on_finalize);
virtual ~BaseAsyncRequest();
bool FinalizeResult(void** tag, bool* status) override;
private:
void ContinueFinalizeResultAfterInterception();
protected:
ServerInterface* const server_;
::grpc_impl::ServerContext* const context_;
internal::ServerAsyncStreamingInterface* const stream_;
::grpc_impl::CompletionQueue* const call_cq_;
::grpc_impl::ServerCompletionQueue* const notification_cq_;
void* const tag_;
const bool delete_on_finalize_;
grpc_call* call_;
internal::Call call_wrapper_;
internal::InterceptorBatchMethodsImpl interceptor_methods_;
bool done_intercepting_;
};
/// RegisteredAsyncRequest is not part of the C++ API
class RegisteredAsyncRequest : public BaseAsyncRequest {
public:
RegisteredAsyncRequest(ServerInterface* server,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag, const char* name,
internal::RpcMethod::RpcType type);
virtual bool FinalizeResult(void** tag, bool* status) override {
/* If we are done intercepting, then there is nothing more for us to do */
if (done_intercepting_) {
return BaseAsyncRequest::FinalizeResult(tag, status);
}
call_wrapper_ = ::grpc::internal::Call(
call_, server_, call_cq_, server_->max_receive_message_size(),
context_->set_server_rpc_info(name_, type_,
*server_->interceptor_creators()));
return BaseAsyncRequest::FinalizeResult(tag, status);
}
protected:
void IssueRequest(void* registered_method, grpc_byte_buffer** payload,
::grpc_impl::ServerCompletionQueue* notification_cq);
const char* name_;
const internal::RpcMethod::RpcType type_;
};
class NoPayloadAsyncRequest final : public RegisteredAsyncRequest {
public:
NoPayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
ServerInterface* server,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag)
: RegisteredAsyncRequest(
server, context, stream, call_cq, notification_cq, tag,
registered_method->name(), registered_method->method_type()) {
IssueRequest(registered_method->server_tag(), nullptr, notification_cq);
}
// uses RegisteredAsyncRequest::FinalizeResult
};
template <class Message>
class PayloadAsyncRequest final : public RegisteredAsyncRequest {
public:
PayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
ServerInterface* server,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag, Message* request)
: RegisteredAsyncRequest(
server, context, stream, call_cq, notification_cq, tag,
registered_method->name(), registered_method->method_type()),
registered_method_(registered_method),
request_(request) {
IssueRequest(registered_method->server_tag(), payload_.bbuf_ptr(),
notification_cq);
}
~PayloadAsyncRequest() {
payload_.Release(); // We do not own the payload_
}
bool FinalizeResult(void** tag, bool* status) override {
/* If we are done intercepting, then there is nothing more for us to do */
if (done_intercepting_) {
return RegisteredAsyncRequest::FinalizeResult(tag, status);
}
if (*status) {
if (!payload_.Valid() || !SerializationTraits<Message>::Deserialize(
payload_.bbuf_ptr(), request_)
.ok()) {
// If deserialization fails, we cancel the call and instantiate
// a new instance of ourselves to request another call. We then
// return false, which prevents the call from being returned to
// the application.
g_core_codegen_interface->grpc_call_cancel_with_status(
call_, GRPC_STATUS_INTERNAL, "Unable to parse request", nullptr);
g_core_codegen_interface->grpc_call_unref(call_);
new PayloadAsyncRequest(registered_method_, server_, context_,
stream_, call_cq_, notification_cq_, tag_,
request_);
delete this;
return false;
}
}
/* Set interception point for recv message */
interceptor_methods_.AddInterceptionHookPoint(
experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
interceptor_methods_.SetRecvMessage(request_, nullptr);
return RegisteredAsyncRequest::FinalizeResult(tag, status);
}
private:
internal::RpcServiceMethod* const registered_method_;
Message* const request_;
ByteBuffer payload_;
};
class GenericAsyncRequest : public BaseAsyncRequest {
public:
GenericAsyncRequest(ServerInterface* server, GenericServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag, bool delete_on_finalize);
bool FinalizeResult(void** tag, bool* status) override;
private:
grpc_call_details call_details_;
};
template <class Message>
void RequestAsyncCall(internal::RpcServiceMethod* method,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag, Message* message) {
GPR_CODEGEN_ASSERT(method);
new PayloadAsyncRequest<Message>(method, this, context, stream, call_cq,
notification_cq, tag, message);
}
void RequestAsyncCall(internal::RpcServiceMethod* method,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag) {
GPR_CODEGEN_ASSERT(method);
new NoPayloadAsyncRequest(method, this, context, stream, call_cq,
notification_cq, tag);
}
void RequestAsyncGenericCall(
GenericServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
new GenericAsyncRequest(this, context, stream, call_cq, notification_cq,
tag, true);
}
private:
// EXPERIMENTAL
// Getter method for the vector of interceptor factory objects.
// Returns a nullptr (rather than being pure) since this is a post-1.0 method
// and adding a new pure method to an interface would be a breaking change
// (even though this is private and non-API)
virtual std::vector<
std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>*
interceptor_creators() {
return nullptr;
}
// EXPERIMENTAL
// A method to get the callbackable completion queue associated with this
// server. If the return value is nullptr, this server doesn't support
// callback operations.
// TODO(vjpai): Consider a better default like using a global CQ
// Returns nullptr (rather than being pure) since this is a post-1.0 method
// and adding a new pure method to an interface would be a breaking change
// (even though this is private and non-API)
virtual ::grpc_impl::CompletionQueue* CallbackCQ() { return nullptr; }
};
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SERVER_INTERFACE_H
+279
View File
@@ -0,0 +1,279 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
#define GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/rpc_service_method.h>
#include <grpcpp/impl/codegen/serialization_traits.h>
#include <grpcpp/impl/codegen/server_interface.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
class Server;
class CompletionQueue;
class ServerContext;
} // namespace grpc_impl
namespace grpc {
class ServerInterface;
namespace internal {
class Call;
class ServerAsyncStreamingInterface {
public:
virtual ~ServerAsyncStreamingInterface() {}
/// Request notification of the sending of initial metadata to the client.
/// Completion will be notified by \a tag on the associated completion
/// queue. This call is optional, but if it is used, it cannot be used
/// concurrently with or after the \a Finish method.
///
/// \param[in] tag Tag identifying this request.
virtual void SendInitialMetadata(void* tag) = 0;
private:
friend class ::grpc::ServerInterface;
virtual void BindCall(Call* call) = 0;
};
} // namespace internal
/// Desriptor of an RPC service and its various RPC methods
class Service {
public:
Service() : server_(nullptr) {}
virtual ~Service() {}
bool has_async_methods() const {
for (const auto& method : methods_) {
if (method && method->handler() == nullptr) {
return true;
}
}
return false;
}
bool has_synchronous_methods() const {
for (const auto& method : methods_) {
if (method &&
method->api_type() == internal::RpcServiceMethod::ApiType::SYNC) {
return true;
}
}
return false;
}
bool has_callback_methods() const {
for (const auto& method : methods_) {
if (method && (method->api_type() ==
internal::RpcServiceMethod::ApiType::CALL_BACK ||
method->api_type() ==
internal::RpcServiceMethod::ApiType::RAW_CALL_BACK)) {
return true;
}
}
return false;
}
bool has_generic_methods() const {
for (const auto& method : methods_) {
if (method.get() == nullptr) {
return true;
}
}
return false;
}
protected:
// TODO(vjpai): Promote experimental contents once callback API is accepted
class experimental_type {
public:
explicit experimental_type(Service* service) : service_(service) {}
void MarkMethodCallback(int index, internal::MethodHandler* handler) {
service_->MarkMethodCallbackInternal(index, handler);
}
void MarkMethodRawCallback(int index, internal::MethodHandler* handler) {
service_->MarkMethodRawCallbackInternal(index, handler);
}
internal::MethodHandler* GetHandler(int index) {
return service_->GetHandlerInternal(index);
}
private:
Service* service_;
};
experimental_type experimental() { return experimental_type(this); }
template <class Message>
void RequestAsyncUnary(int index, ::grpc_impl::ServerContext* context,
Message* request,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag) {
// Typecast the index to size_t for indexing into a vector
// while preserving the API that existed before a compiler
// warning was first seen (grpc/grpc#11664)
size_t idx = static_cast<size_t>(index);
server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
notification_cq, tag, request);
}
void RequestAsyncClientStreaming(
int index, ::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
size_t idx = static_cast<size_t>(index);
server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
notification_cq, tag);
}
template <class Message>
void RequestAsyncServerStreaming(
int index, ::grpc_impl::ServerContext* context, Message* request,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
size_t idx = static_cast<size_t>(index);
server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
notification_cq, tag, request);
}
void RequestAsyncBidiStreaming(
int index, ::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
size_t idx = static_cast<size_t>(index);
server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
notification_cq, tag);
}
void AddMethod(internal::RpcServiceMethod* method) {
methods_.emplace_back(method);
}
void MarkMethodAsync(int index) {
// This does not have to be a hard error, however no one has approached us
// with a use case yet. Please file an issue if you believe you have one.
size_t idx = static_cast<size_t>(index);
GPR_CODEGEN_ASSERT(
methods_[idx].get() != nullptr &&
"Cannot mark the method as 'async' because it has already been "
"marked as 'generic'.");
methods_[idx]->SetServerApiType(internal::RpcServiceMethod::ApiType::ASYNC);
}
void MarkMethodRaw(int index) {
// This does not have to be a hard error, however no one has approached us
// with a use case yet. Please file an issue if you believe you have one.
size_t idx = static_cast<size_t>(index);
GPR_CODEGEN_ASSERT(methods_[idx].get() != nullptr &&
"Cannot mark the method as 'raw' because it has already "
"been marked as 'generic'.");
methods_[idx]->SetServerApiType(internal::RpcServiceMethod::ApiType::RAW);
}
void MarkMethodGeneric(int index) {
// This does not have to be a hard error, however no one has approached us
// with a use case yet. Please file an issue if you believe you have one.
size_t idx = static_cast<size_t>(index);
GPR_CODEGEN_ASSERT(
methods_[idx]->handler() != nullptr &&
"Cannot mark the method as 'generic' because it has already been "
"marked as 'async' or 'raw'.");
methods_[idx].reset();
}
void MarkMethodStreamed(int index, internal::MethodHandler* streamed_method) {
// This does not have to be a hard error, however no one has approached us
// with a use case yet. Please file an issue if you believe you have one.
size_t idx = static_cast<size_t>(index);
GPR_CODEGEN_ASSERT(methods_[idx] && methods_[idx]->handler() &&
"Cannot mark an async or generic method Streamed");
methods_[idx]->SetHandler(streamed_method);
// From the server's point of view, streamed unary is a special
// case of BIDI_STREAMING that has 1 read and 1 write, in that order,
// and split server-side streaming is BIDI_STREAMING with 1 read and
// any number of writes, in that order.
methods_[idx]->SetMethodType(internal::RpcMethod::BIDI_STREAMING);
}
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
void MarkMethodCallback(int index, internal::MethodHandler* handler) {
MarkMethodCallbackInternal(index, handler);
}
void MarkMethodRawCallback(int index, internal::MethodHandler* handler) {
MarkMethodRawCallbackInternal(index, handler);
}
internal::MethodHandler* GetHandler(int index) {
return GetHandlerInternal(index);
}
#endif
private:
// TODO(vjpai): migrate the Internal functions to mainline functions once
// callback API is fully de-experimental
void MarkMethodCallbackInternal(int index, internal::MethodHandler* handler) {
// This does not have to be a hard error, however no one has approached us
// with a use case yet. Please file an issue if you believe you have one.
size_t idx = static_cast<size_t>(index);
GPR_CODEGEN_ASSERT(
methods_[idx].get() != nullptr &&
"Cannot mark the method as 'callback' because it has already been "
"marked as 'generic'.");
methods_[idx]->SetHandler(handler);
methods_[idx]->SetServerApiType(
internal::RpcServiceMethod::ApiType::CALL_BACK);
}
void MarkMethodRawCallbackInternal(int index,
internal::MethodHandler* handler) {
// This does not have to be a hard error, however no one has approached us
// with a use case yet. Please file an issue if you believe you have one.
size_t idx = static_cast<size_t>(index);
GPR_CODEGEN_ASSERT(
methods_[idx].get() != nullptr &&
"Cannot mark the method as 'raw callback' because it has already "
"been marked as 'generic'.");
methods_[idx]->SetHandler(handler);
methods_[idx]->SetServerApiType(
internal::RpcServiceMethod::ApiType::RAW_CALL_BACK);
}
internal::MethodHandler* GetHandlerInternal(int index) {
size_t idx = static_cast<size_t>(index);
return methods_[idx]->handler();
}
friend class grpc_impl::Server;
friend class ServerInterface;
ServerInterface* server_;
std::vector<std::unique_ptr<internal::RpcServiceMethod>> methods_;
};
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
+143
View File
@@ -0,0 +1,143 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_SLICE_H
#define GRPCPP_IMPL_CODEGEN_SLICE_H
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/string_ref.h>
#include <grpc/impl/codegen/slice.h>
namespace grpc {
/// A wrapper around \a grpc_slice.
///
/// A slice represents a contiguous reference counted array of bytes.
/// It is cheap to take references to a slice, and it is cheap to create a
/// slice pointing to a subset of another slice.
class Slice final {
public:
/// Construct an empty slice.
Slice() : slice_(g_core_codegen_interface->grpc_empty_slice()) {}
/// Destructor - drops one reference.
~Slice() { g_core_codegen_interface->grpc_slice_unref(slice_); }
enum AddRef { ADD_REF };
/// Construct a slice from \a slice, adding a reference.
Slice(grpc_slice slice, AddRef)
: slice_(g_core_codegen_interface->grpc_slice_ref(slice)) {}
enum StealRef { STEAL_REF };
/// Construct a slice from \a slice, stealing a reference.
Slice(grpc_slice slice, StealRef) : slice_(slice) {}
/// Allocate a slice of specified size
Slice(size_t len)
: slice_(g_core_codegen_interface->grpc_slice_malloc(len)) {}
/// Construct a slice from a copied buffer
Slice(const void* buf, size_t len)
: slice_(g_core_codegen_interface->grpc_slice_from_copied_buffer(
reinterpret_cast<const char*>(buf), len)) {}
/// Construct a slice from a copied string
Slice(const grpc::string& str)
: slice_(g_core_codegen_interface->grpc_slice_from_copied_buffer(
str.c_str(), str.length())) {}
enum StaticSlice { STATIC_SLICE };
/// Construct a slice from a static buffer
Slice(const void* buf, size_t len, StaticSlice)
: slice_(g_core_codegen_interface->grpc_slice_from_static_buffer(
reinterpret_cast<const char*>(buf), len)) {}
/// Copy constructor, adds a reference.
Slice(const Slice& other)
: slice_(g_core_codegen_interface->grpc_slice_ref(other.slice_)) {}
/// Assignment, reference count is unchanged.
Slice& operator=(Slice other) {
std::swap(slice_, other.slice_);
return *this;
}
/// Create a slice pointing at some data. Calls malloc to allocate a refcount
/// for the object, and arranges that destroy will be called with the
/// user data pointer passed in at destruction. Can be the same as buf or
/// different (e.g., if data is part of a larger structure that must be
/// destroyed when the data is no longer needed)
Slice(void* buf, size_t len, void (*destroy)(void*), void* user_data)
: slice_(g_core_codegen_interface->grpc_slice_new_with_user_data(
buf, len, destroy, user_data)) {}
/// Specialization of above for common case where buf == user_data
Slice(void* buf, size_t len, void (*destroy)(void*))
: Slice(buf, len, destroy, buf) {}
/// Similar to the above but has a destroy that also takes slice length
Slice(void* buf, size_t len, void (*destroy)(void*, size_t))
: slice_(g_core_codegen_interface->grpc_slice_new_with_len(buf, len,
destroy)) {}
/// Byte size.
size_t size() const { return GRPC_SLICE_LENGTH(slice_); }
/// Raw pointer to the beginning (first element) of the slice.
const uint8_t* begin() const { return GRPC_SLICE_START_PTR(slice_); }
/// Raw pointer to the end (one byte \em past the last element) of the slice.
const uint8_t* end() const { return GRPC_SLICE_END_PTR(slice_); }
/// Raw C slice. Caller needs to call grpc_slice_unref when done.
grpc_slice c_slice() const {
return g_core_codegen_interface->grpc_slice_ref(slice_);
}
private:
friend class ByteBuffer;
grpc_slice slice_;
};
inline grpc::string_ref StringRefFromSlice(const grpc_slice* slice) {
return grpc::string_ref(
reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(*slice)),
GRPC_SLICE_LENGTH(*slice));
}
inline grpc::string StringFromCopiedSlice(grpc_slice slice) {
return grpc::string(reinterpret_cast<char*>(GRPC_SLICE_START_PTR(slice)),
GRPC_SLICE_LENGTH(slice));
}
inline grpc_slice SliceReferencingString(const grpc::string& str) {
return g_core_codegen_interface->grpc_slice_from_static_buffer(str.data(),
str.length());
}
inline grpc_slice SliceFromCopiedString(const grpc::string& str) {
return g_core_codegen_interface->grpc_slice_from_copied_buffer(str.data(),
str.length());
}
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SLICE_H
+133
View File
@@ -0,0 +1,133 @@
/*
*
* Copyright 2016 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 GRPCPP_IMPL_CODEGEN_STATUS_H
#define GRPCPP_IMPL_CODEGEN_STATUS_H
#include <grpc/impl/codegen/status.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/status_code_enum.h>
namespace grpc {
/// Did it work? If it didn't, why?
///
/// See \a grpc::StatusCode for details on the available code and their meaning.
class Status {
public:
/// Construct an OK instance.
Status() : code_(StatusCode::OK) {
// Static assertions to make sure that the C++ API value correctly
// maps to the core surface API value
static_assert(StatusCode::OK == static_cast<StatusCode>(GRPC_STATUS_OK),
"Mismatched status code");
static_assert(
StatusCode::CANCELLED == static_cast<StatusCode>(GRPC_STATUS_CANCELLED),
"Mismatched status code");
static_assert(
StatusCode::UNKNOWN == static_cast<StatusCode>(GRPC_STATUS_UNKNOWN),
"Mismatched status code");
static_assert(StatusCode::INVALID_ARGUMENT ==
static_cast<StatusCode>(GRPC_STATUS_INVALID_ARGUMENT),
"Mismatched status code");
static_assert(StatusCode::DEADLINE_EXCEEDED ==
static_cast<StatusCode>(GRPC_STATUS_DEADLINE_EXCEEDED),
"Mismatched status code");
static_assert(
StatusCode::NOT_FOUND == static_cast<StatusCode>(GRPC_STATUS_NOT_FOUND),
"Mismatched status code");
static_assert(StatusCode::ALREADY_EXISTS ==
static_cast<StatusCode>(GRPC_STATUS_ALREADY_EXISTS),
"Mismatched status code");
static_assert(StatusCode::PERMISSION_DENIED ==
static_cast<StatusCode>(GRPC_STATUS_PERMISSION_DENIED),
"Mismatched status code");
static_assert(StatusCode::UNAUTHENTICATED ==
static_cast<StatusCode>(GRPC_STATUS_UNAUTHENTICATED),
"Mismatched status code");
static_assert(StatusCode::RESOURCE_EXHAUSTED ==
static_cast<StatusCode>(GRPC_STATUS_RESOURCE_EXHAUSTED),
"Mismatched status code");
static_assert(StatusCode::FAILED_PRECONDITION ==
static_cast<StatusCode>(GRPC_STATUS_FAILED_PRECONDITION),
"Mismatched status code");
static_assert(
StatusCode::ABORTED == static_cast<StatusCode>(GRPC_STATUS_ABORTED),
"Mismatched status code");
static_assert(StatusCode::OUT_OF_RANGE ==
static_cast<StatusCode>(GRPC_STATUS_OUT_OF_RANGE),
"Mismatched status code");
static_assert(StatusCode::UNIMPLEMENTED ==
static_cast<StatusCode>(GRPC_STATUS_UNIMPLEMENTED),
"Mismatched status code");
static_assert(
StatusCode::INTERNAL == static_cast<StatusCode>(GRPC_STATUS_INTERNAL),
"Mismatched status code");
static_assert(StatusCode::UNAVAILABLE ==
static_cast<StatusCode>(GRPC_STATUS_UNAVAILABLE),
"Mismatched status code");
static_assert(
StatusCode::DATA_LOSS == static_cast<StatusCode>(GRPC_STATUS_DATA_LOSS),
"Mismatched status code");
}
/// Construct an instance with associated \a code and \a error_message.
/// It is an error to construct an OK status with non-empty \a error_message.
Status(StatusCode code, const grpc::string& error_message)
: code_(code), error_message_(error_message) {}
/// Construct an instance with \a code, \a error_message and
/// \a error_details. It is an error to construct an OK status with non-empty
/// \a error_message and/or \a error_details.
Status(StatusCode code, const grpc::string& error_message,
const grpc::string& error_details)
: code_(code),
error_message_(error_message),
binary_error_details_(error_details) {}
// Pre-defined special status objects.
/// An OK pre-defined instance.
static const Status& OK;
/// A CANCELLED pre-defined instance.
static const Status& CANCELLED;
/// Return the instance's error code.
StatusCode error_code() const { return code_; }
/// Return the instance's error message.
grpc::string error_message() const { return error_message_; }
/// Return the (binary) error details.
// Usually it contains a serialized google.rpc.Status proto.
grpc::string error_details() const { return binary_error_details_; }
/// Is the status OK?
bool ok() const { return code_ == StatusCode::OK; }
// Ignores any errors. This method does nothing except potentially suppress
// complaints from any tools that are checking that errors are not dropped on
// the floor.
void IgnoreError() const {}
private:
StatusCode code_;
grpc::string error_message_;
grpc::string binary_error_details_;
};
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_STATUS_H
@@ -0,0 +1,143 @@
/*
*
* Copyright 2016 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 GRPCPP_IMPL_CODEGEN_STATUS_CODE_ENUM_H
#define GRPCPP_IMPL_CODEGEN_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. Note that it is
/// not always safe to retry non-idempotent operations.
///
/// \warning Although data MIGHT not have been transmitted when this
/// status occurs, there is NOT A GUARANTEE that the server has not seen
/// anything. So in general it is unsafe to retry on this status code
/// if the call is non-idempotent.
///
/// 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 // GRPCPP_IMPL_CODEGEN_STATUS_CODE_ENUM_H
+146
View File
@@ -0,0 +1,146 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_STRING_REF_H
#define GRPCPP_IMPL_CODEGEN_STRING_REF_H
#include <string.h>
#include <algorithm>
#include <iosfwd>
#include <iostream>
#include <iterator>
#include <grpcpp/impl/codegen/config.h>
namespace grpc {
/// This class is a non owning reference to a string.
///
/// It should be a strict subset of the upcoming std::string_ref.
///
/// \see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html
///
/// The constexpr is dropped or replaced with const for legacy compiler
/// compatibility.
class string_ref {
public:
/// types
typedef const char* const_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
/// constants
const static size_t npos;
/// construct/copy.
string_ref() : data_(nullptr), length_(0) {}
string_ref(const string_ref& other)
: data_(other.data_), length_(other.length_) {}
string_ref& operator=(const string_ref& rhs) {
data_ = rhs.data_;
length_ = rhs.length_;
return *this;
}
string_ref(const char* s) : data_(s), length_(strlen(s)) {}
string_ref(const char* s, size_t l) : data_(s), length_(l) {}
string_ref(const grpc::string& s) : data_(s.data()), length_(s.length()) {}
/// iterators
const_iterator begin() const { return data_; }
const_iterator end() const { return data_ + length_; }
const_iterator cbegin() const { return data_; }
const_iterator cend() const { return data_ + length_; }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
const_reverse_iterator crbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator crend() const {
return const_reverse_iterator(begin());
}
/// capacity
size_t size() const { return length_; }
size_t length() const { return length_; }
size_t max_size() const { return length_; }
bool empty() const { return length_ == 0; }
/// element access
const char* data() const { return data_; }
/// string operations
int compare(string_ref x) const {
size_t min_size = length_ < x.length_ ? length_ : x.length_;
int r = memcmp(data_, x.data_, min_size);
if (r < 0) return -1;
if (r > 0) return 1;
if (length_ < x.length_) return -1;
if (length_ > x.length_) return 1;
return 0;
}
bool starts_with(string_ref x) const {
return length_ >= x.length_ && (memcmp(data_, x.data_, x.length_) == 0);
}
bool ends_with(string_ref x) const {
return length_ >= x.length_ &&
(memcmp(data_ + (length_ - x.length_), x.data_, x.length_) == 0);
}
size_t find(string_ref s) const {
auto it = std::search(cbegin(), cend(), s.cbegin(), s.cend());
return it == cend() ? npos : std::distance(cbegin(), it);
}
size_t find(char c) const {
auto it = std::find(cbegin(), cend(), c);
return it == cend() ? npos : std::distance(cbegin(), it);
}
string_ref substr(size_t pos, size_t n = npos) const {
if (pos > length_) pos = length_;
if (n > (length_ - pos)) n = length_ - pos;
return string_ref(data_ + pos, n);
}
private:
const char* data_;
size_t length_;
};
/// Comparison operators
inline bool operator==(string_ref x, string_ref y) { return x.compare(y) == 0; }
inline bool operator!=(string_ref x, string_ref y) { return x.compare(y) != 0; }
inline bool operator<(string_ref x, string_ref y) { return x.compare(y) < 0; }
inline bool operator<=(string_ref x, string_ref y) { return x.compare(y) <= 0; }
inline bool operator>(string_ref x, string_ref y) { return x.compare(y) > 0; }
inline bool operator>=(string_ref x, string_ref y) { return x.compare(y) >= 0; }
inline std::ostream& operator<<(std::ostream& out, const string_ref& string) {
return out << grpc::string(string.begin(), string.end());
}
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_STRING_REF_H
+29
View File
@@ -0,0 +1,29 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_STUB_OPTIONS_H
#define GRPCPP_IMPL_CODEGEN_STUB_OPTIONS_H
namespace grpc {
/// Useful interface for generated stubs
class StubOptions {};
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_STUB_OPTIONS_H
+151
View File
@@ -0,0 +1,151 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_CODEGEN_SYNC_H
#define GRPCPP_IMPL_CODEGEN_SYNC_H
#include <grpc/impl/codegen/port_platform.h>
#ifdef GPR_HAS_PTHREAD_H
#include <pthread.h>
#endif
#include <mutex>
#include <grpc/impl/codegen/log.h>
#include <grpc/impl/codegen/sync.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
// The core library is not accessible in C++ codegen headers, and vice versa.
// Thus, we need to have duplicate headers with similar functionality.
// Make sure any change to this file is also reflected in
// src/core/lib/gprpp/sync.h too.
//
// Whenever possible, prefer "src/core/lib/gprpp/sync.h" over this file,
// since in core we do not rely on g_core_codegen_interface and hence do not
// pay the costs of virtual function calls.
namespace grpc {
namespace internal {
class Mutex {
public:
Mutex() { g_core_codegen_interface->gpr_mu_init(&mu_); }
~Mutex() { g_core_codegen_interface->gpr_mu_destroy(&mu_); }
Mutex(const Mutex&) = delete;
Mutex& operator=(const Mutex&) = delete;
gpr_mu* get() { return &mu_; }
const gpr_mu* get() const { return &mu_; }
private:
union {
gpr_mu mu_;
std::mutex do_not_use_sth_;
#ifdef GPR_HAS_PTHREAD_H
pthread_mutex_t do_not_use_pth_;
#endif
};
};
// MutexLock is a std::
class MutexLock {
public:
explicit MutexLock(Mutex* mu) : mu_(mu->get()) {
g_core_codegen_interface->gpr_mu_lock(mu_);
}
explicit MutexLock(gpr_mu* mu) : mu_(mu) {
g_core_codegen_interface->gpr_mu_lock(mu_);
}
~MutexLock() { g_core_codegen_interface->gpr_mu_unlock(mu_); }
MutexLock(const MutexLock&) = delete;
MutexLock& operator=(const MutexLock&) = delete;
private:
gpr_mu* const mu_;
};
class ReleasableMutexLock {
public:
explicit ReleasableMutexLock(Mutex* mu) : mu_(mu->get()) {
g_core_codegen_interface->gpr_mu_lock(mu_);
}
explicit ReleasableMutexLock(gpr_mu* mu) : mu_(mu) {
g_core_codegen_interface->gpr_mu_lock(mu_);
}
~ReleasableMutexLock() {
if (!released_) g_core_codegen_interface->gpr_mu_unlock(mu_);
}
ReleasableMutexLock(const ReleasableMutexLock&) = delete;
ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
void Lock() {
GPR_DEBUG_ASSERT(released_);
g_core_codegen_interface->gpr_mu_lock(mu_);
released_ = false;
}
void Unlock() {
GPR_DEBUG_ASSERT(!released_);
released_ = true;
g_core_codegen_interface->gpr_mu_unlock(mu_);
}
private:
gpr_mu* const mu_;
bool released_ = false;
};
class CondVar {
public:
CondVar() { g_core_codegen_interface->gpr_cv_init(&cv_); }
~CondVar() { g_core_codegen_interface->gpr_cv_destroy(&cv_); }
CondVar(const CondVar&) = delete;
CondVar& operator=(const CondVar&) = delete;
void Signal() { g_core_codegen_interface->gpr_cv_signal(&cv_); }
void Broadcast() { g_core_codegen_interface->gpr_cv_broadcast(&cv_); }
int Wait(Mutex* mu) {
return Wait(mu,
g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME));
}
int Wait(Mutex* mu, const gpr_timespec& deadline) {
return g_core_codegen_interface->gpr_cv_wait(&cv_, mu->get(), deadline);
}
template <typename Predicate>
void WaitUntil(Mutex* mu, Predicate pred) {
while (!pred()) {
Wait(mu, g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME));
}
}
private:
gpr_cv cv_;
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SYNC_H
+100
View File
@@ -0,0 +1,100 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H
#define GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H
#include <grpcpp/impl/codegen/sync_stream_impl.h>
namespace grpc {
namespace internal {
typedef ::grpc_impl::internal::ClientStreamingInterface
ClientStreamingInterface;
typedef ::grpc_impl::internal::ServerStreamingInterface
ServerStreamingInterface;
template <class R>
using ReaderInterface = ::grpc_impl::internal::ReaderInterface<R>;
template <class W>
using WriterInterface = ::grpc_impl::internal::WriterInterface<W>;
template <class R>
using ClientReaderFactory = ::grpc_impl::internal::ClientReaderFactory<R>;
template <class W>
using ClientWriterFactory = ::grpc_impl::internal::ClientWriterFactory<W>;
template <class W, class R>
using ClientReaderWriterFactory =
::grpc_impl::internal::ClientReaderWriterFactory<W, R>;
} // namespace internal
template <class R>
using ClientReaderInterface = ::grpc_impl::ClientReaderInterface<R>;
template <class R>
using ClientReader = ::grpc_impl::ClientReader<R>;
template <class W>
using ClientWriterInterface = ::grpc_impl::ClientWriterInterface<W>;
template <class W>
using ClientWriter = ::grpc_impl::ClientWriter<W>;
template <class W, class R>
using ClientReaderWriterInterface =
::grpc_impl::ClientReaderWriterInterface<W, R>;
template <class W, class R>
using ClientReaderWriter = ::grpc_impl::ClientReaderWriter<W, R>;
template <class R>
using ServerReaderInterface = ::grpc_impl::ServerReaderInterface<R>;
template <class R>
using ServerReader = ::grpc_impl::ServerReader<R>;
template <class W>
using ServerWriterInterface = ::grpc_impl::ServerWriterInterface<W>;
template <class W>
using ServerWriter = ::grpc_impl::ServerWriter<W>;
template <class W, class R>
using ServerReaderWriterInterface =
::grpc_impl::ServerReaderWriterInterface<W, R>;
template <class W, class R>
using ServerReaderWriter = ::grpc_impl::ServerReaderWriter<W, R>;
template <class RequestType, class ResponseType>
using ServerUnaryStreamer =
::grpc_impl::ServerUnaryStreamer<RequestType, ResponseType>;
template <class RequestType, class ResponseType>
using ServerSplitStreamer =
::grpc_impl::ServerSplitStreamer<RequestType, ResponseType>;
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H
@@ -0,0 +1,948 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_CODEGEN_SYNC_STREAM_IMPL_H
#define GRPCPP_IMPL_CODEGEN_SYNC_STREAM_IMPL_H
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/client_context_impl.h>
#include <grpcpp/impl/codegen/completion_queue_impl.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/server_context_impl.h>
#include <grpcpp/impl/codegen/service_type.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
namespace internal {
/// Common interface for all synchronous client side streaming.
class ClientStreamingInterface {
public:
virtual ~ClientStreamingInterface() {}
/// Block waiting until the stream finishes and a final status of the call is
/// available.
///
/// It is appropriate to call this method exactly once when both:
/// * the calling code (client-side) has no more message to send
/// (this can be declared implicitly by calling this method, or
/// explicitly through an earlier call to <i>WritesDone</i> method of the
/// class in use, e.g. \a ClientWriterInterface::WritesDone or
/// \a ClientReaderWriterInterface::WritesDone).
/// * there are no more messages to be received from the server (which can
/// be known implicitly, or explicitly from an earlier call to \a
/// ReaderInterface::Read that returned "false").
///
/// This function will return either:
/// - when all incoming messages have been read and the server has
/// returned status.
/// - when the server has returned a non-OK status.
/// - OR when the call failed for some reason and the library generated a
/// status.
///
/// Return values:
/// - \a Status contains the status code, message and details for the call
/// - the \a ClientContext associated with this call is updated with
/// possible trailing metadata sent from the server.
virtual ::grpc::Status Finish() = 0;
};
/// Common interface for all synchronous server side streaming.
class ServerStreamingInterface {
public:
virtual ~ServerStreamingInterface() {}
/// Block to send initial metadata to client.
/// This call is optional, but if it is used, it cannot be used concurrently
/// with or after the \a Finish method.
///
/// The initial metadata that will be sent to the client will be
/// taken from the \a ServerContext associated with the call.
virtual void SendInitialMetadata() = 0;
};
/// An interface that yields a sequence of messages of type \a R.
template <class R>
class ReaderInterface {
public:
virtual ~ReaderInterface() {}
/// Get an upper bound on the next message size available for reading on this
/// stream.
virtual bool NextMessageSize(uint32_t* sz) = 0;
/// Block to read a message and parse to \a msg. Returns \a true on success.
/// This is thread-safe with respect to \a Write or \WritesDone methods on
/// the same stream. It should not be called concurrently with another \a
/// Read on the same stream as the order of delivery will not be defined.
///
/// \param[out] msg The read message.
///
/// \return \a false when there will be no more incoming messages, either
/// because the other side has called \a WritesDone() or the stream has failed
/// (or been cancelled).
virtual bool Read(R* msg) = 0;
};
/// An interface that can be fed a sequence of messages of type \a W.
template <class W>
class WriterInterface {
public:
virtual ~WriterInterface() {}
/// Block to write \a msg to the stream with WriteOptions \a options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
/// \param options The WriteOptions affecting the write operation.
///
/// \return \a true on success, \a false when the stream has been closed.
virtual bool Write(const W& msg, ::grpc::WriteOptions options) = 0;
/// Block to write \a msg to the stream with default write options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
///
/// \return \a true on success, \a false when the stream has been closed.
inline bool Write(const W& msg) { return Write(msg, ::grpc::WriteOptions()); }
/// Write \a msg and coalesce it with the writing of trailing metadata, using
/// WriteOptions \a options.
///
/// For client, WriteLast is equivalent of performing Write and WritesDone in
/// a single step. \a msg and trailing metadata are coalesced and sent on wire
/// by calling this function. For server, WriteLast buffers the \a msg.
/// The writing of \a msg is held until the service handler returns,
/// where \a msg and trailing metadata are coalesced and sent on wire.
/// Note that WriteLast can only buffer \a msg up to the flow control window
/// size. If \a msg size is larger than the window size, it will be sent on
/// wire without buffering.
///
/// \param[in] msg The message to be written to the stream.
/// \param[in] options The WriteOptions to be used to write this message.
void WriteLast(const W& msg, ::grpc::WriteOptions options) {
Write(msg, options.set_last_message());
}
};
} // namespace internal
/// Client-side interface for streaming reads of message of type \a R.
template <class R>
class ClientReaderInterface : public internal::ClientStreamingInterface,
public internal::ReaderInterface<R> {
public:
/// Block to wait for initial metadata from server. The received metadata
/// can only be accessed after this call returns. Should only be called before
/// the first read. Calling this method is optional, and if it is not called
/// the metadata will be available in ClientContext after the first read.
virtual void WaitForInitialMetadata() = 0;
};
namespace internal {
template <class R>
class ClientReaderFactory {
public:
template <class W>
static ClientReader<R>* Create(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
const W& request) {
return new ClientReader<R>(channel, method, context, request);
}
};
} // namespace internal
/// Synchronous (blocking) client-side API for doing server-streaming RPCs,
/// where the stream of messages coming from the server has messages
/// of type \a R.
template <class R>
class ClientReader final : public ClientReaderInterface<R> {
public:
/// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
/// semantics.
///
// Side effect:
/// Once complete, the initial metadata read from
/// the server will be accessible through the \a ClientContext used to
/// construct this object.
void WaitForInitialMetadata() override {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
ops;
ops.RecvInitialMetadata(context_);
call_.PerformOps(&ops);
cq_.Pluck(&ops); /// status ignored
}
bool NextMessageSize(uint32_t* sz) override {
int result = call_.max_receive_message_size();
*sz = (result > 0) ? result : UINT32_MAX;
return true;
}
/// See the \a ReaderInterface.Read method for semantics.
/// Side effect:
/// This also receives initial metadata from the server, if not
/// already received (if initial metadata is received, it can be then
/// accessed through the \a ClientContext associated with this call).
bool Read(R* msg) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpRecvMessage<R>>
ops;
if (!context_->initial_metadata_received_) {
ops.RecvInitialMetadata(context_);
}
ops.RecvMessage(msg);
call_.PerformOps(&ops);
return cq_.Pluck(&ops) && ops.got_message;
}
/// See the \a ClientStreamingInterface.Finish method for semantics.
///
/// Side effect:
/// The \a ClientContext associated with this call is updated with
/// possible metadata received from the server.
::grpc::Status Finish() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops;
::grpc::Status status;
ops.ClientRecvStatus(context_, &status);
call_.PerformOps(&ops);
GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
return status;
}
private:
friend class internal::ClientReaderFactory<R>;
::grpc_impl::ClientContext* context_;
::grpc_impl::CompletionQueue cq_;
::grpc::internal::Call call_;
/// Block to create a stream and write the initial metadata and \a request
/// out. Note that \a context will be used to fill in custom initial
/// metadata used to send to the server when starting the call.
template <class W>
ClientReader(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, const W& request)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(ops.SendMessagePtr(&request).ok());
ops.ClientSendClose();
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
};
/// Client-side interface for streaming writes of message type \a W.
template <class W>
class ClientWriterInterface : public internal::ClientStreamingInterface,
public internal::WriterInterface<W> {
public:
/// Half close writing from the client. (signal that the stream of messages
/// coming from the client is complete).
/// Blocks until currently-pending writes are completed.
/// Thread safe with respect to \a ReaderInterface::Read operations only
///
/// \return Whether the writes were successful.
virtual bool WritesDone() = 0;
};
namespace internal {
template <class W>
class ClientWriterFactory {
public:
template <class R>
static ClientWriter<W>* Create(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
R* response) {
return new ClientWriter<W>(channel, method, context, response);
}
};
} // namespace internal
/// Synchronous (blocking) client-side API for doing client-streaming RPCs,
/// where the outgoing message stream coming from the client has messages of
/// type \a W.
template <class W>
class ClientWriter : public ClientWriterInterface<W> {
public:
/// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
/// semantics.
///
// Side effect:
/// Once complete, the initial metadata read from the server will be
/// accessible through the \a ClientContext used to construct this object.
void WaitForInitialMetadata() {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
ops;
ops.RecvInitialMetadata(context_);
call_.PerformOps(&ops);
cq_.Pluck(&ops); // status ignored
}
/// See the WriterInterface.Write(const W& msg, WriteOptions options) method
/// for semantics.
///
/// Side effect:
/// Also sends initial metadata if not already sent (using the
/// \a ClientContext associated with this call).
using internal::WriterInterface<W>::Write;
bool Write(const W& msg, ::grpc::WriteOptions options) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
if (options.is_last_message()) {
options.set_buffer_hint();
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
ops.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
if (!ops.SendMessagePtr(&msg, options).ok()) {
return false;
}
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
bool WritesDone() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops;
ops.ClientSendClose();
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
/// See the ClientStreamingInterface.Finish method for semantics.
/// Side effects:
/// - Also receives initial metadata if not already received.
/// - Attempts to fill in the \a response parameter passed
/// to the constructor of this instance with the response
/// message from the server.
::grpc::Status Finish() override {
::grpc::Status status;
if (!context_->initial_metadata_received_) {
finish_ops_.RecvInitialMetadata(context_);
}
finish_ops_.ClientRecvStatus(context_, &status);
call_.PerformOps(&finish_ops_);
GPR_CODEGEN_ASSERT(cq_.Pluck(&finish_ops_));
return status;
}
private:
friend class internal::ClientWriterFactory<W>;
/// Block to create a stream (i.e. send request headers and other initial
/// metadata to the server). Note that \a context will be used to fill
/// in custom initial metadata. \a response will be filled in with the
/// single expected response message from the server upon a successful
/// call to the \a Finish method of this instance.
template <class R>
ClientWriter(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, R* response)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
finish_ops_.RecvMessage(response);
finish_ops_.AllowNoMessage();
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
}
::grpc_impl::ClientContext* context_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpGenericRecvMessage,
::grpc::internal::CallOpClientRecvStatus>
finish_ops_;
::grpc_impl::CompletionQueue cq_;
::grpc::internal::Call call_;
};
/// Client-side interface for bi-directional streaming with
/// client-to-server stream messages of type \a W and
/// server-to-client stream messages of type \a R.
template <class W, class R>
class ClientReaderWriterInterface : public internal::ClientStreamingInterface,
public internal::WriterInterface<W>,
public internal::ReaderInterface<R> {
public:
/// Block to wait for initial metadata from server. The received metadata
/// can only be accessed after this call returns. Should only be called before
/// the first read. Calling this method is optional, and if it is not called
/// the metadata will be available in ClientContext after the first read.
virtual void WaitForInitialMetadata() = 0;
/// Half close writing from the client. (signal that the stream of messages
/// coming from the clinet is complete).
/// Blocks until currently-pending writes are completed.
/// Thread-safe with respect to \a ReaderInterface::Read
///
/// \return Whether the writes were successful.
virtual bool WritesDone() = 0;
};
namespace internal {
template <class W, class R>
class ClientReaderWriterFactory {
public:
static ClientReaderWriter<W, R>* Create(
::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context) {
return new ClientReaderWriter<W, R>(channel, method, context);
}
};
} // namespace internal
/// Synchronous (blocking) client-side API for bi-directional streaming RPCs,
/// where the outgoing message stream coming from the client has messages of
/// type \a W, and the incoming messages stream coming from the server has
/// messages of type \a R.
template <class W, class R>
class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
public:
/// Block waiting to read initial metadata from the server.
/// This call is optional, but if it is used, it cannot be used concurrently
/// with or after the \a Finish method.
///
/// Once complete, the initial metadata read from the server will be
/// accessible through the \a ClientContext used to construct this object.
void WaitForInitialMetadata() override {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
ops;
ops.RecvInitialMetadata(context_);
call_.PerformOps(&ops);
cq_.Pluck(&ops); // status ignored
}
bool NextMessageSize(uint32_t* sz) override {
int result = call_.max_receive_message_size();
*sz = (result > 0) ? result : UINT32_MAX;
return true;
}
/// See the \a ReaderInterface.Read method for semantics.
/// Side effect:
/// Also receives initial metadata if not already received (updates the \a
/// ClientContext associated with this call in that case).
bool Read(R* msg) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpRecvMessage<R>>
ops;
if (!context_->initial_metadata_received_) {
ops.RecvInitialMetadata(context_);
}
ops.RecvMessage(msg);
call_.PerformOps(&ops);
return cq_.Pluck(&ops) && ops.got_message;
}
/// See the \a WriterInterface.Write method for semantics.
///
/// Side effect:
/// Also sends initial metadata if not already sent (using the
/// \a ClientContext associated with this call to fill in values).
using internal::WriterInterface<W>::Write;
bool Write(const W& msg, ::grpc::WriteOptions options) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
if (options.is_last_message()) {
options.set_buffer_hint();
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
ops.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
if (!ops.SendMessagePtr(&msg, options).ok()) {
return false;
}
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
bool WritesDone() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops;
ops.ClientSendClose();
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
/// See the ClientStreamingInterface.Finish method for semantics.
///
/// Side effect:
/// - the \a ClientContext associated with this call is updated with
/// possible trailing metadata sent from the server.
::grpc::Status Finish() override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
::grpc::internal::CallOpClientRecvStatus>
ops;
if (!context_->initial_metadata_received_) {
ops.RecvInitialMetadata(context_);
}
::grpc::Status status;
ops.ClientRecvStatus(context_, &status);
call_.PerformOps(&ops);
GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
return status;
}
private:
friend class internal::ClientReaderWriterFactory<W, R>;
::grpc_impl::ClientContext* context_;
::grpc_impl::CompletionQueue cq_;
::grpc::internal::Call call_;
/// Block to create a stream and write the initial metadata and \a request
/// out. Note that \a context will be used to fill in custom initial metadata
/// used to send to the server when starting the call.
ClientReaderWriter(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context)
: context_(context),
cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) {
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
}
};
/// Server-side interface for streaming reads of message of type \a R.
template <class R>
class ServerReaderInterface : public internal::ServerStreamingInterface,
public internal::ReaderInterface<R> {};
/// Synchronous (blocking) server-side API for doing client-streaming RPCs,
/// where the incoming message stream coming from the client has messages of
/// type \a R.
template <class R>
class ServerReader final : public ServerReaderInterface<R> {
public:
/// See the \a ServerStreamingInterface.SendInitialMetadata method
/// for semantics. Note that initial metadata will be affected by the
/// \a ServerContext associated with this call.
void SendInitialMetadata() override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
}
bool NextMessageSize(uint32_t* sz) override {
int result = call_->max_receive_message_size();
*sz = (result > 0) ? result : UINT32_MAX;
return true;
}
bool Read(R* msg) override {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>> ops;
ops.RecvMessage(msg);
call_->PerformOps(&ops);
return call_->cq()->Pluck(&ops) && ops.got_message;
}
private:
::grpc::internal::Call* const call_;
ServerContext* const ctx_;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc_impl::internal::ClientStreamingHandler;
ServerReader(::grpc::internal::Call* call, ::grpc_impl::ServerContext* ctx)
: call_(call), ctx_(ctx) {}
};
/// Server-side interface for streaming writes of message of type \a W.
template <class W>
class ServerWriterInterface : public internal::ServerStreamingInterface,
public internal::WriterInterface<W> {};
/// Synchronous (blocking) server-side API for doing for doing a
/// server-streaming RPCs, where the outgoing message stream coming from the
/// server has messages of type \a W.
template <class W>
class ServerWriter final : public ServerWriterInterface<W> {
public:
/// See the \a ServerStreamingInterface.SendInitialMetadata method
/// for semantics.
/// Note that initial metadata will be affected by the
/// \a ServerContext associated with this call.
void SendInitialMetadata() override {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
}
/// See the \a WriterInterface.Write method for semantics.
///
/// Side effect:
/// Also sends initial metadata if not already sent (using the
/// \a ClientContext associated with this call to fill in values).
using internal::WriterInterface<W>::Write;
bool Write(const W& msg, ::grpc::WriteOptions options) override {
if (options.is_last_message()) {
options.set_buffer_hint();
}
if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) {
return false;
}
if (!ctx_->sent_initial_metadata_) {
ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
call_->PerformOps(&ctx_->pending_ops_);
// if this is the last message we defer the pluck until AFTER we start
// the trailing md op. This prevents hangs. See
// https://github.com/grpc/grpc/issues/11546
if (options.is_last_message()) {
ctx_->has_pending_ops_ = true;
return true;
}
ctx_->has_pending_ops_ = false;
return call_->cq()->Pluck(&ctx_->pending_ops_);
}
private:
::grpc::internal::Call* const call_;
::grpc_impl::ServerContext* const ctx_;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc_impl::internal::ServerStreamingHandler;
ServerWriter(::grpc::internal::Call* call, ::grpc_impl::ServerContext* ctx)
: call_(call), ctx_(ctx) {}
};
/// Server-side interface for bi-directional streaming.
template <class W, class R>
class ServerReaderWriterInterface : public internal::ServerStreamingInterface,
public internal::WriterInterface<W>,
public internal::ReaderInterface<R> {};
/// Actual implementation of bi-directional streaming
namespace internal {
template <class W, class R>
class ServerReaderWriterBody final {
public:
ServerReaderWriterBody(grpc::internal::Call* call,
::grpc_impl::ServerContext* ctx)
: call_(call), ctx_(ctx) {}
void SendInitialMetadata() {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
}
bool NextMessageSize(uint32_t* sz) {
int result = call_->max_receive_message_size();
*sz = (result > 0) ? result : UINT32_MAX;
return true;
}
bool Read(R* msg) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>> ops;
ops.RecvMessage(msg);
call_->PerformOps(&ops);
return call_->cq()->Pluck(&ops) && ops.got_message;
}
bool Write(const W& msg, ::grpc::WriteOptions options) {
if (options.is_last_message()) {
options.set_buffer_hint();
}
if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) {
return false;
}
if (!ctx_->sent_initial_metadata_) {
ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
call_->PerformOps(&ctx_->pending_ops_);
// if this is the last message we defer the pluck until AFTER we start
// the trailing md op. This prevents hangs. See
// https://github.com/grpc/grpc/issues/11546
if (options.is_last_message()) {
ctx_->has_pending_ops_ = true;
return true;
}
ctx_->has_pending_ops_ = false;
return call_->cq()->Pluck(&ctx_->pending_ops_);
}
private:
grpc::internal::Call* const call_;
::grpc_impl::ServerContext* const ctx_;
};
} // namespace internal
/// Synchronous (blocking) server-side API for a bidirectional
/// streaming call, where the incoming message stream coming from the client has
/// messages of type \a R, and the outgoing message streaming coming from
/// the server has messages of type \a W.
template <class W, class R>
class ServerReaderWriter final : public ServerReaderWriterInterface<W, R> {
public:
/// See the \a ServerStreamingInterface.SendInitialMetadata method
/// for semantics. Note that initial metadata will be affected by the
/// \a ServerContext associated with this call.
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
bool NextMessageSize(uint32_t* sz) override {
return body_.NextMessageSize(sz);
}
bool Read(R* msg) override { return body_.Read(msg); }
/// See the \a WriterInterface.Write(const W& msg, WriteOptions options)
/// method for semantics.
/// Side effect:
/// Also sends initial metadata if not already sent (using the \a
/// ServerContext associated with this call).
using internal::WriterInterface<W>::Write;
bool Write(const W& msg, ::grpc::WriteOptions options) override {
return body_.Write(msg, options);
}
private:
internal::ServerReaderWriterBody<W, R> body_;
friend class ::grpc_impl::internal::TemplatedBidiStreamingHandler<
ServerReaderWriter<W, R>, false>;
ServerReaderWriter(::grpc::internal::Call* call,
::grpc_impl::ServerContext* ctx)
: body_(call, ctx) {}
};
/// A class to represent a flow-controlled unary call. This is something
/// of a hybrid between conventional unary and streaming. This is invoked
/// through a unary call on the client side, but the server responds to it
/// as though it were a single-ping-pong streaming call. The server can use
/// the \a NextMessageSize method to determine an upper-bound on the size of
/// the message. A key difference relative to streaming: ServerUnaryStreamer
/// must have exactly 1 Read and exactly 1 Write, in that order, to function
/// correctly. Otherwise, the RPC is in error.
template <class RequestType, class ResponseType>
class ServerUnaryStreamer final
: public ServerReaderWriterInterface<ResponseType, RequestType> {
public:
/// Block to send initial metadata to client.
/// Implicit input parameter:
/// - the \a ServerContext associated with this call will be used for
/// sending initial metadata.
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
/// Get an upper bound on the request message size from the client.
bool NextMessageSize(uint32_t* sz) override {
return body_.NextMessageSize(sz);
}
/// Read a message of type \a R into \a msg. Completion will be notified by \a
/// tag on the associated completion queue.
/// This is thread-safe with respect to \a Write or \a WritesDone methods. It
/// should not be called concurrently with other streaming APIs
/// on the same stream. It is not meaningful to call it concurrently
/// with another \a ReaderInterface::Read on the same stream since reads on
/// the same stream are delivered in order.
///
/// \param[out] msg Where to eventually store the read message.
/// \param[in] tag The tag identifying the operation.
bool Read(RequestType* request) override {
if (read_done_) {
return false;
}
read_done_ = true;
return body_.Read(request);
}
/// Block to write \a msg to the stream with WriteOptions \a options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
/// \param options The WriteOptions affecting the write operation.
///
/// \return \a true on success, \a false when the stream has been closed.
using internal::WriterInterface<ResponseType>::Write;
bool Write(const ResponseType& response,
::grpc::WriteOptions options) override {
if (write_done_ || !read_done_) {
return false;
}
write_done_ = true;
return body_.Write(response, options);
}
private:
internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
bool read_done_;
bool write_done_;
friend class ::grpc_impl::internal::TemplatedBidiStreamingHandler<
ServerUnaryStreamer<RequestType, ResponseType>, true>;
ServerUnaryStreamer(::grpc::internal::Call* call,
::grpc_impl::ServerContext* ctx)
: body_(call, ctx), read_done_(false), write_done_(false) {}
};
/// A class to represent a flow-controlled server-side streaming call.
/// This is something of a hybrid between server-side and bidi streaming.
/// This is invoked through a server-side streaming call on the client side,
/// but the server responds to it as though it were a bidi streaming call that
/// must first have exactly 1 Read and then any number of Writes.
template <class RequestType, class ResponseType>
class ServerSplitStreamer final
: public ServerReaderWriterInterface<ResponseType, RequestType> {
public:
/// Block to send initial metadata to client.
/// Implicit input parameter:
/// - the \a ServerContext associated with this call will be used for
/// sending initial metadata.
void SendInitialMetadata() override { body_.SendInitialMetadata(); }
/// Get an upper bound on the request message size from the client.
bool NextMessageSize(uint32_t* sz) override {
return body_.NextMessageSize(sz);
}
/// Read a message of type \a R into \a msg. Completion will be notified by \a
/// tag on the associated completion queue.
/// This is thread-safe with respect to \a Write or \a WritesDone methods. It
/// should not be called concurrently with other streaming APIs
/// on the same stream. It is not meaningful to call it concurrently
/// with another \a ReaderInterface::Read on the same stream since reads on
/// the same stream are delivered in order.
///
/// \param[out] msg Where to eventually store the read message.
/// \param[in] tag The tag identifying the operation.
bool Read(RequestType* request) override {
if (read_done_) {
return false;
}
read_done_ = true;
return body_.Read(request);
}
/// Block to write \a msg to the stream with WriteOptions \a options.
/// This is thread-safe with respect to \a ReaderInterface::Read
///
/// \param msg The message to be written to the stream.
/// \param options The WriteOptions affecting the write operation.
///
/// \return \a true on success, \a false when the stream has been closed.
using internal::WriterInterface<ResponseType>::Write;
bool Write(const ResponseType& response,
::grpc::WriteOptions options) override {
return read_done_ && body_.Write(response, options);
}
private:
internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
bool read_done_;
friend class ::grpc_impl::internal::TemplatedBidiStreamingHandler<
ServerSplitStreamer<RequestType, ResponseType>, false>;
ServerSplitStreamer(::grpc::internal::Call* call,
::grpc_impl::ServerContext* ctx)
: body_(call, ctx), read_done_(false) {}
};
} // namespace grpc_impl
#endif // GRPCPP_IMPL_CODEGEN_SYNC_STREAM_IMPL_H
+87
View File
@@ -0,0 +1,87 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_CODEGEN_TIME_H
#define GRPCPP_IMPL_CODEGEN_TIME_H
#include <chrono>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/config.h>
namespace grpc {
/** If you are trying to use CompletionQueue::AsyncNext with a time class that
isn't either gpr_timespec or std::chrono::system_clock::time_point, you
will most likely be looking at this comment as your compiler will have
fired an error below. In order to fix this issue, you have two potential
solutions:
1. Use gpr_timespec or std::chrono::system_clock::time_point instead
2. Specialize the TimePoint class with whichever time class that you
want to use here. See below for two examples of how to do this.
*/
template <typename T>
class TimePoint {
public:
// If you see the error with methods below, you may need either
// i) using the existing types having a conversion class such as
// gpr_timespec and std::chrono::system_clock::time_point or
// ii) writing a new TimePoint<YourType> to address your case.
TimePoint(const T& /*time*/) = delete;
gpr_timespec raw_time() = delete;
};
template <>
class TimePoint<gpr_timespec> {
public:
TimePoint(const gpr_timespec& time) : time_(time) {}
gpr_timespec raw_time() { return time_; }
private:
gpr_timespec time_;
};
} // namespace grpc
namespace grpc {
// from and to should be absolute time.
void Timepoint2Timespec(const std::chrono::system_clock::time_point& from,
gpr_timespec* to);
void TimepointHR2Timespec(
const std::chrono::high_resolution_clock::time_point& from,
gpr_timespec* to);
std::chrono::system_clock::time_point Timespec2Timepoint(gpr_timespec t);
template <>
class TimePoint<std::chrono::system_clock::time_point> {
public:
TimePoint(const std::chrono::system_clock::time_point& time) {
Timepoint2Timespec(time, &time_);
}
gpr_timespec raw_time() const { return time_; }
private:
gpr_timespec time_;
};
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_TIME_H
+60
View File
@@ -0,0 +1,60 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_GRPC_LIBRARY_H
#define GRPCPP_IMPL_GRPC_LIBRARY_H
#include <iostream>
#include <grpc/grpc.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen.h>
#include <grpcpp/impl/codegen/grpc_library.h>
namespace grpc {
namespace internal {
class GrpcLibrary final : public GrpcLibraryInterface {
public:
void init() override { grpc_init(); }
void shutdown() override { grpc_shutdown(); }
};
/// Instantiating this class ensures the proper initialization of gRPC.
class GrpcLibraryInitializer final {
public:
GrpcLibraryInitializer() {
if (grpc::g_glip == nullptr) {
static auto* const g_gli = new GrpcLibrary();
grpc::g_glip = g_gli;
}
if (grpc::g_core_codegen_interface == nullptr) {
static auto* const g_core_codegen = new CoreCodegen();
grpc::g_core_codegen_interface = g_core_codegen;
}
}
/// A no-op method to force the linker to reference this class, which will
/// take care of initializing and shutting down the gRPC runtime.
int summon() { return 0; }
};
} // namespace internal
} // namespace grpc
#endif // GRPCPP_IMPL_GRPC_LIBRARY_H
+24
View File
@@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_METHOD_HANDLER_IMPL_H
#define GRPCPP_IMPL_METHOD_HANDLER_IMPL_H
#include <grpcpp/impl/codegen/method_handler_impl.h>
#endif // GRPCPP_IMPL_METHOD_HANDLER_IMPL_H
+24
View File
@@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_RPC_METHOD_H
#define GRPCPP_IMPL_RPC_METHOD_H
#include <grpcpp/impl/codegen/rpc_method.h>
#endif // GRPCPP_IMPL_RPC_METHOD_H
+24
View File
@@ -0,0 +1,24 @@
/*
*
* Copyright 2016 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 GRPCPP_IMPL_RPC_SERVICE_METHOD_H
#define GRPCPP_IMPL_RPC_SERVICE_METHOD_H
#include <grpcpp/impl/codegen/rpc_service_method.h>
#endif // GRPCPP_IMPL_RPC_SERVICE_METHOD_H
+24
View File
@@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_SERIALIZATION_TRAITS_H
#define GRPCPP_IMPL_SERIALIZATION_TRAITS_H
#include <grpcpp/impl/codegen/serialization_traits.h>
#endif // GRPCPP_IMPL_SERIALIZATION_TRAITS_H
@@ -0,0 +1,30 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_SERVER_BUILDER_OPTION_H
#define GRPCPP_IMPL_SERVER_BUILDER_OPTION_H
#include <grpcpp/impl/server_builder_option_impl.h>
namespace grpc {
typedef ::grpc_impl::ServerBuilderOption ServerBuilderOption;
} // namespace grpc
#endif // GRPCPP_IMPL_SERVER_BUILDER_OPTION_H
@@ -0,0 +1,43 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_SERVER_BUILDER_OPTION_IMPL_H
#define GRPCPP_IMPL_SERVER_BUILDER_OPTION_IMPL_H
#include <map>
#include <memory>
#include <grpcpp/impl/server_builder_plugin.h>
#include <grpcpp/support/channel_arguments.h>
namespace grpc_impl {
/// Interface to pass an option to a \a ServerBuilder.
class ServerBuilderOption {
public:
virtual ~ServerBuilderOption() {}
/// Alter the \a ChannelArguments used to create the gRPC server.
virtual void UpdateArguments(grpc::ChannelArguments* args) = 0;
/// Alter the ServerBuilderPlugin map that will be added into ServerBuilder.
virtual void UpdatePlugins(
std::vector<std::unique_ptr<grpc::ServerBuilderPlugin>>* plugins) = 0;
};
} // namespace grpc_impl
#endif // GRPCPP_IMPL_SERVER_BUILDER_OPTION_IMPL_H
@@ -0,0 +1,68 @@
/*
*
* Copyright 2016 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 GRPCPP_IMPL_SERVER_BUILDER_PLUGIN_H
#define GRPCPP_IMPL_SERVER_BUILDER_PLUGIN_H
#include <memory>
#include <grpcpp/support/channel_arguments.h>
#include <grpcpp/support/config.h>
namespace grpc_impl {
class ServerBuilder;
class ServerInitializer;
} // namespace grpc_impl
namespace grpc {
/// This interface is meant for internal usage only. Implementations of this
/// interface should add themselves to a \a ServerBuilder instance through the
/// \a InternalAddPluginFactory method.
class ServerBuilderPlugin {
public:
virtual ~ServerBuilderPlugin() {}
virtual grpc::string name() = 0;
/// UpdateServerBuilder will be called at an early stage in
/// ServerBuilder::BuildAndStart(), right after the ServerBuilderOptions have
/// done their updates.
virtual void UpdateServerBuilder(grpc_impl::ServerBuilder* /*builder*/) {}
/// InitServer will be called in ServerBuilder::BuildAndStart(), after the
/// Server instance is created.
virtual void InitServer(grpc_impl::ServerInitializer* si) = 0;
/// Finish will be called at the end of ServerBuilder::BuildAndStart().
virtual void Finish(grpc_impl::ServerInitializer* si) = 0;
/// ChangeArguments is an interface that can be used in
/// ServerBuilderOption::UpdatePlugins
virtual void ChangeArguments(const grpc::string& name, void* value) = 0;
/// UpdateChannelArguments will be called in ServerBuilder::BuildAndStart(),
/// before the Server instance is created.
virtual void UpdateChannelArguments(ChannelArguments* /*args*/) {}
virtual bool has_sync_methods() const { return false; }
virtual bool has_async_methods() const { return false; }
};
} // namespace grpc
#endif // GRPCPP_IMPL_SERVER_BUILDER_PLUGIN_H
+30
View File
@@ -0,0 +1,30 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_SERVER_INITIALIZER_H
#define GRPCPP_IMPL_SERVER_INITIALIZER_H
#include <grpcpp/impl/server_initializer_impl.h>
namespace grpc {
typedef ::grpc_impl::ServerInitializer ServerInitializer;
} // namespace grpc
#endif // GRPCPP_IMPL_SERVER_INITIALIZER_H
@@ -0,0 +1,57 @@
/*
*
* Copyright 2016 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 GRPCPP_IMPL_SERVER_INITIALIZER_IMPL_H
#define GRPCPP_IMPL_SERVER_INITIALIZER_IMPL_H
#include <memory>
#include <vector>
#include <grpcpp/server.h>
namespace grpc {
class Service;
} // namespace grpc
namespace grpc_impl {
class Server;
class ServerInitializer {
public:
ServerInitializer(grpc::Server* server) : server_(server) {}
bool RegisterService(std::shared_ptr<grpc::Service> service) {
if (!server_->RegisterService(nullptr, service.get())) {
return false;
}
default_services_.push_back(service);
return true;
}
const std::vector<grpc::string>* GetServiceList() {
return &server_->services_;
}
private:
grpc::Server* server_;
std::vector<std::shared_ptr<grpc::Service> > default_services_;
};
} // namespace grpc_impl
#endif // GRPCPP_IMPL_SERVER_INITIALIZER_IMPL_H
+24
View File
@@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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 GRPCPP_IMPL_SERVICE_TYPE_H
#define GRPCPP_IMPL_SERVICE_TYPE_H
#include <grpcpp/impl/codegen/service_type.h>
#endif // GRPCPP_IMPL_SERVICE_TYPE_H
+29
View File
@@ -0,0 +1,29 @@
/*
*
* Copyright 2019 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 GRPCPP_RESOURCE_QUOTA_H
#define GRPCPP_RESOURCE_QUOTA_H
#include <grpcpp/resource_quota_impl.h>
namespace grpc {
typedef ::grpc_impl::ResourceQuota ResourceQuota;
} // namespace grpc
#endif // GRPCPP_RESOURCE_QUOTA_H
+68
View File
@@ -0,0 +1,68 @@
/*
*
* Copyright 2016 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 GRPCPP_RESOURCE_QUOTA_IMPL_H
#define GRPCPP_RESOURCE_QUOTA_IMPL_H
struct grpc_resource_quota;
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/grpc_library.h>
namespace grpc_impl {
/// ResourceQuota represents a bound on memory and thread usage by the gRPC
/// library. A ResourceQuota can be attached to a server (via \a ServerBuilder),
/// or a client channel (via \a ChannelArguments).
/// gRPC will attempt to keep memory and threads used by all attached entities
/// below the ResourceQuota bound.
class ResourceQuota final : private ::grpc::GrpcLibraryCodegen {
public:
/// \param name - a unique name for this ResourceQuota.
explicit ResourceQuota(const grpc::string& name);
ResourceQuota();
~ResourceQuota();
/// Resize this \a ResourceQuota to a new size. If \a new_size is smaller
/// than the current size of the pool, memory usage will be monotonically
/// decreased until it falls under \a new_size.
/// No time bound is given for this to occur however.
ResourceQuota& Resize(size_t new_size);
/// Set the max number of threads that can be allocated from this
/// ResourceQuota object.
///
/// If the new_max_threads value is smaller than the current value, no new
/// threads are allocated until the number of active threads fall below
/// new_max_threads. There is no time bound on when this may happen i.e none
/// of the current threads are forcefully destroyed and all threads run their
/// normal course.
ResourceQuota& SetMaxThreads(int new_max_threads);
grpc_resource_quota* c_resource_quota() const { return impl_; }
private:
ResourceQuota(const ResourceQuota& rhs);
ResourceQuota& operator=(const ResourceQuota& rhs);
grpc_resource_quota* const impl_;
};
} // namespace grpc_impl
#endif // GRPCPP_RESOURCE_QUOTA_IMPL_H
+24
View File
@@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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 GRPCPP_SECURITY_AUTH_CONTEXT_H
#define GRPCPP_SECURITY_AUTH_CONTEXT_H
#include <grpcpp/impl/codegen/security/auth_context.h>
#endif // GRPCPP_SECURITY_AUTH_CONTEXT_H
@@ -0,0 +1,30 @@
/*
*
* Copyright 2019 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 GRPCPP_SECURITY_AUTH_METADATA_PROCESSOR_H
#define GRPCPP_SECURITY_AUTH_METADATA_PROCESSOR_H
#include <grpcpp/security/auth_metadata_processor_impl.h>
namespace grpc {
typedef ::grpc_impl::AuthMetadataProcessor AuthMetadataProcessor;
} // namespace grpc
#endif // GRPCPP_SECURITY_AUTH_METADATA_PROCESSOR_H
@@ -0,0 +1,61 @@
/*
*
* Copyright 2015 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 GRPCPP_SECURITY_AUTH_METADATA_PROCESSOR_IMPL_H
#define GRPCPP_SECURITY_AUTH_METADATA_PROCESSOR_IMPL_H
#include <map>
#include <grpcpp/security/auth_context.h>
#include <grpcpp/support/status.h>
#include <grpcpp/support/string_ref.h>
namespace grpc_impl {
/// Interface allowing custom server-side authorization based on credentials
/// encoded in metadata. Objects of this type can be passed to
/// \a ServerCredentials::SetAuthMetadataProcessor().
class AuthMetadataProcessor {
public:
typedef std::multimap<grpc::string_ref, grpc::string_ref> InputMetadata;
typedef std::multimap<grpc::string, grpc::string> OutputMetadata;
virtual ~AuthMetadataProcessor() {}
/// If this method returns true, the \a Process function will be scheduled in
/// a different thread from the one processing the call.
virtual bool IsBlocking() const { return true; }
/// context is read/write: it contains the properties of the channel peer and
/// it is the job of the Process method to augment it with properties derived
/// from the passed-in auth_metadata.
/// consumed_auth_metadata needs to be filled with metadata that has been
/// consumed by the processor and will be removed from the call.
/// response_metadata is the metadata that will be sent as part of the
/// response.
/// If the return value is not Status::OK, the rpc call will be aborted with
/// the error code and error message sent back to the client.
virtual grpc::Status Process(const InputMetadata& auth_metadata,
grpc::AuthContext* context,
OutputMetadata* consumed_auth_metadata,
OutputMetadata* response_metadata) = 0;
};
} // namespace grpc_impl
#endif // GRPCPP_SECURITY_AUTH_METADATA_PROCESSOR_IMPL_H
+143
View File
@@ -0,0 +1,143 @@
/*
*
* Copyright 2015 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 GRPCPP_SECURITY_CREDENTIALS_H
#define GRPCPP_SECURITY_CREDENTIALS_H
#include <grpcpp/security/credentials_impl.h>
namespace grpc {
typedef ::grpc_impl::ChannelCredentials ChannelCredentials;
typedef ::grpc_impl::CallCredentials CallCredentials;
typedef ::grpc_impl::SslCredentialsOptions SslCredentialsOptions;
typedef ::grpc_impl::SecureCallCredentials SecureCallCredentials;
typedef ::grpc_impl::SecureChannelCredentials SecureChannelCredentials;
typedef ::grpc_impl::MetadataCredentialsPlugin MetadataCredentialsPlugin;
static inline std::shared_ptr<grpc_impl::ChannelCredentials>
GoogleDefaultCredentials() {
return ::grpc_impl::GoogleDefaultCredentials();
}
static inline std::shared_ptr<ChannelCredentials> SslCredentials(
const SslCredentialsOptions& options) {
return ::grpc_impl::SslCredentials(options);
}
static inline std::shared_ptr<grpc_impl::CallCredentials>
GoogleComputeEngineCredentials() {
return ::grpc_impl::GoogleComputeEngineCredentials();
}
/// Constant for maximum auth token lifetime.
constexpr long kMaxAuthTokenLifetimeSecs =
::grpc_impl::kMaxAuthTokenLifetimeSecs;
static inline std::shared_ptr<grpc_impl::CallCredentials>
ServiceAccountJWTAccessCredentials(
const grpc::string& json_key,
long token_lifetime_seconds = grpc::kMaxAuthTokenLifetimeSecs) {
return ::grpc_impl::ServiceAccountJWTAccessCredentials(
json_key, token_lifetime_seconds);
}
static inline std::shared_ptr<grpc_impl::CallCredentials>
GoogleRefreshTokenCredentials(const grpc::string& json_refresh_token) {
return ::grpc_impl::GoogleRefreshTokenCredentials(json_refresh_token);
}
static inline std::shared_ptr<grpc_impl::CallCredentials>
AccessTokenCredentials(const grpc::string& access_token) {
return ::grpc_impl::AccessTokenCredentials(access_token);
}
static inline std::shared_ptr<grpc_impl::CallCredentials> GoogleIAMCredentials(
const grpc::string& authorization_token,
const grpc::string& authority_selector) {
return ::grpc_impl::GoogleIAMCredentials(authorization_token,
authority_selector);
}
static inline std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds) {
return ::grpc_impl::CompositeChannelCredentials(channel_creds, call_creds);
}
static inline std::shared_ptr<grpc_impl::CallCredentials>
CompositeCallCredentials(const std::shared_ptr<CallCredentials>& creds1,
const std::shared_ptr<CallCredentials>& creds2) {
return ::grpc_impl::CompositeCallCredentials(creds1, creds2);
}
static inline std::shared_ptr<grpc_impl::ChannelCredentials>
InsecureChannelCredentials() {
return ::grpc_impl::InsecureChannelCredentials();
}
typedef ::grpc_impl::MetadataCredentialsPlugin MetadataCredentialsPlugin;
static inline std::shared_ptr<grpc_impl::CallCredentials>
MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin) {
return ::grpc_impl::MetadataCredentialsFromPlugin(std::move(plugin));
}
namespace experimental {
typedef ::grpc_impl::experimental::StsCredentialsOptions StsCredentialsOptions;
static inline grpc::Status StsCredentialsOptionsFromJson(
const grpc::string& json_string, StsCredentialsOptions* options) {
return ::grpc_impl::experimental::StsCredentialsOptionsFromJson(json_string,
options);
}
static inline grpc::Status StsCredentialsOptionsFromEnv(
StsCredentialsOptions* options) {
return grpc_impl::experimental::StsCredentialsOptionsFromEnv(options);
}
static inline std::shared_ptr<grpc_impl::CallCredentials> StsCredentials(
const StsCredentialsOptions& options) {
return grpc_impl::experimental::StsCredentials(options);
}
typedef ::grpc_impl::experimental::AltsCredentialsOptions
AltsCredentialsOptions;
static inline std::shared_ptr<grpc_impl::ChannelCredentials> AltsCredentials(
const AltsCredentialsOptions& options) {
return ::grpc_impl::experimental::AltsCredentials(options);
}
static inline std::shared_ptr<grpc_impl::ChannelCredentials> LocalCredentials(
grpc_local_connect_type type) {
return ::grpc_impl::experimental::LocalCredentials(type);
}
static inline std::shared_ptr<grpc_impl::ChannelCredentials> TlsCredentials(
const ::grpc_impl::experimental::TlsCredentialsOptions& options) {
return ::grpc_impl::experimental::TlsCredentials(options);
}
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_SECURITY_CREDENTIALS_H
+351
View File
@@ -0,0 +1,351 @@
/*
*
* Copyright 2015 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 GRPCPP_SECURITY_CREDENTIALS_IMPL_H
#define GRPCPP_SECURITY_CREDENTIALS_IMPL_H
#include <map>
#include <memory>
#include <vector>
#include <grpc/grpc_security_constants.h>
#include <grpcpp/channel_impl.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/security/auth_context.h>
#include <grpcpp/security/tls_credentials_options.h>
#include <grpcpp/support/channel_arguments_impl.h>
#include <grpcpp/support/status.h>
#include <grpcpp/support/string_ref.h>
struct grpc_call;
namespace grpc_impl {
class ChannelCredentials;
class CallCredentials;
class SecureCallCredentials;
class SecureChannelCredentials;
std::shared_ptr<Channel> CreateCustomChannelImpl(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args);
namespace experimental {
std::shared_ptr<Channel> CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args,
std::vector<
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
}
/// A channel credentials object encapsulates all the state needed by a client
/// to authenticate with a server for a given channel.
/// It can make various assertions, e.g., about the clients identity, role
/// for all the calls on that channel.
///
/// \see https://grpc.io/docs/guides/auth.html
class ChannelCredentials : private grpc::GrpcLibraryCodegen {
public:
ChannelCredentials();
~ChannelCredentials();
protected:
friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
virtual SecureChannelCredentials* AsSecureCredentials() = 0;
private:
friend std::shared_ptr<Channel> CreateCustomChannelImpl(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args);
friend std::shared_ptr<Channel>
grpc_impl::experimental::CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args,
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
virtual std::shared_ptr<Channel> CreateChannelImpl(
const grpc::string& target, const ChannelArguments& args) = 0;
// This function should have been a pure virtual function, but it is
// implemented as a virtual function so that it does not break API.
virtual std::shared_ptr<Channel> CreateChannelWithInterceptors(
const grpc::string& /*target*/, const ChannelArguments& /*args*/,
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>
/*interceptor_creators*/) {
return nullptr;
}
};
/// A call credentials object encapsulates the state needed by a client to
/// authenticate with a server for a given call on a channel.
///
/// \see https://grpc.io/docs/guides/auth.html
class CallCredentials : private grpc::GrpcLibraryCodegen {
public:
CallCredentials();
~CallCredentials();
/// Apply this instance's credentials to \a call.
virtual bool ApplyToCall(grpc_call* call) = 0;
protected:
friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
friend std::shared_ptr<CallCredentials> CompositeCallCredentials(
const std::shared_ptr<CallCredentials>& creds1,
const std::shared_ptr<CallCredentials>& creds2);
virtual SecureCallCredentials* AsSecureCredentials() = 0;
};
/// Options used to build SslCredentials.
struct SslCredentialsOptions {
/// The buffer containing the PEM encoding of the server root certificates. If
/// this parameter is empty, the default roots will be used. The default
/// roots can be overridden using the \a GRPC_DEFAULT_SSL_ROOTS_FILE_PATH
/// environment variable pointing to a file on the file system containing the
/// roots.
grpc::string pem_root_certs;
/// The buffer containing the PEM encoding of the client's private key. This
/// parameter can be empty if the client does not have a private key.
grpc::string pem_private_key;
/// The buffer containing the PEM encoding of the client's certificate chain.
/// This parameter can be empty if the client does not have a certificate
/// chain.
grpc::string pem_cert_chain;
};
// Factories for building different types of Credentials The functions may
// return empty shared_ptr when credentials cannot be created. If a
// Credentials pointer is returned, it can still be invalid when used to create
// a channel. A lame channel will be created then and all rpcs will fail on it.
/// Builds credentials with reasonable defaults.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials();
/// Builds SSL Credentials given SSL specific options
std::shared_ptr<ChannelCredentials> SslCredentials(
const SslCredentialsOptions& options);
/// Builds credentials for use when running in GCE
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials();
constexpr long kMaxAuthTokenLifetimeSecs = 3600;
/// Builds Service Account JWT Access credentials.
/// json_key is the JSON key string containing the client's private key.
/// token_lifetime_seconds is the lifetime in seconds of each Json Web Token
/// (JWT) created with this credentials. It should not exceed
/// \a kMaxAuthTokenLifetimeSecs or will be cropped to this value.
std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
const grpc::string& json_key,
long token_lifetime_seconds = grpc_impl::kMaxAuthTokenLifetimeSecs);
/// Builds refresh token credentials.
/// json_refresh_token is the JSON string containing the refresh token along
/// with a client_id and client_secret.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
const grpc::string& json_refresh_token);
/// Builds access token credentials.
/// access_token is an oauth2 access token that was fetched using an out of band
/// mechanism.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> AccessTokenCredentials(
const grpc::string& access_token);
/// Builds IAM credentials.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> GoogleIAMCredentials(
const grpc::string& authorization_token,
const grpc::string& authority_selector);
/// Combines a channel credentials and a call credentials into a composite
/// channel credentials.
std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
/// Combines two call credentials objects into a composite call credentials.
std::shared_ptr<CallCredentials> CompositeCallCredentials(
const std::shared_ptr<CallCredentials>& creds1,
const std::shared_ptr<CallCredentials>& creds2);
/// Credentials for an unencrypted, unauthenticated channel
std::shared_ptr<ChannelCredentials> InsecureChannelCredentials();
/// User defined metadata credentials.
class MetadataCredentialsPlugin {
public:
virtual ~MetadataCredentialsPlugin() {}
/// If this method returns true, the Process function will be scheduled in
/// a different thread from the one processing the call.
virtual bool IsBlocking() const { return true; }
/// Type of credentials this plugin is implementing.
virtual const char* GetType() const { return ""; }
/// Gets the auth metatada produced by this plugin.
/// The fully qualified method name is:
/// service_url + "/" + method_name.
/// The channel_auth_context contains (among other things), the identity of
/// the server.
virtual grpc::Status GetMetadata(
grpc::string_ref service_url, grpc::string_ref method_name,
const grpc::AuthContext& channel_auth_context,
std::multimap<grpc::string, grpc::string>* metadata) = 0;
};
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin);
namespace experimental {
/// Options for creating STS Oauth Token Exchange credentials following the IETF
/// draft https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16.
/// Optional fields may be set to empty string. It is the responsibility of the
/// caller to ensure that the subject and actor tokens are refreshed on disk at
/// the specified paths.
struct StsCredentialsOptions {
grpc::string token_exchange_service_uri; // Required.
grpc::string resource; // Optional.
grpc::string audience; // Optional.
grpc::string scope; // Optional.
grpc::string requested_token_type; // Optional.
grpc::string subject_token_path; // Required.
grpc::string subject_token_type; // Required.
grpc::string actor_token_path; // Optional.
grpc::string actor_token_type; // Optional.
};
/// Creates STS Options from a JSON string. The JSON schema is as follows:
/// {
/// "title": "STS Credentials Config",
/// "type": "object",
/// "required": ["token_exchange_service_uri", "subject_token_path",
/// "subject_token_type"],
/// "properties": {
/// "token_exchange_service_uri": {
/// "type": "string"
/// },
/// "resource": {
/// "type": "string"
/// },
/// "audience": {
/// "type": "string"
/// },
/// "scope": {
/// "type": "string"
/// },
/// "requested_token_type": {
/// "type": "string"
/// },
/// "subject_token_path": {
/// "type": "string"
/// },
/// "subject_token_type": {
/// "type": "string"
/// },
/// "actor_token_path" : {
/// "type": "string"
/// },
/// "actor_token_type": {
/// "type": "string"
/// }
/// }
/// }
grpc::Status StsCredentialsOptionsFromJson(const grpc::string& json_string,
StsCredentialsOptions* options);
/// Creates STS credentials options from the $STS_CREDENTIALS environment
/// variable. This environment variable points to the path of a JSON file
/// comforming to the schema described above.
grpc::Status StsCredentialsOptionsFromEnv(StsCredentialsOptions* options);
std::shared_ptr<CallCredentials> StsCredentials(
const StsCredentialsOptions& options);
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin,
grpc_security_level min_security_level);
/// Options used to build AltsCredentials.
struct AltsCredentialsOptions {
/// service accounts of target endpoint that will be acceptable
/// by the client. If service accounts are provided and none of them matches
/// that of the server, authentication will fail.
std::vector<grpc::string> target_service_accounts;
};
/// Builds ALTS Credentials given ALTS specific options
std::shared_ptr<ChannelCredentials> AltsCredentials(
const AltsCredentialsOptions& options);
/// Builds Local Credentials.
std::shared_ptr<ChannelCredentials> LocalCredentials(
grpc_local_connect_type type);
/// Builds TLS Credentials given TLS options.
std::shared_ptr<ChannelCredentials> TlsCredentials(
const TlsCredentialsOptions& options);
} // namespace experimental
} // namespace grpc_impl
#endif // GRPCPP_SECURITY_CREDENTIALS_IMPL_H
@@ -0,0 +1,91 @@
/*
*
* Copyright 2019 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 GRPCPP_SECURITY_SERVER_CREDENTIALS_H
#define GRPCPP_SECURITY_SERVER_CREDENTIALS_H
#include <grpcpp/security/server_credentials_impl.h>
namespace grpc_impl {
class Server;
} // namespace grpc_impl
namespace grpc {
typedef ::grpc_impl::ServerCredentials ServerCredentials;
/// Options to create ServerCredentials with SSL
struct SslServerCredentialsOptions {
/// \warning Deprecated
SslServerCredentialsOptions()
: force_client_auth(false),
client_certificate_request(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE) {}
SslServerCredentialsOptions(
grpc_ssl_client_certificate_request_type request_type)
: force_client_auth(false), client_certificate_request(request_type) {}
struct PemKeyCertPair {
grpc::string private_key;
grpc::string cert_chain;
};
grpc::string pem_root_certs;
std::vector<PemKeyCertPair> pem_key_cert_pairs;
/// \warning Deprecated
bool force_client_auth;
/// If both \a force_client_auth and \a client_certificate_request
/// fields are set, \a force_client_auth takes effect, i.e.
/// \a REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
/// will be enforced.
grpc_ssl_client_certificate_request_type client_certificate_request;
};
static inline std::shared_ptr<ServerCredentials> SslServerCredentials(
const SslServerCredentialsOptions& options) {
return ::grpc_impl::SslServerCredentials(options);
}
static inline std::shared_ptr<ServerCredentials> InsecureServerCredentials() {
return ::grpc_impl::InsecureServerCredentials();
}
namespace experimental {
typedef ::grpc_impl::experimental::AltsServerCredentialsOptions
AltsServerCredentialsOptions;
static inline std::shared_ptr<ServerCredentials> AltsServerCredentials(
const AltsServerCredentialsOptions& options) {
return ::grpc_impl::experimental::AltsServerCredentials(options);
}
static inline std::shared_ptr<ServerCredentials> LocalServerCredentials(
grpc_local_connect_type type) {
return ::grpc_impl::experimental::LocalServerCredentials(type);
}
/// Builds TLS ServerCredentials given TLS options.
static inline std::shared_ptr<ServerCredentials> TlsServerCredentials(
const ::grpc_impl::experimental::TlsCredentialsOptions& options) {
return ::grpc_impl::experimental::TlsServerCredentials(options);
}
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_SECURITY_SERVER_CREDENTIALS_H
@@ -0,0 +1,90 @@
/*
*
* Copyright 2015 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 GRPCPP_SECURITY_SERVER_CREDENTIALS_IMPL_H
#define GRPCPP_SECURITY_SERVER_CREDENTIALS_IMPL_H
#include <memory>
#include <vector>
#include <grpc/grpc_security_constants.h>
#include <grpcpp/security/auth_metadata_processor.h>
#include <grpcpp/security/tls_credentials_options.h>
#include <grpcpp/support/config.h>
struct grpc_server;
namespace grpc {
struct SslServerCredentialsOptions;
} // namespace grpc
namespace grpc_impl {
class Server;
/// Wrapper around \a grpc_server_credentials, a way to authenticate a server.
class ServerCredentials {
public:
virtual ~ServerCredentials();
/// This method is not thread-safe and has to be called before the server is
/// started. The last call to this function wins.
virtual void SetAuthMetadataProcessor(
const std::shared_ptr<grpc::AuthMetadataProcessor>& processor) = 0;
private:
friend class ::grpc_impl::Server;
/// Tries to bind \a server to the given \a addr (eg, localhost:1234,
/// 192.168.1.1:31416, [::1]:27182, etc.)
///
/// \return bound port number on success, 0 on failure.
// TODO(dgq): the "port" part seems to be a misnomer.
virtual int AddPortToServer(const grpc::string& addr,
grpc_server* server) = 0;
};
/// Builds SSL ServerCredentials given SSL specific options
std::shared_ptr<ServerCredentials> SslServerCredentials(
const grpc::SslServerCredentialsOptions& options);
/// Builds insecure server credentials.
std::shared_ptr<ServerCredentials> InsecureServerCredentials();
namespace experimental {
/// Options to create ServerCredentials with ALTS
struct AltsServerCredentialsOptions {
/// Add fields if needed.
};
/// Builds ALTS ServerCredentials given ALTS specific options
std::shared_ptr<ServerCredentials> AltsServerCredentials(
const AltsServerCredentialsOptions& options);
/// Builds Local ServerCredentials.
std::shared_ptr<ServerCredentials> LocalServerCredentials(
grpc_local_connect_type type);
/// Builds TLS ServerCredentials given TLS options.
std::shared_ptr<ServerCredentials> TlsServerCredentials(
const TlsCredentialsOptions& options);
} // namespace experimental
} // namespace grpc_impl
#endif // GRPCPP_SECURITY_SERVER_CREDENTIALS_IMPL_H
@@ -0,0 +1,330 @@
/*
*
* Copyright 2019 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 GRPCPP_SECURITY_TLS_CREDENTIALS_OPTIONS_H
#define GRPCPP_SECURITY_TLS_CREDENTIALS_OPTIONS_H
#include <memory>
#include <vector>
#include <grpc/grpc_security_constants.h>
#include <grpc/status.h>
#include <grpc/support/log.h>
#include <grpcpp/support/config.h>
typedef struct grpc_tls_credential_reload_arg grpc_tls_credential_reload_arg;
typedef struct grpc_tls_credential_reload_config
grpc_tls_credential_reload_config;
typedef struct grpc_tls_server_authorization_check_arg
grpc_tls_server_authorization_check_arg;
typedef struct grpc_tls_server_authorization_check_config
grpc_tls_server_authorization_check_config;
typedef struct grpc_tls_credentials_options grpc_tls_credentials_options;
namespace grpc_impl {
namespace experimental {
/** TLS key materials config, wrapper for grpc_tls_key_materials_config. It is
* used for experimental purposes for now and subject to change. **/
class TlsKeyMaterialsConfig {
public:
struct PemKeyCertPair {
grpc::string private_key;
grpc::string cert_chain;
};
/** Getters for member fields. **/
const grpc::string pem_root_certs() const { return pem_root_certs_; }
const std::vector<PemKeyCertPair>& pem_key_cert_pair_list() const {
return pem_key_cert_pair_list_;
}
int version() const { return version_; }
/** Setter for key materials that will be called by the user. Ownership of the
* arguments will not be transferred. **/
void set_pem_root_certs(const grpc::string& pem_root_certs);
void add_pem_key_cert_pair(const PemKeyCertPair& pem_key_cert_pair);
void set_key_materials(
const grpc::string& pem_root_certs,
const std::vector<PemKeyCertPair>& pem_key_cert_pair_list);
void set_version(int version) { version_ = version; };
private:
int version_ = 0;
std::vector<PemKeyCertPair> pem_key_cert_pair_list_;
grpc::string pem_root_certs_;
};
/** TLS credential reload arguments, wraps grpc_tls_credential_reload_arg. It is
* used for experimental purposes for now and it is subject to change.
*
* The credential reload arg contains all the info necessary to schedule/cancel
* a credential reload request. The callback function must be called after
* finishing the schedule operation. See the description of the
* grpc_tls_credential_reload_arg struct in grpc_security.h for more details.
* **/
class TlsCredentialReloadArg {
public:
/** TlsCredentialReloadArg does not take ownership of the C arg that is passed
* to the constructor. One must remember to free any memory allocated to the
* C arg after using the setter functions below. **/
TlsCredentialReloadArg(grpc_tls_credential_reload_arg* arg);
~TlsCredentialReloadArg();
/** Getters for member fields. **/
void* cb_user_data() const;
bool is_pem_key_cert_pair_list_empty() const;
grpc_ssl_certificate_config_reload_status status() const;
grpc::string error_details() const;
/** Setters for member fields. Ownership of the arguments will not be
* transferred. **/
void set_cb_user_data(void* cb_user_data);
void set_pem_root_certs(const grpc::string& pem_root_certs);
void add_pem_key_cert_pair(
const TlsKeyMaterialsConfig::PemKeyCertPair& pem_key_cert_pair);
void set_key_materials(const grpc::string& pem_root_certs,
std::vector<TlsKeyMaterialsConfig::PemKeyCertPair>
pem_key_cert_pair_list);
void set_key_materials_config(
const std::shared_ptr<TlsKeyMaterialsConfig>& key_materials_config);
void set_status(grpc_ssl_certificate_config_reload_status status);
void set_error_details(const grpc::string& error_details);
/** Calls the C arg's callback function. **/
void OnCredentialReloadDoneCallback();
private:
grpc_tls_credential_reload_arg* c_arg_;
};
/** An interface that the application derives and uses to instantiate a
* TlsCredentialReloadConfig instance. Refer to the definition of the
* grpc_tls_credential_reload_config in grpc_tls_credentials_options.h for more
* details on the expectations of the member functions of the interface. **/
struct TlsCredentialReloadInterface {
virtual ~TlsCredentialReloadInterface() = default;
/** A callback that invokes the credential reload. **/
virtual int Schedule(TlsCredentialReloadArg* arg) = 0;
/** A callback that cancels a credential reload request. **/
virtual void Cancel(TlsCredentialReloadArg* /* arg */) {}
};
/** TLS credential reloag config, wraps grpc_tls_credential_reload_config. It is
* used for experimental purposes for now and it is subject to change. **/
class TlsCredentialReloadConfig {
public:
TlsCredentialReloadConfig(std::shared_ptr<TlsCredentialReloadInterface>
credential_reload_interface);
~TlsCredentialReloadConfig();
int Schedule(TlsCredentialReloadArg* arg) const {
if (credential_reload_interface_ == nullptr) {
gpr_log(GPR_ERROR, "credential reload interface is nullptr");
if (arg != nullptr) {
arg->set_status(GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL);
arg->set_error_details(
"the interface of the credential reload config is nullptr");
}
return 1;
}
return credential_reload_interface_->Schedule(arg);
}
void Cancel(TlsCredentialReloadArg* arg) const {
if (credential_reload_interface_ == nullptr) {
gpr_log(GPR_ERROR, "credential reload interface is nullptr");
if (arg != nullptr) {
arg->set_status(GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL);
arg->set_error_details(
"the interface of the credential reload config is nullptr");
}
return;
}
credential_reload_interface_->Cancel(arg);
}
/** Returns a C struct for the credential reload config. **/
grpc_tls_credential_reload_config* c_config() const { return c_config_; }
private:
grpc_tls_credential_reload_config* c_config_;
std::shared_ptr<TlsCredentialReloadInterface> credential_reload_interface_;
};
/** TLS server authorization check arguments, wraps
* grpc_tls_server_authorization_check_arg. It is used for experimental
* purposes for now and it is subject to change.
*
* The server authorization check arg contains all the info necessary to
* schedule/cancel a server authorization check request. The callback function
* must be called after finishing the schedule operation. See the description
* of the grpc_tls_server_authorization_check_arg struct in grpc_security.h for
* more details. **/
class TlsServerAuthorizationCheckArg {
public:
/** TlsServerAuthorizationCheckArg does not take ownership of the C arg passed
* to the constructor. One must remember to free any memory allocated to the
* C arg after using the setter functions below. **/
TlsServerAuthorizationCheckArg(grpc_tls_server_authorization_check_arg* arg);
~TlsServerAuthorizationCheckArg();
/** Getters for member fields. **/
void* cb_user_data() const;
int success() const;
grpc::string target_name() const;
grpc::string peer_cert() const;
grpc::string peer_cert_full_chain() const;
grpc_status_code status() const;
grpc::string error_details() const;
/** Setters for member fields. **/
void set_cb_user_data(void* cb_user_data);
void set_success(int success);
void set_target_name(const grpc::string& target_name);
void set_peer_cert(const grpc::string& peer_cert);
void set_peer_cert_full_chain(const grpc::string& peer_cert_full_chain);
void set_status(grpc_status_code status);
void set_error_details(const grpc::string& error_details);
/** Calls the C arg's callback function. **/
void OnServerAuthorizationCheckDoneCallback();
private:
grpc_tls_server_authorization_check_arg* c_arg_;
};
/** An interface that the application derives and uses to instantiate a
* TlsServerAuthorizationCheckConfig instance. Refer to the definition of the
* grpc_tls_server_authorization_check_config in grpc_tls_credentials_options.h
* for more details on the expectations of the member functions of the
* interface.
* **/
struct TlsServerAuthorizationCheckInterface {
virtual ~TlsServerAuthorizationCheckInterface() = default;
/** A callback that invokes the server authorization check. **/
virtual int Schedule(TlsServerAuthorizationCheckArg* arg) = 0;
/** A callback that cancels a server authorization check request. **/
virtual void Cancel(TlsServerAuthorizationCheckArg* /* arg */) {}
};
/** TLS server authorization check config, wraps
* grps_tls_server_authorization_check_config. It is used for experimental
* purposes for now and it is subject to change. **/
class TlsServerAuthorizationCheckConfig {
public:
TlsServerAuthorizationCheckConfig(
std::shared_ptr<TlsServerAuthorizationCheckInterface>
server_authorization_check_interface);
~TlsServerAuthorizationCheckConfig();
int Schedule(TlsServerAuthorizationCheckArg* arg) const {
if (server_authorization_check_interface_ == nullptr) {
gpr_log(GPR_ERROR, "server authorization check interface is nullptr");
if (arg != nullptr) {
arg->set_status(GRPC_STATUS_NOT_FOUND);
arg->set_error_details(
"the interface of the server authorization check config is "
"nullptr");
}
return 1;
}
return server_authorization_check_interface_->Schedule(arg);
}
void Cancel(TlsServerAuthorizationCheckArg* arg) const {
if (server_authorization_check_interface_ == nullptr) {
gpr_log(GPR_ERROR, "server authorization check interface is nullptr");
if (arg != nullptr) {
arg->set_status(GRPC_STATUS_NOT_FOUND);
arg->set_error_details(
"the interface of the server authorization check config is "
"nullptr");
}
return;
}
server_authorization_check_interface_->Cancel(arg);
}
/** Returns C struct for the server authorization check config. **/
grpc_tls_server_authorization_check_config* c_config() const {
return c_config_;
}
private:
grpc_tls_server_authorization_check_config* c_config_;
std::shared_ptr<TlsServerAuthorizationCheckInterface>
server_authorization_check_interface_;
};
/** TLS credentials options, wrapper for grpc_tls_credentials_options. It is
* used for experimental purposes for now and it is subject to change. See the
* description of the grpc_tls_credentials_options struct in grpc_security.h for
* more details. **/
class TlsCredentialsOptions {
public:
TlsCredentialsOptions(
grpc_ssl_client_certificate_request_type cert_request_type,
grpc_tls_server_verification_option server_verification_option,
std::shared_ptr<TlsKeyMaterialsConfig> key_materials_config,
std::shared_ptr<TlsCredentialReloadConfig> credential_reload_config,
std::shared_ptr<TlsServerAuthorizationCheckConfig>
server_authorization_check_config);
~TlsCredentialsOptions();
/** Getters for member fields. **/
grpc_ssl_client_certificate_request_type cert_request_type() const {
return cert_request_type_;
}
grpc_tls_server_verification_option server_verification_option() const {
return server_verification_option_;
}
std::shared_ptr<TlsKeyMaterialsConfig> key_materials_config() const {
return key_materials_config_;
}
std::shared_ptr<TlsCredentialReloadConfig> credential_reload_config() const {
return credential_reload_config_;
}
std::shared_ptr<TlsServerAuthorizationCheckConfig>
server_authorization_check_config() const {
return server_authorization_check_config_;
}
grpc_tls_credentials_options* c_credentials_options() const {
return c_credentials_options_;
}
private:
/** The cert_request_type_ flag is only relevant when the
* TlsCredentialsOptions are used to instantiate server credentials; the flag
* goes unused when creating channel credentials, and the user can set it to
* GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE. **/
grpc_ssl_client_certificate_request_type cert_request_type_;
/** The server_verification_option_ flag is only relevant when the
* TlsCredentialsOptions are used to instantiate client credentials; **/
grpc_tls_server_verification_option server_verification_option_;
std::shared_ptr<TlsKeyMaterialsConfig> key_materials_config_;
std::shared_ptr<TlsCredentialReloadConfig> credential_reload_config_;
std::shared_ptr<TlsServerAuthorizationCheckConfig>
server_authorization_check_config_;
grpc_tls_credentials_options* c_credentials_options_;
};
} // namespace experimental
} // namespace grpc_impl
#endif // GRPCPP_SECURITY_TLS_CREDENTIALS_OPTIONS_H

Some files were not shown because too many files have changed in this diff Show More