e5766414c99fe353a26f61b125a034e95b18aea8
[platform/upstream/grpc.git] / src / objective-c / GRPCClient / GRPCCallOptions.m
1 /*
2  *
3  * Copyright 2018 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
19 #import "GRPCCallOptions.h"
20 #import "internal/GRPCCallOptions+Internal.h"
21
22 // The default values for the call options.
23 static NSString *const kDefaultServerAuthority = nil;
24 static const NSTimeInterval kDefaultTimeout = 0;
25 static const BOOL kDefaultFlowControlEnabled = NO;
26 static NSDictionary *const kDefaultInitialMetadata = nil;
27 static NSString *const kDefaultUserAgentPrefix = nil;
28 static const NSUInteger kDefaultResponseSizeLimit = 0;
29 static const GRPCCompressionAlgorithm kDefaultCompressionAlgorithm = GRPCCompressNone;
30 static const BOOL kDefaultRetryEnabled = YES;
31 static const NSTimeInterval kDefaultKeepaliveInterval = 0;
32 static const NSTimeInterval kDefaultKeepaliveTimeout = 0;
33 static const NSTimeInterval kDefaultConnectMinTimeout = 0;
34 static const NSTimeInterval kDefaultConnectInitialBackoff = 0;
35 static const NSTimeInterval kDefaultConnectMaxBackoff = 0;
36 static NSDictionary *const kDefaultAdditionalChannelArgs = nil;
37 static NSString *const kDefaultPEMRootCertificates = nil;
38 static NSString *const kDefaultPEMPrivateKey = nil;
39 static NSString *const kDefaultPEMCertificateChain = nil;
40 static NSString *const kDefaultOauth2AccessToken = nil;
41 static const id<GRPCAuthorizationProtocol> kDefaultAuthTokenProvider = nil;
42 static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeChttp2BoringSSL;
43 static NSString *const kDefaultHostNameOverride = nil;
44 static const id kDefaultLogContext = nil;
45 static NSString *const kDefaultChannelPoolDomain = nil;
46 static const NSUInteger kDefaultChannelID = 0;
47
48 // Check if two objects are equal. Returns YES if both are nil;
49 static BOOL areObjectsEqual(id obj1, id obj2) {
50   if (obj1 == obj2) {
51     return YES;
52   }
53   if (obj1 == nil || obj2 == nil) {
54     return NO;
55   }
56   return [obj1 isEqual:obj2];
57 }
58
59 @implementation GRPCCallOptions {
60  @protected
61   NSString *_serverAuthority;
62   NSTimeInterval _timeout;
63   BOOL _flowControlEnabled;
64   NSString *_oauth2AccessToken;
65   id<GRPCAuthorizationProtocol> _authTokenProvider;
66   NSDictionary *_initialMetadata;
67   NSString *_userAgentPrefix;
68   NSUInteger _responseSizeLimit;
69   GRPCCompressionAlgorithm _compressionAlgorithm;
70   BOOL _retryEnabled;
71   NSTimeInterval _keepaliveInterval;
72   NSTimeInterval _keepaliveTimeout;
73   NSTimeInterval _connectMinTimeout;
74   NSTimeInterval _connectInitialBackoff;
75   NSTimeInterval _connectMaxBackoff;
76   NSDictionary *_additionalChannelArgs;
77   NSString *_PEMRootCertificates;
78   NSString *_PEMPrivateKey;
79   NSString *_PEMCertificateChain;
80   GRPCTransportType _transportType;
81   NSString *_hostNameOverride;
82   id<NSObject> _logContext;
83   NSString *_channelPoolDomain;
84   NSUInteger _channelID;
85 }
86
87 @synthesize serverAuthority = _serverAuthority;
88 @synthesize timeout = _timeout;
89 @synthesize flowControlEnabled = _flowControlEnabled;
90 @synthesize oauth2AccessToken = _oauth2AccessToken;
91 @synthesize authTokenProvider = _authTokenProvider;
92 @synthesize initialMetadata = _initialMetadata;
93 @synthesize userAgentPrefix = _userAgentPrefix;
94 @synthesize responseSizeLimit = _responseSizeLimit;
95 @synthesize compressionAlgorithm = _compressionAlgorithm;
96 @synthesize retryEnabled = _retryEnabled;
97 @synthesize keepaliveInterval = _keepaliveInterval;
98 @synthesize keepaliveTimeout = _keepaliveTimeout;
99 @synthesize connectMinTimeout = _connectMinTimeout;
100 @synthesize connectInitialBackoff = _connectInitialBackoff;
101 @synthesize connectMaxBackoff = _connectMaxBackoff;
102 @synthesize additionalChannelArgs = _additionalChannelArgs;
103 @synthesize PEMRootCertificates = _PEMRootCertificates;
104 @synthesize PEMPrivateKey = _PEMPrivateKey;
105 @synthesize PEMCertificateChain = _PEMCertificateChain;
106 @synthesize transportType = _transportType;
107 @synthesize hostNameOverride = _hostNameOverride;
108 @synthesize logContext = _logContext;
109 @synthesize channelPoolDomain = _channelPoolDomain;
110 @synthesize channelID = _channelID;
111
112 - (instancetype)init {
113   return [self initWithServerAuthority:kDefaultServerAuthority
114                                timeout:kDefaultTimeout
115                     flowControlEnabled:kDefaultFlowControlEnabled
116                      oauth2AccessToken:kDefaultOauth2AccessToken
117                      authTokenProvider:kDefaultAuthTokenProvider
118                        initialMetadata:kDefaultInitialMetadata
119                        userAgentPrefix:kDefaultUserAgentPrefix
120                      responseSizeLimit:kDefaultResponseSizeLimit
121                   compressionAlgorithm:kDefaultCompressionAlgorithm
122                           retryEnabled:kDefaultRetryEnabled
123                      keepaliveInterval:kDefaultKeepaliveInterval
124                       keepaliveTimeout:kDefaultKeepaliveTimeout
125                      connectMinTimeout:kDefaultConnectMinTimeout
126                  connectInitialBackoff:kDefaultConnectInitialBackoff
127                      connectMaxBackoff:kDefaultConnectMaxBackoff
128                  additionalChannelArgs:kDefaultAdditionalChannelArgs
129                    PEMRootCertificates:kDefaultPEMRootCertificates
130                          PEMPrivateKey:kDefaultPEMPrivateKey
131                    PEMCertificateChain:kDefaultPEMCertificateChain
132                          transportType:kDefaultTransportType
133                       hostNameOverride:kDefaultHostNameOverride
134                             logContext:kDefaultLogContext
135                      channelPoolDomain:kDefaultChannelPoolDomain
136                              channelID:kDefaultChannelID];
137 }
138
139 - (instancetype)initWithServerAuthority:(NSString *)serverAuthority
140                                 timeout:(NSTimeInterval)timeout
141                      flowControlEnabled:(BOOL)flowControlEnabled
142                       oauth2AccessToken:(NSString *)oauth2AccessToken
143                       authTokenProvider:(id<GRPCAuthorizationProtocol>)authTokenProvider
144                         initialMetadata:(NSDictionary *)initialMetadata
145                         userAgentPrefix:(NSString *)userAgentPrefix
146                       responseSizeLimit:(NSUInteger)responseSizeLimit
147                    compressionAlgorithm:(GRPCCompressionAlgorithm)compressionAlgorithm
148                            retryEnabled:(BOOL)retryEnabled
149                       keepaliveInterval:(NSTimeInterval)keepaliveInterval
150                        keepaliveTimeout:(NSTimeInterval)keepaliveTimeout
151                       connectMinTimeout:(NSTimeInterval)connectMinTimeout
152                   connectInitialBackoff:(NSTimeInterval)connectInitialBackoff
153                       connectMaxBackoff:(NSTimeInterval)connectMaxBackoff
154                   additionalChannelArgs:(NSDictionary *)additionalChannelArgs
155                     PEMRootCertificates:(NSString *)PEMRootCertificates
156                           PEMPrivateKey:(NSString *)PEMPrivateKey
157                     PEMCertificateChain:(NSString *)PEMCertificateChain
158                           transportType:(GRPCTransportType)transportType
159                        hostNameOverride:(NSString *)hostNameOverride
160                              logContext:(id)logContext
161                       channelPoolDomain:(NSString *)channelPoolDomain
162                               channelID:(NSUInteger)channelID {
163   if ((self = [super init])) {
164     _serverAuthority = [serverAuthority copy];
165     _timeout = timeout < 0 ? 0 : timeout;
166     _flowControlEnabled = flowControlEnabled;
167     _oauth2AccessToken = [oauth2AccessToken copy];
168     _authTokenProvider = authTokenProvider;
169     _initialMetadata =
170         initialMetadata == nil
171             ? nil
172             : [[NSDictionary alloc] initWithDictionary:initialMetadata copyItems:YES];
173     _userAgentPrefix = [userAgentPrefix copy];
174     _responseSizeLimit = responseSizeLimit;
175     _compressionAlgorithm = compressionAlgorithm;
176     _retryEnabled = retryEnabled;
177     _keepaliveInterval = keepaliveInterval < 0 ? 0 : keepaliveInterval;
178     _keepaliveTimeout = keepaliveTimeout < 0 ? 0 : keepaliveTimeout;
179     _connectMinTimeout = connectMinTimeout < 0 ? 0 : connectMinTimeout;
180     _connectInitialBackoff = connectInitialBackoff < 0 ? 0 : connectInitialBackoff;
181     _connectMaxBackoff = connectMaxBackoff < 0 ? 0 : connectMaxBackoff;
182     _additionalChannelArgs =
183         additionalChannelArgs == nil
184             ? nil
185             : [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES];
186     _PEMRootCertificates = [PEMRootCertificates copy];
187     _PEMPrivateKey = [PEMPrivateKey copy];
188     _PEMCertificateChain = [PEMCertificateChain copy];
189     _transportType = transportType;
190     _hostNameOverride = [hostNameOverride copy];
191     _logContext = logContext;
192     _channelPoolDomain = [channelPoolDomain copy];
193     _channelID = channelID;
194   }
195   return self;
196 }
197
198 - (nonnull id)copyWithZone:(NSZone *)zone {
199   GRPCCallOptions *newOptions =
200       [[GRPCCallOptions allocWithZone:zone] initWithServerAuthority:_serverAuthority
201                                                             timeout:_timeout
202                                                  flowControlEnabled:_flowControlEnabled
203                                                   oauth2AccessToken:_oauth2AccessToken
204                                                   authTokenProvider:_authTokenProvider
205                                                     initialMetadata:_initialMetadata
206                                                     userAgentPrefix:_userAgentPrefix
207                                                   responseSizeLimit:_responseSizeLimit
208                                                compressionAlgorithm:_compressionAlgorithm
209                                                        retryEnabled:_retryEnabled
210                                                   keepaliveInterval:_keepaliveInterval
211                                                    keepaliveTimeout:_keepaliveTimeout
212                                                   connectMinTimeout:_connectMinTimeout
213                                               connectInitialBackoff:_connectInitialBackoff
214                                                   connectMaxBackoff:_connectMaxBackoff
215                                               additionalChannelArgs:_additionalChannelArgs
216                                                 PEMRootCertificates:_PEMRootCertificates
217                                                       PEMPrivateKey:_PEMPrivateKey
218                                                 PEMCertificateChain:_PEMCertificateChain
219                                                       transportType:_transportType
220                                                    hostNameOverride:_hostNameOverride
221                                                          logContext:_logContext
222                                                   channelPoolDomain:_channelPoolDomain
223                                                           channelID:_channelID];
224   return newOptions;
225 }
226
227 - (nonnull id)mutableCopyWithZone:(NSZone *)zone {
228   GRPCMutableCallOptions *newOptions = [[GRPCMutableCallOptions allocWithZone:zone]
229       initWithServerAuthority:[_serverAuthority copy]
230                       timeout:_timeout
231            flowControlEnabled:_flowControlEnabled
232             oauth2AccessToken:[_oauth2AccessToken copy]
233             authTokenProvider:_authTokenProvider
234               initialMetadata:[[NSDictionary alloc] initWithDictionary:_initialMetadata
235                                                              copyItems:YES]
236               userAgentPrefix:[_userAgentPrefix copy]
237             responseSizeLimit:_responseSizeLimit
238          compressionAlgorithm:_compressionAlgorithm
239                  retryEnabled:_retryEnabled
240             keepaliveInterval:_keepaliveInterval
241              keepaliveTimeout:_keepaliveTimeout
242             connectMinTimeout:_connectMinTimeout
243         connectInitialBackoff:_connectInitialBackoff
244             connectMaxBackoff:_connectMaxBackoff
245         additionalChannelArgs:[[NSDictionary alloc] initWithDictionary:_additionalChannelArgs
246                                                              copyItems:YES]
247           PEMRootCertificates:[_PEMRootCertificates copy]
248                 PEMPrivateKey:[_PEMPrivateKey copy]
249           PEMCertificateChain:[_PEMCertificateChain copy]
250                 transportType:_transportType
251              hostNameOverride:[_hostNameOverride copy]
252                    logContext:_logContext
253             channelPoolDomain:[_channelPoolDomain copy]
254                     channelID:_channelID];
255   return newOptions;
256 }
257
258 - (BOOL)hasChannelOptionsEqualTo:(GRPCCallOptions *)callOptions {
259   if (callOptions == nil) return NO;
260   if (!areObjectsEqual(callOptions.userAgentPrefix, _userAgentPrefix)) return NO;
261   if (!(callOptions.responseSizeLimit == _responseSizeLimit)) return NO;
262   if (!(callOptions.compressionAlgorithm == _compressionAlgorithm)) return NO;
263   if (!(callOptions.retryEnabled == _retryEnabled)) return NO;
264   if (!(callOptions.keepaliveInterval == _keepaliveInterval)) return NO;
265   if (!(callOptions.keepaliveTimeout == _keepaliveTimeout)) return NO;
266   if (!(callOptions.connectMinTimeout == _connectMinTimeout)) return NO;
267   if (!(callOptions.connectInitialBackoff == _connectInitialBackoff)) return NO;
268   if (!(callOptions.connectMaxBackoff == _connectMaxBackoff)) return NO;
269   if (!areObjectsEqual(callOptions.additionalChannelArgs, _additionalChannelArgs)) return NO;
270   if (!areObjectsEqual(callOptions.PEMRootCertificates, _PEMRootCertificates)) return NO;
271   if (!areObjectsEqual(callOptions.PEMPrivateKey, _PEMPrivateKey)) return NO;
272   if (!areObjectsEqual(callOptions.PEMCertificateChain, _PEMCertificateChain)) return NO;
273   if (!areObjectsEqual(callOptions.hostNameOverride, _hostNameOverride)) return NO;
274   if (!(callOptions.transportType == _transportType)) return NO;
275   if (!areObjectsEqual(callOptions.logContext, _logContext)) return NO;
276   if (!areObjectsEqual(callOptions.channelPoolDomain, _channelPoolDomain)) return NO;
277   if (!(callOptions.channelID == _channelID)) return NO;
278
279   return YES;
280 }
281
282 - (NSUInteger)channelOptionsHash {
283   NSUInteger result = 0;
284   result ^= _userAgentPrefix.hash;
285   result ^= _responseSizeLimit;
286   result ^= _compressionAlgorithm;
287   result ^= _retryEnabled;
288   result ^= (unsigned int)(_keepaliveInterval * 1000);
289   result ^= (unsigned int)(_keepaliveTimeout * 1000);
290   result ^= (unsigned int)(_connectMinTimeout * 1000);
291   result ^= (unsigned int)(_connectInitialBackoff * 1000);
292   result ^= (unsigned int)(_connectMaxBackoff * 1000);
293   result ^= _additionalChannelArgs.hash;
294   result ^= _PEMRootCertificates.hash;
295   result ^= _PEMPrivateKey.hash;
296   result ^= _PEMCertificateChain.hash;
297   result ^= _hostNameOverride.hash;
298   result ^= _transportType;
299   result ^= _logContext.hash;
300   result ^= _channelPoolDomain.hash;
301   result ^= _channelID;
302
303   return result;
304 }
305
306 @end
307
308 @implementation GRPCMutableCallOptions
309
310 @dynamic serverAuthority;
311 @dynamic timeout;
312 @dynamic flowControlEnabled;
313 @dynamic oauth2AccessToken;
314 @dynamic authTokenProvider;
315 @dynamic initialMetadata;
316 @dynamic userAgentPrefix;
317 @dynamic responseSizeLimit;
318 @dynamic compressionAlgorithm;
319 @dynamic retryEnabled;
320 @dynamic keepaliveInterval;
321 @dynamic keepaliveTimeout;
322 @dynamic connectMinTimeout;
323 @dynamic connectInitialBackoff;
324 @dynamic connectMaxBackoff;
325 @dynamic additionalChannelArgs;
326 @dynamic PEMRootCertificates;
327 @dynamic PEMPrivateKey;
328 @dynamic PEMCertificateChain;
329 @dynamic transportType;
330 @dynamic hostNameOverride;
331 @dynamic logContext;
332 @dynamic channelPoolDomain;
333 @dynamic channelID;
334
335 - (instancetype)init {
336   return [self initWithServerAuthority:kDefaultServerAuthority
337                                timeout:kDefaultTimeout
338                     flowControlEnabled:kDefaultFlowControlEnabled
339                      oauth2AccessToken:kDefaultOauth2AccessToken
340                      authTokenProvider:kDefaultAuthTokenProvider
341                        initialMetadata:kDefaultInitialMetadata
342                        userAgentPrefix:kDefaultUserAgentPrefix
343                      responseSizeLimit:kDefaultResponseSizeLimit
344                   compressionAlgorithm:kDefaultCompressionAlgorithm
345                           retryEnabled:kDefaultRetryEnabled
346                      keepaliveInterval:kDefaultKeepaliveInterval
347                       keepaliveTimeout:kDefaultKeepaliveTimeout
348                      connectMinTimeout:kDefaultConnectMinTimeout
349                  connectInitialBackoff:kDefaultConnectInitialBackoff
350                      connectMaxBackoff:kDefaultConnectMaxBackoff
351                  additionalChannelArgs:kDefaultAdditionalChannelArgs
352                    PEMRootCertificates:kDefaultPEMRootCertificates
353                          PEMPrivateKey:kDefaultPEMPrivateKey
354                    PEMCertificateChain:kDefaultPEMCertificateChain
355                          transportType:kDefaultTransportType
356                       hostNameOverride:kDefaultHostNameOverride
357                             logContext:kDefaultLogContext
358                      channelPoolDomain:kDefaultChannelPoolDomain
359                              channelID:kDefaultChannelID];
360 }
361
362 - (nonnull id)copyWithZone:(NSZone *)zone {
363   GRPCCallOptions *newOptions =
364       [[GRPCCallOptions allocWithZone:zone] initWithServerAuthority:_serverAuthority
365                                                             timeout:_timeout
366                                                  flowControlEnabled:_flowControlEnabled
367                                                   oauth2AccessToken:_oauth2AccessToken
368                                                   authTokenProvider:_authTokenProvider
369                                                     initialMetadata:_initialMetadata
370                                                     userAgentPrefix:_userAgentPrefix
371                                                   responseSizeLimit:_responseSizeLimit
372                                                compressionAlgorithm:_compressionAlgorithm
373                                                        retryEnabled:_retryEnabled
374                                                   keepaliveInterval:_keepaliveInterval
375                                                    keepaliveTimeout:_keepaliveTimeout
376                                                   connectMinTimeout:_connectMinTimeout
377                                               connectInitialBackoff:_connectInitialBackoff
378                                                   connectMaxBackoff:_connectMaxBackoff
379                                               additionalChannelArgs:_additionalChannelArgs
380                                                 PEMRootCertificates:_PEMRootCertificates
381                                                       PEMPrivateKey:_PEMPrivateKey
382                                                 PEMCertificateChain:_PEMCertificateChain
383                                                       transportType:_transportType
384                                                    hostNameOverride:_hostNameOverride
385                                                          logContext:_logContext
386                                                   channelPoolDomain:_channelPoolDomain
387                                                           channelID:_channelID];
388   return newOptions;
389 }
390
391 - (nonnull id)mutableCopyWithZone:(NSZone *)zone {
392   GRPCMutableCallOptions *newOptions = [[GRPCMutableCallOptions allocWithZone:zone]
393       initWithServerAuthority:_serverAuthority
394                       timeout:_timeout
395            flowControlEnabled:_flowControlEnabled
396             oauth2AccessToken:_oauth2AccessToken
397             authTokenProvider:_authTokenProvider
398               initialMetadata:_initialMetadata
399               userAgentPrefix:_userAgentPrefix
400             responseSizeLimit:_responseSizeLimit
401          compressionAlgorithm:_compressionAlgorithm
402                  retryEnabled:_retryEnabled
403             keepaliveInterval:_keepaliveInterval
404              keepaliveTimeout:_keepaliveTimeout
405             connectMinTimeout:_connectMinTimeout
406         connectInitialBackoff:_connectInitialBackoff
407             connectMaxBackoff:_connectMaxBackoff
408         additionalChannelArgs:[_additionalChannelArgs copy]
409           PEMRootCertificates:_PEMRootCertificates
410                 PEMPrivateKey:_PEMPrivateKey
411           PEMCertificateChain:_PEMCertificateChain
412                 transportType:_transportType
413              hostNameOverride:_hostNameOverride
414                    logContext:_logContext
415             channelPoolDomain:_channelPoolDomain
416                     channelID:_channelID];
417   return newOptions;
418 }
419
420 - (void)setServerAuthority:(NSString *)serverAuthority {
421   _serverAuthority = [serverAuthority copy];
422 }
423
424 - (void)setTimeout:(NSTimeInterval)timeout {
425   if (timeout < 0) {
426     _timeout = 0;
427   } else {
428     _timeout = timeout;
429   }
430 }
431
432 - (void)setFlowControlEnabled:(BOOL)flowControlEnabled {
433   _flowControlEnabled = flowControlEnabled;
434 }
435
436 - (void)setOauth2AccessToken:(NSString *)oauth2AccessToken {
437   _oauth2AccessToken = [oauth2AccessToken copy];
438 }
439
440 - (void)setAuthTokenProvider:(id<GRPCAuthorizationProtocol>)authTokenProvider {
441   _authTokenProvider = authTokenProvider;
442 }
443
444 - (void)setInitialMetadata:(NSDictionary *)initialMetadata {
445   _initialMetadata = [[NSDictionary alloc] initWithDictionary:initialMetadata copyItems:YES];
446 }
447
448 - (void)setUserAgentPrefix:(NSString *)userAgentPrefix {
449   _userAgentPrefix = [userAgentPrefix copy];
450 }
451
452 - (void)setResponseSizeLimit:(NSUInteger)responseSizeLimit {
453   _responseSizeLimit = responseSizeLimit;
454 }
455
456 - (void)setCompressionAlgorithm:(GRPCCompressionAlgorithm)compressionAlgorithm {
457   _compressionAlgorithm = compressionAlgorithm;
458 }
459
460 - (void)setRetryEnabled:(BOOL)retryEnabled {
461   _retryEnabled = retryEnabled;
462 }
463
464 - (void)setKeepaliveInterval:(NSTimeInterval)keepaliveInterval {
465   if (keepaliveInterval < 0) {
466     _keepaliveInterval = 0;
467   } else {
468     _keepaliveInterval = keepaliveInterval;
469   }
470 }
471
472 - (void)setKeepaliveTimeout:(NSTimeInterval)keepaliveTimeout {
473   if (keepaliveTimeout < 0) {
474     _keepaliveTimeout = 0;
475   } else {
476     _keepaliveTimeout = keepaliveTimeout;
477   }
478 }
479
480 - (void)setConnectMinTimeout:(NSTimeInterval)connectMinTimeout {
481   if (connectMinTimeout < 0) {
482     _connectMinTimeout = 0;
483   } else {
484     _connectMinTimeout = connectMinTimeout;
485   }
486 }
487
488 - (void)setConnectInitialBackoff:(NSTimeInterval)connectInitialBackoff {
489   if (connectInitialBackoff < 0) {
490     _connectInitialBackoff = 0;
491   } else {
492     _connectInitialBackoff = connectInitialBackoff;
493   }
494 }
495
496 - (void)setConnectMaxBackoff:(NSTimeInterval)connectMaxBackoff {
497   if (connectMaxBackoff < 0) {
498     _connectMaxBackoff = 0;
499   } else {
500     _connectMaxBackoff = connectMaxBackoff;
501   }
502 }
503
504 - (void)setAdditionalChannelArgs:(NSDictionary *)additionalChannelArgs {
505   _additionalChannelArgs =
506       [[NSDictionary alloc] initWithDictionary:additionalChannelArgs copyItems:YES];
507 }
508
509 - (void)setPEMRootCertificates:(NSString *)PEMRootCertificates {
510   _PEMRootCertificates = [PEMRootCertificates copy];
511 }
512
513 - (void)setPEMPrivateKey:(NSString *)PEMPrivateKey {
514   _PEMPrivateKey = [PEMPrivateKey copy];
515 }
516
517 - (void)setPEMCertificateChain:(NSString *)PEMCertificateChain {
518   _PEMCertificateChain = [PEMCertificateChain copy];
519 }
520
521 - (void)setTransportType:(GRPCTransportType)transportType {
522   _transportType = transportType;
523 }
524
525 - (void)setHostNameOverride:(NSString *)hostNameOverride {
526   _hostNameOverride = [hostNameOverride copy];
527 }
528
529 - (void)setLogContext:(id)logContext {
530   _logContext = logContext;
531 }
532
533 - (void)setChannelPoolDomain:(NSString *)channelPoolDomain {
534   _channelPoolDomain = [channelPoolDomain copy];
535 }
536
537 - (void)setChannelID:(NSUInteger)channelID {
538   _channelID = channelID;
539 }
540
541 @end