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 #include <grpcpp/support/channel_arguments.h> 19 20 #include <sstream> 21 22 #include <grpc/impl/codegen/grpc_types.h> 23 #include <grpc/support/log.h> 24 #include <grpcpp/grpcpp.h> 25 #include <grpcpp/resource_quota.h> 26 #include "src/core/lib/channel/channel_args.h" 27 #include "src/core/lib/iomgr/exec_ctx.h" 28 #include "src/core/lib/iomgr/socket_mutator.h" 29 30 namespace grpc { 31 ChannelArguments()32 ChannelArguments::ChannelArguments() { 33 // This will be ignored if used on the server side. 34 SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, "grpc-c++/" + grpc::Version()); 35 } 36 ChannelArguments(const ChannelArguments & other)37 ChannelArguments::ChannelArguments(const ChannelArguments& other) 38 : strings_(other.strings_) { 39 args_.reserve(other.args_.size()); 40 auto list_it_dst = strings_.begin(); 41 auto list_it_src = other.strings_.begin(); 42 for (const auto& a : other.args_) { 43 grpc_arg ap; 44 ap.type = a.type; 45 GPR_ASSERT(list_it_src->c_str() == a.key); 46 ap.key = const_cast<char*>(list_it_dst->c_str()); 47 ++list_it_src; 48 ++list_it_dst; 49 switch (a.type) { 50 case GRPC_ARG_INTEGER: 51 ap.value.integer = a.value.integer; 52 break; 53 case GRPC_ARG_STRING: 54 GPR_ASSERT(list_it_src->c_str() == a.value.string); 55 ap.value.string = const_cast<char*>(list_it_dst->c_str()); 56 ++list_it_src; 57 ++list_it_dst; 58 break; 59 case GRPC_ARG_POINTER: 60 ap.value.pointer = a.value.pointer; 61 ap.value.pointer.p = a.value.pointer.vtable->copy(ap.value.pointer.p); 62 break; 63 } 64 args_.push_back(ap); 65 } 66 } 67 ~ChannelArguments()68 ChannelArguments::~ChannelArguments() { 69 for (auto& arg : args_) { 70 if (arg.type == GRPC_ARG_POINTER) { 71 grpc_core::ExecCtx exec_ctx; 72 arg.value.pointer.vtable->destroy(arg.value.pointer.p); 73 } 74 } 75 } 76 Swap(ChannelArguments & other)77 void ChannelArguments::Swap(ChannelArguments& other) { 78 args_.swap(other.args_); 79 strings_.swap(other.strings_); 80 } 81 SetCompressionAlgorithm(grpc_compression_algorithm algorithm)82 void ChannelArguments::SetCompressionAlgorithm( 83 grpc_compression_algorithm algorithm) { 84 SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM, algorithm); 85 } 86 SetGrpclbFallbackTimeout(int fallback_timeout)87 void ChannelArguments::SetGrpclbFallbackTimeout(int fallback_timeout) { 88 SetInt(GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS, fallback_timeout); 89 } 90 SetSocketMutator(grpc_socket_mutator * mutator)91 void ChannelArguments::SetSocketMutator(grpc_socket_mutator* mutator) { 92 if (!mutator) { 93 return; 94 } 95 grpc_arg mutator_arg = grpc_socket_mutator_to_arg(mutator); 96 bool replaced = false; 97 grpc_core::ExecCtx exec_ctx; 98 for (auto& arg : args_) { 99 if (arg.type == mutator_arg.type && 100 std::string(arg.key) == std::string(mutator_arg.key)) { 101 GPR_ASSERT(!replaced); 102 arg.value.pointer.vtable->destroy(arg.value.pointer.p); 103 arg.value.pointer = mutator_arg.value.pointer; 104 replaced = true; 105 } 106 } 107 108 if (!replaced) { 109 strings_.push_back(std::string(mutator_arg.key)); 110 args_.push_back(mutator_arg); 111 args_.back().key = const_cast<char*>(strings_.back().c_str()); 112 } 113 } 114 115 // Note: a second call to this will add in front the result of the first call. 116 // An example is calling this on a copy of ChannelArguments which already has a 117 // prefix. The user can build up a prefix string by calling this multiple times, 118 // each with more significant identifier. SetUserAgentPrefix(const std::string & user_agent_prefix)119 void ChannelArguments::SetUserAgentPrefix( 120 const std::string& user_agent_prefix) { 121 if (user_agent_prefix.empty()) { 122 return; 123 } 124 bool replaced = false; 125 auto strings_it = strings_.begin(); 126 for (auto& arg : args_) { 127 ++strings_it; 128 if (arg.type == GRPC_ARG_STRING) { 129 if (std::string(arg.key) == GRPC_ARG_PRIMARY_USER_AGENT_STRING) { 130 GPR_ASSERT(arg.value.string == strings_it->c_str()); 131 *(strings_it) = user_agent_prefix + " " + arg.value.string; 132 arg.value.string = const_cast<char*>(strings_it->c_str()); 133 replaced = true; 134 break; 135 } 136 ++strings_it; 137 } 138 } 139 if (!replaced) { 140 SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, user_agent_prefix); 141 } 142 } 143 SetResourceQuota(const grpc::ResourceQuota & resource_quota)144 void ChannelArguments::SetResourceQuota( 145 const grpc::ResourceQuota& resource_quota) { 146 SetPointerWithVtable(GRPC_ARG_RESOURCE_QUOTA, 147 resource_quota.c_resource_quota(), 148 grpc_resource_quota_arg_vtable()); 149 } 150 SetMaxReceiveMessageSize(int size)151 void ChannelArguments::SetMaxReceiveMessageSize(int size) { 152 SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, size); 153 } 154 SetMaxSendMessageSize(int size)155 void ChannelArguments::SetMaxSendMessageSize(int size) { 156 SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, size); 157 } 158 SetLoadBalancingPolicyName(const std::string & lb_policy_name)159 void ChannelArguments::SetLoadBalancingPolicyName( 160 const std::string& lb_policy_name) { 161 SetString(GRPC_ARG_LB_POLICY_NAME, lb_policy_name); 162 } 163 SetServiceConfigJSON(const std::string & service_config_json)164 void ChannelArguments::SetServiceConfigJSON( 165 const std::string& service_config_json) { 166 SetString(GRPC_ARG_SERVICE_CONFIG, service_config_json); 167 } 168 SetInt(const std::string & key,int value)169 void ChannelArguments::SetInt(const std::string& key, int value) { 170 grpc_arg arg; 171 arg.type = GRPC_ARG_INTEGER; 172 strings_.push_back(key); 173 arg.key = const_cast<char*>(strings_.back().c_str()); 174 arg.value.integer = value; 175 176 args_.push_back(arg); 177 } 178 SetPointer(const std::string & key,void * value)179 void ChannelArguments::SetPointer(const std::string& key, void* value) { 180 static const grpc_arg_pointer_vtable vtable = { 181 &PointerVtableMembers::Copy, &PointerVtableMembers::Destroy, 182 &PointerVtableMembers::Compare}; 183 SetPointerWithVtable(key, value, &vtable); 184 } 185 SetPointerWithVtable(const std::string & key,void * value,const grpc_arg_pointer_vtable * vtable)186 void ChannelArguments::SetPointerWithVtable( 187 const std::string& key, void* value, 188 const grpc_arg_pointer_vtable* vtable) { 189 grpc_arg arg; 190 arg.type = GRPC_ARG_POINTER; 191 strings_.push_back(key); 192 arg.key = const_cast<char*>(strings_.back().c_str()); 193 arg.value.pointer.p = vtable->copy(value); 194 arg.value.pointer.vtable = vtable; 195 args_.push_back(arg); 196 } 197 SetString(const std::string & key,const std::string & value)198 void ChannelArguments::SetString(const std::string& key, 199 const std::string& value) { 200 grpc_arg arg; 201 arg.type = GRPC_ARG_STRING; 202 strings_.push_back(key); 203 arg.key = const_cast<char*>(strings_.back().c_str()); 204 strings_.push_back(value); 205 arg.value.string = const_cast<char*>(strings_.back().c_str()); 206 207 args_.push_back(arg); 208 } 209 SetChannelArgs(grpc_channel_args * channel_args) const210 void ChannelArguments::SetChannelArgs(grpc_channel_args* channel_args) const { 211 channel_args->num_args = args_.size(); 212 if (channel_args->num_args > 0) { 213 channel_args->args = const_cast<grpc_arg*>(&args_[0]); 214 } 215 } 216 217 } // namespace grpc 218