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