diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m index 5aecdb1cbeb2be284891847d6ae21951ba270876..bb25743ed177b4a93b00c5661b103d624834867d 100644 --- a/src/objective-c/GRPCClient/private/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -36,6 +36,7 @@ #include <grpc/grpc_security.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include <grpc/support/string_util.h> /** * Returns @c grpc_channel_credentials from the specifie @c path. If the file at the path could not @@ -57,6 +58,17 @@ static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **er 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 @@ -68,31 +80,39 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) { return NULL; } - NSUInteger argCount = [dictionary count]; + NSArray *keys = [dictionary allKeys]; + NSUInteger argCount = [keys count]; - // Allocate memory for both the individual args and their container - grpc_channel_args *channelArgs = gpr_malloc(sizeof(grpc_channel_args) - + argCount * sizeof(grpc_arg)); + grpc_channel_args *channelArgs = gpr_malloc(sizeof(grpc_channel_args)); channelArgs->num_args = argCount; - channelArgs->args = (grpc_arg *) (channelArgs + sizeof(grpc_channel_args)); + channelArgs->args = gpr_malloc(argCount * sizeof(grpc_arg)); + + // TODO(kriswuollett) Check that keys adhere to GRPC core library requirements - __block NSUInteger argIndex = 0; - [dictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, - BOOL * _Nonnull stop) { - // use of UTF8String assumes that grpc won't modify the pointers - grpc_arg *arg = &channelArgs->args[argIndex++]; - arg->key = (char *) [key UTF8String]; // allow exception to be raised if not supported + Class invalidValueType = NULL; - if ([obj respondsToSelector:@selector(UTF8String)]) { + 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 = (char *) [obj UTF8String]; - } else if ([obj respondsToSelector:@selector(intValue)]) { + arg->value.string = gpr_strdup([value UTF8String]); + } else if ([value respondsToSelector:@selector(intValue)]) { arg->type = GRPC_ARG_INTEGER; - arg->value.integer = [obj intValue]; + arg->value.integer = [value intValue]; } else { - [NSException raise:NSInvalidArgumentException format:@"Invalid value type: %@", [obj class]]; + invalidValueType = [value class]; + break; } - }]; + } + + if (invalidValueType) { + freeChannelArgs(channelArgs); + [NSException raise:NSInvalidArgumentException + format:@"Invalid value type: %@", invalidValueType]; + } return channelArgs; } @@ -135,7 +155,7 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) { // 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); - gpr_free(_channelArgs); + freeChannelArgs(_channelArgs); } + (GRPCChannel *)secureChannelWithHost:(NSString *)host {