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