blob: 049c3e36b26259f33d37c3303db3798ea5f92a71 [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) {
122 void *tag;
123 if (!cq->Next(&tag, ok)) {
124 return nullptr;
125 }
126 auto *mrd = static_cast<MethodRequestData *>(tag);
127 GPR_ASSERT(mrd->in_flight_);
128 return mrd;
129 }
130
Craig Tiller3b29b562015-02-11 12:58:46 -0800131 void Request(grpc_server *server) {
Craig Tillerc4165772015-02-11 10:51:04 -0800132 GPR_ASSERT(!in_flight_);
133 in_flight_ = true;
134 cq_ = grpc_completion_queue_create();
135 GPR_ASSERT(GRPC_CALL_OK ==
136 grpc_server_request_registered_call(
137 server, tag_, &call_, &deadline_, &request_metadata_,
Craig Tiller3b29b562015-02-11 12:58:46 -0800138 has_request_payload_ ? &request_payload_ : nullptr,
Craig Tillerc4165772015-02-11 10:51:04 -0800139 cq_, this));
140 }
141
Craig Tiller04c8ff02015-02-11 11:01:07 -0800142 void FinalizeResult(void **tag, bool *status) override {}
Craig Tillerc4165772015-02-11 10:51:04 -0800143
144 class CallData {
145 public:
146 explicit CallData(MethodRequestData *mrd)
147 : cq_(mrd->cq_),
148 call_(mrd->call_, nullptr, &cq_),
149 ctx_(mrd->deadline_, mrd->request_metadata_.metadata,
150 mrd->request_metadata_.count),
151 has_request_payload_(mrd->has_request_payload_),
152 has_response_payload_(mrd->has_response_payload_),
153 request_payload_(mrd->request_payload_),
154 method_(mrd->method_) {
155 GPR_ASSERT(mrd->in_flight_);
156 mrd->in_flight_ = false;
157 mrd->request_metadata_.count = 0;
158 }
159
160 void Run() {
161 std::unique_ptr<google::protobuf::Message> req;
162 std::unique_ptr<google::protobuf::Message> res;
163 if (has_request_payload_) {
164 req.reset(method_->AllocateRequestProto());
165 if (!DeserializeProto(request_payload_, req.get())) {
166 abort(); // for now
167 }
168 }
169 if (has_response_payload_) {
Craig Tiller7c2f3f72015-02-11 13:21:54 -0800170 res.reset(method_->AllocateResponseProto());
Craig Tillerc4165772015-02-11 10:51:04 -0800171 }
172 auto status = method_->handler()->RunHandler(
173 MethodHandler::HandlerParameter(&call_, &ctx_, req.get(), res.get()));
174 CallOpBuffer buf;
175 buf.AddServerSendStatus(nullptr, status);
176 if (has_response_payload_) {
177 buf.AddSendMessage(*res);
178 }
179 call_.PerformOps(&buf);
180 GPR_ASSERT(cq_.Pluck(&buf));
181 }
182
183 private:
184 CompletionQueue cq_;
185 Call call_;
186 ServerContext ctx_;
187 const bool has_request_payload_;
188 const bool has_response_payload_;
189 grpc_byte_buffer *request_payload_;
190 RpcServiceMethod *const method_;
191 };
192
193 private:
194 RpcServiceMethod *const method_;
195 void *const tag_;
196 bool in_flight_ = false;
197 const bool has_request_payload_;
198 const bool has_response_payload_;
199 grpc_call *call_;
200 gpr_timespec deadline_;
201 grpc_metadata_array request_metadata_;
202 grpc_byte_buffer *request_payload_;
203 grpc_completion_queue *cq_;
204};
205
Craig Tiller0db1bef2015-02-09 13:47:39 -0800206bool Server::Start() {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800207 GPR_ASSERT(!started_);
208 started_ = true;
209 grpc_server_start(server_);
210
211 // Start processing rpcs.
Craig Tiller3b29b562015-02-11 12:58:46 -0800212 if (!methods_.empty()) {
Craig Tillerc4165772015-02-11 10:51:04 -0800213 for (auto &m : methods_) {
Craig Tiller3b29b562015-02-11 12:58:46 -0800214 m.Request(server_);
Craig Tillercbd04852015-02-10 17:39:54 -0800215 }
216
Craig Tiller7c72adc2015-02-09 14:07:26 -0800217 ScheduleCallback();
218 }
Craig Tiller0db1bef2015-02-09 13:47:39 -0800219
220 return true;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800221}
222
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800223void Server::Shutdown() {
224 {
225 std::unique_lock<std::mutex> lock(mu_);
226 if (started_ && !shutdown_) {
227 shutdown_ = true;
228 grpc_server_shutdown(server_);
229
230 // Wait for running callbacks to finish.
231 while (num_running_cb_ != 0) {
232 callback_cv_.wait(lock);
233 }
234 }
235 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800236}
237
238void Server::ScheduleCallback() {
239 {
240 std::unique_lock<std::mutex> lock(mu_);
241 num_running_cb_++;
242 }
Craig Tiller0db1bef2015-02-09 13:47:39 -0800243 thread_pool_->ScheduleCallback(std::bind(&Server::RunRpc, this));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800244}
245
246void Server::RunRpc() {
247 // Wait for one more incoming rpc.
Craig Tillerc4165772015-02-11 10:51:04 -0800248 bool ok;
Craig Tiller3b29b562015-02-11 12:58:46 -0800249 auto *mrd = MethodRequestData::Wait(&cq_, &ok);
Craig Tillercbd04852015-02-10 17:39:54 -0800250 if (mrd) {
251 MethodRequestData::CallData cd(mrd);
252
Craig Tillerc4165772015-02-11 10:51:04 -0800253 if (ok) {
Craig Tiller3b29b562015-02-11 12:58:46 -0800254 mrd->Request(server_);
Craig Tillerc4165772015-02-11 10:51:04 -0800255 ScheduleCallback();
Craig Tillercbd04852015-02-10 17:39:54 -0800256
Craig Tillerc4165772015-02-11 10:51:04 -0800257 cd.Run();
258 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800259 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800260
261 {
262 std::unique_lock<std::mutex> lock(mu_);
263 num_running_cb_--;
264 if (shutdown_) {
265 callback_cv_.notify_all();
266 }
267 }
268}
269
270} // namespace grpc