OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * |
| 3 * Copyright 2015-2016, Google Inc. |
| 4 * All rights reserved. |
| 5 * |
| 6 * Redistribution and use in source and binary forms, with or without |
| 7 * modification, are permitted provided that the following conditions are |
| 8 * met: |
| 9 * |
| 10 * * Redistributions of source code must retain the above copyright |
| 11 * notice, this list of conditions and the following disclaimer. |
| 12 * * Redistributions in binary form must reproduce the above |
| 13 * copyright notice, this list of conditions and the following disclaimer |
| 14 * in the documentation and/or other materials provided with the |
| 15 * distribution. |
| 16 * * Neither the name of Google Inc. nor the names of its |
| 17 * contributors may be used to endorse or promote products derived from |
| 18 * this software without specific prior written permission. |
| 19 * |
| 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 * |
| 32 */ |
| 33 |
| 34 #import "GRPCChannel.h" |
| 35 |
| 36 #include <grpc/grpc_security.h> |
| 37 #include <grpc/support/alloc.h> |
| 38 #include <grpc/support/log.h> |
| 39 #include <grpc/support/string_util.h> |
| 40 |
| 41 /** |
| 42 * Returns @c grpc_channel_credentials from the specified @c path. If the file a
t the path could not |
| 43 * be read then NULL is returned. If NULL is returned, @c errorPtr may not be NU
LL if there are |
| 44 * details available describing what went wrong. |
| 45 */ |
| 46 static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **er
rorPtr) { |
| 47 // Files in PEM format can have non-ASCII characters in their comments (e.g. f
or the name of the |
| 48 // issuer). Load them as UTF8 and produce an ASCII equivalent. |
| 49 NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path |
| 50 encoding:NSUTF8StringEncod
ing |
| 51 error:errorPtr]; |
| 52 NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncodin
g |
| 53 allowLossyConversion:YES]; |
| 54 if (!contentInASCII.bytes) { |
| 55 // Passing NULL to grpc_ssl_credentials_create produces behavior we don't wa
nt, so return. |
| 56 return NULL; |
| 57 } |
| 58 return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL); |
| 59 } |
| 60 |
| 61 void freeChannelArgs(grpc_channel_args *channel_args) { |
| 62 for (size_t i = 0; i < channel_args->num_args; ++i) { |
| 63 grpc_arg *arg = &channel_args->args[i]; |
| 64 gpr_free(arg->key); |
| 65 if (arg->type == GRPC_ARG_STRING) { |
| 66 gpr_free(arg->value.string); |
| 67 } |
| 68 } |
| 69 gpr_free(channel_args); |
| 70 } |
| 71 |
| 72 /** |
| 73 * Allocates a @c grpc_channel_args and populates it with the options specified
in the |
| 74 * @c dictionary. Keys must be @c NSString. If the value responds to @c @selecto
r(UTF8String) then |
| 75 * it will be mapped to @c GRPC_ARG_STRING. If not, it will be mapped to @c GRPC
_ARG_INTEGER if the |
| 76 * value responds to @c @selector(intValue). Otherwise, an exception will be rai
sed. The caller of |
| 77 * this function is responsible for calling @c freeChannelArgs on a non-NULL ret
urned value. |
| 78 */ |
| 79 grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) { |
| 80 if (!dictionary) { |
| 81 return NULL; |
| 82 } |
| 83 |
| 84 NSArray *keys = [dictionary allKeys]; |
| 85 NSUInteger argCount = [keys count]; |
| 86 |
| 87 grpc_channel_args *channelArgs = gpr_malloc(sizeof(grpc_channel_args)); |
| 88 channelArgs->num_args = argCount; |
| 89 channelArgs->args = gpr_malloc(argCount * sizeof(grpc_arg)); |
| 90 |
| 91 // TODO(kriswuollett) Check that keys adhere to GRPC core library requirements |
| 92 |
| 93 for (NSUInteger i = 0; i < argCount; ++i) { |
| 94 grpc_arg *arg = &channelArgs->args[i]; |
| 95 arg->key = gpr_strdup([keys[i] UTF8String]); |
| 96 |
| 97 id value = dictionary[keys[i]]; |
| 98 if ([value respondsToSelector:@selector(UTF8String)]) { |
| 99 arg->type = GRPC_ARG_STRING; |
| 100 arg->value.string = gpr_strdup([value UTF8String]); |
| 101 } else if ([value respondsToSelector:@selector(intValue)]) { |
| 102 arg->type = GRPC_ARG_INTEGER; |
| 103 arg->value.integer = [value intValue]; |
| 104 } else { |
| 105 [NSException raise:NSInvalidArgumentException |
| 106 format:@"Invalid value type: %@", [value class]]; |
| 107 } |
| 108 } |
| 109 |
| 110 return channelArgs; |
| 111 } |
| 112 |
| 113 @implementation GRPCChannel { |
| 114 // Retain arguments to channel_create because they may not be used on the thre
ad that invoked |
| 115 // the channel_create function. |
| 116 NSString *_host; |
| 117 grpc_channel_args *_channelArgs; |
| 118 } |
| 119 |
| 120 |
| 121 - (instancetype)initWithHost:(NSString *)host |
| 122 secure:(BOOL)secure |
| 123 credentials:(struct grpc_channel_credentials *)credentials |
| 124 channelArgs:(NSDictionary *)channelArgs { |
| 125 if (!host) { |
| 126 [NSException raise:NSInvalidArgumentException format:@"host argument missing
"]; |
| 127 } |
| 128 |
| 129 if (secure && !credentials) { |
| 130 return nil; |
| 131 } |
| 132 |
| 133 if (self = [super init]) { |
| 134 _channelArgs = buildChannelArgs(channelArgs); |
| 135 _host = [host copy]; |
| 136 if (secure) { |
| 137 _unmanagedChannel = grpc_secure_channel_create(credentials, _host.UTF8Stri
ng, _channelArgs, |
| 138 NULL); |
| 139 } else { |
| 140 _unmanagedChannel = grpc_insecure_channel_create(_host.UTF8String, _channe
lArgs, NULL); |
| 141 } |
| 142 } |
| 143 |
| 144 return self; |
| 145 } |
| 146 |
| 147 - (void)dealloc { |
| 148 // TODO(jcanizales): Be sure to add a test with a server that closes the conne
ction prematurely, |
| 149 // as in the past that made this call to crash. |
| 150 grpc_channel_destroy(_unmanagedChannel); |
| 151 freeChannelArgs(_channelArgs); |
| 152 } |
| 153 |
| 154 + (GRPCChannel *)secureChannelWithHost:(NSString *)host { |
| 155 return [[GRPCChannel alloc] initWithHost:host secure:YES credentials:NULL chan
nelArgs:NULL]; |
| 156 } |
| 157 |
| 158 + (GRPCChannel *)secureChannelWithHost:(NSString *)host |
| 159 pathToCertificates:(NSString *)path |
| 160 channelArgs:(NSDictionary *)channelArgs { |
| 161 // Load default SSL certificates once. |
| 162 static grpc_channel_credentials *kDefaultCertificates; |
| 163 static dispatch_once_t loading; |
| 164 dispatch_once(&loading, ^{ |
| 165 NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem |
| 166 // Do not use NSBundle.mainBundle, as it's nil for tests of library projects
. |
| 167 NSBundle *bundle = [NSBundle bundleForClass:self.class]; |
| 168 NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"]; |
| 169 NSError *error; |
| 170 kDefaultCertificates = CertificatesAtPath(path, &error); |
| 171 NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with t
he root " |
| 172 "certificates, is needed to establish secure (TLS) connections. Bec
ause the file is " |
| 173 "distributed with the gRPC library, this error is usually a sign th
at the library " |
| 174 "wasn't configured correctly for your project. Error: %@", |
| 175 bundle.bundlePath, defaultPath, error); |
| 176 }); |
| 177 |
| 178 //TODO(jcanizales): Add NSError** parameter to the initializer. |
| 179 grpc_channel_credentials *certificates = path |
| 180 ? CertificatesAtPath(path, NULL) |
| 181 : kDefaultCertificates; |
| 182 |
| 183 return [[GRPCChannel alloc] initWithHost:host |
| 184 secure:YES |
| 185 credentials:certificates |
| 186 channelArgs:channelArgs]; |
| 187 } |
| 188 |
| 189 |
| 190 + (GRPCChannel *)secureChannelWithHost:(NSString *)host |
| 191 credentials:(struct grpc_channel_credentials *)creden
tials |
| 192 channelArgs:(NSDictionary *)channelArgs { |
| 193 return [[GRPCChannel alloc] initWithHost:host |
| 194 secure:YES |
| 195 credentials:credentials |
| 196 channelArgs:channelArgs]; |
| 197 |
| 198 } |
| 199 |
| 200 + (GRPCChannel *)insecureChannelWithHost:(NSString *)host |
| 201 channelArgs:(NSDictionary *)channelArgs { |
| 202 return [[GRPCChannel alloc] initWithHost:host |
| 203 secure:NO |
| 204 credentials:NULL |
| 205 channelArgs:channelArgs]; |
| 206 } |
| 207 |
| 208 @end |
OLD | NEW |