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 32 ChannelArguments::ChannelArguments() { 33 // This will be ignored if used on the server side. 34 SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, "grpc-c++/" + Version()); 35 } 36 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 (auto a = other.args_.begin(); a != other.args_.end(); ++a) { 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 68 ChannelArguments::~ChannelArguments() { 69 grpc_core::ExecCtx exec_ctx; 70 for (auto it = args_.begin(); it != args_.end(); ++it) { 71 if (it->type == GRPC_ARG_POINTER) { 72 it->value.pointer.vtable->destroy(it->value.pointer.p); 73 } 74 } 75 } 76 77 void ChannelArguments::Swap(ChannelArguments& other) { 78 args_.swap(other.args_); 79 strings_.swap(other.strings_); 80 } 81 82 void ChannelArguments::SetCompressionAlgorithm( 83 grpc_compression_algorithm algorithm) { 84 SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM, algorithm); 85 } 86 87 void ChannelArguments::SetGrpclbFallbackTimeout(int fallback_timeout) { 88 SetInt(GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS, fallback_timeout); 89 } 90 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 it = args_.begin(); it != args_.end(); ++it) { 99 if (it->type == mutator_arg.type && 100 grpc::string(it->key) == grpc::string(mutator_arg.key)) { 101 GPR_ASSERT(!replaced); 102 it->value.pointer.vtable->destroy(it->value.pointer.p); 103 it->value.pointer = mutator_arg.value.pointer; 104 replaced = true; 105 } 106 } 107 108 if (!replaced) { 109 args_.push_back(mutator_arg); 110 } 111 } 112 113 // Note: a second call to this will add in front the result of the first call. 114 // An example is calling this on a copy of ChannelArguments which already has a 115 // prefix. The user can build up a prefix string by calling this multiple times, 116 // each with more significant identifier. 117 void ChannelArguments::SetUserAgentPrefix( 118 const grpc::string& user_agent_prefix) { 119 if (user_agent_prefix.empty()) { 120 return; 121 } 122 bool replaced = false; 123 auto strings_it = strings_.begin(); 124 for (auto it = args_.begin(); it != args_.end(); ++it) { 125 const grpc_arg& arg = *it; 126 ++strings_it; 127 if (arg.type == GRPC_ARG_STRING) { 128 if (grpc::string(arg.key) == GRPC_ARG_PRIMARY_USER_AGENT_STRING) { 129 GPR_ASSERT(arg.value.string == strings_it->c_str()); 130 *(strings_it) = user_agent_prefix + " " + arg.value.string; 131 it->value.string = const_cast<char*>(strings_it->c_str()); 132 replaced = true; 133 break; 134 } 135 ++strings_it; 136 } 137 } 138 if (!replaced) { 139 SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, user_agent_prefix); 140 } 141 } 142 143 void ChannelArguments::SetResourceQuota( 144 const grpc::ResourceQuota& resource_quota) { 145 SetPointerWithVtable(GRPC_ARG_RESOURCE_QUOTA, 146 resource_quota.c_resource_quota(), 147 grpc_resource_quota_arg_vtable()); 148 } 149 150 void ChannelArguments::SetMaxReceiveMessageSize(int size) { 151 SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, size); 152 } 153 154 void ChannelArguments::SetMaxSendMessageSize(int size) { 155 SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, size); 156 } 157 158 void ChannelArguments::SetLoadBalancingPolicyName( 159 const grpc::string& lb_policy_name) { 160 SetString(GRPC_ARG_LB_POLICY_NAME, lb_policy_name); 161 } 162 163 void ChannelArguments::SetServiceConfigJSON( 164 const grpc::string& service_config_json) { 165 SetString(GRPC_ARG_SERVICE_CONFIG, service_config_json); 166 } 167 168 void ChannelArguments::SetInt(const grpc::string& key, int value) { 169 grpc_arg arg; 170 arg.type = GRPC_ARG_INTEGER; 171 strings_.push_back(key); 172 arg.key = const_cast<char*>(strings_.back().c_str()); 173 arg.value.integer = value; 174 175 args_.push_back(arg); 176 } 177 178 void ChannelArguments::SetPointer(const grpc::string& key, void* value) { 179 static const grpc_arg_pointer_vtable vtable = { 180 &PointerVtableMembers::Copy, &PointerVtableMembers::Destroy, 181 &PointerVtableMembers::Compare}; 182 SetPointerWithVtable(key, value, &vtable); 183 } 184 185 void ChannelArguments::SetPointerWithVtable( 186 const grpc::string& key, void* value, 187 const grpc_arg_pointer_vtable* vtable) { 188 grpc_arg arg; 189 arg.type = GRPC_ARG_POINTER; 190 strings_.push_back(key); 191 arg.key = const_cast<char*>(strings_.back().c_str()); 192 arg.value.pointer.p = vtable->copy(value); 193 arg.value.pointer.vtable = vtable; 194 args_.push_back(arg); 195 } 196 197 void ChannelArguments::SetString(const grpc::string& key, 198 const grpc::string& value) { 199 grpc_arg arg; 200 arg.type = GRPC_ARG_STRING; 201 strings_.push_back(key); 202 arg.key = const_cast<char*>(strings_.back().c_str()); 203 strings_.push_back(value); 204 arg.value.string = const_cast<char*>(strings_.back().c_str()); 205 206 args_.push_back(arg); 207 } 208 209 void ChannelArguments::SetChannelArgs(grpc_channel_args* channel_args) const { 210 channel_args->num_args = args_.size(); 211 if (channel_args->num_args > 0) { 212 channel_args->args = const_cast<grpc_arg*>(&args_[0]); 213 } 214 } 215 216 } // namespace grpc 217