server_builder.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /*
  2. *
  3. * Copyright 2015-2016 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. #include <utility>
  19. #include <grpc/support/cpu.h>
  20. #include <grpc/support/log.h>
  21. #include <grpcpp/impl/service_type.h>
  22. #include <grpcpp/resource_quota.h>
  23. #include <grpcpp/server.h>
  24. #include <grpcpp/server_builder.h>
  25. #include "src/core/lib/channel/channel_args.h"
  26. #include "src/core/lib/gpr/string.h"
  27. #include "src/core/lib/gpr/useful.h"
  28. #include "src/cpp/server/external_connection_acceptor_impl.h"
  29. #include "src/cpp/server/thread_pool_interface.h"
  30. namespace grpc {
  31. static std::vector<std::unique_ptr<ServerBuilderPlugin> (*)()>*
  32. g_plugin_factory_list;
  33. static gpr_once once_init_plugin_list = GPR_ONCE_INIT;
  34. static void do_plugin_list_init(void) {
  35. g_plugin_factory_list =
  36. new std::vector<std::unique_ptr<ServerBuilderPlugin> (*)()>();
  37. }
  38. ServerBuilder::ServerBuilder()
  39. : max_receive_message_size_(INT_MIN),
  40. max_send_message_size_(INT_MIN),
  41. sync_server_settings_(SyncServerSettings()),
  42. resource_quota_(nullptr) {
  43. gpr_once_init(&once_init_plugin_list, do_plugin_list_init);
  44. for (const auto& value : *g_plugin_factory_list) {
  45. plugins_.emplace_back(value());
  46. }
  47. // all compression algorithms enabled by default.
  48. enabled_compression_algorithms_bitset_ =
  49. (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
  50. memset(&maybe_default_compression_level_, 0,
  51. sizeof(maybe_default_compression_level_));
  52. memset(&maybe_default_compression_algorithm_, 0,
  53. sizeof(maybe_default_compression_algorithm_));
  54. }
  55. ServerBuilder::~ServerBuilder() {
  56. if (resource_quota_ != nullptr) {
  57. grpc_resource_quota_unref(resource_quota_);
  58. }
  59. }
  60. std::unique_ptr<grpc::ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
  61. bool is_frequently_polled) {
  62. grpc::ServerCompletionQueue* cq = new grpc::ServerCompletionQueue(
  63. GRPC_CQ_NEXT,
  64. is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING,
  65. nullptr);
  66. cqs_.push_back(cq);
  67. return std::unique_ptr<grpc::ServerCompletionQueue>(cq);
  68. }
  69. ServerBuilder& ServerBuilder::RegisterService(Service* service) {
  70. services_.emplace_back(new NamedService(service));
  71. return *this;
  72. }
  73. ServerBuilder& ServerBuilder::RegisterService(const std::string& host,
  74. Service* service) {
  75. services_.emplace_back(new NamedService(host, service));
  76. return *this;
  77. }
  78. ServerBuilder& ServerBuilder::RegisterAsyncGenericService(
  79. AsyncGenericService* service) {
  80. if (generic_service_ || callback_generic_service_) {
  81. gpr_log(GPR_ERROR,
  82. "Adding multiple generic services is unsupported for now. "
  83. "Dropping the service %p",
  84. service);
  85. } else {
  86. generic_service_ = service;
  87. }
  88. return *this;
  89. }
  90. ServerBuilder& ServerBuilder::RegisterCallbackGenericService(
  91. CallbackGenericService* service) {
  92. if (generic_service_ || callback_generic_service_) {
  93. gpr_log(GPR_ERROR,
  94. "Adding multiple generic services is unsupported for now. "
  95. "Dropping the service %p",
  96. service);
  97. } else {
  98. callback_generic_service_ = service;
  99. }
  100. return *this;
  101. }
  102. ServerBuilder& ServerBuilder::SetContextAllocator(
  103. std::unique_ptr<grpc::ContextAllocator> context_allocator) {
  104. context_allocator_ = std::move(context_allocator);
  105. return *this;
  106. }
  107. std::unique_ptr<grpc::experimental::ExternalConnectionAcceptor>
  108. ServerBuilder::experimental_type::AddExternalConnectionAcceptor(
  109. experimental_type::ExternalConnectionType type,
  110. std::shared_ptr<ServerCredentials> creds) {
  111. std::string name_prefix("external:");
  112. char count_str[GPR_LTOA_MIN_BUFSIZE];
  113. gpr_ltoa(static_cast<long>(builder_->acceptors_.size()), count_str);
  114. builder_->acceptors_.emplace_back(
  115. std::make_shared<grpc::internal::ExternalConnectionAcceptorImpl>(
  116. name_prefix.append(count_str), type, creds));
  117. return builder_->acceptors_.back()->GetAcceptor();
  118. }
  119. void ServerBuilder::experimental_type::SetAuthorizationPolicyProvider(
  120. std::shared_ptr<experimental::AuthorizationPolicyProviderInterface>
  121. provider) {
  122. builder_->authorization_provider_ = std::move(provider);
  123. }
  124. ServerBuilder& ServerBuilder::SetOption(
  125. std::unique_ptr<ServerBuilderOption> option) {
  126. options_.push_back(std::move(option));
  127. return *this;
  128. }
  129. ServerBuilder& ServerBuilder::SetSyncServerOption(
  130. ServerBuilder::SyncServerOption option, int val) {
  131. switch (option) {
  132. case NUM_CQS:
  133. sync_server_settings_.num_cqs = val;
  134. break;
  135. case MIN_POLLERS:
  136. sync_server_settings_.min_pollers = val;
  137. break;
  138. case MAX_POLLERS:
  139. sync_server_settings_.max_pollers = val;
  140. break;
  141. case CQ_TIMEOUT_MSEC:
  142. sync_server_settings_.cq_timeout_msec = val;
  143. break;
  144. }
  145. return *this;
  146. }
  147. ServerBuilder& ServerBuilder::SetCompressionAlgorithmSupportStatus(
  148. grpc_compression_algorithm algorithm, bool enabled) {
  149. if (enabled) {
  150. grpc_core::SetBit(&enabled_compression_algorithms_bitset_, algorithm);
  151. } else {
  152. grpc_core::ClearBit(&enabled_compression_algorithms_bitset_, algorithm);
  153. }
  154. return *this;
  155. }
  156. ServerBuilder& ServerBuilder::SetDefaultCompressionLevel(
  157. grpc_compression_level level) {
  158. maybe_default_compression_level_.is_set = true;
  159. maybe_default_compression_level_.level = level;
  160. return *this;
  161. }
  162. ServerBuilder& ServerBuilder::SetDefaultCompressionAlgorithm(
  163. grpc_compression_algorithm algorithm) {
  164. maybe_default_compression_algorithm_.is_set = true;
  165. maybe_default_compression_algorithm_.algorithm = algorithm;
  166. return *this;
  167. }
  168. ServerBuilder& ServerBuilder::SetResourceQuota(
  169. const grpc::ResourceQuota& resource_quota) {
  170. if (resource_quota_ != nullptr) {
  171. grpc_resource_quota_unref(resource_quota_);
  172. }
  173. resource_quota_ = resource_quota.c_resource_quota();
  174. grpc_resource_quota_ref(resource_quota_);
  175. return *this;
  176. }
  177. ServerBuilder& ServerBuilder::AddListeningPort(
  178. const std::string& addr_uri, std::shared_ptr<ServerCredentials> creds,
  179. int* selected_port) {
  180. const std::string uri_scheme = "dns:";
  181. std::string addr = addr_uri;
  182. if (addr_uri.compare(0, uri_scheme.size(), uri_scheme) == 0) {
  183. size_t pos = uri_scheme.size();
  184. while (addr_uri[pos] == '/') ++pos; // Skip slashes.
  185. addr = addr_uri.substr(pos);
  186. }
  187. Port port = {addr, std::move(creds), selected_port};
  188. ports_.push_back(port);
  189. return *this;
  190. }
  191. ChannelArguments ServerBuilder::BuildChannelArgs() {
  192. ChannelArguments args;
  193. if (max_receive_message_size_ >= -1) {
  194. args.SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, max_receive_message_size_);
  195. }
  196. if (max_send_message_size_ >= -1) {
  197. args.SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, max_send_message_size_);
  198. }
  199. for (const auto& option : options_) {
  200. option->UpdateArguments(&args);
  201. option->UpdatePlugins(&plugins_);
  202. }
  203. args.SetInt(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET,
  204. enabled_compression_algorithms_bitset_);
  205. if (maybe_default_compression_level_.is_set) {
  206. args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL,
  207. maybe_default_compression_level_.level);
  208. }
  209. if (maybe_default_compression_algorithm_.is_set) {
  210. args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM,
  211. maybe_default_compression_algorithm_.algorithm);
  212. }
  213. if (resource_quota_ != nullptr) {
  214. args.SetPointerWithVtable(GRPC_ARG_RESOURCE_QUOTA, resource_quota_,
  215. grpc_resource_quota_arg_vtable());
  216. }
  217. for (const auto& plugin : plugins_) {
  218. plugin->UpdateServerBuilder(this);
  219. plugin->UpdateChannelArguments(&args);
  220. }
  221. if (authorization_provider_ != nullptr) {
  222. args.SetPointerWithVtable(GRPC_ARG_AUTHORIZATION_POLICY_PROVIDER,
  223. authorization_provider_->c_provider(),
  224. grpc_authorization_policy_provider_arg_vtable());
  225. }
  226. return args;
  227. }
  228. std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
  229. ChannelArguments args = BuildChannelArgs();
  230. // == Determine if the server has any syncrhonous methods ==
  231. bool has_sync_methods = false;
  232. for (const auto& value : services_) {
  233. if (value->service->has_synchronous_methods()) {
  234. has_sync_methods = true;
  235. break;
  236. }
  237. }
  238. if (!has_sync_methods) {
  239. for (const auto& value : plugins_) {
  240. if (value->has_sync_methods()) {
  241. has_sync_methods = true;
  242. break;
  243. }
  244. }
  245. }
  246. // If this is a Sync server, i.e a server expositing sync API, then the server
  247. // needs to create some completion queues to listen for incoming requests.
  248. // 'sync_server_cqs' are those internal completion queues.
  249. //
  250. // This is different from the completion queues added to the server via
  251. // ServerBuilder's AddCompletionQueue() method (those completion queues
  252. // are in 'cqs_' member variable of ServerBuilder object)
  253. std::shared_ptr<std::vector<std::unique_ptr<grpc::ServerCompletionQueue>>>
  254. sync_server_cqs(
  255. std::make_shared<
  256. std::vector<std::unique_ptr<grpc::ServerCompletionQueue>>>());
  257. bool has_frequently_polled_cqs = false;
  258. for (const auto& cq : cqs_) {
  259. if (cq->IsFrequentlyPolled()) {
  260. has_frequently_polled_cqs = true;
  261. break;
  262. }
  263. }
  264. // == Determine if the server has any callback methods ==
  265. bool has_callback_methods = false;
  266. for (const auto& service : services_) {
  267. if (service->service->has_callback_methods()) {
  268. has_callback_methods = true;
  269. has_frequently_polled_cqs = true;
  270. break;
  271. }
  272. }
  273. if (callback_generic_service_ != nullptr) {
  274. has_frequently_polled_cqs = true;
  275. }
  276. const bool is_hybrid_server = has_sync_methods && has_frequently_polled_cqs;
  277. if (has_sync_methods) {
  278. grpc_cq_polling_type polling_type =
  279. is_hybrid_server ? GRPC_CQ_NON_POLLING : GRPC_CQ_DEFAULT_POLLING;
  280. // Create completion queues to listen to incoming rpc requests
  281. for (int i = 0; i < sync_server_settings_.num_cqs; i++) {
  282. sync_server_cqs->emplace_back(
  283. new grpc::ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr));
  284. }
  285. }
  286. // TODO(vjpai): Add a section here for plugins once they can support callback
  287. // methods
  288. if (has_sync_methods) {
  289. // This is a Sync server
  290. gpr_log(GPR_INFO,
  291. "Synchronous server. Num CQs: %d, Min pollers: %d, Max Pollers: "
  292. "%d, CQ timeout (msec): %d",
  293. sync_server_settings_.num_cqs, sync_server_settings_.min_pollers,
  294. sync_server_settings_.max_pollers,
  295. sync_server_settings_.cq_timeout_msec);
  296. }
  297. if (has_callback_methods) {
  298. gpr_log(GPR_INFO, "Callback server.");
  299. }
  300. std::unique_ptr<grpc::Server> server(new grpc::Server(
  301. &args, sync_server_cqs, sync_server_settings_.min_pollers,
  302. sync_server_settings_.max_pollers, sync_server_settings_.cq_timeout_msec,
  303. std::move(acceptors_), server_config_fetcher_, resource_quota_,
  304. std::move(interceptor_creators_)));
  305. ServerInitializer* initializer = server->initializer();
  306. // Register all the completion queues with the server. i.e
  307. // 1. sync_server_cqs: internal completion queues created IF this is a sync
  308. // server
  309. // 2. cqs_: Completion queues added via AddCompletionQueue() call
  310. for (const auto& cq : *sync_server_cqs) {
  311. grpc_server_register_completion_queue(server->server_, cq->cq(), nullptr);
  312. has_frequently_polled_cqs = true;
  313. }
  314. if (has_callback_methods || callback_generic_service_ != nullptr) {
  315. auto* cq = server->CallbackCQ();
  316. grpc_server_register_completion_queue(server->server_, cq->cq(), nullptr);
  317. }
  318. // cqs_ contains the completion queue added by calling the ServerBuilder's
  319. // AddCompletionQueue() API. Some of them may not be frequently polled (i.e by
  320. // calling Next() or AsyncNext()) and hence are not safe to be used for
  321. // listening to incoming channels. Such completion queues must be registered
  322. // as non-listening queues. In debug mode, these should have their server list
  323. // tracked since these are provided the user and must be Shutdown by the user
  324. // after the server is shutdown.
  325. for (const auto& cq : cqs_) {
  326. grpc_server_register_completion_queue(server->server_, cq->cq(), nullptr);
  327. cq->RegisterServer(server.get());
  328. }
  329. if (!has_frequently_polled_cqs) {
  330. gpr_log(GPR_ERROR,
  331. "At least one of the completion queues must be frequently polled");
  332. return nullptr;
  333. }
  334. server->RegisterContextAllocator(std::move(context_allocator_));
  335. for (const auto& value : services_) {
  336. if (!server->RegisterService(value->host.get(), value->service)) {
  337. return nullptr;
  338. }
  339. }
  340. for (const auto& value : plugins_) {
  341. value->InitServer(initializer);
  342. }
  343. if (generic_service_) {
  344. server->RegisterAsyncGenericService(generic_service_);
  345. } else if (callback_generic_service_) {
  346. server->RegisterCallbackGenericService(callback_generic_service_);
  347. } else {
  348. for (const auto& value : services_) {
  349. if (value->service->has_generic_methods()) {
  350. gpr_log(GPR_ERROR,
  351. "Some methods were marked generic but there is no "
  352. "generic service registered.");
  353. return nullptr;
  354. }
  355. }
  356. }
  357. bool added_port = false;
  358. for (auto& port : ports_) {
  359. int r = server->AddListeningPort(port.addr, port.creds.get());
  360. if (!r) {
  361. if (added_port) server->Shutdown();
  362. return nullptr;
  363. }
  364. added_port = true;
  365. if (port.selected_port != nullptr) {
  366. *port.selected_port = r;
  367. }
  368. }
  369. auto cqs_data = cqs_.empty() ? nullptr : &cqs_[0];
  370. server->Start(cqs_data, cqs_.size());
  371. for (const auto& value : plugins_) {
  372. value->Finish(initializer);
  373. }
  374. return server;
  375. }
  376. void ServerBuilder::InternalAddPluginFactory(
  377. std::unique_ptr<ServerBuilderPlugin> (*CreatePlugin)()) {
  378. gpr_once_init(&once_init_plugin_list, do_plugin_list_init);
  379. (*g_plugin_factory_list).push_back(CreatePlugin);
  380. }
  381. ServerBuilder& ServerBuilder::EnableWorkaround(grpc_workaround_list id) {
  382. switch (id) {
  383. case GRPC_WORKAROUND_ID_CRONET_COMPRESSION:
  384. return AddChannelArgument(GRPC_ARG_WORKAROUND_CRONET_COMPRESSION, 1);
  385. default:
  386. gpr_log(GPR_ERROR, "Workaround %u does not exist or is obsolete.", id);
  387. return *this;
  388. }
  389. }
  390. } // namespace grpc