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 19#import "GRPCHost.h" 20 21#import <GRPCClient/GRPCCall+Cronet.h> 22#import <GRPCClient/GRPCCall.h> 23#import <GRPCClient/GRPCCallOptions.h> 24#import <GRPCClient/GRPCTransport.h> 25 26#include <grpc/grpc.h> 27#include <grpc/grpc_security.h> 28 29#import "../../internal/GRPCCallOptions+Internal.h" 30#import "GRPCChannelFactory.h" 31#import "GRPCCompletionQueue.h" 32#import "GRPCSecureChannelFactory.h" 33#import "NSDictionary+GRPC.h" 34 35NS_ASSUME_NONNULL_BEGIN 36 37static NSMutableDictionary *gHostCache; 38 39@implementation GRPCHost { 40 NSString *_PEMRootCertificates; 41 NSString *_PEMPrivateKey; 42 NSString *_PEMCertificateChain; 43} 44 45+ (nullable instancetype)hostWithAddress:(NSString *)address { 46 return [[self alloc] initWithAddress:address]; 47} 48 49// Default initializer. 50- (nullable instancetype)initWithAddress:(NSString *)address { 51 if (!address) { 52 return nil; 53 } 54 55 // To provide a default port, we try to interpret the address. If it's just a host name without 56 // scheme and without port, we'll use port 443. If it has a scheme, we pass it untouched to the C 57 // gRPC library. 58 // TODO(jcanizales): Add unit tests for the types of addresses we want to let pass untouched. 59 NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]]; 60 if (hostURL.host && hostURL.port == nil) { 61 address = [hostURL.host stringByAppendingString:@":443"]; 62 } 63 64 // Look up the GRPCHost in the cache. 65 static dispatch_once_t cacheInitialization; 66 dispatch_once(&cacheInitialization, ^{ 67 gHostCache = [NSMutableDictionary dictionary]; 68 }); 69 @synchronized(gHostCache) { 70 GRPCHost *cachedHost = gHostCache[address]; 71 if (cachedHost) { 72 return cachedHost; 73 } 74 75 if ((self = [super init])) { 76 _address = [address copy]; 77 _retryEnabled = YES; 78 gHostCache[address] = self; 79 } 80 } 81 return self; 82} 83 84+ (void)resetAllHostSettings { 85 @synchronized(gHostCache) { 86 gHostCache = [NSMutableDictionary dictionary]; 87 } 88} 89 90- (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts 91 withPrivateKey:(nullable NSString *)pemPrivateKey 92 withCertChain:(nullable NSString *)pemCertChain 93 error:(NSError **)errorPtr { 94 _PEMRootCertificates = [pemRootCerts copy]; 95 _PEMPrivateKey = [pemPrivateKey copy]; 96 _PEMCertificateChain = [pemCertChain copy]; 97 return YES; 98} 99 100- (GRPCCallOptions *)callOptions { 101 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 102 options.userAgentPrefix = _userAgentPrefix; 103 options.responseSizeLimit = _responseSizeLimitOverride; 104 options.compressionAlgorithm = (GRPCCompressionAlgorithm)_compressAlgorithm; 105 options.retryEnabled = _retryEnabled; 106 options.keepaliveInterval = (NSTimeInterval)_keepaliveInterval / 1000; 107 options.keepaliveTimeout = (NSTimeInterval)_keepaliveTimeout / 1000; 108 options.connectMinTimeout = (NSTimeInterval)_minConnectTimeout / 1000; 109 options.connectInitialBackoff = (NSTimeInterval)_initialConnectBackoff / 1000; 110 options.connectMaxBackoff = (NSTimeInterval)_maxConnectBackoff / 1000; 111 options.PEMRootCertificates = _PEMRootCertificates; 112 options.PEMPrivateKey = _PEMPrivateKey; 113 options.PEMCertificateChain = _PEMCertificateChain; 114 options.hostNameOverride = _hostNameOverride; 115 if (_transportType == GRPCTransportTypeInsecure) { 116 options.transport = GRPCDefaultTransportImplList.core_insecure; 117 } else if ([GRPCCall isUsingCronet]) { 118 options.transport = gGRPCCoreCronetID; 119 } else { 120 options.transport = GRPCDefaultTransportImplList.core_secure; 121 } 122 options.logContext = _logContext; 123 124 return options; 125} 126 127+ (GRPCCallOptions *)callOptionsForHost:(NSString *)host { 128 // TODO (mxyan): Remove when old API is deprecated 129 GRPCCallOptions *callOptions = nil; 130 @synchronized(gHostCache) { 131 GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; 132 callOptions = [hostConfig callOptions]; 133 } 134 NSAssert(callOptions != nil, @"Unable to create call options object"); 135 if (callOptions == nil) { 136 NSLog(@"Unable to create call options object"); 137 callOptions = [[GRPCCallOptions alloc] init]; 138 } 139 return callOptions; 140} 141 142@end 143 144NS_ASSUME_NONNULL_END 145