blob: be3d22563027864589219d5f16d6bc39f973c4c0 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
3 * Copyright 2014, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include <grpc++/server.h>
35#include <utility>
36
37#include <grpc/grpc.h>
yangg9e21f722014-12-08 15:49:52 -080038#include <grpc/grpc_security.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080039#include <grpc/support/log.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080040#include <grpc++/completion_queue.h>
yangg1b151092015-01-09 15:31:05 -080041#include <grpc++/impl/rpc_service_method.h>
Craig Tillerb4701692015-02-09 16:12:00 -080042#include <grpc++/server_context.h>
yangg9e21f722014-12-08 15:49:52 -080043#include <grpc++/server_credentials.h>
Craig Tiller0db1bef2015-02-09 13:47:39 -080044#include <grpc++/thread_pool_interface.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080045
Craig Tillerc4165772015-02-11 10:51:04 -080046#include "src/cpp/proto/proto_utils.h"
47
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080048namespace grpc {
49
Craig Tillerc4165772015-02-11 10:51:04 -080050Server::Server(ThreadPoolInterface *thread_pool, bool thread_pool_owned,
51 ServerCredentials *creds)
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080052 : started_(false),
53 shutdown_(false),
54 num_running_cb_(0),
Craig Tiller0db1bef2015-02-09 13:47:39 -080055 thread_pool_(thread_pool),
56 thread_pool_owned_(thread_pool_owned),
yangg9e21f722014-12-08 15:49:52 -080057 secure_(creds != nullptr) {
58 if (creds) {
Craig Tiller3b29b562015-02-11 12:58:46 -080059 server_ = grpc_secure_server_create(creds->GetRawCreds(), cq_.cq(), nullptr);
yangg9e21f722014-12-08 15:49:52 -080060 } else {
Craig Tiller3b29b562015-02-11 12:58:46 -080061 server_ = grpc_server_create(cq_.cq(), nullptr);
yangg9e21f722014-12-08 15:49:52 -080062 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080063}
64
65Server::Server() {
66 // Should not be called.
67 GPR_ASSERT(false);
68}
69
70Server::~Server() {
71 std::unique_lock<std::mutex> lock(mu_);
72 if (started_ && !shutdown_) {
73 lock.unlock();
74 Shutdown();
Craig Tiller061754a2015-02-09 14:56:49 -080075 } else {
76 lock.unlock();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080077 }
78 grpc_server_destroy(server_);
79 if (thread_pool_owned_) {
80 delete thread_pool_;
81 }
82}
83
Craig Tiller0db1bef2015-02-09 13:47:39 -080084bool Server::RegisterService(RpcService *service) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080085 for (int i = 0; i < service->GetMethodCount(); ++i) {
Craig Tillerecd49342015-01-18 14:36:47 -080086 RpcServiceMethod *method = service->GetMethod(i);
Craig Tillercbd04852015-02-10 17:39:54 -080087 void *tag = grpc_server_register_method(server_, method->name(), nullptr);
88 if (!tag) {
Craig Tillerc4165772015-02-11 10:51:04 -080089 gpr_log(GPR_DEBUG, "Attempt to register %s multiple times",
90 method->name());
Craig Tiller0db1bef2015-02-09 13:47:39 -080091 return false;
92 }
Craig Tillercbd04852015-02-10 17:39:54 -080093 methods_.emplace_back(method, tag);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080094 }
Craig Tiller7c72adc2015-02-09 14:07:26 -080095 return true;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080096}
97
Craig Tiller0db1bef2015-02-09 13:47:39 -080098int Server::AddPort(const grpc::string &addr) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080099 GPR_ASSERT(!started_);
yangg9e21f722014-12-08 15:49:52 -0800100 if (secure_) {
Craig Tiller0db1bef2015-02-09 13:47:39 -0800101 return grpc_server_add_secure_http2_port(server_, addr.c_str());
yangg9e21f722014-12-08 15:49:52 -0800102 } else {
Craig Tiller0db1bef2015-02-09 13:47:39 -0800103 return grpc_server_add_http2_port(server_, addr.c_str());
yangg9e21f722014-12-08 15:49:52 -0800104 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800105}
106
Craig Tillerc4165772015-02-11 10:51:04 -0800107class Server::MethodRequestData final : public CompletionQueueTag {
108 public:
109 MethodRequestData(RpcServiceMethod *method, void *tag)
110 : method_(method),
111 tag_(tag),
112 has_request_payload_(method->method_type() == RpcMethod::NORMAL_RPC ||
113 method->method_type() ==
114 RpcMethod::SERVER_STREAMING),
115 has_response_payload_(method->method_type() == RpcMethod::NORMAL_RPC ||
116 method->method_type() ==
117 RpcMethod::CLIENT_STREAMING) {
118 grpc_metadata_array_init(&request_metadata_);
119 }
120
121 static MethodRequestData *Wait(CompletionQueue *cq, bool *ok) {
Craig Tiller504bd332015-02-11 20:34:33 -0800122 void *tag = nullptr;
123 *ok = false;
Craig Tillerc4165772015-02-11 10:51:04 -0800124 if (!cq->Next(&tag, ok)) {
125 return nullptr;
126 }
127 auto *mrd = static_cast<MethodRequestData *>(tag);
128 GPR_ASSERT(mrd->in_flight_);
129 return mrd;
130 }
131
Craig Tiller3b29b562015-02-11 12:58:46 -0800132 void Request(grpc_server *server) {
Craig Tillerc4165772015-02-11 10:51:04 -0800133 GPR_ASSERT(!in_flight_);
134 in_flight_ = true;
135 cq_ = grpc_completion_queue_create();
136 GPR_ASSERT(GRPC_CALL_OK ==
137 grpc_server_request_registered_call(
138 server, tag_, &call_, &deadline_, &request_metadata_,
Craig Tiller3b29b562015-02-11 12:58:46 -0800139 has_request_payload_ ? &request_payload_ : nullptr,
Craig Tillerc4165772015-02-11 10:51:04 -0800140 cq_, this));
141 }
142
Craig Tiller04c8ff02015-02-11 11:01:07 -0800143 void FinalizeResult(void **tag, bool *status) override {}
Craig Tillerc4165772015-02-11 10:51:04 -0800144
145 class CallData {
146 public:
Craig Tillerbb5227f2015-02-11 13:34:48 -0800147 explicit CallData(Server *server, MethodRequestData *mrd)
Craig Tillerc4165772015-02-11 10:51:04 -0800148 : cq_(mrd->cq_),
Craig Tillerbb5227f2015-02-11 13:34:48 -0800149 call_(mrd->call_, server, &cq_),
Craig Tillerc4165772015-02-11 10:51:04 -0800150 ctx_(mrd->deadline_, mrd->request_metadata_.metadata,
151 mrd->request_metadata_.count),
152 has_request_payload_(mrd->has_request_payload_),
153 has_response_payload_(mrd->has_response_payload_),
154 request_payload_(mrd->request_payload_),
155 method_(mrd->method_) {
156 GPR_ASSERT(mrd->in_flight_);
157 mrd->in_flight_ = false;
158 mrd->request_metadata_.count = 0;
159 }
160
Craig Tiller47a57362015-02-11 16:31:45 -0800161 ~CallData() {
Craig Tillerbd217572015-02-11 18:10:56 -0800162 if (call_.call()) grpc_call_destroy(call_.call());
Craig Tiller47a57362015-02-11 16:31:45 -0800163 }
164
Craig Tillerc4165772015-02-11 10:51:04 -0800165 void Run() {
166 std::unique_ptr<google::protobuf::Message> req;
167 std::unique_ptr<google::protobuf::Message> res;
168 if (has_request_payload_) {
169 req.reset(method_->AllocateRequestProto());
170 if (!DeserializeProto(request_payload_, req.get())) {
171 abort(); // for now
172 }
173 }
174 if (has_response_payload_) {
Craig Tiller7c2f3f72015-02-11 13:21:54 -0800175 res.reset(method_->AllocateResponseProto());
Craig Tillerc4165772015-02-11 10:51:04 -0800176 }
177 auto status = method_->handler()->RunHandler(
178 MethodHandler::HandlerParameter(&call_, &ctx_, req.get(), res.get()));
179 CallOpBuffer buf;
Craig Tiller9dcb0f82015-02-11 15:36:31 -0800180 if (!ctx_.sent_initial_metadata_) {
181 buf.AddSendInitialMetadata(&ctx_.initial_metadata_);
182 }
Craig Tillerc4165772015-02-11 10:51:04 -0800183 if (has_response_payload_) {
184 buf.AddSendMessage(*res);
185 }
Craig Tiller9dcb0f82015-02-11 15:36:31 -0800186 buf.AddServerSendStatus(&ctx_.trailing_metadata_, status);
Craig Tiller504bd332015-02-11 20:34:33 -0800187 bool cancelled;
188 buf.AddServerRecvClose(&cancelled);
Craig Tillerc4165772015-02-11 10:51:04 -0800189 call_.PerformOps(&buf);
190 GPR_ASSERT(cq_.Pluck(&buf));
191 }
192
193 private:
194 CompletionQueue cq_;
195 Call call_;
196 ServerContext ctx_;
197 const bool has_request_payload_;
198 const bool has_response_payload_;
199 grpc_byte_buffer *request_payload_;
200 RpcServiceMethod *const method_;
201 };
202
203 private:
204 RpcServiceMethod *const method_;
205 void *const tag_;
206 bool in_flight_ = false;
207 const bool has_request_payload_;
208 const bool has_response_payload_;
209 grpc_call *call_;
210 gpr_timespec deadline_;
211 grpc_metadata_array request_metadata_;
212 grpc_byte_buffer *request_payload_;
213 grpc_completion_queue *cq_;
214};
215
Craig Tiller0db1bef2015-02-09 13:47:39 -0800216bool Server::Start() {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800217 GPR_ASSERT(!started_);
218 started_ = true;
219 grpc_server_start(server_);
220
221 // Start processing rpcs.
Craig Tiller3b29b562015-02-11 12:58:46 -0800222 if (!methods_.empty()) {
Craig Tillerc4165772015-02-11 10:51:04 -0800223 for (auto &m : methods_) {
Craig Tiller3b29b562015-02-11 12:58:46 -0800224 m.Request(server_);
Craig Tillercbd04852015-02-10 17:39:54 -0800225 }
226
Craig Tiller7c72adc2015-02-09 14:07:26 -0800227 ScheduleCallback();
228 }
Craig Tiller0db1bef2015-02-09 13:47:39 -0800229
230 return true;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800231}
232
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800233void Server::Shutdown() {
234 {
235 std::unique_lock<std::mutex> lock(mu_);
236 if (started_ && !shutdown_) {
237 shutdown_ = true;
238 grpc_server_shutdown(server_);
Craig Tillerbd217572015-02-11 18:10:56 -0800239 cq_.Shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800240
241 // Wait for running callbacks to finish.
242 while (num_running_cb_ != 0) {
243 callback_cv_.wait(lock);
244 }
245 }
246 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800247}
248
Craig Tillerbb5227f2015-02-11 13:34:48 -0800249void Server::PerformOpsOnCall(CallOpBuffer *buf, Call *call) {
250 static const size_t MAX_OPS = 8;
251 size_t nops = MAX_OPS;
252 grpc_op ops[MAX_OPS];
253 buf->FillOps(ops, &nops);
254 GPR_ASSERT(GRPC_CALL_OK ==
255 grpc_call_start_batch(call->call(), ops, nops,
256 buf));
257}
258
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800259void Server::ScheduleCallback() {
260 {
261 std::unique_lock<std::mutex> lock(mu_);
262 num_running_cb_++;
263 }
Craig Tiller0db1bef2015-02-09 13:47:39 -0800264 thread_pool_->ScheduleCallback(std::bind(&Server::RunRpc, this));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800265}
266
267void Server::RunRpc() {
268 // Wait for one more incoming rpc.
Craig Tillerc4165772015-02-11 10:51:04 -0800269 bool ok;
Craig Tiller3b29b562015-02-11 12:58:46 -0800270 auto *mrd = MethodRequestData::Wait(&cq_, &ok);
Craig Tillercbd04852015-02-10 17:39:54 -0800271 if (mrd) {
Craig Tillerbd217572015-02-11 18:10:56 -0800272 ScheduleCallback();
Craig Tillerc4165772015-02-11 10:51:04 -0800273 if (ok) {
Craig Tillerbd217572015-02-11 18:10:56 -0800274 MethodRequestData::CallData cd(this, mrd);
Craig Tiller3b29b562015-02-11 12:58:46 -0800275 mrd->Request(server_);
Craig Tillercbd04852015-02-10 17:39:54 -0800276
Craig Tillerc4165772015-02-11 10:51:04 -0800277 cd.Run();
278 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800279 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800280
281 {
282 std::unique_lock<std::mutex> lock(mu_);
283 num_running_cb_--;
284 if (shutdown_) {
285 callback_cv_.notify_all();
286 }
287 }
288}
289
290} // namespace grpc