1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #ifndef GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
20 #define GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
21 
22 #include <grpcpp/impl/codegen/config.h>
23 #include <grpcpp/impl/codegen/core_codegen_interface.h>
24 #include <grpcpp/impl/codegen/rpc_service_method.h>
25 #include <grpcpp/impl/codegen/serialization_traits.h>
26 #include <grpcpp/impl/codegen/server_interface.h>
27 #include <grpcpp/impl/codegen/status.h>
28 
29 namespace grpc_impl {
30 
31 class Server;
32 class CompletionQueue;
33 class ServerContext;
34 }  // namespace grpc_impl
35 namespace grpc {
36 
37 class ServerInterface;
38 
39 namespace internal {
40 class Call;
41 class ServerAsyncStreamingInterface {
42  public:
~ServerAsyncStreamingInterface()43   virtual ~ServerAsyncStreamingInterface() {}
44 
45   /// Request notification of the sending of initial metadata to the client.
46   /// Completion will be notified by \a tag on the associated completion
47   /// queue. This call is optional, but if it is used, it cannot be used
48   /// concurrently with or after the \a Finish method.
49   ///
50   /// \param[in] tag Tag identifying this request.
51   virtual void SendInitialMetadata(void* tag) = 0;
52 
53  private:
54   friend class ::grpc::ServerInterface;
55   virtual void BindCall(Call* call) = 0;
56 };
57 }  // namespace internal
58 
59 /// Desriptor of an RPC service and its various RPC methods
60 class Service {
61  public:
Service()62   Service() : server_(nullptr) {}
~Service()63   virtual ~Service() {}
64 
has_async_methods()65   bool has_async_methods() const {
66     for (const auto& method : methods_) {
67       if (method && method->handler() == nullptr) {
68         return true;
69       }
70     }
71     return false;
72   }
73 
has_synchronous_methods()74   bool has_synchronous_methods() const {
75     for (const auto& method : methods_) {
76       if (method &&
77           method->api_type() == internal::RpcServiceMethod::ApiType::SYNC) {
78         return true;
79       }
80     }
81     return false;
82   }
83 
has_callback_methods()84   bool has_callback_methods() const {
85     for (const auto& method : methods_) {
86       if (method && (method->api_type() ==
87                          internal::RpcServiceMethod::ApiType::CALL_BACK ||
88                      method->api_type() ==
89                          internal::RpcServiceMethod::ApiType::RAW_CALL_BACK)) {
90         return true;
91       }
92     }
93     return false;
94   }
95 
has_generic_methods()96   bool has_generic_methods() const {
97     for (const auto& method : methods_) {
98       if (method.get() == nullptr) {
99         return true;
100       }
101     }
102     return false;
103   }
104 
105  protected:
106   // TODO(vjpai): Promote experimental contents once callback API is accepted
107   class experimental_type {
108    public:
experimental_type(Service * service)109     explicit experimental_type(Service* service) : service_(service) {}
110 
MarkMethodCallback(int index,internal::MethodHandler * handler)111     void MarkMethodCallback(int index, internal::MethodHandler* handler) {
112       service_->MarkMethodCallbackInternal(index, handler);
113     }
114 
MarkMethodRawCallback(int index,internal::MethodHandler * handler)115     void MarkMethodRawCallback(int index, internal::MethodHandler* handler) {
116       service_->MarkMethodRawCallbackInternal(index, handler);
117     }
118 
GetHandler(int index)119     internal::MethodHandler* GetHandler(int index) {
120       return service_->GetHandlerInternal(index);
121     }
122 
123    private:
124     Service* service_;
125   };
126 
experimental()127   experimental_type experimental() { return experimental_type(this); }
128 
129   template <class Message>
RequestAsyncUnary(int index,::grpc_impl::ServerContext * context,Message * request,internal::ServerAsyncStreamingInterface * stream,::grpc_impl::CompletionQueue * call_cq,::grpc_impl::ServerCompletionQueue * notification_cq,void * tag)130   void RequestAsyncUnary(int index, ::grpc_impl::ServerContext* context,
131                          Message* request,
132                          internal::ServerAsyncStreamingInterface* stream,
133                          ::grpc_impl::CompletionQueue* call_cq,
134                          ::grpc_impl::ServerCompletionQueue* notification_cq,
135                          void* tag) {
136     // Typecast the index to size_t for indexing into a vector
137     // while preserving the API that existed before a compiler
138     // warning was first seen (grpc/grpc#11664)
139     size_t idx = static_cast<size_t>(index);
140     server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
141                               notification_cq, tag, request);
142   }
RequestAsyncClientStreaming(int index,::grpc_impl::ServerContext * context,internal::ServerAsyncStreamingInterface * stream,::grpc_impl::CompletionQueue * call_cq,::grpc_impl::ServerCompletionQueue * notification_cq,void * tag)143   void RequestAsyncClientStreaming(
144       int index, ::grpc_impl::ServerContext* context,
145       internal::ServerAsyncStreamingInterface* stream,
146       ::grpc_impl::CompletionQueue* call_cq,
147       ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
148     size_t idx = static_cast<size_t>(index);
149     server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
150                               notification_cq, tag);
151   }
152   template <class Message>
RequestAsyncServerStreaming(int index,::grpc_impl::ServerContext * context,Message * request,internal::ServerAsyncStreamingInterface * stream,::grpc_impl::CompletionQueue * call_cq,::grpc_impl::ServerCompletionQueue * notification_cq,void * tag)153   void RequestAsyncServerStreaming(
154       int index, ::grpc_impl::ServerContext* context, Message* request,
155       internal::ServerAsyncStreamingInterface* stream,
156       ::grpc_impl::CompletionQueue* call_cq,
157       ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
158     size_t idx = static_cast<size_t>(index);
159     server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
160                               notification_cq, tag, request);
161   }
RequestAsyncBidiStreaming(int index,::grpc_impl::ServerContext * context,internal::ServerAsyncStreamingInterface * stream,::grpc_impl::CompletionQueue * call_cq,::grpc_impl::ServerCompletionQueue * notification_cq,void * tag)162   void RequestAsyncBidiStreaming(
163       int index, ::grpc_impl::ServerContext* context,
164       internal::ServerAsyncStreamingInterface* stream,
165       ::grpc_impl::CompletionQueue* call_cq,
166       ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
167     size_t idx = static_cast<size_t>(index);
168     server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
169                               notification_cq, tag);
170   }
171 
AddMethod(internal::RpcServiceMethod * method)172   void AddMethod(internal::RpcServiceMethod* method) {
173     methods_.emplace_back(method);
174   }
175 
MarkMethodAsync(int index)176   void MarkMethodAsync(int index) {
177     // This does not have to be a hard error, however no one has approached us
178     // with a use case yet. Please file an issue if you believe you have one.
179     size_t idx = static_cast<size_t>(index);
180     GPR_CODEGEN_ASSERT(
181         methods_[idx].get() != nullptr &&
182         "Cannot mark the method as 'async' because it has already been "
183         "marked as 'generic'.");
184     methods_[idx]->SetServerApiType(internal::RpcServiceMethod::ApiType::ASYNC);
185   }
186 
MarkMethodRaw(int index)187   void MarkMethodRaw(int index) {
188     // This does not have to be a hard error, however no one has approached us
189     // with a use case yet. Please file an issue if you believe you have one.
190     size_t idx = static_cast<size_t>(index);
191     GPR_CODEGEN_ASSERT(methods_[idx].get() != nullptr &&
192                        "Cannot mark the method as 'raw' because it has already "
193                        "been marked as 'generic'.");
194     methods_[idx]->SetServerApiType(internal::RpcServiceMethod::ApiType::RAW);
195   }
196 
MarkMethodGeneric(int index)197   void MarkMethodGeneric(int index) {
198     // This does not have to be a hard error, however no one has approached us
199     // with a use case yet. Please file an issue if you believe you have one.
200     size_t idx = static_cast<size_t>(index);
201     GPR_CODEGEN_ASSERT(
202         methods_[idx]->handler() != nullptr &&
203         "Cannot mark the method as 'generic' because it has already been "
204         "marked as 'async' or 'raw'.");
205     methods_[idx].reset();
206   }
207 
MarkMethodStreamed(int index,internal::MethodHandler * streamed_method)208   void MarkMethodStreamed(int index, internal::MethodHandler* streamed_method) {
209     // This does not have to be a hard error, however no one has approached us
210     // with a use case yet. Please file an issue if you believe you have one.
211     size_t idx = static_cast<size_t>(index);
212     GPR_CODEGEN_ASSERT(methods_[idx] && methods_[idx]->handler() &&
213                        "Cannot mark an async or generic method Streamed");
214     methods_[idx]->SetHandler(streamed_method);
215 
216     // From the server's point of view, streamed unary is a special
217     // case of BIDI_STREAMING that has 1 read and 1 write, in that order,
218     // and split server-side streaming is BIDI_STREAMING with 1 read and
219     // any number of writes, in that order.
220     methods_[idx]->SetMethodType(internal::RpcMethod::BIDI_STREAMING);
221   }
222 
223 #ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
MarkMethodCallback(int index,internal::MethodHandler * handler)224   void MarkMethodCallback(int index, internal::MethodHandler* handler) {
225     MarkMethodCallbackInternal(index, handler);
226   }
227 
MarkMethodRawCallback(int index,internal::MethodHandler * handler)228   void MarkMethodRawCallback(int index, internal::MethodHandler* handler) {
229     MarkMethodRawCallbackInternal(index, handler);
230   }
231 
GetHandler(int index)232   internal::MethodHandler* GetHandler(int index) {
233     return GetHandlerInternal(index);
234   }
235 #endif
236  private:
237   // TODO(vjpai): migrate the Internal functions to mainline functions once
238   //              callback API is fully de-experimental
MarkMethodCallbackInternal(int index,internal::MethodHandler * handler)239   void MarkMethodCallbackInternal(int index, internal::MethodHandler* handler) {
240     // This does not have to be a hard error, however no one has approached us
241     // with a use case yet. Please file an issue if you believe you have one.
242     size_t idx = static_cast<size_t>(index);
243     GPR_CODEGEN_ASSERT(
244         methods_[idx].get() != nullptr &&
245         "Cannot mark the method as 'callback' because it has already been "
246         "marked as 'generic'.");
247     methods_[idx]->SetHandler(handler);
248     methods_[idx]->SetServerApiType(
249         internal::RpcServiceMethod::ApiType::CALL_BACK);
250   }
251 
MarkMethodRawCallbackInternal(int index,internal::MethodHandler * handler)252   void MarkMethodRawCallbackInternal(int index,
253                                      internal::MethodHandler* handler) {
254     // This does not have to be a hard error, however no one has approached us
255     // with a use case yet. Please file an issue if you believe you have one.
256     size_t idx = static_cast<size_t>(index);
257     GPR_CODEGEN_ASSERT(
258         methods_[idx].get() != nullptr &&
259         "Cannot mark the method as 'raw callback' because it has already "
260         "been marked as 'generic'.");
261     methods_[idx]->SetHandler(handler);
262     methods_[idx]->SetServerApiType(
263         internal::RpcServiceMethod::ApiType::RAW_CALL_BACK);
264   }
265 
GetHandlerInternal(int index)266   internal::MethodHandler* GetHandlerInternal(int index) {
267     size_t idx = static_cast<size_t>(index);
268     return methods_[idx]->handler();
269   }
270 
271   friend class grpc_impl::Server;
272   friend class ServerInterface;
273   ServerInterface* server_;
274   std::vector<std::unique_ptr<internal::RpcServiceMethod>> methods_;
275 };
276 
277 }  // namespace grpc
278 
279 #endif  // GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
280