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