diff options
-rw-r--r-- | examples/objective-c/helloworld/main.m | 2 | ||||
-rw-r--r-- | src/objective-c/GRPCClient/GRPCCall+ChannelArg.h (renamed from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h) | 16 | ||||
-rw-r--r-- | src/objective-c/GRPCClient/GRPCCall+ChannelArg.m (renamed from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m) | 23 | ||||
-rw-r--r-- | src/objective-c/GRPCClient/private/GRPCChannel.h | 45 | ||||
-rw-r--r-- | src/objective-c/GRPCClient/private/GRPCChannel.m | 166 | ||||
-rw-r--r-- | src/objective-c/GRPCClient/private/GRPCHost.h | 1 | ||||
-rw-r--r-- | src/objective-c/GRPCClient/private/GRPCHost.m | 31 | ||||
-rw-r--r-- | src/objective-c/GRPCClient/private/GRPCSecureChannel.h | 55 | ||||
-rw-r--r-- | src/objective-c/GRPCClient/private/GRPCSecureChannel.m | 118 |
9 files changed, 247 insertions, 210 deletions
diff --git a/examples/objective-c/helloworld/main.m b/examples/objective-c/helloworld/main.m index a62f8362a2..755dce33df 100644 --- a/examples/objective-c/helloworld/main.m +++ b/examples/objective-c/helloworld/main.m @@ -34,6 +34,7 @@ #import <UIKit/UIKit.h> #import "AppDelegate.h" +#import <GRPCClient/GRPCCall+ChannelArg.h> #import <GRPCClient/GRPCCall+Tests.h> #import <HelloWorld/Helloworld.pbrpc.h> @@ -42,6 +43,7 @@ static NSString * const kHostAddress = @"localhost:50051"; int main(int argc, char * argv[]) { @autoreleasepool { [GRPCCall useInsecureConnectionsForHost:kHostAddress]; + [GRPCCall setUserAgentPrefix:@"HelloWorld/1.0" forHost:kHostAddress]; HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress]; diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h index 8528be44c0..bd6b064f16 100644 --- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,9 +30,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ +#import "GRPCCall.h" -#import "GRPCChannel.h" +/** + * Methods to configure GRPC channel options. + */ +@interface GRPCCall (ChannelArg) + +/** + * Use the provided @c userAgentPrefix at the beginning of the HTTP User Agent string for all calls + * to the specified @c host. + */ ++ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host; -@interface GRPCUnsecuredChannel : GRPCChannel -- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER; @end diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m index 15b6ffc75c..5f9932d86d 100644 --- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,20 +31,19 @@ * */ -#import "GRPCUnsecuredChannel.h" +#import "GRPCCall+ChannelArg.h" -#include <grpc/grpc.h> +#import "private/GRPCHost.h" -@implementation GRPCUnsecuredChannel +@implementation GRPCCall (ChannelArg) -- (instancetype)initWithHost:(NSString *)host { - return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL, NULL)]); ++ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host { + if (!host) { + [NSException raise:NSInvalidArgumentException + format:@"host and userAgentPrefix must be provided."]; + } + GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; + hostConfig.userAgentPrefix = userAgentPrefix; } -// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers -// for GRPCChannel. Move them into GRPCChannel, which will make the following unnecessary. -- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel { - [NSException raise:NSInternalInconsistencyException format:@"use the other initializer"]; - return [self initWithHost:nil]; // silence warnings -} @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h index e2d19d506a..1888dea1b4 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCChannel.h @@ -33,18 +33,51 @@ #import <Foundation/Foundation.h> -struct grpc_channel; +#include <grpc/grpc.h> + +struct grpc_channel_credentials; + /** * Each separate instance of this class represents at least one TCP connection to the provided host. - * Create them using one of the subclasses |GRPCSecureChannel| and |GRPCUnsecuredChannel|. */ @interface GRPCChannel : NSObject -@property(nonatomic, readonly) struct grpc_channel *unmanagedChannel; + +@property(nonatomic, readonly, nonnull) struct grpc_channel *unmanagedChannel; + +- (nullable instancetype)init NS_UNAVAILABLE; /** - * This initializer takes ownership of the passed channel, and will destroy it when this object is - * deallocated. It's illegal to pass the same grpc_channel to two different GRPCChannel objects. + * Creates a secure channel to the specified @c host using default credentials and channel + * arguments. If certificates could not be found to create a secure channel, then @c nil is + * returned. */ -- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER; ++ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host; + +/** + * Creates a secure channel to the specified @c host using the specified @c pathToCertificates and + * @c channelArgs. Only in tests should @c pathToCertificates be nil or + * @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set. Passing nil for @c pathToCertificates + * results in using the default root certificates distributed with the library. If certificates + * could not be found in any case, then @c nil is returned. + */ ++ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host + pathToCertificates:(nullable NSString *)pathToCertificates + channelArgs:(nullable NSDictionary *)channelArgs; + + +/** + * Creates a secure channel to the specified @c host using the specified @c credentials and + * @c channelArgs. Only in tests should @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set. + */ ++ (nonnull GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host + credentials:(nonnull struct grpc_channel_credentials *)credentials + channelArgs:(nullable NSDictionary *)channelArgs; + +/** + * Creates an insecure channel to the specified @c host using the specified @c channelArgs. + */ ++ (nonnull GRPCChannel *)insecureChannelWithHost:(nonnull NSString *)host + channelArgs:(nullable NSDictionary *)channelArgs; + @end diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 4366e63320..7a676060c1 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -33,22 +33,114 @@ #import "GRPCChannel.h" -#include <grpc/grpc.h> +#include <grpc/grpc_security.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> -@implementation GRPCChannel +/** + * Returns @c grpc_channel_credentials from the specified @c path. If the file at the path could not + * be read then NULL is returned. If NULL is returned, @c errorPtr may not be NULL if there are + * details available describing what went wrong. + */ +static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) { + // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the + // issuer). Load them as UTF8 and produce an ASCII equivalent. + NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path + encoding:NSUTF8StringEncoding + error:errorPtr]; + NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding + allowLossyConversion:YES]; + if (!contentInASCII.bytes) { + // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return. + return NULL; + } + return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL); +} + +void freeChannelArgs(grpc_channel_args *channel_args) { + for (size_t i = 0; i < channel_args->num_args; ++i) { + grpc_arg *arg = &channel_args->args[i]; + gpr_free(arg->key); + if (arg->type == GRPC_ARG_STRING) { + gpr_free(arg->value.string); + } + } + gpr_free(channel_args); +} + +/** + * Allocates a @c grpc_channel_args and populates it with the options specified in the + * @c dictionary. Keys must be @c NSString. If the value responds to @c @selector(UTF8String) then + * it will be mapped to @c GRPC_ARG_STRING. If not, it will be mapped to @c GRPC_ARG_INTEGER if the + * value responds to @c @selector(intValue). Otherwise, an exception will be raised. The caller of + * this function is responsible for calling @c freeChannelArgs on a non-NULL returned value. + */ +grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) { + if (!dictionary) { + return NULL; + } -- (instancetype)init { - return [self initWithChannel:NULL]; + NSArray *keys = [dictionary allKeys]; + NSUInteger argCount = [keys count]; + + grpc_channel_args *channelArgs = gpr_malloc(sizeof(grpc_channel_args)); + channelArgs->num_args = argCount; + channelArgs->args = gpr_malloc(argCount * sizeof(grpc_arg)); + + // TODO(kriswuollett) Check that keys adhere to GRPC core library requirements + + for (NSUInteger i = 0; i < argCount; ++i) { + grpc_arg *arg = &channelArgs->args[i]; + arg->key = gpr_strdup([keys[i] UTF8String]); + + id value = dictionary[keys[i]]; + if ([value respondsToSelector:@selector(UTF8String)]) { + arg->type = GRPC_ARG_STRING; + arg->value.string = gpr_strdup([value UTF8String]); + } else if ([value respondsToSelector:@selector(intValue)]) { + arg->type = GRPC_ARG_INTEGER; + arg->value.integer = [value intValue]; + } else { + [NSException raise:NSInvalidArgumentException + format:@"Invalid value type: %@", [value class]]; + } + } + + return channelArgs; +} + +@implementation GRPCChannel { + // Retain arguments to channel_create because they may not be used on the thread that invoked + // the channel_create function. + NSString *_host; + grpc_channel_args *_channelArgs; } -// Designated initializer -- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel { - if (!unmanagedChannel) { + +- (instancetype)initWithHost:(NSString *)host + secure:(BOOL)secure + credentials:(struct grpc_channel_credentials *)credentials + channelArgs:(NSDictionary *)channelArgs { + if (!host) { + [NSException raise:NSInvalidArgumentException format:@"host argument missing"]; + } + + if (secure && !credentials) { return nil; } - if ((self = [super init])) { - _unmanagedChannel = unmanagedChannel; + + if (self = [super init]) { + _channelArgs = buildChannelArgs(channelArgs); + _host = [host copy]; + if (secure) { + _unmanagedChannel = grpc_secure_channel_create(credentials, _host.UTF8String, _channelArgs, + NULL); + } else { + _unmanagedChannel = grpc_insecure_channel_create(_host.UTF8String, _channelArgs, NULL); + } } + return self; } @@ -56,5 +148,61 @@ // TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely, // as in the past that made this call to crash. grpc_channel_destroy(_unmanagedChannel); + freeChannelArgs(_channelArgs); } + ++ (GRPCChannel *)secureChannelWithHost:(NSString *)host { + return [[GRPCChannel alloc] initWithHost:host secure:YES credentials:NULL channelArgs:NULL]; +} + ++ (GRPCChannel *)secureChannelWithHost:(NSString *)host + pathToCertificates:(NSString *)path + channelArgs:(NSDictionary *)channelArgs { + // Load default SSL certificates once. + static grpc_channel_credentials *kDefaultCertificates; + static dispatch_once_t loading; + dispatch_once(&loading, ^{ + NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem + // Do not use NSBundle.mainBundle, as it's nil for tests of library projects. + NSBundle *bundle = [NSBundle bundleForClass:self.class]; + NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"]; + NSError *error; + kDefaultCertificates = CertificatesAtPath(path, &error); + NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root " + "certificates, is needed to establish secure (TLS) connections. Because the file is " + "distributed with the gRPC library, this error is usually a sign that the library " + "wasn't configured correctly for your project. Error: %@", + bundle.bundlePath, defaultPath, error); + }); + + //TODO(jcanizales): Add NSError** parameter to the initializer. + grpc_channel_credentials *certificates = path + ? CertificatesAtPath(path, NULL) + : kDefaultCertificates; + + return [[GRPCChannel alloc] initWithHost:host + secure:YES + credentials:certificates + channelArgs:channelArgs]; +} + + ++ (GRPCChannel *)secureChannelWithHost:(NSString *)host + credentials:(struct grpc_channel_credentials *)credentials + channelArgs:(NSDictionary *)channelArgs { + return [[GRPCChannel alloc] initWithHost:host + secure:YES + credentials:credentials + channelArgs:channelArgs]; + +} + ++ (GRPCChannel *)insecureChannelWithHost:(NSString *)host + channelArgs:(NSDictionary *)channelArgs { + return [[GRPCChannel alloc] initWithHost:host + secure:NO + credentials:NULL + channelArgs:channelArgs]; +} + @end diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h index 6b4f98746d..69a115e88c 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.h +++ b/src/objective-c/GRPCClient/private/GRPCHost.h @@ -39,6 +39,7 @@ struct grpc_call; @interface GRPCHost : NSObject @property(nonatomic, readonly) NSString *address; +@property(nonatomic, copy) NSString *userAgentPrefix; /** The following properties should only be modified for testing: */ diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index a8cd3a0e74..f750841a44 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -34,11 +34,15 @@ #import "GRPCHost.h" #include <grpc/grpc.h> +#import <GRPCClient/GRPCCall+ChannelArg.h> #import "GRPCChannel.h" #import "GRPCCompletionQueue.h" -#import "GRPCSecureChannel.h" -#import "GRPCUnsecuredChannel.h" +#import "NSDictionary+GRPC.h" + +// TODO(jcanizales): Generate the version in a standalone header, from templates. Like +// templates/src/core/surface/version.c.template . +#define GRPC_OBJC_VERSION_STRING @"0.13.0" @interface GRPCHost () // TODO(mlumish): Investigate whether caching channels with strong links is a good idea. @@ -106,13 +110,28 @@ - (GRPCChannel *)channel { // Create it lazily, because we don't want to open a connection just because someone is // configuring a host. + if (!_channel) { + NSMutableDictionary *args = [NSMutableDictionary dictionary]; + + // TODO(jcanizales): Add OS and device information (see + // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#user-agents ). + NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING; + if (_userAgentPrefix) { + userAgent = [@[_userAgentPrefix, userAgent] componentsJoinedByString:@" "]; + } + args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent; + if (_secure) { - _channel = [[GRPCSecureChannel alloc] initWithHost:_address - pathToCertificates:_pathToCertificates - hostNameOverride:_hostNameOverride]; + if (_hostNameOverride) { + args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride; + } + + _channel = [GRPCChannel secureChannelWithHost:_address + pathToCertificates:_pathToCertificates + channelArgs:args]; } else { - _channel = [[GRPCUnsecuredChannel alloc] initWithHost:_address]; + _channel = [GRPCChannel insecureChannelWithHost:_address channelArgs:args]; } } return _channel; diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h deleted file mode 100644 index b82b9fe35a..0000000000 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <grpc/grpc.h> - -#import "GRPCChannel.h" - -struct grpc_channel_credentials; - -@interface GRPCSecureChannel : GRPCChannel -- (instancetype)initWithHost:(NSString *)host; - -/** - * Only in tests shouldn't pathToCertificates or hostNameOverride be nil. Passing nil for - * pathToCertificates results in using the default root certificates distributed with the library. - */ -- (instancetype)initWithHost:(NSString *)host - pathToCertificates:(NSString *)path - hostNameOverride:(NSString *)hostNameOverride; - -/** The passed arguments aren't required to be valid beyond the invocation of this initializer. */ -- (instancetype)initWithHost:(NSString *)host - credentials:(struct grpc_channel_credentials *)credentials - args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER; -@end diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m deleted file mode 100644 index a573c171e9..0000000000 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#import "GRPCSecureChannel.h" - -#include <grpc/grpc_security.h> - -// Returns NULL if the file at path couldn't be read. In that case, if errorPtr isn't NULL, -// *errorPtr will be an object describing what went wrong. -static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) { - // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the - // issuer). Load them as UTF8 and produce an ASCII equivalent. - NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path - encoding:NSUTF8StringEncoding - error:errorPtr]; - NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding - allowLossyConversion:YES]; - if (!contentInASCII.bytes) { - // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return. - return NULL; - } - return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL); -} - -@implementation GRPCSecureChannel - -- (instancetype)initWithHost:(NSString *)host { - return [self initWithHost:host pathToCertificates:nil hostNameOverride:nil]; -} - -- (instancetype)initWithHost:(NSString *)host - pathToCertificates:(NSString *)path - hostNameOverride:(NSString *)hostNameOverride { - // Load default SSL certificates once. - static grpc_channel_credentials *kDefaultCertificates; - static dispatch_once_t loading; - dispatch_once(&loading, ^{ - NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem - // Do not use NSBundle.mainBundle, as it's nil for tests of library projects. - NSBundle *bundle = [NSBundle bundleForClass:self.class]; - NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"]; - NSError *error; - kDefaultCertificates = CertificatesAtPath(path, &error); - NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root " - "certificates, is needed to establish secure (TLS) connections. Because the file is " - "distributed with the gRPC library, this error is usually a sign that the library " - "wasn't configured correctly for your project. Error: %@", - bundle.bundlePath, defaultPath, error); - }); - - //TODO(jcanizales): Add NSError** parameter to the initializer. - grpc_channel_credentials *certificates = path - ? CertificatesAtPath(path, NULL) - : kDefaultCertificates; - if (!certificates) { - return nil; - } - - // Ritual to pass the SSL host name override to the C library. - grpc_channel_args channelArgs; - grpc_arg nameOverrideArg; - channelArgs.num_args = 1; - channelArgs.args = &nameOverrideArg; - nameOverrideArg.type = GRPC_ARG_STRING; - nameOverrideArg.key = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG; - // Cast const away. Hope C gRPC doesn't modify it! - nameOverrideArg.value.string = (char *) hostNameOverride.UTF8String; - grpc_channel_args *args = hostNameOverride ? &channelArgs : NULL; - - return [self initWithHost:host credentials:certificates args:args]; -} - -- (instancetype)initWithHost:(NSString *)host - credentials:(grpc_channel_credentials *)credentials - args:(grpc_channel_args *)args { - return (self = [super - initWithChannel:grpc_secure_channel_create( - credentials, host.UTF8String, args, NULL)]); -} - -// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers -// for GRPCChannel. Move them into GRPCChannel, which will make the following unnecessary. -- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel { - [NSException raise:NSInternalInconsistencyException format:@"use another initializer"]; - return [self initWithHost:nil]; // silence warnings -} - -@end |